diff --git a/game/poker/card.go b/game/poker/card.go deleted file mode 100644 index cafb8dd..0000000 --- a/game/poker/card.go +++ /dev/null @@ -1,13 +0,0 @@ -package poker - -import "github.com/kercylan98/minotaur/utils/generic" - -// Card 扑克牌 -type Card[P, C generic.Number] interface { - // GetGuid 获取扑克牌的唯一标识 - GetGuid() int64 - // GetPoint 获取扑克牌的点数 - GetPoint() P - // GetColor 获取扑克牌的花色 - GetColor() C -} diff --git a/game/poker/card_pile.go b/game/poker/card_pile.go deleted file mode 100644 index e9a0421..0000000 --- a/game/poker/card_pile.go +++ /dev/null @@ -1,170 +0,0 @@ -package poker - -import ( - "fmt" - "github.com/kercylan98/minotaur/utils/generic" - "github.com/kercylan98/minotaur/utils/hash" - "github.com/kercylan98/minotaur/utils/random" - "github.com/kercylan98/minotaur/utils/slice" - "sort" -) - -// NewCardPile 返回一个新的牌堆,其中 size 表示了该牌堆由多少副牌组成 -// - 在不洗牌的情况下,默认牌堆顶部到底部为从大到小排列 -// -// Deprecated: 从 Minotaur 0.0.25 开始,由于设计原因已弃用,请尝试考虑使用 deck.Deck 或 deck.Group 代替,构建函数为 deck.NewDeck 或 deck.NewGroup -func NewCardPile[P, C generic.Number, T Card[P, C]](size int, jokers [2]P, points [13]P, colors [4]C, generateCard func(guid int64, point P, color C) T, options ...CardPileOption[P, C, T]) *CardPile[P, C, T] { - pile := &CardPile[P, C, T]{ - size: size, - pile: make([]T, 0, size*54), - generateCard: generateCard, - cards: map[int64]T{}, - jokers: jokers, - points: points, - colors: colors, - } - pile.shuffleHandle = func(cards []T) []T { - sort.Slice(cards, func(i, j int) bool { - return random.Float64() >= 0.5 - }) - return cards - } - for _, option := range options { - option(pile) - } - pile.Reset() - return pile -} - -// CardPile 扑克牌堆 -type CardPile[P, C generic.Number, T Card[P, C]] struct { - pile []T - size int - shuffleHandle func(cards []T) []T - excludeColor map[C]struct{} - excludePoint map[P]struct{} - excludeCard map[P]map[C]struct{} - generateCard func(guid int64, point P, color C) T - guid int64 - cards map[int64]T - jokers [2]P - points [13]P - colors [4]C -} - -// GetCard 通过 guid 获取一张牌 -func (slf *CardPile[P, C, T]) GetCard(guid int64) T { - return slf.cards[guid] -} - -// Reset 重置牌堆的扑克牌数量及顺序 -func (slf *CardPile[P, C, T]) Reset() { - slf.guid = 0 - var cards = make([]T, 0, 54*slf.size) - for i := 0; i < slf.size; i++ { - for _, joker := range slf.jokers { - if !slf.IsExclude(joker, C(0)) { - slf.guid++ - card := slf.generateCard(slf.guid, joker, C(0)) - slf.cards[slf.guid] = card - cards = append(cards, card) - } - } - - for p := 0; p < len(slf.points); p++ { - for c := 0; c < len(slf.colors); c++ { - point, color := slf.points[p], slf.colors[c] - if !slf.IsExclude(point, color) { - slf.guid++ - card := slf.generateCard(slf.guid, point, color) - slf.cards[slf.guid] = card - cards = append(cards, card) - } - } - } - } - slf.pile = cards -} - -// IsExclude 检查特定点数和花色是否被排除在外 -func (slf *CardPile[P, C, T]) IsExclude(point P, color C) bool { - return hash.Exist(slf.excludePoint, point) || hash.Exist(slf.excludeColor, color) || hash.Exist(slf.excludeCard[point], color) -} - -// IsExcludeWithCard 检查特定扑克牌是否被排除在外 -func (slf *CardPile[P, C, T]) IsExcludeWithCard(card T) bool { - point, color := GetPointAndColor[P, C, T](card) - return hash.Exist(slf.excludePoint, point) || hash.Exist(slf.excludeColor, color) || hash.Exist(slf.excludeCard[point], color) -} - -// Shuffle 洗牌 -func (slf *CardPile[P, C, T]) Shuffle() { - before := slf.Count() - cards := slf.shuffleHandle(slf.Cards()) - if len(cards) != before { - panic("the count after shuffling does not match the count before shuffling") - } - slf.pile = cards -} - -// Cards 获取当前牌堆的所有扑克牌 -func (slf *CardPile[P, C, T]) Cards() []T { - return slf.pile -} - -// IsFree 返回牌堆是否没有扑克牌了 -func (slf *CardPile[P, C, T]) IsFree() bool { - return len(slf.pile) == 0 -} - -// Count 获取牌堆剩余牌量 -func (slf *CardPile[P, C, T]) Count() int { - return len(slf.pile) -} - -// Pull 从牌堆特定位置抽出一张牌 -func (slf *CardPile[P, C, T]) Pull(index int) T { - if index >= slf.Count() || index < 0 { - panic(fmt.Errorf("failed to pull a poker card from the pile, the index is less than 0 or exceeds the remaining number of cards in the pile. count: %d, index: %d", slf.Count(), index)) - } - pc := slf.pile[index] - slice.Del(&slf.pile, index) - return pc -} - -// PullTop 从牌堆顶部抽出一张牌 -func (slf *CardPile[P, C, T]) PullTop() T { - if slf.IsFree() { - panic("empty poker cards pile") - } - pc := slf.pile[0] - slice.Del(&slf.pile, 0) - return pc -} - -// PullBottom 从牌堆底部抽出一张牌 -func (slf *CardPile[P, C, T]) PullBottom() T { - if slf.IsFree() { - panic("empty poker cards pile") - } - i := len(slf.pile) - 1 - pc := slf.pile[i] - slice.Del(&slf.pile, i) - return pc -} - -// Push 将扑克牌插入到牌堆特定位置 -func (slf *CardPile[P, C, T]) Push(index int, card T) { - slice.Insert(&slf.pile, index, card) - return -} - -// PushTop 将扑克牌插入到牌堆顶部 -func (slf *CardPile[P, C, T]) PushTop(card T) { - slf.pile = append([]T{card}, slf.pile...) -} - -// PushBottom 将扑克牌插入到牌堆底部 -func (slf *CardPile[P, C, T]) PushBottom(card T) { - slf.pile = append(slf.pile, card) -} diff --git a/game/poker/card_pile_options.go b/game/poker/card_pile_options.go deleted file mode 100644 index 19c94a2..0000000 --- a/game/poker/card_pile_options.go +++ /dev/null @@ -1,62 +0,0 @@ -package poker - -import "github.com/kercylan98/minotaur/utils/generic" - -type CardPileOption[P, C generic.Number, T Card[P, C]] func(pile *CardPile[P, C, T]) - -// WithCardPileShuffle 通过特定的洗牌算法创建牌堆 -// - 需要保证洗牌后的牌堆剩余扑克数量与之前相同,否则将会引发 panic -func WithCardPileShuffle[P, C generic.Number, T Card[P, C]](shuffleHandle func(pile []T) []T) CardPileOption[P, C, T] { - return func(pile *CardPile[P, C, T]) { - if shuffleHandle == nil { - return - } - pile.shuffleHandle = shuffleHandle - } -} - -// WithCardPileExcludeColor 通过排除特定花色的方式创建牌堆 -func WithCardPileExcludeColor[P, C generic.Number, T Card[P, C]](colors ...C) CardPileOption[P, C, T] { - return func(pile *CardPile[P, C, T]) { - if pile.excludeColor == nil { - pile.excludeColor = map[C]struct{}{} - } - for _, color := range colors { - pile.excludeColor[color] = struct{}{} - } - } -} - -// WithCardPileExcludePoint 通过排除特定点数的方式创建牌堆 -func WithCardPileExcludePoint[P, C generic.Number, T Card[P, C]](points ...P) CardPileOption[P, C, T] { - return func(pile *CardPile[P, C, T]) { - if pile.excludePoint == nil { - pile.excludePoint = map[P]struct{}{} - } - for _, point := range points { - pile.excludePoint[point] = struct{}{} - } - } -} - -// WithCardPileExcludeCard 通过排除特定扑克牌的方式创建牌堆 -func WithCardPileExcludeCard[P, C generic.Number, T Card[P, C]](cards ...Card[P, C]) CardPileOption[P, C, T] { - return func(pile *CardPile[P, C, T]) { - if pile.excludeCard == nil { - pile.excludeCard = map[P]map[C]struct{}{} - } - for _, card := range cards { - point := card.GetPoint() - cs, exist := pile.excludeCard[point] - if !exist { - cs = map[C]struct{}{} - pile.excludeCard[point] = cs - } - for _, joker := range pile.jokers { - if point != joker { - cs[card.GetColor()] = struct{}{} - } - } - } - } -} diff --git a/game/poker/card_pile_test.go b/game/poker/card_pile_test.go deleted file mode 100644 index 1c76a60..0000000 --- a/game/poker/card_pile_test.go +++ /dev/null @@ -1,40 +0,0 @@ -package poker_test - -import ( - "github.com/kercylan98/minotaur/game/poker" - "testing" -) - -type Card struct { - Guid int64 - Point int32 - Color int32 -} - -func (slf *Card) GetGuid() int64 { - return slf.Guid -} - -func (slf *Card) GetPoint() int32 { - return slf.Point -} - -func (slf *Card) GetColor() int32 { - return slf.Color -} - -func TestCardPile_PullTop(t *testing.T) { - var pile = poker.NewCardPile[int32, int32, *Card](6, - [2]int32{14, 15}, - [13]int32{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, - [4]int32{1, 2, 3, 4}, - func(guid int64, point int32, color int32) *Card { - return &Card{Guid: guid, Point: point, Color: color} - }, - ) - - pile.Shuffle() - for i := 0; i < 10; i++ { - t.Log(pile.PullTop()) - } -} diff --git a/game/poker/doc.go b/game/poker/doc.go deleted file mode 100644 index 8d4621a..0000000 --- a/game/poker/doc.go +++ /dev/null @@ -1,10 +0,0 @@ -// Package poker 提供了一组用于处理扑克牌游戏的函数和数据结构。该包旨在简化扑克牌游戏的开发过程,并提供一致的接口和易于使用的功能。 -// -// 主要特性: -// - 扑克牌操作:"poker"包支持处理扑克牌的各种操作,如洗牌、发牌、比较牌面大小等。您可以使用这些操作来模拟和实现各种扑克牌游戏。 -// - 扑克牌规则:该包提供了一系列函数,用于执行常见的扑克牌规则,如判断是否是同花顺、计算牌面点数等。这些函数旨在提供准确和可靠的规则判断和计算结果。 -// - 扑克牌算法:"poker"包还提供了一些算法,用于解决扑克牌游戏中的问题,如计算最佳牌型、判断是否存在顺子等。这些算法旨在提供高效和优化的解决方案。 -// - 简化接口:该包的设计目标之一是提供简化的接口,使扑克牌游戏的开发变得更加直观和易于使用。您可以轻松地创建和操作扑克牌对象,而无需处理繁琐的底层细节。 -// -// Deprecated: 从 Minotaur 0.0.25 开始,由于设计原因已弃用,请尝试考虑使用 utils/combination 和 utils/deck 代替 -package poker diff --git a/game/poker/hand.go b/game/poker/hand.go deleted file mode 100644 index 2a16d1a..0000000 --- a/game/poker/hand.go +++ /dev/null @@ -1,414 +0,0 @@ -package poker - -import "github.com/kercylan98/minotaur/utils/generic" - -const ( - HandNone = "None" // 无牌型 -) - -// HandHandle 扑克牌型验证函数 -type HandHandle[P, C generic.Number, T Card[P, C]] func(rule *Rule[P, C, T], cards []T) bool - -// HandSingle 单牌 -func HandSingle[P, C generic.Number, T Card[P, C]]() HandHandle[P, C, T] { - return func(rule *Rule[P, C, T], cards []T) bool { - return len(cards) == 1 - } -} - -// HandPairs 对子 -func HandPairs[P, C generic.Number, T Card[P, C]]() HandHandle[P, C, T] { - return func(rule *Rule[P, C, T], cards []T) bool { - return len(cards) == 2 && rule.IsPointContinuity(2, cards...) - } -} - -// HandThreeOfKind 三张 -func HandThreeOfKind[P, C generic.Number, T Card[P, C]]() HandHandle[P, C, T] { - return func(rule *Rule[P, C, T], cards []T) bool { - return len(cards) == 3 && rule.IsPointContinuity(3, cards...) - } -} - -// HandThreeOfKindWithOne 三带一 -func HandThreeOfKindWithOne[P, C generic.Number, T Card[P, C]]() HandHandle[P, C, T] { - return func(rule *Rule[P, C, T], cards []T) bool { - group := GroupByPoint[P, C, T](cards...) - if len(group) != 2 { - return false - } - var hasThree bool - var count int - for _, cards := range group { - if len(cards) == 3 { - hasThree = true - } else { - count = len(cards) - } - } - return hasThree && count == 1 - } -} - -// HandThreeOfKindWithTwo 三带二 -func HandThreeOfKindWithTwo[P, C generic.Number, T Card[P, C]]() HandHandle[P, C, T] { - return func(rule *Rule[P, C, T], cards []T) bool { - group := GroupByPoint[P, C, T](cards...) - if len(group) != 2 { - return false - } - var hasThree bool - var count int - for _, cards := range group { - if len(cards) == 3 { - hasThree = true - } else { - count = len(cards) - } - } - return hasThree && count == 2 - } -} - -// HandOrderSingle 顺子 -func HandOrderSingle[P, C generic.Number, T Card[P, C]](count int) HandHandle[P, C, T] { - return func(rule *Rule[P, C, T], cards []T) bool { - return len(cards) >= count && rule.IsPointContinuity(1, cards...) - } -} - -// HandOrderPairs 对子顺子 -func HandOrderPairs[P, C generic.Number, T Card[P, C]](count int) HandHandle[P, C, T] { - return func(rule *Rule[P, C, T], cards []T) bool { - if len(cards) < count*2 || len(cards)%2 != 0 { - return false - } - return rule.IsPointContinuity(2, cards...) - } -} - -// HandOrderSingleThree 三张顺子 -func HandOrderSingleThree[P, C generic.Number, T Card[P, C]](count int) HandHandle[P, C, T] { - return func(rule *Rule[P, C, T], cards []T) bool { - if len(cards) < count*3 || len(cards)%3 != 0 { - return false - } - return rule.IsPointContinuity(3, cards...) - } -} - -// HandOrderSingleFour 四张顺子 -func HandOrderSingleFour[P, C generic.Number, T Card[P, C]](count int) HandHandle[P, C, T] { - return func(rule *Rule[P, C, T], cards []T) bool { - if len(cards) < count*4 || len(cards)%4 != 0 { - return false - } - return rule.IsPointContinuity(4, cards...) - } -} - -// HandOrderThreeWithOne 三带一顺子 -func HandOrderThreeWithOne[P, C generic.Number, T Card[P, C]](count int) HandHandle[P, C, T] { - return func(rule *Rule[P, C, T], cards []T) bool { - group := GroupByPoint[P, C, T](cards...) - var continuous []T - var other int - for _, cards := range group { - if len(cards) == 3 { - continuous = append(continuous, cards...) - } else { - other += len(cards) - } - } - if !rule.IsPointContinuity(3, continuous...) { - return false - } - return other == len(continuous)/3 - } -} - -// HandOrderThreeWithTwo 三带二顺子 -func HandOrderThreeWithTwo[P, C generic.Number, T Card[P, C]](count int) HandHandle[P, C, T] { - return func(rule *Rule[P, C, T], cards []T) bool { - group := GroupByPoint[P, C, T](cards...) - var continuous []T - var other int - for _, cards := range group { - if len(cards) == 3 { - continuous = append(continuous, cards...) - } else if len(cards)%2 == 0 { - other += len(cards) / 2 - } else { - return false - } - } - if !rule.IsPointContinuity(3, continuous...) { - return false - } - return other == len(continuous)/3 - } -} - -// HandOrderFourWithOne 四带一顺子 -func HandOrderFourWithOne[P, C generic.Number, T Card[P, C]](count int) HandHandle[P, C, T] { - return func(rule *Rule[P, C, T], cards []T) bool { - group := GroupByPoint[P, C, T](cards...) - var continuous []T - var other int - for _, cards := range group { - if len(cards) == 4 { - continuous = append(continuous, cards...) - } else { - other += len(cards) - } - } - if !rule.IsPointContinuity(4, continuous...) { - return false - } - return other == len(continuous)/4 - } -} - -// HandOrderFourWithTwo 四带二顺子 -func HandOrderFourWithTwo[P, C generic.Number, T Card[P, C]](count int) HandHandle[P, C, T] { - return func(rule *Rule[P, C, T], cards []T) bool { - group := GroupByPoint[P, C, T](cards...) - var continuous []T - var other int - for _, cards := range group { - if len(cards) == 4 { - continuous = append(continuous, cards...) - } else if len(cards)%2 == 0 { - other += len(cards) / 2 - } else { - return false - } - } - if !rule.IsPointContinuity(4, continuous...) { - return false - } - return other == len(continuous)/4 - } -} - -// HandOrderFourWithThree 四带三顺子 -func HandOrderFourWithThree[P, C generic.Number, T Card[P, C]](count int) HandHandle[P, C, T] { - return func(rule *Rule[P, C, T], cards []T) bool { - group := GroupByPoint[P, C, T](cards...) - var continuous []T - var other int - for _, cards := range group { - if len(cards) == 4 { - continuous = append(continuous, cards...) - } else if len(cards)%3 == 0 { - other += len(cards) / 3 - } else { - return false - } - } - if !rule.IsPointContinuity(4, continuous...) { - return false - } - return other == len(continuous)/4 - } -} - -// HandFourWithOne 四带一 -func HandFourWithOne[P, C generic.Number, T Card[P, C]]() HandHandle[P, C, T] { - return func(rule *Rule[P, C, T], cards []T) bool { - group := GroupByPoint[P, C, T](cards...) - var hasFour bool - var count int - for _, cards := range group { - if len(cards) == 4 { - hasFour = true - } else { - count = len(cards) - } - } - return hasFour && count == 1 - } -} - -// HandFourWithTwo 四带二 -func HandFourWithTwo[P, C generic.Number, T Card[P, C]]() HandHandle[P, C, T] { - return func(rule *Rule[P, C, T], cards []T) bool { - group := GroupByPoint[P, C, T](cards...) - var hasFour bool - var count int - for _, cards := range group { - if len(cards) == 4 { - hasFour = true - } else { - count = len(cards) - } - } - return hasFour && count == 2 - } -} - -// HandFourWithThree 四带三 -func HandFourWithThree[P, C generic.Number, T Card[P, C]]() HandHandle[P, C, T] { - return func(rule *Rule[P, C, T], cards []T) bool { - group := GroupByPoint[P, C, T](cards...) - var hasFour bool - var count int - for _, cards := range group { - if len(cards) == 4 { - hasFour = true - } else { - count = len(cards) - } - } - return hasFour && count == 3 - } -} - -// HandFourWithTwoPairs 四带两对 -func HandFourWithTwoPairs[P, C generic.Number, T Card[P, C]]() HandHandle[P, C, T] { - return func(rule *Rule[P, C, T], cards []T) bool { - group := GroupByPoint[P, C, T](cards...) - var hasFour bool - var count int - for _, cards := range group { - length := len(cards) - if length == 4 && !hasFour { - hasFour = true - } else if length%2 == 0 { - count += len(cards) / 2 - if count > 2 { - return false - } - } else { - return false - } - } - return hasFour && count == 2 - } -} - -// HandBomb 炸弹 -func HandBomb[P, C generic.Number, T Card[P, C]]() HandHandle[P, C, T] { - return func(rule *Rule[P, C, T], cards []T) bool { - return len(cards) == 4 && rule.IsPointContinuity(4, cards...) - } -} - -// HandStraightPairs 连对 -func HandStraightPairs[P, C generic.Number, T Card[P, C]]() HandHandle[P, C, T] { - return func(rule *Rule[P, C, T], cards []T) bool { - if len(cards) < 6 || len(cards)%2 != 0 { - return false - } - return rule.IsPointContinuity(2, cards...) - } -} - -// HandPlane 飞机 -// - 表示三张点数相同的牌组成的连续的牌 -func HandPlane[P, C generic.Number, T Card[P, C]]() HandHandle[P, C, T] { - return func(rule *Rule[P, C, T], cards []T) bool { - if len(cards) < 6 || len(cards)%3 != 0 { - return false - } - return rule.IsPointContinuity(3, cards...) - } -} - -// HandPlaneWithOne 飞机带单 -func HandPlaneWithOne[P, C generic.Number, T Card[P, C]]() HandHandle[P, C, T] { - return func(rule *Rule[P, C, T], cards []T) bool { - group := GroupByPoint[P, C, T](cards...) - if len(group) < 2 { - return false - } - var hasThree bool - var count int - for _, cards := range group { - if len(cards) == 3 { - hasThree = true - } else { - count = len(cards) - } - } - return hasThree && count == 1 - } -} - -// HandRocket 王炸 -// - 表示一对王牌,即大王和小王 -func HandRocket[P, C generic.Number, T Card[P, C]](pile *CardPile[P, C, T]) HandHandle[P, C, T] { - return func(rule *Rule[P, C, T], cards []T) bool { - if len(cards) != 2 { - return false - } - return IsRocket[P, C, T](pile, cards[0], cards[1]) - } -} - -// HandFlush 同花 -// - 表示所有牌的花色都相同 -func HandFlush[P, C generic.Number, T Card[P, C]]() HandHandle[P, C, T] { - return func(rule *Rule[P, C, T], cards []T) bool { - return IsFlush[P, C, T](cards...) - } -} - -// HandFlushStraight 同花顺 -// - count: 顺子的对子数量,例如当 count = 2 时,可以是 334455、445566、556677、667788、778899 -// - lower: 顺子的最小连续数量 -// - limit: 顺子的最大连续数量 -func HandFlushStraight[P, C generic.Number, T Card[P, C]](count, lower, limit int) HandHandle[P, C, T] { - return func(rule *Rule[P, C, T], cards []T) bool { - if len(cards) < lower*count || len(cards) > limit*count || len(cards)%count != 0 { - return false - } - if !IsFlush[P, C, T](cards...) { - return false - } - return rule.IsPointContinuity(count, cards...) - } -} - -// HandLeopard 豹子 -// - 表示三张点数相同的牌 -// - 例如:333、444、555、666、777、888、999、JJJ、QQQ、KKK、AAA -// - 大小王不能用于豹子,因为他们没有点数 -func HandLeopard[P, C generic.Number, T Card[P, C]]() HandHandle[P, C, T] { - return func(rule *Rule[P, C, T], cards []T) bool { - if len(cards) == 0 { - return false - } - if len(cards) == 1 { - return true - } - var card = cards[0] - for i := 1; i < len(cards); i++ { - if !Equal[P, C, T](card, cards[1]) { - return false - } - } - return true - } -} - -// HandTwoWithOne 二带一 -// - 表示两张点数相同的牌,加上一张其他点数的牌 -// - 例如:334、445、556、667、778、889、99J、TTQ、JJK、QQA、AA2 -// - 大小王不能用于二带一,因为他们没有点数 -// - 通常用于炸金花玩法中检查对子 -func HandTwoWithOne[P, C generic.Number, T Card[P, C]]() HandHandle[P, C, T] { - return func(rule *Rule[P, C, T], cards []T) bool { - group := GroupByPoint[P, C, T](cards...) - var hasTwo bool - var count int - for _, cards := range group { - if len(cards) == 2 { - hasTwo = true - } else { - count = len(cards) - } - } - return hasTwo && count == 1 - } -} diff --git a/game/poker/options.go b/game/poker/options.go deleted file mode 100644 index 502e819..0000000 --- a/game/poker/options.go +++ /dev/null @@ -1,98 +0,0 @@ -package poker - -import ( - "fmt" - "github.com/kercylan98/minotaur/utils/generic" -) - -type Option[P, C generic.Number, T Card[P, C]] func(rule *Rule[P, C, T]) - -// WithHand 通过绑定特定牌型的方式创建扑克玩法 -// - 牌型顺序决定了牌型的优先级 -func WithHand[P, C generic.Number, T Card[P, C]](pokerHand string, value int, handle HandHandle[P, C, T]) Option[P, C, T] { - return func(rule *Rule[P, C, T]) { - if _, exist := rule.pokerHand[pokerHand]; exist { - panic(fmt.Errorf("same poker hand name: %s", pokerHand)) - } - rule.pokerHand[pokerHand] = handle - rule.pokerHandValue[pokerHand] = value - - restraint, exist := rule.restraint[pokerHand] - if !exist { - restraint = map[string]struct{}{} - rule.restraint[pokerHand] = restraint - } - restraint[pokerHand] = struct{}{} - } -} - -// WithHandRestraint 通过绑定特定克制牌型的方式创建扑克玩法 -func WithHandRestraint[P, C generic.Number, T Card[P, C]](pokerHand, restraint string) Option[P, C, T] { - return func(rule *Rule[P, C, T]) { - r, exist := rule.restraint[pokerHand] - if !exist { - r = map[string]struct{}{} - rule.restraint[pokerHand] = r - } - r[restraint] = struct{}{} - } -} - -// WithHandRestraintFull 通过绑定所有克制牌型的方式创建扑克玩法 -// - 需要确保在牌型声明之后调用 -func WithHandRestraintFull[P, C generic.Number, T Card[P, C]](pokerHand string) Option[P, C, T] { - return func(rule *Rule[P, C, T]) { - for hand := range rule.pokerHand { - r, exist := rule.restraint[pokerHand] - if !exist { - r = map[string]struct{}{} - rule.restraint[pokerHand] = r - } - r[hand] = struct{}{} - } - } -} - -// WithPointValue 通过特定的扑克点数牌值创建扑克玩法 -func WithPointValue[P, C generic.Number, T Card[P, C]](pointValues map[P]int) Option[P, C, T] { - return func(rule *Rule[P, C, T]) { - rule.pointValue = pointValues - } -} - -// WithColorValue 通过特定的扑克花色牌值创建扑克玩法 -func WithColorValue[P, C generic.Number, T Card[P, C]](colorValues map[C]int) Option[P, C, T] { - return func(rule *Rule[P, C, T]) { - rule.colorValue = colorValues - } -} - -// WithPointSort 通过特定的扑克点数顺序创建扑克玩法,顺序必须为连续的 -func WithPointSort[P, C generic.Number, T Card[P, C]](pointSort map[P]int) Option[P, C, T] { - return func(rule *Rule[P, C, T]) { - for k, v := range pointSort { - rule.pointSort[k] = v - } - } -} - -// WithColorSort 通过特定的扑克花色顺序创建扑克玩法,顺序必须为连续的 -func WithColorSort[P, C generic.Number, T Card[P, C]](colorSort map[C]int) Option[P, C, T] { - return func(rule *Rule[P, C, T]) { - for k, v := range colorSort { - rule.colorSort[k] = v - } - } -} - -// WithExcludeContinuityPoint 排除连续的点数 -func WithExcludeContinuityPoint[P, C generic.Number, T Card[P, C]](points ...P) Option[P, C, T] { - return func(rule *Rule[P, C, T]) { - if rule.excludeContinuityPoint == nil { - rule.excludeContinuityPoint = make(map[P]struct{}) - } - for _, point := range points { - rule.excludeContinuityPoint[point] = struct{}{} - } - } -} diff --git a/game/poker/poker.go b/game/poker/poker.go deleted file mode 100644 index d982e5d..0000000 --- a/game/poker/poker.go +++ /dev/null @@ -1,207 +0,0 @@ -package poker - -import ( - "github.com/kercylan98/minotaur/utils/generic" - "math" -) - -// IsContainJoker 检查扑克牌是否包含大小王 -func IsContainJoker[P, C generic.Number, T Card[P, C]](pile *CardPile[P, C, T], cards ...T) bool { - for _, card := range cards { - if IsJoker[P, C, T](pile, card) { - return true - } - } - return false -} - -// GroupByPoint 将扑克牌按照点数分组 -func GroupByPoint[P, C generic.Number, T Card[P, C]](cards ...T) map[P][]T { - group := map[P][]T{} - for _, card := range cards { - group[card.GetPoint()] = append(group[card.GetPoint()], card) - } - return group -} - -// GroupByColor 将扑克牌按照花色分组 -func GroupByColor[P, C generic.Number, T Card[P, C]](cards ...T) map[C][]T { - group := map[C][]T{} - for _, card := range cards { - group[card.GetColor()] = append(group[card.GetColor()], card) - } - return group -} - -// IsRocket 两张牌能否组成红黑 Joker -func IsRocket[P, C generic.Number, T Card[P, C]](pile *CardPile[P, C, T], cardA, cardB T) bool { - var num int - for _, joker := range pile.jokers { - if cardA.GetPoint() == joker || cardB.GetPoint() == joker { - num++ - } - } - return num == 2 -} - -// IsFlush 判断是否是同花 -func IsFlush[P, C generic.Number, T Card[P, C]](cards ...T) bool { - if len(cards) == 0 { - return false - } - if len(cards) == 1 { - return true - } - - color := cards[0].GetColor() - for i := 1; i < len(cards); i++ { - if cards[i].GetColor() != color { - return false - } - } - return true -} - -// GetCardsPoint 获取一组扑克牌的点数 -func GetCardsPoint[P, C generic.Number, T Card[P, C]](cards ...T) []P { - var points = make([]P, len(cards)) - for i, card := range cards { - points[i] = card.GetPoint() - } - return points -} - -// GetCardsColor 获取一组扑克牌的花色 -func GetCardsColor[P, C generic.Number, T Card[P, C]](cards ...T) []C { - var colors = make([]C, len(cards)) - for i, card := range cards { - colors[i] = card.GetColor() - } - return colors -} - -// IsContain 一组扑克牌是否包含某张牌 -func IsContain[P, C generic.Number, T Card[P, C]](cards []T, card T) bool { - for _, c := range cards { - if Equal[P, C, T](c, card) { - return true - } - } - return false -} - -// IsContainAll 一组扑克牌是否包含另一组扑克牌 -func IsContainAll[P, C generic.Number, T Card[P, C]](cards []T, cards2 []T) bool { - for _, card := range cards2 { - if !IsContain[P, C, T](cards, card) { - return false - } - } - return true -} - -// GetPointAndColor 返回扑克牌的点数和花色 -func GetPointAndColor[P, C generic.Number, T Card[P, C]](card T) (P, C) { - return card.GetPoint(), card.GetColor() -} - -// EqualPoint 比较两张扑克牌的点数是否相同 -func EqualPoint[P, C generic.Number, T Card[P, C]](card1 T, card2 T) bool { - return card1.GetPoint() == card2.GetPoint() -} - -// EqualColor 比较两张扑克牌的花色是否相同 -func EqualColor[P, C generic.Number, T Card[P, C]](card1 T, card2 T) bool { - return card1.GetColor() == card2.GetColor() -} - -// Equal 比较两张扑克牌的点数和花色是否相同 -func Equal[P, C generic.Number, T Card[P, C]](card1 T, card2 T) bool { - return EqualPoint[P, C, T](card1, card2) && EqualColor[P, C, T](card1, card2) -} - -// MaxPoint 返回两张扑克牌中点数较大的一张 -func MaxPoint[P, C generic.Number, T Card[P, C]](card1 T, card2 T) T { - if card1.GetPoint() > card2.GetPoint() { - return card1 - } - return card2 -} - -// MinPoint 返回两张扑克牌中点数较小的一张 -func MinPoint[P, C generic.Number, T Card[P, C]](card1 T, card2 T) T { - if card1.GetPoint() < card2.GetPoint() { - return card1 - } - return card2 -} - -// MaxColor 返回两张扑克牌中花色较大的一张 -func MaxColor[P, C generic.Number, T Card[P, C]](card1 T, card2 T) T { - if card1.GetColor() > card2.GetColor() { - return card1 - } - return card2 -} - -// MinColor 返回两张扑克牌中花色较小的一张 -func MinColor[P, C generic.Number, T Card[P, C]](card1 T, card2 T) T { - if card1.GetColor() < card2.GetColor() { - return card1 - } - return card2 -} - -// Max 返回两张扑克牌中点数和花色较大的一张 -func Max[P, C generic.Number, T Card[P, C]](card1 T, card2 T) T { - if card1.GetPoint() > card2.GetPoint() { - return card1 - } else if card1.GetPoint() < card2.GetPoint() { - return card2 - } else if card1.GetColor() > card2.GetColor() { - return card1 - } - return card2 -} - -// Min 返回两张扑克牌中点数和花色较小的一张 -func Min[P, C generic.Number, T Card[P, C]](card1 T, card2 T) T { - if card1.GetPoint() < card2.GetPoint() { - return card1 - } else if card1.GetPoint() > card2.GetPoint() { - return card2 - } else if card1.GetColor() < card2.GetColor() { - return card1 - } - return card2 -} - -// PointDifference 计算两张扑克牌的点数差 -func PointDifference[P, C generic.Number, T Card[P, C]](card1 T, card2 T) int { - return int(math.Abs(float64(card1.GetPoint()) - float64(card2.GetPoint()))) -} - -// ColorDifference 计算两张扑克牌的花色差 -func ColorDifference[P, C generic.Number, T Card[P, C]](card1 T, card2 T) int { - return int(math.Abs(float64(card1.GetColor()) - float64(card2.GetColor()))) -} - -// IsNeighborColor 判断两张扑克牌是否为相邻的花色 -func IsNeighborColor[P, C generic.Number, T Card[P, C]](card1 T, card2 T) bool { - return ColorDifference[P, C, T](card1, card2) == 1 -} - -// IsNeighborPoint 判断两张扑克牌是否为相邻的点数 -func IsNeighborPoint[P, C generic.Number, T Card[P, C]](card1 T, card2 T) bool { - return PointDifference[P, C, T](card1, card2) == 1 -} - -// IsJoker 判断扑克牌是否为大小王 -func IsJoker[P, C generic.Number, T Card[P, C]](pile *CardPile[P, C, T], card T) bool { - for _, joker := range pile.jokers { - if card.GetPoint() == joker { - return true - } - } - return false -} diff --git a/game/poker/rule.go b/game/poker/rule.go deleted file mode 100644 index ae0d024..0000000 --- a/game/poker/rule.go +++ /dev/null @@ -1,256 +0,0 @@ -package poker - -import ( - "github.com/kercylan98/minotaur/utils/generic" - "github.com/kercylan98/minotaur/utils/hash" - "github.com/kercylan98/minotaur/utils/maths" - "sort" -) - -// Deprecated: 从 Minotaur 0.0.25 开始,由于设计原因已弃用,请尝试考虑使用 combination.Combination、combination.Matcher、combination.Validator 代替 -func NewRule[P, C generic.Number, T Card[P, C]](options ...Option[P, C, T]) *Rule[P, C, T] { - poker := &Rule[P, C, T]{ - pokerHand: map[string]HandHandle[P, C, T]{}, - //pointSort: hash.Copy(defaultPointSort), - //colorSort: hash.Copy(defaultColorSort), - pokerHandValue: map[string]int{}, - restraint: map[string]map[string]struct{}{}, - } - for _, option := range options { - option(poker) - } - if poker.pointValue == nil { - poker.pointValue = poker.pointSort - } - return poker -} - -type Rule[P, C generic.Number, T Card[P, C]] struct { - pokerHand map[string]HandHandle[P, C, T] - pokerHandValue map[string]int - pointValue map[P]int - colorValue map[C]int - pointSort map[P]int - colorSort map[C]int - excludeContinuityPoint map[P]struct{} - restraint map[string]map[string]struct{} -} - -// GetCardCountWithPointMaximumNumber 获取指定点数的牌的数量 -func (slf *Rule[P, C, T]) GetCardCountWithPointMaximumNumber(cards []T, point P, maximumNumber int) int { - count := 0 - for _, card := range cards { - if card.GetPoint() == point { - count++ - if count >= maximumNumber { - return count - } - } - } - return count -} - -// GetCardCountWithColorMaximumNumber 获取指定花色的牌的数量 -func (slf *Rule[P, C, T]) GetCardCountWithColorMaximumNumber(cards []T, color C, maximumNumber int) int { - count := 0 - for _, card := range cards { - if card.GetColor() == color { - count++ - if count >= maximumNumber { - return count - } - } - } - return count -} - -// GetCardCountWithMaximumNumber 获取指定牌的数量 -func (slf *Rule[P, C, T]) GetCardCountWithMaximumNumber(cards []T, card T, maximumNumber int) int { - count := 0 - for _, c := range cards { - if Equal[P, C, T](c, card) { - count++ - if count >= maximumNumber { - return count - } - } - } - return count -} - -// GetCardCountWithPoint 获取指定点数的牌的数量 -func (slf *Rule[P, C, T]) GetCardCountWithPoint(cards []T, point P) int { - count := 0 - for _, card := range cards { - if card.GetPoint() == point { - count++ - } - } - return count -} - -// GetCardCountWithColor 获取指定花色的牌的数量 -func (slf *Rule[P, C, T]) GetCardCountWithColor(cards []T, color C) int { - count := 0 - for _, card := range cards { - if card.GetColor() == color { - count++ - } - } - return count -} - -// GetCardCount 获取指定牌的数量 -func (slf *Rule[P, C, T]) GetCardCount(cards []T, card T) int { - count := 0 - for _, c := range cards { - if Equal[P, C, T](c, card) { - count++ - } - } - return count -} - -// PokerHandIsMatch 检查两组扑克牌牌型是否匹配 -func (slf *Rule[P, C, T]) PokerHandIsMatch(cardsA, cardsB []T) bool { - handA, exist := slf.PokerHand(cardsA...) - if !exist { - return false - } - handB, exist := slf.PokerHand(cardsB...) - if !exist { - return false - } - if hash.Exist(slf.restraint[handA], handB) || hash.Exist(slf.restraint[handB], handA) { - return false - } - return len(cardsA) == len(cardsB) -} - -// PokerHand 获取一组扑克的牌型 -func (slf *Rule[P, C, T]) PokerHand(cards ...T) (pokerHand string, hit bool) { - for phn := range slf.pokerHandValue { - if slf.pokerHand[phn](slf, cards) { - return phn, true - } - } - return HandNone, false -} - -// IsPointContinuity 检查一组扑克牌点数是否连续,count 表示了每个点数的数量 -func (slf *Rule[P, C, T]) IsPointContinuity(count int, cards ...T) bool { - if len(cards) == 0 { - return false - } - group := GroupByPoint[P, C, T](cards...) - var values []int - for point, cards := range group { - if _, exist := slf.excludeContinuityPoint[point]; exist { - return false - } - if count != len(cards) { - return false - } - values = append(values, slf.GetValueWithPoint(point)) - } - return maths.IsContinuityWithSort(values) -} - -// IsSameColor 检查一组扑克牌是否同花 -func (slf *Rule[P, C, T]) IsSameColor(cards ...T) bool { - length := len(cards) - if length == 0 { - return false - } - if length == 1 { - return true - } - var color = cards[0].GetColor() - for i := 1; i < length; i++ { - if cards[i].GetColor() != color { - return false - } - } - return true -} - -// IsSamePoint 检查一组扑克牌是否同点 -func (slf *Rule[P, C, T]) IsSamePoint(cards ...T) bool { - length := len(cards) - if length == 0 { - return false - } - if length == 1 { - return true - } - var point = cards[0].GetPoint() - for i := 1; i < length; i++ { - if cards[i].GetPoint() != point { - return false - } - } - return true -} - -// SortByPointDesc 将扑克牌按照点数从大到小排序 -func (slf *Rule[P, C, T]) SortByPointDesc(cards []T) []T { - sort.Slice(cards, func(i, j int) bool { - return slf.pointSort[cards[i].GetPoint()] > slf.pointSort[cards[j].GetPoint()] - }) - return cards -} - -// SortByPointAsc 将扑克牌按照点数从小到大排序 -func (slf *Rule[P, C, T]) SortByPointAsc(cards []T) []T { - sort.Slice(cards, func(i, j int) bool { - return slf.pointSort[cards[i].GetPoint()] < slf.pointSort[cards[j].GetPoint()] - }) - return cards -} - -// SortByColorDesc 将扑克牌按照花色从大到小排序 -func (slf *Rule[P, C, T]) SortByColorDesc(cards []T) []T { - sort.Slice(cards, func(i, j int) bool { - return slf.colorSort[cards[i].GetColor()] > slf.colorSort[cards[j].GetColor()] - }) - return cards -} - -// SortByColorAsc 将扑克牌按照花色从小到大排序 -func (slf *Rule[P, C, T]) SortByColorAsc(cards []T) []T { - sort.Slice(cards, func(i, j int) bool { - return slf.colorSort[cards[i].GetColor()] < slf.colorSort[cards[j].GetColor()] - }) - return cards -} - -// GetValueWithPokerHand 获取扑克牌的牌型牌值 -func (slf *Rule[P, C, T]) GetValueWithPokerHand(hand string, cards ...T) int { - hv := slf.pokerHandValue[hand] - return hv * slf.GetValueWithCards(cards...) -} - -// GetValueWithCards 获取扑克牌的牌值 -func (slf *Rule[P, C, T]) GetValueWithCards(cards ...T) int { - var value int - for _, card := range cards { - value += slf.GetValueWithPoint(card.GetPoint()) - value += slf.GetValueWithColor(card.GetColor()) - } - return value -} - -// GetValueWithPoint 获取扑克牌的点数牌值 -func (slf *Rule[P, C, T]) GetValueWithPoint(point P) int { - return slf.pointValue[point] -} - -// GetValueWithColor 获取扑克牌的花色牌值 -func (slf *Rule[P, C, T]) GetValueWithColor(color C) int { - return slf.colorValue[color] -} - -// CompareValueWithCards 根据特定的条件表达式比较两组扑克牌的牌值 -func (slf *Rule[P, C, T]) CompareValueWithCards(cards1 []T, expression maths.CompareExpression, cards2 []T) bool { - return maths.Compare(slf.GetValueWithCards(cards1...), expression, slf.GetValueWithCards(cards2...)) -}