refactor: 重构 poker 包设计,移除 Poker 结构体,以 Rule 结构体进行取代
- 移除了 poker.Poker 的设计,采用了 poker.Rule 管理规则。 - 将牌堆和规则进行分离,可单独使用。 - 增加大量辅助函数及内置牌型检测函数。
This commit is contained in:
parent
0ab38c7023
commit
d1b7699cb4
|
@ -1,6 +1,9 @@
|
|||
package poker
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
)
|
||||
|
||||
// NewCard 创建一张扑克牌
|
||||
// - 当 point 为 PointBlackJoker 或 PointRedJoker 时,color 将没有效果
|
||||
|
@ -54,6 +57,102 @@ func (slf Card) Equal(card Card) bool {
|
|||
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 将扑克牌转换为字符串形式
|
||||
func (slf Card) String() string {
|
||||
return fmt.Sprintf("(%s %s)", slf.point, slf.color)
|
||||
|
|
|
@ -48,7 +48,7 @@ func (slf *CardPile) Reset() {
|
|||
cards = append(cards, NewCard(PointBlackJoker, ColorNone))
|
||||
}
|
||||
for point := PointK; point >= PointA; point-- {
|
||||
for color := ColorSpade; color <= ColorDiamond; color++ {
|
||||
for color := ColorDiamond; color <= ColorSpade; color++ {
|
||||
if !slf.IsExclude(point, color) {
|
||||
cards = append(cards, NewCard(point, color))
|
||||
}
|
||||
|
|
|
@ -2,12 +2,20 @@ package poker
|
|||
|
||||
const (
|
||||
ColorNone Color = 0 // 无花色,通常为大小王
|
||||
ColorSpade Color = 1 // 黑桃
|
||||
ColorHeart Color = 2 // 红桃
|
||||
ColorClub Color = 3 // 梅花
|
||||
ColorDiamond Color = 4 // 方片
|
||||
ColorSpade Color = 4 // 黑桃
|
||||
ColorHeart Color = 3 // 红桃
|
||||
ColorClub Color = 2 // 梅花
|
||||
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 扑克牌花色
|
||||
type Color int
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -1,36 +1,412 @@
|
|||
package poker
|
||||
|
||||
const (
|
||||
HandNone = "None" // 无牌型
|
||||
)
|
||||
|
||||
// HandHandle 扑克牌型验证函数
|
||||
type HandHandle func(poker *Poker, 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)
|
||||
}
|
||||
}
|
||||
type HandHandle func(rule *Rule, cards []Card) bool
|
||||
|
||||
// HandSingle 单牌
|
||||
func HandSingle() HandHandle {
|
||||
return func(poker *Poker, cards []Card) bool {
|
||||
return func(rule *Rule, cards []Card) bool {
|
||||
return len(cards) == 1
|
||||
}
|
||||
}
|
||||
|
||||
// HandPairs 对子
|
||||
func HandPairs() HandHandle {
|
||||
return func(rule *Rule, cards []Card) bool {
|
||||
return len(cards) == 2 && rule.IsPointContinuity(2, cards...)
|
||||
}
|
||||
}
|
||||
|
||||
// HandThreeOfKind 三张
|
||||
func HandThreeOfKind() HandHandle {
|
||||
return func(poker *Poker, cards []Card) bool {
|
||||
return len(cards) == 3 && cards[0].EqualPoint(cards[1]) && cards[1].EqualPoint(cards[2])
|
||||
return func(rule *Rule, cards []Card) bool {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,38 +2,94 @@ package poker
|
|||
|
||||
import "fmt"
|
||||
|
||||
type Option func(poker *Poker)
|
||||
type Option func(rule *Rule)
|
||||
|
||||
// WithHand 通过绑定特定牌型的方式创建扑克玩法
|
||||
func WithHand(pokerHand string, handle HandHandle) Option {
|
||||
return func(poker *Poker) {
|
||||
if _, exist := poker.pokerHand[pokerHand]; exist {
|
||||
// - 牌型顺序决定了牌型的优先级
|
||||
func WithHand(pokerHand string, value int, handle HandHandle) Option {
|
||||
return func(rule *Rule) {
|
||||
if _, exist := rule.pokerHand[pokerHand]; exist {
|
||||
panic(fmt.Errorf("same poker hand name: %s", pokerHand))
|
||||
}
|
||||
poker.pokerHand[pokerHand] = handle
|
||||
poker.pokerHandPriority = append(poker.pokerHandPriority, 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(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 通过特定的扑克点数牌值创建扑克玩法
|
||||
func WithPointValue(pointValues map[Point]int) Option {
|
||||
return func(poker *Poker) {
|
||||
poker.pointValue = pointValues
|
||||
return func(rule *Rule) {
|
||||
rule.pointValue = pointValues
|
||||
}
|
||||
}
|
||||
|
||||
// WithColorValue 通过特定的扑克花色牌值创建扑克玩法
|
||||
func WithColorValue(colorValues map[Color]int) Option {
|
||||
return func(poker *Poker) {
|
||||
poker.colorValue = colorValues
|
||||
return func(rule *Rule) {
|
||||
rule.colorValue = colorValues
|
||||
}
|
||||
}
|
||||
|
||||
// WithPointSort 通过特定的扑克点数顺序创建扑克玩法
|
||||
// WithPointSort 通过特定的扑克点数顺序创建扑克玩法,顺序必须为连续的
|
||||
func WithPointSort(pointSort map[Point]int) Option {
|
||||
return func(poker *Poker) {
|
||||
return func(rule *Rule) {
|
||||
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{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,90 +1,70 @@
|
|||
package poker
|
||||
|
||||
import (
|
||||
"github.com/kercylan98/minotaur/utils/hash"
|
||||
"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
|
||||
// IsContainJoker 检查扑克牌是否包含大小王
|
||||
func IsContainJoker(cards ...Card) bool {
|
||||
for _, card := range cards {
|
||||
value += slf.pointValue[card.GetPoint()]
|
||||
value += slf.colorValue[card.GetColor()]
|
||||
if card.IsJoker() {
|
||||
return true
|
||||
}
|
||||
return value
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Compare 根据特定的条件表达式比较两组扑克牌的牌值
|
||||
func (slf *Poker) Compare(cards1 []Card, expression maths.CompareExpression, cards2 []Card) bool {
|
||||
return maths.Compare(slf.CardValue(cards1...), expression, slf.CardValue(cards2...))
|
||||
// GroupByPoint 将扑克牌按照点数分组
|
||||
func GroupByPoint(cards ...Card) map[Point][]Card {
|
||||
group := map[Point][]Card{}
|
||||
for _, card := range cards {
|
||||
group[card.GetPoint()] = append(group[card.GetPoint()], card)
|
||||
}
|
||||
return group
|
||||
}
|
||||
|
||||
// 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
|
||||
// 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 "", false
|
||||
return group
|
||||
}
|
||||
|
||||
// GetPile 获取牌堆
|
||||
func (slf *Poker) GetPile() *CardPile {
|
||||
return slf.pile
|
||||
// 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
|
||||
}
|
||||
|
|
|
@ -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...))
|
||||
}
|
|
@ -3,6 +3,7 @@ package maths
|
|||
import (
|
||||
"github.com/kercylan98/minotaur/utils/generic"
|
||||
"math"
|
||||
"sort"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -121,3 +122,19 @@ func UnMerge[V generic.SignedNumber](refer, num V) (a, b V) {
|
|||
b = num / refer
|
||||
return a, b
|
||||
}
|
||||
|
||||
// ToContinuous 将一组非连续的数字转换为从1开始的连续数字
|
||||
// - 返回值是一个 map,key 是从 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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue