Skip to content

Repository files navigation

LiarsDeckAgent

Game-theoretic agents for Liar's Deck, a social-deduction bluffing card game — from a deterministic rules engine up to trained agents you can play against in the browser. Two-player tables are solved with counterfactual regret minimization (CFR); three- and four-player tables use population-based reinforcement learning (PSRO) — hence "agent", not "RL", in the name.

▶ Live demo: https://liarsdeck-demo-319509297648.us-west1.run.app

Choose a 2-, 3-, or 4-seat table and either play one seat against the trained agents or spectate an all-agent game with pause/step/speed controls. An optional Learning mode compares each decision you commit with the deployed policy's action distribution at that exact information state — shown only after you act, so your choice stays honest. The demo is a single-visitor showcase: no accounts, no data collection, sessions are in-memory and expire. The first visit after an idle period may take ~10–15 s to load (the free-tier backend scales to zero).

The agents

Seats Policy Notes
2 Whole-game CFR on the full information-set lattice Near-exact equilibrium play
3 16-member PSRO population 0.517 mixed-lineup win rate vs 1/3 chance; qualified under pre-registered gates
4 12-member PSRO population Uniform-sigma release; +0.077 over chance, BR-probe edge +0.254

Multiway games that reach heads-up switch the surviving agents to the projected 2p CFR strategy (a measured, pre-registered improvement), and served PSRO policies suppress a class of dominated mixed plays — both disclosed in the demo's UI. Opponents sample one population member per seat per game, so styles vary between games but stay consistent within one.

The evolution of the project — engine, scripted baselines, PPO/NFSP/league training, CFR solving and acceleration, PSRO populations, and the web demo's hardening and launch — is documented as dated engineering reports under reports/.

Repository layout

Path Contents
liarsdeck/ Rules engine, PettingZoo AEC env, encoding, baselines, tournament, CFR, and the FastAPI game service (liarsdeck/service/)
train/ PPO self-play, league/NFSP/PSRO training, probes
web/ React + TypeScript SPA (Vite), Vitest unit tests, Playwright e2e matrix
scripts/ Training/evaluation CLIs, release packaging, deploy tooling, soak/benchmark harnesses
tests/ Engine, encoding, agent, and service test suites
reports/ Dated experiment reports, release inventory, runbook, closeouts

Running locally

Backend + tests:

python3.12 -m venv .venv
.venv/bin/python -m pip install -e ".[dev]"
.venv/bin/python -m pytest                     # engine + service suites

Web demo (dev mode, Vite proxying to the service):

.venv/bin/uvicorn --factory liarsdeck.service.api:create_app --port 7860
cd web && npm ci && npm run dev

Browser test matrix:

cd web && npm run build && npx playwright test

Or the exact production container (multi-stage build; startup validates every model artifact against the checksummed release inventory and refuses to serve on any mismatch):

docker build -t liarsdeck-demo .
docker run --rm -p 7860:7860 liarsdeck-demo

Training your own agents

The released agents were trained on a MacBook Pro (M3 Pro); wall-clock numbers below are from that machine.

1. Solve the 2p CFR policy. The whole game factors into a lattice of 72 round subgames solved by backward induction; this is the compute-heavy step at roughly 9 hours of cumulative solver time (it parallelizes across subgames via --workers, and --resume continues an interrupted solve):

.venv/bin/python scripts/solve_lattice.py \
  --checkpoint reports/cfr-lattice-dcfr-sweep.npz --workers 8

2. Train the 3p/4p PSRO populations. Each iteration trains a best-response probe against the current population and adds it as a member. The released populations bootstrap from seed checkpoints produced by earlier league/self-play training (--seed-member NAME=PATH; training good seeds from scratch with train/ppo_league.py adds hours). The PSRO loops themselves are fast on this laptop: the released 4p run (8 iterations → 12 members) took ~40 minutes on Apple-silicon MPS, and the 3p run (→ 16 members) under 10 minutes on CPU:

.venv/bin/python train/psro.py --num-players 4 --iterations 8 \
  --meta-solver uniform --psro-dir reports/psro-4p --json reports/psro-4p.json
.venv/bin/python train/psro.py --num-players 3 --iterations 8 \
  --meta-solver uniform --psro-dir reports/psro-3p --json reports/psro-3p.json

3. Package and validate the release. Re-pins every artifact hash into the inventory/registry and regenerates the Learning golden corpus; the service tests fail loudly on any mismatch, and the container will refuse to serve an inconsistent bundle:

.venv/bin/python scripts/build_web_release_inventory.py
.venv/bin/python scripts/build_policy_registry.py
.venv/bin/python scripts/build_learning_golden.py
.venv/bin/python -m pytest tests/service

Two expectations to set: retrained results are not bit-identical (PSRO is stochastic — you get a different population and release digest, by design), and strength claims need re-evaluation — the released policies passed pre-registered gates (mixed-lineup win rates, best-response probes, behavioral probes; see scripts/evaluate_*.py and the dated reports) that a new population should be re-run through before trusting its labels.

Deployment

https://liarsdeck-demo-319509297648.us-west1.run.app/

The demo runs on Google Cloud Run (single instance, scale-to-zero, free-tier configuration). scripts/deploy_cloud_run.py builds the image, tags it with the release digest, pushes it to Artifact Registry, and applies the full pinned service configuration; it also manages rollbacks and the keep-warm scheduler job. Operations are documented in reports/phase6-runbook.md.

Training and evaluation entry points

.venv/bin/python -m pip install -e ".[train]"
.venv/bin/python scripts/fuzz_random_games.py --games 100000    # engine fuzz gate
.venv/bin/python scripts/tournament.py random honest paranoid heuristic --games 10000
.venv/bin/python train/ppo_selfplay.py --updates 200 --batch-games 128
.venv/bin/python scripts/train_cfr.py --help                    # CFR solver
.venv/bin/python scripts/benchmark_serving_policies.py --report /dev/stdout

About

Play Liar's Deck against game-theoretic agents — CFR heads-up, PSRO populations at 3-4 seats — with a spectate mode and a Learning panel

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages