1 #include <stdio.h>
2 #include <stdlib.h>
3 /*
4 具体思路如下:
5 1.定义一个二维数组chessboard[8][8],用于保存黑白双方棋子的位置。如果数组元素为0,表示该单元格未落子;如果是-1,表示该单元格是黑子;如果是1,则表示该单元格是白子。
6 2.当一方下棋时,先检查是否有位置可下,如果有则己方下棋,如果没有就让对手下棋。
7 3.若玩家下,需要等待玩家输入棋子坐标,然后执行翻转对手棋子操作。
8 4.若计算机下,程序需对棋盘所有可以落子的位置进行判断,找出最佳的落子位置,然后执行翻转对手棋子操作。
9 5.重复步骤2~4,直到棋盘已满或双方都不能下子时结束。
10 */
11
12 void Output(char chessboard[][8]); //显示棋盘中的下子情况
13 int Check(char chessboard[][8],int moves[][8],char player);//检查一方是否有位置下子
14 void PlayStep(char chessboard[][8],int row,int col,char player);//在指定位置下棋
15 void AutoPlayStep(char chessboard[][8],int moves[][8],char player);//计算机思考下子
16 int GetMaxScore(char chessboard[][8],char player);//获取分数
17 int BestPlay(char chessboard[][8],int moves[][8],char player);//最优下子位置
18
19
20 int main(){
21 char chessboard[8][8];//保存棋盘中各单元格下子的状态
22 int isDown[8][8] = {0};//保存棋盘中的各个位置是否可以下子,可以下的位置为1,其余为0
23 int row,col,x,y;
24 int iCount = 0;//以下子的数量
25 int player = 0;//下棋方
26 int SkipPlay = 0;//重置下子的次数为0,若为2,则表示双方都不能下子
27 int Score[2];//保存计算机和玩家的得分
28
29 char select,ch;
30
31 printf("黑白棋
");
32 printf("玩家执黑子先行,计算机执白,按Enter开始
");
33
34
35 scanf("%c",&select);
36
37 do{
38
39 if(player==0){
40 player = 1;
41 }else{
42 player = 0;
43 }
44
45 for(row=0;row<8;row++){
46 for(col=0;col<8;col++){
47 chessboard[row][col]=0;
48 }
49 }
50
51 iCount = 4;//游戏开始的四颗棋子
52 chessboard[3][3] = chessboard[4][4] = 1;
53 chessboard[3][4] = chessboard[4][3] = -1;
54
55 printf("
棋盘初始状态:
");
56 Output(chessboard);
57
58 //双方下棋
59 do{
60 if(player==1){//玩家下棋(黑)
61 player = 0;
62 if(Check(chessboard,isDown,2)){
63 while(1){
64 fflush(stdin);
65 printf("输入下子的位置(行,列):");
66 scanf("%d%c",&x,&ch);
67 x--;//因为数组是从0开始存的
68 if(ch>='a'){
69 y = ch - 'a' + 1;
70 } else{
71 y = ch - 'A' + 1;
72 }
73 y--;
74 //判断是否越界、是否已有棋子
75 if(x>=0&&x<8&&y>=0&&y<8&&isDown[x][y]){
76 PlayStep(chessboard,x,y,2);
77 iCount++;
78 break;
79 }else{
80 printf("坐标输入有误,请重新输入。
");
81 }
82 }
83
84 printf("
你下子之后的状态:
");
85 Output(chessboard);
86 system("pause");
87
88 }else if(++SkipPlay < 2){//无效下子的次数小于2
89 fflush(stdin);
90 printf("你没位置可下,按Enter让计算机下子");
91 scanf("%c",&select);
92 } else{
93 printf("双方都没位置下子,游戏结束!
");
94 }
95 }else{//计算机下棋(白)
96
97 player = 1;
98 if(Check(chessboard,isDown,1)) {
99 SkipPlay = 0;//清除无效下子次数
100 AutoPlayStep(chessboard,isDown,1); //下子
101 iCount++;
102 printf("
计算机下子后的状态:
");
103 Output(chessboard);
104 }else if(++SkipPlay < 2){//无效下子的次数小于2
105 fflush(stdin);
106 printf("我没位置可下,你走
");
107 scanf("%c",&select);
108 } else{
109 printf("双方都没位置下子,游戏结束!
");
110 }
111
112
113
114 }
115
116
117 }while(iCount<64&&SkipPlay<2);
118
119 Output(chessboard);
120 Score[0] = Score[1] = 0;//清空几份变量
121
122 for(row=0;row<8;row++){
123 for(col=0;col<8;col++){
124 if(chessboard[row][col]==-1){
125 Score[0]++;//统计黑子数量
126 }
127 if(chessboard[row][col]==1){
128 Score[1]++;//统计白子数量
129 }
130 }
131 }
132 printf("最终成绩:
");
133 printf("玩家:%d
计算机:%d
",Score[0],Score[1]);
134 fflush(stdin);
135 printf("继续下一局(y/n)?
");
136 scanf("%c",&select);
137
138 }while(select=='y'||select=='Y');
139 printf("游戏结束!");
140 system("pause");
141 return 0;
142
143 }
144
145
146 //显示棋盘中的下子情况
147 void Output(char chessboard[][8]){
148 int row, col;
149 printf("
");
150 for (col = 0; col < 8; col++) //输出列标号
151 printf(" %c", 'A' + col);
152 printf("
");
153 printf(" ┌"); //输出顶部横线
154 for (col = 0; col < 7; col++) //输出一行
155 printf("—┬");
156 printf("—┐
");
157 for (row = 0; row < 8; row++)
158 {
159 printf("%2d|", row + 1); //输出行号
160 for (col = 0; col < 8; col++) //输出棋盘各单元格中棋子的状态
161 {
162 if (chessboard[row][col] == 1) //白棋
163 printf("○|");
164 else if (chessboard[row][col] == -1) //黑棋
165 printf("●|");
166 else //未下子处
167 printf(" |");
168 }
169 printf("
");
170 if (row < 8-1)
171 {
172 printf(" ├"); //输出交叉线
173 for (col = 0; col < 8-1; col++) //输出一行
174 printf("—┼");
175 printf("—┤
");
176 }
177 }
178 printf(" └");
179 for (col = 0; col < 8-1; col++) //最后一行的横线
180 printf("—┴");
181 printf("—┘
");
182 }
183
184 //检查一方是否有位置下子
185 int Check(char chessboard[][8], int isDown[][8], char player)
186 {
187 int rowdelta, coldelta, row, col, x, y = 0;
188 int iStep = 0;//可下的位置数量
189 char opponent = (player == 1) ? -1 : 1; //对方棋子
190 char myplayer = -1 *opponent;//我方棋子
191 for (row = 0; row < 8; row++) //将isDown数组全部清0
192 for (col = 0; col < 8; col++)
193 isDown[row][col] = 0;
194 for (row = 0; row < 8; row++) //循环判断棋盘中的哪些单元格可以下子
195 {
196 for (col = 0; col < 8; col++)
197 {
198 if (chessboard[row][col] != 0) //若棋盘上的对应位置不为空(表示已经有子)
199 continue; //继续处理下一个单元格
200 for (rowdelta = -1; rowdelta <= 1; rowdelta++) //循环检查上下行
201 {
202 for (coldelta = -1; coldelta <= 1; coldelta++) //循环检查左右列
203 {
204 if (row + rowdelta < 0 || row + rowdelta >= 8 || col + coldelta < 0 || col + coldelta >= 8|| (rowdelta == 0 && coldelta == 0))//若坐标超过棋盘或为当前单元格
205 continue; //继续循环
206 if (chessboard[row + rowdelta][col + coldelta] == opponent)//若(row,col)四周有对手下的子
207 {
208 x = row + rowdelta; //以对手的下子位置为坐标
209 y = col + coldelta;
210 while(1)//以对手的下子为起始点,沿着该方向查找自己方的棋子,以攻击对方棋子
211 {
212 x += rowdelta; //对手下子的四周坐标
213 y += coldelta;
214 if (x < 0 || x >= 8 || y < 0 || y >= 8) //超过棋盘
215 break; //退出循环
216 if (chessboard[x][y] == 0) //若对应位置为空
217 break;
218 if (chessboard[x][y] == myplayer) //若对应位置下的子是当前棋手的
219 {
220 //设置移动数组中对应位置为1 (该位置可下子,形成向对手进攻的棋形)
221 isDown[row][col] = 1;
222 iStep++; //加可下子的位置数量
223 break;
224 }
225 }
226 }
227 }
228 }
229 }
230 }
231 return iStep; //返回可下的位置数量(若返回值为0,表示没地方可下)
232 }
233
234
235 //在指定位置下子
236 void PlayStep(char chessboard[][8], int row, int col, char player)
237 {
238 int rowdelta = 0;
239 int coldelta = 0;
240 int x = 0;
241 int y = 0;
242 char opponent = (player == 1) ? -1 : 1; //对方棋子
243 char myplayer = -1 * opponent;//我方棋子
244 chessboard[row][col] = myplayer; //保存所下的棋子
245 for (rowdelta = -1; rowdelta <= 1; rowdelta++)//检查所下子四周的棋子
246 {
247 for (coldelta = -1; coldelta <= 1; coldelta++)
248 {
249 if (row + rowdelta < 0 || row + rowdelta >= 8 || col + coldelta < 0 || col + coldelta >= 8 || (rowdelta == 0 && coldelta == 0))
250 //若坐标超过棋盘界限
251 continue; //继续下一位置
252 //若该位置是对手的棋子
253 if (chessboard[row + rowdelta][col + coldelta] == opponent)
254 {
255 x = row + rowdelta; //以对手的棋子作为坐标
256 y = col + coldelta;
257 while(1) //在对手棋子的四周寻找我方棋子
258 {
259 x += rowdelta;
260 y += coldelta;
261 if (x < 0 || x >= 8 || y < 0 || y >= 8) //若坐标超过棋盘
262 break; //退出循环
263 if (chessboard[x][y] == 0)//若对应位置为空
264 break; //退出循环
265 if (chessboard[x][y] == myplayer) //若对应位置是我方棋子
266 {
267 //循环处理
268 while (chessboard[x -= rowdelta][y -= coldelta] == opponent)
269 chessboard[x][y] = myplayer; //将中间的棋子都变成我方棋子
270 break; //退出循环
271 }
272 }
273 }
274 }
275 }
276 }
277
278 //计算机自动下子
279 void AutoPlayStep(char chessboard[][8], int isDown[][8], char player)
280 {
281 int row, col, row1, col1, i, j;
282 int Score = 0, MinScore = 100;//对方可下子得到的分数和最小分数
283 char chessboard1[8][8]; //临时数组,保存棋盘的下子位置
284 int isDown1[8][8]; //临时数组,保存可下子的位置
285 char opponent = (player == 1) ? -1 : 1; //对手下的棋子
286 for (row = 0; row < 8; row++) //循环检查棋盘的每个单元格
287 {
288 for (col = 0; col < 8; col++)
289 {
290 if (isDown[row][col] == 0) //若不可下子
291 continue; //继续下一个位置
292 for (i = 0; i < 8; i++)//将棋盘原来的棋子复制到临时数组中
293 for (j = 0; j < 8; j++)
294 chessboard1[i][j] = chessboard[i][j];
295 PlayStep(chessboard1, row, col, player);
296 //试着在临时棋盘中的一个位置下子
297 Check(chessboard1, isDown1, opponent); //检查对手是否有地方可下子
298 Score = BestPlay(chessboard1, isDown1, opponent);
299 //获得临时棋盘中对方下子的得分情况
300 if (Score < MinScore) //保存对方得分最低的下法
301 {
302 MinScore = Score;
303 row1 = row;
304 col1 = col;
305 }
306 }
307 }
308 PlayStep(chessboard, row1, col1, player); //计算机按最优下法下子
309 }
310
311 //获取分数
312 int GetMaxScore(char chessboard[][8], char player)
313 {
314 int Score, row, col;
315 char opponent = (player == 1) ? -1 : 1; //对方棋子
316 char myplayer=-1*opponent;
317 for (row = 0; row < 8; row++) //循环
318 {
319 for (col = 0; col < 8; col++)
320 {
321 //如果棋盘对应位置是对手下的棋子,从总分中减1分
322 Score -= chessboard[row][col] == opponent;
323 //如果棋盘对应位置是我方的棋子,在总分中加1分
324 Score += chessboard[row][col] == myplayer;
325 }
326 }
327 return Score; //返回分数
328 }
329
330 //最优下子位置
331 int BestPlay(char chessboard[][8], int isDown[][8], char player)
332 {
333 int row, col, i, j;
334 char chessboard1[8][8] = { 0 }; //定义一个临时数组
335 int MaxScore = 0; //保存最高分
336 int Score = 0;
337 char opponent = (player == 1) ? -1 : 1;//对手下的棋子
338 for (row = 0; row < 8; row++) //循环检查每个单元格
339 {
340 for (col = 0; col < 8; col++)
341 {
342 if (!isDown[row][col]) //如果该位置不可下子
343 continue; //继续检查
344 for (i = 0; i < 8; i++) //复制棋盘各单元格下子的状态到临时数组
345 for (j = 0; j < 8; j++)
346 chessboard1[i][j] = chessboard[i][j];
347 PlayStep(chessboard1, row, col, player); //在临时数组中的指定行列下子
348 Score = GetMaxScore(chessboard1, player); //获取下子后可得到的分数
349 if (MaxScore < Score) //若原方案得到的分数小于本次下子的分数
350 MaxScore = Score; //保存最高分
351 }
352 }
353 return MaxScore; //返回得到的最高分
354 }