Minesweeper feels intricate — numbers, cascading reveals, flags. Build it and you find it's a grid, a neighbour count, and one recursive function. This is Day 6 of my GameFromZero series.
Each cell holds four facts
const cell = { mine: false, open: false, flag: false, n: 0 };
n = how many of the 8 neighbours are mines. That number is all the player gets to reason about.
Count neighbours once
After scattering mines randomly, precompute every non-mine cell's n:
let n = 0;
neighbours(r, c, (rr, cc) => { if (cells[rr][cc].mine) n++; });
cell.n = n;
Flood-fill is the whole trick
When you open a cell with zero neighbouring mines, there's nothing dangerous nearby — so auto-open all 8 neighbours, and if any of those are also zero, they cascade. That's why one click can clear half the board. It's recursion:
function open(r, c) {
const cell = cells[r][c];
if (cell.open || cell.flag) return; // base case
cell.open = true;
if (cell.n === 0)
neighbours(r, c, (rr, cc) => open(rr, cc)); // recurse
}
This is the same algorithm behind the paint-bucket tool and maze region-filling.
Flags + win/lose
Right-click toggles a flag (and blocks accidental opens). Click a mine → lose. Win when opened cells = total − mines:
if (cell.mine) gameOver();
if (opened === R * C - M) win();
That's the entire game. Master the state-step-draw loop once and every classic — Snake, Pong, Tetris, 2048, Minesweeper — is an evening each.
▶️ Play it + read the step-by-step breakdown: https://dev48v.infy.uk/game/day6-minesweeper.html
Day 6 of GameFromZero.
Top comments (0)