import { Board, Card, Hand, Pile, Stack, Suit } from "./types/cards"; import { clone } from "./fn"; const AGG: Suit = "spades"; const CUL: Suit = "hearts"; const TECH: Suit = "diamonds"; const MIL: Suit = "clubs"; type GameState = { mainPile: Pile; discardStack: Stack; deadPile: Pile; players: { hand: Hand; board: Board; }[]; playerTurn: number; lastMove: Move; prevState: GameState | null; }; type Move = | { type: "draw"; fromPile: "main" | "discard"; } | { type: "play"; card: Card } | { type: "remove"; card: Card } | { type: "attack"; army: Card[] } | { type: "pass" }; type Action = Move | { type: "discard"; cards: Card[] }; const techTier = (techValue: number) => Math.ceil(techValue / 14); const moveCost = (move: Move) => (move.type == "attack" ? move.army.length : 1); const movesSpent = (state: GameState): number => state.playerTurn != state.prevState?.playerTurn ? 0 : moveCost(state.lastMove) + movesSpent(state.prevState); const value = (suit: Suit) => (board: Board) => board .filter((card) => card.suit === suit) .reduce((v, card) => v + card.value, 0); export const getNextState = (p: { state: GameState; move: Move; }): GameState | { illegal: string } => { const { state, move } = p; const currentPlayer = state.players[state.playerTurn]; const population = currentPlayer.board.thru(value(AGG)); const culture = currentPlayer.board.thru(value(CUL)); const tech = techTier(currentPlayer.board.thru(value(TECH))); const movesRemaining = tech - movesSpent(state); const newState = clone(state); if (move.type === "draw") { const pile = move.fromPile === "main" ? newState.mainPile : newState.discardStack; if (pile.length === 0) { return { illegal: `The ${move.fromPile} pile is empty; cannot draw`, }; } newState.players[newState.playerTurn].hand.push(pile.pop()!); if (movesRemaining == 1) { newState.playerTurn = (newState.playerTurn + 1) % newState.players.length; } return newState; } return { illegal: "idk bruh" }; };