In object-oriented programming (OOP), maximizing API use streamlines development, leading to simpler and more concise code. This clarity not only improves readability but also eases debugging. Leveraging an API effectively in OOP thus ensures a blend of simplicity, efficiency and maintainability in software development.
This demo (partially) implements the minesweeper video game using p5-v2 and the Quadrille API with a four-layer strategy. Each layer is one quadrille with a single responsibility:
mines— the bombs.counts— the numbers next to bombs.cover— a two-tone internal layer (red over filled cells, green over empty cells) that distinguishes the two click zones and drives flood fill.mask— the uniformly magenta layer the player actually sees, derived fromcover.
As gameplay progresses, clicking on cells uncovers them by clearing either individual or connected cells from cover; mask is re-derived from cover after each click.
(mouse click to play; press any key to init)
Code
let mines, counts, cover, mask;
let size = 20;
let n = size * 2;
function init() {
// Layer 1: mines
mines = createQuadrille(size, size, n, '💣');
// Layer 2: counts (neighbor counts on empty cells of `mines`)
counts = createQuadrille(size, size);
mines.visit(({ row, col }) => {
const order = mines.ring(row, col).order;
if (order > 0) counts.fill(row, col, order.toString());
}, ({ value }) => value === null);
// Layer 3: cover — merge mines+counts, then recolor
cover = Quadrille.or(mines, counts);
cover.replace(color('red')).fill(color('green'));
// Layer 4: mask (uniform magenta cover derived from `cover`)
mask = cover.clone().replace(color('magenta'));
}
function setup() {
Quadrille.cellLength = 400 / size;
createCanvas(400, 400);
init();
document.oncontextmenu = () => false;
}
function draw() {
background('moccasin');
drawQuadrille(mines);
drawQuadrille(counts);
drawQuadrille(mask, { outline: color('lime') });
}
function mouseClicked() {
const row = cover.mouseRow;
const col = cover.mouseCol;
if (mines.isFilled(row, col)) cover.clear();
else if (counts.isFilled(row, col)) cover.clear(row, col);
else cover.clear(row, col, true);
mask = cover.clone().replace(color('magenta'));
}
function keyPressed() {
init();
}
Init
The init function builds the four layers in dependency order: mines → counts → cover → mask. Each layer is set once and never reassigned.
function init() {
// Layer 1: mines
mines = createQuadrille(size, size, n, '💣');
// Layer 2: counts (neighbor counts on empty cells of `mines`)
counts = createQuadrille(size, size);
mines.visit(({ row, col }) => {
const order = mines.ring(row, col).order;
if (order > 0) counts.fill(row, col, order.toString());
}, ({ value }) => value === null);
// Layer 3: cover — merge mines+counts, then recolor
cover = Quadrille.or(mines, counts);
cover.replace(color('red')).fill(color('green'));
// Layer 4: mask (uniform magenta cover derived from `cover`)
mask = cover.clone().replace(color('magenta'));
}
ℹ️ Ring Method
ringreturns a Quadrille instance of all neighbors within radius 1. Its.orderproperty reports how many of those neighbors are filled. Becauseminescontains only bombs,mines.ring(row, col).orderis exactly the count of neighboring mines — no manual neighbor inspection needed.
ℹ️ Visit Predicate
The counting loop visits only empty cells thanks to the filter argument of
visit, the predicate({ value }) => value === null.
ℹ️ Building the Cover with
or
Quadrille.or(mines, counts)returns a new quadrille whose cells are filled wherever eitherminesorcountsis filled — i.e. exactly the union of the filled cells. Thenreplace(color('red'))recolors all of those filled cells red, andfill(color('green'))fills the remaining empties green. The two tones makecoverlook like a heatmap of the two click zones — but more importantly, the boundary between red and green is what stops the flood fill at the right place (see Interaction).
ℹ️ Mask Display Layer
The player never sees the two-tone
coverdirectly. The visiblemaskis built by cloningcoverand replacing every cell color (red or green) withmagenta, producing a uniform cover that hides the game state while keepingcoveravailable for the click logic.
The demo below uses cover itself as the visible layer so you can see the algorithm in action. Click around: a red cell next to a number clears one cell (clear(row, col)); a green cell clears a connected region plus its red border (clear(row, col, true)); a mine clears the entire cover (clear()). The static mines and counts layers underneath become visible as cover is cleared.
(mouse click to play; press any key to init)
Draw
The draw function renders all three visible layers: mines and counts underneath, then mask on top.
function draw() {
background('moccasin');
drawQuadrille(mines);
drawQuadrille(counts);
drawQuadrille(mask, { outline: color('lime') });
}
ℹ️ Info
- Static layers (
mines,counts): built once, never modified.- Dynamic layer (
mask): rebuilt after each click. As cells are cleared incover,maskreflects the updates, revealing the underlyingminesandcounts.
Interaction
Mouse clicks modify cover to uncover cells, then rebuild mask. The three branches map one-to-one onto the three Minesweeper rules, and each branch uses a different overload of clear:
- Clicked a mine → game over: clear() wipes the entire cover.
- Clicked a number → reveal that cell only: clear(row, col) clears one cell.
- Clicked an empty cell → cascade: clear(row, col, border) flood-fills the connected empty region and, because
border = true, also clears the surrounding numbers — exactly the classic Minesweeper cascade rule.
function mouseClicked() {
const row = cover.mouseRow;
const col = cover.mouseCol;
if (mines.isFilled(row, col)) cover.clear(); // boom
else if (counts.isFilled(row, col)) cover.clear(row, col); // single
else cover.clear(row, col, true); // flood + border
mask = cover.clone().replace(color('magenta'));
}
ℹ️ Why the two tones matter for flood fill
Quadrille’s flood fill clears the connected region of cells whose value matches the start cell. When the player clicks an empty cell, the start cell is green in
cover; the flood expands across connected green cells and stops at the red boundary. Withborder = true, the bordering red cells (the surrounding numbers) are cleared too. Ifcoverwere a single uniform color, the flood would clear everything.
Further Exploration
- Safe first click: Recreate the board after the first click to ensure the player never starts on a mine.
- Difficulty levels: Adjust the grid size, mine count, or mine density.
- Undo / redo timeline: Store previous
coverstates so players can move backward and forward through the game history. - Timer: Track and display the completion time.
- Flagging mechanic: Use right-click, or another input, to mark suspected mines.
- Win condition: Define when the game is complete, such as revealing all safe cells and/or correctly flagging all mines.
- Enhanced graphics: Replace raw emoticons with custom cell effects.
- Scoring system: Reward safe reveals, correct flags, speed, or efficient play.
- Visual hints: Add an option to display
cover(the two-tone debug view) or provide other visual aids for learning and accessibility. - Research-inspired feature: After studying one paper from Further Reading, propose and implement one feature inspired by it.
References
Quadrille API
- createQuadrille(width, height, order, value)
- drawQuadrille(quadrille, options)
- visit
- clone()
- mouseRow
- mouseCol
- isFilled()
- ring(row, col, dimension, wrap)
- order
- Quadrille.or(q1, q2)
- replace(value)
- fill
- clear
Coding Train Tutorial
Further Reading
Math papers. These papers present Minesweeper as a small mathematical model of constraint reasoning, logical deduction, probability, and computational complexity. Each revealed number constrains the hidden neighboring cells, and the player must reason from those constraints while managing uncertainty. The surprising result is that this reasoning can become computationally very hard, making Minesweeper a useful first example of how familiar games can lead to deep questions about algorithms, logic, and uncertainty.
Research papers. Minesweeper has also been used as a compact experimental platform for studying programming, learning, usability, human-computer interaction, artificial intelligence, sensors, authentication, cognitive science, and quantum-game ideas.
School papers. These papers present Minesweeper as an accessible but rich student project: it can be implemented as a game, analyzed as a computational problem, and extended with solvers based on constraint satisfaction, equations, graphical models, machine learning, flood fill, and reinforcement learning.