扫雷进阶(能够展开一片)

实现目标:

 在之前,已经完成了扫雷的简化版本,在此基础上,这篇博客来进行展开一片的实现,如下图所示:

 如果还不知道如何编写扫雷的小伙伴可以点击以下链接进行查看:

扫雷实现的初级具体代码icon-default.png?t=M85Bhttps://blog.csdn.net/weixin_72883322/article/details/127793890?spm=1001.2014.3001.5501

逻辑推理:

那么,这个展开一片的逻辑是什么呢?

        大致可以这么想,当你显示一个格子时,如果这个格子不是雷,并且其周围8个也没有雷,那么就将这9块格子全部展示出来,然后,再分别判断被展开的8个格子周围的8个是否有雷,如果没有雷,就继续展开其周围的8个格子,讲到这里,应该就很容易判断出想要做到展开一片的功能,就需要用到递归。

先统计周围8个格子的雷数,如果为0展开全部,然后再判断周围8个的8个......以此类推,这里需要注意的是,若一个格子已经展开,就不需要再继续展开了,否则就会出现死递归的现象!!!

我们设计一个open_board()的函数来实现递归操作,根据上面的推理,我们知道判断是否需要展开需要判断这个格子是否已经被展开,并且还要知道雷数,因此两个棋盘都需要作为参数传给函数,并且,由于在设计二维数组时为了便于操作,我们将数组的行和列数都加了2(详情请看扫雷实现简化版的博客),因此我们还应该传入我们想让函数看到的行数和列数,这样才能避免发生错误

 

具体代码:

void open_board(char show[][COLS],char mine[][COLS],int x,int y,int * z,int row,int col)
{
	int count = 0;
	count = mine_num(mine, x, y);
	if (count == 0 && show[x][y] == '*'&&x>=1&&x<=row&&y>=1&&y<=col)
	{
		show[x][y] = ' ';
		//print_board(show, ROW, COL);
		(*z)++;
		open_board(show, mine, x - 1, y - 1,z,row,col);
		open_board(show, mine, x - 1, y,z, row, col);
		open_board(show, mine, x - 1, y+1,z, row, col);
		open_board(show, mine, x , y - 1,z, row, col);
		open_board(show, mine, x , y + 1,z, row, col);
		open_board(show, mine, x + 1, y - 1,z, row, col);
		open_board(show, mine, x + 1, y ,z, row, col);
		open_board(show, mine, x + 1, y + 1,z, row, col);

	}
	else if (count != 0 && show[x][y] == '*' && x >= 1 && x <= row && y >= 1 && y <= col)
	{
		show[x][y] = count + '0';
		(*z)++;
	}

}

在排雷函数中的使用:

open_board(show,mine, i, j,&win,ROW,COL);

为什么要将win的地址传给函数呢?

        我们知道扫雷的游戏获胜规则是总格子数-排除的格子数==雷数,为了让游戏正常结束,递归中每次展开一个格子,就要让win++,这样才能正常统计已经排除的数。

game.c的新代码:

 

#define _CRT_SECURE_NO_WARNINGS 1

#include"game.h"

void init_board(char board[][COLS], int rows, int cols, char c)
{//c为初始化内容的指定,用此技巧可以一个函数完成两个初始化功能
	int i = 0;
	for (i = 0; i < rows; i++)
	{
		int j = 0;
		for (j = 0; j < cols; j++)
			board[i][j] = c;
	}
}

void print_board(char board[][COLS], int row, int col)
{
	int j = 0;
	int i = 0;
	printf("-----------扫雷----------\n");
	for (i = 0; i <= row; i++)
	{
		if (i == 0)
			printf("   ");
		else
			printf("%d ", i);
	}
	//这是为了让游戏可玩度更高,打印出了一个标识行
	printf("\n");
	for (i = 0; i <= row; i++)
	{
		printf("--");
		if (i == 0)
			printf("|");
	}
	printf("\n");
	for (i = 1; i <= row; i++)
	{
		printf("%d |", i);
		for (j = 1; j <= col; j++)
			printf("%c ", board[i][j]);
		printf("\n");
	}
	printf("-----------扫雷----------\n");
}

