package otherutils import ( "errors" "math/rand" ) func init() { // rand.Seed(time.Now().UnixNano()) } // RandInterval 随机1个数 func RandInterval(b1, b2 int64) int64 { min, max := normalizeRange(b1, b2) return min + rand.Int63n(max-min+1) } // RandInterval64 随机1个数 func RandInterval64(b1, b2 int64) int64 { min, max := normalizeRange64(b1, b2) return min + rand.Int63n(max-min+1) } func normalizeRange64(b1, b2 int64) (min, max int64) { if b1 < b2 { return b1, b2 } return b2, b1 } // RandIntervalN 随机生成n个范围在[b1, b2]之间的唯一整数 // 使用Fisher-Yates洗牌算法 func RandIntervalN(b1, b2 int64, n int64) []int64 { min, max := normalizeRange(b1, b2) rangeSize := max - min + 1 n = limitCount(n, int64(rangeSize)) if n == 1 { return []int64{min + rand.Int63n(max-min+1)} } return generateUniqueRandomNumbers(min, max, n) } func normalizeRange(b1, b2 int64) (min, max int64) { if b1 < b2 { return b1, b2 } return b2, b1 } func limitCount(n int64, rangeSize int64) int64 { if n > rangeSize { return rangeSize } return n } func generateUniqueRandomNumbers(min, max int64, n int64) []int64 { result := make([]int64, n) usedNumbers := make(map[int64]int64) rangeSize := max - min + 1 for i := int64(0); i < n; i++ { randomValue := min + rand.Int63n(rangeSize) if replacementValue, exists := usedNumbers[randomValue]; exists { result[i] = replacementValue } else { result[i] = randomValue } lastValue := max - i if randomValue != lastValue { if replacementValue, exists := usedNumbers[lastValue]; exists { usedNumbers[randomValue] = replacementValue } else { usedNumbers[randomValue] = lastValue } } rangeSize-- } return result } type Number interface { int | int8 | int16 | int32 | int64 | uint | uint8 | uint16 | uint32 | uint64 | float32 | float64 } // RandOneNum 随机一个数字 func RandOneNum[T Number](min, max T) T { if min == max { return min } if min > max { min, max = max, min } var result T switch any(min).(type) { case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64: result = T(rand.Int63n(int64(max-min)) + int64(min)) case float32, float64: result = T(rand.Float64()*(float64(max)-float64(min)) + float64(min)) default: panic("invalid type") } return result } // RandChoiceByWeighted 根据权重选取一个元素 [[id,weight]] func RandChoiceByWeighted(items [][]int64) int64 { var totalWeight int64 for _, item := range items { totalWeight += item[1] } if totalWeight <= 0 { return -1 } // 生成一个0到总权重之间的随机数 randomNumber := rand.Int63n(totalWeight) + 1 // 累积权重,直到累积权重超过随机数 var cumulativeWeight int64 for _, item := range items { cumulativeWeight += item[1] if randomNumber <= cumulativeWeight { return item[0] } } // 如果没有找到(理论上不会发生),返回0 return -1 } // type WeightedItem interface { // GetWeight() int64 // } type WeightedTable[T any] struct { items []T totalWeight int64 getWeight func(T) int64 } func SetWeightedTable[T any](items []T, getWeight func(T) int64) *WeightedTable[T] { var totalWeight int64 for _, item := range items { totalWeight += getWeight(item) //item.GetWeight() } return &WeightedTable[T]{ items: items, totalWeight: totalWeight, getWeight: getWeight, } } func (rt *WeightedTable[T]) RandOneItem(reCalcWeight bool) (val T, err error) { var item T if reCalcWeight { var totalWeight int64 for _, item := range rt.items { totalWeight += rt.getWeight(item) } rt.totalWeight = totalWeight } if rt.totalWeight <= 0 { return item, errors.New("total weight is zero") } // 生成一个0到总权重之间的随机数 randomNumber := rand.Int63n(rt.totalWeight) + 1 // 累积权重,直到累积权重超过随机数 var cumulativeWeight int64 for _, item := range rt.items { cumulativeWeight += rt.getWeight(item) if randomNumber <= cumulativeWeight { return item, nil } } // 如果没有找到(理论上不会发生),返回0 return item, errors.New("not found") }