Can you please review my Minesweeper implementation in Java?
package com.game;
public class Tile {
private boolean hasMine = false;
private boolean revealed = false;
private int mineCount = 0;
public boolean hasMine() {
return hasMine;
}
public void setHasMine(boolean hasMine) {
this.hasMine = hasMine;
}
public boolean isRevealed() {
return revealed;
}
public void setRevealed(boolean revealed) {
this.revealed = revealed;
}
public int getMineCount() {
return mineCount;
}
public void setMineCount(int mineCount) {
this.mineCount = mineCount;
}
}
package com.game;
import java.util.Random;
public class Board {
private Tile[][] tiles;
private int N = 0;
private int totalRevealed = 0;
private static int[][] neighbors = {{-1,-1}, {-1,0}, {-1,1}, {0,-1}, {0,1}, {1, 0}, {1, 1}, {1, -1}};
public void initialize(int n, int m) throws Exception {
this.N = n;
tiles = new Tile[n][n];
// If there are more mines to place than the total tiles, throw an exception
if (m > n*n) {
throw new Exception("Invalid mines.");
}
// Initialize each tile in the grid
for (int i=0; i<n; i++) {
for (int j=0; j<n; j++) {
tiles[i][j] = new Tile();
}
}
placeMines(m); // time to place the mines
}
/*
Randomly places mines.
*/
private void placeMines(int m) {
// Need to generate random row and column values to place the mine
Random rand1 = new Random(), rand2 = new Random();
while (m > 0) {
int i = rand1.nextInt(this.N), j = rand2.nextInt(this.N);
//System.out.println("i: " + i + "| j: " + j);
if (!tiles[i][j].hasMine()) {
tiles[i][j].setHasMine(true);
for (int[] nei : neighbors) {
if (i + nei[0] < 0 || j + nei[1] < 0 || i + nei[0] >= this.N || j + nei[1] >= this.N) continue;
if (!tiles[i+nei[0]][j+nei[1]].hasMine()) {
tiles[i+nei[0]][j+nei[1]].setMineCount(tiles[i+nei[0]][j+nei[1]].getMineCount()+1);
}
}
m--;
}
}
}
public void printBoard() {
for (Tile[] tile : tiles) {
for (Tile t : tile) {
if (t.hasMine() && t.isRevealed()){
System.out.print("\t " + "*");
}else {
if (t.isRevealed()) {
System.out.print("\t " + t.getMineCount());
} else {
System.out.print("\t -");
}
}
}
System.out.println();
}
}
/*
* If clicked on a mine, reveal all the mines and then it's game over.
*
* If revealed all the tiles without stepping on a mine, it's game over too.
*/
public boolean click(int i, int j) {
if (tiles[i][j].isRevealed()) return false;
if (tiles[i][j].hasMine()) {
revealAllMines();
return true;
}
reveal(tiles[i][j], i, j);
return totalRevealed == (this.N * this.N);
}
/*
* Reveals all possible neighbors and their neighbors recursively.
*
*/
private void reveal(Tile curr, int i, int j) {
if (curr.getMineCount() == 0) { // reveal neighboring tiles
curr.setRevealed(true);
totalRevealed++;
for (int[] nei : neighbors) {
if (i + nei[0] < 0 || j + nei[1] < 0 || i + nei[0] >= this.N || j + nei[1] >= this.N) continue;
if (!tiles[i+nei[0]][j+nei[1]].hasMine() && !tiles[i+nei[0]][j+nei[1]].isRevealed()) {
//tiles[i+nei[0]][j+nei[1]].revealed = true;
reveal(tiles[i+nei[0]][j+nei[1]], i+nei[0], j+nei[1]);
}
}
} else {
curr.setRevealed(true);
}
}
private void revealAllMines() {
for (Tile[] tile : tiles) {
for (Tile t : tile) {
if (t.hasMine()) {
t.setRevealed(true);
totalRevealed++;
}
}
}
}
}
package com.game;
import java.util.Scanner;
/*
*
* Implemented Minesweeper game.
*
*/
public class Minesweeper {
public static void main(String[] args) {
Board board = new Board();
try {
Scanner scanner = new Scanner(System.in);
int n = 0, m = 0;
do {
System.out.println("Enter the grid size (less than or equal to 30): ");
n = scanner.nextInt();
System.out.println("Enter the number of mines: ");
m = scanner.nextInt();
} while (n > 30);
board.initialize(n, m);
System.out.println("Initialized board:");
board.printBoard();
boolean gameOver = false;
int row = 0, col = 0;
do {
System.out.println("Row?");
row = scanner.nextInt();
System.out.println("Column?");
col = scanner.nextInt();
if (row == -1 && col == -1) {
System.exit(0);
}
if ((row >= 0 && row < n) && (col >= 0 && col < n)) {
gameOver = board.click(row, col);
if (gameOver) {
System.out.println("\n\nGame Over");
board.printBoard();
System.exit(0);
} else {
System.out.println("\n\n");
board.printBoard();
System.out.println("\n\n");
}
}
} while (!gameOver);
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
Implemented Minesweeper game without a graphical interface.
Steps to run the game:
I have created Minesweeper.java class. Run it and it will ask you to enter the grid size, mines, row and column on every play.
Currently, you cannot create a grid larger than 30 x 30 tiles.
The total mines cannot exceed the total tiles in the grid.
Rules to play:
- Create a board of size n x n tiles.
- Enter the number of mines to place on the board randomly.
- Enter valid row number and column number (0 based index).
- If you step on a mine, it's game over and all the mines are revealed.
- You can win by not stepping on any mine and reveal all the safe tiles.
Please let me know your feedback.
Thanks.