cardrank

package module
v0.14.9 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 29, 2024 License: MIT Imports: 14 Imported by: 0

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 Releases

Overview

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).

Supported Types

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 Courchevel StudFive Badugi
Double CourchevelHiLo
Showtime
Swap
River

See the package's 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 for in-depth overviews of APIs.

Quickstart

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 any Type's
  • holdem - shows using types and utilities to deal Holdem
  • omahahilo - shows using types and utilities to OmahaHiLo, demonstrating splitting Hi and Lo wins
Eval Ranking

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 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] - 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.

Hi/Lo

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.

Cactus Kev

For most Type's, the EvalRank is determined by Go implementations of a few well-known Cactus Kev algorithms:

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.

Rank Cactus Func

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.

Two-Plus-Two

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 Determination

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.

Comparing Eval Ranks

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.

Ordering Evals

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

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, 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
embedded

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
noinit

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)
}
forcefat

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

Documentation

Overview

Package cardrank is a library of types, utilities, and interfaces for working with playing cards, card decks, evaluating poker hand ranks, and managing deals and run outs for different game types.

Example
package main

import (
	"fmt"
	"math/rand"

	"github.com/cardrank/cardrank"
)

func main() {
	for i, game := range []struct {
		seed     int64
		players  int
		change   byte
		runs     int
		inactive []int
		names    []string
	}{
		{566, 2, 't', 3, nil, []string{"Alice", "Bob"}},
		{1039, 5, 'f', 2, []int{0, 3, 4}, []string{"Alice", "Bob", "Carl", "Dave", "Elizabeth"}},
		{2087, 6, 't', 2, []int{0, 5}, []string{"Alice", "Bob", "Carl", "Dave", "Elizabeth", "Frank"}},
		{4022, 6, 'p', 2, []int{0, 1, 4}, []string{"Alice", "Bob", "Carl", "Dave", "Elizabeth", "Fenny"}},
	} {
		// note: use a real random source
		r := rand.New(rand.NewSource(game.seed))
		fmt.Printf("------ FusionHiLo %d ------\n", i+1)
		// setup dealer and display
		d := cardrank.FusionHiLo.Dealer(r, 1, game.players)
		// display deck
		deck := d.Deck.All()
		fmt.Println("Deck:")
		for i := 0; i < len(deck); i += 8 {
			n := i + 8
			if n > len(deck) {
				n = len(deck)
			}
			fmt.Printf("  %v\n", deck[i:n])
		}
		last := -1
		for d.Next() {
			i, run := d.Run()
			if last != i {
				fmt.Printf("Run %d:\n", i)
			}
			last = i
			fmt.Printf("  %s\n", d)
			// display pockets
			if d.HasPocket() {
				for i := 0; i < game.players; i++ {
					fmt.Printf("    %d %s: %v\n", i, game.names[i], run.Pockets[i])
				}
			}
			// display discarded cards
			if v := d.Discarded(); len(v) != 0 {
				fmt.Printf("    Discard: %v\n", v)
			}
			// display board
			if d.HasBoard() {
				fmt.Printf("    Board: %v\n", run.Hi)
				if d.Double {
					fmt.Printf("           %v\n", run.Lo)
				}
			}
			// change runs, deactivate positions
			if d.Id() == game.change && i == 0 {
				if success := d.ChangeRuns(game.runs); !success {
					panic("unable to change runs")
				}
				// deactivate
				if success := d.Deactivate(game.inactive...); !success {
					panic("unable to deactivate positions")
				}
			}
		}
		fmt.Println("Showdown:")
		for d.NextResult() {
			n, res := d.Result()
			fmt.Printf("  Run %d:\n", n)
			for i := 0; i < game.players; i++ {
				if d.Active[i] {
					hi := res.Evals[i].Desc(false)
					fmt.Printf("    %d: %v %v %s\n", i, hi.Best, hi.Unused, hi)
					if d.Low || d.Double {
						lo := res.Evals[i].Desc(true)
						fmt.Printf("       %v %v %s\n", lo.Best, lo.Unused, lo)
					}
				} else {
					fmt.Printf("    %d: inactive\n", i)
				}
			}
			hi, lo := res.Win(game.names...)
			fmt.Printf("    Result: %S\n", hi)
			if lo != nil {
				fmt.Printf("            %S\n", lo)
			}
		}
	}
}
Output:

------ FusionHiLo 1 ------
Deck:
  [4h Qs 5c 4c 5d 8d 8c As]
  [Ks 6h 7s 9s 3h Ac Js 9h]
  [4s 7d 2h 8s 2s Ad Ts Qh]
  [Qc 5h 6s 9d 9c 6c Kd 2d]
  [3s Ah Kh 5s Jd Jc 2c Td]
  [3c Jh 8h 4d Th 7c 7h 3d]
  [6d Tc Kc Qd]
Run 0:
  p: Pre-Flop (p: 2)
    0 Alice: [4h 5c]
    1 Bob: [Qs 4c]
  f: Flop (p: 1, d: 1, b: 3)
    0 Alice: [4h 5c 5d]
    1 Bob: [Qs 4c 8d]
    Discard: [8c]
    Board: [As Ks 6h]
  t: Turn (p: 1, d: 1, b: 1)
    0 Alice: [4h 5c 5d 7s]
    1 Bob: [Qs 4c 8d 9s]
    Discard: [8c 3h]
    Board: [As Ks 6h Ac]
  r: River (d: 1, b: 1)
    Discard: [8c 3h Js]
    Board: [As Ks 6h Ac 9h]
Run 1:
  r: River (d: 1, b: 1)
    Discard: [4s]
    Board: [As Ks 6h Ac 7d]
Run 2:
  r: River (d: 1, b: 1)
    Discard: [2h]
    Board: [As Ks 6h Ac 8s]
Showdown:
  Run 0:
    0: [Ac As 5c 5d Ks] [9h 7s 6h 4h] Two Pair, Aces over Fives, kicker King
       [] [] None
    1: [Ac As 9h 9s Qs] [Ks 8d 6h 4c] Two Pair, Aces over Nines, kicker Queen
       [] [] None
    Result: Bob scoops with Two Pair, Aces over Nines, kicker Queen
  Run 1:
    0: [Ac As 7d 7s 5c] [Ks 6h 5d 4h] Two Pair, Aces over Sevens, kicker Five
       [7d 6h 5c 4h As] [Ac Ks 7s 5d] Seven, Six, Five, Four, Ace-low
    1: [Ac As Ks Qs 9s] [8d 7d 6h 4c] Pair, Aces, kickers King, Queen, Nine
       [8d 7d 6h 4c As] [Ac Ks Qs 9s] Eight, Seven, Six, Four, Ace-low
    Result: Alice wins with Two Pair, Aces over Sevens, kicker Five
            Alice wins with Seven, Six, Five, Four, Ace-low
  Run 2:
    0: [Ac As 5c 5d Ks] [8s 7s 6h 4h] Two Pair, Aces over Fives, kicker King
       [8s 6h 5c 4h As] [Ac Ks 7s 5d] Eight, Six, Five, Four, Ace-low
    1: [As Ks Qs 9s 8s] [Ac 8d 6h 4c] Flush, Ace-high, kickers King, Queen, Nine, Eight
       [] [] None
    Result: Bob wins with Flush, Ace-high, kickers King, Queen, Nine, Eight
            Alice wins with Eight, Six, Five, Four, Ace-low
------ FusionHiLo 2 ------
Deck:
  [2h 5s Ac Ts Kd 5h 6d Th]
  [2s 6s 7c 4h 8c 9h Ah 8s]
  [Kc 9d 5c 5d As 4d 3h 2c]
  [7s 8h 4c 7d 8d Qs 3c 7h]
  [Jc Jh 6c 3s Qd 9c 4s 3d]
  [Ks Ad Qc Td Tc Qh Js 6h]
  [2d 9s Jd Kh]
Run 0:
  p: Pre-Flop (p: 2)
    0 Alice: [2h 5h]
    1 Bob: [5s 6d]
    2 Carl: [Ac Th]
    3 Dave: [Ts 2s]
    4 Elizabeth: [Kd 6s]
  f: Flop (p: 1, d: 1, b: 3)
    0 Alice: [2h 5h 7c]
    1 Bob: [5s 6d 4h]
    2 Carl: [Ac Th 8c]
    3 Dave: [Ts 2s 9h]
    4 Elizabeth: [Kd 6s Ah]
    Discard: [8s]
    Board: [Kc 9d 5c]
  t: Turn (p: 1, d: 1, b: 1)
    0 Alice: [2h 5h 7c 5d]
    1 Bob: [5s 6d 4h As]
    2 Carl: [Ac Th 8c 4d]
    3 Dave: [Ts 2s 9h 3h]
    4 Elizabeth: [Kd 6s Ah 2c]
    Discard: [8s 7s]
    Board: [Kc 9d 5c 8h]
  r: River (d: 1, b: 1)
    Discard: [8s 7s 4c]
    Board: [Kc 9d 5c 8h 7d]
Run 1:
  t: Turn (p: 1, d: 1, b: 1)
    0 Alice: [2h 5h 7c 8d]
    1 Bob: [5s 6d 4h Qs]
    2 Carl: [Ac Th 8c 3c]
    3 Dave: [Ts 2s 9h 7h]
    4 Elizabeth: [Kd 6s Ah Jc]
    Discard: [Jh]
    Board: [Kc 9d 5c 6c]
  r: River (d: 1, b: 1)
    Discard: [Jh 3s]
    Board: [Kc 9d 5c 6c Qd]
Showdown:
  Run 0:
    0: inactive
    1: [9d 8h 7d 6d 5s] [As Kc 5c 4h] Straight, Nine-high
       [8h 7d 5c 4h As] [Kc 9d 6d 5s] Eight, Seven, Five, Four, Ace-low
    2: [8c 8h Ac Kc 9d] [Th 7d 5c 4d] Pair, Eights, kickers Ace, King, Nine
       [8h 7d 5c 4d Ac] [Kc Th 9d 8c] Eight, Seven, Five, Four, Ace-low
    3: inactive
    4: inactive
    Result: Bob wins with Straight, Nine-high
            Bob, Carl split with Eight, Seven, Five, Four, Ace-low
  Run 1:
    0: inactive
    1: [Qd Qs 6c 6d Kc] [9d 5c 5s 4h] Two Pair, Queens over Sixes, kicker King
       [] [] None
    2: [Ac Kc 8c 6c 5c] [Qd Th 9d 3c] Flush, Ace-high, kickers King, Eight, Six, Five
       [] [] None
    3: inactive
    4: inactive
    Result: Carl scoops with Flush, Ace-high, kickers King, Eight, Six, Five
------ FusionHiLo 3 ------
Deck:
  [8h 5d 5c 3h Jc 6h Kd Td]
  [6s As 7c 6c 2c Jd 9h 8c]
  [7s 5s 8d Tc 3s Kc Qh Qd]
  [7d Ks Jh 4s 9s 4h Th Qc]
  [Ah 2d Ts 7h 4c Qs Kh 6d]
  [9d 2s Js 3d 5h 2h Ac Ad]
  [3c 8s 4d 9c]
Run 0:
  p: Pre-Flop (p: 2)
    0 Alice: [8h Kd]
    1 Bob: [5d Td]
    2 Carl: [5c 6s]
    3 Dave: [3h As]
    4 Elizabeth: [Jc 7c]
    5 Frank: [6h 6c]
  f: Flop (p: 1, d: 1, b: 3)
    0 Alice: [8h Kd 2c]
    1 Bob: [5d Td Jd]
    2 Carl: [5c 6s 9h]
    3 Dave: [3h As 8c]
    4 Elizabeth: [Jc 7c 7s]
    5 Frank: [6h 6c 5s]
    Discard: [8d]
    Board: [Tc 3s Kc]
  t: Turn (p: 1, d: 1, b: 1)
    0 Alice: [8h Kd 2c Qh]
    1 Bob: [5d Td Jd Qd]
    2 Carl: [5c 6s 9h 7d]
    3 Dave: [3h As 8c Ks]
    4 Elizabeth: [Jc 7c 7s Jh]
    5 Frank: [6h 6c 5s 4s]
    Discard: [8d 9s]
    Board: [Tc 3s Kc 4h]
  r: River (d: 1, b: 1)
    Discard: [8d 9s Th]
    Board: [Tc 3s Kc 4h Qc]
Run 1:
  r: River (d: 1, b: 1)
    Discard: [Ah]
    Board: [Tc 3s Kc 4h 2d]
Showdown:
  Run 0:
    0: inactive
    1: [Qc Qd Tc Td Kc] [Jd 5d 4h 3s] Two Pair, Queens over Tens, kicker King
       [] [] None
    2: [Kc Qc Tc 9h 7d] [6s 5c 4h 3s] King-high, kickers Queen, Ten, Nine, Seven
       [] [] None
    3: [Kc Ks 3h 3s Qc] [As Tc 8c 4h] Two Pair, Kings over Threes, kicker Queen
       [] [] None
    4: [Kc Qc Jc Tc 7c] [Jh 7s 4h 3s] Flush, King-high, kickers Queen, Jack, Ten, Seven
       [] [] None
    5: inactive
    Result: Elizabeth scoops with Flush, King-high, kickers Queen, Jack, Ten, Seven
  Run 1:
    0: inactive
    1: [Tc Td Kc Qd 4h] [Jd 5d 3s 2d] Pair, Tens, kickers King, Queen, Four
       [] [] None
    2: [6s 5c 4h 3s 2d] [Kc Tc 9h 7d] Straight, Six-high
       [6s 5c 4h 3s 2d] [Kc Tc 9h 7d] Six, Five, Four, Three, Two-low
    3: [Kc Ks 3h 3s Tc] [As 8c 4h 2d] Two Pair, Kings over Threes, kicker Ten
       [8c 4h 3s 2d As] [Kc Ks Tc 3h] Eight, Four, Three, Two, Ace-low
    4: [Jc Jh Kc Tc 4h] [7c 7s 3s 2d] Pair, Jacks, kickers King, Ten, Four
       [] [] None
    5: inactive
    Result: Carl wins with Straight, Six-high
            Carl wins with Six, Five, Four, Three, Two-low
------ FusionHiLo 4 ------
Deck:
  [Qc 4h 2c 7c Kc 5c 9d 5h]
  [3c Tc 9c Qd As 4s 5d Jc]
  [4c Ad 9s 8s Qh 3h Td 7h]
  [7s Ks 6d Kd 7d Jh 2d Js]
  [4d 6h Th Ah Ac Ts 3d 6c]
  [Jd 2s 2h 9h 3s 5s 8d 8c]
  [Qs 8h Kh 6s]
Run 0:
  p: Pre-Flop (p: 2)
    0 Alice: [Qc 9d]
    1 Bob: [4h 5h]
    2 Carl: [2c 3c]
    3 Dave: [7c Tc]
    4 Elizabeth: [Kc 9c]
    5 Fenny: [5c Qd]
  f: Flop (p: 1, d: 1, b: 3)
    0 Alice: [Qc 9d As]
    1 Bob: [4h 5h 4s]
    2 Carl: [2c 3c 5d]
    3 Dave: [7c Tc Jc]
    4 Elizabeth: [Kc 9c 4c]
    5 Fenny: [5c Qd Ad]
    Discard: [9s]
    Board: [8s Qh 3h]
  t: Turn (p: 1, d: 1, b: 1)
    0 Alice: [Qc 9d As Td]
    1 Bob: [4h 5h 4s 7h]
    2 Carl: [2c 3c 5d 7s]
    3 Dave: [7c Tc Jc Ks]
    4 Elizabeth: [Kc 9c 4c 6d]
    5 Fenny: [5c Qd Ad Kd]
    Discard: [9s 7d]
    Board: [8s Qh 3h Jh]
  r: River (d: 1, b: 1)
    Discard: [9s 7d 2d]
    Board: [8s Qh 3h Jh Js]
Run 1:
  f: Flop (p: 1, d: 1, b: 3)
    0 Alice: [Qc 9d 4d]
    1 Bob: [4h 5h 6h]
    2 Carl: [2c 3c Th]
    3 Dave: [7c Tc Ah]
    4 Elizabeth: [Kc 9c Ac]
    5 Fenny: [5c Qd Ts]
    Discard: [3d]
    Board: [6c Jd 2s]
  t: Turn (p: 1, d: 1, b: 1)
    0 Alice: [Qc 9d 4d 2h]
    1 Bob: [4h 5h 6h 9h]
    2 Carl: [2c 3c Th 3s]
    3 Dave: [7c Tc Ah 5s]
    4 Elizabeth: [Kc 9c Ac 8d]
    5 Fenny: [5c Qd Ts 8c]
    Discard: [3d Qs]
    Board: [6c Jd 2s 8h]
  r: River (d: 1, b: 1)
    Discard: [3d Qs Kh]
    Board: [6c Jd 2s 8h 6s]
Showdown:
  Run 0:
    0: inactive
    1: inactive
    2: [Jh Js 3c 3h 7s] [Qh 8s 5d 2c] Two Pair, Jacks over Threes, kicker Seven
       [] [] None
    3: [Jc Jh Js Ks Qh] [Tc 8s 7c 3h] Three of a Kind, Jacks, kickers King, Queen
       [] [] None
    4: inactive
    5: [Qd Qh Jh Js Ad] [Kd 8s 5c 3h] Two Pair, Queens over Jacks, kicker Ace
       [] [] None
    Result: Dave scoops with Three of a Kind, Jacks, kickers King, Queen
  Run 1:
    0: inactive
    1: inactive
    2: [6c 6s 3c 3s Jd] [Th 8h 2c 2s] Two Pair, Sixes over Threes, kicker Jack
       [] [] None
    3: [6c 6s Ah Jd Tc] [8h 7c 5s 2s] Pair, Sixes, kickers Ace, Jack, Ten
       [8h 6c 5s 2s Ah] [Jd Tc 7c 6s] Eight, Six, Five, Two, Ace-low
    4: inactive
    5: [8c 8h 6c 6s Qd] [Jd Ts 5c 2s] Two Pair, Eights over Sixes, kicker Queen
       [] [] None
    Result: Fenny wins with Two Pair, Eights over Sixes, kicker Queen
            Dave wins with Eight, Six, Five, Two, Ace-low
Example (ComputerHand)
package main

import (
	"context"
	"fmt"

	"github.com/cardrank/cardrank"
)

func main() {
	pocket := cardrank.Must("Qh 7s")
	expv, ok := cardrank.Holdem.ExpValue(context.Background(), pocket)
	if !ok {
		panic("unable to calculate expected value")
	}
	fmt.Println("expected value:", expv)
}
Output:

expected value: 51.8% (1046780178,78084287/2097572400)

Index

Examples

Constants

View Source
const (
	UnicodeSpadeAce     rune = '🂡'
	UnicodeHeartAce     rune = '🂱'
	UnicodeDiamondAce   rune = '🃁'
	UnicodeClubAce      rune = '🃑'
	UnicodeSpadeBlack   rune = '♠'
	UnicodeSpadeWhite   rune = '♤'
	UnicodeHeartBlack   rune = '♥'
	UnicodeHeartWhite   rune = '♡'
	UnicodeDiamondBlack rune = '♦'
	UnicodeDiamondWhite rune = '♢'
	UnicodeClubBlack    rune = '♣'
	UnicodeClubWhite    rune = '♧'
)

Unicode card runes.

View Source
const (
	// DeckFrench is a standard deck of 52 playing cards.
	DeckFrench = DeckType(Two)
	// DeckShort is a deck of 36 playing cards of rank 6+ (see [Short]).
	DeckShort = DeckType(Six)
	// DeckManila is a deck of 32 playing cards of rank 7+ (see [Manila]).
	DeckManila = DeckType(Seven)
	// DeckSpanish is a deck of 28 playing cards of rank 8+ (see [Spanish]).
	DeckSpanish = DeckType(Eight)
	// DeckRoyal is a deck of 20 playing cards of rank 10+ (see [Royal]).
	DeckRoyal = DeckType(Ten)
	// DeckKuhn is a deck of 3 playing cards, a [King], [Queen], and a [Jack]
	// (see [Kuhn]).
	DeckKuhn = DeckType(^uint8(0) - 1)
	// DeckLeduc is a deck of 6 playing cards, a [King], [Queen], and a [Jack]
	// of the [Spade] and [Heart] suits (see [Leduc]).
	DeckLeduc = DeckType(^uint8(0) - 2)
)

Deck types.

View Source
const InvalidCard = ^Card(0)

