package game const ( HandNoType HandType = (iota << 8) | 0 // 无牌型 HandPingHu HandType = (iota << 8) | 1 // 平胡 HandDaDuiZi HandType = (iota << 8) | 4 // 大对子 HandQingYiSe HandType = (iota << 8) | 4 // 清一色 HandQiDui HandType = (iota << 8) | 4 // 七对 HandLongQiDui HandType = (iota << 8) | 8 // 龙七对 HandQingDui HandType = (iota << 8) | 8 // 清一色大对子 HandQingQiDui HandType = (iota << 8) | 16 // 清七对 HandQingLongQiDui HandType = (iota << 8) | 32 // 清龙七对 HandShuangLongQiDui HandType = (iota << 8) | 32 // 双龙七对 HandShiBaLuoHan HandType = (iota << 8) | 4 // 十八罗汉 *4杠=64 HandQingShiBaLuoHan HandType = (iota << 8) | 16 // 清18罗汉 *4杠=256 ) type HandType int32 var handTypeNames = []string{"non", "平胡", "大对子", "清一色", "七对", "龙七对", "清对", "清七对", "清龙七对", "双龙七对", "十八罗汉", "清18罗汉"} func (h HandType) String() string { return handTypeNames[h>>8] } func (h HandType) Type() int8 { return int8(h >> 8) } func (h HandType) Weight() int32 { return int32(h) & 0xff } // 将双龙七对 64 // 十八罗汉 64 // 将三龙七对 126 // 清18罗汉 256 const ( WeightGang MjWeight = (iota << 8) | 2 // 杠 WeightZiMo MjWeight = (iota << 8) | 2 // 自摸 WeightGangShangKaiHua MjWeight = (iota << 8) | 2 // 杠上开花 WeightGangShangPao MjWeight = (iota << 8) | 2 // 杠上炮 WeightHaiDiLaoYue MjWeight = (iota << 8) | 2 // 海底捞月 WeightDuanYaoJiu MjWeight = (iota << 8) | 2 // 断幺九 WeightYaoJiu MjWeight = (iota << 8) | 4 // 幺九 (清幺九) WeightJinGouDiao MjWeight = (iota << 8) | 4 // 金钩吊 (清勾勾) WeightJiangDui MjWeight = (iota << 8) | 8 // 将对 WeightDiHu MjWeight = (iota << 8) | 32 // 地胡 WeightTianHu MjWeight = (iota << 8) | 32 // 天胡 ) type MjWeight int32 var weightNames = []string{"杠", "自摸", "杠上开花", "杠上炮", "海底捞月", "断幺九", "幺九", "金钩吊", "将对", "地胡", "天胡"} func (w MjWeight) String() string { return weightNames[w>>8] } func (w MjWeight) Type() int8 { return int8(w >> 8) } func (w MjWeight) Weight() int32 { return int32(w) & 0xff } type WinSettle struct { Weight int32 WinType HandType Weights []MjWeight } type HandWin struct { Pairs [][2]int8 Triplets [][3]int8 handType HandType // 牌型 } // GetWinType 计算胡牌牌型 func (win *HandWin) GetWinType(peng [][3]int8, gang [][4]int8) HandType { win.handType = HandPingHu if len(win.Pairs) == 7 { // 七对 win.handType = HandQiDui qing := true long := false // 龙七对, 手牌有一杠 for i, pair := range win.Pairs { qing = qing && win.Pairs[0][0]/10 == pair[0]/10 long = long || (i > 0 && pair[0] == win.Pairs[i-1][0]) } if qing { // 清七对 win.handType = HandQingQiDui } // TODO 龙七对, 将七对 ... return win.handType } // 清一色, 大对子 pair := win.Pairs[0] qing, dui := true, len(win.Triplets) > 0 for _, tile3 := range win.Triplets { qing = qing && pair[0]/10 == tile3[0]/10 dui = dui && isTriplet(tile3) } if qing { for _, peng := range peng { qing = qing && pair[0]/10 == peng[0]/10 } for _, gang := range gang { qing = qing && pair[0]/10 == gang[0]/10 } } if qing && dui { win.handType = HandQingDui // 清对 } else { switch true { case qing: win.handType = HandQingYiSe case dui: win.handType = HandDaDuiZi default: win.handType = HandPingHu } } // 十八罗汉 if len(gang) == 4 { if win.handType == HandQingYiSe { win.handType = HandQingShiBaLuoHan // 清十八罗汉 } else { win.handType = HandShiBaLuoHan } } return win.handType } // IsHuaZhu 是否花猪 func IsHuaZhu(lack int8, draw int8, hand []int8) bool { if draw > 0 && draw/10 == lack { return true } for _, card := range hand { if card/10 == lack { return true } } return false } func getPairs(cards []int8) (pairs [][2]int8) { for i := 0; i < len(cards)-1; i++ { if cards[i] == cards[i+1] { pairs = append(pairs, [2]int8{cards[i], cards[i+1]}) i++ } } return } func isQingYiSe(cards []int8, assemble []int8) bool { cardType := cards[0] / 10 for _, card := range cards { if card/10 != cardType { return false } } for _, card := range assemble { if card/10 != cardType { return false } } return true } // GetHandWins 计算手牌可胡牌牌型 func GetHandWins(draw int8, hand []int8) (wins []HandWin) { cards := InsertTile(draw, hand) pairs := getPairs(cards) // 无对胡不了 if len(pairs) == 0 { return } // 单调 if len(cards) == 2 { win := HandWin{Pairs: [][2]int8{pairs[0]}} wins = append(wins, win) return } if len(pairs) == 7 { wins = append(wins, HandWin{Pairs: pairs}) return } if (len(cards)-2)%3 != 0 { // 除对子外剩余牌数量不能都组成刻 return } // 除眼外其他的牌都能组成刻 pairLoop: for _, pair := range pairs { var _ [][3]int8 rest, _ := FilterTiles(cards, pair[0], pair[1]) win := HandWin{Pairs: [][2]int8{pair}} for len(rest) > 0 { // todo 统计所有牌型 tile3, ok := findAndRemoveTriplet(&rest) if !ok { tile3, ok = findAndRemoveSequence(&rest) } if !ok { continue pairLoop } win.Triplets = append(win.Triplets, tile3) } wins = append(wins, win) } return } // InsertTile 插入单张手牌 func InsertTile(tile int8, sortedTiles []int8) (cards []int8) { cards = make([]int8, len(sortedTiles)+1) copy(cards, sortedTiles) cards[len(cards)-1] = tile // 放到最后,最大则不变 for i := 0; i < len(sortedTiles); i++ { if tile < sortedTiles[i] { copy(cards[i+1:], cards[i:len(cards)-1]) cards[i] = tile break } } return } func InsertHand(lack int8, tile int8, soredHand []int8) (cards []int8) { length := len(soredHand) + 1 cards = make([]int8, length) copy(cards[1:], soredHand) cards[0] = tile // 放到最前,最小则不变 score := tile if tile/10 == lack { score += 63 } for i := length - 1; i >= 0; i-- { handScore := cards[i] if cards[i]/10 == lack { handScore += 63 } if score > handScore { copy(cards[0:i], cards[1:i+1]) cards[i] = tile break } } return } func FilterTiles(cards []int8, tiles ...int8) (rest []int8, ok bool) { tilesLen := len(tiles) if tilesLen == 0 { return cards, true } if len(cards) < tilesLen { return rest, false } filters := make([]int8, tilesLen) copy(filters, tiles) rest = make([]int8, 0, len(cards)-tilesLen) for _, card := range cards { for j, tile := range filters { if card == tile { filters[j] = 0 tilesLen-- card = 0 break } } if card > 0 { rest = append(rest, card) } } ok = tilesLen == 0 return } // findAndRemoveTriplet 从已排序的[]int中移除排头的刻子 func findAndRemoveTriplet(sortedCards *[]int8) (triplet [3]int8, ok bool) { var v = *sortedCards triplet = [3]int8{v[0], v[1], v[2]} if ok = isTriplet(triplet); ok { *sortedCards = append([]int8{}, v[3:]...) } return } // findAndRemoveSequence 从已排序的[]int中移除排头的顺子 func findAndRemoveSequence(sortedCards *[]int8) (sequence [3]int8, ok bool) { var v = *sortedCards var tmp = make([]int8, 0) for i := 1; i < len(v); i++ { switch { case v[i] == v[i-1]: tmp = append(tmp, v[i]) case v[i] == v[i-1]+1: if ok = v[i]-v[0] == 2; ok { tmp = append(tmp, v[i+1:]...) *sortedCards = tmp sequence = [3]int8{v[0], v[i-1], v[i]} return } default: return } } return } // FindQuaternion 找到所有四元组 func FindQuaternion(cards []int8) (gangs [][4]int8) { length := len(cards) for i := 0; i < length-3; { for j := 1; j < 4; j++ { if cards[i] != cards[i+j] { i += j break } if j == 3 { gangs = append(gangs, [4]int8{cards[i], cards[i], cards[i], cards[i]}) i += j } } } return } // isTriplet 是否刻子 func isTriplet(tile3 [3]int8) bool { return tile3[0] == tile3[1] && tile3[1] == tile3[2] } // IsSequence 是否顺子 func isSequence(tile3 [3]int8) bool { if tile3[0] > 29 || tile3[1] > 29 || tile3[2] > 29 { return false } return tile3[1] == tile3[0]+1 && tile3[2] == tile3[1]+1 }