|
|
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 > 1.00 {
|
|
|
t.Fatalf("L5 mixed win rate drift: %.3f (expected rough band 0.30–1.00)", 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)
|
|
|
}
|
|
|
}
|