ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

C语言三子棋小游戏:从零到一的手写实现

C语言三子棋小游戏:从零到一的手写实现 1. 引言大家好今天我要分享一个三子棋的小游戏及其思路。这是我学习十几天 C 语言写的第一个小游戏后续还会更新扫雷游戏。这篇文章会从整体框架到具体实现一步步拆解希望能给同样在学 C 语言的朋友一些启发。2. 游戏基本框架写任何一个小游戏第一步都是先搭好整体框架。三子棋的整体流程可以分成三步打印菜单让玩家选择是否进入游戏玩家选择进入游戏后调用game()函数开始一局游戏游戏结束后回到菜单让玩家决定是否再来一局。下面先看主函数main()的写法#define_CRT_SECURE_NO_WARNINGS1#includestdio.h#includegame.h//这个是我的头文件voidmenu(){printf(^^^^^^^^^^^^^^^^^^\n);printf(^^^^1.开始游戏^^^^\n);printf(^^^^^^^^^^^^^^^^^^\n);printf(^^^^0.退出游戏^^^^\n);printf(^^^^^^^^^^^^^^^^^^\n);}voidtext(){intinput0;do{menu();//打印菜单printf(请选择);scanf(%d,input);switch(input)//用switch选择语句来执行{case1:game();//**游戏执行过程**break;case0:printf(退出游戏);break;default:printf(提示请选择0或1\n);break;}printf(\n);printf(\n);}while(input);}intmain(){text();return0;}这里用do...while循环很合适因为菜单至少要打印一次玩家玩完一局后还能回到菜单继续选择体验比较流畅。注意while(input)的使用input0为假循环不再执行退出游戏3. 游戏核心流程game()函数是三子棋的主战场一局游戏大致要经历这几个步骤初始化棋盘打印棋盘玩家落子判断胜负电脑落子判断胜负重复,直到分出胜负或棋盘下满。以下是game()这个函数的内容voidgame(){charret0;srand((unsignedint)time(NULL));//调用rand()函数chararr[ROW][COL]{0};init_board(arr,ROW,COL);//初始化棋盘printf_board(arr,ROW,COL);//打印棋盘while(1){player_board(arr,ROW,COL);printf_board(arr,ROW,COL);retis_win(arr,ROW,COL);if(ret!c){break;}computer_board(arr,ROW,COL);printf_board(arr,ROW,COL);if(ret!c){break;}}if(ret)printf(玩家赢了\n);if(ret$)printf(电脑赢了\n);if(retp)printf(平局\n);}这里用字符c表示游戏继续表示玩家赢$表示电脑赢p表示平局逻辑清晰又直观。4. 接下来是game()函数内部的详细解析1.我们要想实现下棋的操作首先的有棋盘但棋盘是什么样呢这里我可以给大家看一下我的棋盘棋盘是网格线样的玩家下棋的时候如’这个字符得放进去放在哪里呢没错我们很容易就能想到数组这里我定义了char arr[ROW][COL] {0};这样的二维数组为了让之后我们容易修改我们的棋盘大小可以创建一个头文件game.h在头文件里把行和列用宏定义出来#defineROW3#defineCOL3接下来必须初始化初始时全部置为空格这样棋盘生成的时候才会出现像网格状的样子。我们可以再定义一个init_board(arr,ROW,COL)这样一个函数把它放在另一个源文件中game.c2.初始化棋盘#define_CRT_SECURE_NO_WARNINGS1#includegame.h#includestdio.hvoidinit_board(chararr[ROW][COL],introw,intcol){inti0;for(i0;irow;i){intj0;for(j0;jcol;j){arr[i][j] ;}}}注意这个函数必须要在头文件中声明才能够在game.c下执行声明void init_board(char arr[ROW][COL], int row, int col);3.打印棋盘voidprintf_board(chararr[ROW][COL],introw,intcol){inti0;for(i0;irow;i){intj0;for(j0;jcol;j){printf( %c ,arr[i][j]);if(jcol-1)//最右边的列不用打印printf(|);}printf(\n);if(irow-1)//最下边的行不用打印{for(j0;jcol;j){printf(---);if(jcol-1)最右边的列不用打印printf(|);}printf(\n);}}}同样需要在头文件中声明void printf_board(char arr[ROW][COL], int row, int col);4.玩家下棋voidplayer_board(chararr[ROW][COL],introw,intcol){printf(玩家下棋\n);while(1){printf(请输入坐标);//玩家并不知道数组下标是从0开始的intx0;inty0;scanf(%d %d,x,y);if((x1xrow)(y1ycol))//所以这里的if判断x或者y1才会执行内部{if(arr[x-1][y-1] )//这里是让电脑查看是否有一个坐标里有空格有的话就把放进去{arr[x-1][y-1];break;}elseprintf((该坐标被占用,请重新输入)\n);}else{printf((输入的坐标非法)\n);}}}5.玩家下过之后把棋盘打印出来printf_board(arr,ROW,COL);6.之后是电脑下棋voidcomputer_board(chararr[ROW][COL],introw,intcol){while(1){printf(电脑下棋\n);intx0;inty0;xrand()%row;yrand()%col;if(arr[x][y] ){arr[x][y]$;break;}}}这里需要注意的是rand()函数这个函数的功能是随机生成一个数字但它是有范围的。rand()生成的范围是0 ~ 32767。那怎么让电脑落子落在棋盘范围内呢这里就用到了取模运算%。因为棋盘是 3×3 的所以用rand() % row和rand() % col就能把随机数限制在0 ~ 2之间正好对应数组的下标范围。比如rand()生成了1234512345 % 3的结果是0就落在第 0 行。这样电脑就能在棋盘内随机落子了。另外要注意rand()生成的是伪随机数如果不设置随机种子每次运行程序生成的序列都是一样的。所以在game()函数开头调用srand((unsigned int)time(NULL))scand只需要调用一次所以放在game 里而不是放computer_board里在用当前时间作为种子这样每次运行游戏时随机序列才会不同电脑的落子才真正随机起来。而且使用rand函数必须加上#includestdlib.h #includetime.h才能使用7.电脑下过后把棋盘打印出来printf_board(arr,ROW,COL);5.判断输赢我们可以想想如果我们走一步电脑走一步完全有可能会赢得游戏所以我们得判断这里我定义了一个函数is_win(arr, ROW, COL);前面说过用字符c表示游戏继续表示玩家赢$表示电脑赢p表示平局所以这个函数时返回的是字符用char类型返回值用ret接收charis_win(chararr[ROW][COL],introw,intcol){inti0;for(i0;irow;i){if(arr[i][0]arr[i][1]arr[i][1]arr[i][2]arr[i][1]! )//判断一行是否相等returnarr[i][1];}for(i0;icol;i){if(arr[0][i]arr[1][i]arr[1][i]arr[2][i]arr[1][i]! )//判断一列是否相等returnarr[1][i];}if(arr[0][0]arr[1][1]arr[1][1]arr[2][2]arr[1][1]! )//判断左对角线是否相等returnarr[1][1];if(arr[0][2]arr[1][1]arr[1][1]arr[2][0]arr[1][1]! )//判断右对角线是否相等returnarr[1][1];if(is_full(arr,row,col)1)//判断是否平局{returnp;}returnc;//如果都不是则返回c,游戏继续}这里总结一下获胜的条件1一行或一列全部为同一个字符玩家赢了是“。电脑赢了是”$$$不能三个字符都为空格2左右对角线为同一个字符而且不能同为空格平局的条件无疑就是棋盘满了还没有分出胜负定义is_full(arr, row, col)函数来判断staticintis_full(chararr[ROW][COL],introw,intcol)//static使得is_full函数只能在game.c下使用{intx0;inty0;for(x0;xrow;x){for(y0;ycol;y){if(arr[x][y] )return0;}}return1;//满了返回1}6. 总结三子棋虽然简单但麻雀虽小五脏俱全它涵盖了 C 语言入门阶段非常重要的几个知识点二维数组的初始化和遍历函数的定义、声明和调用模块化编程思想随机数的使用循环和分支的综合运用。写这个小游戏让我对函数和数组的理解深了不少。下一篇我会分享扫雷游戏它比三子棋多了一些递归展开的逻辑更有挑战性欢迎大家持续关注我会继续努力的7.附加头文件game.h截图
返回列表