yumi-golang/internal/service/wheel/probability_test.go
2026-05-19 19:50:50 +08:00

74 lines
1.8 KiB
Go

package wheel
import (
"math"
"testing"
"chatapp3-golang/internal/service/prizepool"
)
func TestPickRewardDistribution1000000Draws(t *testing.T) {
const (
draws = 1000000
maxAllowedDriftPercent = 1.0
)
rewards := []struct {
id int64
name string
probability int
}{
{id: 1, name: "Coral Crown", probability: 300000},
{id: 2, name: "Aurora Wing", probability: 220000},
{id: 3, name: "Moon Card", probability: 150000},
{id: 4, name: "Snow Pet", probability: 120000},
{id: 5, name: "Love Banner", probability: 90000},
{id: 6, name: "Emerald Ring", probability: 60000},
{id: 7, name: "Royal Chest", probability: 40000},
{id: 8, name: "Gold", probability: 20000},
}
items := make([]prizepool.PickResult, 0, len(rewards))
for index, reward := range rewards {
items = append(items, prizepool.PickResult{
Item: prizepool.Item{
ID: reward.id,
Enabled: true,
Weight: reward.probability,
},
Index: index,
})
}
counts := make(map[int64]int, len(rewards))
for index := 0; index < draws; index++ {
reward, err := prizepool.PickWeighted(items)
if err != nil {
t.Fatalf("PickWeighted() error = %v", err)
}
counts[reward.Item.ID]++
}
for _, reward := range rewards {
expectedPercent := float64(reward.probability) / probabilityTotal * 100
actualPercent := float64(counts[reward.id]) / draws * 100
driftPercent := math.Abs(actualPercent - expectedPercent)
t.Logf(
"reward=%s configured=%.2f%% actual=%.2f%% drift=%.2f%% hits=%d/%d",
reward.name,
expectedPercent,
actualPercent,
driftPercent,
counts[reward.id],
draws,
)
if driftPercent > maxAllowedDriftPercent {
t.Fatalf(
"reward %s probability drift %.2f%% exceeds %.2f%%",
reward.name,
driftPercent,
maxAllowedDriftPercent,
)
}
}
}