Ranking poker hands: Difference between revisions
m (Text replacement - " ⊢( *[^∘])" to " ⎕←$1") |
m (Text replacement - "<source" to "<syntaxhighlight") |
||
Line 1: | Line 1: | ||
This article uses [[Dyalog APL]] to rank poker hands using the rules of [[wikipedia:Texas hold 'em|Texas hold 'em]] and other popular poker variants. The function < | This article uses [[Dyalog APL]] to rank poker hands using the rules of [[wikipedia:Texas hold 'em|Texas hold 'em]] and other popular poker variants. The function <syntaxhighlight lang=apl inline>handrank</source> below transforms a representation of a poker hand into a "rank" array so that the ordering of ranks under [[total array ordering]] is the same as the ordering of the initial poker hands. Poker hands can then by sorted or compared by calling <syntaxhighlight lang=apl inline>handrank</source> on each one, then ordering with normal APL functions. | ||
== Dyalog '19 version == | == Dyalog '19 version == | ||
[[Marshall Lochbaum]] showed the following code in a presentation (D04: "Tacit Techniques with Dyalog version 18.0 Operators"; video [https://dyalog.tv/Dyalog19/?v=czWC4tjwzOQ here]) at the [https://www.dyalog.com/user-meetings/dyalog19.htm Dyalog '19] user meeting. | [[Marshall Lochbaum]] showed the following code in a presentation (D04: "Tacit Techniques with Dyalog version 18.0 Operators"; video [https://dyalog.tv/Dyalog19/?v=czWC4tjwzOQ here]) at the [https://www.dyalog.com/user-meetings/dyalog19.htm Dyalog '19] user meeting. | ||
< | <syntaxhighlight lang=apl> | ||
handrank←{⊃{((8|@1⊢2-/⍺)⍵∧.=¨1,⊃⍵){(∧/⍺),(2=≢⍵),⍺,⊂⍵[⍒⍵;]⊖⍨⊃⍺},⍨∘≢⌸⍺}/↓⍉⍵[⍒⍵;]} | handrank←{⊃{((8|@1⊢2-/⍺)⍵∧.=¨1,⊃⍵){(∧/⍺),(2=≢⍵),⍺,⊂⍵[⍒⍵;]⊖⍨⊃⍺},⍨∘≢⌸⍺}/↓⍉⍵[⍒⍵;]} | ||
cmp ← {⍺⍵-⍥(⊃⍋)⍵⍺} | cmp ← {⍺⍵-⍥(⊃⍋)⍵⍺} | ||
cmphand ← cmp ⍥ handrank | cmphand ← cmp ⍥ handrank | ||
</source> | </source> | ||
The < | The <syntaxhighlight lang=apl inline>cmphand</source> function compares two hands to yield ¯1 if the left hand is better, 1 if the right is better, and 0 if they are tied. In the talk Marshall calls it by inverting a display function (a task which Dyalog's [[Inverse]] cannot yet handle): | ||
< | <syntaxhighlight lang=apl> | ||
I ← ⌷⍤0 99 | I ← ⌷⍤0 99 | ||
disp ← I¨ ∘ ((2↓⎕D),'TJQKA')('♣♢♡♠') ⍤ 1 | disp ← I¨ ∘ ((2↓⎕D),'TJQKA')('♣♢♡♠') ⍤ 1 | ||
Line 16: | Line 16: | ||
¯1 | ¯1 | ||
</source> | </source> | ||
These functions demonstrate the usefulness of [[Over]], but the < | These functions demonstrate the usefulness of [[Over]], but the <syntaxhighlight lang=apl inline>handrank</source> function doesn't depend on any new features from Dyalog 18.0. | ||
The implementation of < | The implementation of <syntaxhighlight lang=apl inline>handrank</source> above has an error: it ranks flushes above straights. This can be fixed by [[Reverse|reversing]] in two places: | ||
< | <syntaxhighlight lang=apl> | ||
handrank←{⊃{(⌽(8|@1⊢2-/⍺)⍵∧.=¨1,⊃⍵){(∧/⍺),(2=≢⍵),⍺,⊂⍵[⍒⍵;]⊖⍨⊃⌽⍺},⍨∘≢⌸⍺}/↓⍉⍵[⍒⍵;]} | handrank←{⊃{(⌽(8|@1⊢2-/⍺)⍵∧.=¨1,⊃⍵){(∧/⍺),(2=≢⍵),⍺,⊂⍵[⍒⍵;]⊖⍨⊃⌽⍺},⍨∘≢⌸⍺}/↓⍉⍵[⍒⍵;]} | ||
</source> | </source> | ||
Line 25: | Line 25: | ||
== Displaying and parsing hands == | == Displaying and parsing hands == | ||
We will describe each card with an [[index]] for its rank (two to ace) and another index for its suit (clubs to spades). The function < | We will describe each card with an [[index]] for its rank (two to ace) and another index for its suit (clubs to spades). The function <syntaxhighlight lang=apl inline>disp</source> below displays a single card by [[Pick|picking]] the appropriate character for suit and rank. We use the character <syntaxhighlight lang=apl inline>'T'</source> for ten. | ||
< | <syntaxhighlight lang=apl> | ||
disp ← ⊃¨ ∘ ((2↓⎕D),'TJQKA')('♣♢♡♠') | disp ← ⊃¨ ∘ ((2↓⎕D),'TJQKA')('♣♢♡♠') | ||
disp 1 1 | disp 1 1 | ||
Line 33: | Line 33: | ||
1 1 | 1 1 | ||
</source> | </source> | ||
Because < | Because <syntaxhighlight lang=apl inline>disp</source> is invertible, we can also use it to read a single card, as shown in the last line above. We can parse a hand of five cards, written as a single [[string]], by [[Reshape|reshaping]] it to [[shape]] 5 2, and undisplaying each row ([[Rank operator|rank]] 1). | ||
< | <syntaxhighlight lang=apl> | ||
(disp⍣¯1⍤1) 5 2⍴'A♠2♠3♣4♠5♢' | (disp⍣¯1⍤1) 5 2⍴'A♠2♠3♣4♠5♢' | ||
13 4 | 13 4 | ||
Line 47: | Line 47: | ||
In poker ranking, the highest card in the hand is the most important. We start our ranking by placing the highest card first, that is, sorting in descending order: | In poker ranking, the highest card in the hand is the most important. We start our ranking by placing the highest card first, that is, sorting in descending order: | ||
< | <syntaxhighlight lang=apl> | ||
sort ← {(⊂⍒⍵)⌷⍵} | sort ← {(⊂⍒⍵)⌷⍵} | ||
sort hand 'A♠2♠3♣4♠5♢' | sort hand 'A♠2♠3♣4♠5♢' | ||
Line 56: | Line 56: | ||
1 4 | 1 4 | ||
</source> | </source> | ||
However, hands are sorted not just by the highest card but by how many of each rank there are. For example, two twos in a hand are more important than a single king. We take this into account by grouping equal ranks together with the [[Key]] operator. In the operand to Key, we place the number of cards of each rank (< | However, hands are sorted not just by the highest card but by how many of each rank there are. For example, two twos in a hand are more important than a single king. We take this into account by grouping equal ranks together with the [[Key]] operator. In the operand to Key, we place the number of cards of each rank (<syntaxhighlight lang=apl inline>(≢⍵)</source>) before the number of the rank (<syntaxhighlight lang=apl inline>⍺</source>). Then we sort in descending order again, to put the ranks that appear the most times first. For this part of the ranking algorithm the cards didn't need to be sorted initially, but we'll use the initial sorting above later. | ||
< | <syntaxhighlight lang=apl> | ||
⊣/ sort hand '6♡6♣6♢K♡K♠' | ⊣/ sort hand '6♡6♣6♢K♡K♠' | ||
12 12 5 5 5 | 12 12 5 5 5 | ||
Line 67: | Line 67: | ||
=== Straights and flushes === | === Straights and flushes === | ||
The small amount of code above is enough to rank any hands if we ignore the rules for straights (five ranks in a row) and flushes (all five cards of the same suit). However, poker has some complicated rules for these types of hands which we must take into account. We begin by splitting the hand into ranks < | The small amount of code above is enough to rank any hands if we ignore the rules for straights (five ranks in a row) and flushes (all five cards of the same suit). However, poker has some complicated rules for these types of hands which we must take into account. We begin by splitting the hand into ranks <syntaxhighlight lang=apl inline>r</source> and suits <syntaxhighlight lang=apl inline>s</source>: | ||
< | <syntaxhighlight lang=apl> | ||
r s ← ↓⍉sort hand 'A♠2♠3♣4♠5♢' | r s ← ↓⍉sort hand 'A♠2♠3♣4♠5♢' | ||
</source> | </source> | ||
First we compute whether the hand is a flush, a decision that depends only on the suits. If every suit is equal to the [[first]] one, then the hand is a flush. | First we compute whether the hand is a flush, a decision that depends only on the suits. If every suit is equal to the [[first]] one, then the hand is a flush. | ||
< | <syntaxhighlight lang=apl> | ||
s | s | ||
4 2 4 1 4 | 4 2 4 1 4 | ||
Line 81: | Line 81: | ||
</source> | </source> | ||
Now we determine whether the hand is a straight. We can find the difference from each card's rank to the next highest (recall that the ranks are sorted descending) using a pair-wise difference, a kind of [[windowed reduction]]. Ordinarily, a hand is a straight if each difference is exactly one. However, there is an additional complication in that an ace (the highest rank; 13 here) may come before a two in a straight—it can be treated as the lowest rank if this improves the hand. To account for this we also allow the difference between the highest and next-highest card to be 9, the difference between ace and five. If this difference is 9 and each other difference is 1, then the ranks must be ace, five, four, three, and two—a straight. To allow both 1 and 9 for the first value, we use the [[residue]] on division by 8. Residue is applied to only the first difference using the [[At]] operator. | Now we determine whether the hand is a straight. We can find the difference from each card's rank to the next highest (recall that the ranks are sorted descending) using a pair-wise difference, a kind of [[windowed reduction]]. Ordinarily, a hand is a straight if each difference is exactly one. However, there is an additional complication in that an ace (the highest rank; 13 here) may come before a two in a straight—it can be treated as the lowest rank if this improves the hand. To account for this we also allow the difference between the highest and next-highest card to be 9, the difference between ace and five. If this difference is 9 and each other difference is 1, then the ranks must be ace, five, four, three, and two—a straight. To allow both 1 and 9 for the first value, we use the [[residue]] on division by 8. Residue is applied to only the first difference using the [[At]] operator. | ||
< | <syntaxhighlight lang=apl> | ||
r | r | ||
13 4 3 2 1 | 13 4 3 2 1 | ||
Line 92: | Line 92: | ||
</source> | </source> | ||
The rank and suit combination can be combined to save characters (an important consideration when presenting with limited screen width!). Each compares two arrays using scalar [[Equals]] and combines the results with [[And]]. Rather than writing this computation twice we can merge the two sides of each computation together and use [[Each]]. | The rank and suit combination can be combined to save characters (an important consideration when presenting with limited screen width!). Each compares two arrays using scalar [[Equals]] and combines the results with [[And]]. Rather than writing this computation twice we can merge the two sides of each computation together and use [[Each]]. | ||
< | <syntaxhighlight lang=apl> | ||
(8|@1⊢2-/r)s | (8|@1⊢2-/r)s | ||
┌───────┬─────────┐ | ┌───────┬─────────┐ | ||
Line 106: | Line 106: | ||
1 0 | 1 0 | ||
</source> | </source> | ||
The choice of the [[inner product]] < | The choice of the [[inner product]] <syntaxhighlight lang=apl inline>∧.=</source> over a reduction is entirely stylistic. | ||
=== Final ranking === | === Final ranking === | ||
Taking a sample hand, let's compute the ranks and a boolean indicator for whether it's a straight and/or flush. | Taking a sample hand, let's compute the ranks and a boolean indicator for whether it's a straight and/or flush. | ||
< | <syntaxhighlight lang=apl> | ||
r s ← ↓⍉sort hand 'A♠2♠3♣4♠5♢' | r s ← ↓⍉sort hand 'A♠2♠3♣4♠5♢' | ||
⎕←ranks ← sort {(≢⍵),⍺}⌸ r | ⎕←ranks ← sort {(≢⍵),⍺}⌸ r | ||
Line 123: | Line 123: | ||
</source> | </source> | ||
The final rank is now a combination of four arrays. At the end we will compare hands based on the number of each rank involved, but first we will modify this ranking based on some features that make certain hands more valuable than others. A straight flush is the highest-ranked hand, followed by a four of a kind and a full house (three of one rank and two of another). We can quickly test whether a hand has one of the latter combinations by testing whether there are exactly two different ranks present—if so, they must be split 4-1 or 3-2. After these, flushes and then straights are ranked higher than other hands. | The final rank is now a combination of four arrays. At the end we will compare hands based on the number of each rank involved, but first we will modify this ranking based on some features that make certain hands more valuable than others. A straight flush is the highest-ranked hand, followed by a four of a kind and a full house (three of one rank and two of another). We can quickly test whether a hand has one of the latter combinations by testing whether there are exactly two different ranks present—if so, they must be split 4-1 or 3-2. After these, flushes and then straights are ranked higher than other hands. | ||
< | <syntaxhighlight lang=apl> | ||
∧/sf ⍝ Is it a straight flush? | ∧/sf ⍝ Is it a straight flush? | ||
0 | 0 | ||
Line 143: | Line 143: | ||
== Complete function == | == Complete function == | ||
< | <syntaxhighlight lang=apl> | ||
handrank ← { | handrank ← { | ||
sort ← {(⊂⍒⍵)⌷⍵} ⍝ Sort descending idiom | sort ← {(⊂⍒⍵)⌷⍵} ⍝ Sort descending idiom | ||
Line 156: | Line 156: | ||
To test our function, we can try it on the sample hands given in Wikipedia's page on Texas hold 'em [[wikipedia:Texas hold 'em#Hand_values|here]]. The ranks for each of these hands are shown, as well as a [[grade up]] to demonstrate that they are in ascending order. | To test our function, we can try it on the sample hands given in Wikipedia's page on Texas hold 'em [[wikipedia:Texas hold 'em#Hand_values|here]]. The ranks for each of these hands are shown, as well as a [[grade up]] to demonstrate that they are in ascending order. | ||
< | <syntaxhighlight lang=apl> | ||
hands ← ' '(≠⊆⊢)'A♣4♡7♢K♣2♠ K♣K♡7♢2♣5♠ K♣K♡7♢7♣5♠ K♣K♡K♢7♣5♠ 3♣4♡5♢6♣7♠ K♣Q♣9♣8♣2♣ K♣K♡K♢7♣7♠ K♣K♡K♢K♠5♠ 3♣4♣5♣6♣7♣ T♡J♡Q♡K♡A♡' | hands ← ' '(≠⊆⊢)'A♣4♡7♢K♣2♠ K♣K♡7♢2♣5♠ K♣K♡7♢7♣5♠ K♣K♡K♢7♣5♠ 3♣4♡5♢6♣7♠ K♣Q♣9♣8♣2♣ K♣K♡K♢7♣7♠ K♣K♡K♢K♠5♠ 3♣4♣5♣6♣7♣ T♡J♡Q♡K♡A♡' | ||
↑hands | ↑hands |
Revision as of 22:07, 10 September 2022
This article uses Dyalog APL to rank poker hands using the rules of Texas hold 'em and other popular poker variants. The function <syntaxhighlight lang=apl inline>handrank</source> below transforms a representation of a poker hand into a "rank" array so that the ordering of ranks under total array ordering is the same as the ordering of the initial poker hands. Poker hands can then by sorted or compared by calling <syntaxhighlight lang=apl inline>handrank</source> on each one, then ordering with normal APL functions.
Dyalog '19 version
Marshall Lochbaum showed the following code in a presentation (D04: "Tacit Techniques with Dyalog version 18.0 Operators"; video here) at the Dyalog '19 user meeting. <syntaxhighlight lang=apl> handrank←{⊃{((8|@1⊢2-/⍺)⍵∧.=¨1,⊃⍵){(∧/⍺),(2=≢⍵),⍺,⊂⍵[⍒⍵;]⊖⍨⊃⍺},⍨∘≢⌸⍺}/↓⍉⍵[⍒⍵;]} cmp ← {⍺⍵-⍥(⊃⍋)⍵⍺} cmphand ← cmp ⍥ handrank </source> The <syntaxhighlight lang=apl inline>cmphand</source> function compares two hands to yield ¯1 if the left hand is better, 1 if the right is better, and 0 if they are tied. In the talk Marshall calls it by inverting a display function (a task which Dyalog's Inverse cannot yet handle): <syntaxhighlight lang=apl>
I ← ⌷⍤0 99 disp ← I¨ ∘ ((2↓⎕D),'TJQKA')('♣♢♡♠') ⍤ 1 (5 2⍴'6♡6♣6♢K♡K♠') cmphand⍥(disp⍣¯1) (5 2⍴'A♠2♠3♣4♠5♢')
¯1 </source> These functions demonstrate the usefulness of Over, but the <syntaxhighlight lang=apl inline>handrank</source> function doesn't depend on any new features from Dyalog 18.0.
The implementation of <syntaxhighlight lang=apl inline>handrank</source> above has an error: it ranks flushes above straights. This can be fixed by reversing in two places: <syntaxhighlight lang=apl> handrank←{⊃{(⌽(8|@1⊢2-/⍺)⍵∧.=¨1,⊃⍵){(∧/⍺),(2=≢⍵),⍺,⊂⍵[⍒⍵;]⊖⍨⊃⌽⍺},⍨∘≢⌸⍺}/↓⍉⍵[⍒⍵;]} </source>
Displaying and parsing hands
We will describe each card with an index for its rank (two to ace) and another index for its suit (clubs to spades). The function <syntaxhighlight lang=apl inline>disp</source> below displays a single card by picking the appropriate character for suit and rank. We use the character <syntaxhighlight lang=apl inline>'T'</source> for ten. <syntaxhighlight lang=apl>
disp ← ⊃¨ ∘ ((2↓⎕D),'TJQKA')('♣♢♡♠') disp 1 1
2♣
disp⍣¯1 ⊢'2♣'
1 1 </source> Because <syntaxhighlight lang=apl inline>disp</source> is invertible, we can also use it to read a single card, as shown in the last line above. We can parse a hand of five cards, written as a single string, by reshaping it to shape 5 2, and undisplaying each row (rank 1). <syntaxhighlight lang=apl>
(disp⍣¯1⍤1) 5 2⍴'A♠2♠3♣4♠5♢'
13 4
1 4 2 1 3 4 4 2 hand ← {(disp⍣¯1⍤1) 5 2⍴⍵}
</source>
Hand rank
In poker ranking, the highest card in the hand is the most important. We start our ranking by placing the highest card first, that is, sorting in descending order: <syntaxhighlight lang=apl>
sort ← {(⊂⍒⍵)⌷⍵} sort hand 'A♠2♠3♣4♠5♢'
13 4
4 2 3 4 2 1 1 4
</source> However, hands are sorted not just by the highest card but by how many of each rank there are. For example, two twos in a hand are more important than a single king. We take this into account by grouping equal ranks together with the Key operator. In the operand to Key, we place the number of cards of each rank (<syntaxhighlight lang=apl inline>(≢⍵)</source>) before the number of the rank (<syntaxhighlight lang=apl inline>⍺</source>). Then we sort in descending order again, to put the ranks that appear the most times first. For this part of the ranking algorithm the cards didn't need to be sorted initially, but we'll use the initial sorting above later. <syntaxhighlight lang=apl>
⊣/ sort hand '6♡6♣6♢K♡K♠'
12 12 5 5 5
{(≢⍵),⍺}⌸ ⊣/ sort hand '6♡6♣6♢K♡K♠'
2 12 3 5 </source>
Straights and flushes
The small amount of code above is enough to rank any hands if we ignore the rules for straights (five ranks in a row) and flushes (all five cards of the same suit). However, poker has some complicated rules for these types of hands which we must take into account. We begin by splitting the hand into ranks <syntaxhighlight lang=apl inline>r</source> and suits <syntaxhighlight lang=apl inline>s</source>: <syntaxhighlight lang=apl>
r s ← ↓⍉sort hand 'A♠2♠3♣4♠5♢'
</source> First we compute whether the hand is a flush, a decision that depends only on the suits. If every suit is equal to the first one, then the hand is a flush. <syntaxhighlight lang=apl>
s
4 2 4 1 4
s=⊃s
1 0 1 0 1
∧/s=⊃s
0 </source> Now we determine whether the hand is a straight. We can find the difference from each card's rank to the next highest (recall that the ranks are sorted descending) using a pair-wise difference, a kind of windowed reduction. Ordinarily, a hand is a straight if each difference is exactly one. However, there is an additional complication in that an ace (the highest rank; 13 here) may come before a two in a straight—it can be treated as the lowest rank if this improves the hand. To account for this we also allow the difference between the highest and next-highest card to be 9, the difference between ace and five. If this difference is 9 and each other difference is 1, then the ranks must be ace, five, four, three, and two—a straight. To allow both 1 and 9 for the first value, we use the residue on division by 8. Residue is applied to only the first difference using the At operator. <syntaxhighlight lang=apl>
r
13 4 3 2 1
2-/r
9 1 1 1
8|@1⊢2-/r
1 1 1 1
1 ∧.= 8|@1⊢2-/r
1 </source> The rank and suit combination can be combined to save characters (an important consideration when presenting with limited screen width!). Each compares two arrays using scalar Equals and combines the results with And. Rather than writing this computation twice we can merge the two sides of each computation together and use Each. <syntaxhighlight lang=apl>
(8|@1⊢2-/r)s
┌───────┬─────────┐ │1 1 1 1│4 2 4 1 4│ └───────┴─────────┘
(8|@1⊢2-/r)s = 1,⊃s
┌───────┬─────────┐ │1 1 1 1│1 0 1 0 1│ └───────┴─────────┘
∧/¨(8|@1⊢2-/r)s=1,⊃s
1 0
(8|@1⊢2-/r)s∧.=¨1,⊃s
1 0 </source> The choice of the inner product <syntaxhighlight lang=apl inline>∧.=</source> over a reduction is entirely stylistic.
Final ranking
Taking a sample hand, let's compute the ranks and a boolean indicator for whether it's a straight and/or flush. <syntaxhighlight lang=apl>
r s ← ↓⍉sort hand 'A♠2♠3♣4♠5♢' ⎕←ranks ← sort {(≢⍵),⍺}⌸ r
1 13 1 4 1 3 1 2 1 1
⎕←sf ← (8|@1⊢2-/r)s∧.=¨1,⊃s
1 0 </source> The final rank is now a combination of four arrays. At the end we will compare hands based on the number of each rank involved, but first we will modify this ranking based on some features that make certain hands more valuable than others. A straight flush is the highest-ranked hand, followed by a four of a kind and a full house (three of one rank and two of another). We can quickly test whether a hand has one of the latter combinations by testing whether there are exactly two different ranks present—if so, they must be split 4-1 or 3-2. After these, flushes and then straights are ranked higher than other hands. <syntaxhighlight lang=apl>
∧/sf ⍝ Is it a straight flush?
0
2=≢ranks ⍝ Is it a four of a kind or full house?
0
⌽sf ⍝ Flushes before straights
0 1
(⊃sf)⊖ranks ⍝ Treat high card as low for straights
1 4 1 3 1 2 1 1 1 13 </source> Within each category based on the first three special values, hands are ranked by card ranks. Suits are never used for comparison: they only affect whether the hand is a straight.
To order straights correctly, we must take into account ace-low straights. In such straights five is considered the high card. We fix the ordering by rotating all straights to compare starting at the second-highest card.
Complete function
<syntaxhighlight lang=apl> handrank ← {
sort ← {(⊂⍒⍵)⌷⍵} ⍝ Sort descending idiom r s←↓⍉sort ⍵ ⍝ Rank and suit after sorting ranks ← sort {(≢⍵),⍺}⌸ r ⍝ Number of each rank sf ← (8|@1⊢2-/r)s∧.=¨1,⊃s ⍝ Is straight, is flush (∧/sf),(2=≢ranks),(⌽sf),⊂(⊃sf)⊖ranks ⍝ Final rank
} </source>
Examples
To test our function, we can try it on the sample hands given in Wikipedia's page on Texas hold 'em here. The ranks for each of these hands are shown, as well as a grade up to demonstrate that they are in ascending order. <syntaxhighlight lang=apl>
hands ← ' '(≠⊆⊢)'A♣4♡7♢K♣2♠ K♣K♡7♢2♣5♠ K♣K♡7♢7♣5♠ K♣K♡K♢7♣5♠ 3♣4♡5♢6♣7♠ K♣Q♣9♣8♣2♣ K♣K♡K♢7♣7♠ K♣K♡K♢K♠5♠ 3♣4♣5♣6♣7♣ T♡J♡Q♡K♡A♡' ↑hands
A♣4♡7♢K♣2♠ K♣K♡7♢2♣5♠ K♣K♡7♢7♣5♠ K♣K♡K♢7♣5♠ 3♣4♡5♢6♣7♠ K♣Q♣9♣8♣2♣ K♣K♡K♢7♣7♠ K♣K♡K♢K♠5♠ 3♣4♣5♣6♣7♣ T♡J♡Q♡K♡A♡
{⍵,↑handrank∘hand¨⍵} hands
┌──────────┬─┬─┬─┬─┬────┐ │A♣4♡7♢K♣2♠│0│0│0│0│1 13│ │ │ │ │ │ │1 12│ │ │ │ │ │ │1 6│ │ │ │ │ │ │1 3│ │ │ │ │ │ │1 1│ ├──────────┼─┼─┼─┼─┼────┤ │K♣K♡7♢2♣5♠│0│0│0│0│2 12│ │ │ │ │ │ │1 6│ │ │ │ │ │ │1 4│ │ │ │ │ │ │1 1│ ├──────────┼─┼─┼─┼─┼────┤ │K♣K♡7♢7♣5♠│0│0│0│0│2 12│ │ │ │ │ │ │2 6│ │ │ │ │ │ │1 4│ ├──────────┼─┼─┼─┼─┼────┤ │K♣K♡7♢7♣5♠│0│0│0│0│2 12│ │ │ │ │ │ │2 6│ │ │ │ │ │ │1 4│ ├──────────┼─┼─┼─┼─┼────┤ │K♣K♡K♢7♣5♠│0│0│0│0│3 12│ │ │ │ │ │ │1 6│ │ │ │ │ │ │1 4│ ├──────────┼─┼─┼─┼─┼────┤ │3♣4♡5♢6♣7♠│0│0│0│1│1 5 │ │ │ │ │ │ │1 4 │ │ │ │ │ │ │1 3 │ │ │ │ │ │ │1 2 │ │ │ │ │ │ │1 6 │ ├──────────┼─┼─┼─┼─┼────┤ │K♣Q♣9♣8♣2♣│0│0│1│0│1 12│ │ │ │ │ │ │1 11│ │ │ │ │ │ │1 8│ │ │ │ │ │ │1 7│ │ │ │ │ │ │1 1│ ├──────────┼─┼─┼─┼─┼────┤ │K♣K♡K♢7♣7♠│0│1│0│0│3 12│ │ │ │ │ │ │2 6│ ├──────────┼─┼─┼─┼─┼────┤ │K♣K♡K♢K♠5♠│0│1│0│0│4 12│ │ │ │ │ │ │1 4│ ├──────────┼─┼─┼─┼─┼────┤ │3♣4♣5♣6♣7♣│1│0│1│1│1 5 │ │ │ │ │ │ │1 4 │ │ │ │ │ │ │1 3 │ │ │ │ │ │ │1 2 │ │ │ │ │ │ │1 6 │ ├──────────┼─┼─┼─┼─┼────┤ │T♡J♡Q♡K♡A♡│1│0│1│1│1 12│ │ │ │ │ │ │1 11│ │ │ │ │ │ │1 10│ │ │ │ │ │ │1 9│ │ │ │ │ │ │1 13│ └──────────┴─┴─┴─┴─┴────┘
⍋ handrank∘hand¨ hands
1 2 3 4 5 6 7 8 9 10 </source>