package tienlen import ( "math" tienlenApi "mongo.games.com/game/api3th/smart/tienlen" "mongo.games.com/goserver/core/logger" "sort" ) // 新tienlenAI 获取牌型 func GetCardsType(myCards []int32, isYuLe bool) map[int]map[int32][]int32 { cards := make([]int32, len(myCards)) copy(cards, myCards) cardsTypeMap := make(map[int]map[int32][]int32) //先找炸弹 bombMap := GetBomb(cards) if len(bombMap) > 0 { cardsTypeMap[Four_Bomb] = bombMap } cards = DelCards(cards, bombMap) //找连对(5连对>4连对>3连队>2连队) pair, pairMap := GetPair(cards) //再找连对 pairStraightMap := GetConsecutivePairs(cards, pair) if len(pairStraightMap) > 0 { cardsTypeMap[Straight_Twin] = pairStraightMap } for i, pairStraight := range pairStraightMap { if len(pairStraight)/2 <= 2 { //先删除2连对 去找顺子和三条 delete(cardsTypeMap[Straight_Twin], i) } } //先排除2连对 //排除3连对以上的连对 for _, pairStraight := range pairStraightMap { if isYuLe { //娱乐模式 如果3连对以上,则删除3连对以上的连对 if len(pairStraight)/2 >= 3 { delMap := make(map[int32][]int32) delMap[int32(len(delMap)+1)] = pairStraight cards = DelCards(cards, delMap) } } else { delMap := make(map[int32][]int32) delMap[int32(len(delMap)+1)] = pairStraight cards = DelCards(cards, delMap) } } //娱乐模式先找三张 //连队和三条有冲突 既能组成连对 也是三条 这个时候要判断是不是娱乐模式 娱乐模式保留三条拆连对,不是娱乐模式保留连对 拆三条 if isYuLe { threeMap := GetThreeOfkind(cards) if len(threeMap) > 0 { cardsTypeMap[Triple] = threeMap } //娱乐模式三张不拆 删除掉三张的牌找顺子 cards = DelCards(cards, threeMap) //判断获取到的三条在不在连对中 for _, three := range threeMap { for i, pairStraight := range pairStraightMap { if len(pairStraight)/2 >= 3 { continue } for _, data := range pairStraight { if Value(data) == Value(three[0]) { //删除连对 delete(cardsTypeMap[Straight_Twin], i) break } } } } cards = DelCards(cards, threeMap) } //找顺子(同花顺>杂色顺子) straightMap := findStraights(cards) if len(straightMap) > 0 { cardsTypeMap[Straight] = straightMap cards = DelCards(cards, straightMap) } //找三张 if !isYuLe { threeMap := GetThreeOfkind(cards) if len(threeMap) > 0 { cardsTypeMap[Triple] = threeMap } //不是娱乐模式删除三条 for i, three := range threeMap { for _, pairStraight := range pairStraightMap { if len(pairStraight)/2 >= 3 { continue } for _, data := range pairStraight { if Value(data) == Value(three[0]) { //删除连对 delete(cardsTypeMap[Triple], i) break } } } } cards = DelCards(cards, threeMap) } //找三顺 var arr []int32 for _, three := range cardsTypeMap[Triple] { for _, value := range three { arr = append(arr, value) } } StraightTripleMap := GetStraightTriple(arr) if len(StraightTripleMap) > 0 { cardsTypeMap[Straight_Triple] = StraightTripleMap } //剩余的牌再找对子 pair, pairMap = GetPair(cards) //再找连队 pairStraightMap = GetConsecutivePairs(cards, pair) for _, pairStraight := range pairStraightMap { cardsTypeMap[Straight_Twin][int32(len(cardsTypeMap[Straight_Twin])+1)] = pairStraight } cards = DelCards(cards, pairStraightMap) pair, pairMap = GetPair(cards) if len(pairMap) > 0 { cardsTypeMap[Twin] = pairMap } //找单张 移除上面所有牌型的牌,剩余的牌就是单张 cards = DelCards(cards, pairMap) if len(cards) > 0 { cardsTypeMap[Single] = make(map[int32][]int32) for i := 0; i < len(cards); i++ { cardsTypeMap[Single][int32(i)] = []int32{cards[i]} } } return cardsTypeMap } // 找炸弹 func GetBomb(cards []int32) map[int32][]int32 { cardCount := make(map[int32]int) cardMap := make(map[int32][]int32) // 统计每张牌的数量 for _, card := range cards { cardCount[int32(Value(card))]++ cardMap[int32(Value(card))] = append(cardMap[int32(Value(card))], card) } // 查找炸弹组合 bombMap := make(map[int32][]int32) for card, count := range cardCount { if count == 4 { bombMap[card] = cardMap[card] } } return bombMap } // 找连对 func GetConsecutivePairs(cards, pair []int32) map[int32][]int32 { // 对切片进行排序 sort.Slice(pair, func(i, j int) bool { return pair[i] < pair[j] }) // 存储顺子的 map straightMap := make(map[int32][]int32) for i := 0; i < len(pair); i++ { // 如果当前数字与前一个数字相同,则跳过 if i > 0 && pair[i] == pair[i-1] { continue } // 初始值为当前数字 current := pair[i] straight := []int32{current} // 检查是否连续递增 num := i for j := i + 1; j < len(pair); j++ { if pair[j] == current+1 && pair[j] < 12 { straight = append(straight, pair[j]) current = pair[j] num = j } } i = num if len(straight) >= 2 { straightMap[int32(len(straightMap)+1)] = straight } } //找原牌 cardsMap := make(map[int32][]int32) for i, v := range straightMap { for _, v1 := range v { num := 0 for _, v2 := range cards { if v1 == int32(Value(v2)) { num += 1 cardsMap[i] = append(cardsMap[i], v2) if num == 2 { break } } } } } return cardsMap } // 找顺子 func GetAllStraight(cards []int32, length int) map[int32][]int32 { // 对切片进行排序 sort.Slice(cards, func(i, j int) bool { return cards[i] < cards[j] }) // 存储顺子的 map straightMap := make(map[int32][]int32) for i := 0; i < len(cards); i++ { // 如果当前数字与前一个数字相同,则跳过 if i > 0 && Value(cards[i]) == Value(cards[i-1]) { continue } // 初始值为当前数字 current := cards[i] straight := []int32{current} // 检查是否连续递增 for j := i + 1; j < len(cards); j++ { if Value(cards[j]) == Value(current)+1 && Value(cards[j]) < 12 { straight = append(straight, cards[j]) current = cards[j] if len(straight) >= length { straightMap[int32(len(straightMap)+1)] = straight } } } } return straightMap } // 1.先找到所有长度为3的顺子 // 2.剩余的牌再和已经取出来的顺子组合,知道组合成更大的牌, // 3.合并顺子 // 4.最后再确定单顺,剩余的牌和三条连对进行组合 看看能不能组成新的顺子(娱乐版不拆三条)拆连队只能拆长度等于2的连对 // 找出所有长度为3的顺子 func findStraights(cards []int32) map[int32][]int32 { straights := [][]int32{} length := len(cards) if length < 3 { return make(map[int32][]int32) } sort.Slice(cards, func(i, j int) bool { return Value(cards[i]) < Value(cards[j]) }) for i := 0; i <= length-3; { if Value(cards[i]) == Value(cards[i+1]) || Value(cards[i]) >= 10 { i++ continue } if i+2 < length { arr := []int32{} value := cards[i] arr = append(arr, cards[i]) for j := i + 1; j <= length-1; j++ { if Value(cards[j]) == Value(value) || Value(cards[j]) >= 12 { continue } arr = append(arr, cards[j]) value = cards[j] if len(arr) == 3 { break } } if isStraight(arr) { straights = append(straights, arr) // 从牌组中移除当前顺子的牌 cards = removeCards(cards, arr) length = len(cards) // 更新牌组长度 } else { i++ } } else { break } } sort.Slice(straights, func(i, j int) bool { return Value(straights[i][0]) < Value(straights[j][0]) }) //2.剩余的牌再和已经取出来的顺子组合,知道组合成更大的牌, removeCard := []int32{} for _, card := range cards { for i, straight := range straights { if Value(card) == Value(straight[len(straight)-1]+1) && Value(card) < 12 { straight = append(straight, card) removeCard = append(removeCard, card) straights[i] = straight break } } } cards = removeCards(cards, removeCard) //3.合并顺子 for i := 0; i < len(straights)-1; i++ { if Value(straights[i][len(straights[i])-1]) == Value(straights[i+1][0])-1 { straights[i] = append(straights[i], straights[i+1]...) straights = append(straights[:i+1], straights[i+2:]...) i -= 1 } } //转正map straightsMap := make(map[int32][]int32) for i, straight := range straights { straightsMap[int32(i)] = straight } return straightsMap } // 暂时不做 现在的找牌顺序可以兼容这种 拆三条 二连对组顺子 func TwoFindStraights(cards []int32, isYuLe bool, cardsType map[int]map[int32][]int32, straights [][]int32) { //4.剩余的牌和三条连对进行组合 看看能不能组成新的顺子(娱乐版不拆三条)拆连队只能拆长度等于2的连对 //找相邻的两张牌 twoCards := [][]int32{} for i := 0; i < len(cards)-1; i++ { if cards[i] == cards[i+1]-1 || cards[i] == cards[i+1]-2 { twoCards = append(twoCards, []int32{cards[i], cards[i+1]}) i += 1 } } if len(twoCards) > 0 { indexesToRemove := []int{} for _, twoCard := range twoCards { value := twoCard //添加三条 和连对的牌进去再找顺子 if !isYuLe { threeCards := cardsType[Triple] for i, three := range threeCards { //logger.Logger.Tracef("开始拆三条组顺子 three = %d \n", three) value = append(value, three[0]) sort.Slice(value, func(i, j int) bool { return value[i] < value[j] }) //判断是不是顺子 if isStraight(value) { //找到顺子了 移除三张 cards = removeCards(cards, value) delete(cardsType[Triple], i) straights = append(straights, value) indexesToRemove = append(indexesToRemove, int(i)) cards = append(cards, three[1], three[2]) break } } } } // 根据索引从切片中删除元素 for i := len(indexesToRemove) - 1; i >= 0; i-- { twoCards = append(twoCards[:indexesToRemove[i]], twoCards[indexesToRemove[i]+1:]...) } //添加二连对组顺子 //最后在合并一下顺子 for i := 0; i < len(straights)-1; i++ { if straights[i][len(straights[i])-1] == straights[i+1][0]-1 { straights[i] = append(straights[i], straights[i+1]...) straights = append(straights[:i+1], straights[i+2:]...) i -= 1 } } } } func removeCards(cards []int32, toRemove []int32) []int32 { newCards := []int32{} removed := make([]bool, len(cards)) for _, card := range toRemove { for i, c := range cards { if c == card && !removed[i] { removed[i] = true break } } } for i, card := range cards { if !removed[i] { newCards = append(newCards, card) } } return newCards } func isStraight(cards []int32) bool { if len(cards) < 3 { return false } return Value(cards[1])-Value(cards[0]) == 1 && Value(cards[2])-Value(cards[1]) == 1 } // 找三张 func GetThreeOfkind(cards []int32) map[int32][]int32 { cardCount := make(map[int32]int) var three []int32 cardMap := make(map[int32][]int32) // 统计每张牌的数量 for _, card := range cards { cardCount[int32(Value(card))]++ cardMap[int32(Value(card))] = append(cardMap[int32(Value(card))], card) } // 查找炸弹组合 threeMap := make(map[int32][]int32) for card, count := range cardCount { if count >= 3 { three = append(three, card) threeMap[card] = cardMap[card] } } return threeMap } // 找三顺 func GetStraightTriple(cards []int32) map[int32][]int32 { sort.Slice(cards, func(i, j int) bool { if Value(cards[i]) == Value(cards[j]) { return cards[i] < cards[j] } return Value(cards[i]) < Value(cards[j]) }) result := make(map[int32][]int32) for i := 0; i < len(cards)-3; { num := 1 for j := i + 3; j < len(cards); { if Value(cards[i]) == Value(cards[j])-num && Value(cards[j]) < 12 { num += 1 } j += 3 } if num >= 2 { arr := cards[i : i+num*3] result[int32(Value(arr[len(arr)-1]))] = arr } i += 3 } return result } // 找对子 func GetPair(cards []int32) ([]int32, map[int32][]int32) { cardCount := make(map[int32]int) cardMap := make(map[int32][]int32) // 统计每张牌的数量 for _, card := range cards { cardCount[int32(Value(card))]++ cardMap[int32(Value(card))] = append(cardMap[int32(Value(card))], card) } // 查找对子组合 pairMap := make(map[int32][]int32) var pair []int32 for card, count := range cardCount { if count >= 2 { //logger.Logger.Tracef("\n找到所有的对子:%d \n", card) pair = append(pair, card) pairMap[card] = cardMap[card] } } return pair, pairMap } // 牌型转换 func CardsChange(cards []int32) []int { //map key-相同牌数量 value-key: var cardChange []int for _, card := range cards { cardChange = append(cardChange, Value(card)) } sort.Ints(cardChange) return cardChange } // 删除牌 func DelCards(cards []int32, delCards map[int32][]int32) []int32 { // 创建一个新的切片,用于存储不需要删除的元素 newCards := make([]int32, 0, len(cards)) // 遍历 cards 中的元素 for _, card := range cards { // 检查当前元素是否需要删除 shouldDelete := false for _, delCard := range delCards { for _, del := range delCard { if card == del { shouldDelete = true break } } } // 如果不需要删除,则将元素添加到新的切片中 if !shouldDelete { newCards = append(newCards, card) } } return newCards } // 获取牌型分计算 func GetCardTypeScore(cardsType map[int]map[int32][]int32, isYuLe bool, cards []int32) (int, int) { //计算每张牌的牌值 cardValues := []int{ -120, -100, -80, -60, -40, -20, 0, 20, 50, 90, 140, 200, 300, -115, -95, -75, -55, -35, -15, 5, 25, 55, 95, 145, 205, 325, -110, -90, -70, -50, -30, -10, 10, 30, 60, 100, 150, 210, 350, -105, -85, -65, -45, -25, -5, 15, 35, 65, 105, 155, 215, 400, } //logger.Logger.Trace("计算牌型分 cardsType = ", cardsType) //计算牌型分值 var score int //炸弹 if len(cardsType[Four_Bomb]) > 0 { if isYuLe { score += len(cardsType[Four_Bomb]) * 1000 } else { score += len(cardsType[Four_Bomb]) * 700 } } //连队 if len(cardsType[Straight_Twin]) > 0 { for _, twin := range cardsType[Straight_Twin] { switch len(twin) / 2 { case 5: score += 500 case 4: score += 400 case 3: score += 300 case 2: score += 200 } } } //顺子 if len(cardsType[Straight]) > 0 { for _, straight := range cardsType[Straight] { score += len(straight)*100 + (len(straight)-3)*(cardValues[straight[len(straight)-1]]/3) } } //三张 if len(cardsType[Triple]) > 0 { for _, triples := range cardsType[Triple] { if Value(triples[0]) < 7 { score += int(math.Abs(float64(250 + cardValues[triples[2]]))) } else { score += cardValues[triples[0]] + cardValues[triples[1]] + cardValues[triples[2]] } } if isYuLe { score += len(cardsType[Triple]) * 300 } } //两对 if len(cardsType[Twin]) > 0 { for _, twins := range cardsType[Twin] { if Value(twins[0]) < 7 { score += cardValues[twins[1]] / 2 } else { score += cardValues[twins[0]] + cardValues[twins[1]] } } } //删除三连对以上且三连对小于10的牌 copyCards := make([]int32, len(cards)) copy(copyCards, cards) copyCards = DelCards(copyCards, cardsType[Four_Bomb]) for _, straightTwin := range cardsType[Straight_Twin] { delMap := make(map[int32][]int32) if len(straightTwin)/2 >= 3 && Value(straightTwin[len(straightTwin)-1]) < 10 { delMap[int32(len(delMap)+1)] = straightTwin copyCards = DelCards(copyCards, delMap) } } for _, card := range copyCards { score += cardValues[card] } handCardnum := len(cardsType[Four_Bomb]) + len(cardsType[Straight_Twin]) + len(cardsType[Straight]) + len(cardsType[Triple]) + len(cardsType[Twin]) + len(cardsType[Single]) if isYuLe { handCardnum -= (len(cardsType[Triple]) * 2) } if handCardnum <= 1 { handCardnum = 1 if isYuLe && handCardnum == 1 { if len(cardsType[Triple]) > 0 { if len(cards) > 5 { handCardnum = 2 } } } } if Have6StraightTwin(cards) || Have12Straight(cards) || Have2FourBomb(cards) { return 9999, 1 } return score - (handCardnum-5)*150, handCardnum } // 压牌 isWin-是否胜利 func GetPressCards(cards, lastCards []int32, data *tienlenApi.PredictRequest, pos int32) []int32 { logger.Logger.Tracef("---------------压牌开始-------------------") sort.Slice(cards, func(i, j int) bool { if Value(cards[i]) == Value(cards[j]) { return cards[i] < cards[j] } return Value(cards[i]) < Value(cards[j]) }) isWin := data.IsWin //测试代码 isWin = true logger.Logger.Trace("压牌 调控输赢 isWin = ", isWin) outCards := []int32{} //压牌测试代码 // cards = []int32{6, 19, 2, 28, 41, 43, 12, 25} // lastCards = []int32{14, 27} // pos = 0 // data.Cards_left_2 = []int32{45, 32} // data.Cards_left_3 = nil // data.Cards_left_1 = nil // data.Last_pos = 2 lastPos := data.Last_pos //上家出牌人的位置 logger.Logger.Tracef(" 上家出牌人的位置%d,出的牌:%v\n", lastPos, lastCards) isYuLe := data.IsTienLenYule isEnd := data.IsEnd winSnids := data.WinSnids logger.Logger.Trace("当前模式是否是打到底%v\n,当前获胜玩家:%v\n", isEnd, winSnids) //获取牌型 cardsTypeMap := GetCardsType(cards, isYuLe) score, handCardnum := GetCardTypeScore(cardsTypeMap, isYuLe, cards) logger.Logger.Tracef("压牌 获取牌型:%v\n,分值:%d\n手牌:%d、n,我的位置:%d\n", cardsTypeMap, score, handCardnum, pos) //获取出牌人的 手数 otherCards := getOtherPlayerCards(pos, lastPos, data) otherCardsTypeMap := GetCardsType(otherCards, isYuLe) lastScore, lastHandCardnum := GetCardTypeScore(otherCardsTypeMap, isYuLe, otherCards) logger.Logger.Tracef("压牌,获取出牌玩家的剩余牌的牌型:", otherCardsTypeMap, "分值:", lastScore, "手牌:", lastHandCardnum, "\n") //获取下一家的位置和剩余的牌 nextPos, nextCards := GetNextPos(pos, data) logger.Logger.Tracef("我的位置:%d\n,获取下家牌和位置:nextPos = %d\n,nextCards := %v\n", pos, nextPos, nextCards) isRule, ruleType := RulePopEnable_yl(lastCards) if isRule { switch ruleType { case Single: //单张 cardsMap := cardsTypeMap[Single] //转成数组 singleArr := []int32{} for _, single := range cardsMap { singleArr = append(singleArr, single[0]) } if isEnd && !isYuLe { sort.Slice(singleArr, func(i, j int) bool { if Value(singleArr[i]) == Value(singleArr[j]) { return singleArr[i] < singleArr[j] } return Value(singleArr[i]) < Value(singleArr[j]) }) } //如果我的下一家剩余一张牌 出比他大的牌 if len(singleArr) > 0 { if len(singleArr) == 2 && len(cards) == 2 { for _, mycard := range singleArr { if getMaxCardTypeNum(Single, []int32{mycard}, pos, data) { outCards = []int32{mycard} } } } else { for _, card := range singleArr { if Value(card) >= Value(lastCards[0]) { if Value(card) == Value(lastCards[0]) { if Color(card) < Color(lastCards[0]) { continue } } if len(nextCards) == 1 { if Value(card) >= Value(nextCards[0]) { if Value(card) == Value(nextCards[0]) { if Color(card) > Color(nextCards[0]) { outCards = []int32{card} break } } else { outCards = []int32{card} break } } } else { outCards = []int32{card} break } } } } } else { //找顺子交集 返回值[][]int32 result := FindIntersection(cardsTypeMap[Straight]) if len(result) > 0 { sort.Slice(cards, func(i, j int) bool { if Value(cards[i]) == Value(cards[j]) { return cards[i] < cards[j] } return Value(cards[i]) < Value(cards[j]) }) for _, arr := range result { for _, card := range arr { if Value(card) >= Value(lastCards[0]) { if Value(card) == Value(lastCards[0]) { if Color(card) < Color(lastCards[0]) { continue } } if len(nextCards) == 1 { if Value(card) >= Value(nextCards[0]) { if Value(card) == Value(nextCards[0]) { if Color(card) > Color(nextCards[0]) { outCards = []int32{card} break //return card } } else { outCards = []int32{card} break } } } else { outCards = []int32{card} break } } } if len(outCards) > 0 { break } } } } if isWin { //拆牌 先找顺子的交集 拆对子 拆2 拆长度大于3的顺子 最后找大于这张出牌的牌除了炸弹 出牌这家只剩一首牌了 if len(outCards) == 0 && len(cardsTypeMap[Twin]) > 0 { logger.Logger.Trace("拆对子") twinMap := cardsTypeMap[Twin] //拆小于2的对子 for _, card := range twinMap { if Value(card[0]) == 12 { //排除掉对2 continue } //先拆小于2的对子 if Value(card[0]) >= Value(lastCards[0]) { if Value(card[0]) == Value(lastCards[0]) { if Color(card[0]) < Color(lastCards[0]) { continue } } if len(nextCards) == 1 { if Value(card[0]) >= Value(nextCards[0]) { if Value(card[0]) == Value(nextCards[0]) { if Color(card[0]) > Color(nextCards[0]) { outCards = []int32{card[0]} break } } else { outCards = []int32{card[0]} break } } } else { //玩家出完这张牌 还剩一张 剩余的牌比我现在出的牌大 if len(otherCards) == 1 && Value(otherCards[0]) >= Value(card[0]) { continue } outCards = []int32{card[0]} break } } } //判断一下下一家剩1张牌比我的大的情况 if len(outCards) > 0 { break } } //直接拆2上 if len(outCards) == 0 && (lastHandCardnum <= 4 || handCardnum <= 3 || (len(nextCards) == 1 && Value(nextCards[0]) >= Value(lastCards[0]))) { for _, card := range cards { if Value(card) == 12 && Value(card) >= Value(lastCards[0]) { if Value(card) == Value(lastCards[0]) { if Color(card) > Color(lastCards[0]) { outCards = []int32{card} break } else { continue } } else { outCards = []int32{card} break } } } if len(outCards) > 0 && len(otherCards) == 1 && Value(otherCards[0]) >= Value(outCards[0]) { if Value(outCards[0]) == Value(otherCards[0]) { if Color(outCards[0]) < Color(otherCards[0]) { if Value(cards[len(cards)-1]) >= Value(lastCards[0]) { outCards = []int32{cards[len(cards)-1]} } } } else { if Value(cards[len(cards)-1]) >= Value(lastCards[0]) { outCards = []int32{cards[len(cards)-1]} } } } } //拆连对 map[int32][]int32 if len(outCards) == 0 && len(cardsTypeMap[Straight_Twin]) > 0 { for _, straightTwin := range cardsTypeMap[Straight_Twin] { if len(straightTwin)/2 == 2 || lastHandCardnum == 1 { for _, twin := range straightTwin { if Value(twin) > Value(lastCards[0]) { outCards = []int32{twin} break } } if len(outCards) > 0 { break } } } } if !isYuLe { //拆三条 if len(outCards) == 0 && len(cardsTypeMap[Triple]) > 0 { tripleMap := cardsTypeMap[Triple] for _, card := range tripleMap { if Value(card[0]) >= Value(lastCards[0]) { if Value(card[0]) == Value(lastCards[0]) { if Color(card[0]) < Color(lastCards[0]) { continue } } if len(nextCards) == 1 { if Value(card[0]) >= Value(nextCards[0]) { if Value(card[0]) == Value(nextCards[0]) { if Color(card[0]) > Color(nextCards[0]) { outCards = []int32{card[0]} break } } else { outCards = []int32{card[0]} break } } } else { outCards = []int32{card[0]} break } } } } } //拆长度>3的顺子 if len(outCards) == 0 && len(cardsTypeMap[Straight]) > 0 { straightMap := cardsTypeMap[Straight] for _, card := range straightMap { if len(card) <= 3 && lastHandCardnum != 1 { continue } if Value(card[len(card)-1]) >= Value(lastCards[0]) { if Value(card[0]) == Value(lastCards[0]) { if Color(card[0]) < Color(lastCards[0]) { continue } } if len(nextCards) == 1 { if Value(card[0]) >= Value(nextCards[0]) { if Value(card[0]) == Value(nextCards[0]) { if Color(card[0]) > Color(nextCards[0]) { outCards = []int32{card[len(card)-1]} break } } else { outCards = []int32{card[len(card)-1]} break } } } else { outCards = []int32{card[len(card)-1]} break } } } } } if len(outCards) == 0 && Value(lastCards[0]) == 12 { //找三连对 >四连对 >五连对 > 炸弹 straightTwinMap := cardsTypeMap[Straight_Twin] //找最小长度的key if len(straightTwinMap) > 0 { for _, straightTwin := range straightTwinMap { if len(straightTwin)/2 >= 3 { outCards = straightTwin logger.Logger.Trace("-----------------单张压牌 找到连对!", outCards) break //return straightTwin } } } //找炸弹 if !isYuLe { if len(outCards) == 0 && len(cardsTypeMap[Four_Bomb]) > 0 && Value(lastCards[0]) == 12 { minKey := findMinKey(cardsTypeMap[Four_Bomb]) outCards = cardsTypeMap[Four_Bomb][minKey] } } } if isYuLe { //找炸弹 if len(outCards) == 0 && len(cardsTypeMap[Four_Bomb]) > 0 && (lastHandCardnum <= 2 || handCardnum <= 2) { minKey := findMinKey(cardsTypeMap[Four_Bomb]) outCards = cardsTypeMap[Four_Bomb][minKey] } } if len(outCards) > 0 { if Value(lastCards[0]) == 12 && Value(outCards[0]) == 12 && lastHandCardnum != 1 { //如果出牌玩家剩余手数大于2 或者我的剩余手数小于等于3 //存在一种情况 上家剩余1张牌 其他人出单张 上家不要 这个时候我执行了这个判断 没有出2去接牌 && 我的上家单张数量>=2 ||上家剩余1张牌了 我要跑牌了 _, myLastCards := GetLastPos(pos, data) if ((lastHandCardnum > 2 && len(otherCardsTypeMap[Single]) > 2) || (handCardnum > 3 && len(cardsTypeMap[Single]) >= 2)) && len(myLastCards) >= 2 { if lastHandCardnum > 3 { logger.Logger.Tracef("上家出2剩余的手数:%d,我的手数:%d\n,让一手", lastHandCardnum, handCardnum) outCards = []int32{} } } } } if len(outCards) == 0 { if len(nextCards) == 1 && Value(lastCards[0]) < Value(nextCards[0]) { if Value(cards[len(cards)-1]) >= Value(nextCards[0]) { outCards = []int32{cards[len(cards)-1]} } } } //强压 if len(outCards) == 0 && (len(lastCards) == 1 || len(nextCards) == 1) { if Value(cards[len(cards)-1]) >= Value(lastCards[0]) { outCards = []int32{cards[len(cards)-1]} } } //打到底 最后一首牌判断 if len(otherCards) == 1 && (!isYuLe && isEnd) && (winSnids == nil || len(winSnids) == 0) && len(outCards) != 0 && nextPos != lastPos { if Value(outCards[0]) == Value(cards[len(cards)-1]) && handCardnum > 2 { if Value(outCards[0]) <= Value(otherCards[0]) { if Value(outCards[0]) == Value(otherCards[0]) { if Color(outCards[0]) < Color(otherCards[0]) { logger.Logger.Tracef("判断我的最大牌小于上家剩余的牌,不出!") outCards = []int32{} } } else { logger.Logger.Trace("打到底最后一手牌牌,让一手!") outCards = []int32{} } } } } if isEnd && len(otherCards) == 0 && len(outCards) > 0 { if len(nextCards) == 1 { //在这加一道防线 if Value(outCards[0]) < Value(nextCards[0]) { //出最大牌 if Value(cards[len(cards)-1]) >= Value(lastCards[0]) && Value(cards[len(cards)-1]) >= Value(nextCards[0]) { outCards = []int32{cards[len(cards)-1]} } } } } if len(outCards) == 0 && len(lastCards) == 1 && nextPos == lastPos { //出最大的牌 if Value(cards[len(cards)-1]) >= Value(lastCards[0]) { outCards = []int32{cards[len(cards)-1]} } } //打到底 出牌人打完了 if !IsPressed(isYuLe, isEnd, otherCards, lastCards, data, pos, lastPos, nextPos, handCardnum, Single) { logger.Logger.Trace("出牌人打完牌了,我过一手!!!!", lastCards) outCards = []int32{} } logger.Logger.Tracef("--------------单张压牌完毕,出的牌:", outCards) return outCards case Twin: //对子 cardsMap := cardsTypeMap[Twin] if len(cardsMap) > 0 { for _, card := range cardsMap { if lastHandCardnum == 1 && len(otherCards) == 2 && Value(otherCards[len(otherCards)-1]) >= Value(card[1]) { if Value(otherCards[len(otherCards)-1]) == Value(card[1]) { if Color(otherCards[len(otherCards)-1]) > Color(card[1]) { continue } } else { continue } } if Value(card[1]) >= Value(lastCards[1]) { if Value(card[1]) == 12 { //判断能不能直接出对2 if handCardnum > 3 && lastHandCardnum > 3 { continue } } if Value(card[1]) == Value(lastCards[1]) { //判断花色 if Color(card[1]) > Color(lastCards[1]) { outCards = card break } } else { outCards = card break } } } //再找一遍 if len(outCards) == 0 { for _, card := range cardsMap { if Value(card[1]) >= Value(lastCards[1]) { if Value(card[1]) == 12 { //判断能不能直接出对2 if handCardnum > 3 && lastHandCardnum > 3 { continue } } if Value(card[1]) == Value(lastCards[1]) { //判断花色 if Color(card[1]) > Color(lastCards[1]) { outCards = card break } } else { outCards = card break } } } } } logger.Logger.Trace("找到对子-------------------outCards =", outCards) //拆连对 if isWin { straightTwinMap := cardsTypeMap[Straight_Twin] if len(outCards) == 0 { if Value(lastCards[0]) == 12 { if len(straightTwinMap) > 0 { for _, straightTwin := range straightTwinMap { if len(straightTwin)/2 >= 4 { outCards = straightTwin break } } } } else { //拆连对 if len(straightTwinMap) > 0 { for _, straightTwin := range straightTwinMap { if len(straightTwin)/2 >= 2 { //判断第一个和最后一位 if Value(straightTwin[0]) >= Value(lastCards[0]) { if Color(straightTwin[1]) > Color(lastCards[1]) { outCards = []int32{straightTwin[0], straightTwin[1]} break } } else { //判断最后一位 if Value(straightTwin[3]) >= Value(lastCards[0]) { if Color(straightTwin[3]) > Color(lastCards[1]) { outCards = []int32{straightTwin[2], straightTwin[3]} break } } } } } } } } //拆三条 //找最大的三条拆 if !isYuLe { if len(outCards) == 0 && len(cardsTypeMap[Triple]) > 0 { for _, triple := range cardsTypeMap[Triple] { if Value(triple[0]) > Value(lastCards[0]) { outCards = []int32{triple[0], triple[1]} logger.Logger.Trace("拆三条压对子 outCards = ", outCards) break } } } } else { if len(outCards) == 0 && len(cardsTypeMap[Triple]) > 0 && (lastHandCardnum <= 2 || handCardnum <= 3) { for _, triple := range cardsTypeMap[Triple] { if Value(triple[0]) > Value(lastCards[0]) { outCards = []int32{triple[0], triple[1]} logger.Logger.Trace("拆三条压对子 outCards = ", outCards) break } } } } } //找炸弹 if isYuLe { if len(outCards) == 0 && len(cardsTypeMap[Four_Bomb]) > 0 && (lastHandCardnum <= 2 || handCardnum <= 2) { minKey := findMinKey(cardsTypeMap[Four_Bomb]) outCards = cardsTypeMap[Four_Bomb][minKey] } } else { if len(outCards) == 0 && len(cardsTypeMap[Four_Bomb]) > 0 && Value(lastCards[0]) == 12 { minKey := findMinKey(cardsTypeMap[Four_Bomb]) outCards = cardsTypeMap[Four_Bomb][minKey] } } if len(outCards) > 0 { if Value(lastCards[0]) == 12 && Value(outCards[0]) == 12 { //如果出牌玩家剩余手数大于2 或者我的剩余手数小于等于3 if lastHandCardnum > 3 && (len(otherCardsTypeMap[Twin]) > 2 || len(otherCardsTypeMap[Single]) > 2) || (handCardnum > 3 && len(cardsTypeMap[Single]) > 2) { if lastHandCardnum > 1 { logger.Logger.Tracef("上家出2剩余的手数:%d,我的手数:%d\n,让一手", lastHandCardnum, handCardnum) outCards = []int32{} } } } } if len(outCards) == 0 && lastHandCardnum <= 2 { //重组对子 找大对子 _, pairMap := GetPair(cards) if len(pairMap) > 0 { maxkey := int32(-1) for key, pairs := range pairMap { if Value(pairs[0]) >= Value(lastCards[0]) { if key > maxkey { maxkey = key } } } if maxkey != -1 { outCards = append(outCards, pairMap[maxkey][0], pairMap[maxkey][1]) } } } if len(otherCards) == 2 && lastHandCardnum == 1 && (!isYuLe && isEnd) && (winSnids == nil || len(winSnids) == 0) && len(outCards) != 0 && nextPos != lastPos { if Value(outCards[0]) == Value(cards[len(cards)-1]) && handCardnum > 2 { if Value(outCards[0]) <= Value(otherCards[0]) { if Value(outCards[0]) == Value(otherCards[0]) { if Color(outCards[0]) < Color(otherCards[0]) { outCards = []int32{} } } else { outCards = []int32{} } } } } //打到底 出牌人打完了 if !IsPressed(isYuLe, isEnd, otherCards, lastCards, data, pos, lastPos, nextPos, handCardnum, Twin) { outCards = []int32{} } logger.Logger.Trace("--------------压牌完毕,出的牌:", outCards) return outCards case Straight: //顺子 cardsMap := cardsTypeMap[Straight] //获取顺子长度 for _, card := range cardsMap { if len(card) == len(lastCards) { if Value(card[len(card)-1]) >= Value(lastCards[len(lastCards)-1]) { if Value(card[len(card)-1]) == Value(lastCards[len(lastCards)-1]) { //比较花色 if Color(card[len(card)-1]) > Color(lastCards[len(lastCards)-1]) { outCards = card break //return card } } else { outCards = card break //return card } } } else if len(card) > len(lastCards) && Value(card[len(card)-1]) >= Value(lastCards[len(lastCards)-1]) && (lastHandCardnum <= 2 || isEnd) { //拆顺子 if Value(card[len(card)-1]) == Value(lastCards[len(lastCards)-1]) { //比较花色 if Color(card[len(card)-1]) < Color(lastCards[len(lastCards)-1]) { //截取 //return []int32{} } } outCards = card[len(card)-len(lastCards):] logger.Logger.Tracef("拆顺子 outCards = %d\n,lastCard = %d\n", outCards, lastCards) } } // if len(outCards) == 0 && lastHandCardnum <= 2 { //找顺子 allStraight := GetAllStraight(cards, len(lastCards)) logger.Logger.Trace("allStraight = ", allStraight) if len(allStraight) > 0 { for _, straight := range allStraight { if len(straight) >= len(lastCards) { if Value(straight[len(straight)-1]) >= Value(lastCards[len(lastCards)-1]) { if Value(straight[len(straight)-1]) == Value(lastCards[len(lastCards)-1]) { if Color(straight[len(straight)-1]) > Color(lastCards[len(lastCards)-1]) { outCards = straight[len(straight)-len(lastCards):] break } } else { outCards = straight[len(straight)-len(lastCards):] break } logger.Logger.Tracef("找所有顺子来压牌 outCards = ", outCards) } } } } } if isYuLe { //找炸弹 if len(outCards) == 0 && len(cardsTypeMap[Four_Bomb]) > 0 && lastHandCardnum <= 2 { minKey := findMinKey(cardsTypeMap[Four_Bomb]) outCards = cardsTypeMap[Four_Bomb][minKey] } } //打到底 出牌人打完了 if !IsPressed(isYuLe, isEnd, otherCards, lastCards, data, pos, lastPos, nextPos, handCardnum, Straight) { outCards = []int32{} } logger.Logger.Trace("--------------顺子压牌完毕,出的牌:", outCards) return outCards case ColorStraight: //同花顺 if len(cardsTypeMap[Straight]) > 0 { straightMap := cardsTypeMap[Straight] for _, straight := range straightMap { if len(straight) >= len(lastCards) { //判断是不是同花顺 if IsColorStraight(straight) { if Value(straight[len(straight)-1]) >= Value(lastCards[len(lastCards)-1]) { if Value(straight[len(straight)-1]) == Value(lastCards[len(lastCards)-1]) { if Color(straight[len(straight)-1]) > Color(lastCards[len(lastCards)-1]) { return straight[len(straight)-len(lastCards):] } } else { return straight[len(straight)-len(lastCards):] } } } } } } //找炸弹 if isYuLe && ((len(cardsTypeMap[Four_Bomb]) > 0 && lastHandCardnum <= 2) || handCardnum <= 2) { minKey := findMinKey(cardsTypeMap[Four_Bomb]) logger.Logger.Trace("--------------同花顺压牌完毕,出的牌:", outCards) return cardsTypeMap[Four_Bomb][minKey] } //打到底 出牌人打完了 if !IsPressed(isYuLe, isEnd, otherCards, lastCards, data, pos, lastPos, nextPos, handCardnum, ColorStraight) { outCards = []int32{} } case Straight_Twin: //连对 //获取连对长度 lastCardNum := len(lastCards) / 2 lastMaxCard := Value(lastCards[len(lastCards)-1]) cardsMap := cardsTypeMap[Straight_Twin] for _, card := range cardsMap { if len(card) >= len(lastCards) { if len(card) == len(lastCards) { if Value(card[len(card)-1]) >= lastMaxCard { if Value(card[len(card)-1]) == lastMaxCard { //比较花色 if Color(card[len(card)-1]) > Color(lastCards[len(lastCards)-1]) { //截取 outCards = card break } } else { outCards = card break } } } else { outCards = card break } } } if isYuLe { //找炸弹 if len(outCards) == 0 && (len(cardsTypeMap[Four_Bomb]) > 0 && lastHandCardnum <= 2 && lastCardNum <= 3) || handCardnum <= 2 { minKey := findMinKey(cardsTypeMap[Four_Bomb]) outCards = cardsTypeMap[Four_Bomb][minKey] } } else { if lastCardNum == 3 { //找炸弹 if len(outCards) == 0 && len(cardsTypeMap[Four_Bomb]) > 0 { minKey := findMinKey(cardsTypeMap[Four_Bomb]) outCards = cardsTypeMap[Four_Bomb][minKey] } } } if !IsPressed(isYuLe, isEnd, otherCards, lastCards, data, pos, lastPos, nextPos, handCardnum, Straight_Twin) { outCards = []int32{} } logger.Logger.Tracef("--------------连对压牌完毕,出的牌:", outCards) return outCards case Triple: //三张 cardsMap := cardsTypeMap[Triple] for _, card := range cardsMap { if Value(card[len(card)-1]) > Value(lastCards[len(lastCards)-1]) { if Value(card[0]) == 12 && lastHandCardnum > 2 { continue } outCards = card break //return card } } if isYuLe { //找炸弹 if len(outCards) == 0 && ((len(cardsTypeMap[Four_Bomb]) > 0 && lastHandCardnum <= 2) || handCardnum <= 2) { minKey := findMinKey(cardsTypeMap[Four_Bomb]) outCards = cardsTypeMap[Four_Bomb][minKey] } } if !IsPressed(isYuLe, isEnd, otherCards, lastCards, data, pos, lastPos, nextPos, handCardnum, Triple) { outCards = []int32{} } logger.Logger.Trace("--------------三张压牌完毕,出的牌:", outCards) return outCards case Four_Bomb: //炸弹 cardsMap := cardsTypeMap[Four_Bomb] for _, card := range cardsMap { if Value(card[0]) > Value(lastCards[0]) { logger.Logger.Trace("--------------炸弹压牌,找到的牌:", outCards) if isYuLe && (lastHandCardnum <= 2 || handCardnum <= 2) { return card } if !isYuLe { return card } } } if !IsPressed(isYuLe, isEnd, otherCards, lastCards, data, pos, lastPos, nextPos, handCardnum, Four_Bomb) { outCards = []int32{} } case Straight_Triple: //三顺 cardsMap := cardsTypeMap[Straight_Triple] if len(cardsMap) > 0 { for _, card := range cardsMap { if Value(card[0]) > Value(lastCards[0]) && len(card) == len(lastCards) { outCards = card break } } } if isYuLe { //找炸弹 if (len(outCards) == 0 || len(outCards) != len(lastCards)) && len(cardsTypeMap[Four_Bomb]) > 0 { minKey := findMinKey(cardsTypeMap[Four_Bomb]) outCards = cardsTypeMap[Four_Bomb][minKey] } } if !IsPressed(isYuLe, isEnd, otherCards, lastCards, data, pos, lastPos, nextPos, handCardnum, Straight_Triple) { outCards = []int32{} } logger.Logger.Trace("--------------三顺压牌完毕,出的牌:", outCards) return outCards case Plane_Single: //三代单 --不用考虑 只有最后一首才会出三代单 singleHand, singleLen := FindPlaneSingleHead(lastCards) logger.Logger.Trace("飞机找带双 singleHand = ", singleHand, "singleLen = ", singleLen) if singleLen > 1 && len(cards) >= len(lastCards) { //333 444 5 6 7 8 //找相同长度三顺 straightTripleMap := cardsTypeMap[Straight_Triple] if len(straightTripleMap) > 0 { for _, straightTriple := range straightTripleMap { if len(straightTriple)/3 >= singleLen { if Value(straightTriple[len(straightTriple)-1]) > int(singleHand) { outCards = straightTriple[len(straightTriple)-singleLen*3:] } } } } } if len(outCards) != 0 { copyCards := make([]int32, len(cards)) copy(copyCards, cards) delCard := make(map[int32][]int32) delCard[0] = outCards copyCards = DelCards(copyCards, delCard) copyCards = DelCards(copyCards, cardsTypeMap[Four_Bomb]) num := len(cards) - len(lastCards) if num == 1 { //留最大牌 outCards = []int32{} maxCard := copyCards[len(copyCards)-1:] for _, card := range cards { if card == maxCard[0] { continue } outCards = append(outCards, card) } } else if num == 2 { //留对子 _, pairMap := GetPair(copyCards) if len(pairMap) > 0 { outCards = []int32{} maxPair := -1 maxKey := int32(0) for i, pair := range pairMap { if Value(pair[0]) > maxPair { maxPair = Value(pair[0]) maxKey = i } } for _, card := range cards { if card == pairMap[maxKey][0] || card == pairMap[maxKey][1] { continue } outCards = append(outCards, card) } } else { //留最后两张大牌 outCards = []int32{} maxCard := copyCards[len(copyCards)-2:] for _, card := range cards { if card == maxCard[0] || card == maxCard[1] { continue } outCards = append(outCards, card) } } } else if num == 3 { //留顺子 straights := cardsTypeMap[Straight] if len(straights) > 0 { outCards = []int32{} straight := straights[int32(len(straights)-1)] saveCards := straight[len(straight)-3:] for _, card := range cards { if card == saveCards[0] || card == saveCards[1] || card == saveCards[2] { continue } outCards = append(outCards, card) } } else { //留最后三张大牌 outCards = []int32{} maxCard := copyCards[len(copyCards)-3:] for _, card := range cards { if card == maxCard[0] || card == maxCard[1] || card == maxCard[2] { continue } outCards = append(outCards, card) } } } else { for _, value := range cards { status := true for _, straight := range outCards { if value == straight || Value(value) == Value(straight) { status = false break } } if status { outCards = append(outCards, value) } if len(outCards) == len(lastCards) { break } } } } if isYuLe { //找炸弹 if (len(outCards) == 0 || len(outCards) != len(lastCards)) && len(cardsTypeMap[Four_Bomb]) > 0 { minKey := findMinKey(cardsTypeMap[Four_Bomb]) return cardsTypeMap[Four_Bomb][minKey] } } if !IsPressed(isYuLe, isEnd, otherCards, lastCards, data, pos, lastPos, nextPos, handCardnum, Plane_Single) { outCards = []int32{} } logger.Logger.Trace("--------------飞机带单压牌完毕,出的牌:", outCards) return outCards case Plane_Twin: outCards = []int32{} twinHand, twinLen := FindPlaneTwinHead(lastCards) logger.Logger.Trace("飞机找带双 twinHand = ", twinHand, "twinLen = ", twinLen) if twinLen == 1 { //三代双 cardsMap := cardsTypeMap[Triple] key := int32(999) for i, data1 := range cardsMap { if Value(data1[len(data1)-1]) > int(twinHand) { if i < key { //card = data1 key = i } break } } if key != 999 { outCards = cardsTypeMap[Triple][key] } if len(outCards) > 0 { minSingleKey := findMinKey(cardsTypeMap[Single]) minTwinKey := findMinKey(cardsTypeMap[Twin]) if len(cardsTypeMap[Single]) >= 2 && Value(cardsTypeMap[Single][minSingleKey][0]) < 12 { //三代2单 if len(cardsTypeMap[Single]) >= 2 { minValue := FindSmallestTwoValues(cardsTypeMap[Single]) //logger.Logger.Trace("找出最小两张单排的值:", minValue) outCards = append(outCards, minValue[0], minValue[1]) } } else if len(cardsTypeMap[Twin]) >= 1 && Value(cardsTypeMap[Twin][minTwinKey][0]) < 11 { //三代一对 outCards = append(outCards, cardsTypeMap[Twin][minTwinKey][0], cardsTypeMap[Twin][minTwinKey][1]) //logger.Logger.Trace("压牌,三代一对: ", card) } else { //直接找最小的两张牌 if len(cards) >= 5 { for _, value := range cards { if Value(value) != Value(outCards[0]) { outCards = append(outCards, value) if len(outCards) == 5 { return outCards } } } } } } } else { //333 444 555 //找相同长度三顺 if len(cards) >= len(lastCards) { straightTripleMap := cardsTypeMap[Straight_Triple] if len(straightTripleMap) > 0 { for _, straightTriple := range straightTripleMap { if len(straightTriple)/3 >= twinLen { if Value(straightTriple[len(straightTriple)-1]) > int(twinHand) { outCards = straightTriple[len(straightTriple)-twinLen*3:] } } } } if len(outCards) != 0 { copyCards := make([]int32, len(cards)) copy(copyCards, cards) delCard := make(map[int32][]int32) delCard[0] = outCards copyCards = DelCards(copyCards, delCard) copyCards = DelCards(copyCards, cardsTypeMap[Four_Bomb]) num := len(cards) - len(lastCards) if num == 1 { //留最大牌 outCards = []int32{} maxCard := copyCards[len(copyCards)-1:] for _, card := range cards { if card == maxCard[0] { continue } outCards = append(outCards, card) } } else if num == 2 { //留对子 _, pairMap := GetPair(copyCards) if len(pairMap) > 0 { maxPair := -1 maxKey := int32(0) for i, pair := range pairMap { if Value(pair[0]) > maxPair { maxPair = Value(pair[0]) maxKey = i } } outCards = []int32{} for _, card := range cards { if card == pairMap[maxKey][0] || card == pairMap[maxKey][1] { continue } outCards = append(outCards, card) } } else { //留最后两张大牌 maxCard := copyCards[len(copyCards)-2:] for _, card := range cards { if card == maxCard[0] || card == maxCard[1] { continue } outCards = append(outCards, card) } } } else if num == 3 { //留顺子 straights := cardsTypeMap[Straight] if len(straights) > 0 { outCards = []int32{} straight := straights[int32(len(straights)-1)] saveCards := straight[len(straight)-3:] for _, card := range cards { if card == saveCards[0] || card == saveCards[1] || card == saveCards[2] { continue } outCards = append(outCards, card) } } else { //留最后三张大牌 maxCard := copyCards[len(copyCards)-3:] outCards = []int32{} for _, card := range cards { if card == maxCard[0] || card == maxCard[1] || card == maxCard[2] { continue } outCards = append(outCards, card) } } } else { for _, value := range cards { status := true for _, straight := range outCards { if value == straight || Value(value) == Value(straight) { status = false break } } if status { outCards = append(outCards, value) } if len(outCards) == len(lastCards) { break } } } } } } if isYuLe { //找炸弹 if len(outCards) == 0 && len(cardsTypeMap[Four_Bomb]) > 0 && (lastHandCardnum <= 2 || handCardnum <= 2) { minKey := findMinKey(cardsTypeMap[Four_Bomb]) return cardsTypeMap[Four_Bomb][minKey] } } if !IsPressed(isYuLe, isEnd, otherCards, lastCards, data, pos, lastPos, nextPos, handCardnum, Plane_Twin) { outCards = []int32{} } logger.Logger.Trace("--------------三代双压牌完毕,出的牌:", outCards) return outCards default: logger.Logger.Trace("--------------default压牌完毕,出的牌:", outCards) return outCards } } logger.Logger.Trace("--------------压牌完毕,出的牌:", outCards) return outCards } // 出牌 isMin是否先手出最小的牌 func GetOutCards(cards []int32, data *tienlenApi.PredictRequest, pos int32) []int32 { logger.Logger.Trace("---------------出牌开始-------------------") sort.Slice(cards, func(i, j int) bool { if Value(cards[i]) == Value(cards[j]) { return cards[i] < cards[j] } return Value(cards[i]) < Value(cards[j]) }) isWin := data.IsWin //测试代码 isWin = true logger.Logger.Trace("出牌 调控输赢 isWin = ", isWin) //测试代码 //cards = []int32{51, 4, 5} //pos = 0 //data.Cards_left_2 = []int32{0, 1, 2, 3} //data.Cards_left_3 = nil //data.Cards_left_1 = nil //data.Last_pos = 2 isYuLe := data.IsTienLenYule isMin := data.IsFirstHand isEnd := data.IsEnd winSnids := data.WinSnids //获取牌型 cardsTypeMap := GetCardsType(cards, isYuLe) //map[int]map[int32][]int32 cardsTypeMap = reloadcardsType(cardsTypeMap, pos, data, isYuLe) logger.Logger.Trace("出牌 获取我的牌型:", cardsTypeMap, "\n") score, handNum := GetCardTypeScore(cardsTypeMap, isYuLe, cards) logger.Logger.Tracef("出牌 获取当前手牌的牌型分数:%v, 手牌数量:%v\n,我的位置:%d \n", score, handNum, pos) if handNum <= 1 { logger.Logger.Trace("只剩最后一手牌 直接全出了", cards) return cards } //出牌逻辑 outCards := []int32{} cardValue := -1 if isMin { outCards = GetMinCardType(cards[0], cardsTypeMap, isYuLe) logger.Logger.Trace("先出第一手,当前出牌只能出最小的牌!", outCards) return outCards } //判断其他玩家剩余的牌的牌型是否能压过当前出牌的牌型 //出牌顺序 //出单张 判断下一家剩余1张牌且剩余的牌比我出的牌大 不出 otherMinHandNum, otherMinCardsNum, otherPos, otherCardsType := getOtherMinCards(pos, data, isYuLe) logger.Logger.Tracef("玩家出牌,获取其他玩家最小剩余手数 和剩余牌数及位置剩余的牌型 otherMinHandNum=%d otherMinCardsNum=%d otherPos=%d cardsType=%d", otherMinHandNum, otherMinCardsNum, otherPos, otherCardsType) //优先出三张 如果是娱乐模式 直接带单张 或者最小的对子 if isYuLe { outCards, cardValue = getTriple(cardsTypeMap, cards, isYuLe, otherMinHandNum, pos, int32(otherPos), data) logger.Logger.Tracef("出三张 cardValue = %d ,outCards = %d", cardValue, outCards) } //出单张 if len(outCards) == 0 && handNum > 2 { straightNum := len(cardsTypeMap[Straight]) //测试一下 //if isYuLe { if len(cardsTypeMap[Straight]) > 0 { straightNum = len(cardsTypeMap[Straight])*2 + 1 } //} if len(cardsTypeMap[Single]) > straightNum && len(cardsTypeMap[Single]) > (len(cardsTypeMap[Twin])+len(cardsTypeMap[Straight_Twin])) { outCards = getSingle(cardsTypeMap, cards, isYuLe) if len(outCards) > 0 && isWin { if otherMinHandNum == 1 && otherMinCardsNum <= 1 && otherCardsType == Single { otherCards := getOtherPlayerCards(pos, int32(otherPos), data) if Value(cards[0]) < Value(otherCards[0]) { logger.Logger.Trace("出单张,其他玩家只剩一首牌 且剩余的牌比我出的牌大 不出!outCards = ", outCards) outCards = []int32{} } else if Value(cards[0]) == Value(otherCards[0]) { //判断花色 if Color(cards[0]) < Color(otherCards[0]) { logger.Logger.Trace("出单张,牌值相同,花色小,不出!outCards = ", outCards) outCards = []int32{} } } otherCardsMap := getOtherCards(pos, data) for _, single := range cardsTypeMap[Single] { status := true for _, other := range otherCardsMap { if len(other) == 1 { if Value(single[0]) <= Value(other[0]) { if Value(single[0]) == Value(other[0]) && Color(single[0]) > Color(other[0]) { continue } status = false } } } if status { outCards = single break } } } //如果是全场最大的单张 不出 if len(outCards) > 0 && (otherMinCardsNum != 1) { if Value(outCards[0]) == 12 && handNum > 2 { outCards = []int32{} } } } } } //出对子 判断下一家剩余2张牌且剩余的牌比我出的牌大 不出 if len(outCards) == 0 { straightNum := len(cardsTypeMap[Straight]) if isYuLe { //straightNum = len(cardsTypeMap[Straight]) if len(cardsTypeMap[Straight]) > 0 { straightNum = len(cardsTypeMap[Straight])*2 + 1 } } if len(cardsTypeMap[Twin]) > straightNum { outCards = getTwin(cardsTypeMap, cards, isYuLe) if len(outCards) > 0 && isWin { logger.Logger.Tracef("------首牌出对子 outcards = %d\n,所有的对子:%d\n", outCards, cardsTypeMap[Twin]) otherCards := getOtherPlayerCards(pos, int32(otherPos), data) if otherMinHandNum == 1 && otherMinCardsNum == 2 && otherCardsType == Twin { if Value(outCards[1]) < Value(otherCards[1]) { logger.Logger.Trace("出对子,其他玩家只剩一首牌 且剩余的牌比我出的牌大 不出!outCards = ", outCards) outCards = []int32{} } else if Value(outCards[1]) == Value(otherCards[1]) { //判断花色 if Color(outCards[1]) < Color(otherCards[1]) { logger.Logger.Trace("出对子,牌值相同,花色小,不出!outCards = ", outCards) outCards = []int32{} } } } otherCardsMap := getOtherCards(pos, data) for _, twin := range cardsTypeMap[Twin] { if Value(twin[0]) == 12 && handNum > 2 { continue } for _, other := range otherCardsMap { _, otherRuleType := RulePopEnable(other) if len(other) == 2 && otherRuleType == Twin { if Value(twin[1]) >= Value(other[1]) { if Value(twin[1]) == Value(other[1]) { if Color(twin[0]) > Color(other[0]) { outCards = twin break } else { continue } } outCards = twin break } } } } } } } //出三张 if isYuLe { if len(outCards) == 0 { outCards, cardValue = getTriple(cardsTypeMap, cards, isYuLe, otherMinHandNum, pos, int32(otherPos), data) if len(outCards) > 0 { if otherMinHandNum == 1 && otherMinCardsNum >= 3 && otherCardsType == Triple { otherCards := getOtherPlayerCards(pos, int32(otherPos), data) //获取牌型 otherCardsTypeMap := GetCardsType(otherCards, isYuLe) otherTriple := otherCardsTypeMap[Triple] //找最小key if len(otherTriple) > 0 { otherMinKey := findMinKey(otherTriple) if cardValue < Value(otherTriple[otherMinKey][0]) { logger.Logger.Trace("出三张,其他玩家只剩一首牌 且剩余的牌比我出的牌大 不出!outCards = ", outCards) outCards = []int32{} } } } } } } //顺子 if len(outCards) == 0 { outCards = getStraight(cardsTypeMap, cards, isYuLe) if len(outCards) > 0 && isWin { if otherMinHandNum == 1 && otherMinCardsNum == len(outCards) && otherCardsType == Straight { otherCards := getOtherPlayerCards(pos, int32(otherPos), data) if Value(outCards[len(outCards)-1]) < Value(otherCards[len(otherCards)-1]) { logger.Logger.Trace("出顺子,其他玩家只剩一首牌 且剩余的牌比我出的牌大 不出!outCards = ", outCards) outCards = []int32{} } else if Value(outCards[len(outCards)-1]) == Value(otherCards[len(otherCards)-1]) { //判断花色 if Color(outCards[len(outCards)-1]) < Color(otherCards[len(otherCards)-1]) { logger.Logger.Trace("出顺子,牌值相同,花色小,不出!outCards = ", outCards) outCards = []int32{} } } } //如果其他玩家剩余牌全是顺子 并且比我的大 我不出顺子了 (后续没牌型可出了!!!! } } if !isYuLe { if len(outCards) == 0 { outCards, cardValue = getTriple(cardsTypeMap, cards, isYuLe, otherMinHandNum, pos, int32(otherPos), data) if len(outCards) > 0 && isWin { if otherMinHandNum == 1 && otherMinCardsNum >= 3 && otherCardsType == Triple { otherCards := getOtherPlayerCards(pos, int32(otherPos), data) //获取牌型 otherCardsTypeMap := GetCardsType(otherCards, isYuLe) otherTriple := otherCardsTypeMap[Triple] //找最小key if len(otherTriple) > 0 { otherMinKey := findMinKey(otherTriple) if cardValue < Value(otherTriple[otherMinKey][0]) { logger.Logger.Trace("出三张,其他玩家只剩一首牌 且剩余的牌比我出的牌大 不出!outCards = ", outCards) outCards = []int32{} } } } } } } //连对 if len(outCards) == 0 { outCards = getStraightTwin(cardsTypeMap, cards, isYuLe) if len(outCards) > 0 && isWin { if otherMinHandNum == 1 && otherMinCardsNum == len(outCards) && otherCardsType == Straight_Twin { otherCards := getOtherPlayerCards(pos, int32(otherPos), data) if Value(outCards[len(outCards)-1]) < Value(otherCards[len(otherCards)-1]) { logger.Logger.Trace("出连对,其他玩家只剩一首牌 且剩余的牌比我出的牌大 不出!outCards = ", outCards) outCards = []int32{} } else if Value(outCards[len(outCards)-1]) == Value(otherCards[len(otherCards)-1]) { //判断花色 if Color(outCards[len(outCards)-1]) < Color(otherCards[len(otherCards)-1]) { logger.Logger.Trace("出连队,牌值相同,花色小,不出!outCards = ", outCards) outCards = []int32{} } } } } if len(outCards)/2 >= 3 && handNum > 2 { outCards = []int32{} } } //炸弹 这个就不用检查了 if len(outCards) == 0 && handNum <= 2 { if isYuLe { if len(cardsTypeMap[Triple]) < 2 && len(cards) < 13 { outCards = getBomb(cardsTypeMap, cards, isYuLe) } } else { //出炸弹 outCards = getBomb(cardsTypeMap, cards, isYuLe) } } //额外判断 //获取下一家的位置和剩余的牌 if isWin { if handNum <= 2 { //判断我的剩余牌型中有没有全场最大的牌型 for cardType, myCards := range cardsTypeMap { //map[int]map[int32][]int32 for _, mycard := range myCards { if getMaxCardTypeNum(cardType, mycard, pos, data) { logger.Logger.Trace("最后两手牌,找到最大牌型,mycard:", mycard) if cardType == Triple { //出三代二 outCards, cardValue = getTriple(cardsTypeMap, cards, isYuLe, otherMinHandNum, pos, int32(otherPos), data) if len(outCards) > 0 { return outCards } else { continue } } return mycard } } } } if (handNum <= 3 && isYuLe && len(cardsTypeMap[Triple]) == 0) || (handNum <= 3 && !isYuLe) { myMaxCardStatus, maxCardNum, maxCardsArr := getMaxCards(cards, data, pos) if len(outCards) == 1 { //判断当前最大牌在不在我手 if !myMaxCardStatus { //找最长的牌 for cardType, myCards := range cardsTypeMap { //map[int]map[int32][]int32 for _, mycard := range myCards { if (cardType == Straight_Twin && len(mycard)/2 >= 3) || cardType == Four_Bomb { //手里有连炸 continue } if len(mycard) > len(outCards) { if cardType == Triple { //出三代二 outCards, cardValue = getTriple(cardsTypeMap, cards, isYuLe, otherMinHandNum, pos, int32(otherPos), data) if len(outCards) > 0 { return outCards } else { break } } if cardType != Single && cardType != Twin { outCards = mycard } else { if Value(mycard[0]) != Value(cards[len(cards)-1]) { outCards = mycard } } } } } } } //获取我最大牌的 if myMaxCardStatus { if otherMinCardsNum > 1 { //这个时候我应该出单牌 //找单张 - 对子- 和最大牌数量相等的顺子长度+1的顺子 status := false if len(cardsTypeMap[Single]) > 0 { card := getSingle(cardsTypeMap, cards, isYuLe) if card[0] != maxCardsArr[len(maxCardsArr)-1] { status = true } } if len(cardsTypeMap[Single]) > 0 && status { card := getSingle(cardsTypeMap, cards, isYuLe) if len(card) > 0 { outCards = card } } else if len(cardsTypeMap[Twin]) > 0 { minKey := findMinKey(cardsTypeMap[Twin]) //map[int]map[int32][]int32 if cardsTypeMap[Twin][minKey] != nil { outCards = []int32{cardsTypeMap[Twin][minKey][0]} } logger.Logger.Trace("对子拆单张出!") } else { if maxCardNum > 1 { //先找顺子的交集 result := FindIntersection(cardsTypeMap[Straight]) if len(result) > 0 { sort.Slice(cards, func(i, j int) bool { if Value(cards[i]) == Value(cards[j]) { return cards[i] < cards[j] } return Value(cards[i]) < Value(cards[j]) }) if len(result) > 0 { for _, arr := range result { outCards = arr break } } } else if len(cardsTypeMap[Straight]) > 0 { minLength := 13 minKey := int32(0) for i, straight := range cardsTypeMap[Straight] { if len(straight) < minLength { minKey = i } } if len(cardsTypeMap[Straight][minKey]) <= maxCardNum+1 { outCards = []int32{cardsTypeMap[Straight][minKey][0]} logger.Logger.Trace("拆顺子,出单张!outCards = ", outCards) } } } } } } } } //最后直接出最小牌型的牌 if len(outCards) == 0 { //直接出最大的单牌 if otherMinHandNum == 1 { //先找其他牌型 for cardType, card := range cardsTypeMap { if len(card) > 0 { if cardType != Single { minKey := findMinKey(card) outCards = card[minKey] logger.Logger.Trace("最后直接先出其他牌型的牌 outCards = ", outCards) break } else if cardType == Triple && isYuLe { //找两张单张 minSingleKey := findMinKey(cardsTypeMap[Single]) minTwinKey := findMinKey(cardsTypeMap[Twin]) if len(cardsTypeMap[Single]) >= 2 && Value(cardsTypeMap[Single][minSingleKey][0]) < 12 { //三代2单 if len(cardsTypeMap[Single]) >= 2 { minValue := FindSmallestTwoValues(cardsTypeMap[Single]) outCards = append(outCards, minValue[0], minValue[1]) } } else if len(cardsTypeMap[Twin]) >= 1 && Value(cardsTypeMap[Twin][minTwinKey][0]) < 11 { //三代一对 outCards = append(outCards, cardsTypeMap[Twin][minTwinKey][0], cardsTypeMap[Twin][minTwinKey][1]) } } } } if len(outCards) == 0 { nextPos, nextCards := GetNextPos(pos, data) otherCards := getOtherPlayerCards(pos, int32(otherPos), data) if nextPos != int32(otherPos) && Value(nextCards[len(nextCards)-1]) > Value(otherCards[0]) { //找最小牌型的牌 outCards = GetMinCardType(cards[0], cardsTypeMap, isYuLe) logger.Logger.Trace("最后直接找最小牌型的牌,让下一家顶上 outCards = ", outCards) } else { lastPos, _ := GetLastPos(pos, data) if isEnd && len(winSnids) == 0 && nextPos != lastPos { //找最小牌型的牌 outCards = GetMinCardType(cards[0], cardsTypeMap, isYuLe) logger.Logger.Trace("打到底模式 最后直接找最小牌型的牌, outCards = ", outCards) } else { if otherMinHandNum > 2 { //找最小牌型的牌 outCards = GetMinCardType(cards[0], cardsTypeMap, isYuLe) logger.Logger.Trace("打到底模式 最后直接找最小牌型的牌, outCards = ", outCards) } else { outCards = []int32{cards[len(cards)-1]} logger.Logger.Trace("最后直接出最大的牌 outCards = ", outCards) } } } } } else { //找最小牌型的牌 outCards = GetMinCardType(cards[0], cardsTypeMap, isYuLe) logger.Logger.Trace("最后直接找最小牌型的牌 outCards = ", outCards) } } logger.Logger.Trace("---------------------------出牌结束 出的牌:", outCards) return outCards } // 判断牌型是否全场最大 func getMaxCardTypeNum(cardsType int, cards []int32, pos int32, data *tienlenApi.PredictRequest) bool { //map[int][]int32 status := true otherCardsMap := getOtherCards(pos, data) for _, otherCards := range otherCardsMap { if len(otherCards) == 0 { continue } sort.Slice(otherCards, func(i, j int) bool { if Value(otherCards[i]) == Value(otherCards[j]) { return otherCards[i] < otherCards[j] } return Value(otherCards[i]) < Value(otherCards[j]) }) if cardsType == Single { if len(otherCards) > 0 && len(cards) > 0 { if Value(otherCards[len(otherCards)-1]) >= Value(cards[0]) { if Value(otherCards[len(otherCards)-1]) == Value(cards[0]) { if Color(otherCards[len(otherCards)-1]) > Color(cards[0]) { return false } } else { return false } } } } else if cardsType == Twin { _, pairMap := GetPair(otherCards) if len(pairMap) > 0 { for _, pair := range pairMap { if Value(pair[len(pair)-1]) >= Value(cards[0]) { if Value(pair[len(pair)-1]) == Value(cards[0]) { if Color(pair[len(pair)-1]) > Color(cards[0]) { return false } } else { return false } } } } } otherCardsTypeMap := GetCardsType(otherCards, data.IsTienLenYule) //map[int]map[int32][]int32 if otherCardsTypeMap[cardsType] != nil && len(otherCardsTypeMap[cardsType]) > 0 { for _, cardsArr := range otherCardsTypeMap[cardsType] { if len(cardsArr) < len(cards) { continue } if Value(cardsArr[len(cardsArr)-1]) > Value(cards[len(cards)-1]) { status = false break } else if Value(cardsArr[len(cardsArr)-1]) == Value(cards[len(cards)-1]) { if Color(cardsArr[len(cardsArr)-1]) > Color(cards[len(cards)-1]) { status = false break } } } if !status { break } } } return status } // 出单张 func getSingle(cardsTypeMap map[int]map[int32][]int32, cards []int32, isYuLe bool) []int32 { outCards := []int32{} if isYuLe { if len(cardsTypeMap[Triple]) == 0 { minKey := findMinKey(cardsTypeMap[Single]) outCards = cardsTypeMap[Single][minKey] } } else { minKey := findMinKey(cardsTypeMap[Single]) outCards = cardsTypeMap[Single][minKey] } return outCards } // 出对子 func getTwin(cardsTypeMap map[int]map[int32][]int32, cards []int32, isYuLe bool) []int32 { outCards := []int32{} _, handNum := GetCardTypeScore(cardsTypeMap, isYuLe, cards) if len(cardsTypeMap[Twin]) > len(cardsTypeMap[Straight]) { minKey := findMinKey(cardsTypeMap[Twin]) if isYuLe { if len(cardsTypeMap[Triple]) == 0 { if Value(cardsTypeMap[Twin][minKey][0]) < 11 || (handNum <= 2 && len(cardsTypeMap[Triple]) == 0) { outCards = cardsTypeMap[Twin][minKey] } } } else { if Value(cardsTypeMap[Twin][minKey][0]) < 11 || (handNum <= 2 && len(cardsTypeMap[Triple]) == 0) { outCards = cardsTypeMap[Twin][minKey] } } } return outCards } // 出三张 cardValue三张的值 value(card) func getTriple(cardsTypeMap map[int]map[int32][]int32, cards []int32, isYuLe bool, otherMinHandNum int, mypos, otherPos int32, data *tienlenApi.PredictRequest) ([]int32, int) { outCards := []int32{} cardValue := 0 _, handNum := GetCardTypeScore(cardsTypeMap, isYuLe, cards) if isYuLe && len(cardsTypeMap[Straight_Triple]) > 0 { //AI机器人三顺的长度只能是2 大于2的直接拆成连对炸弹了 outCards = []int32{} if len(cards) <= 10 && len(cardsTypeMap[Four_Bomb]) == 0 { return cards, cardValue } else { copyCards := make([]int32, len(cards)) copy(copyCards, cards) copyCards = DelCards(copyCards, cardsTypeMap[Straight_Triple]) copyCards = DelCards(copyCards, cardsTypeMap[Four_Bomb]) sort.Slice(copyCards, func(i, j int) bool { if Value(copyCards[i]) == Value(copyCards[j]) { return copyCards[i] < copyCards[j] } return Value(copyCards[i]) < Value(copyCards[j]) }) num := len(cards) - 10 if num == 1 { //留最大牌 maxCard := copyCards[len(copyCards)-1:] for _, card := range cards { if card == maxCard[0] { continue } outCards = append(outCards, card) } } else if num == 2 { //留对子 _, pairMap := GetPair(copyCards) if len(pairMap) > 0 { maxPair := -1 maxKey := int32(0) for i, pair := range pairMap { if Value(pair[0]) > maxPair { maxPair = Value(pair[0]) maxKey = i } } for _, card := range cards { if card == pairMap[maxKey][0] || card == pairMap[maxKey][1] { continue } outCards = append(outCards, card) } } else { //留最后两张大牌 maxCard := copyCards[len(copyCards)-2:] for _, card := range cards { if card == maxCard[0] || card == maxCard[1] { continue } outCards = append(outCards, card) } } } else if num == 3 { //留顺子 straights := cardsTypeMap[Straight] if len(straights) > 0 { straight := straights[int32(len(straights)-1)] saveCards := straight[len(straight)-3:] for _, card := range cards { if card == saveCards[0] || card == saveCards[1] || card == saveCards[2] { continue } outCards = append(outCards, card) } } else { //留最后三张大牌 maxCard := copyCards[len(copyCards)-3:] for _, card := range cards { if card == maxCard[0] || card == maxCard[1] || card == maxCard[2] { continue } outCards = append(outCards, card) } } } else { //直接出三顺 straightTripleMap := cardsTypeMap[Straight_Triple] for _, straightTriple := range straightTripleMap { outCards = straightTriple break } } } logger.Logger.Trace("-----------出三顺--------------------", outCards) return outCards, cardValue } if len(cardsTypeMap[Triple]) > 0 { minSingleKey := findMinKey(cardsTypeMap[Single]) minTwinKey := findMinKey(cardsTypeMap[Twin]) minTripleKey := findMinKey(cardsTypeMap[Triple]) if len(cardsTypeMap[Triple]) == 2 && len(cards) <= 9 { //先出大的三条 minTripleKey = findMaxKey(cardsTypeMap[Triple]) } if len(cardsTypeMap[Triple]) >= 2 && len(cards) <= 8 && isYuLe { //判断单张数量 if len(cardsTypeMap[Single]) < 2 { //判断是不是三顺 var arr []int32 for _, three := range cardsTypeMap[Triple] { for _, value := range three { arr = append(arr, value) } } StraightTripleMap := GetStraightTriple(arr) if len(StraightTripleMap) > 0 { //娱乐场 小于11张牌可以一首扔 return cards, cardValue } } } if isYuLe { //出三代2 或三带一小对 单张小于12 三顺小于等于7 otherCard := getOtherPlayerCards(mypos, otherPos, data) if len(cardsTypeMap[Single]) >= 2 && (Value(cardsTypeMap[Single][minSingleKey][0]) < 12 || handNum <= 2 || (otherMinHandNum == 1 && len(otherCard) == 1 && len(cardsTypeMap[Single]) >= 3)) { //三代2单 if Value(cardsTypeMap[Triple][minTripleKey][0]) <= 9 || handNum <= 2 || (otherMinHandNum == 1 && len(otherCard) == 1 && len(cardsTypeMap[Single]) >= 3) { outCards = cardsTypeMap[Triple][minTripleKey] minValue := FindSmallestTwoValues(cardsTypeMap[Single]) if len(minValue) < 2 { logger.Logger.Tracef("找出最小两张单排的值,没找出来!!!!!!!!!!!!!!!!!!!!!!!!!minValue = %v,cardsTypeMap[Single]= %v", minValue, cardsTypeMap[Single]) } else { outCards = append(outCards, minValue[0], minValue[1]) } } } else if len(cardsTypeMap[Twin]) >= 1 && (Value(cardsTypeMap[Twin][minTwinKey][0]) < 11 || handNum <= 3) { //三代一对 outCards = cardsTypeMap[Triple][minTripleKey] outCards = append(outCards, cardsTypeMap[Twin][minTwinKey][0], cardsTypeMap[Twin][minTwinKey][1]) } else { if len(cards) > 5 { outCards = cardsTypeMap[Triple][minTripleKey] if len(cardsTypeMap[Single]) > 0 { for _, single := range cardsTypeMap[Single] { outCards = append(outCards, single[0]) } } if len(outCards) < 5 { //找顺子交集 result := FindIntersection(cardsTypeMap[Straight]) if len(result) > 0 { sort.Slice(cards, func(i, j int) bool { if Value(cards[i]) == Value(cards[j]) { return cards[i] < cards[j] } return Value(cards[i]) < Value(cards[j]) }) } for _, cardArr := range result { for _, card := range cardArr { outCards = append(outCards, card) if len(outCards) == 5 { break } } if len(outCards) == 5 { break } } //找顺子 if len(outCards) < 5 { if len(cardsTypeMap[Straight]) > 0 { for _, straights := range cardsTypeMap[Straight] { //剩余俩个三张 一共8张牌 if len(straights)-(5-len(outCards)) >= 3 || (len(cards) == 10 && len(cardsTypeMap[Triple]) == 2) { for i := 0; i < 5-len(outCards); i++ { outCards = append(outCards, straights[i]) if len(outCards) == 5 { break } } if len(outCards) == 5 { break } } } } } } if len(outCards) != 5 { //直接出三张 outCards = cardsTypeMap[Triple][minTripleKey] } } else { //直接出三张 outCards = cardsTypeMap[Triple][minTripleKey] } } //出三张拦截 下面三手牌会判断牌型出 这里直接不让出三个2 if Value(cardsTypeMap[Triple][minTripleKey][0]) == 12 && handNum <= 3 && handNum != 1 && len(cards) >= 10 { logger.Logger.Trace("出三张 拦截 三个2 !!!!!!!!!!!!!!!") outCards = []int32{} return outCards, 0 } } else { outCards = cardsTypeMap[Triple][minTripleKey] if isYuLe { if len(cards) <= 5 { //最后4张牌 出三带1 outCards = cards } } } cardValue = Value(cardsTypeMap[Triple][minTripleKey][0]) } return outCards, cardValue } // 出顺子 func getStraight(cardsTypeMap map[int]map[int32][]int32, cards []int32, isYuLe bool) []int32 { outCards := []int32{} _, handNum := GetCardTypeScore(cardsTypeMap, isYuLe, cards) if len(cardsTypeMap[Straight]) >= 1 { //出顺子 //如果只剩两手牌 先出最长的顺子 if handNum <= 2 { //找长度最大的顺子 maxLength := 0 maxKey := int32(0) for i, straight := range cardsTypeMap[Straight] { if len(straight) > maxLength { maxKey = i } } outCards = cardsTypeMap[Straight][maxKey] } else { //找小顺子 outCards = cardsTypeMap[Straight][0] } } return outCards } // 出连对 func getStraightTwin(cardsTypeMap map[int]map[int32][]int32, cards []int32, isYuLe bool) []int32 { outCards := []int32{} if len(cardsTypeMap[Straight_Twin]) > 0 { //找长度最小的连对 length := 0 key := int32(0) for i, straight := range cardsTypeMap[Straight_Twin] { if len(straight) < length && len(straight) > 0 { key = i } } outCards = cardsTypeMap[Straight_Twin][key] } return outCards } // 出炸弹 func getBomb(cardsTypeMap map[int]map[int32][]int32, cards []int32, isYuLe bool) []int32 { outCards := []int32{} //炸弹 if len(cardsTypeMap[Four_Bomb]) > 0 { //出炸弹 minTripleKey := findMinKey(cardsTypeMap[Four_Bomb]) outCards = cardsTypeMap[Four_Bomb][minTripleKey] } return outCards } // ---------------------------------------------// // 找手里最小的牌的组合 func GetMinCardType(minCard int32, cardsType map[int]map[int32][]int32, isYuLe bool) []int32 { for cardType, cards := range cardsType { for _, cardArr := range cards { for i, card := range cardArr { if Value(card) == Value(minCard) { if card == minCard { if cardType == Triple && isYuLe { //找两张单张 minSingleKey := findMinKey(cardsType[Single]) minTwinKey := findMinKey(cardsType[Twin]) if len(cardsType[Single]) >= 2 && Value(cardsType[Single][minSingleKey][0]) < 12 { //三代2单 if len(cardsType[Single]) >= 2 { minValue := FindSmallestTwoValues(cardsType[Single]) cardArr = append(cardArr, minValue[0], minValue[1]) } } else if len(cardsType[Twin]) >= 1 && Value(cardsType[Twin][minTwinKey][0]) < 11 { //三代一对 cardArr = append(cardArr, cardsType[Twin][minTwinKey][0], cardsType[Twin][minTwinKey][1]) } } return cardArr } else { //替换牌 cardArr[i] = minCard if cardType == Triple && isYuLe { //找两张单张 变成三代二 minSingleKey := findMinKey(cardsType[Single]) minTwinKey := findMinKey(cardsType[Twin]) if len(cardsType[Single]) >= 2 && Value(cardsType[Single][minSingleKey][0]) < 12 { //三代2单 if len(cardsType[Single]) >= 2 { minValue := FindSmallestTwoValues(cardsType[Single]) cardArr = append(cardArr, minValue[0], minValue[1]) } } else if len(cardsType[Twin]) >= 1 && Value(cardsType[Twin][minTwinKey][0]) < 11 { //三代一对 cardArr = append(cardArr, cardsType[Twin][minTwinKey][0], cardsType[Twin][minTwinKey][1]) } } return cardArr } } } } } //直接返回单张 return []int32{minCard} } // 获取下一家的位置和剩余的牌 func GetNextPos(pos int32, data *tienlenApi.PredictRequest) (int32, []int32) { for i := 1; i < 4; i++ { nextPos := pos + int32(i) if nextPos > 3 { nextPos -= 4 } //判断这个位置有没有剩余牌 if nextPos == 0 && len(data.Cards_left_0) > 0 { return nextPos, data.Cards_left_0 } else if nextPos == 1 && len(data.Cards_left_1) > 0 { return nextPos, data.Cards_left_1 } else if nextPos == 2 && len(data.Cards_left_2) > 0 { return nextPos, data.Cards_left_2 } else if nextPos == 3 && len(data.Cards_left_3) > 0 { return nextPos, data.Cards_left_3 } } return -1, nil } // 获取上家的位置和剩余的牌 func GetLastPos(pos int32, data *tienlenApi.PredictRequest) (int32, []int32) { for i := 1; i < 4; i++ { nextPos := (pos - int32(i) + 4) % 4 //判断这个位置有没有剩余牌 if nextPos == 0 && len(data.Cards_left_0) > 0 { return nextPos, data.Cards_left_0 } else if nextPos == 1 && len(data.Cards_left_1) > 0 { return nextPos, data.Cards_left_1 } else if nextPos == 2 && len(data.Cards_left_2) > 0 { return nextPos, data.Cards_left_2 } else if nextPos == 3 && len(data.Cards_left_3) > 0 { return nextPos, data.Cards_left_3 } } return -1, nil } // 获取指定玩家的牌 func getOtherPlayerCards(mypos, otherPos int32, data *tienlenApi.PredictRequest) []int32 { otherCardsMap := getOtherCards(mypos, data) sort.Slice(otherCardsMap[int(otherPos)], func(i, j int) bool { if otherCardsMap[int(otherPos)][i] == otherCardsMap[int(otherPos)][j] { return otherCardsMap[int(otherPos)][i] < otherCardsMap[int(otherPos)][j] } return Value(otherCardsMap[int(otherPos)][i]) < Value(otherCardsMap[int(otherPos)][j]) }) return otherCardsMap[int(otherPos)] } // 判断自己手里有没有最大的牌 func getMaxCards(myCards []int32, data *tienlenApi.PredictRequest, mypos int32) (bool, int, []int32) { sort.Slice(myCards, func(i, j int) bool { if Value(myCards[i]) == Value(myCards[j]) { return myCards[i] < myCards[j] } return Value(myCards[i]) < Value(myCards[j]) }) //getOtherCards() otherCardsMap := getOtherCards(mypos, data) var otherCards []int32 for _, otherCard := range otherCardsMap { otherCards = append(otherCards, otherCard...) } sort.Slice(otherCards, func(i, j int) bool { if Value(otherCards[i]) == Value(otherCards[j]) { return otherCards[i] < otherCards[j] } return Value(otherCards[i]) < Value(otherCards[j]) }) maxCardNum := 0 status := false maxCardsArr := []int32{} for _, mycard := range myCards { if Value(mycard) >= Value(otherCards[len(otherCards)-1]) { if Value(mycard) == Value(otherCards[len(otherCards)-1]) { if Color(mycard) < Color(otherCards[len(otherCards)-1]) { continue } } maxCardNum += 1 status = true maxCardsArr = append(maxCardsArr, mycard) } } //排序返回 sort.Slice(maxCardsArr, func(i, j int) bool { if Value(maxCardsArr[i]) == Value(maxCardsArr[j]) { return maxCardsArr[i] < maxCardsArr[j] } return Value(maxCardsArr[i]) < Value(maxCardsArr[j]) }) return status, maxCardNum, maxCardsArr } func findMinKey(data map[int32][]int32) int32 { minValue := int32(math.MaxInt32) minKey := int32(-1) for i, value := range data { if int32(Value(value[0])) < minValue { minValue = int32(Value(value[0])) minKey = i } } return minKey } func findMaxKey(data map[int32][]int32) int32 { maxKey := int32(-1) for key := range data { if key > maxKey { maxKey = key } } return maxKey } // 获取其他玩家的牌 func getOtherCards(myPos int32, data *tienlenApi.PredictRequest) map[int][]int32 { otherCards := make(map[int][]int32) for i := 0; i < 4; i++ { if i == int(myPos) { continue } if i == 0 { otherCards[i] = data.Cards_left_0 } else if i == 1 { otherCards[i] = data.Cards_left_1 } else if i == 2 { otherCards[i] = data.Cards_left_2 } else if i == 3 { otherCards[i] = data.Cards_left_3 } } return otherCards } // 获取其他玩家最小剩余手数 和剩余牌数及位置剩余的牌型 func getOtherMinCards(myPos int32, data *tienlenApi.PredictRequest, isYuLe bool) (int, int, int, int) { otherCards := getOtherCards(myPos, data) otherMinHandNum := 100 otherMinCardsNum := 13 otherPos := -1 cardsType := -1 maxCards := []int32{} for i, other := range otherCards { //获取牌型 if len(other) > 0 { cardsTypeMap := GetCardsType(other, isYuLe) //剩余手数 _, handNum := GetCardTypeScore(cardsTypeMap, isYuLe, other) if handNum <= otherMinHandNum && len(other) <= otherMinCardsNum { if handNum == otherMinHandNum && len(other) <= otherMinHandNum { _, ruleType := RulePopEnable(other) if ruleType == cardsType { //相同牌型找最大的牌 if Value(other[len(other)-1]) < Value(maxCards[len(maxCards)-1]) { continue } } } otherMinHandNum = handNum otherMinCardsNum = len(other) otherPos = i maxCards = other if handNum <= 1 { isRule, ruleType := RulePopEnable(other) if isRule { cardsType = ruleType } else { //三张 三带一 三带二 cardsType = Triple } } } } } return otherMinHandNum, otherMinCardsNum, otherPos, cardsType } // 找到最小的两个值 func FindSmallestTwoValues(m map[int32][]int32) []int32 { // 创建一个切片存储map的键值对 pairs := make([][2]int32, 0) // 将map的键值对存储在切片中 for key := range m { pairs = append(pairs, [2]int32{key, key}) } // 对切片按照键值进行排序 sort.Slice(pairs, func(i, j int) bool { return pairs[i][0] < pairs[j][0] }) // 取出最小的两个值 var smallestTwo []int32 if len(pairs) >= 2 { smallestTwo = append(smallestTwo, m[pairs[0][0]]...) if len(m[pairs[1][0]]) > 0 { smallestTwo = append(smallestTwo, m[pairs[1][0]]...) } } else if len(pairs) == 1 { smallestTwo = m[pairs[0][0]] } return smallestTwo } // 找交集 func FindIntersection(arrays map[int32][]int32) [][]int32 { var result [][]int32 // 获取 map 中的键,并按顺序进行迭代 keys := make([]int32, 0, len(arrays)) for key := range arrays { keys = append(keys, key) } sort.Slice(keys, func(i, j int) bool { return keys[i] < keys[j] }) // 检查相邻的数组之间的交集 for i := 0; i < len(keys)-1; i++ { currentKey := keys[i] nextKey := keys[i+1] currentArray := arrays[currentKey] nextArray := arrays[nextKey] intersection := GetArrayIntersection(currentArray, nextArray) if intersection != nil { result = append(result, intersection) } } return result } // 获取两个切片的交集 func GetArrayIntersection(arr1, arr2 []int32) []int32 { // 创建一个 map 用于存储第一个切片中的元素 elements := make(map[int32]bool) for _, num := range arr1 { elements[num] = true } // 检查第二个切片中的元素是否在第一个切片中出现,如果是,则添加到结果中 var result []int32 for _, num := range arr2 { if elements[num] { result = append(result, num) } } return result } // 是否压牌 func IsPressed(isYuLe, isEnd bool, otherCards, lastCards []int32, data *tienlenApi.PredictRequest, pos, lastPos, nextPos int32, handCardnum, cardsType int) bool { if (!isYuLe && isEnd) && len(otherCards) == 0 { lastNextPos, _ := GetNextPos(lastPos, data) if lastNextPos == pos && nextPos != lastPos { if getMaxCardTypeNum(cardsType, lastCards, pos, data) && handCardnum > 2 { return false } if len(lastCards) > 0 { if Value(lastCards[0]) == 2 && handCardnum > 2 { return false } } } } return true } // 重组牌型 func reloadcardsType(cardsTypeMap map[int]map[int32][]int32, pos int32, data *tienlenApi.PredictRequest, isYuLe bool) map[int]map[int32][]int32 { //其他玩家只剩一张牌了 otherMinHandNum, otherMinCardsNum, otherPos, otherCardsType := getOtherMinCards(pos, data, isYuLe) //otherCards := getOtherPlayerCards(pos, int32(otherPos), data) //剩余两手 全是单牌 status := false allOtherCards := getOtherCards(pos, data) for _, otherCards := range allOtherCards { if len(otherCards) == 2 { otherType := GetCardsType(otherCards, isYuLe) //剩余手数 _, handNum := GetCardTypeScore(otherType, isYuLe, otherCards) if handNum == 2 { otherMaxCard := otherCards[0] if Value(otherCards[0]) < Value(otherCards[1]) { otherMaxCard = otherCards[1] } if getMaxCardTypeNum(Single, []int32{otherMaxCard}, pos, data) { logger.Logger.Trace("玩家剩余2张牌且有一张全场最大的牌,重组牌型!otherCards = ", otherCards) status = true } } } } if (otherMinHandNum == 1 && otherMinCardsNum <= 1 && otherCardsType == Single) || status { //lastPos, _ := GetLastPos(pos, data) //nextPos, _ := GetNextPos(pos, data) //只考虑剩2人的情况下 //if nextPos == int32(otherPos) { //判断我手里的单牌 组对子 if len(cardsTypeMap[Single]) >= 2 { //判断如果单牌有2张以上小于其他玩家的牌,开始组对子 otherCards := getOtherPlayerCards(pos, int32(otherPos), data) minCards := map[int32]int32{} for i, card := range cardsTypeMap[Single] { if Value(card[0]) <= Value(otherCards[0]) { //判断花色 if Value(card[0]) == Value(otherCards[0]) { if Color(card[0]) < Color(otherCards[0]) { //minCards = append(minCards, card[0]) minCards[i] = card[0] continue } } else { //minCards = append(minCards, card[0]) minCards[i] = card[0] } } } //有超过两张的单牌小于其他玩家的牌,开始组对子 if len(minCards) >= 2 { //开始拆顺子 组对子 if len(cardsTypeMap[Straight]) > 0 { straightMap := cardsTypeMap[Straight] for delKey, minCard := range minCards { for straightKey, straight := range straightMap { if len(straight) <= 3 { continue } //先找最小的牌 if Value(straight[0]) == Value(minCard) { if cardsTypeMap[Twin] == nil { cardsTypeMap[Twin] = map[int32][]int32{} } cardsTypeMap[Twin][int32(Value(minCard))] = append(cardsTypeMap[Twin][int32(Value(minCard))], minCard, straight[0]) cardsTypeMap[Straight][straightKey] = cardsTypeMap[Straight][straightKey][1:] //删除单张 delete(cardsTypeMap[Single], delKey) break } else if Value(straight[len(straight)-1]) == Value(minCard) { if cardsTypeMap[Twin] == nil { cardsTypeMap[Twin] = map[int32][]int32{} } cardsTypeMap[Twin][int32(Value(minCard))] = append(cardsTypeMap[Twin][int32(Value(minCard))], minCard, straight[len(straight)-1]) cardsTypeMap[Straight][straightKey] = cardsTypeMap[Straight][straightKey][:len(straight)-1] //删除单张 delete(cardsTypeMap[Single], delKey) break } else { //找中间 暂时不做 情况太复杂了 需要考虑的太多 } } } } } } //} if len(cardsTypeMap[Single]) == 0 { delete(cardsTypeMap, Single) } if len(cardsTypeMap[Straight]) == 0 { delete(cardsTypeMap, Straight) } } return cardsTypeMap } // 获取所有玩家剩余的牌型 func GetAllOtherCardsType(data *tienlenApi.PredictRequest, pos int32, isYuLe bool) map[int]map[int]map[int32][]int32 { allOtherCardsType := map[int]map[int]map[int32][]int32{} for i := 1; i < 4; i++ { if i == int(pos) { continue } //判断这个位置有没有剩余牌 if i == 0 && len(data.Cards_left_0) > 0 { cardsTypeMap0 := GetCardsType(data.Cards_left_0, isYuLe) allOtherCardsType[i] = cardsTypeMap0 } else if i == 1 && len(data.Cards_left_1) > 0 { cardsTypeMap1 := GetCardsType(data.Cards_left_1, isYuLe) allOtherCardsType[i] = cardsTypeMap1 } else if i == 2 && len(data.Cards_left_2) > 0 { cardsTypeMap2 := GetCardsType(data.Cards_left_2, isYuLe) allOtherCardsType[i] = cardsTypeMap2 } else if i == 3 && len(data.Cards_left_3) > 0 { cardsTypeMap3 := GetCardsType(data.Cards_left_3, isYuLe) allOtherCardsType[i] = cardsTypeMap3 } } return allOtherCardsType } // 判断能不能出顺子 func IsOutStraight(data *tienlenApi.PredictRequest, pos int32, isYuLe bool, mycards []int32) (bool, int) { allOtherCardsType := GetAllOtherCardsType(data, pos, isYuLe) copyMap := make(map[int]map[int]map[int32][]int32) for k1, v1 := range allOtherCardsType { copyMap[k1] = make(map[int]map[int32][]int32) for k2, v2 := range v1 { copyMap[k1][k2] = make(map[int32][]int32) for k3, v3 := range v2 { copyMap[k1][k2][k3] = make([]int32, len(v3)) copy(copyMap[k1][k2][k3], v3) } } } for i, OtherCardsType := range copyMap { if len(OtherCardsType[Straight]) > 0 { for _, otherStraight := range OtherCardsType[Straight] { if len(otherStraight) >= len(mycards) { if len(otherStraight)-len(mycards) <= 2 { //说明要拆牌多出来2张,我可以出 } if Value(otherStraight[len(otherStraight)-1]) <= Value(mycards[len(mycards)-1]) { //判断花色 if Value(otherStraight[len(otherStraight)-1]) == Value(mycards[len(mycards)-1]) { if Color(otherStraight[len(otherStraight)-1]) < Color(mycards[len(mycards)-1]) { continue } } else { continue } } } } //判断剩余的牌是不是全是顺子 delete(OtherCardsType, Straight) if len(OtherCardsType) <= 1 { logger.Logger.Trace("全是顺子啊,还比我的大!!!!不能打顺子!") return false, i } } } return true, -1 }