Skip to content

Instantly share code, notes, and snippets.

@z1076
Last active May 31, 2022 08:59
Show Gist options
  • Save z1076/385c0ddf6084bb869fcc526142d53c5d to your computer and use it in GitHub Desktop.
Save z1076/385c0ddf6084bb869fcc526142d53c5d to your computer and use it in GitHub Desktop.
[golang抽奖算法] #go
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]
}
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