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 }