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])
			}
			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])
			}
			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])
		}
		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.PlatformConfigSingleton.Get(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.PlatformConfigSingleton.Get(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]))
			}
			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
}
