The pack
placer
function placer(): Pack<{ placer: PlacerApi }>
The placer pack. Pure logic, so it needs no backend and runs headless.
Helpers
createPlacer
function createPlacer(cfg: PlacerConfig): Placer
Creates a Placer board from the given configuration. Throws when cols or rows is not an integer of at least
2, or when a region has a cell off the board.
PIECES_1010
const PIECES_1010: PieceDef[]
The canonical 1010! piece set: lines 1–5, squares, L/T/S shapes.
PIECES_BLOCKS
const PIECES_BLOCKS: PieceDef[]
Tetromino set (Block Blast leans on these), no rotation in tray games.
sudokuBoxes
function sudokuBoxes(cols = 9, rows = 9, box = 3): RegionDef[]
The sudoku-box regions that tile a cols × rows board (default 9 × 9) with box × box squares (default 3),
left to right and top to bottom: Woodoku's nine 3×3 boxes of a 9×9 board by default, or sudokuBoxes(8, 8, 4)
for four 4×4 boxes of an 8×8. Ids are box<bx><by> by box column and row (box00 at the top left), with a hyphen
between the two (box10-3) once a side has more than ten boxes. Throws when any argument is not a positive integer,
or box does not divide both cols and rows: a box that ran off the board could never fill.
Classes
Placer
class Placer
A drag-piece puzzle board (1010!/Woodoku style). Create one with createPlacer.
readonly cols: number— The number of columns on the board.readonly rows: number— The number of rows on the board.tray: Piece[]— The pieces the player can place now. Refilled when empty.score: number— The score gained from placements and clears so far.placements: number— The number of pieces placed so far.gameOver: boolean— True when no tray piece fits on the board — the game is over.streak: number— Current clearing streak (consecutive placements that cleared ≥1 region).constructor(cfg: PlacerConfig)cell(x: number, y: number): PlacedCell | null— The placed cell at (x,y), or null.canPlace(pieceId: number, at: XY): boolean— CanpieceIdbe placed with its origin atat?rotatePiece(pieceId: number, dir: 1 | -1 = 1): void— Rotate a tray piece 90° in place (dir1 = CW, -1 = CCW). No-op unlessrotateis configured. Cells are re-normalised to a (0,0) origin.place(pieceId: number, at: XY): PlaceResult— Place a tray piece; commit, clear completed regions, refill when empty.findPlacements(pieceId?: number): Placement[]— Every legal placement of every tray piece (or one piece), scored, best first.autoplay(maxPlacements = 500): PlaceResult[]— Auto-play by a policy until game over; returns each result.debugGrid(): string— Rows of#/.— handy in tests.
Types
Piece
interface Piece
A live tray piece.
id: number— The unique instance id of the piece.cells: XY[]— The cells of the piece, relative to its (0,0) origin.tag?: string— The label carried over from the piece definition, if it had one.
PieceDef
interface PieceDef
A tray piece shape: cells relative to (0,0), plus a deal weight.
cells: XY[]— The cells of the shape, relative to its (0,0) origin.weight?: number— Relative deal frequency. Default 1.tag?: string— Optional label carried onto placed cells and journal events.
PlacedCell
interface PlacedCell
One placed board cell.
fill: number— Piece-instance id that filled it (for colour/theming).tag?: string— The label carried over from the piece definition, if it had one.
Placement
interface Placement
A legal placement found by findPlacements.
pieceId: number— The id of the tray piece to place.at: XY— The board cell for the piece origin (its 0,0 cell).clears: number— Regions this placement would complete.value: number— Heuristic value, higher = better.
PlacerApi
type PlacerApi = typeof kit
game.placer — every function and type this pack carries, as one namespace.
PlacerConfig
interface PlacerConfig
Configures createPlacer. cols and rows must be integers of at least 2.
cols: number— The number of columns on the board. Must be an integer of at least 2.rows: number— The number of rows on the board. Must be an integer of at least 2.seed?: number— The seed for the deterministic tray deals. Default 1.regions?: RegionDef[]— Extra clearable regions beyond the default rows+columns (e.g. sudoku boxes). Every cell must be on the board; the constructor throws on one that is not.pieces?: PieceDef[]— The deal pool. Default: the 1010! set.traySize?: number— Pieces per tray. Default 3.rotate?: boolean— Allow rotating tray pieces 90° (board.rotatePiece). Off in the classic games (1010!/Block Blast/Woodoku place pieces as dealt); opt in for a variant.pieceFilter?: (fillRatio: number, pool: PieceDef[]) => PieceDef[]— Adaptive/weighted piece generation hook (Block Blast style). Given board fill ratio 0..1, return the pool to draw from. Default: the static pool.scorer?: (ev: { cellsPlaced: number; regions: number; streak: number }) => number— Score a placement; called for every one, withregions0 when nothing clears andstreakthe run before it. Default: the cells placed, plus a Block-Blast-like steep multi-region curve when it clears.
PlaceResult
interface PlaceResult
The outcome of one Placer.place call.
valid: boolean— True when the piece fit and was placed. False leaves the board unchanged.steps: PlacerStep[]— The ordered event journal for this placement — present the steps in order.combo: number— Regions cleared this placement (combo size).streak: number— Consecutive clearing placements including this one (0 if this cleared nothing).gained: number— The score gained by this placement.gameOver: boolean— True when no remaining tray piece fits on the board.
PlacerStep
type PlacerStep = | { type: 'place'; pieceId: number; cells: XY[]; fill: number } | { type: 'regionClear'; regions: string[]; cells: XY[] } | { type: 'trayRefill'; pieces: { id: number; cells: XY[] }[] } | { type: 'gameOver' }
One event in a placement journal: a place, a region clear, a tray refill, or game over.
RegionDef
interface RegionDef
A clearable region: a named set of cells that vanishes when all are filled.
id: string— The unique name of the region, reported inregionClearsteps.cells: XY[]— The cells that make up the region.
XY
interface XY
A board cell position.
x: number— The column of the cell.y: number— The row of the cell.


