package gamelogic import ( "math/rand" "sort" "bet24.com/log" ) type correction struct { correctCard int correctType int suggestCards []int } type fakerInfo struct { handCards []int // 手牌 currentCard int // 当前轮次的出牌 winCardScore int // 每一小局赢牌得分 projects []SingleProject // 项目数据 correctionList []correction // 玩家出牌对错表 bigCards []int // 大牌 cardTypesRecord []int // 按照人的思维记录玩家所有牌花色是否有打完 outedCards []int // 玩家已出牌 consecutiveWinCardCount int // 连续赢牌次数 actionProb int // 机器人动作概率 } // 初始化数据 func (f *fakerInfo) initData() { f.handCards = []int{} f.winCardScore = 0 f.currentCard = CARD_COUNT f.projects = []SingleProject{} f.correctionList = []correction{} f.bigCards = []int{} f.cardTypesRecord = make([]int, 4) f.outedCards = make([]int, NORMAL_HOLD_CARD) f.consecutiveWinCardCount = 0 f.actionProb = 100 } // 初始化先判定玩家每个花色的牌都是存在的 func (f *fakerInfo) initCardTypesReccord() { for i := 0; i < CHAIR_COUNT; i++ { f.cardTypesRecord[i] = 1 } } // 更新某个花色牌已经不存在 func (f *fakerInfo) updataACardTypeToNotExist(cardType int) { if cardType >= CardType_Diamond && cardType <= CardType_Spade { f.cardTypesRecord[cardType] = 0 } } // 分析手牌中的项目,并做保存 func (f *fakerInfo) analysisProject(suit int) { cardList := make([]int, len(f.handCards)) copy(cardList, f.handCards) projects := []SingleProject{} for i := PROJECT_FOURHUNDRED; i >= PROJECT_SIRA; i-- { if suit == Suit_Hokum && i == PROJECT_FOURHUNDRED { continue } for n := 0; n < 2; n++ { cards, bInclude := isIncludeTheProject(cardList, i, suit) if bInclude { cardList = removeCards(cardList, cards) projects = append(projects, SingleProject{ Type: i, Score: value_project[i], Cards: cards, }) } } } if len(projects) > 0 { f.projects = projects } } func (f *fakerInfo) isExistTheCardInOutedCards(card int) bool { for i := 0; i < len(f.outedCards); i++ { if f.outedCards[i] == card { return true } } return false } // 检查是否有baloot项目 func (f *fakerInfo) haveBaloot(trumpType int) bool { haveTrumpQ := false haveTrumpK := false for i := 0; i < len(f.handCards); i++ { if f.handCards[i] == trumpType*8+CardValueQ { haveTrumpQ = true } if f.handCards[i] == trumpType*8+CardValueK { haveTrumpK = true } } return haveTrumpQ && haveTrumpK } // 从手牌中删除打出的牌,并记录每轮打出的牌 func (f *fakerInfo) removeCard(card int) { for i := 0; i < len(f.handCards); i++ { if f.handCards[i] == card { f.handCards = append(f.handCards[:i], f.handCards[i+1:]...) f.currentCard = card f.outedCards = append(f.outedCards, card) break } } } // 每轮打完牌后初始化压牌列表 func (f *fakerInfo) initBigCards(cards []int) { f.bigCards = []int{} if len(cards) > 0 { f.bigCards = append(f.bigCards, cards...) } } // 判断是否出的是压牌中的数据 func (f *fakerInfo) isOutBigCards(card int) bool { if len(f.bigCards) == 0 { return true } for i := 0; i < len(f.bigCards); i++ { if card == f.bigCards[i] { return true } } return false } // 每轮赢牌分累加 func (f *fakerInfo) addScore(score int) { f.winCardScore += score } // 获取项目得分 func (f *fakerInfo) getProjectScore() int { score := 0 for i := 0; i < len(f.projects); i++ { score += f.projects[i].Score } return score } // 在纠错模式下,检查玩家是否有不合法出牌 func (f *fakerInfo) haveWrongAction() bool { if len(f.correctionList) == 0 { return false } for i := 0; i < len(f.correctionList); i++ { if f.correctionList[i].correctCard != -1 { return true } } return false } // 纠错数据校验 func (f *fakerInfo) isWrongData(correctType int, cards []int) bool { wrongCard := CARD_COUNT for n := 0; n < len(cards); n++ { for i := 0; i < len(f.correctionList); i++ { if f.correctionList[i].correctCard == cards[n] && correctType == f.correctionList[i].correctType { wrongCard = cards[n] otherCard := CARD_COUNT for m := 0; m < len(cards); m++ { if cards[m] != wrongCard { otherCard = cards[m] break } } for j := 0; j < len(f.correctionList[i].suggestCards); j++ { if otherCard == f.correctionList[i].suggestCards[j] { return true } } } } } return false } func (f *fakerInfo) isExistTheCardTypeInHand(cardType int) bool { for i := 0; i < len(f.handCards); i++ { if getCardType(f.handCards[i]) == cardType { return true } } return false } type simulatorScene struct { suit int // 模式 roundType int // 当前圈牌色 trumpType int // 主牌花色,Sun或Ashkal模式下为CardType_Invalid buyChair int // 买牌位置 baseTimes int // 加倍分 isBO1 bool // 是否一把定胜负 isClose bool // 为true表示本局在每一轮第一个出牌时不能出主牌(除了手上全是主牌的情况) lastWinChair int // 最后一轮赢牌玩家 buyWinScore int // 买牌方赢分 gameOutCardHistory []int // 本轮已出的牌 fakers []fakerInfo // 玩家信息 } func newSimulatorScene() *simulatorScene { ss := new(simulatorScene) ss.fakers = make([]fakerInfo, CHAIR_COUNT) for i := 0; i < CHAIR_COUNT; i++ { ss.fakers[i].initData() } ss.roundType = CardType_Invalid ss.gameOutCardHistory = []int{} ss.trumpType = CardType_Invalid ss.suit = Suit_Invalid ss.buyChair = CHAIR_COUNT ss.baseTimes = 1 ss.isBO1 = false ss.lastWinChair = CHAIR_COUNT ss.buyWinScore = 0 ss.isClose = false return ss } /******************************** 模拟场景流程的函数 START ********************************/ // 初始化数据 func (ss *simulatorScene) initData(trumpType, suit, buyChair, baseTimes int, isBo1, isClose bool) { ss.trumpType = trumpType ss.suit = suit ss.buyChair = buyChair ss.baseTimes = baseTimes ss.isBO1 = isBo1 ss.isClose = isClose for i := 0; i < CHAIR_COUNT; i++ { ss.fakers[i].initCardTypesReccord() } } // 检查项目 func (ss *simulatorScene) checkProject() { for i := 0; i < CHAIR_COUNT; i++ { ss.fakers[i].analysisProject(ss.suit) } } // 比较项目 func (ss *simulatorScene) compareProject() { buyProject := []SingleProject{} playerProject := []SingleProject{} for i := 0; i < CHAIR_COUNT; i++ { if len(ss.fakers[i].projects) == 0 { continue } if isSameTeam(i, ss.buyChair) { buyProject = append(buyProject, ss.fakers[i].projects[0]) } else { playerProject = append(playerProject, ss.fakers[i].projects[0]) } } if len(buyProject) == 0 || len(playerProject) == 0 { return } // 从大到小排序 sort.Slice(buyProject, func(i, j int) bool { return buyProject[i].isBiggerThan(buyProject[j]) }) sort.Slice(playerProject, func(i, j int) bool { return playerProject[i].isBiggerThan(playerProject[j]) }) isBuyTeamBig := buyProject[0].isBiggerThan(playerProject[0]) for i := 0; i < CHAIR_COUNT; i++ { if len(ss.fakers[i].projects) == 0 { continue } if isSameTeam(i, ss.buyChair) { if !isBuyTeamBig { ss.fakers[i].projects = []SingleProject{} } } else { if isBuyTeamBig { ss.fakers[i].projects = []SingleProject{} } } } } // 获取已出牌玩家人数 func (ss *simulatorScene) getRoundOutedPlayerCount() int { outedCount := 0 for _, v := range ss.fakers { if v.currentCard != CARD_COUNT { outedCount++ } } return outedCount } // 获取每轮出牌 func (ss *simulatorScene) getRoundCards() []int { ret := make([]int, CHAIR_COUNT) for i := 0; i < CHAIR_COUNT; i++ { ret[i] = ss.fakers[i].currentCard } return ret } // 获取每轮出牌赢家 func (ss *simulatorScene) getWinner(outCards []int, referType int) int { ranks := make([]int, CHAIR_COUNT) winner := -1 bestRank := -2 for i := 0; i < CHAIR_COUNT; i++ { ranks[i] = ss.getCardRank(outCards[i], referType) if ranks[i] > bestRank { bestRank = ranks[i] winner = i } } return winner } // 判断每轮是否出牌结束 func (ss *simulatorScene) isRoundEnd() bool { return ss.getRoundOutedPlayerCount() == CHAIR_COUNT } func (ss *simulatorScene) haveWrongAction(correctMode, sawaChair int) bool { if correctMode == Correct_Sawa { for n := 0; n < CHAIR_COUNT; n++ { if n == sawaChair { continue } for i := 0; i < len(ss.fakers[sawaChair].handCards); i++ { card := ss.fakers[sawaChair].handCards[i] if !ss.isBiggerThanAll(card, getCardType(card), ss.fakers[n].handCards) { return true } } } return false } for i := 0; i < CHAIR_COUNT; i++ { if ss.fakers[i].haveWrongAction() { return true } } return false } func (ss *simulatorScene) checkWrongActionInSawa(sawaChair int, cards []int) int { sawaCount := 0 sawaCard := CARD_COUNT otherCard := CARD_COUNT for i := 0; i < len(cards); i++ { for n := 0; n < len(ss.fakers[sawaChair].handCards); n++ { if cards[i] == ss.fakers[sawaChair].handCards[n] { sawaCount++ sawaCard = cards[i] break } } } if sawaCount != 1 { return 0 } for i := 0; i < len(cards); i++ { if sawaCard != cards[i] { otherCard = cards[i] break } } for i := 0; i < CHAIR_COUNT; i++ { if i == sawaChair { continue } for n := 0; n < len(ss.fakers[i].handCards); n++ { if otherCard == ss.fakers[i].handCards[n] { if ss.getCardRank(sawaCard, getCardType(sawaCard)) < ss.getCardRank(otherCard, getCardType(sawaCard)) { return 1 } else { return 0 } } } } return 0 } func (ss *simulatorScene) checkWrongActionInNormal(whose, correctType int, cards []int) int { wrongChair := CHAIR_COUNT for i := 0; i < CHAIR_COUNT; i++ { if !ss.fakers[i].haveWrongAction() { continue } if ss.fakers[i].isWrongData(correctType, cards) { wrongChair = i break } } if !isValidChair(wrongChair) { return 0 } if !isSameTeam(wrongChair, whose) { return 1 } return 0 } // 每一轮结束,计算得分和赢家 func (ss *simulatorScene) endAOutCardRound(winner int) { winScore := 0 for i := 0; i < CHAIR_COUNT; i++ { score := getCardPoint(ss.fakers[i].currentCard, ss.trumpType) winScore += score ss.gameOutCardHistory = append(ss.gameOutCardHistory, ss.fakers[i].currentCard) ss.fakers[i].currentCard = CARD_COUNT ss.fakers[i].initBigCards([]int{}) } for i := 0; i < CHAIR_COUNT; i++ { if i == winner { ss.fakers[i].addScore(winScore) } } ss.roundType = CardType_Invalid ss.lastWinChair = winner } // 是否小局结束 func (ss *simulatorScene) isGameEnd() bool { for _, v := range ss.fakers { if len(v.handCards) > 0 { return false } } return true } // 获取必压的大牌 func (ss *simulatorScene) getCanOutCards(chairId int, isFriendCallBiggest bool) []int { bigCards := []int{} ss.fakers[chairId].bigCards = []int{} // 1.我方队友出大牌 // 2.不打有主模式 // 3.玩家第一个出牌 // 以上不去限制玩家出牌 if isFriendCallBiggest || ss.suit != Suit_Hokum || ss.roundType == CardType_Invalid { return bigCards } // 4.队友目前赢牌 不去限制玩家出牌 winner := ss.getWinner(ss.getRoundCards(), ss.roundType) if isSameTeam(chairId, winner) { return bigCards } // 5.敌方目前赢牌,这轮出牌的roundType为副牌,当前玩家手上还有相同花色的牌,不去限制玩家出牌 sortedCards := sortCards(ss.fakers[chairId].handCards) if ss.roundType != ss.trumpType && len(sortedCards[ss.roundType]) > 0 { return bigCards } biggestCard := ss.fakers[winner].currentCard r := ss.getCardRank(biggestCard, ss.roundType) for i := 0; i < len(ss.fakers[chairId].handCards); i++ { r1 := ss.getCardRank(ss.fakers[chairId].handCards[i], ss.roundType) if r1 > r { bigCards = append(bigCards, ss.fakers[chairId].handCards[i]) } } return bigCards } // 模拟结算,看买牌输赢 func (ss *simulatorScene) calcBuyWinScore() { buyPoint := 0 playerPoint := 0 buyWinCardScore := 0 playerWinCardScore := 0 for i := 0; i < CHAIR_COUNT; i++ { if isSameTeam(i, ss.buyChair) { buyPoint += ss.fakers[i].getProjectScore() buyPoint += ss.fakers[i].winCardScore buyWinCardScore += ss.fakers[i].winCardScore } else { playerPoint += ss.fakers[i].getProjectScore() playerPoint += ss.fakers[i].winCardScore playerWinCardScore += ss.fakers[i].winCardScore } } ss.fakers[ss.lastWinChair].winCardScore += LAST_WIN_SCORE if isSameTeam(ss.buyChair, ss.lastWinChair) { buyPoint += LAST_WIN_SCORE buyWinCardScore += LAST_WIN_SCORE } else { playerPoint += LAST_WIN_SCORE playerWinCardScore += LAST_WIN_SCORE } playerAbnat := playerPoint // 如果买的一方输的情况 if (buyPoint == playerPoint && (ss.baseTimes > 1 || ss.isBO1)) || buyPoint < playerPoint { playerPoint += buyPoint if ss.fakers[ss.buyChair].winCardScore == 0 { playerPoint += ALL_WIN_EXTRA_SCORE } buyPoint = 0 } else { if ss.fakers[getNextChair(ss.buyChair)].winCardScore == 0 { buyPoint += ALL_WIN_EXTRA_SCORE playerPoint = 0 } if ss.isBO1 || ss.baseTimes > 1 { buyPoint += playerAbnat playerPoint = 0 } } finalBuyPoint := calcFinalPonit(buyPoint) finalPlayerPoint := calcFinalPonit(playerPoint) if ss.suit != Suit_Hokum { finalBuyPoint *= 2 finalPlayerPoint *= 2 if buyWinCardScore%10 == 5 && playerWinCardScore%10 == 5 && buyPoint > 0 && playerPoint > 0 { finalBuyPoint++ finalPlayerPoint++ } } else { if buyWinCardScore%10 == 6 && playerWinCardScore%10 == 6 && buyPoint > 0 && playerPoint > 0 { finalPlayerPoint-- } } finalBuyPoint *= ss.baseTimes finalPlayerPoint *= ss.baseTimes if ss.isBO1 { if finalBuyPoint > finalPlayerPoint { finalBuyPoint = SCORE_TO_WIN finalPlayerPoint = 0 } else { finalBuyPoint = 0 finalPlayerPoint = SCORE_TO_WIN } } ss.buyWinScore = finalBuyPoint - finalPlayerPoint } func (ss *simulatorScene) isWinScoreBigThanFriend() bool { return (ss.fakers[ss.buyChair].winCardScore - ss.fakers[getFriendChair(ss.buyChair)].winCardScore) >= 40 } func (ss *simulatorScene) calcProject() { ss.checkProject() ss.compareProject() if ss.suit == Suit_Hokum { for i := 0; i < CHAIR_COUNT; i++ { if ss.fakers[i].haveBaloot(ss.trumpType) { ss.fakers[i].projects = append(ss.fakers[i].projects, SingleProject{ Type: PROJECT_BALOOT, Score: value_project[PROJECT_BALOOT], Cards: []int{genACard(ss.trumpType, CardValueQ), genACard(ss.trumpType, CardValueK)}, }) break } } } } // 开始模拟出牌场景,得出最终得分,走的机器人出牌策略 func (ss *simulatorScene) startSimulatorScene(startChair int, isQuickOrLadder bool) { ss.calcProject() outCardChair := startChair for { outCard := ss.getBestOutCard(outCardChair, isQuickOrLadder) if !isValidCard(outCard) { ss.dump(outCardChair) if len(ss.fakers[outCardChair].bigCards) > 0 { outCard = ss.fakers[outCardChair].bigCards[0] } else { outCard = ss.worstCard(outCardChair) } } if !isValidCard(outCard) { return } ss.fakers[outCardChair].removeCard(outCard) if ss.roundType != CardType_Invalid && getCardType(outCard) != ss.roundType { ss.fakers[outCardChair].updataACardTypeToNotExist(ss.roundType) } if ss.roundType == CardType_Invalid { ss.roundType = getCardType(outCard) } if ss.isRoundEnd() { outCards := ss.getRoundCards() winner := ss.getWinner(outCards, ss.roundType) ss.endAOutCardRound(winner) outCardChair = winner } else { outCardChair = getPreviousChair(outCardChair) isFriendCallBiggest := false if ss.suit == Suit_Hokum && ss.getRoundOutedPlayerCount() == 2 { card := ss.fakers[getFriendChair(outCardChair)].currentCard if isValidCard(card) && getCardType(card) != ss.trumpType { if !isBiggestCard(card, ss.trumpType) { if isScoreCard(card, []int{}, ss.gameOutCardHistory, ss.trumpType) { isFriendCallBiggest = true } } else { isFriendCallBiggest = true } } } bigCards := ss.getCanOutCards(outCardChair, isFriendCallBiggest) ss.fakers[outCardChair].initBigCards(bigCards) } if ss.isGameEnd() { break } } ss.calcBuyWinScore() } /******************************** 模拟场景流程的函数 END ********************************/ /******************************** 辅助计算函数 START ********************************/ func (ss *simulatorScene) getCardRank(card int, referType int) int { if !isValidCard(card) { return -2 } cardType := getCardType(card) cardScore := 0 if cardType == ss.trumpType { cardScore += 100 } else if cardType != referType { return -1 } value := getCardCompareValue(card, ss.trumpType) return cardScore + value } func (ss *simulatorScene) worstCard(chairId int) int { if len(ss.fakers[chairId].handCards) == 0 { return CARD_COUNT } if len(ss.fakers[chairId].handCards) == 1 { return ss.fakers[chairId].handCards[0] } // 先按花色存储 sortedCards := sortCards(ss.fakers[chairId].handCards) if ss.roundType != CardType_Invalid && len(sortedCards[ss.roundType]) > 0 { return sortedCards[ss.roundType][0] } typeCounts := make([]int, 4) minIndex := -1 minCount := 8 maxIndex := -1 maxCount := 0 for i := 0; i < len(typeCounts); i++ { typeCounts[i] = len(sortedCards[i]) if i == ss.trumpType || typeCounts[i] == 0 { continue } if typeCounts[i] < minCount { minCount = typeCounts[i] minIndex = i } if typeCounts[i] > maxCount { maxCount = typeCounts[i] maxIndex = i } } // 如果我有主,则丢一张最少花色的牌 否则丢最多花色的牌 if ss.trumpType == CardType_Invalid { if maxIndex > 0 { return sortedCards[maxIndex][0] } return ss.fakers[chairId].handCards[0] } if typeCounts[ss.trumpType] == 0 { if maxIndex > 0 { return sortedCards[maxIndex][0] } } else { if minIndex >= 0 { if ss.isClose && minIndex == ss.trumpType && ss.roundType == CardType_Invalid { for i := 0; i < len(ss.fakers[chairId].handCards); i++ { if getCardType(ss.fakers[chairId].handCards[i]) != ss.trumpType { return ss.fakers[chairId].handCards[i] } } } else { return sortedCards[minIndex][0] } } } return ss.fakers[chairId].handCards[0] } func (ss *simulatorScene) isBiggerThanAll(card int, cardType int, cards []int) bool { r := ss.getCardRank(card, cardType) for _, v := range cards { if !isValidCard(v) { continue } if r <= ss.getCardRank(v, cardType) { return false } } return true } func (ss *simulatorScene) canOut(card int, cardType int, handCards []int) bool { found := false for _, v := range handCards { if v == card { found = true } } if !found { return false } if cardType == CardType_Invalid { return true } t := getCardType(card) if t == cardType { return true } foundSameType := false for _, v := range handCards { if cardType == getCardType(v) { foundSameType = true } } return !foundSameType } func (ss *simulatorScene) getMaxValueCardInCards(cards []int, isNeedOutBigCard bool) int { outCard := CARD_COUNT maxCardValue := -1 for i := 0; i < len(cards); i++ { value := getCardPoint(cards[i], ss.trumpType) if value > maxCardValue && (!isBiggestCard(cards[i], ss.trumpType) || isNeedOutBigCard) { maxCardValue = value outCard = cards[i] } } if isValidCard(outCard) { return outCard } for i := 0; i < len(cards); i++ { value := getCardPoint(cards[i], ss.trumpType) if value > maxCardValue { maxCardValue = value outCard = cards[i] } } return outCard } func (ss *simulatorScene) getMinValueCardInCards(cards []int) int { outCard := CARD_COUNT minCardValue := 100 for i := 0; i < len(cards); i++ { value := getCardPoint(cards[i], ss.trumpType) if value < minCardValue { minCardValue = value outCard = cards[i] } } return outCard } func (ss *simulatorScene) getCardsExpectMaxCardsInBigCards(bigCards, maxCards []int) []int { cards := []int{} for i := 0; i < len(bigCards); i++ { bFound := false for j := 0; j < len(maxCards); j++ { if bigCards[i] == maxCards[j] { bFound = true break } } if !bFound { cards = append(cards, bigCards[i]) } } return cards } func (ss *simulatorScene) canOutMiniCardWhileFirstOut(cards []int, chairId int) bool { if len(cards) != 2 { return true } isExistTen := false otherCard := 0 for i := 0; i < len(cards); i++ { if getCardValue(cards[i]) == CardValue10 { isExistTen = true } else { otherCard = cards[i] } } if !isExistTen { return true } isEmenyExistA := false isEmenyExistBigThanOther := false for j := 0; j < CHAIR_COUNT; j++ { if isSameTeam(j, chairId) { continue } for n := 0; n < len(ss.fakers[j].handCards); n++ { if getCardType(otherCard) == getCardType(ss.fakers[j].handCards[n]) && getCardValue(ss.fakers[j].handCards[n]) == CardValueA { isEmenyExistA = true } if getCardType(otherCard) == getCardType(ss.fakers[j].handCards[n]) && getCardValue(ss.fakers[j].handCards[n]) != CardValueA && getCardPoint(ss.fakers[j].handCards[n], ss.trumpType) > getCardPoint(otherCard, ss.trumpType) { isEmenyExistBigThanOther = true } } } return (!isEmenyExistA || !isEmenyExistBigThanOther) } func (ss *simulatorScene) dump(whoseTurn int) { log.Debug("suit[%s], roundType[%d], trump[%d], isClose[%v], whoseTurn[%d]", getSuitDesc(ss.suit), ss.roundType, ss.trumpType, ss.isClose, whoseTurn) log.Debug("gameOutCardHistory:%s", getCardsHex(ss.gameOutCardHistory)) log.Debug("OutedCardCount:[%d]", ss.getRoundOutedPlayerCount()) for i := 0; i < CHAIR_COUNT; i++ { if isValidCard(ss.fakers[i].currentCard) { log.Debug("chair[%d], currentCard[%s], handCards:%s", i, getCardHex(ss.fakers[i].currentCard), getCardsHex(ss.fakers[i].handCards)) } else { log.Debug("chair[%d], handCards%s", i, getCardsHex(ss.fakers[i].handCards)) } if i == whoseTurn { log.Debug("bigCards:%s", getCardsHex(ss.fakers[i].bigCards)) } } } /******************************** 辅助计算函数 END ********************************/ /******************************** 机器人出牌策略 START ********************************/ func (ss *simulatorScene) getBestOutCard(chairId int, isQuickOrLadder bool) int { outCard := ss.getOutCardWhileLastCardIsBiggest(chairId, isQuickOrLadder) if isValidCard(outCard) { return outCard } if ss.suit != Suit_Hokum { outCard = ss.getBestOutCardInSun(chairId) } else { outCard = ss.getBestOutCardInHokum(chairId) } return outCard } // 在Hokum模式下,获取能保证最后一手牌得分的出牌 func (ss *simulatorScene) getOutCardWhileLastCardIsBiggest(chairId int, isQuickOrLadder bool) int { isPenult := len(ss.fakers[chairId].handCards) == 2 && ss.suit == Suit_Hokum && (len(ss.fakers[chairId].bigCards) == 0 || len(ss.fakers[chairId].bigCards) == 2) if !isPenult { return CARD_COUNT } for i := 0; i < len(ss.fakers[chairId].handCards); i++ { isBiggest := true card := ss.fakers[chairId].handCards[i] if getCardType(card) != ss.trumpType { continue } for n := 0; n < CHAIR_COUNT; n++ { if isSameTeam(n, chairId) { continue } if !ss.isBiggerThanAll(card, ss.trumpType, ss.fakers[n].handCards) { isBiggest = false break } } if isBiggest { for n := 0; n < len(ss.fakers[chairId].handCards); n++ { outCard := ss.fakers[chairId].handCards[n] if outCard == card { continue } if ss.canOut(outCard, ss.roundType, ss.fakers[chairId].handCards) { if !isQuickOrLadder { return outCard } outCards := ss.getRoundCards() outCards[chairId] = outCard roundType := ss.roundType if roundType == CardType_Invalid { roundType = getCardType(outCard) } for j := 0; j < CHAIR_COUNT; j++ { if outCards[j] == CARD_COUNT { outCards[j] = ss.getMaxCanOutCardInHokum(roundType, j) } } if isSameTeam(chairId, ss.getWinner(outCards, roundType)) { return outCard } if !ss.isNeedConsecutiveWin(chairId) { return outCard } } } } } return CARD_COUNT } func (ss *simulatorScene) getMaxCanOutCardInHokum(cardType, chairId int) int { sortedCards := sortCards(ss.fakers[chairId].handCards) if len(sortedCards[cardType]) > 0 { maxValue := -1 card := CARD_COUNT for i := 0; i < len(sortedCards[cardType]); i++ { v := getCardCompareValue(sortedCards[cardType][i], ss.trumpType) if v > maxValue { card = sortedCards[cardType][i] maxValue = v } } return card } if len(sortedCards[ss.trumpType]) == 0 { return ss.fakers[chairId].handCards[0] } maxValue := -1 card := CARD_COUNT for i := 0; i < len(sortedCards[ss.trumpType]); i++ { v := getCardCompareValue(sortedCards[ss.trumpType][i], ss.trumpType) if v > maxValue { card = sortedCards[ss.trumpType][i] maxValue = v } } return card } func (ss *simulatorScene) isNeedConsecutiveWin(chairId int) bool { if ss.fakers[chairId].consecutiveWinCardCount < 4 { return false } ourScore := 0 emeneyScore := 0 for i := 0; i < CHAIR_COUNT; i++ { if isSameTeam(i, chairId) { ourScore += ss.fakers[i].getProjectScore() ourScore += ss.fakers[i].winCardScore } else { emeneyScore += ss.fakers[i].getProjectScore() emeneyScore += ss.fakers[i].winCardScore } } return ss.fakers[chairId].winCardScore > 81 && ourScore > emeneyScore } /****************************** Sun START ******************************/ func (ss *simulatorScene) getBestOutCardInSun(chairId int) int { outCard := CARD_COUNT outedCount := ss.getRoundOutedPlayerCount() r := rand.Intn(100) if outedCount == 0 { priorityList := []int{1, 1, 1, 1} for i := CardType_Diamond; i <= CardType_Spade; i++ { if ss.fakers[getFriendChair(chairId)].isExistTheCardInOutedCards(genACard(i, CardValueA)) { priorityList[i] = 2 } else { if ss.fakers[getFriendChair(chairId)].isExistTheCardInOutedCards(genACard(i, CardValue10)) { priorityList[i] = 0 } } } // 自己得分,找到敌方两人都要不起的所有大牌 bigCards := ss.getBigCardsThanAllEnemyHandCardsInSun(chairId, ss.roundType) if len(bigCards) > 0 { for l := 2; l >= 0; l-- { cards := []int{} for i := 0; i < len(bigCards); i++ { if priorityList[getCardType(bigCards[i])] == l { cards = append(cards, bigCards[i]) } } if len(cards) > 0 { return cards[rand.Intn(len(cards))] } } return bigCards[rand.Intn(len(bigCards))] } if r < ss.fakers[chairId].actionProb { // 队友得分,找到敌方两人都要不起的所有大牌,并找出对应的花色中最大牌值的牌 bigCards = ss.getBigCardsThanAllEnemyHandCardsInSun(getFriendChair(chairId), ss.roundType) if len(bigCards) > 0 { for l := 2; l >= 0; l-- { cards := []int{} for i := 0; i < len(bigCards); i++ { if priorityList[getCardType(bigCards[i])] == l { cards = append(cards, bigCards[i]) } } if len(cards) == 0 { continue } outCard = ss.getMinValueCardWhileFriendHaveBigCardsInSun(chairId, cards) if isValidCard(outCard) { break } } } } } else if outedCount == 1 { // 自己得分 enemyChairOfNotOutCard := getPreviousChair(chairId) outCard = ss.getOutCardWhileSelfCanWinInSun(chairId, enemyChairOfNotOutCard) if isValidCard(outCard) { return outCard } if r < ss.fakers[chairId].actionProb { // 队友得分 outCard = ss.getOutCardWhileFriendCanWinInSun(chairId) } } else if outedCount == 2 || outedCount == 3 { // 队友得分 outCard = ss.getOutCardWhileFriendCanWinInSun(chairId) if isValidCard(outCard) { return outCard } // 自己得分 enemyChairOfNotOutCard := getPreviousChair(chairId) if outedCount == 3 { enemyChairOfNotOutCard = -1 } if r < ss.fakers[chairId].actionProb { outCard = ss.getOutCardWhileSelfCanWinInSun(chairId, enemyChairOfNotOutCard) } } // 不得分 if !isValidCard(outCard) { outCard = ss.getMinValueCardInSun(chairId) } return outCard } func (ss *simulatorScene) getBigCardsThanAllEnemyHandCardsInSun(chairId, roundType int) []int { bigCards := []int{} for i := 0; i < len(ss.fakers[chairId].handCards); i++ { card := ss.fakers[chairId].handCards[i] cardType := roundType if roundType == CardType_Invalid { cardType = getCardType(card) } isAllBig := true for n := 0; n < CHAIR_COUNT; n++ { //if isSameTeam(n, chairId) { if n == chairId { continue } if !ss.isBiggerThanAll(card, cardType, ss.fakers[n].handCards) { isAllBig = false break } } if isAllBig { bigCards = append(bigCards, card) } } return bigCards } /* 暂时做屏蔽,先取getMinValueCardWhileFriendHaveBigCardsInSun让机器人做正常思维 func (ss *simulatorScene) getMaxValueCardWhileFriendHaveBigCardsInSun(chairId int, bigCards []int) int { outCard := CARD_COUNT maxCardValue := -1 for i := 0; i < len(bigCards); i++ { for j := 0; j < len(ss.fakers[chairId].handCards); j++ { if getCardType(ss.fakers[chairId].handCards[j]) != getCardType(bigCards[i]) { continue } value := getCardCompareValue(ss.fakers[chairId].handCards[j], ss.trumpType) if value > maxCardValue { maxCardValue = value outCard = ss.fakers[chairId].handCards[j] } } } return outCard } */ func (ss *simulatorScene) getMinValueCardWhileFriendHaveBigCardsInSun(chairId int, bigCards []int) int { outCard := CARD_COUNT minCardValue := 100 for i := 0; i < len(bigCards); i++ { for j := 0; j < len(ss.fakers[chairId].handCards); j++ { if getCardType(ss.fakers[chairId].handCards[j]) != getCardType(bigCards[i]) { continue } value := getCardCompareValue(ss.fakers[chairId].handCards[j], ss.trumpType) if value < minCardValue && getCardValue(ss.fakers[chairId].handCards[j]) != CardValue10 { minCardValue = value outCard = ss.fakers[chairId].handCards[j] } } } return outCard } func (ss *simulatorScene) getOutCardWhileSelfCanWinInSun(chairId, enemyChairOfNotOutCard int) int { bigCards := ss.getBigCardsThanOutCardsInSun(chairId) if len(bigCards) == 0 { return CARD_COUNT } newBigCards := []int{} if enemyChairOfNotOutCard == -1 { newBigCards = append(newBigCards, bigCards...) } else { for i := 0; i < len(bigCards); i++ { if ss.isBiggerThanAll(bigCards[i], ss.roundType, ss.fakers[enemyChairOfNotOutCard].handCards) { newBigCards = append(newBigCards, bigCards[i]) } } } if len(newBigCards) == 0 { return CARD_COUNT } maxCards := []int{} if enemyChairOfNotOutCard == -1 { maxCards = ss.getBigCardsThanAllEnemyHandCardsInSun(chairId, ss.roundType) } else { enemyChairOfOutedCard := getFriendChair(enemyChairOfNotOutCard) for i := 0; i < len(newBigCards); i++ { if ss.isBiggerThanAll(newBigCards[i], ss.roundType, ss.fakers[enemyChairOfOutedCard].handCards) { maxCards = append(maxCards, newBigCards[i]) } } } if len(maxCards) == 0 { return ss.getMaxValueCardInCards(newBigCards, true) } cards := ss.getCardsExpectMaxCardsInBigCards(newBigCards, maxCards) if len(cards) == 0 { return newBigCards[0] } return ss.getMaxValueCardInCards(cards, true) } func (ss *simulatorScene) getBigCardsThanOutCardsInSun(chairId int) []int { bigCards := []int{} for i := 0; i < len(ss.fakers[chairId].handCards); i++ { if getCardType(ss.fakers[chairId].handCards[i]) != ss.roundType { continue } if ss.isBiggerThanAll(ss.fakers[chairId].handCards[i], ss.roundType, ss.getRoundCards()) { bigCards = append(bigCards, ss.fakers[chairId].handCards[i]) } } return bigCards } func (ss *simulatorScene) getOutCardWhileFriendCanWinInSun(chairId int) int { outCards := ss.getRoundCards() isFriendBig := false if outCards[getFriendChair(chairId)] == CARD_COUNT { if ss.isBiggerThanAll(outCards[getNextChair(chairId)], ss.roundType, ss.fakers[getFriendChair(chairId)].handCards) { return CARD_COUNT } for i := 0; i < len(ss.fakers[getFriendChair(chairId)].handCards); i++ { if getCardType(ss.fakers[getFriendChair(chairId)].handCards[i]) != ss.roundType { continue } if ss.isBiggerThanAll(ss.fakers[getFriendChair(chairId)].handCards[i], ss.roundType, ss.fakers[getPreviousChair(chairId)].handCards) { isFriendBig = true break } } } else { winner := ss.getWinner(outCards, ss.roundType) if !isSameTeam(winner, chairId) { return CARD_COUNT } if outCards[getPreviousChair(chairId)] != CARD_COUNT { isFriendBig = true } else { if ss.isBiggerThanAll(outCards[getFriendChair(chairId)], ss.roundType, ss.fakers[getPreviousChair(chairId)].handCards) { isFriendBig = true } } } if !isFriendBig { return CARD_COUNT } if ss.getRoundOutedPlayerCount() < 3 { return ss.getMinValueCardInSun(chairId) } cardType := ss.roundType bRoundType := true sortedCards := sortCards(ss.fakers[chairId].handCards) if len(sortedCards[ss.roundType]) == 0 { cardType = CardType_Invalid bRoundType = false } bigCards := ss.getBigCardsThanAllEnemyHandCardsInSun(chairId, cardType) return ss.getMaxValueCardExpectBigCardsInSun(chairId, bigCards, bRoundType) } func (ss *simulatorScene) getMaxValueCardExpectBigCardsInSun(chairId int, bigCards []int, haveRoundType bool) int { outCard := CARD_COUNT maxValue := -1 for i := 0; i < len(ss.fakers[chairId].handCards); i++ { card := ss.fakers[chairId].handCards[i] if getCardType(card) != ss.roundType && haveRoundType { continue } bFound := false for j := 0; j < len(bigCards); j++ { if card == bigCards[j] { bFound = true break } } if !bFound { value := getCardPoint(card, ss.trumpType) if value > maxValue { maxValue = value outCard = card } } } return outCard } func (ss *simulatorScene) getMinValueCardInSun(chairId int) int { minCardValue := 100 card := CARD_COUNT if ss.roundType == CardType_Invalid && len(ss.fakers[chairId].handCards) > 2 { sortedCard := sortCards(ss.fakers[chairId].handCards) for j := 0; j < len(ss.fakers[chairId].handCards); j++ { if len(sortedCard[getCardType(ss.fakers[chairId].handCards[j])]) == 2 && !ss.canOutMiniCardWhileFirstOut(sortedCard[getCardType(ss.fakers[chairId].handCards[j])], chairId) { continue } value := getCardPoint(ss.fakers[chairId].handCards[j], ss.trumpType) if value < minCardValue { minCardValue = value card = ss.fakers[chairId].handCards[j] } } if isValidCard(card) { return card } } for j := 0; j < len(ss.fakers[chairId].handCards); j++ { if getCardType(ss.fakers[chairId].handCards[j]) != ss.roundType { continue } value := getCardPoint(ss.fakers[chairId].handCards[j], ss.trumpType) if value < minCardValue { minCardValue = value card = ss.fakers[chairId].handCards[j] } } if isValidCard(card) { return card } if ss.roundType == CardType_Invalid { priorityList := []int{1, 1, 1, 1} for i := CardType_Diamond; i <= CardType_Spade; i++ { if ss.fakers[getFriendChair(chairId)].isExistTheCardInOutedCards(genACard(i, CardValueA)) { priorityList[i] = 2 } else { if ss.fakers[getFriendChair(chairId)].isExistTheCardInOutedCards(genACard(i, CardValue10)) { priorityList[i] = 0 } } } for l := 2; l >= 0; l-- { for i := 0; i < len(ss.fakers[chairId].handCards); i++ { if priorityList[getCardType(ss.fakers[chairId].handCards[i])] == l { value := getCardPoint(ss.fakers[chairId].handCards[i], ss.trumpType) if value < minCardValue { minCardValue = value card = ss.fakers[chairId].handCards[i] } } } if isValidCard(card) { return card } } } for j := 0; j < len(ss.fakers[chairId].handCards); j++ { value := getCardPoint(ss.fakers[chairId].handCards[j], ss.trumpType) if value < minCardValue { minCardValue = value card = ss.fakers[chairId].handCards[j] } } return card } /****************************** Sun End ******************************/ /****************************** Hokum START ******************************/ func (ss *simulatorScene) getBestOutCardInHokum(chairId int) int { outCard := CARD_COUNT outedCount := ss.getRoundOutedPlayerCount() r := rand.Intn(100) if outedCount == 0 { // 先出主牌大牌 trumpBigCards := ss.getBigCardsThanAllEnemyHandCardsInHokum(chairId, ss.trumpType, ss.isClose, !ss.isClose, true) maxTrumpCards := []int{} for n := 0; n < len(trumpBigCards); n++ { if ss.isBiggerThanAll(trumpBigCards[n], ss.trumpType, ss.fakers[getFriendChair(chairId)].handCards) { maxTrumpCards = append(maxTrumpCards, trumpBigCards[n]) } } if len(maxTrumpCards) > 0 && !ss.isClose && ss.isOtherPlayerHaveTrumpCardInHokum(chairId) { return maxTrumpCards[rand.Intn(len(maxTrumpCards))] } // 自己得分 bigCards := ss.getBigCardsThanAllEnemyHandCardsInHokum(chairId, CardType_Invalid, ss.isClose, !ss.isClose, true) if len(bigCards) > 0 { // 再出非主牌大牌 sortedCards := sortCards(bigCards) randStartType := rand.Intn(CHAIR_COUNT) for i := CardType_Diamond; i <= CardType_Spade; i++ { t := (randStartType + i) % CHAIR_COUNT if t == ss.trumpType || len(sortedCards[t]) == 0 { continue } if len(sortedCards[t]) == 1 { return sortedCards[t][0] } if !ss.canBigOnNextRoundInHokum(chairId, t) { return ss.getMaxValueCardInCards(sortedCards[t], true) } else { return sortedCards[t][rand.Intn(len(sortedCards[t]))] } } cardType := CardType_Invalid // 再去判断队友能大且是出非主牌 cardType = ss.getCardTypeWhileFriendCanWinInHokum(chairId) if cardType != CardType_Invalid && cardType != ss.trumpType { sortedCards := sortCards(ss.fakers[chairId].handCards) return ss.getMinValueCardInCards(sortedCards[cardType]) } // 最后出主牌大牌,如果敌方有主牌就出最小大牌 if ss.isEnemyExistTrumpTypeInHokum(chairId) { return bigCards[0] } else { return ss.getMinValueCardInHokum(chairId) } } if r < ss.fakers[chairId].actionProb { // 队友得分 cardType := ss.getCardTypeWhileFriendCanWinInHokum(chairId) if cardType != CardType_Invalid && (cardType != ss.trumpType || len(ss.fakers[chairId].handCards) < NORMAL_HOLD_CARD-1) { sortedCards := sortCards(ss.fakers[chairId].handCards) return ss.getMinValueCardInCards(sortedCards[cardType]) } } } else if outedCount == 1 { // 自己得分 outCard = ss.getOutCardWhileSelfCanWinInHokum(chairId) if isValidCard(outCard) { // 如果自己出的是主牌,则判断队友能否赢牌,且队友赢牌的出牌花色不为主牌花色 if getCardType(outCard) == ss.trumpType && ss.roundType != ss.trumpType { card, cardType := ss.getOutCardWhileFriendCanWinInHokum(chairId) if isValidCard(card) && cardType != ss.trumpType { return card } } return outCard } if r < ss.fakers[chairId].actionProb { // 队友得分 outCard, _ = ss.getOutCardWhileFriendCanWinInHokum(chairId) } } else if outedCount == 2 { // 队友得分 outCard, _ = ss.getOutCardWhileFriendCanWinInHokum(chairId) if isValidCard(outCard) { return outCard } if r < ss.fakers[chairId].actionProb { // 自己得分 outCard = ss.getOutCardWhileSelfCanWinInHokum(chairId) } } else if outedCount == 3 { // 队友得分 outCards := ss.getRoundCards() winner := ss.getWinner(outCards, ss.roundType) if isSameTeam(winner, chairId) { return ss.getOutCardWhileFriendIsWinnerInHokum(chairId) } if r < ss.fakers[chairId].actionProb { // 自己得分 outCard = ss.getOutCardWhileSelfCanWinInHokum(chairId) } } // 不得分 if !isValidCard(outCard) { outCard = ss.getMinValueCardInHokum(chairId) } return outCard } func (ss *simulatorScene) isOtherPlayerHaveTrumpCardInHokum(chairId int) bool { isEnemeyTrumpHaveRecord := false for i := 0; i < CHAIR_COUNT; i++ { if isSameTeam(chairId, i) { continue } if ss.fakers[i].cardTypesRecord[ss.trumpType] == 1 { isEnemeyTrumpHaveRecord = true } } if !isEnemeyTrumpHaveRecord { return false } for i := 0; i < CHAIR_COUNT; i++ { if i == chairId { continue } if ss.fakers[i].isExistTheCardTypeInHand(ss.trumpType) { return true } } return false } func (ss *simulatorScene) isEnemyExistTrumpTypeInHokum(chairId int) bool { for i := 0; i < CHAIR_COUNT; i++ { if isSameTeam(i, chairId) { continue } sortedCards := sortCards(ss.fakers[i].handCards) if len(sortedCards[ss.trumpType]) > 0 { return true } } return false } func (ss *simulatorScene) getBigCardsThanAllEnemyHandCardsInHokum(chairId, roundType int, isClose, isIncludeTrump, isCheckAllEnemy bool) []int { bigCards := []int{} handCards := []int{} if len(ss.fakers[chairId].bigCards) == 0 { handCards = append(handCards, ss.fakers[chairId].handCards...) } else { handCards = append(handCards, ss.fakers[chairId].bigCards...) } isAllTrump := true // 如果roundType为CardType_Invaild,则是先找非主牌花色中的大牌,如果roundType不为CardType_Invaild,则是找相同花色的大牌 for i := 0; i < len(handCards); i++ { if getCardType(handCards[i]) == ss.trumpType { continue } isAllTrump = false if roundType != CardType_Invalid && getCardType(handCards[i]) != roundType { continue } isAllBig := true for j := 0; j < CHAIR_COUNT; j++ { if isSameTeam(chairId, j) { //if j == chairId { continue } // 如果isCheckAllEnemy为true,则不找已出牌玩家 if ss.fakers[j].currentCard != CARD_COUNT && !isCheckAllEnemy { continue } sortedCards := sortCards(ss.fakers[j].handCards) if len(sortedCards[getCardType(handCards[i])]) == 0 && !isSameTeam(chairId, j) && len(sortedCards[ss.trumpType]) > 0 { isAllBig = false break } if !ss.isBiggerThanAll(handCards[i], getCardType(handCards[i]), sortedCards[getCardType(handCards[i])]) { isAllBig = false break } } if isAllBig { bigCards = append(bigCards, handCards[i]) } } if len(bigCards) > 0 { return bigCards } // 能否出主牌 if isClose && !isAllTrump { return bigCards } // 是否去找主牌 if !isIncludeTrump { return bigCards } // 去找主牌能否有大牌 for i := 0; i < len(handCards); i++ { if getCardType(handCards[i]) != ss.trumpType { continue } isAllBig := true for j := 0; j < CHAIR_COUNT; j++ { if isSameTeam(chairId, j) { //if chairId == j { continue } if ss.fakers[j].currentCard != CARD_COUNT && !isCheckAllEnemy { continue } sortedCards := sortCards(ss.fakers[j].handCards) if !ss.isBiggerThanAll(handCards[i], ss.trumpType, sortedCards[ss.trumpType]) { isAllBig = false break } } if isAllBig { bigCards = append(bigCards, handCards[i]) } } return bigCards } // 玩家首出情况下,获取队友可赢牌的花色 func (ss *simulatorScene) getCardTypeWhileFriendCanWinInHokum(chairId int) int { friendBigCards := ss.getBigCardsThanAllEnemyHandCardsInHokum(getFriendChair(chairId), CardType_Invalid, false, true, false) sortedCards := sortCards(ss.fakers[chairId].handCards) // 我出非主牌,队友出相同非主牌可赢 if len(friendBigCards) > 0 { for i := 0; i < len(friendBigCards); i++ { if getCardType(friendBigCards[i]) == ss.trumpType { continue } if len(sortedCards[getCardType(friendBigCards[i])]) == 1 && getCardValue(sortedCards[getCardType(friendBigCards[i])][0]) == CardValue10 { continue } if len(sortedCards[getCardType(friendBigCards[i])]) > 0 { return getCardType(friendBigCards[i]) } } } // 我出非主牌,队友出主牌可赢 friendSortedCards := sortCards(ss.fakers[getFriendChair(chairId)].handCards) if len(friendSortedCards[ss.trumpType]) == 0 { return CardType_Invalid } for cardType := CardType_Diamond; cardType <= CardType_Spade; cardType++ { if cardType == ss.trumpType { continue } if len(sortedCards[cardType]) == 0 { continue } if len(friendSortedCards[cardType]) > 0 { continue } // 队友出主牌大于敌方 if ss.isExistTrumpCardBiggerThanAllEmenyInHokum(friendSortedCards[ss.trumpType], chairId, cardType) { if len(sortedCards[cardType]) > 1 || getCardValue(sortedCards[cardType][0]) != CardValue10 { return cardType } } } // 我出主牌,队友出主牌可赢 if (ss.isClose && len(sortedCards[ss.trumpType]) != len(ss.fakers[chairId].handCards)) || len(sortedCards[ss.trumpType]) == 0 { return CardType_Invalid } for i := 0; i < len(friendBigCards); i++ { if getCardType(friendBigCards[i]) == ss.trumpType { if value_trump[getCardValue(sortedCards[ss.trumpType][0])] < value_trump[CardValue10] { return ss.trumpType } } } return CardType_Invalid } func (ss *simulatorScene) isExistTrumpCardBiggerThanAllEmenyInHokum(trumpCards []int, chairId, roundType int) bool { for i := 0; i < len(trumpCards); i++ { if getCardType(trumpCards[i]) != ss.trumpType { continue } isBig := true for n := 0; n < CHAIR_COUNT; n++ { if isSameTeam(chairId, n) { continue } sortedCards := sortCards(ss.fakers[n].handCards) if len(sortedCards[roundType]) > 0 || len(sortedCards[ss.trumpType]) == 0 { continue } if !ss.isBiggerThanAll(trumpCards[i], roundType, sortedCards[ss.trumpType]) { isBig = false break } } if isBig { return true } } return false } func (ss *simulatorScene) getOutCardWhileSelfCanWinInHokum(chairId int) int { outedCards := ss.getRoundCards() // 先找相同花色比未出牌敌方玩家大的牌 bigCards := ss.getBigCardsThanAllEnemyHandCardsInHokum(chairId, ss.roundType, false, ss.roundType == ss.trumpType, false) if len(bigCards) > 0 { // 再找比所有敌方玩家相同花色都大的牌 maxCards := ss.getBigCardsThanAllEnemyHandCardsInHokum(chairId, ss.roundType, false, ss.roundType == ss.trumpType, true) // 没出牌的敌方只剩最后一张牌,且有主牌,出最大牌或者出牌的玩家出的是最后一张牌 if ss.roundType != ss.trumpType && len(maxCards) > 0 { enemySortedCards1 := sortCards(ss.fakers[getPreviousChair(chairId)].handCards) enemySortedCards2 := sortCards(ss.fakers[getNextChair(chairId)].handCards) if (outedCards[getPreviousChair(chairId)] == CARD_COUNT && ((len(enemySortedCards1[ss.roundType]) == 1 && len(enemySortedCards1[ss.trumpType]) > 0) || (len(enemySortedCards2[ss.roundType]) == 0 && len(enemySortedCards2[ss.trumpType]) > 0))) || (outedCards[getPreviousChair(chairId)] != CARD_COUNT && ((len(enemySortedCards1[ss.roundType]) == 0 && len(enemySortedCards1[ss.trumpType]) > 0) || (len(enemySortedCards2[ss.roundType]) == 0 && len(enemySortedCards2[ss.trumpType]) > 0))) { maxValue := -1 outCard := CARD_COUNT for i := 0; i < len(maxCards); i++ { outedCards[chairId] = maxCards[i] if chairId == ss.getWinner(outedCards, ss.roundType) { value := getCardPoint(maxCards[i], ss.trumpType) if value > maxValue { maxValue = value outCard = maxCards[i] } } outedCards[chairId] = CARD_COUNT } if isValidCard(outCard) { return outCard } } } cards := ss.getCardsExpectMaxCardsInBigCards(bigCards, maxCards) if len(cards) > 0 { maxValue := -1 outCard := CARD_COUNT for i := 0; i < len(cards); i++ { outedCards[chairId] = cards[i] if chairId == ss.getWinner(outedCards, ss.roundType) { value := getCardPoint(cards[i], ss.trumpType) if value > maxValue { maxValue = value outCard = cards[i] } } outedCards[chairId] = CARD_COUNT } if isValidCard(outCard) { return outCard } } for i := 0; i < len(bigCards); i++ { outedCards[chairId] = bigCards[i] if chairId == ss.getWinner(outedCards, ss.roundType) { return bigCards[i] } outedCards[chairId] = CARD_COUNT } } handCards := []int{} if len(ss.fakers[chairId].bigCards) == 0 { handCards = append(handCards, ss.fakers[chairId].handCards...) } else { handCards = append(handCards, ss.fakers[chairId].bigCards...) } sortedCards := sortCards(handCards) if len(sortedCards[ss.roundType]) > 0 { return CARD_COUNT } if len(sortedCards[ss.trumpType]) == 0 { return CARD_COUNT } // 没有相同花色,roundType为非主牌,我有主牌大于未出牌的敌方 bigCards = ss.getTrumpCardBiggerThanAllEmenyInHokum(sortedCards[ss.trumpType], chairId, ss.roundType) if len(bigCards) > 0 { // 查找我是否主牌大于所有敌方玩家手牌 maxCards := ss.getBigCardsThanAllEnemyHandCardsInHokum(chairId, ss.trumpType, false, true, true) cards := ss.getCardsExpectMaxCardsInBigCards(bigCards, maxCards) if len(cards) > 0 { maxValue := -1 outCard := CARD_COUNT for i := 0; i < len(cards); i++ { outedCards[chairId] = cards[i] if chairId == ss.getWinner(outedCards, ss.roundType) { value := getCardPoint(cards[i], ss.trumpType) if value > maxValue { maxValue = value outCard = cards[i] } } outedCards[chairId] = CARD_COUNT } if isValidCard(outCard) { return outCard } } for i := 0; i < len(bigCards); i++ { outedCards[chairId] = bigCards[i] if chairId == ss.getWinner(outedCards, ss.roundType) { return bigCards[i] } outedCards[chairId] = CARD_COUNT } } return CARD_COUNT } func (ss *simulatorScene) getTrumpCardBiggerThanAllEmenyInHokum(trumpCards []int, chairId, roundType int) []int { bigCards := []int{} for i := 0; i < len(trumpCards); i++ { if getCardType(trumpCards[i]) != ss.trumpType { continue } isBig := true for n := 0; n < CHAIR_COUNT; n++ { if isSameTeam(chairId, n) { //if chairId == n { continue } if ss.fakers[n].currentCard != CARD_COUNT { continue } sortedCards := sortCards(ss.fakers[n].handCards) if roundType == ss.trumpType && len(sortedCards[ss.trumpType]) == 0 { continue } if (len(sortedCards[roundType]) > 0 || len(sortedCards[ss.trumpType]) == 0) && roundType != ss.trumpType { continue } if !ss.isBiggerThanAll(trumpCards[i], roundType, sortedCards[ss.trumpType]) { isBig = false break } } if isBig { bigCards = append(bigCards, trumpCards[i]) } } return bigCards } func (ss *simulatorScene) getOutCardWhileFriendCanWinInHokum(chairId int) (int, int) { outedCards := ss.getRoundCards() if outedCards[getFriendChair(chairId)] == CARD_COUNT { // 先找相同花色比未出牌玩家大的牌 bigCards := ss.getBigCardsThanAllEnemyHandCardsInHokum(getFriendChair(chairId), ss.roundType, false, ss.roundType == ss.trumpType, false) sortedCards := sortCards(ss.fakers[getFriendChair(chairId)].handCards) if len(bigCards) == 0 && len(sortedCards[ss.roundType]) > 0 { return CARD_COUNT, CardType_Invalid } for i := 0; i < len(bigCards); i++ { outedCards[getFriendChair(chairId)] = bigCards[i] if getFriendChair(chairId) == ss.getWinner(outedCards, ss.roundType) { return ss.getOutCardWhileFriendIsWinnerInHokum(chairId), getCardType(bigCards[i]) } outedCards[getFriendChair(chairId)] = CARD_COUNT } if len(sortedCards[ss.roundType]) > 0 { return CARD_COUNT, CardType_Invalid } if len(sortedCards[ss.trumpType]) == 0 { return CARD_COUNT, CardType_Invalid } // 没有相同花色,roundType为非主牌,我有主牌大于未出牌的敌方 bigCards = ss.getTrumpCardBiggerThanAllEmenyInHokum(sortedCards[ss.trumpType], chairId, ss.roundType) if len(bigCards) == 0 { return CARD_COUNT, CardType_Invalid } for i := 0; i < len(bigCards); i++ { outedCards[getFriendChair(chairId)] = bigCards[i] if getFriendChair(chairId) == ss.getWinner(outedCards, ss.roundType) { return ss.getOutCardWhileFriendIsWinnerInHokum(chairId), getCardType(bigCards[i]) } outedCards[getFriendChair(chairId)] = CARD_COUNT } return CARD_COUNT, CardType_Invalid } if ss.getWinner(outedCards, ss.roundType) != getFriendChair(chairId) { return CARD_COUNT, CardType_Invalid } enemySortedCards := sortCards(ss.fakers[getPreviousChair(chairId)].handCards) if len(enemySortedCards[ss.roundType]) > 0 { if !ss.isBiggerThanAll(outedCards[getFriendChair(chairId)], ss.roundType, enemySortedCards[ss.roundType]) { return CARD_COUNT, CardType_Invalid } return ss.getOutCardWhileFriendIsWinnerInHokum(chairId), getCardType(outedCards[getFriendChair(chairId)]) } if ss.isBiggerThanAll(outedCards[getFriendChair(chairId)], ss.roundType, enemySortedCards[ss.trumpType]) { return ss.getOutCardWhileFriendIsWinnerInHokum(chairId), getCardType(outedCards[getFriendChair(chairId)]) } return CARD_COUNT, CardType_Invalid } func (ss *simulatorScene) getOutCardWhileFriendIsWinnerInHokum(chairId int) int { sortedCards := sortCards(ss.fakers[chairId].handCards) if len(sortedCards[ss.roundType]) > 0 { maxCards := ss.getBigCardsThanAllEnemyHandCardsInHokum(chairId, ss.roundType, false, ss.roundType == ss.trumpType, true) if len(maxCards) == 0 { return ss.getMaxValueCardInCards(sortedCards[ss.roundType], false) } if !ss.canBigOnNextRoundInHokum(chairId, ss.roundType) { return ss.getMaxValueCardInCards(sortedCards[ss.roundType], false) } cards := ss.getCardsExpectMaxCardsInBigCards(sortedCards[ss.roundType], maxCards) if len(cards) == 0 { return ss.getMinValueCardInCards(maxCards) } return ss.getMaxValueCardInCards(cards, false) } bigCards := ss.getBigCardsThanAllEnemyHandCardsInHokum(chairId, CardType_Invalid, false, true, true) return ss.getMaxValueCardExpectBigCardsInHokum(chairId, bigCards) } func (ss *simulatorScene) canBigOnNextRoundInHokum(chairId, roundType int) bool { if ss.trumpType == roundType { return true } outedCards := ss.getRoundCards() for n := 0; n < CHAIR_COUNT; n++ { if isSameTeam(n, chairId) { //if n == chairId { continue } enemySortedCards := sortCards(ss.fakers[n].handCards) if outedCards[n] != CARD_COUNT && len(enemySortedCards[roundType]) == 0 && len(enemySortedCards[ss.trumpType]) > 0 { return false } if outedCards[n] == CARD_COUNT && len(enemySortedCards[roundType]) <= 1 && len(enemySortedCards[ss.trumpType]) > 0 { return false } } return true } func (ss *simulatorScene) getMaxValueCardExpectBigCardsInHokum(chairId int, bigCards []int) int { handCards := []int{} if len(ss.fakers[chairId].bigCards) == 0 { handCards = append(handCards, ss.fakers[chairId].handCards...) } else { handCards = append(handCards, ss.fakers[chairId].bigCards...) } outCard := CARD_COUNT maxValue := -1 for i := 0; i < len(handCards); i++ { if getCardType(handCards[i]) == ss.trumpType { continue } bFound := false for j := 0; j < len(bigCards); j++ { if handCards[i] == bigCards[j] { bFound = true break } } if !bFound { value := getCardPoint(handCards[i], ss.trumpType) if value > maxValue && getCardValue(handCards[i]) != CardValueA { maxValue = value outCard = handCards[i] } } } if isValidCard(outCard) { return outCard } for i := 0; i < len(handCards); i++ { if getCardType(handCards[i]) == ss.trumpType { continue } bFound := false for j := 0; j < len(bigCards); j++ { if handCards[i] == bigCards[j] { bFound = true break } } if !bFound { value := getCardPoint(handCards[i], ss.trumpType) if value > maxValue { maxValue = value outCard = handCards[i] } } } if isValidCard(outCard) { return outCard } minValue := 100 for j := 0; j < len(bigCards); j++ { if getCardType(bigCards[j]) == ss.trumpType { continue } value := getCardPoint(bigCards[j], ss.trumpType) if value < minValue { minValue = value outCard = bigCards[j] } } if isValidCard(outCard) { return outCard } for j := 0; j < len(handCards); j++ { value := getCardPoint(handCards[j], ss.trumpType) if value < minValue { minValue = value outCard = handCards[j] } } return outCard } func (ss *simulatorScene) getMinValueCardInHokum(chairId int) int { minCardValue := 100 card := CARD_COUNT handCards := []int{} if len(ss.fakers[chairId].bigCards) == 0 { handCards = append(handCards, ss.fakers[chairId].handCards...) } else { handCards = append(handCards, ss.fakers[chairId].bigCards...) } // 首出时手牌不少于2张,如果手上有10只剩两张该花色牌,且该花色A没有打出来,则不优先出该花色牌 if ss.roundType == CardType_Invalid && len(ss.fakers[chairId].handCards) > 2 { sortedCards := sortCards(handCards) for j := 0; j < len(handCards); j++ { if getCardType(handCards[j]) == ss.trumpType { continue } if len(sortedCards[getCardType(handCards[j])]) == 2 && !ss.canOutMiniCardWhileFirstOut(sortedCards[getCardType(handCards[j])], chairId) { continue } value := getCardPoint(handCards[j], ss.trumpType) if value < minCardValue { minCardValue = value card = handCards[j] } } if isValidCard(card) { return card } } for j := 0; j < len(handCards); j++ { if getCardType(handCards[j]) != ss.roundType { continue } value := getCardPoint(handCards[j], ss.trumpType) if value < minCardValue { minCardValue = value card = handCards[j] } } if isValidCard(card) { return card } for j := 0; j < len(handCards); j++ { if getCardType(handCards[j]) == ss.trumpType { continue } value := getCardPoint(handCards[j], ss.trumpType) if value < minCardValue { minCardValue = value card = handCards[j] } } if isValidCard(card) { return card } for j := 0; j < len(handCards); j++ { value := getCardPoint(handCards[j], ss.trumpType) if value < minCardValue { minCardValue = value card = handCards[j] } } return card } /****************************** Hokum END ******************************/ /*************************** 机器人出牌策略 end *************************/