Files
dojo_cate/agents/plans/2026-09-25-dojo-board-and-sim.md
T
eisterman 84673c573d Add the Italian playtest edition (7.2.0, D53)
RULES.it.md translates RULES.md v0.9. edition/build.py renders a
printable A4 HTML (edition/it/playtest.html): quick reference, rules,
belt track, board overview and four board tiles drawn from the board
model (Tunnel pairs numbered, Dojo entrances marked), and the 22 Nebbia
cards. Adds markdown as a dev dependency.

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

64 KiB
Raw Blame History

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.
D44 6.9 catch-up skipped: the v0.8 baseline already has 3–4% of player-turns out of contention (worst player 10–13%), so candidate A has little to fix; dropped from RULES.md "variants under test" (never implemented) Developer, after the v0.8 baseline metrics.
D45 The random lineup is no longer run in experiments: it never finishes a game and cost ~80% of a run's time. The bot stays in the code and the tests Developer, 6.10.
D46 Performance work must leave every game identical (same events for the same seed), so every result recorded in this file stays valid Developer, 6.10.
D47 Kiai stays +2: +2 and +1 are indistinguishable on every target (6.6); +2 decides more fights (5% vs 3% of Kumite in casual play). kiai_bonus = 1 stays a simulator switch; RULES.md drops the "+1 to be tested" note Developer, 6.6 results.
D48 6+ players start on 3 (Yellow); any player count may start on 3 as a "shorter game" option (saves 15–20% of the time, 6.7). 8 players stays long (107 / 142 min mixed / casual from Yellow) and is accepted: it will rarely be played. Balancing simulations stay at start 0 at every count (developer); --start 3 reproduces the rules' 6+ setup or the shorter game Developer, 6.7 results.
D49 Chance square parked (6.4.1 and 6.4.3): Fatica on crossing (D36) on board draft 2 (D42) already makes squares matter; 6.4 closed Developer.
D50 Length accepted as is; a failed Exam still costs 3 stripes. L1 (Brown floor against Fatica) rejected; L2 (failed Exam −1 / 0) saves only 3–5 min on the mean and weakens comebacks (6.11.4). exam_failure_loss stays a simulator switch. At 4 players mixed and balanced are inside the target; casual (91 / 122) and all-aggressive (90 / 127) stay slightly outside, within the "1–2 h" promise; the shorter-game start on Yellow (D48) is the players' lever Developer, 6.11 results.
D51 Bots decide alike in every corner (start square and tied paths broken in the player's own frame), overriding D40 for this bias: the old tie-break by absolute board order made corners 1 and 2 win 25–28% and corners 0 and 3 23% Developer, 6.2.1 diagnosis.
D52 No first-player compensation: the seat order stays as it is. At 4 players every seat is inside 25% ± 3 pp; +1 stripe for the first player gains about 1 point (6.2.4), not worth an extra rule. first_player_bonus stays a simulator switch (no CLI axis) Developer, 6.2.4 results.
D53 Italian playtest edition format: source RULES.it.md (full rules, without the tested alternatives) plus edition/it/riepilogo.md and edition/it/carte.toml; edition/build.py renders one local printable A4 HTML (edition/it/playtest.html): quick reference, rules, belt track, board overview plus four A4 tiles, 22 cut-out cards. Board drawn from the board model; card copies from the engine's deck. Japanese names keep an Italian gloss ("Uke (Parata)"). Glossary: stripe = tacca, track = scala delle cinture, Safe Room = Stanza Sicura, Start = Partenza, round = giro, attacker / defender = attaccante / difensore Developer (format, printable board, gloss, local HTML only).

Phases

Phase 0 — Rules consolidation

  • 0.1 Write RULES.md v0.4 with variants A/B marked.
  • 0.2 RULES.md v0.5: mandatory effects, Tecnica secrecy, edge rules and FAQ (D25–D27).

Phase 1 — Project scaffold and board format

  • 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).
  • 1.2 board/FORMAT.md — the format specification:
    • ASCII grid: + corners, | vertical walls, --- horizontal walls, 3-char cells with a centred code.
    • 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.
    • Outer border must be fully walled.
    • Dojo entrance = open edge between a D cell and a non-D cell.
    • Cross-quadrant tunnel links declared in board/legend.toml.
  • 1.3 Parser: quadrant.txt → cell grid + wall set.
  • 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).
  • 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).
  • 1.6 Validator:
    • every non-Dojo square reachable from every Safe Room;
    • each Safe Room has exactly 2 exits, on different sides;
    • no Safe Room lies on a shortest path between two other points (not a shortcut);
    • every tunnel id has exactly one partner;
    • Dojo has ≥1 entrance per quadrant;
    • report: square-type mix and Tatami %, shortest distance from each start to the Dojo.
  • 1.7 CLI: uv run dojo board validate, uv run dojo board render.
  • 1.8 Unit tests for parser, rotation, validator.

Phase 2 — First board

  • 2.1 Draft the first quadrant (board/quadrant.txt), following D7, D9, D18.
  • 2.2 Validate and iterate until clean.
  • 2.3 Developer review of the layout (approved as draft 1).

Phase 3 — Rules engine

  • 3.1 Game state: pawns, track positions, hands, deck/discard, meditation status, turn order.
  • 3.2 Rule configuration object: variant A/B, Kiai value, stripes per belt, starting position, player count.
  • 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.
  • 3.4 Kumite resolution: gap bonus cap, Senshu, Tecnica timing, consequences table per variant, Uke placement.
  • 3.5 Square effects and Nebbia cards (all 13 card types).
  • 3.6 Final Exam.
  • 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

  • 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).
  • 4.1 Random bot (baseline): RandomAgent(rng) in src/dojo/bots.py.
  • 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.
  • 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

  • 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.

  • 5.2 Metrics (src/dojo/metrics.py, computed from the event log; Kumite counts exclude the Exam):

    • game length in rounds and estimated minutes (45 s per turn + 30 s per Kumite);
    • Kumite per round, upset rate, higher-beats-lower rate, longest chain per game (Kumite attacked by the active player in one turn);
    • win rate by seat and by bot profile (per seat occupied);
    • exam attempts per game, exam success rate;
    • turns started on 14, longest streak (variant B deadlock check);
    • net stripe income per turn: squares vs cards vs Kumite vs Exam; square income in the player's own quadrant vs elsewhere (home farming);
    • lead changes per game (strict leader), final spread.
  • 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%
  • 5.4 Follow-up to the baseline review (D28–D30):

    • 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;
    • income per source as gains / losses;
    • 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: the developer's playtest with the Italian edition (7.2.0); then 7.2.1 and 7.1. 6.9 skipped (D44), 6.4.1 parked (D49). Everything up to D52 is committed; 7.2.0 and D53 are not; 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:

  • 6.0 Tooling needed by the experiments

    • 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).
    • 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.
    • 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.
    • 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.
  • 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 (closed: D51, D52) — reopened by the developer after 6.8.4 (was 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.2.1 Diagnosis, 4 players, mixed lineup, 4,000 games per run (scratch seats.py). Seat and corner are the same at 4 players, so the run was repeated with the corners rotated by 1, 2, 3 seats and averaged, separating turn order from board position:

      Averaged over Win rate 0 / 1 / 2 / 3 First to Brown Track after round 1 Net Kumite stripes per game Attacked per game in rounds 2–3
      seats (turn order) 23.9 / 24.2 / 25.5 / 26.4 23.9 / 24.0 / 25.7 / 26.4 0.74 / 0.76 / 0.76 / 0.76 +0.08 / +0.44 / +0.79 / +1.12 0.95 / 0.78 / 0.54 / 0.41
      corners (board position) 23.3 / 27.6 / 25.5 / 23.6 22.6 / 30.4 / 25.4 / 21.6 0.70 / 0.81 / 0.81 / 0.69 +0.56 / +0.54 / +0.49 / +0.84 0.64 / 0.76 / 0.70 / 0.57
      • Corner effect (the larger one, 23–28%) is a bot artifact: bots.start_square breaks the tie between equally distant Safe Room squares by absolute (row, col), so in the quadrant's own frame corners 0 and 3 start on (1, 2) and corners 1 and 2 on (2, 1), which is the better square. The board itself is symmetric. It also shows that the Safe Room squares are not equivalent (a player picks where to start, RULES.md "Safe areas").
      • Turn-order effect (smaller, 24 → 26%, within the 25% ± 3 pp target): later seats are attacked less early in the game (rounds 2–3: 0.95 vs 0.41 times) and end up +1 stripe from Kumite over a game. The earlier seats walk into the open first and the later ones answer.
      • Other bot tie-breaks (max over paths offered in N, E, S, W order) are also orientation-dependent; not measured yet.
    • 6.2.2 Bot fix (developer, D51): bots.start_square breaks ties in the Safe Room's own frame (every corner starts from (2, 1) in the quadrant frame, the better square); HeuristicAgent.place_pawn uses it; HeuristicAgent.choose_path breaks score ties by the path in the player's own frame (bots.best_of, bots.own_frame). Tests: same start square from every corner, tied paths chosen alike from every corner. Every game changes (fingerprints must be re-recorded; earlier tables stay as recorded, measured with the biased bots).

      • Re-run of 6.2.1 with the fix (4 × 4,000 games): corners 24.0 / 25.3 / 25.4 / 25.4 (was 23.3–27.6), track after round 1 equal (0.80–0.81); seats 24.3 / 24.6 / 25.4 / 25.7. Attacked in rounds 2–3 still 0.81 / 0.59 / 0.39 / 0.27 by seat.
    • 6.2.3 Seat order with the fixed bots (dojo sim, start 0; 4,000 games at 4 players, 2,000 at 3 / 6 / 8):

      Players Fair share mixed, seats in turn order casual, seats in turn order
      3 33.3 30.6 / 33.7 / 35.7 34.0 / 32.0 / 34.0
      4 25.0 23.2 / 25.5 / 25.5 / 25.8 24.0 / 26.0 / 25.7 / 24.3
      6 16.7 13.4 / 17.3 / 16.4 / 15.4 / 17.9 / 19.6 15.2 / 16.1 / 16.2 / 16.2 / 19.0 / 17.2
      8 12.5 10.1 / 11.5 / 12.0 / 13.5 / 12.0 / 12.5 / 13.8 / 14.6 10.8 / 12.6 / 11.9 / 13.1 / 12.2 / 13.9 / 11.7 / 14.0

      Mixed 4 players now takes 68 min (72 with the biased bots). Reading: the first seat is 1–3 points under its fair share at every count (more with heuristic than casual bots); at 4 players every seat is inside 25% ± 3 pp. At 6 players the two seats alone in a corner (seats 4 and 5, seat_corners(6) = 0, 1, 0, 1, 2, 3) win 17–20%, the four sharing a Safe Room 13–17%.

    • 6.2.4 First-player compensation, +1 stripe (developer's choice to test): RulesConfig.first_player_bonus (default 0; RulesConfig.start_track(seat) used by the engine and the metrics). No sim axis yet (scratch bonus.py, same seeds as 6.2.3; the bonus-0 rows reproduce 6.2.3 exactly).

      Players Lineup First seat, bonus 0 → 1 (fair share) All seats with bonus 1 Minutes 0 → 1
      3 mixed 30.6 → 33.2 (33.3) 33.2 / 32.5 / 34.2 53 → 52
      3 casual 34.0 → 33.8 33.8 / 30.9 / 35.4 70 → 70
      4 mixed 23.2 → 22.6 (25.0) 22.6 / 25.2 / 26.0 / 26.2 68 → 68
      4 casual 24.0 → 25.4 25.4 / 25.9 / 24.4 / 24.3 90 → 90
      6 mixed 13.3 → 14.8 (16.7) 14.8 / 17.3 / 14.8 / 14.9 / 18.1 / 20.1 101 → 100
      6 casual 15.2 → 16.1 16.1 / 16.8 / 15.4 / 16.2 / 19.3 / 16.1 130 → 131
      8 mixed 10.1 → 10.7 (12.5) 10.7 / 12.3 / 10.8 / 12.6 / 12.3 / 14.4 / 13.8 / 13.1 130 → 128
      8 casual 10.8 → 12.0 12.0 / 12.1 / 12.6 / 13.1 / 12.2 / 12.0 / 13.6 / 12.4 168 → 168

      Reading: +1 stripe lifts the first seat by about 1 point on average (−0.6 to +2.6; the noise is ±0.7–1 point), not enough to close the gap at 6–8 players with heuristic bots, and nothing at 4 players mixed. No other seat is hurt systematically; length unchanged.

  • 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.

    • Run: uv run dojo sim --games 1000 --seed 0 --lineup farmer aggressive balanced casual aggressive,farmer,farmer,farmer farmer,aggressive,aggressive,aggressive balanced,farmer,farmer,farmer (rules v0.8, board draft 2, 4 players; 17 s on 16 workers).

      Lineup Minutes mean / p90 Kumite / round Square gain / loss per turn Halfway leader wins Out of contention; worst player Rivals within 1 belt Win rate by bot
      farmer ×4 63 / 81 0.80 +0.71 / −0.01 34% 1%; 4% 1.47 —
      aggressive ×4 90 / 127 1.32 +0.56 / −0.13 41% 8%; 21% 0.50 —
      balanced ×4 68 / 92 1.04 +0.64 / −0.03 39% 3%; 10% 0.81 —
      casual ×4 91 / 122 0.61 +0.58 / −0.10 39% 4%; 12% 1.42 —
      aggressive + 3 farmer 68 / 92 0.94 +0.67 / −0.04 43% 3%; 11% 1.14 aggressive 26%, farmer 25%
      farmer + 3 aggressive 81 / 117 1.20 +0.60 / −0.10 42% 7%; 20% 0.64 farmer 24%, aggressive 26%
      balanced + 3 farmer 64 / 84 0.87 +0.69 / −0.01 36% 2%; 7% 1.24 balanced 29%, farmer 24%

      All games finished; Exam pass rate 42–43% everywhere.

    • Reading: no stalling (all-farmer is the shortest game). No dominant style: a lone bot wins 24–26%, except balanced among farmers at 29% (±1.4 pp at 1,000 games, so a real but small edge; the style spread target, ≤ 6 pp, holds). More aggression makes games longer and less close: all-aggressive is the only heuristic lineup over the p90 limit (127 min) and at the edge of the rivals target (0.50); fights cost stripes both ways (+0.45 / −0.43 per turn) and aggressive bots also pay more Fatica (−0.13). Input for the length tuning (D39).

  • 6.4 Fatica and the square economy (closed: D49) (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:

    • 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 Parked (D49). 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.

    • 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 Parked (D49). 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).

  • 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. Kiai stays +2 (D47).

    • 6.6.1 Metric: GameMetrics.tecnica_kumite, kiai_decided, exam_fights, exam_kiai_decided; report line "Tecnica". A fight is decided by Kiai when the result flips with the Kiai bonus removed, dice and other cards unchanged. The tie rule moved to RulesConfig.attacker_wins, shared by the engine and the metric (fingerprinted games identical).

    • 6.6.2 Run: uv run dojo sim --games 1000 --seed 0 --kiai 2 1 --lineup balanced,farmer,aggressive balanced casual.

      Lineup Kiai Minutes mean / p90 Exam passed Upsets Tecnica played in; Kiai decided (Kumite / Exam) Halfway leader wins Rivals within 1 belt
      mixed +2 72 / 95 40% 31% 2%; 1% / 1% 40% 0.84
      mixed +1 72 / 95 41% 31% 2%; 1% / 1% 41% 0.85
      balanced +2 68 / 92 42% 30% 2%; 1% / 1% 39% 0.81
      balanced +1 69 / 93 41% 30% 2%; 1% / 1% 39% 0.82
      casual +2 91 / 122 43% 27% 12%; 5% / 5% 39% 1.42
      casual +1 91 / 121 44% 27% 10%; 3% / 4% 39% 1.38
    • Reading: Kiai +2 and +1 are indistinguishable on every target measure (≤ 1 pp, inside the noise). Tecnica are rare: heuristic bots draw a Nebbia card on 2.3% of turns (0.5 Tecnica per game; Nebbia is worth 0.2 to them, below an Allenamento), casual bots on 9.7% (3.3 Tecnica per game). Even for casual play Kiai decides 5% (+2) vs 3% (+1) of Kumite. Scratch script tecnica.py (200 games per lineup).

  • 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+ players start on Yellow; shorter-game option for any count (D48).

    • Run: uv run dojo sim --games 1000 --seed 0 --players 3 4 6 8 --start 0 3 --lineup balanced,farmer,aggressive casual (48 s).

      Players Start Minutes mean / p90: mixed; casual Rounds: mixed; casual Halfway leader wins: mixed; casual Out of contention; worst player (mixed) Rivals within 1 belt: mixed; casual Wins by bot (mixed)
      3 0 55 / 75; 71 / 99 20.7; 28.9 49%; 45% 3%; 9% 0.61; 1.05 34 / 34 / 31
      3 3 46 / 67; 59 / 84 17.4; 24.2 50%; 46% 3%; 8% 0.65; 1.05 34 / 35 / 31
      4 0 72 / 95; 91 / 122 20.4; 27.5 40%; 39% 4%; 13% 0.84; 1.42 24 / 26 / 24
      4 3 57 / 80; 77 / 110 16.2; 23.5 42%; 40% 4%; 12% 0.85; 1.47 24 / 25 / 26
      6 0 107 / 145; 136 / 182 19.4; 26.4 32%; 27% 9%; 29% 1.19; 1.92 17 / 16 / 17
      6 3 86 / 127; 113 / 161 15.8; 22.1 30%; 29% 8%; 28% 1.16; 1.96 15 / 18 / 17
      8 0 133 / 181; 170 / 231 17.8; 24.3 26%; 20% 11%; 37% 1.41; 2.16 13 / 14 / 11
      8 3 107 / 152; 142 / 200 14.5; 20.5 27%; 24% 10%; 38% 1.53; 2.29 13 / 14 / 11

      Wins by bot: aggressive / balanced / farmer. All games finished; Exam pass rate 40–44% everywhere.

    • Reading: rounds stay ~15–29 whatever the count, so table time grows with the number of players (45 s per turn): 6 players take ~1.5x and 8 players ~1.9x the 4-player time. Starting on 3 saves ~3–4 rounds (15–20% of the time) at every count, and changes no other measure by more than a few points. At 6–8 players the worst player is out of contention 28–40% of turns (4-player target ≤ 35%), and the halfway leader wins less (20–32%): more players, more Kumite (2–3 per round), more reshuffling. 8 players on casual stays above 2 hours even from Yellow (142 min).

  • 6.10 Simulation speed (before 6.3; D46: games unchanged). Profile: ~95% of the time was listing moves (movement._extend, Board.neighbours, the outcome keys in Engine._path_choices).

    • 6.10.1 Guard: agents/scripts/fingerprint_games.py hashes every event of 210 games (mixed / casual at 4 players, 6 players, Fatica on stop with Kumite in round 1, random bots, 60-round cap); write before an engine change, check after. A tool for refactoring and speed work, not a test (rule changes are expected to differ). Timings came from a scratch benchmark.
    • 6.10.2 Board: neighbour table, squares per code and Safe Rooms computed once (cached_property); neighbour order N, E, S, W kept (the random and casual bots pick by position in the offered list). Engine: Fatica squares as a set (_tolls), opponents' squares looked up once per move (_fightable_squares), and paths crossing no opponent keyed by their Fatica count with C-level set operations.
    • 6.10.3 movement.walks: walks that exclude nothing but the start are cached per (board, start, steps, Dojo open) with functools.cache (same pattern as bots.dojo_distance); callers get a fresh list. ~3,200 entries per process, ~80 MB peak.
    • 6.10.4 Parallel scaling: 8 processes running at once each take ~1.6x their solo time on this machine (8 real cores, clock and cache sharing), so ~5x on 8 workers is the hardware limit; no pool change. 16 workers (hyperthreads) add ~12%.
    • Result: 100 games on one process 8–12 s → 1.4–1.7 s; mixed + balanced + casual at 1,000 games on 16 workers 57 s → 8 s. All 210 fingerprinted games identical; the v0.8 baseline run prints the same metrics.
  • 6.11 Length tuning (D39; closed by D50): at 4 players, bring every lineup to a mean of 60–90 minutes with p90 ≤ 110 (v0.8: mixed 72 / 95 and balanced 68 / 92 inside; casual 91 / 122 and all-aggressive 90 / 127 outside). Find where the time goes (climb to Brown vs Exam phase), bring candidate levers to the developer, simulate the chosen ones on at least two lineups.

    • 6.11.1 Where the time goes (scratch phases.py, 400 games per lineup; "endgame" = from the first Brown on the table to the win):

      Lineup Climb / endgame (min) Winner's stripes gained (15 needed) Drops out of Brown per game Stripes lost per game: square / Kumite / Exam
      mixed 49 / 22 (31%) 23.3 2.2 3.9 / 27.8 / 4.3
      balanced 48 / 21 (30%) 22.6 2.2 2.4 / 26.6 / 4.3
      casual 56 / 36 (39%) 24.7 4.0 11.2 / 23.1 / 4.4
      aggressive 60 / 32 (35%) 28.6 2.7 12.4 / 42.7 / 4.4

      Casual and aggressive are longer in both phases, most of all in the endgame (+11 to +15 min): casual players fall out of Brown twice as often (Fatica tolls, 11 stripes per game), aggressive ones trade stripes in Kumite (43 lost per game).

    • 6.11.2 Existing switches (--start, --exam), 1,000 games, 4 players, minutes mean / p90:

      Setting mixed balanced casual aggressive
      v0.8 (start 0) 72 / 95 68 / 92 91 / 122 90 / 127
      start 1 68 / 92 65 / 87 88 / 122 88 / 124
      start 2 63 / 88 59 / 83 81 / 112 82 / 122
      start 3 57 / 80 — 77 / 110 74 / 111
      Exam defender not Black (none) 60 / 77 — 79 / 103 74 / 97

      The start position shifts every lineup by about the same amount, so it cannot close the ~23-minute gap between balanced and casual: start 2 puts balanced under 60 while aggressive stays at p90 122. The Black-belt defender off pushes the Exam pass rate to 67–80% (target 35–55%) and the rivals at the end to 0.27–0.49: rejected again (as in D31). Other measures barely move with the start position.

    • 6.11.3 Candidate levers brought to the developer: L1 Fatica cannot drop a player out of Brown (rejected by the developer); L2 a failed challenger loses 0 or 1 stripe instead of 3 (to test); L3 accept the current length (developer: "satisfied enough").

    • 6.11.4 L2 switch: RulesConfig.exam_failure_loss (default 3; engine and bot _exam_score), sim axis Scenario.exam_loss / --exam-loss (scenario names gain fail-N). Fingerprinted games identical at the default. Run: uv run dojo sim --games 1000 --seed 0 --exam-loss 3 1 0 --lineup balanced,farmer,aggressive balanced casual aggressive.

      Lineup Failed Exam loses Minutes mean / p90 Exam challengers per game Lead changes Halfway leader wins Worst player out Rivals within 1 belt
      mixed 3 72 / 95 1.68 6.1 40% 13% 0.84
      mixed 1 68 / 88 1.48 5.0 44% 15% 0.94
      mixed 0 67 / 86 1.45 4.6 44% 16% 0.87
      balanced 3 68 / 92 1.69 6.0 39% 10% 0.81
      balanced 1 65 / 84 1.50 5.0 43% 12% 0.97
      balanced 0 65 / 83 1.46 4.5 43% 13% 0.90
      casual 3 91 / 122 1.74 5.7 39% 12% 1.42
      casual 1 87 / 116 1.61 4.9 42% 13% 1.47
      casual 0 86 / 114 1.55 4.6 41% 14% 1.40
      aggressive 3 90 / 127 1.58 7.3 41% 21% 0.50
      aggressive 1 85 / 115 1.40 6.2 45% 23% 0.59
      aggressive 0 83 / 111 1.32 5.8 49% 25% 0.54

      Exam pass rate unchanged (40–44%). Reading: −1 saves 3–5 minutes on the mean and 6–12 on the p90; 0 adds only 1–2 more. The price is the comeback: the first Brown keeps retrying instead of dropping back (fewer different challengers), lead changes fall by ~1 per game, the halfway leader wins 3–8 points more, the worst player is out a little longer. No setting brings casual under p90 110.

  • 6.9 Catch-up candidate A — skipped (D44). Was: 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 (start 0 as for balancing, plus start 3 at 6 and 8 as in the rules, D48) with all lineups except random (D45), 2,000 games each; every target checked; RULES.md updated to the next version with the decisions; open items moved to Phase 7.

    • 6.8.1 First run, with the biased bots (before D51; superseded by 6.8.6) (rules v0.9 = v0.8 + D47–D50, board draft 2; 2,000 games per scenario, 3 min 27 s): uv run dojo sim --games 2000 --seed 0 --players 3 4 6 8 --start 0 --lineup balanced,farmer,aggressive balanced casual aggressive, and the same with --players 6 8 --start 3. All games finished; Exam pass rate 41–44% everywhere; win rate by bot style (mixed) within 4 pp at every count.

      Players Start Lineup Minutes mean / p90 Exam passed Halfway leader wins Out of contention; worst player Rivals within 1 belt Win rate by seat
      3 0 mixed 54 / 75 42% 50% 3%; 9% 0.60 29 / 37 / 34
      3 0 balanced 53 / 72 42% 46% 3%; 7% 0.59 33 / 34 / 34
      3 0 casual 71 / 98 44% 45% 2%; 6% 1.04 33 / 33 / 34
      3 0 aggressive 64 / 90 42% 52% 6%; 14% 0.36 29 / 34 / 37
      4 0 mixed 72 / 98 41% 40% 4%; 13% 0.86 24 / 27 / 26 / 24
      4 0 balanced 68 / 92 42% 40% 3%; 11% 0.82 22 / 26 / 26 / 26
      4 0 casual 91 / 123 43% 38% 4%; 12% 1.41 22 / 27 / 24 / 26
      4 0 aggressive 90 / 128 42% 43% 8%; 21% 0.51 21 / 26 / 29 / 24
      6 0 mixed 106 / 144 42% 31% 9%; 29% 1.17 12 / 16 / 15 / 18 / 20 / 20
      6 0 balanced 100 / 135 42% 30% 8%; 28% 1.07 13 / 17 / 13 / 18 / 19 / 20
      6 0 casual 135 / 182 42% 27% 8%; 27% 1.90 16 / 15 / 15 / 16 / 20 / 18
      6 0 aggressive 131 / 183 42% 29% 12%; 35% 0.78 13 / 19 / 14 / 17 / 20 / 17
      8 0 mixed 133 / 183 42% 27% 11%; 37% 1.44 9 / 12 / 11 / 12 / 13 / 13 / 14 / 15
      8 0 balanced 127 / 172 43% 25% 11%; 38% 1.30 9 / 11 / 11 / 13 / 13 / 13 / 14 / 15
      8 0 casual 170 / 231 44% 23% 11%; 38% 2.15 12 / 12 / 12 / 13 / 14 / 12 / 14 / 12
      8 0 aggressive 167 / 234 43% 25% 16%; 43% 1.01 9 / 13 / 11 / 14 / 14 / 12 / 15 / 13
      6 3 mixed 85 / 123 42% 31% 8%; 28% 1.16 13 / 17 / 13 / 17 / 20 / 20
      6 3 balanced 81 / 115 42% 29% 7%; 28% 1.17 15 / 15 / 15 / 17 / 21 / 18
      6 3 casual 113 / 160 42% 30% 8%; 28% 1.92 14 / 16 / 15 / 16 / 19 / 20
      6 3 aggressive 106 / 158 42% 32% 12%; 38% 0.81 11 / 18 / 14 / 18 / 22 / 18
      8 3 mixed 107 / 150 42% 27% 10%; 38% 1.51 10 / 12 / 10 / 13 / 14 / 13 / 14 / 13
      8 3 balanced 101 / 145 42% 28% 11%; 40% 1.35 10 / 12 / 11 / 12 / 15 / 14 / 13 / 13
      8 3 casual 144 / 203 42% 24% 11%; 40% 2.33 11 / 12 / 11 / 13 / 13 / 13 / 14 / 13
      8 3 aggressive 135 / 202 41% 27% 17%; 49% 1.05 10 / 12 / 10 / 14 / 14 / 14 / 14 / 13
    • 6.8.2 Targets at 4 players (start 0; first run, see 6.8.6 for the final figures): inside for mixed and balanced on every measure. Accepted misses (D50): casual 91 / 123 and aggressive 90 / 128 minutes; aggressive seats 21–29% and rivals 0.51 (edge). 3 players: short (53–71 min), halfway leader wins 45–52% (edge of 35–55%), rivals 0.36–0.60 with heuristic bots. 6–8 players: long (D48 accepted), worst player out 27–49% of turns, halfway leader wins 23–32%.

    • 6.8.3 RULES.md v0.9: D47–D50 in the text; "Rule variants under test" replaced by "Tested alternatives" (the simulator switches).

    • 6.8.4 Seat order (finding; studied in 6.2, closed by D51 and D52): the first seat is behind at every count, and more so with more players — 4 players 21–24% (fair 25%), 6 players 11–16% (fair 17%), 8 players 9–12% (fair 12.5%); later seats rise to 20% (6) and 15% (8). At 6 players seats 4 and 5 are the two players alone in a corner (seat_corners gives 0, 1, 0, 1, 2, 3) and win most (17–22%), so sharing a Safe Room costs too. 6.2 (suspended, D43) would be the step to study it.

    • 6.8.5 Open items moved to Phase 7 (7.0).

    • 6.8.6 Final run with the fixed bots (D51, D52; same commands as 6.8.1). All games finished; Exam pass rate 40–44% everywhere; bot-style spread (mixed) 2–4 pp.

      Players Start Lineup Minutes mean / p90 Exam passed Halfway leader wins Out of contention; worst player Rivals within 1 belt Win rate by seat Bot spread
      3 0 mixed 53 / 72 41% 50% 2%; 6% 0.71 31 / 34 / 36 4 pp
      3 0 balanced 51 / 70 40% 48% 1%; 4% 0.74 31 / 32 / 37 —
      3 0 casual 70 / 97 44% 45% 2%; 5% 1.06 34 / 32 / 34 —
      3 0 aggressive 61 / 86 41% 52% 4%; 11% 0.45 33 / 33 / 35 —
      4 0 mixed 67 / 91 42% 43% 3%; 11% 0.95 23 / 25 / 26 / 26 3 pp
      4 0 balanced 65 / 86 42% 38% 2%; 8% 0.96 24 / 25 / 26 / 25 —
      4 0 casual 90 / 122 43% 38% 3%; 10% 1.48 24 / 26 / 26 / 24 —
      4 0 aggressive 82 / 114 41% 40% 6%; 17% 0.65 22 / 26 / 26 / 27 —
      6 0 mixed 101 / 135 42% 33% 8%; 27% 1.27 13 / 17 / 16 / 15 / 18 / 20 3 pp
      6 0 balanced 96 / 128 42% 30% 7%; 25% 1.23 14 / 16 / 15 / 17 / 18 / 20 —
      6 0 casual 130 / 176 44% 29% 7%; 25% 1.91 15 / 16 / 16 / 16 / 19 / 17 —
      6 0 aggressive 121 / 167 41% 31% 11%; 32% 0.96 15 / 15 / 16 / 16 / 18 / 20 —
      8 0 mixed 130 / 171 43% 25% 10%; 34% 1.56 10 / 12 / 12 / 13 / 12 / 12 / 14 / 15 3 pp
      8 0 balanced 123 / 164 43% 25% 10%; 36% 1.41 11 / 11 / 12 / 13 / 14 / 13 / 13 / 13 —
      8 0 casual 168 / 224 44% 23% 10%; 36% 2.25 11 / 13 / 12 / 13 / 12 / 14 / 12 / 14 —
      8 0 aggressive 154 / 212 43% 27% 14%; 42% 1.18 11 / 11 / 11 / 14 / 13 / 11 / 15 / 14 —
      6 3 mixed 80 / 111 43% 33% 6%; 25% 1.35 15 / 14 / 17 / 17 / 18 / 19 3 pp
      6 3 balanced 77 / 106 42% 30% 6%; 24% 1.29 14 / 15 / 16 / 18 / 19 / 18 —
      6 3 casual 108 / 150 44% 30% 7%; 26% 1.97 16 / 15 / 16 / 16 / 18 / 19 —
      6 3 aggressive 95 / 136 43% 34% 10%; 34% 1.01 14 / 16 / 15 / 19 / 18 / 18 —
      8 3 mixed 102 / 144 43% 28% 8%; 34% 1.68 10 / 12 / 10 / 14 / 13 / 13 / 14 / 14 2 pp
      8 3 balanced 97 / 138 42% 28% 10%; 37% 1.49 11 / 10 / 12 / 12 / 15 / 14 / 14 / 12 —
      8 3 casual 140 / 198 43% 25% 10%; 38% 2.39 12 / 11 / 12 / 14 / 11 / 13 / 15 / 12 —
      8 3 aggressive 122 / 178 41% 28% 14%; 45% 1.27 10 / 12 / 12 / 14 / 12 / 15 / 13 / 12 —
      • Targets at 4 players: mixed (67 / 91) and balanced (65 / 86) inside on every measure; seats 22–27% in every lineup. Accepted misses (D50): casual 90 / 122 (mean at the edge, p90 over), aggressive 82 / 114 (p90 over). Rivals within one belt 0.65–1.48.
      • 3 players: 51–70 min; halfway leader wins 45–52% (edge); rivals 0.45–1.06. 6–8 players: long (D48), worst player out 24–45% of turns, halfway leader wins 23–34%; from Yellow, 6 players take 77–108 min.

Phase 7 — Finalisation (later)

  • 7.0 Open items carried over from Phase 6 (none blocks 7.1):
    • Q2 board asymmetry (deferred by the developer).
    • 6.4.1 chance square (parked, D49).
    • Heuristic bots draw a Nebbia card on only 2.3% of turns (6.6): card effects are measured mostly through the casual bot.
    • Remaining small bot tie-breaks by absolute board order (Tunnel destination; the engine keeps the first path per outcome): corner residual 24.0–25.4% after D51.
    • At 6 players the two seats alone in a Safe Room win 17–20% vs 13–17% for the four sharing (6.2.3); accepted with D52.
  • 7.1 Freeze rules.
  • 7.2 Italian edition.
    • 7.2.0 Playtest edition (D53): RULES.it.md translated from RULES.md v0.9; quick reference; edition/build.py (dev dependency markdown) writes edition/it/playtest.html, 15 A4 pages when printed (checked by printing to PDF with headless Chromium): quick reference, rules (5 pages), belt track, board overview, 4 board tiles (23 mm squares, Tunnel pairs numbered 1–8 across the board, Dojo entrances marked in gold), 3 card sheets (63 × 88 mm). No card backs.
    • 7.2.1 Playtest feedback folded into RULES.md and RULES.it.md.
  • 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): numbered 1–8 by edition/build.py.

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: after 6.10, ~65 games/s per process (heuristic and casual bots). Further gains would need changing the move enumeration itself (e.g. grouping walks by outcome), not attempted.
  • Simulation conclusions depend on bot quality; compare several profiles before trusting a result.
  • Home farming: board draft 2 (D42) moved the Allenamento onto the Dojo ring; the own-quadrant share of square income is 62–67% (draft 1: 74%), above the 60% aim because players cross their own quadrant for most of the game. Accepted with draft 2 (6.5).

External documentation