A faithful simulator of the Dutch card game Beverbende (999 Games; known internationally as Rat-a-Tat Cat), a style-conditional PPO agent trained by self-play, a LaTeX write-up explaining all of it for ML newcomers, and a browser game ("Otterbende", after the custom otter deck) where you play against the trained network.
Play it: https://jasp-nerd.github.io/beverbende/ · Read the paper:
paper/main.pdf
Headline results: the trained 28k-parameter network outrates every scripted baseline (Elo 1200–1246 vs 1000–1151 over 40,800 duplicate-deal rounds); a single style input moves its knock timing from turn ~14 to turn ~2; and duplicate deals show 60% of round-score variance is the deal across mixed skill levels, 88% between equal players.
src/beverbende/— Python packageengine.py— the full rules as a phase machine over 31 masked actionsobs.py,actions.py— the frozen encoding contract (seedocs/)env.py,vec.py— single-agent RL view + vectorized self-play runneragents/— scripted baselines + policy wrappertrain/ppo.py— CleanRL-style PPO self-play loop (single file)train/nets.py— the 160→96→96→{31,1} tanh network (~28k params)toy.py— enumerable mini-Beverbende solved with tabular Q-learningeval/— duplicate-deal tournament, Elo, behavior metrics, statisticsexport/— weights + parity-fixture export for the web game
tests/— rule tests, fuzz invariants, env/bot gates (pytest)analysis/—paper.mplstyle+plots.py(regenerates every figure)paper/— LaTeX sources;makebuildsmain.pdf(TinyTeX/latexmk)web/— Svelte 5 + Vite 8 browser game; TS engine held to move-for-move parity with Python via recorded traces (npm test)scripts/— card-art extraction, trace export, remote-training ops
uv sync # Python env (pinned 3.12)
uv run pytest # rules + invariants
uv run python -m beverbende.train.ppo --total-steps 5000000 --out results/dev
cd web && npm install && npm run dev # play the game locally- Train:
scripts/launch_remote.sh(or runtrain.ppolocally per seed) - Evaluate:
beverbende.eval.tournament→elo→behavior→stats - Figures:
uv run python analysis/plots.py - Paper:
cd paper && make