// Package ddz 实现斗地主的完整规则:发牌、牌型判定、比较、候选出牌生成与对局状态机 package ddz import ( "math/rand" "sort" ) // 牌的编码约定: // 0-51 普通牌:点数 rank = 编号/4 + 3(3,4,...,10,J=11,Q=12,K=13,A=14,2=15),花色 = 编号%4 // 52 小王(rank=16) // 53 大王(rank=17) const ( SmallJoker = 52 // 小王编号 BigJoker = 53 // 大王编号 ) // Rank 返回牌的点数(3..15,小王16,大王17) func Rank(card int) int { if card == SmallJoker { return 16 } if card == BigJoker { return 17 } return card/4 + 3 } // rankNames 点数到显示名的映射(下标 = rank) var rankNames = map[int]string{ 3: "3", 4: "4", 5: "5", 6: "6", 7: "7", 8: "8", 9: "9", 10: "10", 11: "J", 12: "Q", 13: "K", 14: "A", 15: "2", 16: "小王", 17: "大王", } // RankName 点数的显示名称 func RankName(rank int) string { return rankNames[rank] } // CardName 牌的显示名称(忽略花色,斗地主只关心点数) func CardName(card int) string { return RankName(Rank(card)) } // CardsName 一组牌的显示名称(如 "33 55",按点数降序) func CardsName(cards []int) string { sorted := append([]int{}, cards...) sort.Slice(sorted, func(i, j int) bool { return Rank(sorted[i]) > Rank(sorted[j]) }) s := "" for i, c := range sorted { if i > 0 { s += " " } s += CardName(c) } return s } // SortDesc 手牌按点数降序排序(前端展示与出牌习惯) func SortDesc(cards []int) { sort.Slice(cards, func(i, j int) bool { ri, rj := Rank(cards[i]), Rank(cards[j]) if ri != rj { return ri > rj } return cards[i] > cards[j] }) } // Deal 洗牌并发牌:返回三家手牌(各17张)与3张底牌 func Deal() (hands [3][]int, bottom []int) { deck := make([]int, 54) for i := range deck { deck[i] = i } rand.Shuffle(54, func(i, j int) { deck[i], deck[j] = deck[j], deck[i] }) for i := 0; i < 3; i++ { hands[i] = append([]int{}, deck[i*17:(i+1)*17]...) SortDesc(hands[i]) } bottom = append([]int{}, deck[51:]...) return hands, bottom } // rankCount 统计一组牌各点数的张数 func rankCount(cards []int) map[int]int { m := map[int]int{} for _, c := range cards { m[Rank(c)]++ } return m } // removeCards 从手牌中移除指定牌,返回新手牌(不修改原切片);牌不存在返回 nil func removeCards(hand, cards []int) []int { used := map[int]bool{} for _, c := range cards { used[c] = true } // 校验 cards 都在手牌中 inHand := map[int]bool{} for _, c := range hand { inHand[c] = true } for _, c := range cards { if !inHand[c] { return nil } } rest := make([]int, 0, len(hand)-len(cards)) for _, c := range hand { if !used[c] { rest = append(rest, c) } } return rest }