Implementation of Minesweeper Game (original) (raw)

`// C++ Program for Implementation of Minesweeper Game: Input // for coordinates is taken 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); }

class Board {

public: char** board; Board() { board = new char*[MAXSIDE + 1]; for (int i = 0; i <= MAXSIDE; i++) { board[i] = new char[MAXSIDE + 1]; for (int j = 0; j <= MAXSIDE; j++) { board[i][j] = '-'; } } }

// A Utility Function to check whether given cell (row,
// col) has a mine or not.
bool isMine(int row, int col)
{
    if (board[row][col] == '*')
        return (true);
    else
        return (false);
}

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()
{
    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 ", board[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])
{
    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)
    */

    int dx[8] = { -1, -1, -1, 0, 0, 1, 1, 1 };
    int dy[8] = { -1, 0, 1, -1, 1, -1, 0, 1 };

    for (int d = 0; d < 8; d++) {
        int newRow = row + dx[d];
        int newCol = col + dy[d];

        if (isValid(newRow, newCol) == true) {
            if (isMine(newRow, newCol) == true)
                count++;
        }
    }
    return (count);
}

// A Function to place the mines randomly
// on the board
void placeMines(int mines[][2])
{
    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
            board[mines[i][0]][mines[i][1]] = '*';
            mark[random] = true;
            i++;
        }
    }
    return;
}

// A function to replace the mine from (row, col) and
// put it to a vacant space
void replaceMine(int row, int col)
{
    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;
}

}; class Game { public: // A Recursive Function to play the Minesweeper Game bool playMinesweeperUtil(Board& myBoard, Board& realBoard, int mines[][2], int row, int col, int* movesLeft) { // Base Case of Recursion if (myBoard.board[row][col] != '-') return (false);

    int i, j;

    // You opened a mine
    // You are going to lose
    if (realBoard.board[row][col] == '*') {
        myBoard.board[row][col] = '*';
        for (i = 0; i < MINES; i++)
            myBoard.board[mines[i][0]][mines[i][1]]
                = '*';

        myBoard.printBoard();
        printf("\nYou lost!\n");
        return (true);
    }
    else {
        // Calculate the number of adjacent mines and
        // put it on the board
        int count = realBoard.countAdjacentMines(
            row, col, mines);
        (*movesLeft)--;

        myBoard.board[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)
            */

            int dx[8] = { -1, -1, -1, 0, 0, 1, 1, 1 };
            int dy[8] = { -1, 0, 1, -1, 1, -1, 0, 1 };

            for (int d = 0; d < 8; d++) {
                int newRow = row + dx[d];
                int newCol = col + dy[d];

                if (isValid(newRow, newCol) == true) {
                    if (realBoard.isMine(newRow, newCol)
                        == false)
                        playMinesweeperUtil(
                            myBoard, realBoard, mines,
                            newRow, newCol, movesLeft);
                }
            }
        }
        return (false);
    }
}

// A Function to cheat by revealing where the mines are
// placed.
void cheatMinesweeper(Board& realBoard)
{
    printf("The mines locations are-\n");
    realBoard.printBoard();
    return;
}

// A Function to play Minesweeper game
void playMinesweeper(Board& realBoard, Board& myBoard)
{
    // 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];

    // Place the Mines randomly
    realBoard.placeMines(mines);

    //         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

    myBoard.assignMoves(moves, movesLeft);

    int currentMoveIndex = 0;
    while (gameOver == false) {
        printf("Current Status of Board : \n");
        myBoard.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 (realBoard.isMine(x, y) == true)
                realBoard.replaceMine(x, y);
        }

        currentMoveIndex++;

        gameOver = playMinesweeperUtil(
            myBoard, realBoard, mines, x, y,
            &movesLeft);

        if ((gameOver == false) && (movesLeft == 0)) {
            printf("\nYou won !\n");
            gameOver = true;
        }
    }
    return;
}

};

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;
}

}

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 */

Board myBoard, realBoard;

Game* game = new Game();
chooseDifficultyLevel();

game->playMinesweeper(myBoard, realBoard);
return 0;

}

`