Ruby: possible Poker holds for a hand of length n Hello everyone and thanks in advance for taking the time to read my post!!
In the process of learning Ruby, I'm writing a video poker machine that analyzes hands represented by arrays of Cards, like so: [ card, card, card, card, card ]
You may know that in draw poker, one can hold certain cards and toss the rest to the dealer, to be replaced by drawing new cards from the deck in the hopes of improving one's hand (hence the name). It's natural to figure that holds would be represented by an array of boolean values. To wit: [ true, true, false, false, false ] would mean holding the first two cards in a five-card hand and discarding the rest. What I'm trying to write is a method that will give me an array of all possible holds (an array of arrays) for a given hand size.
I've found that Ruby is terrific (though a bit slow) for permutations and combinations, i.e., all possible unique hands from a 52-card deck. All I have to do for that is call deck.combination( hand_size ).to_a. But unfortunately neither .permutation nor .combination is really giving me what I need for a method to produce possible holds.
High school math (which I'm terrible at, by the way) tells me that when determining possible unique n-combinations of two possible values, the size of the universe of all possible n-combinations will be two to the power of n - meaning there are 32 possible holds for a five-card poker hand.
After slaughtering a snow-white bull for the gods at midnight under a full moon, I've come up with the following solution using binary numbers. This method loops through a range from 0...2 ** hand_size, turns each element of the range into a binary number string with a hand_size number of leading zeroes using .rjust, then .maps each character in the string to an array of hand_size elements using a conditional and ternary; if the character is &quot;1&quot; it maps a true to the array, otherwise the character is a &quot;0&quot; and it maps false to the array.
def possible_holds( hand_size )
   result = []
   for each_hold in 0...2 ** hand_size do
      as_binary = each_hold.to_s( 2 ).rjust( hand_size, &quot;0&quot; )
      result &lt;&lt; ( 0...hand_size ).to_a.map{ | card | as_binary[ card ] == &quot;1&quot; ? true : false }
   end
   result
end

This clunky little method actually works very well, but... it just doesn't seem very rubinic. I would love to hear clever suggestions as to how to improve it. I have this nagging feeling that this can all be done with a neat, simple method/enumerable or two... but no matter how many virgins I sacrifice I just can't seem to come up with anything better.
Thanks in advance for your help and happy coding!!
Here's a demonstration of how you might solve this problem the Ruby way:
SUITS = %w[ H D C S ]
FACES = %w[ 2 3 4 5 6 7 8 9 T J Q K A ]

CARDS = SUITS.flat_map { |s| FACES.map { |f| &quot;#{f}#{s}&quot; } }

def holds(hand)
  hand.length.times.flat_map do |n|
    hand.combination(n).to_a
  end &lt;&lt; hand
end

holds(CARDS.shuffle.take(5))

Where you get results like this:
[[],
 [&quot;AD&quot;],
 [&quot;5H&quot;],
 [&quot;QS&quot;],
 [&quot;4H&quot;],
 [&quot;5D&quot;],
 [&quot;AD&quot;, &quot;5H&quot;],
 [&quot;AD&quot;, &quot;QS&quot;],
 [&quot;AD&quot;, &quot;4H&quot;],
 [&quot;AD&quot;, &quot;5D&quot;],
 [&quot;5H&quot;, &quot;QS&quot;],
 [&quot;5H&quot;, &quot;4H&quot;],
 [&quot;5H&quot;, &quot;5D&quot;],
 [&quot;QS&quot;, &quot;4H&quot;],
 [&quot;QS&quot;, &quot;5D&quot;],
 [&quot;4H&quot;, &quot;5D&quot;],
 [&quot;AD&quot;, &quot;5H&quot;, &quot;QS&quot;],
 [&quot;AD&quot;, &quot;5H&quot;, &quot;4H&quot;],
 [&quot;AD&quot;, &quot;5H&quot;, &quot;5D&quot;],
 [&quot;AD&quot;, &quot;QS&quot;, &quot;4H&quot;],
 [&quot;AD&quot;, &quot;QS&quot;, &quot;5D&quot;],
 [&quot;AD&quot;, &quot;4H&quot;, &quot;5D&quot;],
 [&quot;5H&quot;, &quot;QS&quot;, &quot;4H&quot;],
 [&quot;5H&quot;, &quot;QS&quot;, &quot;5D&quot;],
 [&quot;5H&quot;, &quot;4H&quot;, &quot;5D&quot;],
 [&quot;QS&quot;, &quot;4H&quot;, &quot;5D&quot;],
 [&quot;AD&quot;, &quot;5H&quot;, &quot;QS&quot;, &quot;4H&quot;],
 [&quot;AD&quot;, &quot;5H&quot;, &quot;QS&quot;, &quot;5D&quot;],
 [&quot;AD&quot;, &quot;5H&quot;, &quot;4H&quot;, &quot;5D&quot;],
 [&quot;AD&quot;, &quot;QS&quot;, &quot;4H&quot;, &quot;5D&quot;],
 [&quot;5H&quot;, &quot;QS&quot;, &quot;4H&quot;, &quot;5D&quot;],
 [&quot;AD&quot;, &quot;5H&quot;, &quot;QS&quot;, &quot;4H&quot;, &quot;5D&quot;]]

Personally I'd hold the pair of 5s and the Ace.
For educational purposes here's a more Ruby-esque form of your original code:
def possible_holds(hand_size)
  (2 ** hand_size).times.map do |n|
    n.to_s(2).rjust(hand_size, '0').chars.map { |c| c == '1' }
  end
end

It's kind of messy due to the binary string to boolean conversion.

Tip: Try to avoid &quot;casting a boolean to a boolean&quot; as in patterns like x ? true : false or if x; true; else; false like you had in your code. That reduces down to just x. The x == '1' test already returns a true or false value. There is no maybe or kind_of response.