Add support for up to 6 players.

This commit is contained in:
Greyson Parrelli
2026-07-28 07:36:09 -04:00
parent e542118175
commit a4f5f6910d
38 changed files with 2306 additions and 713 deletions
+51 -14
View File
@@ -1,8 +1,8 @@
# Super Auto Pets: The Board Game — Online
A web app for playing the Super Auto Pets board game remotely. 1v1 for now;
the engine is built to grow to more players. Play a friend by room code, or
play solo against a computer opponent (easy / medium / hard).
A web app for playing the Super Auto Pets board game remotely, at 2, 4, or 6
players. Play friends by room code, fill any empty seat with a computer
opponent (easy / medium / hard), or play solo against a table of them.
## Stack
@@ -81,10 +81,41 @@ Six rounds, each with its own shop tier deck. Per round:
Apples and bees are **temporary**: they leave your deck after the battle.
Most trophies after round 6 wins.
## 4 & 6 player mode
A game seats an even number of players — 2, 4, or 6 — so everyone has an
opponent every round. A lobby with an odd number of humans fills the gap with
a bot; any seat can be a bot, so a table of one human and five computers is
just as valid as six humans.
Above two players the shop is shared but the battles are not: each round
splits the table into pairs, and every pair fights its own battle
simultaneously. The pairings come from the fixed table printed in the rulebook
(`internal/game/schedule.go`) — a round-robin that runs everyone past everyone
before replaying earlier rounds to fill out the six. All of it is public: you
can replay any table's battle, not just your own, and peek at any player's
lineup afterwards.
Two rules change with the bigger table:
- **First shopper** — at two players the priority token does double duty
(shops first, acts first in battle) and passes from a winner to the loser.
With more players it's a separate token that starts at seat A and walks one
seat along each round, while every battle flips its own first player.
- **Packs** — the rulebook asks for one pack per pair (2 packs for 4 players,
3 for 6). The host picks them in the lobby and their tier decks shuffle
together: all the tier 1 cards into one tier 1 deck, and so on. Two players
may combine packs too, for a deeper shop.
Ties on trophies are settled by counting back from the last round: whoever won
round 6 takes it, else round 5, and so on. Players with identical records
share the victory.
## Packs
Three card packs are playable, chosen by the host in the lobby. Each pack is
six tiers, one per round, and every pet ships as two copies.
Three card packs are playable, and the host combines one or more of them in
the lobby. Each pack is six tiers, one per round, and every pet ships as two
copies.
### Turtle pack
@@ -164,12 +195,18 @@ web/ React frontend
## The computer opponent
Any seat can be a bot (`Player.IsBot`); humans and bots are interchangeable
to the engine, which is what will let future >2-player games mix them
freely. The AI in `internal/ai` never touches the `Game` — it decides from a
`game.View`, the same per-player state a human client is sent, plus a
persisted memory of public observations (battle lineups, the event log, shop
row changes). It cannot see your deck order, hidden trade picks, or the
shuffled shop decks. It scores candidate moves by Monte-Carlo battle
rollouts (`game.SimulateBattle`) against sampled guesses of your deck and
ordering, blended with a long-term deck-value heuristic; difficulty tunes a
softmax over the scored moves plus the rollout budget.
to the engine, so a table can mix them freely. The AI in `internal/ai` never
touches the `Game` — it decides from a `game.View`, the same per-player state
a human client is sent, plus a persisted memory of public observations
(battle lineups, the event log, shop row changes). It cannot see your deck
order, hidden trade picks, or the shuffled shop decks. It scores candidate
moves by Monte-Carlo battle rollouts (`game.SimulateBattle`) against sampled
guesses of your deck and ordering, blended with a long-term deck-value
heuristic; difficulty tunes a softmax over the scored moves plus the rollout
budget.
At a bigger table it keeps a model of *every* seat, not just one rival — it
will face each of them eventually, and every battle is fought in the open —
but plans each round against the specific opponent the schedule pairs it
with. Its card counting spans the whole table's known cards and the combined
contents of the packs in play.