Features of a Quadrille

Features of a Quadrille

The Quadrille API underpins all grid-based strategies in this book. It’s designed for multi-paradigm programming, common in modern languages like JavaScript, so you can use each style where it fits best:

  • Declarative — say what, not how.
    Express intent with predicates and boolean algebra:
    fill(({ row, col }) => row === col, value), or/and/xor/not, search(pattern).

  • Functional — compose with functions.
    Treat rules and visuals as values: pass filters and factories; store display functions in cells; iterate with ergonomic for…of over filtered cells only when a loop is truly needed.

  • Object-oriented — model entities and reuse your own code.
    Store cell objects with state and methods; rely on polymorphism and a simple display contract so heterogeneous objects render uniformly.

Composing strategies this way lets you practice multiple paradigms at once—yielding code that’s simpler, clearer, easier to read, maintain, and share—and less error prune.

In the sketch below, toggles enable or disable layers, adjust draw order, and apply per-layer options. An aggregate toggle reduces the enabled layers to a single board—showing how Quadrille swaps between a layered view and an aggregate view.

This chapter covers

  • The grid model (rectangular, null-padded)
  • The data model (any JS value; aggregate at create/fill/merge time)
  • The composition model (layers ↔ boolean aggregation)
  • The rendering model (built-in displays, options, and the display contract)

Grid model

A Quadrille is always rectangular grid: every row has the same length, and empty cells are normalized to null (never undefined). This invariant keeps iteration, search, merges, shifts, and rendering simple.

Data model

Each cell can store any valid JavaScript value—numbers, strings, colors, p5.Image or video, p5.Graphics, functions, or objects. “Empty” is consistently null.

Quadrilles support aggregation at:

  • CreationcreateQuadrille(w, h, k, value)
  • Fillingfill(predicateOrBitmask, value)
  • Merging — boolean algebra on grids (or/and/xor/not)

Composition model

When your game state spans multiple quadrilles, compose it in two complementary ways: use layers to keep them separate—e.g., one quadrille per player or timeline snapshot—and render back-to-front; or use logic to aggregate them with boolean operators into a single grid.

Rendering model

Quadrille is renderer-agnostic. You can use it for:

  • Logic only. Build and transform grids, then export them with toBigInt, toArray, or toImage so another engine or framework handles drawing.
  • Rendering only. Import external data with createQuadrille(...) and let drawQuadrille handle the display.
  • End-to-end. Do both in one place—compute with predicates/layers and render in the same sketch.

When you do render with Quadrille, drawQuadrille stays decoupled from game logic and knows how to display cells containing:

  • Immediate values — colors, numbers, strings, images, video, p5.Graphics
  • Display functions — a cell effect stored in the cell; drawQuadrille calls it with { row, col, origin } and expects no return value (the display contract)
  • Objects — any instance exposing a display method or field that satisfies the display contract, rendering uniformly alongside other values