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 |
DallasDouble |
Draw |
SokoHiLo |
Short |
OmahaDouble |
Houston |
DrawHiLo |
Lowball |
Manila |
OmahaFive |
Fusion |
Stud |
LowballTriple |
Spanish |
OmahaSix |
FusionHiLo |
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/cardrankSee 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:
// truePocket 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 Evaluated 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] - 1When 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 portableThe 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 embeddedThe 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.wasmWhen 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
