Skip to content
Related Articles

Related Articles

Minesweeper Solver
  • Last Updated : 09 Mar, 2021

Given a 2D array arr[][] of dimensions N*M, representing a minesweeper matrix, where each cell contains an integer from the range [0, 9], representing the number of mines in itself and all the eight cells adjacent to it, the task is to solve the minesweeper and uncover all the mines in the matrix. Print ‘X’ for the cell containing a mine and ‘_’ for all the other empty cells. If it is not possible to solve the minesweeper, then print “-1”.

Examples:

Input:
arr[][] = {{1, 1, 0, 0, 1, 1, 1},
               {2, 3, 2, 1, 1, 2, 2},
               {3, 5, 3, 2, 1, 2, 2},
               {3, 6, 5, 3, 0, 2, 2},
               {2, 4, 3, 2, 0, 1, 1},
               {2, 3, 3, 2, 1, 2, 1},
               {1, 1, 1, 1, 1, 1, 0}}.
Output:
_ _ _ _ _ _ _ 
x _ _ _ _ x _ 
_ x x _ _ _ x  
x _ x _ _ _ _ 
_ x x _ _ _ x 
_ _ _ _ _ _ _ 
_ x _ _ x _ _

Input:
arr[][] = {{0, 0, 0, 0, 0, 0, 0},
               {0, 0, 0, 0, 0, 1, 1},
               {0, 0, 0, 0, 0, 1, 1},
               {0, 0, 1, 1, 1, 1, 1},
               {0, 0, 2, 2, 2, 0, 0},
               {0, 0, 2, 2, 2, 0, 0},
               {0, 0, 1, 1, 1, 0, 0}}
Output:
_ _ _ _ _ _ _
_ _ _ _ _ _ _
_ _ _ _ _ _ x
_ _ _ _ _ _ _
_ _ _ x _ _ _ 
_ _ _ x _ _ _
_ _ _ _ _ _ _

Input Generation: To solve the given minesweeper matrix arr[][], it must be a valid input i.e., the minesweeper matrix must be solvable. Therefore, the input matrix is generated in generateMineField() function. Follow the below steps to generate the input minesweeper matrix:



  • The inputs for the generation of input are the size of the minefield N and M and also probability P (or density) of the minefield.
  • A probability P is equal to 0 if there are no mines in the minefield and P is equal to 100 if all the cells are mines in the minefield.
  • A random number is chosen for each cell and if the random number is less than P, a mine is assigned to the grid and a boolean array mines[][] is generated.
  • The input to the constraint solver is the status of each grid which counts the mines of itself and the eight cells around it.

Below is the implementation of the above approach:

C++




// C++ program for the above approach
#include <bits/stdc++.h>
using namespace std;
  
// Stores the number of rows
// and columns of the matrix
int N, M;
  
// Stores the final generated input
int arr[100][100];
  
// Direction arrays
int dx[9] = { -1, 0, 1, -1, 0, 1, -1, 0, 1 };
int dy[9] = { 0, 0, 0, -1, -1, -1, 1, 1, 1 };
  
// Function to check if the
// cell location is valid
bool isValid(int x, int y)
{
    // Returns true if valid
    return (x >= 0 && y >= 0
            && x < N && y < M);
}
  
// Function to generate a valid minesweeper
// matrix of size ROW * COL with P being
// the probablity of a cell being a mine
void generateMineField(int ROW, int COL, int P)
{
    // Generates the random
    // number every time
    srand(time(NULL));
  
    int rand_val;
  
    // Stores whether a cell
    // contains a mine or not
    int mines[ROW][COL];
  
    // Iterate through each cell
    // of the matrix mine
    for (int x = 0; x < ROW; x++) {
        for (int y = 0; y < COL; y++) {
            // Generate a random value
            // from the range [0, 100]
            rand_val = rand() % 100;
  
            // If rand_val is less than P
            if (rand_val < P)
  
                // MArk mines[x][y] as True
                mines[x][y] = true;
  
            // Otherwise, mark
            // mines[x][y] as False
            else
                mines[x][y] = false;
        }
    }
  
    cout << "Generated Input:\n";
  
    // Iterate through each cell (x, y)
    for (int x = 0; x < ROW; x++) {
        for (int y = 0; y < COL; y++) {
            arr[x][y] = 0;
  
            // Count the number of mines
            // around the cell (x, y)
            // and store in arr[x][y]
            for (int k = 0; k < 9; k++) {
                // If current adjacent cell is valid
                if (isValid(x + dx[k], y + dy[k])
                    && (mines[x + dx[k]][y + dy[k]]))
                    arr[x][y]++;
            }
  
            // Print the value at
            // the current cell
            cout << arr[x][y] << " ";
        }
        cout << endl;
    }
}
  
