Only buying costs gold; selling and trading (Triple) are free. Pass is now a final action, legal only at or under the pet limit: it forfeits remaining gold and ends that player's shopping for the round, with the shop closing once everyone has passed. That makes the separate cleanup phase unreachable (you sell down in-shop before passing), so it is removed. The client asks for confirmation before passing, and the bot knows buys are the only coin sink, when passing is legal, and that it must sell down before it can pass.
119 lines
5.4 KiB
Markdown
119 lines
5.4 KiB
Markdown
# 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).
|
||
|
||
## Stack
|
||
|
||
- **Backend**: Go (stdlib-first). Pure game engine in `internal/game`,
|
||
WebSocket sync via `coder/websocket`, persistence as JSON blobs in SQLite
|
||
(`modernc.org/sqlite`, no cgo).
|
||
- **Frontend**: React + Vite + TypeScript in `web/`. DOM/CSS card rendering
|
||
and battle animations.
|
||
- **Tasks**: [mise](https://mise.jdx.dev) (`mise.toml`).
|
||
|
||
## Quick start
|
||
|
||
```sh
|
||
mise run install-web # once: npm install
|
||
mise run serve # build frontend + server, run on :8080
|
||
```
|
||
|
||
Open http://localhost:8080, host a game, and join from another browser (or
|
||
incognito window) with the 5-letter code.
|
||
|
||
### Development
|
||
|
||
```sh
|
||
mise run dev # Go server on :8080 + Vite hot reload on :5173
|
||
mise run test # Go tests (game engine)
|
||
mise run check # go vet + frontend type-check
|
||
```
|
||
|
||
During development open the Vite URL (http://localhost:5173); it proxies
|
||
`/api` (including the WebSocket) to the Go server.
|
||
|
||
## Configuration
|
||
|
||
Set via environment or a `.env` file (see `.env.example`):
|
||
|
||
| Variable | Default | Purpose |
|
||
| ------------ | ---------- | ------------------------------------ |
|
||
| `DATA_DIR` | `data` | Directory holding the SQLite DB |
|
||
| `PORT` | `8080` | HTTP port |
|
||
| `STATIC_DIR` | `web/dist` | Built frontend to serve |
|
||
|
||
## Rules implemented
|
||
|
||
Six rounds, each with its own shop tier deck. Per round:
|
||
|
||
1. **Shop** — each player has 3 gold and players alternate actions: **buy**
|
||
one of 4 face-up cards (1 gold — the only action that costs anything);
|
||
**sell** any number of hand cards for free (each becomes an 🍎 apple, +1
|
||
power food, and Sell effects fire); or **trade in** 3 same-suit pets (the
|
||
Triple action, also free) to pick 1 of the top 2 cards of the next tier's
|
||
deck — Triple effects fire on the traded cards and the received pet's Buy
|
||
effect fires. **Passing** is a final action, only legal at 5 pets or
|
||
fewer: it forfeits remaining gold and ends that player's shopping for the
|
||
round. The shop closes once everyone has passed.
|
||
2. **Arrange** — Battle Prep effects fire first (e.g. Giraffe hands out
|
||
apples), then players secretly order their decks. Food cards apply to the
|
||
next pet after them; trailing foods are wasted. A pet only benefits from
|
||
its last-applied **perk** (e.g. Honey, Garlic).
|
||
3. **Battle** — automatic stack machine. Cards reveal off the top of each
|
||
deck until a pet is in play. Play effects fire on reveal (rocks roll a d6
|
||
with faces 0/0/1/1/2/2 and hit the opposing pet before the clash; Skunk
|
||
strips foods; Wolverine steals apples; Chili mills the enemy deck). The
|
||
two pets simultaneously deal their full power to each other as damage
|
||
markers; a pet with markers ≥ power faints (attack never drops while
|
||
wounded). Faint effects push summons onto either deck, recycle apples
|
||
(Dodo), set aside delayed/recurring/conditional rock volleys (Badger,
|
||
Blowfish, Snake, Crocodile), raise auras (Turkey, Mammoth), or arm a
|
||
team shield (Turtle). Survivors that took damage fire Hurt effects
|
||
(Peacock, Camel, Gorilla). Shields (Turtle/Gorilla/Melon) block whole
|
||
hits, Garlic shaves 1 per attack, and Scorpion KOs anything its clash
|
||
attack manages to hurt. Hippo heals when enemies faint; Rhino rocks each
|
||
enemy pet as it's played. A clash that changes nothing ends the battle
|
||
as a stalemate draw. Last player able to field a pet wins: 1 trophy for
|
||
rounds 1–5, 2 for round 6. Draws award nothing.
|
||
|
||
Apples and bees are **temporary**: they leave your deck after the battle.
|
||
Most trophies after round 6 wins.
|
||
|
||
All six tiers use the real card data:
|
||
|
||
| Tier | Pets | Food |
|
||
| ---- | ---- | ---- |
|
||
| 1 | Ant, Cricket, Duck, Otter, Mosquito, Fish | — |
|
||
| 2 | Worm, Flamingo, Peacock, Swan, Rat, Spider | Honey |
|
||
| 3 | Dog, Dolphin, Giraffe, Camel, Sheep, Dodo, Badger | Garlic |
|
||
| 4 | Squirrel, Turtle, Rooster, Bison, Blowfish, Skunk, Hippo | Pineapple |
|
||
| 5 | Monkey, Rhino, Crocodile, Scorpion, Seal, Shark, Turkey | Chili |
|
||
| 6 | Gorilla, Fly, Leopard, Mammoth, Cat, Snake, Wolverine | Melon |
|
||
|
||
## Layout
|
||
|
||
```
|
||
cmd/server/ entrypoint
|
||
internal/game/ rules engine (pure, fully tested)
|
||
internal/ai/ computer opponent (decides from a player View only)
|
||
internal/server/ HTTP + WebSocket rooms; drives bot turns
|
||
internal/store/ SQLite persistence
|
||
internal/env/ .env loading
|
||
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.
|