# 國立屏東大學電腦五子棋 AI 程式競賽 - 進階篇 ## Table of Contents - [進階](#進階) - [權重分析](#權重分析) - [概念](#概念) - [進攻或是防守](#進攻或是防守) - [分析步驟(以活四為例)](#分析步驟以活四為例) - [虛擬碼](#虛擬碼) ## 進階 在此章節,我們會提供您一些想法,幫助您提升程式的棋力,以便在競賽中取勝。 ### 權重分析 #### 概念 請參考以下範例,若您是黑子(1)且輪到您的回合,依照目前的局面,您應該將棋子落在(F, 10)或是(K, 10)以獲得勝利,因此這兩個點具有最高的「權重」。透過分析棋盤上每一個點的權重,可以幫助您的程式找出最佳的落子位置。 ```text A B C D E F G H I J K L M N O P Q R S 1 . . . . . . . . . . . . . . . . . . . 2 . . . . . . . . . . . . . . . . . . . 3 . . . . . . . . . . . . . . . . . . . 4 . . . . . . . . . . . . . . . . . . . 5 . . . . . . . . . . . . . . . . . . . 6 . . . . . . . . . . . . . . . . . . . 7 . . . . . . . . . . . . . . . . . . . 8 . . . . . . . . . . . . . . . . . . . 9 . . . . 0 0 0 0 0 . . . . . . . . . . 10 . . . . . . 1 1 1 1 . . . . . . . . . 11 . . . . . . . . . . . . . . . . . . . 12 . . . . . . . . . . . . . . . . . . . 13 . . . . . . . . . . . . . . . . . . . 14 . . . . . . . . . . . . . . . . . . . 15 . . . . . . . . . . . . . . . . . . . 16 . . . . . . . . . . . . . . . . . . . 17 . . . . . . . . . . . . . . . . . . . 18 . . . . . . . . . . . . . . . . . . . 19 . . . . . . . . . . . . . . . . . . . ``` 為了方便講解權重的概念,接下來的棋盤範例會以 x 代表黑子、 o 代表白子。 #### 進攻或是防守 請看以下範例,假設我方為黑子,由於在此黑子周圍的八個點可以提供更多的連線機會,因此我們會將此黑子周圍的八點標註為「權重 1 」,而其餘地方因為無法提供更高的連線機會,因此權重為 0。 ```text . . . . . . . . . . . . . . . . 1 1 1 . . . . 1 x 1 . . . . 1 1 1 . . . . . . . . . . . . . . . . ``` 在下列範例中,我方依然是黑子,但我們可以發現,若我們將棋子落在「權重 2 」的位置時,雖然可以使我方達成活三,但同時也會提供對手產生活四的機會,因此在白子活三的兩端我們會將權重調高至「權重 3 」,以便讓程式在這樣的局面採取防守而不是進攻的策略。 ```text . . . . . . . . 3 o o o 3 . . 1 1 1 1 . . . 2 x x 2 . . . 1 1 1 1 . . . . . . . . . . . . . . . . ``` 接下來我們考慮幾個比較複雜的局面,在以下範例中,白子看似呈現兩組活二,但實際上卻已經構成「洞四」,因此在(H, 7)位置的權重勢必為最高權重,若黑子沒有將棋子落在該位置,白子就會獲得勝利。 ```text A B C D E F G H I J K L M N O P Q R S 1 . . . . . . . . . . . . . . . . . . . 2 . . . . . . . . . . . . . . . . . . . 3 . . . . . . . . . . . . . . . . . . . 4 . . . . . . . . . . . . . . . . . . . 5 . . . . . o . . . . . . . . . . . . . 6 . . . . . . o . . . . . . . . . . . . 7 . . . . . . . . . . . . . . . . . . . 8 . . . . . . . . o . . . . . . . . . . 9 . . . . . . . . . o . . . . . . . . . 10 . . . . . . . x x x . . . . . . . . . 11 . . . . . . . . . . . . . . . . . . . 12 . . . . . . . . . . . . . . . . . . . 13 . . . . . . . . . . . . . . . . . . . 14 . . . . . . . . . . . . . . . . . . . 15 . . . . . . . . . . . . . . . . . . . 16 . . . . . . . . . . . . . . . . . . . 17 . . . . . . . . . . . . . . . . . . . 18 . . . . . . . . . . . . . . . . . . . 19 . . . . . . . . . . . . . . . . . . . ``` #### 分析步驟(以活四為例) 1. 讀入棋盤每一個位置,並且呼叫判斷活四各個角度的函式。 2. 在函式中判斷是否為活四,並且回傳符合活四條件的棋子顏色。 3. 呼叫紀錄活四位置的函式。 4. 在紀錄活四位置函式中,判斷回傳顏色與角度,並且呼叫權重比較函式。 5. 在權重比較函式中,比較權重陣列每個位置的權重,若新的權重大於該位置原本的權重,則進行替換。 6. 可透過分析黑子與白子的權重陣列進行落子判斷。 #### 虛擬碼 接下來將透過虛擬碼簡單講解如何使用權重分析的概念。 FiveInARow.c ```c // An array to record the weight of black chess at each posistion on the chessboard int BBR[19][19]; // To compare the weight of black chess at each position on the cheesboard void blackcompare(int i, int j, int br) { int k, l; if (BBR[i][j] < br) BBR[i][j] = br; else if(BBR[i][j]==br) BBR[i][j] += 1; // for (k = 0; k < 19; k++){ // for (l = 0; l < 19; l++) // { // printf("At %d %d BR is %d \n", k, l, BBR[k][l]); // } // } } Player live4Horizontal(char (*p)[6]) { int i, j=0, b=0, w=0; for(i=0;i<6;i++){ if((i==0 || i==5) && ((*p)[i]==46)) j++; if((*p)[i]==Black) b++; else if((*p)[i]==White) w++; } if((b==4) && (j==2)) return Black; else if((w==4) && (j==2)) return White; else return None; } void locationLivw4(Player live4, int i, int j, int d){ if(live4==Black){ switch(d) { case 0: blackcompare(i, j, 4); blackcompare(i, j+5, 4); break; case 45: blackcompare(i, j, 4); blackcompare(i+5, j+5, 4); break; case 90: blackcompare(i, j, 4); blackcompare(i+5, j, 4); break; case 135: blackcompare(i, j, 4); blackcompare(i-5, j+5, 4); break; } } else if(live4==White){ // The same code } } Player check4Winner(char chessboard[19][19]){ Player live4; for(i=0; i<19; i++>){ for(j=0; j<19; j++){ // Live 4 in a hroizontal line (0 degrees) if(j<=13){ live4 = live4Horizontal((char (*)[6])&cheesboard[i][j]); locationLive4(live4, i, j, 0); } // Live 4 in a vertical line (90 degrees) if(i<=13){ live4=live4Vertical((char (*)[19])&chessboard[i][j]); locationLive4(live4, i, j, 90); } // Live 4 in a diagonal line (45 degrees) if((i<=13)&&(j<=13)){ live4=live4Diagonal((char (*)[19])&chessboard[i][j]); locationLive4(live4, i, j, 45); } // Live 4 in a back diagonal line (135 degrees) if((i<=13)&&(j>=5)){ live4=live4BackDiagonal((char (*)[19])&chessboard[i+5][j-5]); locationLive4(live4, i+5, j-5, 135); } } } } ```