52d8af620b
RulesConfig.exam_failure_loss (bots aware) with the sim axis --exam-loss. Losing 1 or 0 stripes saves 3-5 minutes but weakens comebacks, so the rules keep -3. Default games are unchanged. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
416 lines
49 KiB
Markdown
416 lines
49 KiB
Markdown
# 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. |
|
||
|
||
## Phases
|
||
|
||
### Phase 0 — Rules consolidation
|
||
|
||
- [x] 0.1 Write `RULES.md` v0.4 with variants A/B marked.
|
||
- [x] 0.2 `RULES.md` v0.5: mandatory effects, Tecnica secrecy, edge rules and FAQ (D25–D27).
|
||
|
||
### Phase 1 — Project scaffold and board format
|
||
|
||
- [x] 1.1 `uv init` project (package `dojo`), Python version pinned via uv; dev deps: pytest, ruff. No runtime deps (legend in TOML, parsed with stdlib `tomllib`).
|
||
- [x] 1.2 `board/FORMAT.md` — the format specification:
|
||
- [x] ASCII grid: `+` corners, `|` vertical walls, `---` horizontal walls, 3-char cells with a centred code.
|
||
- [x] Cell codes: `S` safe room, `D` dojo, `.` `A` `F` `?` `P` `K` (Allenamento/Fatica were `+`/`-`, changed so no code looks like a wall), digits = tunnel pair ids.
|
||
- [x] Outer border must be fully walled.
|
||
- [x] Dojo entrance = open edge between a `D` cell and a non-`D` cell.
|
||
- [x] Cross-quadrant tunnel links declared in `board/legend.toml`.
|
||
- [x] 1.3 Parser: `quadrant.txt` → cell grid + wall set.
|
||
- [x] 1.4 Generator: rotate the quadrant 90°/180°/270° around the board centre → full 16×16 model; write `board/board.txt` (generated, never hand-edited).
|
||
- [x] 1.5 Graph model: cells as nodes, open edges as links. The Dojo is handled as one cell set (impassable, entrances = open D/non-D edges); treating it as a single space for movement lands in the rules engine (3.3).
|
||
- [x] 1.6 Validator:
|
||
- [x] every non-Dojo square reachable from every Safe Room;
|
||
- [x] each Safe Room has exactly 2 exits, on different sides;
|
||
- [x] no Safe Room lies on a shortest path between two other points (not a shortcut);
|
||
- [x] every tunnel id has exactly one partner;
|
||
- [x] Dojo has ≥1 entrance per quadrant;
|
||
- [x] report: square-type mix and Tatami %, shortest distance from each start to the Dojo.
|
||
- [x] 1.7 CLI: `uv run dojo board validate`, `uv run dojo board render`.
|
||
- [x] 1.8 Unit tests for parser, rotation, validator.
|
||
|
||
### Phase 2 — First board
|
||
|
||
- [x] 2.1 Draft the first quadrant (`board/quadrant.txt`), following D7, D9, D18.
|
||
- [x] 2.2 Validate and iterate until clean.
|
||
- [x] 2.3 Developer review of the layout (approved as draft 1).
|
||
|
||
### Phase 3 — Rules engine
|
||
|
||
- [x] 3.1 Game state: pawns, track positions, hands, deck/discard, meditation status, turn order.
|
||
- [x] 3.2 Rule configuration object: variant A/B, Kiai value, stripes per belt, starting position, player count.
|
||
- [x] 3.3 Movement enumeration: all legal exact-length self-avoiding walks, with Kumite on crossing, chain continuation, Dojo entry with ≥1 step left, Meditazione extra step.
|
||
- [x] 3.4 Kumite resolution: gap bonus cap, Senshu, Tecnica timing, consequences table per variant, Uke placement.
|
||
- [x] 3.5 Square effects and Nebbia cards (all 13 card types).
|
||
- [x] 3.6 Final Exam.
|
||
- [x] 3.7 Unit tests covering every edge rule in `RULES.md` (`tests/test_engine.py`, `tests/test_movement.py`; mutation-checked: breaking Senshu, bonus cap, chain continuation, Meditazione step, variant B cap, Safe Room or meditator immunity each fails tests).
|
||
- Code: `src/dojo/rules.py` (config, variants, deck), `movement.py` (walks), `engine.py` (Game, Agent protocol, Randomness), `events.py` (event log for metrics).
|
||
|
||
### Phase 4 — Bots
|
||
|
||
- [x] 4.0 Hidden information: agents receive a `GameView` snapshot (`Game.view(player)`), never the `Game`: opponents' Tecnica shows only as `holds_tecnica`; the event log (which records `CardDrawn`) is not visible to agents (D26).
|
||
- [x] 4.1 Random bot (baseline): `RandomAgent(rng)` in `src/dojo/bots.py`.
|
||
- [x] 4.2 Heuristic bot: `HeuristicAgent(profile)`. Value = track position; once Brown, plus `DOJO_PULL` (0.3) per step closer to the Dojo. Scores each offered path as the expected value change over the chain of Kumite (exact 1d6-vs-1d6 odds with belt bonus and Senshu, ±0.1 per Tecnica held), then the stop square's effect (Nebbia worth 0.2, Sfida = best target, Tunnel = better of staying/exit). Exam = 100 × pass chance. Tecnica played only when losing (Kiai only if it turns the fight). Known simplifications: Meditazione extra step, Passo Falso origin after a chain, opponents' replies.
|
||
- [x] 4.3 Profiles (`PROFILES`): losses weighted by `risk`, opponents' value changes by `rivalry`, Tecnica keep order. balanced (1.0, 0.5, Kiai>Kaeshi>Uke), farmer (2.5, 0.2, Uke first), aggressive (0.5, 1.0).
|
||
- Smoke run (60 seeds, real board, 1 heuristic vs 3 random): heuristic wins 58–60/60 for every profile and both variants; ~20–22 rounds; ~1,300–1,450 turns/s. Four heuristic bots: ~18.7 rounds. Finding to check in Phase 5/6: attacking a higher belt risks nothing for a non-Brown player (losing costs 0 stripes; Start is no worse than elsewhere), so every profile attacks upward.
|
||
|
||
### Phase 5 — Simulator and metrics
|
||
|
||
- [x] 5.1 Monte Carlo runner over a config matrix; seeded and reproducible. `src/dojo/sim.py`: `Scenario` (variant × players × Kiai bonus × start position × lineup), `matrix`, `run(files, scenarios, games, seed, jobs)`. Game `i` uses seed `base + i` in every scenario (same dice across scenarios); the lineup rotates one seat per game; process pool, results independent of `jobs`.
|
||
- [x] 5.2 Metrics (`src/dojo/metrics.py`, computed from the event log; Kumite counts exclude the Exam):
|
||
- [x] game length in rounds and estimated minutes (45 s per turn + 30 s per Kumite);
|
||
- [x] Kumite per round, upset rate, higher-beats-lower rate, longest chain per game (Kumite attacked by the active player in one turn);
|
||
- [x] win rate by seat and by bot profile (per seat occupied);
|
||
- [x] exam attempts per game, exam success rate;
|
||
- [x] turns started on 14, longest streak (variant B deadlock check);
|
||
- [x] net stripe income per turn: squares vs cards vs Kumite vs Exam; square income in the player's own quadrant vs elsewhere (home farming);
|
||
- [x] lead changes per game (strict leader), final spread.
|
||
- [x] 5.3 Report output: `uv run dojo sim` prints a text summary per scenario; `--csv` writes one row per game (`src/dojo/report.py`). Commands in `README.md`.
|
||
- Baseline (1,000 games per variant, 4 players, lineup balanced/farmer/aggressive, seed 0), for Phase 6:
|
||
|
||
| Metric | A | B |
|
||
|---|---|---|
|
||
| Rounds mean (p10–p90) | 18.4 (14–23) | 13.1 (9–17) |
|
||
| Minutes mean (p10–p90) | 66 (50–85) | 46 (33–62) |
|
||
| Kumite per round | 1.25 | 1.16 |
|
||
| Upsets / higher beats lower | 29% / 55% | 27% / 52% |
|
||
| Exam attempts per game, pass rate | 1.26, 79% | 1.22, 82% |
|
||
| Turns on 14 per game, longest streak | 1.26, 4 | 1.73, 7 |
|
||
| Income per turn: square (home / away), card, Kumite | +0.52 (0.38 / 0.14), 0.00, +0.04 | +0.54 (0.39 / 0.14), 0.00, +0.22 |
|
||
| Lead changes, final spread | 5.6, 9.3 | 3.5, 11.5 |
|
||
| Wins by seat | 23–27% | 23–27% |
|
||
|
||
- [x] 5.4 Follow-up to the baseline review (D28–D30):
|
||
- [x] remove variant B; `--variant` replaced by `--exam` (Exam options, `RulesConfig.exam_ties_to_defender / exam_defender_black / exam_rounds`); "turns on 14" metric removed with it;
|
||
- [x] income per source as gains / losses;
|
||
- [x] one-sidedness measures, sampled at turn ends: (1) gap 1st–2nd (mean per game) and winner margin over the best rival at the end; (2) share of turns the winner led; (3) halfway leader wins; (4) point of the game of the last lead change; (5) rivals within one belt of the winner at the end; (6) share of player-turns more than two belts behind the leader, and the worst player's share; (7) rank swaps between any two players; (8) Kumite lost by the leader; (9) distinct Exam challengers; (10) winner's own turns to reach Brown.
|
||
- After 5.4 (300 games per option, 4 players, lineup balanced/farmer/aggressive, seed 0):
|
||
|
||
| Metric | none | a | c | d |
|
||
|---|---|---|---|---|
|
||
| Rounds mean (p10–p90) | 18.5 (14–23) | 19.3 (14–25) | 21.9 (16–29) | 18.0 (14–22) |
|
||
| Minutes mean | 67 | 70 | 80 | 66 |
|
||
| Exam pass rate, attempts per game | 81%, 1.24 | 67%, 1.50 | 44%, 2.28 | 91%, 1.10 |
|
||
| Distinct challengers per game | 1.13 | 1.24 | 1.58 | 1.06 |
|
||
| Winner margin at the end | 4.7 | 4.6 | 3.9 | 4.8 |
|
||
| Halfway leader wins | 40% | 41% | 40% | 41% |
|
||
| Rivals within one belt at the end | 0.32 | 0.37 | 0.62 | 0.30 |
|
||
| Player-turns out of contention | 22% | 22% | 21% | 22% |
|
||
|
||
Also measured: Kumite moves +0.44 / −0.40 stripes per turn; heuristic bots almost never stop on Fatica (square losses 0.0002 per turn vs 0.08 for random bots): with 2d6 and many paths an Allenamento is nearly always reachable. Seat 3 (last in turn order) won 28–31% in every option.
|
||
|
||
### Phase 6 — Balance experiments
|
||
|
||
**Method** (applies to every step):
|
||
|
||
- Runs use `uv run dojo sim`. Default 1,000 games per scenario (a 25% win rate is then known to about ±1.4 pp); 4,000 games where seat effects are measured (about ±0.7 pp).
|
||
- Compared scenarios share seeds (`--seed 0`), so differences come from the rules, not the dice.
|
||
- Every conclusion is checked on at least two lineups (mixed `balanced,farmer,aggressive`, and one same-style lineup), because results depend on bot quality.
|
||
- One change at a time. When a change is adopted, re-run the 6.1 baseline so later steps start from the current rules, and log the decision (D-number) here and in `RULES.md`.
|
||
- Results go in this file as a table per step (command line, scenario, key measures).
|
||
|
||
**Next action:** 6.8 consolidation, 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 D50 is committed; commit only when the developer asks.
|
||
|
||
**Targets** (confirmed by the developer as a starting point, D32):
|
||
|
||
| Measure | Target |
|
||
|---|---|
|
||
| Minutes, 4 players | mean 60–90, p90 ≤ 110 |
|
||
| Exam pass rate | 35–55% |
|
||
| Halfway leader wins (4 players) | 35–55% |
|
||
| Player-turns out of contention | ≤ 20%; worst player mean ≤ 35% |
|
||
| Rivals within one belt of the winner at the end | ≥ 0.5 |
|
||
| Win rate by seat, 4 players | each 25% ± 3 pp |
|
||
| Win rate by bot style (mixed lineup) | spread ≤ 6 pp |
|
||
| Games finished within 200 rounds | 100%, every lineup |
|
||
|
||
**Steps:**
|
||
|
||
- [x] 6.0 Tooling needed by the experiments
|
||
- [x] 6.0.1 "Casual" bot: the heuristic bot scoring only a small random sample of the offered moves (sample size is a parameter, default 6), as a stand-in for a human who cannot compare ~24 end squares every move. Added to `BOTS` as `casual`. Done: `CasualAgent(rng, profile=BALANCED, sample=CASUAL_SAMPLE)` in `bots.py`; only `choose_path` is sampled, and the sample is blind (a path into the Dojo is taken only if drawn).
|
||
- [x] 6.0.2 `--summary-csv PATH`: one row per scenario with the summary measures, to compare scenarios side by side. Done: `report.write_summary_csv`; spreads become `<name>_mean/_p10/_median/_p90`, income `<source>_gain/loss_per_turn`, seats `seat<i>_<stat>`, bots `win_rate_<bot>`; columns missing in a scenario are empty.
|
||
- [x] 6.0.3 Seat breakdown in the summary: per seat, mean final track, Exam attempts, and share of games where that seat defended the Exam (for 6.2). Done: `GameMetrics.final_track / exam_attempts_by_seat / exam_defences_by_seat` (tuples, comma-joined in the games CSV), `Summary.seats` (`SeatSummary`), one `Seat i` line per seat in the text report.
|
||
- [x] 6.0.4 Square reachability measure: share of moves where an Allenamento / Fatica end square is reachable, and mean distinct end squares per move (the Phase 6 probe, made a metric; for 6.4). Done: the engine emits `MoveOptions(player, ends)` (square codes of the distinct end squares) before every path choice in `_move` (first choice, after a won Kumite, Tsugi Ashi; not the Meditazione extra step); report line `Move options`.
|
||
- [x] 6.1 Baseline on rules v0.7 (Exam c): 4 players, 1,000 games, lineups mixed / `balanced` / `casual` / `random`. Record the table; check it against the targets.
|
||
- Command: `uv run dojo sim --games 1000 --seed 0 --lineup balanced,farmer,aggressive balanced casual random --summary-csv ... --csv ...` (~2 min on all cores).
|
||
|
||
| Measure (target) | mixed | balanced | casual | random |
|
||
|---|---|---|---|---|
|
||
| Finished within 200 rounds (100%) | 100% | 100% | 100% | **94%** |
|
||
| Rounds mean (p10–p90) | 21.8 (15–29) | 22.2 (15–30) | 24.9 (17–34) | 115 (67–179) |
|
||
| Minutes mean (60–90), p90 (≤ 110) | 79, 108 | 81, **110.5** | 83, **114** | 365, 569 |
|
||
| Kumite per round; upsets | 1.24; 29% | 1.26; 30% | 0.66; 28% | 0.36; 23% |
|
||
| Exam attempts per game; pass rate (35–55%) | 2.33; 43% | 2.45; 41% | 2.39; 42% | 2.24; 42% |
|
||
| Halfway leader wins (35–55%) | 39% | 38% | 38% | 29% |
|
||
| Player-turns out of contention (≤ 20%) | **21%** | **21%** | 17% | 19% |
|
||
| Worst player's share out, mean (≤ 35%) | **44%** | **43%** | **40%** | **39%** |
|
||
| Rivals within one belt at the end (≥ 0.5) | 0.60 | 0.57 | 1.22 | 1.46 |
|
||
| Winner margin; lead changes | 4.0; 7.0 | 4.0; 7.4 | 2.4; 5.3 | 1.4; 13.2 |
|
||
| Win rate by seat 0–3 (25% ± 3 pp) | 24 / 23 / 24 / 28 | 25 / 22 / 26 / 27 | 26 / 23 / 26 / 26 | 23 / 23 / 24 / 23 |
|
||
| Win rate by style (spread ≤ 6 pp) | aggr. 25, bal. 27, farmer 22 (5 pp) | — | — | — |
|
||
| Income per turn: square, card, Kumite (gain / loss), Exam loss | +0.51/0, +0.01/0, +0.43/−0.40, −0.05 | same ±0.01 | +0.53/0, +0.01/−0.01, +0.24/−0.23, −0.04 | +0.19/−0.08, +0.02/−0.01, +0.12/−0.12, −0.01 |
|
||
| Square income home / away | +0.38 / +0.14 | +0.38 / +0.13 | +0.36 / +0.17 | +0.07 / +0.05 |
|
||
| End squares per move; can end on Allenamento / Fatica | 23.9; 78% / 76% | 23.9; 78% / 76% | 24.5; 83% / 80% | 24.0; 81% / 78% |
|
||
| Seat 3: Exam attempts per game (others) | 0.65 (0.55–0.57) | 0.67 (0.58–0.61) | 0.62 (0.56–0.63) | 0.56 (0.53–0.60) |
|
||
|
||
Findings:
|
||
- Met: pass rate, halfway leader, rivals within one belt, style spread, seats (mixed seat 3 at the edge, 28%).
|
||
- Missed: the worst player's time out of contention (40–44%, target ≤ 35%) on every lineup; overall time out 21% for heuristic lineups; p90 minutes slightly over 110 for `balanced` and `casual`.
|
||
- `random` does not finish 6% of games in 200 rounds (115 rounds on average): it is a floor, not a player; the "100% finished" target is read as applying to the other lineups.
|
||
- Seat 3 makes more Exam attempts in the heuristic lineups (0.65–0.67 vs ≤ 0.61) and not with `random`: first lead for 6.2.
|
||
- Fatica is reachable on 76% of moves but heuristic bots still avoid it (square losses ≈ 0), confirming Q6; the casual bot also avoids it, since 6 sampled moves nearly always include a better one.
|
||
- The casual bot fights half as often (0.66 Kumite/round) and gives closer games (winner margin 2.4, 1.22 rivals within one belt).
|
||
- Q7 follow-up (1,000 games, seed 0): `casual,balanced` → balanced 36%, casual 14% per seat; `casual,casual,casual,balanced` → balanced 46%, casual 18%. The blind sample of 6 is far weaker than the heuristic bot.
|
||
- Seat probe (4,000 games, scratch script, not in the repo): Kumite attacked in rounds 1–2 per game by seat 0/1/2/3 = 0.25 / 0.40 / 0.54 / 0.67 (mixed lineup), 0.03–0.05 for every seat with `random`; mean track after round 3 = 2.04 / 2.04 / 2.35 / 2.50. Later seats find opponents already out of their Safe Rooms, and an early equal-belt Kumite is nearly free for the attacker (Senshu 58%, and a loss at track 0–2 costs at most what is there). Matches the developer's hypothesis; candidate fixes to be proposed in 6.2.
|
||
- Developer review: D34–D41.
|
||
- Re-baseline on rules v0.8 (D35, D36, 3-belt threshold D37), 1,000 games, seed 0, each rule alone against v0.7, after the Dojo-closing fix below (scratch script: `Scenario` configs with the two switches replaced; the CLI has no switch for them):
|
||
|
||
| Measure | v0.7 | + Fatica on crossing | + no Kumite in round 1 | v0.8 (both) |
|
||
|---|---|---|---|---|
|
||
| Minutes mean / p90, mixed | 79 / 108 | 83 / 114 | 78 / 107 | 83 / 114 |
|
||
| Minutes mean / p90, balanced | 81 / 111 | 79 / 109 | 80 / 110 | 78 / 108 |
|
||
| Minutes mean / p90, casual | 83 / 114 | **126 / 173** | 83 / 114 | **127 / 174** |
|
||
| Square gain / loss per turn: mixed; casual | +0.51 / 0.00; +0.53 / 0.00 | +0.52 / −0.05; +0.45 / −0.12 | = v0.7 | +0.52 / −0.05; +0.45 / −0.12 |
|
||
| Kumite per round: mixed; casual | 1.24; 0.66 | 1.03; 0.51 | 1.23; 0.65 | 1.02; 0.51 |
|
||
| Exam pass rate, mixed | 43% | 44% | 44% | 44% |
|
||
| Out of contention (3 belts): share; worst player, mixed | 5.1%; 15% | 5.2%; 16% | 5.1%; 15% | 5.1%; 15% |
|
||
| Win rate by seat 0–3, mixed | 24 / 23 / 24 / 29 | 30 / 21 / 22 / 27 | 24 / 24 / 25 / 28 | **29 / 23 / 20 / 28** |
|
||
| Win rate by seat 0–3, balanced | 25 / 22 / 26 / 27 | 24 / 23 / 24 / 30 | 24 / 24 / 26 / 26 | 25 / 24 / 23 / 29 |
|
||
| Win rate by seat 0–3, casual | 26 / 23 / 26 / 26 | 25 / 25 / 24 / 26 | 26 / 23 / 26 / 24 | 25 / 25 / 24 / 26 |
|
||
|
||
Fix found while planning Dojo tolls: a Brown player (15) walking a Fatica drops to 14 and must not enter the Dojo on that move (the belt changes at once, FAQ). `_path_choices` no longer offers such Dojo paths (`_still_brown_at_dojo`; a Kumite won on the way re-offers paths). The first run without the fix differed by ≤ 3 minutes and ≤ 2 pp per seat.
|
||
|
||
Findings: (1) at 3 belts the contention targets are met with a wide margin (5% of player-turns, worst player 10–15%). (2) Fatica on crossing on the current board (5 F per quadrant, 20 in all, 10% of the squares) barely touches the heuristic bots (−0.03 to −0.05 per turn) but costs the casual bot −0.12 per turn and adds ~44 minutes (127 mean, p90 174): the board has too many Fatica on ordinary routes for players who do not plan around them. (3) No Kumite in round 1 alone moves seat 3 by about 1 pp (within the ±1.4 pp noise of 1,000 games); 6.2 measures it on 4,000 games. (4) Mixed v0.8 shows seat 0 at 30% and seat 2 at 20%: not seen in the same-bot lineups; to confirm in 6.2 before reading anything into it.
|
||
- [ ] 6.2 Seat order — **suspended (D43)**; runs stopped before any result (monitor; developer concerned): 4,000 games, 4 players, lineups mixed and `random`; 2,000 games at 3 and 6 players. If a seat is outside 25% ± 3 pp, diagnose with the 6.0.3 breakdown (hypotheses: moving last means seeing everyone else move first; Exam defender selection; Sensei / Peso cards) and bring candidate fixes to the developer. No fix without agreement.
|
||
- [x] 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).
|
||
- [x] 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:
|
||
- [x] 6.4.0 Board draft 2 (drafted as `board/drafts/quadrant-2.txt`, now `board/quadrant.txt`), built for Fatica on crossing. Principles approved by the developer: Fatica as tolls on short routes, fewer Fatica, Allenamento away from the Safe Rooms (covers 6.5), validator / Tatami 30–40% / 11-step walk / tunnels kept; judged on casual minutes (≤ ~93, i.e. v0.7 casual + 10) and heuristic bots paying some tolls.
|
||
- Method: walls of draft 1 kept (approved layout); only square codes changed. Route analysis showed every square on a shortest Safe Room → Dojo walk has a detour of at most 1 step, so "detour 2–4" is not reachable without wall changes; tolls were placed by measured traffic instead (bots' walks per square, home players vs visitors, on the board without Fatica). Home players load the row-3 corridor and the inner Dojo approach (5,5); visitors load the ring next to the Dojo.
|
||
- Variants (1,000 games, seed 0, v0.8; scratch scripts `routes.py`, `traffic.py`, `recode.py`, `rules_compare.py`):
|
||
|
||
| Board | Fatica (per quadrant) | Minutes mean / p90: mixed; casual | Square gain / loss per turn: mixed; casual | Home share of square income: mixed; casual | Seats 0–3, mixed |
|
||
|---|---|---|---|---|---|
|
||
| draft 1 (v0.7 rules, reference) | 5, on stop | 79 / 108; 83 / 114 | +0.51 / 0; +0.53 / 0 | 74%; 69% | 24 / 23 / 24 / 28 |
|
||
| draft 1 | 5 | 83 / 114; 127 / 174 | +0.52 / −0.05; +0.45 / −0.12 | 74%; 76% | 29 / 23 / 20 / 28 |
|
||
| 2a | 3: (3,4), (5,5), (7,4) | 73 / 99; 110 / 152 | +0.66 / −0.09; +0.55 / −0.16 | 68%; 69% | 25 / 24 / 25 / 26 |
|
||
| 2b | 2: (3,4), (5,5) | 72 / 98; 89 / 121 | +0.62 / −0.05; +0.58 / −0.09 | 70%; 68% | 23 / 28 / 24 / 25 |
|
||
| 2c | 1: (7,4); Allenamento 16 | 73 / 98; 82 / 112 | +0.59 / −0.02; +0.60 / −0.06 | 68%; 65% | 24 / 23 / 26 / 27 |
|
||
| **2d = draft 2** | 2: (3,4), (5,5); A moved to the ring | 72 / 95; 91 / 122 | +0.64 / −0.05; +0.58 / −0.10 | 67%; 62% | 23 / 27 / 27 / 23 |
|
||
|
||
**Current baseline** (rules v0.8, board draft 2) = the draft 2 row above plus the balanced lineup: 68 / 92 minutes, +0.64 / −0.03, home 67%, seats 22 / 23 / 27 / 28. Square mix per quadrant: Tatami 20 (39%), Allenamento 14, Nebbia 8 (16%, up from 6), Fatica 2, Passo Falso 2, Sfida 1, Tunnel 4.
|
||
- Reading: casual within the ~93-minute bound (91); heuristic bots pay tolls (−0.03 to −0.05); every lineup 68–72 minutes, inside 60–90. Home share down from 74% to 62–67%, not to 60%: players spend most turns crossing their own quadrant, so placement alone reaches its limit. Seat rates move by ±4 pp between variants at 1,000 games: noise, measured properly in 6.2. Adopted by the developer (D42); `board/drafts/` removed.
|
||
- [ ] 6.4.1 **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.
|
||
- [x] 6.4.2 Option 1, Fatica on crossing: `RulesConfig.fatica_on_crossing` — each Fatica square entered during a move costs 1 stripe, **1 in total per square whether or not the move stops there** (developer, D33); stopping on it adds nothing more. Engine: apply in `_walk` per square entered (not on teleports / relocations, which never walk). Bot: count Fatica crossed in `_path_score`. Likely needs fewer Fatica squares; test on the current board and on a draft with fewer F. Done as the baseline rule (D36): engine `_step` / `_path_choices`, bot `_path_score`, tests; measured on the current board in the 6.1 re-baseline.
|
||
- [ ] 6.4.3 **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).
|
||
- [x] 6.5 Home farming: covered by board draft 2 (6.4.0): Allenamento moved from the south training room onto the Dojo ring; own-quadrant share of square income 74% → 62–67%, short of the 60% aim (players cross their own quadrant for most of the game); draft 2 adopted as is (D42). Original step: after 6.4, if the own-quadrant share of square income is still above 60% (baseline: 71%), move Allenamento squares away from the Safe Rooms in a board draft (`dojo sim --quadrant board/drafts/...`) and compare. The board must still pass `dojo board validate`.
|
||
- [x] 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).**
|
||
- [x] 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).
|
||
- [x] 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).
|
||
- [x] 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).
|
||
- [x] 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`).
|
||
- [x] 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.
|
||
- [x] 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.
|
||
- [x] 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.
|
||
- [x] 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.
|
||
- [x] 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.
|
||
- [x] 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).
|
||
- [x] 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.
|
||
- [x] 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").
|
||
- [x] 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.
|
||
|
||
### 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
|
||
|
||
- uv — https://docs.astral.sh/uv/ — project init, dependency and Python version management.
|
||
- Python `tomllib` — https://docs.python.org/3/library/tomllib.html — stdlib TOML parser for `legend.toml`.
|
||
- pytest — https://docs.pytest.org/ — unit tests.
|
||
- Ruff — https://docs.astral.sh/ruff/ — lint and format.
|
||
- WKF Kumite competition rules (wkf.net, "Rules") — source of the Senshu concept.
|