> 文档中心 > 三子棋游戏的具体实现

三子棋游戏的具体实现

文章目录

  • 前言
  • 一、三子棋游戏的玩法及规则
  • 二、设计图
    • 1.游戏菜单
    • 2.设计棋盘
    • 3.规定棋子
    • 4.实现玩家下棋
    • 5.实现电脑下棋
    • 6.对局状态
  • 三、游戏全部代码
  • 总结

前言

大家好,我是耶鲁,今天我先出一篇关于三子棋游戏的具体实现,希望能激发大家学习C的兴趣,使咱们不仅会玩游戏,还能知道玩的游戏是怎么实现的。知其然知其所以然!!废话不多说,下面我们就直接进入主题。


一、三子棋游戏的玩法及规则

三子棋是黑白棋的一种。三子棋是一种民间传统游戏,又叫九宫棋、圈圈叉叉、一条龙、井字棋等。将正方形对角线连起来,相对两边依次摆上三个双方棋子,只要将自己的三个棋子走成一条线,对方就算输了。我相信大家小时候应该都玩过吧!

二、设计图

我们将实现三子棋游戏的程序分成下图所示的三个文件:
在这里插入图片描述
我们再将其细分,大概可设计为下图六大模块:
在这里插入图片描述

接下来我们将这几个模块一一实现,再将模块与模块之间相连接,即可实现三子棋游戏的实现。

小建议:我们写程序的时候,最好是写一部分测试一部分,特别是代码比较多的情况下,这样程序出现bug的话我们可以及时的发现,确保这一部分是正确的。如果等到最后再测试的话,出现问题,解决起来就比较麻烦。

1.游戏菜单

游戏菜单我们可以这样来设置:当玩家输入1时:开始游戏,当玩家输入0时:退出游戏,除此之外,如果玩家输入1 / 0之外的数字应该提醒玩家:输入错误,请重新输入。并且玩家可以多次进行游戏,如果玩一局不过瘾还可以再来一局。
经过上面的分析,我们大概可以知道程序要用到那些语句,我们可以使用switch语句来针对玩家所输入的数字进行相应的操作,使用循环语句使玩家可以按照自己的意愿选择是否多次进行游戏。

具体实现代码如下:在这里插入图片描述

2.设计棋盘

下棋肯定是需要一个棋盘的(一般都是3×3形式的棋盘),这里的棋盘既然是三行三列的,这不跟我们学过的二维数组很像吗?所以我们可以尝试用字符型二维数组存储棋盘上的数据。
我们上面说到棋盘形式一般都是3×3,但是如果有人想改变棋盘的形式,我们还得在程序中一处处的修改数据,太过于复杂,所以我们在头文件中利用 #define 来定义 ROW3,COL 3 这两个符号,就可以将程序中使用到3的地方用ROW和COL进行替换,也可以对这两处进行修改,进而改变我们棋盘的样式。

如下图所示:
三子棋游戏的具体实现
我们先将棋盘初始化为空格,再利用 ’ ‘,’|’,’’ 这几个符号来刻画出棋盘,大概的效果图如下:
在这里插入图片描述
代码实现如下:
在这里插入图片描述图代码运行结果图如下:
三子棋游戏的具体实现

如果我们想将棋盘改为10 × 10的样式,但是我们打印出来的棋盘为什么是10 × 3的样式呢?这是因为我们程序中输出数据的那一行已经写“死”了,它的列数已经固定下来了。所以就会出现如下结果:

三子棋游戏的具体实现

通过观察我们可以把 %c | 看成一组,最后一列我们只打印 %c 不打印 | ,既然我们最后一列不打印 | ,所以我们要将 %c 和 | 分开打印。

代码实现如下:
在这里插入图片描述
代码运行结果如下,经过我们的修改,版本2的代码的实现就非常的灵活了。
三子棋游戏的具体实现

3.规定棋子

棋子可以根据大家个人的喜好来设置,我这里规定玩家的棋子是’*’, 电脑的棋子是’#’。

4.实现玩家下棋

玩家和电脑每走一步棋之后,棋盘都要进行记录。所以再设置一个打印棋盘的函数,不论玩家还是电脑下棋之后我们都会调用打印棋盘的函数,观察对局情况。

在这里插入图片描述

5.实现电脑下棋

