本文讲述笔者对 负值最大与 Alpha-Beta 剪枝的结合 的理解,代码参考计算机博弈-象棋百科全书:Alpha-Beta 搜索,感谢作者与译者
由于本人知识浅薄,难免有解释不当的地方,还请您带着怀疑的态度阅读本文,如有不当之处还请不吝指正
前置内容
此处对极大极小算法与 Alpha-Beta 剪枝不再赘述
可参考博弈游戏的AI设计(一):极大极小树
博弈游戏的AI设计(二):博弈树与 α-β 剪枝
负值最大算法
负值最大是对最小-最大的一种优化,它使得代码形式十分简洁:
int NegaMax(int depth) {
int best = -INFINITY;
if (depth <= 0) {
返回当前着子方的评估值;
}
生成所有着法;
for(遍历所有着法){
执行着法;
val = -NegMax(depth-1);
撤销着法;
if(val > best)
best = val;
}
返回best;
}
在负值最大算法中,由于搜索返回的结果为对方的评估值(估值越高,对对方越有利)的负值,每一层中所需选取的 best 值都为最大值,即选取对对方最不利的值。
负值最大与 Alpha-Beta 剪枝的结合
首先给出代码的结构:
int AlphaBeta(depth, alpha, beta){
if(depth <= 0)
返回当前着子方评估值;
生成所有着法;
for(遍历所有着法){
执行着法;
int val = -AlphaBeta(depth-1, -beta, -alpha);
撤销着法;
if(val >= beta)
返回beta;
if(val > alpha)
更新alpha;
}
返回alpha;
}
下面对 alpha,beta 的传参做出解释:
下一层的 beta 值
alphai 记录了当前第 i 层的预选值(最大值),则在第 i+1 层中向下搜索时,若发现第 i+1 层的预选值返回给第 i 层后将比 alphai 小,则无需继续搜索直接剪枝。由于从第 i+1 层将结果返回给第 i 层会发生取负值,令 betai+1 = -alphai,则有如下转换:
->
预选值
i+1 > beta
i+1 时返回
根据上文对负值最大算法的描述,每一层中的 best(即预选值)为最大值,故只要出现 val > betai+1 即返回。等于亦同理,因此最终剪枝的表达式为:
if(val >= beta)
return beta;
下一层的 alpha 值
由于 alpha 负责记录当前层的预选值(最大值),因此可以在每一层搜索时都令 alpha = -∞,即与不作剪枝的极小极大算法无异。
考虑更深处的搜索:
在第 i+3 层中,有 betai+3 = -alphai+2,其中 alphai+2 为第 i+2 层的预选值。若最终的 alphai+2 将使 -alphai+2 >= betai+1,则在第 i+2 层的向下搜索将变得毫无意义。
倘若仅按照 alpha = -∞ 的方式进行搜索,显然在第 i+3 层中不会知道有关 betai+1 的任何信息,但我们希望能在知道 -alphai+2 >= betai+1 将发生时及时剪枝停止搜索。
基于此,令 alphai+2 = -betai+1,可看作在第 i+3 层中已经搜到值为 -alphai+2 的结点,因为 i+3 层中其他比这个值更大的结点若到达 i+1 层都无意义,所以可以放心地利用 betai+3 剪枝。
另外,当 val > alpha 时才会对 alpha 进行更新,而 alphai+1 = -betai,则有:
->
-val
i+1 < beta
i
即实际上在第 i 层取得的第 i+1 层结果中不会出现比 betai 更大的值,故上节剪枝表达式中的 = 是必不可少的。
如有不当还请不吝指正