The rival's policy now exposes a ranking, which drives both its own move and a new HINT button: it highlights the card to play, where to put it, and where to draw, with the model's confidence. Undo and redo work per action rather than per turn — picking a card, choosing its destination, and drawing are separate steps, as are the rival's moves — so a finished game can be stepped back through from the result screen. The rival is suspended while undone moves are pending, and PLAY FROM HERE resumes from the reviewed position. Cards now travel between zones instead of teleporting: a motion layer measures each card's old and new position and animates the difference, flying cards out of the deck face-down and flipping them over, and back into it on undo. Also: the result screen gets a per-expedition score breakdown mirroring human_play.py, and a rival card revealed by a discard-pile draw no longer renders at full size in the card-back-sized rival hand row. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LmyprzuzanXRhpomc3Ga1i
86 lines
2.8 KiB
Markdown
86 lines
2.8 KiB
Markdown
# COOLRL Lost Cities Web
|
|
|
|
Browser-only Lost Cities client. The rules engine, observation builder, and PPO
|
|
inference all run on the device; there is no application server.
|
|
|
|
The verified final JAX PPO policy is committed at
|
|
`public/models/jax-ppo.onnx` (3.1 MB). Vite copies it to the static build, and
|
|
the app resolves the asset relative to the deployed site so it works on GitHub
|
|
Pages, GitLab Pages, or a normal web root. Its size and SHA-256 are recorded in
|
|
[`public/models/jax-ppo.json`](public/models/jax-ppo.json).
|
|
|
|
Pushes to `main` build and publish the client through the repository's GitHub
|
|
Pages and GitLab Pages workflows. Each workflow supplies the correct base URL
|
|
for its host.
|
|
|
|
## Seeded deals
|
|
|
|
Every game is dealt from a seed, shown in the menu and kept in the URL as
|
|
`?seed=<seed>`. Loading that URL — or typing the seed into the menu — replays
|
|
the exact same deal, so a game can be shared, replayed, or reported with a bug.
|
|
Seeds are arbitrary text; the deal is derived from a deterministic PRNG in
|
|
`src/game/random.ts` and is independent of the Python shuffle bank.
|
|
|
|
The seed shuffles the deck and nothing else. The policy is deterministic: it
|
|
always plays its highest-logit legal action, so the same deal and the same moves
|
|
reproduce the same game.
|
|
|
|
## Hints, undo, and review
|
|
|
|
`HINT` asks the same policy that drives the rival what it would play in your
|
|
seat, and highlights the card, its destination, and the draw source (with the
|
|
policy's confidence when the ONNX model is loaded).
|
|
|
|
Undo and redo work per *action*, not per turn: choosing a card, choosing its
|
|
destination, and drawing are separate steps, and each is undone on its own. The
|
|
rival's moves are steps too, so a finished game can be stepped through from the
|
|
result screen (`REVIEW GAME`) all the way back to the deal. While undone moves
|
|
are pending the rival is suspended; `PLAY FROM HERE` drops them and resumes play
|
|
from the position on screen.
|
|
|
|
## Setup
|
|
|
|
Install and run the checked-in final policy:
|
|
|
|
```bash
|
|
cd web
|
|
npm ci
|
|
npm run dev
|
|
```
|
|
|
|
Build the same static bundle used by a host:
|
|
|
|
```bash
|
|
npm run build
|
|
npm run preview
|
|
```
|
|
|
|
To replace the shipped policy, export a verified Orbax checkpoint from the
|
|
repository root. The exporter writes both the ONNX file and its public
|
|
metadata manifest:
|
|
|
|
```bash
|
|
uv run --with onnx scripts/export_jax_ppo_onnx.py \
|
|
--checkpoint /path/to/checkpoint \
|
|
--output web/public/models/jax-ppo.onnx
|
|
```
|
|
|
|
The policy tries WebGPU first and falls back to ONNX Runtime WebAssembly. If
|
|
the model asset is absent, the UI remains playable using a simple local
|
|
heuristic and reports that fallback in the header.
|
|
|
|
## Checks
|
|
|
|
```bash
|
|
cd web
|
|
npm test
|
|
npm run build
|
|
```
|
|
|
|
The TypeScript engine follows `src/lost_cities_jax/engine.py` and its 96-action
|
|
atomic action space. Cross-runtime fixtures can be regenerated with:
|
|
|
|
```bash
|
|
uv run python scripts/generate_web_parity_fixture.py
|
|
```
|