國際象棋AI設計(二)----搜尋
Alpha-Beta剪枝
Alpha-Beta 同“MinMax”非常相似, 區別主要在於 MinMax 執行時要檢
查整個博弈樹,然後儘可能選擇最好的線路。 Alpha-Beta 則是在MinMax的基礎上把一些不必要的分支剪去,加快搜索速度。
Alpha-Beta 是在搜尋中傳遞兩個值:
- Alpha:搜尋到的最好值。
- Beta:對於對手來說最壞的值。
搜尋過程中Alpha,Beta有以下三種關係情況:
- 評估值小於Alpha:剪枝。因為對我方來說,當前局面的評估值小於Alpha將不可能產生更好的情況,對局面不可能有提升,因此對剩餘的合法著法沒有必要再搜尋。
- 評估值大於Beta
- 評估值大於 Alpha 但小於 Beta:保留該著法,可以考慮該著法。
置換表 + Zobrist 鍵值 + 迭代加深
使用“Zobrist 鍵值”來唯一記錄棋盤的資訊。
這個可以利用 python-chess 來完成,用這個鍵值來代表某一個確定的局面。從搜尋中得到結果後,要儲存到置換表中,主要為了避免重複工作。
使用迭代加深技術來搭配置換表。
有一開始只搜尋一層,如果搜尋的時間比分配的時間少,那麼搜尋兩層,然後再搜尋三層,等等,直到用完時間為止。這足以保證很好地運用時間了。
如果可以很快搜索到一個深度,那麼在接下來的時間可以搜尋得更深,或許可以完成。
如果局面比想象的複雜,那麼不必搜尋得太深,但是至少有合理的著法可以走了,因為不太可能連 1 層搜尋也完不成。
在置換表的基礎上進行迭代加深搜尋,很多局面都可以直接從置換表中得到,從而加快搜索速度。
空著向前裁剪
空著向前裁剪(Null-Move Forward Pruning),運用可能忽視重要路線的
冒險策略,使得國際象棋的分枝因子銳減,它導致搜尋深度的顯著提高,因為大多數情況下它明顯降低了搜尋的數量。它的工作原理是裁剪大量無用著法而只保留好的。
在搜尋著法以前(事實上在你生成著法以前),做一個減少深度的搜尋,讓對手先走,如果這個搜尋的結果大於或等於 Beta,那麼簡單地返回 Beta而不需要搜尋任何著法。這個思想就給了對手出擊的機會,如果你的局面仍然好到超過 Beta 的程度,就假設如果你搜索了所有的著法也會超過 Beta。
這個方法能節省時間的原因是,開始時用了減少深度的搜尋。深度減少
因子稱為 R,因此跟用深度 D 搜尋所有的著法相比,現在你是先以 D - R 搜
索對手的著法。一個比較好 R 是 2,如果你要對所有的著法搜尋 6 層,你最
終只對對手所有的著法搜尋了 4 層
靜態搜尋
國際象棋中會有很多強制的應對。如果有人用馬吃掉我們的象,那麼我
們最好吃還他的馬。Alpha-Beta 搜尋不是特別針對這種情況的。 我們把深度引數傳遞給函式,當深度到達零就做完了,即使一方的後被捉。
靜態搜尋就是一個應對的方法。當 Alpha-Beta 用盡深度後,通過呼叫靜態搜尋來代替呼叫“Evaluate()”。這個函式也對局面作評價,只是避免了
在明顯有對策的情況下看錯局勢。
簡而言之,靜態搜尋就是應對可能的動態局面的搜尋。
典型的靜態搜尋只搜尋吃子著法。這會引發一個問題,因為在國際象棋中吃子通常不是強制的。如果局勢很平靜,而且我們面對的吃子只有 QxP(後吃兵,導致丟後),我們不會強迫後去吃兵的,所以靜態搜尋不應該強迫吃子。
因此,走子一方可以選擇是吃子還是不吃子。
如果評價好得足以截斷而不需要試圖吃子時,就馬上截斷(返回 Beta)。
如果評價不足以產生截斷,但是比 Alpha 好,那麼就更新 Alpha 來反映靜態評價。然後嘗試吃子著法,如果其中任何一個產生截斷,搜尋就中止。可能它們沒有一個是好的,這也沒問題。
這個函式有幾個可能的結果:
- 可能評價函式會返回足夠高的數值,使得函式通過 Beta 截斷馬上返回
- 可能某個吃子產生 Beta 截斷
- 可能靜態評價比較壞,而任何吃子著法也不會更好
- 可能任何吃子都不好,但是靜態評價只比 Alpha 高一點點