GameLogic.go 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. package rezekislot
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "math/rand"
  6. "os"
  7. "sort"
  8. "strconv"
  9. "sync"
  10. "time"
  11. "bet24.com/log"
  12. "bet24.com/servers/games/slotcommon"
  13. "bet24.com/servers/games/slotcommon/betlevel"
  14. "bet24.com/servers/games/slotcommon/slotcount"
  15. "bet24.com/servers/games/slotcommon/usermanager"
  16. "bet24.com/utils"
  17. )
  18. type GameLogic struct {
  19. MinBet int
  20. MaxBet int
  21. MinFreeSlotCount int
  22. MinJackpot int
  23. FreeSlotId int
  24. FreeTime int
  25. MaxNoneFreeCount int
  26. TaxRate int
  27. Slots []Slot
  28. FanConfig []Fan
  29. //SlotCounts [][][]int
  30. //FreeSlotCounts [][][]int
  31. BetLevels []betlevel.BetLevel
  32. AdBets []RezekiSlot_FreeAdBet
  33. lock *sync.RWMutex
  34. userFreeSpins map[int]*FreeSpinInfo
  35. slotSink slotcommon.SlotSink
  36. slotCounts *slotcount.MultipleSlotCountManager
  37. freeSlotCount *slotcount.MultipleSlotCountManager
  38. freeSpin *FreeSpinInfo
  39. slotManager *SlotManager
  40. jackpotManager *JackpotManager
  41. betLevelManager *betlevel.BetLevelManager
  42. fanManager *FanManager
  43. testWinAmount int
  44. slotCommon *slotcommon.Slotcommon
  45. }
  46. func NewGameLogic(slotSink slotcommon.SlotSink) *GameLogic {
  47. obj := new(GameLogic)
  48. obj.lock = &sync.RWMutex{}
  49. obj.slotSink = slotSink
  50. return obj
  51. }
  52. func (this *GameLogic) run() {
  53. log.Color(LogColor, "rezeki GameLogic.run")
  54. rand.Seed(time.Now().UnixNano())
  55. this.slotCommon = slotcommon.NewSlotCommon(this.slotSink, GAMEID, GAME_NAME, this.TaxRate, GAME_MESSAGE)
  56. this.initData()
  57. time.AfterFunc(5*time.Minute, this.refreshData)
  58. }
  59. func (this *GameLogic) test() {
  60. defer utils.TimeCost(fmt.Sprintf("GameLogic.test"))()
  61. /*
  62. for _, v := range this.betLevelManager.levels {
  63. this.testLevel()
  64. }
  65. */
  66. if os.Args[1] != "fanslot" {
  67. return
  68. }
  69. testIndex, err := strconv.Atoi(os.Args[2])
  70. if err != nil {
  71. return
  72. }
  73. log.Color(LogColor, "rezeki.GameLogic test")
  74. levels := this.betLevelManager.Levels()
  75. v := levels[len(levels)-1-testIndex]
  76. this.testLevel(v.Bet)
  77. log.Color(LogColor, "rezeki.GameLogic test end")
  78. }
  79. func (this *GameLogic) testLevel(bet int) {
  80. m, _ := strconv.Atoi(os.Args[3])
  81. tc, _ := strconv.Atoi(os.Args[4])
  82. originAmount := bet * m
  83. log.Debug("开始测试 带入金额[%d] 最多测试次数[%d] 测试底注[%d]", originAmount, tc, bet)
  84. winAmount := 0
  85. testAmount := bet
  86. totalJackpot := 0
  87. testedCount := 0
  88. freeCount := 0
  89. //betLevel, base := this.betLevelManager.getLevelAndBase(testAmount)
  90. betAmount := 0
  91. returnAmount := 0
  92. taxAmount := 0
  93. resultSet := make([]RezekiSlot_Result, tc)
  94. freeResultSet := make([]RezekiSlot_Result, tc*3)
  95. var wg sync.WaitGroup
  96. for i := 0; i < tc; i++ {
  97. wg.Add(1)
  98. go func(idx int) {
  99. defer wg.Done()
  100. r := this.getResult(0, testAmount, false)
  101. resultSet[idx] = r
  102. }(i)
  103. }
  104. for i := 0; i < tc*3; i++ {
  105. wg.Add(1)
  106. go func(idx int) {
  107. defer wg.Done()
  108. freeResultSet[idx] = this.getResult(0, testAmount, true)
  109. }(i)
  110. }
  111. wg.Wait()
  112. log.Color(LogColor, "测试结果已准备")
  113. leftFreeCount := 0
  114. tmpBet := 0
  115. for i := 0; i < tc; {
  116. tmpBet = bet
  117. if originAmount < bet && leftFreeCount <= 0 {
  118. log.Debug("break %d < %d", originAmount, bet)
  119. break
  120. }
  121. betAmount += tmpBet
  122. originAmount -= tmpBet
  123. testedCount++
  124. //slots := this.slotCountManager.get15Slots(betLevel)
  125. //log.Color(LogColor, "test %d +++++++++++++++", i)
  126. //dumpSlots(slots)
  127. //results := this.slotManager.getResults(slots)
  128. this.testWinAmount = winAmount
  129. var result RezekiSlot_Result
  130. if leftFreeCount > 0 {
  131. leftFreeCount--
  132. result = freeResultSet[freeCount]
  133. freeCount++
  134. tmpBet = 0
  135. } else {
  136. result = resultSet[i]
  137. i++
  138. }
  139. winAmount += result.WinAmount
  140. winAmount += result.JackpotAmount
  141. winAmount -= tmpBet
  142. if result.WinAmount+result.JackpotAmount-tmpBet > 0 {
  143. taxAmount += int((result.WinAmount + result.JackpotAmount - tmpBet) / 100 * this.TaxRate)
  144. }
  145. returnAmount += result.WinAmount + result.JackpotAmount
  146. leftFreeCount += result.FreeSpin
  147. originAmount += result.WinAmount
  148. originAmount += result.JackpotAmount
  149. //log.Color(LogColor, "test %d end ------------------", i)
  150. }
  151. log.Color(LogColor, "转数[%d] 底注[%d] 奖池[%d],剩余[%d],输赢[%d] 税[%d] 返还率[%.4f] 概率分布%v",
  152. testedCount, bet, totalJackpot, originAmount, winAmount, taxAmount, float64(returnAmount-taxAmount)/float64(betAmount), "")
  153. }
  154. func (this *GameLogic) refreshData() {
  155. go this.initData()
  156. time.AfterFunc(5*time.Minute, this.refreshData)
  157. }
  158. func (this *GameLogic) initData() {
  159. data, err := os.ReadFile("slotconf/rezekislot.json")
  160. if err != nil {
  161. log.Error("read rezekislot.json failed")
  162. }
  163. this.lock.Lock()
  164. err = json.Unmarshal(data, &this)
  165. if err != nil {
  166. log.Error("Unmarshal rezekislot.json failed err:%v", err)
  167. this.lock.Unlock()
  168. return
  169. }
  170. this.slotManager = newSlotManager(this.Slots, this.FreeSlotId)
  171. this.fanManager = newFanManager(this.FanConfig)
  172. this.slotCounts = slotcount.NewMultipleSlotCountManager("rezekislot_normal_mul")
  173. this.freeSlotCount = slotcount.NewMultipleSlotCountManager("rezekislot_free_mul")
  174. this.betLevelManager = betlevel.NewBetLevelManagerByData(this.BetLevels, Msg_BetLevel)
  175. this.slotCommon.SetBetLevelManager(this.betLevelManager)
  176. this.jackpotManager = newJackpotManager(this.fanManager.getJackpotFanId(), 1, this.slotSink.IsChipRoom())
  177. this.freeSpin = newFreeSpinInfo(this.FreeSlotId, this.MinFreeSlotCount, this.FreeTime)
  178. sort.Slice(this.AdBets, func(i, j int) bool {
  179. return this.AdBets[i].AdCount > this.AdBets[j].AdCount
  180. })
  181. this.lock.Unlock()
  182. if this.MaxNoneFreeCount > 0 {
  183. usermanager.SetMaxNoneFreeCount(GAMEID, this.MaxNoneFreeCount)
  184. }
  185. if len(os.Args) >= 2 {
  186. time.AfterFunc(time.Second, this.test)
  187. }
  188. }
  189. func (this *GameLogic) getUserSlotCountNormal(userId int, betAmount int) *slotcount.SlotCountManager {
  190. level := usermanager.GetUserReturnLevel(userId, GAMEID, betAmount)
  191. return this.slotCounts.GetMgr(level)
  192. }
  193. func (this *GameLogic) getUserSlotCountFree(userId int, betAmount int) *slotcount.SlotCountManager {
  194. level := usermanager.GetUserReturnLevel(userId, GAMEID, betAmount)
  195. return this.freeSlotCount.GetMgr(level)
  196. }
  197. func (this *GameLogic) getResult(userId int, betAmount int, isFree bool) RezekiSlot_Result {
  198. var ret RezekiSlot_Result
  199. ret.IsFree = isFree //此次下注是否为免费产生的
  200. var sc *slotcount.SlotCountManager
  201. if isFree {
  202. sc = this.getUserSlotCountFree(userId, betAmount)
  203. } else {
  204. sc = this.getUserSlotCountNormal(userId, betAmount)
  205. }
  206. if sc == nil {
  207. log.Release("GameLogic.getResult 服务器配置有问题")
  208. return ret
  209. }
  210. ret.Slots = make([]int, RESULT_COUNT)
  211. ret.BetAmount = betAmount
  212. level, base := this.betLevelManager.GetLevelAndBase(betAmount)
  213. // 取16个result
  214. ret.Slots = sc.Get16Slots(level, isFree, this.FreeSlotId)
  215. ret.Lines = this.slotManager.getResults(ret.Slots)
  216. if len(ret.Lines) > 0 {
  217. for _, v := range ret.Lines {
  218. winAmount := int(float64(base) * v.WinRate)
  219. ret.WinAmount += winAmount
  220. }
  221. }
  222. freeSlotCount := 0
  223. ret.FreeSpin, freeSlotCount = this.freeSpin.getFreeTime(ret.Slots)
  224. if isFree {
  225. //检查是否重连前有次数
  226. ret.RemainFreeTime = this.getFreeSpinTime(userId)
  227. }
  228. if ret.FreeSpin > 0 {
  229. this.addFreeSpin(userId, ret.FreeSpin, betAmount, false)
  230. ret.RemainFreeTime = this.getFreeSpinTime(userId)
  231. }
  232. //检查有没有Scatter 只要出现三个以上就按倍率乘以投注额返还
  233. if freeSlotCount >= 3 {
  234. slot := this.slotManager.getSlot(this.FreeSlotId)
  235. winMultiple := float64(0)
  236. if slot != nil {
  237. switch freeSlotCount {
  238. case 3:
  239. winMultiple = slot.Win3
  240. case 4:
  241. winMultiple = slot.Win4
  242. case 5:
  243. winMultiple = slot.Win5
  244. default:
  245. winMultiple = slot.Win5
  246. }
  247. }
  248. winAmount := int(float64(betAmount) * winMultiple)
  249. ret.WinAmount += winAmount
  250. }
  251. //每次下注抽取
  252. added := this.jackpotManager.addJackpot(ret.Slots, betAmount, isFree, userId)
  253. //顶格ID
  254. topSlotId := ret.Slots[RESULT_COUNT-1]
  255. fanId := sc.GetFanID(this.slotManager.getMagicSlotId(), topSlotId, level, isFree) //随机获得扇子id
  256. baseAmount := this.betLevelManager.GetAmountByLevel(0) //获得基础下注额
  257. ret.Fan = this.fanManager.getResults(fanId, betAmount, baseAmount, ret.WinAmount)
  258. if ret.Fan.FanID >= 0 {
  259. winAmount := int(ret.Fan.WinAmount)
  260. //免费过程中顶格出现扇子的时候,扇子奖励x2
  261. if isFree && topSlotId == this.slotManager.getMagicSlotId() {
  262. winAmount = winAmount * 2
  263. }
  264. ret.WinAmount += winAmount
  265. }
  266. // 奖池
  267. ret.JackpotLevel, ret.JackpotAmount = this.jackpotManager.checkJackpot(ret.Fan, betAmount, level, userId)
  268. if added || ret.JackpotAmount > 0 {
  269. this.sendJackpot(userId)
  270. }
  271. return ret
  272. }
  273. func (this *GameLogic) useFreeSpin(userId int) (bool, int, bool) {
  274. return this.slotCommon.UseFreeSpin(userId)
  275. }
  276. func (this *GameLogic) getFreeSpinTime(userId int) int {
  277. return this.slotCommon.GetFreeSpinTime(userId)
  278. }
  279. func (this *GameLogic) userExit(userId int) {
  280. this.slotCommon.OnUserExit(userId)
  281. }
  282. func (this *GameLogic) getResultDesc(result RezekiSlot_Result) string {
  283. var total struct {
  284. Slots []int
  285. Lines []int
  286. }
  287. total.Slots = result.Slots
  288. for _, v := range result.Lines {
  289. total.Lines = append(total.Lines, v.WinShape)
  290. }
  291. data, _ := json.Marshal(total)
  292. return string(data)
  293. }
  294. func (this *GameLogic) addFreeSpin(userId int, freeCount, bet int, fromAd bool) {
  295. this.slotCommon.AddFreeSpin(userId, freeCount, bet, fromAd)
  296. }