Files
dojo_cate/agents/plans/2026-09-25-dojo-board-and-sim.md
T
eisterman bbc95b6722 Rules v0.8: Fatica on crossing, no Kumite in round 1, board draft 2
- Fatica costs a stripe for every Fatica walked onto; a route whose Fatica
  drops a Brown player below 15 no longer enters the Dojo
- No Kumite in the first round: opponents are treated like meditating pawns
- Board draft 2: two Fatica tolls per quadrant, Allenamento moved to the ring
- Casual bot, --summary-csv, per-seat breakdown and move-options metric
- Out of contention measured at 3 belts
- Plan: Phase 6 baselines, decisions D34-D43

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-27 15:59:45 +02:00

320 lines
36 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Il Labirinto del Dojo — board format, rules engine, simulator
## Goal and scope
A small tabletop game (1–2 h, target 4 players, playable 3–8), gifted to a friend.
Logic and balance first; graphics and cosmetics are out of scope for now.
Deliverables:
1. `RULES.md` — the rulebook (English while iterating; Italian final edition produced separately).
2. A text-based board format, with parser, full-board generator and validator.
3. A first playable board.
4. A rules engine + bots + Monte Carlo simulator to validate balance and pacing,
and in particular to choose between rule variants A and B (B dropped, D28; now the Final Exam options, D29).
## Decisions log
| # | Decision | Why |
|---|---|---|
| D1 | Kumite loser loses 1 belt (−3), never below 0 | Developer requirement. |
| D2 | "Punching up": belts change only on equal-belt fights or upsets | Prevents leader farming weak players; built-in catch-up. |
| D3 | Kumite: 1d6 each, higher belt +1 per belt of gap, capped at +2 | Uncapped d6 bonus made fights predetermined (gap 5 = 100%). |
| D4 | **Senshu rule**: ties go to the attacker | WKF-inspired, one rule without exceptions, makes attacking slightly favourable so fights happen. |
| D5 | Kumite triggers on **crossing** (entering an occupied square), always forced; winning attacker continues moving; chains allowed | Developer requirement; route choice gives the agency. |
| D6 | Kumite loser is sent to own Start (corner Safe Room) | Developer requirement. |
| D7 | Corner Safe Rooms: 3×3, 2 exits, no Kumite/effects/targeting, stacking allowed | Prevents spawn camping / spawn lock. |
| D8 | Movement 2d6, exact count, orthogonal, no re-entering a square in the same move | Developer requirement + clarity. |
| D9 | Most squares carry an effect from a small vocabulary (7 codes); ~30–40% Tatami | Developer requirement; limits reading load and analysis paralysis. |
| D10 | Effects trigger only when stopping on a square (except Fatica since D36) | Avoids multiple triggers per move. |
| D11 | Nebbia works like Monopoly Chance: the square stays active | Developer requirement. |
| D12 | Progress track 0–17, 3 stripes per belt; squares ±1, Kumite ±3 | Fine-grained board income without breaking pacing. Physical tracking method decided later. |
| D13 | Nebbia deck is mostly movement/interaction/Tecniche, very few flat stripes | Prevents "stripe farming" that would make players avoid fights. |
| D14 | Tecnica cards: hold max 1, played after dice, attacker first | Converts Nebbia luck into a reason to fight. |
| D15 | Passo Falso returns to the start of the current move; skip-turn allowed only if rare (1 card) | Developer requirement. |
| D16 | Tunnel: when stopping on it you may teleport; movement is over; occupied exit starts a Kumite | Developer confirmed. |
| D17 | Meditazione: pass-through; ending on it forces one extra step | Developer rule. |
| D18 | Central Dojo is one logical space, several entrances, Brown only, no exact count to enter | Avoids end-game "need exactly a 3" frustration. |
| D19 | Final Exam: highest opponent defends; challenger wins → game; challenger loses → −3 and Start; defender gains nothing | Avoids the top-two flip-flop. Brown's extra stripes protect against the board, not the exam. |
| D20 | Two rule variants to be decided by simulation: **A** (no Brown cap, higher-beats-lower 0) vs **B** (squares/cards cannot move 14→15, higher-beats-lower +1) | Neither is clearly better a priori. *Superseded by D28.* |
| D21 | Board 16×16, 4×4 Dojo in the centre, authored as one 8×8 quadrant rotated 3× (C4 symmetry) | Fairness by construction. Small asymmetries may be wanted later (see Q2). |
| D22 | Tooling in Python, environment managed with **uv** | Developer choice. |
| D23 | Rules drafted in English; Italian final edition generated separately | Developer choice. |
| D24 | Board format: see `board/FORMAT.md`. Tunnel pairing across quadrants via `quadrant_offset` in `board/legend.toml` (cell `a` in quadrant k ↔ cell `b` in quadrant k+o) | Every tunnel cell keeps exactly one partner under rotation. |
| D25 | Only the Tunnel square is optional. Sfida (square and card), Irimi and Tunnel Segreto are mandatory; every Nebbia card must be resolved | Sfida prevents stalling; Nebbia cards are chances that can also turn out badly. |
| D26 | Tecnica cards are secret: drawn face down, others only know *whether* you hold one, a replaced Tecnica is discarded face down, revealed only when played | Hidden information and bluffing. Bots must not see opponents' Tecnica identity (Phase 4). |
| D27 | Edge rules (RULES.md v0.5, inline + FAQ): boxed-in → move as far as possible (safeguard; boards have no dead ends); Uke-saved attacker stops on its previous square, turn ends, no square effect; extra-step rule for ending on any unfightable pawn; tunnel exits with a meditating pawn unusable; meditating players cannot defend the Exam; Tecnica window after both dice, attacker first; relocations never fight or trigger squares; Tsugi-ashi has its own origin; becoming Brown mid-move opens the Dojo | Developer confirmed all ten. |
| D28 | Variant B dropped (developer, after the Phase 5 baseline): no Brown cap; a higher belt beating a lower one gains nothing. Removed from engine, bots, simulator, RULES.md (v0.6) | B made games shorter (13 vs 18 rounds) instead of adding an endgame challenge; the cap barely bit and the +1 applied to every such win. Too complex for what it gave. |
| D29 | Final Exam options under test: **a** ties go to the defender; **c** the defender fights as a Black belt (defender +1 vs a Brown challenger); **d** best of 3. Combinable (`--exam ac`). Option b (no belt bonus in the Exam) not pursued. Developer favours c | Baseline pass rate ~80%: the defender is usually 1–2 belts below the Brown challenger, who also gets Senshu. |
| D30 | Simulator reporting: income per source as gains and losses separately (Kumite is zero-sum, so its net hid the flow); standings sampled at the end of every turn; ten one-sidedness measures (see 5.4) | Developer request after the Phase 5 baseline. |
| D31 | Final Exam rule: **the defender fights as a Black belt** (option c; RULES.md v0.7). Options a (ties to the defender) and d (best of 3) stay as simulator switches only; `--exam` lists the options in force and defaults to `c` | c gave a 44% pass rate, more distinct challengers (1.58/game) and closer endings; d alone raised the pass rate to 91%. |
| D32 | Phase 6 targets confirmed by the developer as a starting point (table in Phase 6) | Q5. |
| D33 | Fatica fix: test **option 2 first** — a chance square (stop on it, roll 1d6: 1–2 lose a stripe, 3–6 gain one) replacing Fatica and some Allenamento; then **option 1 must also be tested** — Fatica costs a stripe when walked through as well as when stopped on (breaks D10 for that square only). Options 3 (fewer paths: board rework) and 4 (fewer / once-per-room Allenamento) kept in reserve. The casual bot (6.0.1) is built regardless | Q6. Any on-stop penalty is avoidable when a move reaches ~24 end squares; the chance outcome cannot be dodged. Developer likes 1 and 2. |
| D34 | The "games finished within 200 rounds: 100%" target does not apply to the `random` lineup (it is a floor, not a player: 94% finished, 115 rounds on average) | 6.1 review. |
| D35 | **No Kumite in round 1**: opponents are treated like meditating pawns (pass through, extra step if the move would end on one, no Tunnel exit onto them, Sfida has no target; Irimi still works). `RulesConfig.first_kumite_round = 2`. RULES.md v0.8 | 6.1 review, finding 3: later seats find opponents already outside their Safe Rooms and early equal-belt Kumite are nearly free. |
| D36 | **Fatica on crossing is the baseline**: every Fatica square stepped onto while walking costs 1 stripe (last step and Meditazione extra step included, before any Kumite on it); stopping adds nothing; teleports and relocations cost nothing. `RulesConfig.fatica_on_crossing = True`. Supersedes the order in D33 (the chance square, option 2, remains a candidate). Paths to the same end square are offered separately when they cross Fatica differently. RULES.md v0.8 | 6.1 review, finding 4. |
| D37 | Out of contention = more than **3 belts** (9 stripes) behind the leader (`metrics.CONTENTION_BELTS`); the targets (≤ 20% of player-turns, worst player ≤ 35%) now apply to this threshold | 6.1 review, finding 1: one Kumite swings two players 6 stripes apart, so 2 belts was too strict. |
| D38 | Catch-up: only candidate **A** (Allenamento gives +2 instead of +1 to a player 2+ belts behind the leader) is to be simulated. Rejected: bounty on the leader, belt bonus capped at +1, more Sensei Osserva | 6.1 review, finding 1. |
| D39 | Game length is tuned **last**; target stays a mean of 60–90 minutes at 4 players | 6.1 review, finding 2. |
| D40 | Bots stay as they are for Phase 6 (casual included, although much weaker than the heuristic bots) | Q7. |
| D41 | Phase 6 order: board and Fatica (6.4 with 6.5) → seat order (6.2) → catch-up (6.9) → style dynamics (6.3) → Kiai (6.6), player counts (6.7), length → consolidation (6.8). Structural fixes before tuning | 6.1 review. |
| D42 | **Board draft 2 adopted** as `board/quadrant.txt` (`board/board.txt` regenerated; draft 1 is in git history, commit 4998931) | 6.4.0 results. |
| D43 | **6.2 seat order suspended**: measuring it needs 4,000+ games per scenario for an effect of a few points; D35 (no Kumite in round 1) stays in the rules. Seat rates are still reported by every run and watched in 6.8 | Developer, after the 4,000-game runs were started. |
## Phases
### Phase 0 — Rules consolidation
- [x] 0.1 Write `RULES.md` v0.4 with variants A/B marked.
- [x] 0.2 `RULES.md` v0.5: mandatory effects, Tecnica secrecy, edge rules and FAQ (D25–D27).
### Phase 1 — Project scaffold and board format
- [x] 1.1 `uv init` project (package `dojo`), Python version pinned via uv; dev deps: pytest, ruff. No runtime deps (legend in TOML, parsed with stdlib `tomllib`).
- [x] 1.2 `board/FORMAT.md` — the format specification:
- [x] ASCII grid: `+` corners, `|` vertical walls, `---` horizontal walls, 3-char cells with a centred code.
- [x] Cell codes: `S` safe room, `D` dojo, `.` `A` `F` `?` `P` `K` (Allenamento/Fatica were `+`/`-`, changed so no code looks like a wall), digits = tunnel pair ids.
- [x] Outer border must be fully walled.
- [x] Dojo entrance = open edge between a `D` cell and a non-`D` cell.
- [x] Cross-quadrant tunnel links declared in `board/legend.toml`.
- [x] 1.3 Parser: `quadrant.txt` → cell grid + wall set.
- [x] 1.4 Generator: rotate the quadrant 90°/180°/270° around the board centre → full 16×16 model; write `board/board.txt` (generated, never hand-edited).
- [x] 1.5 Graph model: cells as nodes, open edges as links. The Dojo is handled as one cell set (impassable, entrances = open D/non-D edges); treating it as a single space for movement lands in the rules engine (3.3).
- [x] 1.6 Validator:
- [x] every non-Dojo square reachable from every Safe Room;
- [x] each Safe Room has exactly 2 exits, on different sides;
- [x] no Safe Room lies on a shortest path between two other points (not a shortcut);
- [x] every tunnel id has exactly one partner;
- [x] Dojo has ≥1 entrance per quadrant;
- [x] report: square-type mix and Tatami %, shortest distance from each start to the Dojo.
- [x] 1.7 CLI: `uv run dojo board validate`, `uv run dojo board render`.
- [x] 1.8 Unit tests for parser, rotation, validator.
### Phase 2 — First board
- [x] 2.1 Draft the first quadrant (`board/quadrant.txt`), following D7, D9, D18.
- [x] 2.2 Validate and iterate until clean.
- [x] 2.3 Developer review of the layout (approved as draft 1).
### Phase 3 — Rules engine
- [x] 3.1 Game state: pawns, track positions, hands, deck/discard, meditation status, turn order.
- [x] 3.2 Rule configuration object: variant A/B, Kiai value, stripes per belt, starting position, player count.
- [x] 3.3 Movement enumeration: all legal exact-length self-avoiding walks, with Kumite on crossing, chain continuation, Dojo entry with ≥1 step left, Meditazione extra step.
- [x] 3.4 Kumite resolution: gap bonus cap, Senshu, Tecnica timing, consequences table per variant, Uke placement.
- [x] 3.5 Square effects and Nebbia cards (all 13 card types).
- [x] 3.6 Final Exam.
- [x] 3.7 Unit tests covering every edge rule in `RULES.md` (`tests/test_engine.py`, `tests/test_movement.py`; mutation-checked: breaking Senshu, bonus cap, chain continuation, Meditazione step, variant B cap, Safe Room or meditator immunity each fails tests).
- Code: `src/dojo/rules.py` (config, variants, deck), `movement.py` (walks), `engine.py` (Game, Agent protocol, Randomness), `events.py` (event log for metrics).
### Phase 4 — Bots
- [x] 4.0 Hidden information: agents receive a `GameView` snapshot (`Game.view(player)`), never the `Game`: opponents' Tecnica shows only as `holds_tecnica`; the event log (which records `CardDrawn`) is not visible to agents (D26).
- [x] 4.1 Random bot (baseline): `RandomAgent(rng)` in `src/dojo/bots.py`.
- [x] 4.2 Heuristic bot: `HeuristicAgent(profile)`. Value = track position; once Brown, plus `DOJO_PULL` (0.3) per step closer to the Dojo. Scores each offered path as the expected value change over the chain of Kumite (exact 1d6-vs-1d6 odds with belt bonus and Senshu, ±0.1 per Tecnica held), then the stop square's effect (Nebbia worth 0.2, Sfida = best target, Tunnel = better of staying/exit). Exam = 100 × pass chance. Tecnica played only when losing (Kiai only if it turns the fight). Known simplifications: Meditazione extra step, Passo Falso origin after a chain, opponents' replies.
- [x] 4.3 Profiles (`PROFILES`): losses weighted by `risk`, opponents' value changes by `rivalry`, Tecnica keep order. balanced (1.0, 0.5, Kiai>Kaeshi>Uke), farmer (2.5, 0.2, Uke first), aggressive (0.5, 1.0).
- Smoke run (60 seeds, real board, 1 heuristic vs 3 random): heuristic wins 58–60/60 for every profile and both variants; ~20–22 rounds; ~1,300–1,450 turns/s. Four heuristic bots: ~18.7 rounds. Finding to check in Phase 5/6: attacking a higher belt risks nothing for a non-Brown player (losing costs 0 stripes; Start is no worse than elsewhere), so every profile attacks upward.
### Phase 5 — Simulator and metrics
- [x] 5.1 Monte Carlo runner over a config matrix; seeded and reproducible. `src/dojo/sim.py`: `Scenario` (variant × players × Kiai bonus × start position × lineup), `matrix`, `run(files, scenarios, games, seed, jobs)`. Game `i` uses seed `base + i` in every scenario (same dice across scenarios); the lineup rotates one seat per game; process pool, results independent of `jobs`.
- [x] 5.2 Metrics (`src/dojo/metrics.py`, computed from the event log; Kumite counts exclude the Exam):
- [x] game length in rounds and estimated minutes (45 s per turn + 30 s per Kumite);
- [x] Kumite per round, upset rate, higher-beats-lower rate, longest chain per game (Kumite attacked by the active player in one turn);
- [x] win rate by seat and by bot profile (per seat occupied);
- [x] exam attempts per game, exam success rate;
- [x] turns started on 14, longest streak (variant B deadlock check);
- [x] net stripe income per turn: squares vs cards vs Kumite vs Exam; square income in the player's own quadrant vs elsewhere (home farming);
- [x] lead changes per game (strict leader), final spread.
- [x] 5.3 Report output: `uv run dojo sim` prints a text summary per scenario; `--csv` writes one row per game (`src/dojo/report.py`). Commands in `README.md`.
- Baseline (1,000 games per variant, 4 players, lineup balanced/farmer/aggressive, seed 0), for Phase 6:
| Metric | A | B |
|---|---|---|
| Rounds mean (p10–p90) | 18.4 (14–23) | 13.1 (9–17) |
| Minutes mean (p10–p90) | 66 (50–85) | 46 (33–62) |
| Kumite per round | 1.25 | 1.16 |
| Upsets / higher beats lower | 29% / 55% | 27% / 52% |
| Exam attempts per game, pass rate | 1.26, 79% | 1.22, 82% |
| Turns on 14 per game, longest streak | 1.26, 4 | 1.73, 7 |
| Income per turn: square (home / away), card, Kumite | +0.52 (0.38 / 0.14), 0.00, +0.04 | +0.54 (0.39 / 0.14), 0.00, +0.22 |
| Lead changes, final spread | 5.6, 9.3 | 3.5, 11.5 |
| Wins by seat | 23–27% | 23–27% |
- [x] 5.4 Follow-up to the baseline review (D28–D30):
- [x] remove variant B; `--variant` replaced by `--exam` (Exam options, `RulesConfig.exam_ties_to_defender / exam_defender_black / exam_rounds`); "turns on 14" metric removed with it;
- [x] income per source as gains / losses;
- [x] one-sidedness measures, sampled at turn ends: (1) gap 1st–2nd (mean per game) and winner margin over the best rival at the end; (2) share of turns the winner led; (3) halfway leader wins; (4) point of the game of the last lead change; (5) rivals within one belt of the winner at the end; (6) share of player-turns more than two belts behind the leader, and the worst player's share; (7) rank swaps between any two players; (8) Kumite lost by the leader; (9) distinct Exam challengers; (10) winner's own turns to reach Brown.
- After 5.4 (300 games per option, 4 players, lineup balanced/farmer/aggressive, seed 0):
| Metric | none | a | c | d |
|---|---|---|---|---|
| Rounds mean (p10–p90) | 18.5 (14–23) | 19.3 (14–25) | 21.9 (16–29) | 18.0 (14–22) |
| Minutes mean | 67 | 70 | 80 | 66 |
| Exam pass rate, attempts per game | 81%, 1.24 | 67%, 1.50 | 44%, 2.28 | 91%, 1.10 |
| Distinct challengers per game | 1.13 | 1.24 | 1.58 | 1.06 |
| Winner margin at the end | 4.7 | 4.6 | 3.9 | 4.8 |
| Halfway leader wins | 40% | 41% | 40% | 41% |
| Rivals within one belt at the end | 0.32 | 0.37 | 0.62 | 0.30 |
| Player-turns out of contention | 22% | 22% | 21% | 22% |
Also measured: Kumite moves +0.44 / −0.40 stripes per turn; heuristic bots almost never stop on Fatica (square losses 0.0002 per turn vs 0.08 for random bots): with 2d6 and many paths an Allenamento is nearly always reachable. Seat 3 (last in turn order) won 28–31% in every option.
### Phase 6 — Balance experiments
**Method** (applies to every step):
- Runs use `uv run dojo sim`. Default 1,000 games per scenario (a 25% win rate is then known to about ±1.4 pp); 4,000 games where seat effects are measured (about ±0.7 pp).
- Compared scenarios share seeds (`--seed 0`), so differences come from the rules, not the dice.
- Every conclusion is checked on at least two lineups (mixed `balanced,farmer,aggressive`, and one same-style lineup), because results depend on bot quality.
- One change at a time. When a change is adopted, re-run the 6.1 baseline so later steps start from the current rules, and log the decision (D-number) here and in `RULES.md`.
- Results go in this file as a table per step (command line, scenario, key measures).
**Next action:** 6.9 catch-up candidate A, when the developer says to continue. 6.2 is suspended (D43); 6.4.1 (chance square) stays optional. Order of the steps: D41. Everything up to D43 and RULES.md v0.8 is committed; commit only when the developer asks. 6.0, 6.1, D35 and D36 are not committed yet; commit only when the developer asks.
**Targets** (confirmed by the developer as a starting point, D32):
| Measure | Target |
|---|---|
| Minutes, 4 players | mean 60–90, p90 ≤ 110 |
| Exam pass rate | 35–55% |
| Halfway leader wins (4 players) | 35–55% |
| Player-turns out of contention | ≤ 20%; worst player mean ≤ 35% |
| Rivals within one belt of the winner at the end | ≥ 0.5 |
| Win rate by seat, 4 players | each 25% ± 3 pp |
| Win rate by bot style (mixed lineup) | spread ≤ 6 pp |
| Games finished within 200 rounds | 100%, every lineup |
**Steps:**
- [x] 6.0 Tooling needed by the experiments
- [x] 6.0.1 "Casual" bot: the heuristic bot scoring only a small random sample of the offered moves (sample size is a parameter, default 6), as a stand-in for a human who cannot compare ~24 end squares every move. Added to `BOTS` as `casual`. Done: `CasualAgent(rng, profile=BALANCED, sample=CASUAL_SAMPLE)` in `bots.py`; only `choose_path` is sampled, and the sample is blind (a path into the Dojo is taken only if drawn).
- [x] 6.0.2 `--summary-csv PATH`: one row per scenario with the summary measures, to compare scenarios side by side. Done: `report.write_summary_csv`; spreads become `<name>_mean/_p10/_median/_p90`, income `<source>_gain/loss_per_turn`, seats `seat<i>_<stat>`, bots `win_rate_<bot>`; columns missing in a scenario are empty.
- [x] 6.0.3 Seat breakdown in the summary: per seat, mean final track, Exam attempts, and share of games where that seat defended the Exam (for 6.2). Done: `GameMetrics.final_track / exam_attempts_by_seat / exam_defences_by_seat` (tuples, comma-joined in the games CSV), `Summary.seats` (`SeatSummary`), one `Seat i` line per seat in the text report.
- [x] 6.0.4 Square reachability measure: share of moves where an Allenamento / Fatica end square is reachable, and mean distinct end squares per move (the Phase 6 probe, made a metric; for 6.4). Done: the engine emits `MoveOptions(player, ends)` (square codes of the distinct end squares) before every path choice in `_move` (first choice, after a won Kumite, Tsugi Ashi; not the Meditazione extra step); report line `Move options`.
- [x] 6.1 Baseline on rules v0.7 (Exam c): 4 players, 1,000 games, lineups mixed / `balanced` / `casual` / `random`. Record the table; check it against the targets.
- Command: `uv run dojo sim --games 1000 --seed 0 --lineup balanced,farmer,aggressive balanced casual random --summary-csv ... --csv ...` (~2 min on all cores).
| Measure (target) | mixed | balanced | casual | random |
|---|---|---|---|---|
| Finished within 200 rounds (100%) | 100% | 100% | 100% | **94%** |
| Rounds mean (p10–p90) | 21.8 (15–29) | 22.2 (15–30) | 24.9 (17–34) | 115 (67–179) |
| Minutes mean (60–90), p90 (≤ 110) | 79, 108 | 81, **110.5** | 83, **114** | 365, 569 |
| Kumite per round; upsets | 1.24; 29% | 1.26; 30% | 0.66; 28% | 0.36; 23% |
| Exam attempts per game; pass rate (35–55%) | 2.33; 43% | 2.45; 41% | 2.39; 42% | 2.24; 42% |
| Halfway leader wins (35–55%) | 39% | 38% | 38% | 29% |
| Player-turns out of contention (≤ 20%) | **21%** | **21%** | 17% | 19% |
| Worst player's share out, mean (≤ 35%) | **44%** | **43%** | **40%** | **39%** |
| Rivals within one belt at the end (≥ 0.5) | 0.60 | 0.57 | 1.22 | 1.46 |
| Winner margin; lead changes | 4.0; 7.0 | 4.0; 7.4 | 2.4; 5.3 | 1.4; 13.2 |
| Win rate by seat 0–3 (25% ± 3 pp) | 24 / 23 / 24 / 28 | 25 / 22 / 26 / 27 | 26 / 23 / 26 / 26 | 23 / 23 / 24 / 23 |
| Win rate by style (spread ≤ 6 pp) | aggr. 25, bal. 27, farmer 22 (5 pp) | — | — | — |
| Income per turn: square, card, Kumite (gain / loss), Exam loss | +0.51/0, +0.01/0, +0.43/−0.40, −0.05 | same ±0.01 | +0.53/0, +0.01/−0.01, +0.24/−0.23, −0.04 | +0.19/−0.08, +0.02/−0.01, +0.12/−0.12, −0.01 |
| Square income home / away | +0.38 / +0.14 | +0.38 / +0.13 | +0.36 / +0.17 | +0.07 / +0.05 |
| End squares per move; can end on Allenamento / Fatica | 23.9; 78% / 76% | 23.9; 78% / 76% | 24.5; 83% / 80% | 24.0; 81% / 78% |
| Seat 3: Exam attempts per game (others) | 0.65 (0.55–0.57) | 0.67 (0.58–0.61) | 0.62 (0.56–0.63) | 0.56 (0.53–0.60) |
Findings:
- Met: pass rate, halfway leader, rivals within one belt, style spread, seats (mixed seat 3 at the edge, 28%).
- Missed: the worst player's time out of contention (40–44%, target ≤ 35%) on every lineup; overall time out 21% for heuristic lineups; p90 minutes slightly over 110 for `balanced` and `casual`.
- `random` does not finish 6% of games in 200 rounds (115 rounds on average): it is a floor, not a player; the "100% finished" target is read as applying to the other lineups.
- Seat 3 makes more Exam attempts in the heuristic lineups (0.65–0.67 vs ≤ 0.61) and not with `random`: first lead for 6.2.
- Fatica is reachable on 76% of moves but heuristic bots still avoid it (square losses ≈ 0), confirming Q6; the casual bot also avoids it, since 6 sampled moves nearly always include a better one.
- The casual bot fights half as often (0.66 Kumite/round) and gives closer games (winner margin 2.4, 1.22 rivals within one belt).
- Q7 follow-up (1,000 games, seed 0): `casual,balanced` → balanced 36%, casual 14% per seat; `casual,casual,casual,balanced` → balanced 46%, casual 18%. The blind sample of 6 is far weaker than the heuristic bot.
- Seat probe (4,000 games, scratch script, not in the repo): Kumite attacked in rounds 1–2 per game by seat 0/1/2/3 = 0.25 / 0.40 / 0.54 / 0.67 (mixed lineup), 0.03–0.05 for every seat with `random`; mean track after round 3 = 2.04 / 2.04 / 2.35 / 2.50. Later seats find opponents already out of their Safe Rooms, and an early equal-belt Kumite is nearly free for the attacker (Senshu 58%, and a loss at track 0–2 costs at most what is there). Matches the developer's hypothesis; candidate fixes to be proposed in 6.2.
- Developer review: D34–D41.
- Re-baseline on rules v0.8 (D35, D36, 3-belt threshold D37), 1,000 games, seed 0, each rule alone against v0.7, after the Dojo-closing fix below (scratch script: `Scenario` configs with the two switches replaced; the CLI has no switch for them):
| Measure | v0.7 | + Fatica on crossing | + no Kumite in round 1 | v0.8 (both) |
|---|---|---|---|---|
| Minutes mean / p90, mixed | 79 / 108 | 83 / 114 | 78 / 107 | 83 / 114 |
| Minutes mean / p90, balanced | 81 / 111 | 79 / 109 | 80 / 110 | 78 / 108 |
| Minutes mean / p90, casual | 83 / 114 | **126 / 173** | 83 / 114 | **127 / 174** |
| Square gain / loss per turn: mixed; casual | +0.51 / 0.00; +0.53 / 0.00 | +0.52 / −0.05; +0.45 / −0.12 | = v0.7 | +0.52 / −0.05; +0.45 / −0.12 |
| Kumite per round: mixed; casual | 1.24; 0.66 | 1.03; 0.51 | 1.23; 0.65 | 1.02; 0.51 |
| Exam pass rate, mixed | 43% | 44% | 44% | 44% |
| Out of contention (3 belts): share; worst player, mixed | 5.1%; 15% | 5.2%; 16% | 5.1%; 15% | 5.1%; 15% |
| Win rate by seat 0–3, mixed | 24 / 23 / 24 / 29 | 30 / 21 / 22 / 27 | 24 / 24 / 25 / 28 | **29 / 23 / 20 / 28** |
| Win rate by seat 0–3, balanced | 25 / 22 / 26 / 27 | 24 / 23 / 24 / 30 | 24 / 24 / 26 / 26 | 25 / 24 / 23 / 29 |
| Win rate by seat 0–3, casual | 26 / 23 / 26 / 26 | 25 / 25 / 24 / 26 | 26 / 23 / 26 / 24 | 25 / 25 / 24 / 26 |
Fix found while planning Dojo tolls: a Brown player (15) walking a Fatica drops to 14 and must not enter the Dojo on that move (the belt changes at once, FAQ). `_path_choices` no longer offers such Dojo paths (`_still_brown_at_dojo`; a Kumite won on the way re-offers paths). The first run without the fix differed by ≤ 3 minutes and ≤ 2 pp per seat.
Findings: (1) at 3 belts the contention targets are met with a wide margin (5% of player-turns, worst player 10–15%). (2) Fatica on crossing on the current board (5 F per quadrant, 20 in all, 10% of the squares) barely touches the heuristic bots (−0.03 to −0.05 per turn) but costs the casual bot −0.12 per turn and adds ~44 minutes (127 mean, p90 174): the board has too many Fatica on ordinary routes for players who do not plan around them. (3) No Kumite in round 1 alone moves seat 3 by about 1 pp (within the ±1.4 pp noise of 1,000 games); 6.2 measures it on 4,000 games. (4) Mixed v0.8 shows seat 0 at 30% and seat 2 at 20%: not seen in the same-bot lineups; to confirm in 6.2 before reading anything into it.
- [ ] 6.2 Seat order — **suspended (D43)**; runs stopped before any result (monitor; developer concerned): 4,000 games, 4 players, lineups mixed and `random`; 2,000 games at 3 and 6 players. If a seat is outside 25% ± 3 pp, diagnose with the 6.0.3 breakdown (hypotheses: moving last means seeing everyone else move first; Exam defender selection; Sensei / Peso cards) and bring candidate fixes to the developer. No fix without agreement.
- [ ] 6.3 Style dynamics: same-style lineups (`farmer`, `aggressive`, `balanced`, `casual`) and one-against-three (`aggressive,farmer,farmer,farmer`, `farmer,aggressive,aggressive,aggressive`, `balanced,farmer,farmer,farmer`). Watch: all-farmer stalling (length, games finished, Kumite per round), a dominant style, time out of contention.
- [ ] 6.4 Fatica and the square economy (D33; Fatica on crossing became the baseline, D36; board draft 2 adopted, D42). Each candidate is a board draft in `board/drafts/` (new square codes need `Square`, `board/FORMAT.md`, validator stats and `RULES.md` entries) and/or a `RulesConfig` switch, compared with the 6.1 baseline on square gains / losses per turn, reachability (6.0.4), game length, style win rates, casual vs heuristic gap:
- [x] 6.4.0 Board draft 2 (drafted as `board/drafts/quadrant-2.txt`, now `board/quadrant.txt`), built for Fatica on crossing. Principles approved by the developer: Fatica as tolls on short routes, fewer Fatica, Allenamento away from the Safe Rooms (covers 6.5), validator / Tatami 30–40% / 11-step walk / tunnels kept; judged on casual minutes (≤ ~93, i.e. v0.7 casual + 10) and heuristic bots paying some tolls.
- Method: walls of draft 1 kept (approved layout); only square codes changed. Route analysis showed every square on a shortest Safe Room → Dojo walk has a detour of at most 1 step, so "detour 2–4" is not reachable without wall changes; tolls were placed by measured traffic instead (bots' walks per square, home players vs visitors, on the board without Fatica). Home players load the row-3 corridor and the inner Dojo approach (5,5); visitors load the ring next to the Dojo.
- Variants (1,000 games, seed 0, v0.8; scratch scripts `routes.py`, `traffic.py`, `recode.py`, `rules_compare.py`):
| Board | Fatica (per quadrant) | Minutes mean / p90: mixed; casual | Square gain / loss per turn: mixed; casual | Home share of square income: mixed; casual | Seats 0–3, mixed |
|---|---|---|---|---|---|
| draft 1 (v0.7 rules, reference) | 5, on stop | 79 / 108; 83 / 114 | +0.51 / 0; +0.53 / 0 | 74%; 69% | 24 / 23 / 24 / 28 |
| draft 1 | 5 | 83 / 114; 127 / 174 | +0.52 / −0.05; +0.45 / −0.12 | 74%; 76% | 29 / 23 / 20 / 28 |
| 2a | 3: (3,4), (5,5), (7,4) | 73 / 99; 110 / 152 | +0.66 / −0.09; +0.55 / −0.16 | 68%; 69% | 25 / 24 / 25 / 26 |
| 2b | 2: (3,4), (5,5) | 72 / 98; 89 / 121 | +0.62 / −0.05; +0.58 / −0.09 | 70%; 68% | 23 / 28 / 24 / 25 |
| 2c | 1: (7,4); Allenamento 16 | 73 / 98; 82 / 112 | +0.59 / −0.02; +0.60 / −0.06 | 68%; 65% | 24 / 23 / 26 / 27 |
| **2d = draft 2** | 2: (3,4), (5,5); A moved to the ring | 72 / 95; 91 / 122 | +0.64 / −0.05; +0.58 / −0.10 | 67%; 62% | 23 / 27 / 27 / 23 |
**Current baseline** (rules v0.8, board draft 2) = the draft 2 row above plus the balanced lineup: 68 / 92 minutes, +0.64 / −0.03, home 67%, seats 22 / 23 / 27 / 28. Square mix per quadrant: Tatami 20 (39%), Allenamento 14, Nebbia 8 (16%, up from 6), Fatica 2, Passo Falso 2, Sfida 1, Tunnel 4.
- Reading: casual within the ~93-minute bound (91); heuristic bots pay tolls (−0.03 to −0.05); every lineup 68–72 minutes, inside 60–90. Home share down from 74% to 62–67%, not to 60%: players spend most turns crossing their own quadrant, so placement alone reaches its limit. Seat rates move by ±4 pp between variants at 1,000 games: noise, measured properly in 6.2. Adopted by the developer (D42); `board/drafts/` removed.
- [ ] 6.4.1 Option 2, chance square: new code (proposal `C`, name to choose with the developer, e.g. "Sorte" / "Randori") — on stop roll 1d6, 1–2 → −1 stripe, 3–6 → +1. Draft: replace every Fatica and some Allenamento with it (start: all F plus about a third of A, keep the square mix inside the validator's Tatami range). Bot: value = expected change (+1/3 stripe, risk-weighted: gain 2/3, loss 1/3). Try variations of the split (e.g. 1–3 / 4–6) if income is off.
- [x] 6.4.2 Option 1, Fatica on crossing: `RulesConfig.fatica_on_crossing` — each Fatica square entered during a move costs 1 stripe, **1 in total per square whether or not the move stops there** (developer, D33); stopping on it adds nothing more. Engine: apply in `_walk` per square entered (not on teleports / relocations, which never walk). Bot: count Fatica crossed in `_path_score`. Likely needs fewer Fatica squares; test on the current board and on a draft with fewer F. Done as the baseline rule (D36): engine `_step` / `_path_choices`, bot `_path_score`, tests; measured on the current board in the 6.1 re-baseline.
- [ ] 6.4.3 If 6.4.1 is run: compare it with the v0.8 baseline on draft 2 (Fatica on crossing, D36) and bring the table to the developer for a decision (then `RULES.md` and D-number).
- [x] 6.5 Home farming: covered by board draft 2 (6.4.0): Allenamento moved from the south training room onto the Dojo ring; own-quadrant share of square income 74% → 62–67%, short of the 60% aim (players cross their own quadrant for most of the game); draft 2 adopted as is (D42). Original step: after 6.4, if the own-quadrant share of square income is still above 60% (baseline: 71%), move Allenamento squares away from the Safe Rooms in a board draft (`dojo sim --quadrant board/drafts/...`) and compare. The board must still pass `dojo board validate`.
- [ ] 6.6 Kiai +2 vs +1: 1,000 games each on two lineups. Watch the Exam pass rate, upset rate and how often a Tecnica turns a fight.
- [ ] 6.7 Player counts: 3 / 4 / 6 / 8 players, start 0; plus start 3 at 6 and 8 players. Minutes per count; decide whether 6+ players start on Yellow.
- [ ] 6.9 Catch-up candidate A (D38), next in the order (D41; 6.2 suspended, D43): `RulesConfig` switch, Allenamento +2 for a player 2+ belts behind the leader (bot aware of it); compare on the contention, lead and length measures and on the style win rates.
- [ ] 6.8 Consolidation: the final configuration at 3 / 4 / 6 / 8 players with all lineups, 2,000 games each; every target checked; `RULES.md` v0.8 with the decisions; open items moved to Phase 7.
### Phase 7 — Finalisation (later)
- [ ] 7.1 Freeze rules.
- [ ] 7.2 Italian edition.
- [ ] 7.3 Physical tracking method and components; printable board.
- [ ] Tunnel pairs need unique labels on the printed board (the text format repeats each digit in all 4 quadrants).
## Questions
### Resolved
- Tie rule → Senshu (attacker wins).
- Several opponents on one square → impossible (loser is teleported); only exception handled by the Meditazione extra-step rule.
- Exam loss → −3 and Start; defender gains nothing.
- Tunnel → teleport optional on stop, movement over.
- Optional vs mandatory effects → D25.
- Engine edge rules → D27.
- Sfida squares → keep, balance via low count.
- Il Peso della Cintura → keep (1 card).
- Player count → focus 4, support 3–8.
- Tests → the agent runs the suite (`uv run pytest`), plus `ruff check`, `ruff format --check`, `pyright`.
- Minutes estimate → 45 s per turn, +30 s per Kumite.
- Q4 Target net income per turn → current pace is fine: A already runs ~66 min (p90 ~85); the winner's pace is measured instead of a table average.
- Variant A vs B → B dropped (D28).
- Final Exam → the defender fights as a Black belt (D31).
- Q5 Phase 6 targets → confirmed as a starting point (D32).
- Q6 Fatica avoidable (bots stop on it once in ~4,000 turns; ~24 distinct end squares per move; Allenamento reachable on 79% of moves, Fatica never forced) → test the chance square first, then Fatica on crossing (D33).
- Q7 Casual bot sample size → the blind sample of 6 is far weaker than the heuristic bot (14–18% vs 36–46% win rate per seat); bots stay as they are (D40).
- Safe Room placement → the owner places the pawn on any square of their room (setup and when sent to Start).
### Open
- Q2 Board asymmetry: keep the quadrant as source of truth, or later switch to the full board as source of truth with a symmetry *report* (warnings) instead of generation? *(Deferred by the developer.)*
### Risks
- Movement enumeration: self-avoiding walks of length up to 12 can explode in open rooms. Keep rooms small; prune by outcome (destination + ordered opponents crossed + Dojo entry).
- Engine speed ~1,400 turns/s (random and heuristic bots, real board). If Phase 5 needs more: precompute neighbour lists in `Board`.
- Simulation conclusions depend on bot quality; compare several profiles before trusting a result.
- Board draft 1 puts 4 Allenamento in each 3x3 room next to the Safe Room: possible "home farming" (see the Phase 2 review). Measured (Phase 5 baseline): square income is +0.38/turn in the own quadrant vs +0.14/turn elsewhere; 6.5 decides whether that is a problem. Board draft 2 (D42) moved them to the Dojo ring: 62–67%.
## External documentation
- uv — https://docs.astral.sh/uv/ — project init, dependency and Python version management.
- Python `tomllib` — https://docs.python.org/3/library/tomllib.html — stdlib TOML parser for `legend.toml`.
- pytest — https://docs.pytest.org/ — unit tests.
- Ruff — https://docs.astral.sh/ruff/ — lint and format.
- WKF Kumite competition rules (wkf.net, "Rules") — source of the Senshu concept.