// Driver Code
int main()
{
    N = 7, M = 7;
    int P = 20;
  
    // Function call to generate
    // a valid minesweeper matrix
    generateMineField(N, M, 15);
}
Output:
Generated Input:
0 1 1 1 1 1 1 
1 3 3 3 2 2 1 
1 2 2 2 2 2 1 
1 2 2 2 1 1 0 
1 2 1 1 1 1 1 
1 3 2 2 1 1 1 
1 3 2 2 1 1 1

Approach: The given problem can be solved using Backtracking. The idea is to iterate over each cell of a matrix, based on the information available from the neighboring cells, assign a mine to that cell or not. 
Follow the below steps to solve the given problem:

  • Initialize a matrix, say grid[][], and visited[][] to store the resultant grid and keep the track of visited cells while traversing the grid. Initialize all grid values as false.
  • Declare a recursive function solveMineSweeper() to accept arrays arr[][], grid[][], and visited[][] as a parameter.
    • If all the cells are visited and a mine is assigned to the cells satisfying the given input grid[][], then return true for the current recursive call.
    • If all the cells are visited but the solution is not satisfying the input grid[], return false for the current recursive call.
    • If the above two conditions are found to be false, then find an unvisited cell (x, y) and mark (x, y) as visited.
    • If a mine can be assigned to the position (x, y), then perform the following steps:
      • Mark grid[x][y] as true.
      • Decrease the number of mine of the neighboring cells of (x, y) in the matrix arr[][] by 1.
      • Recursively call for solveMineSweeper() with (x, y) having a mine and if it returns true, then a solution exists. Return true for the current recursive call.
      • Otherwise, reset the position (x, y) i.e., mark grid[x][y] as false and increase the number of mines of the neighboring cells of (x, y) in the matrix arr[][] by 1.
    • If the function solveMineSweeper() with (x, y) having no mine, returns true, then it means a solution exists. Return true from the current recursive call.
    • If the recursive call in the above step returns false, that means the solution doesn’t exist. Therefore, return false from the current recursive calls.
  • If the value returned by the function solveMineSweeper(grid, arr, visited) is true, then a solution exists. Print the matrix grid[][] as the required solution. Otherwise, print “-1”.

Below is the implementation of the above approach: 

CPP




// C++ program for the above approach
#include <bits/stdc++.h>
using namespace std;
  
// Stores the number of rows
// and columns in given matrix
int N, M;
  
// Maximum number of rows
// and columns possible
#define MAXM 100
#define MAXN 100
  
// Directional Arrays
int dx[9] = { -1, 0, 1, -1, 0, 1, -1, 0, 1 };
int dy[9] = { 0, 0, 0, -1, -1, -1, 1, 1, 1 };
  
// Function to check if the
// cell (x, y) is valid or not
bool isValid(int x, int y)
{
    return (x >= 0 && y >= 0
            && x < N && y < M);
}
  
// Function to print the matrix grid[][]
void printGrid(bool grid[MAXN][MAXM])
{
    for (int row = 0; row < N; row++) {
        for (int col = 0; col < M; col++) {
            if (grid[row][col])
                cout << "x ";
            else
                cout << "_ ";
        }
        cout << endl;
    }
}
  
// Function to check if the cell (x, y)
// is valid to have a mine or not
bool isSafe(int arr[MAXN][MAXM], int x, int y)
{
  
    // Check if the cell (x, y) is a
    // valid cell or not
    if (!isValid(x, y))
        return false;
  
    // Check if any of the neighbouring cell
    // of (x, y) supports (x, y) to have a mine
    for (int i = 0; i < 9; i++) {
  
        if (isValid(x + dx[i], y + dy[i])
            && (arr[x + dx[i]][y + dy[i]] - 1 < 0))
            return (false);
    }
  
    // If (x, y) is valid to have a mine
    for (int i = 0; i < 9; i++) {
        if (isValid(x + dx[i], y + dy[i]))
  
            // Reduce count of mines in
            // the neighboring cells
            arr[x + dx[i]][y + dy[i]]--;
    }
  
    return true;
}
  
