
目录
0.前言
1. 游戏框架
2.game中棋盘的 *** 作
2.1初始化棋盘
2.2 打印棋盘
3.game函数中游戏的实现
3.1 玩家下棋
3.2 电脑下棋
3.3 判断输赢
3.3.1 准备工作
3.3.2 判断输赢函数的实现
3.4 游戏展示
4.游戏代码
0.前言
目的:实现玩家和电脑简单的三子棋游戏
玩家棋子:*
电脑棋子:#
游戏结构:
- test.c(用于测试游戏,主程序的实现)
- game.c(游戏函数的定义实现)
- game.h(游戏函数的声明)
2.game中棋盘的 *** 作
- 用input接收玩家的输入
- 1为开始游戏,0为退出游戏,其余的输入放到default里面
- 当输入为0的时候,while的条件判断也为假,退出循环,也就是退出游戏
- 当玩家选择1玩游戏的时候,case 1中新建game函数,然后开始实现game函数
- 这里希望棋盘的大小随意控制,利用define定义常量,在game.h文件中,所以要引用game.h头文件
写在test.c中的程序:
2.1初始化棋盘game函数中初始化棋盘
game.h中声明初始化棋盘的函数
2.2 打印棋盘
- game.c中对初始化棋盘函数进行实现
- 因为这里用到了ROW、COL定义的标识符常量,所以也需要引用头文件game.h
- 初始化棋盘的作用是将board里面的元素初始化掉,这样不管一开始棋盘里面方的啥,都不受影响
- 同样再geme函数里面打印棋盘,然后.h中声明,.c中定义
- 因为这里.c中打印也需要printf,干脆直接将stdio放到game.h中,让test.c和game.c引用game.h就行
3.game函数中游戏的实现
- 函数的声明省略了图片,下面是打印棋盘函数的实现
- 首先,我们希望的棋盘是这样的,颜色无所谓。
- 因为我们下的棋放在正中间才好看,所以打印的时候是 " %c " 两边有空格,每三个位置过后需要一个 | 分隔两个棋子。因为最后的一列通常是没有 | 分隔的,所以有个if判断。第一行打印完加个换行
- 打印--- 分开上下棋子的时候,因为往往最后一行是没有的。所以,一开始就放到if判断中去,满足条件就打印分隔行(---)。if里面具体的实现和前面一样
- 最后打印的棋盘如图
用个死循环while实现玩家和电脑的下棋 *** 作,当出现胜负的时候在跳出循环
3.1 玩家下棋首先,玩家 *** 作过,要将棋盘打印出来
3.2 电脑下棋
- 用x、y保存玩家输入的位置
- 因为正常用户不知道数组下标从0开始,所以判断的时候是>=1 && <= row
- 如果输入坐标错误,或者输入的位置已经有棋子,就报错。通过while的循环直到玩家正确 *** 作为止,break跳出玩家移动
3.3 判断输赢 3.3.1 准备工作
- 电脑下棋的代码比较简单,因为只需要让电脑下棋的坐标通过随机数产生就行了
- 这里rand%row,就能是生成的随机数刚刚适合整个棋盘
- 使用rand需要srand,而srand需要time时间戳。所以game.h文件中需要包含stdlib和time的头文件
- 而srand只需要设置一次,所以只需要在主函数的test函数中设置一次随机种子就行
3.3.2 判断输赢函数的实现
- 这里用TDD的思想,先要实现什么任务,然后再怎么去实现
- 因为每次走了一步棋子都要判断一下是否输赢,所以每次玩家或者电脑走了打印棋盘后都要判断一下游戏结果
- 这里定义四种结果(* 玩家赢,#电脑赢,Q 平局, C 继续)
- 所以IsWin需要返回值,且需要定义一个char变量接收返回值。如果不是C继续下棋的话,直接跳出循环
- 最后循环结束的话,根据返回值,打印游戏的结果
- 因为鹏哥的视频只是针对3*3的
- 这样的话,棋盘就不能扩展了。那之前为什么打印棋盘之类的要用循环来写呢,之前的 *** 作不是得不偿失嘛
- 所以判断输赢的代码自己尝试实现,因为早都写好了,但是总有好多个bug,比如没有连成线也获胜了....
- 当时完成的代码是这样的
- 因为还没有学习到关于二维数组的讲解,下面的内容可能会出错....
- 比如刚刚出错的,假如i=j=1的话,对应的中间那个位置。但是这样j+2的时候,二维数组就会越界。这样计算机就会把(1,1)(1,2)(2,1)的这三个连在一块,就会出现上面的错误(因为j=2的时候没法再往下加了,强行加就会得到下一行的首元素)
- 当然,上面也只是猜测,毕竟水平有限。不过通过代码我们可以得到论证
- 这样简单的论证,说明前面数组越界还是比较靠谱的
- 所以要把代码修改一下,保证i,j加减后不会超过0到row,col的范围
- 这里比如i+1,i+2只要保证最大值,也就是i+2不要超过row就行了
- 如果有相减的话,保证最小值不要小于0就行
最后将判断IsFull函数写完就ok了
3.4 游戏展示4.游戏代码
- 之前的问题就不会出现了
- Tips:如果之前的猜测是正确的,那么可以按照这种逻辑改成五子棋。而且将电脑移动换成玩家2移动的话,可以实现两人对弈
test.c 主程序部分
#define _CRT_SECURE_NO_WARNINGS 1 #include "game.h" void menu() { printf("************************************\n"); printf("********* 1.play 0.exit *********\n"); printf("************************************\n"); } void game() { char ret = 0; char board[ROW][COL] = { 0 }; InitBoard(board, ROW, COL); // 初始化棋盘 DisplayBoard(board, ROW, COL); // 打印棋盘 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); // 打印棋盘 ret = IsWin(board,ROW,COL); // 判断输赢 if (ret != 'C') { break; } } // 打印游戏结果 if (ret == '*') printf("玩家赢\n"); else if (ret == '#') printf("电脑赢\n"); else printf("平局\n"); } void test() { int input = 0; srand((unsigned int)time(NULL)); do { menu(); printf("请选择:>"); scanf("%d", &input); switch (input) { case 1: printf("三子棋游戏\n"); game(); break; case 0: printf("退出游戏\n"); break; default: printf("选择错误,请重新选择\n"); break; } } while (input); } int main() { test(); return 0; }
game.h 函数声明部分
#define _CRT_SECURE_NO_WARNINGS 1 #include#include #include #define ROW 3 #define COL 3 void InitBoard(char board[ROW][COL],int row,int col); void DisplayBoard(char board[ROW][COL],int row,int col); void PlayerMove(char board[ROW][COL],int row,int col); void ComputerMove(char board[ROW][COL],int row,int col); char IsWin(char board[ROW][COL],int row,int col);
game.c 函数实现部分
#define _CRT_SECURE_NO_WARNINGS 1 #include "game.h" #includevoid InitBoard(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++) { board[i][j] = ' '; } } } void DisplayBoard(char board[ROW][COL], int row, int col) { int i = 0; for (i = 0; i < row; i++) { int j = 0; for (j = 0; j < col; j++) { // 打印一行数据 printf(" %c ", board[i][j]); if(j \n"); while (1) { printf("请输入要下的坐标:>"); scanf("%d%d", &x, &y); // 判断坐标是否正确 if (x >= 1 && x <= row && y >= 1 && y <= col) { if (board[x - 1][y - 1] == ' ') { board[x - 1][y - 1] = '*'; break; } else { printf("该坐标被占用\n"); } } else { printf("坐标不正确,请重新输入\n"); } } } 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() % row; if (board[x][y] == ' ') { board[x][y] = '#'; break; } } } // 1满了 0没有满 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; } char IsWin(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] != ' '&&board[i][j] == board[i][j + 1] && board[i][j] == board[i][j + 2]&&j+2 =0&&j+1 =0)// 判断副对角线(包括平行) return board[i][j]; } } if (1 == IsFull(board, ROW, COL)) { return 'Q'; } return 'C'; }
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)