Files
2026-08-14 13:17:03 +08:00

114 lines
2.7 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Package ddz 实现斗地主的完整规则:发牌、牌型判定、比较、候选出牌生成与对局状态机
package ddz
import (
"math/rand"
"sort"
)
// 牌的编码约定:
// 0-51 普通牌:点数 rank = 编号/4 + 33,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
}