AlphaBeta剪枝演算法

2021-09-06 06:11:16 字數 3812 閱讀 9571

關於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)

board.getorderedmoves();

int best = -mate-1;

intmove;

chessboard nextboard;

while

(board.hasmoremoves())

return

best;

}

下面這個pdf更清楚地說明了negamax風格的alphabeta演算法的過程:

為了更準確地理解minmax和negamax兩種不同風格的搜尋執行過程,畫出了詳細的**,發現negamax更容易理解了,**也確實精練了不少。

當採用了置換表演算法後,還需要對pv-nodes, cut-nodes和all-nodes三種型別結點的含義以及如何變化有更準確地了解。

可以發現,negamax風格的演算法有下面的特點(**來自象棋巫師):

int alphabeta(int depth, int alpha, int beta)

generatelegalmoves();

while (movesleft())

if (val > alpha)

} recordhash(depth, alpha, hashf);

return alpha;   // 此時的alpha就是記錄了當前結點的所有子結點的最大的負評估值!

}這面的**在置換表探查方面感覺有點問題,又從marek strejczek的**《some aspects of chess programming》的第87頁上找到一段**,感覺這段**充分利用了置換表中儲存的資訊。

chscore alphabetawithtt(chposition node,chscore alpha,beta) 

if (entry.score

beta =flag.score;}}

if (entry.flag ==lower)

if (entry.score >alpha)

}if (entry.flag ==exact)

}else

}}g =alpha;

x =left_most_child(node);

hash_flag =upper;

best_move =null;

while

(isnotnull (x) )

hash_flag =exact;

best_move =current_move;

}x =next_brother(x);

}puttohash(node, g, hash_flag, best_move)

return

alpha;

} //

end of alphabetawithtt

Alpha beta剪枝演算法例項分析

看本章之前,請先參看前一篇文章 minimax演算法及例項分析 由於minimax演算法有乙個很大的問題就是計算複雜性。由於所需搜尋的節點數隨最大深度呈指數膨脹,而演算法的效果往往和深度相關,因此這極大限制了演算法的效果。alpha beta剪枝是對minimax的補充和改進。採用alpha bet...

Alpha beta剪枝演算法例項分析

原帖 看本章之前,請先參看前一篇文章 minimax演算法及例項分析 由於minimax演算法有乙個很大的問題就是計算複雜性。由於所需搜尋的節點數隨最大深度呈指數膨脹,而演算法的效果往往和深度相關,因此這極大限制了演算法的效果。alpha beta剪枝是對minimax的補充和改進。採用alpha ...

Alpha beta剪枝演算法例項分析

看本章之前,請先參看前一篇文章 minimax演算法及例項分析 由於minimax演算法有乙個很大的問題就是計算複雜性。由於所需搜尋的節點數隨最大深度呈指數膨脹,而演算法的效果往往和深度相關,因此這極大限制了演算法的效果。alpha beta剪枝是對minimax的補充和改進。採用alpha bet...