pokercore/scoring.go

146 lines
3.5 KiB
Go

package pokercore
import (
"fmt"
)
type HandScore int
const (
ScoreHighCard = HandScore(iota * 100_000_000_000)
ScorePair
ScoreTwoPair
ScoreThreeOfAKind
ScoreStraight
ScoreFlush
ScoreFullHouse
ScoreFourOfAKind
ScoreStraightFlush
ScoreRoyalFlush
)
func (c Card) Score() HandScore {
return HandScore(c.Rank.Score())
}
func (c Cards) PokerHandScore() (HandScore, error) {
ph, err := c.PokerHand()
if err != nil {
return 0, err
}
return ph.Score, nil
}
func (x HandScore) String() string {
return fmt.Sprintf("<HandScore %d>", x)
}
func (ph *PokerHand) calculateScore() {
// sanity check, we should only be called in the PokerHand() method from
// a Cards, but just in case
if len(ph.Hand) != 5 {
// normally we don't panic in a library but this is a "should never
// happen"
panic("PokerHand.calculateScore() called on a PokerHand with != 5 cards")
}
if ph.Hand.containsRoyalFlush() {
ph.Type = RoyalFlush
ph.Score = ScoreRoyalFlush
return
}
if ph.Hand.containsStraightFlush() {
ph.Type = StraightFlush
ph.Score = ScoreStraightFlush
ph.Score += ph.Hand.HighestRank().Score()
return
}
if ph.Hand.containsFourOfAKind() {
ph.Type = FourOfAKind
ph.Score = ScoreFourOfAKind
ph.Score += 10000 * ph.Hand.fourOfAKindRank().Score()
ph.Score += 100 * ph.Hand.fourOfAKindKicker().Score()
return
}
if ph.Hand.containsFullHouse() {
ph.Type = FullHouse
ph.Score = ScoreFullHouse
ph.Score += 10000 * ph.Hand.fullHouseTripsRank().Score()
ph.Score += 100 * ph.Hand.fullHousePairRank().Score()
return
}
if ph.Hand.containsFlush() {
ph.Type = Flush
ph.Score = ScoreFlush
// flush base score plus sum of card ranks
ph.Score += ph.Hand[0].Score()
ph.Score += ph.Hand[1].Score()
ph.Score += ph.Hand[2].Score()
ph.Score += ph.Hand[3].Score()
ph.Score += ph.Hand[4].Score()
return
}
if ph.Hand.containsStraight() {
ph.Type = Straight
ph.Score = ScoreStraight
// note that ph.Hand is already sorted by rank ascending with ace
// high
// Straights are scored by the highest card in the straight
// UNLESS the second highest card is a 5 and the highest card is an Ace
// In that case, the straight is a 5-high straight, not an Ace-high straight
if ph.Hand[3].Rank == FIVE && ph.Hand[4].Rank == ACE {
// 5-high straight, scored by the five's rank
ph.Score += ph.Hand[3].Score()
} else {
// All other straights are scored by the highest card in the straight
ph.Score += ph.Hand[4].Score()
}
return
}
if ph.Hand.containsThreeOfAKind() {
ph.Type = ThreeOfAKind
ph.Score = ScoreThreeOfAKind
ph.Score += 10000 * ph.Hand.threeOfAKindTripsRank().Score()
ph.Score += 100 * ph.Hand.threeOfAKindFirstKicker().Score()
ph.Score += ph.Hand.threeOfAKindSecondKicker().Score()
return
}
if ph.Hand.containsTwoPair() {
ph.Type = TwoPair
ph.Score = ScoreTwoPair
ph.Score += 10000 * ph.Hand.twoPairBiggestPair().Score()
ph.Score += 100 * ph.Hand.twoPairSmallestPair().Score()
ph.Score += ph.Hand.twoPairKicker().Score()
return
}
if ph.Hand.containsPair() {
ph.Type = Pair
ph.Score = ScorePair
ph.Score += 10000 * ph.Hand.pairRank().Score()
ph.Score += 100 * ph.Hand.pairFirstKicker().Score()
ph.Score += ph.Hand.pairSecondKicker().Score()
ph.Score += ph.Hand.pairThirdKicker().Score()
return
}
ph.Type = HighCard
ph.Score = ScoreHighCard // base score
// unmade hands are scored like flushes, just add up the values
ph.Score += ph.Hand[0].Score()
ph.Score += ph.Hand[1].Score()
ph.Score += ph.Hand[2].Score()
ph.Score += ph.Hand[3].Score()
ph.Score += ph.Hand[4].Score()
}