315 lines
6.1 KiB
Go
Raw Normal View History

2025-12-05 20:15:55 +08:00
package model
2025-12-09 17:49:29 +08:00
import (
"fmt"
"math/rand"
"roserver/serverproto"
2026-01-08 12:45:09 +08:00
"strconv"
2025-12-09 17:49:29 +08:00
"strings"
)
2025-12-05 20:15:55 +08:00
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 (
2025-12-12 11:48:39 +08:00
LIVEROOM_TYPE_CARD = 1
LIVEROOM_TYPE_SELL = 2
LIVEROOM_TYPE_ANSWER = 3
LIVEROOM_TYPE_GAME = 4
2025-12-12 19:20:10 +08:00
LIVEROOM_TYPE_BID = 5
LIVEROOM_TYPE_SEND_GIFT = 6
2025-12-05 20:15:55 +08:00
)
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
2025-12-12 19:20:10 +08:00
LIVEROOM_BID_MAX_READY_NUM = 100
2025-12-05 20:15:55 +08:00
)
const (
LIVEROOM_MAX_PLAYER_NUM = 1000
LIVEROOM_TICK_INTERVAL = 1000
)
const (
LIVEROOM_CMD_TALK = 1
LIVEROOM_CMD_PLAY = 2
)
2025-12-12 19:20:10 +08:00
const (
LIVEROOM_CMD_PLAY_PARAM_BidPreview = "BidPreview"
LIVEROOM_CMD_PLAY_PARAM_Bid = "Bid"
)
2025-12-05 20:15:55 +08:00
// 泛型按值删除
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
}
2025-12-09 17:49:29 +08:00
2025-12-13 17:06:18 +08:00
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
}
2025-12-12 19:20:10 +08:00
func SliceContains[T any](slice []T, predicate func(T) bool) bool {
for _, v := range slice {
if predicate(v) {
return true
}
}
return false
}
2026-01-08 12:45:09 +08:00
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
}
2025-12-09 17:49:29 +08:00
// 从 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{
2025-12-12 11:48:39 +08:00
Uid: uid,
2025-12-09 17:49:29 +08:00
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
}
2026-01-08 12:45:09 +08:00
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)
}
2026-01-12 19:27:32 +08:00
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()
}