?作者简介:大家好我是zoroxs
📃个人主页:c/c++学习之路 🔥💖如果觉得博主的文章还不错的话,请👍三连支持一下博主哦
今天来讲解一下三子棋,大家小时候应该都玩过,记得之前上课和同桌画来画去玩这个被老师骂,哈哈哈,
给大家说一下三子棋的规则----三子成杀
将正方形对角线连起来,相对两边依次摆上三个双方棋子,只要将自己的三个棋子走成一条线,对方就算输了
📕1.游戏整体思路
这就是游戏大体思路,图应该有些问题,我来给大家简述一下游戏思路
- 打印 3*3 棋盘
- 玩家下棋
- 判断是否三子成杀
- 电脑下棋
- 判断是否三子成杀
我们在这里规定: 玩家下棋的子用 ’ * ‘表示,电脑下棋的 棋子’ # ’ 三个* 先成玩家胜,###先成电脑胜,如果棋盘下满了,还没分出胜负,则平局
📗2.棋盘设计
下棋必不可少的两个东西,就是棋盘和棋子,我们先来设计一下棋盘 3 * 3的棋盘,我们很容易就想到了前边学过的二维数组,没学过的朋友可以看我之前博客传送门 就像这样子的,没下棋之前棋盘是空的,空并不是无,我们这里用空格填充的二维数组,我们把最边界的几个横线省略掉,来看一下VS下的调试 就像这样棋盘就设计好了, 这其实就是一个二维数组,只不过匹配的打印了很多线 那我们来总结一下,我们需要
- 一个字符的二维数组 3 * 3
- 将二维数组初始化为全空格
- 打印相匹配的横竖线
我们需要两个函数来帮我们完成, 一个初始化,一个打印,我们起为 void init_board(char board[ROW][COL], int row, int col); void display_board(char board[ROW][COL], int row, int col); 我们来实现一个这两个函数
void init_board(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 display_board(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");
}
}
这样我们只需要一个二维数组,调用这两个函数就有了一个棋盘了。
📘3.玩家下棋实现
棋盘上边已经准备好了,那有了棋盘就得有人下棋吧,我们这里考虑让玩家先手棋。
上边我们规定了,玩家下棋就是 * ,其实就是向二维数组中填充 * 我们接受一下玩家输入的坐标,然后判断此坐标是否非法,是否已经被下过了,如果都没有的话,就让玩家落子
我们定义一个函数,让玩家下棋; void player_move(char board[ROW][COL], int row, int col);
我们来实现一下
void player_move(char board[ROW][COL], int row, int col)
{
printf("玩家下棋\n");
while (1)
{
int x = 0;
int y = 0;
printf("请输入下棋坐标:>\n");
scanf("%d %d", &x, &y);
if (x <= row && y <= col && x >= 1 && y >= 1 && board[x - 1][y - 1] == ' ')
{
board[x - 1][y - 1] = '*';
break;
}
else if (board[x-1][y-1] != ' ')
{
printf("坐标已经被占用,请重新输入\n");
}
else
{
printf("坐标非法,请重新输入\n");
}
}
}
我们来测试一下 在每次下棋之后,打印一下棋盘。
这里就有一部分帅气的观众就要问了,void player_move(char board[ROW][COL], int row, int col); 这里接受到的数组中的ROW COL是什么? 这个是定义的宏,常量,还是3,为了降低耦合
#define ROW 3 #define COL 3 这个我们定义在头文件中,然后如果需要改3*3的棋盘,只需要把这个常量改了就行,极大降低耦合。
📙4.电脑下棋实现
我们来看一下电脑下棋,电脑下棋可以堵截玩家下棋,也谋划着如何赢。说实话,我连象棋的人机都赢不过去, 但是我们这里实现这个笨笨的机器人,就是斗地主中的那个
我们这里的机器人随机落子,我们来实现一下 照样编写一个函数 void computer_move(char board[ROW][COL], int row, int col); 这里用到如何创建随机数
void computer_move(char board[ROW][COL], int row, int col)
{
printf("电脑下棋\n");
while (1)
{
int x = rand() % row;
int y = rand() % col;
if (board[x][y] == ' ' && x < row && y < col)
{
board[x][y] = '#';
break;
}
}
}
来给大家讲解一下随机数的创建 这里用到之前查函数的一个网站,www.cplusplus.com ,不了解的朋友可以看我博客一文带你详解函数 但是每次更新rand函数返回的值都是一样的,需要创建一个随机数触发器 srand(time(NULL)); srand的参数是一个需要变化的数,时间一直在变化,所以我们把时间戳传进去。
这里给大家简单介绍一下,具体请去www.cplusplus.com自行探索
rand()%n得到的一定是 0 —(n-1) 之间的数字
我们这里实现的笨笨的机器人来陪你下棋
📓5.判断输赢
玩家可以下棋,电脑也可以下棋,那我们就需要判断输赢了,胜负何时出现? 当任何一方有三子成杀的时候,便分出胜负 当棋盘已满,平局
我们在这里实现一个is_win() 函数判断输赢: 函数返回值:
- Q —代表平局
- 一颗* —代表玩家赢
- #—代表电脑赢
- C----表示游戏继续
三子成杀----横竖成杀都算,对角线成杀也算,我们只需要判断是否有这样的情况出现即可 还需要判断棋盘是否满,我们实现一个工具函数—is_full 用来判断棋盘是否满 我们来看一下代码
char is_win(char board[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ')
{
return board[i][0];
}
if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[2][i] != ' ')
{
return board[i][0];
}
}
if (board[0][0] == board[1][1] && board[0][0] == board[2][2] && board[1][1] != ' ' ||
board[0][2] == board[1][1] && board[0][0] == board[2][0] && board[1][1] != ' ')
{
return board[0][0];
}
if (is_full(board, row, col) != 0)
{
return 'Q';
}
return 'C';
}
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;
}
这样我们的游戏核心代码就已经实现了,我们来复盘一下: 打印棋盘–玩家下棋–电脑下棋—判断输赢,我们都已经实现
📔6.测试函数编写
我们来测试一下我们的代码,编写一个测试函数。 我们使用do-while循环,因为有人玩了游戏可能意犹未尽,可以再来一次 我们首先打印一个菜单,供用户选择.
void menu()
{
printf("***************************\n");
printf("******* 1.play *******\n");
printf("******* 0.exit *******\n");
printf("***************************\n");
}
然后编写主函数用来测试。
int main(void)
{
int input = 0;
srand(time(NULL));
do
{
menu();
printf("请选择:>\n");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("输入有误,请重新输入\n");
break;
}
} while (input);
return 0;
}
我们还需要一个game函数用来玩游戏
game函数需要实现的东西:
- 定义二维数组当棋盘
- 初始化棋盘
- 展示棋盘
- 玩家下棋
- 电脑下棋
注: 每次落子之后都要判断输赢,如果出现游戏结果则跳出循环
每次落子之后应该打印一下棋盘给用户展示
我们来看一下代码
void game()
{
char board[ROW][COL] = { 0 };
init_board(board, ROW, COL);
display_board(board, ROW, COL);
int ret = 0;
while (1)
{
player_move(board, ROW, COL);
ret = is_win(board, ROW, COL);
display_board(board, ROW, COL);
if (ret != 'C')
{
break;
}
computer_move(board, ROW, COL);
display_board(board, ROW, COL);
ret = is_win(board, ROW, COL);
if (ret != 'C')
{
break;
}
}
if (ret == 'Q')
{
printf("平局\n");
}
else if (ret == '*')
{
printf("玩家胜\n");
}
else
{
printf("电脑胜\n");
}
}
📒7.游戏代码与测试代码拼接
上边我们把游戏代码以及如何测试进行了讲解,但是需要把游戏代码和测试代码综合起来
我们把测试代码写成一个test.c 把游戏代码封装成一个game.c 然后在一个game.h的头文件中进行定义宏,函数声明…
大家可以自己编写一下,不懂得地方可以私信我
📚8.总结
在学习了数组之后,简单的三子棋就带大家写到这里了,这就是数组的使用,把我们前边的知识做了充分的使用,我们下一期带大家写一个扫雷,大家一定要多练习。一步一步通过思考,逻辑分明,去实现代码
🔥💖如果觉得博主的文章还不错的话,请👍三连支持一下博主哦
|