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 the p5.quadrille.js API to instantiate and handle two quadrilles: a board and a mask. The former embodies the game board, while the latter covers it. As gameplay progresses clicking on mask cells uncovers the underlying board.

(mouse click to play; press any key to init)

code
let board, mask;
let size = 20;
let n = size * 2;

function init() {
  board = createQuadrille(size, size, n, '๐Ÿ’ฃ');
  mask = board.clone();
  visitQuadrille(board,
    (row, col) => {
      if (board.isEmpty(row, col)) {
        let order = board.ring(row, col).order;
        if (order) {
          mask.fill(row, col, order.toString());
        }
      }
    }
  );
  board = mask.clone();
  mask.replace(color('red')).fill(color('green'));
}

function setup() {
  Quadrille.cellLength = 400 / size;
  createCanvas(400, 400);
  init();
  // suppress right-click context menu
  document.oncontextmenu = () => false;
}

function draw() {
  background('moccasin');
  drawQuadrille(board);
  drawQuadrille(mask.clone().replace(color('magenta')), {outline: (color('lime'))});
}

function mouseClicked() {
  const row = board.mouseRow;
  const col = board.mouseCol;
  if (board.read(row, col) === '๐Ÿ’ฃ') {
    mask = createQuadrille(size, size);
    return;
  }
  board.isFilled(row, col) ? mask.clear(row, col) : mask.clear(row, col, true);
}

function keyPressed() {
  init();
}

Init

The init function initializes both the board and its covering mask:

let board, mask;
let size = 20;
let n = size * 2;

function init() {
  // 1. Board instantiation
  board = createQuadrille(size, size, n, '๐Ÿ’ฃ');
  // 2. Mask instantiation
  mask = board.clone();
  // 3. The number of neighboring mines is determined
  // on the board visited cells using the ring method
  // with its order saved in the respective mask cell
  visitQuadrille(board,
    (row, col) => {
      if (board.isEmpty(row, col)) {
        let order = board.ring(row, col).order;
        if (order) {
          mask.fill(row, col, order.toString());
        }
      }
    }
  );
  // 4. The mask is cloned into the board
  board = mask.clone();
  // 5. The mask filled cells are colored in red
  // and the remaining ones in green
  mask.replace(color('red')).fill(color('green'));
}

Upon creation, the board and mask should appear as follows:

(mouse click or press any key to toggle the mask drawing)

API references

Drawing

To uniformly color mask-filled cells as magenta the clone and the replace quadrille methods are chained within the drawQuadrille p5.js function:

function draw() {
  background('moccasin');
  // 1. Draw board
  drawQuadrille(board);
  // 2. Color mask-filled cells in magenta
  drawQuadrille(mask.clone().replace(color('magenta')), {outline: (color('lime'))});
}

API references

Interaction

The game interaction uses mouse clicks to clear single cells or multiple cells through flood fill.

function mouseClicked() {
  // 1. Convert mouse screen position to quadrille row col coords
  const row = board.mouseRow;
  const col = board.mouseCol;
  // 2. Game over when mine explodes thus revealing board
  if (board.read(row, col) === '๐Ÿ’ฃ') {
    mask = createQuadrille(size, size);
    return;
  }
  // 3. Otherwise clear single or multiple cells
  board.isFilled(row, col) ? mask.clear(row, col) : mask.clear(row, col, true);
}

API references

References

  1. Minesweeper wikipedia article.
  2. Coding train minesweeper coding challenge tutorial: