v0.3.1 — multiplayer groundwork: 13 engine tests covering 2-4 player games, a seat parameter on snapshot and actionMenu so a player sees their own railroad rather than seat 0's, and the 22 opponent-directed cards held out of every deck until they are built

This commit is contained in:
Jesse
2026-08-12 22:37:10 -04:00
parent 1bf1e95058
commit 216006b091
11 changed files with 460 additions and 44 deletions
+40 -2
View File
@@ -21,6 +21,46 @@ page as `v0.1.0 · <sha> · <date>`, so what is deployed can always be identifie
## Unreleased
## 0.3.1 — 2026-08-13
### Groundwork for multiplayer
Two steps that hold whichever way the hotseat-or-server question goes, plus a deck change.
**The 22 opponent-directed cards are out of every deck, not just solitaire's.** Q6 removed them from
solitaire because they have no legal target with one player; they are out of the competitive deck now
too, because `checkPlay` answers both categories `NOT_IMPLEMENTED` and dealing them would make ~9% of
draws reject outright. `buildDeck` returns 213 in both modes. `DECK_SIZE` (235) is now documented as
the CATALOGUE rather than the size of any deck in play — the two had quietly become different numbers.
Three Enhancements (Facing Point Locks, Water Column, Overpass) exist only to answer these cards and
stay dormant until they return; recorded in `TODO.md` as multiplayer work.
**A net under the multi-player engine paths** — `test/multiplayer.test.ts`, 13 tests. Everything else
in the suite is solitaire, so these had been running unwatched. They cover 2/3/4-player games playing
to a finish; per-seat Office Areas and Crew Tray counts; the Fedora passing to the *next* seat, only on
a shift boundary, reaching every seat over a game; Subdivisions splitting at the Offices that have
upgraded and not at the ones that have not; one player's oncoming train barring another's departure,
and no longer barring it once a Control Point puts them in different Subdivisions; and that
`awardDeparture` pays the Office that ran the train rather than seat 0 — which with one player was
unfalsifiable.
Two failed when first written and both times the TEST was wrong, not the engine: the Superintendent
cases drove the clock by calling `advance` in a loop, which never moves it — `advance` stops and asks
for input, so the game has to actually be played. **The engine's multi-player paths passed everything
on the first honest run**, which is the useful result here.
**`snapshot` and `actionMenu` take a seat.** They were hardcoded to player 0 in eight places across
`view.ts`, `game.ts` and `main.ts` — correct with one player, and a quiet disaster with more: every
seat would have been shown player 0's railroad *including player 0's hand*, which is the one thing the
state model calls secret. All eight now take a viewer, defaulting to 0 so solitaire and every replay
are untouched, and `describeIntent` now describes an intent against the acting player's district
rather than seat 0's. A test shows three seats getting three different boards and three different
hands, so the parameter is exercised rather than merely present.
Bot unchanged at 7.0 — solitaire never dealt the opponent cards, so none of this moves it.
## 0.3.0 — 2026-08-12
### Sharp curves are out of the deck
Eight cards, dealt zero copies. The only thing that made a sharp curve different from an ordinary one
@@ -95,8 +135,6 @@ game harder, which is the point — but it is worth knowing that enforcing §7 t
of what the departure-Revenue rule gave. The train tooltip no longer says "NOT YET ENFORCED BY THE
ENGINE"; it says what each rule does, because the restriction is the character of the card.
## 0.3.0 — 2026-08-12
### Two rule changes, both provisional, both measured
**The opening deal is now 3 track + 3 other, from two separately shuffled piles.** Track is shuffled