2025 lines
63 KiB
Go
2025 lines
63 KiB
Go
package tienlen
|
||
|
||
import (
|
||
"encoding/json"
|
||
"fmt"
|
||
"math"
|
||
"math/rand"
|
||
"sort"
|
||
"strings"
|
||
"time"
|
||
|
||
"mongo.games.com/goserver/core/logger"
|
||
|
||
tienlenApi "mongo.games.com/game/api3th/smart/tienlen"
|
||
"mongo.games.com/game/common"
|
||
rule "mongo.games.com/game/gamerule/tienlen"
|
||
"mongo.games.com/game/gamesrv/base"
|
||
"mongo.games.com/game/model"
|
||
"mongo.games.com/game/proto"
|
||
"mongo.games.com/game/protocol/tienlen"
|
||
"mongo.games.com/game/srvdata"
|
||
)
|
||
|
||
// 房间上的额外数据
|
||
type TienLenSceneData struct {
|
||
*base.Scene //场景
|
||
players map[int32]*TienLenPlayerData //玩家信息
|
||
seats [4]*TienLenPlayerData //玩家
|
||
poker *rule.Poker //扑克牌对象
|
||
curGamingPlayerNum int //当前在玩玩家数量
|
||
lastGamingPlayerNum int //上局参与游戏的人数
|
||
lastOpPos int32 //前一个出牌的玩家位置
|
||
currOpPos int32 //当前等待出牌的玩家位置
|
||
lastBombPos int32 //上一个出炸弹的玩家位置
|
||
curBombPos int32 //当前出炸弹的玩家位置
|
||
roundScore int32 //小轮分
|
||
startOpPos int32 //开始操作的玩家,拿最小牌的先出牌
|
||
curMinCard int32 //当局最小牌值
|
||
tianHuSnids []int32 //天胡玩家id
|
||
winSnids []int32 //赢家id
|
||
lastWinSnid int32 //上局赢家id
|
||
masterSnid int32 //房主
|
||
delCards [][]int32 //已出牌
|
||
delOrders []int32 //出牌顺序
|
||
isKongBomb bool //是否空放,打出炸弹没人能接
|
||
bombToEnd int //空放炸弹致底分翻倍次数
|
||
card_play_action_seq []string //出牌历史记录
|
||
card_play_action_seq_int32 [][]int32 //出牌历史记录
|
||
lastPos int32 //前一个玩家位置
|
||
isAllRob bool //是否是纯AI场
|
||
robotGamingNum int // 机器人玩家数量
|
||
allPlayerCards [][]int32 //所有玩家的牌
|
||
recordId string // 牌局记录id
|
||
testPokers []int32 // 发指定的牌,用于测试
|
||
cHintCards []int32 //客户端提示出牌记录
|
||
isCardsKu bool //是否是牌库
|
||
cardsKuId int32 //牌库ID
|
||
}
|
||
|
||
func NewTienLenSceneData(s *base.Scene) *TienLenSceneData {
|
||
sceneEx := &TienLenSceneData{
|
||
Scene: s,
|
||
poker: rule.NewPoker(),
|
||
players: make(map[int32]*TienLenPlayerData),
|
||
}
|
||
sceneEx.Clear()
|
||
return sceneEx
|
||
}
|
||
|
||
func (this *TienLenSceneData) init() bool {
|
||
this.tianHuSnids = []int32{}
|
||
this.winSnids = []int32{}
|
||
this.roundScore = 0
|
||
this.currOpPos = rule.InvalidePos
|
||
this.lastOpPos = rule.InvalidePos
|
||
this.curBombPos = rule.InvalidePos
|
||
this.lastBombPos = rule.InvalidePos
|
||
this.lastPos = rule.InvalidePos
|
||
this.UnmarkPass()
|
||
this.curGamingPlayerNum = 0
|
||
this.curMinCard = 0
|
||
this.delCards = [][]int32{}
|
||
this.delOrders = []int32{}
|
||
this.card_play_action_seq = []string{}
|
||
this.card_play_action_seq_int32 = [][]int32{}
|
||
this.bombToEnd = 0
|
||
this.allPlayerCards = [][]int32{}
|
||
this.recordId, _ = model.AutoIncGameLogId()
|
||
if this.GetPlayerNum() == 0 {
|
||
this.SetPlayerNum(rule.MaxNumOfPlayer)
|
||
}
|
||
|
||
this.cHintCards = []int32{}
|
||
return true
|
||
}
|
||
|
||
func (this *TienLenSceneData) Clear() {
|
||
this.tianHuSnids = []int32{}
|
||
this.winSnids = []int32{}
|
||
this.roundScore = 0
|
||
this.currOpPos = rule.InvalidePos
|
||
this.lastOpPos = rule.InvalidePos
|
||
this.curBombPos = rule.InvalidePos
|
||
this.lastBombPos = rule.InvalidePos
|
||
this.lastPos = rule.InvalidePos
|
||
this.curGamingPlayerNum = 0
|
||
this.curMinCard = 0
|
||
this.UnmarkPass()
|
||
this.delCards = [][]int32{}
|
||
this.delOrders = []int32{}
|
||
this.card_play_action_seq = []string{}
|
||
this.card_play_action_seq_int32 = [][]int32{}
|
||
this.bombToEnd = 0
|
||
this.isAllRob = false
|
||
this.robotGamingNum = 0
|
||
this.allPlayerCards = [][]int32{}
|
||
this.recordId, _ = model.AutoIncGameLogId()
|
||
for _, player := range this.players {
|
||
if player != nil {
|
||
player.UnmarkFlag(base.PlayerState_WaitNext)
|
||
}
|
||
}
|
||
this.cHintCards = []int32{}
|
||
}
|
||
|
||
func (this *TienLenSceneData) CanStart() bool {
|
||
if this.GetGaming() == true {
|
||
return false
|
||
}
|
||
|
||
nPlayerCount := this.GetPlayerCnt()
|
||
nRobotCount := this.GetRobotCnt()
|
||
if this.IsMatchScene() {
|
||
if nRobotCount == 4 {
|
||
this.isAllRob = true
|
||
}
|
||
if nPlayerCount == 4 { // 比赛场4人开赛
|
||
return true
|
||
} else {
|
||
return false
|
||
}
|
||
}
|
||
// 房间人数>=2开始,并且有真人或者是预创建房间,并且有房主
|
||
if nPlayerCount >= 2 && (this.GetRealPlayerNum() > 0 || this.IsPreCreateScene()) { //人数>=2开始
|
||
return true
|
||
}
|
||
return false
|
||
}
|
||
|
||
func (this *TienLenSceneData) GetPlayerCnt() int {
|
||
var cnt int
|
||
for i := 0; i < this.GetPlayerNum(); i++ {
|
||
playerEx := this.seats[i]
|
||
if playerEx == nil {
|
||
continue
|
||
}
|
||
cnt++
|
||
}
|
||
return cnt
|
||
}
|
||
func (this *TienLenSceneData) GetGameingPlayerCnt() int {
|
||
var cnt int
|
||
for i := 0; i < this.GetPlayerNum(); i++ {
|
||
playerEx := this.seats[i]
|
||
if playerEx == nil {
|
||
continue
|
||
}
|
||
if playerEx.IsGameing() {
|
||
cnt++
|
||
}
|
||
}
|
||
return cnt
|
||
}
|
||
|
||
func (this *TienLenSceneData) GetRobotCnt() int {
|
||
var cnt int
|
||
for i := 0; i < this.GetPlayerNum(); i++ {
|
||
playerEx := this.seats[i]
|
||
if playerEx == nil {
|
||
continue
|
||
}
|
||
if playerEx.IsRob {
|
||
cnt++
|
||
}
|
||
}
|
||
return cnt
|
||
}
|
||
|
||
func (this *TienLenSceneData) GetGameingRobotCnt() int {
|
||
var cnt int
|
||
for i := 0; i < this.GetPlayerNum(); i++ {
|
||
playerEx := this.seats[i]
|
||
if playerEx == nil {
|
||
continue
|
||
}
|
||
if playerEx.IsRob && playerEx.IsGameing() {
|
||
cnt++
|
||
}
|
||
}
|
||
return cnt
|
||
}
|
||
|
||
func (this *TienLenSceneData) GetSeatPlayerCnt() int {
|
||
var cnt int
|
||
for i := 0; i < this.GetPlayerNum(); i++ {
|
||
playerEx := this.seats[i]
|
||
if playerEx == nil {
|
||
continue
|
||
}
|
||
cnt++
|
||
}
|
||
return cnt
|
||
}
|
||
|
||
func (this *TienLenSceneData) BroadcastPlayerLeave(p *base.Player, reason int) {
|
||
scLeavePack := &tienlen.SCTienLenPlayerLeave{
|
||
Pos: proto.Int(p.GetPos()),
|
||
}
|
||
proto.SetDefaults(scLeavePack)
|
||
logger.Logger.Trace("SCTienLenPlayerLeave: ", p.SnId, " scLeavePack: ", scLeavePack)
|
||
this.Broadcast(int(tienlen.TienLenPacketID_PACKET_SCTienLenPlayerLeave), scLeavePack, p.GetSid())
|
||
}
|
||
|
||
func (this *TienLenSceneData) BroadcastAudienceNum(p *base.Player) {
|
||
pack := &tienlen.SCTienLenUpdateAudienceNum{
|
||
AudienceNum: proto.Int(this.GetAudiencesNum()),
|
||
}
|
||
proto.SetDefaults(pack)
|
||
this.Broadcast(int(tienlen.TienLenPacketID_PACKET_SCTienLenUpdateAudienceNum), pack, p.GetSid())
|
||
}
|
||
|
||
func (this *TienLenSceneData) delPlayer(p *base.Player) {
|
||
if p, exist := this.players[p.SnId]; exist {
|
||
this.seats[p.GetPos()] = nil
|
||
delete(this.players, p.SnId)
|
||
}
|
||
}
|
||
func (this *TienLenSceneData) OnPlayerLeave(p *base.Player, reason int) {
|
||
// 清除上局赢家id
|
||
if this.lastWinSnid == p.SnId {
|
||
this.lastWinSnid = 0
|
||
}
|
||
|
||
this.delPlayer(p)
|
||
this.BroadcastPlayerLeave(p, reason)
|
||
|
||
if !p.IsRob { //真人离开
|
||
hadSeat := false
|
||
for _, seat := range this.seats {
|
||
if seat != nil {
|
||
hadSeat = true
|
||
break
|
||
}
|
||
}
|
||
if !hadSeat { //座位上没有人了,把观众踢出去
|
||
audiences := this.GetAudiences()
|
||
for _, audience := range audiences {
|
||
if audience != nil {
|
||
this.AudienceLeave(audience, common.PlayerLeaveReason_RoomClose)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
func (this *TienLenSceneData) SceneDestroy(force bool) {
|
||
//销毁房间
|
||
this.Scene.Destroy(force)
|
||
}
|
||
|
||
// 广播房主更换
|
||
func (this *TienLenSceneData) BroadcastUpdateMasterSnid() {
|
||
pack := &tienlen.SCTienLenUpdateMasterSnid{
|
||
MasterSnid: proto.Int32(this.masterSnid),
|
||
}
|
||
proto.SetDefaults(pack)
|
||
this.Broadcast(int(tienlen.TienLenPacketID_PACKET_SCTienLenUpdateMasterSnid), pack, 0)
|
||
logger.Logger.Trace("BroadcastUpdateMasterSnid ", pack)
|
||
}
|
||
|
||
// 广播当前操作的玩家位置
|
||
func (this *TienLenSceneData) BroadcastOpPos() {
|
||
|
||
if this.currOpPos != rule.InvalidePos && this.seats[this.currOpPos] != nil && this.seats[this.currOpPos].IsRobot() {
|
||
//计算其它人手牌,所有牌-出过的牌-自己手牌
|
||
othercards := []int32{}
|
||
handcards := []int32{}
|
||
/* for i := int32(0); i < 52; i++ {
|
||
othercards = append(othercards, i)
|
||
}*/
|
||
for _, cards := range this.allPlayerCards {
|
||
for _, card := range cards {
|
||
if card != -1 {
|
||
othercards = append(othercards, tienlenApi.CardToAiCard[card])
|
||
}
|
||
}
|
||
}
|
||
logger.Logger.Info("--------------------------------------othercards = ", othercards)
|
||
card_play_action_seqs := []string{}
|
||
for _, cards := range this.card_play_action_seq_int32 {
|
||
//转棋牌到AI中的牌
|
||
aicards := []int32{}
|
||
for _, card := range cards {
|
||
aicards = append(aicards, tienlenApi.CardToAiCard[card])
|
||
}
|
||
|
||
card_play_action_seqs = append(card_play_action_seqs, common.Int32SliceToString(aicards, ","))
|
||
othercards = common.DelSliceIn32s(othercards, aicards)
|
||
}
|
||
//删除手牌
|
||
for _, v := range this.seats[this.currOpPos].cards {
|
||
if v != -1 {
|
||
aicard := tienlenApi.CardToAiCard[v]
|
||
othercards = common.DelSliceInt32(othercards, aicard)
|
||
handcards = append(handcards, aicard)
|
||
}
|
||
}
|
||
//logger.Logger.Infof("%v出牌历史记录:%v",this.currOpPos,this.card_play_action_seq)
|
||
//logger.Logger.Infof("%v出牌历史记录:%v",this.currOpPos,common.StringSliceToString(card_play_action_seqs,"|"))
|
||
//logger.Logger.Infof("%v手牌:%v 数量:%v",this.currOpPos,handcards,len(handcards))
|
||
//logger.Logger.Infof("%v其它人牌:%v 数量:%v",this.currOpPos,othercards,len(othercards))
|
||
|
||
lastmove := make(map[int][]int32)
|
||
numCardsLeft := make(map[int]int)
|
||
playedCards := make(map[int][]int32)
|
||
for pos, v := range this.seats {
|
||
if v != nil && v.IsGameing() {
|
||
//出过的牌
|
||
delcards := []int32{}
|
||
for _, cards := range v.delCards {
|
||
for _, card := range cards {
|
||
aicard := tienlenApi.CardToAiCard[card]
|
||
delcards = append(delcards, aicard)
|
||
}
|
||
}
|
||
//logger.Logger.Infof("%v出过的牌:%v",pos,delcards)
|
||
//logger.Logger.Infof("%v剩余的牌:%v",pos,13-len(delcards))
|
||
playedCards[pos] = delcards
|
||
numCardsLeft[pos] = 13 - len(delcards)
|
||
last := len(v.delCards)
|
||
if last > 0 {
|
||
aicards := []int32{}
|
||
for _, card := range v.delCards[last-1] {
|
||
aicards = append(aicards, tienlenApi.CardToAiCard[card])
|
||
}
|
||
//logger.Logger.Infof("%v最后一次出牌:%v",pos,aicards)
|
||
lastmove[pos] = aicards
|
||
} else {
|
||
//logger.Logger.Infof("%v最后一次出牌:%v",pos,"")
|
||
lastmove[pos] = []int32{}
|
||
}
|
||
|
||
} else {
|
||
numCardsLeft[pos] = 0
|
||
}
|
||
}
|
||
isFirstHand := false
|
||
if this.lastOpPos == rule.InvalidePos { //首出玩家
|
||
//有赢家,赢家先出,出牌不受限制
|
||
//无赢家,手持最小牌先出,最小牌必先出
|
||
winPos := this.FindWinPos()
|
||
if winPos == -1 { //无赢家
|
||
isFirstHand = true
|
||
}
|
||
}
|
||
isWin := true
|
||
B := int32(0)
|
||
for _, seat := range this.seats {
|
||
if seat != nil && seat.IsGameing() {
|
||
if !seat.IsRob {
|
||
seat.odds = this.GetPlayerOdds(seat.Player, this.GameId, this.robotGamingNum > 0)
|
||
if seat.odds < 0 {
|
||
B -= seat.odds
|
||
}
|
||
}
|
||
}
|
||
}
|
||
if B < 0 {
|
||
isWin = false
|
||
}
|
||
isTienLenYule := this.IsTienLenYule()
|
||
pack := &tienlen.SCTienLenAIData{
|
||
BombNum: 0, //炸弹数量
|
||
CardPlayActionSeq: proto.String(strings.Replace(common.StringSliceToString(card_play_action_seqs, "|"), "-1", "", -1)),
|
||
LastMove_0: proto.String(common.Int32SliceToString(lastmove[0], ",")),
|
||
LastMove_1: proto.String(common.Int32SliceToString(lastmove[1], ",")),
|
||
LastMove_2: proto.String(common.Int32SliceToString(lastmove[2], ",")),
|
||
LastMove_3: proto.String(common.Int32SliceToString(lastmove[3], ",")),
|
||
NumCardsLeft_0: proto.Int32(int32(numCardsLeft[0])),
|
||
NumCardsLeft_1: proto.Int32(int32(numCardsLeft[1])),
|
||
NumCardsLeft_2: proto.Int32(int32(numCardsLeft[2])),
|
||
NumCardsLeft_3: proto.Int32(int32(numCardsLeft[3])),
|
||
OtherHandCards: proto.String(common.Int32SliceToString(othercards, ",")),
|
||
PlayedCards_0: proto.String(common.Int32SliceToString(playedCards[0], ",")),
|
||
PlayedCards_1: proto.String(common.Int32SliceToString(playedCards[1], ",")),
|
||
PlayedCards_2: proto.String(common.Int32SliceToString(playedCards[2], ",")),
|
||
PlayedCards_3: proto.String(common.Int32SliceToString(playedCards[3], ",")),
|
||
PlayerHandCards: proto.String(common.Int32SliceToString(handcards, ",")),
|
||
PlayerPosition: proto.Int32(this.currOpPos),
|
||
IsTienLenYule: proto.Bool(isTienLenYule),
|
||
IsFirstHand: proto.Bool(isFirstHand),
|
||
CardsLeft_0: this.GetPlayerCards(0),
|
||
CardsLeft_1: this.GetPlayerCards(1),
|
||
CardsLeft_2: this.GetPlayerCards(2),
|
||
CardsLeft_3: this.GetPlayerCards(3),
|
||
LastPos: proto.Int32(this.lastOpPos),
|
||
IsEnd: this.IsTienLenToEnd(),
|
||
WinSnids: this.winSnids,
|
||
IsWin: isWin,
|
||
}
|
||
proto.SetDefaults(pack)
|
||
this.seats[this.currOpPos].SendToClient(int(tienlen.TienLenPacketID_PACKET_SCTienLenAI), pack)
|
||
logger.Logger.Infof("--------------------Send Robot AI Data:%v", pack)
|
||
}
|
||
|
||
pack := &tienlen.SCTienLenCurOpPos{
|
||
Pos: proto.Int32(this.currOpPos),
|
||
IsNew: proto.Bool(this.currOpPos == this.lastOpPos || this.lastOpPos == rule.InvalidePos),
|
||
}
|
||
|
||
lastOpPlayer := this.GetLastOpPlayer()
|
||
if lastOpPlayer != nil && this.currOpPos != this.lastOpPos {
|
||
if len(lastOpPlayer.delCards) > 0 {
|
||
lastDelCards := lastOpPlayer.delCards[len(lastOpPlayer.delCards)-1]
|
||
for _, card := range lastDelCards {
|
||
if card != rule.InvalideCard {
|
||
pack.Cards = append(pack.Cards, card)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if this.lastPos != rule.InvalidePos && this.lastOpPos == this.lastPos {
|
||
// 特殊牌型才去添加额外延迟时间
|
||
if rule.NeedExDelay(pack.Cards) {
|
||
pack.ExDelay = proto.Int32(int32(rule.DelayCanOp))
|
||
}
|
||
}
|
||
|
||
proto.SetDefaults(pack)
|
||
this.Broadcast(int(tienlen.TienLenPacketID_PACKET_SCTienLenCurOpPos), pack, 0)
|
||
logger.Logger.Trace("(this *TienLenSceneData) BroadcastOpPos TienLenPacketID_PACKET_SCTienLenCurOpPos", this.GetSceneId(), ";pack:", pack)
|
||
}
|
||
|
||
// 获取玩家剩余的牌
|
||
func (this *TienLenSceneData) GetPlayerCards(pos int32) []int32 {
|
||
data := []int32{}
|
||
if len(this.allPlayerCards)-1 < int(pos) {
|
||
return data
|
||
}
|
||
|
||
cards := this.allPlayerCards[pos]
|
||
//去除值为-1的牌
|
||
for _, card := range cards {
|
||
if card != -1 {
|
||
data = append(data, card)
|
||
}
|
||
}
|
||
|
||
return data
|
||
}
|
||
|
||
// 出牌
|
||
func (this *TienLenSceneData) DelCards(playerEx *TienLenPlayerData, cards []int32) bool {
|
||
if playerEx != nil && len(cards) != 0 {
|
||
cs := make([]int32, len(cards))
|
||
copy(cs, cards)
|
||
for _, delCard := range cs {
|
||
for i, hcard := range playerEx.cards {
|
||
if delCard == hcard && hcard != rule.InvalideCard {
|
||
playerEx.cards[i] = rule.InvalideCard
|
||
continue
|
||
}
|
||
}
|
||
}
|
||
rule.MinSortCards(cs)
|
||
playerEx.delCards = append(playerEx.delCards, cs)
|
||
this.delCards = append(this.delCards, cs)
|
||
this.delOrders = append(this.delOrders, playerEx.SnId)
|
||
this.card_play_action_seq = append(this.card_play_action_seq, fmt.Sprintf("%v-%v", playerEx.GetPos(), common.Int32SliceToString(cs, ",")))
|
||
this.card_play_action_seq_int32 = append(this.card_play_action_seq_int32, cs)
|
||
return true
|
||
}
|
||
return false
|
||
}
|
||
|
||
func (this *TienLenSceneData) PlayerCanOp(pos int32) bool {
|
||
if pos < 0 || pos >= int32(this.GetPlayerNum()) {
|
||
return false
|
||
}
|
||
if this.seats[pos] != nil && this.seats[pos].CanOp() {
|
||
return true
|
||
}
|
||
this.card_play_action_seq = append(this.card_play_action_seq, fmt.Sprintf("%v-过", pos))
|
||
this.card_play_action_seq_int32 = append(this.card_play_action_seq_int32, []int32{-1})
|
||
return false
|
||
}
|
||
|
||
func (this *TienLenSceneData) AllPlayerEnterGame() {
|
||
|
||
for i := 0; i < this.GetPlayerNum(); i++ {
|
||
if this.seats[i] == nil {
|
||
continue
|
||
}
|
||
|
||
if this.seats[i].IsMarkFlag(base.PlayerState_GameBreak) == false {
|
||
this.seats[i].UnmarkFlag(base.PlayerState_WaitNext)
|
||
this.seats[i].SyncFlag()
|
||
}
|
||
}
|
||
}
|
||
|
||
// 娱乐版
|
||
func (this *TienLenSceneData) IsTienLenYule() bool {
|
||
return common.IsTienLenYuLe(this.GetGameId())
|
||
}
|
||
|
||
// 打到底
|
||
func (this *TienLenSceneData) IsTienLenToEnd() bool {
|
||
return common.IsTienLenToEnd(this.GetGameId())
|
||
}
|
||
func (this *TienLenSceneData) GetFreeGameSceneType() int32 {
|
||
return int32(this.SceneType)
|
||
}
|
||
|
||
// 比赛场发牌
|
||
// 纯真人,随机发牌
|
||
// 有机器人和真人,真人拿好牌
|
||
func (this *TienLenSceneData) SendHandCard_Match() {
|
||
this.poker.Shuffle()
|
||
buf := this.poker.GetPokerBuf()
|
||
cardss := map[int][]int32{}
|
||
for i, card := range buf {
|
||
if int32(card) != rule.InvalideCard {
|
||
index := i / 13
|
||
cardss[index] = append(cardss[index], int32(card))
|
||
}
|
||
}
|
||
|
||
realPlayers := []*TienLenPlayerData{}
|
||
robotPlayers := []*TienLenPlayerData{}
|
||
for _, seat := range this.seats {
|
||
if seat != nil && seat.IsGameing() {
|
||
if seat.IsRob {
|
||
robotPlayers = append(robotPlayers, seat)
|
||
} else {
|
||
realPlayers = append(realPlayers, seat)
|
||
}
|
||
}
|
||
}
|
||
if len(realPlayers) > 0 && len(robotPlayers) > 0 {
|
||
type gradeInfo struct {
|
||
id int
|
||
grade int
|
||
cards []int32
|
||
}
|
||
grades := []gradeInfo{}
|
||
for i, card13 := range cardss {
|
||
cardTmp := make([]int32, 13)
|
||
copy(cardTmp, card13)
|
||
grade := rule.GetCardsGrade(cardTmp, this.IsTienLenYule())
|
||
gi := gradeInfo{
|
||
id: i,
|
||
grade: grade,
|
||
cards: card13,
|
||
}
|
||
grades = append(grades, gi)
|
||
}
|
||
realWin := 1 //-1最差 0正常 1最好
|
||
switch realWin {
|
||
case -1:
|
||
sort.Slice(grades, func(i, j int) bool {
|
||
return grades[i].grade > grades[j].grade
|
||
})
|
||
case 0:
|
||
case 1:
|
||
sort.Slice(grades, func(i, j int) bool {
|
||
return grades[i].grade < grades[j].grade
|
||
})
|
||
}
|
||
|
||
for i, gi := range grades {
|
||
cardss[i] = gi.cards
|
||
}
|
||
}
|
||
|
||
minCard := int32(999)
|
||
if len(robotPlayers) > 0 {
|
||
for i, seat := range robotPlayers {
|
||
for index, card := range cardss[i] {
|
||
seat.cards[index] = card
|
||
if rule.Value(card) < rule.Value(minCard) {
|
||
this.startOpPos = int32(seat.GetPos())
|
||
minCard = card
|
||
this.curMinCard = minCard
|
||
} else if rule.Value(card) == rule.Value(minCard) {
|
||
if rule.Color(card) < rule.Color(minCard) {
|
||
this.startOpPos = int32(seat.GetPos())
|
||
minCard = card
|
||
this.curMinCard = minCard
|
||
}
|
||
}
|
||
}
|
||
|
||
cardTmp := make([]int32, 13)
|
||
copy(cardTmp, cardss[i])
|
||
grade := rule.GetCardsGrade(cardTmp, this.IsTienLenYule())
|
||
logger.Logger.Trace("SnId: ", seat.SnId, ";grade: ", grade)
|
||
|
||
pack := &tienlen.SCTienLenCard{}
|
||
for j := int32(0); j < rule.HandCardNum; j++ {
|
||
pack.Cards = append(pack.Cards, seat.cards[j])
|
||
}
|
||
pack.IsOutRecord = seat.CanUseRecordItem()
|
||
|
||
proto.SetDefaults(pack)
|
||
seat.SendToClient(int(tienlen.TienLenPacketID_PACKET_SCTienLenCard), pack)
|
||
logger.Logger.Trace("SnId: ", seat.SnId, ";SCTienLenCard: ", pack.Cards)
|
||
}
|
||
}
|
||
|
||
if len(realPlayers) > 0 {
|
||
for i, seat := range realPlayers {
|
||
for index, card := range cardss[len(robotPlayers)+i] {
|
||
seat.cards[index] = card
|
||
if rule.Value(card) < rule.Value(minCard) {
|
||
this.startOpPos = int32(seat.GetPos())
|
||
minCard = card
|
||
this.curMinCard = minCard
|
||
} else if rule.Value(card) == rule.Value(minCard) {
|
||
if rule.Color(card) < rule.Color(minCard) {
|
||
this.startOpPos = int32(seat.GetPos())
|
||
minCard = card
|
||
this.curMinCard = minCard
|
||
}
|
||
}
|
||
}
|
||
|
||
cardTmp := make([]int32, 13)
|
||
copy(cardTmp, cardss[len(robotPlayers)+i])
|
||
grade := rule.GetCardsGrade(cardTmp, this.IsTienLenYule())
|
||
logger.Logger.Trace("SnId: ", seat.SnId, ";grade: ", grade)
|
||
|
||
pack := &tienlen.SCTienLenCard{}
|
||
for j := int32(0); j < rule.HandCardNum; j++ {
|
||
pack.Cards = append(pack.Cards, seat.cards[j])
|
||
}
|
||
pack.IsOutRecord = seat.CanUseRecordItem()
|
||
proto.SetDefaults(pack)
|
||
seat.SendToClient(int(tienlen.TienLenPacketID_PACKET_SCTienLenCard), pack)
|
||
logger.Logger.Trace("SnId: ", seat.SnId, ";SCTienLenCard: ", pack.Cards)
|
||
}
|
||
}
|
||
}
|
||
|
||
// Shuffle 发牌
|
||
// offGrade 需要牌分最少差值(非打到底牌分最大的一组牌和最小的一组牌的分差;打到底,分数最少的两组牌的分差)
|
||
// num 函数内部使用,限制搜索次数
|
||
// maxOff 函数内部使用
|
||
func (this *TienLenSceneData) Shuffle(offGrade, num, maxOff int) {
|
||
this.poker.Shuffle()
|
||
buf := this.poker.GetPokerBuf()
|
||
cardss := map[int][]int32{}
|
||
for i, card := range buf {
|
||
if int32(card) != rule.InvalideCard {
|
||
index := i / 13
|
||
cardss[index] = append(cardss[index], int32(card))
|
||
}
|
||
}
|
||
type gradeInfo struct {
|
||
id int
|
||
grade int
|
||
cards []int32
|
||
}
|
||
grades := []gradeInfo{}
|
||
for i, card13 := range cardss {
|
||
cardTmp := make([]int32, 13)
|
||
copy(cardTmp, card13)
|
||
cardsTypeMap := rule.GetCardsType(cardTmp, this.IsTienLenYule())
|
||
grade, _ := rule.GetCardTypeScore(cardsTypeMap, this.IsTienLenYule(), cardTmp)
|
||
gi := gradeInfo{
|
||
id: i,
|
||
grade: grade,
|
||
cards: card13,
|
||
}
|
||
grades = append(grades, gi)
|
||
}
|
||
sort.Slice(grades, func(i, j int) bool {
|
||
return grades[i].grade < grades[j].grade
|
||
})
|
||
if grades[len(grades)-1].grade == 9999 && !this.poker.IsTianhuPoker() { //天胡
|
||
this.poker.TianhuPokerBuf()
|
||
}
|
||
if this.IsTienLenToEnd() {
|
||
//所有值都比最小值大offGrade分
|
||
off := grades[1].grade - grades[0].grade
|
||
if off > maxOff {
|
||
maxOff = off
|
||
this.poker.CopyPokerBuf()
|
||
}
|
||
if offGrade == 0 || off >= offGrade || num > 10000 {
|
||
if num > 10000 {
|
||
if this.poker.IsTianhuPoker() && rand.Intn(100) < 20 {
|
||
this.poker.UnTianhuPokerBuf()
|
||
} else {
|
||
this.poker.UncopyPokerBuf()
|
||
}
|
||
}
|
||
return
|
||
}
|
||
} else {
|
||
//最大值比最小值大offGrade分
|
||
off := grades[len(grades)-1].grade - grades[0].grade
|
||
if off > maxOff && grades[len(grades)-1].grade != 9999 {
|
||
maxOff = off
|
||
this.poker.CopyPokerBuf()
|
||
}
|
||
if offGrade == 0 || off >= offGrade || num > 10000 {
|
||
if num > 10000 {
|
||
if this.poker.IsTianhuPoker() && rand.Intn(100) < 20 {
|
||
this.poker.UnTianhuPokerBuf()
|
||
} else {
|
||
this.poker.UncopyPokerBuf()
|
||
}
|
||
}
|
||
return
|
||
}
|
||
}
|
||
num++
|
||
this.Shuffle(offGrade, num, maxOff)
|
||
}
|
||
|
||
/*
|
||
公共房:赔率发牌
|
||
私人房:随机发牌
|
||
比赛场:
|
||
纯真人,随机发牌
|
||
有机器人和真人,真人拿好牌
|
||
纯机器人,随机发牌
|
||
|
||
赔率发牌
|
||
1.52张牌随机分成4组(评估牌好坏)
|
||
2.找出个人赔率最低的玩家
|
||
3.只有一个真实玩家
|
||
1.该玩家个人赔率≤80%,30%概率给予玩家最好牌,70%概率随机发牌
|
||
2.该玩家 80%<个人赔率≤95%,随机发牌
|
||
3.该玩家 95%<个人赔率≤98%,50%概率给予玩家最小牌,50%概率随机发牌
|
||
4.该玩家 个人赔率>98%,给予玩家最小牌,切保证最大牌型和最小牌型之间的分差≥5(代码里对应50)
|
||
4.多个真实玩家
|
||
1.纯真人
|
||
50%概率给予最大牌,50%概率随机发牌
|
||
2.有机器人
|
||
1.该玩家个人赔率≤90%,50%概率给予玩家最好牌,50%概率随机发牌
|
||
2.该玩家 90%<个人赔率>98%,随机发牌
|
||
3.该玩家 个人赔率>98%,给予机器人最大牌
|
||
5.根据赔率最低玩家发牌,如果被控人拿最小牌,机器人拿最大牌,其余玩家随机发牌
|
||
*/
|
||
|
||
// SendHandCard_LoseRate 按照赔率发牌
|
||
//func (this *TienLenSceneData) SendHandCard_LoseRate() {
|
||
// var minLoseRateSnid int32 //snid
|
||
// var realPlayerType int //-1最小牌 0正常随机 1最大牌
|
||
// var offGrade int //需求分值差
|
||
//
|
||
// realPlayers := []*TienLenPlayerData{}
|
||
// robotPlayers := []*TienLenPlayerData{}
|
||
// for _, seat := range this.seats {
|
||
// if seat != nil && seat.IsGameing() {
|
||
// if seat.IsRob {
|
||
// robotPlayers = append(robotPlayers, seat)
|
||
// } else {
|
||
// realPlayers = append(realPlayers, seat)
|
||
// }
|
||
// }
|
||
// }
|
||
// if len(realPlayers) > 0 {
|
||
// //找出个人赔率最低的玩家
|
||
// minLoseRate := realPlayers[0].LoseRate(this.GetGameFreeId(), int32(this.GetGameId()))
|
||
// minLoseRateSnid = realPlayers[0].SnId
|
||
// for _, player := range realPlayers {
|
||
// loseRate := player.LoseRate(this.GetGameFreeId(), int32(this.GetGameId()))
|
||
// logger.Logger.Trace("snid: ", player.SnId, " loseRate: ", loseRate)
|
||
// if loseRate < minLoseRate {
|
||
// minLoseRate = loseRate
|
||
// minLoseRateSnid = player.SnId
|
||
// }
|
||
// }
|
||
// if !this.IsMatchScene() && !this.IsPrivateScene() { //比赛场或者私有房间纯随机
|
||
// //一个真实玩家
|
||
// if len(realPlayers) == 1 {
|
||
// //1.该玩家个人赔率≤80%,30%概率给予玩家最好牌,70%概率随机发牌
|
||
// if minLoseRate <= 0.8 {
|
||
// if rand.Int31n(100) < 30 {
|
||
// realPlayerType = 1
|
||
// } else {
|
||
// realPlayerType = 0
|
||
// }
|
||
// } else if minLoseRate <= 0.95 { //2.该玩家 80%<个人赔率≤95%,随机发牌
|
||
// realPlayerType = 0
|
||
// } else if minLoseRate <= 0.98 { //3.该玩家 95%<个人赔率≤98%,50%概率给予玩家最小牌,50%概率随机发牌
|
||
// if rand.Int31n(100) < 50 {
|
||
// realPlayerType = -1
|
||
// } else {
|
||
// realPlayerType = 0
|
||
// }
|
||
// } else { //3.该玩家 个人赔率>98%,给予玩家最小牌,切保证最大牌型和最小牌型之间的分差≥5(代码里对应50)
|
||
// realPlayerType = -1
|
||
// offGrade = 40
|
||
// }
|
||
// } else { //多个真人
|
||
// if len(robotPlayers) == 0 { //纯真人
|
||
// if this.IsPrivateScene() { //私有房间纯随机
|
||
// realPlayerType = 0
|
||
// } else {
|
||
// if rand.Int31n(100) < 50 { //50%概率给予最大牌,50%概率随机发牌
|
||
// realPlayerType = 1
|
||
// } else {
|
||
// realPlayerType = 0
|
||
// }
|
||
// }
|
||
// } else {
|
||
// //1.该玩家个人赔率≤90%,50%概率给予玩家最好牌,50%概率随机发牌
|
||
// if minLoseRate <= 0.9 {
|
||
// if rand.Int31n(100) < 50 {
|
||
// realPlayerType = 1
|
||
// } else {
|
||
// realPlayerType = 0
|
||
// }
|
||
// } else if minLoseRate < 0.98 { //2.该玩家 90%<个人赔率>98%,随机发牌
|
||
// realPlayerType = 0
|
||
// } else { //3.该玩家 个人赔率>98%,给予机器人最大牌
|
||
// realPlayerType = -1
|
||
// }
|
||
// }
|
||
// }
|
||
// }
|
||
// }
|
||
//
|
||
// this.Shuffle(offGrade, 0, 0)
|
||
//
|
||
// buf := this.poker.GetPokerBuf()
|
||
// cardss := map[int][]int32{}
|
||
// for i, card := range buf {
|
||
// if int32(card) != rule.InvalideCard {
|
||
// index := i / 13
|
||
// cardss[index] = append(cardss[index], int32(card))
|
||
// }
|
||
// }
|
||
//
|
||
// type gradeInfo struct {
|
||
// id int
|
||
// grade int
|
||
// cards []int32
|
||
// }
|
||
// grades := []gradeInfo{}
|
||
// for i, card13 := range cardss {
|
||
// cardTmp := make([]int32, 13)
|
||
// copy(cardTmp, card13)
|
||
// grade := rule.GetCardsGrade(cardTmp, this.IsTienLenYule())
|
||
// gi := gradeInfo{
|
||
// id: i,
|
||
// grade: grade,
|
||
// cards: card13,
|
||
// }
|
||
// grades = append(grades, gi)
|
||
// }
|
||
// if realPlayerType != 0 {
|
||
// sort.Slice(grades, func(i, j int) bool {
|
||
// return grades[i].grade > grades[j].grade
|
||
// })
|
||
// }
|
||
//
|
||
// for i, gi := range grades {
|
||
// cardss[i] = gi.cards
|
||
// }
|
||
//
|
||
// Grades := make(map[int32]int)
|
||
// minCard := int32(999)
|
||
// // 被控人
|
||
// for snid, player := range this.players {
|
||
// if player.IsGameing() && snid == minLoseRateSnid {
|
||
// cards := cardss[0] //最大
|
||
// if realPlayerType == -1 {
|
||
// cards = cardss[len(cardss)-1] //最小
|
||
// delete(cardss, len(cardss)-1)
|
||
// } else {
|
||
// delete(cardss, 0)
|
||
// }
|
||
// switch realPlayerType {
|
||
// case -1:
|
||
// logger.Logger.Trace("player get min grade !")
|
||
// case 0:
|
||
// logger.Logger.Trace("player get rand grade !")
|
||
// case 1:
|
||
// logger.Logger.Trace("player get max grade !")
|
||
// }
|
||
// for index, card := range cards {
|
||
// player.cards[index] = card
|
||
// if rule.Value(card) < rule.Value(minCard) {
|
||
// this.startOpPos = int32(player.GetPos())
|
||
// minCard = card
|
||
// this.curMinCard = minCard
|
||
// } else if rule.Value(card) == rule.Value(minCard) {
|
||
// if rule.Color(card) < rule.Color(minCard) {
|
||
// this.startOpPos = int32(player.GetPos())
|
||
// minCard = card
|
||
// this.curMinCard = minCard
|
||
// }
|
||
// }
|
||
// }
|
||
//
|
||
// cardTmp := make([]int32, 13)
|
||
// copy(cardTmp, cards)
|
||
// grade := rule.GetCardsGrade(cardTmp, this.IsTienLenYule())
|
||
// logger.Logger.Trace("SnId: ", player.SnId, ";grade: ", grade)
|
||
// Grades[player.SnId] = grade
|
||
//
|
||
// pack := &tienlen.SCTienLenCard{}
|
||
// for j := int32(0); j < rule.HandCardNum; j++ {
|
||
// pack.Cards = append(pack.Cards, player.cards[j])
|
||
// }
|
||
// proto.SetDefaults(pack)
|
||
// player.SendToClient(int(tienlen.TienLenPacketID_PACKET_SCTienLenCard), pack)
|
||
// logger.Logger.Trace("SnId: ", player.SnId, ";SCTienLenCard: ", pack)
|
||
// break
|
||
// }
|
||
// }
|
||
// if realPlayerType == -1 { //被控人拿最小牌,机器人拿最大牌
|
||
// snids := []int32{}
|
||
// for snid, player := range this.players {
|
||
// if player.IsRob && player.IsGameing() && snid != minLoseRateSnid && player.cards[0] == rule.InvalideCard {
|
||
// snids = append(snids, snid)
|
||
// }
|
||
// }
|
||
// if len(snids) > 0 {
|
||
// snid := snids[rand.Intn(len(snids))]
|
||
// player := this.players[snid]
|
||
// if player != nil {
|
||
// cards := cardss[0] //最大
|
||
// delete(cardss, 0)
|
||
// for index, card := range cards {
|
||
// player.cards[index] = card
|
||
// if rule.Value(card) < rule.Value(minCard) {
|
||
// this.startOpPos = int32(player.GetPos())
|
||
// minCard = card
|
||
// this.curMinCard = minCard
|
||
// } else if rule.Value(card) == rule.Value(minCard) {
|
||
// if rule.Color(card) < rule.Color(minCard) {
|
||
// this.startOpPos = int32(player.GetPos())
|
||
// minCard = card
|
||
// this.curMinCard = minCard
|
||
// }
|
||
// }
|
||
// }
|
||
//
|
||
// cardTmp := make([]int32, 13)
|
||
// copy(cardTmp, cards)
|
||
// grade := rule.GetCardsGrade(cardTmp, this.IsTienLenYule())
|
||
// logger.Logger.Trace("SnId: ", player.SnId, ";grade: ", grade)
|
||
// Grades[player.SnId] = grade
|
||
//
|
||
// pack := &tienlen.SCTienLenCard{}
|
||
// for j := int32(0); j < rule.HandCardNum; j++ {
|
||
// pack.Cards = append(pack.Cards, player.cards[j])
|
||
// }
|
||
// proto.SetDefaults(pack)
|
||
// player.SendToClient(int(tienlen.TienLenPacketID_PACKET_SCTienLenCard), pack)
|
||
// logger.Logger.Trace("SnId: ", player.SnId, ";SCTienLenCard: ", pack)
|
||
// }
|
||
// }
|
||
// }
|
||
// for _, cards := range cardss {
|
||
// for snid, player := range this.players {
|
||
// if player.IsGameing() && snid != minLoseRateSnid && player.cards[0] == rule.InvalideCard {
|
||
// for index, card := range cards {
|
||
// player.cards[index] = card
|
||
// if rule.Value(card) < rule.Value(minCard) {
|
||
// this.startOpPos = int32(player.GetPos())
|
||
// minCard = card
|
||
// this.curMinCard = minCard
|
||
// } else if rule.Value(card) == rule.Value(minCard) {
|
||
// if rule.Color(card) < rule.Color(minCard) {
|
||
// this.startOpPos = int32(player.GetPos())
|
||
// minCard = card
|
||
// this.curMinCard = minCard
|
||
// }
|
||
// }
|
||
// }
|
||
//
|
||
// cardTmp := make([]int32, 13)
|
||
// copy(cardTmp, cards)
|
||
// grade := rule.GetCardsGrade(cardTmp, this.IsTienLenYule())
|
||
// logger.Logger.Trace("SnId: ", player.SnId, ";grade: ", grade)
|
||
// Grades[player.SnId] = grade
|
||
//
|
||
// pack := &tienlen.SCTienLenCard{}
|
||
// for j := int32(0); j < rule.HandCardNum; j++ {
|
||
// pack.Cards = append(pack.Cards, player.cards[j])
|
||
// }
|
||
// proto.SetDefaults(pack)
|
||
// player.SendToClient(int(tienlen.TienLenPacketID_PACKET_SCTienLenCard), pack)
|
||
// logger.Logger.Trace("SnId: ", player.SnId, ";SCTienLenCard: ", pack)
|
||
// break
|
||
// }
|
||
// }
|
||
// }
|
||
//
|
||
// // 测试数据
|
||
// for snid, player := range this.players {
|
||
// if player.IsGameing() && !player.IsRob {
|
||
// pack := &tienlen.SCTienLenCardTest{}
|
||
// if snid == minLoseRateSnid {
|
||
// switch realPlayerType {
|
||
// case -1:
|
||
// pack.Type = 1
|
||
// case 0:
|
||
// pack.Type = 2
|
||
// case 1:
|
||
// pack.Type = 3
|
||
// }
|
||
// }
|
||
// pack.Totalout, pack.Totalin = player.TotalOutIn(int32(this.GetGameId()))
|
||
// pack.LoseRate = player.LoseRate(this.GetGameFreeId(), int32(this.GetGameId()))
|
||
// if Grades != nil {
|
||
// pack.Grades = make(map[int32]int32)
|
||
// for id, grade := range Grades {
|
||
// pack.Grades[id] = int32(grade)
|
||
// }
|
||
// }
|
||
// proto.SetDefaults(pack)
|
||
// player.SendToClient(int(tienlen.TienLenPacketID_PACKET_SCTienLenCardTest), pack)
|
||
// logger.Logger.Trace("SnId: ", player.SnId, ";SCTienLenCardTest: ", pack)
|
||
// }
|
||
// }
|
||
//}
|
||
|
||
// SendHandCardOdds 调控发牌
|
||
/*
|
||
1.计算玩家调控概率
|
||
新手天胡体验发牌 end
|
||
2.根据玩家调控概率随机获得需要控输或控赢的玩家
|
||
1.有控输玩家
|
||
1.机器人发天胡 end
|
||
2.分差发牌,机器人发好牌 end
|
||
2.有控赢,给控赢的玩家发好牌,其余随机发牌 end
|
||
*/
|
||
func (this *TienLenSceneData) SendHandCardOdds() {
|
||
var realPlayersGood, realPlayersBad, realPlayers, robotPlayers, novicePlayers, notNoviceRealPlayers []*TienLenPlayerData
|
||
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, this.GameId, this.robotGamingNum > 0)
|
||
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)
|
||
}
|
||
_, isNovice := seat.NoviceOdds(this.GameId)
|
||
if isNovice {
|
||
novicePlayers = append(novicePlayers, seat)
|
||
} else {
|
||
notNoviceRealPlayers = append(notNoviceRealPlayers, seat)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
var Grades = make(map[int32]int32)
|
||
var minCard = int32(999)
|
||
f1 := func(p *TienLenPlayerData, cards []int32) { // 发牌方法
|
||
cardsTypeMap := rule.GetCardsType(cards, this.IsTienLenYule())
|
||
score, _ := rule.GetCardTypeScore(cardsTypeMap, this.IsTienLenYule(), cards)
|
||
Grades[p.SnId] = int32(score) // 测试用
|
||
for index, card := range cards {
|
||
p.cards[index] = card
|
||
if rule.Value(card) < rule.Value(minCard) {
|
||
this.startOpPos = int32(p.GetPos())
|
||
minCard = card
|
||
this.curMinCard = minCard
|
||
} else if rule.Value(card) == rule.Value(minCard) {
|
||
if rule.Color(card) < rule.Color(minCard) {
|
||
this.startOpPos = int32(p.GetPos())
|
||
minCard = card
|
||
this.curMinCard = minCard
|
||
}
|
||
}
|
||
}
|
||
pack := &tienlen.SCTienLenCard{}
|
||
for j := int32(0); j < rule.HandCardNum; j++ {
|
||
pack.Cards = append(pack.Cards, p.cards[j])
|
||
}
|
||
pack.IsOutRecord = p.CanUseRecordItem()
|
||
proto.SetDefaults(pack)
|
||
p.SendToClient(int(tienlen.TienLenPacketID_PACKET_SCTienLenCard), pack)
|
||
logger.Logger.Trace("SnId: ", p.SnId, ";SCTienLenCard: ", pack)
|
||
}
|
||
|
||
// 新手天胡体验
|
||
// 前两局不能天胡,之后根据概率给一次天胡,至少天胡一次
|
||
noviceTianHu := false
|
||
noviceCtrl := false
|
||
config := srvdata.PBDB_NewPlayerMgr.GetData(int32(this.GameId))
|
||
if config != nil && config.GetTianHuRate() > 0 && len(this.testPokers) == 0 { // 启用新手天胡体验
|
||
rand.Shuffle(len(novicePlayers), func(i, j int) {
|
||
novicePlayers[i], novicePlayers[j] = novicePlayers[j], novicePlayers[i]
|
||
})
|
||
keyNovice := common.GetKeyNoviceGameId(this.GameId)
|
||
for _, v := range novicePlayers {
|
||
data, ok := v.GDatas[keyNovice]
|
||
if !ok {
|
||
data = &model.PlayerGameInfo{FirstTime: time.Now()}
|
||
v.GDatas[keyNovice] = data
|
||
}
|
||
// 前两局不能天胡
|
||
if data.Statics.GameTimes < 2 {
|
||
continue
|
||
}
|
||
if int(config.GetTianHuRate()) > this.RandInt(1000) {
|
||
var allcs []int32
|
||
for i := 0; i < 52; i++ {
|
||
allcs = append(allcs, int32(i))
|
||
}
|
||
rand.Shuffle(len(allcs), func(i, j int) {
|
||
allcs[i], allcs[j] = allcs[j], allcs[i]
|
||
})
|
||
cs, _ := rule.GetTianHu()
|
||
allcs = common.DelSliceIn32s(allcs, cs)
|
||
for _, seat := range this.seats {
|
||
if seat != nil && seat.IsGameing() {
|
||
if seat != v {
|
||
f1(seat, allcs[:13])
|
||
allcs = allcs[13:]
|
||
} else {
|
||
f1(seat, cs)
|
||
}
|
||
}
|
||
}
|
||
v.TestLog = append(v.TestLog, fmt.Sprintf("新手天胡体验,玩家:%d 发天胡 num:%v", v.SnId, data.Statics.GameTimes))
|
||
logger.Logger.Tracef("新手天胡体验,玩家:%d 发天胡", v.SnId)
|
||
noviceTianHu = true
|
||
noviceCtrl = true
|
||
}
|
||
}
|
||
if !noviceTianHu {
|
||
// 没有新手玩家天胡,随机一个非新手玩家,如果没有天胡过,给一次天胡
|
||
rand.Shuffle(len(notNoviceRealPlayers), func(i, j int) {
|
||
notNoviceRealPlayers[i], notNoviceRealPlayers[j] = notNoviceRealPlayers[j], notNoviceRealPlayers[i]
|
||
})
|
||
for _, v := range notNoviceRealPlayers {
|
||
data, ok := v.GDatas[keyNovice]
|
||
if !ok {
|
||
data = &model.PlayerGameInfo{FirstTime: time.Now()}
|
||
v.GDatas[keyNovice] = data
|
||
}
|
||
|
||
if data.Statics.GetInt(rule.StaticsTianHuTimes) == 0 {
|
||
var allcs []int32
|
||
for i := 0; i < 52; i++ {
|
||
allcs = append(allcs, int32(i))
|
||
}
|
||
rand.Shuffle(len(allcs), func(i, j int) {
|
||
allcs[i], allcs[j] = allcs[j], allcs[i]
|
||
})
|
||
cs, _ := rule.GetTianHu()
|
||
allcs = common.DelSliceIn32s(allcs, cs)
|
||
for _, seat := range this.seats {
|
||
if seat != nil && seat.IsGameing() {
|
||
if seat != v {
|
||
f1(seat, allcs[:13])
|
||
allcs = allcs[13:]
|
||
} else {
|
||
f1(seat, cs)
|
||
}
|
||
}
|
||
}
|
||
v.TestLog = append(v.TestLog, fmt.Sprintf("新手阶段没有天胡过,玩家:%d 发天胡 num:%v", v.SnId, data.Statics.GameTimes))
|
||
logger.Logger.Tracef("新手阶段没有天胡过,玩家:%v 发天胡", v.SnId)
|
||
noviceCtrl = true
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
gameConfig := base.ConfigMgrInst.GetConfig(this.Platform).GameConfig
|
||
|
||
// testPokers 用于测试
|
||
isTestPoker := false
|
||
if len(this.testPokers) > 1 {
|
||
var allcs []int32
|
||
for i := 0; i < 52; i++ {
|
||
allcs = append(allcs, int32(i))
|
||
}
|
||
rand.Shuffle(len(allcs), func(i, j int) {
|
||
allcs[i], allcs[j] = allcs[j], allcs[i]
|
||
})
|
||
|
||
if len(this.testPokers) > 14 {
|
||
this.testPokers = this.testPokers[:14]
|
||
}
|
||
if len(this.testPokers) < 14 {
|
||
allcs = common.DelSliceIn32s(allcs, this.testPokers[1:])
|
||
this.testPokers = append(this.testPokers, allcs[:14-len(this.testPokers)]...)
|
||
allcs = allcs[14-len(this.testPokers):]
|
||
}
|
||
|
||
allcs = common.DelSliceIn32s(allcs, this.testPokers[1:])
|
||
for _, seat := range this.seats {
|
||
if seat != nil && seat.IsGameing() {
|
||
if seat.SnId == this.testPokers[0] {
|
||
f1(seat, this.testPokers[1:])
|
||
} else {
|
||
f1(seat, allcs[:13])
|
||
allcs = allcs[13:]
|
||
}
|
||
}
|
||
}
|
||
this.testPokers = nil
|
||
isTestPoker = true
|
||
}
|
||
// testPokers
|
||
|
||
// 需要换牌
|
||
isGood := len(realPlayersGood) > 0 && int32(this.RandInt(1000)) < G
|
||
isBad := len(realPlayersBad) > 0 && int32(this.RandInt(1000)) < B
|
||
logger.Logger.Tracef("TienLen SendHandCardOdds Good:%v G:%v Bad:%v B:%v", isGood, G, isBad, B)
|
||
|
||
if isBad && !isTestPoker && len(robotPlayers) > 0 && !noviceCtrl && !noviceTianHu {
|
||
gf := base.ConfigMgrInst.GetConfig(this.Platform).GameConfig
|
||
items := []int32{gf.GetTianHu(), gf.GetPaiKu(), gf.GetFenCha()}
|
||
score := this.RandInt(int(gf.GetTianHu() + gf.GetPaiKu() + gf.GetFenCha()))
|
||
sum := int32(0)
|
||
tp := 0
|
||
for k, v := range items {
|
||
sum += v
|
||
if int32(score) < sum {
|
||
tp = k
|
||
break
|
||
}
|
||
}
|
||
logger.Logger.Tracef("TienLen SendHandCardOdds TianHu:%v PaiKu:%v FenCha:%v, tp:%v", items[0], items[1], items[2], tp)
|
||
switch tp {
|
||
case 0: // 天胡发牌
|
||
logger.Logger.Tracef("TienLen SendHandCardOdds TianHuRate")
|
||
p := robotPlayers[0]
|
||
th, _ := rule.GetTianHu()
|
||
if len(th) == rule.Hand_CardNum {
|
||
// 机器人发天胡,其它玩家随机发牌
|
||
f1(p, th)
|
||
var allCards []int32
|
||
for i := 0; i < rule.POKER_CNT; i++ {
|
||
allCards = append(allCards, int32(i))
|
||
}
|
||
allCards = common.DelSliceIn32s(allCards, th)
|
||
rand.Shuffle(len(allCards), func(i, j int) {
|
||
allCards[i], allCards[j] = allCards[j], allCards[i]
|
||
})
|
||
for _, v := range this.players { // map随机
|
||
if v == nil || !v.IsGameing() || v.cards[0] != rule.InvalideCard {
|
||
continue
|
||
}
|
||
f1(v, allCards[:rule.Hand_CardNum])
|
||
allCards = allCards[rule.Hand_CardNum:]
|
||
}
|
||
}
|
||
p.TestLog = append(p.TestLog, fmt.Sprintf("天胡发牌 snid%v 权重%v", p.SnId, gameConfig.GetTianHu()))
|
||
|
||
case 1: // 牌库发牌
|
||
logger.Logger.Tracef("TienLen SendHandCardOdds 牌库")
|
||
//todo 牌库
|
||
random := rand.Intn(10000)
|
||
var cardsArr [][]int32
|
||
this.isCardsKu = true
|
||
this.cardsKuId = int32(random)
|
||
if this.IsTienLenYule() {
|
||
cardsPool := srvdata.PBDB_CardsYuLeMgr.GetData(int32(random))
|
||
logger.Logger.Tracef("娱乐牌库发牌!!!!!! 随机到的牌库id = %d\n,db_CardsYuLe = %v\n", cardsPool.Id, cardsPool)
|
||
var numbers []int32
|
||
err := json.Unmarshal([]byte(cardsPool.Card1), &numbers)
|
||
if err != nil {
|
||
fmt.Println("JSON unmarshaling failed:", err)
|
||
return
|
||
}
|
||
cardsArr = append(cardsArr, numbers)
|
||
numbers = []int32{}
|
||
err = json.Unmarshal([]byte(cardsPool.Card2), &numbers)
|
||
if err != nil {
|
||
fmt.Println("JSON unmarshaling failed:", err)
|
||
return
|
||
}
|
||
cardsArr = append(cardsArr, numbers)
|
||
numbers = []int32{}
|
||
err = json.Unmarshal([]byte(cardsPool.Card3), &numbers)
|
||
if err != nil {
|
||
fmt.Println("JSON unmarshaling failed:", err)
|
||
return
|
||
}
|
||
cardsArr = append(cardsArr, numbers)
|
||
numbers = []int32{}
|
||
err = json.Unmarshal([]byte(cardsPool.Card4), &numbers)
|
||
if err != nil {
|
||
fmt.Println("JSON unmarshaling failed:", err)
|
||
return
|
||
}
|
||
cardsArr = append(cardsArr, numbers)
|
||
//排序
|
||
sort.Slice(cardsArr, func(i, j int) bool {
|
||
cardsTypeMap := rule.GetCardsType(cardsArr[i], this.IsTienLenYule())
|
||
score1, _ := rule.GetCardTypeScore(cardsTypeMap, this.IsTienLenYule(), cardsArr[i])
|
||
cardsTypeMap2 := rule.GetCardsType(cardsArr[j], this.IsTienLenYule())
|
||
score2, _ := rule.GetCardTypeScore(cardsTypeMap2, this.IsTienLenYule(), cardsArr[j])
|
||
return score1 > score2
|
||
})
|
||
if isGood {
|
||
sort.Slice(realPlayersGood, func(i, j int) bool {
|
||
return realPlayersGood[i].odds > realPlayersGood[j].odds
|
||
})
|
||
for _, v := range realPlayersGood {
|
||
f1(v, cardsArr[0])
|
||
cardsArr = cardsArr[1:]
|
||
}
|
||
}
|
||
if isBad {
|
||
sort.Slice(realPlayersBad, func(i, j int) bool {
|
||
return realPlayersBad[i].odds < realPlayersBad[j].odds
|
||
})
|
||
for _, v := range realPlayersBad {
|
||
f1(v, cardsArr[len(cardsArr)-1])
|
||
cardsArr = cardsArr[:len(cardsArr)-1]
|
||
}
|
||
}
|
||
//机器人发牌和不调控的人
|
||
for _, v := range append(robotPlayers, realPlayers...) {
|
||
f1(v, cardsArr[0])
|
||
cardsArr = cardsArr[1:]
|
||
}
|
||
} else {
|
||
cardsPool := srvdata.PBDB_CardsJDMgr.GetData(int32(random))
|
||
logger.Logger.Tracef("经典牌库发牌!!!!!! 随机到的牌库id = %d\n,db_CardsYuLe = %v\n", cardsPool.Id, cardsPool)
|
||
var numbers []int32
|
||
err := json.Unmarshal([]byte(cardsPool.Card1), &numbers)
|
||
if err != nil {
|
||
fmt.Println("JSON unmarshaling failed:", err)
|
||
return
|
||
}
|
||
cardsArr = append(cardsArr, numbers)
|
||
numbers = []int32{}
|
||
err = json.Unmarshal([]byte(cardsPool.Card2), &numbers)
|
||
if err != nil {
|
||
fmt.Println("JSON unmarshaling failed:", err)
|
||
return
|
||
}
|
||
cardsArr = append(cardsArr, numbers)
|
||
numbers = []int32{}
|
||
err = json.Unmarshal([]byte(cardsPool.Card3), &numbers)
|
||
if err != nil {
|
||
fmt.Println("JSON unmarshaling failed:", err)
|
||
return
|
||
}
|
||
cardsArr = append(cardsArr, numbers)
|
||
numbers = []int32{}
|
||
err = json.Unmarshal([]byte(cardsPool.Card4), &numbers)
|
||
if err != nil {
|
||
fmt.Println("JSON unmarshaling failed:", err)
|
||
return
|
||
}
|
||
cardsArr = append(cardsArr, numbers)
|
||
//排序
|
||
sort.Slice(cardsArr, func(i, j int) bool {
|
||
cardsTypeMap := rule.GetCardsType(cardsArr[i], this.IsTienLenYule())
|
||
score1, _ := rule.GetCardTypeScore(cardsTypeMap, this.IsTienLenYule(), cardsArr[i])
|
||
cardsTypeMap2 := rule.GetCardsType(cardsArr[j], this.IsTienLenYule())
|
||
score2, _ := rule.GetCardTypeScore(cardsTypeMap2, this.IsTienLenYule(), cardsArr[j])
|
||
return score1 > score2
|
||
})
|
||
if isGood {
|
||
sort.Slice(realPlayersGood, func(i, j int) bool {
|
||
return realPlayersGood[i].odds > realPlayersGood[j].odds
|
||
})
|
||
for _, v := range realPlayersGood {
|
||
f1(v, cardsArr[0])
|
||
cardsArr = cardsArr[1:]
|
||
}
|
||
}
|
||
if isBad {
|
||
sort.Slice(realPlayersBad, func(i, j int) bool {
|
||
return realPlayersBad[i].odds < realPlayersBad[j].odds
|
||
})
|
||
for _, v := range realPlayersBad {
|
||
f1(v, cardsArr[len(cardsArr)-1])
|
||
cardsArr = cardsArr[:len(cardsArr)-1]
|
||
}
|
||
}
|
||
//机器人发牌和不调控的人
|
||
for _, v := range append(robotPlayers, realPlayers...) {
|
||
f1(v, cardsArr[0])
|
||
cardsArr = cardsArr[1:]
|
||
}
|
||
}
|
||
case 2: // 分差发牌
|
||
logger.Logger.Tracef("TienLen SendHandCardOdds 分差发牌")
|
||
for i := 0; i <= 20; i++ {
|
||
allCards := rand.Perm(rule.POKER_CNT)
|
||
var cardsArr [][]int32
|
||
for i := 0; i < 4; i++ {
|
||
cardsArr = append(cardsArr, common.CopySliceIntToInt32(allCards[:13]))
|
||
allCards = allCards[13:]
|
||
}
|
||
sort.Slice(cardsArr, func(i, j int) bool {
|
||
cardsTypeMap := rule.GetCardsType(cardsArr[i], this.IsTienLenYule())
|
||
score, _ := rule.GetCardTypeScore(cardsTypeMap, this.IsTienLenYule(), cardsArr[i])
|
||
cardsTypeMap2 := rule.GetCardsType(cardsArr[j], this.IsTienLenYule())
|
||
score2, _ := rule.GetCardTypeScore(cardsTypeMap2, this.IsTienLenYule(), cardsArr[j])
|
||
return score > score2
|
||
})
|
||
if len(cardsArr) > 0 {
|
||
cardsTypeMap := rule.GetCardsType(cardsArr[0], this.IsTienLenYule())
|
||
score, _ := rule.GetCardTypeScore(cardsTypeMap, this.IsTienLenYule(), cardsArr[0])
|
||
cardsTypeMap2 := rule.GetCardsType(cardsArr[len(cardsArr)-1], this.IsTienLenYule())
|
||
score2, _ := rule.GetCardTypeScore(cardsTypeMap2, this.IsTienLenYule(), cardsArr[len(cardsArr)-1])
|
||
if score-score2 > int(gameConfig.GetFenChaScore()) {
|
||
logger.Logger.Tracef("分差发牌,分差:%v", score-score2)
|
||
for _, v := range robotPlayers {
|
||
if v == nil || !v.IsGameing() || v.cards[0] != rule.InvalideCard {
|
||
continue
|
||
}
|
||
f1(v, cardsArr[0])
|
||
cardsArr = cardsArr[1:]
|
||
}
|
||
for _, v := range this.players { // map随机
|
||
if v == nil || !v.IsGameing() || v.cards[0] != rule.InvalideCard {
|
||
continue
|
||
}
|
||
f1(v, cardsArr[len(cardsArr)-1])
|
||
cardsArr = cardsArr[:len(cardsArr)-1]
|
||
v.TestLog = append(v.TestLog, fmt.Sprintf("分差发牌 snid%v 权重%v 需要分差%v 真实分差%v", v.SnId,
|
||
gameConfig.GetFenCha(), gameConfig.GetFenChaScore(), score-score2))
|
||
}
|
||
break
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
this.Shuffle(0, 0, 0)
|
||
buf := this.poker.GetPokerBuf()
|
||
cardsArr := make([][]int32, 4)
|
||
for i, card := range buf {
|
||
if int32(card) != rule.InvalideCard {
|
||
index := i / 13
|
||
cardsArr[index] = append(cardsArr[index], int32(card))
|
||
}
|
||
}
|
||
f2 := func(players *[]*TienLenPlayerData) {
|
||
if players == nil || len(*players) == 0 {
|
||
return
|
||
}
|
||
var p *TienLenPlayerData // 发牌给这个玩家
|
||
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 []int32
|
||
if p.odds > 0 {
|
||
// 拿好牌
|
||
cards = cardsArr[0]
|
||
cardsArr = cardsArr[1:]
|
||
} else {
|
||
// 拿坏牌
|
||
cards = cardsArr[len(cardsArr)-1]
|
||
cardsArr = cardsArr[:len(cardsArr)-1]
|
||
}
|
||
if p.cards[0] == rule.InvalideCard {
|
||
f1(p, cards)
|
||
}
|
||
}
|
||
|
||
if !isBad && !isTestPoker && !noviceCtrl && !noviceTianHu { // 天胡调控没有生效
|
||
if isGood || isBad {
|
||
// 牌平分,按从大到小排序
|
||
// 使用分差配置,最好牌和最差牌的牌型分差大于分差配置
|
||
for i := 0; i < 20; i++ { // 尝试20次,如果还不能满足分差配置,则直接发牌
|
||
cardsArr = cardsArr[:0]
|
||
allCards := rand.Perm(rule.POKER_CNT)
|
||
for i := 0; i < 4; i++ {
|
||
cardsArr = append(cardsArr, common.CopySliceIntToInt32(allCards[:13]))
|
||
allCards = allCards[13:]
|
||
}
|
||
sort.Slice(cardsArr, func(i, j int) bool {
|
||
cardsTypeMap := rule.GetCardsType(cardsArr[i], this.IsTienLenYule())
|
||
score, _ := rule.GetCardTypeScore(cardsTypeMap, this.IsTienLenYule(), cardsArr[i])
|
||
cardsTypeMap2 := rule.GetCardsType(cardsArr[j], this.IsTienLenYule())
|
||
score2, _ := rule.GetCardTypeScore(cardsTypeMap2, this.IsTienLenYule(), cardsArr[j])
|
||
return score > score2
|
||
})
|
||
if len(cardsArr) > 0 {
|
||
cardsTypeMap := rule.GetCardsType(cardsArr[0], this.IsTienLenYule())
|
||
score, _ := rule.GetCardTypeScore(cardsTypeMap, this.IsTienLenYule(), cardsArr[0])
|
||
cardsTypeMap2 := rule.GetCardsType(cardsArr[len(cardsArr)-1], this.IsTienLenYule())
|
||
score2, _ := rule.GetCardTypeScore(cardsTypeMap2, this.IsTienLenYule(), cardsArr[len(cardsArr)-1])
|
||
if score-score2 > int(gameConfig.GetGoodFenCha()) {
|
||
break
|
||
}
|
||
}
|
||
}
|
||
// 排序
|
||
type gradeInfo struct {
|
||
grade int
|
||
cards []int32
|
||
}
|
||
var grades []gradeInfo
|
||
for _, card13 := range cardsArr {
|
||
cardTmp := make([]int32, 13)
|
||
copy(cardTmp, card13)
|
||
cardsTypeMap := rule.GetCardsType(cardTmp, this.IsTienLenYule())
|
||
grade, _ := rule.GetCardTypeScore(cardsTypeMap, this.IsTienLenYule(), cardTmp)
|
||
gi := gradeInfo{
|
||
grade: grade,
|
||
cards: card13,
|
||
}
|
||
grades = append(grades, gi)
|
||
}
|
||
sort.Slice(grades, func(i, j int) bool {
|
||
return grades[i].grade > grades[j].grade
|
||
})
|
||
for i, gi := range grades {
|
||
cardsArr[i] = gi.cards
|
||
}
|
||
// 发好牌
|
||
if isGood {
|
||
l := len(realPlayersGood)
|
||
for i := 0; i < l; i++ {
|
||
f2(&realPlayersGood)
|
||
}
|
||
}
|
||
// 发坏牌
|
||
if isBad {
|
||
l := len(realPlayersBad)
|
||
for i := 0; i < l; i++ {
|
||
f2(&realPlayersBad)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 随机拿牌
|
||
for _, v := range this.players { // map随机
|
||
if v == nil || !v.IsGameing() || v.cards[0] != rule.InvalideCard {
|
||
continue
|
||
}
|
||
f1(v, cardsArr[len(cardsArr)-1])
|
||
cardsArr = cardsArr[:len(cardsArr)-1]
|
||
}
|
||
|
||
// 测试
|
||
for _, player := range this.players {
|
||
if player.IsGameing() && !player.IsRob {
|
||
pack := &tienlen.SCTienLenCardTest{}
|
||
pack.Totalout, pack.Totalin = player.TotalOutIn(int32(this.GetGameId()))
|
||
pack.LoseRate = player.LoseRate(this.GetGameFreeId(), int32(this.GetGameId()))
|
||
if Grades != nil {
|
||
pack.Grades = make(map[int32]int32)
|
||
for id, grade := range Grades {
|
||
pack.Grades[id] = int32(grade)
|
||
}
|
||
}
|
||
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))
|
||
pack.Data = strings.Join(player.TestLog, "\n")
|
||
proto.SetDefaults(pack)
|
||
player.SendToClient(int(tienlen.TienLenPacketID_PACKET_SCTienLenCardTest), pack)
|
||
//logger.Logger.Trace("SnId: ", player.SnId, ";SCTienLenCardTest: ", pack)
|
||
for _, v := range player.TestLog {
|
||
logger.Logger.Trace(v)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
func (this *TienLenSceneData) SendHandCardTest() {
|
||
this.poker.Shuffle()
|
||
buf := this.poker.GetPokerBuf()
|
||
//牌序- 2, A, K, Q, J, 10, 9, 8, 7, 6, 5, 4, 3
|
||
//红桃- 51,50,49,48,47,46,45,44,43,42,41,40,39
|
||
//方片- 38,37,36,35,34,33,32,31,30,29,28,27,26
|
||
//梅花- 25,24,23,22,21,20,19,18,17,16,15,14,13
|
||
//黑桃- 12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
|
||
test1 := []int32{35, 34, 33, 32, 31, 30, 0}
|
||
test2 := []int32{42,
|
||
29,
|
||
16,
|
||
3}
|
||
test3 := []int32{}
|
||
test4 := []int32{}
|
||
|
||
need1 := rule.HandCardNum - int32(len(test1))
|
||
need2 := rule.HandCardNum - int32(len(test2))
|
||
need3 := rule.HandCardNum - int32(len(test3))
|
||
need4 := rule.HandCardNum - int32(len(test4))
|
||
|
||
tmpBuf := []int32{}
|
||
|
||
for i, card := range buf {
|
||
for _, card1 := range test1 {
|
||
if int32(card) == card1 {
|
||
buf[i] = rule.Card(rule.InvalideCard)
|
||
}
|
||
}
|
||
for _, card1 := range test2 {
|
||
if int32(card) == card1 {
|
||
buf[i] = rule.Card(rule.InvalideCard)
|
||
}
|
||
}
|
||
for _, card1 := range test3 {
|
||
if int32(card) == card1 {
|
||
buf[i] = rule.Card(rule.InvalideCard)
|
||
}
|
||
}
|
||
for _, card1 := range test4 {
|
||
if int32(card) == card1 {
|
||
buf[i] = rule.Card(rule.InvalideCard)
|
||
}
|
||
}
|
||
}
|
||
|
||
for _, card := range buf {
|
||
if int32(card) != rule.InvalideCard {
|
||
tmpBuf = append(tmpBuf, int32(card))
|
||
}
|
||
}
|
||
|
||
var n int
|
||
minCard := int32(999)
|
||
for _, seatPlayerEx := range this.seats {
|
||
if seatPlayerEx != nil {
|
||
bb := []int32{}
|
||
for i := n * rule.Hand_CardNum; i < (n+1)*rule.Hand_CardNum; i++ {
|
||
bb = append(bb, int32(buf[i]))
|
||
}
|
||
bb = []int32{}
|
||
switch seatPlayerEx.GetPos() {
|
||
case 0:
|
||
for _, card := range test1 {
|
||
bb = append(bb, card)
|
||
}
|
||
for i := int32(0); i < need1; i++ {
|
||
bb = append(bb, tmpBuf[i])
|
||
}
|
||
tmpBuf = append(tmpBuf[need1:])
|
||
case 1:
|
||
for _, card := range test2 {
|
||
bb = append(bb, card)
|
||
}
|
||
for i := int32(0); i < need2; i++ {
|
||
bb = append(bb, tmpBuf[i])
|
||
}
|
||
tmpBuf = append(tmpBuf[need2:])
|
||
case 2:
|
||
for _, card := range test3 {
|
||
bb = append(bb, card)
|
||
}
|
||
for i := int32(0); i < need3; i++ {
|
||
bb = append(bb, tmpBuf[i])
|
||
}
|
||
tmpBuf = append(tmpBuf[need3:])
|
||
case 3:
|
||
for _, card := range test4 {
|
||
bb = append(bb, card)
|
||
}
|
||
for i := int32(0); i < need4; i++ {
|
||
bb = append(bb, tmpBuf[i])
|
||
}
|
||
tmpBuf = append(tmpBuf[need4:])
|
||
}
|
||
//排下序,正常应该客户端排序
|
||
sort.Slice(bb, func(i, j int) bool {
|
||
v_i := rule.Value(int32(bb[i]))
|
||
v_j := rule.Value(int32(bb[j]))
|
||
c_i := rule.Color(int32(bb[i]))
|
||
c_j := rule.Color(int32(bb[j]))
|
||
if v_i > v_j {
|
||
return false
|
||
} else if v_i == v_j {
|
||
return c_i < c_j
|
||
}
|
||
return true
|
||
})
|
||
for idx, card := range bb {
|
||
seatPlayerEx.cards[idx] = int32(card)
|
||
if rule.Value(int32(card)) < rule.Value(minCard) {
|
||
this.startOpPos = int32(seatPlayerEx.GetPos())
|
||
minCard = int32(card)
|
||
this.curMinCard = minCard
|
||
} else if rule.Value(int32(card)) == rule.Value(minCard) {
|
||
if rule.Color(int32(card)) < rule.Color(minCard) {
|
||
this.startOpPos = int32(seatPlayerEx.GetPos())
|
||
minCard = int32(card)
|
||
this.curMinCard = minCard
|
||
}
|
||
}
|
||
}
|
||
pack := &tienlen.SCTienLenCard{}
|
||
for j := int32(0); j < rule.HandCardNum; j++ {
|
||
pack.Cards = append(pack.Cards, int32(seatPlayerEx.cards[j]))
|
||
}
|
||
pack.IsOutRecord = seatPlayerEx.CanUseRecordItem()
|
||
|
||
proto.SetDefaults(pack)
|
||
seatPlayerEx.SendToClient(int(tienlen.TienLenPacketID_PACKET_SCTienLenCard), pack)
|
||
logger.Logger.Trace("player_id", seatPlayerEx.SnId, ";SCTienLenCard", pack.Cards)
|
||
n++
|
||
}
|
||
}
|
||
}
|
||
|
||
func (this *TienLenSceneData) SetCurOpPos(pos int32) {
|
||
this.currOpPos = pos
|
||
}
|
||
func (this *TienLenSceneData) GetCurOpPos() int32 {
|
||
return this.currOpPos
|
||
}
|
||
func (this *TienLenSceneData) GetCurOpPlayer() *TienLenPlayerData {
|
||
if this.currOpPos < 0 || this.currOpPos >= int32(this.GetPlayerNum()) {
|
||
return nil
|
||
}
|
||
return this.seats[this.currOpPos]
|
||
}
|
||
func (this *TienLenSceneData) SetLastOpPos(pos int32) {
|
||
this.lastOpPos = pos
|
||
|
||
//this.RefreshPlayerHandLimitTimeOut()
|
||
}
|
||
func (this *TienLenSceneData) GetLastOpPos() int32 {
|
||
return this.lastOpPos
|
||
}
|
||
func (this *TienLenSceneData) GetLastOpPlayer() *TienLenPlayerData {
|
||
if this.lastOpPos < 0 || this.lastOpPos >= int32(this.GetPlayerNum()) {
|
||
return nil
|
||
}
|
||
return this.seats[this.lastOpPos]
|
||
}
|
||
|
||
func (this *TienLenSceneData) GetLastBombPlayer() *TienLenPlayerData {
|
||
if this.lastBombPos < 0 || this.lastBombPos >= int32(this.GetPlayerNum()) {
|
||
return nil
|
||
}
|
||
return this.seats[this.lastBombPos]
|
||
}
|
||
func (this *TienLenSceneData) GetCurBombPlayer() *TienLenPlayerData {
|
||
if this.curBombPos < 0 || this.curBombPos >= int32(this.GetPlayerNum()) {
|
||
return nil
|
||
}
|
||
return this.seats[this.curBombPos]
|
||
}
|
||
|
||
// 逆时针找一个空位
|
||
func (this *TienLenSceneData) FindOnePos() int {
|
||
for i := 0; i < this.GetPlayerNum(); i++ {
|
||
if this.seats[i] == nil {
|
||
return i
|
||
}
|
||
}
|
||
return int(rule.InvalidePos)
|
||
}
|
||
|
||
// 刷新玩家出牌时间
|
||
func (this *TienLenSceneData) RefreshPlayerHandLimitTimeOut() {
|
||
CurPlayer := this.GetCurOpPlayer()
|
||
if CurPlayer == nil {
|
||
return
|
||
}
|
||
|
||
if CurPlayer.IsRobot() {
|
||
return
|
||
}
|
||
|
||
//curCpCards := []int32{}
|
||
//for _, card := range CurPlayer.cards {
|
||
// if card != rule.InvalideCard {
|
||
// curCpCards = append(curCpCards, card)
|
||
// }
|
||
//}
|
||
|
||
lastOpPlayer := this.GetLastOpPlayer()
|
||
if lastOpPlayer != nil && len(lastOpPlayer.delCards) != 0 {
|
||
// lastDelCards := lastOpPlayer.delCards[len(lastOpPlayer.delCards)-1]
|
||
//logger.Logger.Trace("(this *TienLenSceneData) RefreshPlayerHandLimitTimeOut lastOpPlayer snid: ", lastOpPlayer.SnId, " lastDelCards", lastDelCards)
|
||
|
||
//recmCards := rule.RecommendCardsWithLastCards(lastDelCards, curCpCards)
|
||
//if this.IsTienLenYule() {
|
||
// recmCards = rule.RecommendCardsWithLastCards_yl(lastDelCards, curCpCards)
|
||
//}
|
||
|
||
//canDel, _, _ := rule.CanDel(lastDelCards, recmCards, this.IsTienLenToEnd())
|
||
//if this.IsTienLenYule() {
|
||
// canDel, _, _ = rule.CanDel_yl(lastDelCards, recmCards, this.IsTienLenToEnd())
|
||
//}
|
||
|
||
//logger.Logger.Trace("(this *TienLenSceneData) RefreshPlayerHandLimitTimeOut lastOpPlayer snid: ", lastOpPlayer.SnId, " ThinkLongCnt:", lastOpPlayer.ThinkLongCnt, " flag:", lastOpPlayer.GetFlag())
|
||
|
||
if int32(CurPlayer.GetPos()) != this.lastOpPos {
|
||
//if !canDel { // 压不住别人
|
||
// //CurPlayer.curHandLimitTimeOut = rule.TienLenHandNotExceedTimeLimit
|
||
// //CurPlayer.isNotOverLastHand = true
|
||
// //logger.Logger.Trace("(this *TienLenSceneData) RefreshPlayerHandLimitTimeOut lastOpPlayer snid: ", lastOpPlayer.SnId, " CurPlayerSnid: ", CurPlayer.SnId, " ---压不住")
|
||
//} else {
|
||
// //CurPlayer.RefreshCurHandLimitTimeOut()
|
||
// //CurPlayer.isNotOverLastHand = false
|
||
// //logger.Logger.Trace("(this *TienLenSceneData) RefreshPlayerHandLimitTimeOut lastOpPlayer snid: ", lastOpPlayer.SnId, " CurPlayerSnid: ", CurPlayer.SnId, " ---可以压住")
|
||
//}
|
||
|
||
CurPlayer.RefreshCurHandLimitTimeOut()
|
||
CurPlayer.isNotOverLastHand = false
|
||
} else {
|
||
CurPlayer.RefreshCurHandLimitTimeOut()
|
||
CurPlayer.isNotOverLastHand = false
|
||
//logger.Logger.Trace("(this *TienLenSceneData) RefreshPlayerHandLimitTimeOut lastOpPlayer snid: ", lastOpPlayer.SnId, " CurPlayerSnid: ", CurPlayer.SnId, " ---本轮自己首出牌")
|
||
}
|
||
|
||
//logger.Logger.Trace("(this *TienLenSceneData) RefreshPlayerHandLimitTimeOut lastOpPlayer lastOpPos: ", this.lastOpPos, " currOpPos: ", CurPlayer.GetPos())
|
||
|
||
}
|
||
}
|
||
|
||
func (this *TienLenSceneData) DoNext(pos int32) int32 {
|
||
nextPos := this.GetNextOpPos(pos)
|
||
if nextPos != rule.InvalidePos {
|
||
this.SetCurOpPos(nextPos)
|
||
this.StateStartTime = time.Now()
|
||
}
|
||
this.lastPos = pos
|
||
|
||
//this.RefreshPlayerHandLimitTimeOut()
|
||
//logger.Logger.Trace("(this *TienLenSceneData) DoNext pos: ", pos, " nextPos:", nextPos, " StateStartTime:", this.StateStartTime)
|
||
this.cHintCards = []int32{}
|
||
return nextPos
|
||
}
|
||
|
||
func (this *TienLenSceneData) GetNextOpPos(pos int32) int32 {
|
||
if pos == rule.InvalidePos {
|
||
return rule.InvalidePos
|
||
}
|
||
if pos < 0 || pos >= int32(this.GetPlayerNum()) {
|
||
return rule.InvalidePos
|
||
}
|
||
|
||
for i := pos + 1; i < int32(this.GetPlayerNum()); i++ {
|
||
if this.PlayerCanOp(i) {
|
||
return i
|
||
}
|
||
}
|
||
for i := int32(0); i < pos; i++ {
|
||
if this.PlayerCanOp(i) {
|
||
return i
|
||
}
|
||
}
|
||
|
||
return rule.InvalidePos
|
||
}
|
||
|
||
func (this *TienLenSceneData) UnmarkPass() {
|
||
for i := 0; i < this.GetPlayerNum(); i++ {
|
||
if this.seats[i] != nil {
|
||
this.seats[i].isPass = false
|
||
}
|
||
}
|
||
}
|
||
|
||
func (this *TienLenSceneData) FindWinPos() int {
|
||
winPos := -1
|
||
if this.lastGamingPlayerNum != 0 && this.curGamingPlayerNum != 0 && this.lastWinSnid != 0 {
|
||
haveLastWinPos := -1
|
||
for i := 0; i < this.GetPlayerNum(); i++ {
|
||
if this.seats[i] != nil {
|
||
if this.seats[i].SnId == this.lastWinSnid {
|
||
haveLastWinPos = i
|
||
break
|
||
}
|
||
}
|
||
}
|
||
if haveLastWinPos != -1 {
|
||
if this.lastGamingPlayerNum > 2 {
|
||
winPos = haveLastWinPos
|
||
} else if this.lastGamingPlayerNum == 2 {
|
||
if this.curGamingPlayerNum == 2 {
|
||
winPos = haveLastWinPos
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return winPos
|
||
}
|
||
|
||
func (this *TienLenSceneData) TrySmallGameBilled() {
|
||
// 看是不是炸弹,是炸弹结算分
|
||
if this.isKongBomb {
|
||
this.bombToEnd++
|
||
this.isKongBomb = false
|
||
}
|
||
if this.roundScore > 0 && this.curBombPos != rule.InvalidePos && this.lastBombPos != rule.InvalidePos {
|
||
winPlayer := this.GetCurBombPlayer()
|
||
losePlayer := this.GetLastBombPlayer()
|
||
baseScore := this.GetBaseScore()
|
||
var rankScore = int64(this.roundScore)
|
||
score := int64(this.roundScore) * int64(baseScore)
|
||
if this.IsTienLenToEnd() {
|
||
score = int64(this.roundScore) * int64(baseScore) / 100 //百分比
|
||
}
|
||
losePlayerCoin := losePlayer.GetCoin()
|
||
if !this.IsMatchScene() && losePlayerCoin < score { //输完
|
||
score = losePlayerCoin
|
||
}
|
||
if score != 0 {
|
||
taxRate := this.DbGameFree.GetTaxRate() //万分比
|
||
gainScore := int64(float64(score) * float64(10000-taxRate) / 10000.0) //税后
|
||
bombTaxScore := score - gainScore
|
||
// win
|
||
if this.IsMatchScene() {
|
||
winPlayer.AddCoinNoLog(gainScore, 0)
|
||
} else {
|
||
winPlayer.AddCoin(gainScore, common.GainWay_CoinSceneWin, 0, "system", this.GetSceneName())
|
||
}
|
||
winPlayer.winCoin += gainScore
|
||
winPlayer.bombScore += gainScore
|
||
winPlayer.bombTaxScore += bombTaxScore
|
||
if this.IsTienLenToEnd() {
|
||
winPlayer.bombRankScore += int64(float64(rankScore) / 100.0 * float64(rule.RankBaseScoreToEnd))
|
||
} else {
|
||
winPlayer.bombRankScore += rankScore * rule.RankBaseScore
|
||
}
|
||
//lose
|
||
if this.IsMatchScene() {
|
||
losePlayer.AddCoinNoLog(-score, 0)
|
||
} else {
|
||
losePlayer.AddCoin(-score, common.GainWay_CoinSceneLost, 0, "system", this.GetSceneName())
|
||
}
|
||
losePlayer.winCoin -= score
|
||
losePlayer.bombScore -= score
|
||
if this.IsTienLenToEnd() {
|
||
losePlayer.bombRankScore -= int64(float64(rankScore) / 100.0 * float64(rule.RankBaseScoreToEnd))
|
||
} else {
|
||
losePlayer.bombRankScore -= rankScore * rule.RankBaseScore
|
||
}
|
||
|
||
pack := &tienlen.SCTienLenSmallGameBilled{
|
||
WinPos: proto.Int(winPlayer.GetPos()),
|
||
WinPosCoin: proto.Int64(winPlayer.GetCoin()),
|
||
WinCoin: proto.Int64(gainScore),
|
||
LosePos: proto.Int(losePlayer.GetPos()),
|
||
LosePosCoin: proto.Int64(losePlayer.GetCoin()),
|
||
LoseCoin: proto.Int64(score),
|
||
}
|
||
proto.SetDefaults(pack)
|
||
this.Broadcast(int(tienlen.TienLenPacketID_PACKET_SCTienLenSmallGameBilled), pack, 0)
|
||
logger.Logger.Trace("SCTienLenSmallGameBilled: ", pack)
|
||
}
|
||
}
|
||
this.curBombPos = rule.InvalidePos
|
||
this.lastBombPos = rule.InvalidePos
|
||
this.roundScore = 0
|
||
this.UnmarkPass()
|
||
}
|
||
|
||
func (this *TienLenSceneData) IsTianhuPlayer(snid int32) bool {
|
||
for _, tianhusnid := range this.tianHuSnids {
|
||
if snid == tianhusnid {
|
||
return true
|
||
}
|
||
}
|
||
return false
|
||
}
|
||
|
||
func (this *TienLenSceneData) IsWinPlayer(snid int32) bool {
|
||
for _, winSnid := range this.winSnids {
|
||
if snid == winSnid {
|
||
return true
|
||
}
|
||
}
|
||
return false
|
||
}
|
||
|
||
// SystemCoinOut 系统投入产出都要扣税
|
||
func (this *TienLenSceneData) SystemCoinOut() int64 {
|
||
systemGain := int64(0)
|
||
taxRate := this.GetDBGameFree().GetTaxRate()
|
||
for i := 0; i < this.GetPlayerNum(); i++ {
|
||
playerData := this.seats[i]
|
||
if playerData != nil && playerData.IsGameing() && playerData.IsRob {
|
||
gain := playerData.winCoin - playerData.bombScore
|
||
if playerData.bombScore > 0 && gain > 0 {
|
||
// 小结算赢,局结算都赢
|
||
systemGain += playerData.winCoin
|
||
} else if playerData.bombScore > 0 && gain < 0 {
|
||
// 小结算赢,局结算输
|
||
systemGain += playerData.bombScore - int64(float64(gain)*float64(10000-taxRate)/10000.0)
|
||
} else if playerData.bombScore < 0 && gain > 0 {
|
||
// 小结算输,局结算赢
|
||
systemGain += int64(float64(playerData.bombScore)*float64(10000-taxRate)/10000.0) + gain
|
||
} else if playerData.bombScore < 0 && gain < 0 {
|
||
// 小结算输,局结算输
|
||
systemGain += int64(float64(playerData.bombScore)*float64(10000-taxRate)/10000.0) + int64(float64(gain)*float64(10000-taxRate)/10000.0)
|
||
}
|
||
}
|
||
}
|
||
return systemGain
|
||
}
|