3.3 KiB
3.3 KiB
Super Auto Pets: The Board Game
Go backend (pure rules engine in internal/game, WebSocket rooms in
internal/server, computer opponent in internal/ai) + React frontend in
web/. See README.md for the full layout and rules summary.
mise run test— Go tests ·mise run check— go vet + frontend tsc
Seats, sides, and packs
Three distinctions are easy to conflate and worth keeping straight:
- Seat vs. side. A game seats 2, 4, or 6 players, and each round pairs
them off into simultaneous battles (
schedule.go). Inside aBattleResulteverything is indexed by side — 0 or 1 within that one battle — includingBattleEvent.Seat/Target,Lineups,Survivors, andManaAfter.Seatsmaps side → seat, andSide(seat)maps back.WinnerSeatis the deliberate exception: it's a real seat, because it's the only field that means anything outside the battle. When adding a per-side field to a battle, index it by side and say so. - One battle vs. the round.
resolveBattlesloops the round's pairings;runBattle(first, second)resolves one of them and mutates no persistent state. Anything that should happen once per round rather than once per battle (clearing per-round banks, say) belongs inresolveBattles, notfinalizeBattle. - Packs are plural.
Game.Packsis a list whose tier decks shuffle together. Anything reading printed card data must go throughTierContentsForPacks/CatalogForPacks/g.packList(), never a single pack — a game can hold Trumpets, Mana, and Ailments at once.
Keep the AI in sync with game behavior
Whenever game behavior changes — rules, cards, effects, phases, log entries, or views — make sure the computer opponent accounts for it. The AI plays from the same information a human sees, so changes ripple into it in specific ways:
- Battle rules:
internal/aievaluates moves by running the real resolver (game.SimulateBattle), so battle changes are picked up automatically — but re-check the hand-written heuristics that summarize battle wisdom:leadScore,keepValue,deckValue(eval.go) and the food-placement strategies / synergy pet list (arrange.go). - New or changed cards/effects: shop-time deck effects are mirrored in
applyTemplateShopEffects(shop.go); a new shop-time trigger or action must be added there or the bot will misvalue it. - New public actions or log changes: the bot tracks the opponent via
structured tags on public log entries (
LogBuy,LogSell,LogTrade,LogTradePick, spawn counts — see log.go). New public actions need tags plus handling inObserve(memory.go). Tags must only ever duplicate facts the entry's text already states publicly. - View changes: the AI decides from
game.Viewonly — never hand it theGame. If a field is added to the view, confirm it doesn't leak hidden information (deck order, trade options, shop decks), because the AI (and any client) would legitimately see it. - Phase/flow changes: the server's bot driver (
internal/server/bots.go) must know when a bot owes an action (ai.Pending) and have a legal fallback (botFallback) for any new phase or forced decision.
After any such change, run go test ./internal/ai/ — it plays complete
bot-vs-bot games and fails on any illegal or missing bot action.