在实现电脑下棋之前我们先简单介绍一下rand函数:它是C语言中用来产生一个随机数的函数,rand函数界限:头文件中有宏 #define。RAND_MAX 0x7fff,rand产生一个0-0x7fff之间的的随机数,也就是最大是32767的一个数字。rand函数确实会帮我们生成一个随机数,但是生成随机数的方法有问题,看下图:这是我从rand介绍文档里面截取的一段话。这句话的大概意思是:调用rand函数之前我得先调用srand函数,我们要用srand来设置随机数的生成器。

三子棋游戏的具体实现srand函数原型:
三子棋游戏的具体实现

srand的参数应该是一个无符号整型并且是随时变化的,什么数字是随时在发生变化的?当然是时间啦!时间每分每秒都在发生变化。所以我们可以把时间传给srand这个函数。这里又得引入一个概念叫时间戳,大家如果感兴趣可以自行了解一下哈,我简单说明一下,时间戳就是目前的时间和计算机的起始时间的差值(秒)。我们想要获得时间戳就得利用C语言库函数time,time函数调用要给它传一个NULL,time_t是由typedef定义的整型值且函数头文件为。

三子棋游戏的具体实现
上述实现如下:
三子棋游戏的具体实现
经过上面的一系列铺垫,电脑就可以得到一个随机数,再将随机数的数值通过取模运算控制在合法范围内即可。
在这里插入图片描述

6.对局状态

游戏的对局可分为四种状态
玩家赢 —’*'
电脑赢 — '#'
平均 — 'Q’
继续 ----'C’
根据返回相应的符号可知对局当前对应的状态。
分析:先设置一个判断输赢的函数,那一方三个棋子先连成一线的一方为胜方,横向、竖向、斜向均可,然后在判断是否平局,如果棋盘没有空格时就说明棋盘已经满了,此时还没有分出胜负的话,就说明此局是平局,否则就继续游戏。

代码实现如下:
在这里插入图片描述

三、游戏全部代码

test.c

#define _CRT_SECURE_NO_WARNINGS 1#include "game.h"void menu(){printf("************************\n");printf("*****   1. play   ******\n");printf("*****   0. exit   ******\n");printf("************************\n");}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");}}void test(){int input = 0;srand((unsigned int)time(NULL));do{menu();printf("请选择:>");scanf("%d", &input);    //玩家可能输入1 / 0 / 其它数switch (input)  //运用switch语句可以根据玩家输入的数字,执行相应的语句{case 1: //输入1,进入game函数game();break; case 0: //输入1,进入退出游戏printf("退出游戏\n");break;default://输入其它数字printf("输入错误,请重新输入\n");break;}} while (input);    //输入的input为0,条件为假,跳出循环。输入的input不为0,条件为真,继续进入do...while循环}int main(){test();return 0;}

game.h

#pragma once#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);

game.c

#define _CRT_SECURE_NO_WARNINGS 1#include "game.h"  //包含头文件,避免重复定义//初始化棋盘的具体实现void InitBoard(char board[ROW][COL], int row, int col){int i = 0;int j = 0;for (i = 0; i < row; i++)  //利用for循环设置出三行三列的形式{for (j = 0; j < col; j++) {board[i][j] = ' ';   //棋盘先初始化为空格}}}//版本1//void DisplayBoard(char board[ROW][COL], int row, int col)//{//int i = 0;//int j = 0;//for (i = 0; i < row; i++)//{////数据//printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]); //列数已经固定// ////分割行//if(i<row-1)//printf("---|---|---\n");//}//}//版本2void 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");}}//玩家下棋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] == ' ')      //判断输入坐标处是否有棋子,从玩家的角度去考虑数组的行和列和我们习惯上的行和列有所差别,数组是从0开始,而我们习惯从1开始{board[x - 1][y - 1] = '*';break;  //玩家下完之后,跳出循环,等待电脑下棋}else{printf("该坐标被占用,请重新输入!\n");}}else{printf("坐标非法,请重输入!\n");}}}//电脑下棋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   //rand函数可以产生随机数且使随机数在合法坐标范围内y = rand() % COL;//0~2if (board[x][y] == ' ')  //判断输入坐标处是否有棋子{board[x][y] = '#';break;}}}//判断棋盘是否填满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;   }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';}

总结

好了,三子棋游戏具体的实现过程就介绍至此了,我坚信慢工出细活,所以文章更新得到较为缓慢,希望大家多多支持!我也会尽我最大的努力为大家讲解清楚每一处知识,但精力有限,文章不免有瑕疵之处,如果大家有什么问题或者建议的话,可以在评论区讨论指出,谢谢! ψ(*`ー´)ψ

Alt

China香烟网