What it does
A table is a set of tiles, each with a position, a layer and a key. In mahjong mode a tile is free when no higher tile
overlaps its footprint and its left or right side is open, and two free tiles with the same key can be removed. In
Onet mode the tiles lie on a flat grid and two matching tiles are removed when a path of at most two bends joins them
through empty cells, the one-cell border round the board included. You hand the table a pair; it removes them, or
returns a reason, such as blocked-tile or no-path, and changes nothing. blockedBy explains why a tile is not
free, which is what a "why can't I take this?" tooltip needs.
The hard part of these games is the deal: shuffle the faces at random and many tables cannot be cleared. Here a deal
first finds an order that removes the layout two tiles at a time, then gives each pair a key along that order, so the
table can always be won and the order becomes the hint certificate. When the player strands themselves and no pair is
left, stuck says so, and shuffle deals the remaining faces again along a fresh clearing order. The shuffle is one
move in the history, so undo takes it back.
Keys are matching groups, not pictures, so the four flowers can each have their own picture and still match one another. The pack is pure rules, deterministic from a seed, and draws nothing, so a 2D or 3D presenter shows the tiles.
Features
- Two rule sets — layered mahjong solitaire with covered and side-blocked tiles, and flat connect-the-pair boards with links of up to two bends.
- Solvable deals — every deal is keyed along a proven clearing order, with that order kept for hints.
- Dead-end shuffle —
stuckdetects a table with tiles and no pair;shuffleredeals the remaining faces so it can be cleared, and undo reverses it. - The classic Turtle —
mahjongTurtlegives the traditional 144-tile layout, notched rows, wing tiles and the single tile on top. - Generated layouts — stepped, diamond, bridge, pyramid, rectangle and turtle, at four difficulties.
- Authored layouts — tiles in tile widths with half offsets, any layer, and extra blockers that lock one tile until another is gone.
- Matching groups — keys group tiles, so flowers and seasons can each share a key across different pictures.
- Explanations —
blockedBysays whether a tile is covered, blocked on both sides or held by a blocker. - Solver and hints —
solveBestfollows the deal's certificate until a shuffle, then searches within a budget. - Undo, redo and reset — shuffles included.
Good for
- Mahjong solitaire on the traditional Turtle or on layouts of your own, in the style of Shanghai.
- Connect-the-pair puzzles in the style of Onet or Shisen-Sho, on a grid up to 32 by 32.
- Casual daily puzzles, where a seed gives a layout that is always clearable.
- Themed tile games, with fruit, animals or symbols as keys and your own art per picture.
- Puzzles with unlock rules, using extra blockers to hold a tile until another has gone.
- 3D tile tables, since the rules are independent of how the tiles are drawn.
Make it yours
A table is a PairsConfig: the mode, up to 200 tiles with positions, layers, sizes and keys, the grid size and
largest number of bends for Onet, and any extra blockers. You can author the whole layout, use the Turtle, or let the
generator build one, and dealTilePairs keys any layout you give it from a list of faces, cycling the faces or using
each exactly once.
The generator takes a mode, a seed, a difficulty, a layout, and overrides for the columns, rows, layers, number of key groups and search budget. Three materially different uses:
- A traditional mahjong solitaire on the 144-tile Turtle with 36 key groups.
- A small easy pyramid of two layers and eight groups, for a quick mobile level.
- An authored connect-the-pair board with
maxTurnslimiting links to one bend, keyed bydealTilePairsso it can still be cleared under the stricter rule.
A quick look
Deal the Turtle, remove a pair, and recover from a dead end:
import { createTilePairs, generateTilePairs } from '@phaser-ae/tile-pairs';
const deal = generateTilePairs({ mode: 'mahjong', layout: 'turtle', seed: 12 });
const table = createTilePairs(deal.config, deal.solution);
const free = table.tiles.filter(t => table.isFree(t.id)); // light these up
const r = table.apply({ a: picked[0], b: picked[1] });
if (!r.valid) shake(r.reason); // 'different-group', 'blocked-tile', 'no-path', 'invalid-pair'
if (table.stuck) table.shuffle(seed);
const hint = table.solveBest(10000).actions[0]; // { a, b } or undefined
Works with
tray-match— for collecting three of a kind into a limited tray instead of removing pairs.match3— for swapping tiles to make lines.world-3dandrender-3d— to present the tiles as a 3D table.
Good to know
- Every deal can be cleared, but the player's choices can strand tiles; a table can be lost before it is stuck, and only the solver can tell.
- A table holds at most 200 tiles.
- Generated deals vary by size, layers and groups only; there is no human-difficulty control, and the Turtle is the only traditional layout shipped as data.
- Tiles never settle or slide, and there are no connect-the-pair variants where tiles close up after a removal; model those by rebuilding the deal.
- Searches are synchronous, so keep hint budgets small inside a frame.






