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.
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
"""Closed-form statistics for Monte Carlo balance reports.
|
||||
|
||||
Proportions follow the binomial model: p = wins/n with standard error
|
||||
sqrt(p(1-p)/n). The 3-sigma band is the default confidence interval used in
|
||||
the CLI report; clamp keeps degenerate proportions (0 or 1) exact.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import math
|
||||
|
||||
|
||||
def win_rate(wins: int, runs: int) -> float:
|
||||
"""Fraction of runs won: wins / runs."""
|
||||
if runs <= 0:
|
||||
msg = "runs must be positive"
|
||||
raise ValueError(msg)
|
||||
return wins / runs
|
||||
|
||||
|
||||
def win_rate_sigma(p: float, runs: int) -> float:
|
||||
"""Standard error of a proportion: sqrt(p(1-p)/n)."""
|
||||
if runs <= 0:
|
||||
msg = "runs must be positive"
|
||||
raise ValueError(msg)
|
||||
return math.sqrt(p * (1 - p) / runs)
|
||||
|
||||
|
||||
def win_rate_band(p: float, runs: int, *, sigma_count: float = 3.0) -> tuple[float, float]:
|
||||
"""p +/- sigma_count standard errors, clamped to [0, 1]."""
|
||||
sigma = win_rate_sigma(p, runs)
|
||||
return (max(0.0, p - sigma_count * sigma), min(1.0, p + sigma_count * sigma))
|
||||
Reference in New Issue
Block a user