Search code examples
rubyarraysalgorithmpoker

Determining a poker hand with two arrays


I want to create a simple multiplayer poker program in ruby, but I feel like I'm reinventing the wheel:

table = [card1, card2, card3, card4, card5]
mike = [card6, card7]
john = [card8, card9]

card6.face = "A"
card6.suit = "spades"

I'm having a hard time writing an algorithm to decide which of the possible hands each player has.

For example, in order to determine if a player was dealt a flush I wrote something like this:

  together = table + hand

  # Populate hash with number of times each suit was found
  $suits.each do |suit|
    matched[suit] = together.select{|card| card.suit == suit}.size
  end
  matched.each do |k,v|
    if v == 5
      puts "#{k} were seen five times, looks like a flush."
    end
  end

This doesn't seem very comprehensive (No way to tell if it's an Ace-high or a 6-high flush) nor very ruby-like.

Is there a more obvious way to determine hands in poker?


Solution

  • It's probably far from perfect, but I wrote some methods to detect poker hands to solve a project euler problem. Maybe it can give you some ideas ; full code is here: https://github.com/aherve/Euler/blob/master/pb54.rb

    In a nutshell, Hand is defined by an array of Card, that respond to Card.value and Card.type:

      def royal_flush?
        return @cards if straight_flush? and @cards.map(&:value).max == Poker::values.max
      end
    
      def straight_flush?
        return @cards if straight? and @cards.map(&:type).uniq.size == 1
      end
    
      def four_of_a_kind?
        x_of_a_kind?(4)
      end
    
      def full_house?
        return @hand if three_of_a_kind? and Hand.new(@cards - three_of_a_kind?).one_pair?
        return nil
      end
    
      def flush?
        return @cards if @cards.map(&:type).uniq.size == 1
      end
    
      def straight?
        return @cards if (vs = @cards.map(&:value).sort) == (vs.min..vs.max).to_a
      end
    
      def three_of_a_kind?
        x_of_a_kind?(3)
      end
    
      def two_pairs?
        if (first_pair = one_pair?) and (second = Hand.new(@cards - one_pair?).one_pair?)
          return first_pair + second
        else
          return false
        end
      end
    
      def one_pair?
        x_of_a_kind?(2)
      end
    
      def high_card?
        @cards.sort_by{|c| c.value}.last
      end
    
      private
      def x_of_a_kind?(x)
        Poker::values.each do |v|
          if (ary = @cards.select{|c| c.value == v}).size == x
            return ary
          end
        end
        return false
      end
    end