×

Search anything:

Minesweeper Game in Java

Internship at OpenGenus

Get this book -> Problems on Array: For Interviews and Competitive Programming

In this article, we will develop Minesweeper Game in Java Programming Language. We will analyze the requirements of the game, design a solution and implement it in Java. This is a strong project for SDE portfolio.

We'll discuss:

  • Introduction
  • Game Logic
  • Flow of code
  • Implementation in Java
  • Output
  • Future Improvements
  • Conclusion

Introduction

Minesweeper is a classic puzzle game that has been enjoyed by millions of people all over the world. The objective of the game is to uncover all the cells on the grid without detonating any of the hidden mines. In this blog post, we will be writing a Minesweeper game in Java using a graphical user interface (GUI). The code provided will cover the essential elements of creating a Minesweeper game, including setting up the GUI, implementing the game logic, and enhancing the user experience.

The purpose of this blog post is to provide a step-by-step guide for creating a Minesweeper game in Java. It is suitable for beginner to intermediate level Java programmers who want to learn how to create a game in Java with a GUI. The code provided in this blog post is a starting point for your own Minesweeper game and can be customized to your own specifications.

Game Logic

Here's how the game logic is implemented in this code:

  1. Initialization: The game board is represented by a 10x10 grid of JButton objects stored in a two-dimensional array called buttons. Another two-dimensional array called mines is used to store whether each cell contains a mine or not. The third two-dimensional array, surroundingMines, stores the number of mines surrounding each cell. The variable uncoveredCells is used to keep track of the number of cells that have been uncovered by the player.

  2. Placing Mines: The method placeMines randomly places 10 mines on the game board by generating random indices for the two-dimensional array and marking the corresponding cells as containing a mine.

  3. Counting Surrounding Mines: The method countSurroundingMines uses a nested for loop to iterate through each cell of the game board. If a cell does not contain a mine, the method counts the number of mines in the cells surrounding it and stores that number in the surroundingMines array.

  4. Uncovering Cells: The method uncoverCell is called when the player clicks on a cell. If the cell contains a mine, the player loses the game and the loseGame method is called. If the cell does not contain a mine, the text of the JButton is set to the number of mines surrounding that cell, and the cell is disabled so the player can no longer click on it. If the number of surrounding mines is 0, the uncoverSurroundingCells method is called to uncover any adjacent cells that also do not contain mines. The uncoveredCells variable is incremented every time a cell is uncovered. If all of the cells have been uncovered, the player wins the game and the winGame method is called.

  5. Winning and Losing: The winGame method displays a message to the player indicating that they have won, and the loseGame method displays a message indicating that the player has lost. In both cases, the game is terminated and the program exits.

Flow of Code

The basic flow of code for the Minesweeper game in Java can be described as follows:

  1. Setting up the GUI: First, we import the necessary libraries and create the frame and panels for the game. We then add buttons to the panel and set action listeners for each button.

  2. Initializing the mine locations: Next, we randomly place mines on the grid.

  3. Calculating the number of surrounding mines: For each cell on the grid, we calculate the number of mines surrounding it.

  4. Uncovering cells and checking for win or lose: When a cell is clicked, we uncover it and check if it's a mine. If it's not a mine, we reveal the number of surrounding mines. If it is a mine, the game ends with a loss. If all cells are uncovered without hitting a mine, the game ends with a win.

Implementation in Java

There are two files, named main.java and Minesweeper.java.

main.java

// The main class that contains the main method, the entry point of the program.
public class Main {
    // The main method is the starting point of the program. It creates an instance of the Minesweeper class.
    public static void main(String[] args) {
        // The following line creates an instance of the Minesweeper class.
        new Minesweeper();
    }
}

This is the main class file of the Minesweeper game. The main method is the starting point of the program when it is executed.

The main method calls the constructor of the Minesweeper class, which initializes and sets up the game. The Minesweeper class has the logic for generating the game board, placing the mines, checking the win and lose conditions, etc. The main class acts as a launcher for the game by calling the Minesweeper class.

Minesweeper.java

// Minesweeper class extends JFrame and implements a GUI for the game.
public class Minesweeper extends JFrame {
    // 2D array of JButtons for the game grid
    private JButton[][] buttons;
    // 2D array of booleans to store the presence of mines
    private boolean[][] mines;
    // 2D array of integers to store the number of mines surrounding each cell
    private int[][] surroundingMines;
    // variable to keep track of the number of cells uncovered
    private int uncoveredCells;

    // constructor sets up the GUI and initializes the game state
    public Minesweeper() {
        // sets the title of the window to "Minesweeper"
        setTitle("Minesweeper");
        // exits the program when the user closes the window
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        // sets the layout of the window to a 10x10 grid of cells
        setLayout(new GridLayout(10, 10));

        // initializes the buttons array with JButtons
        buttons = new JButton[10][10];
        // initializes the mines array with false values (no mines placed yet)
        mines = new boolean[10][10];
        // initializes the surroundingMines array with 0 values (no mines counted yet)
        surroundingMines = new int[10][10];
        // sets the initial number of uncovered cells to 0
        uncoveredCells = 0;

        // loops through each cell in the grid and adds a JButton to the window
        for (int i = 0; i < 10; i++) {
            for (int j = 0; j < 10; j++) {
                buttons[i][j] = new JButton();
                // adds a CellClickListener to each JButton to handle user input
                buttons[i][j].addActionListener(new CellClickListener(i, j));
                add(buttons[i][j]);
            }
        }

        // places mines randomly in the grid
        placeMines();
        // counts the number of mines surrounding each cell
        countSurroundingMines();

        // resizes the window to fit the buttons
        pack();
        // makes the window visible
        setVisible(true);
    }

    // places mines randomly in the grid
    private void placeMines() {
        // code to generate random coordinates and place mines goes here
    }

    // counts the number of mines surrounding each cell
    private void countSurroundingMines() {
        // code to count the number of mines surrounding each cell goes here
    }

    // uncovers a cell at the given coordinates
    private void uncoverCell(int i, int j) {
        // code to uncover a cell at (i, j) goes here
    }

    // uncovers all cells surrounding a cell with 0 surrounding mines
    private void uncoverSurroundingCells(int i, int j) {
        // code to uncover surrounding cells goes here
    }

    // displays a message to the user and exits the program if the user has won the game
    private void winGame() {
        // code to check if the user has won the game and display a message goes here
    }

    // The following code will define the winGame method which will be called when the player wins the game
    private void winGame() {
        // Show a message dialog displaying a win message
        // Disable all the buttons to prevent further actions
    }

    // The following code will define the loseGame method which will be called when the player loses the game
    private void loseGame() {
        // Show a message dialog displaying a loss message
        // Disable all the buttons to prevent further actions
        // Show all the mines on the board by uncovering them
    }

    // The following code will define the inner class CellClickListener which implements the ActionListener interface
    private class CellClickListener implements ActionListener {
        // Define the variables to store the row and column of the button that was clicked
        // Add constructor to initialize these variables
        public void actionPerformed(ActionEvent e) {
            // When the button is clicked, get the source of the event
            // Disable the button to prevent it from being clicked again
            // Check if the cell (i, j) has a mine
            // If it has a mine, call the loseGame method
            // If it does not have a mine, call the uncoverCell method
        }
    }
}

It has a class named Minesweeper that extends JFrame and implements the GUI for the game.

The class has several instance variables:

  • buttons: a 2D array of JButtons to represent the game grid.
  • mines: a 2D array of booleans to store the presence of mines.
  • surroundingMines: a 2D array of integers to store the number of mines surrounding each cell.
  • uncoveredCells: a variable to keep track of the number of cells uncovered.

