Cardrank
Go types, funcs, and utilities for working with cards, decks, and evaluating poker hands (Holdem, Omaha, Stud, more)
Install / Use
/learn @cardrank/CardrankREADME
About
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.
Overview
The cardrank package contains types for working with [Card's][card],
[Suit's][suit], [Rank's][rank], [Deck's][deck], [evaluating poker
ranks][eval], and [managing deals and run outs][dealer].
In most cases, using [the high-level Dealer][dealer] with any [registered
Type][type] should be sufficient for most purposes. An in-depth example is
provided [in the package documentation][pkg-example].
A [Type][type] wraps a [type description][type-desc] defining a type's [deal
streets][street-desc], [deck][deck-type], [eval][eval-type], [Hi/Lo
description][desc-type] and other meta-data needed for [dealing streets and
managing run outs][dealer].
[Evaluation and ranking][eval-ranking] of the [types][type] is accomplished through pure Go implementations of well-known poker rank evaluation algorithms. [Evaluation][eval] of cards can be compared and [ordered to determine winner(s)][winners].
Supported Types
Supports [evaluating and ranking][eval] the following [Type][type]'s:
| Holdem Variants | Omaha Variants | Hybrid Variants | Draw Variants | Other |
| ------------------ | ------------------------ | ---------------------- | ------------------ | ----------------------- |
| [Holdem][type] | [Omaha][type] | [Dallas][type] | [Video][type] | [Soko][type] |
| [Split][type] | [OmahaHiLo][type] | [DallasDouble][type] | [Draw][type] | [SokoHiLo][type] |
| [Short][type] | [OmahaDouble][type] | [Houston][type] | [DrawHiLo][type] | [Lowball][type] |
| [Manila][type] | [OmahaFive][type] | [Fusion][type] | [Stud][type] | [LowballTriple][type] |
| [Spanish][type] | [OmahaSix][type] | [FusionHiLo][type] | [StudHiLo][type] | [Razz][type] |
| [Royal][type] | [Jakarta][type] | | [StudFive][type] | [Badugi][type] |
| [Double][type] | [Courchevel][type] | | | |
| [Showtime][type] | [CourchevelHiLo][type] | | | |
| [Swap][type] | | | | |
| [River][type] | | | | |
See the package's [Type][type] documentation for an overview of the above.
Using
To use within a Go package:
go get github.com/cardrank/cardrank
See package level [Go package documentation][pkg] for in-depth overviews of APIs.
Quickstart
Various examples are available in the [Go package documentation][pkg] showing use of various types, utilities, and interfaces.
Additional examples for a [Dealer][dealer] and the [Holdem][type] and
[OmahaHiLo][type] types are included in the example directory:
- dealer - shows use of the [
Dealer][dealer], to handle dealing cards, handling multiple run outs, and determining winners using any [Type's][type] - holdem - shows using types and utilities to deal [
Holdem][type] - omahahilo - shows using types and utilities to [
OmahaHiLo][type], demonstrating splitting Hi and Lo wins
Eval Ranking
[EvalRank][eval-rank]'s are determined using a registered
[EvalFunc][eval-func] associated with the [Type][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][card] can be passed to a [Type's][type] Eval
method, which in turn uses the Type's registered [EvalFunc][eval-func] and
returns an [Evaluated][eval] 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][eval.hi-rank] and [LoRank][eval.lo-rank] values will be set to
[Invalid][invalid].
[Eval][eval]'s can be used to compare different hands of Card's in order to
determine a winner, by comparing the [Eval.HiRank][eval.hi-rank] or
[Eval.LoRank][eval.lo-rank] values.
Hi/Lo
Different [Type's][type] may have both a Hi and Lo [EvalRank][eval-rank],
such as [Double][type] board [Holdem][type], and various *HiLo variants,
such as [OmahaHiLo][type].
When a [Eval][eval] is created, both the Hi and Lo values will be made
available in the resulting Eval as the [HiRank][eval.hi-rank] and
[LoRank][eval.lo-rank], respectively.
Cactus Kev
For most [Type's][type], the [EvalRank][eval-rank] is determined by Go
implementations of a few well-known [Cactus Kev][cactus-kev] algorithms:
- [
Cactus][cactus] - the original [Cactus Kev][cactus-kev] poker hand evaluator - [
CactusFast][cactus-fast] - the [Fast Cactus][senzee] poker hand evaluator, using Paul Senzee's perfect hash lookup - [
TwoPlusTwo][two-plus-two] - the [2+2 forum][tangentforks] 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][build-tags] to enable/disable functionality for different target runtime environments.
Rank Cactus Func
The package-level [RankCactus][rank-cactus] variable is used for regular
poker evaluation, and can be set externally when wanting to build new game
types, or trying new algorithms.
Two-Plus-Two
[NewTwoPlusTwoEval][two-plus-two] 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][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][build-tags].
Winner Determination
Winner(s) are determined by the [lowest possible EvalRank][eval-rank] for
either the Hi or Lo value for the [Type][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.
Comparing Eval Ranks
A [Eval][eval] can be compared to another Eval using [Comp][eval.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][order] func is provided as a high-level way to
order Eval slices and to determine winners. See ordering evals
below.
Ordering Evals
[Order][order] can determine the winner(s) of a hand by ordering the indexes
of a [[]*Eval][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][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][type] 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
Build tags can be used with go build to change the package's build
configuration. Available tags:
portable
The portable tag disables inclusion of the [Two-plus-two lookup
tables][two-plus-two], 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 b
Related Skills
node-connect
349.9kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
xurl
349.9kA CLI tool for making authenticated requests to the X (Twitter) API. Use this skill when you need to post tweets, reply, quote, search, read posts, manage followers, send DMs, upload media, or interact with any X API v2 endpoint.
frontend-design
109.8kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
349.9kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
