Tick model and reducer contract
The SDK uses a genre-neutral reducer and tick-view vocabulary. It does not define terrain tokens, card schemas, level files, or a complete world state. Products expose those concepts through the generic contracts.
Coordinates are optional
Card-only, hidden-role, drafting, and other non-spatial games can skip the coordinate compatibility section and start at Reducer boundary. They still use the same tick, solver, agent, and replay contracts.
Coordinates
Cell is a mutable TypeScript tuple in [x, y] order:
type Cell = [number, number];The built-in cardinal vectors assume screen-style coordinates: x grows to the right and y grows downward.
CARDINAL_VECTORS.up // [ 0, -1]
CARDINAL_VECTORS.down // [ 0, 1]
CARDINAL_VECTORS.left // [-1, 0]
CARDINAL_VECTORS.right // [ 1, 0]Square boards used by the legacy geometry helpers are zero-based rectangles: 0 <= x < width and 0 <= y < height. Movement itself has no board size; its isStaticBlocked callback must reject out-of-bounds cells.
For square, axial-hex, graph, and multi-board games, use locations and layouts.
Treat cells stored in state as values. Copy a tuple before retaining it if a product might mutate the original array.
Reducer boundary
Reusable solving, replay, and agent execution consume the same adapter:
interface TickReducer<TLevel, TState, TView extends TickView> {
init(level: TLevel, seed: number): TState;
advance(state: TState, inputs: readonly SubmittedAction[]): TState;
view(state: TState): TView;
viewFor?(state: TState, seat: string): TView;
}initmust create the same initial state for the same level and seed.advanceresolves exactly one tick from zero, one, or many canonical inputs. It should throw for an illegal submission.viewexposes the complete or single-seat observation and legal-action surface needed by SDK consumers.viewForoptionally derives the observation authorized for one seat. See information partitions.
The reducer contract requires determinism, not persistent immutability. High-frequency products may mutate in place with copy-on-write rollback deltas. When using the solver, however, advance must not corrupt its input: several sibling actions are explored from the same parent. Return an independent state, use persistent data structures, or snapshot before mutation.
An empty-intent tick should use a near-free path and advance only scheduled systems whose explicit boundary is crossed. Wall-clock time is never implicit state input; see fixed-rate ticks.
Actions
An action definition declares one of four parameter shapes:
params | Submission | Values are discovered from |
|---|---|---|
none | { id } | No additional data |
index | { id, index, zoneId? } | Items, dialogue options, points of interest, and product zones |
xy | { id, x, y, boardId? } | Per-action targets, then the shared target list |
targets | { id, targets } | A complete non-truncated targetChoices[targetSpecId] set |
const action: SubmittedAction = {
id: 'Action 4',
x: 3,
y: 2,
boardId: 'arena',
};Multi-seat hosts may attach seat to any submission. Action ids in the reducer are canonical. A hosted protocol may permute their wire labels for an agent; replay verification checks that mapping before re-simulation.
Tick observations
TickView provides:
- legal action definitions;
- status:
playing,won, orfailed; - an optional star result;
hud.actionsUsed; and- optional indexed choices;
- optional sequential or simultaneous
participation; - optional multi-seat
outcome, including rankings and ties; - optional
activeSeatas sequential compatibility sugar; - optional partition-filtered
zones; and - optional spatial targeting under
grid, either for one implicit board or a record keyed by board id; and - optional declarative target-choice sets, including an explicit truncation marker.
Products may extend the view with a board, entities, inventory, objectives, events, or any other observation. Generic SDK algorithms ignore those extra fields unless a supplied callback uses them.
Product invariants
Before connecting a reducer, test these properties:
- Equal
(level, seed, action sequence)inputs produce equal visible results. - Every action advertised by
viewis accepted byapplyfor that state. - Illegal or stale actions are rejected rather than silently reinterpreted.
- Terminal states do not advertise actions that continue scored play.
- State used for solver deduplication excludes presentation-only volatility.
The SDK owns the adapter shape. The product continues to own state layout, validation, rules, content, serialization, and authoritative persistence.
Zonoid example
Zonoid implements one universal TickReducer for Object Delivery, Object Usage, Signal Language, The Breach, Intelligence Lies, and Jailbreak Protocol. The reducer initializes a product World, applies the canonical move/use/talk/ inspect actions, and exposes a redacted TickView; the same adapter is used by human play, agents, the solver, and replay verification.