SkillAgentSearch skills...

Cardrank

Go types, funcs, and utilities for working with cards, decks, and evaluating poker hands (Holdem, Omaha, Stud, more)

Install / Use

/learn @cardrank/Cardrank
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

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.

Tests Go Report Card [Reference][pkg] Releases

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

View on GitHub
GitHub Stars143
CategoryDevelopment
Updated21d ago
Forks12

Languages

Go

Security Score

100/100

Audited on Mar 16, 2026

No findings