The constructor sets up the GUI and initializes the game state. It sets the title of the window to "Minesweeper", sets the layout of the window to a 10x10 grid of cells, and adds a JButton to each cell. The constructor also places mines randomly in the grid, counts the number of mines surrounding each cell, resizes the window, and makes it visible.

// Method to place mines randomly on the game board
private void placeMines() {
    // Create a Random object to generate random numbers
    Random random = new Random();
    // Keep track of the number of mines placed
    int placedMines = 0;
    // Loop until 10 mines have been placed
    while (placedMines < 10) {
        // Generate random x and y coordinates for a cell on the game board
        int i = random.nextInt(10);
        int j = random.nextInt(10);
        // If the cell at (i, j) does not already have a mine
        if (!mines[i][j]) {
            // Place a mine at (i, j)
            mines[i][j] = true;
            // Increase the count of placed mines
            placedMines++;
        }
    }
}

The placeMines() method is used to randomly place 10 mines in the game grid represented by the mines 2D array. The method uses a Random object to generate random coordinates for the placement of the mines. It uses a while loop to place 10 mines in the grid and uses an if statement to check if a mine is already placed at the randomly generated coordinates. If a mine is not placed, it sets the value of the mines array at that coordinate to true and increments the placedMines counter.

private void countSurroundingMines() {
    // Loop through all cells of the game board
    for (int i = 0; i < 10; i++) {
        for (int j = 0; j < 10; j++) {
            // If the current cell does not contain a mine
            if (!mines[i][j]) {
                int count = 0;
                // Check the cells surrounding the current cell
                // and increment the count if there is a mine
                // Top Cell
                if (i > 0 && mines[i - 1][j]) count++;
                // Bottom Cell
                if (i < 9 && mines[i + 1][j]) count++;
                // Left Cell
                if (j > 0 && mines[i][j - 1]) count++;
                // Right Cell
                if (j < 9 && mines[i][j + 1]) count++;
                // Top Left Diagonal
                if (i > 0 && j > 0 && mines[i - 1][j - 1]) count++;
                // Bottom Right Diagonal
                if (i < 9 && j < 9 && mines[i + 1][j + 1]) count++;
                // Top Right Diagonal
                if (i > 0 && j < 9 && mines[i - 1][j + 1]) count++;
                // Bottom Left Diagonal
                if (i < 9 && j > 0 && mines[i + 1][j - 1]) count++;
                // Store the count in the "surroundingMines" array
                surroundingMines[i][j] = count;
            }
        }
    }
}

The countSurroundingMines() method counts the number of mines surrounding each cell in a 10x10 grid. The grid is represented by the mines 2D array, with cells marked as mines being set to true. The resulting count is stored in the surroundingMines 2D array. The method uses nested for loops to iterate through each cell in the grid and checks the 8 surrounding cells for mines using conditions to make sure it stays within the bounds of the grid. The count is incremented for each surrounding mine found and finally stored in the corresponding cell in the surroundingMines array.

// method to uncover surrounding cells
private void uncoverSurroundingCells(int i, int j) {
    // check if the cell above is within bounds and enabled, and if so, uncover it
    if (i > 0 && buttons[i - 1][j].isEnabled()) uncoverCell(i - 1, j);
    // check if the cell below is within bounds and enabled, and if so, uncover it
    if (i < 9 && buttons[i + 1][j].isEnabled()) uncoverCell(i + 1, j);
    // check if the cell to the left is within bounds and enabled, and if so, uncover it
    if (j > 0 && buttons[i][j - 1].isEnabled()) uncoverCell(i, j - 1);
    // check if the cell to the right is within bounds and enabled, and if so, uncover it
    if (j < 9 && buttons[i][j + 1].isEnabled()) uncoverCell(i, j + 1);
    // check if the top-left cell is within bounds and enabled, and if so, uncover it
    if (i > 0 && j > 0 && buttons[i - 1][j - 1].isEnabled()) uncoverCell(i - 1, j - 1);
    // check if the bottom-right cell is within bounds and enabled, and if so, uncover it
    if (i < 9 && j < 9 && buttons[i + 1][j + 1].isEnabled()) uncoverCell(i + 1, j + 1);
    // check if the top-right cell is within bounds and enabled, and if so, uncover it
    if (i > 0 && j < 9 && buttons[i - 1][j + 1].isEnabled()) uncoverCell(i - 1, j + 1);
    // check if the bottom-left cell is within bounds and enabled, and if so, uncover it
    if (i < 9 && j > 0 && buttons[i + 1][j - 1].isEnabled()) uncoverCell(i + 1, j - 1);
}

