ai-code-battle/cmd/acb-evolver/internal/arena/winrate.go
jedarden ea04f4debb style: apply gofmt alignment fixes across codebase
Tab/space alignment consistency from running gofmt on all packages.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-24 10:40:33 -04:00

55 lines
1.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package arena
import "math"
// WinRateResult holds the observed win rate and its 95% Wilson score confidence interval.
type WinRateResult struct {
Wins int
Total int // non-error matches only
Rate float64 // observed win rate (01)
Lower float64 // 95% CI lower bound
Upper float64 // 95% CI upper bound
}
// WinRate computes the win rate and Wilson score 95% confidence interval
// for wins out of total valid matches. When total == 0, all values are 0.5.
//
// Wilson score interval:
//
// center = (p̂ + z²/2n) / (1 + z²/n)
// margin = z * sqrt(p̂(1-p̂)/n + z²/4n²) / (1 + z²/n)
// CI = [center margin, center + margin]
//
// Using z = 1.96 (95% two-tailed confidence).
func WinRate(wins, total int) WinRateResult {
if total == 0 {
return WinRateResult{Rate: 0.5, Lower: 0.0, Upper: 1.0}
}
const z = 1.96 // 95% CI
p := float64(wins) / float64(total)
n := float64(total)
z2 := z * z
center := (p + z2/(2*n)) / (1 + z2/n)
margin := z * math.Sqrt(p*(1-p)/n+z2/(4*n*n)) / (1 + z2/n)
lower := math.Max(0, center-margin)
upper := math.Min(1, center+margin)
return WinRateResult{
Wins: wins,
Total: total,
Rate: p,
Lower: lower,
Upper: upper,
}
}
// ComputeFromResult builds a WinRateResult from a tournament Result.
// Only non-error matches are counted; draws count as 0.5 wins.
func ComputeFromResult(r *Result) WinRateResult {
total := r.Wins + r.Losses + r.Draws
// Count draws as half-wins for the rate; wins/total integers use integer wins.
return WinRate(r.Wins, total)
}