146 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			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()
 | 
						|
}
 |