refactor: 移除过时的 poker 包。其中 poker.Rule 的可替代品为 combination.Combination、combination.Matcher、combination.Validator,poker.CardPile 的可替代品为 deck.Deck、deck.Group

This commit is contained in:
kercylan98 2023-12-22 10:23:04 +08:00
parent 1e0ef4b062
commit 41246ef365
9 changed files with 0 additions and 1270 deletions

View File

@ -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
}

View File

@ -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)
}

View File

@ -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{}{}
}
}
}
}
}

View File

@ -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())
}
}

View File

@ -1,10 +0,0 @@
// Package poker 提供了一组用于处理扑克牌游戏的函数和数据结构。该包旨在简化扑克牌游戏的开发过程,并提供一致的接口和易于使用的功能。
//
// 主要特性:
// - 扑克牌操作:"poker"包支持处理扑克牌的各种操作,如洗牌、发牌、比较牌面大小等。您可以使用这些操作来模拟和实现各种扑克牌游戏。
// - 扑克牌规则:该包提供了一系列函数,用于执行常见的扑克牌规则,如判断是否是同花顺、计算牌面点数等。这些函数旨在提供准确和可靠的规则判断和计算结果。
// - 扑克牌算法:"poker"包还提供了一些算法,用于解决扑克牌游戏中的问题,如计算最佳牌型、判断是否存在顺子等。这些算法旨在提供高效和优化的解决方案。
// - 简化接口:该包的设计目标之一是提供简化的接口,使扑克牌游戏的开发变得更加直观和易于使用。您可以轻松地创建和操作扑克牌对象,而无需处理繁琐的底层细节。
//
// Deprecated: 从 Minotaur 0.0.25 开始,由于设计原因已弃用,请尝试考虑使用 utils/combination 和 utils/deck 代替
package poker

View File

@ -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
}
}

View File

@ -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{}{}
}
}
}

View File

@ -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
}

View File

@ -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...))
}