【程式設計開發】簡單五子棋 AI 設計
【研究報告】簡單五子棋 AI 設計
社會研討課做的研究課題,有空了來完善一下演算法吧,基礎 \(\text{UI}\) 直接搬的 \(ckj\) 的,已獲得本人允許。
一:【探究目標】
學習、設計、部分實現一隻基礎五子棋 \(\text{AI}\),調整引數並簡單測試對弈能力(考慮最簡單的無禁手五子棋)。
二:【設計演算法】
演算法核心問題:落子決策(擇優)。
1.【暴力出奇跡】
“精確記憶”能力是計算機相較於人類的優勢之一,自然引入“棋譜記錄”。
(1).【全棋譜記憶】
在大小為 \(19\times 19\) 的棋盤上,每個格子有 “黑”、“白”、“無” 三種狀態,共 \(3^{361}\)
儲存空間有限、算力不足,不具備可實踐性。
(2).【部分棋譜記憶】
利用有限的儲存空間和算力記錄部分棋譜。
- 查詢開局譜,使用優勢走法到有限步數停止
- 中間局使用單步決策演算法進行臨場決策
- 根據殘局譜,檢測是否出現必勝局
2.【單步決策-落子估價】
開局和殘局有棋譜參考,中間局則需“臨場應變”。
- 每次落子前,掃描當前棋局,選擇最優落點
何為最優?
- 設計“估價函式”,以當前棋局狀態為引數,為可落子位置估計“落點價值”,擇其大者
影響落點價值的因素構成?
【特殊情況】下回合必勝/敗
【攻/防】攻防分數佔比
【當前局面】根據連子點數給予不同分數
【\(^{*}\)
【對手的價值盤】用相同的估價方法計算對手的價值盤,提前斷絕對方的優勢落點
3.【預言決策-對抗搜尋】
(1).【深度搜索】
【Min-Max 搜尋演算法】
分數從終點往起點方向累加(葉節點為 \(0\)),我方落子加正分,對方落子加負分,我方希望最後總分最大,對方希望總分最小。
\(\text{findmax}\) 層:\(s(x)=\max\{s(y)+v(x,y)|y\in son(x)\}\)
\(\text{findmin}\) 層:\(s(x)=\min\{s(y)-v(x,y)|y\in son(x)\}\)
兩者相互遞迴呼叫。
(2).【演算法優化】
【Alpha-beta 剪枝】
對於 \(\text{findmax}(x)\):
設 \(son(x)=\{y_1,y_2...\}\),當前檢索到 \(y_k\) 的位置,設 \(alpha=\max\{s(y_i)+v(x,y_i)|1\leqslant i < k\}\)。
設 \(son(y_k)=\{z_1,z_2...\}\),當前檢索到 \(z_l\) 的位置,若 \(s(z_l)-v(y_k,z_l)\leqslant alpha-v(x,y_k)\),則 \(s(y_k)=\min\{s(z)+v(y_k,z)|z\in son(y_k)\}\) \(\leqslant s(z_l)-v(y_k,z_l)\) \(\leqslant alpha-v(x,y_k)\),而 \(alpha\) 在不斷尋找更大的分數更新自己,所以 \(s(y_k)\) 必對 \(alpha\) 無影響,\(y_k\) 剩下的子節點 \(\{z_{l+1},...z_{m}\}\) 不必再檢索。
對於 \(\text{findmin}\) 層類似。
//(完整程式碼1000+行,不作展示)
inline LL findmin(Re deep,LL alpha,Re op);//對手想讓我儘量小
inline LL findmax(Re deep,LL beta,Re op) {//我想盡量大
if(...)return -inf;//對手贏了
if(...)return 0;//平局
if(deep>MAX_deep)return 0;//搜尋深度限制
LL ans=-dfs_inf;//準備一個對於我來說的最壞情況(低分)
for(i;;){//列舉狀態
luozi();//試探落子
ans=max(ans,v+findmin(deep+1,ans-v,op^1));//搜下一層
luozi_back();//撤銷落子
if(ans>=beta)return ans;//alpha-beta剪枝
}
return ans;
}
【棋盤區域性搜尋】不需要搜尋棋盤上所有位置
(3).【\(^{*}\)更好的落子估價-更多影響因素構成】
【\(^{*}\)未來局面】
【\(^{*}\)空步預測】
4.【引數調整】
調整各種引數,不同引數下的機器相互對戰。
【*估價函式】各種不同的連子局面,分別設定什麼引數
【攻防比】我攻:我防:敵攻:敵防
【搜尋引數】深度、廣度
三:【對弈測試】
對弈參與者:
- \(\text{AI}_{ckj}\):由 \(ckj\) 同學提供,使用單步決策演算法
- \(\text{AI}_0\):採用估價函式進行單步決策
- \(\text{AI}_1\):採用搜尋演算法進行預言決策
- \(\text{Human}_1\):為避免實力差距過大,粗略限制了思考時間
1.【調整引數】
(1).【攻防比】
【對弈物件】我方:\(\text{AI}_0\),敵方:\(\text{AI}_{ckj}\)
【先手開局最佳成績】我攻:我防:敵攻:敵防=2:4:3:1 勝:敗:平=316:129:55
【後手開局最佳成績】我攻:我防:敵攻:敵防=3:4:2:1 勝:敗:平=271:165:64
(2).【搜尋範圍】
【對弈物件】
我方:\(\text{AI}_1\)(估價函式攻防比取 3:4:2:1),敵方:\(\text{AI}_{ckj}\)
【先手開局最佳成績】deep=1,wide=9 勝:敗:平=322:125:53
【後手開局最佳成績】deep=2,wide=4 勝:敗:平=342:83:75
2.【AI 對弈】
【對弈物件】我方:\(\text{AI}_1\),敵方:\(\text{AI}_{0}\)
【先手開局】勝:敗:平=125:49:326
【後手開局】勝:敗:平=6:84:410
3.【人機對弈】
(1).單步決策
【對弈物件】我方:\(\text{AI}_0\),敵方:\(\text{Human}_1\)
【先手開局】勝:敗:平=11:9:0
【後手開局】勝:敗:平=8:12:0
(2).預言決策
【對弈物件】我方:\(\text{AI}_1\),敵方:\(\text{Human}_1\)
【先手開局】勝:敗:平=16:4:0
【後手開局】勝:敗:平=11:9:0
四:【資料分析】
- 調整引數時,更多地是在趨於”如何擊敗 \(\text{AI}_{ckj}\)“,所以先手最佳成績為"deep=1",後手最佳成績為"deep=2"(\(\text{AI}_{ckj}\) 為單步決策演算法)
- \(\text{AI}_0\) 與 \(\text{AI}_1\) 對弈時兩者差異不大、平局居多,推測原因為:估價函式引數設定對強度影響較大,而兩者估價函式同源
- 人機對弈時,搜尋預測明顯比單步預測更強
五:【總結】
1.【對弈演算法一般性】
-
簡單棋類博弈均可採用“估價函式+對抗搜尋”的方法設計 \(\text{AI}\)。對於局面狀態數量較少的型別,可以一次搜尋找到必勝策略;較多者則輔以“部分棋譜記憶”。
-
設計估價函式方案需要大量時間調整引數,“部分棋譜記憶”需要大量棋譜資料。
2.【演算法改進空間】
-
錄入開局譜、殘局譜
-
與較強 \(\text{AI}\) 對弈,尋找最佳估價函式引數方案
-
優化複雜度
六:【致謝】
感謝 \(ckj\) 同學提供基礎 \(\text{UI}\) 程式碼。