// Function to check if there
// exists any unvisited cell or not
bool findUnvisited(bool visited[MAXN][MAXM],
                   int& x, int& y)
{
    for (x = 0; x < N; x++)
        for (y = 0; y < M; y++)
            if (!visited[x][y])
                return (true);
    return (false);
}
  
// Function to check if all the cells
// are visited or not and the input array
// is satisfied with the mine assignments
bool isDone(int arr[MAXN][MAXM],
            bool visited[MAXN][MAXM])
{
    bool done = true;
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            done
                = done && (arr[i][j] == 0)
                  && visited[i][j];
        }
    }
  
    return (done);
}
  
// Function to solve the minesweeper matrix
bool SolveMinesweeper(bool grid[MAXN][MAXM],
                      int arr[MAXN][MAXM],
                      bool visited[MAXN][MAXM])
{
  
    // Function call to check if each cell
    // is visited and the solved grid is
    // satisfying the given input matrix
    bool done = isDone(arr, visited);
  
    // If the solution exists and
    // and all cells are visited
    if (done)
        return true;
  
    int x, y;
  
    // Function call to check if all
    // the cells are visited or not
    if (!findUnvisited(visited, x, y))
        return false;
  
    // Mark cell (x, y) as visited
    visited[x][y] = true;
  
    // Function call to check if it is
    // safe to assign a mine at (x, y)
    if (isSafe(arr, x, y)) {
  
        // Mark the position with a mine
        grid[x][y] = true;
  
        // Recursive call with (x, y) having a mine
        if (SolveMinesweeper(grid, arr, visited))
  
            // If solution exists, then return true
            return true;
  
        // Reset the position x, y
        grid[x][y] = false;
        for (int i = 0; i < 9; i++) {
            if (isValid(x + dx[i], y + dy[i]))
                arr[x + dx[i]][y + dy[i]]++;
        }
    }
  
    // Recursive call without (x, y) having a mine
    if (SolveMinesweeper(grid, arr, visited))
  
        // If solution exists then return true
        return true;
  
    // Mark the position as unvisited again
    visited[x][y] = false;
  
    // If no solution existx
    return false;
}
  
void minesweeperOperations(int arr[MAXN][MAXN], int N,
                           int M)
{
  
    // Stores the final result
    bool grid[MAXN][MAXM];
  
    // Stores whether the positon
    // (x, y) is visited or not
    bool visited[MAXN][MAXM];
  
    // Initialize grid[][] and
    // visited[][] to false
    memset(grid, false, sizeof(grid));
    memset(visited, false, sizeof(visited));
  
    // If the solution to the input
    // minesweeper matrix exists
    if (SolveMinesweeper(grid, arr, visited)) {
  
        // Function call to print the grid[][]
        printGrid(grid);
    }
  
    // No solution exists
    else
        printf("No solution exists\n");
}
  
// Driver Code
int main()
{
    // Given input
    N = 7;
    M = 7;
    int arr[MAXN][MAXN] = {
        { 1, 1, 0, 0, 1, 1, 1 },
        { 2, 3, 2, 1, 1, 2, 2 },
        { 3, 5, 3, 2, 1, 2, 2 },
        { 3, 6, 5, 3, 0, 2, 2 },
        { 2, 4, 3, 2, 0, 1, 1 },
        { 2, 3, 3, 2, 1, 2, 1 },
        { 1, 1, 1, 1, 1, 1, 0 }
    };
  
    // Function call to perform
    // generate and solve a minesweeper
    minesweeperOperations(arr, N, M);
  
    return 0;
}
Output:
_ _ _ _ _ _ _ 
x _ _ _ _ x _ 
_ x x _ _ _ x 
x _ x _ _ _ _ 
_ x x _ _ _ x 
_ _ _ _ _ _ _ 
_ x _ _ x _ _

Time Complexity: O(2N * M * N * M)
Auxiliary Space: O(N * M)

My Personal Notes arrow_drop_up
Recommended Articles
Page :