Files
Go-tool/util/rand/RandByWeight.go
Huangzj dc5d924a2c feat(Go-Tool):
2021/03/02: 新增字符串匹配 暴力匹配、KMP匹配、SunDay匹配算法
            2021/03/02: 修复Rand包随机获取方法
2021-03-02 13:33:07 +08:00

163 lines
4.1 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* @Author : huangzj
* @Time : 2020/6/29 10:23
* @Description
*/
package rand
import (
"Go-Tool/util/array"
"math/rand"
"time"
)
//传入一组包含权重的数组,计算权重,返回对应权重数组的下标(即对应权重获取的结果)
func GetRandValueByWeight(weightList []int) int {
//计算总的权重
totalWeight := 0
for _, value := range weightList {
totalWeight += value
}
nowRand := R.Intn(totalWeight)
rate := 0
for i := 0; i < len(weightList); i++ {
rate += weightList[i]
if nowRand < rate {
return i
}
}
return 0
}
//通过权重获取奖励结果,这边的awardList的结构应该是 [[道具Id,道具数量,权重],....]
//返回结果的第一个元素是不包含权重的数组,第二个元素是包含权重的数组
func GetAwardByWeight(awardList [][]int) ([]int, []int) {
//这边应该加一个数组的检查.
weightListCheck(awardList)
//最后一位一定是权重.
weight := 0
for _, v := range awardList {
weight += v[len(v)-1]
}
randNum := GetRandInt(1, weight)
sum := 0
for _, v := range awardList {
sum += v[len(v)-1]
if sum >= randNum {
result := make([]int, 0)
weightResult := make([]int, 0)
return append(result, v[:len(v)-1]...), append(weightResult, v[:]...)
}
}
return nil, nil
}
//根据权重从列表获取元素
//入参分别是抽取的数字列表、权重列表
func GetByWeight(targetList []int, weightList []int) int {
//一开始就检查权重和对应的元素,长度是否一致
if len(targetList) != len(weightList) {
panic("权重和目标列表元素数量不匹配")
}
weight := 0
for _, v := range weightList {
weight += v
}
randNum := GetRandInt(1, weight)
sum := 0
for index, v := range weightList {
sum += v
if sum >= randNum {
return targetList[index]
}
}
return 0
}
//根据权重不放回的抽取,出参是:抽到的道具、剩余没有抽的道具
func GetAwardByWeightWithLeftAward(srcAwardList [][]int) ([]int, [][]int) {
//这边应该加一个数组的检查.
weightListCheck(srcAwardList)
awardList := array.DeepCopyIntSlice2(srcAwardList)
weight := 0
award := make([]int, 0)
leftAwards := make([][]int, 0)
for _, v := range awardList {
weight += v[len(v)-1]
}
randNum := GetRandInt(1, weight)
sum := 0
for index, v := range awardList {
sum += v[len(v)-1]
if sum >= randNum {
//如果获取到奖励则将当前获取的奖励扣除
leftAwards = append(awardList[0:index], awardList[index+1:]...)
award = v[:len(v)-1]
return award, leftAwards
}
}
return award, leftAwards
}
//根据权重不放回的抽取X个元素,直接返回这些元素
// 入参:奖池、抽取数量,出参:获得的所有道具
func GetCountAwardsFromPool(srcAwardPool [][]int, count int) [][]int {
awardPool := array.DeepCopyIntSlice2(srcAwardPool)
if count > len(awardPool) {
panic("抽取数量不对")
}
var finalAwardList [][]int
var award []int
var leftAward = make([][]int, len(awardPool))
copy(leftAward, awardPool)
for i := 0; i < count; i++ {
award, leftAward = GetAwardByWeightWithLeftAward(leftAward)
finalAwardList = append(finalAwardList, award)
}
return finalAwardList
}
//通过百分比的方式来获取对应的数组,也就是说权重的总值可能超过传入的百分比数,此时取的只是0-百分比数的范围内
//所以这个方法可以按照概率取一个范围内的元素
func GetAwardByPercentage(srcAwardList [][]int, fullPercent int) []int {
weightListCheck(srcAwardList)
if fullPercent <= 0 {
panic("抽取概率不能小于等于0")
}
awardList := array.DeepCopyIntSlice2(srcAwardList)
randNum := GetRandInt(1, fullPercent)
sum := 0
for _, v := range awardList {
sum += v[len(v)-1]
if sum >= randNum {
result := make([]int, 0)
return append(result, v[:len(v)-1]...)
}
}
return []int{}
}
func weightListCheck(awardList [][]int) {
for _, r := range awardList {
if len(r) == 0 {
panic("一维数组长度不能为0,必须存在权重")
}
}
}
func InitRand() {
R = rand.New(rand.NewSource(time.Now().UnixNano()))
}
func init() {
InitRand()
}