InvalidCard is an invalid card.

View Source
const InvalidRank = ^Rank(0)

InvalidRank is an invalid card rank.

View Source
const InvalidSuit = ^Suit(0)

InvalidSuit is an invalid card suit.

Variables

View Source
var AlternateEmoji = [4]string{
	"♠️",
	"♥️",
	"🔷",
	"☘️",
}

AlternateEmoji are alternate emoji pips.

Functions

func CactusDesc added in v0.9.0

func CactusDesc(f fmt.State, verb rune, rank EvalRank, best, unused []Card)

CactusDesc writes a Cactus description to f for the rank, best, and unused cards.

Examples:

Straight Flush, Ace-high, Royal
Straight Flush, King-high, Platinum Oxide
Straight Flush, Five-high, Steel Wheel
Four of a Kind, Nines, kicker Jack
Full House, Sixes full of Fours
Flush, Ten-high
Straight, Eight-high
Three of a Kind, Fours, kickers Ace, King
Two Pair, Nines over Sixes, kicker Jack
Pair, Aces, kickers King, Queen, Nine
Seven-high, kickers Six, Five, Three, Two

func FlushOverDesc added in v0.10.0

func FlushOverDesc(f fmt.State, verb rune, rank EvalRank, best, unused []Card)

FlushOverDesc writes a FlushOver description to f for the rank, best, and unused cards.

func HashKey added in v0.13.0

func HashKey(c0, c1 Card) string

HashKey returns the hash key of the pocket cards.

func HighDesc added in v0.14.7

func HighDesc(f fmt.State, verb rune, rank EvalRank, best, unused []Card)

HighDesc writes a [High] description to f for the rank, best, and unused cards.

func HoldemBlinds added in v0.8.0

func HoldemBlinds() []string

HoldemBlinds returns the Holdem blind names.

func HoldemStarting added in v0.13.0

func HoldemStarting() map[string]ExpValue

HoldemStarting returns the starting Holdem pockets.

func Init

func Init()

Init inits the package level default variables. Must be manually called prior to using the package when built with the [noinit] build tag.

func LowDesc added in v0.9.0

func LowDesc(f fmt.State, verb rune, rank EvalRank, best, unused []Card)

LowDesc writes a Low description to f for the rank, best, and unused cards.

func LowballDesc added in v0.9.0

func LowballDesc(f fmt.State, verb rune, rank EvalRank, best, unused []Card)

LowballDesc writes a Lowball description to f for the rank, best, and unused cards.

func NewTwoPlusTwoEval added in v0.10.0

func NewTwoPlusTwoEval() func([]Card) EvalRank

NewTwoPlusTwoEval creates a new Two-Plus-Two rank eval func, a version of the 2+2 poker forum rank evaluator. Uses the embedded twoplustwo*.dat files to provide extremely fast 7 card lookup.

The lookup table is contained in the embedded 'twoplustwo*.dat' files, broken up from a single file to get around GitHub's size limitations. Files were generated with 'internal/twoplustwogen.go', which is a pure-Go port of the reference TwoPlusTwoHandEvaluator.

When recombined, the lookup table has the same hash as the original table generated using the C code.

func Order

func Order(evs []*Eval, low bool) ([]int, int)

Order builds an ordered slice of indices for the provided evals, ordered by either Hi or Lo (per Eval.Comp), returning the slice of indices and a pivot into the indices indicating the winning vs losing position.

Pivot will always be 1 or higher when ordering by Hi's. When ordering by Lo's, if there are no valid (ie, qualified) evals, the returned pivot will be 0.

func RazzDesc added in v0.9.0

func RazzDesc(f fmt.State, verb rune, rank EvalRank, best, unused []Card)

RazzDesc writes a Razz description to f for the rank, best, and unused cards.

func RegisterDefaultTypes added in v0.8.0

func RegisterDefaultTypes() error

RegisterDefaultTypes registers default types.

See DefaultTypes.

func RegisterType added in v0.8.0

func RegisterType(desc TypeDesc) error

RegisterType registers a type.

func SokoDesc added in v0.9.0

func SokoDesc(f fmt.State, verb rune, rank EvalRank, best, unused []Card)

SokoDesc writes a Soko description to f for the rank, best, and unused cards.

func StudBlinds added in v0.8.0

func StudBlinds() []string

StudBlinds returns the Stud blind names.

func ThreeDesc added in v0.14.7

func ThreeDesc(f fmt.State, verb rune, rank EvalRank, best, unused []Card)

ThreeDesc writes a Three description to f for the rank, best, and unused cards.

Types

type BinGen added in v0.11.1

type BinGen[T any] struct {
	// contains filtered or unexported fields
}

BinGen is a binomial combination generator.

func NewBinGen added in v0.11.1

func NewBinGen[T any](s []T, k int) *BinGen[T]

NewBinGen creates a uninitialized binomial combination generator. The generator must be manually initialized by calling Init.

func NewBinGenInit added in v0.13.0

func NewBinGenInit[T any](s []T, k int, unused bool, d []T) *BinGen[T]

NewBinGenInit creates and initializes a binomial combination generator using f and d.

func NewCombinGen added in v0.13.0

func NewCombinGen[T any](s []T, k int) (*BinGen[T], []T)

NewCombinGen creates a binomial combination generator.

func NewCombinUnusedGen added in v0.13.0

func NewCombinUnusedGen[T any](s []T, k int) (*BinGen[T], []T)

NewCombinUnusedGen creates a binomial combination generator that also copies the unused values.

func (*BinGen[T]) Copy added in v0.13.0

func (g *BinGen[T]) Copy()

Copy copies the next combination, storing in d.

func (*BinGen[T]) Next added in v0.11.1

func (g *BinGen[T]) Next() bool

Next generates the next binomial combination.

func (*BinGen[T]) Unused added in v0.13.0

func (g *BinGen[T]) Unused()

Unused copies the next combination, storing in d along with the unused values.

type CalcOption added in v0.11.1

type CalcOption func(interface{})

CalcOption is a calc option.

func WithActive added in v0.13.1

func WithActive(active map[int]bool, folded bool) CalcOption

WithActive is a calc option to run with the active map and whether or not folded positions should be included.

func WithBoard added in v0.13.1

func WithBoard(board []Card) CalcOption

WithBoard is a calc option to set the board.

func WithDeep added in v0.13.1

func WithDeep(deep bool) CalcOption

WithDeep is a calc option to set whether the run should run deep calculations.

func WithDiscard added in v0.13.1

func WithDiscard(discard bool) CalcOption

WithDiscard is a calc option to set whether the run's discarded cards should be excluded.

func WithOpponents added in v0.13.1

func WithOpponents(opponents int) CalcOption

WithOpponents is a calc option to set the opponents.

func WithPocketsBoard added in v0.13.1

func WithPocketsBoard(pockets [][]Card, board []Card) CalcOption

WithPocketsBoard is a calc option to run with the pockets, board.

func WithRuns added in v0.13.1

func WithRuns(runs []*Run) CalcOption

WithRuns is a calc option to set the runs.

type Card

type Card uint32

Card is a card consisting of a Rank (23456789TJQKA) and Suit (shdc).

Example (Unmarshal)
package main

import (
	"encoding/json"
	"fmt"
	"log"

	"github.com/cardrank/cardrank"
)

func main() {
	var v []cardrank.Card
	if err := json.Unmarshal([]byte(`["3s", "4c", "5c", "Ah", "2d"]`), &v); err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%s\n", v)
}
Output:

[3s 4c 5c Ah 2d]

func Exclude added in v0.13.0

func Exclude(v []Card, ex ...[]Card) []Card

Exclude is returns v excluding any specified cards.

func FromIndex

func FromIndex(i int) Card

FromIndex creates a card from a numerical index (0-51).

func FromRune

func FromRune(r rune) Card

FromRune creates a card from a unicode playing card rune.

Example
package main

import (
	"fmt"

	"github.com/cardrank/cardrank"
)

func main() {
	c := cardrank.FromRune('🂡')
	fmt.Printf("%b\n", c)
}
Output:

A♠

func FromString

func FromString(s string) Card

FromString creates a card from a string.

Example
package main

import (
	"fmt"

	"github.com/cardrank/cardrank"
)

func main() {
	c := cardrank.FromString("Ah")
	fmt.Printf("%N of %L (%b)\n", c, c, c)
}
Output:

Ace of Hearts (A♥)

func Must

func Must(v ...string) []Card

Must parses common string representations of Card's contained in v, ignoring case and whitespace and panicing on any error.

Returns a single slice of all cards from all strings in v.

See Parse for overview of accepted string representations.

Example
package main

import (
	"fmt"

	"github.com/cardrank/cardrank"
)

func main() {
	v := cardrank.Must("Ah K♠ 🃍 J♤ 10h")
	fmt.Printf("%b", v)
}
Output:

[A♥ K♠ Q♦ J♠ T♥]

func New

func New(rank Rank, suit Suit) Card

New creates a card for the rank and suit.

func Parse

func Parse(v ...string) ([]Card, error)

Parse parses common string representations of Card's contained in v, ignoring case and whitespace.

Accepts the following:

  • a rank followed by a suit (ex: "Ah", "ks", "10s", "Tc", "8d", "6c")
  • a rank followed by a white or black unicode suit pip (ex: "J♤", "K♠")
  • unicode playing card runes (ex: "🃆", "🂣").

Returns a single slice of all cards from all strings in v.

func (Card) AceRank added in v0.10.0

func (c Card) AceRank() int

AceRank returns the card Ace-low index.

func (Card) Format

func (c Card) Format(f fmt.State, verb rune)

Format satisfies the fmt.Formatter interface.

Supported verbs:

s - rank (23456789TJQKA) and suit (shdc) (ex: Ks Ah)
S - same as s, uppercased (ex: KS AH)
q - same as s, quoted (ex: "Ks" "Ah")
v - same as s
r - rank (as in s) without suit (ex: K A)
u - suit (as in s) without rank (shdc)
b - rank (as in s) and the black unicode pip rune (♠♥♦♣) (ex: K♠ A♥)
B - black unicode pip rune (as in b) without rank (♠♥♦♣)
h - rank (as in s) and the white unicode pip rune (♤♡♢♧) (ex: K♤ A♡)
H - white unicode pip rune (as in h) without rank (♤♡♢♧)
e - rank (as in s) and the emoji pip (♠️ ❤️ ♦️ ♣️ ) (ex: K♠️ A❤️ )
E - emoji pip (as in e) without rank (♠️ ❤️ ♦️ ♣️ )
a - rank (as in s) and the alternate emoji pip (see [AlternateEmoji])
A - alternate emoji pip (see [AlternateEmoji])
c - playing card rune (ex: 🂡  🂱  🃁  🃑)
C - playing card rune (as in c), substituting knights for jacks (ex: 🂬  🂼  🃌  🃜)
n - rank name, lower cased (ex: one two jack queen king ace)
N - rank name, title cased (ex: One Two Jack Queen King Ace)
p - plural rank name, lower cased (ex: ones twos sixes)
P - plural rank name, title cased (ex: Ones Twos Sixes)
t - suit name, lower cased (spade heart diamond club)
T - suit name, title cased (Spade Heart Diamond Club)
l - plural suit name, lower cased (spades hearts diamonds clubs)
L - plural suit name, title cased (Spades Hearts Diamonds Clubs)
d - base 10 integer value
F - straight flush rank name

func (Card) Index

func (c Card) Index() int

Index returns the card index.

func (Card) KnightRune added in v0.10.4

func (c Card) KnightRune() rune

KnightRune returns the card's unicode playing card rune, substituting knights for Jack's.

func (Card) MarshalText

func (c Card) MarshalText() ([]byte, error)

MarshalText satisfies the encoding.TextMarshaler interface.

func (Card) Rank

func (c Card) Rank() Rank

Rank returns the card rank.

func (Card) RankByte

func (c Card) RankByte() byte

RankByte returns the card rank byte.

func (Card) RankIndex

func (c Card) RankIndex() int

RankIndex returns the card rank index.

func (Card) Rune added in v0.10.4

func (c Card) Rune() rune

Rune returns the card's unicode playing card rune.

func (Card) String

func (c Card) String() string

String satisfies the fmt.Stringer interface.

func (Card) Suit

func (c Card) Suit() Suit

Suit returns the card suit.

func (Card) SuitByte

func (c Card) SuitByte() byte

SuitByte returns the card suit byte.

func (Card) SuitIndex

func (c Card) SuitIndex() int

SuitIndex returns the card suit index.

func (*Card) UnmarshalText

func (c *Card) UnmarshalText(buf []byte) error

UnmarshalText satisfies the encoding.TextUnmarshaler interface.

type Dealer added in v0.8.0

type Dealer struct {
	TypeDesc
	Deck    *Deck
	Count   int
	Active  map[int]bool
	Runs    []*Run
	Results []*Result
	// contains filtered or unexported fields
}

Dealer maintains deal state for a type, streets, deck, positions, runs, results, and wins. Use as a street and run iterator for a Type. See usage details in the package example.

func NewDealer added in v0.8.0

func NewDealer(desc TypeDesc, deck *Deck, count int) *Dealer

NewDealer creates a new dealer for a provided deck and pocket count.

func NewShuffledDealer added in v0.8.0

func NewShuffledDealer(desc TypeDesc, shuffler Shuffler, shuffles, count int) *Dealer

NewShuffledDealer creates a new deck and dealer, shuffling the deck multiple times and returning the dealer with the created deck and pocket count.

func (*Dealer) Board added in v0.8.0

func (d *Dealer) Board() int

Board returns the number of board cards to be dealt on the current street.

func (*Dealer) BoardDiscard added in v0.9.0

func (d *Dealer) BoardDiscard() int

BoardDiscard returns the number of board cards to be discarded prior to dealing a board on the current street.

func (*Dealer) Calc added in v0.11.1

func (d *Dealer) Calc(ctx context.Context, folded bool, opts ...CalcOption) (*Odds, *Odds, bool)

Calc calculates the run odds, including whether or not to include folded positions.

func (*Dealer) ChangeRuns added in v0.9.2

func (d *Dealer) ChangeRuns(runs int) bool

ChangeRuns changes the number of runs, returning true if successful.

func (*Dealer) Deactivate added in v0.9.0

func (d *Dealer) Deactivate(positions ...int) bool

Deactivate deactivates positions, which will not be dealt further cards and will not be included during eval.

func (*Dealer) Deal added in v0.8.0

func (d *Dealer) Deal(street int, run *Run)

Deal deals pocket and board cards for the street and run, discarding cards accordingly.

func (*Dealer) Discarded added in v0.9.0

func (d *Dealer) Discarded() []Card

Discarded returns the cards discarded on the current street and run.

func (*Dealer) Format added in v0.8.0

func (d *Dealer) Format(f fmt.State, verb rune)

Format satisfies the fmt.Formatter interface.

func (*Dealer) HasActive added in v0.9.0

func (d *Dealer) HasActive() bool

HasActive returns true when there is more than 1 active positions.

func (*Dealer) HasBoard added in v0.9.0

func (d *Dealer) HasBoard() bool

HasBoard returns true when one or more board cards are dealt for the current street.

func (*Dealer) HasCalc added in v0.11.1

func (d *Dealer) HasCalc() bool

HasCalc returns true when odds are available for calculation.

func (*Dealer) HasNext added in v0.10.2

func (d *Dealer) HasNext() bool

HasNext returns true when there is one or more remaining streets.

func (*Dealer) HasPocket added in v0.9.0

func (d *Dealer) HasPocket() bool

HasPocket returns true when one or more pocket cards are dealt for the current street.

func (*Dealer) Id added in v0.9.0

func (d *Dealer) Id() byte

Id returns the current street id.

func (*Dealer) Inactive added in v0.9.0

func (d *Dealer) Inactive() []int

Inactive returns the inactive positions.

func (*Dealer) Name added in v0.11.0

func (d *Dealer) Name() string

Name returns the current street name.

func (*Dealer) Next added in v0.8.0

func (d *Dealer) Next() bool

Next iterates the current street and run, discarding cards prior to dealing additional pocket and board cards for each street and run. Returns true when there are at least 2 active positions for a Type having Max greater than 1 and when there are additional streets or runs.

func (*Dealer) NextId added in v0.9.0

func (d *Dealer) NextId() byte

NextId returns the next street id.

func (*Dealer) NextResult added in v0.9.0

func (d *Dealer) NextResult() bool

NextResult iterates the next result.

func (*Dealer) Pocket added in v0.8.0

func (d *Dealer) Pocket() int

Pocket returns the number of pocket cards to be dealt on the current street.

func (*Dealer) PocketDiscard added in v0.9.0

func (d *Dealer) PocketDiscard() int

PocketDiscard returns the number of cards to be discarded prior to dealing pockets on the current street.

func (*Dealer) PocketDraw added in v0.9.0

func (d *Dealer) PocketDraw() int

PocketDraw returns the number of pocket cards that can be drawn on the current street.

func (*Dealer) PocketUp added in v0.9.0

func (d *Dealer) PocketUp() int

PocketUp returns the number of pocket cards to be turned up on the current street.

func (*Dealer) Reset added in v0.8.0

func (d *Dealer) Reset()

Reset resets the dealer and deck.

func (*Dealer) Result added in v0.9.0

func (d *Dealer) Result() (int, *Result)

Result returns the current result.

func (*Dealer) Run added in v0.9.2

func (d *Dealer) Run() (int, *Run)

Run returns the current run.

func (*Dealer) Street added in v0.8.0

func (d *Dealer) Street() int

Street returns the current street.

type Deck

type Deck struct {
	// contains filtered or unexported fields
}

Deck is a set of playing cards.

func DeckOf added in v0.9.0

func DeckOf(cards ...Card) *Deck

DeckOf creates a deck for the provided cards.

func NewDeck

func NewDeck() *Deck

NewDeck creates a French deck of 52 unshuffled cards.

func NewShoe added in v0.9.0

func NewShoe(count int) *Deck

NewShoe creates a card shoe with multiple sets of 52 unshuffled cards.

func (*Deck) All added in v0.9.0

func (d *Deck) All() []Card

All returns a copy of all cards in the deck, without advancing.

func (*Deck) Draw

func (d *Deck) Draw(count int) []Card

Draw draws count cards from the top (front) of the deck.

Example
package main

import (
	"fmt"
	"math/rand"

	"github.com/cardrank/cardrank"
)

func main() {
	d := cardrank.NewDeck()
	// note: use a real random source
	r := rand.New(rand.NewSource(52))
	d.Shuffle(r, 1)
	v := d.Draw(7)
	fmt.Printf("%b\n", v)
}
Output:

[9♣ 6♥ Q♠ 3♠ J♠ 9♥ K♣]

func (*Deck) Empty

func (d *Deck) Empty() bool

Empty returns true when there are no cards remaining in the deck.

func (*Deck) Limit added in v0.9.0

func (d *Deck) Limit(limit int)

Limit limits the cards for the deck, for use with card shoes composed of more than one deck of cards.

func (*Deck) Remaining

func (d *Deck) Remaining() int

Remaining returns the number of remaining cards in the deck.

func (*Deck) Reset added in v0.8.0

func (d *Deck) Reset()

Reset resets the deck.

func (*Deck) Shuffle

func (d *Deck) Shuffle(shuffler Shuffler, shuffles int)

Shuffle shuffles the deck's cards using the shuffler.

type DeckType added in v0.9.0

type DeckType uint8

DeckType is a deck type.

func (DeckType) Desc added in v0.9.0

func (typ DeckType) Desc(short bool) string

Desc returns the deck description.

func (DeckType) Exclude added in v0.11.1

func (typ DeckType) Exclude(ex ...[]Card) []Card

Exclude returns a set of unshuffled cards excluding any supplied cards.

func (DeckType) Format added in v0.9.0

func (typ DeckType) Format(f fmt.State, verb rune)

Format satisfies the fmt.Formatter interface.

func (DeckType) Name added in v0.9.0

func (typ DeckType) Name() string

Name returns the deck name.

func (DeckType) New added in v0.9.0

func (typ DeckType) New() *Deck

New returns a new deck.

func (DeckType) Ordinal added in v0.9.0

func (typ DeckType) Ordinal() int

Ordinal returns the deck ordinal.

func (DeckType) Shoe added in v0.9.0

func (typ DeckType) Shoe(count int) *Deck

Shoe creates a card shoe composed of count number of decks of unshuffled cards.

func (DeckType) Shuffle added in v0.11.0

func (typ DeckType) Shuffle(shuffler Shuffler, shuffles int) *Deck

