| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414 |
- package wildapeslot
- import (
- "encoding/json"
- "fmt"
- "math/rand"
- "os"
- "sort"
- "strconv"
- "sync"
- "time"
- "bet24.com/log"
- "bet24.com/servers/games/slotcommon"
- "bet24.com/servers/games/slotcommon/betlevel"
- "bet24.com/servers/games/slotcommon/usermanager"
- "bet24.com/utils"
- )
- const DELAY_REMOVE = 300 // 300秒后删除用户
- const DELAY_CHECK = 60 // 每分钟检查一次
- type userFreeSpin struct {
- freeSpinTime int // 免费次数
- lastBetAmount int
- fromAd bool
- isBonus bool
- }
- type GameLogic struct {
- AdBets []DragonSlot_FreeAdBet
- TaxRate int
- BonusFree []int
- BonusWild []int
- MinJackpot int
- MaxNoneFreeCount int
- ShapeConfig ShapeConfig
- lock *sync.RWMutex
- userFreeSpins map[int]*userFreeSpin
- freeSpin *FreeSpinInfo
- slotSink slotcommon.SlotSink
- multipleCountMgr *MultipleSlotCountManager
- //slotCountsAd *SlotCountManager
- betLevelManager *betlevel.BetLevelManager
- slotManager *SlotManager
- Test []TestSlots
- testWinAmount int
- slotCountEasy *SlotCountManager
- lockRemove *sync.RWMutex
- removingFreespins map[int]int64
- slotCommon *slotcommon.Slotcommon
- }
- func NewGameLogic(slotSink slotcommon.SlotSink) *GameLogic {
- obj := new(GameLogic)
- obj.lock = &sync.RWMutex{}
- obj.userFreeSpins = make(map[int]*userFreeSpin)
- obj.slotSink = slotSink
- obj.removingFreespins = make(map[int]int64)
- obj.lockRemove = &sync.RWMutex{}
- return obj
- }
- func (this *GameLogic) run() {
- log.Color(LogColor, "wildapeslot.GameLogic run")
- rand.Seed(time.Now().UnixNano())
- this.slotCommon = slotcommon.NewSlotCommon(this.slotSink, GAMEID, GAME_NAME, this.TaxRate, GAME_MESSAGE)
- this.initData()
- time.AfterFunc(5*time.Minute, this.refreshData)
- //this.test()
- go this.checkRemoveUser()
- }
- func (sm *GameLogic) checkRemoveUser() {
- time.AfterFunc(DELAY_CHECK*time.Second, sm.checkRemoveUser)
- var toRemove []int
- latestRemoveTime := time.Now().Unix() - 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() {
- defer utils.TimeCost(fmt.Sprintf("GameLogic.test"))()
- /*
- for _, v := range this.betLevelManager.levels {
- this.testLevel()
- }
- */
- testIndex, err := strconv.Atoi(os.Args[1])
- if err != nil {
- return
- }
- log.Color(LogColor, "wildapeslot.GameLogic test")
- levels := this.betLevelManager.Levels()
- v := levels[len(levels)-1-testIndex]
- this.testLevel(v.Bet)
- log.Color(LogColor, "wildapeslot.GameLogic test end")
- }
- func (this *GameLogic) testLevel(bet int) {
- m, _ := strconv.Atoi(os.Args[2])
- tc, _ := strconv.Atoi(os.Args[3])
- originAmount := bet * m
- log.Debug("开始测试 带入金额[%d] 最多测试次数[%d] 测试底注[%d]", originAmount, tc, bet)
- winAmount := 0
- testAmount := bet
- totalJackpot := 0
- testedCount := 0
- //betLevel, base := this.betLevelManager.getLevelAndBase(testAmount)
- betAmount := 0
- returnAmount := 0
- taxAmount := 0
- for i := 0; i < tc; i++ {
- if originAmount < bet {
- log.Debug("break %d < %d", originAmount, bet)
- break
- }
- betAmount += bet
- originAmount -= bet
- testedCount++
- //slots := this.slotCountManager.get15Slots(betLevel)
- //log.Color(LogColor, "test %d +++++++++++++++", i)
- //dumpSlots(slots)
- //results := this.slotManager.getResults(slots)
- this.testWinAmount = winAmount
- result := this.getResult(0, testAmount, false, false)
- winAmount += result.WinAmount
- winAmount -= bet
- if result.WinAmount-bet > 0 {
- taxAmount += int((result.WinAmount - bet) / 100 * this.TaxRate)
- }
- returnAmount = returnAmount + result.WinAmount
- //tc += result.FreeSpinCount
- //freeCount += result.FreeSpinCount
- //originAmount += result.FreeSpinCount * bet
- originAmount += result.WinAmount
- //log.Color(LogColor, "test %d end ------------------", i)
- }
- log.Color(LogColor, "转数[%d] 底注[%d] 奖池[%d],剩余[%d],输赢[%d] 税[%d] 返还率[%.4f] 概率分布%v",
- testedCount, bet, totalJackpot, originAmount, winAmount, taxAmount, float64(returnAmount)/float64(betAmount), this.multipleCountMgr.testCount)
- }
- func (this *GameLogic) refreshData() {
- go this.initData()
- time.AfterFunc(5*time.Minute, this.refreshData)
- }
- func (this *GameLogic) initData() {
- data, err := os.ReadFile("slotconf/wildapeslot_config.json")
- if err != nil {
- log.Error("read wildapeslot_config.json failed")
- }
- this.lock.Lock()
- err = json.Unmarshal(data, &this)
- if err != nil {
- log.Error("Unmarshal wildapeslot_config.json failed err:%v", err)
- this.lock.Unlock()
- return
- }
- this.ShapeConfig.loadConfig()
- this.freeSpin = newFreeSpinInfo()
- this.multipleCountMgr = newMultipleSlotCountManager()
- this.betLevelManager = betlevel.NewBetLevelManager("dfdcbetlevel", Msg_BetLevel)
- this.slotCommon.SetBetLevelManager(this.betLevelManager)
- this.slotManager = newSlotManager()
- sort.Slice(this.AdBets, func(i, j int) bool {
- return this.AdBets[i].AdCount > this.AdBets[j].AdCount
- })
- this.lock.Unlock()
- if this.MaxNoneFreeCount > 0 {
- usermanager.SetMaxNoneFreeCount(GAMEID, this.MaxNoneFreeCount)
- }
- if len(os.Args) >= 2 {
- time.AfterFunc(time.Second, this.test)
- }
- }
- func (this *GameLogic) getWinShapes() ShapeConfig {
- this.lock.RLock()
- defer this.lock.RUnlock()
- return this.ShapeConfig
- }
- func (this *GameLogic) getUserSlotCount(userId int) *SlotCountManager {
- return this.multipleCountMgr.getMgr(0)
- }
- func (this *GameLogic) getResult(userId int, betAmount int, isFree bool, isBonus bool) DragonSlot_Result {
- var ret DragonSlot_Result
- slotCountManager := this.getUserSlotCount(userId)
- if slotCountManager == nil {
- log.Release("GameLogic.getResult no slotcount manager")
- return ret
- }
- slotCount := RESULT_COUNT
- if isFree || isBonus {
- slotCount = FREE_RESULT_COUNT
- }
- ret.Slots = make([]int, slotCount)
- ret.BetAmount = betAmount
- level, base := this.betLevelManager.GetLevelAndBase(betAmount)
- // 取15个result
- if isFree || isBonus {
- ret.Slots = this.freeSpin.get15Slots(level, isFree, isBonus)
- } else {
- if len(this.Test) > 0 {
- ret.Slots = this.getTestSlots()
- } else {
- ret.Slots = slotCountManager.get15Slots(level, false, false)
- }
- }
- //ret.Lines = this.slotManager.getResults(ret.Slots)
- log.Debug("new Slots=%v", ret.Slots)
- this.fillWinLines(ret.Slots, isFree, isBonus, &ret)
- if len(ret.Lines) > 0 {
- for _, v := range ret.Lines {
- winAmount := int(float64(base) * v.WinRate)
- ret.WinAmount += winAmount
- }
- }
- ret.FreeApe = this.freeSpin.getFreeApe(ret.Slots)
- newBonus := this.fillBonusResult(ret.Slots, &ret)
- if ret.FreeApe {
- log.Debug("has FreeApe")
- this.addFreeSpin(userId, 3, betAmount, false, false)
- } else if newBonus {
- log.Debug("has newBonus")
- this.addFreeSpin(userId, ret.BonusFree, betAmount, false, true)
- }
- return ret
- }
- func (this *GameLogic) getTestSlots() []int {
- // 如果有测试
- count := len(this.Test)
- log.Debug("test count = %d", count)
- ret := make([]int, 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("wildapeslot getTestSlots 测试中 %v", slotIDs)
- for i := 0; i < 15; i++ {
- ret[i] = slotIDs[i]
- }
- return ret
- }
- //判断修改bonus结果
- func (this *GameLogic) fillBonusResult(slots []int, ret *DragonSlot_Result) bool {
- count := this.slotManager.getBonusCount(slots)
- if count >= 3 {
- ret.BonusFree = this.BonusFree[rand.Intn(len(this.BonusFree))]
- ret.WildCount = this.BonusWild[rand.Intn(len(this.BonusWild))]
- return true
- }
- return false
- }
- //判断修改线路结算结果
- func (this *GameLogic) fillWinLines(slots []int, isFree bool, isBonus bool, ret *DragonSlot_Result) {
- var shapeCfgs []WinShape
- if isFree || isBonus {
- log.Debug("USE WinShape2 config")
- shapeCfgs = this.getWinShapes().WinShape2
- } else {
- shapeCfgs = this.getWinShapes().WinShape1
- }
- // 计算结果
- shapeCount := len(shapeCfgs)
- for k, v := range shapeCfgs {
- // 查看每条连线的数量
- slotID, slotCount, _ := v.getCount(slots)
- // 查看结果
- result := this.getOneResult(slotID, slotCount, k)
- if result != nil {
- // 中奖了
- ret.WinAmount += ret.BetAmount * int(result.WinRate) / shapeCount
- ret.Lines = append(ret.Lines, *result)
- }
- }
- }
- //返回结果结构体
- func (this *GameLogic) getOneResult(slotID, slotCount, shapeID int) *Result {
- if slotCount < 3 {
- return nil
- }
- for _, v := range this.slotManager.Slots {
- if v.SlotID != slotID {
- continue
- }
- var winFactor float64 = 1
- if slotCount == 3 {
- winFactor = v.Win3
- } else if slotCount == 4 {
- winFactor = v.Win4
- } else {
- winFactor = v.Win5
- }
- log.Debug("new Line Slotid=%d shape=%d", slotID, shapeID)
- return &Result{SlotID: slotID, SlotCount: slotCount, WinShape: shapeID, WinRate: winFactor}
- }
- return nil
- }
- func (this *GameLogic) useFreeSpin(userId int) (bool, int, bool, bool) {
- this.lock.Lock()
- defer this.lock.Unlock()
- t, ok := this.userFreeSpins[userId]
- if !ok || t.freeSpinTime <= 0 {
- return false, 0, false, false
- }
- t.freeSpinTime--
- log.Debug("免费次数剩余 %d isBonus=%t", t.freeSpinTime, t.isBonus)
- return t.isBonus, t.lastBetAmount, t.fromAd, t.freeSpinTime >= 0
- }
- 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.freeSpinTime
- }
- func (this *GameLogic) userExit(userId int) {
- this.slotCommon.OnUserExit(userId)
- if this.getFreeSpinTime(userId) > 0 {
- this.lockRemove.Lock()
- this.removingFreespins[userId] = time.Now().Unix()
- this.lockRemove.Unlock()
- return
- }
- this.lock.Lock()
- defer this.lock.Unlock()
- delete(this.userFreeSpins, userId)
- }
- func (this *GameLogic) getBetDesc(betAmount int) string {
- return fmt.Sprintf("bet %d", betAmount)
- }
- func (this *GameLogic) getResultDesc(result DragonSlot_Result) string {
- var total struct {
- Slots []int
- Lines []int
- }
- total.Slots = result.Slots
- for _, v := range result.Lines {
- total.Lines = append(total.Lines, v.WinShape)
- }
- data, _ := json.Marshal(total)
- return string(data)
- }
- func (this *GameLogic) addFreeSpin(userId int, freeCount, bet int, fromAd bool, isBonus bool) {
- this.lock.Lock()
- this.userFreeSpins[userId] = &userFreeSpin{freeSpinTime: freeCount,
- lastBetAmount: bet, fromAd: fromAd, isBonus: isBonus}
- this.lock.Unlock()
- }
|