Skip to main content

Game Engine Reference

The Tiao game engine lives in shared/src/tiao.ts. It is a collection of pure functions with zero side effects -- both the server and client use it to validate and apply moves.

Core Types

GameState

The central state object that represents a game in progress:

type GameState = {
positions: TileState[][] // 19x19 grid (null, "white", or "black")
currentTurn: PlayerColor // "white" | "black"
pendingJump: JumpStep[] // active multi-jump chain
pendingCaptures: Position[] // pieces marked for removal on confirm
score: ScoreState // { white: number, black: number }
history: TurnRecord[] // all completed turns
}

Position

type Position = { x: number; y: number }

RuleResult

Every game function returns a RuleResult<T> -- either success with a value, or failure with a code and reason:

type RuleResult<T> =
| { ok: true; value: T }
| { ok: false; code: RuleFailureCode; reason: string }

Functions

State Management

FunctionSignatureDescription
createInitialGameState()() => GameStateEmpty 19x19 board, white to move, score 0-0
cloneGameState(state)(GameState) => GameStateDeep clone a game state
isGameOver(state)(GameState) => booleanTrue if either player has 10+ captures
getWinner(state)(GameState) => PlayerColor | nullThe winning color, or null

Move Functions

FunctionSignatureDescription
placePiece(state, position)(GameState, Position) => RuleResult<GameState>Place a piece (validates cluster + border rules)
jumpPiece(state, from, to)(GameState, Position, Position) => RuleResult<GameState>Jump over an enemy piece
confirmPendingJump(state)(GameState) => RuleResult<GameState>Confirm jump chain, remove captures, switch turn
undoPendingJumpStep(state)(GameState) => RuleResult<GameState>Undo the last hop in a pending chain
undoLastTurn(state)(GameState) => RuleResult<GameState>Undo the most recent completed turn

Query Functions

FunctionSignatureDescription
canPlacePiece(state, position)(GameState, Position) => RuleResult<true>Check if placement is legal (without applying)
getJumpTargets(state, from, color?)(GameState, Position, PlayerColor?) => Position[]All legal jump destinations from a position
getSelectableJumpOrigins(state, color?)(GameState, PlayerColor?) => Position[]All pieces that can initiate a jump
getTile(state, position)(GameState, Position) => TileStateWhat's at a board position
isInBounds(position)(Position) => booleanIs position within 19x19
isBorderPosition(position)(Position) => booleanIs position on an edge
findConnectedCluster(state, start)(GameState, Position) => Position[]All orthogonally connected same-color pieces

Utility Functions

FunctionSignatureDescription
otherColor(color)(PlayerColor) => PlayerColorwhite to black, black to white
arePositionsEqual(a, b)(Position?, Position?) => booleanCompare two positions
getPendingJumpDestination(state)(GameState) => Position | nullWhere the jumping piece currently is
isPositionMarkedForCapture(state, pos)(GameState, Position) => booleanIs this piece pending removal

Constants

const BOARD_SIZE = 19;
const SCORE_TO_WIN = 10;

Failure Codes

CodeWhen
GAME_OVERGame has ended, no moves allowed
OUT_OF_BOUNDSPosition outside 0-18 range
OCCUPIEDIntersection already has a piece
PENDING_JUMPMust finish current jump before placing
INVALID_CLUSTERWould create cluster > 10
INVALID_BORDEREdge placement not jumpable by enemy
NO_PIECENo piece at jump origin
NOT_YOUR_PIECEPiece belongs to opponent
INVALID_JUMPJump is not legal
NO_PENDING_JUMPNo jump chain to confirm/undo