Minesweeper — Solution in Python, Java & C++
Minesweeper solution explained: step-by-step approach, complexity and code in Python, Java, C++ and JavaScript. A medium problem, asked at Amazon and Google.
Minesweeper is a medium coding problem on arrays, depth-first search and matrix, asked in Amazon, Google, Meta and LiveRamp interviews.
- Difficulty: Medium
- Topics: Arrays, Depth-First Search, Matrix, Breadth-First Search
- Asked at: Amazon, Google, Meta, LiveRamp
- Time limit: 2 s
- Memory limit: 256 MB
- Languages: JavaScript, TypeScript, Python, Java, C++, C, C#, Go, Kotlin, Swift, Rust, PHP and Ruby
Problem statement
A Minesweeper board is given as m strings of length n. Each character is one of:
'M'— an unrevealed mine;'E'— an unrevealed empty square;'B'— a revealed blank square with no mines among its (up to 8) neighbours — above, below, left, right and the four diagonals;'1'–'8'— a revealed square showing how many of its neighbours are mines;'X'— a revealed mine.
click = [r, c] is the next click, always on an unrevealed square ('M' or 'E'). Apply these rules and return the resulting board:
- If a mine
'M'is clicked, it becomes'X'and nothing else changes. - If an
'E'with no adjacent mines is revealed, it becomes'B'and every unrevealed'E'neighbour is revealed too, by the same rules (recursively). - If an
'E'with at least one adjacent mine is revealed, it becomes the digit'1'–'8'for that count, and the reveal stops there.
Example 1
Input: board = ["EEEE","EEME","EEEE"], click = [2,0]
Output: ["B1EE","B1ME","B1EE"]
Explanation: The bottom-left corner has no adjacent mines, so it opens up the whole left column; the squares beside the mine stop the spread with a `1`.
Example 2
Input: board = ["EEEE","EEME","EEEE"], click = [1,2]
Output: ["EEEE","EEXE","EEEE"]
Explanation: Clicking the mine ends the game.
Example 3
Input: board = ["EM","EE"], click = [1,0]
Output: ["EM","1E"]
Constraints
m == board.lengthn == board[i].length1 <= m, n <= 50board[i][j] is 'M', 'E', 'B', or a digit from '1' to '8'click.length == 20 <= click[0] < m0 <= click[1] < nboard[click[0]][click[1]] is 'M' or 'E'
Hints for Minesweeper
Hint 1
Handle the mine click first — it changes exactly one square.
Hint 2
Revealing an empty square only ever spreads from squares that turn into
'B'; a square that shows a digit stops the spread.Hint 3
Use a BFS (or DFS) from the click: count the adjacent mines of the current square; write the digit if the count is positive, otherwise write
'B'and enqueue every unrevealed'E'neighbour.
How to solve Minesweeper
The reveal is a flood fill over the 8-neighbour graph that expands only through squares with zero adjacent mines.
Approach
- If the clicked square is
'M', set it to'X'and return. - Otherwise start a queue with the clicked square and mark it visited.
- Pop a square and count mines among its 8 neighbours. If the count is positive, write the digit and stop expanding from it.
- If the count is 0, write
'B'and push every unvisited neighbour that is still'E'. - When the queue is empty, return the board.
Why it works
A 'B' square has no mines around it, so every neighbour is safe and must be revealed — the rule is applied to each in turn. A digit square may border a mine, so the game stops there. The flood fill applies exactly these two rules, and marking visited squares guarantees each is processed once.
Complexity
- Time —
O(m · n) - Space —
O(m · n)
Pitfalls
- Mines are never revealed by the spread — only the clicked mine becomes
'X'. - Neighbours include the four diagonals for both the mine count and the spread.
- A deep recursive DFS can overflow the stack on a 50 × 50 empty board; an explicit queue is safer.
Reference solution
Python
from typing import List
from collections import deque
def updateBoard(board: List[str], click: List[int]) -> List[str]:
m, n = len(board), len(board[0])
g = [list(row) for row in board]
r0, c0 = click
if g[r0][c0] == 'M':
g[r0][c0] = 'X'
return [''.join(row) for row in g]
seen = [[False] * n for _ in range(m)]
seen[r0][c0] = True
q = deque([(r0, c0)])
while q:
r, c = q.popleft()
mines = 0
for dr in (-1, 0, 1):
for dc in (-1, 0, 1):
a, b = r + dr, c + dc
if (dr or dc) and 0 <= a < m and 0 <= b < n and g[a][b] == 'M':
mines += 1
if mines:
g[r][c] = str(mines)
continue
g[r][c] = 'B'
for dr in (-1, 0, 1):
for dc in (-1, 0, 1):
a, b = r + dr, c + dc
if 0 <= a < m and 0 <= b < n and g[a][b] == 'E' and not seen[a][b]:
seen[a][b] = True
q.append((a, b))
return [''.join(row) for row in g]Java
public static String[] updateBoard(String[] board, int[] click) {
int m = board.length, n = board[0].length();
char[][] g = new char[m][];
for (int i = 0; i < m; i++) g[i] = board[i].toCharArray();
int r0 = click[0], c0 = click[1];
if (g[r0][c0] == 'M') {
g[r0][c0] = 'X';
} else {
boolean[][] seen = new boolean[m][n];
ArrayDeque<int[]> q = new ArrayDeque<>();
q.add(new int[]{r0, c0});
seen[r0][c0] = true;
while (!q.isEmpty()) {
int[] cur = q.poll();
int r = cur[0], c = cur[1], mines = 0;
for (int dr = -1; dr <= 1; dr++) for (int dc = -1; dc <= 1; dc++) {
int a = r + dr, b = c + dc;
if ((dr != 0 || dc != 0) && a >= 0 && b >= 0 && a < m && b < n && g[a][b] == 'M') mines++;
}
if (mines > 0) { g[r][c] = (char) ('0' + mines); continue; }
g[r][c] = 'B';
for (int dr = -1; dr <= 1; dr++) for (int dc = -1; dc <= 1; dc++) {
int a = r + dr, b = c + dc;
if (a >= 0 && b >= 0 && a < m && b < n && g[a][b] == 'E' && !seen[a][b]) {
seen[a][b] = true;
q.add(new int[]{a, b});
}
}
}
}
String[] out = new String[m];
for (int i = 0; i < m; i++) out[i] = new String(g[i]);
return out;
}C++
vector<string> updateBoard(vector<string>& board, vector<int>& click) {
vector<string> g = board;
int m = g.size(), n = g[0].size();
int r0 = click[0], c0 = click[1];
if (g[r0][c0] == 'M') { g[r0][c0] = 'X'; return g; }
vector<vector<bool>> seen(m, vector<bool>(n, false));
queue<pair<int, int>> q;
q.push({r0, c0});
seen[r0][c0] = true;
while (!q.empty()) {
int r = q.front().first, c = q.front().second;
q.pop();
int mines = 0;
for (int dr = -1; dr <= 1; dr++) for (int dc = -1; dc <= 1; dc++) {
int a = r + dr, b = c + dc;
if ((dr || dc) && a >= 0 && b >= 0 && a < m && b < n && g[a][b] == 'M') mines++;
}
if (mines > 0) { g[r][c] = (char)('0' + mines); continue; }
g[r][c] = 'B';
for (int dr = -1; dr <= 1; dr++) for (int dc = -1; dc <= 1; dc++) {
int a = r + dr, b = c + dc;
if (a >= 0 && b >= 0 && a < m && b < n && g[a][b] == 'E' && !seen[a][b]) {
seen[a][b] = true;
q.push({a, b});
}
}
}
return g;
}JavaScript
var updateBoard = function(board, click) {
var m = board.length, n = board[0].length;
var g = board.map(function(row) { return row.split(''); });
var r0 = click[0], c0 = click[1];
if (g[r0][c0] === 'M') {
g[r0][c0] = 'X';
return g.map(function(row) { return row.join(''); });
}
var seen = [];
for (var i = 0; i < m; i++) seen.push(new Array(n).fill(false));
seen[r0][c0] = true;
var queue = [[r0, c0]];
for (var h = 0; h < queue.length; h++) {
var r = queue[h][0], c = queue[h][1], mines = 0, dr, dc, a, b;
for (dr = -1; dr <= 1; dr++) for (dc = -1; dc <= 1; dc++) {
a = r + dr; b = c + dc;
if ((dr !== 0 || dc !== 0) && a >= 0 && b >= 0 && a < m && b < n && g[a][b] === 'M') mines++;
}
if (mines > 0) { g[r][c] = String(mines); continue; }
g[r][c] = 'B';
for (dr = -1; dr <= 1; dr++) for (dc = -1; dc <= 1; dc++) {
a = r + dr; b = c + dc;
if (a >= 0 && b >= 0 && a < m && b < n && g[a][b] === 'E' && !seen[a][b]) {
seen[a][b] = true;
queue.push([a, b]);
}
}
}
return g.map(function(row) { return row.join(''); });
};Also on the editorial tab: C, C#, Go, Kotlin, PHP, Ruby, Rust, Swift, TypeScript.
All 1199 arrays problems · the whole catalogue
Learn the technique: Arrays · Depth-First Search (DFS)