,此即為日本動漫棋魂中的千年佐為,也就是SAI。眾所周知,圍棋的規則相比於中國象棋,國際象棋等等都簡單許多,真是因為更簡單的規則,才誕生 了更複雜的邏輯。目前的圍棋AI還很不行,最NB的應該是日本人做出的後又經過眾多中國的圍棋愛好者改進之後的AI——首談,其水平號稱是國際大師的水 平,其實際水平估計也就是業餘一段左右(比我的水平還是要稍微高一點點的樣子)。而且,只要在其中下出一些“非主流布局”,比如神馬天元+五五啊,宇宙流 之類的,手談基本上就GAME OVER了。
目前在OJ(Online Judge)上還沒有類似的圍棋的全面類比演算法,局部的還是有,這是因為圍棋的規則如果包括一些不常見的,比如盤角曲四啊,三劫迴圈等等,也是很難用計算 機類比出的,而一些著名的圍棋類比軟體(比如線上的TOM啊,弈城啊等等)又無法開源,在CSDN上和PUDN上又基本上是工程層級的項目,鮮有直接的核 心演算法。多虧了一個叫荷蒲的網站,我看其作者應該也是圍棋愛好者吧,他自己建立了一個網站,主要是在網上接一些項目,由於他本人喜歡圍棋,故也創辦了“荷 蒲圍棋”,並向廣大的圍棋愛好者提供了關於類比演算法的一些思路。但是,關於三劫迴圈等等,還是沒有列出來。
這 一期的Round,我只給出一些主要的函數以及成員變數,函數與函數之間沒有明顯的先後關係,但是,每一個函數可以實現一些主要功能,在以後封裝的時候也 很好解決。該思路一共分為六個部分,關於吃子的那個部分利用了遞迴的思想解決了對於“一片棋”的氣眼的計算。在統計誰是獲勝方時,不能單一地像黑白棋一樣 來分別統計黑子和白子的數目,因為其中有些空缺的地方需要判斷是黑方還是白方或者既不是黑方又不是白方的,這樣描述起來還是有些麻煩。
更多地關於該源碼的解析(比如具體的數目問題)以及關於源碼在其它功能的拓展和完善,我有待聯絡荷蒲的作者之後再予以補充。
以下,我分為六大塊來解析“荷蒲”先生的源碼:
1 //1、首先定義圍棋子資訊
2
3 #define EDGE 23 //棋盤最大格數
4 #define MAXMM 500 //最大手數
5 //color表示棋子顏色,x,y表示在棋盤上的座標
6 //num表示下子的順序。=0表示提前擺放的子。
7 //zt 表示棋子狀態
8 //qs 表示棋子的氣數
9 //sm 表示有說明資訊
10
11 typedef struct qizi
12 {
13 int color,x,y,num,zt,qs,sm;
14 }qizi;
15
16 //吳昊評述:這個用法比較不常見,意義是為這個執行個體化的結構體定義新的成員變數。
17 qizi qipu[MAXMM]; //棋譜資訊
18 qizi qipan[EDGE][EDGE]; //棋盤資訊
19
20 //2、緊接著要考慮的是下棋相關資訊。
21 //吳昊評述:這裡的定義比較複雜,作者考慮了人機對戰以及非人機對戰中的總共四種情況,並且有學習和聯絡模式,有圍棋中需要的計時器,最後還在規則上考慮了中國規則,日本規則等等(中日韓三國的圍棋規則有不同,比如在盤角曲四的處理上),但是,很多成員變數只是為了以後代碼的擴充作準備的,在後面的代碼 描述中並沒有出現。
22 int nk=0; //顯示棋子序號,nk=2顯示序號,1=氣數
23 int BoardLines=19; //棋盤線數,預設19
24 bool ComputerPlaying; //1=該電腦下 0=人下
25 bool Computerp1=0; //1=電腦下黑 0=人下
26 bool Computerp2=0; //1=電腦下白 0=人下
27 int PlayType=0; //2=人-人,1=人-電腦,13=人-網路,0=沒有開始,-1=刪除棋盤上死子,-2=暫停,3=布黑子,4=布白子,9=示範,11=學習
28 int PlayType1=0; //2=人-人,1=人-電腦,13=人-網路,0=沒有開始,-1=刪除棋盤上死子,-2=暫停,3=布黑子,4=布白子,11=學習
29 int MoveCount,MoveCount1; //計步器,記錄落子手數,自然順序
30 int Playnum=0,Playnum1=0; //要標識的圍棋手數,下棋順序
31 int CurrentX; //記錄熱子X座標,
32 int CurrentY; //記錄熱子Y座標
33 char CurrentWho; //記錄當前棋子顏色,0=黑 1=白 2=空(終局等,待寫)
34 char CurrentWho1; //備份上一次CurrentWho
35 int timew=0,timeb=0; //計時器設定資料
36 int sdy1=0,sdy2=0; //學習功能上使用
37 int gz; //規則0=中國規則,1=日本規則,2=應氏規則
38 bool plays1=true; //學習持黑
39 bool plays2=false; //學習持白
40
41 //3、圍棋電子棋盤的資料初始化。
42 //資料初始化
43
44 void wqinit(void)
45 {
46 BoardLines=19; //19X19路標準圍棋盤
47 MoveCount=0; //一步棋未下,自然順序
48 MoveCount1=0; //一步棋未下
49 ComputerPlaying=1; //預設電腦執黑先行
50 CurrentWho=0; //預設黑先; 黑方=0;白方=1;空方=2;
51 CurrentX=0; //當前一步棋的X座標,水平從左至右為1...19
52 CurrentY=0; //當前一步棋的Y座標,垂直從上到下為1...19
53 timew=0,timeb=0;
54 Playnum=0; //下棋順序
55 Playnum1=0;
56 //下面是棋盤初始化
57 for (int i=0;i<=BoardLines;i++)
58 for (int j=0;j<=BoardLines;j++)
59 {
60 qipan[i][j].color=2;
61 qipan[i][j].x=0;
62 qipan[i][j].y=0;
63 qipan[i][j].num=0;
64 qipan[i][j].zt=0;
65 }
66
67 //清空棋譜記錄,全部設為無效點。QiPu[0][x]留作它用
68 for (int i=0;i<500;i++)
69 {
70 qipu[i].color=2;
71 qipu[i].x=0;
72 qipu[i].y=0;
73 qipu[i].num=0;
74 qipu[i].zt=0;
75 qipu[i].sm=0;
76 qpsm1[i].n=0;
77 qpsm1[i].t=0;
78 strcpy(qpsm1[i].sm,"/");
79 }
80 }
81
82 /*
83 4、根據圍棋規則編寫的一些相關處理函數模組
84 圍棋棋子的吃子,是根據圍棋棋子的氣數來計算的。氣數為0的棋子應當從棋盤上拿掉。
85 圍棋氣數的計算問題,應當說是圍棋軟體的核心問題。
86 "氣"是指棋子在棋盤上可以串連的交叉點,也是棋子的出路。
87 圍棋的氣數計算,要考慮一個圍棋子的連通問題。
88 下面的圖形中,交叉點的X代表棋子的氣,
89 */
90
91
92 [圖1]
93 圖1中右上方的黑子,有兩個交叉點和它的直線相接,因此它有兩口氣。左上方的黑子有三口氣,而下邊的黑子有四口氣。
94
95
96