AlphaBeta剪枝算法
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
AlphaBeta剪枝算法
关于AlphaBeta剪枝的文章太多,这个方法是所有其它搜索方法的基础,得多花些时间认真地理解。
先把基本概念再回顾一遍:
节点:在中国象棋中就是一个棋盘的当前局面Board,当然该轮到谁走棋也是确定的。这里的圆形节点表示终止节点,在中国象棋里就是一方被将死的情况(或者到达了搜索的最大深度),后续不会再有着法产生,游戏如果走到这里就会结束。在引擎里通常给红方一个很大的评估值,如+30000,给黑方一个很小的评估值,如-30000,来方便地判断这种结束局面。(胜利局面有稍微不同的表示法,用-30000+层数ply来表示)
连线:表示一步着法Move,通过这步着法后,局面发生变化,先后手也要交换。
层:通常的术语是ply,复数形式是plies,也有称为levels,当然与depth也是对应的。这个术语是为了与比赛里常说的回合相区分,一个回合通常包含2步,这个ply就表示某一方走了一步。根节点记为0层,以下的层数递增。
深度depth:要注意是从下到上的,还是从上到下的。(1)通常的算法书中都是从下到上递增的,即根节点为最大搜索深度,走到最底部的叶子结点为0,这种算法只要记住一个depth 值就可以了。(2)而另一种记法是根部结点为0,越向下depth增加,这时在搜索时就要传递2个参数值,depth和maxDepth,稍微有点啰嗦,应该也会影响一点效率。另外在探查置换表中的结点时,用第(1)种记法也方便一些,因为要知道从当前节点迭代的深度值,否则还要在置换表中保存depth和maxDepth两个值。
AlphaBeta剪枝方法是对Minimax方法的优化,它们产生的结果是完全相同的,只不过运行效率不一样。
这种方法的前提假设与Minimax也是一样的:
1)双方都按自己认为的最佳着法行棋。
2)对给定的盘面用一个分值来评估,这个评估值永远是从一方(搜索程序)来评价的,红方有利时给一个正数,黑方有利时给一个负数。(如果红方有利时返回正数,当轮到黑方走棋时,评估值又转换到黑方的观点,如果认为黑方有利,也返回正数,这种评估方法都不适合于常规的算法描述)
3)从我们的搜索程序(通常把它称为Max)看来,分值大的数表示对己方有利,而对于对方Min来说,它会选择分值小的着法。
但要注意:用Negamax风格来描述的AlphaBeta中的评估函数,对轮到谁走棋是敏感的。
也就是说:
在Minimax风格的AlphaBeta算法中,轮红方走棋时,评估值为100,轮黑方走棋评估值仍是100。
但在Negamax风格的AlphaBeta算法中,轮红方走棋时,评估值为100,轮黑方走棋时评估值要为-100。
贴一段伪代码:
def ABNegaMax (board, depth, maxDepth, alpha, beta)
if ( board.isGameOver() or depth == maxDepth )
return board.evaluate(), null
bestMove = null
bestScore = -INFINITY
for move in board.getMoves()
newBoard = board.makeMove(move)
score = ABNegaMax(newBoard, maxDepth, depth+1, -beta, -max(alpha, bestScore))
score = -score
if ( score > bestScore )
bestScore = score
bestMove = move
# early loop exit (pruning)
if ( bestScore >= beta ) return bestScore, bestMove
return bestScore, bestMove
用下列语句开始调用:
ABNegaMax(board, player, maxDepth, 0, -INFINITY, INFINITY)
// method call with depth 5 and minimum and maximum boundaries
// minimaxValue = alphaBeta(board, 5, -MATE, +MATE)
int alphaBeta(ChessBoard board, int depth, int alpha, int beta)
{
int value;
if( depth == 0 || board.isEnded())
{
value = evaluate(board);
return value;
}
board.getOrderedMoves();
int best = -MATE-1;
int move;
ChessBoard nextBoard;
while (board.hasMoreMoves())
{
move = board.getNextMove();
nextBoard = board.makeMove(move);
value = -alphaBeta(nextBoard, depth-1,-beta,-alpha);
if(value > best)
best = value;
if(best > alpha)
alpha = best;
if(best >= beta)
break;
}
return best;
}
下面这个PDF更清楚地说明了Negamax风格的alphabeta算法的过程:
/~anderson/cs440/index.html/lib/exe/fetch.php? media=notes:negamax2.pdf
为了更准确地理解minmax和negamax两种不同风格的搜索执行过程,画出了详细的图解,发现negamax更容易理解了,代码也确实精练了不少。
当采用了置换表算法后,还需要对PV-Nodes, Cut-Nodes和All-Nodes三种类型结点的含义以及如何变化有更准确地了解。