package game import ( "testing" "time" ) func TestBalanceMonteCarlo_WolfMedianGear(t *testing.T) { n := 8000 if testing.Short() { n = 1500 } const seed = 424242 level := 5 r := RunBalanceMonteCarlo(level, n, seed, ReferenceGearMedian, BalanceEnemyWolfOnly) t.Logf("level=%d wolf-only median-gear: win=%.3f med=%s p90=%s mean=%s (n=%d)", level, r.WinRate, r.MedianDur.Round(time.Millisecond), r.P90Dur.Round(time.Millisecond), r.MeanDur.Round(time.Millisecond), n) if r.Iterations != n { t.Fatalf("iterations: got %d want %d", r.Iterations, n) } } func TestBalanceMonteCarlo_MixedSpawnL10(t *testing.T) { if testing.Short() { t.Skip() } const n = 4000 const seed = 777 r := RunBalanceMonteCarlo(10, n, seed, ReferenceGearRolled, BalanceEnemyMixedSpawn) t.Logf("level=10 mixed rolled-gear: win=%.3f med=%s p90=%s", r.WinRate, r.MedianDur.Round(time.Millisecond), r.P90Dur.Round(time.Millisecond)) } func TestBalanceMonteCarlo_WolfCurve(t *testing.T) { if testing.Short() { t.Skip() } const n = 6000 const seed = 99 for _, level := range []int{5, 10, 15, 20, 25} { r := RunBalanceMonteCarlo(level, n, seed+int64(level*17), ReferenceGearMedian, BalanceEnemyWolfOnly) t.Logf("L%2d wolf-only median-gear: win=%.3f med=%s p90=%s", level, r.WinRate, r.MedianDur.Round(time.Millisecond), r.P90Dur.Round(time.Millisecond)) } } func TestBalanceMonteCarlo_CurveProbe(t *testing.T) { if testing.Short() { t.Skip("curve probe") } const n = 5000 const seed = 2026 for _, level := range []int{1, 3, 5, 10, 15, 20} { r := RunBalanceMonteCarlo(level, n, seed+int64(level), ReferenceGearMedian, BalanceEnemyMixedSpawn) t.Logf("L%2d mixed median-gear: win=%.3f med=%s p90=%s", level, r.WinRate, r.MedianDur.Round(time.Millisecond), r.P90Dur.Round(time.Millisecond)) } } // TestBalanceMonteCarlo_L5MixedRegression guards against extreme drift after tuning changes. func TestBalanceMonteCarlo_L5MixedRegression(t *testing.T) { if testing.Short() { t.Skip() } const n = 4000 r := RunBalanceMonteCarlo(5, n, 424242, ReferenceGearMedian, BalanceEnemyMixedSpawn) if r.WinRate < 0.30 || r.WinRate > 0.95 { t.Fatalf("L5 mixed win rate drift: %.3f (expected rough band 0.30–0.95)", r.WinRate) } // Mixed spawn has high variance; median duration should stay in a sane band after pace/damage retunes. if r.MedianDur < 90*time.Second || r.MedianDur > 12*time.Minute { t.Fatalf("L5 mixed median duration drift: %s (expected rough ~1.5–10 min band)", r.MedianDur) } }