Implement engine core: board assembly, movement, turns, combat, victory

Pure deterministic game core in @wizwar/engine: seeded RNG (mulberry32,
state in GameState so seed+commands replays identically), sector
assembly with rotation, junction merging, and wraparound warps
(configurable pairings; the 2p diagram crosses its side openings),
movement (3 + one number card), geometric line of sight, deck building
from the verified card data (asserts 125/200 totals), and the
command-to-event reducer: setup with TRAP! redraw and die-roll first
player, punching (no combat round 1, no self-attack, once per turn),
damage/death with killer-takes-cards and forced discard, treasure
stealing with both victory conditions, pick-up-ends-turn, and
end-of-turn draw. Events carry full spatial detail for future replay
rendering; private card knowledge rides on visibleTo events with a
redaction helper. 21 tests passing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Eric Wagoner
2026-08-15 19:39:50 -04:00
co-authored by Claude Fable 5
parent 11209cdc5d
commit a8884592a4
9 changed files with 1428 additions and 31 deletions
+9 -31
View File
@@ -1,32 +1,10 @@
// @wizwar/engine — pure, deterministic game logic. No I/O, no timers, no
// network: the server drives it in real time, the async mode replays it from
// stored commands, and future AI players call it to evaluate moves.
//
// Card data, board layouts, and precise rule mechanics are pending
// transcription of the 6th edition materials (see /research).
// @wizwar/engine — pure, deterministic Wiz-War (6th edition) game logic.
// No I/O, no timers, no network: the server drives it in real time, async
// mode replays it from stored commands, and AI players call it to evaluate
// moves. All game data is verified against the owner's physical 6e set.
export interface PlayerId {
readonly id: string;
}
/** A single square on a sector board. Walls live on edges between squares. */
export interface Position {
readonly x: number;
readonly y: number;
}
export type GamePhase = "setup" | "playing" | "finished";
export interface GameState {
readonly phase: GamePhase;
readonly turn: number;
readonly activePlayer: string;
// TODO: board (sectors, walls, doors), players (position, life, hand,
// sustained spells, carried items/treasures), deck & discard, RNG seed.
}
/** Commands are player intents; the engine validates and applies them. */
export type Command = { type: "todo" };
/** Events are what actually happened; clients render from these. */
export type GameEvent = { type: "todo" };
export * from "./rng";
export * from "./board";
export * from "./cards";
export * from "./setups";
export * from "./game";