Implementación del juego Buscaminas

¿Recuerdas el viejo Buscaminas? 
Jugamos en un tablero cuadrado y tenemos que hacer clic en el tablero en las celdas que no tienen una mina. Y obviamente no sabemos dónde están las minas. Si se hace clic en una celda donde hay una mina, entonces perdemos; de lo contrario, todavía estamos en el juego. 
Hay tres niveles para este juego- 
 

  1. Principiante  – 9 * 9 Tablero y 10 Minas
  2. Intermedio – 16*16 Tablero y 40 Minas
  3. Avanzado  – Tablero 24 * 24 y 99 Minas

Probabilidad de encontrar una mina – 
 

  • Nivel principiante – 10/81 (0,12)
  • Nivel intermedio – 40/256 (0,15)
  • Nivel avanzado – 99 / 576 (0,17)

El número creciente de fichas eleva la barra de dificultad. Entonces, el nivel de complejidad aumenta a medida que avanzamos a los siguientes niveles.
Puede parecer un juego completamente basado en la suerte (tienes suerte si no pisas ninguna mina durante todo el juego y mala suerte si has pisado una). Pero este no es un juego completo basado en la suerte. En cambio, puedes ganar casi todas las veces si sigues las pistas que te da el juego. 
 

Consejos para ganar el juego

  • Cuando hacemos clic en una celda que tiene minas adyacentes en una o más de las ocho celdas circundantes, podemos saber cuántas celdas adyacentes tienen minas. Entonces podemos hacer algunas conjeturas lógicas para averiguar qué celdas tienen minas.
  • Si hace clic en una celda que no tiene minas adyacentes (en cualquiera de las ocho celdas circundantes), todas las celdas adyacentes se borran automáticamente, lo que nos ahorra tiempo.
  • Entonces podemos ver que no siempre tenemos que hacer clic en todas las celdas que no tienen las minas (número total de celdas – número de minas) para ganar. Si tenemos suerte, podemos ganar en muy poco tiempo haciendo clic en las celdas que no tienen celdas adyacentes que tengan minas.

Implementación

Aquí se dan dos implementaciones del juego: 
 

  1. En la primera implementación, el movimiento del usuario se selecciona aleatoriamente usando la función rand().
  2. En la segunda implementación, el propio usuario selecciona sus movimientos usando la función scanf().

También hay dos tableros : realBoard y myBoard . Jugamos nuestro juego en myBoard y realBoard almacena la ubicación de las minas. A lo largo del juego, realBoard permanece sin cambios, mientras que myBoard ve muchos cambios según el movimiento del usuario.
Podemos elegir cualquier nivel entre – PRINCIPIANTE, INTERMEDIO y AVANZADO. Esto se hace pasando uno de los anteriores en la función: elegir Nivel de dificultad() [Sin embargo, en el juego de entrada del usuario, esta opción se le pregunta al usuario antes de jugar].
Una vez elegido el nivel, el realBoard y myBoardse inicializan en consecuencia y colocamos las minas en el realBoard al azar. También asignamos los movimientos usando la función asignarMoves() antes de jugar el juego [Sin embargo, en el juego ingresado por el usuario, el usuario mismo asigna los movimientos durante todo el juego hasta que finaliza el juego].
Podemos hacer trampa antes de jugar (conociendo las posiciones de las minas) usando la función – cheatMinesweepeer() . En el código se comenta esta función. Entonces, si tiene miedo de perder, descomente esta función y luego ¡juegue! 
Luego, el juego se juega hasta que el usuario gana (cuando el usuario nunca pisa/hace clic en una celda que contiene una mina) o pierde (cuando el usuario pisa/hace clic en una celda que contiene una mina). Esto se representa en un ciclo while(). El ciclo while() termina cuando el usuario gana o pierde.
La función makeMove() dentro del bucle while obtiene un movimiento al azar de los movimientos asignados al azar. [Sin embargo, en el juego de entrada del usuario, esta función le pide al usuario que ingrese su propio movimiento].
También para garantizar que el primer movimiento del usuario sea siempre seguro (porque el usuario puede perder en el primer paso al pisar/hacer clic en una celda que tiene una mina, y esto sería muy injusto), marcamos usando la declaración if – if ( currentMoveIndex == 0)
La línea de vida de este programa es la función recursiva: playMinesweeperUtil()
Esta función devuelve un verdadero si el usuario pisa/hace clic en una mina y, por lo tanto, pierde si pisa/hace clic en una celda segura, entonces obtenemos el recuento de minas que la rodean. esa celda Usamos la función countAdjacentMines() para calcular las minas adyacentes. Dado que puede haber un máximo de 8 celdas circundantes, verificamos las 8 celdas circundantes. 
Si no hay minas adyacentes a esta celda, hacemos clic/pisamos recursivamente en todas las celdas adyacentes seguras (lo que reduce el tiempo de juego). Y si hay al menos una sola mina adyacente a esta celda, ese recuento se muestra en la celda actual. Esto se da como una pista para el jugador para que pueda evitar pisar/hacer clic en las celdas que tienen minas por lógica. 
Además, si hace clic en una celda que no tiene minas adyacentes (en cualquiera de las ocho celdas circundantes), todas las celdas adyacentes se borran automáticamente, lo que nos ahorra tiempo.
Entonces podemos ver que no siempre tenemos que hacer clic en todas las celdas que no tienen las minas (número total de celdas – número de minas) para ganar. Si tenemos suerte, podemos ganar en muy poco tiempo haciendo clic en las celdas que no tienen celdas adyacentes que tengan minas. 
El usuario sigue jugando hasta que pisa/hace clic en una celda que tenga una mina (en este caso el usuario pierde) o si ha hecho clic/piso en todas las celdas seguras (en este caso el usuario gana).
 

