builds now, doesn't pass tests yet
This commit is contained in:
parent
3dc63db70c
commit
90a959448a
42
pokercore/findhand.go
Normal file
42
pokercore/findhand.go
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
package pokercore
|
||||||
|
|
||||||
|
import "errors"
|
||||||
|
|
||||||
|
var ErrDuplicateCard = errors.New("cannot score a poker hand out of a set of cards with duplicates")
|
||||||
|
|
||||||
|
// this method makes a n new hands where n is the number of cards in the hand
|
||||||
|
// each of the new hands has one card removed from the original hand
|
||||||
|
// then it calls the identifyBestFiveCardPokerHand method on each of the new hands
|
||||||
|
// and returns the best hand by score. this is recursion.
|
||||||
|
func (hand Cards) identifyBestFiveCardPokerHand() (Cards, error) {
|
||||||
|
if hand.containsDuplicates() {
|
||||||
|
return nil, ErrDuplicateCard
|
||||||
|
}
|
||||||
|
|
||||||
|
newHands := make([]Cards, len(hand))
|
||||||
|
for i := 0; i < len(hand); i++ {
|
||||||
|
newHand := hand[:i]
|
||||||
|
newHand = append(newHand, hand[i+1:]...)
|
||||||
|
newHands[i] = newHand
|
||||||
|
}
|
||||||
|
var bestHand Cards
|
||||||
|
var bestScore HandScore
|
||||||
|
|
||||||
|
for _, h := range newHands {
|
||||||
|
if len(h) == 5 {
|
||||||
|
score, _ := h.PokerHandScore()
|
||||||
|
if score > bestScore {
|
||||||
|
bestScore = score
|
||||||
|
bestHand = h
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rh, _ := h.identifyBestFiveCardPokerHand()
|
||||||
|
score, _ := rh.PokerHandScore()
|
||||||
|
if score > bestScore {
|
||||||
|
bestScore = score
|
||||||
|
bestHand = rh
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bestHand, nil
|
||||||
|
}
|
436
pokercore/handhelpers.go
Normal file
436
pokercore/handhelpers.go
Normal file
@ -0,0 +1,436 @@
|
|||||||
|
package pokercore
|
||||||
|
|
||||||
|
func (c Cards) scoreStraightFlush() HandScore {
|
||||||
|
if !c.containsStraightFlush() {
|
||||||
|
panic("hand must be a straight flush to score it")
|
||||||
|
}
|
||||||
|
return ScoreStraightFlush + 1000*c.HighestRank().Score()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Cards) scoreFlush() HandScore {
|
||||||
|
if !c.containsFlush() {
|
||||||
|
panic("hand must be a flush to score it")
|
||||||
|
}
|
||||||
|
var score HandScore
|
||||||
|
for _, card := range c {
|
||||||
|
score += card.Rank.Score()
|
||||||
|
}
|
||||||
|
return ScoreFlush + score
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Cards) scoreHighCard() HandScore {
|
||||||
|
if !c.isUnmadeHand() {
|
||||||
|
panic("hand must be a high card to score it")
|
||||||
|
}
|
||||||
|
var score HandScore
|
||||||
|
for _, card := range c {
|
||||||
|
score += card.Rank.Score()
|
||||||
|
}
|
||||||
|
return ScoreHighCard + score
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Cards) pairRank() Rank {
|
||||||
|
if !c.containsPair() {
|
||||||
|
panic("hand must have a pair to have a pair rank")
|
||||||
|
}
|
||||||
|
sorted := c.SortByRank()
|
||||||
|
if sorted[0].Rank == sorted[1].Rank {
|
||||||
|
return sorted[0].Rank
|
||||||
|
}
|
||||||
|
if sorted[1].Rank == sorted[2].Rank {
|
||||||
|
return sorted[1].Rank
|
||||||
|
}
|
||||||
|
if sorted[2].Rank == sorted[3].Rank {
|
||||||
|
return sorted[2].Rank
|
||||||
|
}
|
||||||
|
if sorted[3].Rank == sorted[4].Rank {
|
||||||
|
return sorted[3].Rank
|
||||||
|
}
|
||||||
|
panic("nope")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Cards) pairFirstKicker() Card {
|
||||||
|
if !c.containsPair() {
|
||||||
|
panic("hand must have a pair to have a first kicker")
|
||||||
|
}
|
||||||
|
sorted := c.SortByRank()
|
||||||
|
if sorted[0].Rank == sorted[1].Rank {
|
||||||
|
return sorted[4]
|
||||||
|
}
|
||||||
|
if sorted[1].Rank == sorted[2].Rank {
|
||||||
|
return sorted[4]
|
||||||
|
}
|
||||||
|
if sorted[2].Rank == sorted[3].Rank {
|
||||||
|
return sorted[4]
|
||||||
|
}
|
||||||
|
if sorted[3].Rank == sorted[4].Rank {
|
||||||
|
return sorted[2]
|
||||||
|
}
|
||||||
|
panic("nope")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Cards) pairSecondKicker() Card {
|
||||||
|
if !c.containsPair() {
|
||||||
|
panic("hand must have a pair to have a second kicker")
|
||||||
|
}
|
||||||
|
sorted := c.SortByRank()
|
||||||
|
if sorted[0].Rank == sorted[1].Rank {
|
||||||
|
// first kicker is [4]
|
||||||
|
return sorted[3]
|
||||||
|
}
|
||||||
|
if sorted[1].Rank == sorted[2].Rank {
|
||||||
|
// first kicker is [4]
|
||||||
|
return sorted[3]
|
||||||
|
}
|
||||||
|
if sorted[2].Rank == sorted[3].Rank {
|
||||||
|
// first kicker is [4]
|
||||||
|
return sorted[1]
|
||||||
|
}
|
||||||
|
if sorted[3].Rank == sorted[4].Rank {
|
||||||
|
// first kicker is [2]
|
||||||
|
return sorted[1]
|
||||||
|
}
|
||||||
|
panic("nope")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Cards) pairThirdKicker() Card {
|
||||||
|
if !c.containsPair() {
|
||||||
|
panic("hand must have a pair to have a third kicker")
|
||||||
|
}
|
||||||
|
sorted := c.SortByRank()
|
||||||
|
if sorted[0].Rank == sorted[1].Rank {
|
||||||
|
// first kicker is [4]
|
||||||
|
// second kicker is [3]
|
||||||
|
return sorted[2]
|
||||||
|
}
|
||||||
|
if sorted[1].Rank == sorted[2].Rank {
|
||||||
|
// first kicker is [4]
|
||||||
|
// second kicker is [3]
|
||||||
|
return sorted[0]
|
||||||
|
}
|
||||||
|
if sorted[2].Rank == sorted[3].Rank {
|
||||||
|
// first kicker is [4]
|
||||||
|
// second kicker is [1]
|
||||||
|
return sorted[0]
|
||||||
|
}
|
||||||
|
if sorted[3].Rank == sorted[4].Rank {
|
||||||
|
// first kicker is [2]
|
||||||
|
// second kicker is [1]
|
||||||
|
return sorted[0]
|
||||||
|
}
|
||||||
|
panic("nope")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Cards) twoPairBiggestPair() Rank {
|
||||||
|
if !c.containsTwoPair() {
|
||||||
|
panic("hand must have two pair to have a biggest pair")
|
||||||
|
}
|
||||||
|
sorted := c.SortByRank()
|
||||||
|
if sorted[0].Rank == sorted[1].Rank && sorted[2].Rank == sorted[3].Rank {
|
||||||
|
return sorted[2].Rank
|
||||||
|
}
|
||||||
|
|
||||||
|
if sorted[0].Rank == sorted[1].Rank && sorted[3].Rank == sorted[4].Rank {
|
||||||
|
return sorted[0].Rank
|
||||||
|
}
|
||||||
|
if sorted[1].Rank == sorted[2].Rank && sorted[3].Rank == sorted[4].Rank {
|
||||||
|
return sorted[1].Rank
|
||||||
|
}
|
||||||
|
panic("nope")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Cards) twoPairSmallestPair() Rank {
|
||||||
|
if !c.containsTwoPair() {
|
||||||
|
panic("hand must have two pair to have a smallest pair")
|
||||||
|
}
|
||||||
|
sorted := c.SortByRank()
|
||||||
|
if sorted[0].Rank == sorted[1].Rank && sorted[2].Rank == sorted[3].Rank {
|
||||||
|
return sorted[2].Rank
|
||||||
|
}
|
||||||
|
if sorted[0].Rank == sorted[1].Rank && sorted[3].Rank == sorted[4].Rank {
|
||||||
|
return sorted[3].Rank
|
||||||
|
}
|
||||||
|
if sorted[1].Rank == sorted[2].Rank && sorted[3].Rank == sorted[4].Rank {
|
||||||
|
return sorted[3].Rank
|
||||||
|
}
|
||||||
|
panic("nope")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Cards) twoPairKicker() Card {
|
||||||
|
if !c.containsTwoPair() {
|
||||||
|
panic("hand must have two pair to have a twoPairKicker")
|
||||||
|
}
|
||||||
|
sorted := c.SortByRank()
|
||||||
|
if sorted[0].Rank == sorted[1].Rank && sorted[2].Rank == sorted[3].Rank {
|
||||||
|
return sorted[4]
|
||||||
|
}
|
||||||
|
if sorted[0].Rank == sorted[1].Rank && sorted[3].Rank == sorted[4].Rank {
|
||||||
|
return sorted[2]
|
||||||
|
}
|
||||||
|
if sorted[1].Rank == sorted[2].Rank && sorted[3].Rank == sorted[4].Rank {
|
||||||
|
return sorted[0]
|
||||||
|
}
|
||||||
|
panic("nope")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Cards) threeOfAKindTripsRank() Rank {
|
||||||
|
if !c.containsThreeOfAKind() {
|
||||||
|
panic("hand must have three of a kind to have a trips rank")
|
||||||
|
}
|
||||||
|
sorted := c.SortByRank()
|
||||||
|
if sorted[0].Rank == sorted[1].Rank && sorted[1].Rank == sorted[2].Rank {
|
||||||
|
return sorted[0].Rank
|
||||||
|
}
|
||||||
|
if sorted[1].Rank == sorted[2].Rank && sorted[2].Rank == sorted[3].Rank {
|
||||||
|
return sorted[1].Rank
|
||||||
|
}
|
||||||
|
if sorted[2].Rank == sorted[3].Rank && sorted[3].Rank == sorted[4].Rank {
|
||||||
|
return sorted[2].Rank
|
||||||
|
}
|
||||||
|
panic("nope")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Cards) threeOfAKindKickers() Cards {
|
||||||
|
if !c.containsThreeOfAKind() {
|
||||||
|
panic("hand must have three of a kind to have kickers")
|
||||||
|
}
|
||||||
|
sorted := c.SortByRank()
|
||||||
|
if sorted[0].Rank == sorted[1].Rank && sorted[1].Rank == sorted[2].Rank {
|
||||||
|
return Cards{sorted[3], sorted[4]}
|
||||||
|
}
|
||||||
|
if sorted[1].Rank == sorted[2].Rank && sorted[2].Rank == sorted[3].Rank {
|
||||||
|
return Cards{sorted[0], sorted[4]}
|
||||||
|
}
|
||||||
|
if sorted[2].Rank == sorted[3].Rank && sorted[3].Rank == sorted[4].Rank {
|
||||||
|
return Cards{sorted[0], sorted[1]}
|
||||||
|
}
|
||||||
|
panic("nope")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Cards) threeOfAKindFirstKicker() Card {
|
||||||
|
x := c.threeOfAKindKickers()
|
||||||
|
return x[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Cards) threeOfAKindSecondKicker() Card {
|
||||||
|
x := c.threeOfAKindKickers()
|
||||||
|
return x[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Cards) fourOfAKindRank() Rank {
|
||||||
|
if !c.containsFourOfAKind() {
|
||||||
|
panic("hand must have four of a kind to have a four of a kind rank")
|
||||||
|
}
|
||||||
|
sorted := c.SortByRank()
|
||||||
|
if sorted[0].Rank == sorted[1].Rank && sorted[1].Rank == sorted[2].Rank && sorted[2].Rank == sorted[3].Rank {
|
||||||
|
return sorted[0].Rank
|
||||||
|
}
|
||||||
|
if sorted[1].Rank == sorted[2].Rank && sorted[2].Rank == sorted[3].Rank && sorted[3].Rank == sorted[4].Rank {
|
||||||
|
return sorted[1].Rank
|
||||||
|
}
|
||||||
|
panic("nope")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Cards) fourOfAKindKicker() Card {
|
||||||
|
if !c.containsFourOfAKind() {
|
||||||
|
panic("hand must have four of a kind to have a four of a kind kicker")
|
||||||
|
}
|
||||||
|
sorted := c.SortByRank()
|
||||||
|
if sorted[0].Rank == sorted[1].Rank && sorted[1].Rank == sorted[2].Rank && sorted[2].Rank == sorted[3].Rank {
|
||||||
|
return sorted[4]
|
||||||
|
}
|
||||||
|
if sorted[1].Rank == sorted[2].Rank && sorted[2].Rank == sorted[3].Rank && sorted[3].Rank == sorted[4].Rank {
|
||||||
|
return sorted[0]
|
||||||
|
}
|
||||||
|
panic("nope")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Cards) fullHouseTripsRank() Rank {
|
||||||
|
if !c.containsFullHouse() {
|
||||||
|
panic("hand must have a full house to have a trips rank")
|
||||||
|
}
|
||||||
|
sorted := c.SortByRank()
|
||||||
|
if sorted[0].Rank == sorted[1].Rank && sorted[1].Rank == sorted[2].Rank && sorted[3].Rank == sorted[4].Rank {
|
||||||
|
return sorted[0].Rank
|
||||||
|
}
|
||||||
|
if sorted[0].Rank == sorted[1].Rank && sorted[2].Rank == sorted[3].Rank && sorted[3].Rank == sorted[4].Rank {
|
||||||
|
return sorted[4].Rank
|
||||||
|
}
|
||||||
|
panic("nope")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Cards) fullHousePairRank() Rank {
|
||||||
|
if !c.containsFullHouse() {
|
||||||
|
panic("hand must have a full house to have a pair rank")
|
||||||
|
}
|
||||||
|
sorted := c.SortByRank()
|
||||||
|
if sorted[0].Rank == sorted[1].Rank && sorted[1].Rank == sorted[2].Rank && sorted[3].Rank == sorted[4].Rank {
|
||||||
|
return sorted[4].Rank
|
||||||
|
}
|
||||||
|
if sorted[0].Rank == sorted[1].Rank && sorted[2].Rank == sorted[3].Rank && sorted[3].Rank == sorted[4].Rank {
|
||||||
|
return sorted[0].Rank
|
||||||
|
}
|
||||||
|
panic("nope")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hand Cards) containsDuplicates() bool {
|
||||||
|
seen := make(map[Card]bool)
|
||||||
|
for _, card := range hand {
|
||||||
|
if _, ok := seen[card]; ok {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
seen[card] = true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hand Cards) IsFiveCardPokerHand() bool {
|
||||||
|
return len(hand) == 5 && !hand.containsDuplicates()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hand Cards) containsFlush() bool {
|
||||||
|
if !hand.IsFiveCardPokerHand() {
|
||||||
|
panic("hand must have 5 cards to be scored")
|
||||||
|
}
|
||||||
|
suit := hand[0].Suit
|
||||||
|
for i := 1; i < len(hand); i++ {
|
||||||
|
if hand[i].Suit != suit {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hand Cards) containsStraight() bool {
|
||||||
|
if !hand.IsFiveCardPokerHand() {
|
||||||
|
panic("hand must have 5 cards to be scored")
|
||||||
|
}
|
||||||
|
sorted := hand.SortByRank()
|
||||||
|
|
||||||
|
if sorted[4].Rank == ACE && sorted[3].Rank == FIVE {
|
||||||
|
// special case for A-5 straight
|
||||||
|
if sorted[0].Rank == DEUCE && sorted[1].Rank == THREE && sorted[2].Rank == FOUR {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sorted[0].Rank.Int()+1 == sorted[1].Rank.Int() &&
|
||||||
|
sorted[1].Rank.Int()+1 == sorted[2].Rank.Int() &&
|
||||||
|
sorted[2].Rank.Int()+1 == sorted[3].Rank.Int() &&
|
||||||
|
sorted[3].Rank.Int()+1 == sorted[4].Rank.Int()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hand Cards) containsStraightFlush() bool {
|
||||||
|
if !hand.IsFiveCardPokerHand() {
|
||||||
|
panic("hand must have 5 cards to be scored")
|
||||||
|
}
|
||||||
|
if hand.containsStraight() && hand.containsFlush() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hand Cards) containsRoyalFlush() bool {
|
||||||
|
if !hand.IsFiveCardPokerHand() {
|
||||||
|
panic("hand must have 5 cards to be scored")
|
||||||
|
}
|
||||||
|
if hand.containsStraightFlush() && hand.HighestRank() == ACE {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hand Cards) containsFourOfAKind() bool {
|
||||||
|
if !hand.IsFiveCardPokerHand() {
|
||||||
|
panic("hand must have 5 cards to be scored")
|
||||||
|
}
|
||||||
|
sorted := hand.SortByRank()
|
||||||
|
if sorted[0].Rank == sorted[1].Rank && sorted[1].Rank == sorted[2].Rank && sorted[2].Rank == sorted[3].Rank {
|
||||||
|
// the quads precede the kicker
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if sorted[1].Rank == sorted[2].Rank && sorted[2].Rank == sorted[3].Rank && sorted[3].Rank == sorted[4].Rank {
|
||||||
|
// the kicker is the first card
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hand Cards) containsFullHouse() bool {
|
||||||
|
if !hand.IsFiveCardPokerHand() {
|
||||||
|
panic("hand must have 5 cards to be scored")
|
||||||
|
}
|
||||||
|
sorted := hand.SortByRank()
|
||||||
|
|
||||||
|
if sorted[0].Rank == sorted[1].Rank && sorted[1].Rank == sorted[2].Rank && sorted[3].Rank == sorted[4].Rank {
|
||||||
|
// the trips precede the pair
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if sorted[0].Rank == sorted[1].Rank && sorted[2].Rank == sorted[3].Rank && sorted[3].Rank == sorted[4].Rank {
|
||||||
|
// the pair is first
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hand Cards) containsPair() bool {
|
||||||
|
if !hand.IsFiveCardPokerHand() {
|
||||||
|
panic("hand must have 5 cards to be scored")
|
||||||
|
}
|
||||||
|
sorted := hand.SortByRank()
|
||||||
|
if sorted[0].Rank == sorted[1].Rank {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if sorted[1].Rank == sorted[2].Rank {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if sorted[2].Rank == sorted[3].Rank {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if sorted[3].Rank == sorted[4].Rank {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hand Cards) containsThreeOfAKind() bool {
|
||||||
|
if !hand.IsFiveCardPokerHand() {
|
||||||
|
panic("hand must have 5 cards to be scored")
|
||||||
|
}
|
||||||
|
sorted := hand.SortByRank()
|
||||||
|
if sorted[0].Rank == sorted[1].Rank && sorted[1].Rank == sorted[2].Rank {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if sorted[1].Rank == sorted[2].Rank && sorted[2].Rank == sorted[3].Rank {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if sorted[2].Rank == sorted[3].Rank && sorted[3].Rank == sorted[4].Rank {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hand Cards) containsTwoPair() bool {
|
||||||
|
if !hand.IsFiveCardPokerHand() {
|
||||||
|
panic("hand must have 5 cards to be scored")
|
||||||
|
}
|
||||||
|
sorted := hand.SortByRank()
|
||||||
|
if sorted[0].Rank == sorted[1].Rank && sorted[2].Rank == sorted[3].Rank {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if sorted[0].Rank == sorted[1].Rank && sorted[3].Rank == sorted[4].Rank {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if sorted[1].Rank == sorted[2].Rank && sorted[3].Rank == sorted[4].Rank {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hand Cards) isUnmadeHand() bool {
|
||||||
|
if !hand.IsFiveCardPokerHand() {
|
||||||
|
panic("hand must have 5 cards to be scored")
|
||||||
|
}
|
||||||
|
return !hand.containsPair() && !hand.containsTwoPair() && !hand.containsThreeOfAKind() && !hand.containsStraight() && !hand.containsFlush() && !hand.containsFullHouse() && !hand.containsFourOfAKind() && !hand.containsStraightFlush() && !hand.containsRoyalFlush()
|
||||||
|
}
|
@ -56,21 +56,19 @@ type Card struct {
|
|||||||
|
|
||||||
type Cards []Card
|
type Cards []Card
|
||||||
|
|
||||||
func (r Rank) Int(x AcesHighOrLow) int {
|
func (r Rank) Int() int {
|
||||||
return int(rankToScore(r, x))
|
return int(r.Score())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r Rank) HandScore(x AcesHighOrLow) HandScore {
|
func (r Rank) HandScore() HandScore {
|
||||||
return HandScore(r.Int(x))
|
return HandScore(r.Int())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Cards) SortByRank(x AcesHighOrLow) Cards {
|
func (c Cards) SortByRank() Cards {
|
||||||
|
|
||||||
newCards := make(Cards, len(c))
|
newCards := make(Cards, len(c))
|
||||||
copy(newCards, c)
|
copy(newCards, c)
|
||||||
|
|
||||||
sort.Slice(newCards, func(i, j int) bool {
|
sort.Slice(newCards, func(i, j int) bool {
|
||||||
return rankToScore(newCards[i].Rank, x) > rankToScore(newCards[j].Rank, x)
|
return newCards[i].Rank.Score() > newCards[j].Rank.Score()
|
||||||
})
|
})
|
||||||
return newCards
|
return newCards
|
||||||
}
|
}
|
||||||
@ -125,8 +123,8 @@ func (c *Card) String() string {
|
|||||||
return fmt.Sprintf("%s%s", string(c.Rank), string(c.Suit))
|
return fmt.Sprintf("%s%s", string(c.Rank), string(c.Suit))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Cards) HighestRank(x AcesHighOrLow) Rank {
|
func (c Cards) HighestRank() Rank {
|
||||||
c = c.SortByRank(x)
|
c = c.SortByRank()
|
||||||
return c[0].Rank
|
return c[0].Rank
|
||||||
}
|
}
|
||||||
|
|
||||||
|
163
pokercore/pokerhand.go
Normal file
163
pokercore/pokerhand.go
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
package pokercore
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type PokerHandType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
HighCard PokerHandType = iota
|
||||||
|
Pair
|
||||||
|
TwoPair
|
||||||
|
ThreeOfAKind
|
||||||
|
Straight
|
||||||
|
Flush
|
||||||
|
FullHouse
|
||||||
|
FourOfAKind
|
||||||
|
StraightFlush
|
||||||
|
RoyalFlush
|
||||||
|
)
|
||||||
|
|
||||||
|
type PokerHand struct {
|
||||||
|
Hand Cards
|
||||||
|
Type PokerHandType
|
||||||
|
Score HandScore
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Cards) PokerHand() (*PokerHand, error) {
|
||||||
|
if len(c) != 5 {
|
||||||
|
return nil, fmt.Errorf("hand must have 5 cards to be scored as a poker hand")
|
||||||
|
}
|
||||||
|
if c.containsDuplicates() {
|
||||||
|
return nil, fmt.Errorf("hand must have no duplicates to be scored as a poker hand")
|
||||||
|
}
|
||||||
|
|
||||||
|
ph := new(PokerHand)
|
||||||
|
ph.Hand = c
|
||||||
|
if c.containsRoyalFlush() {
|
||||||
|
ph.Type = RoyalFlush
|
||||||
|
ph.Score = ScoreRoyalFlush
|
||||||
|
return ph, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.containsStraightFlush() {
|
||||||
|
ph.Type = StraightFlush
|
||||||
|
ph.Score = ph.Hand.scoreStraightFlush()
|
||||||
|
return ph, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.containsFourOfAKind() {
|
||||||
|
ph.Type = FourOfAKind
|
||||||
|
ph.Score = ScoreFourOfAKind + 1000*c.fourOfAKindRank().Score() + c.fourOfAKindKicker().Score()
|
||||||
|
return ph, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.containsFullHouse() {
|
||||||
|
ph.Type = FullHouse
|
||||||
|
ph.Score = ScoreFullHouse + 1000*c.fullHouseTripsRank().Score() + c.fullHousePairRank().Score()
|
||||||
|
return ph, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.containsFlush() {
|
||||||
|
ph.Type = Flush
|
||||||
|
ph.Score = c.scoreFlush()
|
||||||
|
return ph, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.containsStraight() {
|
||||||
|
ph.Type = Straight
|
||||||
|
ph.Score = ScoreStraight + 1000*c.HighestRank().Score()
|
||||||
|
return ph, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.containsThreeOfAKind() {
|
||||||
|
ph.Type = ThreeOfAKind
|
||||||
|
ph.Score = ScoreThreeOfAKind
|
||||||
|
ph.Score += 1000 * c.threeOfAKindTripsRank().Score()
|
||||||
|
ph.Score += 100 * c.threeOfAKindFirstKicker().Score()
|
||||||
|
ph.Score += 10 * c.threeOfAKindSecondKicker().Score()
|
||||||
|
return ph, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.containsTwoPair() {
|
||||||
|
ph.Type = TwoPair
|
||||||
|
ph.Score = ScoreTwoPair
|
||||||
|
ph.Score += 1000 * c.twoPairBiggestPair().Score()
|
||||||
|
ph.Score += 100 * c.twoPairSmallestPair().Score()
|
||||||
|
ph.Score += 10 * c.twoPairKicker().Score()
|
||||||
|
return ph, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.containsPair() {
|
||||||
|
ph.Type = Pair
|
||||||
|
ph.Score = ScorePair
|
||||||
|
ph.Score += 1000 * c.pairRank().Score()
|
||||||
|
ph.Score += 100 * c.pairFirstKicker().Score()
|
||||||
|
ph.Score += 10 * c.pairSecondKicker().Score()
|
||||||
|
ph.Score += c.pairThirdKicker().Score()
|
||||||
|
return ph, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ph.Type = HighCard
|
||||||
|
ph.Score = c.scoreHighCard()
|
||||||
|
return ph, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c PokerHand) HighestRank() Rank {
|
||||||
|
return c.Hand.HighestRank()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c PokerHand) String() string {
|
||||||
|
sortedHand := c.Hand.SortByRank()
|
||||||
|
if c.Type == RoyalFlush {
|
||||||
|
return fmt.Sprintf("a royal flush in %s", c.Hand[0].Suit)
|
||||||
|
}
|
||||||
|
if c.Hand.containsStraightFlush() {
|
||||||
|
return fmt.Sprintf("%s high straight flush in %s", c.HighestRank().WithArticle(), sortedHand[0].Suit)
|
||||||
|
}
|
||||||
|
if c.Hand.containsFourOfAKind() {
|
||||||
|
return fmt.Sprintf("four %s with %s", c.Hand.fourOfAKindRank().Pluralize(), c.Hand.fourOfAKindKicker().Rank.WithArticle())
|
||||||
|
}
|
||||||
|
if c.Hand.containsFullHouse() {
|
||||||
|
return fmt.Sprintf("a full house, %s full of %s", c.Hand.fullHouseTripsRank().Pluralize(), c.Hand.fullHousePairRank().Pluralize())
|
||||||
|
}
|
||||||
|
if c.Hand.containsFlush() {
|
||||||
|
return fmt.Sprintf("%s high flush in %s", c.HighestRank().WithArticle(), sortedHand[0].Suit)
|
||||||
|
}
|
||||||
|
if c.Hand.containsStraight() {
|
||||||
|
return fmt.Sprintf("%s high straight", c.HighestRank().WithArticle())
|
||||||
|
}
|
||||||
|
if c.Hand.containsThreeOfAKind() {
|
||||||
|
return fmt.Sprintf(
|
||||||
|
"three %s with %s and %s",
|
||||||
|
c.Hand.threeOfAKindTripsRank().Pluralize(),
|
||||||
|
c.Hand.threeOfAKindFirstKicker().Rank.WithArticle(),
|
||||||
|
c.Hand.threeOfAKindSecondKicker().Rank.WithArticle(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if c.Hand.containsTwoPair() {
|
||||||
|
return fmt.Sprintf(
|
||||||
|
"two pair, %s and %s with %s",
|
||||||
|
c.Hand.twoPairBiggestPair().Pluralize(),
|
||||||
|
c.Hand.twoPairSmallestPair().Pluralize(),
|
||||||
|
c.Hand.twoPairKicker().Rank.WithArticle(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if c.Hand.containsPair() {
|
||||||
|
return fmt.Sprintf(
|
||||||
|
"a pair of %s with %s, %s, and %s",
|
||||||
|
c.Hand.pairRank().Pluralize(),
|
||||||
|
c.Hand.pairFirstKicker().Rank.WithArticle(),
|
||||||
|
c.Hand.pairSecondKicker().Rank.WithArticle(),
|
||||||
|
c.Hand.pairThirdKicker().Rank.WithArticle(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf(
|
||||||
|
// "ace high with an eight, a seven, a six, and a deuce"
|
||||||
|
"%s high with %s, %s, %s, and %s",
|
||||||
|
sortedHand[4].Rank,
|
||||||
|
sortedHand[3].Rank.WithArticle(),
|
||||||
|
sortedHand[2].Rank.WithArticle(),
|
||||||
|
sortedHand[1].Rank.WithArticle(),
|
||||||
|
sortedHand[0].Rank.WithArticle(),
|
||||||
|
)
|
||||||
|
}
|
@ -5,7 +5,7 @@ import "fmt"
|
|||||||
type HandScore int
|
type HandScore int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ScoreNoPair = HandScore(iota * 100_000_000_000)
|
ScoreHighCard = HandScore(iota * 100_000_000_000)
|
||||||
ScorePair
|
ScorePair
|
||||||
ScoreTwoPair
|
ScoreTwoPair
|
||||||
ScoreThreeOfAKind
|
ScoreThreeOfAKind
|
||||||
@ -14,23 +14,108 @@ const (
|
|||||||
ScoreFullHouse
|
ScoreFullHouse
|
||||||
ScoreFourOfAKind
|
ScoreFourOfAKind
|
||||||
ScoreStraightFlush
|
ScoreStraightFlush
|
||||||
|
ScoreRoyalFlush
|
||||||
)
|
)
|
||||||
|
|
||||||
type AcesHighOrLow int
|
func (c Card) Score() HandScore {
|
||||||
|
return HandScore(c.Rank.Score())
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
func (c Cards) PokerHandScore() (HandScore, error) {
|
||||||
AcesHigh AcesHighOrLow = iota
|
if len(c) != 5 {
|
||||||
AcesLow
|
return 0, fmt.Errorf("hand must have 5 cards to be scored as a poker hand")
|
||||||
)
|
}
|
||||||
|
ph, err := c.PokerHand()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
func rankToScore(rank Rank, AcesHighOrLow AcesHighOrLow) HandScore {
|
fmt.Println(ph)
|
||||||
switch rank {
|
return ph.Score, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
func scoreToName(x HandScore) string {
|
||||||
|
switch x {
|
||||||
|
case x >= ScoreRoyalFlush:
|
||||||
|
return "Royal Flush"
|
||||||
|
case x >= ScoreStraightFlush:
|
||||||
|
return "Straight Flush"
|
||||||
|
case x >= ScoreFourOfAKind:
|
||||||
|
return "Four of a Kind"
|
||||||
|
case x >= ScoreFullHouse:
|
||||||
|
return "Full House"
|
||||||
|
case x >= ScoreFlush:
|
||||||
|
return "Flush"
|
||||||
|
case x >= ScoreStraight:
|
||||||
|
return "Straight"
|
||||||
|
case x >= ScoreThreeOfAKind:
|
||||||
|
return "Three of a Kind"
|
||||||
|
case x >= ScoreTwoPair:
|
||||||
|
return "Two Pair"
|
||||||
|
case x >= ScorePair:
|
||||||
|
return "Pair"
|
||||||
|
case x >= ScoreHighCard:
|
||||||
|
return "High Card"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
func (r Rank) Article() string {
|
||||||
|
switch r {
|
||||||
case ACE:
|
case ACE:
|
||||||
if AcesHighOrLow == AcesHigh {
|
return "an"
|
||||||
return 14 // Aces are high, so we give them the highest value
|
case EIGHT:
|
||||||
} else {
|
return "an"
|
||||||
return 1
|
default:
|
||||||
}
|
return "a"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r Rank) WithArticle() string {
|
||||||
|
return fmt.Sprintf("%s %s", r.Article(), r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r Rank) Pluralize() string {
|
||||||
|
switch r {
|
||||||
|
case ACE:
|
||||||
|
return "Aces"
|
||||||
|
case DEUCE:
|
||||||
|
return "Deuces"
|
||||||
|
case THREE:
|
||||||
|
return "Threes"
|
||||||
|
case FOUR:
|
||||||
|
return "Fours"
|
||||||
|
case FIVE:
|
||||||
|
return "Fives"
|
||||||
|
case SIX:
|
||||||
|
return "Sixes"
|
||||||
|
case SEVEN:
|
||||||
|
return "Sevens"
|
||||||
|
case EIGHT:
|
||||||
|
return "Eights"
|
||||||
|
case NINE:
|
||||||
|
return "Nines"
|
||||||
|
case TEN:
|
||||||
|
return "Tens"
|
||||||
|
case JACK:
|
||||||
|
return "Jacks"
|
||||||
|
case QUEEN:
|
||||||
|
return "Queens"
|
||||||
|
case KING:
|
||||||
|
return "Kings"
|
||||||
|
default:
|
||||||
|
panic("nope")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x HandScore) String() string {
|
||||||
|
return fmt.Sprintf("<HandScore %d>", x)
|
||||||
|
//return scoreToName(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r Rank) Score() HandScore {
|
||||||
|
switch r {
|
||||||
case DEUCE:
|
case DEUCE:
|
||||||
return 2
|
return 2
|
||||||
case THREE:
|
case THREE:
|
||||||
@ -55,209 +140,8 @@ func rankToScore(rank Rank, AcesHighOrLow AcesHighOrLow) HandScore {
|
|||||||
return 12
|
return 12
|
||||||
case KING:
|
case KING:
|
||||||
return 13
|
return 13
|
||||||
default:
|
case ACE:
|
||||||
panic("nope")
|
return 14
|
||||||
}
|
}
|
||||||
}
|
return 0
|
||||||
|
|
||||||
func (c Cards) ScoreHand() (HandScore, error) {
|
|
||||||
if !c.IsFiveCardPokerHand() {
|
|
||||||
return 0, fmt.Errorf("hand must have 5 cards with no duplicates to be scored")
|
|
||||||
}
|
|
||||||
if c.containsRoyalFlush() {
|
|
||||||
return ScoreStraightFlush + 1000*ACE.HandScore(AcesHigh), nil
|
|
||||||
}
|
|
||||||
if c.containsStraightFlush() {
|
|
||||||
return ScoreStraightFlush + 1000*c.HighestRank(AcesHigh).HandScore(AcesHigh), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
panic("not implemented")
|
|
||||||
// FIXME finish this
|
|
||||||
return 0, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hand Cards) containsDuplicates() bool {
|
|
||||||
seen := make(map[Card]bool)
|
|
||||||
for _, card := range hand {
|
|
||||||
if _, ok := seen[card]; ok {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
seen[card] = true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hand Cards) IsFiveCardPokerHand() bool {
|
|
||||||
return len(hand) == 5 && !hand.containsDuplicates()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hand Cards) containsFlush() bool {
|
|
||||||
if !hand.IsFiveCardPokerHand() {
|
|
||||||
panic("hand must have 5 cards to be scored")
|
|
||||||
}
|
|
||||||
suit := hand[0].Suit
|
|
||||||
for i := 1; i < len(hand); i++ {
|
|
||||||
if hand[i].Suit != suit {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hand Cards) containsStraight() bool {
|
|
||||||
if !hand.IsFiveCardPokerHand() {
|
|
||||||
panic("hand must have 5 cards to be scored")
|
|
||||||
}
|
|
||||||
sorted := hand.SortByRank(AcesHigh)
|
|
||||||
|
|
||||||
if sorted[0].Rank == ACE && sorted[1].Rank == FIVE {
|
|
||||||
// special case for A-5 straight
|
|
||||||
if sorted[1].Rank == FIVE && sorted[2].Rank == FOUR && sorted[3].Rank == THREE && sorted[4].Rank == DEUCE {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return sorted[0].Rank.Int(AcesHigh) == sorted[1].Rank.Int(AcesHigh)+1 && sorted[1].Rank.Int(AcesHigh) == sorted[2].Rank.Int(AcesHigh)+1 && sorted[2].Rank.Int(AcesHigh) == sorted[3].Rank.Int(AcesHigh)+1 && sorted[3].Rank.Int(AcesHigh) == sorted[4].Rank.Int(AcesHigh)+1
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hand Cards) containsStraightFlush() bool {
|
|
||||||
if !hand.IsFiveCardPokerHand() {
|
|
||||||
panic("hand must have 5 cards to be scored")
|
|
||||||
}
|
|
||||||
if hand.containsStraight() && hand.containsFlush() {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hand Cards) containsRoyalFlush() bool {
|
|
||||||
if !hand.IsFiveCardPokerHand() {
|
|
||||||
panic("hand must have 5 cards to be scored")
|
|
||||||
}
|
|
||||||
sorted := hand.SortByRank(AcesHigh)
|
|
||||||
if hand.containsStraightFlush() && sorted[0].Rank == ACE {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hand Cards) containsFourOfAKind() bool {
|
|
||||||
if !hand.IsFiveCardPokerHand() {
|
|
||||||
panic("hand must have 5 cards to be scored")
|
|
||||||
}
|
|
||||||
sorted := hand.SortByRank(AcesHigh)
|
|
||||||
if sorted[0].Rank == sorted[1].Rank && sorted[1].Rank == sorted[2].Rank && sorted[2].Rank == sorted[3].Rank {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if sorted[1].Rank == sorted[2].Rank && sorted[2].Rank == sorted[3].Rank && sorted[3].Rank == sorted[4].Rank {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hand Cards) containsFullHouse() bool {
|
|
||||||
if !hand.IsFiveCardPokerHand() {
|
|
||||||
panic("hand must have 5 cards to be scored")
|
|
||||||
}
|
|
||||||
sorted := hand.SortByRank(AcesHigh)
|
|
||||||
if sorted[0].Rank == sorted[1].Rank && sorted[1].Rank == sorted[2].Rank && sorted[3].Rank == sorted[4].Rank {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if sorted[0].Rank == sorted[1].Rank && sorted[2].Rank == sorted[3].Rank && sorted[3].Rank == sorted[4].Rank {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hand Cards) containsPair() bool {
|
|
||||||
if !hand.IsFiveCardPokerHand() {
|
|
||||||
panic("hand must have 5 cards to be scored")
|
|
||||||
}
|
|
||||||
sorted := hand.SortByRank(AcesHigh)
|
|
||||||
if sorted[0].Rank == sorted[1].Rank {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if sorted[1].Rank == sorted[2].Rank {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if sorted[2].Rank == sorted[3].Rank {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if sorted[3].Rank == sorted[4].Rank {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hand Cards) containsThreeOfAKind() bool {
|
|
||||||
if !hand.IsFiveCardPokerHand() {
|
|
||||||
panic("hand must have 5 cards to be scored")
|
|
||||||
}
|
|
||||||
sorted := hand.SortByRank(AcesHigh)
|
|
||||||
if sorted[0].Rank == sorted[1].Rank && sorted[1].Rank == sorted[2].Rank {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if sorted[1].Rank == sorted[2].Rank && sorted[2].Rank == sorted[3].Rank {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if sorted[2].Rank == sorted[3].Rank && sorted[3].Rank == sorted[4].Rank {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hand Cards) containsTwoPair() bool {
|
|
||||||
if !hand.IsFiveCardPokerHand() {
|
|
||||||
panic("hand must have 5 cards to be scored")
|
|
||||||
}
|
|
||||||
sorted := hand.SortByRank(AcesHigh)
|
|
||||||
if sorted[0].Rank == sorted[1].Rank && sorted[2].Rank == sorted[3].Rank {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if sorted[0].Rank == sorted[1].Rank && sorted[3].Rank == sorted[4].Rank {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if sorted[1].Rank == sorted[2].Rank && sorted[3].Rank == sorted[4].Rank {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hand Cards) isUnmadeHand() bool {
|
|
||||||
if !hand.IsFiveCardPokerHand() {
|
|
||||||
panic("hand must have 5 cards to be scored")
|
|
||||||
}
|
|
||||||
return !hand.containsPair() && !hand.containsTwoPair() && !hand.containsThreeOfAKind() && !hand.containsStraight() && !hand.containsFlush() && !hand.containsFullHouse() && !hand.containsFourOfAKind() && !hand.containsStraightFlush() && !hand.containsRoyalFlush()
|
|
||||||
}
|
|
||||||
|
|
||||||
// this method makes a n new hands where n is the number of cards in the hand
|
|
||||||
// each of the new hands has one card removed from the original hand
|
|
||||||
// then it calls the identifyBestFiveCardPokerHand method on each of the new hands
|
|
||||||
// and returns the best hand by score. this is recursion.
|
|
||||||
func (hand Cards) identifyBestFiveCardPokerHand() (Cards, error) {
|
|
||||||
newHands := make([]Cards, len(hand))
|
|
||||||
for i := 0; i < len(hand); i++ {
|
|
||||||
newHand := hand[:i]
|
|
||||||
newHand = append(newHand, hand[i+1:]...)
|
|
||||||
newHands[i] = newHand
|
|
||||||
}
|
|
||||||
var bestHand Cards
|
|
||||||
var bestScore HandScore
|
|
||||||
|
|
||||||
for _, h := range newHands {
|
|
||||||
if h.IsFiveCardPokerHand() {
|
|
||||||
score, _ := h.ScoreHand()
|
|
||||||
if score > bestScore {
|
|
||||||
bestScore = score
|
|
||||||
bestHand = h
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
rh, _ := h.identifyBestFiveCardPokerHand()
|
|
||||||
score, _ := rh.ScoreHand()
|
|
||||||
if score > bestScore {
|
|
||||||
bestScore = score
|
|
||||||
bestHand = rh
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return bestHand, nil
|
|
||||||
}
|
}
|
||||||
|
@ -75,13 +75,13 @@ func TestFlush(t *testing.T) {
|
|||||||
|
|
||||||
x := ScoreFlush
|
x := ScoreFlush
|
||||||
var multiplier HandScore = 100
|
var multiplier HandScore = 100
|
||||||
x += multiplier * DEUCE.HandScore(AcesHigh)
|
x += multiplier * DEUCE.Score()
|
||||||
multiplier *= 100
|
multiplier *= 100
|
||||||
x += multiplier * THREE.HandScore(AcesHigh)
|
x += multiplier * THREE.Score()
|
||||||
multiplier *= 100
|
multiplier *= 100
|
||||||
x += multiplier * FOUR.HandScore(AcesHigh)
|
x += multiplier * FOUR.Score()
|
||||||
multiplier *= 100
|
multiplier *= 100
|
||||||
x += multiplier * SIX.HandScore(AcesHigh)
|
x += multiplier * SIX.Score()
|
||||||
fmt.Printf("a-2-3-4-6 flush score should be: %d\n", x)
|
fmt.Printf("a-2-3-4-6 flush score should be: %d\n", x)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,7 +103,7 @@ func TestStraightFlush(t *testing.T) {
|
|||||||
assert.False(t, hand.containsTwoPair(), "Expected hand to not be two pair")
|
assert.False(t, hand.containsTwoPair(), "Expected hand to not be two pair")
|
||||||
assert.False(t, hand.containsPair(), "Expected hand to not be a pair")
|
assert.False(t, hand.containsPair(), "Expected hand to not be a pair")
|
||||||
|
|
||||||
assert.True(t, hand.HighestRank(AcesHigh) == SIX, "Expected highest rank to be a six")
|
assert.True(t, hand.HighestRank() == SIX, "Expected highest rank to be a six")
|
||||||
|
|
||||||
nd := NewDeckFromCards(hand)
|
nd := NewDeckFromCards(hand)
|
||||||
nd.ShuffleDeterministically(123456789)
|
nd.ShuffleDeterministically(123456789)
|
||||||
@ -111,8 +111,8 @@ func TestStraightFlush(t *testing.T) {
|
|||||||
fmt.Printf("new deck has %d cards\n", nd.Count())
|
fmt.Printf("new deck has %d cards\n", nd.Count())
|
||||||
shuffledHand := nd.Deal(5)
|
shuffledHand := nd.Deal(5)
|
||||||
assert.True(t, shuffledHand.containsStraightFlush(), "Expected hand to still be a straight flush after shuffle")
|
assert.True(t, shuffledHand.containsStraightFlush(), "Expected hand to still be a straight flush after shuffle")
|
||||||
assert.True(t, shuffledHand.HighestRank(AcesHigh) == SIX, "Expected highest rank to still be a six after shuffle")
|
assert.True(t, shuffledHand.HighestRank() == SIX, "Expected highest rank to still be a six after shuffle")
|
||||||
assert.True(t, shuffledHand.HighestRank(AcesLow) == SIX, "Expected highest rank to be a six after shuffle even with aces low")
|
assert.True(t, shuffledHand.HighestRank() == SIX, "Expected highest rank to be a six after shuffle even with aces low")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRoyalFlush(t *testing.T) {
|
func TestRoyalFlush(t *testing.T) {
|
||||||
@ -134,8 +134,8 @@ func TestRoyalFlush(t *testing.T) {
|
|||||||
assert.False(t, hand.containsTwoPair(), "Expected hand to not be two pair")
|
assert.False(t, hand.containsTwoPair(), "Expected hand to not be two pair")
|
||||||
assert.False(t, hand.containsPair(), "Expected hand to not be a pair")
|
assert.False(t, hand.containsPair(), "Expected hand to not be a pair")
|
||||||
|
|
||||||
assert.True(t, hand.HighestRank(AcesHigh) == ACE, "Expected highest rank to be an ace")
|
assert.True(t, hand.HighestRank() == ACE, "Expected highest rank to be an ace")
|
||||||
assert.False(t, hand.HighestRank(AcesHigh) == TEN, "Expected highest rank to not be an ace")
|
assert.False(t, hand.HighestRank() == TEN, "Expected highest rank to not be an ace")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUnmadeHand(t *testing.T) {
|
func TestUnmadeHand(t *testing.T) {
|
||||||
@ -155,7 +155,7 @@ func TestUnmadeHand(t *testing.T) {
|
|||||||
assert.False(t, hand.containsThreeOfAKind(), "Expected hand to not be three of a kind")
|
assert.False(t, hand.containsThreeOfAKind(), "Expected hand to not be three of a kind")
|
||||||
assert.False(t, hand.containsTwoPair(), "Expected hand to not be two pair")
|
assert.False(t, hand.containsTwoPair(), "Expected hand to not be two pair")
|
||||||
assert.False(t, hand.containsPair(), "Expected hand to not be a pair")
|
assert.False(t, hand.containsPair(), "Expected hand to not be a pair")
|
||||||
assert.True(t, hand.HighestRank(AcesHigh) == KING, "Expected highest rank to be a king")
|
assert.True(t, hand.HighestRank() == KING, "Expected highest rank to be a king")
|
||||||
assert.True(t, hand.isUnmadeHand(), "Expected hand to be unmade")
|
assert.True(t, hand.isUnmadeHand(), "Expected hand to be unmade")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,6 +176,24 @@ func TestTwoPair(t *testing.T) {
|
|||||||
assert.False(t, hand.containsThreeOfAKind(), "Expected hand to not be three of a kind")
|
assert.False(t, hand.containsThreeOfAKind(), "Expected hand to not be three of a kind")
|
||||||
assert.True(t, hand.containsTwoPair(), "Expected hand to be two pair")
|
assert.True(t, hand.containsTwoPair(), "Expected hand to be two pair")
|
||||||
assert.True(t, hand.containsPair(), "Expected hand to also be a pair")
|
assert.True(t, hand.containsPair(), "Expected hand to also be a pair")
|
||||||
assert.True(t, hand.HighestRank(AcesHigh) == KING, "Expected highest rank to be a king")
|
assert.True(t, hand.HighestRank() == KING, "Expected highest rank to be a king")
|
||||||
assert.False(t, hand.isUnmadeHand(), "Expected hand to not be unmade")
|
assert.False(t, hand.isUnmadeHand(), "Expected hand to not be unmade")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestHandScore(t *testing.T) {
|
||||||
|
hand := Cards{
|
||||||
|
KingOfSpades(),
|
||||||
|
JackOfDiamonds(),
|
||||||
|
JackOfSpades(),
|
||||||
|
KingOfDiamonds(),
|
||||||
|
TenOfSpades(),
|
||||||
|
}
|
||||||
|
|
||||||
|
ph, error := hand.PokerHand()
|
||||||
|
assert.Nil(t, error, "Expected no error")
|
||||||
|
assert.True(t, ph.Score > 0, "Expected score to be nonzero 0")
|
||||||
|
assert.True(t, ph.Score < 100000000000000000, "Expected score to be less than 100000000000000000")
|
||||||
|
|
||||||
|
fmt.Printf("PokerHand: %v+\n", ph)
|
||||||
|
fmt.Printf("PH score: %d\n", ph.Score)
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user