Shuffle returns a new deck, shuffled by the shuffler.

func (DeckType) Unshuffled added in v0.9.0

func (typ DeckType) Unshuffled() []Card

Unshuffled returns a set of the deck's unshuffled cards.

type DescType added in v0.9.0

type DescType uint8

DescType is a description type.

const (
	DescCactus    DescType = 0
	DescFlushOver DescType = 'f'
	DescSoko      DescType = 'k'
	DescLow       DescType = 'l'
	DescLowball   DescType = 'b'
	DescRazz      DescType = 'r'
	DescHigh      DescType = 'h'
	DescThree     DescType = '3'
)

Description types.

func (DescType) Byte added in v0.9.0

func (typ DescType) Byte() byte

Byte returns the description type byte.

func (DescType) Desc added in v0.9.0

func (typ DescType) Desc(f fmt.State, verb rune, rank EvalRank, best, unused []Card)

Desc writes a description to f for the rank, best, and unused cards.

Supported verbs:

d - rank formatted as a int (1, 3775, ...)
e - best description, eval rank only (Two Pair, Pair, Flush, 7-Low, ...)
s - best full description (Four of a Kind, Ace, kickers King)
S - best description, no kickers
u - unused cards with [CardFormatter]
v - same as s

func (DescType) Format added in v0.9.0

func (typ DescType) Format(f fmt.State, verb rune)

Format satisfies the fmt.Formatter interface.

func (DescType) Name added in v0.9.0

func (typ DescType) Name() string

Name returns the description type name.

type Error

type Error string

Error is a error.

const (
	// ErrInvalidId is the invalid id error.
	ErrInvalidId Error = "invalid id"
	// ErrMismatchedIdAndType is the mismatched id and type error.
	ErrMismatchedIdAndType Error = "mismatched id and type"
	// ErrInvalidCard is the invalid card error.
	ErrInvalidCard Error = "invalid card"
	// ErrInvalidType is the invalid type error.
	ErrInvalidType Error = "invalid type"
)

Error values.

func (Error) Error

func (err Error) Error() string

Error satisfies the [error] interface.

type Eval added in v0.9.0

type Eval struct {
	Type     Type
	HiRank   EvalRank
	HiBest   []Card
	HiUnused []Card
	LoRank   EvalRank
	LoBest   []Card
	LoUnused []Card
}

Eval contains the eval results of a type's Hi/Lo.

func EvalOf added in v0.9.0

func EvalOf(typ Type) *Eval

EvalOf creates a eval for the type.

func (*Eval) Comp added in v0.9.0

func (ev *Eval) Comp(b *Eval, low bool) int

Comp compares the eval's Hi/Lo to b's Hi/Lo.

func (*Eval) Desc added in v0.9.0

func (ev *Eval) Desc(low bool) *EvalDesc

Desc returns a descriptior for the eval's Hi/Lo.

func (*Eval) Eval added in v0.9.0

func (ev *Eval) Eval(pocket, board []Card)

Eval evaluates the pocket, board.

func (*Eval) Format added in v0.9.0

func (ev *Eval) Format(f fmt.State, verb rune)

Format satisfies the fmt.Formatter interface.

func (*Eval) Hi5 added in v0.10.0

func (ev *Eval) Hi5(f RankFunc, v []Card)

Hi5 evaluates the 5 cards in v, using f.

func (*Eval) Hi6 added in v0.10.0

func (ev *Eval) Hi6(f RankFunc, v []Card)

Hi6 evaluates the 6 cards in v, using f.

func (*Eval) Hi7 added in v0.10.0

func (ev *Eval) Hi7(f RankFunc, v []Card)

Hi7 evaluates the 7 cards in v, using f.

func (*Eval) HiLo23 added in v0.10.0

func (ev *Eval) HiLo23(hi, lo RankFunc, c0, c1 Card, b []Card, max EvalRank)

HiLo23 evaluates the 2 cards c0, c1 and the 3 in b, using hi, lo.

func (*Eval) HiLo24 added in v0.10.0

func (ev *Eval) HiLo24(hi, lo RankFunc, c0, c1 Card, b []Card, max EvalRank)

HiLo24 evaluates the 2 cards c0, c1 and the 4 in b, using hi, lo.

func (*Eval) HiLo25 added in v0.10.0

func (ev *Eval) HiLo25(hi, lo RankFunc, c0, c1 Card, b []Card, max EvalRank)

HiLo25 evaluates the 2 cards c0, c1 and the 5 in b, using hi, lo.

func (*Eval) HiLo5 added in v0.10.0

func (ev *Eval) HiLo5(hi, lo RankFunc, v []Card, max EvalRank)

HiLo5 evaluates the 5 cards in v, using hi, lo.

func (*Eval) HiLo6 added in v0.10.0

func (ev *Eval) HiLo6(hi, lo RankFunc, v []Card, max EvalRank)

HiLo6 evaluates the 6 cards in v, using hi, lo.

func (*Eval) HiLo7 added in v0.10.0

func (ev *Eval) HiLo7(hi, lo RankFunc, v []Card, max EvalRank)

HiLo7 evaluates the 7 cards in v, using hi, lo.

func (*Eval) Max5 added in v0.10.0

func (ev *Eval) Max5(f RankFunc, v []Card, max EvalRank, low bool)

Max5 evaluates the 5 cards in v, using f, storing only when below max.

func (*Eval) Max6 added in v0.10.0

func (ev *Eval) Max6(f RankFunc, v []Card, max EvalRank, low bool)

Max6 evaluates the 6 cards in v, using f, storing only when below max.

func (*Eval) Max7 added in v0.10.0

func (ev *Eval) Max7(f RankFunc, v []Card, max EvalRank, low bool)

Max7 evaluates the 7 cards in v, using f, storing only when below max.

type EvalDesc added in v0.10.4

type EvalDesc struct {
	Type   DescType
	Rank   EvalRank
	Best   []Card
	Unused []Card
}

EvalDesc describes a Hi/Lo eval.

func (*EvalDesc) Format added in v0.10.4

func (desc *EvalDesc) Format(f fmt.State, verb rune)

Format satisfies the fmt.Stringer interface.

type EvalFunc added in v0.8.0

type EvalFunc func(*Eval, []Card, []Card)

EvalFunc is a eval func.

func NewBadugiEval added in v0.8.0

func NewBadugiEval(normalize bool) EvalFunc

NewBadugiEval creates a Badugi eval func.

4 cards, low evaluation of separate suits
All 4 face down pre-flop
3 rounds of player discards (up to 4)

func NewCactusEval added in v0.9.0

func NewCactusEval(normalize, low bool) EvalFunc

NewCactusEval creates a Cactus eval func.

func NewEval added in v0.10.0

func NewEval(f RankFunc) EvalFunc

NewEval returns a eval func that ranks 5, 6, or 7 cards using f. The returned eval func will store the results on an eval's Hi.

func NewHighEval added in v0.14.7

func NewHighEval() EvalFunc

NewHighEval creates a high card eval func.

func NewHybridEval added in v0.10.0

func NewHybridEval(normalize, low bool) EvalFunc

NewHybridEval creates a hybrid Cactus and TwoPlusTwo eval func, using RankCactus for 5 and 6 cards, and a TwoPlusTwo eval func for 7 cards.

Gives optimal performance when evaluating the best-5 of any 5, 6, or 7 cards of a combined pocket and board.

func NewJacksOrBetterEval added in v0.10.0

func NewJacksOrBetterEval(normalize bool) EvalFunc

NewJacksOrBetterEval creates a JacksOrBetter eval func, used for Video.

func NewLeducEval added in v0.14.7

func NewLeducEval() EvalFunc

NewLeducEval creates a matching high card eval func.

func NewLowballEval added in v0.9.0

func NewLowballEval(normalize bool) EvalFunc

NewLowballEval creates a Lowball eval func.

func NewMaxEval added in v0.10.0

func NewMaxEval(f RankFunc, max EvalRank, low bool) EvalFunc

NewMaxEval returns a eval func that ranks 5, 6, or 7 cards using f and max.

The returned eval func will store results on an eval's Hi only when lower than max.

func NewModifiedEval added in v0.10.2

func NewModifiedEval(hi RankFunc, base Rank, inv func(EvalRank) EvalRank, normalize, low bool) EvalFunc

NewModifiedEval creates a modified Cactus eval.

func NewOmahaEval added in v0.8.0

func NewOmahaEval(hi RankFunc, base Rank, inv func(EvalRank) EvalRank, normalize, low bool) EvalFunc

NewOmahaEval creates a Omaha eval func.

Uses any 2 from 2, 3, 4, 5, or 6 pocket cards, and any 3 from 3, 4 or 5 board cards to make a best-5.

func NewRazzEval added in v0.8.0

func NewRazzEval(normalize bool) EvalFunc

NewRazzEval creates a Razz eval func.

func NewSokoEval added in v0.9.0

func NewSokoEval(normalize, low bool) EvalFunc

NewSokoEval creates a Soko eval func.

func NewSplitEval added in v0.10.0

func NewSplitEval(hi, lo RankFunc, max EvalRank) EvalFunc

NewSplitEval returns a eval func that ranks 5, 6, or 7 cards using hi, lo and max.

The returned eval func will store results on an eval's Hi and Lo depending on the result of hi and lo, respectively. Will store the Lo value only when lower than max.

func NewThreeEval added in v0.14.7

func NewThreeEval() EvalFunc

NewThreeEval creates a best-3 eval func.

Straight Flush
Three of a Kind
Straight
Flush
One Pair
High Card

type EvalRank added in v0.9.0

type EvalRank uint16

EvalRank is a eval rank.

Ranks are ordered low-to-high.

const (
	StraightFlush EvalRank = 10
	FourOfAKind   EvalRank = 166
	FullHouse     EvalRank = 322
	Flush         EvalRank = 1599
	Straight      EvalRank = 1609
	ThreeOfAKind  EvalRank = 2467
	TwoPair       EvalRank = 3325
	Pair          EvalRank = 6185
	Nothing       EvalRank = 7462
	HighCard      EvalRank = Nothing
	Invalid       EvalRank = ^EvalRank(0)
)

Eval ranks.

See: https://archive.is/G6GZg

func Cactus added in v0.8.0

func Cactus(c0, c1, c2, c3, c4 Card) EvalRank

Cactus is a Cactus Kev rank eval func, using lookup maps generated on the fly.

See: https://archive.is/G6GZg

func CactusFast added in v0.8.0

func CactusFast(c0, c1, c2, c3, c4 Card) EvalRank

CactusFast is a fast Cactus Kev rank eval func, implementing Paul Senzee's perfect hash lookup.

See: http://senzee.blogspot.com/2006/06/some-perfect-hash.html

func RankAceFiveLow added in v0.10.0

func RankAceFiveLow(mask EvalRank, c0, c1, c2, c3, c4 Card) EvalRank

RankAceFiveLow is a A-to-5 low rank eval func. Ace's are low, Straight's and Flush's do not count.

func RankEightOrBetter added in v0.8.0

func RankEightOrBetter(c0, c1, c2, c3, c4 Card) EvalRank

RankEightOrBetter is a 8-or-better low rank eval func. Ace's are low, Straight's and Flush's do not count.

func RankLowball added in v0.9.0

func RankLowball(c0, c1, c2, c3, c4 Card) EvalRank

RankLowball is a Lowball (2-to-7) low rank eval func. Ace's are high, Straight's and Flush's count.

Works by adding 2 additional ranks for Ace-high StraightFlush's and Straight's.

See EvalRank.ToLowball.

func RankManila added in v0.10.0

func RankManila(c0, c1, c2, c3, c4 Card) EvalRank

RankManila is a Manila rank eval func.

func RankRazz added in v0.8.0

func RankRazz(c0, c1, c2, c3, c4 Card) EvalRank

RankRazz is a Razz (A-to-5) low rank eval func. Ace's are low, Straight's and Flush's do not count.

When there is a Pair (or higher) of matching ranks, will be the inverted Cactus value.

func RankShort added in v0.10.0

func RankShort(c0, c1, c2, c3, c4 Card) EvalRank

RankShort is a Short rank eval func.

func RankSoko added in v0.10.0

func RankSoko(c0, c1, c2, c3, c4 Card) EvalRank

RankSoko is a Soko rank eval func.

Has ranks to Cactus, adding a Four Flush and Four Straight that beat Pair's and Nothing:

Straight Flush
Four of a Kind
Full House
Flush
Straight
Three of a Kind
Two Pair
Four Flush
Four Straight
Pair
Nothing

func RankSpanish added in v0.10.0

func RankSpanish(c0, c1, c2, c3, c4 Card) EvalRank

RankSpanish is a Spanish rank eval func.

func (EvalRank) Fixed added in v0.9.0

func (r EvalRank) Fixed() EvalRank

Fixed converts a relative eval rank to a fixed eval rank.

func (EvalRank) Format added in v0.14.4

func (r EvalRank) Format(f fmt.State, verb rune)

Format satisfies the fmt.Formatter interface.

func (EvalRank) FromFlushOver added in v0.10.0

func (r EvalRank) FromFlushOver() EvalRank

FromFlushOver changes a rank from a Flush Over a Full House rank to a Cactus rank.

FullHouse: FullHouse(322) - FourOfAKind(166) == 156
Flush:     Flush(1599)    - FullHouse(322)   == 1277

func (EvalRank) FromLowball added in v0.10.0

func (r EvalRank) FromLowball() EvalRank

FromLowball converts a Lowball rank to a Cactus rank.

See EvalRank.ToLowball for a description of the operations performed.

func (EvalRank) Name added in v0.9.0

func (r EvalRank) Name() string

Name returns the eval rank name.

Examples:

StraightFlush
FourOfAKind

func (EvalRank) Title added in v0.14.4

func (r EvalRank) Title() string

Title returns the eval rank title.

Examples:

Straight Flush
Four of a Kind

func (EvalRank) ToFlushOver added in v0.10.0

func (r EvalRank) ToFlushOver() EvalRank

ToFlushOver changes a Cactus rank to a Flush Over a Full House rank.

FullHouse: FullHouse(322) - FourOfAKind(166) == 156
Flush:     Flush(1599)    - FullHouse(322)   == 1277

func (EvalRank) ToLowball added in v0.10.0

func (r EvalRank) ToLowball() EvalRank

ToLowball converts a Cactus rank to a Lowball rank, by inverting the rank and converting the lowest Straight and Straight Flushes (5-4-3-2-A) to different ranks.

Changes the rank as follows:

Moves lowest Straight Flush (10) to lowest Ace Flush (811)
Moves any rank between Straight Flush (10) < r <= lowest Ace Flush (811) down 1 rank
Moves lowest Straight (1609) to lowest Ace Nothing (6678)
Moves any rank between Straight (1609) < r <= lowest Ace Nothing (6678) down 1 rank
Inverts the rank (Nothing - r + 1)

type EvalType added in v0.9.0

type EvalType uint8

EvalType is a eval type.

const (
	EvalCactus        EvalType = 0
	EvalJacksOrBetter EvalType = 'j'
	EvalShort         EvalType = 't'
	EvalManila        EvalType = 'm'
	EvalSpanish       EvalType = 'p'
	EvalOmaha         EvalType = 'o'
	EvalSoko          EvalType = 'k'
	EvalLowball       EvalType = 'l'
	EvalRazz          EvalType = 'r'
	EvalBadugi        EvalType = 'b'
	EvalHigh          EvalType = 'h'
	EvalThree         EvalType = '3'
)

Eval types.

func (EvalType) Byte added in v0.9.0

func (typ EvalType) Byte() byte

Byte returns the eval type byte.

func (EvalType) Cactus added in v0.11.1

func (typ EvalType) Cactus() bool

Cactus returns true when the eval is a Cactus eval.

func (EvalType) Format added in v0.9.0

func (typ EvalType) Format(f fmt.State, verb rune)

Format satisfies the fmt.Formatter interface.

func (EvalType) Name added in v0.9.0

func (typ EvalType) Name() string

Name returns the eval type name.

func (EvalType) New added in v0.9.0

func (typ EvalType) New(normalize, low bool) EvalFunc

New creates a eval func for the type.

type ExpValue added in v0.13.0

type ExpValue struct {
	Opponents int
	Wins      uint64
	Splits    uint64
	Losses    uint64
	Total     uint64
}

ExpValue is the result of a expected value calculation.

func NewExpValue added in v0.13.4

func NewExpValue(opponents int) *ExpValue

NewExpValue creates a new expected value.

func StartingExpValue added in v0.13.0

func StartingExpValue(pocket []Card) *ExpValue

StartingExpValue returns the starting pocket expected value.

func (*ExpValue) Add added in v0.13.3

func (expv *ExpValue) Add(v *ExpValue)

Add adds b to the expected value.

func (*ExpValue) Float64 added in v0.13.0

func (expv *ExpValue) Float64() float64

Float32 returns the expected value as a float32.

func (*ExpValue) Format added in v0.13.0

func (expv *ExpValue) Format(f fmt.State, verb rune)

Format satisfies the fmt.Formatter interface.

func (*ExpValue) Percent added in v0.13.0

func (expv *ExpValue) Percent() float64

Percent returns the expected value calculated as a percent.

type ExpValueCalc added in v0.13.0

type ExpValueCalc struct {
	// contains filtered or unexported fields
}

ExpValueCalc is a expected value calculator.

Example
package main

import (
	"context"
	"fmt"

	"github.com/cardrank/cardrank"
)

func main() {
	pocket, board := cardrank.Must("Kh 3h"), cardrank.Must("Ah 8h 3c")
	expv, ok := cardrank.Holdem.ExpValue(context.Background(), pocket, cardrank.WithBoard(board))
	if !ok {
		panic("unable to calculate expected value")
	}
	fmt.Println("expected value:", expv)
}
Output:

expected value: 75.6% (802371,13659/1070190)

func NewExpValueCalc added in v0.13.0

func NewExpValueCalc(typ Type, pocket []Card, opts ...CalcOption) *ExpValueCalc

NewExpValueCalc creates a new expected value calculator.

func (*ExpValueCalc) Calc added in v0.13.0

func (c *ExpValueCalc) Calc(ctx context.Context) (*ExpValue, bool)

Calc calculates the expected value.

func (*ExpValueCalc) NewExpValue added in v0.13.0

func (c *ExpValueCalc) NewExpValue() *ExpValue

NewExpValue creates a new expected value.

type Formatter added in v0.14.4

type Formatter []Card

Formatter wraps formatting a set of cards. Allows `go test` to function without disabling vet.

func (Formatter) Format added in v0.14.4

func (v Formatter) Format(f fmt.State, verb rune)

Format satisfies the fmt.Formatter interface.

type Odds added in v0.11.1

type Odds struct {
	// Total is the total number of outcomes.
	Total int
	// Counts is each position's outcome count for wins and splits.
	Counts []int
	// Outs are map of the available outs for a position.
	Outs []map[Card]bool
}

Odds are calculated run odds.

func NewOdds added in v0.11.1

func NewOdds(count int, u []Card) *Odds

NewOdds creates a new odds.

func (*Odds) Add added in v0.11.1

func (odds *Odds) Add(evs []*Eval, suits [][4]int, v []Card, low bool)

Add adds the eval results to the odds.

func (*Odds) Float32 added in v0.11.1

func (odds *Odds) Float32() []float32

Float32 returns the odds as a slice of float32.

func (*Odds) Format added in v0.11.1

func (odds *Odds) Format(f fmt.State, verb rune)

Format satisfies the fmt.Formatter interface.

func (*Odds) Percent added in v0.11.1

func (odds *Odds) Percent(pos int) float32

Percent returns the odds for pos calculated as a percent.

type OddsCalc added in v0.13.0

type OddsCalc struct {
	// contains filtered or unexported fields
}

OddsCalc calculates run odds.

Example
package main

import (
	"context"
	"fmt"

	"github.com/cardrank/cardrank"
)

func main() {
	pockets := [][]cardrank.Card{
		cardrank.Must("Ah As Jc Qs"),
		cardrank.Must("3h 2h Ks Tc"),
	}
	board := cardrank.Must("6h 6s Jh")
	odds, _, ok := cardrank.Omaha.Odds(context.Background(), pockets, board)
	if !ok {
		panic("unable to calculate odds")
	}
	for i := range pockets {
		fmt.Printf("%d: %*v\n", i, i, odds)
	}
}
Output:

0: 66.1% (542/820)
1: 33.9% (278/820)

func NewOddsCalc added in v0.13.0

func NewOddsCalc(typ Type, opts ...CalcOption) *OddsCalc

NewOddsCalc creates a new run odds calc.

func (*OddsCalc) Calc added in v0.13.0

func (c *OddsCalc) Calc(ctx context.Context) (*Odds, *Odds, bool)

Calc calculates odds.

type ParseError added in v0.7.1

type ParseError struct {
	S   string
	N   int
	I   int
	Err error
}

ParseError is a parse error.

func (*ParseError) Error added in v0.7.1

func (err *ParseError) Error() string

Error satisfies the [error] interface.

func (*ParseError) Unwrap added in v0.7.1

func (err *ParseError) Unwrap() error

Unwrap satisfies the errors.Unwrap interface.

type Rank

type Rank uint8

Rank is a card rank.

const (
	Ace Rank = 12 - iota
	King
	Queen
	Jack
	Ten
	Nine
	Eight
	Seven
	Six
	Five
	Four
	Three
	Two
)

Card ranks.

func RankFromRune

func RankFromRune(r rune) Rank

RankFromRune returns a rune's card rank.

func (Rank) Byte

func (rank Rank) Byte() byte

Byte returns the card rank byte.

func (Rank) Index

func (rank Rank) Index() int

Index the card rank int index (0-12 for Two-Ace).

func (Rank) Name

func (rank Rank) Name() string

Name returns the card rank name.

func (Rank) PluralName

func (rank Rank) PluralName() string

PluralName returns the card rank plural name.

func (Rank) StraightFlushName added in v0.10.0

func (rank Rank) StraightFlushName() string

StraightFlushName returns the card rank StraightFlush name.

func (Rank) String

func (rank Rank) String() string

String satisfies the fmt.Stringer interface.

type RankFunc added in v0.8.0

type RankFunc func(c0, c1, c2, c3, c4 Card) EvalRank

RankFunc returns the eval rank of 5 cards.

var (
	// RankCactus is the default Cactus Kev func.
	RankCactus RankFunc
)

type Result added in v0.9.0

type Result struct {
	Evals   []*Eval
	HiOrder []int
	HiPivot int
	LoOrder []int
	LoPivot int
}

Result contains dealer eval results.

func NewResult added in v0.11.1

func NewResult(typ Type, run *Run, active map[int]bool, calc bool) *Result

NewResult creates a result for the run, storing the calculated or evaluated result.

func (*Result) Win added in v0.9.0

func (res *Result) Win(names ...string) (*Win, *Win)

Win returns the Hi and Lo win.

type Run added in v0.9.2

type Run struct {
	Discard []Card
	Pockets [][]Card
	Hi      []Card
	Lo      []Card
}

Run holds pockets, and a Hi/Lo board for a deal.

func NewRun added in v0.9.2

func NewRun(count int) *Run

NewRun creates a new run for the pocket count.

func (*Run) CalcStart added in v0.11.1

func (run *Run) CalcStart(low bool) (*Odds, *Odds)

CalcStart returns the run's starting odds.

func (*Run) Dupe added in v0.9.2

func (run *Run) Dupe() *Run

Dupe creates a duplicate of run, with a copy of the pockets and Hi and Lo board.

func (*Run) Eval added in v0.9.2

func (run *Run) Eval(typ Type, active map[int]bool, calc bool) []*Eval

Eval returns the evals for the run.

type Shuffler added in v0.5.0

type Shuffler interface {
	Shuffle(int, func(int, int))
}

Shuffler is an interface for a deck shuffler. Compatible with math/rand.Rand's Shuffle method.

type StreetDesc added in v0.8.0

type StreetDesc struct {
	// Id is the id of the street.
	Id byte
	// Name is the name of the street.
	Name string
	// Pocket is the count of cards to deal.
	Pocket int
	// PocketUp is the count of cards to reveal.
	PocketUp int
	// PocketDiscard is the count of cards to discard before pockets dealt.
	PocketDiscard int
	// PocketDraw is the count of cards to draw.
	PocketDraw int
	// Board is the count of board cards to deal.
	Board int
	// BoardDiscard is the count of cards to discard before board dealt.
	BoardDiscard int
}

StreetDesc is a type's street description.

func HoldemStreets added in v0.8.0

func HoldemStreets(pocket, discard, flop, turn, river int) []StreetDesc

HoldemStreets creates Holdem streets (Pre-Flop, Flop, Turn, and River).

func NumberedStreets added in v0.8.0

func NumberedStreets(pockets ...int) []StreetDesc

NumberedStreets creates numbered streets (Ante, 1st, 2nd, ..., River) for each of the pockets.

func StudStreets added in v0.8.0

func StudStreets() []StreetDesc

StudStreets creates Stud streets (Ante, 3rd, 4th, 5th, 6th, and River).

func (StreetDesc) Desc added in v0.9.0

func (desc StreetDesc) Desc() string

Desc returns a description of the street.

type StreetOption added in v0.8.0

type StreetOption func(int, *StreetDesc)

StreetOption is a street option.

type Suit

type Suit uint8

Suit is a card suit.

const (
	Spade Suit = 1 << iota
	Heart
	Diamond
	Club
)

Card suits.

func SuitFromRune

func SuitFromRune(r rune) Suit

SuitFromRune returns a rune's card suit.

func (Suit) AlternateEmoji added in v0.14.9

func (suit Suit) AlternateEmoji() string

ALterEmoji returns the card suit alternate pip emoji.

func (Suit) Byte

func (suit Suit) Byte() byte

Byte returns the card suit byte.

func (Suit) Emoji added in v0.11.6

func (suit Suit) Emoji() string

Emoji returns the card suit pip emoji.

func (Suit) Index

func (suit Suit) Index() int

Index returns the card suit int index (0-3 for Spade, Heart, Diamond, Club).

func (Suit) Name

func (suit Suit) Name() string

Name returns the card suit name.

func (Suit) PluralName

func (suit Suit) PluralName() string

PluralName returns the card suit plural name.

func (Suit) String

func (suit Suit) String() string

String satisfies the fmt.Stringer interface.

func (Suit) UnicodeBlack

func (suit Suit) UnicodeBlack() rune

UnicodeBlack returns the card suit black unicode pip rune.

func (Suit) UnicodeWhite

func (suit Suit) UnicodeWhite() rune

UnicodeWhite returns the card suit white unicode pip rune.

type Type

type Type uint16

Type wraps a registered type description (see TypeDesc), providing a standard way to use the DefaultTypes, or a custom type registered with RegisterType. DefaultTypes are registered by default unless using the noinit build tag.

Standard Types

Holdem is a best-5 card game using a standard deck of 52 cards (see DeckFrench), having a pocket of 2 cards, 5 community board cards, and a Pre-Flop, Flop, Turn, and River streets. 2 pocket cards are dealt on the Pre-Flop, with 3 board cards on the Flop, 1 board card on the Turn, and 1 board card on the River. 1 card is discarded on the Flop, Turn, and River, prior to the board cards being dealt.

Split is the Hi/Lo variant of Holdem, using a Eight-or-better qualifier (see RankEightOrBetter) for the Lo.

Short is a Holdem variant using a Short deck of 36 cards, having only cards with ranks of 6+ (see DeckShort). Flush ranks over FullHouse.

Manila is a Holdem variant using a Manila deck of 32 cards, having only cards with ranks of 7+ (see DeckManila), forcing the use of the 2 pocket cards, adding a Drop street before the Flop, and with all 5 streets receiving 1 board card each. Flush ranks over FullHouse.

Spanish is a Holdem/Manila variant, using a Spanish deck of 28 cards, having only cards with ranks of 8+ (see DeckSpanish).

Royal is a Holdem variant using a Royal deck of 20 cards, having only cards with ranks of 10+ (see DeckRoyal).

Double is a Holdem variant having two separate Hi and Lo community boards.

Showtime is a Holdem variant where folded cards are shown.

Swap is a Holdem variant where up to 2 pocket cards may be drawn (exchanged) exactly once on the Flop, Turn, or River.

River is a Holdem variant that deals 1 pocket card on the River instead of to the community board, resulting in a total pocket of 3 cards and a community board of 4 cards. Any of the 3 pocket cards or 4 board cards may be used to create the best-5.

Dallas is Holdem variant that forces the use of the 2 pocket cards and any 3 of the 5 board cards to make the best-5. Comparable to Omaha, but with 2 pocket cards instead of 4.

Houston is a Holdem/Dallas variant with 3 pocket cards, instead of 2, where only 2 board cards are dealt on the Flop, instead of 3. Requires using 2 of the 3 pocket cards and any 3 of the 4 board cards to make the best-5. Comparable to Omaha, but with 3 pocket cards instead of 4, and a community board of 4.

Draw is a best-5 card game using a standard deck of 52 cards (see DeckFrench), comprising a pocket of 5 cards, no community cards, with a Ante, 6th, and River streets. 5 cards are dealt on the Ante, and up to 5 pocket cards can be drawn (exchanged) on the 6th street.

DrawHiLo is the Hi/Lo variant of Draw, using a Eight-or-better qualifier (see RankEightOrBetter) for the Lo.

Stud is a best-5 card game, using a standard deck of 52 cards (see DeckFrench), comprising a pocket of 7 cards, no community cards, with Ante, 4th, 5th, 6th and River streets. 2 pocket cards are dealt down and 1 pocket card up on the Ante, and 1 additional pocket card dealt up on the 4th, 5th, and 6th streets, with 1 final additional pocket card dealt down on the 7th street.

StudHiLo is the Hi/Lo variant of Stud, using a Eight-or-better qualifier (see RankEightOrBetter) for the Lo.

StudFive is a best-5 card game using a standard deck of 52 cards (see DeckFrench), comprising a pocket of 5 cards, no community cards, with Ante, 3rd, 4th, and River streets. 2 pocket cards are dealt on the Ante, with 1 pocket card dealt up, and an additional pocket card dealt up on the 3rd, 4th, and 5th streets. Similar to Stud, but without 5th and 6th streets.

Video is a best-5 card game, using a standard deck of 52 cards (see DeckFrench), comprising a pocket of 5 cards, no community cards, with a Ante and River. 5 pocket cards are dealt on the Ante, all up. Up to 5 pocket cards can be drawn (exchanged) on the River. Uses a qualifier of a Jack's-or-better for Hi eval (see NewJacksOrBetterEval).

Omaha is a Holdem variant with 4 pocket cards instead of 2, requiring use of 2 of 4 the pocket cards and any 3 of the 5 board cards to make the best-5.

OmahaHiLo is the Hi/Lo variant of Omaha, using a Eight-or-better qualifier (see RankEightOrBetter) for the Lo.

OmahaDouble is a Omaha variant having two separate Hi and Lo community boards.

OmahaFive is a Holdem/Omaha variant with 5 pocket cards, requiring the use of 2 of the 5 pocket cards and any 3 of the 5 board cards to make the best-5.

OmahaSix is a Holdem/Omaha variant with 6 pocket cards, requiring the use of 2 of the 6 pocket cards and any 3 of the 5 board cards to make the best-5.

Courchevel is a OmahaFive variant, where 1 board card is dealt on the Pre-Flop, and only 2 board cards dealt on the Flop.

CourchevelHiLo is the Hi/Lo variant of Courchevel, using a Eight-or-better qualifier (see RankEightOrBetter) for the Lo.

Fusion is a Holdem/Omaha variant where only 2 pocket cards are dealt on the Pre-Flop, with 1 additional pocket card dealt on the Flop and Turn.

FusionHiLo is the Hi/Lo variant of Fusion, using a Eight-or-better qualifier (see RankEightOrBetter) for the Lo.

Soko is a Stud/StudFive variant with 2 additional ranks, a Four Flush (4 cards of the same suit), and a Four Straight (4 cards in sequential rank, with no wrapping straights), besting Pair and Nothing, with only a Ante and River streets where 2 pocket cards are dealt on the Ante, and 3 pocket cards are dealt, up, on the River.

SokoHiLo is the Hi/Lo variant of Soko, using a Eight-or-better qualifier (see RankEightOrBetter) for the Lo.

Lowball is a best-5 low card game using a standard deck of 52 cards (see DeckFrench), comprising 5 pocket cards, no community cards, and a Ante, 6th, 7th, and River streets using a Two-to-Seven low inverted ranking system, where Ace's are always high, and non-Flush, and non-Straight lows are best. Up to 5 pocket cards may be drawn (exchanged) exactly once on either the 6th, 7th, or River streets.

LowballTriple is a Lowball variant, where up to 5 pocket cards may be drawn (exchanged) on any of the 6th, 7th, or River streets.

Razz is a Stud low variant, using a Ace-to-Five ranking (see RankRazz), where Ace's play low, and Flush's and Straight's do not affect ranking.

Badugi is a best-4 low non-matching-suit card game, using a standard deck of 52 cards (see DeckFrench), comprising 4 pocket cards, no community cards, and Ante, 5th, 6th, and River streets. Up to 4 cards can be drawn (exchanged) multiple times on the 5th, 6th, or River streets. See NewBadugiEval for more details.

Kuhn is a best high card game, using a 3 card deck (King, Queen, Jack), having 1 pocket card and no community board cards. Useful for game tree testing. See Kuhn poker.

Leduc is a best high card game, using a 6 card deck (King, Queen, Jack each of the Spade and Heart), having 1 pocket card and 1 community card. Useful for game tree testing. See Deepstack Leduc.

RhodeIsland is a best-3 card game that is simplified version of Holdem, using a standard deck of 52 cards (see DeckFrench), having 1 pocket card, and 1 community board cards dealt each on the Flop and Turn. Useful for game tree testing. See Gilpin & Sandholm.

Example (Badugi)
package main

import (
	"fmt"
	"math/rand"
	"strconv"
	"strings"

	"github.com/cardrank/cardrank"
)

func main() {
	for i, game := range []struct {
		seed    int64
		players int
	}{
		{119, 2},
		{321, 5},
		{408, 6},
		{455, 6},
		{1113, 6},
	} {
		// note: use a real random source
		r := rand.New(rand.NewSource(game.seed))
		pockets, _ := cardrank.Badugi.Deal(r, 1, game.players)
		evs := cardrank.Badugi.EvalPockets(pockets, nil)
		fmt.Printf("------ Badugi %d ------\n", i+1)
		for j := 0; j < game.players; j++ {
			desc := evs[j].Desc(false)
			fmt.Printf("Player %d: %b %s %b %b\n", j+1, pockets[j], desc, desc.Best, desc.Unused)
		}
		order, pivot := cardrank.Order(evs, false)
		desc := evs[order[0]].Desc(false)
		if pivot == 1 {
			fmt.Printf("Result:   Player %d wins with %s\n", order[0]+1, desc)
		} else {
			var s []string
			for j := 0; j < pivot; j++ {
				s = append(s, strconv.Itoa(order[j]+1))
			}
			fmt.Printf("Result:   Players %s push with %s\n", strings.Join(s, ", "), desc)
		}
	}
}
Output:

------ Badugi 1 ------
Player 1: [K♥ J♣ A♥ Q♠] Queen, Jack, Ace-low [Q♠ J♣ A♥] [K♥]
Player 2: [7♣ 4♣ 5♠ 2♠] Four, Two-low [4♣ 2♠] [7♣ 5♠]
Result:   Player 1 wins with Queen, Jack, Ace-low
------ Badugi 2 ------
Player 1: [3♠ 3♦ T♠ Q♠] Ten, Three-low [T♠ 3♦] [Q♠ 3♠]
Player 2: [6♦ Q♣ 8♥ 6♣] Queen, Eight, Six-low [Q♣ 8♥ 6♦] [6♣]
Player 3: [Q♦ K♠ 8♣ A♥] King, Queen, Eight, Ace-low [K♠ Q♦ 8♣ A♥] []
Player 4: [K♦ T♦ 8♦ 4♥] Eight, Four-low [8♦ 4♥] [K♦ T♦]
Player 5: [J♦ 2♥ Q♥ 6♠] Jack, Six, Two-low [J♦ 6♠ 2♥] [Q♥]
Result:   Player 3 wins with King, Queen, Eight, Ace-low
------ Badugi 3 ------
Player 1: [K♠ Q♠ 4♣ J♦] Queen, Jack, Four-low [Q♠ J♦ 4♣] [K♠]
Player 2: [J♠ 3♣ 8♥ 2♠] Eight, Three, Two-low [8♥ 3♣ 2♠] [J♠]
Player 3: [3♠ T♠ 2♣ Q♦] Queen, Three, Two-low [Q♦ 3♠ 2♣] [T♠]
Player 4: [5♣ 5♥ T♦ 2♦] Five, Two-low [5♥ 2♦] [T♦ 5♣]
Player 5: [7♠ 3♥ 6♠ A♣] Six, Three, Ace-low [6♠ 3♥ A♣] [7♠]
Player 6: [4♠ 8♦ K♦ T♣] Ten, Eight, Four-low [T♣ 8♦ 4♠] [K♦]
Result:   Player 5 wins with Six, Three, Ace-low
------ Badugi 4 ------
Player 1: [6♠ K♥ A♣ 8♣] King, Six, Ace-low [K♥ 6♠ A♣] [8♣]
Player 2: [Q♥ 4♥ J♣ 5♥] Jack, Four-low [J♣ 4♥] [Q♥ 5♥]
Player 3: [2♣ 6♥ 5♣ Q♠] Queen, Six, Two-low [Q♠ 6♥ 2♣] [5♣]
Player 4: [9♠ J♥ K♠ J♠] Jack, Nine-low [J♥ 9♠] [K♠ J♠]
Player 5: [3♦ 4♦ K♣ 8♦] King, Three-low [K♣ 3♦] [8♦ 4♦]
Player 6: [T♣ Q♦ A♠ 7♥] Queen, Ten, Seven, Ace-low [Q♦ T♣ 7♥ A♠] []
Result:   Player 6 wins with Queen, Ten, Seven, Ace-low
------ Badugi 5 ------
Player 1: [3♦ 4♦ 5♦ J♣] Jack, Three-low [J♣ 3♦] [5♦ 4♦]
Player 2: [T♥ J♠ K♠ 2♣] Jack, Ten, Two-low [J♠ T♥ 2♣] [K♠]
Player 3: [A♣ 9♠ T♠ 3♠] Three, Ace-low [3♠ A♣] [T♠ 9♠]
Player 4: [7♦ 3♣ 8♠ 7♣] Eight, Seven, Three-low [8♠ 7♦ 3♣] [7♣]
Player 5: [5♣ Q♠ J♥ 2♠] Jack, Five, Two-low [J♥ 5♣ 2♠] [Q♠]
Player 6: [6♠ 7♠ 7♥ 2♥] Six, Two-low [6♠ 2♥] [7♥ 7♠]
Result:   Player 4 wins with Eight, Seven, Three-low
Example (Holdem)
package main

import (
	"fmt"
	"math/rand"
	"strconv"
	"strings"

	"github.com/cardrank/cardrank"
)

func main() {
	for i, game := range []struct {
		seed    int64
		players int
	}{
		{3, 2},
		{278062, 2},
		{1928, 6},
		{6151, 6},
		{5680, 6},
		{23965, 2},
		{13959, 2},
		{23366, 6},
		{29555, 3},
		{472600, 3},
		{107, 10},
	} {
		// note: use a real random source
		r := rand.New(rand.NewSource(game.seed))
		pockets, board := cardrank.Holdem.Deal(r, 1, game.players)
		evs := cardrank.Holdem.EvalPockets(pockets, board)
		fmt.Printf("------ Holdem %d ------\n", i+1)
		fmt.Printf("Board:    %b\n", board)
		for j := 0; j < game.players; j++ {
			desc := evs[j].Desc(false)
			fmt.Printf("Player %d: %b %s %b %b\n", j+1, pockets[j], desc, desc.Best, desc.Unused)
		}
		order, pivot := cardrank.Order(evs, false)
		desc := evs[order[0]].Desc(false)
		if pivot == 1 {
			fmt.Printf("Result:   Player %d wins with %s\n", order[0]+1, desc)
		} else {
			var s []string
			for j := 0; j < pivot; j++ {
				s = append(s, strconv.Itoa(order[j]+1))
			}
			fmt.Printf("Result:   Players %s push with %s\n", strings.Join(s, ", "), desc)
		}
	}
}
Output:

------ Holdem 1 ------
Board:    [J♠ T♠ 2♦ 2♠ Q♥]
Player 1: [6♦ 7♠] Pair, Twos, kickers Queen, Jack, Ten [2♦ 2♠ Q♥ J♠ T♠] [7♠ 6♦]
Player 2: [8♠ 4♣] Pair, Twos, kickers Queen, Jack, Ten [2♦ 2♠ Q♥ J♠ T♠] [8♠ 4♣]
Result:   Players 1, 2 push with Pair, Twos, kickers Queen, Jack, Ten
------ Holdem 2 ------
Board:    [8♠ 9♠ J♠ 9♣ T♠]
Player 1: [7♠ 6♦] Straight Flush, Jack-high, Bronze Fist [J♠ T♠ 9♠ 8♠ 7♠] [9♣ 6♦]
Player 2: [T♣ Q♠] Straight Flush, Queen-high, Silver Tongue [Q♠ J♠ T♠ 9♠ 8♠] [T♣ 9♣]
Result:   Player 2 wins with Straight Flush, Queen-high, Silver Tongue
------ Holdem 3 ------
Board:    [A♠ T♣ K♠ J♣ 6♥]
Player 1: [T♥ 5♦] Pair, Tens, kickers Ace, King, Jack [T♣ T♥ A♠ K♠ J♣] [6♥ 5♦]
Player 2: [2♠ K♦] Pair, Kings, kickers Ace, Jack, Ten [K♦ K♠ A♠ J♣ T♣] [6♥ 2♠]
Player 3: [Q♣ Q♥] Straight, Ace-high [A♠ K♠ Q♣ J♣ T♣] [Q♥ 6♥]
Player 4: [J♠ 7♣] Pair, Jacks, kickers Ace, King, Ten [J♣ J♠ A♠ K♠ T♣] [7♣ 6♥]
Player 5: [4♥ 6♠] Pair, Sixes, kickers Ace, King, Jack [6♥ 6♠ A♠ K♠ J♣] [T♣ 4♥]
Player 6: [Q♠ 3♣] Straight, Ace-high [A♠ K♠ Q♠ J♣ T♣] [6♥ 3♣]
Result:   Players 3, 6 push with Straight, Ace-high
------ Holdem 4 ------
Board:    [9♦ J♣ A♥ 9♥ J♠]
Player 1: [K♠ 8♦] Two Pair, Jacks over Nines, kicker Ace [J♣ J♠ 9♦ 9♥ A♥] [K♠ 8♦]
Player 2: [7♦ 9♠] Full House, Nines full of Jacks [9♦ 9♥ 9♠ J♣ J♠] [A♥ 7♦]
Player 3: [A♦ 8♥] Two Pair, Aces over Jacks, kicker Nine [A♦ A♥ J♣ J♠ 9♦] [9♥ 8♥]
Player 4: [4♥ 6♣] Two Pair, Jacks over Nines, kicker Ace [J♣ J♠ 9♦ 9♥ A♥] [6♣ 4♥]
Player 5: [3♥ 5♥] Two Pair, Jacks over Nines, kicker Ace [J♣ J♠ 9♦ 9♥ A♥] [5♥ 3♥]
Player 6: [T♣ J♦] Full House, Jacks full of Nines [J♣ J♦ J♠ 9♦ 9♥] [A♥ T♣]
Result:   Player 6 wins with Full House, Jacks full of Nines
------ Holdem 5 ------
Board:    [3♠ 9♥ A♦ 6♥ Q♦]
Player 1: [T♦ 4♥] Ace-high, kickers Queen, Ten, Nine, Six [A♦ Q♦ T♦ 9♥ 6♥] [4♥ 3♠]
Player 2: [8♦ 7♦] Ace-high, kickers Queen, Nine, Eight, Seven [A♦ Q♦ 9♥ 8♦ 7♦] [6♥ 3♠]
Player 3: [K♠ K♥] Pair, Kings, kickers Ace, Queen, Nine [K♥ K♠ A♦ Q♦ 9♥] [6♥ 3♠]
Player 4: [T♣ 5♦] Ace-high, kickers Queen, Ten, Nine, Six [A♦ Q♦ T♣ 9♥ 6♥] [5♦ 3♠]
Player 5: [7♥ T♥] Ace-high, kickers Queen, Ten, Nine, Seven [A♦ Q♦ T♥ 9♥ 7♥] [6♥ 3♠]
Player 6: [8♣ 5♣] Ace-high, kickers Queen, Nine, Eight, Six [A♦ Q♦ 9♥ 8♣ 6♥] [5♣ 3♠]
Result:   Player 3 wins with Pair, Kings, kickers Ace, Queen, Nine
------ Holdem 6 ------
Board:    [T♥ 6♥ 7♥ 2♥ 7♣]
Player 1: [6♣ K♥] Flush, King-high, kickers Ten, Seven, Six, Two [K♥ T♥ 7♥ 6♥ 2♥] [7♣ 6♣]
Player 2: [6♠ 5♥] Flush, Ten-high, kickers Seven, Six, Five, Two [T♥ 7♥ 6♥ 5♥ 2♥] [7♣ 6♠]
Result:   Player 1 wins with Flush, King-high, kickers Ten, Seven, Six, Two
------ Holdem 7 ------
Board:    [4♦ A♥ A♣ 4♠ A♦]
Player 1: [T♥ 9♣] Full House, Aces full of Fours [A♣ A♦ A♥ 4♦ 4♠] [T♥ 9♣]
Player 2: [T♠ A♠] Four of a Kind, Aces, kicker Ten [A♣ A♦ A♥ A♠ T♠] [4♦ 4♠]
Result:   Player 2 wins with Four of a Kind, Aces, kicker Ten
------ Holdem 8 ------
Board:    [Q♥ T♥ T♠ J♥ K♥]
Player 1: [A♥ 8♥] Straight Flush, Ace-high, Royal [A♥ K♥ Q♥ J♥ T♥] [T♠ 8♥]
Player 2: [9♠ 8♦] Straight, King-high [K♥ Q♥ J♥ T♥ 9♠] [T♠ 8♦]
Player 3: [Q♣ 4♦] Two Pair, Queens over Tens, kicker King [Q♣ Q♥ T♥ T♠ K♥] [J♥ 4♦]
Player 4: [2♠ Q♦] Two Pair, Queens over Tens, kicker King [Q♦ Q♥ T♥ T♠ K♥] [J♥ 2♠]
Player 5: [6♥ A♦] Flush, King-high, kickers Queen, Jack, Ten, Six [K♥ Q♥ J♥ T♥ 6♥] [A♦ T♠]
Player 6: [3♦ T♣] Three of a Kind, Tens, kickers King, Queen [T♣ T♥ T♠ K♥ Q♥] [J♥ 3♦]
Result:   Player 1 wins with Straight Flush, Ace-high, Royal
------ Holdem 9 ------
Board:    [A♣ 2♣ 4♣ 5♣ 9♥]
Player 1: [T♣ 6♠] Flush, Ace-high, kickers Ten, Five, Four, Two [A♣ T♣ 5♣ 4♣ 2♣] [9♥ 6♠]
Player 2: [J♦ 3♣] Straight Flush, Five-high, Steel Wheel [5♣ 4♣ 3♣ 2♣ A♣] [J♦ 9♥]
Player 3: [4♥ T♠] Pair, Fours, kickers Ace, Ten, Nine [4♣ 4♥ A♣ T♠ 9♥] [5♣ 2♣]
Result:   Player 2 wins with Straight Flush, Five-high, Steel Wheel
------ Holdem 10 ------
Board:    [8♣ J♣ 8♥ 7♥ 9♥]
Player 1: [8♦ T♥] Straight, Jack-high [J♣ T♥ 9♥ 8♣ 7♥] [8♦ 8♥]
Player 2: [8♠ 3♣] Three of a Kind, Eights, kickers Jack, Nine [8♣ 8♥ 8♠ J♣ 9♥] [7♥ 3♣]
Player 3: [6♥ K♥] Flush, King-high, kickers Nine, Eight, Seven, Six [K♥ 9♥ 8♥ 7♥ 6♥] [J♣ 8♣]
Result:   Player 3 wins with Flush, King-high, kickers Nine, Eight, Seven, Six
------ Holdem 11 ------
Board:    [5♥ 3♣ J♥ 6♦ 6♣]
Player 1: [8♥ T♥] Pair, Sixes, kickers Jack, Ten, Eight [6♣ 6♦ J♥ T♥ 8♥] [5♥ 3♣]
Player 2: [4♥ Q♣] Pair, Sixes, kickers Queen, Jack, Five [6♣ 6♦ Q♣ J♥ 5♥] [4♥ 3♣]
Player 3: [T♣ Q♠] Pair, Sixes, kickers Queen, Jack, Ten [6♣ 6♦ Q♠ J♥ T♣] [5♥ 3♣]
Player 4: [3♥ 5♦] Two Pair, Sixes over Fives, kicker Jack [6♣ 6♦ 5♦ 5♥ J♥] [3♣ 3♥]
Player 5: [A♠ T♠] Pair, Sixes, kickers Ace, Jack, Ten [6♣ 6♦ A♠ J♥ T♠] [5♥ 3♣]
Player 6: [6♠ 2♠] Three of a Kind, Sixes, kickers Jack, Five [6♣ 6♦ 6♠ J♥ 5♥] [3♣ 2♠]
Player 7: [J♠ 5♣] Two Pair, Jacks over Sixes, kicker Five [J♥ J♠ 6♣ 6♦ 5♣] [5♥ 3♣]
Player 8: [8♠ 9♦] Pair, Sixes, kickers Jack, Nine, Eight [6♣ 6♦ J♥ 9♦ 8♠] [5♥ 3♣]
Player 9: [6♥ J♣] Full House, Sixes full of Jacks [6♣ 6♦ 6♥ J♣ J♥] [5♥ 3♣]
Player 10: [2♣ A♣] Pair, Sixes, kickers Ace, Jack, Five [6♣ 6♦ A♣ J♥ 5♥] [3♣ 2♣]
Result:   Player 9 wins with Full House, Sixes full of Jacks
Example (Omaha)
package main

import (
	"fmt"
	"math/rand"
	"strconv"
	"strings"

	"github.com/cardrank/cardrank"
)

func main() {
	for i, game := range []struct {
		seed    int64
		players int
	}{
		{119, 2},
		{321, 5},
		{408, 6},
		{455, 6},
		{1113, 6},
	} {
		// note: use a real random source
		r := rand.New(rand.NewSource(game.seed))
		pockets, board := cardrank.Omaha.Deal(r, 1, game.players)
		evs := cardrank.Omaha.EvalPockets(pockets, board)
		fmt.Printf("------ Omaha %d ------\n", i+1)
		fmt.Printf("Board:    %b\n", board)
		for j := 0; j < game.players; j++ {
			desc := evs[j].Desc(false)
			fmt.Printf("Player %d: %b %s %b %b\n", j+1, pockets[j], desc, desc.Best, desc.Unused)
		}
		order, pivot := cardrank.Order(evs, false)
		desc := evs[order[0]].Desc(false)
		if pivot == 1 {
			fmt.Printf("Result:   Player %d wins with %s\n", order[0]+1, desc)
		} else {
			var s []string
			for j := 0; j < pivot; j++ {
				s = append(s, strconv.Itoa(order[j]+1))
			}
			fmt.Printf("Result:   Players %s push with %s\n", strings.Join(s, ", "), desc)
		}
	}
}
Output:

------ Omaha 1 ------
Board:    [3♥ 5♥ 4♥ 7♥ K♣]
Player 1: [K♥ J♣ A♥ Q♠] Flush, Ace-high, kickers King, Seven, Five, Four [A♥ K♥ 7♥ 5♥ 4♥] [K♣ Q♠ J♣ 3♥]
Player 2: [7♣ 4♣ 5♠ 2♠] Two Pair, Sevens over Fives, kicker King [7♣ 7♥ 5♥ 5♠ K♣] [4♣ 4♥ 3♥ 2♠]
Result:   Player 1 wins with Flush, Ace-high, kickers King, Seven, Five, Four
------ Omaha 2 ------
Board:    [3♥ 7♣ 3♣ 9♠ 9♣]
Player 1: [3♠ 3♦ T♠ Q♠] Four of a Kind, Threes, kicker Nine [3♣ 3♦ 3♥ 3♠ 9♠] [Q♠ T♠ 9♣ 7♣]
Player 2: [6♦ Q♣ 8♥ 6♣] Flush, Queen-high, kickers Nine, Seven, Six, Three [Q♣ 9♣ 7♣ 6♣ 3♣] [9♠ 8♥ 6♦ 3♥]
Player 3: [Q♦ K♠ 8♣ A♥] Pair, Nines, kickers Ace, King, Seven [9♣ 9♠ A♥ K♠ 7♣] [Q♦ 8♣ 3♣ 3♥]
Player 4: [K♦ T♦ 8♦ 4♥] Pair, Nines, kickers King, Ten, Seven [9♣ 9♠ K♦ T♦ 7♣] [8♦ 4♥ 3♣ 3♥]
Player 5: [J♦ 2♥ Q♥ 6♠] Pair, Nines, kickers Queen, Jack, Seven [9♣ 9♠ Q♥ J♦ 7♣] [6♠ 3♣ 3♥ 2♥]
Result:   Player 1 wins with Four of a Kind, Threes, kicker Nine
------ Omaha 3 ------
Board:    [J♣ T♥ 4♥ K♣ Q♣]
Player 1: [K♠ Q♠ 4♣ J♦] Two Pair, Kings over Queens, kicker Jack [K♣ K♠ Q♣ Q♠ J♣] [J♦ T♥ 4♣ 4♥]
Player 2: [J♠ 3♣ 8♥ 2♠] Pair, Jacks, kickers King, Queen, Eight [J♣ J♠ K♣ Q♣ 8♥] [T♥ 4♥ 3♣ 2♠]
Player 3: [3♠ T♠ 2♣ Q♦] Two Pair, Queens over Tens, kicker King [Q♣ Q♦ T♥ T♠ K♣] [J♣ 4♥ 3♠ 2♣]
Player 4: [5♣ 5♥ T♦ 2♦] Pair, Tens, kickers King, Queen, Five [T♦ T♥ K♣ Q♣ 5♣] [J♣ 5♥ 4♥ 2♦]
Player 5: [7♠ 3♥ 6♠ A♣] Ace-high, kickers King, Queen, Jack, Seven [A♣ K♣ Q♣ J♣ 7♠] [T♥ 6♠ 4♥ 3♥]
Player 6: [4♠ 8♦ K♦ T♣] Two Pair, Kings over Tens, kicker Queen [K♣ K♦ T♣ T♥ Q♣] [J♣ 8♦ 4♥ 4♠]
Result:   Player 1 wins with Two Pair, Kings over Queens, kicker Jack
------ Omaha 4 ------
Board:    [2♦ 6♦ 6♣ Q♣ 7♣]
Player 1: [6♠ K♥ A♣ 8♣] Flush, Ace-high, kickers Queen, Eight, Seven, Six [A♣ Q♣ 8♣ 7♣ 6♣] [K♥ 6♦ 6♠ 2♦]
Player 2: [Q♥ 4♥ J♣ 5♥] Two Pair, Queens over Sixes, kicker Jack [Q♣ Q♥ 6♣ 6♦ J♣] [7♣ 5♥ 4♥ 2♦]
Player 3: [2♣ 6♥ 5♣ Q♠] Full House, Sixes full of Queens [6♣ 6♦ 6♥ Q♣ Q♠] [7♣ 5♣ 2♣ 2♦]
Player 4: [9♠ J♥ K♠ J♠] Two Pair, Jacks over Sixes, kicker Queen [J♥ J♠ 6♣ 6♦ Q♣] [K♠ 9♠ 7♣ 2♦]
Player 5: [3♦ 4♦ K♣ 8♦] Pair, Sixes, kickers King, Queen, Eight [6♣ 6♦ K♣ Q♣ 8♦] [7♣ 4♦ 3♦ 2♦]
Player 6: [T♣ Q♦ A♠ 7♥] Two Pair, Queens over Sevens, kicker Six [Q♣ Q♦ 7♣ 7♥ 6♦] [A♠ T♣ 6♣ 2♦]
Result:   Player 3 wins with Full House, Sixes full of Queens
------ Omaha 5 ------
Board:    [4♣ K♣ 6♦ 9♦ 5♠]
Player 1: [3♦ 4♦ 5♦ J♣] Two Pair, Fives over Fours, kicker King [5♦ 5♠ 4♣ 4♦ K♣] [J♣ 9♦ 6♦ 3♦]
Player 2: [T♥ J♠ K♠ 2♣] Pair, Kings, kickers Jack, Nine, Six [K♣ K♠ J♠ 9♦ 6♦] [T♥ 5♠ 4♣ 2♣]
Player 3: [A♣ 9♠ T♠ 3♠] Pair, Nines, kickers Ace, King, Six [9♦ 9♠ A♣ K♣ 6♦] [T♠ 5♠ 4♣ 3♠]
Player 4: [7♦ 3♣ 8♠ 7♣] Straight, Nine-high [9♦ 8♠ 7♦ 6♦ 5♠] [K♣ 7♣ 4♣ 3♣]
Player 5: [5♣ Q♠ J♥ 2♠] Pair, Fives, kickers King, Queen, Nine [5♣ 5♠ K♣ Q♠ 9♦] [J♥ 6♦ 4♣ 2♠]
Player 6: [6♠ 7♠ 7♥ 2♥] Pair, Sevens, kickers King, Nine, Six [7♥ 7♠ K♣ 9♦ 6♦] [6♠ 5♠ 4♣ 2♥]
Result:   Player 4 wins with Straight, Nine-high
Example (OmahaHiLo)
package main

import (
	"fmt"
	"math/rand"
	"strconv"
	"strings"

	"github.com/cardrank/cardrank"
)

func main() {
	for i, game := range []struct {
		seed    int64
		players int
	}{
		{119, 2},
		{321, 5},
		{408, 6},
		{455, 6},
		{1113, 6},
	} {
		// note: use a real random source
		r := rand.New(rand.NewSource(game.seed))
		pockets, board := cardrank.OmahaHiLo.Deal(r, 1, game.players)
		evs := cardrank.OmahaHiLo.EvalPockets(pockets, board)
		fmt.Printf("------ OmahaHiLo %d ------\n", i+1)
		fmt.Printf("Board: %b\n", board)
		for j := 0; j < game.players; j++ {
			hi, lo := evs[j].Desc(false), evs[j].Desc(true)
			fmt.Printf("Player %d: %b\n", j+1, pockets[j])
			fmt.Printf("  Hi: %s %b %b\n", hi, hi.Best, hi.Unused)
			fmt.Printf("  Lo: %s %b %b\n", lo, lo.Best, lo.Unused)
		}
		hiOrder, hiPivot := cardrank.Order(evs, false)
		loOrder, loPivot := cardrank.Order(evs, true)
		typ := "wins"
		if loPivot == 0 {
			typ = "scoops"
		}
		desc := evs[hiOrder[0]].Desc(false)
		if hiPivot == 1 {
			fmt.Printf("Result (Hi): Player %d %s with %s\n", hiOrder[0]+1, typ, desc)
		} else {
			var s []string
			for j := 0; j < hiPivot; j++ {
				s = append(s, strconv.Itoa(hiOrder[j]+1))
			}
			fmt.Printf("Result (Hi): Players %s push with %s\n", strings.Join(s, ", "), desc)
		}
		if loPivot == 1 {
			desc := evs[loOrder[0]].Desc(true)
			fmt.Printf("Result (Lo): Player %d wins with %s\n", loOrder[0]+1, desc)
		} else if loPivot > 1 {
			var s []string
			for j := 0; j < loPivot; j++ {
				s = append(s, strconv.Itoa(loOrder[j]+1))
			}
			desc := evs[loOrder[0]].Desc(true)
			fmt.Printf("Result (Lo): Players %s push with %s\n", strings.Join(s, ", "), desc)
		} else {
			fmt.Printf("Result (Lo): no player made a lo\n")
		}
	}
}
Output:

------ OmahaHiLo 1 ------
Board: [3♥ 5♥ 4♥ 7♥ K♣]
Player 1: [K♥ J♣ A♥ Q♠]
  Hi: Flush, Ace-high, kickers King, Seven, Five, Four [A♥ K♥ 7♥ 5♥ 4♥] [K♣ Q♠ J♣ 3♥]
  Lo: None [] []
Player 2: [7♣ 4♣ 5♠ 2♠]
  Hi: Two Pair, Sevens over Fives, kicker King [7♣ 7♥ 5♥ 5♠ K♣] [4♣ 4♥ 3♥ 2♠]
  Lo: Seven, Five, Four, Three, Two-low [7♣ 5♥ 4♥ 3♥ 2♠] [K♣ 7♥ 5♠ 4♣]
Result (Hi): Player 1 wins with Flush, Ace-high, kickers King, Seven, Five, Four
Result (Lo): Player 2 wins with Seven, Five, Four, Three, Two-low
------ OmahaHiLo 2 ------
Board: [3♥ 7♣ 3♣ 9♠ 9♣]
Player 1: [3♠ 3♦ T♠ Q♠]
  Hi: Four of a Kind, Threes, kicker Nine [3♣ 3♦ 3♥ 3♠ 9♠] [Q♠ T♠ 9♣ 7♣]
  Lo: None [] []
Player 2: [6♦ Q♣ 8♥ 6♣]
  Hi: Flush, Queen-high, kickers Nine, Seven, Six, Three [Q♣ 9♣ 7♣ 6♣ 3♣] [9♠ 8♥ 6♦ 3♥]
  Lo: None [] []
Player 3: [Q♦ K♠ 8♣ A♥]
  Hi: Pair, Nines, kickers Ace, King, Seven [9♣ 9♠ A♥ K♠ 7♣] [Q♦ 8♣ 3♣ 3♥]
  Lo: None [] []
Player 4: [K♦ T♦ 8♦ 4♥]
  Hi: Pair, Nines, kickers King, Ten, Seven [9♣ 9♠ K♦ T♦ 7♣] [8♦ 4♥ 3♣ 3♥]
  Lo: None [] []
Player 5: [J♦ 2♥ Q♥ 6♠]
  Hi: Pair, Nines, kickers Queen, Jack, Seven [9♣ 9♠ Q♥ J♦ 7♣] [6♠ 3♣ 3♥ 2♥]
  Lo: None [] []
Result (Hi): Player 1 scoops with Four of a Kind, Threes, kicker Nine
Result (Lo): no player made a lo
------ OmahaHiLo 3 ------
Board: [J♣ T♥ 4♥ K♣ Q♣]
Player 1: [K♠ Q♠ 4♣ J♦]
  Hi: Two Pair, Kings over Queens, kicker Jack [K♣ K♠ Q♣ Q♠ J♣] [J♦ T♥ 4♣ 4♥]
  Lo: None [] []
Player 2: [J♠ 3♣ 8♥ 2♠]
  Hi: Pair, Jacks, kickers King, Queen, Eight [J♣ J♠ K♣ Q♣ 8♥] [T♥ 4♥ 3♣ 2♠]
  Lo: None [] []
Player 3: [3♠ T♠ 2♣ Q♦]
  Hi: Two Pair, Queens over Tens, kicker King [Q♣ Q♦ T♥ T♠ K♣] [J♣ 4♥ 3♠ 2♣]
  Lo: None [] []
Player 4: [5♣ 5♥ T♦ 2♦]
  Hi: Pair, Tens, kickers King, Queen, Five [T♦ T♥ K♣ Q♣ 5♣] [J♣ 5♥ 4♥ 2♦]
  Lo: None [] []
Player 5: [7♠ 3♥ 6♠ A♣]
  Hi: Ace-high, kickers King, Queen, Jack, Seven [A♣ K♣ Q♣ J♣ 7♠] [T♥ 6♠ 4♥ 3♥]
  Lo: None [] []
Player 6: [4♠ 8♦ K♦ T♣]
  Hi: Two Pair, Kings over Tens, kicker Queen [K♣ K♦ T♣ T♥ Q♣] [J♣ 8♦ 4♥ 4♠]
  Lo: None [] []
Result (Hi): Player 1 scoops with Two Pair, Kings over Queens, kicker Jack
Result (Lo): no player made a lo
------ OmahaHiLo 4 ------
Board: [2♦ 6♦ 6♣ Q♣ 7♣]
Player 1: [6♠ K♥ A♣ 8♣]
  Hi: Flush, Ace-high, kickers Queen, Eight, Seven, Six [A♣ Q♣ 8♣ 7♣ 6♣] [K♥ 6♦ 6♠ 2♦]
  Lo: Eight, Seven, Six, Two, Ace-low [8♣ 7♣ 6♦ 2♦ A♣] [K♥ Q♣ 6♣ 6♠]
Player 2: [Q♥ 4♥ J♣ 5♥]
  Hi: Two Pair, Queens over Sixes, kicker Jack [Q♣ Q♥ 6♣ 6♦ J♣] [7♣ 5♥ 4♥ 2♦]
  Lo: Seven, Six, Five, Four, Two-low [7♣ 6♦ 5♥ 4♥ 2♦] [Q♣ Q♥ J♣ 6♣]
Player 3: [2♣ 6♥ 5♣ Q♠]
  Hi: Full House, Sixes full of Queens [6♣ 6♦ 6♥ Q♣ Q♠] [7♣ 5♣ 2♣ 2♦]
  Lo: None [] []
Player 4: [9♠ J♥ K♠ J♠]
  Hi: Two Pair, Jacks over Sixes, kicker Queen [J♥ J♠ 6♣ 6♦ Q♣] [K♠ 9♠ 7♣ 2♦]
  Lo: None [] []
Player 5: [3♦ 4♦ K♣ 8♦]
  Hi: Pair, Sixes, kickers King, Queen, Eight [6♣ 6♦ K♣ Q♣ 8♦] [7♣ 4♦ 3♦ 2♦]
  Lo: Seven, Six, Four, Three, Two-low [7♣ 6♦ 4♦ 3♦ 2♦] [K♣ Q♣ 8♦ 6♣]
Player 6: [T♣ Q♦ A♠ 7♥]
  Hi: Two Pair, Queens over Sevens, kicker Six [Q♣ Q♦ 7♣ 7♥ 6♦] [A♠ T♣ 6♣ 2♦]
  Lo: None [] []
Result (Hi): Player 3 wins with Full House, Sixes full of Queens
Result (Lo): Player 5 wins with Seven, Six, Four, Three, Two-low
------ OmahaHiLo 5 ------
Board: [4♣ K♣ 6♦ 9♦ 5♠]
Player 1: [3♦ 4♦ 5♦ J♣]
  Hi: Two Pair, Fives over Fours, kicker King [5♦ 5♠ 4♣ 4♦ K♣] [J♣ 9♦ 6♦ 3♦]
  Lo: None [] []
Player 2: [T♥ J♠ K♠ 2♣]
  Hi: Pair, Kings, kickers Jack, Nine, Six [K♣ K♠ J♠ 9♦ 6♦] [T♥ 5♠ 4♣ 2♣]
  Lo: None [] []
Player 3: [A♣ 9♠ T♠ 3♠]
  Hi: Pair, Nines, kickers Ace, King, Six [9♦ 9♠ A♣ K♣ 6♦] [T♠ 5♠ 4♣ 3♠]
  Lo: Six, Five, Four, Three, Ace-low [6♦ 5♠ 4♣ 3♠ A♣] [K♣ T♠ 9♦ 9♠]
Player 4: [7♦ 3♣ 8♠ 7♣]
  Hi: Straight, Nine-high [9♦ 8♠ 7♦ 6♦ 5♠] [K♣ 7♣ 4♣ 3♣]
  Lo: Seven, Six, Five, Four, Three-low [7♦ 6♦ 5♠ 4♣ 3♣] [K♣ 9♦ 8♠ 7♣]
Player 5: [5♣ Q♠ J♥ 2♠]
  Hi: Pair, Fives, kickers King, Queen, Nine [5♣ 5♠ K♣ Q♠ 9♦] [J♥ 6♦ 4♣ 2♠]
  Lo: None [] []
Player 6: [6♠ 7♠ 7♥ 2♥]
  Hi: Pair, Sevens, kickers King, Nine, Six [7♥ 7♠ K♣ 9♦ 6♦] [6♠ 5♠ 4♣ 2♥]
  Lo: Seven, Six, Five, Four, Two-low [7♠ 6♦ 5♠ 4♣ 2♥] [K♣ 9♦ 7♥ 6♠]
Result (Hi): Player 4 wins with Straight, Nine-high
Result (Lo): Player 3 wins with Six, Five, Four, Three, Ace-low
Example (Razz)
package main

import (
	"fmt"
	"math/rand"
	"strconv"
	"strings"

	"github.com/cardrank/cardrank"
)

func main() {
	for i, game := range []struct {
		seed    int64
		players int
	}{
		{119, 2},
		{321, 5},
		{408, 6},
		{455, 6},
		{1113, 6},
	} {
		// note: use a real random source
		r := rand.New(rand.NewSource(game.seed))
		pockets, _ := cardrank.Razz.Deal(r, 1, game.players)
		evs := cardrank.Razz.EvalPockets(pockets, nil)
		fmt.Printf("------ Razz %d ------\n", i+1)
		for j := 0; j < game.players; j++ {
			desc := evs[j].Desc(false)
			fmt.Printf("Player %d: %b %s %b %b\n", j+1, pockets[j], desc, desc.Best, desc.Unused)
		}
		order, pivot := cardrank.Order(evs, false)
		desc := evs[order[0]].Desc(false)
		if pivot == 1 {
			fmt.Printf("Result:   Player %d wins with %s\n", order[0]+1, desc)
		} else {
			var s []string
			for j := 0; j < pivot; j++ {
				s = append(s, strconv.Itoa(order[j]+1))
			}
			fmt.Printf("Result:   Players %s push with %s\n", strings.Join(s, ", "), desc)
		}
	}
}
Output:

------ Razz 1 ------
Player 1: [K♥ J♣ A♥ Q♠ 6♣ 5♥ Q♦] Queen, Jack, Six, Five, Ace-low [Q♠ J♣ 6♣ 5♥ A♥] [K♥ Q♦]
Player 2: [7♣ 4♣ 5♠ 2♠ 3♥ 4♥ 7♥] Seven, Five, Four, Three, Two-low [7♣ 5♠ 4♣ 3♥ 2♠] [7♥ 4♥]
Result:   Player 2 wins with Seven, Five, Four, Three, Two-low
------ Razz 2 ------
Player 1: [3♠ 3♦ T♠ Q♠ T♥ 9♠ K♥] King, Queen, Ten, Nine, Three-low [K♥ Q♠ T♠ 9♠ 3♠] [T♥ 3♦]
Player 2: [6♦ Q♣ 8♥ 6♣ 3♥ T♣ 7♥] Ten, Eight, Seven, Six, Three-low [T♣ 8♥ 7♥ 6♦ 3♥] [Q♣ 6♣]
Player 3: [Q♦ K♠ 8♣ A♥ 7♣ 9♣ 2♣] Nine, Eight, Seven, Two, Ace-low [9♣ 8♣ 7♣ 2♣ A♥] [K♠ Q♦]
Player 4: [K♦ T♦ 8♦ 4♥ 3♣ J♠ 2♦] Ten, Eight, Four, Three, Two-low [T♦ 8♦ 4♥ 3♣ 2♦] [K♦ J♠]
Player 5: [J♦ 2♥ Q♥ 6♠ 5♦ 7♠ A♦] Seven, Six, Five, Two, Ace-low [7♠ 6♠ 5♦ 2♥ A♦] [Q♥ J♦]
Result:   Player 5 wins with Seven, Six, Five, Two, Ace-low
------ Razz 3 ------
Player 1: [K♠ Q♠ 4♣ J♦ 7♥ 7♣ J♥] King, Queen, Jack, Seven, Four-low [K♠ Q♠ J♦ 7♥ 4♣] [J♥ 7♣]
Player 2: [J♠ 3♣ 8♥ 2♠ J♣ Q♣ 7♦] Jack, Eight, Seven, Three, Two-low [J♠ 8♥ 7♦ 3♣ 2♠] [Q♣ J♣]
Player 3: [3♠ T♠ 2♣ Q♦ T♥ K♥ 3♦] King, Queen, Ten, Three, Two-low [K♥ Q♦ T♠ 3♠ 2♣] [T♥ 3♦]
Player 4: [5♣ 5♥ T♦ 2♦ 4♥ 9♦ 2♥] Ten, Nine, Five, Four, Two-low [T♦ 9♦ 5♣ 4♥ 2♦] [5♥ 2♥]
Player 5: [7♠ 3♥ 6♠ A♣ 8♠ 6♦ A♦] Eight, Seven, Six, Three, Ace-low [8♠ 7♠ 6♠ 3♥ A♣] [A♦ 6♦]
Player 6: [4♠ 8♦ K♦ T♣ K♣ 5♠ 9♣] Ten, Nine, Eight, Five, Four-low [T♣ 9♣ 8♦ 5♠ 4♠] [K♣ K♦]
Result:   Player 5 wins with Eight, Seven, Six, Three, Ace-low
------ Razz 4 ------
Player 1: [6♠ K♥ A♣ 8♣ 2♠ 5♦ A♥] Eight, Six, Five, Two, Ace-low [8♣ 6♠ 5♦ 2♠ A♣] [A♥ K♥]
Player 2: [Q♥ 4♥ J♣ 5♥ 2♦ 7♣ 3♠] Seven, Five, Four, Three, Two-low [7♣ 5♥ 4♥ 3♠ 2♦] [Q♥ J♣]
Player 3: [2♣ 6♥ 5♣ Q♠ 6♦ 9♥ 3♣] Nine, Six, Five, Three, Two-low [9♥ 6♥ 5♣ 3♣ 2♣] [Q♠ 6♦]
Player 4: [9♠ J♥ K♠ J♠ 6♣ K♦ T♠] King, Jack, Ten, Nine, Six-low [K♠ J♥ T♠ 9♠ 6♣] [K♦ J♠]
Player 5: [3♦ 4♦ K♣ 8♦ 8♥ 9♣ T♥] Ten, Nine, Eight, Four, Three-low [T♥ 9♣ 8♦ 4♦ 3♦] [K♣ 8♥]
Player 6: [T♣ Q♦ A♠ 7♥ Q♣ 7♦ 2♥] Queen, Ten, Seven, Two, Ace-low [Q♦ T♣ 7♥ 2♥ A♠] [Q♣ 7♦]
Result:   Player 2 wins with Seven, Five, Four, Three, Two-low
------ Razz 5 ------
Player 1: [3♦ 4♦ 5♦ J♣ 4♥ K♥ 8♣] Jack, Eight, Five, Four, Three-low [J♣ 8♣ 5♦ 4♦ 3♦] [K♥ 4♥]
Player 2: [T♥ J♠ K♠ 2♣ 4♣ 5♠ 2♦] Jack, Ten, Five, Four, Two-low [J♠ T♥ 5♠ 4♣ 2♣] [K♠ 2♦]
Player 3: [A♣ 9♠ T♠ 3♠ K♣ 8♦ A♥] Ten, Nine, Eight, Three, Ace-low [T♠ 9♠ 8♦ 3♠ A♣] [A♥ K♣]
Player 4: [7♦ 3♣ 8♠ 7♣ 6♦ 6♥ 6♣] Pair, Sixes, kickers Eight, Seven, Three [6♦ 6♥ 8♠ 7♦ 3♣] [7♣ 6♣]
Player 5: [5♣ Q♠ J♥ 2♠ A♠ 8♥ 4♠] Eight, Five, Four, Two, Ace-low [8♥ 5♣ 4♠ 2♠ A♠] [Q♠ J♥]
Player 6: [6♠ 7♠ 7♥ 2♥ 9♦ K♦ T♦] Ten, Nine, Seven, Six, Two-low [T♦ 9♦ 7♠ 6♠ 2♥] [K♦ 7♥]
Result:   Player 5 wins with Eight, Five, Four, Two, Ace-low
Example (Royal)
package main

import (
	"fmt"
	"math/rand"
	"strconv"
	"strings"

	"github.com/cardrank/cardrank"
)

func main() {
	for i, game := range []struct {
		seed    int64
		players int
	}{
		{119, 2},
		{155, 3},
		{384, 4},
		{880, 5},
		{3453, 2},
		{5662, 3},
		{65481, 4},
		{27947, 5},
	} {
		// note: use a real random source
		r := rand.New(rand.NewSource(game.seed))
		pockets, board := cardrank.Royal.Deal(r, 1, game.players)
		evs := cardrank.Royal.EvalPockets(pockets, board)
		fmt.Printf("------ Royal %d ------\n", i+1)
		fmt.Printf("Board:    %b\n", board)
		for j := 0; j < game.players; j++ {
			desc := evs[j].Desc(false)
			fmt.Printf("Player %d: %b %s %b %b\n", j+1, pockets[j], desc, desc.Best, desc.Unused)
		}
		order, pivot := cardrank.Order(evs, false)
		desc := evs[order[0]].Desc(false)
		if pivot == 1 {
			fmt.Printf("Result:   Player %d wins with %s\n", order[0]+1, desc)
		} else {
			var s []string
			for j := 0; j < pivot; j++ {
				s = append(s, strconv.Itoa(order[j]+1))
			}
			fmt.Printf("Result:   Players %s push with %s\n", strings.Join(s, ", "), desc)
		}
	}
}
Output:

------ Royal 1 ------
Board:    [K♦ A♦ T♥ T♣ J♠]
Player 1: [A♠ T♠] Full House, Tens full of Aces [T♣ T♥ T♠ A♦ A♠] [K♦ J♠]
Player 2: [A♥ K♠] Two Pair, Aces over Kings, kicker Jack [A♦ A♥ K♦ K♠ J♠] [T♣ T♥]
Result:   Player 1 wins with Full House, Tens full of Aces
------ Royal 2 ------
Board:    [A♣ K♠ J♦ Q♣ J♣]
Player 1: [A♠ Q♠] Two Pair, Aces over Queens, kicker King [A♣ A♠ Q♣ Q♠ K♠] [J♣ J♦]
Player 2: [T♠ J♥] Straight, Ace-high [A♣ K♠ Q♣ J♣ T♠] [J♦ J♥]
Player 3: [K♣ T♥] Straight, Ace-high [A♣ K♣ Q♣ J♣ T♥] [K♠ J♦]
Result:   Players 2, 3 push with Straight, Ace-high
------ Royal 3 ------
Board:    [K♠ T♦ T♣ Q♦ A♥]
Player 1: [T♠ T♥] Four of a Kind, Tens, kicker Ace [T♣ T♦ T♥ T♠ A♥] [K♠ Q♦]
Player 2: [J♣ Q♣] Straight, Ace-high [A♥ K♠ Q♣ J♣ T♣] [Q♦ T♦]
Player 3: [A♦ K♦] Two Pair, Aces over Kings, kicker Queen [A♦ A♥ K♦ K♠ Q♦] [T♣ T♦]
Player 4: [K♥ K♣] Full House, Kings full of Tens [K♣ K♥ K♠ T♣ T♦] [A♥ Q♦]
Result:   Player 1 wins with Four of a Kind, Tens, kicker Ace
------ Royal 4 ------
Board:    [J♥ A♠ T♥ T♣ K♠]
Player 1: [Q♦ T♠] Straight, Ace-high [A♠ K♠ Q♦ J♥ T♣] [T♥ T♠]
Player 2: [K♥ T♦] Full House, Tens full of Kings [T♣ T♦ T♥ K♥ K♠] [A♠ J♥]
Player 3: [A♣ Q♠] Straight, Ace-high [A♣ K♠ Q♠ J♥ T♣] [A♠ T♥]
Player 4: [A♦ J♠] Two Pair, Aces over Jacks, kicker King [A♦ A♠ J♥ J♠ K♠] [T♣ T♥]
Player 5: [K♦ J♦] Two Pair, Kings over Jacks, kicker Ace [K♦ K♠ J♦ J♥ A♠] [T♣ T♥]
Result:   Player 2 wins with Full House, Tens full of Kings
------ Royal 5 ------
Board:    [J♣ K♥ K♠ J♥ Q♣]
Player 1: [A♥ T♦] Straight, Ace-high [A♥ K♥ Q♣ J♣ T♦] [K♠ J♥]
Player 2: [J♦ Q♠] Full House, Jacks full of Kings [J♣ J♦ J♥ K♥ K♠] [Q♣ Q♠]
Result:   Player 2 wins with Full House, Jacks full of Kings
------ Royal 6 ------
Board:    [K♥ A♠ K♦ K♠ A♣]
Player 1: [J♥ J♠] Full House, Kings full of Aces [K♦ K♥ K♠ A♣ A♠] [J♥ J♠]
Player 2: [Q♦ A♥] Full House, Aces full of Kings [A♣ A♥ A♠ K♦ K♥] [K♠ Q♦]
Player 3: [Q♠ T♣] Full House, Kings full of Aces [K♦ K♥ K♠ A♣ A♠] [Q♠ T♣]
Result:   Player 2 wins with Full House, Aces full of Kings
------ Royal 7 ------
Board:    [J♥ T♦ Q♠ K♣ K♥]
Player 1: [K♦ J♣] Full House, Kings full of Jacks [K♣ K♦ K♥ J♣ J♥] [Q♠ T♦]
Player 2: [T♥ T♠] Full House, Tens full of Kings [T♦ T♥ T♠ K♣ K♥] [Q♠ J♥]
Player 3: [A♠ A♥] Straight, Ace-high [A♥ K♣ Q♠ J♥ T♦] [A♠ K♥]
Player 4: [Q♣ A♦] Straight, Ace-high [A♦ K♣ Q♣ J♥ T♦] [K♥ Q♠]
Result:   Player 1 wins with Full House, Kings full of Jacks
------ Royal 8 ------
Board:    [A♠ K♦ Q♦ A♦ A♣]
Player 1: [Q♠ J♠] Full House, Aces full of Queens [A♣ A♦ A♠ Q♦ Q♠] [K♦ J♠]
Player 2: [T♦ A♥] Four of a Kind, Aces, kicker King [A♣ A♦ A♥ A♠ K♦] [Q♦ T♦]
Player 3: [J♥ K♠] Full House, Aces full of Kings [A♣ A♦ A♠ K♦ K♠] [Q♦ J♥]
Player 4: [Q♥ J♦] Full House, Aces full of Queens [A♣ A♦ A♠ Q♦ Q♥] [K♦ J♦]
Player 5: [K♣ T♥] Full House, Aces full of Kings [A♣ A♦ A♠ K♣ K♦] [Q♦ T♥]
Result:   Player 2 wins with Four of a Kind, Aces, kicker King
Example (Short)
package main

import (
	"fmt"
	"math/rand"
	"strconv"
	"strings"

	"github.com/cardrank/cardrank"
)

func main() {
	for i, game := range []struct {
		seed    int64
		players int
	}{
		{119, 2},
		{155, 4},
		{384, 8},
		{880, 4},
		{3453, 3},
		{5662, 3},
		{65481, 2},
		{27947, 4},
	} {
		// note: use a real random source
		r := rand.New(rand.NewSource(game.seed))
		pockets, board := cardrank.Short.Deal(r, 1, game.players)
		evs := cardrank.Short.EvalPockets(pockets, board)
		fmt.Printf("------ Short %d ------\n", i+1)
		fmt.Printf("Board:    %b\n", board)
		for j := 0; j < game.players; j++ {
			desc := evs[j].Desc(false)
			fmt.Printf("Player %d: %b %s %b %b\n", j+1, pockets[j], desc, desc.Best, desc.Unused)
		}
		order, pivot := cardrank.Order(evs, false)
		desc := evs[order[0]].Desc(false)
		if pivot == 1 {
			fmt.Printf("Result:   Player %d wins with %s\n", order[0]+1, desc)
		} else {
			var s []string
			for j := 0; j < pivot; j++ {
				s = append(s, strconv.Itoa(order[j]+1))
			}
			fmt.Printf("Result:   Players %s push with %s\n", strings.Join(s, ", "), desc)
		}
	}
}
Output:

------ Short 1 ------
Board:    [9♥ A♦ A♥ 8♣ A♣]
Player 1: [8♥ A♠] Four of a Kind, Aces, kicker Nine [A♣ A♦ A♥ A♠ 9♥] [8♣ 8♥]
Player 2: [7♥ J♦] Three of a Kind, Aces, kickers Jack, Nine [A♣ A♦ A♥ J♦ 9♥] [8♣ 7♥]
Result:   Player 1 wins with Four of a Kind, Aces, kicker Nine
------ Short 2 ------
Board:    [9♣ 6♦ A♠ J♠ 6♠]
Player 1: [T♥ A♣] Two Pair, Aces over Sixes, kicker Jack [A♣ A♠ 6♦ 6♠ J♠] [T♥ 9♣]
Player 2: [6♣ 7♣] Three of a Kind, Sixes, kickers Ace, Jack [6♣ 6♦ 6♠ A♠ J♠] [9♣ 7♣]
Player 3: [6♥ T♠] Three of a Kind, Sixes, kickers Ace, Jack [6♦ 6♥ 6♠ A♠ J♠] [T♠ 9♣]
Player 4: [9♥ K♠] Two Pair, Nines over Sixes, kicker Ace [9♣ 9♥ 6♦ 6♠ A♠] [K♠ J♠]
Result:   Players 2, 3 push with Three of a Kind, Sixes, kickers Ace, Jack
------ Short 3 ------
Board:    [T♥ J♣ 7♥ 9♥ K♣]
Player 1: [8♥ T♣] Straight, Jack-high [J♣ T♣ 9♥ 8♥ 7♥] [K♣ T♥]
Player 2: [T♠ Q♠] Straight, King-high [K♣ Q♠ J♣ T♥ 9♥] [T♠ 7♥]
Player 3: [J♠ 7♣] Two Pair, Jacks over Sevens, kicker King [J♣ J♠ 7♣ 7♥ K♣] [T♥ 9♥]
Player 4: [6♣ Q♦] Straight, King-high [K♣ Q♦ J♣ T♥ 9♥] [7♥ 6♣]
Player 5: [7♦ 6♠] Pair, Sevens, kickers King, Jack, Ten [7♦ 7♥ K♣ J♣ T♥] [9♥ 6♠]
Player 6: [8♠ 8♦] Straight, Jack-high [J♣ T♥ 9♥ 8♦ 7♥] [K♣ 8♠]
Player 7: [9♣ K♥] Two Pair, Kings over Nines, kicker Jack [K♣ K♥ 9♣ 9♥ J♣] [T♥ 7♥]
Player 8: [A♥ K♦] Pair, Kings, kickers Ace, Jack, Ten [K♣ K♦ A♥ J♣ T♥] [9♥ 7♥]
Result:   Players 2, 4 push with Straight, King-high
------ Short 4 ------
Board:    [T♦ 9♣ 9♦ Q♦ 8♦]
Player 1: [J♠ 9♥] Straight, Queen-high [Q♦ J♠ T♦ 9♣ 8♦] [9♦ 9♥]
Player 2: [T♥ 8♠] Two Pair, Tens over Nines, kicker Queen [T♦ T♥ 9♣ 9♦ Q♦] [8♦ 8♠]
Player 3: [6♣ J♦] Straight Flush, Queen-high, Silver Tongue [Q♦ J♦ T♦ 9♦ 8♦] [9♣ 6♣]
Player 4: [A♣ A♦] Flush, Ace-high, kickers Queen, Ten, Nine, Eight [A♦ Q♦ T♦ 9♦ 8♦] [A♣ 9♣]
Result:   Player 3 wins with Straight Flush, Queen-high, Silver Tongue
------ Short 5 ------
Board:    [6♠ A♣ 7♦ A♠ 6♦]
Player 1: [9♣ T♦] Two Pair, Aces over Sixes, kicker Ten [A♣ A♠ 6♦ 6♠ T♦] [9♣ 7♦]
Player 2: [T♠ K♠] Two Pair, Aces over Sixes, kicker King [A♣ A♠ 6♦ 6♠ K♠] [T♠ 7♦]
Player 3: [J♥ A♥] Full House, Aces full of Sixes [A♣ A♥ A♠ 6♦ 6♠] [J♥ 7♦]
Result:   Player 3 wins with Full House, Aces full of Sixes
------ Short 6 ------
Board:    [A♣ 6♣ 9♣ T♦ 8♣]
Player 1: [6♥ 9♠] Two Pair, Nines over Sixes, kicker Ace [9♣ 9♠ 6♣ 6♥ A♣] [T♦ 8♣]
Player 2: [7♣ J♥] Straight Flush, Nine-high, Iron Maiden [9♣ 8♣ 7♣ 6♣ A♣] [J♥ T♦]
Player 3: [6♠ Q♠] Pair, Sixes, kickers Ace, Queen, Ten [6♣ 6♠ A♣ Q♠ T♦] [9♣ 8♣]
Result:   Player 2 wins with Straight Flush, Nine-high, Iron Maiden
------ Short 7 ------
Board:    [K♥ K♦ K♠ K♣ J♣]
Player 1: [7♦ 8♦] Four of a Kind, Kings, kicker Jack [K♣ K♦ K♥ K♠ J♣] [8♦ 7♦]
Player 2: [T♦ 6♥] Four of a Kind, Kings, kicker Jack [K♣ K♦ K♥ K♠ J♣] [T♦ 6♥]
Result:   Players 1, 2 push with Four of a Kind, Kings, kicker Jack
------ Short 8 ------
Board:    [8♦ 8♥ 8♠ Q♠ T♦]
Player 1: [J♦ 9♣] Straight, Queen-high [Q♠ J♦ T♦ 9♣ 8♦] [8♥ 8♠]
Player 2: [T♣ J♣] Full House, Eights full of Tens [8♦ 8♥ 8♠ T♣ T♦] [Q♠ J♣]
Player 3: [K♠ T♥] Full House, Eights full of Tens [8♦ 8♥ 8♠ T♦ T♥] [K♠ Q♠]
Player 4: [T♠ 7♥] Full House, Eights full of Tens [8♦ 8♥ 8♠ T♦ T♠] [Q♠ 7♥]
Result:   Players 2, 3, 4 push with Full House, Eights full of Tens
Example (Stud)
package main

import (
	"fmt"
	"math/rand"
	"strconv"
	"strings"

	"github.com/cardrank/cardrank"
)

func main() {
	for i, game := range []struct {
		seed    int64
		players int
	}{
		{119, 2},
		{321, 5},
		{408, 6},
		{455, 6},
		{1113, 6},
	} {
		// note: use a real random source
		r := rand.New(rand.NewSource(game.seed))
		pockets, _ := cardrank.Stud.Deal(r, 1, game.players)
		evs := cardrank.Stud.EvalPockets(pockets, nil)
		fmt.Printf("------ Stud %d ------\n", i+1)
		for j := 0; j < game.players; j++ {
			desc := evs[j].Desc(false)
			fmt.Printf("Player %d: %b %s %b %b\n", j+1, pockets[j], desc, desc.Best, desc.Unused)
		}
		order, pivot := cardrank.Order(evs, false)
		desc := evs[order[0]].Desc(false)
		if pivot == 1 {
			fmt.Printf("Result:   Player %d wins with %s\n", order[0]+1, desc)
		} else {
			var s []string
			for j := 0; j < pivot; j++ {
				s = append(s, strconv.Itoa(order[j]+1))
			}
			fmt.Printf("Result:   Players %s push with %s\n", strings.Join(s, ", "), desc)
		}
	}
}
Output:

------ Stud 1 ------
Player 1: [K♥ J♣ A♥ Q♠ 6♣ 5♥ Q♦] Pair, Queens, kickers Ace, King, Jack [Q♦ Q♠ A♥ K♥ J♣] [6♣ 5♥]
Player 2: [7♣ 4♣ 5♠ 2♠ 3♥ 4♥ 7♥] Two Pair, Sevens over Fours, kicker Five [7♣ 7♥ 4♣ 4♥ 5♠] [3♥ 2♠]
Result:   Player 2 wins with Two Pair, Sevens over Fours, kicker Five
------ Stud 2 ------
Player 1: [3♠ 3♦ T♠ Q♠ T♥ 9♠ K♥] Two Pair, Tens over Threes, kicker King [T♥ T♠ 3♦ 3♠ K♥] [Q♠ 9♠]
Player 2: [6♦ Q♣ 8♥ 6♣ 3♥ T♣ 7♥] Pair, Sixes, kickers Queen, Ten, Eight [6♣ 6♦ Q♣ T♣ 8♥] [7♥ 3♥]
Player 3: [Q♦ K♠ 8♣ A♥ 7♣ 9♣ 2♣] Ace-high, kickers King, Queen, Nine, Eight [A♥ K♠ Q♦ 9♣ 8♣] [7♣ 2♣]
Player 4: [K♦ T♦ 8♦ 4♥ 3♣ J♠ 2♦] King-high, kickers Jack, Ten, Eight, Four [K♦ J♠ T♦ 8♦ 4♥] [3♣ 2♦]
Player 5: [J♦ 2♥ Q♥ 6♠ 5♦ 7♠ A♦] Ace-high, kickers Queen, Jack, Seven, Six [A♦ Q♥ J♦ 7♠ 6♠] [5♦ 2♥]
Result:   Player 1 wins with Two Pair, Tens over Threes, kicker King
------ Stud 3 ------
Player 1: [K♠ Q♠ 4♣ J♦ 7♥ 7♣ J♥] Two Pair, Jacks over Sevens, kicker King [J♦ J♥ 7♣ 7♥ K♠] [Q♠ 4♣]
Player 2: [J♠ 3♣ 8♥ 2♠ J♣ Q♣ 7♦] Pair, Jacks, kickers Queen, Eight, Seven [J♣ J♠ Q♣ 8♥ 7♦] [3♣ 2♠]
Player 3: [3♠ T♠ 2♣ Q♦ T♥ K♥ 3♦] Two Pair, Tens over Threes, kicker King [T♥ T♠ 3♦ 3♠ K♥] [Q♦ 2♣]
Player 4: [5♣ 5♥ T♦ 2♦ 4♥ 9♦ 2♥] Two Pair, Fives over Twos, kicker Ten [5♣ 5♥ 2♦ 2♥ T♦] [9♦ 4♥]
Player 5: [7♠ 3♥ 6♠ A♣ 8♠ 6♦ A♦] Two Pair, Aces over Sixes, kicker Eight [A♣ A♦ 6♦ 6♠ 8♠] [7♠ 3♥]
Player 6: [4♠ 8♦ K♦ T♣ K♣ 5♠ 9♣] Pair, Kings, kickers Ten, Nine, Eight [K♣ K♦ T♣ 9♣ 8♦] [5♠ 4♠]
Result:   Player 5 wins with Two Pair, Aces over Sixes, kicker Eight
------ Stud 4 ------
Player 1: [6♠ K♥ A♣ 8♣ 2♠ 5♦ A♥] Pair, Aces, kickers King, Eight, Six [A♣ A♥ K♥ 8♣ 6♠] [5♦ 2♠]
Player 2: [Q♥ 4♥ J♣ 5♥ 2♦ 7♣ 3♠] Queen-high, kickers Jack, Seven, Five, Four [Q♥ J♣ 7♣ 5♥ 4♥] [3♠ 2♦]
Player 3: [2♣ 6♥ 5♣ Q♠ 6♦ 9♥ 3♣] Pair, Sixes, kickers Queen, Nine, Five [6♦ 6♥ Q♠ 9♥ 5♣] [3♣ 2♣]
Player 4: [9♠ J♥ K♠ J♠ 6♣ K♦ T♠] Two Pair, Kings over Jacks, kicker Ten [K♦ K♠ J♥ J♠ T♠] [9♠ 6♣]
Player 5: [3♦ 4♦ K♣ 8♦ 8♥ 9♣ T♥] Pair, Eights, kickers King, Ten, Nine [8♦ 8♥ K♣ T♥ 9♣] [4♦ 3♦]
Player 6: [T♣ Q♦ A♠ 7♥ Q♣ 7♦ 2♥] Two Pair, Queens over Sevens, kicker Ace [Q♣ Q♦ 7♦ 7♥ A♠] [T♣ 2♥]
Result:   Player 4 wins with Two Pair, Kings over Jacks, kicker Ten
------ Stud 5 ------
Player 1: [3♦ 4♦ 5♦ J♣ 4♥ K♥ 8♣] Pair, Fours, kickers King, Jack, Eight [4♦ 4♥ K♥ J♣ 8♣] [5♦ 3♦]
Player 2: [T♥ J♠ K♠ 2♣ 4♣ 5♠ 2♦] Pair, Twos, kickers King, Jack, Ten [2♣ 2♦ K♠ J♠ T♥] [5♠ 4♣]
Player 3: [A♣ 9♠ T♠ 3♠ K♣ 8♦ A♥] Pair, Aces, kickers King, Ten, Nine [A♣ A♥ K♣ T♠ 9♠] [8♦ 3♠]
Player 4: [7♦ 3♣ 8♠ 7♣ 6♦ 6♥ 6♣] Full House, Sixes full of Sevens [6♣ 6♦ 6♥ 7♣ 7♦] [8♠ 3♣]
Player 5: [5♣ Q♠ J♥ 2♠ A♠ 8♥ 4♠] Ace-high, kickers Queen, Jack, Eight, Five [A♠ Q♠ J♥ 8♥ 5♣] [4♠ 2♠]
Player 6: [6♠ 7♠ 7♥ 2♥ 9♦ K♦ T♦] Pair, Sevens, kickers King, Ten, Nine [7♥ 7♠ K♦ T♦ 9♦] [6♠ 2♥]
Result:   Player 4 wins with Full House, Sixes full of Sevens
Example (StudHiLo)
package main

import (
	"fmt"
	"math/rand"
	"strconv"
	"strings"

	"github.com/cardrank/cardrank"
)

func main() {
	for i, game := range []struct {
		seed    int64
		players int
	}{
		{119, 2},
		{321, 5},
		{408, 6},
		{455, 6},
		{1113, 6},
	} {
		// note: use a real random source
		r := rand.New(rand.NewSource(game.seed))
		pockets, _ := cardrank.StudHiLo.Deal(r, 1, game.players)
		evs := cardrank.StudHiLo.EvalPockets(pockets, nil)
		fmt.Printf("------ StudHiLo %d ------\n", i+1)
		for j := 0; j < game.players; j++ {
			hi, lo := evs[j].Desc(false), evs[j].Desc(true)
			fmt.Printf("Player %d: %b\n", j+1, pockets[j])
			fmt.Printf("  Hi: %s %b %b\n", hi, hi.Best, hi.Unused)
			fmt.Printf("  Lo: %s %b %b\n", lo, lo.Best, lo.Unused)
		}
		hiOrder, hiPivot := cardrank.Order(evs, false)
		loOrder, loPivot := cardrank.Order(evs, true)
		typ := "wins"
		if loPivot == 0 {
			typ = "scoops"
		}
		desc := evs[hiOrder[0]].Desc(false)
		if hiPivot == 1 {
			fmt.Printf("Result (Hi): Player %d %s with %s\n", hiOrder[0]+1, typ, desc)
		} else {
			var s []string
			for j := 0; j < hiPivot; j++ {
				s = append(s, strconv.Itoa(hiOrder[j]+1))
			}
			fmt.Printf("Result (Hi): Players %s push with %s\n", strings.Join(s, ", "), desc)
		}
		if loPivot == 1 {
			desc := evs[loOrder[0]].Desc(true)
			fmt.Printf("Result (Lo): Player %d wins with %s\n", loOrder[0]+1, desc)
		} else if loPivot > 1 {
			var s []string
			for j := 0; j < loPivot; j++ {
				s = append(s, strconv.Itoa(loOrder[j]+1))
			}
			desc := evs[loOrder[0]].Desc(true)
			fmt.Printf("Result (Lo): Players %s push with %s\n", strings.Join(s, ", "), desc)
		} else {
			fmt.Printf("Result (Lo): no player made a lo\n")
		}
	}
}
Output:

------ StudHiLo 1 ------
Player 1: [K♥ J♣ A♥ Q♠ 6♣ 5♥ Q♦]
  Hi: Pair, Queens, kickers Ace, King, Jack [Q♦ Q♠ A♥ K♥ J♣] [6♣ 5♥]
  Lo: None [] []
Player 2: [7♣ 4♣ 5♠ 2♠ 3♥ 4♥ 7♥]
  Hi: Two Pair, Sevens over Fours, kicker Five [7♣ 7♥ 4♣ 4♥ 5♠] [3♥ 2♠]
  Lo: Seven, Five, Four, Three, Two-low [7♣ 5♠ 4♣ 3♥ 2♠] [7♥ 4♥]
Result (Hi): Player 2 wins with Two Pair, Sevens over Fours, kicker Five
Result (Lo): Player 2 wins with Seven, Five, Four, Three, Two-low
------ StudHiLo 2 ------
Player 1: [3♠ 3♦ T♠ Q♠ T♥ 9♠ K♥]
  Hi: Two Pair, Tens over Threes, kicker King [T♥ T♠ 3♦ 3♠ K♥] [Q♠ 9♠]
  Lo: None [] []
Player 2: [6♦ Q♣ 8♥ 6♣ 3♥ T♣ 7♥]
  Hi: Pair, Sixes, kickers Queen, Ten, Eight [6♣ 6♦ Q♣ T♣ 8♥] [7♥ 3♥]
  Lo: None [] []
Player 3: [Q♦ K♠ 8♣ A♥ 7♣ 9♣ 2♣]
  Hi: Ace-high, kickers King, Queen, Nine, Eight [A♥ K♠ Q♦ 9♣ 8♣] [7♣ 2♣]
  Lo: None [] []
Player 4: [K♦ T♦ 8♦ 4♥ 3♣ J♠ 2♦]
  Hi: King-high, kickers Jack, Ten, Eight, Four [K♦ J♠ T♦ 8♦ 4♥] [3♣ 2♦]
  Lo: None [] []
Player 5: [J♦ 2♥ Q♥ 6♠ 5♦ 7♠ A♦]
  Hi: Ace-high, kickers Queen, Jack, Seven, Six [A♦ Q♥ J♦ 7♠ 6♠] [5♦ 2♥]
  Lo: Seven, Six, Five, Two, Ace-low [7♠ 6♠ 5♦ 2♥ A♦] [Q♥ J♦]
Result (Hi): Player 1 wins with Two Pair, Tens over Threes, kicker King
Result (Lo): Player 5 wins with Seven, Six, Five, Two, Ace-low
------ StudHiLo 3 ------
Player 1: [K♠ Q♠ 4♣ J♦ 7♥ 7♣ J♥]
  Hi: Two Pair, Jacks over Sevens, kicker King [J♦ J♥ 7♣ 7♥ K♠] [Q♠ 4♣]
  Lo: None [] []
Player 2: [J♠ 3♣ 8♥ 2♠ J♣ Q♣ 7♦]
  Hi: Pair, Jacks, kickers Queen, Eight, Seven [J♣ J♠ Q♣ 8♥ 7♦] [3♣ 2♠]
  Lo: None [] []
Player 3: [3♠ T♠ 2♣ Q♦ T♥ K♥ 3♦]
  Hi: Two Pair, Tens over Threes, kicker King [T♥ T♠ 3♦ 3♠ K♥] [Q♦ 2♣]
  Lo: None [] []
Player 4: [5♣ 5♥ T♦ 2♦ 4♥ 9♦ 2♥]
  Hi: Two Pair, Fives over Twos, kicker Ten [5♣ 5♥ 2♦ 2♥ T♦] [9♦ 4♥]
  Lo: None [] []
Player 5: [7♠ 3♥ 6♠ A♣ 8♠ 6♦ A♦]
  Hi: Two Pair, Aces over Sixes, kicker Eight [A♣ A♦ 6♦ 6♠ 8♠] [7♠ 3♥]
  Lo: Eight, Seven, Six, Three, Ace-low [8♠ 7♠ 6♠ 3♥ A♣] [A♦ 6♦]
Player 6: [4♠ 8♦ K♦ T♣ K♣ 5♠ 9♣]
  Hi: Pair, Kings, kickers Ten, Nine, Eight [K♣ K♦ T♣ 9♣ 8♦] [5♠ 4♠]
  Lo: None [] []
Result (Hi): Player 5 wins with Two Pair, Aces over Sixes, kicker Eight
Result (Lo): Player 5 wins with Eight, Seven, Six, Three, Ace-low
------ StudHiLo 4 ------
Player 1: [6♠ K♥ A♣ 8♣ 2♠ 5♦ A♥]
  Hi: Pair, Aces, kickers King, Eight, Six [A♣ A♥ K♥ 8♣ 6♠] [5♦ 2♠]
  Lo: Eight, Six, Five, Two, Ace-low [8♣ 6♠ 5♦ 2♠ A♣] [A♥ K♥]
Player 2: [Q♥ 4♥ J♣ 5♥ 2♦ 7♣ 3♠]
  Hi: Queen-high, kickers Jack, Seven, Five, Four [Q♥ J♣ 7♣ 5♥ 4♥] [3♠ 2♦]
  Lo: Seven, Five, Four, Three, Two-low [7♣ 5♥ 4♥ 3♠ 2♦] [Q♥ J♣]
Player 3: [2♣ 6♥ 5♣ Q♠ 6♦ 9♥ 3♣]
  Hi: Pair, Sixes, kickers Queen, Nine, Five [6♦ 6♥ Q♠ 9♥ 5♣] [3♣ 2♣]
  Lo: None [] []
Player 4: [9♠ J♥ K♠ J♠ 6♣ K♦ T♠]
  Hi: Two Pair, Kings over Jacks, kicker Ten [K♦ K♠ J♥ J♠ T♠] [9♠ 6♣]
  Lo: None [] []
Player 5: [3♦ 4♦ K♣ 8♦ 8♥ 9♣ T♥]
  Hi: Pair, Eights, kickers King, Ten, Nine [8♦ 8♥ K♣ T♥ 9♣] [4♦ 3♦]
  Lo: None [] []
Player 6: [T♣ Q♦ A♠ 7♥ Q♣ 7♦ 2♥]
  Hi: Two Pair, Queens over Sevens, kicker Ace [Q♣ Q♦ 7♦ 7♥ A♠] [T♣ 2♥]
  Lo: None [] []
Result (Hi): Player 4 wins with Two Pair, Kings over Jacks, kicker Ten
Result (Lo): Player 2 wins with Seven, Five, Four, Three, Two-low
------ StudHiLo 5 ------
Player 1: [3♦ 4♦ 5♦ J♣ 4♥ K♥ 8♣]
  Hi: Pair, Fours, kickers King, Jack, Eight [4♦ 4♥ K♥ J♣ 8♣] [5♦ 3♦]
  Lo: None [] []
Player 2: [T♥ J♠ K♠ 2♣ 4♣ 5♠ 2♦]
  Hi: Pair, Twos, kickers King, Jack, Ten [2♣ 2♦ K♠ J♠ T♥] [5♠ 4♣]
  Lo: None [] []
Player 3: [A♣ 9♠ T♠ 3♠ K♣ 8♦ A♥]
  Hi: Pair, Aces, kickers King, Ten, Nine [A♣ A♥ K♣ T♠ 9♠] [8♦ 3♠]
  Lo: None [] []
Player 4: [7♦ 3♣ 8♠ 7♣ 6♦ 6♥ 6♣]
  Hi: Full House, Sixes full of Sevens [6♣ 6♦ 6♥ 7♣ 7♦] [8♠ 3♣]
  Lo: None [] []
Player 5: [5♣ Q♠ J♥ 2♠ A♠ 8♥ 4♠]
  Hi: Ace-high, kickers Queen, Jack, Eight, Five [A♠ Q♠ J♥ 8♥ 5♣] [4♠ 2♠]
  Lo: Eight, Five, Four, Two, Ace-low [8♥ 5♣ 4♠ 2♠ A♠] [Q♠ J♥]
Player 6: [6♠ 7♠ 7♥ 2♥ 9♦ K♦ T♦]
  Hi: Pair, Sevens, kickers King, Ten, Nine [7♥ 7♠ K♦ T♦ 9♦] [6♠ 2♥]
  Lo: None [] []
Result (Hi): Player 4 wins with Full House, Sixes full of Sevens
Result (Lo): Player 5 wins with Eight, Five, Four, Two, Ace-low
const (
	Holdem         Type = 'H'<<8 | 'h' // Hh
	Split          Type = 'H'<<8 | 'l' // Hl
	Short          Type = 'H'<<8 | 's' // Hs
	Manila         Type = 'H'<<8 | 'm' // Hm
	Spanish        Type = 'H'<<8 | 'p' // Hp
	Royal          Type = 'H'<<8 | 'r' // Hr
	Double         Type = 'H'<<8 | 'd' // Hd
	Showtime       Type = 'H'<<8 | 't' // Ht
	Swap           Type = 'H'<<8 | 'w' // Hw
	River          Type = 'H'<<8 | 'v' // Hv
	Dallas         Type = 'H'<<8 | 'a' // Ha
	Houston        Type = 'H'<<8 | 'u' // Hu
	Draw           Type = 'D'<<8 | 'h' // Dh
	DrawHiLo       Type = 'D'<<8 | 'l' // Dl
	Stud           Type = 'S'<<8 | 'h' // Sh
	StudHiLo       Type = 'S'<<8 | 'l' // Sl
	StudFive       Type = 'S'<<8 | '5' // S5
	Video          Type = 'J'<<8 | 'h' // Jh
	Omaha          Type = 'O'<<8 | '4' // O4
	OmahaHiLo      Type = 'O'<<8 | 'l' // Ol
	OmahaDouble    Type = 'O'<<8 | 'd' // Od
	OmahaFive      Type = 'O'<<8 | '5' // O5
	OmahaSix       Type = 'O'<<8 | '6' // O6
	Courchevel     Type = 'O'<<8 | 'c' // Oc
	CourchevelHiLo Type = 'O'<<8 | 'e' // Oe
	Fusion         Type = 'O'<<8 | 'f' // Of
	FusionHiLo     Type = 'O'<<8 | 'F' // OF
	Soko           Type = 'K'<<8 | 'h' // Kh
	SokoHiLo       Type = 'K'<<8 | 'l' // Kl
	Lowball        Type = 'L'<<8 | '1' // L1
	LowballTriple  Type = 'L'<<8 | '3' // L3
	Razz           Type = 'R'<<8 | 'a' // Ra
	Badugi         Type = 'B'<<8 | 'a' // Ba
	Kuhn           Type = 'K'<<8 | 'u' // Ku
	Leduc          Type = 'L'<<8 | 'e' // Le
	RhodeIsland    Type = 'R'<<8 | 'I' // RI
)

Types.

func IdToType added in v0.9.0

func IdToType(id string) (Type, error)

IdToType converts id to a type.

func Types added in v0.8.0

func Types() []Type

Types returns registered types.

func (Type) Blinds added in v0.8.0

func (typ Type) Blinds() []string

Blinds returns the type's blind names.

func (Type) Board added in v0.9.0

func (typ Type) Board() int

Board returns the type's total dealt board cards.

func (Type) BoardDiscard added in v0.9.0

func (typ Type) BoardDiscard() int

BoardDiscard returns the type's total board discard.

func (Type) Cactus added in v0.11.1

func (typ Type) Cactus() bool

Cactus returns true when the type's eval is a Cactus eval.

func (Type) Deal

func (typ Type) Deal(shuffler Shuffler, shuffles, count int) ([][]Card, []Card)

Deal creates a new dealer for the type, shuffling the deck by shuffles, returning the specified pocket count and Hi board.

func (Type) Dealer added in v0.8.0

func (typ Type) Dealer(shuffler Shuffler, shuffles, count int) *Dealer

Dealer creates a new dealer with a deck shuffled by shuffles, with specified pocket count.

func (Type) Deck

func (typ Type) Deck() *Deck

Deck returns a new deck for the type.

func (Type) DeckType added in v0.9.0

func (typ Type) DeckType() DeckType

DeckType returns the type's deck type.

func (Type) Desc added in v0.8.0

func (typ Type) Desc() TypeDesc

Desc returns the type description.

func (Type) Double added in v0.8.0

func (typ Type) Double() bool

Double returns true when the type has double boards.

func (Type) Draw added in v0.11.0

func (typ Type) Draw() bool

Draw returns true when one or more streets allows draws.

func (Type) Eval added in v0.8.0

func (typ Type) Eval(pocket, board []Card) *Eval

Eval creates a new eval for the type, evaluating the pocket and board.

func (Type) EvalPockets added in v0.10.0

func (typ Type) EvalPockets(pockets [][]Card, board []Card) []*Eval

EvalPockets creates new evals for the type, evaluating each of the pockets and board.

func (Type) ExpValue added in v0.13.1

func (typ Type) ExpValue(ctx context.Context, pocket []Card, opts ...CalcOption) (*ExpValue, bool)

ExpValue calculates expected value for a single pocket. Use WithBoard to pass a board.

func (Type) Format added in v0.8.0

func (typ Type) Format(f fmt.State, verb rune)

Format satisfies the fmt.Formatter interface.

func (Type) Id added in v0.9.0

func (typ Type) Id() string

Id returns the type's id.

func (Type) Low

func (typ Type) Low() bool

Low returns true when the type supports 8-or-better lo eval.

func (Type) MarshalText

func (typ Type) MarshalText() ([]byte, error)

MarshalText satisfies the encoding.TextMarshaler interface.

func (Type) Max added in v0.8.0

func (typ Type) Max() int

Max returns the type's max players.

func (Type) Name added in v0.8.0

func (typ Type) Name() string

Name returns the type name.

func (Type) Odds added in v0.13.1

func (typ Type) Odds(ctx context.Context, pockets [][]Card, board []Card, opts ...CalcOption) (*Odds, *Odds, bool)

Odds calculates the odds for the pockets, board.

func (Type) Once added in v0.9.0

func (typ Type) Once() bool

Once returns true when draws are limited to one time.

func (Type) Pocket added in v0.9.0

func (typ Type) Pocket() int

Pocket returns the type's total dealt pocket cards.

func (Type) PocketDiscard added in v0.9.0

func (typ Type) PocketDiscard() int

PocketDiscard returns the type's total pocket discard.

func (Type) Show added in v0.8.0

func (typ Type) Show() bool

Show returns true when the type shows folded cards.

func (Type) Streets added in v0.9.0

func (typ Type) Streets() []StreetDesc

Streets returns the type's street descriptions.

func (*Type) UnmarshalText

func (typ *Type) UnmarshalText(buf []byte) error

UnmarshalText satisfies the encoding.TextUnmarshaler interface.

type TypeDesc added in v0.8.0

type TypeDesc struct {
	// Num is the registered number.
	Num int
	// Type is the type.
	Type Type
	// Name is the type name.
	Name string
	// Max is the max number of players.
	Max int
	// Low is true when the enabling the Hi/Lo variant, with an 8-or-better
	// evaluated Lo.
	Low bool
	// Double is true when there are double community boards where the first
	// and second board is evaluated as the Hi and Lo, respectively.
	Double bool
	// Show is true when folded cards are shown.
	Show bool
	// Once is true when a draw can only occur once.
	Once bool
	// Blinds are the blind names.
	Blinds []string
	// Streets are the betting streets.
	Streets []StreetDesc
	// Deck is the deck type.
	Deck DeckType
	// Eval is the eval type.
	Eval EvalType
	// HiDesc is the Hi description type.
	HiDesc DescType
	// LoDesc is the Lo description type.
	LoDesc DescType
	// contains filtered or unexported fields
}

TypeDesc is a type description.

func DefaultTypes added in v0.9.0

func DefaultTypes() []TypeDesc

DefaultTypes returns the default type descriptions. The returned TypeDesc's will be automatically registered, unless using the noinit tag.

func NewType added in v0.10.0

func NewType(id string, typ Type, name string, opts ...TypeOption) (*TypeDesc, error)

NewType creates a new type description. Created type descriptions must be registered with RegisterType before being used for eval.

func (*TypeDesc) Apply added in v0.8.0

func (desc *TypeDesc) Apply(opts ...StreetOption)

Apply applies street options.

type TypeOption added in v0.8.0

type TypeOption func(*TypeDesc)

TypeOption is a type description option.

func WithBadugi added in v0.8.0

func WithBadugi(opts ...StreetOption) TypeOption

WithBadugi is a type description option to set Badugi definitions.

func WithCourchevel added in v0.8.0

func WithCourchevel(low bool, opts ...StreetOption) TypeOption

WithCourchevel is a type description option to set Courchevel definitions.

func WithDallas added in v0.10.0

func WithDallas(low bool, opts ...StreetOption) TypeOption

WithDallas is a type description option to set Dallas definitions.

func WithDouble added in v0.8.0

func WithDouble(opts ...StreetOption) TypeOption

WithDouble is a type description option to set Double definitions.

func WithDraw added in v0.10.0

func WithDraw(low bool, opts ...StreetOption) TypeOption

WithDraw is a type description option to set Draw definitions.

func WithFusion added in v0.8.0

func WithFusion(low bool, opts ...StreetOption) TypeOption

WithFusion is a type description option to set Fusion definitions.

func WithHoldem added in v0.8.0

func WithHoldem(low bool, opts ...StreetOption) TypeOption

WithHoldem is a type description option to set Holdem definitions.

func WithHouston added in v0.10.0

func WithHouston(low bool, opts ...StreetOption) TypeOption

WithHouston is a type description option to set Houston definitions.

func WithKuhn added in v0.14.7

func WithKuhn(opts ...StreetOption) TypeOption

WithKuhn is a type description option to set Kuhn definitions.

func WithLeduc added in v0.14.7

func WithLeduc(opts ...StreetOption) TypeOption

WithLeduc is a type description option to set Leduc definitions.

func WithLowball added in v0.9.0

func WithLowball(multi bool, opts ...StreetOption) TypeOption

WithLowball is a type description option to set Lowball definitions.

func WithManila added in v0.9.0

func WithManila(opts ...StreetOption) TypeOption

WithManila is a type description option to set Manila definitions.

func WithOmaha added in v0.8.0

func WithOmaha(low bool, opts ...StreetOption) TypeOption

WithOmaha is a type description option to set Omaha definitions.

func WithOmahaDouble added in v0.8.0

func WithOmahaDouble(opts ...StreetOption) TypeOption

WithOmahaDouble is a type description option to set OmahaDouble definitions.

func WithOmahaFive added in v0.8.0

func WithOmahaFive(low bool, opts ...StreetOption) TypeOption

WithOmahaFive is a type description option to set OmahaFive definitions.

func WithOmahaSix added in v0.8.0

func WithOmahaSix(low bool, opts ...StreetOption) TypeOption

WithOmahaSix is a type description option to set OmahaSix definitions.

func WithRazz added in v0.8.0

func WithRazz(opts ...StreetOption) TypeOption

WithRazz is a type description option to set Razz definitions.

func WithRhodeIsland added in v0.14.7

func WithRhodeIsland(opts ...StreetOption) TypeOption

WithRhodeIsland is a type description option to set RhodeIsland definitions.

func WithRiver added in v0.10.0

func WithRiver(low bool, opts ...StreetOption) TypeOption

WithRiver is a type description option to set River definitions.

func WithRoyal added in v0.8.0

func WithRoyal(opts ...StreetOption) TypeOption

WithRoyal is a type description option to set Royal definitions.

func WithShort added in v0.8.0

func WithShort(opts ...StreetOption) TypeOption

WithShort is a type description option to set Short definitions.

func WithShowtime added in v0.8.0

func WithShowtime(low bool, opts ...StreetOption) TypeOption

WithShowtime is a type description option to set Showtime definitions.

func WithSoko added in v0.9.0

func WithSoko(low bool, opts ...StreetOption) TypeOption

WithSoko is a type description option to set Soko definitions.

func WithSpanish added in v0.10.0

func WithSpanish(opts ...StreetOption) TypeOption

WithSpanish is a type description option to set Spanish definitions.

func WithStud added in v0.8.0

func WithStud(low bool, opts ...StreetOption) TypeOption

WithStud is a type description option to set Stud definitions.

func WithStudFive added in v0.10.0

func WithStudFive(low bool, opts ...StreetOption) TypeOption

WithStudFive is a type description option to set StudFive definitions.

func WithSwap added in v0.9.0

func WithSwap(low bool, opts ...StreetOption) TypeOption

WithSwap is a type description option to set Swap definitions.

func WithVideo added in v0.10.0

func WithVideo(low bool, opts ...StreetOption) TypeOption

WithVideo is a type description option to set Video definitions.

type Win added in v0.8.0

type Win struct {
	Evals []*Eval
	Order []int
	Pivot int
	Low   bool
	Scoop bool
	Names []string
}

Win formats win information.

func NewWin added in v0.8.0

func NewWin(evs []*Eval, order []int, pivot int, low, scoop bool, names []string) *Win

NewWin creates a new win.

func (*Win) Desc added in v0.10.0

func (win *Win) Desc() []*EvalDesc

Desc returns the eval descriptions.

func (*Win) Format added in v0.8.0

func (win *Win) Format(f fmt.State, verb rune)

Format satisfies the fmt.Formatter interface.

func (*Win) Invalid added in v0.10.0

func (win *Win) Invalid() bool

Invalid returns true when there are no valid winners.

func (*Win) Verb added in v0.8.0

func (win *Win) Verb() string

Verb returns the win verb.

Directories

Path Synopsis
_example
Package paycalc contains a tournament payout tables.
Package paycalc contains a tournament payout tables.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL