package thirteen import ( "fmt" "math" "math/rand" "sort" "strings" "time" "mongo.games.com/goserver/core/logger" "mongo.games.com/game/common" rule "mongo.games.com/game/gamerule/thirteen" "mongo.games.com/game/gamesrv/base" "mongo.games.com/game/proto" "mongo.games.com/game/protocol/thirteen" ) type PlayerData struct { SnId int32 cards [13]int //手牌信息 cardsO *rule.Group //确定的牌型信息 isDP bool // 是否倒排 gainCoin int64 //本局赢的金币 taxCoin int64 //本局税收 clubPump int64 //俱乐部抽水 deterMine bool //玩家是否确定牌 score [7]int64 //玩家每墩的得分 0:头 1中 2尾 3:特殊牌型分数 4打枪 5全垒打 6离场补偿分 tableScore [6]int64 // 客户端展示 winThreePos map[int]int64 //只包含打枪玩家位置和总赢分 winAllPlayers map[int]int64 //玩家位置和输赢分 isStand bool //玩家站起 true打开 本局结束后自动离开房间 false未打开 isBilled bool // 是否结算 IsRob bool Pos int Coin int64 StartCoin int64 Head int32 //头像 flag int Platform string //平台 Channel string //渠道信息 PackageID string //推广包标识 对应客户端的packagetag PromoterTree int32 InviterId int32 //邀请人Id WBLevel int32 //黑白名单 白:[1,10] 黑:[-1,-10] CurIsWin int64 //当局输赢 负数:输 0:平局 正数:赢 BeUnderAgentCode string //隶属经销商(推广人) Name string //名字 Sex int32 //性别 City string //城市 Longitude int32 //经纬度 Latitude int32 //经纬度 AgentCode string //代理商编号 HeadOutLine int32 //头像框 VIP int32 //VIP帐号 等级 allGroup map[int]*rule.Group TestLog []string RoleId int32 PlayerPool int // 个人水池分 SkinId int32 } type SceneEx struct { *base.Scene //场景 poker *rule.Pokers // 扑克牌对象 logic *rule.Logic // 十三张算法 players map[int32]*PlayerEx // 玩家信息 seats []*PlayerEx // 本局游戏中的玩家状态数据 isCanAllHitPos int // 全垒打玩家坐标 =4人 并且没有特殊牌型 currOpPos int // 当前操作的玩家 hitTime time.Duration // 打枪阶段按打枪人数加时间 specialTime time.Duration // 亮牌阶段有特殊牌型增加时间 specialTypeNum int // 玩家有特殊牌的个数 entryHitState bool // 是否可以进入打枪阶段 robotNum int // 参与游戏的机器人数量 gamePlayerNum int // 参与游戏的人数量 r int // 体验场测试数据 cardsSlice [][13]int // 从大到小排列四副牌 nowMaxCardsIsIn bool // 现在最大牌是否还在 PlayerBackup map[int32]*PlayerData // 本局离场玩家数据备份 LeaveNum int // 离场扣分人数 testPokers []int64 // 测试牌堆 logid string ctrlType int // 1控赢 2控输 0不控 cardsArr [][13]int cardsGroup []map[int]*rule.Group timestamp time.Time } func NewThirteenWaterSceneData(s *base.Scene) *SceneEx { sceneEx := &SceneEx{ Scene: s, logic: new(rule.Logic), players: make(map[int32]*PlayerEx), seats: make([]*PlayerEx, s.GetPlayerNum()), PlayerBackup: make(map[int32]*PlayerData), } if s.GetPlayerNum() > 4 { // 两幅牌 sceneEx.poker = rule.NewPokers(2, sceneEx.HasLaiZi()) } else { sceneEx.poker = rule.NewPokers(1, sceneEx.HasLaiZi()) } if sceneEx.HasLaiZi() { sceneEx.logic.LaiZi = []int{52, 53} // 目前只有大小王为癞子 } return sceneEx } func (this *SceneEx) init() bool { this.Clear() return true } func (this *SceneEx) Clear() { this.poker.Init() this.isCanAllHitPos = -1 this.currOpPos = -1 this.hitTime = rule.ThirteenWaterHitTimeout this.specialTypeNum = 0 this.entryHitState = false this.robotNum = 0 this.gamePlayerNum = 0 this.r = 1 this.cardsSlice = nil this.nowMaxCardsIsIn = true this.PlayerBackup = make(map[int32]*PlayerData) this.LeaveNum = 0 this.ctrlType = 0 this.cardsArr = nil this.cardsGroup = nil for i := 0; i < this.GetPlayerNum(); i++ { if this.seats[i] != nil { this.seats[i].Clear() } } } func (this *SceneEx) delPlayer(p *base.Player) { if p, exist := this.players[p.SnId]; exist { this.seats[p.GetPos()] = nil delete(this.players, p.SnId) } } func (this *SceneEx) BroadcastPlayerLeave(p *base.Player, reason int) { scLeavePack := &thirteen.SCThirteenPlayerLeave{ Pos: proto.Int(p.GetPos()), } proto.SetDefaults(scLeavePack) this.Broadcast(int(thirteen.TWMmoPacketID_PACKET_SCThirteenPlayerLeave), scLeavePack, p.GetSid()) } func (this *SceneEx) OnPlayerLeave(p *base.Player, reason int) { this.delPlayer(p) this.BroadcastPlayerLeave(p, reason) } func (this *SceneEx) SceneDestroy(force bool) { //销毁房间 this.Scene.Destroy(force) } func (this *SceneEx) CanStart() bool { //房间人数>=2自动开始,并且有真人或者是预创建房间 if len(this.players) >= 2 && (this.GetRealPlayerNum() > 0 || this.IsPreCreateScene()) { return true } return false } func (this *SceneEx) ThirteenWaterCreateRoomInfoPacket(s *base.Scene, p *base.Player) interface{} { pack := &thirteen.SCThirteenRoomInfo{ RoomId: proto.Int(s.GetSceneId()), Creator: proto.Int32(s.GetCreator()), GameId: proto.Int(s.GetGameId()), RoomMode: proto.Int(s.GetSceneMode()), SceneType: s.GetDBGameFree().SceneType, State: proto.Int(s.GetSceneState().GetState()), TimeOut: proto.Int(s.GetSceneState().GetTimeout(s)), DisbandGen: proto.Int(this.GetDisbandGen()), BaseScore: int32(this.GetBaseScore()), LeaveDeduct: this.GetDBGameFree().GetLeaveDeduct(), LeaveCombat: this.GetDBGameFree().GetLeaveCombat(), Params: common.CopySliceInt64ToInt32(s.Params), } pack.TimeOuts = make([]int64, 4) pack.TimeOuts[rule.TimeoutStart] = int64(rule.GetTimeout(this.GetDBGameFree().GetOtherIntParams(), rule.TimeoutStart).Seconds()) pack.TimeOuts[rule.TimeoutSendCards] = int64(rule.GetTimeout(this.GetDBGameFree().GetOtherIntParams(), rule.TimeoutSendCards).Seconds()) pack.TimeOuts[rule.TimeoutOp] = int64(rule.GetTimeout(this.GetDBGameFree().GetOtherIntParams(), rule.TimeoutOp).Seconds()) pack.TimeOuts[rule.TimeoutBill] = int64(rule.GetTimeout(this.GetDBGameFree().GetOtherIntParams(), rule.TimeoutBill).Seconds()) // 玩家信息 for _, playerEx := range this.players { pd := &thirteen.ThirteenPlayerData{ SnId: proto.Int32(playerEx.SnId), Name: proto.String(playerEx.Name), Head: proto.Int32(playerEx.Head), Sex: proto.Int32(playerEx.Sex), Coin: proto.Int64(playerEx.Coin), Pos: proto.Int(playerEx.Pos), Flag: proto.Int(playerEx.GetFlag()), Longitude: proto.Int32(playerEx.Longitude), Latitude: proto.Int32(playerEx.Latitude), City: proto.String(playerEx.City), AgentCode: proto.String(playerEx.AgentCode), HeadOutLine: proto.Int32(playerEx.HeadOutLine), VIP: proto.Int32(playerEx.VIP), IsStand: proto.Bool(playerEx.isStand), IsConfirm: proto.Bool(playerEx.deterMine), RoleId: playerEx.PlayerData.GetRoleId(), Level: proto.Int64(playerEx.PlayerData.Level), Exp: proto.Int64(playerEx.PlayerData.Exp), } if playerEx.Skin != nil { pd.SkinId = playerEx.Skin.ModId } ppp := &thirteen.Poker{} ppp.IndexType = -1 pd.CardsO = ppp if playerEx.cardsO != nil { if playerEx.cardsO.PokerType > 0 { //确定之后为特殊牌型 ppp := &thirteen.Poker{} ppp.Head = common.CopySliceIntToInt32(playerEx.cards[:3]) ppp.Mid = common.CopySliceIntToInt32(playerEx.cards[3:8]) ppp.End = common.CopySliceIntToInt32(playerEx.cards[8:]) ppp.IndexType = proto.Int32(int32(playerEx.cardsO.PokerType * 1000000)) pd.CardsO = ppp pd.IsDP = playerEx.isDP } else if playerEx.cardsO.PokerType == 0 { //确定之后为普通牌型 ppp := &thirteen.Poker{} ppp.Head = common.CopySliceIntToInt32(playerEx.cardsO.Head[:]) ppp.Mid = common.CopySliceIntToInt32(playerEx.cardsO.Mid[:]) ppp.End = common.CopySliceIntToInt32(playerEx.cardsO.End[:]) ppp.IndexType = proto.Int32(int32(this.FormatCards(playerEx.cardsO))) pd.CardsO = ppp pd.IsDP = playerEx.isDP } } if playerEx.cards[0] != -1 { pd.Cards = common.CopySliceIntToInt32(playerEx.cards[:]) } if playerEx.allGroup != nil { pd.AllCardsO, _ = AllGroupToProto(playerEx.allGroup) } if p == nil || playerEx.SnId != p.SnId { if s.SceneState.GetState() == rule.ThirteenWaterSceneStateSendCards || s.SceneState.GetState() == rule.ThirteenWaterSceneStateOptCard { pd.Cards = nil pd.AllCardsO = nil if pd.CardsO.IndexType > 0 { ppp := &thirteen.Poker{} ppp.IndexType = 0 pd.CardsO = ppp pd.IsDP = false } } } if s.SceneState.GetState() == rule.ThirteenWaterSceneStateShowCards || s.SceneState.GetState() == rule.ThirteenWaterSceneStateHit || s.SceneState.GetState() == rule.ThirteenWaterSceneStateBilled { pd.Score = playerEx.score[:] pd.TableScore = playerEx.tableScore[:] var hitScore []*thirteen.HitScore for k, v := range playerEx.winThreePos { pck := &thirteen.HitScore{ Pos: proto.Int32(int32(k)), Score: proto.Int64(v), } hitScore = append(hitScore, pck) } pd.Hit = hitScore } if s.SceneState.GetState() == rule.ThirteenWaterSceneStateBilled { pd.WinCoin = playerEx.gainCoin } pack.Players = append(pack.Players, pd) } // 备份的玩家信息 for _, playerEx := range this.PlayerBackup { if playerEx != nil || !playerEx.isBilled { continue } pd := &thirteen.ThirteenPlayerData{ SnId: proto.Int32(playerEx.SnId), Name: proto.String(playerEx.Name), Head: proto.Int32(playerEx.Head), Sex: proto.Int32(playerEx.Sex), Coin: proto.Int64(playerEx.Coin), Pos: proto.Int(playerEx.Pos), Flag: proto.Int(playerEx.flag), Longitude: proto.Int32(playerEx.Longitude), Latitude: proto.Int32(playerEx.Latitude), City: proto.String(playerEx.City), AgentCode: proto.String(playerEx.AgentCode), HeadOutLine: proto.Int32(playerEx.HeadOutLine), VIP: proto.Int32(playerEx.VIP), IsStand: proto.Bool(playerEx.isStand), IsConfirm: proto.Bool(playerEx.deterMine), IsLeave: true, RoleId: playerEx.RoleId, SkinId: playerEx.SkinId, } ppp := &thirteen.Poker{} ppp.IndexType = -1 pd.CardsO = ppp if playerEx.cardsO != nil { if playerEx.cardsO.PokerType > 0 { //确定之后为特殊牌型 ppp := &thirteen.Poker{} ppp.Head = common.CopySliceIntToInt32(playerEx.cards[:3]) ppp.Mid = common.CopySliceIntToInt32(playerEx.cards[3:8]) ppp.End = common.CopySliceIntToInt32(playerEx.cards[8:]) ppp.IndexType = proto.Int32(int32(playerEx.cardsO.PokerType * 1000000)) pd.CardsO = ppp pd.IsDP = playerEx.isDP } else if playerEx.cardsO.PokerType == 0 { //确定之后为普通牌型 ppp := &thirteen.Poker{} ppp.Head = common.CopySliceIntToInt32(playerEx.cardsO.Head[:]) ppp.Mid = common.CopySliceIntToInt32(playerEx.cardsO.Mid[:]) ppp.End = common.CopySliceIntToInt32(playerEx.cardsO.End[:]) ppp.IndexType = proto.Int32(int32(this.FormatCards(playerEx.cardsO))) pd.CardsO = ppp pd.IsDP = playerEx.isDP } } if playerEx.cards[0] != -1 { pd.Cards = common.CopySliceIntToInt32(playerEx.cards[:]) } if playerEx.allGroup != nil { pd.AllCardsO, _ = AllGroupToProto(playerEx.allGroup) } if p == nil || playerEx.SnId != p.SnId { if s.SceneState.GetState() == rule.ThirteenWaterSceneStateSendCards || s.SceneState.GetState() == rule.ThirteenWaterSceneStateOptCard { pd.Cards = nil pd.AllCardsO = nil if pd.CardsO.IndexType > 0 { ppp := &thirteen.Poker{} ppp.IndexType = 0 pd.CardsO = ppp pd.IsDP = false } } } if s.SceneState.GetState() == rule.ThirteenWaterSceneStateShowCards || s.SceneState.GetState() == rule.ThirteenWaterSceneStateHit || s.SceneState.GetState() == rule.ThirteenWaterSceneStateBilled { pd.Score = playerEx.score[:] pd.TableScore = playerEx.tableScore[:] var hitScore []*thirteen.HitScore for k, v := range playerEx.winThreePos { pck := &thirteen.HitScore{ Pos: proto.Int32(int32(k)), Score: proto.Int64(v), } hitScore = append(hitScore, pck) } pd.Hit = hitScore } if s.SceneState.GetState() == rule.ThirteenWaterSceneStateBilled { pd.WinCoin = playerEx.gainCoin } pack.Players = append(pack.Players, pd) } proto.SetDefaults(pack) if p != nil { p.SyncFlag() } logger.Logger.Trace("SCThirteenWaterRoomInfo:", pack) return pack } func (this *SceneEx) GetBaseScore() int64 { //游戏底分 if this.GetDBGameFree().FreeMode == 1 { baseScore := this.GetParam(rule.ParamBaseScore) if baseScore > 0 { return baseScore } } if this.GetDBGameFree() != nil { return int64(this.GetDBGameFree().GetBaseScore()) } return 1 } func (this *SceneEx) GetBaiPai() time.Duration { if this.IsSceneMode(common.SceneModePublic) { second := rule.GetTimeout(this.GetDBGameFree().GetOtherIntParams(), rule.TimeoutOp) // 后台配置摆牌时间 if second > 0 { return second } } s := this.GetParam(rule.ParamBaiPai) // 自建房,摆牌时间 if s > 0 { return time.Duration(s) * time.Second } return rule.ThirteenWaterOptCardTimeout // 默认摆牌时间 } func (this *SceneEx) HasLaiZi() bool { s := this.GetParam(rule.ParamLaiZi) if s >= 0 { return s == 1 } return false } func (this *SceneEx) AutoCombine() bool { s := this.GetParam(rule.ParamAuto) if s >= 0 { return s == 0 } return true } // GetLeaveDeductCoin 离场扣分 func (this *SceneEx) GetLeaveDeductCoin() int64 { return int64(this.GetDBGameFree().GetLeaveDeduct()) * int64(this.GetBaseScore()) } func (this *SceneEx) GetScore(player *PlayerEx) { if player == nil || player.isDP { return } // 计算特殊牌型分数 ptRate := int64(0) //清龙* 一条龙* 十二皇族 三同花顺* 三分天下 全大 全小 凑一色* 四套三条 五对三条 六对半* 三顺子* 三同花 if player.cardsO.PokerType != 0 { this.specialTypeNum++ //特殊牌处理 if player.cardsO.PokerType >= 1 && player.cardsO.PokerType <= 13 { ptRate = rule.SpecialScore[player.cardsO.PokerType] } } if this.specialTypeNum > 0 { for _, p := range this.players { if p != nil && p.IsGameing() && player.cardsO.PokerType != 0 { if player.Pos == p.Pos { continue } if p.cardsO.PokerType == 0 || p.isDP { player.score[3] += ptRate p.score[3] -= ptRate player.winAllPlayers[p.Pos] += ptRate p.winAllPlayers[player.Pos] -= ptRate } else if p.cardsO.PokerType != 0 { //多个特殊牌型处理 if player.cardsO.PokerType < p.cardsO.PokerType { player.score[3] += ptRate p.score[3] -= ptRate player.winAllPlayers[p.Pos] += ptRate p.winAllPlayers[player.Pos] -= ptRate } } } } } // 计算普通牌型分数 for _, p := range this.players { if p != nil && p.IsGameing() && player.cardsO.PokerType == 0 { if player.Pos == p.Pos || p.cardsO.PokerType != 0 { continue } s := 0 score := int64(0) //赢的分数 //头墩 rate := int64(1) n := this.logic.CompareHead(player.cardsO.Head, p.cardsO.Head) h := this.logic.GetType(player.cardsO.Head[:]) if h == rule.PokersTypeThree { rate += 2 } if n == 1 || p.isDP { player.score[0] += rate p.score[0] -= rate score += rate s++ player.winAllPlayers[p.Pos] += rate p.winAllPlayers[player.Pos] -= rate player.tableScore[3] += rate - 1 p.tableScore[3] -= rate - 1 } //中墩 rate = int64(1) n = this.logic.CompareFive(player.cardsO.Mid, p.cardsO.Mid) m := this.logic.GetType(player.cardsO.Mid[:]) if m == rule.PokersTypeFullHouse { rate += 1 } else if m == rule.PokersTypeFour { rate += 6 } else if m == rule.PokersTypeStraightFlush { rate += 8 } else if m == rule.PokersTypeFive { rate += 10 } if n == 1 || p.isDP { player.score[1] += rate p.score[1] -= rate score += rate s++ player.winAllPlayers[p.Pos] += rate p.winAllPlayers[player.Pos] -= rate player.tableScore[4] += rate - 1 p.tableScore[4] -= rate - 1 } //尾墩 rate = int64(1) n = this.logic.CompareFive(player.cardsO.End, p.cardsO.End) e := this.logic.GetType(player.cardsO.End[:]) if e == rule.PokersTypeFour { rate += 3 } else if e == rule.PokersTypeStraightFlush { rate += 4 } else if e == rule.PokersTypeFive { rate += 5 } if n == 1 || p.isDP { player.score[2] += rate p.score[2] -= rate score += rate s++ player.winAllPlayers[p.Pos] += rate p.winAllPlayers[player.Pos] -= rate player.tableScore[5] += rate - 1 p.tableScore[5] -= rate - 1 } if s == 3 { player.winThreePos[p.Pos] = score } } } } func (this *SceneEx) SendToPlayerCardsBySnid(snid int32) { for _, player := range this.players { if player != nil && player.IsGameing() && (snid == 0 || player.SnId == snid) { all, k := AllGroupToProto(player.allGroup) pack := &thirteen.SCThirteenPlayerCards{ Cards: common.CopySliceIntToInt32(player.cards[:]), Pos: proto.Int32(int32(player.Pos)), AllCardsO: all, } // 记录默认牌型 if k > 0 { player.defGroup = player.allGroup[k] } if len(pack.AllCardsO) == 0 { logger.Logger.Warnf("no poker suggest: %v %v", player.cards, rule.PokersShow(player.cards[:])) // 没有推荐牌,随便给个数据 pack.AllCardsO = []*thirteen.Poker{ { IndexType: 90909, Head: common.CopySliceIntToInt32(player.cards[:3]), Mid: common.CopySliceIntToInt32(player.cards[3:8]), End: common.CopySliceIntToInt32(player.cards[8:]), }, } } proto.SetDefaults(pack) logger.Logger.Trace("SCThirteenWaterPlayerCards:", pack) player.SendToClient(int(thirteen.TWMmoPacketID_PACKET_SCThirteenPlayerCards), pack) Send := &thirteen.SCThirteenPlayerCards{ Pos: proto.Int32(int32(player.Pos)), } proto.SetDefaults(Send) logger.Logger.Trace("SCThirteenWaterPlayerCards:", Send) this.Broadcast(int(thirteen.TWMmoPacketID_PACKET_SCThirteenPlayerCards), Send, player.GetSid()) } } } func AllGroupToProto(allGroup map[int]*rule.Group) ([]*thirteen.Poker, int) { var pack []*thirteen.Poker for k, v := range allGroup { p := &thirteen.Poker{ Head: common.CopySliceIntToInt32(v.Head[:]), Mid: common.CopySliceIntToInt32(v.Mid[:]), End: common.CopySliceIntToInt32(v.End[:]), IndexType: proto.Int32(int32(k)), } pack = append(pack, p) } sort.Slice(pack, func(i, j int) bool { ii := pack[i] jj := pack[j] // 特殊牌在前面 if ii.IndexType >= 1000000 && jj.IndexType >= 1000000 { return ii.IndexType < jj.IndexType } if ii.IndexType >= 1000000 { return true } if jj.IndexType >= 1000000 { return false } // 普通牌型,从尾墩到头墩大的在前面 if ii.IndexType%100 < jj.IndexType%100 { return true } else if ii.IndexType%100 > jj.IndexType%100 { return false } if ii.IndexType%10000/100 < jj.IndexType%10000/100 { return true } else if ii.IndexType%10000/100 > jj.IndexType%10000/100 { return false } if ii.IndexType/10000 < jj.IndexType/10000 { return true } else if ii.IndexType/10000 > jj.IndexType/10000 { return false } return false }) //for _, v := range pack { // logger.Logger.Tracef("AllGroupToProto: %v %v %v %v", v.IndexType, rule.PokersShow(common.CopySliceInt32ToInt(v.Head)), rule.PokersShow(common.CopySliceInt32ToInt(v.Mid)), rule.PokersShow(common.CopySliceInt32ToInt(v.End))) //} if len(pack) > 0 { return pack, int(pack[0].IndexType) } return pack, 0 } // CheckIsCanHit 检查是否可以打枪 func (this *SceneEx) CheckIsCanHit() bool { pt := 0 //特殊牌型数量 isHit := 0 //几个人可以打枪 for _, v := range this.players { if v != nil && v.IsGameing() { if v.cardsO.PokerType != 0 { pt++ } //全垒打: 打枪所有人并且至少打3人 if len(v.winThreePos) >= 3 && len(v.winThreePos) == this.gamePlayerNum-1 { this.isCanAllHitPos = v.Pos } if len(v.winThreePos) > 0 { isHit++ } } } // 人数至少2人 if /*pt == 0 &&*/ this.gamePlayerNum >= 2 && isHit > 0 { return true } this.isCanAllHitPos = -1 return false } func (this *SceneEx) SelectCards(p *PlayerEx, indexType int) *rule.Group { switch indexType { case -1: // 使用特殊牌型 for k, v := range p.allGroup { if k >= 1000000 { p.cardsO = v break } } case -2: // 使用牌值最大的牌型 this.GetMaxCardsO(p) // 真人默认选牌规则 if !p.IsRob && p.defGroup != nil { p.cardsO = p.defGroup } } if indexType > 10000 { // 从推荐牌中选一个 c := p.allGroup[indexType] if c != nil { p.cardsO = c } } // 还没有确认就随机推荐一个 if p.cardsO == nil || p.cardsO.PokerType == -1 { for k, v := range p.allGroup { p.cardsO = v if k >= 1000000 { break } } logger.Logger.Tracef("随机推荐:SnId(%v) %v", p.SnId, p.cardsO) } return p.cardsO } // SendSelectCards 玩家选择特定的牌显示 func (this *SceneEx) SendSelectCards(player *PlayerEx, indexType int, opcode int64) { ShowCardsO := this.SelectCards(player, indexType) pack := &thirteen.SCThirteenPlayerOp{ OpRetCode: thirteen.OpResultCode_OPRC_Sucess, OpCode: int32(opcode), Pos: proto.Int32(int32(player.Pos)), Cards: &thirteen.Poker{}, } if indexType == -1 || indexType >= 1000000 { // 特殊牌 pack.Cards.Head = common.CopySliceIntToInt32(player.cards[:3]) pack.Cards.Mid = common.CopySliceIntToInt32(player.cards[3:8]) pack.Cards.End = common.CopySliceIntToInt32(player.cards[8:]) } else { // 自动组牌或玩家自选 pack.Cards.Head = common.CopySliceIntToInt32(ShowCardsO.Head[:]) pack.Cards.Mid = common.CopySliceIntToInt32(ShowCardsO.Mid[:]) pack.Cards.End = common.CopySliceIntToInt32(ShowCardsO.End[:]) pack.Cards.IsDP = this.logic.IsDP(ShowCardsO.Head, ShowCardsO.Mid, ShowCardsO.End) } pack.Cards.IndexType = proto.Int32(int32(this.FormatCards(ShowCardsO))) pack.Cards.Pos = int32(player.GetPos()) proto.SetDefaults(pack) logger.Logger.Trace("SCThirteenPlayerOp1:", pack) player.SendToClient(int(thirteen.TWMmoPacketID_PACKET_SCThirteenPlayerOp), pack) pack.Cards.Head = nil pack.Cards.Mid = nil pack.Cards.End = nil pack.Cards.IndexType = 0 pack.Cards.IsDP = false logger.Logger.Trace("SCThirteenPlayerOp2:", pack) this.Broadcast(int(thirteen.TWMmoPacketID_PACKET_SCThirteenPlayerOp), pack, player.GetSid()) for _, v := range this.seats { if v == nil { continue } if v.SnId != player.SnId && v.IsRobot() { logger.Logger.Trace("SCThirteenPlayerOpRobot:", pack) v.SendToClient(int(thirteen.TWMmoPacketID_PACKET_SCThirteenPlayerOp), pack) } } } func (this *SceneEx) FormatCards(cardsO *rule.Group) int { num := 0 if cardsO != nil && cardsO.PokerType != 0 { num = cardsO.PokerType * 1000000 } else if cardsO != nil && cardsO.PokerType == 0 && cardsO.Head[0] != -1 { num += this.logic.GetType(cardsO.Head[:]) * 10000 num += this.logic.GetType(cardsO.Mid[:]) * 100 num += this.logic.GetType(cardsO.End[:]) } return num } // GetMinCards 默认获取玩家最小牌值的类型 func (this *SceneEx) GetMinCards(player *PlayerEx) { min := 1000000 for v, m := range player.allGroup { sum := 0 if v >= 1000000 { continue } a := v / 10000 b := (v - a*10000) / 100 c := v - a*10000 - b*100 s := []int{a, b, c} for _, k := range s { if k >= 1 && k <= 20 { sum += 20 - k } } if min >= sum { min = sum player.cardsO = m } } } func (this *SceneEx) GetRandsType() (playerCards [13]int) { //r := rand.Intn(15) + 1 //全垒打 //playerCards = [13]int{9, 9 + 13, 9 + 13*2, 2, 3, 4, 5, 6, 3 + 13, 4 + 13, 5 + 13, 6 + 13, 7 + 13} //return c := [][13]int{ //清龙 {39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51}, //一条龙 {13, 14, 28, 29, 30, 44, 45, 7, 34, 9, 23, 11, 51}, //十二皇族 {9, 10, 23, 36, 49, 11, 24, 37, 50, 12, 25, 38, 51}, //三同花顺 {1, 2, 3, 4, 5, 15, 16, 17, 18, 19, 27, 28, 29}, //三分天下 {10, 23, 36, 49, 11, 24, 37, 50, 12, 25, 38, 51, 13}, //全大 {7, 21, 35, 23, 11, 38, 51, 33, 48, 49, 50, 12, 25}, //全小 {14, 27, 40, 15, 28, 41, 4, 17, 5, 18, 6, 19, 32}, //凑一色 {13, 14, 40, 16, 42, 18, 44, 19, 46, 47, 23, 49, 25}, //四套三条 {5, 18, 44, 6, 19, 32, 7, 33, 46, 10, 23, 36, 50}, //五对三条 {17, 30, 5, 31, 6, 32, 8, 47, 23, 36, 12, 25, 38}, //六对半 {17, 30, 5, 31, 6, 32, 8, 47, 23, 36, 38, 51, 39}, //三顺子 {1, 28, 16, 17, 18, 30, 31, 45, 20, 8, 36, 50, 12}, //三同花 {2, 3, 6, 4 + 13, 8 + 13, 9 + 13, 13, 25, 31, 34, 27, 28, 29}, } if this.r < 12 { this.r++ } else { this.r = 1 } playerCards = c[this.r] return } // SortCards 把所有牌排序 //func (this *SceneEx) SortCards() { // //确定所有玩家拿可以拿到的最大牌型 // for _, player := range this.players { // if player != nil && player.IsGameing() { // this.GetMaxCardsO(player) // } // } // //计算总分数 // this.CountScore() // scoreMap := make(map[int]int64) // for _, player := range this.seats { // if player != nil && player.IsGameing() { // score := int64(0) // //计算玩家输赢的分数 // for _, v := range player.score { // score += v // } // scoreMap[player.Pos] = score // } // } // for i := 0; i < 6; i++ { // max := int64(-1000) // pos := -1 // for k, v := range scoreMap { // if max <= v { // max = v // pos = k // } // } // if pos != -1 { // delete(scoreMap, pos) // this.cardsSlice = append(this.cardsSlice, this.seats[pos].cards) // this.seats[pos].cards = [13]int{-1} // if len(scoreMap) == 0 { // break // } // } // } //} // GetMaxCardsO 一副牌中拿最大牌值的方案 func (this *SceneEx) GetMaxCardsO(p *PlayerEx) { if p != nil { p.cardsO = rule.GetMaxCard(p.allGroup) } } // cardsSort 按从大到小的排列发牌 func (this *SceneEx) cardsSort(cardArr [][13]int, cardGroup []map[int]*rule.Group) { type P struct { i int score [6]int64 cardsO *rule.Group cards [13]int group map[int]*rule.Group winThreePos map[int]int64 winAllPlayers map[int]int64 } var ps []*P for i := 0; i < len(cardArr); i++ { p := &P{ i: i, score: [6]int64{0, 0, 0, 0, 0, 0}, cardsO: rule.GetMaxCard(cardGroup[i]), cards: cardArr[i], group: cardGroup[i], winThreePos: map[int]int64{}, winAllPlayers: map[int]int64{}, } ps = append(ps, p) } var specialTypeNum int for i := 0; i < len(cardArr); i++ { player := ps[i] // 计算特殊牌型分数 ptRate := int64(0) if player.cardsO.PokerType != 0 { specialTypeNum++ //特殊牌处理 if player.cardsO.PokerType >= 1 && player.cardsO.PokerType <= 13 { ptRate = rule.SpecialScore[player.cardsO.PokerType] } } if specialTypeNum > 0 { for _, p := range ps { if player.cardsO.PokerType != 0 { if player.i == p.i { continue } if p.cardsO.PokerType == 0 { player.score[3] += ptRate p.score[3] -= ptRate player.winAllPlayers[p.i] += ptRate p.winAllPlayers[player.i] -= ptRate } else if p.cardsO.PokerType != 0 { //多个特殊牌型处理 if player.cardsO.PokerType < p.cardsO.PokerType { player.score[3] += ptRate p.score[3] -= ptRate player.winAllPlayers[p.i] += ptRate p.winAllPlayers[player.i] -= ptRate } } } } } // 计算普通牌型分数 for _, p := range ps { if player.cardsO.PokerType == 0 { if player.i == p.i || p.cardsO.PokerType != 0 { continue } s := 0 score := int64(0) //赢的分数 //头墩 rate := int64(1) n := this.logic.CompareHead(player.cardsO.Head, p.cardsO.Head) h := this.logic.GetType(player.cardsO.Head[:]) if h == rule.PokersTypeThree { rate += 2 } if n == 1 { player.score[0] += rate p.score[0] -= rate score += rate player.winAllPlayers[p.i] += rate p.winAllPlayers[player.i] -= rate s++ } //中墩 rate = int64(1) n = this.logic.CompareFive(player.cardsO.Mid, p.cardsO.Mid) m := this.logic.GetType(player.cardsO.Mid[:]) if m == rule.PokersTypeFullHouse { rate += 1 } else if m == rule.PokersTypeFour { rate += 6 } else if m == rule.PokersTypeStraightFlush { rate += 8 } else if m == rule.PokersTypeFive { rate += 10 } if n == 1 { player.score[1] += rate p.score[1] -= rate score += rate player.winAllPlayers[p.i] += rate p.winAllPlayers[player.i] -= rate s++ } //尾墩 rate = int64(1) n = this.logic.CompareFive(player.cardsO.End, p.cardsO.End) e := this.logic.GetType(player.cardsO.End[:]) if e == rule.PokersTypeFour { rate += 3 } else if e == rule.PokersTypeStraightFlush { rate += 4 } else if e == rule.PokersTypeFive { rate += 5 } if n == 1 { player.score[2] += rate p.score[2] -= rate score += rate player.winAllPlayers[p.i] += rate p.winAllPlayers[player.i] -= rate s++ } if s == 3 { player.winThreePos[p.i] = score } } } } // 打枪分 isCanAllHitPos := -1 pt := 0 //特殊牌型数量 isHit := 0 //几个人可以打枪 for _, v := range ps { if v.cardsO.PokerType != 0 { pt++ } //全垒打: 打枪所有人并且至少打3人 if len(v.winThreePos) >= 3 && len(v.winThreePos) == this.gamePlayerNum-1 { isCanAllHitPos = v.i } if len(v.winThreePos) > 0 { isHit++ } } // 可以打枪:没有特殊牌型,人数至少2人 if pt == 0 && this.gamePlayerNum >= 2 && isHit > 0 { for _, playerEx := range ps { if len(playerEx.winThreePos) > 0 { for k, v := range playerEx.winThreePos { // 打枪 ps[k].score[4] -= v ps[k].winAllPlayers[playerEx.i] -= v playerEx.score[4] += v playerEx.winAllPlayers[k] += v // 全垒打分数 if playerEx.i == isCanAllHitPos { ps[k].score[5] -= v ps[k].winAllPlayers[playerEx.i] -= v playerEx.score[5] += v playerEx.winAllPlayers[k] += v } } } } } sort.Slice(ps, func(i, j int) bool { var a, b int64 for _, v := range ps[i].score { a += v } for _, v := range ps[j].score { b += v } return a > b }) for i := 0; i < len(cardArr); i++ { cardArr[i] = ps[i].cards cardGroup[i] = ps[i].group } } // CountScore 计算总分数 func (this *SceneEx) CountScore() { //计算头、中、尾道、特殊牌分数 for _, player := range this.seats { if player != nil && player.IsGameing() { this.GetScore(player) // 离场补偿分 if this.LeaveNum > 0 { player.score[6] = int64(this.LeaveNum) * int64(this.GetDBGameFree().GetLeaveCombat()) } } } for _, player := range this.seats { if player != nil && player.IsGameing() { for i := 0; i < 3; i++ { player.tableScore[i] = player.score[i] - player.tableScore[i+3] } } } this.entryHitState = this.CheckIsCanHit() if !this.entryHitState { //如果不能进入打枪阶段 不计算打枪和全垒打 return } //计算打枪分数 for _, playerEx := range this.players { if playerEx != nil && playerEx.IsGameing() { if len(playerEx.winThreePos) > 0 { for k, v := range playerEx.winThreePos { // 并且都不是特殊牌型 if playerEx.cardsO.PokerType != 0 || this.seats[k].cardsO.PokerType != 0 { continue } // 打枪 this.seats[k].score[4] -= v this.seats[k].winAllPlayers[playerEx.Pos] -= v playerEx.score[4] += v playerEx.winAllPlayers[k] += v // 全垒打分数 if playerEx.Pos == this.isCanAllHitPos { this.seats[k].score[5] -= v * 2 this.seats[k].winAllPlayers[playerEx.Pos] -= v * 2 playerEx.score[5] += v * 2 playerEx.winAllPlayers[k] += v * 2 } } } } } } func (this *SceneEx) GetInGameNum() { for _, v := range this.players { if v != nil && v.IsGameing() { this.gamePlayerNum++ if v.IsRob { this.robotNum++ } } } } // 获取最小牌 func (this *SceneEx) GetAllMinCards() (a [13]int) { for i := len(this.cardsSlice) - 1; i >= 0; i-- { a = this.cardsSlice[i] this.cardsSlice[i] = [13]int{-1} this.cardsSlice = append(this.cardsSlice[:i], this.cardsSlice[i+1:]...) break } return [13]int{-1} } // 获取最大牌 func (this *SceneEx) GetAllMaxCards() (a [13]int) { if this.nowMaxCardsIsIn { this.nowMaxCardsIsIn = false } for i := 0; i < len(this.cardsSlice); i++ { a = this.cardsSlice[i] this.cardsSlice = append(this.cardsSlice[:i], this.cardsSlice[i+1:]...) break } return [13]int{-1} } // 随机拿牌 func (this *SceneEx) GetRandCards(b bool) (a [13]int) { n := len(this.cardsSlice) if n == 0 { return [13]int{-1} } r := rand.Intn(n) if !b { if this.nowMaxCardsIsIn { //最大牌还在 //不带最大牌随机 if n == 1 { //就剩一副牌 return [13]int{-1} } if r == 0 { //随到最大牌 r++ } } } else { //带最大牌随机 if this.nowMaxCardsIsIn { if r == 0 { this.nowMaxCardsIsIn = false } } } a = this.cardsSlice[r] this.cardsSlice = append(this.cardsSlice[:r], this.cardsSlice[r+1:]...) return } func (this *SceneEx) ShowCards() { var allCards []*thirteen.Poker for _, p := range this.players { if p != nil && p.IsGameing() && p.cardsO != nil { var hitScore []*thirteen.HitScore for k, v := range p.winThreePos { pck := &thirteen.HitScore{ Pos: proto.Int32(int32(k)), Score: proto.Int64(v), } hitScore = append(hitScore, pck) } pk := &thirteen.Poker{ IndexType: proto.Int32(int32(this.FormatCards(p.cardsO))), Head: common.IntSliceToInt32(p.cardsO.Head[:]), Mid: common.IntSliceToInt32(p.cardsO.Mid[:]), End: common.IntSliceToInt32(p.cardsO.End[:]), IsDP: p.isDP, Pos: int32(p.GetPos()), Score: p.score[:], Hit: hitScore, TableScore: p.tableScore[:], Cards: common.IntSliceToInt32(p.cards[:]), } allCards = append(allCards, pk) } } opCode := 0 if this.GetSceneState().GetState() == rule.ThirteenWaterSceneStateHit { opCode = 1 // 打枪 } pc := &thirteen.SCThirteenShowCards{ OpCode: proto.Int32(int32(opCode)), AllCards: allCards, } proto.SetDefaults(pc) logger.Logger.Trace("SCThirteenWaterShowCards is pc: ", pc) this.Broadcast(int(thirteen.TWMmoPacketID_PACKET_SCThirteenShowCards), pc, 0) } func (this *SceneEx) CountBilled() { var totalWinScore, totalLoseScore int64 // 总赢分 for _, v := range this.players { if v != nil && v.IsGameing() { // 玩家总分 v.totalScore = 0 for _, vv := range v.score[:6] { v.totalScore += vv } v.totalScore *= int64(this.GetBaseScore()) if v.totalScore > 0 { if v.totalScore > v.Coin { v.totalScore = v.Coin } } else if v.totalScore < 0 { if v.totalScore < -v.Coin { v.totalScore = -v.Coin } } // 总输赢分 if v.totalScore > 0 { totalWinScore += v.totalScore } else if v.totalScore < 0 { totalLoseScore += -v.totalScore } logger.Logger.Tracef("玩家[%d]总赢分: %d", v.GetPos(), v.totalScore) } } if totalWinScore > totalLoseScore { // 赢分大,输分玩家分数不需要修改 for _, v := range this.players { if v != nil && v.IsGameing() { if v.totalScore > 0 { v.gainCoin = int64(float64(v.totalScore*totalLoseScore) / float64(totalWinScore)) } else if v.totalScore < 0 { v.gainCoin = v.totalScore } } } } else if totalWinScore < totalLoseScore { // 输分大,赢分玩家分数不需要修改 for _, v := range this.players { if v != nil && v.IsGameing() { if v.totalScore > 0 { v.gainCoin = v.totalScore } else if v.totalScore < 0 { v.gainCoin = int64(float64(v.totalScore*totalWinScore) / float64(totalLoseScore)) } } } } else { for _, v := range this.players { if v != nil && v.IsGameing() { v.gainCoin = v.totalScore } } } for _, playerEx := range this.players { if playerEx == nil || !playerEx.IsGameing() { continue } if playerEx.gainCoin > 0 { gainCoin := playerEx.gainCoin playerEx.gainCoin = playerEx.gainCoin * int64(10000-this.GetDBGameFree().GetTaxRate()) / 10000 playerEx.taxCoin = gainCoin - playerEx.gainCoin } logger.Logger.Tracef("玩家分数 %v, coin:%v tax:%v win:%v", playerEx.SnId, playerEx.gainCoin, playerEx.taxCoin, playerEx.winAllPlayers) } } func (this *SceneEx) BackupPlayer(p *PlayerEx, isBilled bool) { testLog := make([]string, len(p.TestLog)) copy(testLog, p.TestLog) skinId := int32(0) if p.Skin != nil { skinId = p.Skin.ModId } this.PlayerBackup[p.SnId] = &PlayerData{ SnId: p.SnId, cards: p.cards, cardsO: p.cardsO, isDP: p.isDP, gainCoin: p.gainCoin, taxCoin: p.taxCoin, deterMine: p.deterMine, score: p.score, tableScore: p.tableScore, winThreePos: p.winThreePos, winAllPlayers: p.winAllPlayers, isStand: p.isStand, isBilled: isBilled, IsRob: p.IsRob, Pos: p.Pos, Coin: p.Coin, StartCoin: p.StartCoin, Head: p.Head, flag: p.GetFlag(), Platform: p.Platform, Channel: p.Channel, PackageID: p.PackageID, PromoterTree: p.PromoterTree, InviterId: p.InviterId, WBLevel: p.WBLevel, CurIsWin: p.CurIsWin, BeUnderAgentCode: p.BeUnderAgentCode, Name: p.Name, Sex: p.Sex, City: p.City, Longitude: p.Longitude, Latitude: p.Latitude, AgentCode: p.AgentCode, HeadOutLine: p.HeadOutLine, VIP: p.VIP, allGroup: p.allGroup, TestLog: testLog, RoleId: p.PlayerData.GetRoleId(), PlayerPool: p.playerPool, SkinId: skinId, } } func (this *SceneEx) SendHandCardOdds() { var realPlayersGood, realPlayersBad, realPlayers, robotPlayers []*PlayerEx var G, B int32 for _, seat := range this.seats { if seat != nil && seat.IsGameing() { if seat.IsRob { robotPlayers = append(robotPlayers, seat) } else { seat.odds = this.GetPlayerOdds(seat.Player, int(this.GameId), this.robotNum > 0) seat.playerPool = int(this.PlayerPoolOdds(seat.Player)) if seat.odds > 0 { realPlayersGood = append(realPlayersGood, seat) G += seat.odds } else if seat.odds < 0 { realPlayersBad = append(realPlayersBad, seat) B -= seat.odds } else { realPlayers = append(realPlayers, seat) } } } } this.poker.Init() this.cardsArr = make([][13]int, this.poker.N*4) this.cardsGroup = make([]map[int]*rule.Group, this.poker.N*4) for k := range this.cardsArr { this.cardsArr[k] = this.poker.Get13Crads() this.cardsGroup[k] = this.logic.Suggest(this.cardsArr[k]) } f := func(players *[]*PlayerEx) { if players == nil || len(*players) == 0 { return } var p *PlayerEx // 发牌给这个玩家 var a int for _, v := range *players { a += int(math.Abs(float64(v.odds))) } n := this.RandInt(a) total := 0 for k, v := range *players { total += int(math.Abs(float64(v.odds))) if n < total { p = (*players)[k] *players = append((*players)[:k], (*players)[k+1:]...) break } } var cards [13]int var group map[int]*rule.Group if p.odds > 0 { // 拿好牌 cards = this.cardsArr[0] this.cardsArr = this.cardsArr[1:] group = this.cardsGroup[0] this.cardsGroup = this.cardsGroup[1:] } else { // 拿坏牌 cards = this.cardsArr[len(this.cardsArr)-1] this.cardsArr = this.cardsArr[:len(this.cardsArr)-1] group = this.cardsGroup[len(this.cardsGroup)-1] this.cardsGroup = this.cardsGroup[:len(this.cardsGroup)-1] } p.cards = cards p.allGroup = group } // 需要换牌 isGood := len(realPlayersGood) > 0 && int32(this.RandInt(1000)) < G isBad := len(realPlayersBad) > 0 && int32(this.RandInt(1000)) < B logger.Logger.Tracef("Thirteen SendHandCardOdds Good:%v G:%v Bad:%v B:%v", isGood, G, isBad, B) if isBad { this.ctrlType = 2 } if isGood && !isBad { this.ctrlType = 1 } if isGood || isBad { // 按从大到小排序 this.cardsSort(this.cardsArr, this.cardsGroup) // 发好牌 if isGood { l := len(realPlayersGood) for i := 0; i < l; i++ { f(&realPlayersGood) } } // 发坏牌 if isBad { l := len(realPlayersBad) for i := 0; i < l; i++ { f(&realPlayersBad) } } } // 随机拿牌 for _, v := range this.players { // map随机 if v == nil || !v.IsGameing() || v.cards[0] != -1 { continue } v.cards = this.cardsArr[0] v.allGroup = this.cardsGroup[0] this.cardsArr = this.cardsArr[1:] this.cardsGroup = this.cardsGroup[1:] } for _, player := range this.players { if player.IsGameing() && !player.IsRob { logger.Logger.Trace("snid:", player.SnId) player.TestLog = append(player.TestLog, fmt.Sprintf("随机换牌 Good:%v G:%v Bad:%v B:%v", isGood, G, isBad, B)) for _, v := range player.TestLog { logger.Logger.Trace(v) } pack := &thirteen.SCThirteenTest{} player.TestLog = append(player.TestLog, fmt.Sprintf("随机换牌 Good:%v G:%v Bad:%v B:%v", isGood, G, isBad, B)) pack.Data = strings.Join(player.TestLog, "\n") proto.SetDefaults(pack) player.SendToClient(int(thirteen.TWMmoPacketID_PACKET_SCThirteenTest), pack) logger.Logger.Trace("SnId: ", player.SnId, ";SCThirteenTest: ", pack) } } }