Lesson 7.1 扫雷扩展

本文详细描述了如何实现扫雷游戏的扩展功能,包括标记雷、扩展区域遍历、判断输赢以及修改找雷函数以支持标记和排查操作。通过递归逻辑处理相邻格子,提升游戏体验。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

扫雷扩展

这里主要实现标记雷和一次开一片的功能。原始版请参考Lesson 7 从零开始实现扫雷游戏。本来是想在递归学完之后就实现的,实在太忙拖到了今天。这篇文章一定要结合链接里的文章一起看,否则可能会有很多不明白的地方。

标记地雷

标记是很简单的,按照之前的做法,所有*位置都是未操作过的,需要标记某个位置的时候,只需要把这个位置对应的show数组中的*改成别的符号就可以了。我这里改的是$。同时,如果对一个坐标再次标记的话,将其改回去重新变成*
具体代码如下:

	if (x >= 1 && x <= row && y >= 1 && y <= col)
			{
				if (show[x][y] == '$')
				{
					show[x][y] = '*';
					Displayboard(show, ROW, COL);
				}
				else if (show[x][y] != '*')
				{
					printf("无法标记!\n");
				}
				else
				{
					show[x][y] = '$';
					Displayboard(show, ROW, COL);
				}
			}
			else
			{
				printf("位置错误!\n");
			}

以上只是标记相关的一段代码,等后面写完扩展会给出完整的。

扩展区域

还是先说思路后放代码。
这里的逻辑如下:

  1. 输入的坐标不是雷
  2. 输入坐标的周围没有雷
  3. 这个坐标没有被排查过
    当满足上面的条件时,对这个坐标周围的8个坐标做同样的事情即可。停止的条件就是上述三个条件之一不再满足。排查过的地方为了显示清楚,将show数组中的*改为_(下划线)即可。
    那么代码就可以写了:
void Expand_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
	if (mine[x][y] != '1')//该坐标不是雷
	{
		if (get_mine_count(mine, x, y) == 0)//该坐标周围没有雷
		{
			if (show[x][y] != ' ')//该坐标没有被排查
			{
				show[x][y] = ' ';//标记为排查过
				Expand_mine(mine, show, x - 1, y);
				Expand_mine(mine, show, x - 1, y + 1);
				Expand_mine(mine, show, x - 1, y - 1);
				Expand_mine(mine, show, x, y - 1);
				Expand_mine(mine, show, x, y + 1);
				Expand_mine(mine, show, x + 1, y);
				Expand_mine(mine, show, x + 1, y + 1);
				Expand_mine(mine, show, x + 1, y - 1);
			}
		}
		else
		{
			int count = get_mine_count(mine, x, y);//如果周围有雷,计算数目
			show[x][y] = count + '0';
		}
	}
}

判断输赢

由于在扩展区域的时候,计算输赢比较困难,因此需要对计算输赢的函数改造一下。只需要统计show数组中已经被打开格子的数量就可以了。具体代码如下:

int Cal_win(char show[ROWS][COLS], int row, int col)
{
	int win = 0;
	int i = 0;
	int j = 0;
	for (i = 1; i <= row; i++)
	{
		for (j = 1; j <= col; j++)
		{
			if (show[i][j] == ' ')//判断已经展开
			{
				win++;
			}
			else if (show[i][j]>=49 && show[i][j] <= 56)//判断是字符1~字符9
			{
				win++;
			}
		}
	}
	return win;
}

最后再每次找雷完成的时候,用winrol*col-EASY_COUNT比较,如果相等则说明胜利。

找雷函数改造

有了上面代码,就可以对找雷过程修改了。逻辑是这样的:

  1. 根据用户输入,确定是标记还是排查(使用flag确认)
  2. 根据用户输入的坐标,执行相应的操作
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	char flag = '0';
	char n_line = '0';
	int win = 0;//找到非雷的个数

	while (win < row*col - EASY_COUNT)
	{
		printf("输入 x + 坐标标记地雷,输入 p + 坐标扫雷(x 1 1 或者 p 1 5):>");
		scanf("%c %d %d%c", &flag, &x, &y,&n_line);

		if (flag == 'x')
		{
			if (x >= 1 && x <= row && y >= 1 && y <= col)
			{
				if (show[x][y] == '$')
				{
					show[x][y] = '*';
					Displayboard(show, ROW, COL);
				}
				else if (show[x][y] != '*')
				{
					printf("无法标记!\n");
				}
				else
				{
					show[x][y] = '$';
					Displayboard(show, ROW, COL);
				}
			}
			else
			{
				printf("位置错误!\n");
			}
		}
		else if (flag == 'p')
		{
			if (x >= 1 && x <= row && y >= 1 && y <= col)//坐标合法性
			{
				if (show[x][y] != '*')//重复输入
				{
					printf("重复输入!\n");
				}
				else
				{
					if (mine[x][y] == '1')//是雷
					{
						printf("爆炸了!\n");
						Displayboard(mine, ROW, COL);
						break;
					}
					else//不是雷
					{
						Expand_mine(mine, show, x, y);
						win = Cal_win(show, ROW, COL);//统计已经点开的数量
						Displayboard(show, ROW, COL);
					}
				}
			}
			else
			{
				printf("位置错误!\n");
			}
		}

		if (win == row*col - EASY_COUNT)
		{
			printf("恭喜你,扫雷完成!\n");
			Displayboard(mine, ROW, COL);
		}
	}

}

最终实现

再放一下最终实现的主函数代码吧:

#include "game.h"

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

void game()
{
	char mine[ROWS][COLS] = { 0 };//存放布置好的雷的信息
	char show[ROWS][COLS] = { 0 };//存放排查出的雷的信息
	//初始化数组的内容
	//mine:在没有布置雷的时候都是‘0’
	InitBoard(mine, ROWS, COLS,'0');//想初始化为什么,就传什么
	//show:在没有排查雷的时候都是‘*’
	InitBoard(show, ROWS, COLS,'*');

	//设置雷
	SetMine(mine,ROW,COL);	
	//Displayboard(mine, ROW, COL);
	Displayboard(show, ROW, COL);//只打印9行9列的

	//排查雷
	FindMine(mine, show, ROW, COL);
}


int main()
{
	int input = 0;
	char temp = '0';
	//设置随机数的生产起点
	srand((unsigned int)time(NULL));
	do
	{
		menu();
		printf("请选择:>");
		scanf("%d%c", &input,&temp);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("Exit\n");
			break;
		default:
			printf("选择错误!\n");
			break;
		}
	} while (input);
	return 0;
}

运行效果

扩展效果:
扩展效果
游戏胜利:
游戏胜利
游戏失败:
游戏失败

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值