摘要:前言本篇文章记录了用语言实现三子棋小游戏,主要目的是对之前语言知识学习的巩固,联系各个知识,以及怎么样实际使用各个知识。效果显示函数当玩家输入时,跳入到游戏的实现代码之中。这里调用了函数,实现代码如下由于在这里强制转化为正整数。
本篇文章记录了用C语言实现三子棋小游戏,主要目的是对之前C语言知识学习的巩固,联系各个知识,以及怎么样实际使用各个知识。
一、三子棋的游戏规则
玩家将会看到一个3X3的网格棋盘,默认玩家先下棋,电脑后下棋。
规定:先连成一条直线(3个棋子)的玩家获胜,行,列,对角线均可。若在棋盘下满时仍未分出胜负,则为平局
二、使用到的头文件
#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 player_move(char board[ROW][COL], int row, int col);
void computer_move(char board[ROW][COL], int row, int col);
//玩家赢 - "*"//电脑赢 - "#"//平局 - "Q"//继续 - "C"char is_win(char board[ROW][COL],int row,int col);
三、游戏的测试
int main() { test();//调用test测试函数 return 0;}
void test() { int input = 0; srand((unsigned int)time(NULL)); do { menu(); printf("请选择:>"); scanf("%d",&input); switch (input) { case 1: game(); break; case 0: printf("退出游戏/n"); break; default: printf("选择错误/n"); break; } } while (input);}
解析test函数主要构成:
i>菜单menu()函数:
void menu() { printf("******************************/n"); printf("***** 1. play ********/n"); printf("***** 0. exit ********/n"); printf("******************************/n");}
实现效果:
ii>switch case 语句:实现了玩家通过不同输入选择实现不同的功能。
效果显示:
iii>game()函数:当玩家输入1时,跳入到游戏的实现代码之中。
void game() { // 数据存储,玩家下棋"*",电脑下棋是"#" char board[ROW][COL] = {0};//数组的内容 应该是全部空格 InitBoard(board,ROW,COL);// 初始化棋盘 // 打印棋盘 DisplayBoard(board,ROW,COL); //下棋 char ret = 0; while (1) { player_move(board, ROW, COL); DisplayBoard(board, ROW, COL); ret = is_win(board, ROW, COL); if (ret != "C") { break; } computer_move(board, ROW, COL); DisplayBoard(board, ROW, COL); ret = is_win(board, ROW, COL); if (ret != "C") { break; } } if (ret == "*") { printf("玩家赢/n"); } else if (ret == "#") { printf("电脑赢/n"); } else{ printf("平局/n"); } }
game()函数里面包括了:打印棋盘函数,初始化棋盘函数,玩家下棋函数,电脑下棋函数,判断输赢函数的调用,已经规定输赢的条件,具体每个函数的实现代码和问题如下。
注:最后有game()函数的逻辑顺序。
四、游戏的实现
我们首先实现对棋盘的打印:
我们在头文件中规定了 3行3列
#define ROW 3 #define COL 3
自定义函数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]); if (j < col - 1) printf("|"); } printf("/n"); //分割行 if (i < row - 1) { for (j = 0; j < col; j++) { printf("---"); if (j < col - 1) { printf("|"); } } } printf("/n"); }}
定义InitBoard()函数,主要实现代码如下:
void InitBoard(char board[ROW][COL], int row, int col){ int i = 0; int j = 0; for (i = 0; i < row; i++) { //3行 for (j = 0; j < col; j++) { // 3列 board[i][j] = " "; } }}
初始化棋盘全为空格
自定义函数 player_move 实现,代码如下:
void player_move(char board[ROW][COL], int row, int col) { printf("玩家下棋:>"); int x = 0; int y = 0; while (1) { 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"); } }}
这里面包含了很多小问题和解决方案:
1:输入的坐标不在棋盘的范围内怎么办?
答:使用if else 选择语句,如果输入的坐标合法,则输入成功,如果输入的坐标不合法则会提醒“坐标非法,请重新输入!”字样。
if (x >= 1 && x <= row && y >= 1 && y <= col)
2:输入的坐标在棋盘上已被占用怎么办?
这个问题我们需要转化成这个问题解决:
i>怎么判断输入坐标被占用?
答:我们通过对选择语句if else 对改坐标进行判断,由于我们在初始化棋盘时,初始化棋盘全部为空格,如果输入坐标所对应的格子是空格,则说明未被占用,如果输入坐标所对应的格子不是空格,则说明该格子已经被占用。
if (board[x - 1][y - 1] == " ")
ii>如何正确输入棋子?
如果输入坐标所对应的格子是空格,则可以成功输入,如果不是空格,则会else提醒玩家“该坐标被占用,请重新输入!”字样。利用while循环语句可再次输入正确的未被占用的坐标。
自定义函数 computer_move 实现,代码如下:
void computer_move(char board[ROW][COL], int row, int col) { int x = 0; int y = 0; printf("电脑下棋:>/n"); while (1) { x = rand() % ROW; // 0 ~ 2 y = rand() % COL; // 0 ~ 2 if (board[x][y] == " ") { board[x][y] = "#"; break; } }}
这里也包含了几个小问题和解决方案:
1:这里电脑的输入是随机输入,如何实现?
答:这里我们并非是真的随机值,只是利用了时间戳,由于时间在每时每刻的改变,所以在不同的时间,经过处理后的时间我们也无法知道,可当做随机值使用。这里调用了time函数,实现代码如下:
#include srand((unsigned int)time(NULL));
由于在这里强制转化为正整数。
2:如何控制电脑随机输入的值合法?
答:这个问题的意思是,如果不对这个随机值进行处理,那么这个值很可能超出棋盘,所以要对这个值进行控制,由于棋盘规定3行3列,数组下标由0开始,所以随机值只要在0~2之内即可。所以我们对这个随机值进行取模(取余数)处理即可解决此问题:
x = rand() % ROW; // 0 ~ 2y = rand() % COL; // 0 ~ 2
为了区分玩家和电脑的棋子不同,在此规定
玩家使用 " * " , 电脑使用 " # "
因为这里电脑输入坐标均为随机值,所以不具有判断的能力,读者可以思考一种优化算法,写出一种最快赢下比赛的算法。而不至于出现可能都已经一行出现2个棋子了,随机值可能再下到别处的情况(哈哈 人工“智障”)。
实现代码:
char is_win(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]; } //判断平局 if (1 == is_full(board, row, col)) { return "Q"; } //继续 return "C";}
游戏规定,首先完成一行或者一列或者对角线的玩家获胜,在此我们只需要进行三行,三列,对角线的判断以及平局的判断,游戏继续判断。具体是玩家赢还是电脑赢,我们在测试函数test中有规定,不同的玩家对应不同的字符,在此规定:
三行的判断:
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]; }
平局的判断:
游戏规定,当棋盘下满时,还未分出胜负时,则为平局。
因此首先我们思考如何判断棋盘是否下满?
答:在这里我们通过返回值的数字来判断是否下满
自定义函数 is_full函数,具体代码:
int is_full(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;}
代码逻辑:我们通过返回值来判断棋盘是否下满,
如果未被下满,则返回值是0(return 0 )
如果下满我们将返回1(return 1)
小问题:我们如何判断是否下满?
我们遍历数组的过程中,如果发现还有空格存在,说明棋盘还没有被下满,我们立刻返回0,否则说明棋盘没有空格存在,说明已经下满,返回1.
所以我们就可以通过返回值判断平局,代码如下:
if (1 == is_full(board, row, col)) { return "Q"; }
如果返回值 == 1 说明 棋盘被下满 我们返回字符 " Q " (我们刚刚已经规定Q为平局)
五、game()函数
我们再次将game()函数调出进行详解:
void game() { // 数据存储,玩家下棋"*",电脑下棋是"#" char board[ROW][COL] = {0};//数组的内容 应该是全部空格 InitBoard(board,ROW,COL);// 初始化棋盘 // 打印棋盘 DisplayBoard(board,ROW,COL); //下棋 char ret = 0; while (1) { player_move(board, ROW, COL); DisplayBoard(board, ROW, COL); ret = is_win(board, ROW, COL); if (ret != "C") { break; } computer_move(board, ROW, COL); DisplayBoard(board, ROW, COL); ret = is_win(board, ROW, COL); if (ret != "C") { break; } } if (ret == "*") { printf("玩家赢/n"); } else if (ret == "#") { printf("电脑赢/n"); } else{ printf("平局/n"); } }
根据代码发现主要逻辑顺序:
这是game()函数内部的主要逻辑顺序,每一步所对应的函数调用和判断也均在图中显示。
六、演示
完整代码: 完整代码我放在我的Gitee仓库内,链接如下:
https://gitee.com/Yaulixingyu/c-language/tree/master/三子棋/三子棋
游戏演示:
以上就是我对三棋子小游戏的实现,有兴趣的小伙伴可以对代码进行优化,可实现五子棋等,也可以对电脑下棋记性优化,使电脑不再人工“智障”。
哈哈哈~由于文章较长,感谢各位小伙伴的观看,由于本人的技术水平有待提高,如果遇到错误也请及时指正。如果各位小伙伴觉得不错的话,可以点赞关注一波~多谢多谢
下期预告:扫雷 小游戏
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/123187.html
摘要:简单介绍了三子棋原理后接下来为大家讲解分步目标及代码如何实现。电脑下棋我们实现了玩家和电脑的下棋后,我们需要编写一个函数来判断双方的输赢。我们使用函数来实现这一目标。 目录 1.三子棋原理 2.分块代码实现 3.总结 1.首先向大家介绍一下三子棋的原理 首先我们需要有一个棋盘,初始时棋...
摘要:三子棋目录一问题介绍三子棋,在民间又叫井字棋。因为人们在游玩时常常不画棋盘的边框,正如汉字中的井字,多称为井字棋。 三子棋 目录 一、问题介绍 三子棋,在民间又叫井字棋。因为人们在游玩时常常不画棋盘的边框,正如汉字中的井字,多称为井字棋。 三子棋的游戏规则十分的简单: ...
摘要:今天博主将为大家带来语言入门级小游戏三子棋井字棋的详细介绍,希望这篇文章对大家能有帮助。在这里,我们使用函数来实现这一功能。 今天博主将为大家带来C语言入门级小游戏——三子棋(井字棋)的详细介绍,希望这篇文章对大家能有帮助 。 在编程的学习过程中,编写一些中这样...
阅读 3542·2023-04-25 19:56
阅读 1660·2021-11-12 10:36
阅读 1780·2021-11-08 13:19
阅读 1544·2019-08-30 14:06
阅读 3030·2019-08-30 11:01
阅读 1711·2019-08-29 13:23
阅读 2731·2019-08-29 11:18
阅读 3422·2019-08-26 13:35