✨ 扑克牌堆实现
This commit is contained in:
parent
f414ffe28c
commit
52d707486a
|
@ -0,0 +1,12 @@
|
|||
package builtin
|
||||
|
||||
func NewPoker() {
|
||||
|
||||
}
|
||||
|
||||
type Poker struct {
|
||||
}
|
||||
|
||||
func (slf *Poker) Generate() {
|
||||
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package builtin
|
||||
|
||||
import "fmt"
|
||||
|
||||
// NewPokerCard 创建一张扑克牌
|
||||
// - 当 point 为 PokerPointBlackJoker 或 PokerPointRedJoker 时,color 将没有效果
|
||||
func NewPokerCard(point PokerPoint, color PokerColor) PokerCard {
|
||||
if point == PokerPointRedJoker || point == PokerPointBlackJoker {
|
||||
color = PokerColorNone
|
||||
}
|
||||
card := PokerCard{
|
||||
point: point,
|
||||
color: color,
|
||||
}
|
||||
return card
|
||||
}
|
||||
|
||||
// PokerCard 扑克牌
|
||||
type PokerCard struct {
|
||||
point PokerPoint
|
||||
color PokerColor
|
||||
}
|
||||
|
||||
// GetPoint 返回扑克牌的点数
|
||||
func (slf PokerCard) GetPoint() PokerPoint {
|
||||
return slf.point
|
||||
}
|
||||
|
||||
// GetColor 返回扑克牌的花色
|
||||
func (slf PokerCard) GetColor() PokerColor {
|
||||
return slf.color
|
||||
}
|
||||
|
||||
// GetPointAndColor 返回扑克牌的点数和花色
|
||||
func (slf PokerCard) GetPointAndColor() (PokerPoint, PokerColor) {
|
||||
return slf.point, slf.color
|
||||
}
|
||||
|
||||
// String 将扑克牌转换为字符串形式
|
||||
func (slf PokerCard) String() string {
|
||||
return fmt.Sprintf("(%s %s)", slf.point, slf.color)
|
||||
}
|
|
@ -0,0 +1,144 @@
|
|||
package builtin
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/kercylan98/minotaur/utils/hash"
|
||||
"github.com/kercylan98/minotaur/utils/random"
|
||||
"github.com/kercylan98/minotaur/utils/slice"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// NewPokerCardPile 返回一个新的牌堆,其中 size 表示了该牌堆由多少副牌组成
|
||||
// - 在不洗牌的情况下,默认牌堆顶部到底部为从大到小排列
|
||||
func NewPokerCardPile(size int, options ...PokerCardPileOption) *PokerCardPile {
|
||||
pile := &PokerCardPile{
|
||||
size: size,
|
||||
pile: make([]PokerCard, 0, size*54),
|
||||
}
|
||||
pile.shuffleHandle = func(cards []PokerCard) []PokerCard {
|
||||
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
|
||||
}
|
||||
|
||||
// PokerCardPile 扑克牌堆
|
||||
type PokerCardPile struct {
|
||||
pile []PokerCard
|
||||
size int
|
||||
shuffleHandle func(cards []PokerCard) []PokerCard
|
||||
excludeColor map[PokerColor]struct{}
|
||||
excludePoint map[PokerPoint]struct{}
|
||||
excludeCard map[PokerPoint]map[PokerColor]struct{}
|
||||
}
|
||||
|
||||
// Reset 重置牌堆的扑克牌数量及顺序
|
||||
func (slf *PokerCardPile) Reset() {
|
||||
var cards = make([]PokerCard, 0, 54)
|
||||
if !slf.IsExclude(PokerPointRedJoker, PokerColorNone) {
|
||||
cards = append(cards, NewPokerCard(PokerPointRedJoker, PokerColorNone))
|
||||
}
|
||||
if !slf.IsExclude(PokerPointBlackJoker, PokerColorNone) {
|
||||
cards = append(cards, NewPokerCard(PokerPointBlackJoker, PokerColorNone))
|
||||
}
|
||||
for point := PokerPointK; point >= PokerPointA; point-- {
|
||||
for color := PokerColorSpade; color <= PokerColorDiamond; color++ {
|
||||
if !slf.IsExclude(point, color) {
|
||||
cards = append(cards, NewPokerCard(point, color))
|
||||
}
|
||||
}
|
||||
}
|
||||
slf.pile = slf.pile[0:0]
|
||||
for i := 0; i < slf.size; i++ {
|
||||
slf.pile = append(slf.pile, cards...)
|
||||
}
|
||||
}
|
||||
|
||||
// IsExclude 检查特定点数和花色是否被排除在外
|
||||
func (slf *PokerCardPile) IsExclude(point PokerPoint, color PokerColor) bool {
|
||||
return hash.Exist(slf.excludePoint, point) || hash.Exist(slf.excludeColor, color) || hash.Exist(slf.excludeCard[point], color)
|
||||
}
|
||||
|
||||
// IsExcludeWithCard 检查特定扑克牌是否被排除在外
|
||||
func (slf *PokerCardPile) IsExcludeWithCard(card PokerCard) bool {
|
||||
point, color := card.GetPointAndColor()
|
||||
return hash.Exist(slf.excludePoint, point) || hash.Exist(slf.excludeColor, color) || hash.Exist(slf.excludeCard[point], color)
|
||||
}
|
||||
|
||||
// Shuffle 洗牌
|
||||
func (slf *PokerCardPile) 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 *PokerCardPile) Cards() []PokerCard {
|
||||
return slf.pile
|
||||
}
|
||||
|
||||
// IsFree 返回牌堆是否没有扑克牌了
|
||||
func (slf *PokerCardPile) IsFree() bool {
|
||||
return len(slf.pile) == 0
|
||||
}
|
||||
|
||||
// Count 获取牌堆剩余牌量
|
||||
func (slf *PokerCardPile) Count() int {
|
||||
return len(slf.pile)
|
||||
}
|
||||
|
||||
// Pull 从牌堆特定位置抽出一张牌
|
||||
func (slf *PokerCardPile) Pull(index int) PokerCard {
|
||||
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 *PokerCardPile) PullTop() PokerCard {
|
||||
if slf.IsFree() {
|
||||
panic("empty poker cards pile")
|
||||
}
|
||||
pc := slf.pile[0]
|
||||
slice.Del(&slf.pile, 0)
|
||||
return pc
|
||||
}
|
||||
|
||||
// PullBottom 从牌堆底部抽出一张牌
|
||||
func (slf *PokerCardPile) PullBottom() PokerCard {
|
||||
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 *PokerCardPile) Push(index int, card PokerCard) {
|
||||
slice.Insert(&slf.pile, index, card)
|
||||
return
|
||||
}
|
||||
|
||||
// PushTop 将扑克牌插入到牌堆顶部
|
||||
func (slf *PokerCardPile) PushTop(card PokerCard) {
|
||||
slf.pile = append([]PokerCard{card}, slf.pile...)
|
||||
}
|
||||
|
||||
// PushBottom 将扑克牌插入到牌堆底部
|
||||
func (slf *PokerCardPile) PushBottom(card PokerCard) {
|
||||
slf.pile = append(slf.pile, card)
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package builtin
|
||||
|
||||
type PokerCardPileOption func(pile *PokerCardPile)
|
||||
|
||||
// WithPokerCardPileShuffle 通过特定的洗牌算法创建牌堆
|
||||
// - 需要保证洗牌后的牌堆剩余扑克数量与之前相同,否则将会引发 panic
|
||||
func WithPokerCardPileShuffle(shuffleHandle func(pile []PokerCard) []PokerCard) PokerCardPileOption {
|
||||
return func(pile *PokerCardPile) {
|
||||
if shuffleHandle == nil {
|
||||
return
|
||||
}
|
||||
pile.shuffleHandle = shuffleHandle
|
||||
}
|
||||
}
|
||||
|
||||
// WithPokerCardPileExcludeColor 通过排除特定花色的方式创建牌堆
|
||||
func WithPokerCardPileExcludeColor(colors ...PokerColor) PokerCardPileOption {
|
||||
return func(pile *PokerCardPile) {
|
||||
if pile.excludeColor == nil {
|
||||
pile.excludeColor = map[PokerColor]struct{}{}
|
||||
}
|
||||
for _, color := range colors {
|
||||
pile.excludeColor[color] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithPokerCardPileExcludePoint 通过排除特定点数的方式创建牌堆
|
||||
func WithPokerCardPileExcludePoint(points ...PokerPoint) PokerCardPileOption {
|
||||
return func(pile *PokerCardPile) {
|
||||
if pile.excludePoint == nil {
|
||||
pile.excludePoint = map[PokerPoint]struct{}{}
|
||||
}
|
||||
for _, point := range points {
|
||||
pile.excludePoint[point] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithPokerCardPileExcludeCard 通过排除特定扑克牌的方式创建牌堆
|
||||
func WithPokerCardPileExcludeCard(cards ...PokerCard) PokerCardPileOption {
|
||||
return func(pile *PokerCardPile) {
|
||||
if pile.excludeCard == nil {
|
||||
pile.excludeCard = map[PokerPoint]map[PokerColor]struct{}{}
|
||||
}
|
||||
for _, card := range cards {
|
||||
cs, exist := pile.excludeCard[card.GetPoint()]
|
||||
if !exist {
|
||||
cs = map[PokerColor]struct{}{}
|
||||
}
|
||||
cs[card.GetColor()] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package builtin
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNewPokerCardPile(t *testing.T) {
|
||||
pile := NewPokerCardPile(2)
|
||||
_ = pile.PullTop()
|
||||
pile.Reset()
|
||||
fmt.Println(pile)
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package builtin
|
||||
|
||||
const (
|
||||
PokerColorNone PokerColor = 0 // 无花色,通常为大小王
|
||||
PokerColorSpade PokerColor = 1 // 黑桃
|
||||
PokerColorHeart PokerColor = 2 // 红桃
|
||||
PokerColorClub PokerColor = 3 // 梅花
|
||||
PokerColorDiamond PokerColor = 4 // 方片
|
||||
)
|
||||
|
||||
// PokerColor 扑克牌花色
|
||||
type PokerColor int
|
||||
|
||||
// InBounds 扑克牌花色是否在界限内
|
||||
// - 将检查花色是否在黑桃、红桃、梅花、方片之间
|
||||
func (slf PokerColor) InBounds() bool {
|
||||
return slf <= PokerColorSpade && slf >= PokerColorDiamond
|
||||
}
|
||||
|
||||
func (slf PokerColor) String() string {
|
||||
var str string
|
||||
switch slf {
|
||||
case PokerColorSpade:
|
||||
str = "Spade"
|
||||
case PokerColorHeart:
|
||||
str = "Heart"
|
||||
case PokerColorClub:
|
||||
str = "Club"
|
||||
case PokerColorDiamond:
|
||||
str = "Diamond"
|
||||
default:
|
||||
str = "None"
|
||||
}
|
||||
return str
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package builtin
|
||||
|
||||
import "strconv"
|
||||
|
||||
const (
|
||||
PokerPointA PokerPoint = 1
|
||||
PokerPoint2 PokerPoint = 2
|
||||
PokerPoint3 PokerPoint = 3
|
||||
PokerPoint4 PokerPoint = 4
|
||||
PokerPoint5 PokerPoint = 5
|
||||
PokerPoint6 PokerPoint = 6
|
||||
PokerPoint7 PokerPoint = 7
|
||||
PokerPoint8 PokerPoint = 8
|
||||
PokerPoint9 PokerPoint = 9
|
||||
PokerPoint10 PokerPoint = 10
|
||||
PokerPointJ PokerPoint = 11
|
||||
PokerPointQ PokerPoint = 12
|
||||
PokerPointK PokerPoint = 13
|
||||
PokerPointBlackJoker PokerPoint = 14
|
||||
PokerPointRedJoker PokerPoint = 15
|
||||
)
|
||||
|
||||
// PokerPoint 扑克点数
|
||||
type PokerPoint int
|
||||
|
||||
func (slf PokerPoint) String() string {
|
||||
var str string
|
||||
switch slf {
|
||||
case PokerPointA:
|
||||
str = "A"
|
||||
case PokerPointJ:
|
||||
str = "J"
|
||||
case PokerPointQ:
|
||||
str = "Q"
|
||||
case PokerPointK:
|
||||
str = "K"
|
||||
case PokerPointBlackJoker:
|
||||
str = "B"
|
||||
case PokerPointRedJoker:
|
||||
str = "R"
|
||||
default:
|
||||
str = strconv.Itoa(int(slf))
|
||||
}
|
||||
return str
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
package game
|
||||
|
||||
// Poker 扑克牌游戏通用玩法接口定义
|
||||
type Poker interface {
|
||||
}
|
|
@ -137,7 +137,6 @@ func PointToPos[V generic.SignedNumber](width V, xy Point[V]) V {
|
|||
|
||||
// PosToCoordinate 通过宽度将一个二维数组的顺序位置转换为xy坐标
|
||||
func PosToCoordinate[V generic.SignedNumber](width, pos V) (x, y V) {
|
||||
|
||||
x = V(math.Mod(float64(pos), float64(width)))
|
||||
y = pos / width
|
||||
return x, y
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
package hash
|
||||
|
||||
// Exist 检查特定 key 是否存在
|
||||
func Exist[K comparable, V any](m map[K]V, key K) bool {
|
||||
_, exist := m[key]
|
||||
return exist
|
||||
}
|
||||
|
||||
// AllExist 检查多个 key 是否存在
|
||||
func AllExist[K comparable, V any](m map[K]V, keys ...K) bool {
|
||||
for key := range m {
|
||||
if _, exist := m[key]; !exist {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
|
@ -109,3 +109,15 @@ func Clamp[V generic.Number](value, min, max V) V {
|
|||
func Tolerance[V generic.Number](value1, value2, tolerance V) bool {
|
||||
return V(math.Abs(float64(value1-value2))) <= tolerance
|
||||
}
|
||||
|
||||
// Merge 通过一个参考值合并两个数字
|
||||
func Merge[V generic.SignedNumber](refer, a, b V) V {
|
||||
return b*refer + a
|
||||
}
|
||||
|
||||
// UnMerge 通过一个参考值取消合并的两个数字
|
||||
func UnMerge[V generic.SignedNumber](refer, num V) (a, b V) {
|
||||
a = V(math.Mod(float64(num), float64(refer)))
|
||||
b = num / refer
|
||||
return a, b
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue