This is a deterministic, headless-first Clash Royale-style simulator scaffold with a small localhost debug renderer.
Current scope:
- Arena geometry, bridge/river placement rules, tower layout, elixir, 8-card decks, and 4-card hand cycling.
- Starting cards: Knight, Archers, Minions, Fireball, Cannon, Giant, Musketeer, Mini P.E.K.K.A.
- Data-driven card specs sourced from
legacy_ref/retro_royale_80_cards_stats_v2.xlsx. - Tick-based command scheduling for future online play concepts: simulated latency, placement delay, and authoritative synchronization.
- Compact deterministic replay export with decks, each side's starting hand cycle, and command tuples to reconstruct a match.
- Canvas renderer at
localhost:8000with blue/red circles, labels, and per-card secondary colors.
The repository includes an opt-in, laptop-bounded pipeline for the default-deck mirror matchup: streaming behavior cloning, masked PPO against a diverse heuristic population, frozen-checkpoint self-play, paired held-out evaluation, and browser play against a checkpoint. No training starts on import or during setup; every experiment below is started explicitly by you. No win rate is claimed until your own run produces its evaluation artifact.
Start with the RL runbook. It gives the exact progression from a 3-minute smoke run through the 5.5-hour final preset, monitoring and resume commands, the statistical success gate, and a 20+ game human test. Read the RL design for the observation/fairness contract, action mask, network, BC/PPO objectives, reward, opponent diversity, and frozen self-play. Laptop operations documents the target Legion 5 hardware and required preflight, preset ceilings, artifacts, troubleshooting, and the go/no-go checklist between experiments.
The first command should be run from a normal terminal, not this Codex sandbox, because the sandbox currently cannot access the NVIDIA driver:
.venv/bin/python -m clashbot.rl.cli preflight --preset smokeProceed only when the JSON report says "ok": true,
"using_project_venv": true, "cuda_available": true, and
"cuda_tensor_test": "pass".
Run tests:
python3 -m unittest discover -s testsThe normal GameEngine uses deterministic C++ kernels for crowded targeting,
ground-path validation, building avoidance, and collision resolution, while
retaining the complete Python API and all card mechanics. Select the reference
path with GameEngine(backend="python"); native kernels are selected by
default and built into a content-addressed temporary cache on first use.
For high-throughput matches using the project's eight-card default deck,
NativeDefaultDeckEngine keeps the whole tick loop in C++. Python entities are
materialized only when a Python policy actually evaluates the board:
from clashbot.engine import NativeDefaultDeckEngine
engine = NativeDefaultDeckEngine(seed=7)Run the end-to-end heuristic-vs-heuristic parity and performance gate with:
python3 tools/benchmark_heuristic_match.pyThe benchmark requires at least 10x speedup and compares every chosen card,
placement tick/coordinate, match result, and final tower health against the
Python reference. NativeDefaultDeckEngine deliberately rejects other decks;
use GameEngine for the full card set and mutation-heavy mechanics tests.
Run the higher-level movement/targeting interaction scenarios while tuning the arena mechanics:
python3 -m unittest discover -s tests -p 'test_interaction_scenarios.py' -vSee INTERACTION_SCENARIOS.md for the scenarios and the mechanics they cover.
Run the debug server:
.venv/bin/python -m clashbot.debug_server --host 127.0.0.1 --port 8000Open http://localhost:8000.
Battle the rule-based default-deck opponent at
http://localhost:8000/heuristic/. You control blue; the heuristic controls
red as GPT-Hbot using the same battle UI as /two; its live hand and card
cycle are hidden. Completed matches and compact deterministic replays are kept
in clashbot/data/heuristic_games.jsonl, with replay-copy controls in the page's
history panel. The policy is fully documented in clashbot/heuristic.py and
covers defensive pulls, air and ground responses, Fireball value, Giant push
construction, counter-pushing, elixir conservation, and legal anti-leak plays.
For arbitrary eight-card decks in the full Python simulator, use the deck-agnostic second-generation policy:
from clashbot.engine.constants import SIDE_RED
from clashbot.heuristic_v2 import HeuristicV2
policy = HeuristicV2(SIDE_RED)
action = policy.maybe_submit(engine)HeuristicV2 derives tank, win-condition, anti-air, splash, swarm, ranged,
spawner, and damage-spell profiles from the current card specs. It also tracks
all opponent hand cycles consistent with publicly accepted plays once the
eight cards have been revealed; it never reads the opponent's live deck, hand,
or hidden order. Run its focused tests with
python3 -m unittest -v tests.test_heuristic_v2, or run representative
full-match sanity checks with python3 tools/benchmark_heuristic_v2.py.
When the debug server is running, open
http://localhost:8000/heuristic-v2/ to choose any eight-card human deck and
play against V2. Its match history is stored separately in
clashbot/data/heuristic_v2_games.jsonl.
The replay viewer is available at http://localhost:8000/replay/. Paste a
compact replay JSON payload (for example, one copied from a completed
two-player match) to play it back, change speed, or scrub to an exact tick.
Two-player remote debug mode is served by the same process:
.venv/bin/python -m clashbot.debug_server --host 0.0.0.0 --port 8000Open http://<server-ip>:8000/two/. The two-player mode keeps the simulator server-authoritative, starts only after both seats are ready, supports reconnecting by browser token, and writes completed match summaries to clashbot/data/two_player_games.jsonl by default. Card pictures can be dropped into clashbot/web/two/card-art/ as <card_id>.webp, .png, .jpg, or .jpeg.
Each newly completed two-player match also stores its compact replay, final tick, state hash, and engine version. The history list deliberately omits that payload from its frequent state poll; fetch a single artifact with:
curl 'http://127.0.0.1:8000/api/two/replay?matchId=<match-id>'Use the trace helper to compare a recording with the simulator at exact ticks (the --line -1 form reads the latest JSONL history entry):
python3 tools/replay_trace.py clashbot/data/two_player_games.jsonl --line -1 --every 15This is the intended human-in-the-loop loop for movement bugs: reproduce once in /two, retain the replay artifact, then inspect target changes, spawns, jumps, and positions before changing a rule.
The /two history panel also has a Copy replay button for this workflow.
For a Raspberry Pi, prefer running the Python server on an unprivileged port such as 8000 or 8080 and forwarding port 80 with a reverse proxy or firewall rule. Binding Python directly to port 80 usually requires root or extra capabilities.
The engine package is intentionally split by responsibility:
clashbot.engine.arena: tile classification, placement legality, bridge helpers.clashbot.engine.cards: card/tower stats and spawn formations.clashbot.engine.simulation: deterministic authoritative tick loop.clashbot.engine.replay: compact replay format.clashbot.debug_server: stdlib HTTP server for human-in-the-loop checking.