| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402 |
- package slotpanda
- import (
- "encoding/json"
- "math/rand"
- "os"
- "strconv"
- "sync"
- "time"
- "bet24.com/log"
- "bet24.com/servers/micros/slotsservice/handler/slotcommon"
- "bet24.com/servers/micros/slotsservice/handler/slotcommon/betlevel"
- "bet24.com/servers/micros/slotsservice/handler/slotcommon/slotcount"
- )
- var gameLogic *GameLogic
- func getGameLogic() *GameLogic {
- if gameLogic == nil {
- gameLogic = new(GameLogic)
- gameLogic.ctor()
- }
- return gameLogic
- }
- type GameLogic_config struct {
- Slots []Slot
- WinShapes []WinShape
- BetLevels []betlevel.BetLevel
- JackpotAmount int
- }
- type GameLogic struct {
- GameLogic_config
- MinBet int
- MaxBet int
- Wins []Win
- TaxRate int
- lock *sync.RWMutex
- slotmgr *slotmanager
- Test []TestSlots
- FreeSlotChanged []FreeSlotChange
- userFreeSpins map[int]*FreeSpinInfo
- slotCounts *slotcount.MultipleSlotCountManager
- bonusSlotCount *slotcount.MultipleSlotCountManager
- freeSlotCount *slotcount.MultipleSlotCountManager
- jackpotManager *JackpotManager
- betLevelManager *betlevel.BetLevelManager
- MinJackpotGameCount int
- lockRemove *sync.RWMutex
- removingFreespins map[int]int64
- slotCommon *slotcommon.Slotcommon
- }
- func (this *GameLogic) ctor() {
- log.Color(LogColor, "slotpanda GameLogic.run")
- this.lock = &sync.RWMutex{}
- this.userFreeSpins = make(map[int]*FreeSpinInfo)
- this.removingFreespins = make(map[int]int64)
- this.lockRemove = &sync.RWMutex{}
- rand.Seed(time.Now().UnixNano())
- this.slotCommon = slotcommon.NewSlotCommon(GAMEID, GAME_NAME, this.TaxRate)
- this.initData()
- time.AfterFunc(5*time.Minute, this.refreshData)
- time.AfterFunc(time.Second, this.test)
- go this.checkRemoveUser()
- }
- func (this *GameLogic) initUserFreeSpin(userId int) {
- this.lock.Lock()
- _, ok := this.userFreeSpins[userId]
- if !ok {
- this.userFreeSpins[userId] = newFreeSpinInfo(userId, this.freeSlotCount, this.WinShapes, this.Wins, this.slotmgr, this.FreeSlotChanged)
- }
- this.lock.Unlock()
- }
- func (this *GameLogic) getSlotConfig(userId int) string {
- // update user's ping
- // ...
- this.initUserFreeSpin(userId)
- d, _ := json.Marshal(this.GameLogic_config)
- return string(d)
- }
- func (this *GameLogic) dump(param1, param2 string) {
- }
- func (sm *GameLogic) checkRemoveUser() {
- time.AfterFunc(slotcommon.DELAY_CHECK*time.Second, sm.checkRemoveUser)
- var toRemove []int
- latestRemoveTime := time.Now().Unix() - slotcommon.DELAY_REMOVE
- sm.lockRemove.RLock()
- for k, v := range sm.removingFreespins {
- if v < latestRemoveTime {
- toRemove = append(toRemove, k)
- }
- }
- sm.lockRemove.RUnlock()
- if len(toRemove) == 0 {
- return
- }
- sm.lockRemove.Lock()
- for _, v := range toRemove {
- delete(sm.removingFreespins, v)
- }
- sm.lockRemove.Unlock()
- sm.lock.Lock()
- for _, v := range toRemove {
- delete(sm.userFreeSpins, v)
- }
- sm.lock.Unlock()
- }
- func (this *GameLogic) test() {
- if len(os.Args) < 2 {
- return
- }
- if os.Args[1] != "panda" {
- return
- }
- init := 1000000000
- if len(os.Args) >= 3 {
- init, _ = strconv.Atoi(os.Args[2])
- }
- initGold := init
- betAmount := 250000
- if len(os.Args) >= 4 {
- betAmount, _ = strconv.Atoi(os.Args[3])
- }
- maxCount := 1000
- if len(os.Args) >= 5 {
- maxCount, _ = strconv.Atoi(os.Args[4])
- }
- log.Debug("testing panda slot initGold[%d] betAmount[%d] maxCount[%d]", initGold, betAmount, maxCount)
- testId := 0
- freeWin := 0
- bonusWin := 0
- jackpotWin := 0
- bonusCount := 0
- this.userFreeSpins[testId] = newFreeSpinInfo(testId, this.freeSlotCount, this.WinShapes, this.Wins, this.slotmgr, this.FreeSlotChanged)
- resultSet := make([]SlotPanda_Result, maxCount)
- var wg sync.WaitGroup
- for i := 0; i < maxCount; i++ {
- wg.Add(1)
- go func(idx int) {
- defer wg.Done()
- r, _ := this.getResult(testId, betAmount, 0, false)
- resultSet[idx] = r
- }(i)
- }
- wg.Wait()
- log.Color(LogColor, "测试结果已准备")
- for i := 0; i < maxCount; i++ {
- free, freeResult, _ := this.useFreeSpin(testId)
- if free {
- i--
- freeWin += freeResult.getWinAmount()
- initGold += freeResult.getWinAmount()
- continue
- }
- if initGold < betAmount {
- break
- }
- initGold -= betAmount
- result := resultSet[i]
- bonusAmount := 0
- if result.Bonus != nil {
- bonusCount++
- bonusAmount = result.Bonus.BonusResult + result.Bonus.JackpotResult
- bonusWin += result.Bonus.BonusResult
- jackpotWin += result.Bonus.JackpotResult
- }
- initGold += result.WinAmount + bonusAmount
- }
- log.Debug("pandaslot left[%d],win[%d],BonusCount[%d],Bonus[%d],Jackpot[%d],Free[%d]", initGold, initGold-init, bonusCount, bonusWin, jackpotWin, freeWin)
- }
- func (this *GameLogic) refreshData() {
- go this.initData()
- time.AfterFunc(5*time.Minute, this.refreshData)
- }
- func (this *GameLogic) initData() {
- data, err := os.ReadFile("slotconf/slotpanda.json")
- if err != nil {
- log.Error("read slotpanda.json failed")
- }
- this.lock.Lock()
- err = json.Unmarshal(data, &this)
- if err != nil {
- log.Error("Unmarshal slotpanda.json failed err:%v", err)
- this.lock.Unlock()
- return
- }
- this.slotmgr = newSlotManager(this.Slots)
- this.slotCounts = slotcount.NewMultipleSlotCountManager("slotpanda_normal_mul") // newSlotCounts(this.SlotCounts)
- this.bonusSlotCount = slotcount.NewMultipleSlotCountManager("slotpanda_bonus_mul") //newSlotCounts(this.BonusSlotCounts)
- this.freeSlotCount = slotcount.NewMultipleSlotCountManager("slotpanda_free_mul") //newSlotCounts(this.FreeSlotCounts)
- this.betLevelManager = betlevel.NewBetLevelManagerByData(this.BetLevels)
- this.jackpotManager = newJackpotManager(this.slotmgr.getBonusSlotId(), this.MinJackpotGameCount,
- this.bonusSlotCount, this.betLevelManager)
- this.lock.Unlock()
- if len(this.Test) > 0 {
- log.Debug("slotpanda testing")
- result, _ := this.getResult(0, 100, 0, false)
- d, _ := json.Marshal(result)
- log.Debug("%s", string(d))
- }
- }
- func (this *GameLogic) getUserSlotCountNormal(userId int, betAmount int) *slotcount.SlotCountManager {
- level := 0
- return this.slotCounts.GetMgr(level)
- }
- func (this *GameLogic) get15Slots(betAmount int, userId int) []Slot {
- // 如果有测试
- if len(this.Test) > 0 {
- count := len(this.Test)
- log.Debug("test count = %d", count)
- ret := make([]Slot, 15)
- slotIDs := this.Test[rand.Intn(len(this.Test))].Slots
- if len(slotIDs) < 15 {
- for i := 0; i < 15-len(slotIDs); i++ {
- slotIDs = append(slotIDs, 1+rand.Intn(10))
- }
- }
- log.Release("slotpanda get15Slots 测试中 %v", slotIDs)
- for i := 0; i < 15; i++ {
- ret[i] = this.slotmgr.getSlot(slotIDs[i])
- }
- return ret
- }
- betLevel := this.betLevelManager.GetLevel(betAmount)
- sc := this.getUserSlotCountNormal(userId, betAmount)
- ret := make([]Slot, RESULT_COUNT)
- slotIDs := sc.Get15Slots(betLevel) //this.slotCounts.get15Slots(isFree, level)
- for i := 0; i < 15; i++ {
- ret[i] = this.slotmgr.getSlot(slotIDs[i])
- }
- return ret
- }
- func (this *GameLogic) getOneResult(slotID, slotCount, shapeID int) *Result {
- for _, v := range this.Wins {
- if v.SlotID != slotID {
- continue
- }
- for _, rate := range v.Rates {
- if rate.Count == slotCount {
- return &Result{SlotID: slotID, SlotCount: slotCount, WinShapeID: shapeID, WinRate: rate.Win}
- }
- }
- }
- return nil
- }
- func (this *GameLogic) getResult(userId int, betAmount int, controlType int, isChipRoom bool) (SlotPanda_Result, bool) {
- var ret SlotPanda_Result
- if betAmount <= 0 {
- log.Release("slotpanda.GameLogic.GetResult betAmount = %d", betAmount)
- return ret, true
- }
- ret.Slots = make([]int, RESULT_COUNT)
- ret.BetAmount = betAmount
- // 取15个result
- slots := this.get15Slots(betAmount, userId)
- for k, v := range slots {
- ret.Slots[k] = v.SlotID
- if v.SlotID == this.slotmgr.getBonusSlotId() {
- ret.Slots[k] = this.jackpotManager.getRandomMultiple()*100 + v.SlotID
- }
- }
- // 计算结果
- shapeCount := len(this.WinShapes)
- for k, v := range this.WinShapes {
- // 查看每条连线的数量
- slotID, slotCount, _ := v.getCount(slots)
- // 查看结果
- result := this.getOneResult(slotID, slotCount, k)
- if result != nil {
- // 中奖了
- ret.WinAmount += betAmount * result.WinRate / shapeCount
- ret.Lines = append(ret.Lines, *result)
- }
- }
- if controlType == 1 && (ret.WinAmount > betAmount || this.jackpotManager.isJackpot(ret.Slots)) {
- return this.getResult(userId, betAmount, controlType, isChipRoom)
- }
- if controlType == 2 && ret.WinAmount < betAmount && !this.jackpotManager.isJackpot(ret.Slots) {
- return this.getResult(userId, betAmount, controlType, isChipRoom)
- }
- // Bonus
- _, bonus := this.jackpotManager.addJackpot(ret.Slots, betAmount, userId, isChipRoom)
- ret.Bonus = bonus
- // 已经产生bonus,不产生freespin
- if bonus != nil {
- return ret, true
- }
- // 检查是否产生freespin
- this.lock.RLock()
- _, ok := this.userFreeSpins[userId]
- if !ok {
- log.Debug("Not Exist User:%d", userId)
- this.lock.RUnlock()
- return ret, false
- }
- ret.FreeSpinInner, ret.FreeSpinOuter = this.userFreeSpins[userId].initFree(betAmount, ret.Slots, isChipRoom)
- this.lock.RUnlock()
- if controlType == 1 && ret.FreeSpinInner > 0 {
- // 控制的时候,需要把已产生的免费次数去掉
- log.Release("control and reset free")
- this.userFreeSpins[userId].removeFreeTimes(ret.FreeSpinInner * ret.FreeSpinOuter)
- return this.getResult(userId, betAmount, controlType, isChipRoom)
- }
- return ret, true
- }
- func (this *GameLogic) getSlots() []Slot {
- this.lock.RLock()
- defer this.lock.RUnlock()
- return this.Slots
- }
- func (this *GameLogic) getWinShapes() []WinShape {
- this.lock.RLock()
- defer this.lock.RUnlock()
- return this.WinShapes
- }
- func (this *GameLogic) useFreeSpin(userId int) (bool, FreeSpinResult, bool) {
- this.lock.Lock()
- defer this.lock.Unlock()
- t, ok := this.userFreeSpins[userId]
- if !ok {
- return false, FreeSpinResult{}, false
- }
- return t.useFreeSpin()
- }
- func (this *GameLogic) getFreeSpinTime(userId int) int {
- this.lock.RLock()
- defer this.lock.RUnlock()
- t, ok := this.userFreeSpins[userId]
- if !ok {
- return 0
- }
- return t.getFreeCount()
- }
- func (this *GameLogic) getResultDesc(result SlotPanda_Result) string {
- var total struct {
- Slots []int
- Lines []int
- }
- total.Slots = result.Slots
- for _, v := range result.Lines {
- total.Lines = append(total.Lines, v.WinShapeID)
- }
- //total.Special = result.BetAmount * (result.Special.WinRate1 + result.Special.WinRate2)
- data, _ := json.Marshal(total)
- return string(data)
- }
|