Minesweeper

Medium
1561.

Minesweeper

Minesweeper is a medium coding problem on arrays, depth-first search and matrix, asked in Amazon, Google, Meta and LiveRamp interviews.

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:

  1. If a mine 'M' is clicked, it becomes 'X' and nothing else changes.
  2. 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).
  3. 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.length
  • n == board[i].length
  • 1 <= m, n <= 50
  • board[i][j] is 'M', 'E', 'B', or a digit from '1' to '8'
  • click.length == 2
  • 0 <= click[0] < m
  • 0 <= click[1] < n
  • board[click[0]][click[1]] is 'M' or 'E'
Write your solution here. Running it against the tests needs a free account — what you type comes with you.Sign in to run
/**
 * @param {string[]} board
 * @param {number[]} click
 * @return {string[]}
 */
var updateBoard = function(board, click) {
    // Write your code here
    
};

Sign in to run your own test cases

Sign in

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.

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:

  1. If a mine 'M' is clicked, it becomes 'X' and nothing else changes.
  2. 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).
  3. 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.length
  • n == board[i].length
  • 1 <= m, n <= 50
  • board[i][j] is 'M', 'E', 'B', or a digit from '1' to '8'
  • click.length == 2
  • 0 <= click[0] < m
  • 0 <= click[1] < n
  • board[click[0]][click[1]] is 'M' or 'E'

Hints for Minesweeper

  1. Hint 1

    Handle the mine click first — it changes exactly one square.

  2. Hint 2

    Revealing an empty square only ever spreads from squares that turn into 'B'; a square that shows a digit stops the spread.

  3. 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

  1. If the clicked square is 'M', set it to 'X' and return.
  2. Otherwise start a queue with the clicked square and mark it visited.
  3. Pop a square and count mines among its 8 neighbours. If the count is positive, write the digit and stop expanding from it.
  4. If the count is 0, write 'B' and push every unvisited neighbour that is still 'E'.
  5. 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)