void set_mine(char board[][COLS], int row, int col)
{
	int count = 0;
	while (count < EASY_PATTERN)
	{
		int i = rand() % row + 1;
		int j = rand() % col + 1;
		if (board[i][j] != '1')
		{
			count++;
			board[i][j] = '1';
		}
	}
}

int mine_num(char board[][COLS], int x, int y)
{
	return board[x - 1][y - 1] + board[x - 1][y] + board[x - 1][y + 1] 
	+ board[x][y - 1] + board[x][y + 1] + board[x + 1][y - 1] 
	+ board[x + 1][y] + board[x + 1][y + 1]-8*'0';
}

void open_board(char show[][COLS],char mine[][COLS],int x,int y,int * z,int row,int col)
{
	int count = 0;
	count = mine_num(mine, x, y);
	if (count == 0 && show[x][y] == '*'&&x>=1&&x<=row&&y>=1&&y<=col)
	{
		show[x][y] = ' ';
		//print_board(show, ROW, COL);
		(*z)++;
		open_board(show, mine, x - 1, y - 1,z,row,col);
		open_board(show, mine, x - 1, y,z, row, col);
		open_board(show, mine, x - 1, y+1,z, row, col);
		open_board(show, mine, x , y - 1,z, row, col);
		open_board(show, mine, x , y + 1,z, row, col);
		open_board(show, mine, x + 1, y - 1,z, row, col);
		open_board(show, mine, x + 1, y ,z, row, col);
		open_board(show, mine, x + 1, y + 1,z, row, col);

	}
	else if (count != 0 && show[x][y] == '*' && x >= 1 && x <= row && y >= 1 && y <= col)
	{
		show[x][y] = count + '0';
		(*z)++;
	}

}

void mine_clear(char mine[][COLS], char show[][COLS], int row, int col)
{
	int i = 0;
	int j = 0;
	int count = 0;
	int win = 0;
	while(win<ROW*COL-EASY_PATTERN)
	{
		print_board(show, ROW, COL);
		//print_board(mine, ROW, COL);
		printf("请输入要排查的坐标:>");
		scanf("%d %d", &i, &j);
		if (i >= 1 && i <= row && j >= 1 && j <= col)
		{
			if (show[i][j] == '*')
			{
				open_board(show,mine, i, j,&win,ROW,COL);
				if (mine[i][j] == '1')
				{
					printf("你被炸死了,真惨!\n");
					Sleep(500);
					break;
				}
			}
			else
			{
				printf("该坐标已经被排查过,请重新输入!\n");
				Sleep(500);
			}
		}
		else
		{
			printf("输入错误,请重新输入!\n");
			Sleep(500);
		}
		system("cls");
	}
	if (win == ROW * COL - EASY_PATTERN)
	{
		printf("你真是个排雷大师呢!\n");
		print_board(mine, ROW, COL);
	}
	else
	{
		printf("真遗憾,下次努力把。\n");
		print_board(mine, ROW, COL);
	}

}

 注意,该博客的扫雷实现运用了模块化编写,想要完成编译还需要上一篇博客的text.c和game.h文件,这两个文件并没有进行修改,这里不再给出,请参考这篇博客:

扫雷实现的初级具体代码icon-default.png?t=M85Bhttps://blog.csdn.net/weixin_72883322/article/details/127793890?spm=1001.2014.3001.5501 

 现在还剩下标记雷和显示剩余雷的功能还没实现啦!!虽然学习任务比较多,但是我还是会努力哒!!

 

 

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

暮雨清秋.L

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

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

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

打赏作者

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

抵扣说明:

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

余额充值