export type PlayerId = number; export type NodeKey = `${number}:${number}`; export type PlayerPalette = { name: string; primary: string; glow: string; }; export type Position = { row: number; column: number; }; export type SetupState = { playerCount: number; columns: number; rows: number; startingNodesPerPlayer: number; sunbeamChance: number; diseaseChance: number; seedInputs: string[]; paletteOrder: number[]; initiativeMode: "fixed" | "bid"; biddingOrderRule: "rotating" | "lowest_growth_income"; weatherDraftEnabled: boolean; winCondition: "rounds" | "top_leaves"; maxRounds: number; topLeafTarget: number; }; export type Player = { id: PlayerId; name: string; color: string; glow: string; totalScore: number; roundScore: number; growthPoints: number; bankedPoints: number; bonusPoints: number; lifetimeGrowthIncome: number; passed: boolean; }; export type GameConfig = { columns: number; rows: number; playerCount: number; startingNodesPerPlayer: number; playerPaletteOrder: number[]; initiativeMode: SetupState["initiativeMode"]; biddingOrderRule: SetupState["biddingOrderRule"]; weatherDraftEnabled: boolean; winCondition: SetupState["winCondition"]; maxRounds: number; topLeafTarget: number; }; export type NodeState = { ownerId: PlayerId; }; export type Edge = { from: Position; to: Position; ownerId: PlayerId; }; export type GrowDirection = "vertical" | "left" | "right"; export type GrowTarget = Position & { cost: number; direction: GrowDirection; }; export type ShiftMove = { type: "shift"; cost: number; direction: "left" | "right"; movedNodes: Array<{ fromKey: NodeKey; toKey: NodeKey; row: number; fromColumn: number; toColumn: number; }>; movedEdges: Array<{ before: Edge; after: Edge; }>; undoKeys: NodeKey[]; selectKey: NodeKey; }; export type GrowMove = { type: "grow"; from: Position; to: Position; cost: number; targetKey: NodeKey; undoKeys: NodeKey[]; selectKey: NodeKey; }; export type TurnMove = GrowMove | ShiftMove; export type ColumnEnergy = { column: number; terminalRow: number; intercepted: boolean; ownerId: PlayerId | null; hitNode: Position | null; rootKey: NodeKey | null; branchNodes: Position[]; branchEdges: Array<{ from: Position; to: Position }>; }; export type RootBurst = { key: NodeKey; playerId: PlayerId; count: number; }; export type EnergySimulation = { scores: number[]; columns: ColumnEnergy[]; rootBursts: RootBurst[]; }; export type RoundAnimationTrace = { playerId: PlayerId; verticalCells: Position[]; ray: { x: number; y: number }; rootKey: NodeKey | null; branchNodes: Position[]; }; export type RoundAnimation = { phase: "sunlight" | "branches" | "bonus" | "events"; columns: ColumnEnergy[]; traces: RoundAnimationTrace[]; rootBursts: RootBurst[]; sunbeamPlayerId: PlayerId | null; bonusTrace: RoundAnimationTrace | null; bonusBurst: RootBurst | null; diseaseKeys: NodeKey[]; }; export type ColumnResult = { column: number; ownerId: PlayerId | null; topRow: number | null; tied: boolean; }; export type RoundSummary = { scores: number[]; columnResults: ColumnResult[]; event: string | null; }; export type ScoreSnapshot = { currentExposure: number; growthPoints: number; bankedPoints: number; lifetimeGrowthIncome: number; }; export type ColumnLeader = { ownerId: PlayerId | null; row: number | null; tied: boolean; }; export type RandomEffects = { sunbeamChance: number; diseaseChance: number; }; export type GamePhase = "initiative" | "turn" | "round_end" | "game_over"; export type WeatherCardId = | "leaf_surge" | "branching_season" | "west_light" | "east_light" | "high_noon" | "edge_bloom" | "wide_reach" | "tall_reward"; export type WeatherCardDefinition = { id: WeatherCardId; title: string; description: string; }; export type InitiativeDraftState = { biddingOrder: PlayerId[]; biddingIndex: number; seatAssignments: Array; seatBonuses: number[]; }; export type WeatherDraftState = { playerOrder: PlayerId[]; draftIndex: number; row: WeatherCardId[]; drafted: WeatherCardId[]; banned: WeatherCardId[]; }; export type GameState = { config: GameConfig; players: Player[]; nodes: Map; edges: Edge[]; round: number; activePlayerId: PlayerId; turnOrder: PlayerId[]; phase: GamePhase | "weather"; turnMoves: TurnMove[]; selectedSource: NodeKey | null; availableTargets: GrowTarget[]; animation: RoundAnimation | null; initiativeAnchorPlayerId: PlayerId; initiativeDraft: InitiativeDraftState | null; weatherDraft: WeatherDraftState | null; activeRoundEffects: WeatherCardId[]; randomEffects: RandomEffects; gameOver: boolean; history: string[]; roundSummary: RoundSummary | null; };