ポーカーの役の判定

class Cards
  class Card
    attr_reader :suit, :rank
    def initialize(suit, rank)
      @suit = suit
      @rank = rank
    end
  end

  attr_reader :suits, :ranks
  def initialize(cards)
    @cards = cards.map{|e| e.kind_of?(Card) ? e : Card.new(*e)}
    @ranks = @cards.map(&:rank).sort
    @suits = @cards.map(&:suit)
  end

  def same_rank_counts
    same_ranks = ranks.group_by{|r|r}.values
    same_ranks.map(&:size).sort.reverse
  end

  def straight?
    steps = ranks.map{|r|r-ranks[0]}
    steps==[0,1,2,3,4] || steps==[0,9,10,11,12]
  end

  def flush?
    suits.uniq.size == 1
  end

  def hand
    case same_rank_counts
    when [2,1,1,1]
      :one_pair
    when [2,2,1]
      :two_pair
    when [3,1,1]
      :three_of_a_kind
    when [3,2]
      :full_house
    when [4,1]
      :four_of_a_kind
    else
      case [straight?, flush?]
      when [true, false]
        :straight
      when [false, true]
        :flush
      when [true, true]
        if ranks == [1,10,11,12,13]
          :royal_flush
        else
          :straight_flush
        end
      else
        :hi_card
      end
    end
  end
end

if __FILE__ == $0
  ranks = (1..13).to_a
  suits = [:spade,:heart,:diamond,:club]

  all_cards = suits.product(ranks)
  result = Hash.new(0)
  all_cards.combination(5).each_with_index{|a, i|
    cards = Cards.new(a)
    result[cards.hand] += 1
    p result if i%100000 == 0
  }
  
  p result
end