• 沒有找到結果。

程式的搜尋演算法

第三章 資料結構與演算法

3.2 程式的搜尋演算法

傳統的棋類搜尋演算法都是使用最大最小搜尋樹。最大最小搜尋樹是依據人 類下棋觀點所研發出的一種演算法,棋手思考下一步棋要下哪時,當然會想要下 在看起來最好的一個位置上,而對方同樣也會下在對他最有利的位置來作反制,

若盤面對我方有利則給予高分,反之則給低分。以電腦觀點來看就是一個搜尋樹,

輪我方走時會選擇對自己最好的,輪敵方走時就選擇對自己最差的,直到底層以 後回傳,最後根據傳回的分數選擇最好的走步。

搜尋樹的成長是呈指數成長的,若每方每步都有 10 種選擇可走,雙方各走 10 步,則總共就有1020個節點。這種成長速度使得深層的搜尋完全無法在有限時 間內作完,所以通常會將雙方可走的步數作個限制,達到限制的節點稱為葉節點,

達到葉節點時我們必須賦予該盤面一個分數,最後會根據這個分數來決定這個盤 面是好或壞,賦予分數的動作即是審局函數。

棋手下棋時的基本思考原則是:我走了 A 走步,對方可能會用 B 作為回應,

若我再走 C 走步,則對方走 D 走步回應。如此反覆繼續深入,直到棋手認為推演 的覆蓋度足夠,則會開始評價下這手棋造成的局面對現況的影響是否良好,若覺 得不夠好,則會退回去初始盤面不走 A 而走另一步,對方的回應又有所不同。如 此繼續推演直到將所有走法嘗試一次之後取出最好的出步。

利用樹狀結構來將人類這樣的思考行為表示出來,稱為遊戲樹。

圖 3.2.1 井字遊戲的遊戲樹

以井字遊戲為例,由圖 3.2.1 可以發現搜尋層數越深,其節點數量呈現指數 成長,並且井字遊戲的分支數量是隨層數逐漸縮小的,因為棋子放入以後不會再 取出,能下的著手會越來越少,所以能夠在較短的時間之內搜到底層完成搜尋,

得出最好的答案。但西洋棋或是中國象棋並不會因為棋子數量變動而使走步減少,

甚至可能在棋子數量減少時,由於盤面更空曠導致走步選擇更多。雙方皆有 n 種 走步可走的情形下,若雙方各推 k 步,這棵遊戲樹就具有 n2k個節點需要搜尋,

這種巨大的搜尋量通常沒有辦法在短時間內搜完,所以必須要避開部分無用的分 支或者限制搜尋的深度。

搜尋至所限制的深度時,我們會呼叫審局函數,對現在的盤面情形給予一個 對應的分數,然後往父節點層層向上回傳至根節點,再搜下一個走步,重複至整 棵樹搜尋完畢,根節點即可得知哪一個走步最高分。

搜尋演算法我們採用 Alpha-Beta Pruning,該演算法於 1956 年由 McCarthy

John 提出概念,在 1963 年由 Alexander Brudno 發表。

Alpha-Beta Pruning 脫胎於 Min-Max 演算法,大幅提升搜尋效率。

Min-Max Search 演算法設定敵我雙方皆會選擇對自己最有利的走步執行,採 取深度優先的方式由根節點逐層往下搜尋,到了限制深度時,於葉節點呼叫審局 函數給予分數以確定盤面好壞。

該演算法分為取 Min 以及取 Max 兩部分,分別在我方層以及敵方層使用,

在我方層時會取最大值作為最佳走步,而輪敵方走步時則會取最小值作為最佳走 步,如此交互進行至指定深度即回傳結果輸出。

圖 3.2.2 Min-Max 搜尋的例子

圖 3.2.2 即為 Min-Max 搜尋的例子,以深度優先的方式在根節點我們得到第 一次的審局分後,即會開始進行與其他走步的比較,並依照所屬層數進行取最大

Min-Max Search 演算法對整棵樹進行搜尋,所有節點一個不漏,能夠解決問 題沒有錯誤,但效率低落。其虛擬碼如圖 3.2.3 所示。

圖 3.2.3 Min-Max 演算法的虛擬碼

