Harnessing the art of chess pattern recognition—emphasized by experts, among them Grandmaster Jonathan Rowson in “The Seven Deadly Chess Sins”—the demonstration below utilizes the powerful quadrille search method to identify key tactical patterns on the provided board, given in FEN notation. These patterns, which encompass maneuvers like knight forks where a piece simultaneously threatens multiple opponent pieces, can decisively influence the game’s dynamics. The p5.quadrille.js library aids players in detecting and adeptly deploying these patterns, thereby refining gameplay and strategic decision-making on the chessboard.

code
Quadrille.cellLength = 40;
const COLS = 8, ROWS = 8;
let fenBoard, fen, patternBoard, pattern, hint;
const defaultFen = 'r3kb1r/ppN1pppp/5n2/8/8/8/PPP3PP/R3KB1R';
let fenInput;
let rows, cols;
let pieces;
let hits;

function setup() {
  createCanvas((2 * COLS + 1) * Quadrille.cellLength,
               (ROWS + 1) * Quadrille.cellLength);
  fenBoard = createQuadrille();
  fenInput = createInput();
  fenInput.size(8 * Quadrille.cellLength - 5);
  fenInput.position(9 * Quadrille.cellLength + 5, 8 * Quadrille.cellLength + 15);
  fenInput.changed(() => update());
  pieces = createSelect();
  pieces.option('clear');
  for (const symbol of Object.values(Quadrille.chessSymbols)) {
    pieces.option(symbol);
  }
  pieces.selected('clear');
  pieces.position(10, 8 * Quadrille.cellLength + 15);
  rows = createSelect();
  cols = createSelect();
  for (let value = 1; value < 9; value++) {
    rows.option(value.toString());
    cols.option(value.toString());
  }
  rows.selected('2');
  rows.position(75, 8 * Quadrille.cellLength + 15);
  rows.changed(() => {
    pattern.height = +rows.value();
    patternBoard.height = +rows.value();
    patternBoard.fill();
    update()});
  cols.selected('5');
  cols.position(115, 8 * Quadrille.cellLength + 15);
  cols.changed(() => {
    pattern.width = +cols.value();
    patternBoard.width = +cols.value();
    patternBoard.fill();
    update()});
  reset();
  update();
}

function draw() {
  background('darkkhaki');
  drawQuadrille(patternBoard, { tileDisplay: 0 });
  drawQuadrille(pattern, { textColor: 'black', tileDisplay: 0 });
  drawQuadrille(fenBoard, { row: 0, col: 9, tileDisplay: 0 });
  drawQuadrille(fen, { row: 0, col: 9, textColor: 'black', tileDisplay: 0 });
  if (hits.length > 0) {
    drawQuadrille(hint, { row: hits[0].row, 
                          col: 9 + hits[0].col, outline: 'magenta' });
  }
}

function keyPressed() {
  if (key === 'r') {
    reset();
    update();
  }
}

function mouseClicked() {
  const row = pattern.mouseRow;
  const col = pattern.mouseCol;
  const value = pieces.value();
  pieces.value() === 'clear' ? pattern.clear(row, col) : 
                               pattern.fill(row, col, pieces.value());
  update();
}

function reset() {
  fenInput.value(defaultFen);
  fen = createQuadrille(fenInput.value());
  const r = Quadrille.chessSymbols['r'];
  const k = Quadrille.chessSymbols['k'];
  const N = Quadrille.chessSymbols['N'];
  pattern = createQuadrille([
    [r,    null, null, null, k],
    [null, null, N]
  ]);
  patternBoard = createQuadrille(pattern.width, pattern.height).fill();
  rows.selected(pattern.height);
  cols.selected(pattern.width);
}

function update() {
  fen = createQuadrille(fenInput.value());
  hits = fen.search(pattern, true);
  hint = pattern.clone();
  const black = color('black');
  hint = Quadrille.neg(pattern, color(red(black), green(black), blue(black), 180));
}

Reset

The reset function restores the initial FEN and sets up the pattern for subsequent searches:

function reset() {
  // i. set default fen
  fenInput.value(defaultFen);
  // ii. loads fen quadrille
  fen = createQuadrille(fenInput.value());
  // iii. creates default pattern
  const r = Quadrille.chessSymbols['r'];
  const k = Quadrille.chessSymbols['k'];
  const N = Quadrille.chessSymbols['N'];
  pattern = createQuadrille([
    [r,    null, null, null, k],
    [null, null, N]
  ]);
  patternBoard = createQuadrille(pattern.width, pattern.height).fill();
  rows.selected(pattern.height);
  cols.selected(pattern.width);
}

This function initializes the environment for pattern recognition with a standard starting position.

API references

Update

The update function refreshes the app state in response to user interactions:

function update() {
  fen = createQuadrille(fenInput.value());
  hits = fen.search(pattern, true);
  hint = pattern.clone();
  const black = color('black');
  hint = Quadrille.neg(pattern, color(red(black), green(black), blue(black), 180));
}

Each action taken by the user triggers this function, which reevaluates the FEN, identifies pattern matches, and creates a semi-transparent red overlay (hint) to signify discovered patterns on the board.

API references

Drawing

The draw function visually represents the chessboard state and identified patterns:

function draw() {
  background('darkkhaki');
  drawQuadrille(patternBoard, { tileDisplay: 0 });
  drawQuadrille(pattern, { textColor: 'black', tileDisplay: 0 });
  drawQuadrille(fenBoard, { row: 0, col: 9, tileDisplay: 0 });
  drawQuadrille(fen, { row: 0, col: 9, textColor: 'black', tileDisplay: 0 });
  if (hits.length > 0) {
    drawQuadrille(hint, { row: hits[0].row, 
                          col: 9 + hits[0].col, outline: 'magenta' });
  }
}

The rendering sequence is pivotal for correct visual output: the pattern and its board on the left, the FEN and hints on the right. Highlighting occurs only when matches are identified by the search.

Interaction

Keyboard

Pressing the r key resets the board and updates the view:

function keyPressed() {
  if (key === 'r') {
    reset();
    update();
  }
}

This binds the ‘r’ key to reinitialize the game state to its default and process any changes.

Mouse

Clicking the mouse edits the pattern and triggers an update:

function mouseClicked() {
  const row = pattern.mouseRow;
  const col = pattern.mouseCol;
  if (pieces.value() === 'clear') {
    pattern.clear(row, col);
  } else {
    pattern.fill(row, col, pieces.value());
  }
  update();
}

Mouse interactions allow the user to modify the pattern on the board and immediately reflect those modifications.

API references

References