Detailed explanation of expanding blanks with recursion in minesweeping

Basic ideas explained

Not much to say, first look at the overall effect in the picture above:
Insert picture description here

Count the number of mines around

I use an 11x11 array as the entire map size, and the game interface display uses a 9x9 map size. Why do you want this? The purpose is to prevent cross-border situations when counting the number of mines on the border.

How to count the number of mines around?

This has to mention the method of mine-laying, where the character '1' is used to indicate that there is a mine, and the character '0' is used to indicate that there is no mine. This method of mine-laying is of great benefit in statistics, because characters can be calculated in ASCLL decimal system, and

'1'-'0' = 1;
'0'-'0' = 0;

In this way, you can add up all the eight coordinates at and around the coordinates and then subtract 9 x '0' to calculate the number of 0s around. Note that the value calculated here is a decimal value, and the show array used at the beginning is of character type, and '0' should be added to convert it into a character number.

The following is the function implementation

//统计(x,y)坐标周围雷的个数
int GetMine(char mine[ROWS][COLS], int x, int y)
{
    
    
	//根据ASCLL码表
	//'1'-'0'=1; '0'-'0'=0
	 //   return mine[x - 1][y] +
		//mine[x - 1][y - 1] +
		//mine[x - 1][y + 1]+
		//mine[x][y - 1] +
		//mine[x][y + 1] +
		//mine[x + 1][y - 1] +
		//mine[x + 1][y + 1] +
		//mine[x + 1][y] - 8 * '0';
	int i = 0;
	int j = 0;
	int sum = 0;
	int len = 0;
	for (i = x - 1; i <= x + 1; i++)
	{
    
    
		for (j = y - 1; j <= y + 1; j++)
		{
    
    
			sum += mine[i][j];
			len++;
		}
	}
	return sum - len * '0';
}

9* '0' is not used in the function, but len ​​is counted in the loop. This is to facilitate future expansion of the program.

Realize expansion gap when there is no thunder around

When the count of the number of surrounding mines at the coordinate is 0, check the number of surrounding mines in the eight surrounding locations in turn. If the count of surrounding mines at any location is 0, continue to expand its surroundings, and repeat until the The nearby location is checked.
Insert picture description here
With a general idea, some details need to be added:

1. The checked position, do not need to check repeatedly when expanding
2. The checked coordinate cannot be mine
3. The surrounding coordinate checking the surrounding coordinate is a recursive idea

What is recursion?

The programming technique of a program calling itself is called recursion. Recursion as an algorithm is widely used in programming languages. A process or function has a method of directly or indirectly calling itself in its definition or description. It usually transforms a large and complex problem into a smaller problem similar to the original problem to solve. The recursive strategy only A small amount of programs can describe the repeated calculations required in the process of solving the problem, which greatly reduces the amount of code of the program. The main way of thinking about recursion is: make big things small

Two necessary conditions for recursion

  • There are restrictions. When this restriction is met, the recursion will not continue.
  • After each recursive call, it gets closer and closer to this restriction.

The restriction here is to find all the positions where the number of mines around is 0, and the recursion ends after searching.
In order to avoid repeated inspections, every time a position is found, the original symbol is replaced with a blank. I originally initialized the symbol to display the chessboard as'*', and then replace it. The next time you recurse, first check whether the symbol at its position is' *'.

show[x][y] = ' ' ;

Function implementation

void SetBlank(char show[ROWS][COLS], char mine[ROWS][COLS], int x, int y)
{
    
    
	int count = GetMine(mine, x, y);
	if (count == 0)
	{
    
    
		show[x][y] = ' ';
		if (x - 1 >= 0 && x <= ROW && y >= 0 && y <= COL && show[x - 1][y] == '*')
			SetBlank(show, mine, x - 1, y);
		if (x + 1 >= 0 && x + 1 <= ROW&&y >= 0 && y <= COL && show[x + 1][y] == '*')
			SetBlank(show, mine, x + 1, y);
		if (x >= 0 && x <= ROW && y - 1 >= 0 && y - 1 <= COL && show[x][y - 1] == '*')
			SetBlank(show, mine, x, y - 1);
		if (x >= 0 && x <= ROW && y + 1 >= 0 && y + 1 <= COL && show[x][y + 1] == '*')
			SetBlank(show, mine, x, y + 1);
	}
	else
	{
    
    
		show[x][y] = count + '0';//存放的数字字符
	}
	
}

