refactor: 重构 poker 包设计,移除 Poker 结构体,以 Rule 结构体进行取代

- 移除了 poker.Poker 的设计,采用了 poker.Rule 管理规则。
- 将牌堆和规则进行分离,可单独使用。
-
增加大量辅助函数及内置牌型检测函数。
This commit is contained in:
kercylan98 2023-06-30 12:50:10 +08:00
parent 0ab38c7023
commit d1b7699cb4
9 changed files with 823 additions and 128 deletions

View File

@ -1,6 +1,9 @@
package poker package poker
import "fmt" import (
"fmt"
"math"
)
// NewCard 创建一张扑克牌 // NewCard 创建一张扑克牌
// - 当 point 为 PointBlackJoker 或 PointRedJoker 时color 将没有效果 // - 当 point 为 PointBlackJoker 或 PointRedJoker 时color 将没有效果
@ -54,6 +57,102 @@ func (slf Card) Equal(card Card) bool {
return slf.GetPoint() == card.GetPoint() && slf.GetColor() == card.GetColor() return slf.GetPoint() == card.GetPoint() && slf.GetColor() == card.GetColor()
} }
// MaxPoint 返回两张扑克牌中点数较大的一张
func (slf Card) MaxPoint(card Card) Card {
if slf.GetPoint() > card.GetPoint() {
return slf
}
return card
}
// MinPoint 返回两张扑克牌中点数较小的一张
func (slf Card) MinPoint(card Card) Card {
if slf.GetPoint() < card.GetPoint() {
return slf
}
return card
}
// MaxColor 返回两张扑克牌中花色较大的一张
func (slf Card) MaxColor(card Card) Card {
if slf.GetColor() > card.GetColor() {
return slf
}
return card
}
// MinColor 返回两张扑克牌中花色较小的一张
func (slf Card) MinColor(card Card) Card {
if slf.GetColor() < card.GetColor() {
return slf
}
return card
}
// Max 返回两张扑克牌中点数和花色较大的一张
func (slf Card) Max(card Card) Card {
if slf.GetPoint() > card.GetPoint() {
return slf
} else if slf.GetPoint() < card.GetPoint() {
return card
} else {
if slf.GetColor() > card.GetColor() {
return slf
}
return card
}
}
// Min 返回两张扑克牌中点数和花色较小的一张
func (slf Card) Min(card Card) Card {
if slf.GetPoint() < card.GetPoint() {
return slf
} else if slf.GetPoint() > card.GetPoint() {
return card
} else {
if slf.GetColor() < card.GetColor() {
return slf
}
return card
}
}
// IsJoker 判断是否为大小王
func (slf Card) IsJoker() bool {
point := slf.GetPoint()
return point == PointRedJoker || point == PointBlackJoker
}
// CalcPointDifference 计算两张扑克牌的点数差
func (slf Card) CalcPointDifference(card Card) int {
return int(slf.GetPoint()) - int(card.GetPoint())
}
// CalcPointDifferenceAbs 计算两张扑克牌的点数差的绝对值
func (slf Card) CalcPointDifferenceAbs(card Card) int {
return int(math.Abs(float64(slf.CalcPointDifference(card))))
}
// CalcColorDifference 计算两张扑克牌的花色差
func (slf Card) CalcColorDifference(card Card) int {
return int(slf.GetColor()) - int(card.GetColor())
}
// CalcColorDifferenceAbs 计算两张扑克牌的花色差的绝对值
func (slf Card) CalcColorDifferenceAbs(card Card) int {
return int(math.Abs(float64(slf.CalcColorDifference(card))))
}
// IsNeighborPoint 判断两张扑克牌是否为相邻的点数
func (slf Card) IsNeighborPoint(card Card) bool {
return slf.CalcPointDifferenceAbs(card) == 1
}
// IsNeighborColor 判断两张扑克牌是否为相邻的花色
func (slf Card) IsNeighborColor(card Card) bool {
return slf.CalcColorDifferenceAbs(card) == 1
}
// String 将扑克牌转换为字符串形式 // String 将扑克牌转换为字符串形式
func (slf Card) String() string { func (slf Card) String() string {
return fmt.Sprintf("(%s %s)", slf.point, slf.color) return fmt.Sprintf("(%s %s)", slf.point, slf.color)

View File

@ -48,7 +48,7 @@ func (slf *CardPile) Reset() {
cards = append(cards, NewCard(PointBlackJoker, ColorNone)) cards = append(cards, NewCard(PointBlackJoker, ColorNone))
} }
for point := PointK; point >= PointA; point-- { for point := PointK; point >= PointA; point-- {
for color := ColorSpade; color <= ColorDiamond; color++ { for color := ColorDiamond; color <= ColorSpade; color++ {
if !slf.IsExclude(point, color) { if !slf.IsExclude(point, color) {
cards = append(cards, NewCard(point, color)) cards = append(cards, NewCard(point, color))
} }

View File

@ -2,12 +2,20 @@ package poker
const ( const (
ColorNone Color = 0 // 无花色,通常为大小王 ColorNone Color = 0 // 无花色,通常为大小王
ColorSpade Color = 1 // 黑桃 ColorSpade Color = 4 // 黑桃
ColorHeart Color = 2 // 红桃 ColorHeart Color = 3 // 红桃
ColorClub Color = 3 // 梅花 ColorClub Color = 2 // 梅花
ColorDiamond Color = 4 // 方片 ColorDiamond Color = 1 // 方片
) )
var defaultColorSort = map[Color]int{
ColorSpade: int(ColorSpade),
ColorHeart: int(ColorHeart),
ColorClub: int(ColorClub),
ColorDiamond: int(ColorDiamond),
ColorNone: int(ColorDiamond + 1),
}
// Color 扑克牌花色 // Color 扑克牌花色
type Color int type Color int

View File

@ -1,19 +0,0 @@
package poker
// GetCardsPoint 获取一组扑克牌的点数
func GetCardsPoint(cards ...Card) []Point {
var points = make([]Point, len(cards))
for i, card := range cards {
points[i] = card.GetPoint()
}
return points
}
// GetCardsColor 获取一组扑克牌的花色
func GetCardsColor(cards ...Card) []Color {
var colors = make([]Color, len(cards))
for i, card := range cards {
colors[i] = card.GetColor()
}
return colors
}

View File

@ -1,36 +1,412 @@
package poker package poker
const (
HandNone = "None" // 无牌型
)
// HandHandle 扑克牌型验证函数 // HandHandle 扑克牌型验证函数
type HandHandle func(poker *Poker, cards []Card) bool type HandHandle func(rule *Rule, cards []Card) bool
// HandPairs 对子
func HandPairs() HandHandle {
return func(poker *Poker, cards []Card) bool {
return len(cards) == 2 && cards[0].EqualPoint(cards[1])
}
}
// HandFlushPairs 同花对子
func HandFlushPairs() HandHandle {
return func(poker *Poker, cards []Card) bool {
if len(cards) != 2 {
return false
}
card1, card2 := cards[0], cards[1]
return card1.Equal(card2)
}
}
// HandSingle 单牌 // HandSingle 单牌
func HandSingle() HandHandle { func HandSingle() HandHandle {
return func(poker *Poker, cards []Card) bool { return func(rule *Rule, cards []Card) bool {
return len(cards) == 1 return len(cards) == 1
} }
} }
// HandPairs 对子
func HandPairs() HandHandle {
return func(rule *Rule, cards []Card) bool {
return len(cards) == 2 && rule.IsPointContinuity(2, cards...)
}
}
// HandThreeOfKind 三张 // HandThreeOfKind 三张
func HandThreeOfKind() HandHandle { func HandThreeOfKind() HandHandle {
return func(poker *Poker, cards []Card) bool { return func(rule *Rule, cards []Card) bool {
return len(cards) == 3 && cards[0].EqualPoint(cards[1]) && cards[1].EqualPoint(cards[2]) return len(cards) == 3 && rule.IsPointContinuity(3, cards...)
}
}
// HandThreeOfKindWithOne 三带一
func HandThreeOfKindWithOne() HandHandle {
return func(rule *Rule, cards []Card) bool {
group := GroupByPoint(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() HandHandle {
return func(rule *Rule, cards []Card) bool {
group := GroupByPoint(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(count int) HandHandle {
return func(rule *Rule, cards []Card) bool {
return len(cards) >= count && rule.IsPointContinuity(1, cards...)
}
}
// HandOrderPairs 对子顺子
func HandOrderPairs(count int) HandHandle {
return func(rule *Rule, cards []Card) bool {
if len(cards) < count*2 || len(cards)%2 != 0 {
return false
}
return rule.IsPointContinuity(2, cards...)
}
}
// HandOrderSingleThree 三张顺子
func HandOrderSingleThree(count int) HandHandle {
return func(rule *Rule, cards []Card) bool {
if len(cards) < count*3 || len(cards)%3 != 0 {
return false
}
return rule.IsPointContinuity(3, cards...)
}
}
// HandOrderSingleFour 四张顺子
func HandOrderSingleFour(count int) HandHandle {
return func(rule *Rule, cards []Card) bool {
if len(cards) < count*4 || len(cards)%4 != 0 {
return false
}
return rule.IsPointContinuity(4, cards...)
}
}
// HandOrderThreeWithOne 三带一顺子
func HandOrderThreeWithOne(count int) HandHandle {
return func(rule *Rule, cards []Card) bool {
group := GroupByPoint(cards...)
var continuous []Card
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(count int) HandHandle {
return func(rule *Rule, cards []Card) bool {
group := GroupByPoint(cards...)
var continuous []Card
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(count int) HandHandle {
return func(rule *Rule, cards []Card) bool {
group := GroupByPoint(cards...)
var continuous []Card
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(count int) HandHandle {
return func(rule *Rule, cards []Card) bool {
group := GroupByPoint(cards...)
var continuous []Card
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(count int) HandHandle {
return func(rule *Rule, cards []Card) bool {
group := GroupByPoint(cards...)
var continuous []Card
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() HandHandle {
return func(rule *Rule, cards []Card) bool {
group := GroupByPoint(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() HandHandle {
return func(rule *Rule, cards []Card) bool {
group := GroupByPoint(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() HandHandle {
return func(rule *Rule, cards []Card) bool {
group := GroupByPoint(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() HandHandle {
return func(rule *Rule, cards []Card) bool {
group := GroupByPoint(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() HandHandle {
return func(rule *Rule, cards []Card) bool {
return len(cards) == 4 && rule.IsPointContinuity(4, cards...)
}
}
// HandStraightPairs 连对
func HandStraightPairs() HandHandle {
return func(rule *Rule, cards []Card) bool {
if len(cards) < 6 || len(cards)%2 != 0 {
return false
}
return rule.IsPointContinuity(2, cards...)
}
}
// HandPlane 飞机
// - 表示三张点数相同的牌组成的连续的牌
func HandPlane() HandHandle {
return func(rule *Rule, cards []Card) bool {
if len(cards) < 6 || len(cards)%3 != 0 {
return false
}
return rule.IsPointContinuity(3, cards...)
}
}
// HandPlaneWithOne 飞机带单
func HandPlaneWithOne() HandHandle {
return func(rule *Rule, cards []Card) bool {
group := GroupByPoint(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() HandHandle {
return func(rule *Rule, cards []Card) bool {
if len(cards) != 2 {
return false
}
return IsRocket(cards[0], cards[1])
}
}
// HandFlush 同花
// - 表示所有牌的花色都相同
func HandFlush() HandHandle {
return func(rule *Rule, cards []Card) bool {
return IsFlush(cards...)
}
}
// HandFlushStraight 同花顺
// - count: 顺子的对子数量,例如当 count = 2 时,可以是 334455、445566、556677、667788、778899
// - lower: 顺子的最小连续数量
// - limit: 顺子的最大连续数量
func HandFlushStraight(count, lower, limit int) HandHandle {
return func(rule *Rule, cards []Card) bool {
if len(cards) < lower*count || len(cards) > limit*count || len(cards)%count != 0 {
return false
}
if !IsFlush(cards...) {
return false
}
return rule.IsPointContinuity(count, cards...)
}
}
// HandLeopard 豹子
// - 表示三张点数相同的牌
// - 例如333、444、555、666、777、888、999、JJJ、QQQ、KKK、AAA
// - 大小王不能用于豹子,因为他们没有点数
func HandLeopard() HandHandle {
return func(rule *Rule, cards []Card) 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 !card.Equal(cards[1]) {
return false
}
}
return true
}
}
// HandTwoWithOne 二带一
// - 表示两张点数相同的牌,加上一张其他点数的牌
// - 例如334、445、556、667、778、889、99J、TTQ、JJK、QQA、AA2
// - 大小王不能用于二带一,因为他们没有点数
// - 通常用于炸金花玩法中检查对子
func HandTwoWithOne() HandHandle {
return func(rule *Rule, cards []Card) bool {
group := GroupByPoint(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

@ -2,38 +2,94 @@ package poker
import "fmt" import "fmt"
type Option func(poker *Poker) type Option func(rule *Rule)
// WithHand 通过绑定特定牌型的方式创建扑克玩法 // WithHand 通过绑定特定牌型的方式创建扑克玩法
func WithHand(pokerHand string, handle HandHandle) Option { // - 牌型顺序决定了牌型的优先级
return func(poker *Poker) { func WithHand(pokerHand string, value int, handle HandHandle) Option {
if _, exist := poker.pokerHand[pokerHand]; exist { return func(rule *Rule) {
if _, exist := rule.pokerHand[pokerHand]; exist {
panic(fmt.Errorf("same poker hand name: %s", pokerHand)) panic(fmt.Errorf("same poker hand name: %s", pokerHand))
} }
poker.pokerHand[pokerHand] = handle rule.pokerHand[pokerHand] = handle
poker.pokerHandPriority = append(poker.pokerHandPriority, pokerHand) 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(pokerHand, restraint string) Option {
return func(rule *Rule) {
r, exist := rule.restraint[pokerHand]
if !exist {
r = map[string]struct{}{}
rule.restraint[pokerHand] = r
}
r[restraint] = struct{}{}
}
}
// WithHandRestraintFull 通过绑定所有克制牌型的方式创建扑克玩法
// - 需要确保在牌型声明之后调用
func WithHandRestraintFull(pokerHand string) Option {
return func(rule *Rule) {
for hand := range rule.pokerHand {
r, exist := rule.restraint[pokerHand]
if !exist {
r = map[string]struct{}{}
rule.restraint[pokerHand] = r
}
r[hand] = struct{}{}
}
} }
} }
// WithPointValue 通过特定的扑克点数牌值创建扑克玩法 // WithPointValue 通过特定的扑克点数牌值创建扑克玩法
func WithPointValue(pointValues map[Point]int) Option { func WithPointValue(pointValues map[Point]int) Option {
return func(poker *Poker) { return func(rule *Rule) {
poker.pointValue = pointValues rule.pointValue = pointValues
} }
} }
// WithColorValue 通过特定的扑克花色牌值创建扑克玩法 // WithColorValue 通过特定的扑克花色牌值创建扑克玩法
func WithColorValue(colorValues map[Color]int) Option { func WithColorValue(colorValues map[Color]int) Option {
return func(poker *Poker) { return func(rule *Rule) {
poker.colorValue = colorValues rule.colorValue = colorValues
} }
} }
// WithPointSort 通过特定的扑克点数顺序创建扑克玩法 // WithPointSort 通过特定的扑克点数顺序创建扑克玩法,顺序必须为连续的
func WithPointSort(pointSort map[Point]int) Option { func WithPointSort(pointSort map[Point]int) Option {
return func(poker *Poker) { return func(rule *Rule) {
for k, v := range pointSort { for k, v := range pointSort {
poker.pointSort[k] = v rule.pointSort[k] = v
}
}
}
// WithColorSort 通过特定的扑克花色顺序创建扑克玩法,顺序必须为连续的
func WithColorSort(colorSort map[Color]int) Option {
return func(rule *Rule) {
for k, v := range colorSort {
rule.colorSort[k] = v
}
}
}
// WithExcludeContinuityPoint 排除连续的点数
func WithExcludeContinuityPoint(points ...Point) Option {
return func(rule *Rule) {
if rule.excludeContinuityPoint == nil {
rule.excludeContinuityPoint = make(map[Point]struct{})
}
for _, point := range points {
rule.excludeContinuityPoint[point] = struct{}{}
} }
} }
} }

View File

@ -1,90 +1,70 @@
package poker package poker
import ( // IsContainJoker 检查扑克牌是否包含大小王
"github.com/kercylan98/minotaur/utils/hash" func IsContainJoker(cards ...Card) bool {
"github.com/kercylan98/minotaur/utils/maths"
"sort"
)
func New(pile *CardPile, options ...Option) *Poker {
poker := &Poker{
pile: pile,
pokerHand: map[string]HandHandle{},
pointSort: hash.Copy(defaultPointSort),
}
for _, option := range options {
option(poker)
}
if poker.pointValue == nil {
poker.pointValue = poker.pointSort
}
return poker
}
type Poker struct {
pile *CardPile
pokerHand map[string]HandHandle
pokerHandPriority []string
pointValue map[Point]int
colorValue map[Color]int
pointSort map[Point]int
}
// IsContinuity 检查一组扑克牌是否连续
func (slf *Poker) IsContinuity(cards ...Card) bool {
length := len(cards)
if length == 0 {
return false
}
if length == 1 {
return true
}
var points = make([]int, length)
for i, card := range cards {
points[i] = slf.pointSort[card.GetPoint()]
}
sort.Slice(points, func(i, j int) bool { return points[i] < points[j] })
for i := 0; i < length-1; i++ {
if points[i+1]-points[i] != 1 {
return false
}
}
return true
}
// CardValue 获取扑克牌的牌值
func (slf *Poker) CardValue(cards ...Card) int {
var value int
for _, card := range cards { for _, card := range cards {
value += slf.pointValue[card.GetPoint()] if card.IsJoker() {
value += slf.colorValue[card.GetColor()] return true
}
return value
}
// Compare 根据特定的条件表达式比较两组扑克牌的牌值
func (slf *Poker) Compare(cards1 []Card, expression maths.CompareExpression, cards2 []Card) bool {
return maths.Compare(slf.CardValue(cards1...), expression, slf.CardValue(cards2...))
}
// PokerHand 获取一组扑克的牌型
//
// 参数:
// - cards: 扑克牌切片,类型为 []builtin.Card表示一组扑克牌。
//
// 返回值:
// - string: 命中的牌型名称。
// - bool: 是否命中牌型。
func (slf *Poker) PokerHand(cards ...Card) (cardType string, hit bool) {
for _, phn := range slf.pokerHandPriority {
if slf.pokerHand[phn](slf, cards) {
return phn, true
} }
} }
return "", false return false
} }
// GetPile 获取牌堆 // GroupByPoint 将扑克牌按照点数分组
func (slf *Poker) GetPile() *CardPile { func GroupByPoint(cards ...Card) map[Point][]Card {
return slf.pile group := map[Point][]Card{}
for _, card := range cards {
group[card.GetPoint()] = append(group[card.GetPoint()], card)
}
return group
}
// GroupByColor 将扑克牌按照花色分组
func GroupByColor(cards ...Card) map[Color][]Card {
group := map[Color][]Card{}
for _, card := range cards {
group[card.GetColor()] = append(group[card.GetColor()], card)
}
return group
}
// IsRocket 两张牌能否组成红黑 Joker
func IsRocket(cardA, cardB Card) bool {
return cardA.GetPoint() == PointRedJoker && cardB.GetPoint() == PointBlackJoker || cardA.GetPoint() == PointBlackJoker && cardB.GetPoint() == PointRedJoker
}
// IsFlush 判断是否是同花
func IsFlush(cards ...Card) 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(cards ...Card) []Point {
var points = make([]Point, len(cards))
for i, card := range cards {
points[i] = card.GetPoint()
}
return points
}
// GetCardsColor 获取一组扑克牌的花色
func GetCardsColor(cards ...Card) []Color {
var colors = make([]Color, len(cards))
for i, card := range cards {
colors[i] = card.GetColor()
}
return colors
} }

178
game/poker/rule.go Normal file
View File

@ -0,0 +1,178 @@
package poker
import (
"github.com/kercylan98/minotaur/utils/hash"
"github.com/kercylan98/minotaur/utils/maths"
"sort"
)
func NewRule(options ...Option) *Rule {
poker := &Rule{
pokerHand: map[string]HandHandle{},
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 struct {
pokerHand map[string]HandHandle
pokerHandValue map[string]int
pointValue map[Point]int
colorValue map[Color]int
pointSort map[Point]int
colorSort map[Color]int
excludeContinuityPoint map[Point]struct{}
restraint map[string]map[string]struct{}
}
// PokerHandIsMatch 检查两组扑克牌牌型是否匹配
func (slf *Rule) PokerHandIsMatch(cardsA, cardsB []Card) 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) PokerHand(cards ...Card) (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) IsPointContinuity(count int, cards ...Card) bool {
if len(cards) == 0 {
return false
}
group := GroupByPoint(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) IsSameColor(cards ...Card) 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) IsSamePoint(cards ...Card) 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) SortByPointDesc(cards []Card) []Card {
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) SortByPointAsc(cards []Card) []Card {
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) SortByColorDesc(cards []Card) []Card {
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) SortByColorAsc(cards []Card) []Card {
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) GetValueWithPokerHand(hand string) int {
return slf.pokerHandValue[hand]
}
// GetValueWithCards 获取扑克牌的牌值
func (slf *Rule) GetValueWithCards(cards ...Card) int {
var value int
for _, card := range cards {
value += slf.pointValue[card.GetPoint()]
value += slf.colorValue[card.GetColor()]
}
return value
}
// GetValueWithPoint 获取扑克牌的点数牌值
func (slf *Rule) GetValueWithPoint(point Point) int {
return slf.pointValue[point]
}
// GetValueWithColor 获取扑克牌的花色牌值
func (slf *Rule) GetValueWithColor(color Color) int {
return slf.colorValue[color]
}
// CompareValueWithCards 根据特定的条件表达式比较两组扑克牌的牌值
func (slf *Rule) CompareValueWithCards(cards1 []Card, expression maths.CompareExpression, cards2 []Card) bool {
return maths.Compare(slf.GetValueWithCards(cards1...), expression, slf.GetValueWithCards(cards2...))
}

View File

@ -3,6 +3,7 @@ package maths
import ( import (
"github.com/kercylan98/minotaur/utils/generic" "github.com/kercylan98/minotaur/utils/generic"
"math" "math"
"sort"
) )
const ( const (
@ -121,3 +122,19 @@ func UnMerge[V generic.SignedNumber](refer, num V) (a, b V) {
b = num / refer b = num / refer
return a, b return a, b
} }
// ToContinuous 将一组非连续的数字转换为从1开始的连续数字
// - 返回值是一个 mapkey 是从 1 开始的连续数字value 是原始数字
func ToContinuous[V generic.Integer](nums []V) map[V]V {
if len(nums) == 0 {
return nil
}
sort.Slice(nums, func(i, j int) bool {
return nums[i] < nums[j]
})
var result = make(map[V]V)
for i, num := range nums {
result[V(i+1)] = num
}
return result
}