tablesink.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473
  1. package gamelogic
  2. import (
  3. "encoding/json"
  4. "math/rand"
  5. "os"
  6. "sync"
  7. "time"
  8. "bet24.com/log"
  9. "bet24.com/servers/games/masharie_table/common"
  10. "bet24.com/servers/games/masharie_table/config"
  11. "bet24.com/servers/insecureframe/frame"
  12. )
  13. type tablesink struct {
  14. table frame.Table
  15. LastStateTick time.Time
  16. userBetList map[int][]common.Bet
  17. lock *sync.RWMutex
  18. userList *userlist
  19. dayBetRank *betPool
  20. weekBetRank *betPool
  21. freeChips *freeChips
  22. prizePool *prizePool
  23. prizeArea int
  24. prizeProject common.CardProject
  25. prizeTotalBet int
  26. score_users *common.ScoreUsers
  27. logic *cardlogic
  28. robotActions []robot_action
  29. robotStopEvent chan bool
  30. robotLock *sync.RWMutex
  31. scores []common.UserSetScore // 结算阶段,广播所有人的分数,给桌面玩家或者自己头像飘分用
  32. trumpCard int // 主牌(投注阶段下发)
  33. bankerCards common.HandCards // 庄家手牌
  34. diamondCards common.HandCards // 方块手牌
  35. clubCards common.HandCards // 梅花手牌
  36. heartCards common.HandCards // 红心手牌
  37. spadeCards common.HandCards // 黑桃手牌
  38. bankerInfo common.BankerInfo // 庄家信息
  39. forceChangeBanker bool // 当庄家请求下庄时,需要等待本局游戏结束
  40. bankerSettle int
  41. areaResult []int
  42. diamondAmount int
  43. clubAmount int
  44. heartAmount int
  45. spadeAmount int
  46. privateData string
  47. roomInfo config.RoomInfo
  48. stat StatisticsList
  49. isBankerAllKill bool
  50. }
  51. func newTableSink(table frame.Table, data string) *tablesink {
  52. ts := new(tablesink)
  53. ts.table = table
  54. ts.privateData = data
  55. ts.lock = &sync.RWMutex{}
  56. err := json.Unmarshal([]byte(data), &ts.roomInfo)
  57. if err != nil {
  58. found := false
  59. for _, v := range config.Rooms.Rooms {
  60. if data == v.RoomName {
  61. ts.roomInfo = v
  62. found = true
  63. break
  64. }
  65. }
  66. if !found {
  67. ts.roomInfo = config.Rooms.Rooms[0]
  68. }
  69. }
  70. if ts.roomInfo.HistoryCount == 0 {
  71. ts.roomInfo.HistoryCount = 50
  72. }
  73. ts.dayBetRank = newDayBetPool(&ts.roomInfo)
  74. ts.weekBetRank = newWeekBetPool(&ts.roomInfo)
  75. ts.logic = newCardLogic()
  76. ts.bankerInfo.UserId = -1 //设置为系统庄
  77. ts.bankerInfo.Candidates = make([]common.BankerCandidate, 0)
  78. ts.userList = newUserList()
  79. ts.freeChips = newFreeChips(&ts.roomInfo, ts.onFreeChipsChange)
  80. ts.prizePool = newPrizePool(&ts.roomInfo)
  81. ts.score_users = new(common.ScoreUsers)
  82. ts.robotLock = &sync.RWMutex{}
  83. ts.startPeriod()
  84. ts.stat.initData(ts.table.GetTableID())
  85. if ts.test() {
  86. log.Debug("tablesink.setFrame test end")
  87. }
  88. table.SetTimer(common.TIMERID_CHECKROBOT, 5000)
  89. ts.isBankerAllKill = false
  90. return ts
  91. }
  92. func (ts *tablesink) test() bool {
  93. if len(os.Args) < 2 {
  94. return false
  95. }
  96. common.ResetProjectMultiple(ts.roomInfo.ProjectMultiple)
  97. type areaData struct {
  98. betCount int // 下注次数
  99. winCount int // 胜利次数
  100. odds []float64 // 赔率
  101. }
  102. bidTypeMax := int(common.BidType_Max)
  103. testCount := 100
  104. total := float64(-testCount * bidTypeMax)
  105. returns := make([]int, bidTypeMax)
  106. areaDataList := make([]areaData, bidTypeMax)
  107. for i := 0; i < testCount; i++ {
  108. _, areaDeck, areaResult, _ := ts.testShuffle()
  109. for j := 0; j < bidTypeMax; j++ {
  110. areaDataList[j].betCount++
  111. if common.Win == areaResult[j] {
  112. odds := common.GetMultiple(areaDeck[j].Project) + 1
  113. areaDataList[j].winCount++
  114. areaDataList[j].odds = append(areaDataList[j].odds, odds)
  115. returns[j]++
  116. total += odds
  117. }
  118. }
  119. }
  120. testResult := make([]float64, bidTypeMax)
  121. for j := 0; j < bidTypeMax; j++ {
  122. //评估每个区域的盈利能力。
  123. winRate := float64(areaDataList[j].winCount) / float64(areaDataList[j].betCount)
  124. var oddsSum float64
  125. for _, odds := range areaDataList[j].odds {
  126. oddsSum += odds
  127. }
  128. oddsAvg := oddsSum / float64(len(areaDataList[j].odds))
  129. testResult[j] = winRate * oddsAvg
  130. }
  131. log.Debug("评估每个区域的盈利能力 总投注次数[%d] 每个区域的结果 %v ", testCount, testResult)
  132. for j := 0; j < bidTypeMax; j++ {
  133. ts.testOne(j)
  134. }
  135. return true
  136. }
  137. func (ts *tablesink) testOne(betType int) {
  138. testCount := 100
  139. returns := float64(0)
  140. for i := 0; i < testCount; i++ {
  141. _, areaDeck, areaResult, _ := ts.testShuffle()
  142. if common.Win == areaResult[betType] {
  143. odds := common.GetMultiple(areaDeck[betType].Project) + 1
  144. returns += odds
  145. }
  146. }
  147. log.Debug("单区域下注结果 下注区域[%s] 下注次数[%d] 累计总赔率:%v 平均赔率 = %f", common.GetBetDesc(betType), testCount, returns, float64(returns)/float64(testCount))
  148. }
  149. // 测试洗牌结果
  150. func (ts *tablesink) testShuffle() (prizeProject common.CardProject, areaDeck []common.CardDeck, areaResult []int, prizeArea int) {
  151. prizeProject = common.Project_Base
  152. curCardIndex := 0
  153. curDeckIndex := 0
  154. cards := make([]int, CARD_COUNT)
  155. for d := 0; d < CARD_COUNT; d++ {
  156. cards[d] = d
  157. }
  158. for i := CARD_COUNT - 1; i > 1; i-- {
  159. place := rand.Intn(i)
  160. tmp := cards[place]
  161. cards[place] = cards[i]
  162. cards[i] = tmp
  163. }
  164. drawCard := func(cards []int, curCardIndex *int) int {
  165. ret := cards[*curCardIndex]
  166. *curCardIndex++
  167. return ret
  168. }
  169. trumpCard := drawCard(cards, &curCardIndex)
  170. trumpType := GetCardType(trumpCard)
  171. generateHandCards := func(cards []int, curCardIndex *int) []int {
  172. count := HAND_CARD_COUNT
  173. ret := make([]int, count)
  174. for i := 0; i < count; i++ {
  175. ret[i] = drawCard(cards, curCardIndex)
  176. }
  177. return ret
  178. }
  179. getCardDeck := func(cards []int, curCardIndex *int, trumpType int) []common.CardDeck {
  180. count := CARD_DECK_COUNT
  181. cardDeck := make([]common.CardDeck, count)
  182. for i := 0; i < count; i++ {
  183. handCards := generateHandCards(cards, curCardIndex)
  184. hand, project, projectLength, maxCard := SortHandCards(handCards, trumpType)
  185. cardDeck[i] = common.CardDeck{
  186. HandCards: common.HandCards{
  187. Cards: hand,
  188. Project: project,
  189. ProjectLength: projectLength,
  190. MaxCard: maxCard,
  191. },
  192. }
  193. }
  194. calculateRankings := func(cardDeck []common.CardDeck, trumpType int) {
  195. for i := 0; i < len(cardDeck); i++ {
  196. cardDeck[i].Ranking = 1
  197. for j := 0; j < len(cardDeck); j++ {
  198. if i == j {
  199. continue
  200. }
  201. if cardDeck[j].HandCards.Project > cardDeck[i].HandCards.Project {
  202. cardDeck[i].Ranking++
  203. } else if cardDeck[j].HandCards.Project == cardDeck[i].HandCards.Project {
  204. //如果是没有项目按照单张牌比较
  205. if cardDeck[j].HandCards.Project == common.Project_Base {
  206. ranking := calculateCardsScore(cardDeck[i].HandCards.Cards, cardDeck[j].HandCards.Cards, trumpType)
  207. if ranking == 2 {
  208. cardDeck[i].Ranking++
  209. }
  210. } else {
  211. //有项目则 只拿项目中的牌进行比较 不考虑主花色
  212. //因为已经排好序了 所以只需要比较单张牌值
  213. ranking := calculateProjectScore(cardDeck[i].HandCards.Cards, cardDeck[j].HandCards.Cards)
  214. if ranking == 2 {
  215. cardDeck[i].Ranking++
  216. }
  217. }
  218. }
  219. }
  220. }
  221. }
  222. calculateRankings(cardDeck, trumpType)
  223. return cardDeck
  224. }
  225. curCardDeck := getCardDeck(cards, &curCardIndex, trumpType)
  226. //log.Debug("testShuffle CardDeck [%v] curDeckIndex [%v]", curCardDeck, curDeckIndex)
  227. //trumpCard := ts.logic.trumpCard
  228. var bankerCards = common.GetInvalidHandCards(HAND_CARD_COUNT, CARD_COUNT)
  229. var diamondCards = common.GetInvalidHandCards(HAND_CARD_COUNT, CARD_COUNT)
  230. var clubCards = common.GetInvalidHandCards(HAND_CARD_COUNT, CARD_COUNT)
  231. var heartCards = common.GetInvalidHandCards(HAND_CARD_COUNT, CARD_COUNT)
  232. var spadeCards = common.GetInvalidHandCards(HAND_CARD_COUNT, CARD_COUNT)
  233. areaResult = make([]int, 0)
  234. //bankerSettle := 0
  235. getHandCardsByIndex := func(cardDeck []common.CardDeck, curDeckIndex *int) common.CardDeck {
  236. ret := cardDeck[*curDeckIndex]
  237. *curDeckIndex++
  238. return ret
  239. }
  240. for i := 0; i < CARD_DECK_COUNT; i++ {
  241. deck := getHandCardsByIndex(curCardDeck, &curDeckIndex)
  242. areaDeck = append(areaDeck, deck)
  243. }
  244. bankerRanking := areaDeck[common.Area_Banker].Ranking
  245. bankerDeck := areaDeck[common.Area_Banker]
  246. bankerCards = bankerDeck.HandCards
  247. diamondDeck := areaDeck[common.Area_Diamond]
  248. diamondCards = diamondDeck.HandCards
  249. clubDeck := areaDeck[common.Area_Club]
  250. clubCards = clubDeck.HandCards
  251. heartDeck := areaDeck[common.Area_Heart]
  252. heartCards = heartDeck.HandCards
  253. spadeDeck := areaDeck[common.Area_Spade]
  254. spadeCards = spadeDeck.HandCards
  255. prizeArea = -1
  256. for i := 0; i < CARD_DECK_COUNT-1; i++ {
  257. result := common.Lose
  258. //排名小于庄家的则算赢
  259. if areaDeck[i].Ranking < bankerRanking {
  260. result = common.Win
  261. }
  262. areaResult = append(areaResult, result)
  263. if areaDeck[i].Project >= common.Project_Fifty && areaDeck[i].Project >= prizeProject {
  264. //如果相同则取最大的
  265. if prizeArea != -1 && areaDeck[i].Project == prizeProject && areaDeck[i].Ranking > areaDeck[prizeArea].Ranking {
  266. continue
  267. }
  268. prizeArea = i
  269. prizeProject = areaDeck[i].Project
  270. }
  271. }
  272. log.Debug("testShuffle bankerCards [%v] diamondCards [%v] clubCards [%v] heartCards [%v] spadeCards [%v] areaResult:%v", bankerCards, diamondCards, clubCards, heartCards, spadeCards, areaResult)
  273. return prizeProject, areaDeck, areaResult, prizeArea
  274. }
  275. func (ts *tablesink) Destroy() {
  276. ts.table.LogWithTableId("------tablesink:Destroy-------")
  277. //close(ts.stopChan)
  278. }
  279. func (ts *tablesink) OnUserEnterTable(userIndex int32, chairId int) {
  280. u, _ := ts.table.GetUser(userIndex)
  281. if u == nil {
  282. log.Debug("tablesink.OnUserEnterTable %d not exist", userIndex)
  283. return
  284. }
  285. if !u.IsRobot() {
  286. // 发送配置信息
  287. ts.sendGameOption(userIndex)
  288. // 发送场景
  289. ts.sendGameScene(userIndex)
  290. go ts.onCheckFreeChip(userIndex, u.GetUserId(), FreeChip, "")
  291. }
  292. ts.userList.addUser(u.GetUserId(), u.GetUserNickName(), u.GetUserFaceId(), u.GetUserFaceUrl(), u.GetUserVipLevel(), u.GetUserVipExpire(), u.GetDecorations())
  293. ts.dayBetRank.addUser(u.GetUserId())
  294. ts.weekBetRank.addUser(u.GetUserId())
  295. }
  296. func (ts *tablesink) OnUserExitTable(userIndex int32, chairId int) {
  297. //判断一下用户是否有下注
  298. usr, _ := ts.table.GetUser(userIndex)
  299. if usr == nil {
  300. log.Debug("tablesink.OnUserExit %d not exist", userIndex)
  301. return
  302. }
  303. userId := usr.GetUserId()
  304. ts.lock.RLock()
  305. _, isBet := ts.userBetList[userId]
  306. isBanker := ts.bankerInfo.UserId == userId
  307. log.Release("tablesink.OnUserExit userId %d isBet %v isBanker %v", userId, isBet, isBanker)
  308. ts.lock.RUnlock()
  309. if !isBanker && !isBet {
  310. ts.lock.Lock()
  311. ts.userList.removeUser(userId)
  312. if ts.removeCandidate(userId) {
  313. ts.broadcastBankerInfo()
  314. } else {
  315. log.Debug("tablesink.OnUserExit removeCandidate userId %d fail", userId)
  316. }
  317. if usr.IsRobot() {
  318. if !ts.weekBetRank.isRank(userId) {
  319. ts.weekBetRank.removeUser(userId)
  320. }
  321. if !ts.dayBetRank.isRank(userId) {
  322. ts.dayBetRank.removeUser(userId)
  323. }
  324. }
  325. ts.lock.Unlock()
  326. return
  327. }
  328. betRemaining := ts.getBetRemainingSecond()
  329. //是否允许离开
  330. isExit := true
  331. //庄家也不允许离开
  332. if isBanker || (isBet && ts.roomInfo.State == common.GameState_Bet && betRemaining > 0) {
  333. isExit = false
  334. }
  335. //检查当前阶段是否为下注阶段
  336. if !usr.IsRobot() && !isExit {
  337. //如果第一次下注写重连
  338. gs.setOfflineStatus(userId, true, betRemaining, !isBanker)
  339. return
  340. }
  341. ts.lock.Lock()
  342. if usr.IsRobot() && isExit {
  343. if !ts.weekBetRank.isRank(userId) {
  344. ts.weekBetRank.removeUser(userId)
  345. }
  346. if !ts.dayBetRank.isRank(userId) {
  347. ts.dayBetRank.removeUser(userId)
  348. }
  349. }
  350. ts.userList.removeUser(userId)
  351. if ts.removeCandidate(userId) {
  352. ts.broadcastBankerInfo()
  353. } else {
  354. log.Debug("tablesink.OnUserExit removeCandidate userId %d fail", userId)
  355. }
  356. ts.lock.Unlock()
  357. }
  358. func (ts *tablesink) OnUserOffline(chairId int) {
  359. }
  360. func (ts *tablesink) OnUserReplay(chairId int) {
  361. }
  362. func (ts *tablesink) OnUserReady(userIndex int32, chairId int) {
  363. }
  364. func (ts *tablesink) OnUserCancelReady(userIndex int32, chairId int) {
  365. }
  366. func (ts *tablesink) OnGetChairScene(chairId int, isPlayer bool) string {
  367. return ts.getStateData()
  368. }
  369. func (ts *tablesink) OnGetPrivateRoomScene(chairId int) string {
  370. return ts.getStateData()
  371. }
  372. func (ts *tablesink) OnGetChairCount() int {
  373. return 1
  374. }
  375. func (ts *tablesink) OnTimer(timerId int) {
  376. switch timerId {
  377. case common.TIMERID_CHECKROBOT:
  378. ts.checkRobot()
  379. ts.table.SetTimer(timerId, 5000)
  380. default:
  381. ts.table.LogWithTableId("tablesink.OnTimer unhandled timer[%d]", timerId)
  382. }
  383. }
  384. func (ts *tablesink) DumpScene() {
  385. }
  386. func (ts *tablesink) GetGoldLimit() (min, max int) {
  387. return ts.roomInfo.MinBet, ts.roomInfo.MaxBet
  388. }
  389. func (ts *tablesink) IsDual() bool {
  390. return false
  391. }
  392. func (ts *tablesink) OnBaseScoreChanged(baseScore int) {
  393. }
  394. func (ts *tablesink) SetPrivateRoomParam(param int, value string) {
  395. ts.table.LogWithTableId("tablesink.SetPrivateRoomParam %d:%s", param, value)
  396. }
  397. func (ts *tablesink) OnPrivateRoomStatusChanged(oldStatus, newStatus int) {
  398. ts.table.LogWithTableId("OnPrivateRoomStatusChanged %d->%d", oldStatus, newStatus)
  399. }
  400. func (ts *tablesink) OnPrivateRoomDismissed() {
  401. ts.table.LogWithTableId("OnPrivateRoomDismissed ")
  402. }
  403. func (ts *tablesink) IsAllRobot() bool {
  404. return false
  405. }