CPP

// A C++ Program to Implement and Play Minesweeper
 
#include<bits/stdc++.h>
using namespace std;
 
#define BEGINNER 0
#define INTERMEDIATE 1
#define ADVANCED 2
#define MAXSIDE 25
#define MAXMINES 99
#define MOVESIZE 526 // (25 * 25 - 99)
 
int SIDE ; // side length of the board
int MINES ; // number of mines on the board
 
// A Utility Function to check whether given cell (row, col)
// is a valid cell or not
bool isValid(int row, int col)
{
    // Returns true if row number and column number
    // is in range
    return (row >= 0) && (row < SIDE) &&
           (col >= 0) && (col < SIDE);
}
 
// A Utility Function to check whether given cell (row, col)
// has a mine or not.
bool isMine (int row, int col, char board[][MAXSIDE])
{
    if (board[row][col] == '*')
        return (true);
    else
        return (false);
}
 
// A Function to get the user's move
void makeMove(int *x, int *y)
{
    // Take the input move
    printf("Enter your move, (row, column) -> ");
    scanf("%d %d", x, y);
    return;
}
 
// A Function to print the current gameplay board
void printBoard(char myBoard[][MAXSIDE])
{
    int i, j;
 
    printf ("    ");
 
    for (i=0; i<SIDE; i++)
        printf ("%d ", i);
 
    printf ("\n\n");
 
    for (i=0; i<SIDE; i++)
    {
        printf ("%d   ", i);
 
        for (j=0; j<SIDE; j++)
            printf ("%c ", myBoard[i][j]);
        printf ("\n");
    }
    return;
}
 
// A Function to count the number of
// mines in the adjacent cells
int countAdjacentMines(int row, int col, int mines[][2],
                      char realBoard[][MAXSIDE])
{
 
    int i;
    int count = 0;
 
    /*
        Count all the mines in the 8 adjacent
        cells
 
            N.W   N   N.E
              \   |   /
               \  |  /
            W----Cell----E
                 / | \
               /   |  \
            S.W    S   S.E
 
        Cell-->Current Cell (row, col)
        N -->  North        (row-1, col)
        S -->  South        (row+1, col)
        E -->  East         (row, col+1)
        W -->  West            (row, col-1)
        N.E--> North-East   (row-1, col+1)
        N.W--> North-West   (row-1, col-1)
        S.E--> South-East   (row+1, col+1)
        S.W--> South-West   (row+1, col-1)
    */
 
    //----------- 1st Neighbour (North) ------------
 
        // Only process this cell if this is a valid one
        if (isValid (row-1, col) == true)
        {
               if (isMine (row-1, col, realBoard) == true)
               count++;
        }
 
    //----------- 2nd Neighbour (South) ------------
 
        // Only process this cell if this is a valid one
        if (isValid (row+1, col) == true)
        {
               if (isMine (row+1, col, realBoard) == true)
               count++;
        }
 
    //----------- 3rd Neighbour (East) ------------
 
        // Only process this cell if this is a valid one
        if (isValid (row, col+1) == true)
        {
            if (isMine (row, col+1, realBoard) == true)
               count++;
        }
 
    //----------- 4th Neighbour (West) ------------
 
        // Only process this cell if this is a valid one
        if (isValid (row, col-1) == true)
        {
               if (isMine (row, col-1, realBoard) == true)
               count++;
        }
 
    //----------- 5th Neighbour (North-East) ------------
 
        // Only process this cell if this is a valid one
        if (isValid (row-1, col+1) == true)
        {
            if (isMine (row-1, col+1, realBoard) == true)
               count++;
        }
 
     //----------- 6th Neighbour (North-West) ------------
 
        // Only process this cell if this is a valid one
        if (isValid (row-1, col-1) == true)
        {
             if (isMine (row-1, col-1, realBoard) == true)
               count++;
        }
 
     //----------- 7th Neighbour (South-East) ------------
 
        // Only process this cell if this is a valid one
        if (isValid (row+1, col+1) == true)
        {
               if (isMine (row+1, col+1, realBoard) == true)
               count++;
        }
 
    //----------- 8th Neighbour (South-West) ------------
 
        // Only process this cell if this is a valid one
        if (isValid (row+1, col-1) == true)
        {
            if (isMine (row+1, col-1, realBoard) == true)
               count++;
        }
 
    return (count);
}
 
