| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473 |
- package gamelogic
- import (
- "encoding/json"
- "math/rand"
- "os"
- "sync"
- "time"
- "bet24.com/log"
- "bet24.com/servers/games/masharie_table/common"
- "bet24.com/servers/games/masharie_table/config"
- "bet24.com/servers/insecureframe/frame"
- )
- type tablesink struct {
- table frame.Table
- LastStateTick time.Time
- userBetList map[int][]common.Bet
- lock *sync.RWMutex
- userList *userlist
- dayBetRank *betPool
- weekBetRank *betPool
- freeChips *freeChips
- prizePool *prizePool
- prizeArea int
- prizeProject common.CardProject
- prizeTotalBet int
- score_users *common.ScoreUsers
- logic *cardlogic
- robotActions []robot_action
- robotStopEvent chan bool
- robotLock *sync.RWMutex
- scores []common.UserSetScore // 结算阶段,广播所有人的分数,给桌面玩家或者自己头像飘分用
- trumpCard int // 主牌(投注阶段下发)
- bankerCards common.HandCards // 庄家手牌
- diamondCards common.HandCards // 方块手牌
- clubCards common.HandCards // 梅花手牌
- heartCards common.HandCards // 红心手牌
- spadeCards common.HandCards // 黑桃手牌
- bankerInfo common.BankerInfo // 庄家信息
- forceChangeBanker bool // 当庄家请求下庄时,需要等待本局游戏结束
- bankerSettle int
- areaResult []int
- diamondAmount int
- clubAmount int
- heartAmount int
- spadeAmount int
- privateData string
- roomInfo config.RoomInfo
- stat StatisticsList
- isBankerAllKill bool
- }
- func newTableSink(table frame.Table, data string) *tablesink {
- ts := new(tablesink)
- ts.table = table
- ts.privateData = data
- ts.lock = &sync.RWMutex{}
- err := json.Unmarshal([]byte(data), &ts.roomInfo)
- if err != nil {
- found := false
- for _, v := range config.Rooms.Rooms {
- if data == v.RoomName {
- ts.roomInfo = v
- found = true
- break
- }
- }
- if !found {
- ts.roomInfo = config.Rooms.Rooms[0]
- }
- }
- if ts.roomInfo.HistoryCount == 0 {
- ts.roomInfo.HistoryCount = 50
- }
- ts.dayBetRank = newDayBetPool(&ts.roomInfo)
- ts.weekBetRank = newWeekBetPool(&ts.roomInfo)
- ts.logic = newCardLogic()
- ts.bankerInfo.UserId = -1 //设置为系统庄
- ts.bankerInfo.Candidates = make([]common.BankerCandidate, 0)
- ts.userList = newUserList()
- ts.freeChips = newFreeChips(&ts.roomInfo, ts.onFreeChipsChange)
- ts.prizePool = newPrizePool(&ts.roomInfo)
- ts.score_users = new(common.ScoreUsers)
- ts.robotLock = &sync.RWMutex{}
- ts.startPeriod()
- ts.stat.initData(ts.table.GetTableID())
- if ts.test() {
- log.Debug("tablesink.setFrame test end")
- }
- table.SetTimer(common.TIMERID_CHECKROBOT, 5000)
- ts.isBankerAllKill = false
- return ts
- }
- func (ts *tablesink) test() bool {
- if len(os.Args) < 2 {
- return false
- }
- common.ResetProjectMultiple(ts.roomInfo.ProjectMultiple)
- type areaData struct {
- betCount int // 下注次数
- winCount int // 胜利次数
- odds []float64 // 赔率
- }
- bidTypeMax := int(common.BidType_Max)
- testCount := 100
- total := float64(-testCount * bidTypeMax)
- returns := make([]int, bidTypeMax)
- areaDataList := make([]areaData, bidTypeMax)
- for i := 0; i < testCount; i++ {
- _, areaDeck, areaResult, _ := ts.testShuffle()
- for j := 0; j < bidTypeMax; j++ {
- areaDataList[j].betCount++
- if common.Win == areaResult[j] {
- odds := common.GetMultiple(areaDeck[j].Project) + 1
- areaDataList[j].winCount++
- areaDataList[j].odds = append(areaDataList[j].odds, odds)
- returns[j]++
- total += odds
- }
- }
- }
- testResult := make([]float64, bidTypeMax)
- for j := 0; j < bidTypeMax; j++ {
- //评估每个区域的盈利能力。
- winRate := float64(areaDataList[j].winCount) / float64(areaDataList[j].betCount)
- var oddsSum float64
- for _, odds := range areaDataList[j].odds {
- oddsSum += odds
- }
- oddsAvg := oddsSum / float64(len(areaDataList[j].odds))
- testResult[j] = winRate * oddsAvg
- }
- log.Debug("评估每个区域的盈利能力 总投注次数[%d] 每个区域的结果 %v ", testCount, testResult)
- for j := 0; j < bidTypeMax; j++ {
- ts.testOne(j)
- }
- return true
- }
- func (ts *tablesink) testOne(betType int) {
- testCount := 100
- returns := float64(0)
- for i := 0; i < testCount; i++ {
- _, areaDeck, areaResult, _ := ts.testShuffle()
- if common.Win == areaResult[betType] {
- odds := common.GetMultiple(areaDeck[betType].Project) + 1
- returns += odds
- }
- }
- log.Debug("单区域下注结果 下注区域[%s] 下注次数[%d] 累计总赔率:%v 平均赔率 = %f", common.GetBetDesc(betType), testCount, returns, float64(returns)/float64(testCount))
- }
- // 测试洗牌结果
- func (ts *tablesink) testShuffle() (prizeProject common.CardProject, areaDeck []common.CardDeck, areaResult []int, prizeArea int) {
- prizeProject = common.Project_Base
- curCardIndex := 0
- curDeckIndex := 0
- cards := make([]int, CARD_COUNT)
- for d := 0; d < CARD_COUNT; d++ {
- cards[d] = d
- }
- for i := CARD_COUNT - 1; i > 1; i-- {
- place := rand.Intn(i)
- tmp := cards[place]
- cards[place] = cards[i]
- cards[i] = tmp
- }
- drawCard := func(cards []int, curCardIndex *int) int {
- ret := cards[*curCardIndex]
- *curCardIndex++
- return ret
- }
- trumpCard := drawCard(cards, &curCardIndex)
- trumpType := GetCardType(trumpCard)
- generateHandCards := func(cards []int, curCardIndex *int) []int {
- count := HAND_CARD_COUNT
- ret := make([]int, count)
- for i := 0; i < count; i++ {
- ret[i] = drawCard(cards, curCardIndex)
- }
- return ret
- }
- getCardDeck := func(cards []int, curCardIndex *int, trumpType int) []common.CardDeck {
- count := CARD_DECK_COUNT
- cardDeck := make([]common.CardDeck, count)
- for i := 0; i < count; i++ {
- handCards := generateHandCards(cards, curCardIndex)
- hand, project, projectLength, maxCard := SortHandCards(handCards, trumpType)
- cardDeck[i] = common.CardDeck{
- HandCards: common.HandCards{
- Cards: hand,
- Project: project,
- ProjectLength: projectLength,
- MaxCard: maxCard,
- },
- }
- }
- calculateRankings := func(cardDeck []common.CardDeck, trumpType int) {
- for i := 0; i < len(cardDeck); i++ {
- cardDeck[i].Ranking = 1
- for j := 0; j < len(cardDeck); j++ {
- if i == j {
- continue
- }
- if cardDeck[j].HandCards.Project > cardDeck[i].HandCards.Project {
- cardDeck[i].Ranking++
- } else if cardDeck[j].HandCards.Project == cardDeck[i].HandCards.Project {
- //如果是没有项目按照单张牌比较
- if cardDeck[j].HandCards.Project == common.Project_Base {
- ranking := calculateCardsScore(cardDeck[i].HandCards.Cards, cardDeck[j].HandCards.Cards, trumpType)
- if ranking == 2 {
- cardDeck[i].Ranking++
- }
- } else {
- //有项目则 只拿项目中的牌进行比较 不考虑主花色
- //因为已经排好序了 所以只需要比较单张牌值
- ranking := calculateProjectScore(cardDeck[i].HandCards.Cards, cardDeck[j].HandCards.Cards)
- if ranking == 2 {
- cardDeck[i].Ranking++
- }
- }
- }
- }
- }
- }
- calculateRankings(cardDeck, trumpType)
- return cardDeck
- }
- curCardDeck := getCardDeck(cards, &curCardIndex, trumpType)
- //log.Debug("testShuffle CardDeck [%v] curDeckIndex [%v]", curCardDeck, curDeckIndex)
- //trumpCard := ts.logic.trumpCard
- var bankerCards = common.GetInvalidHandCards(HAND_CARD_COUNT, CARD_COUNT)
- var diamondCards = common.GetInvalidHandCards(HAND_CARD_COUNT, CARD_COUNT)
- var clubCards = common.GetInvalidHandCards(HAND_CARD_COUNT, CARD_COUNT)
- var heartCards = common.GetInvalidHandCards(HAND_CARD_COUNT, CARD_COUNT)
- var spadeCards = common.GetInvalidHandCards(HAND_CARD_COUNT, CARD_COUNT)
- areaResult = make([]int, 0)
- //bankerSettle := 0
- getHandCardsByIndex := func(cardDeck []common.CardDeck, curDeckIndex *int) common.CardDeck {
- ret := cardDeck[*curDeckIndex]
- *curDeckIndex++
- return ret
- }
- for i := 0; i < CARD_DECK_COUNT; i++ {
- deck := getHandCardsByIndex(curCardDeck, &curDeckIndex)
- areaDeck = append(areaDeck, deck)
- }
- bankerRanking := areaDeck[common.Area_Banker].Ranking
- bankerDeck := areaDeck[common.Area_Banker]
- bankerCards = bankerDeck.HandCards
- diamondDeck := areaDeck[common.Area_Diamond]
- diamondCards = diamondDeck.HandCards
- clubDeck := areaDeck[common.Area_Club]
- clubCards = clubDeck.HandCards
- heartDeck := areaDeck[common.Area_Heart]
- heartCards = heartDeck.HandCards
- spadeDeck := areaDeck[common.Area_Spade]
- spadeCards = spadeDeck.HandCards
- prizeArea = -1
- for i := 0; i < CARD_DECK_COUNT-1; i++ {
- result := common.Lose
- //排名小于庄家的则算赢
- if areaDeck[i].Ranking < bankerRanking {
- result = common.Win
- }
- areaResult = append(areaResult, result)
- if areaDeck[i].Project >= common.Project_Fifty && areaDeck[i].Project >= prizeProject {
- //如果相同则取最大的
- if prizeArea != -1 && areaDeck[i].Project == prizeProject && areaDeck[i].Ranking > areaDeck[prizeArea].Ranking {
- continue
- }
- prizeArea = i
- prizeProject = areaDeck[i].Project
- }
- }
- log.Debug("testShuffle bankerCards [%v] diamondCards [%v] clubCards [%v] heartCards [%v] spadeCards [%v] areaResult:%v", bankerCards, diamondCards, clubCards, heartCards, spadeCards, areaResult)
- return prizeProject, areaDeck, areaResult, prizeArea
- }
- func (ts *tablesink) Destroy() {
- ts.table.LogWithTableId("------tablesink:Destroy-------")
- //close(ts.stopChan)
- }
- func (ts *tablesink) OnUserEnterTable(userIndex int32, chairId int) {
- u, _ := ts.table.GetUser(userIndex)
- if u == nil {
- log.Debug("tablesink.OnUserEnterTable %d not exist", userIndex)
- return
- }
- if !u.IsRobot() {
- // 发送配置信息
- ts.sendGameOption(userIndex)
- // 发送场景
- ts.sendGameScene(userIndex)
- go ts.onCheckFreeChip(userIndex, u.GetUserId(), FreeChip, "")
- }
- ts.userList.addUser(u.GetUserId(), u.GetUserNickName(), u.GetUserFaceId(), u.GetUserFaceUrl(), u.GetUserVipLevel(), u.GetUserVipExpire(), u.GetDecorations())
- ts.dayBetRank.addUser(u.GetUserId())
- ts.weekBetRank.addUser(u.GetUserId())
- }
- func (ts *tablesink) OnUserExitTable(userIndex int32, chairId int) {
- //判断一下用户是否有下注
- usr, _ := ts.table.GetUser(userIndex)
- if usr == nil {
- log.Debug("tablesink.OnUserExit %d not exist", userIndex)
- return
- }
- userId := usr.GetUserId()
- ts.lock.RLock()
- _, isBet := ts.userBetList[userId]
- isBanker := ts.bankerInfo.UserId == userId
- log.Release("tablesink.OnUserExit userId %d isBet %v isBanker %v", userId, isBet, isBanker)
- ts.lock.RUnlock()
- if !isBanker && !isBet {
- ts.lock.Lock()
- ts.userList.removeUser(userId)
- if ts.removeCandidate(userId) {
- ts.broadcastBankerInfo()
- } else {
- log.Debug("tablesink.OnUserExit removeCandidate userId %d fail", userId)
- }
- if usr.IsRobot() {
- if !ts.weekBetRank.isRank(userId) {
- ts.weekBetRank.removeUser(userId)
- }
- if !ts.dayBetRank.isRank(userId) {
- ts.dayBetRank.removeUser(userId)
- }
- }
- ts.lock.Unlock()
- return
- }
- betRemaining := ts.getBetRemainingSecond()
- //是否允许离开
- isExit := true
- //庄家也不允许离开
- if isBanker || (isBet && ts.roomInfo.State == common.GameState_Bet && betRemaining > 0) {
- isExit = false
- }
- //检查当前阶段是否为下注阶段
- if !usr.IsRobot() && !isExit {
- //如果第一次下注写重连
- gs.setOfflineStatus(userId, true, betRemaining, !isBanker)
- return
- }
- ts.lock.Lock()
- if usr.IsRobot() && isExit {
- if !ts.weekBetRank.isRank(userId) {
- ts.weekBetRank.removeUser(userId)
- }
- if !ts.dayBetRank.isRank(userId) {
- ts.dayBetRank.removeUser(userId)
- }
- }
- ts.userList.removeUser(userId)
- if ts.removeCandidate(userId) {
- ts.broadcastBankerInfo()
- } else {
- log.Debug("tablesink.OnUserExit removeCandidate userId %d fail", userId)
- }
- ts.lock.Unlock()
- }
- func (ts *tablesink) OnUserOffline(chairId int) {
- }
- func (ts *tablesink) OnUserReplay(chairId int) {
- }
- func (ts *tablesink) OnUserReady(userIndex int32, chairId int) {
- }
- func (ts *tablesink) OnUserCancelReady(userIndex int32, chairId int) {
- }
- func (ts *tablesink) OnGetChairScene(chairId int, isPlayer bool) string {
- return ts.getStateData()
- }
- func (ts *tablesink) OnGetPrivateRoomScene(chairId int) string {
- return ts.getStateData()
- }
- func (ts *tablesink) OnGetChairCount() int {
- return 1
- }
- func (ts *tablesink) OnTimer(timerId int) {
- switch timerId {
- case common.TIMERID_CHECKROBOT:
- ts.checkRobot()
- ts.table.SetTimer(timerId, 5000)
- default:
- ts.table.LogWithTableId("tablesink.OnTimer unhandled timer[%d]", timerId)
- }
- }
- func (ts *tablesink) DumpScene() {
- }
- func (ts *tablesink) GetGoldLimit() (min, max int) {
- return ts.roomInfo.MinBet, ts.roomInfo.MaxBet
- }
- func (ts *tablesink) IsDual() bool {
- return false
- }
- func (ts *tablesink) OnBaseScoreChanged(baseScore int) {
- }
- func (ts *tablesink) SetPrivateRoomParam(param int, value string) {
- ts.table.LogWithTableId("tablesink.SetPrivateRoomParam %d:%s", param, value)
- }
- func (ts *tablesink) OnPrivateRoomStatusChanged(oldStatus, newStatus int) {
- ts.table.LogWithTableId("OnPrivateRoomStatusChanged %d->%d", oldStatus, newStatus)
- }
- func (ts *tablesink) OnPrivateRoomDismissed() {
- ts.table.LogWithTableId("OnPrivateRoomDismissed ")
- }
- func (ts *tablesink) IsAllRobot() bool {
- return false
- }
|