C语言实现简化版扫雷游戏

###简介

扫雷游戏实现的总代码对初学者来说是一个比较大的工程,许多朋友可能会被它的庞大的外观吓住,但是我通过逐步学习,慢慢梳理逻辑,发现它其实并没有看上去那么困难。我是怎样一步一步学会的呢?接下来,我们一起来具体看看。

###整体逻辑

通过试玩网页版小游戏扫雷,我们大致对扫雷游戏的过程有了一个初步认识。在用代码设计扫雷游戏时,我将其整体分为几个过程:

#一是选择游戏进入与否

#二是扫雷游戏各个部分函数的定义以及扫雷游戏的实现,其中细分为扫雷框架的定义,框架内容的初始化,框架如何打印,雷的设置以及最后扫雷游戏的进行

###整个程序要用到的头文件以及宏定义如下,其中的内容需结合下面的解释一起解读。

#include<stdio.h>
#include<stdlib.h>
#include<time.h>

#define row 9
#define col 9
#define rows row+2
#define cols col+2

#define  _COUNT 10//雷的个数,宏定义方便改变个数

void InitBoard(char board[][cols], int rs, int cs, char set);//初始化棋盘

void DisplayBoard(char board[][cols], int r, int c);//打印棋盘

void SetBoard(char board[][cols], int r, int c);//设置雷

void Find(char mine[][cols], char show[][cols], int r, int c);开始扫雷

其中需要提前声明的是row、col分别代表的扫雷框架的行列,它们之所以要加上2是因为我们在扫9*9的框架的边缘时,无法统计这个位置周围的的相关信息,所以我们把它扩展,这样方便游戏的进行,当然我们实际上操作的仍是9*9的框架。如有不解,可结合后续的解释来看。

###设计函数选择游戏进入与否

void test()
{
	int input = 0;
	do
	{
		srand((unsigned)time(NULL));
		menu();
		puts("请选择:");
		scanf("%d",&input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("输入错误,重新输入:\n");
		}
	} while (input);
}
int main()
{
	test();
	return 0;
}

首先定义主函数,再设计选择进入游戏与否的函数,值得注意的是本段代码中srand的所在行的代码是为后续的工作准备的,再此可以先忽略不看,menu()是自己设计的一个菜单;这段代码主要是选择游戏的进入,用到选择语句switch。选择1进入游戏,于是在后面,我们要开始设计game()函数了。

###game函数定义

void game()
{
	char mine[rows][cols] = { 0 };
	char show[rows][cols] = { 0 };

	//初始化棋盘
	InitBoard(mine, rows, cols,'0');
	InitBoard(show, rows, cols,'*');

	//打印棋盘
	//DisplayBoard(mine, row, col);
	DisplayBoard(show, row, col);

	//设置雷
	SetBoard(mine, row, col);
	DisplayBoard(mine, row, col);

	//扫雷
	Find(mine, show, row, col);

}

此段代码中我们定义的game函数,其中内容见代码,接下来我们具体来看这些内容到底是写什么,为什么要写这些代码,这些代码对扫雷游戏起了一些什么作用

#首先是mine和show数组的定义,这两个数组是扫雷的框架的具体化,我们知道的是,当在玩扫雷游戏时,屏幕呈现出来的是一个类似于棋盘的框架,因此我们用二维数组来表示这个框架可以说非常具体化了

#其次是对这两个数组(数组棋盘)的初始化,首先要声明的是,在mine数组里面我们之后是要存放设置雷的,二show数组的棋盘是要呈现给玩家看的,所以我们把mine数组先全部初始化为字符‘0’,之后把雷设置为字符‘1’;把show数组初始化为‘*’,之后我们每扫一次雷,就在show里面把这个位置周围的雷个数算出来并且在show数组上面呈现给玩家看。

#下列是初始化定义的代码以及打印代码的打印以及其运行结果

//初始化
void InitBoard(char board[][cols], int rs, int cs, char set)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < rs; i++)
	{
		for (j = 0; j < cs; j++)
		{
			board[i][j] = set;
		}
	}
}
//打印
void DisplayBoard(char board[][cols], int r, int c)
{
	int i = 0;
	int j = 0;
	for(i=0;i<=r;i++)
	{
		printf("%d ", i);
	}
	printf("\n");
	for (i = 1; i <= r; i++)
	{
		printf("%d ", i);
		for (j = 1; j <=c; j++)
		{
			printf("%c ", board[i][j]);
		}
		putchar('\n');
	}
}

