在考虑到对手的可能走法之后,Minimax算法能够较为恰当地找出玩家的最优走法。但是,在生成博弈树时,这个信息却没有使用!我们看看早先介绍的BoardEvaluation评分函数。回忆一下图7-17,这是从初始状态开始,玩家X走了两步,玩家O走了一步之后,生成的博弈树的一部分。我们可以注意到,Minimax算法的性能非常低下,即使每一个子搜索都能够表示一个负棋面状态。总共有36个节点需要评价。Minimax并不会利用玩家O第一步走在左上角避免被秒杀这个事实。AlphaBeta算法(图7-20)使用一个固定的策略来从搜索树中剪除无效的搜索,而不是在搜索中采取特殊的策略来使用信息。使用AlphaBeta算法的博弈树等价扩展如图7-21所示。
图 7-20 AlphaBeta详解 图 7-21 AlphaBeta追寻深度为2时的搜索AlphaBeta算法也是搜索最好的走法,它能够记住如果玩家O走在左上角,那么玩家X的得分不会超过2这样的信息。对于玩家O的后续每一步,AlphaBeta会决定是否玩家X有至少一步这样的走法,这步走法能够比玩家O第一步要好。因此,博弈树只扩展了16个节点(相比Minimax节省了50%的开销)。更重要的是,如果这个部分的结果无关紧要,那么算法就不需要预计算可能的走法并且修改状态。
AlphaBeta选择Minimax也同样会选择的走法,但是会节省大量的开销。和本章之前描述的其他寻路算法一样,AlphaBeta算法也假设对手不会犯错,这样避免了搜索那些对局面没有影响的部分。
AlphaBeta递归地搜索博弈树,并且维护两个值,α和β,如果α<β,那么表示玩家α有胜利的机会。值α表示已经为玩家找到的最坏局面状态(如果没有找到即负无穷),并且声明玩家的走法能够保证不低于这个下界。α越大表示玩家能够表现得越好,如果α等于正无穷,那么玩家能够找到一步绝杀,并且搜索中值。β值表示现在的最好局面状态(如果没有找到即正无穷),即我们玩家能够达到的最好局面状态。β越小表示对手在限制玩家方面表现得越好。因为AlphaBeta算法有一个最大追寻深度,所以任何决定都受这个深度限制。
图7-21的博弈树给出了执行时候的[α,β]值;最开始为[-∞,∞]。使用追寻深度为2的搜索,仅仅只考虑玩家X接下来会采取的一步走法,AlphaBeta试着为玩家O找出最优走法。因为AlphaBeta是递归的,我们能够追寻其进程,对博弈树进行遍历。AlphaBeta指导玩家O首先应该占住左上角的位置。在评价了玩家X的5个可行走法之后,很明显玩家X只能保证α最小等于-2(使用一字棋的BoardEvaluation静态评估函数)。当AlphaBeta考虑O的第二步时,其[α,β]值现在是[-2,∞],即“O做出最坏的决定能够达到的状态得分为-2,最好的决定可能赢得比赛”。当评价完玩家X的第一步对策,AlphaBeta发现X已经赢得比赛,所以将不会再考虑X的更多走法。
回忆一下AlphaBeta搜索是基于NegMax。AlphaBeta保证不会搜索无用节点。图7-22是在图7-17的基础上进行追寻深度为3的搜索,我们可以看到AlphaBeta是如何剪枝的,Minimax的博弈树需要156个节点,而AlphaBeta博弈树只扩展了66个节点。
图 7-22 AlphaBeta的追寻深度为3的搜索初始位置为节点n,玩家O需要考虑6个可行走法。在轮到玩家或者对手时都可以进行键值。在图7-22的搜索中,有两个这样的例子。
轮到玩家
假设玩家O在下在左列中间的位置,X于是下在顶行中间的位置(搜索树中这是根节点的最左边的孙子节点)。现在,从O的角度来看,O能够得到的最好的分数是-1。当X走在底行中间,我们决定是否O能够赢得比赛时,将会用到这个值。这个时候[α,β]是[-∞,-1]。当O走在顶行的中间时,AlphaBeta进行评价,得到分数为1,因为这个值大于-1,所以在这个层级上的O剩余三个走法都可以忽略。
轮到对手
假设玩家O在下在左列中间的位置,X于是下在右上角,那么将会立刻赢得比赛。AlphaBeta将不会考虑X的其他两个可行走法,因为在以玩家O上一步走法为根节点的子树中,其剩余的搜索节点都会剪除。
搜索将会剪掉那些确定会失败的子树。当基于Minimax扩展出AlphaBeta时,存在两种剪枝的方法,α剪枝和β剪枝,当基于NegMax扩展出简单的AlphaBeta时,那么只有一种剪枝的方法。因为AlphaBeta是递归的,那么[α,β]表示玩家的获胜机会大小,[-β,-α]表示对手获胜机会的大小。在递归调用AlphaBeta时,会轮流从玩家和对手的角度来考虑问题。AlphaBeta会返回Minimax(如果是基于NegMax扩展,返回和NegMax相同的结果)相同的结果,但是它只会很少地扩展博弈树。AlphaBeta仍然使用深度的限制,这样来看,它的行为非常类似于深度优先搜索。
输入/输出
输入输出和Minimax相同。主要的区别是AlphaBeta将会利用已经计算过的状态来决定是否继续搜索特定的子树。