2026-03-06 10:31:16 +08:00

334 lines
6.4 KiB
Go
Raw 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.

package model
import (
"fmt"
"math/rand"
"roserver/serverproto"
"strconv"
"strings"
)
const (
LIVEROOM_STAGE_NULL = 0
LIVEROOM_STAGE_IDLE = 1
LIVEROOM_STAGE_READY = 2
LIVEROOM_STAGE_SHOW = 3
LIVEROOM_STAGE_RESULT = 4
)
const (
LIVEROOM_STAGE_IDLE_TIMER = 0
LIVEROOM_STAGE_SHOW_READY_TIMER = 15
LIVEROOM_STAGE_SHOWING_TIMER = 30
LIVEROOM_STAGE_SHOW_END_TIMER = 5
)
const (
LIVEROOM_TYPE_CARD = 1
LIVEROOM_TYPE_SELL = 2
LIVEROOM_TYPE_ANSWER = 3
LIVEROOM_TYPE_GAME = 4
LIVEROOM_TYPE_BID = 5
LIVEROOM_TYPE_SEND_GIFT = 6
)
const (
LIVEROOM_CARD_MAX_READY_NUM = 5
LIVEROOM_SELL_MAX_READY_NUM = 100
LIVEROOM_ANSWER_MAX_READY_NUM = 100
LIVEROOM_GAME_MAX_READY_NUM = 100
LIVEROOM_BID_MAX_READY_NUM = 100
)
const (
LIVEROOM_MAX_PLAYER_NUM = 1000
LIVEROOM_TICK_INTERVAL = 1000
)
const (
LIVEROOM_CMD_TALK = 1
LIVEROOM_CMD_PLAY = 2
)
const (
LIVEROOM_CMD_PLAY_PARAM_BidPreview = "BidPreview"
LIVEROOM_CMD_PLAY_PARAM_Bid = "Bid"
)
const (
LIVEROOM_SEND_GIFT_TALK_TYPE = 1000
)
// 泛型按值删除
func SliceRemoveByValue[T comparable](slice []T, value T) []T {
result := slice[:0]
for _, v := range slice {
if v != value {
result = append(result, v)
}
}
return truncateSlice(result)
}
// 截断切片容量,避免内存泄漏
func truncateSlice[T any](slice []T) []T {
return slice[:len(slice):len(slice)]
}
func SliceIsExist[T comparable](slice []T, value T) bool {
for _, v := range slice {
if v == value {
return true
}
}
return false
}
func ArrayJoin[T any](slice []T, str string) string {
if len(slice) == 0 {
return ""
}
var builder strings.Builder
for i, v := range slice {
if i > 0 {
builder.WriteString(str)
}
builder.WriteString(fmt.Sprint(v)) // 使用 fmt.Sprint 转换为字符串
}
return builder.String()
}
func WeightedRandomChoice(weights map[string]int) string {
total := 0
for _, w := range weights {
total += w
}
r := rand.Intn(total)
current := 0
for item, weight := range weights {
current += weight
if r < current {
return item
}
}
var lastItem string
for item := range weights {
lastItem = item
}
return lastItem
}
func SliceContains[T any](slice []T, predicate func(T) bool) bool {
for _, v := range slice {
if predicate(v) {
return true
}
}
return false
}
func SliceFind[T any](slice []T, predicate func(T) bool) (T, bool) {
for _, v := range slice {
if predicate(v) {
return v, true
}
}
var zero T
return zero, false
}
// 从 map 中随机选择 N 个键
func RandomKeys[K comparable, V any](m map[K]V, n int) []K {
if n <= 0 || len(m) == 0 {
return []K{}
}
// 如果请求的数量大于 map 大小,返回所有键
if n >= len(m) {
keys := make([]K, 0, len(m))
for k := range m {
keys = append(keys, k)
}
return keys
}
// 获取所有键
allKeys := make([]K, 0, len(m))
for k := range m {
allKeys = append(allKeys, k)
}
// Fisher-Yates 洗牌算法
rand.Shuffle(len(allKeys), func(i, j int) {
allKeys[i], allKeys[j] = allKeys[j], allKeys[i]
})
// 返回前 N 个
return allKeys[:n]
}
func ShuffleInPlace[T any](slice []T) {
rand.Shuffle(len(slice), func(i, j int) {
slice[i], slice[j] = slice[j], slice[i]
})
}
func JoinSlice[T any](slice []T, sep string) string {
if len(slice) == 0 {
return ""
}
var sb strings.Builder
for i, item := range slice {
if i > 0 {
sb.WriteString(sep)
}
sb.WriteString(fmt.Sprint(item))
}
return sb.String()
}
func MakeLiveRoomPlayerInfo(uid uint64) *serverproto.LiveRoomPlayerInfo {
currPlayer := RoomMgr.GetPlayer(uid)
return &serverproto.LiveRoomPlayerInfo{
Uid: uid,
Nickname: currPlayer.Name,
Level: currPlayer.Level,
HeadId: currPlayer.HeadId,
HeadTitle: currPlayer.HeadTitle,
}
}
// 获取前N个元素自动处理边界情况
func GetFirstN[T any](slice []T, n int) []T {
if n <= 0 {
return []T{} // 返回空切片
}
// 如果n大于切片长度返回整个切片的副本
if n >= len(slice) {
result := make([]T, len(slice))
copy(result, slice)
return result
}
// 正常情况返回前n个元素的副本
result := make([]T, n)
copy(result, slice[:n])
return result
}
type ProbabilityItem struct {
ID int
Probability int
}
func parseProbabilityStr(str string) ([]ProbabilityItem, error) {
if str == "" {
return nil, fmt.Errorf("概率字符串为空")
}
items := make([]ProbabilityItem, 0)
pairs := strings.Split(str, ";")
for _, pair := range pairs {
if pair == "" {
continue
}
parts := strings.Split(pair, ":")
if len(parts) != 2 {
return nil, fmt.Errorf("格式错误: %s", pair)
}
id, err := strconv.Atoi(strings.TrimSpace(parts[0]))
if err != nil {
return nil, fmt.Errorf("ID转换错误: %s", parts[0])
}
prob, err := strconv.Atoi(strings.TrimSpace(parts[1]))
if err != nil {
return nil, fmt.Errorf("概率转换错误: %s", parts[1])
}
if prob < 0 {
return nil, fmt.Errorf("概率不能为负数: %d", prob)
}
items = append(items, ProbabilityItem{
ID: id,
Probability: prob,
})
}
return items, nil
}
// SelectByProbability 根据概率随机选择一项
func selectByProbability(items []ProbabilityItem) (int, error) {
if len(items) == 0 {
return 0, fmt.Errorf("概率项列表为空")
}
// 计算总概率
totalProb := 0
for _, item := range items {
totalProb += item.Probability
}
if totalProb <= 0 {
// 如果所有概率都为0则从所有ID中随机选择一个
randIdx := rand.Intn(len(items))
return items[randIdx].ID, nil
}
// 生成随机数
randomValue := rand.Intn(totalProb)
// 根据概率选择
currentSum := 0
for _, item := range items {
currentSum += item.Probability
if randomValue < currentSum {
return item.ID, nil
}
}
// 理论上不会执行到这里
return items[len(items)-1].ID, nil
}
// -1:50;601:50;602:30;603:10;604:10;605:5;606:5;607:0;608:0;609:0
func RollForRateCfg(str string) (int, error) {
items, _ := parseProbabilityStr(str)
return selectByProbability(items)
}
func MapToString(m map[string]string) string {
if len(m) == 0 {
return ""
}
var builder strings.Builder
// 有序输出按key排序
keys := make([]string, 0, len(m))
for k := range m {
keys = append(keys, k)
}
// 排序(可选)
//sort.Strings(keys)
for i, k := range keys {
builder.WriteString(k)
builder.WriteString(":")
builder.WriteString(m[k])
if i < len(keys)-1 {
builder.WriteString(";")
}
}
return builder.String()
}