diff --git a/card.rb b/card.rb index dbe0c3e..c556be9 100644 --- a/card.rb +++ b/card.rb @@ -23,30 +23,22 @@ class Card end end - def to_s - rank_s + " of " + suit_s - end - def rank_s case @rank - when 2 then "two" - when 3 then "three" - when 4 then "four" - when 5 then "five" - when 6 then "six" - when 7 then "seven" - when 8 then "eight" - when 9 then "nine" - when 10 then "ten" - when 11 then "jack" - when 12 then "queen" - when 13 then "king" - when 14 then "ace" + when 2..10 then @rank.to_s + when 11 then "Jack" + when 12 then "Queen" + when 13 then "King" + when 14 then "Ace" end end def suit_s - @suit.to_s + @suit.to_s.capitalize + end + + def to_s + rank_s + "-" + suit_s end def ==(other) diff --git a/combinations.rb b/combinations.rb new file mode 100644 index 0000000..29b5f1e --- /dev/null +++ b/combinations.rb @@ -0,0 +1,16 @@ +#!/usr/bin/env ruby + +class Array + def combinations n + result = Array.new + if n > 0 + (0 .. self.length - n).each do |i| + combs = self[i + 1 .. -1].combinations(n - 1) + combs = [[]] if combs.empty? + combs.collect {|comb| [self[i]] + comb}.each {|x| result << x} + end + end + return result + end +end + diff --git a/hand.rb b/hand.rb new file mode 100644 index 0000000..5ba8635 --- /dev/null +++ b/hand.rb @@ -0,0 +1,93 @@ +#!/usr/bin/env ruby + +require 'card' + +class Hand + def initialize(hand_string) + @cards = hand_string.scan(/../).collect { |s| Card.new(s) }.sort + end + + def legal? + @cards.size == @cards.sort.uniq.size && [5,10].include?(@cards.size) + end + + def illegal? + !(legal?) + end + + def rank + return nil if illegal? + + # array of suits, ranks + suits = @cards.collect { |c| c.suit_s } + ranks = @cards.collect { |c| c.rank } + + # count of suits + suit_counts = Hash.new(0) + suits.each { |s| suit_counts[s] += 1 } + + # count of ranks + rank_counts = Hash.new(0) + ranks.each { |s| rank_counts[s] += 1 } + + # test for straight & flush + straight = (ranks.sort == (ranks.min .. ranks.max).to_a) + flush = (suits.sort.uniq.size == 1) + + # rank hand + return :royal_flush if straight && flush && ranks.min == 10 + return :straight_flush if straight && flush + return :four_of_a_kind if [1,4] == rank_counts.values.sort + return :full_house if [2,3] == rank_counts.values.sort + return :flush if flush + return :straight if straight + + # nothing + nil + end + + + def score + r = rank + + return 0 if r.nil? + + # ten card hands + return 80 if @cards.size == 10 && r == :straight_flush + return 40 if @cards.size == 10 && r == :flush + return 20 if @cards.size == 10 && r == :straight + + # five card hands + return 21 if r == :royal_flush + return 20 if r == :straight_flush + return 15 if r == :four_of_a_kind + return 10 if r == :full_house + return 7 if r == :flush + return 5 if r == :straight + + # nothing + return 0 + end + + def score_name + rank.to_s.gsub(/_/,' ') if rank + end + + def to_s + @cards.collect { |c| c.to_s }.join(', ') + end + + def hash + to_s.hash + end + + def <=>(other) + to_s <=> other.to_s + end + +end + + + + + diff --git a/rank.rb b/rank.rb index 2adb684..2420119 100644 --- a/rank.rb +++ b/rank.rb @@ -1,70 +1,64 @@ #!/usr/bin/env ruby -class Array - def combinations n - result = Array.new - if n > 0 - (0 .. self.length - n).each do |i| - combs = self[i + 1 .. -1].combinations(n - 1) - combs = [[]] if combs.empty? - combs.collect {|comb| [self[i]] + comb}.each {|x| result << x} - end - end - return result - end -end +require 'hand' +require 'combinations' -require 'card' +def score(hand_string, verbose=false) + # split into an array of two character strings (each representing a card) + cards = hand_string.scan(/../) -def score5(hand,verbose=false) - # reject illegal hands (hands with duplicate cards) - return nil if hand.sort.uniq.size < 5 - return 0 -end + # a place to store all of our scores + best_hands = nil + best_score = -1 -def score10(hand,verbose=false) - # reject illegal hands (hands with duplicate cards) - return nil if hand.sort.uniq.size < 10 - - # count number of suits - suits = Hash.new(0) - ranks = Hash.new(0) - hand.each { |c| ranks[c[0]] += 1 } - hand.each { |c| suits[c[1]] += 1 } - - puts ranks.inspect - puts suits.inspect - - return 0 -end - - -def score(hand_string) - # split into Cards - cards = hand_string.scan(/../).collect { |s| Card.new(s) }.sort - puts cards.inspect - - # create all permutations of two 5 card hands - hand_scores = Hash.new + # create and score all permutations of two 5 card hands cards.combinations(5).each do |c| - other = cards - c - hand_scores[ [c.sort,other.sort].sort ] = nil + # create each hand from two 10 character strings + hand_a = Hand.new(c.join) + hand_b = Hand.new((cards-c).join) + score = hand_a.score + hand_b.score + + # save the hand if it's the best + best_hands,best_score = [hand_a,hand_b],score if score > best_score end - puts hand_scores.inspect - puts hand_scores.size + # now create and score the 10 card hand + ten_card_hand = Hand.new(cards.join) + best_hands,best_score = [ten_card_hand],ten_card_hand.score if ten_card_hand.score > best_score - # now score each set of two 5 card hands - hand_scores.each do |k,v| - score_a = score5(k[0]) - score_b = score5(k[1]) - hand_scores[k] = score_a + score_b unless score_a.nil? || score_b.nil? + # DEBUG + if verbose then + best_hands.each do |h| + puts "#{h.score} points for a #{h.score_name}" + puts h + puts + end + puts "#{best_score} TOTAL POINTS" end - # score the 10 card hand - hand_scores[ cards.sort ] = score10(cards) + # return score + best_score end -#score('tsjsqsksastcjcqckcac') - +score('tsjsqsksastcjcqckcac',true) +puts +puts +score('3d8c6s7d8h9s9dkdqd5d',true) +puts +puts +score('2s3s4s5s6s7s8s9stsjs',true) +puts +puts +score('2c3s4c5d6h7s8d9sthjs',true) +puts +puts +score('as3s4s5s6s7s8s9stsjs',true) +puts +puts +score('asadacah6s7s8s9stsjs',true) +puts +puts +score('asadackskd7s8s9stsjs',true) +puts +puts