【C语言】-万字博客详解任意棋盘的三子棋小游戏!!!快进来瞅瞅吧

🎇作者:小树苗渴望变成参天大树
💖作者宣言:写好每一篇博客
💦作者gitee:link
img
快来看三子棋小游戏的实现😁


✨前言

我们在之前学习了关于数组的一些知识,我们知道了数组怎么创建和使用,今天我将即将一个人机对战的三子棋小游戏,并且我们将采用3-12方阵的任意一种棋盘来玩这个小游戏,使游戏不在单调死板,而且各个功能的实现先不用函数的形式展现,最后看源码的时候大家在去理解,大家来看正文吧!!!


一、🎉三子棋小游戏的介绍

🎊1.1游戏规则的介绍

我们这次所讲的三子棋并不是每个玩家只有三个棋子,而是在棋盘未满的情况下,双方各下一个棋子,当哪一方连成横三个,竖三个或者斜三个相等的时候就胜利了,当棋盘满了还没有谁胜利就是平局,我们接下来看看运行实例:
在这里插入图片描述
这样就是平局的情况。那我们要怎么实现这个代码呢??

💫1.2游戏界面的介绍

我们看到运行界面的图片,他是由棋子和棋盘构成的,我们的棋子使用一个数组来存储的,然而棋盘是需要自己去打印的,
那让我们看看棋盘怎么打印:
在这里插入图片描述
但这样不太好,把问题给固定死,只能打印33的棋盘,今天我们讲解的是3-12方阵的任意棋盘,如果是1212的方阵我们上面的代码就会出现下面这个问题:

Alt
那我们怎么修改代码呢,并且保证棋盘越大的时候我们方便找坐标,那我们是不是需要标记每一行每一列,不至于数。
所以打算把代码改成下面的样子
在这里插入图片描述

int i = 0;
	int j = 0;
	for(i=1;i<=row;i++)
	{
		printf("  %d ", i);
	}//打印行标记
	printf("\n");
	for (i = 0; i < row; i++)
	{
		printf("%2d",i+1);//打印列标记
		for (j = 0; j < col; j++)
		{
			//打印每一行的数据;
			printf(" %c ", board[i][j]);
			if (j < col - 1)
				printf("|");
		}printf("\n");
		if (i < row - 1)
		{       //打印分割行
			printf("  ");
			for (j = 0; j < col; j++)
			{
				printf("---");
				if (j < col - 1)
					printf("|");
			}
			printf("\n");
		}

	}
	

打印12*12的棋盘就是这样的,3-12任意的都行
在这里插入图片描述

这才是我们想要达到的结果,我们需要做的界面。

💥1.3棋子的初始化介绍

那我们下的棋子放在哪里呢,这个时候就需要我们定义一个数组来存放棋子,数组的大小应该随着棋盘的大小而变化,所我们可以这样做
在这里插入图片描述
我们将数组里面先初始化空格,如果初始化为1,就会出现下面的情况

int i = 0;
	for (i = 0; i < row; i++)
	{
		int j = 0;
		{
			for (j = 0; j < col; j++)
			{
				board[i][j] = ' ';
			}
		}
	}

在这里插入图片描述

这是初始化为1的结果,显然我们需要初始化为我们看不到空格,才能达到我们想要的结果。

这个时候我们棋盘的准备工作才熬这里结束了,接下来将下棋的一些功能

💢二、三子棋小游戏功能介绍

💌2.1玩家下棋

玩家下棋就需要改变我们数组的值,作为我们的棋子,我们将“*”作为我们玩家的棋子,我们玩家需要输入左边进行下棋,但普通玩家不是我们程序员,不知道下标是从0开始的,所以我们到时候需要把下标减一,但我们也要避免有些玩家随便输入下标,和下在了有子的坐标上造成越界问题和改变对方棋子的问题,所以我们要一个循环和判断,输入不合法就循环进去,输入正确就天厨循环,完成落子。

所以我们的代码如下:

int x = 0;
	int y = 0;
	while (1)
	{
		printf("请输入要下的坐标:");
		scanf("%d%d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col && board[x - 1][y - 1] == ' ')
		{
			board[x - 1][y - 1] = '*';
			break;
		}
		else
		{
			printf("输入下标不合法,请重新输入:");
		}
	}

💝2.2电脑下棋

我们知道就算是电脑下棋,也是通过下标来实现的,并且把电脑下的棋子记作“#”。那我们怎么过的电脑下的坐标呢?我在之前的博客是不是介绍过怎么生成随机数,并且实现了猜数字小i游戏,那我们这里可不可以通过随机数来获得呢?答案是可以的那我们怎么实现呢,看下面的代码:

int x = 0;
	int y = 0;
	while (1)
	{
		x = rand() % row;
		y = rand() % col;
		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}
	printf("电脑下棋为(%d,%d)\n", x + 1, y + 1);
}

