package tienlen /* import ( "encoding/json" "fmt" "github.com/tealeg-new/xlsx" "math" "math/rand" "sort" "strconv" "testing" ) func TestCardsKu(t *testing.T) { fmt.Printf("生成牌库!!!!\n") file := xlsx.NewFile() sheet, err := file.AddSheet("Sheet1") if err != nil { fmt.Printf("Error creating sheet: %s\n", err) return } // 表头数据 header := []string{ "Id", "Card1", "Card1Score", "Card1HandNum", "Change1Cards", "Card2", "Card2Score", "Card2HandNum", "Change2Cards", "Card3", "Card3Score", "Card3HandNum", "Change3Cards", "Card4", "Card4Score", "Card4HandNum", "Change4Cards", } // 创建表头行 headerRow := sheet.AddRow() for _, column := range header { cell := headerRow.AddCell() cell.Value = column } allCards := map[int32][][]int32{} for { slice := []int32{12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39} // 使用 Fisher-Yates 算法对切片进行乱序处理 for i := len(slice) - 1; i > 0; i-- { j := rand.Intn(i + 1) slice[i], slice[j] = slice[j], slice[i] } // 确保切片长度为 52,以便均分为 4 份 if len(slice) != 52 { fmt.Println("切片长度不正确") return } // 将切片分成 4 份,每份 13 张牌 partSize := 13 parts := make([][]int32, 4) for i := 0; i < 4; i++ { startIndex := i * partSize endIndex := startIndex + partSize parts[i] = slice[startIndex:endIndex] } isYuLe := true // 打印分割后的每份牌 for i, part := range parts { //获取手数 和分数 cardsTypeMap := GetCardsType(part, isYuLe) score, handNum := GetCardTypeScore(cardsTypeMap, isYuLe, part) num := 3000 handSum := 6 if isYuLe { num = 4000 handSum = 4 } if score < num || handNum > handSum || score == 9999 { continue } fmt.Printf("生成第%d份牌,分数:%d,手数:%d\n", i+1, score, handNum) //写如到xlsx文件中 cards1TypeMap := GetCardsType(parts[0], true) score1, handNum1 := GetCardTypeScore(cards1TypeMap, true, part) cards2TypeMap := GetCardsType(parts[1], true) score2, handNum2 := GetCardTypeScore(cards2TypeMap, true, part) cards3TypeMap := GetCardsType(parts[2], true) score3, handNum3 := GetCardTypeScore(cards3TypeMap, true, part) cards4TypeMap := GetCardsType(parts[3], true) score4, handNum4 := GetCardTypeScore(cards4TypeMap, true, part) json1Data, _ := json.Marshal(parts[0]) json2Data, _ := json.Marshal(parts[1]) json3Data, _ := json.Marshal(parts[2]) json4Data, _ := json.Marshal(parts[3]) change1, _ := json.Marshal(CardsChange(parts[0])) change2, _ := json.Marshal(CardsChange(parts[1])) change3, _ := json.Marshal(CardsChange(parts[2])) change4, _ := json.Marshal(CardsChange(parts[3])) if score1 == 9999 || score2 == 9999 || score3 == 9999 || score4 == 9999 { break } scoreNum := 1000 if isYuLe { scoreNum = 2000 } if !areSlicesEqual(part, parts[0]) && score-score1 < scoreNum { break } if !areSlicesEqual(part, parts[1]) && score-score2 < scoreNum { break } if !areSlicesEqual(part, parts[2]) && score-score3 < scoreNum { break } if !areSlicesEqual(part, parts[3]) && score-score4 < scoreNum { break } if !areSlicesEqual(part, parts[0]) && handNum1 < 5 { break } if !areSlicesEqual(part, parts[0]) && handNum2 < 5 { break } if !areSlicesEqual(part, parts[0]) && handNum3 < 5 { break } if !areSlicesEqual(part, parts[0]) && handNum4 < 5 { break } //判断炸弹 if !areSlicesEqual(part, parts[0]) && len(cards1TypeMap[Four_Bomb]) > 0 { break } if !areSlicesEqual(part, parts[0]) && len(cards2TypeMap[Four_Bomb]) > 0 { break } if !areSlicesEqual(part, parts[0]) && len(cards3TypeMap[Four_Bomb]) > 0 { break } if !areSlicesEqual(part, parts[0]) && len(cards4TypeMap[Four_Bomb]) > 0 { break } //判断连对 if !areSlicesEqual(part, parts[0]) && len(cards1TypeMap[Straight_Twin]) > 0 { status := false for _, straight := range cards1TypeMap[Straight_Twin] { if len(straight)/2 >= 3 { status = true break } } if status { break } } if !areSlicesEqual(part, parts[0]) && len(cards2TypeMap[Straight_Twin]) > 0 { status := false for _, straight := range cards2TypeMap[Straight_Twin] { if len(straight)/2 >= 3 { status = true break } } if status { break } } if !areSlicesEqual(part, parts[0]) && len(cards3TypeMap[Straight_Twin]) > 0 { status := false for _, straight := range cards3TypeMap[Straight_Twin] { if len(straight)/2 >= 3 { status = true break } } if status { break } } if !areSlicesEqual(part, parts[0]) && len(cards4TypeMap[Straight_Twin]) > 0 { status := false for _, straight := range cards4TypeMap[Straight_Twin] { if len(straight)/2 >= 3 { status = true break } } if status { break } } //机器人打一局 看看谁赢了 winId := RobotPlay(parts, isYuLe, true, true) if winId != i { fmt.Printf("这手牌没赢!!!winId = %d,i = %d\n", winId, i) break } //找最小的牌 先手 allCards[int32(len(allCards)+1)] = parts data := []map[string]string{ { "Id": strconv.Itoa(len(allCards)), "Card1": string(json1Data), "Card1Score": strconv.Itoa(score1), "Card1HandNum": strconv.Itoa(handNum1), "Change1Cards": string(change1), "Card2": string(json2Data), "Card2Score": strconv.Itoa(score2), "Card2HandNum": strconv.Itoa(handNum2), "Change2Cards": string(change2), "Card3": string(json3Data), "Card3Score": strconv.Itoa(score3), "Card3HandNum": strconv.Itoa(handNum3), "Change3Cards": string(change3), "Card4": string(json4Data), "Card4Score": strconv.Itoa(score4), "Card4HandNum": strconv.Itoa(handNum4), "Change4Cards": string(change4), }, } // 写入数据 for _, rowData := range data { row := sheet.AddRow() for _, column := range header { cell := row.AddCell() value := rowData[column] // 直接访问映射中的值 cell.Value = value } } break } if len(allCards) >= 10000 { break } fmt.Printf("当前生成的牌库条数:%d 条\n", len(allCards)) } // 保存文件 err = file.Save("output.xlsx") if err != nil { fmt.Printf("Error saving file: %s\n", err) return } fmt.Print("File saved successfully.\n") fmt.Print("生成牌库完毕!!!!!\n") } func areSlicesEqual(slice1, slice2 []int32) bool { if len(slice1) != len(slice2) { return false } for i := 0; i < len(slice1); i++ { if slice1[i] != slice2[i] { return false } } return true } // 机器人打牌 func RobotPlay(cards [][]int32, isYuLe, isFirstHand, isOut bool) int { //4个机器人打牌 winId := 0 data := &PredictRequest{ IsWin: true, IsEnd: false, IsTienLenYule: isYuLe, IsFirstHand: isFirstHand, Cards_left_0: cards[0], Cards_left_1: cards[1], Cards_left_2: cards[2], Cards_left_3: cards[3], } //手牌ID oneId := -1 for id, card := range cards { for _, value := range card { if value == 0 { oneId = id break } } if oneId != -1 { break } } fmt.Printf("出手牌的玩家ID = %d\n", oneId) lastCards := []int32{} count := 0 for pos := 0; pos < 4; pos++ { if data.IsFirstHand { if pos != oneId { continue } } card := cards[pos] //出首牌 if isOut { outCards := GetOutCards(card, data, int32(pos)) fmt.Printf("出手牌 outCards= %v\n", outCards) data.IsFirstHand = false lastCards = outCards delMap := make(map[int32][]int32) delMap[int32(len(delMap)+1)] = outCards card = DelCards(card, delMap) cards[pos] = card if pos == 0 { data.Cards_left_0 = card } else if pos == 1 { data.Cards_left_1 = card } else if pos == 2 { data.Cards_left_2 = card } else if pos == 3 { data.Cards_left_3 = card } if len(card) == 0 { winId = pos fmt.Printf("最后一手牌 outCards= %v\n", outCards) return winId } isOut = false } else { //压牌 outCards := GetPressCards(card, lastCards, data, int32(pos)) fmt.Printf("压牌 outCards= %v\n", outCards) delMap := make(map[int32][]int32) delMap[int32(len(delMap)+1)] = outCards card = DelCards(card, delMap) cards[pos] = card if len(outCards) > 0 { lastCards = outCards count = 0 if pos == 0 { data.Cards_left_0 = card } else if pos == 1 { data.Cards_left_1 = card } else if pos == 2 { data.Cards_left_2 = card } else if pos == 3 { data.Cards_left_3 = card } } else { count += 1 } if len(card) == 0 { winId = pos fmt.Printf("压牌出完了 outCards= %v\n", outCards) return winId } } if count == 3 { isOut = true count = 0 } if pos == 3 { pos = -1 } } return winId } // 新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 { 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 { 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 { pair = append(pair, card) pairMap[card] = cardMap[card] } } return pair, pairMap } // 转换 func CardsChange(cards []int32) []string { sort.Slice(cards, func(i, j int) bool { if Value(cards[i]) == Value(cards[j]) { return Color(cards[i]) > Color(cards[j]) } return Value(cards[i]) > Value(cards[j]) }) var cardName = []string{ "3♠", "4♠", "5♠", "6♠", "7♠", "8♠", "9♠", "10♠", "J♠", "Q♠", "K♠", "A♠", "2♠", // 0-12 黑桃 "3♣", "4♣", "5♣", "6♣", "7♣", "8♣", "9♣", "10♣", "J♣", "Q♣", "K♣", "A♣", "2♣", // 13-25 梅花 "3♦", "4♦", "5♦", "6♦", "7♦", "8♦", "9♦", "10♦", "J♦", "Q♦", "K♦", "A♦", "2♦", // 26-38 方片 "3♥", "4♥", "5♥", "6♥", "7♥", "8♥", "9♥", "10♥", "J♥", "Q♥", "K♥", "A♥", "2♥", // 39-51 红桃 } change := []string{} for _, card := range cards { change = append(change, cardName[card]) } return change } // 删除牌 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, } //计算牌型分值 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 *PredictRequest, pos 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]) }) isWin := data.IsWin //测试代码 //isWin = false outCards := []int32{} lastPos := data.Last_pos //上家出牌人的位置 isYuLe := data.IsTienLenYule isEnd := data.IsEnd winSnids := data.WinSnids //获取牌型 cardsTypeMap := GetCardsType(cards, isYuLe) _, handCardnum := GetCardTypeScore(cardsTypeMap, isYuLe, cards) //获取出牌人的 手数 otherCards := getOtherPlayerCards(pos, lastPos, data) otherCardsTypeMap := GetCardsType(otherCards, isYuLe) _, lastHandCardnum := GetCardTypeScore(otherCardsTypeMap, isYuLe, otherCards) //获取下一家的位置和剩余的牌 nextPos, nextCards := GetNextPos(pos, data) 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 { 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 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 { 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 { 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]) { outCards = []int32{} } } else { 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) { outCards = []int32{} } 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 } } } } } //拆连对 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]} 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]} break } } } } } //找炸弹 if isYuLe { if len(outCards) == 0 && len(cardsTypeMap[Four_Bomb]) > 0 && lastHandCardnum <= 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 { 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{} } 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):] } } // if len(outCards) == 0 && lastHandCardnum <= 2 { //找顺子 allStraight := GetAllStraight(cards, len(lastCards)) 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 } } } } } } 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{} } 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 { minKey := findMinKey(cardsTypeMap[Four_Bomb]) 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 { 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{} } 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 { minKey := findMinKey(cardsTypeMap[Four_Bomb]) outCards = cardsTypeMap[Four_Bomb][minKey] } } if !IsPressed(isYuLe, isEnd, otherCards, lastCards, data, pos, lastPos, nextPos, handCardnum, Triple) { outCards = []int32{} } return outCards case Four_Bomb: //炸弹 cardsMap := cardsTypeMap[Four_Bomb] for _, card := range cardsMap { if Value(card[0]) > Value(lastCards[0]) { 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{} } return outCards case Plane_Single: //三代单 --不用考虑 只有最后一首才会出三代单 singleHand, singleLen := FindPlaneSingleHead(lastCards) 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{} } return outCards case Plane_Twin: outCards = []int32{} twinHand, twinLen := FindPlaneTwinHead(lastCards) 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]) 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]) } 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 { 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{} } return outCards default: return outCards } } return outCards } // 出牌 isMin是否先手出最小的牌 func GetOutCards(cards []int32, data *PredictRequest, pos 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]) }) isWin := data.IsWin 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) _, handNum := GetCardTypeScore(cardsTypeMap, isYuLe, cards) if handNum <= 1 { return cards } //出牌逻辑 outCards := []int32{} cardValue := -1 if isMin { outCards = GetMinCardType(cards[0], cardsTypeMap, isYuLe) return outCards } //判断其他玩家剩余的牌的牌型是否能压过当前出牌的牌型 //出牌顺序 //出单张 判断下一家剩余1张牌且剩余的牌比我出的牌大 不出 otherMinHandNum, otherMinCardsNum, otherPos, otherCardsType := getOtherMinCards(pos, data, isYuLe) //优先出三张 如果是娱乐模式 直接带单张 或者最小的对子 if isYuLe { outCards, cardValue = getTriple(cardsTypeMap, cards, isYuLe, otherMinHandNum, pos, int32(otherPos), data) } //出单张 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]) { outCards = []int32{} } else if Value(cards[0]) == Value(otherCards[0]) { //判断花色 if Color(cards[0]) < Color(otherCards[0]) { 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 { otherCards := getOtherPlayerCards(pos, int32(otherPos), data) if otherMinHandNum == 1 && otherMinCardsNum == 2 && otherCardsType == Twin { if Value(outCards[1]) < Value(otherCards[1]) { outCards = []int32{} } else if Value(outCards[1]) == Value(otherCards[1]) { //判断花色 if Color(outCards[1]) < Color(otherCards[1]) { 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]) { 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]) { 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]) { 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]) { 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]) { 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]) { outCards = []int32{} } } } } if len(outCards)/2 >= 3 && handNum > 2 { outCards = []int32{} } } //炸弹 这个就不用检查了 if len(outCards) == 0 && handNum <= 2 { //出炸弹 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) { if cardType == Triple { //出三代二 outCards, cardValue = getTriple(cardsTypeMap, cards, isYuLe, otherMinHandNum, pos, int32(otherPos), data) if len(outCards) > 0 { return outCards } else { break } } else { return mycard } } } } } if handNum <= 3 { 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) return outCards } 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 := true if len(cardsTypeMap[Single]) > 0 { card := getSingle(cardsTypeMap, cards, isYuLe) if len(card) > 0 { for _, maxCard := range maxCardsArr { if maxCard == card[0] { status = false break } } } } 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]} } } 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]} } } } } } } } } //最后直接出最小牌型的牌 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] 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) } else { lastPos, _ := GetLastPos(pos, data) if isEnd && len(winSnids) == 0 && nextPos != lastPos { //找最小牌型的牌 outCards = GetMinCardType(cards[0], cardsTypeMap, isYuLe) } else { if otherMinHandNum > 2 { //找最小牌型的牌 outCards = GetMinCardType(cards[0], cardsTypeMap, isYuLe) } else { outCards = []int32{cards[len(cards)-1]} } } } } } else { //找最小牌型的牌 outCards = GetMinCardType(cards[0], cardsTypeMap, isYuLe) } } return outCards } // 判断牌型是否全场最大 func getMaxCardTypeNum(cardsType int, cards []int32, pos int32, data *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 *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 } } } 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 { } 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 && len(cards) >= 10 { 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 *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 *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 *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 *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) } } 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 *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 *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 *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 *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) { 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 *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 *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 { return false, i } } } return true, -1 } type PredictRequest struct { Bomb_num int `url:"bomb_num" form:"bomb_num"` Card_play_action_seq string `url:"card_play_action_seq" form:"card_play_action_seq"` Last_move_0 string `url:"last_move_0" form:"last_move_0"` Last_move_1 string `url:"last_move_1" form:"last_move_1"` Last_move_2 string `url:"last_move_2" form:"last_move_2"` Last_move_3 string `url:"last_move_3" form:"last_move_3"` Num_cards_left_0 int `url:"num_cards_left_0" form:"num_cards_left_0"` Num_cards_left_1 int `url:"num_cards_left_1" form:"num_cards_left_1"` Num_cards_left_2 int `url:"num_cards_left_2" form:"num_cards_left_2"` Num_cards_left_3 int `url:"num_cards_left_3" form:"num_cards_left_3"` Other_hand_cards string `url:"other_hand_cards" form:"other_hand_cards"` Played_cards_0 string `url:"played_cards_0" form:"played_cards_0"` Played_cards_1 string `url:"played_cards_1" form:"played_cards_1"` Played_cards_2 string `url:"played_cards_2" form:"played_cards_2"` Played_cards_3 string `url:"played_cards_3" form:"played_cards_3"` Player_hand_cards string `url:"player_hand_cards" form:"player_hand_cards"` Player_position int `url:"player_position" form:"player_position"` IsTienLenYule bool `url:"isTienLenYule" form:"isTienLenYule"` IsFirstHand bool `url:"isFirstHand" form:"isFirstHand"` Cards_left_0 []int32 `url:"cards_left_0" form:"cards_left_0"` Cards_left_1 []int32 `url:"cards_left_1" form:"cards_left_1"` Cards_left_2 []int32 `url:"cards_left_2" form:"cards_left_2"` Cards_left_3 []int32 `url:"cards_left_3" form:"cards_left_3"` Last_pos int32 `url:"last_pos" form:"last_pos"` IsEnd bool `url:"isend" form:"isend"` WinSnids []int32 `url:"winsnids" form:"winsnids"` IsWin bool `url:"iswin" form:"iswin"` } */