Open-Source Internship opportunity by OpenGenus for programmers. Apply now.
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:
-
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 variableuncoveredCells
is used to keep track of the number of cells that have been uncovered by the player. -
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. -
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 thesurroundingMines
array. -
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 theloseGame
method is called. If the cell does not contain a mine, the text of theJButton
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, theuncoverSurroundingCells
method is called to uncover any adjacent cells that also do not contain mines. TheuncoveredCells
variable is incremented every time a cell is uncovered. If all of the cells have been uncovered, the player wins the game and thewinGame
method is called. -
Winning and Losing: The
winGame
method displays a message to the player indicating that they have won, and theloseGame
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:
-
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.
-
Initializing the mine locations: Next, we randomly place mines on the grid.
-
Calculating the number of surrounding mines: For each cell on the grid, we calculate the number of mines surrounding it.
-
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:
After playing the game,
Future Improvements
Enhancing the User Experience in the Game:
- 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.
- 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.
- Improving the Graphical User Interface: A better GUI design, with more attractive and user-friendly visuals, would enhance the overall gaming experience.
- Adding Sound Effects and Music: Incorporating sound effects and background music to the game would make it more immersive and engaging for the player.
- 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.