首先我们生成的随机数需要%上行列才能获得对应的下标,以3*3棋盘来说,x,y的值都为0-2的数所以不存在数组越界的情况,但可能会在已经有的棋子上落子,如果有,就进入循环继续生成随机数,所以我们要加一个判断来解决这个问题。

💘2.3棋盘是否为满

这里我以3*3的棋盘画图为例

我们在下棋的时候,如果出现为满就下不了棋了,就为平局,那我们怎么判断棋盘为满呢,如果棋盘为满就返回1,有一个为空,那整个棋盘就不满,返回0;

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;

如果棋盘有空格,就代表棋盘不为满就直接返回1,如果整个棋盘都遍历一遍发现都有棋子,就返回1.

🎨2.4怎么判断输赢

输赢才是i这个游戏的关键所在,也是这个游戏的核心算法,那我们应该怎么去实现这个代码呢?

规定:
玩家赢返回对应的棋子,也就是“*”
电脑赢返回对应的下标,也就是“#”
平局就返回“Q”,
游戏继续就返回“C”

1.我们知道平局的情况就一种,棋盘满的情况,那我们看代码:

if (1 == is_full(board, ROW, COL))
	{
		return 'Q';
	}

返回1就为满,直接俄返回我们的“Q”;

2.不管玩家赢,还是电脑赢都分为三种情况
(1)判断行三个
在这里插入图片描述
相信大家看到这个图也明白了怎么实现这个功能了吧。给上正确的代码:

int i = 0;
	int j = 0;
	for (i = 0; i < row; i++)//判断横三列
	{
		for (j = 0; j < col; j++)
		{
			if ((j+2<row)&&(board[i][j] == board[i][j + 1]) &&(board[i][j + 1] == board[i][j + 2] )&& board[i][j] != ' ')
			{
				return board[i][j];
			}
		}
	}

(2)判断竖三个
和行三个几乎一样,这里博主就不具体展开了,读者看代码对比第一个去理解

for (j= 0; j < col; j++)
	{
		for (i = 0; i < row; i++)
		{
			if ((i+2<row)&&(board[i][j] == board[i+1][j] )&& (board[i+1][j] == board[i+2][j]) && board[i][j] != ' ')
			{
				return board[i][j];
			}
		}
	}

注:不懂的可以私信博主哦!

(3)判断斜对角线
在这里插入图片描述
我们来看看代码吧:

for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			if ((i + 2 < row)&& (j + 2 < row)&&(board[i][j] == board[i+1][j+1]) &&(board[i+2][j+2] == board[i+1][j+1]) && board[i][j] != ' ')
			{
				return board[i][j];
			}
			if ((i-2>=0)&&(j + 2 < row)&&(board[i][j] == board[i-1][j+1]) &&( board[i-2][j+2] == board[i-1][j+1] )&& board[i][j] != ' ')
			{
				return board[i][j];
			}
		}
	}

如果上面一个都没有返回,那么游戏继续:

return 'C';//游戏继续

至此我们将三子棋游戏,整个功能都讲解完毕了,接下来,我们就需要吧框架搭起来,然后来电泳我们实现的这些函数,我们需要使用模块化来实现。

💕三、游戏框架的搭建

1.每个游戏都有一个菜单让选择,不会直接上面就让你开始玩游戏的,那我们就需要做一个简易的菜单

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

2.这时候我们就需要选择了,我们知道选择就会和分支联系起来,我们有if else语句,和switch语句,在这里我们使用switch语句,还要实现玩一次不过瘾的情况可以多次去玩,我们就需要使用循环,这里我将采用do while循环
让我们来看代码:

void test()
{
	int input = 0;
	do
	{
		menu();
		printf("请选择:");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();//就是我们要实现的游戏函数
			break;
		case 0:
			printf("退出游戏");
			break;
		default:
			printf("输入错误,请重新选择:");
			break;
		}
	} while (input);
}

我们就test();放在主函数里面
int main()
{
test();
return 0;
}
3.那我们游戏功能怎么来凝结在一起呢,我们先要定义一个数组,然后初始化,打印棋盘后在进行游戏,然我们看看带啊吗吧

