4.4 电脑下棋
定义ComputerMove()函数,代码实现:
void ComputerMove(char board[ROW][COL], int row, int col) { int x = 0; int y = 0; printf("电脑下棋:>\n"); while (1) { x = rand() % row; y = rand() % col; if (board[x][y] == ' ') { board[x][y] = '#'; break; } } }
这里也是存在一些问题,解决办法如下:
1.如何实现电脑随机输入一个坐标?
答:我们利用srand()函数来实现随机数字,但是srand()函数需要一个随机值,这里的随机值就是利用时间戳,因为时间在时刻改变着,不同的时间经过srand处理过后就得到了我们需要的随机值。因为要用时间戳,所以需要调用time函数,代码实现:
#include <time.h>
srand()函数的使用:
srand((unsigned int)time(NULL));
2.如何处理电脑随机坐标的合法性?
答:在使用srand()函数处理的随机值不再经过处理可能会出现大于棋盘的格数,所以我们需要再对srand()函数处理的随机值再进行处理,代码实现:
x = rand() % row;//0~2 y = rand() % col;//0~2
对srand传过来的随机值进行取模处理,我们的棋盘是3*3的,所以取模后得到的随机值是在0~2范围里。
3.如果出现坐标被占用的情况怎么处理?
答:我们使用while循环,如果给出的坐标位置判断不是空格,就说明是被占用,经过循环最后给出合法的坐标,实现落子后就会触发break跳出循环。
4.5 判断输赢
定义IsWin()函数,代码实现:
char IsWin(char board[ROW][COL], int row, int col) { int i = 0; //三行连成 for (i = 0; i < row; i++) { if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ') return board[i][0];//如果连成,返回这个符号就是代表哪一玩家胜利 } //三列连成 for (i = 0; i < col; i++) { if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ') return board[0][i];//如果连成,返回这个符号就是代表哪一玩家胜利 } //两对角线连成 if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' ') return board[0][0];//如果连成,返回这个符号就是代表哪一玩家胜利 if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][2] != ' ') return board[0][0];//如果连成,返回这个符号就是代表哪一玩家胜利 //判断是否平局 if (1 == IsFull(board, row, col)) { return 'Q'; } return 'C'; }
判断输赢的代码逻辑是根据游戏规则来写,行、列、对角线三子连成就认定哪一方胜出,若棋盘下满都没出现三子连成认定为平局。分别用这些符号表示:
4.5.1 三行连成
代码实现:
for (i = 0; i < row; i++) { if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ') return board[i][0]; }
4.5.2 三列连成
代码实现:
for (i = 0; i < col; i++) { if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ') return board[0][i]; }
4.5.3 两对角线连成
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' ') return board[0][0]; if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][2] != ' ') return board[0][0];
4.5.4 平局判断
如果棋盘被下满还是没有分出胜负便是平局。
如何判断是否棋盘被下满呢?
答:我们遍历棋盘的每一个格子,如果没有一个是空格了,就返回数字 1 ,否则返回数字 0 。
定义IsFull()函数,代码实现:
int IsFull(char board[ROW][COL], int row, int col) { int i = 0; int j = 0; for (i = 0; i < row; i++) { for (j = 0; j < col; j++) { if (board[i][j] == ' ') return 0; } } return 1; }
IsFull()函数仅仅实现棋盘格是否被占满。在IsWin()函数中判断返回值是否是 1 ,如果是就是平局,我们这里只对棋盘格被占满判断,只需要判断返回值 1 ,如果是0便是没有占满,不用考虑,继续下棋就行。
代码实现:
if (1 == IsFull(board, row, col)) { return 'Q'; }
判断 1 == IsFull(),就返回字符'Q'。(规定 Q 是平局)
5、game()函数详解
void game() { srand((unsigned int)time(NULL)); //存放数据需要一个3*3的二维数组 char board[ROW][COL] = { 0 }; //初始化棋盘 InitBoard(board, ROW, COL); //显示棋盘 DisplayBoard(board, ROW, COL); char ret = 0; while (1) { //玩家下棋 - * PlayerMove(board, ROW, COL); //打印棋盘 DisplayBoard(board, ROW, COL); //判断输赢 ret = IsWin(board, ROW, COL); if (ret != 'C') { break; } //电脑下棋 - # ComputerMove(board, ROW, COL); //打印棋盘 DisplayBoard(board, ROW, COL); //判断输赢 if (ret != 'C') { break; } } if ('*' == ret) printf("玩家赢\n"); else if ('#' == ret) printf("电脑赢\n"); else printf("平局\n"); }
逻辑顺序:创建一个数组 -- 初始化棋盘 -- 打印棋盘 -- 玩家下棋 -- 打印棋盘 -- 判断输赢(赢/输/平局:本局结束;没结果:继续) -- 电脑下棋 -- 打印棋盘 -- 判断输赢 (赢/输/平局:本局结束;没结果:继续)
逻辑顺序图示:
6、整体效果展示
完整代码在代码仓库,入口在这: