This commit is contained in:
Jeffrey Paul 2026-01-06 10:13:38 -08:00
parent e26b79751f
commit 8dbfc45ebb
7 changed files with 394 additions and 291 deletions

View File

@ -4,9 +4,9 @@ import (
"fmt" "fmt"
"time" "time"
"git.eeqj.de/sneak/pokercore"
"github.com/rcrowley/go-metrics" "github.com/rcrowley/go-metrics"
"github.com/schollz/progressbar/v3" "github.com/schollz/progressbar/v3"
"sneak.berlin/go/pokercore"
) )
var gameCount = 50_000 var gameCount = 50_000
@ -101,13 +101,16 @@ func main() {
timer := metrics.NewTimer() timer := metrics.NewTimer()
registry.Register("pokerGame", timer) registry.Register("pokerGame", timer)
bar := progressbar.NewOptions(gameCount, bar := progressbar.NewOptions(
gameCount,
progressbar.OptionSetDescription("Gambling..."), progressbar.OptionSetDescription("Gambling..."),
progressbar.OptionShowCount(), progressbar.OptionShowCount(),
progressbar.OptionShowIts(), progressbar.OptionShowIts(),
progressbar.OptionSetPredictTime(true), progressbar.OptionSetPredictTime(true),
progressbar.OptionClearOnFinish(), progressbar.OptionClearOnFinish(),
progressbar.OptionThrottle(100*time.Millisecond), // Update every 100ms progressbar.OptionThrottle(
100*time.Millisecond,
), // Update every 100ms
) )
for i := 0; i < gameCount; i++ { for i := 0; i < gameCount; i++ {
@ -128,11 +131,13 @@ func main() {
fmt.Printf("Max: %d ns\n", timer.Max()) fmt.Printf("Max: %d ns\n", timer.Max())
fmt.Printf("Mean: %0.2f ns\n", timer.Mean()) fmt.Printf("Mean: %0.2f ns\n", timer.Mean())
fmt.Printf("StdDev: %0.2f ns\n", timer.StdDev()) fmt.Printf("StdDev: %0.2f ns\n", timer.StdDev())
fmt.Printf("Percentiles: 50%%: %0.2f ns, 75%%: %0.2f ns, 95%%: %0.2f ns, 99%%: %0.2f ns\n", fmt.Printf(
"Percentiles: 50%%: %0.2f ns, 75%%: %0.2f ns, 95%%: %0.2f ns, 99%%: %0.2f ns\n",
timer.Percentile(0.50), timer.Percentile(0.50),
timer.Percentile(0.75), timer.Percentile(0.75),
timer.Percentile(0.95), timer.Percentile(0.95),
timer.Percentile(0.99)) timer.Percentile(0.99),
)
oneWinPercentage := float64(oneWins) / float64(gameCount) * 100 oneWinPercentage := float64(oneWins) / float64(gameCount) * 100
twoWinPercentage := float64(twoWins) / float64(gameCount) * 100 twoWinPercentage := float64(twoWins) / float64(gameCount) * 100
fmt.Printf("Player 1 won: %d (%0.2f%%)\n", oneWins, oneWinPercentage) fmt.Printf("Player 1 won: %d (%0.2f%%)\n", oneWins, oneWinPercentage)

56
examples/sf/main.go Normal file
View File

@ -0,0 +1,56 @@
package main
import (
"fmt"
"sneak.berlin/go/pokercore"
)
func main() {
var sfp bool
var tries int
var found int
const maxTries = 100_000_000
for i := 0; i < maxTries; i++ {
sfp = searchStraightFlush()
if sfp {
found++
}
tries++
if tries%1000 == 0 {
fmt.Printf("Tries: %d, Found: %d\n", tries, found)
}
}
fmt.Printf("Tries: %d, Found: %d\n", tries, found)
}
func searchStraightFlush() bool {
d := pokercore.NewDeck()
d.ShuffleRandomly()
var hand pokercore.Cards
hand = d.Deal(7)
ph, err := hand.PokerHand()
if err != nil {
fmt.Println("Error: ", err)
return false
}
if ph.Type == pokercore.StraightFlush ||
ph.Type == pokercore.RoyalFlush {
fmt.Println("straight flush found")
fmt.Println("Hand: ", hand.FormatForTerminal())
fmt.Println("PokerHand: ", ph)
return true
}
return false
}

4
go.mod
View File

@ -1,14 +1,14 @@
module git.eeqj.de/sneak/pokercore module sneak.berlin/go/pokercore
go 1.22.2 go 1.22.2
require ( require (
git.eeqj.de/sneak/timingbench v0.0.0-20240519025145-fb13c5c56a02
github.com/logrusorgru/aurora/v4 v4.0.0 github.com/logrusorgru/aurora/v4 v4.0.0
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475
github.com/schollz/progressbar/v3 v3.14.2 github.com/schollz/progressbar/v3 v3.14.2
github.com/sirupsen/logrus v1.9.3 github.com/sirupsen/logrus v1.9.3
github.com/stretchr/testify v1.8.0 github.com/stretchr/testify v1.8.0
sneak.berlin/go/timingbench v0.0.0-20240522212031-a6243a470213
) )
require ( require (

4
go.sum
View File

@ -1,5 +1,3 @@
git.eeqj.de/sneak/timingbench v0.0.0-20240519025145-fb13c5c56a02 h1:b/v1EDAlsfvINIeV4znI/vH7SY7mUJOO1KWeBD+IW90=
git.eeqj.de/sneak/timingbench v0.0.0-20240519025145-fb13c5c56a02/go.mod h1:iKAlgt/liDtXifmn7fPJK+KYMr0c4lXYFJ+j5d3gfEQ=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@ -43,3 +41,5 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
sneak.berlin/go/timingbench v0.0.0-20240522212031-a6243a470213 h1:jgfwL2lUUp6aII87vgkgFenfKftsbKvUR3jlsRdS2yo=
sneak.berlin/go/timingbench v0.0.0-20240522212031-a6243a470213/go.mod h1:W+0S+VhiuNIU/06KPhWJCmNhMaCztg2MuHitNEVEFG0=

View File

@ -5,11 +5,12 @@ import (
"testing" "testing"
"time" "time"
"git.eeqj.de/sneak/timingbench"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"sneak.berlin/go/timingbench"
) )
func TestShuffleSpeed(t *testing.T) { func TestShuffleSpeed(t *testing.T) {
t.Parallel()
iterations := 1000 iterations := 1000
t.Logf("Running %d iterations of shuffle speed test", iterations) t.Logf("Running %d iterations of shuffle speed test", iterations)
// Create a context with a timeout for cancellation. // Create a context with a timeout for cancellation.
@ -27,18 +28,21 @@ func TestShuffleSpeed(t *testing.T) {
} }
func TestHandFindingSpeedFiveCard(t *testing.T) { func TestHandFindingSpeedFiveCard(t *testing.T) {
t.Parallel()
iterations := 1000 iterations := 1000
t.Logf("Running %d iterations of hand finding speed test for 5 card hand", iterations) t.Logf("Running %d iterations of hand finding speed test for 5 card hand", iterations)
measureHandFinding(t, iterations, 5) measureHandFinding(t, iterations, 5)
} }
func TestHandFindingSpeedSevenCard(t *testing.T) { func TestHandFindingSpeedSevenCard(t *testing.T) {
t.Parallel()
iterations := 1000 iterations := 1000
t.Logf("Running %d iterations of hand finding speed test for 7 card hand", iterations) t.Logf("Running %d iterations of hand finding speed test for 7 card hand", iterations)
measureHandFinding(t, iterations, 7) measureHandFinding(t, iterations, 7)
} }
func TestHandFindingSpeedNineCard(t *testing.T) { func TestHandFindingSpeedNineCard(t *testing.T) {
t.Parallel()
iterations := 100 iterations := 100
t.Logf("Running %d iterations of hand finding speed test for 9 card hand", iterations) t.Logf("Running %d iterations of hand finding speed test for 9 card hand", iterations)
measureHandFinding(t, iterations, 9) measureHandFinding(t, iterations, 9)

View File

@ -12,6 +12,7 @@ type ShuffleTestResults []struct {
} }
func TestPokerDeck(t *testing.T) { func TestPokerDeck(t *testing.T) {
t.Parallel()
d := NewDeck() d := NewDeck()
//fmt.Printf("newdeck: %+v\n", d) //fmt.Printf("newdeck: %+v\n", d)
d.ShuffleDeterministically(437) d.ShuffleDeterministically(437)
@ -35,6 +36,7 @@ func TestPokerDeck(t *testing.T) {
} }
func TestDealing(t *testing.T) { func TestDealing(t *testing.T) {
t.Parallel()
d := NewDeckFromCards(Cards{ d := NewDeckFromCards(Cards{
Card{Rank: ACE, Suit: HEART}, Card{Rank: ACE, Suit: HEART},
Card{Rank: DEUCE, Suit: HEART}, Card{Rank: DEUCE, Suit: HEART},
@ -50,6 +52,7 @@ func TestDealing(t *testing.T) {
} }
func TestSpecialCaseOfFiveHighStraightFlush(t *testing.T) { func TestSpecialCaseOfFiveHighStraightFlush(t *testing.T) {
t.Parallel()
// actual bug from first implementation // actual bug from first implementation
d := NewDeckFromCards(Cards{ d := NewDeckFromCards(Cards{
Card{Rank: ACE, Suit: HEART}, Card{Rank: ACE, Suit: HEART},
@ -68,6 +71,7 @@ func TestSpecialCaseOfFiveHighStraightFlush(t *testing.T) {
} }
func TestSpecialCaseOfFiveHighStraight(t *testing.T) { func TestSpecialCaseOfFiveHighStraight(t *testing.T) {
t.Parallel()
// actual bug from first implementation // actual bug from first implementation
d := NewDeckFromCards(Cards{ d := NewDeckFromCards(Cards{
Card{Rank: ACE, Suit: HEART}, Card{Rank: ACE, Suit: HEART},

View File

@ -6,15 +6,16 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func TestHandDescripionBug(t *testing.T) { func TestHandDescriptionBug(t *testing.T) {
t.Parallel()
playerCount := 8 playerCount := 8
d := NewDeck() d := NewDeck()
d.ShuffleDeterministically(1337) d.ShuffleDeterministically(1337)
players := make([]*Cards, playerCount) players := make([]*Cards, playerCount)
for i := 1; i-1 < playerCount; i++ { for i := 0; i < playerCount; i++ {
c := d.Deal(2) c := d.Deal(2)
players[i-1] = &c players[i] = &c
t.Logf("Player %d dealt: %+v\n", i, c) t.Logf("Player %d dealt: %+v\n", i+1, c)
} }
t.Logf("Players: %+v\n", players) t.Logf("Players: %+v\n", players)
@ -23,17 +24,17 @@ func TestHandDescripionBug(t *testing.T) {
var playerResults []*PokerHand var playerResults []*PokerHand
for i := 1; i-1 < playerCount; i++ { for i := 0; i < playerCount; i++ {
t.Logf("Player %d hole cards: %+v\n", i, *players[i-1]) t.Logf("Player %d hole cards: %+v\n", i+1, *players[i])
pc := append(*players[i-1], community...) pc := append(*players[i], community...)
t.Logf("Player %d cards available: %+v\n", i, pc) t.Logf("Player %d cards available: %+v\n", i+1, pc)
hand, err := pc.IdentifyBestFiveCardPokerHand() hand, err := pc.IdentifyBestFiveCardPokerHand()
assert.Nil(t, err, "Expected no error") assert.NoError(t, err, "Expected no error")
ph, err := hand.PokerHand() ph, err := hand.PokerHand()
assert.Nil(t, err, "Expected no error") assert.NoError(t, err, "Expected no error")
t.Logf("Player %d five cards used: %+v\n", i, hand) t.Logf("Player %d five cards used: %+v\n", i+1, hand)
t.Logf("Player %d poker hand: %+v\n", i, ph) t.Logf("Player %d poker hand: %+v\n", i+1, ph)
t.Logf("Player %d best hand description: %s\n", i, ph.Description()) t.Logf("Player %d best hand description: %s\n", i+1, ph.Description())
playerResults = append(playerResults, ph) playerResults = append(playerResults, ph)
} }
@ -43,30 +44,31 @@ func TestHandDescripionBug(t *testing.T) {
t.Logf("Weird one description: %s\n", weirdOne.Description()) t.Logf("Weird one description: %s\n", weirdOne.Description())
// T♠,7♠,9♦,7♣,T♥ // T♠,7♠,9♦,7♣,T♥
assert.Equal(t, weirdOne.Description(), "two pair, tens and sevens with a nine") assert.Equal(t, "two pair, tens and sevens with a nine", weirdOne.Description())
scoreShouldBe := ScoreTwoPair scoreShouldBe := ScoreTwoPair
scoreShouldBe += 10000 * TEN.Score() scoreShouldBe += 10000 * TEN.Score()
scoreShouldBe += 100 * SEVEN.Score() scoreShouldBe += 100 * SEVEN.Score()
scoreShouldBe += NINE.Score() scoreShouldBe += NINE.Score()
assert.Equal(t, weirdOne.Score, scoreShouldBe) assert.Equal(t, scoreShouldBe, weirdOne.Score)
cards := weirdOne.Hand cards := weirdOne.Hand
assert.True(t, cards.containsTwoPair(), "Expected hand to be two pair") assert.True(t, cards.containsTwoPair(), "Expected hand to be two pair")
bp := cards.twoPairBiggestPair() // returns Rank, because describing a pair bp := cards.twoPairBiggestPair() // returns Rank, because describing a pair
assert.Equal(t, bp, TEN, "Expected biggest pair to be a ten") assert.Equal(t, TEN, bp, "Expected biggest pair to be a ten")
sp := cards.twoPairSmallestPair() // returns Rank, because describing a pair sp := cards.twoPairSmallestPair() // returns Rank, because describing a pair
assert.Equal(t, sp, SEVEN, "Expected smallest pair to be a seven") assert.Equal(t, SEVEN, sp, "Expected smallest pair to be a seven")
k := cards.twoPairKicker() // returns Card, because describing a single card k := cards.twoPairKicker() // returns Card, because describing a single card
assert.Equal(t, k.Rank, NINE, "Expected kicker to be a nine") assert.Equal(t, NINE, k.Rank, "Expected kicker to be a nine")
} }
func TestAceLowStraight(t *testing.T) { func TestAceLowStraight(t *testing.T) {
t.Parallel()
t.Run("Test Ace-Low Straight", func(t *testing.T) {
hand := Cards{ hand := Cards{
AceOfSpades(), AceOfSpades(),
DeuceOfHearts(), DeuceOfHearts(),
@ -76,22 +78,25 @@ func TestAceLowStraight(t *testing.T) {
} }
assert.True(t, hand.containsStraight(), "Expected hand to be a straight") assert.True(t, hand.containsStraight(), "Expected hand to be a straight")
ph, err := hand.PokerHand() ph, err := hand.PokerHand()
assert.Nil(t, err, "Expected no error") assert.NoError(t, err, "Expected no error")
assert.Greater(t, ph.Score, 0, "Expected score to be greater than 0") 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.Less(t, ph.Score, 100000000000000000, "Expected score to be less than 100000000000000000")
assert.Equal(t, ph.Score, ScoreStraight+FIVE.Score()) assert.Equal(t, ph.Score, ScoreStraight+FIVE.Score())
assert.Equal(t, ph.Description(), "a five high straight") assert.Equal(t, "a five high straight", ph.Description())
assert.True(t, hand.HighestRank() == ACE, "Expected highest rank to be an ace") assert.Equal(t, ACE, hand.HighestRank(), "Expected highest rank to be an ace")
s := hand.SortByRankAscending() s := hand.SortByRankAscending()
assert.True(t, s.First().Rank == DEUCE, "Expected first card to be a deuce") assert.Equal(t, DEUCE, s.First().Rank, "Expected first card to be a deuce")
assert.True(t, s.Last().Rank == ACE, "Expected last card in sorted to be a ace") assert.Equal(t, ACE, s.Last().Rank, "Expected last card in sorted to be an ace")
assert.True(t, s.Second().Rank == THREE, "Expected second card to be a three") assert.Equal(t, THREE, s.Second().Rank, "Expected second card to be a three")
assert.True(t, s.Third().Rank == FOUR, "Expected third card to be a four") assert.Equal(t, FOUR, s.Third().Rank, "Expected third card to be a four")
assert.True(t, s.Fourth().Rank == FIVE, "Expected fourth card to be a five") assert.Equal(t, FIVE, s.Fourth().Rank, "Expected fourth card to be a five")
assert.True(t, s.Fifth().Rank == ACE, "Expected fifth card to be an ace") assert.Equal(t, ACE, s.Fifth().Rank, "Expected fifth card to be an ace")
})
} }
func TestAceHighStraight(t *testing.T) { func TestAceHighStraight(t *testing.T) {
t.Parallel()
t.Run("Test Ace-High Straight", func(t *testing.T) {
hand := Cards{ hand := Cards{
TenOfSpades(), TenOfSpades(),
JackOfHearts(), JackOfHearts(),
@ -105,16 +110,19 @@ func TestAceHighStraight(t *testing.T) {
newDeck.ShuffleDeterministically(123456789) newDeck.ShuffleDeterministically(123456789)
shuffledHand := newDeck.Deal(5) shuffledHand := newDeck.Deal(5)
assert.True(t, shuffledHand.containsStraight(), "Expected hand to still be a straight after shuffle") assert.True(t, shuffledHand.containsStraight(), "Expected hand to still be a straight after shuffle")
assert.True(t, shuffledHand.HighestRank() == ACE, "Expected highest rank to be an ace") assert.Equal(t, ACE, shuffledHand.HighestRank(), "Expected highest rank to be an ace")
sortedHand := shuffledHand.SortByRankAscending() sortedHand := shuffledHand.SortByRankAscending()
assert.True(t, sortedHand[0].Rank == TEN, "Expected lowest rank to be a ten") assert.Equal(t, TEN, sortedHand[0].Rank, "Expected lowest rank to be a ten")
assert.True(t, sortedHand[1].Rank == JACK, "Expected second lowest rank to be a jack") assert.Equal(t, JACK, sortedHand[1].Rank, "Expected second lowest rank to be a jack")
assert.True(t, sortedHand[2].Rank == QUEEN, "Expected third lowest rank to be a queen") assert.Equal(t, QUEEN, sortedHand[2].Rank, "Expected third lowest rank to be a queen")
assert.True(t, sortedHand[3].Rank == KING, "Expected fourth lowest rank to be a king") assert.Equal(t, KING, sortedHand[3].Rank, "Expected fourth lowest rank to be a king")
assert.True(t, sortedHand[4].Rank == ACE, "Expected highest rank to be an ace") assert.Equal(t, ACE, sortedHand[4].Rank, "Expected highest rank to be an ace")
})
} }
func TestOtherStraight(t *testing.T) { func TestOtherStraight(t *testing.T) {
t.Parallel()
t.Run("Test Other Straight", func(t *testing.T) {
hand := Cards{ hand := Cards{
DeuceOfSpades(), DeuceOfSpades(),
ThreeOfHearts(), ThreeOfHearts(),
@ -126,17 +134,18 @@ func TestOtherStraight(t *testing.T) {
newDeck := NewDeckFromCards(hand) newDeck := NewDeckFromCards(hand)
newDeck.ShuffleDeterministically(123456789) newDeck.ShuffleDeterministically(123456789)
//fmt.Printf("Shuffled deck: %s\n", newDeck.String())
//fmt.Printf("new deck has %d cards\n", newDeck.Count())
shuffledHand := newDeck.Deal(5) shuffledHand := newDeck.Deal(5)
assert.True(t, shuffledHand.containsStraight(), "Expected hand to still be a straight after shuffle") 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.containsTwoPair(), "Expected hand to not be two pair")
assert.False(t, shuffledHand.containsPair(), "Expected hand to not be a pair") assert.False(t, shuffledHand.containsPair(), "Expected hand to not be a pair")
assert.True(t, shuffledHand.HighestRank() == SIX, "Expected highest rank to be a six") assert.Equal(t, SIX, shuffledHand.HighestRank(), "Expected highest rank to be a six")
assert.True(t, shuffledHand.SortByRankAscending().First().Rank == DEUCE, "Expected first card to be a deuce") assert.Equal(t, DEUCE, shuffledHand.SortByRankAscending().First().Rank, "Expected first card to be a deuce")
})
} }
func TestFlush(t *testing.T) { func TestFlush(t *testing.T) {
t.Parallel()
t.Run("Test Flush", func(t *testing.T) {
hand := Cards{ hand := Cards{
AceOfSpades(), AceOfSpades(),
DeuceOfSpades(), DeuceOfSpades(),
@ -147,8 +156,6 @@ func TestFlush(t *testing.T) {
assert.True(t, hand.containsFlush(), "Expected hand to be a flush") assert.True(t, hand.containsFlush(), "Expected hand to be a flush")
newDeck := NewDeckFromCards(hand) newDeck := NewDeckFromCards(hand)
newDeck.ShuffleDeterministically(123456789) newDeck.ShuffleDeterministically(123456789)
//fmt.Printf("Shuffled deck: %s\n", newDeck.String())
//fmt.Printf("new deck has %d cards\n", newDeck.Count())
shuffledHand := newDeck.Deal(5) shuffledHand := newDeck.Deal(5)
assert.True(t, shuffledHand.containsFlush(), "Expected hand to still be a flush after shuffle") assert.True(t, shuffledHand.containsFlush(), "Expected hand to still be a flush after shuffle")
@ -159,15 +166,17 @@ func TestFlush(t *testing.T) {
x += THREE.Score() x += THREE.Score()
x += FOUR.Score() x += FOUR.Score()
x += SIX.Score() x += SIX.Score()
//fmt.Printf("a-2-3-4-6 flush score should be: %d\n", x)
ph, err := shuffledHand.PokerHand() ph, err := shuffledHand.PokerHand()
assert.Nil(t, err, "Expected no error") assert.NoError(t, err, "Expected no error")
assert.Greater(t, ph.Score, 0, "Expected score to be nonzero 0") assert.Greater(t, ph.Score, 0, "Expected score to be nonzero")
assert.Equal(t, ph.Score, x) assert.Equal(t, ph.Score, x)
})
} }
func TestStraightFlush(t *testing.T) { func TestStraightFlush(t *testing.T) {
t.Parallel()
t.Run("Test Straight Flush", func(t *testing.T) {
hand := Cards{ hand := Cards{
SixOfSpades(), SixOfSpades(),
DeuceOfSpades(), DeuceOfSpades(),
@ -185,19 +194,20 @@ 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() == SIX, "Expected highest rank to be a six") assert.Equal(t, SIX, hand.HighestRank(), "Expected highest rank to be a six")
nd := NewDeckFromCards(hand) nd := NewDeckFromCards(hand)
nd.ShuffleDeterministically(123456789) nd.ShuffleDeterministically(123456789)
//fmt.Printf("Shuffled deck: %s\n", nd.String())
//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() == SIX, "Expected highest rank to still be a six after shuffle") assert.Equal(t, SIX, shuffledHand.HighestRank(), "Expected highest rank to still be a six after shuffle")
assert.True(t, shuffledHand.HighestRank() == SIX, "Expected highest rank to be a six after shuffle even with aces low") assert.Equal(t, SIX, shuffledHand.HighestRank(), "Expected highest rank to be a six after shuffle even with aces low")
})
} }
func TestFourOfAKind(t *testing.T) { func TestFourOfAKind(t *testing.T) {
t.Parallel()
t.Run("Test Four of a Kind", func(t *testing.T) {
hand := Cards{ hand := Cards{
SixOfSpades(), SixOfSpades(),
SixOfHearts(), SixOfHearts(),
@ -223,10 +233,13 @@ func TestFourOfAKind(t *testing.T) {
assert.True(t, hand.containsTwoPair(), "Expected hand to contain two pair") assert.True(t, hand.containsTwoPair(), "Expected hand to contain two pair")
assert.True(t, hand.containsPair(), "Expected hand to contain a pair") assert.True(t, hand.containsPair(), "Expected hand to contain a pair")
assert.True(t, hand.HighestRank() == SIX, "Expected highest rank to be a six") assert.Equal(t, SIX, hand.HighestRank(), "Expected highest rank to be a six")
})
} }
func TestRoyalFlush(t *testing.T) { func TestRoyalFlush(t *testing.T) {
t.Parallel()
t.Run("Test Royal Flush", func(t *testing.T) {
hand := Cards{ hand := Cards{
TenOfSpades(), TenOfSpades(),
JackOfSpades(), JackOfSpades(),
@ -245,11 +258,14 @@ 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() == ACE, "Expected highest rank to be an ace") assert.Equal(t, ACE, hand.HighestRank(), "Expected highest rank to be an ace")
assert.False(t, hand.HighestRank() == TEN, "Expected highest rank to not be an ace") assert.NotEqual(t, TEN, hand.HighestRank(), "Expected highest rank to not be a ten")
})
} }
func TestUnmadeHand(t *testing.T) { func TestUnmadeHand(t *testing.T) {
t.Parallel()
t.Run("Test Unmade Hand", func(t *testing.T) {
hand := Cards{ hand := Cards{
TenOfSpades(), TenOfSpades(),
JackOfDiamonds(), JackOfDiamonds(),
@ -266,11 +282,14 @@ 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() == KING, "Expected highest rank to be a king") assert.Equal(t, KING, hand.HighestRank(), "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")
})
} }
func TestTwoPair(t *testing.T) { func TestTwoPair(t *testing.T) {
t.Parallel()
t.Run("Test Two Pair", func(t *testing.T) {
hand := Cards{ hand := Cards{
KingOfSpades(), KingOfSpades(),
JackOfDiamonds(), JackOfDiamonds(),
@ -287,11 +306,14 @@ 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() == KING, "Expected highest rank to be a king") assert.Equal(t, KING, hand.HighestRank(), "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 TestDetectDuplicates(t *testing.T) { func TestDetectDuplicates(t *testing.T) {
t.Parallel()
t.Run("Test Detect Duplicates", func(t *testing.T) {
hand := Cards{ hand := Cards{
KingOfSpades(), KingOfSpades(),
JackOfDiamonds(), JackOfDiamonds(),
@ -300,9 +322,12 @@ func TestDetectDuplicates(t *testing.T) {
TenOfSpades(), TenOfSpades(),
} }
assert.True(t, hand.containsDuplicates(), "Expected hand to contain duplicates") assert.True(t, hand.containsDuplicates(), "Expected hand to contain duplicates")
})
} }
func TestHandScore(t *testing.T) { func TestHandScore(t *testing.T) {
t.Parallel()
t.Run("Test Hand Score", func(t *testing.T) {
hand := Cards{ hand := Cards{
KingOfSpades(), KingOfSpades(),
JackOfDiamonds(), JackOfDiamonds(),
@ -311,33 +336,33 @@ func TestHandScore(t *testing.T) {
TenOfSpades(), TenOfSpades(),
} }
ph, error := hand.PokerHand() ph, err := hand.PokerHand()
assert.Nil(t, error, "Expected no error") assert.NoError(t, err, "Expected no error")
assert.True(t, ph.Score > 0, "Expected score to be nonzero 0") assert.True(t, ph.Score > 0, "Expected score to be nonzero")
assert.True(t, ph.Score < 100000000000000000, "Expected score to be less than 100000000000000000") assert.True(t, ph.Score < 100000000000000000, "Expected score to be less than 100000000000000000")
// write more assertions FIXME
//fmt.Printf("PokerHand: %v+\n", ph) })
//fmt.Printf("PH score: %d\n", ph.Score)
} }
func TestTwoPairBug(t *testing.T) { 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 // this is an actual bug in the first implementation
c, err := NewCardsFromString("9♠,9♣,Q♥,Q♦,K♣") c, err := NewCardsFromString("9♠,9♣,Q♥,Q♦,K♣")
assert.Nil(t, err, "Expected no error") assert.NoError(t, err, "Expected no error")
//fmt.Printf("Cards: %v+\n", c)
ph, err := c.PokerHand() ph, err := c.PokerHand()
assert.Nil(t, err, "Expected no error") assert.NoError(t, err, "Expected no error")
assert.Greater(t, ph.Score, 0, "Expected score to be nonzero 0") assert.Greater(t, ph.Score, 0, "Expected score to be nonzero")
desc := ph.Description() desc := ph.Description()
assert.Equal(t, desc, "two pair, queens and nines with a king") assert.Equal(t, "two pair, queens and nines with a king", desc)
})
//fmt.Printf("PokerHand: %v+\n", ph)
//fmt.Printf("PH score: %d\n", ph.Score)
} }
func TestScoringStructureQuads(t *testing.T) { 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{ handA := Cards{
DeuceOfSpades(), DeuceOfSpades(),
DeuceOfHearts(), DeuceOfHearts(),
@ -355,13 +380,21 @@ func TestScoringStructureQuads(t *testing.T) {
} }
phA, err := handA.PokerHand() phA, err := handA.PokerHand()
assert.Nil(t, err, "Expected no error") assert.NoError(t, err, "Expected no error")
phB, err := handB.PokerHand() phB, err := handB.PokerHand()
assert.Nil(t, err, "Expected no error") assert.NoError(t, err, "Expected no error")
assert.Greater(t, phB.Score, phA.Score, "Expected hand B to be higher than hand A") assert.Greater(t, phB.Score, phA.Score, "Expected hand B to be higher than hand A")
})
} }
func TestScoringStructureFullHouse(t *testing.T) { 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{ handA := Cards{
DeuceOfSpades(), DeuceOfSpades(),
DeuceOfHearts(), DeuceOfHearts(),
@ -371,7 +404,7 @@ func TestScoringStructureFullHouse(t *testing.T) {
} }
phA, err := handA.PokerHand() phA, err := handA.PokerHand()
assert.Nil(t, err, "Expected no error") assert.NoError(t, err, "Expected no error")
deucesFullOfAcesScore := phA.Score deucesFullOfAcesScore := phA.Score
handB := Cards{ handB := Cards{
@ -382,8 +415,9 @@ func TestScoringStructureFullHouse(t *testing.T) {
DeuceOfHearts(), DeuceOfHearts(),
} }
phB, err := handB.PokerHand() phB, err := handB.PokerHand()
assert.Nil(t, err, "Expected no error") assert.NoError(t, err, "Expected no error")
threesFullOfDeucesScore := phB.Score threesFullOfDeucesScore := phB.Score
assert.Greater(t, threesFullOfDeucesScore, deucesFullOfAcesScore, "Expected Threes full of deuces to beat deuces full of aces") assert.Greater(t, threesFullOfDeucesScore, deucesFullOfAcesScore, "Expected Threes full of deuces to beat deuces full of aces")
})
} }