Files
dojo_cate/agents/plans/2026-09-25-dojo-board-and-sim.md
T
eisterman f0e112590a Record 6.3 style dynamics results
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-27 17:23:28 +02:00

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

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: developer review of the 6.3 results; then 6.6 Kiai, when the developer says to continue. 6.2 is suspended (D43), 6.9 skipped (D44); 6.4.1 (chance square) stays optional. Order of the steps: D41. Everything up to 6.10 and D46 is committed (0ca905e); the 6.3 results 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 — 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.

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

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

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: 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