// A Recursive Function to play the Minesweeper Game
bool playMinesweeperUtil(char myBoard[][MAXSIDE], char realBoard[][MAXSIDE],
            int mines[][2], int row, int col, int *movesLeft)
{
 
    // Base Case of Recursion
    if (myBoard[row][col] != '-')
        return (false);
 
    int i, j;
 
    // You opened a mine
    // You are going to lose
    if (realBoard[row][col] == '*')
    {
        myBoard[row][col]='*';
 
        for (i=0; i<MINES; i++)
            myBoard[mines[i][0]][mines[i][1]]='*';
 
        printBoard (myBoard);
        printf ("\nYou lost!\n");
        return (true) ;
    }
 
    else
     {
        // Calculate the number of adjacent mines and put it
        // on the board
        int count = countAdjacentMines(row, col, mines, realBoard);
        (*movesLeft)--;
 
        myBoard[row][col] = count + '0';
 
        if (!count)
        {
            /*
            Recur for all 8 adjacent cells
 
                N.W   N   N.E
                  \   |   /
                      \  |  /
                W----Cell----E
                     / | \
                   /   |  \
                S.W    S   S.E
 
            Cell-->Current Cell (row, col)
            N -->  North        (row-1, col)
            S -->  South        (row+1, col)
            E -->  East         (row, col+1)
            W -->  West            (row, col-1)
            N.E--> North-East   (row-1, col+1)
            N.W--> North-West   (row-1, col-1)
            S.E--> South-East   (row+1, col+1)
            S.W--> South-West   (row+1, col-1)
            */
 
                //----------- 1st Neighbour (North) ------------
 
            // Only process this cell if this is a valid one
            if (isValid (row-1, col) == true)
            {
                   if (isMine (row-1, col, realBoard) == false)
                   playMinesweeperUtil(myBoard, realBoard, mines, row-1, col, movesLeft);
            }
 
            //----------- 2nd Neighbour (South) ------------
 
            // Only process this cell if this is a valid one
            if (isValid (row+1, col) == true)
            {
                   if (isMine (row+1, col, realBoard) == false)
                    playMinesweeperUtil(myBoard, realBoard, mines, row+1, col, movesLeft);
            }
 
            //----------- 3rd Neighbour (East) ------------
 
            // Only process this cell if this is a valid one
            if (isValid (row, col+1) == true)
            {
                if (isMine (row, col+1, realBoard) == false)
                    playMinesweeperUtil(myBoard, realBoard, mines, row, col+1, movesLeft);
            }
 
            //----------- 4th Neighbour (West) ------------
 
            // Only process this cell if this is a valid one
            if (isValid (row, col-1) == true)
            {
                   if (isMine (row, col-1, realBoard) == false)
                    playMinesweeperUtil(myBoard, realBoard, mines, row, col-1, movesLeft);
            }
 
            //----------- 5th Neighbour (North-East) ------------
 
            // Only process this cell if this is a valid one
            if (isValid (row-1, col+1) == true)
            {
                if (isMine (row-1, col+1, realBoard) == false)
                    playMinesweeperUtil(myBoard, realBoard, mines, row-1, col+1, movesLeft);
            }
 
             //----------- 6th Neighbour (North-West) ------------
 
            // Only process this cell if this is a valid one
            if (isValid (row-1, col-1) == true)
            {
                 if (isMine (row-1, col-1, realBoard) == false)
                    playMinesweeperUtil(myBoard, realBoard, mines, row-1, col-1, movesLeft);
            }
 
             //----------- 7th Neighbour (South-East) ------------
 
            // Only process this cell if this is a valid one
            if (isValid (row+1, col+1) == true)
            {
                 if (isMine (row+1, col+1, realBoard) == false)
                    playMinesweeperUtil(myBoard, realBoard, mines, row+1, col+1, movesLeft);
            }
 
            //----------- 8th Neighbour (South-West) ------------
 
            // Only process this cell if this is a valid one
            if (isValid (row+1, col-1) == true)
            {
                if (isMine (row+1, col-1, realBoard) == false)
                    playMinesweeperUtil(myBoard, realBoard, mines, row+1, col-1, movesLeft);
            }
        }
 
        return (false);
    }
}
 
