Implementing a Minesweeper Game in Java with BFS Algorithm
Data Structure Design
The core data structure for the game is encapsulated in a global class called Data, wich stores all game-related information as static variables. This design allows for a single game instance to run at a time. The main data fields include:
status: Represents the game state (e.g., running, failed, completed).size: The dimension of the minefield (e.g., 16x16).numOfMine: The number of mines, determined by the selected difficulty.maps: A 2D array indicating whether a cell contains a mine (1) or not (0).visited: A boolean matrix tracking visited cells.nums: Stores the number of adjacent mines for each cell.flags: A boolean matrix for tracking user-placed flags.lastVisitedPoint: Records the last clicked cell to display explosion effects.
Separation of View and Data
The implementation follows a basic separation between UI and game logicc. Each cell (represented by a Block class) has mouse listeners that trigger data updates. After modifying the game state, the view is refreshed separately via repaintBlocks().
Here’s a simplified example of the mouse event handler:
new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (Data.status == Status.RUNNING) {
Block block = (Block) e.getComponent();
int x = block.getXCoord();
int y = block.getYCoord();
if (SwingUtilities.isLeftMouseButton(e)) {
Data.revealCell(x, y);
} else if (SwingUtilities.isRightMouseButton(e)) {
if (!Data.isVisited(x, y)) {
Data.toggleFlag(x, y);
}
}
}
refreshGameBoard();
}
}
Each block overrides the paintComponent() method to render its background image, such as flags, numbers, or default tiles.
Breadth-First Search Implementation
The core logic for revealing cells is based on Breadth-First Search (BFS). When a cell with zero adjacent mines is clicked, the algorithm explores all connected empty cells. Here’s the logic:
public static void revealCell(int x, int y) {
lastVisitedPoint.set(x, y);
if (maps[x][y] == 1) {
status = Status.FAILED;
return;
}
Queue<point> queue = new LinkedList<>();
queue.add(new Point(x, y));
while (!queue.isEmpty()) {
Point current = queue.poll();
visited[current.x][current.y] = true;
if (nums[current.x][current.y] == 0) {
exploreNeighbors(queue, current.x, current.y);
}
}
}
</point>
The exploreNeighbors method checks all 8 surrounding cells and adds unvisited, mine-free cells to the queue for processing.
Win/Loss Conditions
The game ends in failure when a mine is revealed. A win condition is triggered when all mines are correctly flagged. Alternatively, the game could also be won by revealing all safe cells, but this version uses flag-based validation for simplicity.