The game kit: the shared infrastructure of Wiz-War and Waving Hands as a template
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141G6xqLeNRYEtviLWSB5Up
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
// The contract between a game and everything else in this kit. The server,
|
||||
// the client store and the hall know nothing about the game beyond this
|
||||
// file: they create a state from names and a seed, feed it one round of
|
||||
// inputs at a time, ask who still has to move, and hand each viewer the
|
||||
// view they are allowed to see. A new game implements GameSpec once, in
|
||||
// src/lib/game/index.ts, and the rest of the kit works unchanged.
|
||||
|
||||
/** A seat at the table: a single letter from GameSpec.seatIds. */
|
||||
export type SeatId = string;
|
||||
|
||||
/** The viewer with no seat: the Peanut Gallery. Views built for it show only what every seat could see. */
|
||||
export const SPECTATOR: SeatId = '';
|
||||
|
||||
export interface Outcome {
|
||||
winner: SeatId | null;
|
||||
reason: string;
|
||||
}
|
||||
|
||||
export interface GameSpec<State, Input> {
|
||||
/** Seats in table order; the table takes at most this many. */
|
||||
seatIds: SeatId[];
|
||||
minSeats: number;
|
||||
/** Names the server draws for bots, in preference order. */
|
||||
botNames: string[];
|
||||
/**
|
||||
* The rules revision new games begin under. A game keeps the revision it
|
||||
* started with, recorded on its ledger, so a later fix can keep the old
|
||||
* path for old ledgers behind `state.rules < N`. Bump only when the deploy
|
||||
* gate shows a fix changes how an already-played turn resolves.
|
||||
*/
|
||||
currentRules: number;
|
||||
|
||||
create(names: Record<SeatId, string>, seed: number, rules: number): State;
|
||||
/** Resolve one round. Must be a pure function of its arguments: the ledger is replayed through it. */
|
||||
resolve(state: State, inputs: Record<SeatId, Input>): State;
|
||||
/** Whether this seat's input is needed before the next resolution. */
|
||||
needsInput(state: State, seat: SeatId): boolean;
|
||||
over(state: State): Outcome | null;
|
||||
/** The round being written, counted from one, for the ledger and the report pin. */
|
||||
turn(state: State): number;
|
||||
/** What one viewer may see. The server sends nothing else. */
|
||||
view(state: State, viewer: SeatId): State;
|
||||
botInput(state: State, seat: SeatId): Input;
|
||||
/** Only the shapes the engine understands get through; the engine validates the rest. */
|
||||
cleanInput(raw: unknown): Input;
|
||||
/** A seat's name from the state, for the hall and the chronicle. */
|
||||
nameOf(state: State, seat: SeatId): string;
|
||||
}
|
||||
Reference in New Issue
Block a user