Design Minesweeper
OOP design for minesweeper covering grid generation with mine placement, recursive cell revealing with BFS/DFS flood fill, flagging, adjacency counting, and game state management.
The Problem
You are building a puzzle game platform that needs to support the classic Minesweeper game. The current prototype is a single function with a 2D boolean array for mines and a pile of nested if-else blocks for revealing, flagging, and counting neighbors. Every new feature (custom difficulties, first-click safety, chord reveal) means editing that function, and the boundary checks alone account for 40% of the code.
Minesweeper looks deceptively simple, but it tests several core OOP skills: modeling a grid of cells with hidden state, implementing flood fill to auto-reveal safe regions, managing game state transitions, and designing a board generator that guarantees first-click safety. The interviewer wants clean entity separation, an efficient reveal algorithm, and a design that handles follow-up twists without structural changes.
Design the core classes for a Minesweeper game that handles board generation with mine placement, cell revealing with flood fill, flagging, adjacency counting, and game state management.
Requirements
Clarifying Questions
Before jumping into class design, ask questions to turn the vague prompt into a concrete specification. Cover four areas: core actions, error handling, boundaries, and future extensions.
You: "What grid sizes should we support? Classic presets (Beginner 9x9, Intermediate 16x16, Expert 30x16) or fully custom?"
Interviewer: "Start with the three classic presets. But design it so custom dimensions and mine counts are possible."
Good. Define a Difficulty configuration that holds rows, columns, and mine count. The three presets are just predefined instances.
You: "Is the first click always safe? In classic Windows Minesweeper, mines are placed after the first click to guarantee it."
Interviewer: "Yes. The first click must never be a mine. Place mines after the first click, excluding that cell."
This is a critical design constraint. The board cannot be fully generated at construction time. Mine placement happens lazily on the first reveal.
You: "What happens when a player reveals a cell with zero adjacent mines? Does it auto-reveal neighbors recursively?"
Interviewer: "Yes. Revealing a zero-neighbor cell triggers flood fill: recursively reveal all connected cells until you hit cells with non-zero neighbor counts."
That tells you the reveal operation is the most interesting algorithm here: a BFS or DFS flood fill bounded by adjacency counts.
You: "Can players flag cells? Is there a flag counter?"
Interviewer: "Yes. Players can toggle flags on unrevealed cells. Show remaining flag count as total mines minus flags placed."
Simple toggle mechanic. Flagging does not affect win/loss logic directly; it is a player convenience.
You: "What defines a win? All non-mine cells revealed, or all mines flagged?"
Interviewer: "All non-mine cells revealed. Flagging is optional for winning."
Good. The win condition is purely about revealed cell count, not flags. This simplifies the check.
You: "Should we support chord reveal (clicking a number cell where all surrounding mines are flagged to auto-reveal remaining neighbors)?"
Interviewer: "Not in the initial design. Mention it as an extensibility option."
Perfect. Keep the core simple: reveal and flag. Chord reveal is a follow-up extension.
You: "Do we need a timer, scoring, or leaderboard?"
Interviewer: "No. Just core game logic. Timer can be mentioned in extensibility."
You have clarified scope and ruled out unnecessary complexity.
Final Requirements
Functional Requirements:
- A grid of configurable size (rows x columns) with a configurable number of mines
- Three preset difficulties: Beginner (9x9, 10 mines), Intermediate (16x16, 40 mines), Expert (30x16, 99 mines)
- First click is always safe: mines are placed after the first reveal, excluding the clicked cell and its neighbors
- Revealing a mine ends the game (LOST)
- Revealing a cell with zero adjacent mines triggers flood fill, auto-revealing all connected safe cells
- Revealing a cell with non-zero adjacent mines shows the count and stops
- Players can toggle flags on unrevealed cells; remaining flag count = total mines minus flags placed
- Game is won when all non-mine cells are revealed
Non-Functional Requirements:
- Extensible for new board shapes and difficulty presets without modifying core classes
- Flood fill must handle large boards (30x16 = 480 cells) efficiently, no stack overflow
- Clean separation between game rules and board generation
Out of Scope:
- UI rendering
- Timer and scoring
- Chord reveal (extensibility section)
- Persistence and leaderboards
- Multiplayer
Example Inputs and Outputs
Scenario 1: First Click Reveal (Safe)
- Input: New Beginner game (9x9, 10 mines). Player reveals cell (4, 4).
- Expected: Mines are placed (excluding cell (4,4) and its 8 neighbors). Cell (4,4) shows its adjacency count. If count is 0, flood fill expands outward, revealing all connected zero-count cells and their non-zero borders.
- Why: validates first-click safety and flood fill
Scenario 2: Revealing a Mine (Game Over)
- Input: Player reveals cell (2, 3), which contains a mine.
- Expected: Game state transitions to LOST. All mines are revealed on the board.
- Why: validates game-over detection and state transition
Scenario 3: Winning the Game
- Input: Player reveals the last non-mine cell on the board.
- Expected: Game state transitions to WON. Remaining mines are auto-flagged.
- Why: validates win condition check after every reveal
Try It Yourself
Try it yourself
Before reading the solution, spend 15-20 minutes sketching your own class diagram and identifying the core entities. Focus on the Cell class (what state does each cell need?) and the reveal algorithm (how does flood fill know when to stop?). Compare your approach with the walkthrough below.
Step 1: Identify Core Entities
Start by asking: what are the main "things" in this problem? Look for nouns in your requirements: game, board, cell, mine, flag, difficulty. Some of these are standalone classes; others are just attributes.
A common mistake is putting all logic in a single Board class. The board owns the grid, but the game orchestrates state transitions and delegates to the board for spatial operations. Another mistake is making Cell too thin (just a boolean) or too fat (responsible for flood fill). Good design gives each class a single, clear job.
| Entity | Responsibility | Key attributes |
|---|---|---|
| Game | Orchestrator. Manages game state, delegates reveal/flag to Board, checks win/loss. | board, gameState, mineCount, flagCount |
| Board | The grid. Owns cells, handles mine placement, adjacency calculation, and flood fill. | cells[][], rows, cols |
| Cell | A single tile. Knows its own state (revealed, flagged, mined) and adjacency count. | isMine, isRevealed, isFlagged, adjacentMineCount, row, col |
| Difficulty | Configuration holder. Preset or custom rows, columns, mine count. | rows, cols, mineCount |
| GameState | Enum tracking the current phase of the game. | NOT_STARTED, IN_PROGRESS, WON, LOST |
Notice that Difficulty is a simple record, not a class with behavior. It exists so the Game constructor takes a single configuration object rather than three separate integers. GameState is an enum because the game has exactly four discrete phases with no shared behavior.
Step 2: Define Relationships and Class Design
Class Diagram
Class Interface Derivation
Game (The Orchestrator)
The Game class owns the Board and manages state transitions. It does not know how flood fill works or where mines are placed; it delegates those to the Board.
Deriving state from requirements:
| Requirement | What Game must track |
|---|---|
| "First click is always safe" | Whether this is the first reveal (triggers mine placement) |
| "Revealing a mine ends the game" | The current game state (NOT_STARTED, IN_PROGRESS, WON, LOST) |
| "Remaining flag count = mines minus flags" | Total mine count and current flag count |
| "All non-mine cells revealed = win" | Derived from Board: count of revealed non-mine cells |
Deriving methods from needs:
| Need from requirements | Method |
|---|---|
| "Player reveals a cell" | reveal(row, col): GameState |
| "Player toggles a flag" | toggleFlag(row, col): void |
| "Show remaining mines" | getRemainingMines(): int |
| "Check game state" | getGameState(): GameState |
Board (The Grid)
The Board owns the 2D cell array and handles all spatial operations: mine placement, adjacency calculation, and flood fill. It does not know about game state or win conditions.
Deriving state from requirements:
Continue Reading with Premium
Unlock this article and every other in-depth system design guide on the platform with NotesFromSDE Premium.