Last active
May 31, 2022 08:59
-
-
Save z1076/385c0ddf6084bb869fcc526142d53c5d to your computer and use it in GitHub Desktop.
[golang抽奖算法] #go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
//需求就是 Product 的Chance越大 抽到的几率越小 | |
// 来源 https://segmentfault.com/q/1010000021810370?utm_source=tag-newest | |
// 一般抽奖设计,Chance 是表示中奖概率,你这种反向操作的其实有点变态 | |
// 特别是你给出的数据中两个 Chance = 0 ; 这想表示什么; | |
// 按照正常操作,我们都是将各个抽奖商品的中奖概率进行累加,然后随机取值在累加和范围内选中抽奖商品 | |
// OK | |
// 针对你这个情况,我只能说按照正常抽奖中奖概率,得到中奖偏移量 | |
// 然后反着中奖概率商品的方式,进行偏移量取值 | |
// 比如: 1, 2, 3, 4, 5, 6 | |
// 当抽中2 的时候,那么实际上就会用 6-2+1 这个偏移量得到5 | |
// 当抽中4 的时候,那么实际就是 6 - 4 + 1 = 3 这个偏移量的值 | |
import ( | |
"fmt" | |
"math/rand" | |
"sort" | |
"time" | |
) | |
// Product 产品 | |
type Product struct { | |
ID int64 | |
Name string | |
Chance int | |
} | |
func main() { | |
products := []Product{ | |
{ | |
ID: 1, | |
Name: "Apple", | |
Chance: 30, | |
}, | |
{ | |
ID: 1, | |
Name: "Banana", | |
Chance: 20, | |
}, | |
{ | |
ID: 1, | |
Name: "Orange", | |
Chance: 50, | |
}, | |
} | |
// 排序抽奖内容,用来计算抽奖偏移量 | |
sort.Slice(products, func(i, j int) bool { | |
return products[i].Chance < products[j].Chance | |
}) | |
high := 0 | |
for _, product := range products { | |
high += product.Chance | |
} | |
rand.Seed(time.Now().UnixNano()) | |
random := rand.Int31n(int32(high)) | |
fmt.Println("=====>hight: ", high) | |
fmt.Println("=====>random: ", random) | |
product := filter(int(random), products) | |
// 输出中奖商品 | |
fmt.Println(product) | |
} | |
func filter(random int, products []Product) Product { | |
reverse := len(products) | |
for _, product := range products { | |
reverse-- | |
if product.Chance >= random { | |
break | |
} | |
random -= product.Chance | |
} | |
return products[reverse] | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
// 常规抽奖算法 | |
import ( | |
"encoding/json" | |
"fmt" | |
"math" | |
"math/rand" | |
"sort" | |
"time" | |
) | |
type Prize struct { | |
PlayerId int64 | |
Weight int | |
} | |
func main() { | |
//设置奖项名称、权重等数组 | |
var prizes = make([]*Prize, 0) | |
for i := 0; i < 4; i++ { | |
prize := &Prize{ | |
PlayerId: int64(i) + 10000, | |
Weight: (5 - i) * 10, | |
} | |
prizes = append(prizes, prize) | |
} | |
for _, v := range prizes { | |
fmt.Println(v.PlayerId, v.Weight) | |
} | |
for i := 0; i < 50; i++ { | |
id := RandomDraw(prizes) | |
fmt.Println("本次抽奖结果:", id) | |
} | |
} | |
// 权重随机抽奖 | |
func RandomDraw(prizes []*Prize) int64 { | |
//权重累加求和 | |
var weightSum int | |
for _, v := range prizes { | |
weightSum += v.Weight | |
} | |
//生成一个权重随机数,介于0-weightSum之间 | |
rand.Seed(time.Now().UnixNano()) | |
randomNum := rand.Intn(weightSum) | |
//权重数组重组并排序 | |
randomNumTmp := &Prize{PlayerId: -1, Weight: randomNum} | |
concatWeightArr := make([]*Prize, 0) | |
aa, _ := json.Marshal(prizes) | |
_ = json.Unmarshal(aa, &concatWeightArr) | |
concatWeightArr = append(concatWeightArr, randomNumTmp) //将随机数加入权重数组 | |
//将包含随机数的新权重数组按从小到大(升序)排序 | |
sort.Slice(concatWeightArr, func(i, j int) bool { | |
return concatWeightArr[i].Weight < concatWeightArr[j].Weight | |
}) | |
sort.Slice(prizes, func(i, j int) bool { | |
return prizes[i].Weight < prizes[j].Weight | |
}) | |
//索引权重随机数的数组下标 | |
var randomNumIndex = -1 //索引随机数在新权重数组中的位置 | |
for p, v := range concatWeightArr { | |
if v.Weight == randomNum { | |
randomNumIndex = p | |
} | |
} | |
randomNumIndexTmp := math.Min(float64(randomNumIndex), float64(len(prizes)-1)) //权重随机数的下标不得超过奖项数组的长度-1,重新计算随机数在奖项数组中的索引位置 | |
randomNumIndex = int(randomNumIndexTmp) | |
//取出对应奖项 | |
res := prizes[randomNumIndex] //从奖项数组中取出本次抽奖结果 | |
return res.PlayerId | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment