【C语言】如何实现三子棋和五子棋?

本文详细介绍了如何从零开始构建一个简单的三子棋游戏,包括游戏框架、菜单设计、棋盘初始化、玩家与电脑交替下棋的逻辑,以及游戏胜利和平局的判断。同时,文章还讨论了如何将游戏扩展为五子棋,只需修改棋盘大小和胜利条件。通过逐步讲解和代码示例,读者可以了解到游戏编程的基本思路和技巧。
摘要由CSDN通过智能技术生成

首先,我们因该分装3个文件,分别是:

以方便后期维护和增加代码可读性,防止代码冗余

game.c用来封装函数,实现各部分功能test.c用来构建整个程序的框架game.h用来存放所有头文件,我们只需把#include包含的头文件放在test.h文件,再在game.c 、test.c里加上#include"game.h"即可。

现在我们来构建框架

玩游戏的时候总要在开始界面有个菜单,我们可以这样做

void menu()
{
	printf("*************************\n");
	printf("******1.play  0.exit*****\n");
	printf("*************************\n");
}
int main()
{
	menu();

	return 0;
}

考虑到玩家玩完之后还想继续玩,所以可以构建一个do while循环的结构;既然有了菜单可选项,我们可以给程序一个输入值1和0,用switch语句进行选择

void menu()
{
	printf("*************************\n");
	printf("******1.play  0.exit*****\n");
	printf("*************************\n");
}
int main()
{
	int input = 0;
	do
	{
		menu();
		printf("请选择:");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("输入非法,请重新输入\n");
			break;
		}
	}while(input);

	return 0;
}

注意:每完成块步骤,记得执行以下,看看有没有bug,以免到最后程序写完了,出现一堆bug,一个一个找起来实在麻烦!

程序走了case 1就进入游戏啦,这里可以写一个game()函数来封装

这里我们继续一步一步走,既然玩的是三子棋或者五子棋,那肯定先要有个棋盘嘛,而且下棋怎么实现呢?这里可以创建一个二维数组来实现,这里初始化一下棋盘,封装一个函数,可以放在game.h里啦,在test.c文件里只需声明一下即可

void game()
{
	char board[3][3] = { 0 };
	//初始化棋盘
	Initboard(board, 3, 3);
}

这里细心的人可能就发现了,“哎呀,如果我要将这个三子棋改成五子棋那岂不是重新创建一个矩阵,那程序内部不就乱套了啊”       

 哈哈,没事,不用着急,这里我们可以这样做

这样以后如果要把游戏改成五子棋也方便了不少 

那这里函数自然也要变

void game()
{
	char board[ROW][COL] = { 0 };
	//初始化棋盘
	Initboard(board, ROW, COL);
}

记得把这个函数声明放到.h文件里哦

//初始化棋盘
void Initboard(char board[ROW][COL],int row, int col);

接下来在game.c里实现一下 初始化棋盘:

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] = ' ';
		}
	}
}

实际上,就是将数组里的每个元素初始化成空格

光是空格也不行啊,该看看实际效果了,该打印展示一下棋盘了

先来看一下,棋盘大概样子

 这里如果你直接用一个printf搞定也不是不可以,但又没有想过太挫了(狗头保命)

如果要修改成五子棋,那printf岂不是要重写

所以我们可以这样

void Showboard(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++)
		{
			printf(" %c ",board[i][j]);
			if (j < col - 1)
				printf("|");
		}
		printf("\n");
		for (j = 0; j < col; j++)
		{

			if (i < row - 1)
			{
				printf("---");
				if (j < col - 1)
				{
					printf("|");
				}
			}
		}
		printf("\n");
	}
}

这里大家仔细看一下,不难理解

接下来看一下目前程序执行的结果

如果想要更大的棋盘,直接修改#define定义的行和列就好啦

是不是很nice!

好咯

现在重头戏来了

该轮到玩家或者电脑下棋了

来分析一波~

这里可以给玩家的棋子设置为‘ * ’符号,电脑的棋子为‘ # ’符号

首先玩家下棋,再继续轮到电脑下棋,直到最后谁赢了或者是平局,先抛开这个不想,先解决手头的问题,这样对弈的过程实际上是一个循环,可以这样来写

void game()
{
	char board[ROW][COL] = { 0 };
	//初始化棋盘
	Initboard(board, ROW, COL);
	//展示棋盘
	Showboard(board, ROW, COL);
	//下棋
	while (1)
	{
		//玩家下棋
		Game_board(board, ROW, COL);
		//电脑下棋
		//Computer_board(board, ROW, COL);
	}
}

 因为暂时不考虑其他因素,可以先把循环写死

同时,玩家或电脑下完棋,我们最好能看到棋盘,所以

void game()
{
	char board[ROW][COL] = { 0 };
	//初始化棋盘
	Initboard(board, ROW, COL);
	//展示棋盘
	Showboard(board, ROW, COL);
	//下棋
	while (1)
	{
		//玩家下棋
		Game_board(board, ROW, COL);
		Showboard(board, ROW, COL);

		//电脑下棋
		//Computer_board(board, ROW, COL);
		//Showboard(board, ROW, COL);

	}
}

接下来可以实现以下,玩家下棋了

这里可以通过让玩家输入坐标来完成下棋

void Game_board(char board[ROW][COL], int row, int col)
{
	printf("玩家走(输入坐标):");
	int x = 0;
	int y = 0;
	scanf("%d %d", &x, &y);
}

接着,我们因该思考这样一个问题,咱写程序的人知道数组下标是从0开始的,但不见得玩家也是程序员啊,所以我们在输入坐标以后可以给x-1 , y-1,这样OK~

不仅仅是这个问题,比如:如果玩家已经在(1,1)这个格子里下过了,玩家又不小心下在这个格子里怎么办?如果棋盘大小只有3*3,玩家走(4,8)下出格了怎么办...

这一些列问题我们都因该考虑到,这里我们可以用if else 来解决

这个用来解决下出格子的问题

这个用来解决重复问题

 成品:

void Game_board(char board[ROW][COL], int row, int col)
{
	
	int x = 0;
	int y = 0;
	while (1)
	{
		printf("玩家走(输入坐标):");
		scanf("%d %d", &x, &y);
		if (x > 0 && x <= row && y > 0 && y <= col)
		{
			if (board[x - 1][y - 1] == ' ')
			{
				board[x - 1][y - 1] = '*';
				break;
			}
			else
			{
				printf("该位置已被占用,请重新输入!\n");
			}
		}
		else
		{
			printf("输入非法,请重新输入!\n");
		}
	}
}

接下来轮到电脑下棋咯

先分析一下,大致思路和玩家下棋一样,要避免一些重复,出格等问题,除此之外,还因该想想电脑该如何下棋呢?

可以这样做,创造一个随机数,让电脑随机下棋;

怎么创造随机数呢?

这里我们引入两个函数来产生随机数

rand用来产生随机数

srand用来产生随机数生成起点

还需要引入两个头文件

 至于time.h这个头文件,是一会用srand函数会用到的

srand函数需要放在整个程序的开头用,这样rand产生的数才是随机的(具体用法可以去搜一下,这里主要讲三子棋和五子棋,这里不细讲);

srand((unsigned int)time(NULL));//设置随机数起点

unsigned int 强制类型转换成无符号整形,防止出现负数.

有个了这个随机数种子,就可以去编写电脑下棋的代码了

void Computer_board(char board[ROW][COL], int row, int col)
{
	printf("电脑走:\n");
	int x = 0; 
	int y = 0; 
	while (1)
	{
		x = rand() % row;
		y = rand() % col;
		if (board[x][y] == " ")
		{
			board[x][y] = '#';
			break;
		}
	}
}

rand()可以产生随机数

rand()%3可以产生0~2的数字

再用   if  来排除重复问题.

提醒以下:别忘了电脑下完棋以后也要展示以下喔~

说到这里,不知道大家有没有发现上面这段代码有问题(哈哈哈)

上方代码会让程序死循环...

作者在这蹭了有一会时间哈哈哈哈

我就刚开始瞪着眼睛看,怎么找都找不出来!把我可急坏了哈哈哈哈

再后来我在while那里设置了断点调试了以下,才发现原来  if  语句那里我用的是 " "  双引号,哈哈哈哈~

所以在这里提醒以下大家:

#出错了不要光瞪着眼睛看!去调试以下,打开你的监视窗口,看你想要知道的变量的值,调试真的很有用!!!哭晕~

看到这里觉得不错的小伙伴点个赞咯

正确代码如下

void Computer_board(char board[ROW][COL], int row, int col)
{
	printf("电脑走:\n");
	int x = 0; 
	int y = 0; 
	while (1)
	{
		x = rand() % row;
		y = rand() % col;
		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}
}