Code interpretation:

x, y are the coordinates entered by the player. First use the coordinates to calculate the number of mines around it. If it is 0, replace the location symbol '*' with a space' 'to ensure that it is in the 9x9 map, and then check whether the location symbol is '*', if it is, then the x coordinate remains unchanged, the y coordinate -1 recursively, the y coordinate +1 recursively; the y coordinate remains unchanged, the x coordinate -1 recursively, and the x coordinate +1 recursively; so if count= 0, it will check the up, down, left, and right coordinates of the position, and then the up, down, left, and right coordinates will check their respective up, down, left, and right coordinates, and keep updating the count of the surrounding positions, and repeat until count=0 no longer occurs.

Win or lose

Here is an idea. The statistics will finally show the number of'*' on the board. If it is the same as the number of mines, it means that mine clearance is successful and exit mine hunting.

int CountMine(char show[ROWS][COLS], int row, int col)
{
    
    
	int i = 0;
	int j = 0;
	int count = 0;
	for (i = 1; i <= row; i++)
	{
    
    
		for (j = 1; j <= col; j++)
		{
    
    
			if (show[i][j] == '*')
				count++;
		}
	}
	return count;
}

Finally, the full version of the mine finding function is given

void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
    
    
	
	//9*9-10=71不是雷的个数
	while (1)
	{
    
    
		printf("请输入要排查的坐标(两个坐标用空格隔开):->");
		int x = 0;
		int y = 0;
		scanf("%d%d", &x, &y);
		//1.坐标合法性
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
    
    
			if (mine[x][y] == '1')
			{
    
    
				printf("很遗憾,你被炸死了!\n");
				DisplayBoard(mine, row, col);
				break;
			}
			else
			{
    
    
				//2.该坐标处是不是雷?不是雷,统计周围雷的个数
				//3.扩展空白
					SetBlank(show,mine,x,y);
					int count = CountMine(show,row,col);
					if (count == EASY_COUNT)
					{
    
    
						printf("恭喜你,排雷成功!\n");
						DisplayBoard(show, row, col);
						break;
					}
					DisplayBoard(show, row, col);
				}
		}
		else
		{
    
    
			printf("坐标非法,请重新输入!\n");
		}
	}
}

The appearance of the final displayed map is also very important. I will give my display function for your reference.

void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
    
    
	int i = 0;
	int j = 0;
	printf("-------------扫雷游戏---------------\n");
	printf("\n");
	//打印行号
	for (i = 0; i <= row; i++)
	{
    
    
		if (i == 0)
		{
    
    
			printf("   ", i);
		}
		else
		{
    
    
			printf("  %d ", i);
		}
	}
	printf("\n");

	//打印第一行分割符
	for (i = 0; i <= row; i++)
	{
    
    
		if (i == 0)
		{
    
    
			printf("---");
		}
		else if (i == row )
		{
    
    
			printf("|---|-");
		}
		else
		{
    
    
			printf("|---");
		}
	}
	printf("\n");

	//打印棋盘
	for (i = 1; i <= row; i++)
	{
    
    
		
		for (j = 0; j <= col; j++)
		{
    
    
			if (j == 0)
			{
    
    
				printf(" %d ", i);//放列号
			}
		    else if (j == col)
			{
    
    
				printf("| %c |", board[i][j]);
				
			}
			else
			{
    
    
				printf("| %c ", board[i][j]);
			}
		}
		printf("\n");
		//分割符
		for (j = 0; j <=col; j++)
		{
    
    
			if (j == 0)
			{
    
    
				printf("---");
			}
			else if (j == col)
			{
    
    
				printf("|---|-");
			}
			else
			{
    
    
				printf("|---");
			}
		}
		printf("\n");
	}
	printf("\n");
	printf("-------------扫雷游戏---------------\n");
}

The end of this article, a complete analysis of minesweeping, next time, everyone thinks that the writing is good, don't forget to encourage the author to the three companies, welcome mutual attention and exchanges~

Guess you like

Origin blog.csdn.net/weixin_42907822/article/details/114992416