package pokercore import ( "testing" "github.com/stretchr/testify/assert" ) func TestHandDescriptionBug(t *testing.T) { t.Parallel() playerCount := 8 d := NewDeck() d.ShuffleDeterministically(1337) players := make([]*Cards, playerCount) for i := 0; i < playerCount; i++ { c := d.Deal(2) players[i] = &c t.Logf("Player %d dealt: %+v\n", i+1, c) } t.Logf("Players: %+v\n", players) community := d.Deal(5) t.Logf("Community: %+v\n", community) var playerResults []*PokerHand for i := 0; i < playerCount; i++ { t.Logf("Player %d hole cards: %+v\n", i+1, *players[i]) pc := append(*players[i], community...) t.Logf("Player %d cards available: %+v\n", i+1, pc) hand, err := pc.IdentifyBestFiveCardPokerHand() assert.NoError(t, err, "Expected no error") ph, err := hand.PokerHand() assert.NoError(t, err, "Expected no error") t.Logf("Player %d five cards used: %+v\n", i+1, hand) t.Logf("Player %d poker hand: %+v\n", i+1, ph) t.Logf("Player %d best hand description: %s\n", i+1, ph.Description()) playerResults = append(playerResults, ph) } weirdOne := playerResults[7] t.Logf("Weird one: %v\n", weirdOne) t.Logf("Weird one description: %s\n", weirdOne.Description()) // T♠,7♠,9♦,7♣,T♥ assert.Equal(t, "two pair, tens and sevens with a nine", weirdOne.Description()) scoreShouldBe := ScoreTwoPair scoreShouldBe += 10000 * TEN.Score() scoreShouldBe += 100 * SEVEN.Score() scoreShouldBe += NINE.Score() assert.Equal(t, scoreShouldBe, weirdOne.Score) cards := weirdOne.Hand assert.True(t, cards.containsTwoPair(), "Expected hand to be two pair") bp := cards.twoPairBiggestPair() // returns Rank, because describing a pair assert.Equal(t, TEN, bp, "Expected biggest pair to be a ten") sp := cards.twoPairSmallestPair() // returns Rank, because describing a pair assert.Equal(t, SEVEN, sp, "Expected smallest pair to be a seven") k := cards.twoPairKicker() // returns Card, because describing a single card assert.Equal(t, NINE, k.Rank, "Expected kicker to be a nine") } func TestAceLowStraight(t *testing.T) { t.Parallel() t.Run("Test Ace-Low Straight", func(t *testing.T) { hand := Cards{ AceOfSpades(), DeuceOfHearts(), ThreeOfDiamonds(), FourOfClubs(), FiveOfSpades(), } assert.True(t, hand.containsStraight(), "Expected hand to be a straight") ph, err := hand.PokerHand() assert.NoError(t, err, "Expected no error") assert.Greater(t, ph.Score, 0, "Expected score to be greater than 0") assert.Less(t, ph.Score, 100000000000000000, "Expected score to be less than 100000000000000000") assert.Equal(t, ph.Score, ScoreStraight+FIVE.Score()) assert.Equal(t, "a five high straight", ph.Description()) assert.Equal(t, ACE, hand.HighestRank(), "Expected highest rank to be an ace") s := hand.SortByRankAscending() assert.Equal(t, DEUCE, s.First().Rank, "Expected first card to be a deuce") assert.Equal(t, ACE, s.Last().Rank, "Expected last card in sorted to be an ace") assert.Equal(t, THREE, s.Second().Rank, "Expected second card to be a three") assert.Equal(t, FOUR, s.Third().Rank, "Expected third card to be a four") assert.Equal(t, FIVE, s.Fourth().Rank, "Expected fourth card to be a five") assert.Equal(t, ACE, s.Fifth().Rank, "Expected fifth card to be an ace") }) } func TestAceHighStraight(t *testing.T) { t.Parallel() t.Run("Test Ace-High Straight", func(t *testing.T) { hand := Cards{ TenOfSpades(), JackOfHearts(), KingOfClubs(), AceOfSpades(), QueenOfDiamonds(), } assert.True(t, hand.containsStraight(), "Expected hand to be a straight") newDeck := NewDeckFromCards(hand) newDeck.ShuffleDeterministically(123456789) shuffledHand := newDeck.Deal(5) assert.True(t, shuffledHand.containsStraight(), "Expected hand to still be a straight after shuffle") assert.Equal(t, ACE, shuffledHand.HighestRank(), "Expected highest rank to be an ace") sortedHand := shuffledHand.SortByRankAscending() assert.Equal(t, TEN, sortedHand[0].Rank, "Expected lowest rank to be a ten") assert.Equal(t, JACK, sortedHand[1].Rank, "Expected second lowest rank to be a jack") assert.Equal(t, QUEEN, sortedHand[2].Rank, "Expected third lowest rank to be a queen") assert.Equal(t, KING, sortedHand[3].Rank, "Expected fourth lowest rank to be a king") assert.Equal(t, ACE, sortedHand[4].Rank, "Expected highest rank to be an ace") }) } func TestOtherStraight(t *testing.T) { t.Parallel() t.Run("Test Other Straight", func(t *testing.T) { hand := Cards{ DeuceOfSpades(), ThreeOfHearts(), FourOfDiamonds(), FiveOfClubs(), SixOfSpades(), } assert.True(t, hand.containsStraight(), "Expected hand to be a straight") newDeck := NewDeckFromCards(hand) newDeck.ShuffleDeterministically(123456789) shuffledHand := newDeck.Deal(5) assert.True(t, shuffledHand.containsStraight(), "Expected hand to still be a straight after shuffle") assert.False(t, shuffledHand.containsTwoPair(), "Expected hand to not be two pair") assert.False(t, shuffledHand.containsPair(), "Expected hand to not be a pair") assert.Equal(t, SIX, shuffledHand.HighestRank(), "Expected highest rank to be a six") assert.Equal(t, DEUCE, shuffledHand.SortByRankAscending().First().Rank, "Expected first card to be a deuce") }) } func TestFlush(t *testing.T) { t.Parallel() t.Run("Test Flush", func(t *testing.T) { hand := Cards{ AceOfSpades(), DeuceOfSpades(), ThreeOfSpades(), FourOfSpades(), SixOfSpades(), } assert.True(t, hand.containsFlush(), "Expected hand to be a flush") newDeck := NewDeckFromCards(hand) newDeck.ShuffleDeterministically(123456789) shuffledHand := newDeck.Deal(5) assert.True(t, shuffledHand.containsFlush(), "Expected hand to still be a flush after shuffle") // flush value is the sum of the ranks, just like high card x := ScoreFlush x += ACE.Score() x += DEUCE.Score() x += THREE.Score() x += FOUR.Score() x += SIX.Score() ph, err := shuffledHand.PokerHand() assert.NoError(t, err, "Expected no error") assert.Greater(t, ph.Score, 0, "Expected score to be nonzero") assert.Equal(t, ph.Score, x) }) } func TestStraightFlush(t *testing.T) { t.Parallel() t.Run("Test Straight Flush", func(t *testing.T) { hand := Cards{ SixOfSpades(), DeuceOfSpades(), ThreeOfSpades(), FourOfSpades(), FiveOfSpades(), } assert.True(t, hand.containsStraight(), "Expected hand to be a straight") assert.True(t, hand.containsFlush(), "Expected hand to be a flush") assert.True(t, hand.containsStraightFlush(), "Expected hand to be a straight flush") assert.False(t, hand.containsRoyalFlush(), "Expected hand to not be a royal flush") assert.False(t, hand.containsFourOfAKind(), "Expected hand to not be four of a kind") assert.False(t, hand.containsFullHouse(), "Expected hand to not be a full house") 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.containsPair(), "Expected hand to not be a pair") assert.Equal(t, SIX, hand.HighestRank(), "Expected highest rank to be a six") nd := NewDeckFromCards(hand) nd.ShuffleDeterministically(123456789) shuffledHand := nd.Deal(5) assert.True(t, shuffledHand.containsStraightFlush(), "Expected hand to still be a straight flush after shuffle") assert.Equal(t, SIX, shuffledHand.HighestRank(), "Expected highest rank to still be a six after shuffle") assert.Equal(t, SIX, shuffledHand.HighestRank(), "Expected highest rank to be a six after shuffle even with aces low") }) } func TestFourOfAKind(t *testing.T) { t.Parallel() t.Run("Test Four of a Kind", func(t *testing.T) { hand := Cards{ SixOfSpades(), SixOfHearts(), SixOfDiamonds(), SixOfClubs(), FiveOfSpades(), } assert.False(t, hand.containsStraight(), "Expected hand to not be a straight") assert.False(t, hand.containsFlush(), "Expected hand to not be a flush") assert.False(t, hand.containsStraightFlush(), "Expected hand to not be a straight flush") assert.False(t, hand.containsRoyalFlush(), "Expected hand to not be a royal flush") assert.True(t, hand.containsFourOfAKind(), "Expected hand to be four of a kind") assert.False(t, hand.containsFullHouse(), "Expected hand to not be a full house") // note that these are *expected* to be true. the contains* functions // are used in the PokerHand.calculateScore method to determine the best hand // and are checked in sequence of descending value, so if a hand is four of a kind // it will not be checked for full house, three of a kind, etc. // technically quads *is* two pair also, and a hand with quads does // indeed contain three of a kind, and contains a pair. assert.True(t, hand.containsThreeOfAKind(), "Expected hand to contain three of a kind") assert.True(t, hand.containsTwoPair(), "Expected hand to contain two pair") assert.True(t, hand.containsPair(), "Expected hand to contain a pair") assert.Equal(t, SIX, hand.HighestRank(), "Expected highest rank to be a six") }) } func TestRoyalFlush(t *testing.T) { t.Parallel() t.Run("Test Royal Flush", func(t *testing.T) { hand := Cards{ TenOfSpades(), JackOfSpades(), QueenOfSpades(), KingOfSpades(), AceOfSpades(), } assert.True(t, hand.containsStraight(), "Expected hand to be a straight") assert.True(t, hand.containsFlush(), "Expected hand to be a flush") assert.True(t, hand.containsStraightFlush(), "Expected hand to be a straight flush") assert.True(t, hand.containsRoyalFlush(), "Expected hand to be a royal flush") assert.False(t, hand.containsFourOfAKind(), "Expected hand to not be four of a kind") assert.False(t, hand.containsFullHouse(), "Expected hand to not be a full house") 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.containsPair(), "Expected hand to not be a pair") assert.Equal(t, ACE, hand.HighestRank(), "Expected highest rank to be an ace") assert.NotEqual(t, TEN, hand.HighestRank(), "Expected highest rank to not be a ten") }) } func TestUnmadeHand(t *testing.T) { t.Parallel() t.Run("Test Unmade Hand", func(t *testing.T) { hand := Cards{ TenOfSpades(), JackOfDiamonds(), QueenOfSpades(), KingOfSpades(), DeuceOfSpades(), } assert.False(t, hand.containsStraight(), "Expected hand to not be a straight") assert.False(t, hand.containsFlush(), "Expected hand to not be a flush") assert.False(t, hand.containsStraightFlush(), "Expected hand to not be a straight flush") assert.False(t, hand.containsRoyalFlush(), "Expected hand to not be a royal flush") assert.False(t, hand.containsFourOfAKind(), "Expected hand to not be four of a kind") assert.False(t, hand.containsFullHouse(), "Expected hand to not be a full house") 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.containsPair(), "Expected hand to not be a pair") assert.Equal(t, KING, hand.HighestRank(), "Expected highest rank to be a king") assert.True(t, hand.isUnmadeHand(), "Expected hand to be unmade") }) } func TestTwoPair(t *testing.T) { t.Parallel() t.Run("Test Two Pair", func(t *testing.T) { hand := Cards{ KingOfSpades(), JackOfDiamonds(), JackOfSpades(), KingOfDiamonds(), TenOfSpades(), } assert.False(t, hand.containsStraight(), "Expected hand to not be a straight") assert.False(t, hand.containsFlush(), "Expected hand to not be a flush") assert.False(t, hand.containsStraightFlush(), "Expected hand to not be a straight flush") assert.False(t, hand.containsRoyalFlush(), "Expected hand to not be a royal flush") assert.False(t, hand.containsFourOfAKind(), "Expected hand to not be four of a kind") assert.False(t, hand.containsFullHouse(), "Expected hand to not be a full house") 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.containsPair(), "Expected hand to also be a pair") assert.Equal(t, KING, hand.HighestRank(), "Expected highest rank to be a king") assert.False(t, hand.isUnmadeHand(), "Expected hand to not be unmade") }) } func TestDetectDuplicates(t *testing.T) { t.Parallel() t.Run("Test Detect Duplicates", func(t *testing.T) { hand := Cards{ KingOfSpades(), JackOfDiamonds(), JackOfSpades(), KingOfSpades(), TenOfSpades(), } assert.True(t, hand.containsDuplicates(), "Expected hand to contain duplicates") }) } func TestHandScore(t *testing.T) { t.Parallel() t.Run("Test Hand Score", func(t *testing.T) { hand := Cards{ KingOfSpades(), JackOfDiamonds(), JackOfSpades(), KingOfDiamonds(), TenOfSpades(), } ph, err := hand.PokerHand() assert.NoError(t, err, "Expected no error") assert.True(t, ph.Score > 0, "Expected score to be nonzero") assert.True(t, ph.Score < 100000000000000000, "Expected score to be less than 100000000000000000") // write more assertions FIXME }) } func TestTwoPairBug(t *testing.T) { t.Parallel() t.Run("Test Two Pair Bug", func(t *testing.T) { // this is an actual bug in the first implementation c, err := NewCardsFromString("9♠,9♣,Q♥,Q♦,K♣") assert.NoError(t, err, "Expected no error") ph, err := c.PokerHand() assert.NoError(t, err, "Expected no error") assert.Greater(t, ph.Score, 0, "Expected score to be nonzero") desc := ph.Description() assert.Equal(t, "two pair, queens and nines with a king", desc) }) } func TestScoringStructureQuads(t *testing.T) { t.Parallel() t.Run("Test Scoring Structure Quads", func(t *testing.T) { // this test case was for a bug, but is now fixed handA := Cards{ DeuceOfSpades(), DeuceOfHearts(), DeuceOfDiamonds(), DeuceOfClubs(), AceOfSpades(), } handB := Cards{ ThreeOfSpades(), ThreeOfHearts(), ThreeOfDiamonds(), ThreeOfClubs(), DeuceOfSpades(), } phA, err := handA.PokerHand() assert.NoError(t, err, "Expected no error") phB, err := handB.PokerHand() assert.NoError(t, err, "Expected no error") assert.Greater(t, phB.Score, phA.Score, "Expected hand B to be higher than hand A") }) } func TestScoringStructureFullHouse(t *testing.T) { t.Parallel() t.Run("Test Scoring Structure Full House", func(t *testing.T) { // this test case documents an actual bug i found in my scoring code // related to the fact that i was multiplying by 100 then by 1000, // instead of by 100 then by 10000 in the scoring. because the ranks // are 2-14, the different levels of kickers (or in the case of a full // house, the pair) were not distinguishing sufficiently. handA := Cards{ DeuceOfSpades(), DeuceOfHearts(), DeuceOfDiamonds(), AceOfSpades(), AceOfHearts(), } phA, err := handA.PokerHand() assert.NoError(t, err, "Expected no error") deucesFullOfAcesScore := phA.Score handB := Cards{ ThreeOfSpades(), ThreeOfHearts(), ThreeOfDiamonds(), DeuceOfSpades(), DeuceOfHearts(), } phB, err := handB.PokerHand() assert.NoError(t, err, "Expected no error") threesFullOfDeucesScore := phB.Score assert.Greater(t, threesFullOfDeucesScore, deucesFullOfAcesScore, "Expected Threes full of deuces to beat deuces full of aces") }) }