void game()
{
	int ret = 0;
	srand((unsigned int)time(NULL));//调用随机函数生成器函数,不懂的可以去看我前面的博客
	char board[ROW][COL] = { 0 };//存储数据;
	Initboard(board, ROW, COL);//初始化数据内容;
	Displayboard(board, ROW, COL);//打印棋盘;
	while (1)
	{
		printf("玩家走:\n");
		playerMove(board, ROW, COL);
		system("cls");
		Displayboard(board, ROW, COL);//打印棋盘;
		ret = is_win(board, ROW, COL);//判断是否玩家赢;
		if (ret != 'c')//等于C代表游戏继续,跳过这个判断,执行下一步,不然ret肯定等于“*”,“#”,“Q”其中一个,然后跳出循环,执行下面的输赢判断
		{
			break;
		}
		printf("电脑走:\n");
		system("cls");
		competerMove(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");
	}
}

这样我们就把框架给搭建好了

🎄四、游戏的源代码

🧨 test.c(测试模块)

#include"game.c"
void game()
{
	int ret = 0;
	srand((unsigned int)time(NULL));
	char board[ROW][COL] = { 0 };//存储数据;
	Initboard(board, ROW, COL);//初始化数据内容;
	Displayboard(board, ROW, COL);//打印棋盘;
	while (1)
	{
		printf("玩家走:\n");
		playerMove(board, ROW, COL);
		system("cls");
		Displayboard(board, ROW, COL);//打印棋盘;
		ret = is_win(board, ROW, COL);//判断是否玩家赢;
		if (ret != 'c')
		{
			break;
		}
		printf("电脑走:\n");
		system("cls");
		competerMove(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 menu()
{
	printf("********************\n");
	printf("***1.play  0.exit***\n");
	printf("********************\n");
}
void test()
{
	int input = 0;
	do
	{
		menu();
		printf("请选择:");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出游戏");
			break;
		default:
			printf("输入错误,请重新选择:");
			break;
		}
	} while (input);
}
int main()
{
	test();
	return 0;
}

⛳game.h(声明函数模块)

#define ROW 3
#define COL 3

//#define ROWS ROW
//#define COLS COL
#include<stdio.h>
#include<stdlib.h>
#include<time.h>



void Initboard(char board[][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 competerMove(char board[ROW][COL], int row, int col);
char is_win(char board[ROW][COL], int row, int col);

🐅game.c(函数定义模块)

#include"game.h"
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;
}
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] = ' ';
			}
		}
	}
}
void Displayboard(char board[ROW][COL], int row, int col)
{

	int i = 0;
	int j = 0;
	for(i=1;i<=row;i++)
	{
		printf("  %d ", i);
	}
	printf("\n");
	for (i = 0; i < row; i++)
	{
		printf("%2d",i+1);
		for (j = 0; j < col; j++)
		{
			//打印每一行的数据;
			printf(" %c ", board[i][j]);
			if (j < col - 1)
				printf("|");
		}printf("\n");
		if (i < row - 1)
		{       //打印分割行
			printf("  ");
			for (j = 0; j < col; j++)
			{
				printf("---");
				if (j < col - 1)
					printf("|");
			}
			printf("\n");
		}

	}
	

}
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 && board[x - 1][y - 1] == ' ')
		{
			board[x - 1][y - 1] = '*';
			break;
		}
		else
		{
			printf("输入下标不合法,请重新输入:");
		}
	}
}
void competerMove(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	while (1)
	{
		x = rand() % row;
		y = rand() % col;
		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}
	printf("电脑下棋为(%d,%d)\n", x + 1, y + 1);
}
char is_win(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 ((j+2<row)&&(board[i][j] == board[i][j + 1]) &&(board[i][j + 1] == board[i][j + 2] )&& board[i][j] != ' ')
			{
				return board[i][j];
			}
		}
	}
	for (j= 0; j < col; j++)
	{
		for (i = 0; i < row; i++)
		{
			if ((i+2<row)&&(board[i][j] == board[i+1][j] )&& (board[i+1][j] == board[i+2][j]) && board[i][j] != ' ')
			{
				return board[i][j];
			}
		}
	}
	//判断对角线
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			if ((i + 2 < row)&& (j + 2 < row)&&(board[i][j] == board[i+1][j+1]) &&(board[i+2][j+2] == board[i+1][j+1]) && board[i][j] != ' ')
			{
				return board[i][j];
			}
			if ((i-2>=0)&&(j + 2 < row)&&(board[i][j] == board[i-1][j+1]) &&( board[i-2][j+2] == board[i-1][j+1] )&& board[i][j] != ' ')
			{
				return board[i][j];
			}
		}
	}
	//判断是否为平局
	if (1 == is_full(board, ROW, COL))
	{
		return 'Q';
	}
	return 'c';
}

大家如果不懂为啥要模块话可以看一下这个博客link

🪁五、总结

今天博主的三子棋小游戏终于要完工了,这也算是博主独立写的比较长的代码了,也遇到了好多问题,但也一一克服了,如果读者也想实现这个三子棋小游戏,遇到问题了可以慢慢解决,不要担心,这几天博主的课程也是非常多,这也时抽时间按完成的,如果写的不好的地方,还希望大佬们指点出来,希望我的博客能给读者带来一些收获,那博主也就知足了,那我们下期再见,我将讲解扫雷小游戏,也是关于数组方面的实战。
在这里插入图片描述

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

橘柚!

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

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

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

打赏作者

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

抵扣说明:

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

余额充值