Alpha-Beta 演算法對於 Min-Max 演算法的改進就是發現無法改變上層選擇時 即停止搜尋所在節點的子樹。

圖 3.2.4 即為一個較單純的例子,單數層為最大層使用方型節點,會選擇對 子樹取最大值,最小層則使用圓形節點,對子樹取最小值。三個截斷的時間點都 是餘下子樹已經無法對上層的選擇做出影響,左方截斷時第四層的 4 已經過小,

沒有任何機會取代上層的 5;中央第四層截斷的 6 也相同,雖是同分,但也代表 結果不會再改變,因為第四層是最小層,該層的分數只會往更小變化,最多是持 平;右方的截斷則發生在第二層,5 已經過小無法影響根節點的 6。

圖 3.2.4 Alpha-Beta 搜尋演算法例子

Alpha-Beta Search 使用了α和β兩個參數,α代表所有最大層目前的最大值,

β則代表最小層目前的最小值,兩者的作用是做為界限使用,在 Alpha-Beta 搜尋 過程中,兩者會交錯傳遞至下層。當在最大層取最大值發現分數大於β時,即代 表上層取最小時不會取到目前節點,故可忽略餘下其它分支,不需搜尋,此稱β 截斷;同理,於最小層取最小值時若發現其值小於α,就可以放棄其它分支的搜 尋,此稱α截斷。

圖 3.2.5 是一個具有α、β值的遊戲樹,裡面分別有四次截斷,順序如下:

Type 1:PV(Principle Variation),每個分支第一次搜尋的的節點(圖上為最左 子節點)皆為 Type 1。根節點為 Type 1。

Type 2:Cut Nodes。Type 1 的子節點中,除最左子節點外,皆為 Cut Nodes。

Type 3:All Nodes。Type 2 的子節點為 Type 3,Type 3 的子節點為 Type 2。

節點的示意圖如圖 3.2.6:

圖 3.2.6 Nodes Type

走步的排序只對 Type 1 和 Type 2 生效,能夠節省搜尋時間,Type 3 則無幫助。

圖 3.2.7 Alpha-Beta 的虛擬碼

Alpha-Beta 搜尋虛擬碼如圖 3.2.7 所示。透過圖 3.2.7 我們可以發現,無論是 Min-Max 或是 Alpha-Beta,程式碼都分成兩個部分,分別掌握最小值端與最大值 端,除了取值行為本身不同以外,α與β截斷判斷也完全不同。

Knuth 和 Moore 在 1975 年提出了 Nega-Max 搜尋演算法,將最小值與最大值 整合在一起,其核心概念為:在一個零和遊戲中,對我方有利的走步,同時也是 對敵方不利的走步。

Nega-Max 虛擬碼如圖 3.2.8 所示。

圖 3.2.8 Nega-Max 搜尋的虛擬碼

更進一步,NegaMax 形式的 Alpha-Beta Search 虛擬碼不只將最大最小兩端作 整合,α與β在往下層傳遞時也能以相同的方式改變。下層分數取負值時,同時 將α與β順序對調並且加上負號,即能保持相同的作用,在這種情況下,α截斷 的行為變得與β截斷的類似,消除了於 Min-Max 基底下 Alpha-Beta Search 演算法 α截斷與β截斷行為的不同,讓程式碼更簡潔也更易維護。

其虛擬碼如下。

圖 3.2.9 NegaMax 形式的 Alpha-Beta Search 虛擬碼

與傳統棋類不同,暗棋多出了一個翻子的動作,也就是可以選擇不走子去翻 暗子,而傳統的 Alpha-Beta 必須選擇一個走步以讓搜尋繼續進行下去,無論走步 的結果多差。所以我們在搜尋裡面加入了空步,即讓對方直接進行下一次動作,

以代表翻棋動作的執行。在執行空步的結果比走步還好的時候,就是代表該翻棋 了,此時我們就會讓程式去執行翻棋的動作。

搜尋中我們不考慮直接加入翻棋的行動而選擇以空步取代的原因是,翻棋的 期望值計算會導致分支度過大,並且準度有限, 同時α與β值的設定也是一個 問題,種種因素下我們決定將翻棋的計算獨立在 Alpha-Beta 之外。

相關文件