这是目前代码的运行结果,其中set的形参设计是因为mine和show两个数组初始化时字符不同,为避免重复,我们直接使用传参的方式用一个函数就解决了。在这张运行结果中第一个棋盘其实时不能打印的,最后呈现给玩家的只能是show棋盘,在这里只是为了方便结合前面的代码来学习。

#接着是设置雷,我们先看代码

void SetBoard(char board[][cols], int r, int c)
{
	
	int count = _COUNT;
	while (count)
	{
		int x = rand() % 9 + 1;
		int y = rand() % 9 + 1;
		if (board[x][y] == '0')
		{
			board[x][y] = '1';
			count--;
		}
	}
}

具体解读:首先定义count是循环设置雷的次数(雷的个数):接着是x、y的随机生成,在这里我们使用到rand相关知识,这个与前面srand对应起来了,因为棋盘是9*9规格的,所以我们生成9*9的随机值用以对应棋盘上的各个坐标:在选择语句if里面我们将是‘0’的坐标赋值为‘1’,如果第一次以后在赋值时刚好选到了是‘1’的坐标那么if就不会进去,循环次数也不会减少,相应的要设置的雷的个数也不会变化,这时再重新循环,只到选到‘0’的坐标并且依次进行赋值10次后循环结束,雷的设置也完成了,为了进一步理解,下面展示设置完雷的棋盘

#接下来便是扫雷游戏的真正实现了 

void Find(char mine[][cols], char show[][cols], int r, int c)
{
	
	int win = 0;
	win = c * r - _COUNT;
	while (win!= 0) {
		int x, y;
		printf("输入要查找的坐标:");
		scanf("%d%d", &x, &y);
		if (x >= 1 && x <= r && y >= 1 && y <= c)
		{
			if (mine[x][y] == '1')
			{
				printf("你被炸死了\n");
				break;
			}
			if(mine[x][y]=='0')
			{
				int ret = 0;
				ret = mine[x - 1][y - 1] +
					mine[x - 1][y] +
					mine[x - 1][y + 1] +
					mine[x][y - 1] +
					mine[x][y + 1] +
					mine[x + 1][y - 1] +
					mine[x + 1][y] +
					mine[x + 1][y + 1] - 8 * '0';
				show[x][y] = ret + '0';
				DisplayBoard(show, row, col);
				win--;
			}
		}
		else
		{
			printf("坐标输入不合法,请重新输入:\n");
		}
	}
	if (win == 0)
	{
		printf("恭喜你,扫雷完成\n");
		DisplayBoard(mine, row, col);
	}
}

具体解读:先从定义x、y那行看起,先输入你要排查的坐标,如果你通过游戏了,那么你要排查的次数是棋盘的总坐标数减去雷占的坐标数,于是我们看到循环的条件以及条件的设置,便可以理解了;接着是分析排查雷时出现的几种情况:首先是输入坐标是否合理,这是最外层的选择语句的设置原理,如果合理那么进入 合理的部分,若排查了一次雷win就减少一次,那么循环次数就减少一次,如果合法就再循环,循环次数也不会减少(排查次数);合理输入坐标后如果刚好排查到雷,那么游戏就结束了,break;跳出循环;如果排查成功,就要呈现给玩家看这个排查到没有雷的坐标周围有几个雷,在这里,我们使用统计大小的方式来反映,因为周围存放的是字符‘0’或‘1’,我们先将周围八个字符加起来再减去8*‘0’得出的结果就是周围雷的个数(参考ASCLL表),然后再把show棋盘上的相应的坐标赋值这个得到的结果加‘0’,最后呈现给玩家看到的就是一个字数,也就是雷的个数。后面的if是一个顺利完成的结束语,最后打印一次棋盘是为了让玩家玩完游戏后看到雷的位置。

以下是总的运行结果

 本次分享完毕,如有不对,希望能一起讨论。

  • 24
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值