井字棋(人機對戰版)


游戲介紹

井字棋,英文名叫Tic-Tac-Toe,是一種在3*3格子上進行的連珠游戲,和五子棋類似。然后由分別代表O和X的兩個游戲者輪流在格子里留下標記(一般來說先手者為X),任意三個標記形成一條直線(包括行、列、對角線、反對角線),則為獲勝。

解決策略

重點在於電腦方如何下棋,我們采取估計棋局每個位置的權重,首先要對棋局進行分類。

---3個為空,重要性最低,權值設置為1    //視為暫時不管

---2個空1個對方,重要性次低,權值為10    //一下三個區別不大,可比較隨意的設置

----1個空格1個對方1個己方,重要行較低,權值50 

----2個空格1個己方,重要性較高,權值為100

---1個空格2個對方,重要性次高,權值500  //不堵住會輸

---1個空格2個己方,重要性最高,權值1000    //可以直接贏

注意幾點:

1、權值之間的間距可以設大一點

2、對每個空位置,權值等於行權值+列權值+對角線權值+反對角線權值,這4中權值都可以用上面的估算,但不做改進會出bug

考慮如下情況:

(1,3)-->(3,1)-->(1,1)-->(2,1)電腦就輸了

---->--->-->-->人獲勝

關鍵在於第二步,應該選擇一個非角的位置,原因在於此時右上角位置的權值大於中上位置,分析權值的來源

右上角時,10+10+100(對角線己方),而中上時,10+100(行己方),所以同樣是2空1己方時,己方位於行或列的權重應大於己方位於對角線

所以按行或列計算時,2空1己方的權值可改為200