// A Function to place the mines randomly
// on the board
void placeMines(int mines[][2], char realBoard[][MAXSIDE])
{
    bool mark[MAXSIDE*MAXSIDE];
 
    memset (mark, false, sizeof (mark));
 
    // Continue until all random mines have been created.
    for (int i=0; i<MINES; )
     {
        int random = rand() % (SIDE*SIDE);
        int x = random / SIDE;
        int y = random % SIDE;
 
        // Add the mine if no mine is placed at this
        // position on the board
        if (mark[random] == false)
        {
            // Row Index of the Mine
            mines[i][0]= x;
            // Column Index of the Mine
            mines[i][1] = y;
 
            // Place the mine
            realBoard[mines[i][0]][mines[i][1]] = '*';
            mark[random] = true;
            i++;
        }
    }
 
    return;
}
 
// A Function to initialise the game
void initialise(char realBoard[][MAXSIDE], char myBoard[][MAXSIDE])
{
    // Initiate the random number generator so that
    // the same configuration doesn't arises
    srand(time (NULL));
 
    // Assign all the cells as mine-free
    for (int i=0; i<SIDE; i++)
    {
        for (int j=0; j<SIDE; j++)
        {
            myBoard[i][j] = realBoard[i][j] = '-';
        }
    }
 
    return;
}
 
// A Function to cheat by revealing where the mines are
// placed.
void cheatMinesweeper (char realBoard[][MAXSIDE])
{
    printf ("The mines locations are-\n");
    printBoard (realBoard);
    return;
}
 
// A function to replace the mine from (row, col) and put
// it to a vacant space
void replaceMine (int row, int col, char board[][MAXSIDE])
{
    for (int i=0; i<SIDE; i++)
    {
        for (int j=0; j<SIDE; j++)
            {
                // Find the first location in the board
                // which is not having a mine and put a mine
                // there.
                if (board[i][j] != '*')
                {
                    board[i][j] = '*';
                    board[row][col] = '-';
                    return;
                }
            }
    }
    return;
}
 
// A Function to play Minesweeper game
void playMinesweeper ()
{
    // Initially the game is not over
    bool gameOver = false;
 
    // Actual Board and My Board
    char realBoard[MAXSIDE][MAXSIDE], myBoard[MAXSIDE][MAXSIDE];
 
    int movesLeft = SIDE * SIDE - MINES, x, y;
    int mines[MAXMINES][2]; // stores (x,y) coordinates of all mines.
 
      initialise (realBoard, myBoard);
 
    // Place the Mines randomly
    placeMines (mines, realBoard);
 
     /*
     If you want to cheat and know
     where mines are before playing the game
     then uncomment this part
 
     cheatMinesweeper(realBoard);
     */
 
    // You are in the game until you have not opened a mine
    // So keep playing
 
    int currentMoveIndex = 0;
    while (gameOver == false)
     {
        printf ("Current Status of Board : \n");
        printBoard (myBoard);
        makeMove (&x, &y);
 
        // This is to guarantee that the first move is
        // always safe
        // If it is the first move of the game
        if (currentMoveIndex == 0)
        {
            // If the first move itself is a mine
            // then we remove the mine from that location
            if (isMine (x, y, realBoard) == true)
                replaceMine (x, y, realBoard);
        }
 
        currentMoveIndex ++;
 
        gameOver = playMinesweeperUtil (myBoard, realBoard, mines, x, y, &movesLeft);
 
        if ((gameOver == false) && (movesLeft == 0))
         {
            printf ("\nYou won !\n");
            gameOver = true;
         }
    }
    return;
}
 
// A Function to choose the difficulty level
// of the game
void chooseDifficultyLevel ()
{
    /*
    --> BEGINNER = 9 * 9 Cells and 10 Mines
    --> INTERMEDIATE = 16 * 16 Cells and 40 Mines
    --> ADVANCED = 24 * 24 Cells and 99 Mines
    */
 
    int level;
 
    printf ("Enter the Difficulty Level\n");
    printf ("Press 0 for BEGINNER (9 * 9 Cells and 10 Mines)\n");
    printf ("Press 1 for INTERMEDIATE (16 * 16 Cells and 40 Mines)\n");
    printf ("Press 2 for ADVANCED (24 * 24 Cells and 99 Mines)\n");
 
    scanf ("%d", &level);
 
    if (level == BEGINNER)
    {
        SIDE = 9;
        MINES = 10;
    }
 
    if (level == INTERMEDIATE)
    {
        SIDE = 16;
        MINES = 40;
    }
 
    if (level == ADVANCED)
    {
        SIDE = 24;
        MINES = 99;
    }
 
    return;
}
 
// Driver Program to test above functions
int main()
{
    /* Choose a level between
    --> BEGINNER = 9 * 9 Cells and 10 Mines
    --> INTERMEDIATE = 16 * 16 Cells and 40 Mines
    --> ADVANCED = 24 * 24 Cells and 99 Mines
    */
    chooseDifficultyLevel ();
 
    playMinesweeper ();
 
    return (0);
}

Aporte: 
 

0
1 2
2 3
3 4
4 5

Producción: 
 

Enter the Difficulty Level
Press 0 for BEGINNER (9 * 9 Cells and 10 Mines)
Press 1 for INTERMEDIATE (16 * 16 Cells and 40 Mines)
Press 2 for ADVANCED (24 * 24 Cells and 99 Mines)
Current Status of Board : 
    0 1 2 3 4 5 6 7 8 

0   - - - - - - - - - 
1   - - - - - - - - - 
2   - - - - - - - - - 
3   - - - - - - - - - 
4   - - - - - - - - - 
5   - - - - - - - - - 
6   - - - - - - - - - 
7   - - - - - - - - - 
8   - - - - - - - - - 
Enter your move, (row, column) -> Current Status of Board : 
    0 1 2 3 4 5 6 7 8 

0   - - - - - - - - - 
1   - - 2 - - - - - - 
2   - - - - - - - - - 
3   - - - - - - - - - 
4   - - - - - - - - - 
5   - - - - - - - - - 
6   - - - - - - - - - 
7   - - - - - - - - - 
8   - - - - - - - - - 
Enter your move, (row, column) ->     0 1 2 3 4 5 6 7 8 

0   - - - - - - - * * 
1   - - 2 * - - - - - 
2   - - - * * - - - - 
3   - - - - - - - * - 
4   - - - - - - - - - 
5   - - - - - - - - - 
6   - - * - - - - - - 
7   - - - - * - - * - 
8   - * - - - - - - - 

You lost!

Implementación del programa C cuando la entrada del usuario se elige al azar
 

CPP

// A C++ Program to Implement and Play Minesweeper
// without taking input from user
 
#include<bits/stdc++.h>
using namespace std;
 
#define BEGINNER 0
#define INTERMEDIATE 1
#define ADVANCED 2
#define MAXSIDE 25
#define MAXMINES 99
#define MOVESIZE 526 // (25 * 25 - 99)
 
int SIDE ; // side length of the board
int MINES ; // number of mines on the board
 
// A Utility Function to check whether given cell (row, col)
// is a valid cell or not
bool isValid(int row, int col)
{
    // Returns true if row number and column number
    // is in range
    return (row >= 0) && (row < SIDE) &&
           (col >= 0) && (col < SIDE);
}
 
// A Utility Function to check whether given cell (row, col)
// has a mine or not.
bool isMine (int row, int col, char board[][MAXSIDE])
{
    if (board[row][col] == '*')
        return (true);
    else
        return (false);
}
 
// A Function to get the user's move and print it
// All the moves are assumed to be distinct and valid.
void makeMove (int *x, int *y, int moves[][2], int currentMoveIndex)
{
    *x = moves[currentMoveIndex][0];
    *y = moves[currentMoveIndex][1];
 
    printf ("\nMy move is (%d, %d)\n", *x, *y);
 
    /*
    // The above moves are pre-defined
    // If you want to make your own move
    // then uncomment this section and comment
    // the above section
 
      scanf("%d %d", x, y);
    */
 
    return;
}
 
// A Function to randomly assign moves
void assignMoves (int moves[][2], int movesLeft)
{
    bool mark[MAXSIDE*MAXSIDE];
 
    memset(mark, false, sizeof(mark));
 
    // Continue until all moves are assigned.
    for (int i=0; i<movesLeft; )
     {
        int random = rand() % (SIDE*SIDE);
        int x = random / SIDE;
        int y = random % SIDE;
 
        // Add the mine if no mine is placed at this
        // position on the board
        if (mark[random] == false)
        {
            // Row Index of the Mine
            moves[i][0]= x;
            // Column Index of the Mine
            moves[i][1] = y;
 
            mark[random] = true;
            i++;
        }
    }
 
    return;
}
 
// A Function to print the current gameplay board
void printBoard(char myBoard[][MAXSIDE])
{
    int i,j;
 
    printf ("    ");
 
    for (i=0; i<SIDE; i++)
        printf ("%d ", i);
 
    printf ("\n\n");
 
    for (i=0; i<SIDE; i++)
    {
        printf ("%d   ", i);
 
        for (j=0; j<SIDE; j++)
            printf ("%c ", myBoard[i][j]);
        printf ("\n");
    }
    return;
}
 
// A Function to count the number of
// mines in the adjacent cells
int countAdjacentMines(int row ,int col ,int mines[][2], char realBoard[][MAXSIDE])
{
 
    int i;
    int count = 0;
 
    /*
        Count all the mines in the 8 adjacent
        cells
 
            N.W   N   N.E
              \   |   /
               \  |  /
            W----Cell----E
                 / | \
               /   |  \
            S.W    S   S.E
 
        Cell-->Current Cell (row, col)
        N -->  North        (row-1, col)
        S -->  South        (row+1, col)
        E -->  East         (row, col+1)
        W -->  West            (row, col-1)
        N.E--> North-East   (row-1, col+1)
        N.W--> North-West   (row-1, col-1)
        S.E--> South-East   (row+1, col+1)
        S.W--> South-West   (row+1, col-1)
    */
 
    //----------- 1st Neighbour (North) ------------
 
        // Only process this cell if this is a valid one
        if (isValid (row-1, col) == true)
        {
               if (isMine (row-1, col, realBoard) == true)
               count++;
        }
 
    //----------- 2nd Neighbour (South) ------------
 
        // Only process this cell if this is a valid one
        if (isValid (row+1, col) == true)
        {
               if (isMine (row+1, col, realBoard) == true)
               count++;
        }
 
    //----------- 3rd Neighbour (East) ------------
 
        // Only process this cell if this is a valid one
        if (isValid (row, col+1) == true)
        {
            if (isMine (row, col+1, realBoard) == true)
               count++;
        }
 
    //----------- 4th Neighbour (West) ------------
 
        // Only process this cell if this is a valid one
        if (isValid (row, col-1) == true)
        {
               if (isMine (row, col-1, realBoard) == true)
               count++;
        }
 
    //----------- 5th Neighbour (North-East) ------------
 
        // Only process this cell if this is a valid one
        if (isValid (row-1, col+1) == true)
        {
            if (isMine (row-1, col+1, realBoard) == true)
               count++;
        }
 
     //----------- 6th Neighbour (North-West) ------------
 
        // Only process this cell if this is a valid one
        if (isValid (row-1, col-1) == true)
        {
             if (isMine (row-1, col-1, realBoard) == true)
               count++;
        }
 
     //----------- 7th Neighbour (South-East) ------------
 
        // Only process this cell if this is a valid one
        if (isValid (row+1, col+1) == true)
        {
               if (isMine (row+1, col+1, realBoard) == true)
               count++;
        }
 
    //----------- 8th Neighbour (South-West) ------------
 
        // Only process this cell if this is a valid one
        if (isValid (row+1, col-1) == true)
        {
            if (isMine (row+1, col-1, realBoard) == true)
               count++;
        }
 
    return (count);
}
 
// A Recursive Function to play the Minesweeper Game
bool playMinesweeperUtil(char myBoard[][MAXSIDE], char realBoard[][MAXSIDE],
            int mines[][2], int row, int col, int *movesLeft)
{
 
    // Base Case of Recursion
    if (myBoard[row][col]!='-')
        return (false);
 
    int i, j;
 
    // You opened a mine
    // You are going to lose
    if (realBoard[row][col] == '*')
    {
        myBoard[row][col]='*';
 
        for (i=0; i<MINES; i++)
            myBoard[mines[i][0]][mines[i][1]]='*';
 
        printBoard (myBoard);
        printf ("\nYou lost!\n");
        return (true) ;
    }
 
    else
    {
 
        // Calculate the number of adjacent mines and put it
        // on the board.
        int count = countAdjacentMines(row, col, mines, realBoard);
        (*movesLeft)--;
 
        myBoard[row][col] = count + '0';
 
        if (!count)
        {
            /*
            Recur for all 8 adjacent cells
 
                N.W   N   N.E
                  \   |   /
                      \  |  /
                W----Cell----E
                     / | \
                   /   |  \
                S.W    S   S.E
 
            Cell-->Current Cell (row, col)
            N -->  North        (row-1, col)
            S -->  South        (row+1, col)
            E -->  East         (row, col+1)
            W -->  West            (row, col-1)
            N.E--> North-East   (row-1, col+1)
            N.W--> North-West   (row-1, col-1)
            S.E--> South-East   (row+1, col+1)
            S.W--> South-West   (row+1, col-1)
            */
 
                //----------- 1st Neighbour (North) ------------
 
            // Only process this cell if this is a valid one
            if (isValid (row-1, col) == true)
            {
                   if (isMine (row-1, col, realBoard) == false)
                   playMinesweeperUtil(myBoard, realBoard, mines, row-1, col, movesLeft);
            }
 
            //----------- 2nd Neighbour (South) ------------
 
            // Only process this cell if this is a valid one
            if (isValid (row+1, col) == true)
            {
                   if (isMine (row+1, col, realBoard) == false)
                    playMinesweeperUtil(myBoard, realBoard, mines, row+1, col, movesLeft);
            }
 
            //----------- 3rd Neighbour (East) ------------
 
            // Only process this cell if this is a valid one
            if (isValid (row, col+1) == true)
            {
                if (isMine (row, col+1, realBoard) == false)
                    playMinesweeperUtil(myBoard, realBoard, mines, row, col+1, movesLeft);
            }
 
            //----------- 4th Neighbour (West) ------------
 
            // Only process this cell if this is a valid one
            if (isValid (row, col-1) == true)
            {
                   if (isMine (row, col-1, realBoard) == false)
                    playMinesweeperUtil(myBoard, realBoard, mines, row, col-1, movesLeft);
            }
 
            //----------- 5th Neighbour (North-East) ------------
 
            // Only process this cell if this is a valid one
            if (isValid (row-1, col+1) == true)
            {
                if (isMine (row-1, col+1, realBoard) == false)
                    playMinesweeperUtil(myBoard, realBoard, mines, row-1, col+1, movesLeft);
            }
 
             //----------- 6th Neighbour (North-West) ------------
 
            // Only process this cell if this is a valid one
            if (isValid (row-1, col-1) == true)
            {
                 if (isMine (row-1, col-1, realBoard) == false)
                    playMinesweeperUtil(myBoard, realBoard, mines, row-1, col-1, movesLeft);
            }
 
             //----------- 7th Neighbour (South-East) ------------
 
            // Only process this cell if this is a valid one
            if (isValid (row+1, col+1) == true)
            {
                   if (isMine (row+1, col+1, realBoard) == false)
                    playMinesweeperUtil(myBoard, realBoard, mines, row+1, col+1, movesLeft);
            }
 
            //----------- 8th Neighbour (South-West) ------------
 
            // Only process this cell if this is a valid one
            if (isValid (row+1, col-1) == true)
            {
                if (isMine (row+1, col-1, realBoard) == false)
                    playMinesweeperUtil(myBoard, realBoard, mines, row+1, col-1, movesLeft);
            }
        }
 
        return (false);
    }
}
 
// A Function to place the mines randomly
// on the board
void placeMines(int mines[][2], char realBoard[][MAXSIDE])
{
    bool mark[MAXSIDE*MAXSIDE];
 
    memset (mark, false, sizeof (mark));
 
    // Continue until all random mines have been created.
    for (int i=0; i<MINES; )
     {
        int random = rand() % (SIDE*SIDE);
        int x = random / SIDE;
        int y = random % SIDE;
 
        // Add the mine if no mine is placed at this
        // position on the board
        if (mark[random] == false)
        {
            // Row Index of the Mine
            mines[i][0]= x;
            // Column Index of the Mine
            mines[i][1] = y;
 
            // Place the mine
            realBoard[mines[i][0]][mines[i][1]] = '*';
            mark[random] = true;
            i++;
        }
    }
 
    return;
}
 
// A Function to initialise the game
void initialise (char realBoard[][MAXSIDE], char myBoard[][MAXSIDE])
{
    // Initiate the random number generator so that
    // the same configuration doesn't arises
    srand (time (NULL));
 
    // Assign all the cells as mine-free
    for (int i=0; i<SIDE; i++)
    {
        for (int j=0; j<SIDE; j++)
        {
            myBoard[i][j] = realBoard[i][j] = '-';
        }
    }
 
    return;
}
 
// A Function to cheat by revealing where the mines are
// placed.
void cheatMinesweeper (char realBoard[][MAXSIDE])
{
    printf ("The mines locations are-\n");
    printBoard (realBoard);
    return;
}
 
// A function to replace the mine from (row, col) and put
// it to a vacant space
void replaceMine (int row, int col, char board[][MAXSIDE])
{
    for (int i=0; i<SIDE; i++)
    {
        for (int j=0; j<SIDE; j++)
            {
                // Find the first location in the board
                // which is not having a mine and put a mine
                // there.
                if (board[i][j] != '*')
                {
                    board[i][j] = '*';
                    board[row][col] = '-';
                    return;
                }
            }
    }
    return;
}
 
// A Function to play Minesweeper game
void playMinesweeper ()
{
    // Initially the game is not over
    bool gameOver = false;
 
    // Actual Board and My Board
    char realBoard[MAXSIDE][MAXSIDE], myBoard[MAXSIDE][MAXSIDE];
 
    int movesLeft = SIDE * SIDE - MINES, x, y;
    int mines[MAXMINES][2]; // Stores (x, y) coordinates of all mines.
      int moves[MOVESIZE][2]; // Stores (x, y) coordinates of the moves
 
      // Initialise the Game
      initialise (realBoard, myBoard);
 
    // Place the Mines randomly
    placeMines (mines, realBoard);
 
    // Assign Moves
    // If you want to make your own input move,
    // then the below function should be commented
    assignMoves (moves, movesLeft);
 
    /*
     //If you want to cheat and know
     //where mines are before playing the game
     //then uncomment this part
 
     cheatMinesweeper(realBoard);
    */
 
    // You are in the game until you have not opened a mine
    // So keep playing
 
    int currentMoveIndex = 0;
    while (gameOver == false)
     {
        printf ("Current Status of Board : \n");
        printBoard (myBoard);
 
        makeMove (&x, &y, moves, currentMoveIndex);
 
        // This is to guarantee that the first move is
        // always safe
        // If it is the first move of the game
        if (currentMoveIndex == 0)
        {
            // If the first move itself is a mine
            // then we remove the mine from that location
            if (isMine (x, y, realBoard) == true)
                replaceMine (x, y, realBoard);
        }
 
        currentMoveIndex ++;
 
        gameOver = playMinesweeperUtil (myBoard, realBoard, mines, x, y, &movesLeft);
 
        if ((gameOver == false) && (movesLeft == 0))
         {
            printf ("\nYou won !\n");
            gameOver = true;
         }
    }
 
    return;
}
 
// A Function to choose the difficulty level
// of the game
void chooseDifficultyLevel (int level)
{
    /*
    --> BEGINNER = 9 * 9 Cells and 10 Mines
    --> INTERMEDIATE = 16 * 16 Cells and 40 Mines
    --> ADVANCED = 24 * 24 Cells and 99 Mines
    */
 
    if (level == BEGINNER)
    {
        SIDE = 9;
        MINES = 10;
    }
 
    if (level == INTERMEDIATE)
    {
        SIDE = 16;
        MINES = 40;
    }
 
    if (level == ADVANCED)
    {
        SIDE = 24;
        MINES = 99;
    }
 
    return;
}
 
// Driver Program to test above functions
int main()
{
    /* Choose a level between
    --> BEGINNER = 9 * 9 Cells and 10 Mines
    --> INTERMEDIATE = 16 * 16 Cells and 40 Mines
    --> ADVANCED = 24 * 24 Cells and 99 Mines
    */
    chooseDifficultyLevel (BEGINNER);
 
    playMinesweeper ();
    return (0);
}

Producción: 
 

Current Status of Board : 
    0 1 2 3 4 5 6 7 8 

0   - - - - - - - - - 
1   - - - - - - - - - 
2   - - - - - - - - - 
3   - - - - - - - - - 
4   - - - - - - - - - 
5   - - - - - - - - - 
6   - - - - - - - - - 
7   - - - - - - - - - 
8   - - - - - - - - - 

My move is (4, 7)
Current Status of Board : 
    0 1 2 3 4 5 6 7 8 

0   - - - - - - - - - 
1   - - - - - - - - - 
2   - - - - - - - - - 
3   - - - - - - - - - 
4   - - - - - - - 2 - 
5   - - - - - - - - - 
6   - - - - - - - - - 
7   - - - - - - - - - 
8   - - - - - - - - - 

My move is (3, 7)
Current Status of Board : 
    0 1 2 3 4 5 6 7 8 

0   - - - - - - - - - 
1   - - - - - - - - - 
2   - - - - - - - - - 
3   - - - - - - - 1 - 
4   - - - - - - - 2 - 
5   - - - - - - - - - 
6   - - - - - - - - - 
7   - - - - - - - - - 
8   - - - - - - - - - 

My move is (7, 3)
    0 1 2 3 4 5 6 7 8 

0   - - - - - - - - - 
1   - - - - * - - - - 
2   - - - - * - - - - 
3   - - - - - - - 1 - 
4   - - - * - - * 2 - 
5   - - - - - - - * - 
6   * - * - - - * - - 
7   - - - * * - - - - 
8   - - - - - - - - - 

You lost!

Este artículo es una contribución de Rachit Belwariar . Si le gusta GeeksforGeeks y le gustaría contribuir, también puede escribir un artículo y enviarlo por correo a review-team@geeksforgeeks.org. Vea su artículo que aparece en la página principal de GeeksforGeeks y ayude a otros Geeks.
Escriba comentarios si encuentra algo incorrecto o si desea compartir más información sobre el tema tratado anteriormente.
 

Publicación traducida automáticamente

Artículo escrito por GeeksforGeeks-1 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *