You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
220 lines
5.1 KiB
220 lines
5.1 KiB
package game |
|
|
|
import ( |
|
"errors" |
|
"math" |
|
"strconv" |
|
) |
|
|
|
// Hand 5张牌的牌型 |
|
type Hand struct { |
|
cards [5]*Card // 组合牌型 |
|
point int // 组合牌型点数 |
|
CardType CardType // 组合牌型名称 |
|
} |
|
|
|
func (h *Hand) Init(cards [5]*Card) *Hand { |
|
SortCards(&cards) |
|
// 牌型排序降序 |
|
face := GetCardFace(cards) |
|
// 计算牌型 |
|
switch true { |
|
case isRoyalFlush(cards): |
|
h.CardType = RoyalFlush |
|
case isStraightFlush(cards): |
|
h.CardType = StraightFlush |
|
case isFourOfKind(face): |
|
h.CardType = FourOfKind |
|
case isFullHouse(face): |
|
h.CardType = FullHouse |
|
case isFlush(cards): |
|
h.CardType = Flush |
|
case isStraight(cards): |
|
h.CardType = Straight |
|
case isThreeOfKind(face): |
|
h.CardType = ThreeOfKind |
|
case isTwoPairs(face): |
|
h.CardType = TwoPairs |
|
case isOnePair(face): |
|
h.CardType = OnePair |
|
default: |
|
h.CardType = HighCard |
|
} |
|
h.cards = cards |
|
// 计算牌点数 |
|
h.point = int(h.CardType) + getHighCardPoint(cards) |
|
return h |
|
} |
|
|
|
func (h *Hand) GetPoint() int { |
|
return h.point |
|
} |
|
|
|
type CardType int |
|
|
|
func (ct CardType) String() string { |
|
f, _ := strconv.ParseFloat(strconv.Itoa(int(ct)>>13), 32) |
|
return cardTypeNames[int(math.Log2(f))] |
|
} |
|
|
|
func (ct CardType) Name() string { |
|
return ct.String() |
|
} |
|
|
|
func (ct CardType) NameZh() string { |
|
f, _ := strconv.ParseFloat(strconv.Itoa(int(ct)>>13), 32) |
|
return cardTypeZhNames[int(math.Log2(f))] |
|
} |
|
|
|
var cardTypeNames = []string{"HighCard", "OnePair", "TwoPairs", "ThreeOfKind", "Straight", "Flush", "FullHouse", "FourOfKind", "StraightFlush", "RoyalFlush"} |
|
var cardTypeZhNames = []string{"高牌", "对子", "两对", "三条", "顺子", "同花", "葫芦", "四条", "同花顺", "皇家同花顺"} |
|
|
|
const ( |
|
HighCard CardType = 1 << 13 << iota // 高牌 |
|
OnePair CardType = 1 << 13 << iota // 对子 |
|
TwoPairs CardType = 1 << 13 << iota // 两对 |
|
ThreeOfKind CardType = 1 << 13 << iota // 三张 |
|
Straight CardType = 1 << 13 << iota // 顺子 |
|
Flush CardType = 1 << 13 << iota // 同花 |
|
FullHouse CardType = 1 << 13 << iota // 葫芦 |
|
FourOfKind CardType = 1 << 13 << iota // 四条 |
|
StraightFlush CardType = 1 << 13 << iota // 同花顺 |
|
RoyalFlush CardType = 1 << 13 << iota // 皇家同花顺 |
|
) |
|
|
|
// AnalyzeMaxHand 分析牌型,选出5张最大牌 |
|
func AnalyzeMaxHand(handCards [2]*Card, publicCards [5]*Card) (*Hand, error) { |
|
// 计算牌的组合 |
|
var allCards = make([]*Card, 0, 7) |
|
for _, hc := range handCards { |
|
if hc != nil { |
|
allCards = append(allCards, hc) |
|
} |
|
} |
|
for _, pc := range publicCards { |
|
if pc != nil { |
|
allCards = append(allCards, pc) |
|
} |
|
} |
|
if len(allCards) < 5 { |
|
return nil, errors.New("all cards count less 5") |
|
} |
|
|
|
var cards [5]*Card // 选出的5张牌 |
|
|
|
// 只能组合一手牌 |
|
if len(allCards) == 5 { |
|
copy(cards[:], allCards) |
|
return new(Hand).Init(cards), nil |
|
} |
|
// 查找最大分数组合 |
|
// tempCards := allCards[:5] |
|
copy(cards[:], allCards[:5]) |
|
|
|
maxHand := new(Hand).Init(cards) |
|
for i := 0; i < len(cards); i++ { |
|
for j := 5; j < len(allCards); j++ { |
|
var tempCards = cards |
|
tempCards[i] = allCards[j] |
|
h := new(Hand).Init(tempCards) |
|
if h.point > maxHand.point { |
|
maxHand = h |
|
} |
|
} |
|
} |
|
return maxHand, nil |
|
} |
|
|
|
// SortCards 5张牌降序排序 |
|
func SortCards(cards *[5]*Card) { |
|
for i := 0; i < len(cards); i++ { |
|
for j := i + 1; j < len(cards); j++ { |
|
if cards[i].Compare(cards[j]) < 0 { |
|
cards[i], cards[j] = cards[j], cards[i] |
|
} |
|
} |
|
} |
|
} |
|
|
|
// GetCardFace 分析相同点数的牌个数 |
|
// return 0:单牌个数 1:对子个数 2:三条个数 3四条个数 |
|
func GetCardFace(cards [5]*Card) [4]int { |
|
var faceMap = make(map[PokerDot]int, 5) |
|
for _, c := range cards { |
|
faceMap[c.Dot]++ |
|
} |
|
// 0:单牌个数 1:对子个数 2:三条个数 3四条个数 |
|
var face = [4]int{} |
|
for dot := range faceMap { |
|
face[faceMap[dot]-1]++ |
|
} |
|
return face |
|
} |
|
|
|
// isRoyalFlush 皇家同花顺 |
|
func isRoyalFlush(cards [5]*Card) bool { |
|
return PokerA == cards[0].Dot && isStraight(cards) && isFlush(cards) |
|
} |
|
|
|
// isStraightFlush 同花顺 |
|
func isStraightFlush(cards [5]*Card) bool { |
|
return isStraight(cards) && isFlush(cards) |
|
} |
|
|
|
// isFourOfKind 四条 |
|
func isFourOfKind(face [4]int) bool { |
|
return face[3] > 0 |
|
} |
|
|
|
// isFullHouse 葫芦, 3条加2对 |
|
func isFullHouse(face [4]int) bool { |
|
return face[2] > 0 && face[1] > 0 |
|
} |
|
|
|
// isFlush 同花 |
|
func isFlush(cards [5]*Card) bool { |
|
firstSuit := cards[0].Suit // 首张牌花色 |
|
// 判断花色是否都相同 |
|
for i := 1; i < len(cards); i++ { |
|
if firstSuit != cards[i].Suit { |
|
return false |
|
} |
|
} |
|
return true |
|
} |
|
|
|
// isStraight 顺子 |
|
func isStraight(cards [5]*Card) bool { |
|
var value int64 |
|
// 000111110000000 |
|
for _, c := range cards { |
|
value |= 1 << int64(c.Dot) |
|
} |
|
// 是顺子 00011111 == 31 |
|
return value>>cards[len(cards)-1].Dot == 31 |
|
} |
|
|
|
// isThreeOfKind 三条 |
|
func isThreeOfKind(face [4]int) bool { |
|
return face[2] > 0 |
|
} |
|
|
|
// isTwoPairs 两对 |
|
func isTwoPairs(face [4]int) bool { |
|
return face[1] >= 2 |
|
} |
|
|
|
// isOnePair 对子 |
|
func isOnePair(face [4]int) bool { |
|
return face[1] > 0 |
|
} |
|
|
|
// getHighCardPoint 高牌,返回散牌点数 |
|
func getHighCardPoint(cards [5]*Card) int { |
|
totalPoint := 0 |
|
for i, c := range cards { |
|
// 牌权重降序 |
|
totalPoint += int(c.Dot) << (4 - i) |
|
} |
|
return totalPoint |
|
}
|
|
|