这样就可以和电脑下棋喽~

哈哈,不要高兴的太早,还要分出胜负呢,今天不是你死就是我亡!当然也有可能平局哈哈

接下来,回到我们的test.c文件

我们需要分几种情况:

不妨分装一个函数 用来判断,玩家下一次棋判断一次,电脑下一次棋判断一次,一直循环,直到分出胜负

接下来我们转化成代码实现:

char Judgment(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])
		{
			if (board[i][1] == '*')
				return '*';
			else if (board[i][1] == '#')
				return '#';
		}
		//竖
		if (board[0][i] == board[1][i] && board[1][i] == board[2][i])
		{
			if (board[1][i] == '*')
				return '*';
			else if (board[1][i] == '#')
				return '#';
		}
	}//对角线
	if ((board[0][0] == board[1][1] && board[1][1] == board[2][2])
		|| (board[0][2] == board[1][1] && board[1][1] == board[2][0]))
	{
		if (board[1][1] == '*')
			return '*';
		else if (board[1][1] == '#')
			return '#';
	}
}

 这是电脑和玩家谁赢的判断

接下来判断平局

char Judgment(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])
		{
			if (board[i][1] == '*')
				return '*';
			else if (board[i][1] == '#')
				return '#';
		}
		//竖
		if (board[0][i] == board[1][i] && board[1][i] == board[2][i])
		{
			if (board[1][i] == '*')
				return '*';
			else if (board[1][i] == '#')
				return '#';
		}
	}//对角线
	if ((board[0][0] == board[1][1] && board[1][1] == board[2][2])
		|| (board[0][2] == board[1][1] && board[1][1] == board[2][0]))
	{
		if (board[1][1] == '*')
			return '*';
		else if (board[1][1] == '#')
			return '#';
	}
	//平局和继续
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			if (board[i][j] == ' ')
				return 'C';
		}
	}
	return 'P';
}

回到test.c文件中,继续建立框架,对judgment函数的反馈作出反应

看一下上面这段代码,如果要判断的话,电脑和玩家下面都要进行相同的判断,代码就有些地方冗余了,不够优化

我们可以这样

void game()
{
	char board[ROW][COL] = { 0 };
	//初始化棋盘
	Initboard(board, ROW, COL);
	//展示棋盘
	Showboard(board, ROW, COL);
	//下棋
	while (1)
	{
		//玩家下棋
		Game_board(board, ROW, COL);
		Showboard(board, ROW, COL);
		if (Judgment(board, ROW, COL) != 'C')
		{
			break;
		}
		//电脑下棋
		Computer_board(board, ROW, COL);
		Showboard(board, ROW, COL);
		if (Judgment(board, ROW, COL) != 'C')
		{
			break;
		}
	}
	if (Judgment(board, ROW, COL) == '*')
	{
		printf("玩家赢\n");
	}
	else if (Judgment(board, ROW, COL) == '#')
	{
		printf("电脑赢\n");
	}
	else
	{
		printf("平局\n");
	}
}

 这样是不是看起来舒服多了呢~

三子棋其实到这里就完成啦!

///

如果想改成五子棋,其实也很简单

只需要改一下Judgment这个函数,再将#define定义的棋盘大小一改成5*5就okk(这里有点局限性,棋盘大小如果超过5*5,对角线将不好判断,可以这样解决:加几个for循环寻找任意对角线上相同元素,在进行判断即可);

那怎么改呢?

char Judgment(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][2] == board[i][3] && board[i][3] == board[i][4])
		{
			if (board[i][0] == '*')
				return '*';
			else if (board[i][0] == '#')
				return '#';
		}
		//竖
		if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[2][i] == board[3][i] && board[3][i] == board[4][i])
		{
			if (board[0][i] == '*')
				return '*';
			else if (board[0][i] == '#')
				return '#';
		}
	}//对角线
	if ((board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[2][2] == board[3][3] && board[3][3] == board[4][4])
		|| (board[0][4] == board[1][3] && board[1][3] == board[2][2] && board[2][2] == board[3][1] && board[3][1] == board[4][0]))
	{
		if (board[2][2] == '*')
			return '*';
		else if (board[2][2] == '#')
			return '#';
	}
	//平局和继续
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			if (board[i][j] == ' ')
				return 'C';
		}
	}
	return 'P';
}

再将

#define ROW 5

#define COL 5

即可

以上就是三子棋以及五子棋的创作过程即讲解了

码字不易~

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陈亦康

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值