The method takes as input the indices (i, j) of a cell in a 2D array of buttons (buttons[][]). It then checks if each of the 8 surrounding cells are within bounds and enabled, and if so, calls the uncoverCell(int i, int j) method on those cells. The code checks for cells above, below, to the left and right, and the diagonals (top-left, bottom-right, top-right, bottom-left).

// method to display "You won!" message and end the game
private void winGame() {
    // show a message dialog with the message "You won!"
    JOptionPane.showMessageDialog(this, "You won!");
    // exit the game with status code 0 (success)
    System.exit(0);
}

This method displays a message dialog with the message "You won!" and then ends the game by calling System.exit(0).

// method to display the minefield and a "You lost." message, and end the game
private void loseGame() {
    // loop through the 2D array of buttons
    for (int i = 0; i < 10; i++) {
        for (int j = 0; j < 10; j++) {
            // if the current cell is a mine, set its text to "*"
            if (mines[i][j]) {
                buttons[i][j].setText("*");
            }
            // disable the current button
            buttons[i][j].setEnabled(false);
        }
    }
    // show a message dialog with the message "You lost."
    JOptionPane.showMessageDialog(this, "You lost.");
    // exit the game with status code 0 (success)
    System.exit(0);
}

This method loops through the 2D array of buttons and does the following for each cell:

  • If the current cell is a mine, sets its text to "*".
  • Disables the current button.
  • After the loop, the method displays a message dialog with the message "You lost." and then ends the game by calling System.exit(0).
// inner class that implements the ActionListener interface to handle button clicks
private class CellClickListener implements ActionListener {
    // instance variables to store the row and column indices of the button
    private int i;
    private int j;

    // constructor to initialize the instance variables
    public CellClickListener(int i, int j) {
        this.i = i;
        this.j = j;
    }

    // method to handle button clicks
    public void actionPerformed(ActionEvent e) {
        // call the uncoverCell method with the row and column indices of the button
        uncoverCell(i, j);
    }
}

CellClickListener is an inner class that implements the ActionListener interface. It contains a constructor to initialize the row and column indices of the button, and an actionPerformed method to handle button clicks. When a button is clicked, the uncoverCell method is called with the row and column indices of the button.

Output

Here, you can see the output of the code:
Screenshot-2023-02-10-004327
After playing the game,
Screenshot-2023-02-10-004408

Future Improvements

Enhancing the User Experience in the Game:

  1. Providing the Option for Customizing the Board Size: Asking the user for their preferred size of the game board would offer them a more personalized gaming experience.
  2. Difficulty Level Selection: Providing options for selecting the difficulty level would give players the flexibility to choose the level that best suits their skill level.
  3. Improving the Graphical User Interface: A better GUI design, with more attractive and user-friendly visuals, would enhance the overall gaming experience.
  4. Adding Sound Effects and Music: Incorporating sound effects and background music to the game would make it more immersive and engaging for the player.
  5. Saving and Loading Game Progress: Enabling players to save and load their progress in the game would allow them to pick up from where they left off and play at their own pace.

Conclusion

In conclusion, creating a Minesweeper game in Java using a graphical user interface is a great way for beginner to intermediate level Java programmers to gain experience in game development. By following the steps outlined in this blog post at OpenGenus, you can build a functional Minesweeper game that can be customized to your own specifications.

Minesweeper Game in Java
Share this