[BFS]529. Minesweeper

【记又一次阵亡在“==”上的惨痛经历微笑

题目:

Let's play the minesweeper game (Wikipedia, online game)!

You are given a 2D char matrix representing the game board. 'M' represents an unrevealed mine, 'E' represents an unrevealed empty square, 'B' represents a revealed blank square that has no adjacent (above, below, left, right, and all 4 diagonals) mines, digit ('1' to '8') represents how many mines are adjacent to this revealed square, and finally 'X' represents a revealed mine.

Now given the next click position (row and column indices) among all the unrevealed squares ('M' or 'E'), return the board after revealing this position according to the following rules:

  1. If a mine ('M') is revealed, then the game is over - change it to 'X'.
  2. If an empty square ('E') with no adjacent mines is revealed, then change it to revealed blank ('B') and all of its adjacent unrevealed squares should be revealed recursively.
  3. If an empty square ('E') with at least one adjacent mine is revealed, then change it to a digit ('1' to '8') representing the number of adjacent mines.
  4. Return the board when no more squares will be revealed.

Example 1:

Input: 

[['E', 'E', 'E', 'E', 'E'],
 ['E', 'E', 'M', 'E', 'E'],
 ['E', 'E', 'E', 'E', 'E'],
 ['E', 'E', 'E', 'E', 'E']]

Click : [3,0]

Output: 

[['B', '1', 'E', '1', 'B'],
 ['B', '1', 'M', '1', 'B'],
 ['B', '1', '1', '1', 'B'],
 ['B', 'B', 'B', 'B', 'B']]

Explanation:

题目分析:

1、根据题目,要求是根据给出的矩阵(包含地雷标记M,和未点开标记E)和输入的点击位置,按要求得出点击后的矩阵并返回。

2、对于点击后的显示规则,大概有三类:①如果是雷,直接标记为X并结束;②如果不是雷且周围有雷,那么将这一格标记为周围雷的数量;③如果不是雷且周围也没有雷,那么就标记为B并递归地继续点开周围标记为E的格子。

3、很容易发现这道题的解决是利用递归的方法,且根据递归的条件容易发现所有的B应该都是连通的,不然没法被递归打开。

4、对于此题的解决算法。考虑先检验这个格子的属于2中的哪个类型,即首先检验是否为M,其次检验是否周围有M,如果都不是则为B且开始递归。至于将递归放在最后的原因,是为了避免在某个格子周围有雷的时候仍然要打开其它E的情况。

5、具体在代码实现中有两个问题。①检验顺序。解决方法前面已经介绍了;②边界检测。由于中间的格子和矩阵边界的格子要打开(检测)的格子(如果要打开)情况不同,那么如果利用循环来遍历周围的八个格子,就必须检测行列参数是否越界。

代码实现:

void func(vector<vector<char>>& board, int row, int col){
	if(board[row][col] == 'M') {
		board[row][col] = 'X';
		return;
	}
	else{
		int count = 0;
		bool checkM = 0;
		int i = row - 1;
		int j = col - 1;
		if(i < 0) i = 0;
		if(j < 0) j = 0;
		for(; i <= row + 1; i++){
			if(i == board.size())
				break; 
			for(int j = col - 1; j <= col + 1; j++){
				if(j == board[0].size())
					break;
				if(i == row && j == col)
					continue;
				if(board[i][j] == 'M'){
					checkM = 1;
					count ++;
				}
			}
		}
		if(checkM == 1){
			board[row][col] = count + '0';
			return;
		}
		board[row][col] = 'B';
		int i = row - 1;
		int j = col - 1;
		if(i < 0) i = 0;
		if(j < 0) j = 0;
		for(; i <= row + 1; i++){
			if(i == board.size())
				break; 
			for(int j = col - 1; j <= col + 1; j++){
				if(j == board[0].size())
					break;
				if(i == row && j == col)
					continue;
				if(board[i][j] == 'E')	
					func(board, i, j);
			}
		}
	}
}
class Solution {
public:
    vector<vector<char>> updateBoard(vector<vector<char>>& board, vector<int>& click) {
        func(board, click[0], click[1]);
		return board;
    }
};

总结与经验:

1、在开始编写代码之前一定要对整个题目要求有清晰明确的认识。我在刚开始完成这道题的时候并没有注意到如果某个格子周围有雷它就不会去打开周围没有被打开的格子,这导致我在考虑递归的时候是把标记B和数字的格子统一起来的,这就导致发现了问题后要纠正代码时工作量很大;

2、要学会利用错误的答案分析问题所在。在最后几次提交代码测试的时候发现标记B能正常递归,但是本该标记数字的格子却没有变化,然而结果却显示程序在运行途中是知道这个格子应该被标记数字的(因为程序中设置了bool变量来检测)。但是为什么既然检测出来了却并没有任何操作呢?这个问题困扰了我很久很久很久.....甚至最后我都放弃debug了。好在睡了一觉后爬起来继续看了看代码,突然发现检测出周围有M后对本格子的赋值操作是“==”(本来该是“=”)........呵呵,又是熟悉的情景。






编写一个自动扫雷的工具通常涉及创建一个简单的游戏环境模拟器,并利用搜索算法来解决寻宝的问题。这里是一个基本的概念概述: 首先,你需要安装一些必要的库,如`pygame`用于图形界面,以及数据结构库来存储和操作雷区信息。以下是一个简化的步骤: 1. **设置环境**: - 导入所需的模块:`import pygame`, `random`等。 2. **创建游戏板**: - 定义一个二维数组表示雷区,其中0代表安全区域,其他数字表示有雷的数量。 3. **初始化游戏**: - 创建窗口,设置大小,背景色等。 4. **生成随机雷**: - 随机选择位置放置雷,确保它们不会重叠。 5. **用户交互**: - 设计鼠标点击事件处理函数,检查点击位置是否触雷或揭示周围的地雷。 6. **搜索算法**: - 可能需要使用广度优先搜索(BFS)、A*搜索或其他启发式搜索算法来探索未标记的区域。 7. **标记和显示结果**: - 根据算法的结果更新游戏板,显示已标记的安全区域。 8. **循环和结束条件**: - 游戏持续进行直到玩家找到所有非雷格子或触发雷。可以添加“游戏结束”提示并提供重新开始的功能。 9. **保存和加载游戏状态**: - 如果你想让游戏更复杂,可以考虑保存和加载当前的游戏状态以便暂停或继续。 下面是一段非常基础的代码示例,展示了如何创建一个简单的扫雷游戏框架: ```python import pygame import random # 初始化游戏 pygame.init() screen = pygame.display.set_mode((800, 600)) clock = pygame.time.Clock() class Minesweeper: def __init__(self, width=10, height=10, mines=40): self.board = [[' ' for _ in range(width)] for _ in range(height)] self.mines = mines self.create_mines() self.explored = [[False for _ in range(width)] for _ in range(height)] def create_mines(self): mine_positions = set() while len(mine_positions) < self.mines: x, y = random.randint(0, len(self.board)-1), random.randint(0, len(self.board[0])-1) if (x, y) not in mine_positions: mine_positions.add((x, y)) self.board[x][y] = '*' # ... 其他方法... # 开始游戏循环 game = Minesweeper() running = True while running: for event in pygame.event.get(): if event.type == pygame.QUIT: running = False elif event.type == pygame.MOUSEBUTTONDOWN: # 处理鼠标点击事件 pass screen.fill((0, 0, 0)) # 更新屏幕 game.update() # 更新游戏状态 pygame.display.flip() clock.tick(10) pygame.quit() ``` 这只是一个起点,完整的扫雷工具还需要完善交互、错误处理和其他细节。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值