渡劫篇:扫雷进阶版,让你重温你的童年的快乐,找回妈妈的味道

前言:

如果是第一次看,可以去看博主的上一篇基础版本的扫雷渡劫篇:用c语言简易实现扫雷游戏,超详细!附图解!包看包会!看完你也能写!✿-CSDN博客⁤

二者是紧密连在一起的~



扫雷拓展

在上一篇中,我们已经完成了简易版的扫雷,但是感觉和我们幼时玩的似乎不太一样哈~

从图中我们可以发现,在我们输入一个坐标的时候,如果当前位置九宫格方位都没有雷,它只会显示出0这个数字,但我们游玩正常的扫雷的时候,倘若该地方无雷,会显示出一篇无雷的区域,就像这样。

那这个是怎么实现的呢?这就需要用到递归的知识,今天采花贼就给大家详细介绍如何实现这种扫雷。

代码实现以及思路

在上一篇的代码中,我们已经实现了可以返会以一个位置为中心,再以九宫格扫描的方式去获取到雷的个数的getminecount函数,如果有雷就返回雷的个数,没有就返回0。

那聪明的宝子肯定能意识到今们的递归函数肯定也要使用我们getminecount函数,这里我们首先先定义一个递归查找函数refindmine函数。

注意:1.为了游戏更具有观赏性,这里博主会将show图没有雷的位置赋值成空格,也就是将0变成空格。

           2.扫描时以当前位置为中心进行九宫格的方式进行扫描

传入参数如下

厉害的小伙伴注意到了我们这里传了一个int* win,这里为了不影响大家的思路,不做解释,往后看便知

1.递归思路

前提:在递归中我们会使用getminecount函数,倘若getminecount函数的返回值是0,也就代表该以该点为中心进行九宫格扫描时没有发现雷,这时候我们就要进行递归探索。

当然在我们进行递归的时候,我们首先要判断递归结束的条件,不然的话,嘿嘿嘿……

递归结束条件

这里我们递归结束的条件有两个

1.当我们的递归的过程中碰到了空格,停止递归

原因:空格的地方代表我们已经扫描过了,没有必要再去扫描。

2.当我们递归的时候扫描出来了雷,停止递归。

原因:这里我们是让每个格子进行递归扫描,在递归的途中我们会调用getminecount函数,去寻找以当前格子位置为中心的九宫格方位是否存在雷,如果存在雷,我们就会返回一个值给当前格子,这个位置也就不再是空格,是有数字的,不符合我们递归进入的条件

知道了这些我们就可以进行代码的编写了。

递归代码

void refindmine(char show[ROWS][COLS], char mine[ROWS][COLS], int row, int col, int x, int y,int* win)
{
	if (x >= 1 && x <= row && y >= 1 && y <= col)//判断边界
	{
		if (show[x][y] == ' ')
		{
			return;//遇到了空格,结束递归
		}
		else if (getminecount(mine, x, y) != 0)//扫描到了雷,结束递归
		{
			show[x][y] = getminecount(mine, x, y) + '0';
			(*win)++;///遇到数字了,加加一次
			return;
		}
		show[x][y] = ' ';//将未扫描到雷的地方赋值成空格
		(*win)++;
		refindmine(show, mine, row, col, x - 1, y - 1,win);//九宫格扫描有八个方向,所以我们进行八次递归
		refindmine(show, mine, row, col, x - 1, y,win);
		refindmine(show, mine, row, col, x - 1, y + 1,win);
		refindmine(show, mine, row, col, x, y - 1,win);
		refindmine(show, mine, row, col, x, y + 1,win);
		refindmine(show, mine, row, col, x + 1, y - 1,win);
		refindmine(show, mine, row, col, x + 1, y,win);
		refindmine(show, mine, row, col, x + 1, y + 1,win);
	}
}

递归效果

如果你在运行的时候出现了问题,请在评论区提出,博主会收集起来,然后去解决,去完善扫雷。

1.判断胜利的思路

注意:之前我们的win代表的是我们每输入一个不是雷的坐标,win就会加加一次,但这次我们使用了递归,这种方法就无法使用。

那我们怎么判断胜利的条件呢?

其实这里与之前一样,同样是win < row * col - mine_count,但是!我们这里的win代表的是我们所有非雷的地方,也就是我们的win的数量等于我们show图中空白格的数量加上我们数字格的数量

这时候就可以解答refindmine函数中为什么传入了int* win的问题了,如图所示

代码实现 