代碼實現

  1 #include<stdio.h>
  2 #include<Windows.h>
  3 
  4 const int ROW = 3;
  5 const int COL = 3;
  6 int chessboard[ROW][COL];
  7 int score[ROW][COL];
  8 
  9 void Initmap();
 10 void Showmap();        //打印棋局
 11 bool isWin();        //判斷是否有一方獲勝
 12 bool isFull();        //判斷棋盤是否為滿
 13 void PcPlay();        //電腦下棋
 14 void HumanPlay();    //人下棋
 15 
 16 int main()
 17 {
 18     Initmap();
 19     Showmap();
 20     while ((!isFull()) && (!isWin()))
 21     {
 22         HumanPlay();
 23         system("cls");
 24         Showmap();
 25         if (isWin())
 26             break;
 27 
 28         Sleep(500);    //模擬實際過程,讓電腦慢點,hh
 29         PcPlay();
 30         system("cls");
 31         Showmap();
 32     }
 33 
 34     if (isFull())
 35         printf("\n\n平局\n");
 36 
 37     system("pause");
 38     return 0;
 39 }
 40 
 41 void Initmap()
 42 {
 43     for (int i = 0; i < ROW; i++)
 44         for (int j = 0; j < COL; j++)
 45             chessboard[i][j] = 1;
 46 }
 47 
 48 void Showmap()
 49 {
 50     for (int i = 0; i < ROW; i++)
 51     {
 52         for (int j = 0; j < COL; j++)
 53         {
 54             if (chessboard[i][j] == 1)    //"1"代表空
 55                 printf("");
 56             if (chessboard[i][j] == 2)    //"2"代表人
 57                 printf("");
 58             if (chessboard[i][j] == 5)    //"5"代表電腦
 59                 printf("");
 60         }
 61         printf("\n");
 62     }
 63 }
 64 
 65 bool isWin()
 66 {
 67     int sum = 0;
 68     for (int i = 0; i < ROW; i++)      //對每行判斷是否獲勝
 69     {
 70         for (int j = 0; j < COL; j++)
 71             sum += chessboard[i][j];
 72 
 73         if (sum == 6)
 74         {
 75             printf("人獲勝!\n");
 76             return true;
 77         }
 78         if (sum == 15)
 79         {
 80             printf("電腦獲勝!\n");
 81             return true;
 82         }
 83         sum = 0;
 84     }
 85 
 86     for (int j = 0; j < ROW; j++)      //對每列判斷是否獲勝
 87     {
 88         for (int i = 0; i < COL; i++)
 89             sum += chessboard[i][j];
 90 
 91         if (sum == 6)
 92         {
 93             printf("人獲勝!\n");
 94             return true;
 95         }
 96         if (sum == 15)
 97         {
 98             printf("電腦獲勝!\n");
 99             return true;
100         }
101         sum = 0;
102     }
103 
104     for (int i = 0; i < ROW; i++)     //對對角線判斷是否獲勝
105         sum += chessboard[i][i];
106     if (sum == 6)
107     {
108         printf("人獲勝!\n");
109         return true;
110     }
111     if (sum == 15)
112     {
113         printf("電腦獲勝!\n");
114         return true;
115     }
116 
117     sum = 0;
118     for (int i = 0; i < ROW; i++)     //對反對角線判斷是否獲勝
119         sum += chessboard[i][2 - i];
120     if (sum == 6)
121     {
122         printf("人獲勝!\n");
123         return true;
124     }
125     if (sum == 15)
126     {
127         printf("電腦獲勝!\n");
128         return true;
129     }
130 
131     return false;
132 }
133 
134 bool isFull()
135 {
136     for (int i = 0; i < ROW; i++)
137         for (int j = 0; j < COL; j++)
138             if (chessboard[i][j] == 1)
139                 return false;
140     return true;
141 }
142 
143 void HumanPlay()
144 {
145     int x, y;
146     printf("請輸入棋子的橫坐標X:");
147     scanf_s("%d", &x);
148     printf("請輸入棋子的縱坐標Y:");
149     scanf_s("%d", &y);
150 
151     while (x < 1 || x>3 || y < 1 || y>3)
152     {
153         printf("\n請正確輸入!\n");
154         printf("x,y均屬於1~3\n\n");
155 
156         printf("請輸入棋子的橫坐標X:");
157         scanf_s("%d", &x);
158         printf("請輸入棋子的縱坐標Y:");
159         scanf_s("%d", &y);
160     }
161 
162     while (chessboard[3 - y][x - 1] != 1)
163     {
164         printf("\n\n該位置已被占用!\n");
165         printf("請選擇正確的位置\n\n");
166         Sleep(1000);
167 
168         printf("\n請輸入棋子的橫坐標X:");
169         scanf_s("%d", &x);
170         printf("請輸入棋子的縱坐標Y:");
171         scanf_s("%d", &y);
172     }
173 
174     chessboard[3 - y][x - 1] = 2;
175 }
176 
177 void PcPlay()
178 {
179     int sum = 0;
180     for (int i = 0; i < ROW; i++)
181         for (int j = 0; j < COL; j++)
182             score[i][j] = 0;
183 
184     // 對每行進行分數統計
185     for (int i = 0; i < ROW; i++)
186     {
187         for (int j = 0; j < COL; j++)
188             sum += chessboard[i][j];
189 
190         switch (sum)
191         {
192         case 3:                     //1+1+1;重要性:最低;權重:1
193             for (int k = 0; k < COL; k++)
194             {
195                 if (chessboard[i][k] == 1)
196                     score[i][k] += 1;
197             }
198             break;
199         case 4:                     //1+1+2;重要性:次低;權重:10
200             for (int k = 0; k < COL; k++)
201             {
202                 if (chessboard[i][k] == 1)
203                     score[i][k] += 10;
204             }
205             break;
206         case 8:                    //1+2+5;重要性:較低,權值50
207             for (int k = 0; k < COL; k++)
208             {
209                 if (chessboard[i][k] == 1)
210                     score[i][k] += 50;
211             }
212             break;
213         case 7:                     //1+1+5;重要性:較高;權重:200
214             for (int k = 0; k < COL; k++)
215             {
216                 if (chessboard[i][k] == 1)
217                     score[i][k] += 200;     //把行列的重要性比對角線高
218             }
219             break;
220         case 5:                     //1+2+2;重要性:次高;權重:500
221             for (int k = 0; k < COL; k++)
222             {
223                 if (chessboard[i][k] == 1)
224                     score[i][k] += 500;
225             }
226             break;
227         case 11:                     //1+5+5;重要性:最高;權重:1000
228             for (int k = 0; k < COL; k++)
229             {
230                 if (chessboard[i][k] == 1)
231                     score[i][k] += 1000;
232             }
233             break;
234         }
235         sum = 0;
236     }
237 
238     // 對每列進行分數統計
239     for (int j = 0; j < COL; j++)
240     {
241         for (int i = 0; i < ROW; i++)
242             sum += chessboard[i][j];
243 
244         switch (sum)
245         {
246         case 3:                   
247             for (int k = 0; k < COL; k++)
248             {
249                 if (chessboard[k][j] == 1)
250                     score[k][j] += 1;
251             }
252             break;
253         case 4:                    
254             for (int k = 0; k < COL; k++)
255             {
256                 if (chessboard[k][j] == 1)
257                     score[k][j] += 10;
258             }
259             break;
260         case 8:                    
261             for (int k = 0; k <
262                 COL; k++)
263             {
264                 if (chessboard[k][j] == 1)
265                     score[k][j] += 50;
266             }
267             break;
268         case 7:                    
269             for (int k = 0; k < COL; k++)
270             {
271                 if (chessboard[k][j] == 1)     //1+1+5;重要性:較高;權重:200
272                     score[k][j] += 200;  
273             }
274             break;
275         case 5:                    
276             for (int k = 0; k < COL; k++)
277             {
278                 if (chessboard[k][j] == 1)
279                     score[k][j] += 500;
280             }
281             break;
282         case 11:                  
283             for (int k = 0; k < COL; k++)
284             {
285                 if (chessboard[k][j] == 1)
286                     score[k][j] += 1000;
287             }
288             break;
289         }
290         sum = 0;
291     }
292 
293     // 對對角線進行分數統計
294     for (int i = 0; i < ROW; i++)
295         sum += chessboard[i][i];
296     switch (sum)
297     {
298     case 3:                    
299         for (int i = 0; i < COL; i++)
300         {
301             if (chessboard[i][i] == 1)
302                 score[i][i] += 1;
303         }
304         break;
305     case 4:                   
306         for (int i = 0; i < COL; i++)
307         {
308             if (chessboard[i][i] == 1)
309                 score[i][i] += 10;
310         }
311         break;
312     case 8:                
313         for (int i = 0; i < COL; i++)
314         {
315             if (chessboard[i][i] == 1)
316                 score[i][i] += 50;
317         }
318         break;
319     case 7:                     //1+1+5;權重:100
320         for (int i = 0; i < COL; i++)
321         {
322             if (chessboard[i][i] == 1)
323                 score[i][i] += 100;
324         }
325         break;
326     case 5:                
327         for (int i = 0; i < COL; i++)
328         {
329             if (chessboard[i][i] == 1)
330                 score[i][i] += 500;
331         }
332         break;
333     case 11:                    
334         for (int i = 0; i < COL; i++)
335         {
336             if (chessboard[i][i] == 1)
337                 score[i][i] += 1000;
338         }
339         break;
340     }
341 
342     // 對反對角線進行分數統計
343     sum = 0;
344     for (int i = 0; i < ROW; i++)
345         sum += chessboard[i][2 - i];
346     switch (sum)
347     {
348     case 3:                    
349         for (int i = 0; i < COL; i++)
350         {
351             if (chessboard[i][2 - i] == 1)
352                 score[i][2 - i] += 1;
353         }
354         break;
355     case 4:                    
356         for (int i = 0; i < COL; i++)
357         {
358             if (chessboard[i][2 - i] == 1)
359                 score[i][2 - i] += 10;
360         }
361         break;
362     case 8:
363         for (int i = 0; i < COL; i++)
364         {
365             if (chessboard[i][2 - i] == 1)
366                 score[i][2 - i] += 50;
367         }
368         break;
369     case 7:                     
370         for (int i = 0; i < COL; i++)
371         {
372             if (chessboard[i][2 - i] == 1)    //1+1+5;權重:100
373                 score[i][2 - i] += 100;
374         }
375         break;
376     case 5:                   
377         for (int i = 0; i < COL; i++)
378         {
379             if (chessboard[i][2 - i] == 1)
380                 score[i][2 - i] += 500;
381         }
382         break;
383     case 11:                    
384         for (int i = 0; i < COL; i++)
385         {
386             if (chessboard[i][2 - i] == 1)
387                 score[i][2 - i] += 1000;
388         }
389         break;
390     }
391 
392     int maxRow = 0, maxCol = 0;
393     for (int i = 0; i < ROW; i++)
394         for (int j = 0; j < COL; j++)
395         {
396             if (score[i][j] > score[maxRow][maxCol])
397             {
398                 maxRow = i;
399                 maxCol = j;
400             }
401         }
402     chessboard[maxRow][maxCol] = 5;
403 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM