M2: бот и headless-прогон матчей
- PlayerView: проекция состояния, в которой боту видно только то, что видно живому игроку (своя рука, стол, размеры чужих рук, счётчики) - BasicBot: политика из GAMEPLAY.md, полностью детерминированная - Match: обёртка с состоянием и подпиской на события (её же возьмёт UI) - runMatch: прогон матча без движка и без таймеров - soak-тесты: 3500 полных матчей (боты и случайные легальные ходы, 2-4 игрока), инварианты состояния проверяются после каждого действия - npm run stats:bot — распределение исходов самоигры Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+27
-7
@@ -45,8 +45,9 @@ assets/
|
||||
core/ PURE TS — no engine imports
|
||||
cards/ Suit, Rank, Card, Deck
|
||||
rules/ GameState, actions, events, the reducer
|
||||
bot/ PlayerView projection, BasicBot
|
||||
util/ seeded RNG, shuffle, assertions
|
||||
bot/ PlayerView projection, Bot contract, BasicBot
|
||||
match/ Match (stateful shell), runMatch (headless driver)
|
||||
util/ seeded RNG, shuffle
|
||||
modules/
|
||||
save/ SaveManager, ISaveSection, StatsSection, storage
|
||||
app/ Bootstrap, ServiceLocator, SceneRouter
|
||||
@@ -54,7 +55,10 @@ assets/
|
||||
lobby/ lobby screen controller
|
||||
game/ match screen: hand, table, deck, animations
|
||||
common/ reusable widgets, safe-area root
|
||||
tests/ vitest specs against assets/scripts/core
|
||||
tests/
|
||||
core/ vitest specs against assets/scripts/core
|
||||
support/ position fixtures and the state invariant checker
|
||||
tools/ measuring tools, not part of the suite
|
||||
docs/ specs, this file, plan, decisions
|
||||
local/ scratch art storage; contents get consumed
|
||||
extensions/cocos-code-mode/ editor tool server
|
||||
@@ -83,9 +87,16 @@ apply(state: GameState, action: Action): { state: GameState; events: GameEvent[]
|
||||
|
||||
## Bots
|
||||
|
||||
A bot is a function `(view: PlayerView) => Action`. `PlayerView` is a projection
|
||||
of `GameState` containing only legitimately visible information. `BasicBot`
|
||||
implements the policy in [GAMEPLAY.md](GAMEPLAY.md) verbatim.
|
||||
A bot is `decide(view: PlayerView) => Action`. `PlayerView` is a projection of
|
||||
`GameState` containing only legitimately visible information — own hand, table,
|
||||
trump, opponents' hand *sizes*, deck and discard counts — plus the list of legal
|
||||
actions. `BasicBot` implements the policy in [GAMEPLAY.md](GAMEPLAY.md).
|
||||
|
||||
`Match` wraps the reducer with the current state and an event subscription; the
|
||||
game screen and the headless `runMatch` driver both hold one. As a reference
|
||||
point, 5000 `BasicBot` self-play matches split roughly 43/43/14 between the two
|
||||
seats and draws, with the opening attacker losing about 37% of the time —
|
||||
`npm run stats:bot` reprints these.
|
||||
|
||||
## Savegame
|
||||
|
||||
@@ -114,7 +125,16 @@ Keys are explicit string constants, not class names — release builds minify.
|
||||
npm test
|
||||
```
|
||||
|
||||
Runs vitest over `tests/` against `assets/scripts/core`. No editor required.
|
||||
Runs vitest over `tests/core` against `assets/scripts/core`. No editor required.
|
||||
The soak specs play several thousand complete matches and re-check every state
|
||||
invariant after every single action, so a rule regression surfaces at the move
|
||||
that caused it.
|
||||
|
||||
```bash
|
||||
npm run typecheck # strict tsc over core/ and the tests
|
||||
npm run check:core-purity # fails if core/ ever imports the engine
|
||||
npm run stats:bot # BasicBot self-play distribution, not a test
|
||||
```
|
||||
|
||||
### Driving the editor
|
||||
|
||||
|
||||
Reference in New Issue
Block a user