import { DominoValue } from '../game/DominoValue'; import { TrainBranch } from '../game/TrainData'; import { RulesConfig } from './rulesConfig'; /** * Locates a branch inside a chicken-foot tree. Empty path = the main line; each * step descends into the `toeIndex`-th side toe hanging off the double at * `doubleIndex` of the current branch. */ export type BranchPath = ReadonlyArray<{ doubleIndex: number; toeIndex: number; }>; export interface OpenEnd { path: BranchPath; attach: 'run-tail' | 'side-toe'; /** Pip value a tile must match to attach here. */ value: number; /** For side-toe ends: which double in the branch, and which toe slot. */ doubleIndex?: number; toeSlot?: number; /** The tile being attached to is a double (for the no-consecutive rule). */ attachToDouble: boolean; /** This end exists only because an unanswered double must be satisfied. */ obligation: boolean; } export interface Move { end: OpenEnd; tile: DominoValue; } export type PlacementViolation = 'value-mismatch' | 'duplicate-tile' | 'consecutive-doubles'; export interface PlacementResult { legal: boolean; violations: PlacementViolation[]; } export declare function getBranchAt(root: TrainBranch, path: BranchPath): TrainBranch | undefined; interface DoubleStatus { path: BranchPath; doubleIndex: number; value: number; hasCenter: boolean; sideToes: number; answers: number; } /** Doubles that still owe answers under the current rules. */ export declare function getUnsatisfiedDoubles(root: TrainBranch, config: RulesConfig): DoubleStatus[]; /** Every key of every tile already placed in the tree (for uniqueness checks). */ export declare function collectPlayedKeys(root: TrainBranch): Set; /** * All places a tile may legally attach to this train, honoring double * obligations. When a double is unanswered (and the rules require answers), * only that double's open slots are offered until it is satisfied. */ export declare function getOpenEnds(root: TrainBranch, startValue: number, config: RulesConfig): OpenEnd[]; export declare function evaluatePlacement(tile: DominoValue, end: OpenEnd, playedKeys: ReadonlySet, config: RulesConfig): PlacementResult; /** Every legal (open end × hand tile) move for this train. */ export declare function getLegalMoves(root: TrainBranch, startValue: number, hand: readonly DominoValue[], playedKeys: ReadonlySet, config: RulesConfig): Move[]; /** * Returns a new tree with `move` applied. The tile is oriented so its matching * end connects. Does not validate; call {@link evaluatePlacement} first (or use * {@link playMove}). */ export declare function applyMove(root: TrainBranch, move: Move, _config?: RulesConfig): TrainBranch; export interface PlayMoveResult { ok: boolean; board: TrainBranch; violations: PlacementViolation[]; } /** Validates a move against the rules and applies it only if legal. */ export declare function playMove(root: TrainBranch, move: Move, config: RulesConfig): PlayMoveResult; export {};