void findmine(char show[ROWS][COLS], char mine[ROWS][COLS], int row, int col)
{
	int win = 0; 
	int x, y = 0;///初始化要排查的坐标
	while (win < row * col - mine_count)
	{
		printf("请输入您要排查的坐标:>");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)///控制排查的位置在图内
		{
			if (mine[x][y] == '1')
			{
				printf("你被炸死了");
				displayboard(mine, ROW, COL);///打印出我们布置雷的图,让玩家失败后知道雷的位置
				break;
			}
			else///该坐标不是雷,所以要统计周围有几个雷
			{
				refindmine(show, mine, ROW, COL, x, y,&win);
				displayboard(show, ROW, COL);//要再次打印出我们的show图,因为我们排查的位置的数字已经发生变化。
				if (win == row * col - mine_count)
				{
					printf("恭喜您扫雷成功");
					break;
				}
			}
		}
		else
		{
			printf("坐标错误,请重新输入\n");
		}
	}
}

注意:这里我们运用了指针的相关知识,通过指针使我们的win能够肆无忌惮飞驰在其他函数中

(偷偷插一嘴,有一说一,指针是真的

这里还有个地方要注意

我们要将win++,写成(*win)++,不然传入的win就没有用了

完整代码

#include"game.h"
void Initboard(char arr[ROWS][COLS], int rows, int cols, char ret)///初始化地图
{
	for (int i = 0; i < rows; i++)
	{
		for (int j = 0; j < cols; j++)
		{
			arr[i][j] = ret;
		}
	}
}
void displayboard(char arr[ROWS][COLS], int row, int col)///打印地图
{
	printf("---------------------------\n");
	for (int m = 0; m <= col; m++)///打印列
	{
		printf("%2d ", m);///这里改成%2d,%2d是按照两个字符对齐
		                  ///原因是当我们在修改ROW和COL的值的时候,可以避免行和列无法对齐方格的情况
	}
	printf("\n");
	for (int i = 1; i <= row; i++)
	{
		printf("%2d ", i);///打印行
		for (int j = 1; j <= col; j++)
		{
			printf("%2c ", arr[i][j]);
		}
		printf("\n");
	}
}

void Setmine(char arr[ROWS][COLS], int row, int col)///放置雷
{
	int count = mine_count;
	while (count)
	{
		int x = rand() % row + 1;
		int y = rand() % col + 1;
		if (arr[x][y] == '0')
		{
			arr[x][y] = '1';
			count--;
		}
	}
}
void findmine(char show[ROWS][COLS], char mine[ROWS][COLS], int row, int col)
{
	int win = 0; 
	int x, y = 0;///初始化要排查的坐标
	while (win < row * col - mine_count)
	{
		printf("请输入您要排查的坐标:>");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)///控制排查的位置在图内
		{
			if (mine[x][y] == '1')
			{
				printf("你被炸死了");
				displayboard(mine, ROW, COL);///打印出我们布置雷的图,让玩家失败后知道雷的位置
				break;
			}
			else///该坐标不是雷,所以要统计周围有几个雷
			{
				refindmine(show, mine, ROW, COL, x, y,&win);
				displayboard(show, ROW, COL);//要再次打印出我们的show图,因为我们排查的位置的数字已经发生变化。
				if (win == row * col - mine_count)
				{
					printf("恭喜您扫雷成功");
					break;
				}
			}
		}
		else
		{
			printf("坐标错误,请重新输入\n");
		}
	}
}
void refindmine(char show[ROWS][COLS], char mine[ROWS][COLS], int row, int col, int x, int y,int* win)
{
	if (x >= 1 && x <= row && y >= 1 && y <= col)//判断边界
	{
		if (show[x][y] == ' ')
		{
			return;//遇到了空格,结束递归
			(*win)++;
		}
		else if (getminecount(mine, x, y) != 0)//扫描到了雷,结束递归
		{
			(*win++);
			show[x][y] = getminecount(mine, x, y) + '0';
			return;
		}
		show[x][y] = ' ';//将未扫描到雷的地方赋值成空格
		(*win)++;
		refindmine(show, mine, row, col, x - 1, y - 1,win);//九宫格扫描有八个方向,所以我们进行八次递归
		refindmine(show, mine, row, col, x - 1, y,win);
		refindmine(show, mine, row, col, x - 1, y + 1,win);
		refindmine(show, mine, row, col, x, y - 1,win);
		refindmine(show, mine, row, col, x, y + 1,win);
		refindmine(show, mine, row, col, x + 1, y - 1,win);
		refindmine(show, mine, row, col, x + 1, y,win);
		refindmine(show, mine, row, col, x + 1, y + 1,win);
	}
}
int getminecount(char mine[ROWS][COLS], int x, int y)
{
	int res = 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];
	res = res - 8 * '0';
	return res;
}

总结

如果大家在运行中出现错误或者建议,请大家在讨论区下面留言,博主会去收集起来,再统一更新。

这里多运用了递归的指针的知识,如果对您有用的话,不妨给博主一个点赞,关注加收藏三连哦~阿里嘎多,美羊羊桑~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值