package gold2chipwheel import ( "encoding/json" "math/rand" "os" "strconv" "sync" "time" "bet24.com/log" "bet24.com/servers/common" inventory "bet24.com/servers/micros/item_inventory/proto" item "bet24.com/servers/micros/item_inventory/proto" cash "bet24.com/servers/micros/money/proto" platformconfig "bet24.com/servers/micros/platformconfig/proto" ) const refresh_config_sec = 600 const config_key = "gold2chipwheel_config" type Prize struct { Id int Chance int `json:",omitempty"` Items []item.ItemPack ReWheel int `json:",omitempty"` MaxChip int `json:",omitempty"` } type BetPrize struct { Accumulate int Bet int // 投注额 Prizes []Prize pool []*Prize } func (bp *BetPrize) makePool() { bp.pool = []*Prize{} for j := 0; j < len(bp.Prizes); j++ { for i := 0; i < bp.Prizes[j].Chance; i++ { bp.pool = append(bp.pool, &bp.Prizes[j]) } bp.Prizes[j].Chance = 0 } } func (bp *BetPrize) getRandomPrize(acc int) int { count := len(bp.pool) if count == 0 { return 0 } var ret *Prize loopCount := 0 for { ret = bp.pool[rand.Intn(count)] if acc == 0 { break } if ret.MaxChip == 0 { break } if ret.MaxChip >= acc { break } loopCount++ if loopCount > 20 { log.Release("BetPrize.getRandomPrize loopCount > 20 acc[%d] maxChip[%d]", acc, ret.MaxChip) break } } return ret.Id } type gold2chipwheelmgr struct { betPrizes []*BetPrize lock *sync.RWMutex freeWheels map[int]int prizes map[int]*Prize historyMgr *historymanager accumulate *dayaccumulation } func newPrizeWheelManager() *gold2chipwheelmgr { w := new(gold2chipwheelmgr) w.lock = &sync.RWMutex{} w.freeWheels = make(map[int]int) w.prizes = make(map[int]*Prize) w.historyMgr = newHistoryManager() w.accumulate = newDayAccumulation() w.loadPrizes() log.Debug("gold2chipwheelmgr manager running") return w } func (w *gold2chipwheelmgr) loadPrizes() { defer func() { time.AfterFunc(refresh_config_sec*time.Second, w.loadPrizes) }() configString := platformconfig.GetConfig(config_key) if configString == "" { data, err := os.ReadFile("fishconf/gold2chipwheel.json") if err != nil { log.Release("gold2chipwheelmgr.loadData read gold2chipwheel failed") return } configString = string(data) platformconfig.SetConfig(config_key, configString) } else { log.Debug("gold2chipwheelmgr loading config from redis") } w.lock.Lock() defer w.lock.Unlock() err := json.Unmarshal([]byte(configString), &w.betPrizes) if err != nil { log.Release("gold2chipwheelmgr.loadData Unmarshal gold2chipwheel failed err:%v", err) return } id := 1 //for _, v := range w.betPrizes { for j := 0; j < len(w.betPrizes); j++ { v := w.betPrizes[j] v.makePool() for i := 0; i < len(v.Prizes); i++ { v.Prizes[i].Id = id w.prizes[id] = &v.Prizes[i] id++ } } } func (w *gold2chipwheelmgr) isFreeWheel(userId int) int { w.lock.RLock() bet, ok := w.freeWheels[userId] w.lock.RUnlock() if !ok || bet == 0 { return 0 } w.lock.Lock() delete(w.freeWheels, userId) w.lock.Unlock() return bet } func (w *gold2chipwheelmgr) getPrizeById(id int) *Prize { w.lock.RLock() defer w.lock.RUnlock() ret, ok := w.prizes[id] if !ok { return nil } return ret } func (w *gold2chipwheelmgr) addFreeWheel(userId int, bet int) { w.lock.Lock() w.freeWheels[userId] = bet w.lock.Unlock() } func (w *gold2chipwheelmgr) getPrizes() string { w.lock.RLock() defer w.lock.RUnlock() d, _ := json.Marshal(w.betPrizes) return string(d) } func (w *gold2chipwheelmgr) getBetPrize(bet int) *BetPrize { w.lock.RLock() defer w.lock.RUnlock() for _, v := range w.betPrizes { if v.Bet == bet { return v } } return nil } // 摇奖,返回中奖结果 func (w *gold2chipwheelmgr) wheel(userId, bet int, ipAddress string) int { freeBet := w.isFreeWheel(userId) if freeBet > 0 { log.Debug("gold2chipwheelmgr.wheel userId[%d] freeWheel [%d]", userId, freeBet) bet = freeBet } else { if !cash.ReduceMoney(userId, bet, common.LOGTYPE_GOLD_WHEEL, "gold2chipwheel", "wheel", ipAddress) { log.Release("gold2chipwheelmgr.wheel userId[%d] bet[%d] not enough gold", userId, bet) return 0 } } bp := w.getBetPrize(bet) if bp == nil { log.Release("gold2chipwheelmgr.wheel userId[%d] bet[%d] not found", userId, bet) if freeBet == 0 { cash.GiveMoney(userId, bet, common.LOGTYPE_GOLD_WHEEL, "gold2chipwheel", "return", ipAddress) } return 0 } p := w.getPrizeById(bp.getRandomPrize(w.accumulate.getAccumulate(userId))) if p == nil { log.Release("gold2chipwheelmgr.wheel userId[%d] bet[%d] prize not found", userId, bet) return 0 } // 给奖励 if len(p.Items) > 0 { time.AfterFunc(time.Second*9, func() { inventory.AddItems(userId, p.Items, "gold2chipwheel", common.LOGTYPE_GOLD_WHEEL) w.historyMgr.addHistory(userId, bet, p.Items) }) for _, v := range p.Items { if v.ItemId == item.Item_Chip { w.accumulate.addAccumulate(userId, v.Count) } } } if p.ReWheel > 0 { w.addFreeWheel(userId, bet) } return p.Id } func (w *gold2chipwheelmgr) dump(param1, param2 string) { log.Release("-------------------------------") log.Release("gold2chipwheelmgr.dump %s %s", param1, param2) defer func() { log.Release("+++++++++++++++++++++++++++++++") log.Release("") }() if param1 == "test" { count, err := strconv.Atoi(param2) if err != nil { count = 10000 } w.test(count) return } if param1 == "" { w.lock.RLock() for _, v := range w.betPrizes { log.Release(" Bet:%d", v.Bet) for _, v1 := range v.Prizes { log.Release(" %d:Chance[%d],%v", v1.Id, v1.Chance, v1) } } w.lock.RUnlock() return } userId, err := strconv.Atoi(param1) if err == nil { log.Release(" User[%d]:Accumulate[%d]", userId, w.accumulate.getAccumulate(userId)) } } func (w *gold2chipwheelmgr) getRecord(userId int) string { return w.historyMgr.getHistory(userId) } func (w *gold2chipwheelmgr) flush() { w.historyMgr.flush() w.accumulate.flush() } func (w *gold2chipwheelmgr) test(count int) { win := 0 bet := 0 for _, v := range w.betPrizes { b, w := w.testOne(count, v) bet += b win += w } log.Release("gold2chipwheelmgr test total bet[%d] win[%d]", bet, win) } func (w *gold2chipwheelmgr) testOne(count int, bet *BetPrize) (int, int) { totalBet := bet.Bet * count totalWin := 0 for i := 0; i < count; i++ { p := w.getPrizeById(bet.getRandomPrize(0)) if p == nil { i-- continue } for _, v := range p.Items { totalWin += v.Count } } log.Release(" testOne[%d] bet[%d] win[%d]", bet.Bet, totalBet, totalWin) return totalBet, totalWin }