# December 16: Possible hands and holds in a Ruby poker machine ♠♥♦♣

I’m not a gambling man — I work too hard for my money to give it away — but I *am *an avid poker player. I love poker because *it’s a game of skill disguised as a game of chance*. The engine of poker, its beating heart, is a complex and nuanced probability puzzle. The world’s top poker players aren’t unusually lucky or rich or obsessed with winning big money — they‘re just skilled at calculating lots of odds and analyzing large probability universes, and doing so quickly, accurately, under pressure, and while distracted or multitasking. (It should come as no surprise that many high-rolling regulars of the professional poker circuit, like Haseeb Qureshi and Paul Philips, are software engineers.)

# Background/history and domain model

Motivated by my love of poker, I’ve decided to write a poker machine in Ruby using the skills I’m acquiring during my time at Flatiron. It’s inspired by the world’s first electronic poker machine, the IGT 701*, *which was introduced in 1982 and employed a 6502 processor just like contemporary arcade games and home video game systems like the NES and Game Boy. (Mechanical poker machines, most of which use spinning wheels just like old-fashioned slot machines, are even older, dating to the inter-war period.) The IGT 701 simulates Jacks or Better five-card draw, also known as *California draw,* and even today most Vegas/Atlantic City video poker machines are based on this five-card variety of poker. It’s called *Jacks or Better *because the lowest-scoring hand is a pair of Jacks; pairs of non-face cards have no score or value.

In my Ruby poker machine, hands are represented by arrays of cards, to wit: `[ card, card, card, card, card ]`

# Generating possible hands

Ruby is excellent (though a bit slow) for permutations and combinations, and this makes generating hand possibilities a breeze. In another language like Java, getting all `possible_hands`

from a 52-card deck would take dozens of lines of code and possibly a helper method for recursion. But in Ruby it’s as simple as invoking:

`deck.combination( hand_size ).to_a`

Note the `to_a`

method at the end: that’s because `.combination`

returns an `Enumerator`

instance, not an array.

Draw poker is so named because cards can be discarded and *drawn* from the deck in the hopes of improving one’s hand, typically after a round of betting. The cards that aren’t discarded are referred to as *hold cards. *So, how do we generate all possible hands for a given set of hold cards? Ruby’s powerful and flexible enumerable methods make it easy:

`def possible_hands( deck, hand_size, hold_cards = [] )`

hold_cards.each{ | hold_card | deck.delete( hold_card ) }

deck.combination( hand_size - hold_cards.length ).to_a.map{ | hand | hand.concat( hold_cards ) }

end

What’s going on here? First, in line 1, we’re removing our chosen hold cards from the deck using `.each`

and `.delete`

. Then, in the first half of line 2, we call `.combination.to_a`

with an argument of `hand_size — hold_cards.length`

, to generate smaller combinations without our hold cards using the deck we stripped in line 1. Finally, we finish the job by `.map`

ping our hold cards onto each `.combination`

we generated from the stripped deck, using the `.concat`

method.

What’s especially wonderful about this method is that it works even without any hold cards! In that case, Ruby will just skip line 1 and the second half of line 2 and call `.combination( hand_size )`

on the full, unstripped deck. Neato!

# Generating possible holds

A particular configuration of hold cards for a hand is called a *hold. *Suppose we represent a hold as another array of cards; for example, for a hand `[ card_one, card_two, card_three, card_four, card_five ]`

, `[ card_four, card_five ]`

would mean holding the last two cards and discarding the rest.

Generating `possible_holds`

in this model is a bit more complicated than generating `possible_hands`

, but it can be done in a relatively straightforward manner (on one line) by `.map`

ping our `.combination`

s:

`def possible_holds( hand, number_of_hold_cards )`

hand.size.times.to_a.combination( number_of_hold_cards ).to_a.map{ | hold | hold.map{ | index | hand[ index ] } }

end

First, we turn the number of cards in our hand to an array of each card’s index, using `.size.times.to_a`

. Next we call `.combination.to_a`

using `number_of_hold_cards`

as an argument, giving us an array of possible card indices. Then finally, for each `.combination`

, we `.map`

the indices to actual cards in our `hand`

!

# Generating possible holds: a more naïve solution using binary numbers and .to_s( 2 )

Another way to represent a hold is with an array of boolean values; for example, when `hand_size.eq?( 5 )`

, then `[ true, true, false, false, false ]`

would mean holding the first two cards and discarding the rest.

What if I want to write a method that will give me an array of all `possible_holds`

(an array of arrays) for a given `hand_size`

? Unfortunately, neither `.permutation`

nor `.combination`

is what I need for a method to produce possible holds… but there *is* a clever solution!

High school math (which I’m terrible at, by the way) tells me that when determining possible combinations of size `n`

from two possible values, the size of the universe of all possible combinations will be two to the power of `n`

- meaning there are 32 possible holds for a five-card poker hand. This gets really interesting when we make use of the `Integer.to_s( 2 )`

method, which takes a base-10 integer (the kind we’re all familiar with from high school math) and converts it to that integer’s binary (base 2) representation as a string. For example:

`24.to_s( 2 ) # => "11000" `

That looks an awful lot like how we want to represent a hold, doesn’t it? In fact, we *can* represent each number in the range `0...2 ** hand_size`

as a binary string using `.to_s( 2 )`

and, with some clever `.map`

ping, use this to scrape out boolean holds:

`def possible_holds( hand_size )`

( 2 ** hand_size ).times.map{ | each_hold | each_hold.to_s( 2 ).rjust( hand_size, '0' ).chars.map { | character | character == '1' } }

end

This looks like gobbledygook — what’s happening here? Let’s break it down line by line:

- We
`.map`

over each possible hold by number—`0`

to`2 ** hand_size`

; - We turn
`each_hold`

into a string of zeroes and ones using`.rjust`

, which we use because`.to_s( 2 )`

does not give us leading zeroes: if we create a binary string without leading zeroes, we’ll get a bunch of`nil`

values; - For
`each_hold`

string in the range`0...2 ** hand_size`

, we nest another`.map`

inside our first`.map`

over each`character`

using a conditional to turn`'1’`

into`true`

and anything else into`false`

!

Unfortunately, this hold configuration is terribly inefficient because it essentially casts a boolean to another boolean. It’s really just a holdover from when I first wrote a poker hand odds calculator in Java, which lacks Ruby’s powerful native enumerables and thus favors logic like this. So it should be treated as a thought experiment only.

# Conclusion: the bigger picture

The power and flexibility of Ruby’s `.combination`

and `.permutation`

methods, combined with Ruby’s enumerables, will enable me to create a robust and flexible video poker machine. For example, I can now generate all `possible_hands`

for a given set of hold cards, then find the hand with the `.max`

score; in other words, the hold with the highest possible chance of winning my bet. I can also create an array of `possible_holds`

and then an array of `possible_hands`

for each possible hold — enabling me to enumerate through all `possible_holds`

to determine which hold for a given hand is the smartest move.

These methods and the logic behind them also have powerful uses for domains beyond video poker. Imagine a chess bot that can analyze a chess board and generate `possible_moves`

, using it to determine the best move (this is, in fact, exactly the idea behind many basic chess engines). Or even imagine a program that examines a representation of a protein with a `possible_protein_folds`

method, and analyzes each individual fold to find new lifesaving drugs. Using `.combination`

and `.permutation`

in clever, out-of-the-box ways yields but a clue to the power of combinatorics with Ruby!