Documentation
¶
Overview ¶
Package pokerstove provides native Go card parsing, hand evaluation, and showdown equity enumeration for PokerStove-style poker games.
The package does not wrap or call the C++ PokerStove library at runtime. Instead, copied golden vectors and optional oracle-backed tests keep the Go implementation aligned with PokerStove compatibility behavior.
Cards are represented compactly as bits in a CardSet. CardSet is a value type: methods such as Insert and Remove return a new set and never mutate the receiver. Public helpers parse PokerStove card text such as "AhKd", construct evaluators for supported game codes, compare complete or partial hands, and enumerate showdown equities.
LowEvaluation.Code is opaque ordering data, and CompareHandEvaluations is meaningful for HandEvaluation values produced by this package's evaluators. Showdown enumeration follows lower-level PokerStove parity behavior, including successful zero-share results when legal inputs have no disjoint completion. Applications can layer stricter user-facing validation on top.
Example (LowballComparison) ¶
package main
import (
"fmt"
pokerstove "github.com/kevinmcmahon/pokerstove-go"
)
func mustCardSet(text string) pokerstove.CardSet {
cards, err := pokerstove.ParseCardSet(text)
if err != nil {
panic(err)
}
return cards
}
func main() {
evaluator, err := pokerstove.NewEvaluator("k")
if err != nil {
panic(err)
}
comparison, err := evaluator.Compare(
mustCardSet("2c3d4h5s7c"),
mustCardSet("2d3h4s5c6d"),
0,
)
if err != nil {
panic(err)
}
fmt.Println(comparison > 0)
}
Output: true
Example (OmahaEightSplitPot) ¶
package main
import (
"fmt"
pokerstove "github.com/kevinmcmahon/pokerstove-go"
)
func main() {
result, err := pokerstove.EvaluateShowdown(pokerstove.ShowdownRequest{
Game: "o8",
Board: "2c5c6cJhTd",
Hands: []string{"3d4hKhQd", "AcKcQhTs"},
})
if err != nil {
panic(err)
}
fmt.Printf("%.1f %.1f\n", result.Players[0].WinShares, result.Players[1].WinShares)
}
Output: 0.5 0.5
Example (PartialHandsAndBoards) ¶
package main
import (
"fmt"
pokerstove "github.com/kevinmcmahon/pokerstove-go"
)
func main() {
result, err := pokerstove.EvaluateShowdown(pokerstove.ShowdownRequest{
Game: "h",
Board: "2c3d4h5s",
Hands: []string{"Ac", "KhQh"},
})
if err != nil {
panic(err)
}
fmt.Printf("%.0f\n", result.TotalShares)
fmt.Println(result.Players[0].WinShares > 0)
fmt.Println(result.Players[1].WinShares > 0)
}
Output: 1980 true false
Example (StudEight) ¶
package main
import (
"fmt"
pokerstove "github.com/kevinmcmahon/pokerstove-go"
)
func main() {
result, err := pokerstove.EvaluateShowdown(pokerstove.ShowdownRequest{
Game: "e",
Hands: []string{"Ac2d3h4c5s7d8c", "KcKdQhQsJc9d8h"},
})
if err != nil {
panic(err)
}
fmt.Printf("%.0f %.0f\n", result.Players[0].WinShares, result.Players[1].WinShares)
}
Output: 1 0
Example (WeightedRanges) ¶
package main
import (
"fmt"
pokerstove "github.com/kevinmcmahon/pokerstove-go"
)
func main() {
result, err := pokerstove.EvaluateShowdown(pokerstove.ShowdownRequest{
Game: "h",
Board: "2c3d4h5s9c",
Hands: []string{"AcAs=0.25,KcKs=0.75", "QhQs=0.5,JhJs=0.5"},
})
if err != nil {
panic(err)
}
fmt.Printf("%.1f %.1f\n", result.Players[0].WinShares, result.Players[1].WinShares)
fmt.Printf("%.1f\n", result.TotalShares)
}
Output: 1.0 0.0 1.0
Index ¶
- Constants
- func CompareEvaluations(a, b Evaluation) int
- func CompareHandEvaluations(a HandEvaluation, b HandEvaluation) int
- type Card
- type CardSet
- func (cs CardSet) Cards() []Card
- func (cs CardSet) Contains(card Card) bool
- func (cs CardSet) ContainsSet(other CardSet) bool
- func (cs CardSet) Disjoint(other CardSet) bool
- func (cs CardSet) Insert(card Card) CardSet
- func (cs CardSet) Remove(other CardSet) CardSet
- func (cs CardSet) Size() int
- func (cs CardSet) String() string
- type CardTextError
- type Evaluation
- type Evaluator
- type Game
- type GameMetadata
- type HandDistribution
- type HandEvaluation
- type HandOption
- type LowEvaluation
- type PlayerEquity
- type Rank
- type ShowdownRequest
- type ShowdownResult
- type Suit
Examples ¶
Constants ¶
const ( // NoPair is a high-card hand. NoPair = 0 // OnePair is one pair. OnePair = 1 // ThreeFlush is a three-card poker flush. ThreeFlush = 2 // ThreeStraight is a three-card poker straight. ThreeStraight = 3 // TwoPair is two pair. TwoPair = 4 // ThreeOfAKind is three of a kind. ThreeOfAKind = 5 // ThreeStraightFlush is a three-card poker straight flush. ThreeStraightFlush = 6 // Straight is a five-card straight. Straight = 7 // Flush is a five-card flush. Flush = 8 // FullHouse is a full house. FullHouse = 9 // FourOfAKind is four of a kind. FourOfAKind = 10 // StraightFlush is a five-card straight flush. StraightFlush = 11 )
Variables ¶
This section is empty.
Functions ¶
func CompareEvaluations ¶
func CompareEvaluations(a, b Evaluation) int
CompareEvaluations compares two high-hand evaluations.
It returns 1 when a is stronger, -1 when b is stronger, and 0 when they tie.
func CompareHandEvaluations ¶
func CompareHandEvaluations(a HandEvaluation, b HandEvaluation) int
CompareHandEvaluations compares two hand evaluations.
It returns 1 when a is stronger, -1 when b is stronger, and 0 when they tie. The comparison is meaningful for HandEvaluation values returned by Evaluator.Evaluate or package helpers; manually constructed values do not contain the private PokerStove-compatible ordering code.
Types ¶
type Card ¶
type Card uint8
Card identifies one card in a standard 52-card deck.
type CardSet ¶
type CardSet uint64
CardSet is a bit set of cards.
CardSet is a value type. Methods such as Insert and Remove return a new set instead of mutating the receiver.
func FullDeck ¶
func FullDeck() CardSet
FullDeck returns a CardSet containing all 52 standard deck cards.
func ParseCardSet ¶
ParseCardSet parses whitespace-separated or contiguous PokerStove card text.
It rejects malformed cards and duplicate cards. The returned String form is canonical PokerStove card order, not necessarily the input order.
Example ¶
package main
import (
"fmt"
pokerstove "github.com/kevinmcmahon/pokerstove-go"
)
func main() {
cards, err := pokerstove.ParseCardSet("Ac Kd\nQh")
if err != nil {
panic(err)
}
fmt.Println(cards)
fmt.Println(cards.Size())
}
Output: AcKdQh 3
func (CardSet) ContainsSet ¶
ContainsSet reports whether cs contains every card in other.
type CardTextError ¶
type CardTextError struct {
// Message is the human-readable parse error.
Message string
}
CardTextError describes invalid PokerStove card text.
func (CardTextError) Error ¶
func (e CardTextError) Error() string
Error returns the card text parse error message.
type Evaluation ¶
type Evaluation struct {
// Type is one of the exported hand category constants.
Type int
// Major is the primary rank for made hands such as pairs or straights.
Major Rank
// Minor is the secondary rank for hands such as two pair or full houses.
Minor Rank
// Kickers are remaining ranks used to break ties, highest first.
Kickers []Rank
}
Evaluation describes the high-hand category and tie breakers.
func EvaluateHoldem ¶
func EvaluateHoldem(hand CardSet, board CardSet) (Evaluation, error)
EvaluateHoldem evaluates a hold'em hand and board as a high hand.
The hand may contain at most two cards and the board may contain at most five. Partial inputs are evaluated as the best high hand available from the cards provided; use EvaluateShowdown when missing cards should be enumerated.
Example ¶
package main
import (
"fmt"
pokerstove "github.com/kevinmcmahon/pokerstove-go"
)
func mustCardSet(text string) pokerstove.CardSet {
cards, err := pokerstove.ParseCardSet(text)
if err != nil {
panic(err)
}
return cards
}
func main() {
evaluation, err := pokerstove.EvaluateHoldem(
mustCardSet("AcKs"),
mustCardSet("AhKd2c3d9s"),
)
if err != nil {
panic(err)
}
fmt.Println(evaluation.Type == pokerstove.TwoPair)
fmt.Println(evaluation.Major, evaluation.Minor)
}
Output: true A K
type Evaluator ¶
type Evaluator struct {
// contains filtered or unexported fields
}
Evaluator evaluates hands for one game.
func NewEvaluator ¶
NewEvaluator parses text as a game code and returns an evaluator for it.
Example ¶
package main
import (
"fmt"
pokerstove "github.com/kevinmcmahon/pokerstove-go"
)
func main() {
evaluator, err := pokerstove.NewEvaluator("omaha/8")
if err != nil {
panic(err)
}
metadata := evaluator.Metadata()
fmt.Println(metadata.Name)
fmt.Println(metadata.HandSize, metadata.BoardSize, metadata.EvaluationSize)
}
Output: Omaha high/low 4 5 2
func (*Evaluator) Compare ¶
Compare evaluates and compares two hands according to the evaluator's game.
Example ¶
package main
import (
"fmt"
pokerstove "github.com/kevinmcmahon/pokerstove-go"
)
func mustCardSet(text string) pokerstove.CardSet {
cards, err := pokerstove.ParseCardSet(text)
if err != nil {
panic(err)
}
return cards
}
func main() {
evaluator, err := pokerstove.NewEvaluator("h")
if err != nil {
panic(err)
}
comparison, err := evaluator.Compare(
mustCardSet("AcAs"),
mustCardSet("KhQh"),
mustCardSet("2c3d4h5s9c"),
)
if err != nil {
panic(err)
}
fmt.Println(comparison > 0)
}
Output: true
func (*Evaluator) Evaluate ¶
func (e *Evaluator) Evaluate(hand CardSet, board CardSet) (HandEvaluation, error)
Evaluate evaluates a hand and board according to the evaluator's game.
Validation follows the selected game. Hold'em accepts partial hands and boards up to their maximum sizes; Omaha variants require complete inputs because evaluation must choose exact counts from hand and board.
Example ¶
package main
import (
"fmt"
pokerstove "github.com/kevinmcmahon/pokerstove-go"
)
func mustCardSet(text string) pokerstove.CardSet {
cards, err := pokerstove.ParseCardSet(text)
if err != nil {
panic(err)
}
return cards
}
func main() {
evaluator, err := pokerstove.NewEvaluator("o8")
if err != nil {
panic(err)
}
evaluation, err := evaluator.Evaluate(
mustCardSet("4c3cKhQd"),
mustCardSet("AcKc6cJs2d"),
)
if err != nil {
panic(err)
}
fmt.Println(evaluation.High.Type == pokerstove.Flush)
fmt.Println(evaluation.HighLow())
}
Output: true true
func (*Evaluator) Metadata ¶
func (e *Evaluator) Metadata() GameMetadata
Metadata returns metadata for the evaluator's game.
type Game ¶
type Game string
Game is a PokerStove game code.
const ( // Holdem is Texas hold'em high. Holdem Game = "h" // OmahaHigh is four-card Omaha high. OmahaHigh Game = "o" // OmahaEight is four-card Omaha high/low with an eight-or-better low qualifier. OmahaEight Game = "o8" // OmahaFive is the C++ PokerStove five-card Omaha high game code. OmahaFive Game = "o5" // OmahaSix is the C++ PokerStove six-card Omaha high game code. OmahaSix Game = "o6" // OmahaFiveEight is the C++ PokerStove five-card Omaha high/low game code. OmahaFiveEight Game = "o5/8" // OmahaSixEight is the C++ PokerStove six-card Omaha high/low game code. OmahaSixEight Game = "o6/8" // KansasCityLowball is deuce-to-seven lowball. KansasCityLowball Game = "k" // AceToFiveLowball is ace-to-five lowball. AceToFiveLowball Game = "l" // ThreeCardPoker is three-card poker high. ThreeCardPoker Game = "3" // Razz is seven-card ace-to-five lowball. Razz Game = "r" // Stud is seven-card stud high. Stud Game = "s" // StudHighLowNoQualifier is seven-card stud high/low with no low qualifier. StudHighLowNoQualifier Game = "q" // DrawHigh is five-card draw high. DrawHigh Game = "d" // TripleDrawDeuceToSeven is triple draw deuce-to-seven lowball. TripleDrawDeuceToSeven Game = "t" // TripleDrawA5 is triple draw ace-to-five lowball. TripleDrawA5 Game = "T" // StudEight is seven-card stud high/low with an eight-or-better low qualifier. StudEight Game = "e" // Badugi is four-card badugi. Badugi Game = "b" )
func ParseGame ¶
ParseGame parses a PokerStove game code or supported game name.
Most game names are normalized by their leading lowercase character. The uppercase "T" code is intentionally distinct and selects TripleDrawA5; lowercase "t" selects TripleDrawDeuceToSeven.
func (Game) Metadata ¶
func (g Game) Metadata() GameMetadata
Metadata returns metadata for the game.
type GameMetadata ¶
type GameMetadata struct {
// Game is the game code described by this metadata.
Game Game
// Name is the human-readable game name.
Name string
// HandSize is the number of cards accepted in one hand option according to
// the current PokerStove-compatible metadata row.
HandSize int
// BoardSize is the number of board cards used by the game.
BoardSize int
// EvaluationSize is the number of evaluation pots, such as high and low.
EvaluationSize int
// UsesSuits reports whether suits affect hand strength.
UsesSuits bool
}
GameMetadata describes the hand and board shape for a game.
type HandDistribution ¶
type HandDistribution []HandOption
HandDistribution is a list of weighted hand options.
func ParseHandDistribution ¶
func ParseHandDistribution(text string) (HandDistribution, error)
ParseHandDistribution parses comma-separated weighted hand options.
Options use "cards" or "cards=weight" syntax. The special string "." represents a random completion placeholder and must be the entire distribution text.
type HandEvaluation ¶
type HandEvaluation struct {
// High is the high-hand evaluation. Lowball-only games may leave High at
// its zero value and use internal ordering data for comparison.
High Evaluation
// Low is non-nil when the hand has a qualifying low evaluation.
Low *LowEvaluation
// contains filtered or unexported fields
}
HandEvaluation combines the high hand with an optional qualifying low hand.
func (HandEvaluation) HighLow ¶
func (e HandEvaluation) HighLow() bool
HighLow reports whether the hand has a qualifying low evaluation.
type HandOption ¶
type HandOption struct {
// Cards is the fixed or partial hand for this option.
Cards CardSet
// Weight is the relative frequency assigned to this option.
Weight float64
}
HandOption is one weighted hand option in a distribution.
type LowEvaluation ¶
type LowEvaluation struct {
// Code is the ordering code for a qualifying low hand.
Code int
}
LowEvaluation is the low side of a split-pot hand evaluation.
Code is opaque PokerStove-compatible ordering data. Use Evaluator.Compare, CompareHandEvaluations, or showdown results to compare lows instead of presenting or interpreting the integer directly.
type PlayerEquity ¶
type PlayerEquity struct {
// Label is the original hand distribution text for this player.
Label string
// IsRandomHand reports whether this player was generated automatically.
IsRandomHand bool
WinShares float64
TieShares float64
// Equity is this player's normalized share of TotalShares.
Equity float64
}
PlayerEquity is one player's share of the enumerated showdown.
type Rank ¶
type Rank uint8
Rank identifies a card rank from Two through Ace.
const ( // Two is the deuce rank. Two Rank = iota // Three is the trey rank. Three // Four is the four rank. Four // Five is the five rank. Five // Six is the six rank. Six // Seven is the seven rank. Seven // Eight is the eight rank. Eight // Nine is the nine rank. Nine // Ten is the ten rank. Ten // Jack is the jack rank. Jack // Queen is the queen rank. Queen // King is the king rank. King // Ace is the ace rank. Ace )
type ShowdownRequest ¶
type ShowdownRequest struct {
// Game is the PokerStove game code. An empty value defaults to hold'em.
Game string
// Board is PokerStove card text for known board cards. "-" is accepted as an
// empty board.
Board string
// Hands contains one hand distribution string per player.
Hands []string
// AddRandomHandForSingleHand adds a random hold'em opponent for one-hand requests.
AddRandomHandForSingleHand bool
}
ShowdownRequest describes a showdown equity calculation.
type ShowdownResult ¶
type ShowdownResult struct {
// Players contains equity results in request hand order.
Players []PlayerEquity
// zero when no legal disjoint completion exists.
TotalShares float64
}
ShowdownResult is the result of a showdown equity calculation.
func EvaluateShowdown ¶
func EvaluateShowdown(req ShowdownRequest) (ShowdownResult, error)
EvaluateShowdown enumerates a showdown request and returns player equities.
It accepts weighted ranges, dot/random hand placeholders, partial hands, and partial boards. Missing cards are enumerated from the live deck. If no disjoint completion exists, the function succeeds with zero shares to match lower-level PokerStove parity behavior.
Example ¶
package main
import (
"fmt"
pokerstove "github.com/kevinmcmahon/pokerstove-go"
)
func main() {
result, err := pokerstove.EvaluateShowdown(pokerstove.ShowdownRequest{
Game: "h",
Board: "2c3d4h5s9c",
Hands: []string{"AcAs", "KhQh"},
})
if err != nil {
panic(err)
}
fmt.Printf("%.0f %.0f\n", result.Players[0].WinShares, result.Players[1].WinShares)
fmt.Printf("%.2f %.2f\n", result.Players[0].Equity, result.Players[1].Equity)
}
Output: 1 0 1.00 0.00