Game Interface
Overview
Section titled “Overview”Every Ludus game implements the Game<TState, TAction> generic interface. This enables the protocol to run any game through the same engine, record deterministic replays, and generate commentary — without knowing anything about the game’s specific rules.
Both Konquista and Destreect have been migrated to this interface.
The Interface
Section titled “The Interface”import type { GameConfig, GameMetadata, Player, PlayerRanking, SeededRNG } from '@ludus/game-engine';
interface Game<TState extends BaseGameState, TAction extends BaseAction> { /** Game metadata (name, player range, description) */ metadata: GameMetadata;
/** Create initial game state from config */ initialize(config: GameConfig, players: Player[], rng: SeededRNG): TState;
/** Get valid actions for a player in current state */ getValidActions(state: TState, playerId: string): TAction[];
/** Apply an action to produce a new state (must return new object) */ executeAction(state: TState, action: TAction, rng: SeededRNG): TState;
/** Check if the game is over */ isGameOver(state: TState): boolean;
/** Get the winner (null if draw or not over) */ getWinner(state: TState): Player | null;
/** Get final rankings for all players */ getRankings(state: TState): PlayerRanking[];
/** Human-readable description of an action */ describeAction(action: TAction, state: TState): string;}Base Types
Section titled “Base Types”All game states extend BaseGameState:
interface BaseGameState { gameId: string; turn: number; activePlayerId: string; playerOrder: string[]; eliminated: string[]; maxTurns: number;}All actions extend BaseAction:
interface BaseAction { type: string; playerId: string;}Determinism
Section titled “Determinism”Every game receives a SeededRNG instance (Mulberry32 algorithm) instead of Math.random(). This guarantees identical results from the same seed, enabling replay verification.
import { SeededRNG } from '@ludus/game-engine';
const rng = new SeededRNG(42);rng.next(); // Always the same value for seed 42rng.range(1, 6); // Deterministic dice rollrng.shuffle(arr); // Deterministic shuffleImmutability
Section titled “Immutability”The StateManager enforces that executeAction returns a new state object. If it returns the same reference, a StateImmutabilityError is thrown. This prevents accidental mutation bugs.
Game Loop
Section titled “Game Loop”GameLoopController runs the game loop for any Game<TState, TAction>:
- Initialize state with
SeededRNG - Each turn: get valid actions → agent decides → validate action → execute → emit events
- Record every action via
ReplayRecorder - On game over: produce
GameResultwith replay, rankings, final state
See @ludus/game-engine SDK Reference for the full API.