Package cardrank
is a library of types, utilities, and interfaces for working
with playing cards, card decks, evaluating poker ranks, managing deals and run
outs for different game types.
The cardrank
package contains types for working with Card
's,
Suit
's, Rank
's, Deck
's, evaluating poker
ranks, and managing deals and run outs.
In most cases, using the high-level Dealer
with any registered
Type
should be sufficient for most purposes. An in-depth example is
provided in the package documentation.
A Type
wraps a type description defining a type's deal
streets, deck, eval, Hi/Lo
description and other meta-data needed for dealing streets and
managing run outs.
Evaluation and ranking of the types is accomplished through pure Go implementations of well-known poker rank evaluation algorithms. Evaluation of cards can be compared and ordered to determine winner(s).
Supports evaluating and ranking the following Type
's:
Holdem Variants | Omaha Variants | Hybrid Variants | Draw Variants | Other |
---|---|---|---|---|
Holdem |
Omaha |
Dallas |
Video |
Soko |
Split |
OmahaHiLo |
Houston |
Draw |
SokoHiLo |
Short |
OmahaDouble |
Fusion |
DrawHiLo |
Lowball |
Manila |
OmahaFive |
FusionHiLo |
Stud |
LowballTriple |
Spanish |
OmahaSix |
StudHiLo |
Razz |
|
Royal |
Jakarta |
StudFive |
Badugi |
|
Double |
Courchevel |
|||
Showtime |
CourchevelHiLo |
|||
Swap |
||||
River |
See the package's Type
documentation for an overview of the above.
To use within a Go package:
go get github.com/cardrank/cardrank
See package level Go package documentation for in-depth overviews of APIs.
Various examples are available in the Go package documentation showing use of various types, utilities, and interfaces.
Additional examples for a Dealer
and the Holdem
and
OmahaHiLo
types are included in the example directory:
- dealer - shows use of the
Dealer
, to handle dealing cards, handling multiple run outs, and determining winners using anyType
's - holdem - shows using types and utilities to deal
Holdem
- omahahilo - shows using types and utilities to
OmahaHiLo
, demonstrating splitting Hi and Lo wins
EvalRank
's are determined using a registered
EvalFunc
associated with the Type
. EvalRank
's are
always ordered, low to high, and are relative/comparable:
fmt.Printf("%t\n", cardrank.StraightFlush < cardrank.FullHouse)
// Output:
// true
Pocket and board Card
's can be passed to a Type
's Eval
method, which in turn uses the Type
's registered EvalFunc
and
returns an Eval
uated value:
pocket, board := cardrank.Must("Ah Kh"), cardrank.Must("Qh Jh Th 2s 3s")
ev := cardrank.Holdem.Eval(pocket, board)
fmt.Printf("%s - %d\n", ev, ev.HiRank)
// Output:
// Straight Flush, Ace-high, Royal [Ah Kh Qh Jh Th] - 1
When evaluating cards, usually the eval is for 5, 6, or 7 cards, but some
Type
's are capable of evaluating fewer Card
's:
pocket := cardrank.Must("2h 3s 4c")
ev := cardrank.Badugi.Eval(pocket, nil)
fmt.Printf("%s\n", ev)
// Output:
// Four, Three, Two-low [4c 3s 2h]
If an invalid number of cards is passed to a Type
's EvalFunc
, the Eval
's
HiRank
and LoRank
values will be set to
Invalid
.
Eval
's can be used to compare different hands of Card
's in order to
determine a winner, by comparing the Eval.HiRank
or
Eval.LoRank
values.
Different Type
's may have both a Hi and Lo EvalRank
,
such as Double
board Holdem
, and various *HiLo
variants,
such as OmahaHiLo
.
When a Eval
is created, both the Hi and Lo values will be made
available in the resulting Eval
as the HiRank
and
LoRank
, respectively.
For most Type
's, the EvalRank
is determined by Go
implementations of a few well-known Cactus Kev algorithms:
Cactus
- the original Cactus Kev poker hand evaluatorCactusFast
- the Fast Cactus poker hand evaluator, using Paul Senzee's perfect hash lookupTwoPlusTwo
- the 2+2 forum poker hand evaluator, using a 130 MiB lookup table
See below for more information on the default rank func in use by the package, and for information on using build tags to enable/disable functionality for different target runtime environments.
The package-level RankCactus
variable is used for regular
poker evaluation, and can be set externally when wanting to build new game
types, or trying new algorithms.
NewTwoPlusTwoEval
makes use of a large (approximately 130
MiB) lookup table to accomplish extremely fast 5, 6 and 7 card hand rank
evaluation. Due to the large size of the lookup table, the lookup table can be
excluded when using the portable
or embedded
build tags, with
a tradeoff of slightly degraded performance when evaluating 7 cards.
Note: the Two-Plus-Two eval is disabled by default when GOOS=js
(ie, WASM)
builds, but can be forced included with the forcefat
build tag.
Winner(s) are determined by the lowest possible EvalRank
for
either the Hi or Lo value for the Type
. Two or more hands having a
EvalRank
of equal value indicate that the hands have equivalent ranks, and
have both won.
Eval
's can be sorted (low-to-high) by the Eval
's HiRank
and LoRank
member variables. Winner(s) of a hand will be the hands in the lowest position
and having equivalent HiRank
's or LoRank
's.
A Eval
can be compared to another Eval
using Comp
.
Comp
returns -1
, 0
, or +1
, making it easy to compare or sort hands:
// Compare a and b's Hi:
if a.Comp(b, false) < 0 {
fmt.Printf("%s is a winner!", a)
}
// Compare a and b's Lo:
if a.Comp(b, true) == 0 {
fmt.Printf("%s and %s are equal!", a, b)
}
// Sort slice of []*Eval by Hi:
sort.Slice(evs, func(i, j int) bool {
return evs[i].Comp(evs[j], false) < 0
})
// Sort slice of []*Eval by Lo:
sort.Slice(evs, func(i, j int) bool {
return evs[i].Comp(evs[j], true) < 0
})
The package level Order
func is provided as a high-level way to
order Eval
slices and to determine winners. See ordering evals
below.
Order
can determine the winner(s) of a hand by ordering the indexes
of a []*Eval
and returning the list of ordered evals as a []int
and
an int
pivot indicating the position within the returned []int
as a cutoff
for a win:
// Order by HiRank:
hiOrder, hiPivot := cardrank.Order(evs, false)
For a Type with a lo value:
// Order by LoRank:
loOrder, loPivot := cardrank.Order(evs, true)
A Eval
whose index is in position i < pivot
is considered to be the
winner(s). When ordering by HiRank
, there will be 1 or more winner(s) (with
exception for Video
types), but when ordering by LoRank
there may
be 0 or more winner(s):
for i := 0; i < hiPivot; i++ {
fmt.Printf("%s is a Hi winner!", evs[hiOrder[i]])
}
Similarly, for lo winners:
for i := 0; i < loPivot; i++ {
fmt.Printf("%s is a Lo winner!", evs[loOrder[i]])
}
Build tags can be used with go build
to change the package's build
configuration. Available tags:
The portable
tag disables inclusion of the Two-plus-two lookup
tables, and creating significantly smaller binaries but at the
cost of more expensive poker hand rank evaluation. Useful when building for
portable or embedded environments, such as a client application:
go build -tags portable
The embedded
tag disables the CactusFast
and the TwoPlusTwo
, creating the
smallest possible binaries. Useful when either embedding the package in another
application, or in constrained runtime environments such as WASM:
GOOS=js GOARCH=wasm go build -tags embedded
The noinit
tag disables the package level initialization. Useful when
applications need the fastest possible startup times and can defer
initialization, or when using a third-party algorithm:
GOOS=js GOARCH=wasm go build -tags 'embedded noinit' -o cardrank.wasm
When using the noinit
build tag, the user will need to call the Init
func to set RankCactus
and to register the default types
automatically:
// Set DefaultCactus, DefaultRank based on available implementations:
cardrank.Init()
Alternatively, the RankCactus
can be set manually. After RankCactus
has
been set, call RegisterDefaultTypes
to register built in types:
// Set when using a third-party implementation, or experimenting with new
// Cactus implementations:
cardrank.RankCactus = cardrank.CactusFast
// Call RegisterDefaultTypes to register default types
if err := cardrank.RegisterDefaultTypes(); err != nil {
panic(err)
}
The forcefat
tag forces a "fat" binary build, including the TwoPlusTwo
's
large lookup table, irrespective of other build tags:
GOOS=js GOARCH=wasm go build -tags 'forcefat' -o cardrank.wasm
- Overview of Cactus Kev - original Cactus Kev article
- Coding the Wheel - article covering various poker hand evaluators
- Paul Senzee Perfect Hash for Cactus Kev - overview of the "Fast Cactus" perfect hash by Paul Senzee
- TwoPlusTwoHandEvaluator - original implementation of the Two-Plus-Two evaluator