Compare commits
No commits in common. "8dbfc45ebb2e30009e184ce806d8d77d2516bd8c" and "ab92f29a88189da85476ba5658f971879086fddd" have entirely different histories.
8dbfc45ebb
...
ab92f29a88
154
card.go
154
card.go
@ -7,7 +7,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
aurora "github.com/logrusorgru/aurora/v4"
|
"github.com/logrusorgru/aurora/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Card struct {
|
type Card struct {
|
||||||
@ -19,52 +19,55 @@ func NewCardFromString(card string) (Card, error) {
|
|||||||
// FIXME extend this later to common format strings like "9s"
|
// FIXME extend this later to common format strings like "9s"
|
||||||
length := utf8.RuneCountInString(card)
|
length := utf8.RuneCountInString(card)
|
||||||
if length != 2 {
|
if length != 2 {
|
||||||
return Card{}, fmt.Errorf("invalid card string %s, must be 2 characters", card)
|
return Card{}, fmt.Errorf("Invalid card string %s", card)
|
||||||
}
|
}
|
||||||
|
|
||||||
rankMap := map[rune]Rank{
|
|
||||||
rune(DEUCE): DEUCE,
|
|
||||||
rune(THREE): THREE,
|
|
||||||
rune(FOUR): FOUR,
|
|
||||||
rune(FIVE): FIVE,
|
|
||||||
rune(SIX): SIX,
|
|
||||||
rune(SEVEN): SEVEN,
|
|
||||||
rune(EIGHT): EIGHT,
|
|
||||||
rune(NINE): NINE,
|
|
||||||
rune(TEN): TEN,
|
|
||||||
rune(JACK): JACK,
|
|
||||||
rune(QUEEN): QUEEN,
|
|
||||||
rune(KING): KING,
|
|
||||||
rune(ACE): ACE,
|
|
||||||
}
|
|
||||||
|
|
||||||
suitMap := map[rune]Suit{
|
|
||||||
rune(SPADE): SPADE,
|
|
||||||
rune(HEART): HEART,
|
|
||||||
rune(DIAMOND): DIAMOND,
|
|
||||||
rune(CLUB): CLUB,
|
|
||||||
}
|
|
||||||
|
|
||||||
var rank Rank
|
var rank Rank
|
||||||
var suit Suit
|
var suit Suit
|
||||||
for r := range rankMap {
|
if strings.ContainsRune(card, rune(SPADE)) {
|
||||||
if strings.ContainsRune(card, r) {
|
suit = Suit(SPADE)
|
||||||
rank = rankMap[r]
|
} else if strings.ContainsRune(card, rune(HEART)) {
|
||||||
break
|
suit = Suit(HEART)
|
||||||
}
|
} else if strings.ContainsRune(card, rune(DIAMOND)) {
|
||||||
|
suit = Suit(DIAMOND)
|
||||||
|
} else if strings.ContainsRune(card, rune(CLUB)) {
|
||||||
|
suit = Suit(CLUB)
|
||||||
|
} else {
|
||||||
|
return Card{}, fmt.Errorf("Invalid card string %s", card)
|
||||||
}
|
}
|
||||||
|
|
||||||
for s := range suitMap {
|
if strings.ContainsRune(card, rune(DEUCE)) {
|
||||||
if strings.ContainsRune(card, s) {
|
rank = Rank(DEUCE)
|
||||||
suit = suitMap[s]
|
} else if strings.ContainsRune(card, rune(THREE)) {
|
||||||
break
|
rank = Rank(THREE)
|
||||||
}
|
} else if strings.ContainsRune(card, rune(FOUR)) {
|
||||||
|
rank = Rank(FOUR)
|
||||||
|
} else if strings.ContainsRune(card, rune(FIVE)) {
|
||||||
|
rank = Rank(FIVE)
|
||||||
|
} else if strings.ContainsRune(card, rune(SIX)) {
|
||||||
|
rank = Rank(SIX)
|
||||||
|
} else if strings.ContainsRune(card, rune(SEVEN)) {
|
||||||
|
rank = Rank(SEVEN)
|
||||||
|
} else if strings.ContainsRune(card, rune(EIGHT)) {
|
||||||
|
rank = Rank(EIGHT)
|
||||||
|
} else if strings.ContainsRune(card, rune(NINE)) {
|
||||||
|
rank = Rank(NINE)
|
||||||
|
} else if strings.ContainsRune(card, rune(TEN)) {
|
||||||
|
rank = Rank(TEN)
|
||||||
|
} else if strings.ContainsRune(card, rune(JACK)) {
|
||||||
|
rank = Rank(JACK)
|
||||||
|
} else if strings.ContainsRune(card, rune(QUEEN)) {
|
||||||
|
rank = Rank(QUEEN)
|
||||||
|
} else if strings.ContainsRune(card, rune(KING)) {
|
||||||
|
rank = Rank(KING)
|
||||||
|
} else if strings.ContainsRune(card, rune(ACE)) {
|
||||||
|
rank = Rank(ACE)
|
||||||
|
} else {
|
||||||
|
return Card{}, fmt.Errorf("Invalid card string %s", card)
|
||||||
}
|
}
|
||||||
|
|
||||||
if rank == Rank(0) || suit == Suit(0) {
|
if rank == Rank(0) || suit == Suit(0) {
|
||||||
return Card{}, fmt.Errorf("invalid card string %s", card)
|
return Card{}, fmt.Errorf("Invalid card string %s", card)
|
||||||
}
|
}
|
||||||
|
|
||||||
return Card{Rank: rank, Suit: suit}, nil
|
return Card{Rank: rank, Suit: suit}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,17 +75,18 @@ func NewCardsFromString(cards string) (Cards, error) {
|
|||||||
// supports a string like 9♠,9♣,Q♥,Q♦,K♣
|
// supports a string like 9♠,9♣,Q♥,Q♦,K♣
|
||||||
// FIXME extend this later to common format strings like "9c Qh Qd Kc"
|
// FIXME extend this later to common format strings like "9c Qh Qd Kc"
|
||||||
// with or without commas
|
// with or without commas
|
||||||
|
var newCards Cards
|
||||||
|
newCards = make(Cards, 0)
|
||||||
cardStrings := strings.Split(cards, ",")
|
cardStrings := strings.Split(cards, ",")
|
||||||
newCards := make(Cards, len(cardStrings))
|
for _, cardString := range cardStrings {
|
||||||
for i, cardString := range cardStrings {
|
|
||||||
card, err := NewCardFromString(cardString)
|
card, err := NewCardFromString(cardString)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return Cards{}, err
|
||||||
}
|
}
|
||||||
newCards[i] = card
|
newCards = append(newCards, card)
|
||||||
}
|
}
|
||||||
if len(newCards) == 0 {
|
if len(newCards) == 0 {
|
||||||
return nil, fmt.Errorf("no cards found in string %s", cards)
|
return Cards{}, fmt.Errorf("No cards found in string %s", cards)
|
||||||
}
|
}
|
||||||
return newCards, nil
|
return newCards, nil
|
||||||
}
|
}
|
||||||
@ -93,41 +97,42 @@ func (c *Card) String() string {
|
|||||||
|
|
||||||
type Cards []Card
|
type Cards []Card
|
||||||
|
|
||||||
func (cards Cards) First() Card {
|
func (c Cards) First() Card {
|
||||||
return cards[0]
|
return c[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cards Cards) Second() Card {
|
func (c Cards) Second() Card {
|
||||||
return cards[1]
|
return c[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cards Cards) Third() Card {
|
func (c Cards) Third() Card {
|
||||||
return cards[2]
|
return c[2]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cards Cards) Fourth() Card {
|
func (c Cards) Fourth() Card {
|
||||||
return cards[3]
|
return c[3]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cards Cards) Fifth() Card {
|
func (c Cards) Fifth() Card {
|
||||||
return cards[4]
|
return c[4]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cards Cards) Last() Card {
|
func (c Cards) Last() Card {
|
||||||
return cards[len(cards)-1]
|
return c[len(c)-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cards Cards) SortByRankAscending() Cards {
|
func (c Cards) SortByRankAscending() Cards {
|
||||||
sortedCards := make(Cards, len(cards))
|
newCards := make(Cards, len(c))
|
||||||
copy(sortedCards, cards)
|
copy(newCards, c)
|
||||||
sort.Slice(sortedCards, func(i, j int) bool {
|
sort.Slice(newCards, func(i, j int) bool {
|
||||||
return sortedCards[i].Rank.Score() < sortedCards[j].Rank.Score()
|
return newCards[i].Rank.Score() < newCards[j].Rank.Score()
|
||||||
})
|
})
|
||||||
return sortedCards
|
|
||||||
|
return newCards
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cards Cards) PrintToTerminal() {
|
func (c Cards) PrintToTerminal() {
|
||||||
fmt.Printf("%s", cards.FormatForTerminal())
|
fmt.Printf("%s", c.FormatForTerminal())
|
||||||
}
|
}
|
||||||
|
|
||||||
type SortOrder int
|
type SortOrder int
|
||||||
@ -137,18 +142,18 @@ const (
|
|||||||
AceHighDescending
|
AceHighDescending
|
||||||
)
|
)
|
||||||
|
|
||||||
func (cards Cards) FormatForTerminalSorted(order SortOrder) string {
|
func (c Cards) FormatForTerminalSorted(order SortOrder) string {
|
||||||
sorted := cards.SortByRankAscending() // this is ascending
|
sorted := c.SortByRankAscending() // this is ascending
|
||||||
if order == AceHighDescending {
|
if order == AceHighDescending {
|
||||||
slices.Reverse(sorted)
|
slices.Reverse(sorted)
|
||||||
}
|
}
|
||||||
return sorted.FormatForTerminal()
|
return sorted.FormatForTerminal()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cards Cards) FormatForTerminal() string {
|
func (c Cards) FormatForTerminal() string {
|
||||||
var cardstrings []string
|
var cardstrings []string
|
||||||
for i := 0; i < len(cards); i++ {
|
for i := 0; i < len(c); i++ {
|
||||||
cardstrings = append(cardstrings, cards[i].FormatForTerminal())
|
cardstrings = append(cardstrings, c[i].FormatForTerminal())
|
||||||
}
|
}
|
||||||
return strings.Join(cardstrings, ",")
|
return strings.Join(cardstrings, ",")
|
||||||
}
|
}
|
||||||
@ -173,15 +178,16 @@ func (c Card) FormatForTerminal() string {
|
|||||||
return fmt.Sprintf("%s%s", rank, suit)
|
return fmt.Sprintf("%s%s", rank, suit)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cards Cards) HighestRank() Rank {
|
func (c Cards) HighestRank() Rank {
|
||||||
sorted := cards.SortByRankAscending()
|
sorted := c.SortByRankAscending()
|
||||||
return sorted[len(sorted)-1].Rank
|
return sorted[len(sorted)-1].Rank
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cards Cards) String() string {
|
func (s Cards) String() (output string) {
|
||||||
var cardstrings []string
|
var cardstrings []string
|
||||||
for i := 0; i < len(cards); i++ {
|
for i := 0; i < len(s); i++ {
|
||||||
cardstrings = append(cardstrings, cards[i].String())
|
cardstrings = append(cardstrings, s[i].String())
|
||||||
}
|
}
|
||||||
return strings.Join(cardstrings, ",")
|
output = strings.Join(cardstrings, ",")
|
||||||
|
return output
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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,16 +101,13 @@ func main() {
|
|||||||
timer := metrics.NewTimer()
|
timer := metrics.NewTimer()
|
||||||
registry.Register("pokerGame", timer)
|
registry.Register("pokerGame", timer)
|
||||||
|
|
||||||
bar := progressbar.NewOptions(
|
bar := progressbar.NewOptions(gameCount,
|
||||||
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(
|
progressbar.OptionThrottle(100*time.Millisecond), // Update every 100ms
|
||||||
100*time.Millisecond,
|
|
||||||
), // Update every 100ms
|
|
||||||
)
|
)
|
||||||
|
|
||||||
for i := 0; i < gameCount; i++ {
|
for i := 0; i < gameCount; i++ {
|
||||||
@ -131,13 +128,11 @@ 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(
|
fmt.Printf("Percentiles: 50%%: %0.2f ns, 75%%: %0.2f ns, 95%%: %0.2f ns, 99%%: %0.2f ns\n",
|
||||||
"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)
|
||||||
|
|||||||
@ -1,56 +0,0 @@
|
|||||||
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
4
go.mod
@ -1,14 +1,14 @@
|
|||||||
module sneak.berlin/go/pokercore
|
module git.eeqj.de/sneak/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
4
go.sum
@ -1,3 +1,5 @@
|
|||||||
|
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=
|
||||||
@ -41,5 +43,3 @@ 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=
|
|
||||||
|
|||||||
@ -5,12 +5,11 @@ 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.
|
||||||
@ -28,21 +27,18 @@ 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)
|
||||||
|
|||||||
@ -12,7 +12,6 @@ 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)
|
||||||
@ -36,7 +35,6 @@ 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},
|
||||||
@ -52,7 +50,6 @@ 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},
|
||||||
@ -71,7 +68,6 @@ 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},
|
||||||
|
|||||||
78
pokerhand.go
78
pokerhand.go
@ -62,13 +62,13 @@ func (c Cards) PokerHand() (*PokerHand, error) {
|
|||||||
return ph, nil
|
return ph, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ph *PokerHand) ToSortedCards() Cards {
|
func (ph PokerHand) ToSortedCards() Cards {
|
||||||
// I believe ph.Hand is already sorted, but in any case it's only 5
|
// I believe ph.Hand is already sorted, but in any case it's only 5
|
||||||
// cards and sorting it costs ~nothing
|
// cards and sorting it costs ~nothing
|
||||||
return ph.Hand.SortByRankAscending()
|
return ph.Hand.SortByRankAscending()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ph *PokerHand) Compare(other PokerHand) int {
|
func (ph PokerHand) Compare(other PokerHand) int {
|
||||||
if ph.Score > other.Score {
|
if ph.Score > other.Score {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
@ -78,74 +78,74 @@ func (ph *PokerHand) Compare(other PokerHand) int {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ph *PokerHand) HighestRank() Rank {
|
func (ph PokerHand) HighestRank() Rank {
|
||||||
return ph.Hand.HighestRank()
|
return ph.Hand.HighestRank()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ph *PokerHand) String() string {
|
func (ph PokerHand) String() string {
|
||||||
return fmt.Sprintf("<PokerHand: %s (%s)>", ph.Hand.String(), ph.Description())
|
return fmt.Sprintf("<PokerHand: %s (%s)>", ph.Hand.String(), ph.Description())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ph *PokerHand) Description() string {
|
func (c PokerHand) Description() string {
|
||||||
if ph.Type == RoyalFlush {
|
if c.Type == RoyalFlush {
|
||||||
return fmt.Sprintf("a royal flush in %s", ph.Hand[0].Suit)
|
return fmt.Sprintf("a royal flush in %s", c.Hand[0].Suit)
|
||||||
}
|
}
|
||||||
if ph.Hand.containsStraightFlush() {
|
if c.Hand.containsStraightFlush() {
|
||||||
if ph.Hand[3].Rank == FIVE && ph.Hand[4].Rank == ACE {
|
if c.Hand[3].Rank == FIVE && c.Hand[4].Rank == ACE {
|
||||||
// special case for steel wheel
|
// special case for steel wheel
|
||||||
return fmt.Sprintf("%s high straight flush in %s", ph.Hand[3].Rank.WithArticle(), ph.Hand[4].Suit)
|
return fmt.Sprintf("%s high straight flush in %s", c.Hand[3].Rank.WithArticle(), c.Hand[4].Suit)
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%s high straight flush in %s", ph.HighestRank().WithArticle(), ph.Hand[4].Suit)
|
return fmt.Sprintf("%s high straight flush in %s", c.HighestRank().WithArticle(), c.Hand[4].Suit)
|
||||||
}
|
}
|
||||||
if ph.Hand.containsFourOfAKind() {
|
if c.Hand.containsFourOfAKind() {
|
||||||
return fmt.Sprintf("four %s with %s", ph.Hand.fourOfAKindRank().Pluralize(), ph.Hand.fourOfAKindKicker().Rank.WithArticle())
|
return fmt.Sprintf("four %s with %s", c.Hand.fourOfAKindRank().Pluralize(), c.Hand.fourOfAKindKicker().Rank.WithArticle())
|
||||||
}
|
}
|
||||||
if ph.Hand.containsFullHouse() {
|
if c.Hand.containsFullHouse() {
|
||||||
return fmt.Sprintf("a full house, %s full of %s", ph.Hand.fullHouseTripsRank().Pluralize(), ph.Hand.fullHousePairRank().Pluralize())
|
return fmt.Sprintf("a full house, %s full of %s", c.Hand.fullHouseTripsRank().Pluralize(), c.Hand.fullHousePairRank().Pluralize())
|
||||||
}
|
}
|
||||||
if ph.Hand.containsFlush() {
|
if c.Hand.containsFlush() {
|
||||||
return fmt.Sprintf("%s high flush in %s", ph.HighestRank().WithArticle(), ph.Hand[4].Suit)
|
return fmt.Sprintf("%s high flush in %s", c.HighestRank().WithArticle(), c.Hand[4].Suit)
|
||||||
}
|
}
|
||||||
if ph.Hand.containsStraight() {
|
if c.Hand.containsStraight() {
|
||||||
if ph.Hand[3].Rank == FIVE && ph.Hand[4].Rank == ACE {
|
if c.Hand[3].Rank == FIVE && c.Hand[4].Rank == ACE {
|
||||||
// special case for wheel straight
|
// special case for wheel straight
|
||||||
return fmt.Sprintf("%s high straight", ph.Hand[3].Rank.WithArticle())
|
return fmt.Sprintf("%s high straight", c.Hand[3].Rank.WithArticle())
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%s high straight", ph.HighestRank().WithArticle())
|
return fmt.Sprintf("%s high straight", c.HighestRank().WithArticle())
|
||||||
}
|
}
|
||||||
if ph.Hand.containsThreeOfAKind() {
|
if c.Hand.containsThreeOfAKind() {
|
||||||
return fmt.Sprintf(
|
return fmt.Sprintf(
|
||||||
"three %s with %s and %s",
|
"three %s with %s and %s",
|
||||||
ph.Hand.threeOfAKindTripsRank().Pluralize(),
|
c.Hand.threeOfAKindTripsRank().Pluralize(),
|
||||||
ph.Hand.threeOfAKindFirstKicker().Rank.WithArticle(),
|
c.Hand.threeOfAKindFirstKicker().Rank.WithArticle(),
|
||||||
ph.Hand.threeOfAKindSecondKicker().Rank.WithArticle(),
|
c.Hand.threeOfAKindSecondKicker().Rank.WithArticle(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if ph.Hand.containsTwoPair() {
|
if c.Hand.containsTwoPair() {
|
||||||
return fmt.Sprintf(
|
return fmt.Sprintf(
|
||||||
"two pair, %s and %s with %s",
|
"two pair, %s and %s with %s",
|
||||||
ph.Hand.twoPairBiggestPair().Pluralize(),
|
c.Hand.twoPairBiggestPair().Pluralize(),
|
||||||
ph.Hand.twoPairSmallestPair().Pluralize(),
|
c.Hand.twoPairSmallestPair().Pluralize(),
|
||||||
ph.Hand.twoPairKicker().Rank.WithArticle(),
|
c.Hand.twoPairKicker().Rank.WithArticle(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if ph.Hand.containsPair() {
|
if c.Hand.containsPair() {
|
||||||
return fmt.Sprintf(
|
return fmt.Sprintf(
|
||||||
"a pair of %s with %s, %s, and %s",
|
"a pair of %s with %s, %s, and %s",
|
||||||
ph.Hand.pairRank().Pluralize(),
|
c.Hand.pairRank().Pluralize(),
|
||||||
ph.Hand.pairFirstKicker().Rank.WithArticle(),
|
c.Hand.pairFirstKicker().Rank.WithArticle(),
|
||||||
ph.Hand.pairSecondKicker().Rank.WithArticle(),
|
c.Hand.pairSecondKicker().Rank.WithArticle(),
|
||||||
ph.Hand.pairThirdKicker().Rank.WithArticle(),
|
c.Hand.pairThirdKicker().Rank.WithArticle(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Sprintf(
|
return fmt.Sprintf(
|
||||||
// "ace high with an eight, a seven, a six, and a deuce"
|
// "ace high with an eight, a seven, a six, and a deuce"
|
||||||
"%s high with %s, %s, %s, and %s",
|
"%s high with %s, %s, %s, and %s",
|
||||||
ph.Hand[4].Rank,
|
c.Hand[4].Rank,
|
||||||
ph.Hand[3].Rank.WithArticle(),
|
c.Hand[3].Rank.WithArticle(),
|
||||||
ph.Hand[2].Rank.WithArticle(),
|
c.Hand[2].Rank.WithArticle(),
|
||||||
ph.Hand[1].Rank.WithArticle(),
|
c.Hand[1].Rank.WithArticle(),
|
||||||
ph.Hand[0].Rank.WithArticle(),
|
c.Hand[0].Rank.WithArticle(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
178
scoring_test.go
178
scoring_test.go
@ -6,16 +6,15 @@ import (
|
|||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestHandDescriptionBug(t *testing.T) {
|
func TestHandDescripionBug(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 := 0; i < playerCount; i++ {
|
for i := 1; i-1 < playerCount; i++ {
|
||||||
c := d.Deal(2)
|
c := d.Deal(2)
|
||||||
players[i] = &c
|
players[i-1] = &c
|
||||||
t.Logf("Player %d dealt: %+v\n", i+1, c)
|
t.Logf("Player %d dealt: %+v\n", i, c)
|
||||||
}
|
}
|
||||||
t.Logf("Players: %+v\n", players)
|
t.Logf("Players: %+v\n", players)
|
||||||
|
|
||||||
@ -24,17 +23,17 @@ func TestHandDescriptionBug(t *testing.T) {
|
|||||||
|
|
||||||
var playerResults []*PokerHand
|
var playerResults []*PokerHand
|
||||||
|
|
||||||
for i := 0; i < playerCount; i++ {
|
for i := 1; i-1 < playerCount; i++ {
|
||||||
t.Logf("Player %d hole cards: %+v\n", i+1, *players[i])
|
t.Logf("Player %d hole cards: %+v\n", i, *players[i-1])
|
||||||
pc := append(*players[i], community...)
|
pc := append(*players[i-1], community...)
|
||||||
t.Logf("Player %d cards available: %+v\n", i+1, pc)
|
t.Logf("Player %d cards available: %+v\n", i, pc)
|
||||||
hand, err := pc.IdentifyBestFiveCardPokerHand()
|
hand, err := pc.IdentifyBestFiveCardPokerHand()
|
||||||
assert.NoError(t, err, "Expected no error")
|
assert.Nil(t, err, "Expected no error")
|
||||||
ph, err := hand.PokerHand()
|
ph, err := hand.PokerHand()
|
||||||
assert.NoError(t, err, "Expected no error")
|
assert.Nil(t, err, "Expected no error")
|
||||||
t.Logf("Player %d five cards used: %+v\n", i+1, hand)
|
t.Logf("Player %d five cards used: %+v\n", i, hand)
|
||||||
t.Logf("Player %d poker hand: %+v\n", i+1, ph)
|
t.Logf("Player %d poker hand: %+v\n", i, ph)
|
||||||
t.Logf("Player %d best hand description: %s\n", i+1, ph.Description())
|
t.Logf("Player %d best hand description: %s\n", i, ph.Description())
|
||||||
playerResults = append(playerResults, ph)
|
playerResults = append(playerResults, ph)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,31 +43,30 @@ func TestHandDescriptionBug(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, "two pair, tens and sevens with a nine", weirdOne.Description())
|
assert.Equal(t, weirdOne.Description(), "two pair, tens and sevens with a nine")
|
||||||
|
|
||||||
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, scoreShouldBe, weirdOne.Score)
|
assert.Equal(t, weirdOne.Score, scoreShouldBe)
|
||||||
|
|
||||||
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, TEN, bp, "Expected biggest pair to be a ten")
|
assert.Equal(t, bp, TEN, "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, SEVEN, sp, "Expected smallest pair to be a seven")
|
assert.Equal(t, sp, SEVEN, "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, NINE, k.Rank, "Expected kicker to be a nine")
|
assert.Equal(t, k.Rank, NINE, "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(),
|
||||||
@ -78,25 +76,22 @@ 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.NoError(t, err, "Expected no error")
|
assert.Nil(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, "a five high straight", ph.Description())
|
assert.Equal(t, ph.Description(), "a five high straight")
|
||||||
assert.Equal(t, ACE, hand.HighestRank(), "Expected highest rank to be an ace")
|
assert.True(t, hand.HighestRank() == ACE, "Expected highest rank to be an ace")
|
||||||
s := hand.SortByRankAscending()
|
s := hand.SortByRankAscending()
|
||||||
assert.Equal(t, DEUCE, s.First().Rank, "Expected first card to be a deuce")
|
assert.True(t, s.First().Rank == DEUCE, "Expected first card to be a deuce")
|
||||||
assert.Equal(t, ACE, s.Last().Rank, "Expected last card in sorted to be an ace")
|
assert.True(t, s.Last().Rank == ACE, "Expected last card in sorted to be a ace")
|
||||||
assert.Equal(t, THREE, s.Second().Rank, "Expected second card to be a three")
|
assert.True(t, s.Second().Rank == THREE, "Expected second card to be a three")
|
||||||
assert.Equal(t, FOUR, s.Third().Rank, "Expected third card to be a four")
|
assert.True(t, s.Third().Rank == FOUR, "Expected third card to be a four")
|
||||||
assert.Equal(t, FIVE, s.Fourth().Rank, "Expected fourth card to be a five")
|
assert.True(t, s.Fourth().Rank == FIVE, "Expected fourth card to be a five")
|
||||||
assert.Equal(t, ACE, s.Fifth().Rank, "Expected fifth card to be an ace")
|
assert.True(t, s.Fifth().Rank == ACE, "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(),
|
||||||
@ -110,19 +105,16 @@ 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.Equal(t, ACE, shuffledHand.HighestRank(), "Expected highest rank to be an ace")
|
assert.True(t, shuffledHand.HighestRank() == ACE, "Expected highest rank to be an ace")
|
||||||
sortedHand := shuffledHand.SortByRankAscending()
|
sortedHand := shuffledHand.SortByRankAscending()
|
||||||
assert.Equal(t, TEN, sortedHand[0].Rank, "Expected lowest rank to be a ten")
|
assert.True(t, sortedHand[0].Rank == TEN, "Expected lowest rank to be a ten")
|
||||||
assert.Equal(t, JACK, sortedHand[1].Rank, "Expected second lowest rank to be a jack")
|
assert.True(t, sortedHand[1].Rank == JACK, "Expected second lowest rank to be a jack")
|
||||||
assert.Equal(t, QUEEN, sortedHand[2].Rank, "Expected third lowest rank to be a queen")
|
assert.True(t, sortedHand[2].Rank == QUEEN, "Expected third lowest rank to be a queen")
|
||||||
assert.Equal(t, KING, sortedHand[3].Rank, "Expected fourth lowest rank to be a king")
|
assert.True(t, sortedHand[3].Rank == KING, "Expected fourth lowest rank to be a king")
|
||||||
assert.Equal(t, ACE, sortedHand[4].Rank, "Expected highest rank to be an ace")
|
assert.True(t, sortedHand[4].Rank == ACE, "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(),
|
||||||
@ -134,18 +126,17 @@ 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.Equal(t, SIX, shuffledHand.HighestRank(), "Expected highest rank to be a six")
|
assert.True(t, shuffledHand.HighestRank() == SIX, "Expected highest rank to be a six")
|
||||||
assert.Equal(t, DEUCE, shuffledHand.SortByRankAscending().First().Rank, "Expected first card to be a deuce")
|
assert.True(t, shuffledHand.SortByRankAscending().First().Rank == DEUCE, "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(),
|
||||||
@ -156,6 +147,8 @@ 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")
|
||||||
|
|
||||||
@ -166,17 +159,15 @@ 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.NoError(t, err, "Expected no error")
|
assert.Nil(t, err, "Expected no error")
|
||||||
assert.Greater(t, ph.Score, 0, "Expected score to be nonzero")
|
assert.Greater(t, ph.Score, 0, "Expected score to be nonzero 0")
|
||||||
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(),
|
||||||
@ -194,20 +185,19 @@ 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.Equal(t, SIX, hand.HighestRank(), "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)
|
||||||
|
//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.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 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")
|
assert.True(t, shuffledHand.HighestRank() == SIX, "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(),
|
||||||
@ -233,13 +223,10 @@ 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.Equal(t, SIX, hand.HighestRank(), "Expected highest rank to be a six")
|
assert.True(t, hand.HighestRank() == SIX, "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(),
|
||||||
@ -258,14 +245,11 @@ 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.Equal(t, ACE, hand.HighestRank(), "Expected highest rank to be an ace")
|
assert.True(t, hand.HighestRank() == ACE, "Expected highest rank to be an ace")
|
||||||
assert.NotEqual(t, TEN, hand.HighestRank(), "Expected highest rank to not be a ten")
|
assert.False(t, hand.HighestRank() == TEN, "Expected highest rank to not be an ace")
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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(),
|
||||||
@ -282,14 +266,11 @@ 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.Equal(t, KING, hand.HighestRank(), "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")
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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(),
|
||||||
@ -306,14 +287,11 @@ 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.Equal(t, KING, hand.HighestRank(), "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 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(),
|
||||||
@ -322,12 +300,9 @@ 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(),
|
||||||
@ -336,33 +311,33 @@ func TestHandScore(t *testing.T) {
|
|||||||
TenOfSpades(),
|
TenOfSpades(),
|
||||||
}
|
}
|
||||||
|
|
||||||
ph, err := hand.PokerHand()
|
ph, error := hand.PokerHand()
|
||||||
assert.NoError(t, err, "Expected no error")
|
assert.Nil(t, error, "Expected no error")
|
||||||
assert.True(t, ph.Score > 0, "Expected score to be nonzero")
|
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")
|
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.NoError(t, err, "Expected no error")
|
assert.Nil(t, err, "Expected no error")
|
||||||
|
|
||||||
|
//fmt.Printf("Cards: %v+\n", c)
|
||||||
|
|
||||||
ph, err := c.PokerHand()
|
ph, err := c.PokerHand()
|
||||||
assert.NoError(t, err, "Expected no error")
|
assert.Nil(t, err, "Expected no error")
|
||||||
assert.Greater(t, ph.Score, 0, "Expected score to be nonzero")
|
assert.Greater(t, ph.Score, 0, "Expected score to be nonzero 0")
|
||||||
desc := ph.Description()
|
desc := ph.Description()
|
||||||
assert.Equal(t, "two pair, queens and nines with a king", desc)
|
assert.Equal(t, desc, "two pair, queens and nines with a king")
|
||||||
})
|
|
||||||
|
//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(),
|
||||||
@ -380,21 +355,13 @@ func TestScoringStructureQuads(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
phA, err := handA.PokerHand()
|
phA, err := handA.PokerHand()
|
||||||
assert.NoError(t, err, "Expected no error")
|
assert.Nil(t, err, "Expected no error")
|
||||||
phB, err := handB.PokerHand()
|
phB, err := handB.PokerHand()
|
||||||
assert.NoError(t, err, "Expected no error")
|
assert.Nil(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(),
|
||||||
@ -404,7 +371,7 @@ func TestScoringStructureFullHouse(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
phA, err := handA.PokerHand()
|
phA, err := handA.PokerHand()
|
||||||
assert.NoError(t, err, "Expected no error")
|
assert.Nil(t, err, "Expected no error")
|
||||||
deucesFullOfAcesScore := phA.Score
|
deucesFullOfAcesScore := phA.Score
|
||||||
|
|
||||||
handB := Cards{
|
handB := Cards{
|
||||||
@ -415,9 +382,8 @@ func TestScoringStructureFullHouse(t *testing.T) {
|
|||||||
DeuceOfHearts(),
|
DeuceOfHearts(),
|
||||||
}
|
}
|
||||||
phB, err := handB.PokerHand()
|
phB, err := handB.PokerHand()
|
||||||
assert.NoError(t, err, "Expected no error")
|
assert.Nil(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")
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user