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, ) } } }