Commit Graph

6 Commits

Author SHA1 Message Date
ctan de88543c5c feat(phase2): danger-cartography spike - per-run outcomes, objectives, focus-fire adversary
run_encounter gains an opt-in collect_runs flag returning one RunOutcome
per battle (winner, rounds, per-combatant id/side/hp/hp_max/dead) next to
the EncounterReport; default behavior is unchanged. objectives.py provides
the pure optimizer primitives: P(survives all), P(TPK), P(>=1 death),
expected hp lost, expected rounds and a worst-decile (CVaR-style) tail
metric. phase2_spike.py holds the spike-level strengthened monster policy
(focus fire on the lowest-AC enemy, ties to the wounded; party side stays
on default_policy). tests/test_phase2_danger_map.py prints the danger-map
sketch: warband and lich scenarios measured default vs focus-fire at
100 runs / seed 11, pinning the delta deterministically.
2026-09-21 12:07:23 +02:00
ctan e9c2a63122 fix(runner): disambiguation suffix skips ids already taken by explicit combatants 2026-09-20 17:33:35 +02:00
ctan e6021a6dda fix(rules): expose healing_done in per-combatant stats and the CLI report - the channel/spell healing deliberately removed from damage_dealt (2e2873f) was invisible; CombatantStats/_LiveStats gain a healing_done counter booked with the hp actually restored (capped at the target's hp_max, overheal uncounted) by _channel_heal and by spell HealEffect on living targets, while cure-as-damage on undead stays in damage_dealt and the damage counters keep their exact semantics; the runner aggregates and averages the new field and the French report prints it as 'soins prodigués'; +4 tests (channel heal, cure spell, undead cure guard, run_encounter aggregate) +1 CLI assertion 2026-09-19 23:23:00 +02:00
ctan 5e7436b210 fix(rules): duplicate summons get disambiguated ids - the engine now counts id occurrences (seeded from the deployed roster) and gives each new summon of the same creature a build_states-style suffix (celestial_wolf, celestial_wolf-2, ...), so two summons no longer share one _LiveStats slot (the second summon used to reset the first one's counters and their attrition merged); run_encounter aggregation verified to report each slot separately; runner 'known limitation' comment updated; +4 tests (id split, distinct slots, per-slot attrition, run_encounter aggregate) 2026-09-19 23:13:06 +02:00
ctan 7fefce4653 fix(runner): aggregation creates per-id accumulators on demand so summoned creature ids in result.stats no longer KeyError run_encounter (totals were seeded from the deployed roster only); duplicate summons of one creature id share a stats slot - noted as a limitation, pinned by a summon-encounter report test 2026-09-19 16:56:48 +02:00
ctan a21e234b41 feat(runner): Monte Carlo runner, closed-form metrics and balance CLI
Adds the S6 layer on top of the deterministic combat engine:
- metrics.py: closed-form binomial statistics (win rate, standard error,
  3-sigma confidence band) with clamped degenerate proportions.
- runner.py: EncounterSpec/Side definitions, per-run SeededRng streams,
  global duplicate-id disambiguation, attrition averages per combatant.
- cli.py: pf1e-sim entry point producing a French balance report with
  win rates, 3-sigma bands, draws, rounds, and attrition.
- Movement fix: greedy straight-line heuristic could oscillate at walls;
  _step_toward now follows the true shortest path via an unbounded
  Dijkstra cost field from the target (Grid.reachable budget=None).
- Regression tests: melee unit routes around a wall and engages; grid
  unbounded-budget coverage.
2026-08-17 22:49:50 +02:00