-
Notifications
You must be signed in to change notification settings - Fork 1
/
weighted_random_hit.go
78 lines (63 loc) · 1.7 KB
/
weighted_random_hit.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
// Copyright 2024 Grabtaxi Holdings Pte Ltd (GRAB), All rights reserved.
package weightedrandomhit
import (
"math/rand"
)
type Options struct {
defaultWeight int
chanceMultiplier int
}
type OptionsFunc func(*Options)
// IsCategoryHit checks if a category hit/miss based on category weights
func IsCategoryHit(
category string,
categoryWeights map[string]int,
targetHit int,
maxAllowedHitsForEachCategory int,
opts ...OptionsFunc) bool {
// set default options
options := Options{
defaultWeight: 0,
chanceMultiplier: 1,
}
// override default options
for _, opt := range opts {
opt(&options)
}
var weight, maxWeight, totalWeight int
for _, weight = range categoryWeights {
totalWeight += weight
if weight > maxWeight {
maxWeight = weight
}
}
if val, exists := categoryWeights[category]; exists {
weight = val
} else {
if options.defaultWeight == 0 {
// if no default weight is set, unknown categories will be ignored
return false
}
weight = options.defaultWeight
}
adjustedTarget := targetHit * (maxWeight / weight)
if adjustedTarget > maxAllowedHitsForEachCategory {
adjustedTarget = maxAllowedHitsForEachCategory
}
if rand.Intn(totalWeight)%totalWeight <= adjustedTarget*options.chanceMultiplier {
return true
}
return false
}
// WithChanceMultiplier use this to multiply the chance of category hit. Useful for testing
func WithChanceMultiplier(multiplier int) OptionsFunc {
return func(options *Options) {
options.chanceMultiplier = multiplier
}
}
// WithDefaultWeight use this to have a default weight for unknown categories
func WithDefaultWeight(defaultWeight int) OptionsFunc {
return func(options *Options) {
options.defaultWeight = defaultWeight
}
}