闽清县城乡建设局网站,台州网站建设平台,制作网站需要的软件,计算机专业网页制作C语言程序设计笔记---019 初阶三子棋小游戏(开源)1、arr_main.c程序大纲2、arr_game1.h3、arr_game1.c3.1、 自定义初识化函数 InitBoard( ) 和 自定义显示函数 DisPlayBoard( )3.2、 自定义玩家下棋函数 PlayerMove( )3.4、 自定义电脑下棋函数 ComputerMove( )3.5、 输赢判断… C语言程序设计笔记---019 初阶三子棋小游戏(开源)1、arr_main.c程序大纲2、arr_game1.h3、arr_game1.c3.1、 自定义初识化函数 InitBoard( ) 和 自定义显示函数 DisPlayBoard( )3.2、 自定义玩家下棋函数 PlayerMove( )3.4、 自定义电脑下棋函数 ComputerMove( )3.5、 输赢判断函数 IsWin( ) 4、结束语 初阶三子棋小游戏(开源)
前言 游戏规则 (1)、在打印的数组棋盘里输入坐标下棋。 (2)、坐标格式x空格 y (3)、x横坐标y竖坐标 (4)、连成三个棋子为一线则判定胜利 如图所示
采用模块化编写 arr_game1.c执行主要逻辑程序 arr_game1.h存放头文件或函数声明等程序 arr_main.c放主函数逻辑程序
1、arr_main.c程序大纲
首先从以往玩游戏的经验来谈我们需要为游戏写一个游戏开始菜单由玩家选择是否开始游戏。 这里可以借助所学的menu( )自定义函数设计一个简易的菜单。
void menu()
{printf(****************************************\n);printf(************** 1.play game *************\n);printf(************** 0.game over *************\n);printf(****************************************\n);
}当我们选择1则开始游戏当选择0则退出游戏。 那么就得思考如何对玩家得选择进行判定 1.利用 scanf( ) 函数获取输入值将获取的值借用 do while 循环语句和switch( )选择语句进行下一步。 2.当选择1开始游戏则执行game()自定义游戏主逻辑执行程序 3.当选择0switch中 进入case 0 : 的入口执行退出游戏并且 do while( )判定为0则退出程序 4.当玩家误选择非法数值则default : 提示玩家输入错误
int input 0;do{menu();printf(请选择:);scanf(%d, input);switch (input){case 1:printf(\n*********** 三子棋游戏开始 *************\n\n);game();//游戏执行逻辑函数break;case 0:printf(\n退出游戏\n);break;default:printf(\n选择错误请重新选择\n\n);break;}} while (input);接下来主要阐述game( )函数内容游戏的执行逻辑 1.当玩家选择1开始游戏后会显示整个空棋盘 如何实现空棋盘的显示呢 (1)、利用所学的数组知识可以联想到棋盘不过是由一个个字符拼接而成在需要下棋的地方放置空格字符进行占位达到肉眼所见的空棋盘。 (2)、又因为棋盘是一个平面平面由一条条线组成线又由一个个点组成首先得定义和初识化一个二维数组 board[ROW][COL] 由几行几列的方式实现一个面的显示/打印。 (3)、自定义初识化函数 InitBoard( ) ,自定义显示棋盘函数 DisPlayBoard( ) ; (4)、函数的参数可想而知需要数组名(board) — 首元素的地址指定需操作的数组需要行(ROW)和列(COL)指定操作的元素或坐标或地址
void game()
{//定义棋盘大小char board[ROW][COL] { 0 };//初识化棋盘InitBoard(board,ROW,COL);//显示棋盘DisPlayBoard(board, ROW, COL);}2.当我们完成棋盘的初识化和显示后那么默认玩家先下棋电脑再下棋 所以就得写一个玩家下棋的自定义逻辑函数和电脑下棋的自定义函数交替下棋直到游戏判定输赢或平局。 (1)、玩家下棋自定义函数 PlayerMove( ) ; (2)、电脑下棋自定义函数 ComputerMove( ) ; (3)、判断输赢函数 IsWin( ); 那么很容易思考到交替进行下棋就是反复的调用玩家下棋函数和电脑下棋函数同时不停的判断每一步棋是否达到输赢的结果。所以需要一个循环来实现这里就用while循环实现不停的下棋。 但是不停的下棋始终在死循环那么就思考利用break跳出循环所以 IsWin( )函数是具备返回值的可以由IsWin( )函数的返回值进行判定跳出。 且由于棋局均有字符进行的操作所以确定了 IsWin( )数据类型也为 char 类型。 (4)、IsWin( )跳出循环的返回值判定 a、玩家获胜 - - - - ‘ * ’ a、电脑获胜 - - - - ‘ # ’ a、平局 - - - - ‘ Q ’ a、游戏继续 - - - - ‘ C ’
//游戏执行逻辑函数
void game()
{//定义棋盘大小char board[ROW][COL] { 0 };//初识化棋盘InitBoard(board,ROW,COL);//显示棋盘DisPlayBoard(board, ROW, COL);//根据IsWin()返回值判断输赢char ret 0;//下棋while (1){//玩家下棋PlayerMove(board, ROW, COL);//判断输赢ret IsWin(board, ROW, COL);if (ret ! C){break;}//显示棋局DisPlayBoard(board, ROW, COL);//电脑下棋ComputerMove(board, ROW, COL);//判断输赢ret IsWin(board, ROW, COL);if (ret ! C){break;}//显示棋局DisPlayBoard(board, ROW, COL);}if (ret *)printf(\n玩家赢\n\n);else if (ret #)printf(\n电脑赢\n\n);elseprintf(\n平局\n\n);//显示棋局DisPlayBoard(board, ROW, COL);
}arr_main.c程序大纲展示
#include arr_game1.h//游戏菜单
void menu()
{printf(****************************************\n);printf(************** 1.play game *************\n);printf(************** 0.game over *************\n);printf(****************************************\n);
}
//游戏执行逻辑函数
void game()
{//定义棋盘大小char board[ROW][COL] { 0 };//初识化棋盘InitBoard(board,ROW,COL);//显示棋盘DisPlayBoard(board, ROW, COL);//根据IsWin()返回值判断输赢char ret 0;//下棋while (1){//玩家下棋PlayerMove(board, ROW, COL);//判断输赢ret IsWin(board, ROW, COL);if (ret ! C){break;}//显示棋局DisPlayBoard(board, ROW, COL);//电脑下棋ComputerMove(board, ROW, COL);//判断输赢ret IsWin(board, ROW, COL);if (ret ! C){break;}//显示棋局DisPlayBoard(board, ROW, COL);}if (ret *)printf(\n玩家赢\n\n);else if (ret #)printf(\n电脑赢\n\n);elseprintf(\n平局\n\n);//显示棋局DisPlayBoard(board, ROW, COL);
}int main()
{srand((unsigned int)time(NULL));//初识化随机值生成器int input 0;do{menu();printf(请选择:);scanf(%d, input);switch (input){case 1:printf(\n*********** 三子棋游戏开始 *************\n\n);game();//游戏执行逻辑函数break;case 0:printf(\n退出游戏\n);break;default:printf(\n选择错误请重新选择\n\n);break;}} while (input);return 0;
}2、arr_game1.h
用于存放所自定义的函数和头文件等声明的程序 通俗易懂就不多赘述详见代码注释的说明。
#include stdio.h
#include time.h//调用time函数所需声明的头文件
#include stdlib.h//调用srand和rand函数所需声明的头文件//宏定义棋盘大小
#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);3、arr_game1.c
用于存放对 arr_main.c 程序大纲做提到的函数进行封装实现具体的功能的程序 说明基于arr_main.c 程序大纲逻辑对代码进行讲解 注意这里均以3*3的棋盘为例哦
3.1、 自定义初识化函数 InitBoard( ) 和 自定义显示函数 DisPlayBoard( )
首先根据需求我们需要一个棋盘才可以正常的下棋. 如何让棋盘初识化呢 1.根据所学的二维数组知识便可以知道当我们遍历二维数组的每一个元素使得填充为空格字符便可以由InitBoard( ) 达到效果。
//初识化棋盘
void InitBoard(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){board[i][j] ;}}
}如图所示 如图所示
2.但是这样的棋盘全是空格字符只有程序员可见字符空格玩家并不知道所以将对棋盘进行修饰美化使得大众化。所以借助 DisPlayBoard( ) 达到修饰棋盘的效果。 这里使用一些分隔符将棋盘划分出三组并且数组元素加分隔符为一组。
//打印棋盘
void DisPlayBoard(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){printf( %c ,board[i][j]);printf(|);}printf(\n);//每行打印完换行}printf(\n);
}如图所示
但是目前的效果达不到理想的棋盘效果导致最后一组的分隔符也被打印了出来。 所以思考可知由 if (j col - 1) 进行判断让最后一行的分割符被约束不打印出来。 然后打印完一行换行一次。 同理每一列打印完使用 if (i row - 1) 使得最后一列的分隔符不被打印出来 所以优化后得到以下代码
//打印棋盘
void DisPlayBoard(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){printf( %c ,board[i][j]);if(j col-1)printf(|);}printf(\n);//每行打印完换行if (i row - 1){int j 0;for (j 0; j col; j){printf(---);if (j col - 1)printf(|);}printf(\n);//每行打印完换行}}printf(\n);
}如图所示 棋盘显示最终效果如图所示
3.2、 自定义玩家下棋函数 PlayerMove( )
1.首先我们下棋需要给棋子一个坐标并且需要以作为玩家的角度思考坐标的取值范围。因为玩家不一定知道数组的下标从0开始所以我们定义 x,y 坐标变量使得 if (x 1 x row y 1 y col )//符合玩家下棋坐标的逻辑 2.当我们坐标符合了范围还得判定玩家输入错误坐标超出范围时给予提示信息超出范围重新输入。 3.当玩家输入坐标范围正确但是此时的坐标处已经被上一步棋子占用时也得提示重新输入。
//玩家下棋
void PlayerMove(char board[ROW][COL], int row, int col)
{//定义下棋的坐标int x 0;int y 0;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坐标被占用请重新输入坐标\n);}}else {printf(\n坐标超出棋盘范围请重新输入棋子坐标\n);}}
}如图所示
3.4、 自定义电脑下棋函数 ComputerMove( )
1.下棋的逻辑与玩家如出一辙不多赘述。 2.这里强调一下电脑如何实现产生随机的坐标下棋 首先在之前的篇章链接: link 里提到的srand函数与rand函数的应用原理相同。通过初识化srand随机值生成器函数提供变化的随机值范围给rand随机值函数将rand()%row 和 rand()%col就可以得到符合范围的数组元素坐标。 然后根据srand的参数要求放一个时刻变化的数据这里就用到了time时间转换函数相互作用即可。 查阅资料文档的具体参数 void srand( unsigned int seed ); 头文件 stdlib.h int rand(void ); 头文件 stdlib.h time_t time( time_t *timer ); 头文件 time.h 所以得到
srand((unsigned int)time(NULL));
x rand() % row;
y rand() % col;注意srand只需要整个工程初识化一次即可
//电脑下棋
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;}}
}如图所示
3.5、 输赢判断函数 IsWin( )
由arr_main.c程序大纲提到的思路可知 如何判定输赢 玩家赢 — ‘*’ 电脑赢 — ‘#’ 平局 ---- ‘Q’ 继续游戏 — ‘C’ 所以可以明确 IsWin( ) 的返回值类型为char字符型
根据三子棋的游戏规则三个棋子连城一线即可判定获胜所以有 (1)、一行三个棋子 (2)、一列三个棋子 (3)、对角线三个棋子 那么如何判定平局呢? 顾名思义当我们的棋盘被占用完还是没有连成一线则判定为平局。 这里利用 int IsFull( )函数遍历判断数组每个元素是否已用完即可当返回0则仍然有空位继续游戏当返回1则所有元素均被占用且未连成一线判定为平局。 //判断输赢
//玩家赢 --- *
//电脑赢 --- #
//平局 ---- Q
//继续游戏 --- C
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;//判断三行均相同for (i 0; i row; i){if (board[i][0] board[i][1] board[i][1] board[i][2] board[i][1] ! ){return board[i][1];//*/#}}//判断三列均相同for (i 0; i col; i){if (board[0][i] board[1][i] board[1][i] board[2][i] board[1][i] ! ){return board[1][i];//#/*}}//判断对角线均相同三子棋//主对角if (board[0][0] board[1][1] board[1][1] board[2][2] board[1][1] ! ){return board[1][1];//*/#}//副对角if (board[0][2] board[1][1] board[1][1] board[2][0] board[1][1] ! ){return board[1][1];//*/#}//判断平局int ret Isfull(board, ROW, COL);if (ret 1)//棋盘无空位平局{return Q;}//以上所有情况不满足时继续游戏return C;
}
输赢结果如图所示
4、结束语
相信通过这样一个三子棋的小游戏更具掌握了对数组的操作以及对自定义函数的深刻认识 如果觉着文章对您有所帮助请不要吝啬的一赞三连哦谢谢阅读不足之处还请多多指教。
三子棋源码获取链接: 三子棋