[Derek Wyatt <tone_hole / yahoo.ca>, 2005-03-20 15.55 CET] > -----BEGIN PGP SIGNED MESSAGE----- > Hash: SHA1 > > This was a fun one :) > > I'm looking forward to seeing other solutions. Well, here is mine. I agree it was a fun one, except in the very long part where I try to match different plays (what is the correct word?). Poker has too many! The strategy was nothing OO, or elegant. I just ordered the hand by rank (or by suit when checking for flush) and tried to match some regexes. Probably has bugs, the supplied card generator program never yielded a Royal Flush... Here it is: RANKS = "AKQJT98765432" INTERNAL = "ABCDEFGHIJKLM" RANKS_REVERSED = RANKS.reverse ACE = "A" LOW_ACE = "N" # "plays"? maybe "figures"? (?) PLAYS = { "Royal Flush" => 10, "Straight Flush" => 9, "Four of a Kind" => 8, "Full House" => 7, "Flush" => 6, "Straight" => 5, "Three of a Kind" => 4, "Double Pair" => 3, "Pair" => 2, "High Card" => 1, "" => 0 } class String # split, do something with the array except finding, join, replace # I never find the right method name... def do! (method, low_ace=false, &block) s = self.tr RANKS, INTERNAL s.tr!(ACE, LOW_ACE) if low_ace arr = s.split.send(method, &block) s = arr.join(" ") s.tr!(LOW_ACE, ACE) if low_ace replace s.tr(INTERNAL, RANKS) self end end module Enumerable # yields n items each time (but advances by one) def each_n (n) a = [] each do |cur| a << cur next if a.size < n yield *a a.shift end end end # moves the used cards to the left, calculates hand score, # creates hash to insert in hands array # hand is the hand, name is name of the play (game?) # m is the matched play (game? hand?) # groups are the indices of the groups in m that form the hand # I repeat, I'm very bad choosing method names def finish (hand, name, m, *groups) # extract the matched play (?) from hand, # sort its parts from biggest to smallest (for the full house) duphand = hand.dup groups = groups.map {|g| b = m.begin(g); e = m.end(g) hand[b...e] = "*" * (e-b) duphand.slice(b...e) }. sort_by {|g| -g.size } hand.delete!("*") # if there are any remaining cards (kickers), sort them if hand.size > 2 hand.do!(:sort) end # reinsert hand at the beginning hand = groups.join(" ") + " " + hand hand.squeeze! # calculate score # the score is a 5-digit hex number, each digit with # the rank of the card at that position # ups... can't use String#do! here :( score = hand.split[0,5].inject(1) { |sc, card| (sc << 4) + RANKS_REVERSED.index(card[0].chr) } # build the hash and return it { :hand => hand, :name => name, :score => score } end hands = [] while line = gets line.chomp! if line.split.size != 7 hands << {:hand => line, :name => "", :score => 0} next end line.do!(:sort) catch :found do # try to find... # ... straight (and royal) flush RANKS.split(//).each_n(5) do |a,b,c,d,e| r = /(#{a}(.) #{b}\2 #{c}\2 #{d}\2 #{e}\2)/ if m = r.match(line) hands << finish(line, (m[0][0]==?A ? # if it starts with ace "Royal Flush" : # it's royal "Straight Flush"), m, 1) throw :found end end # try to find straight flush with low ace line.do!(:sort, true) if m = /(5(.) 4\2 3\2 2\2 A\2)/.match(line) hands << finish(line, "Straight Flush", m, 1) throw :found end # ... four of a kind line.do!(:sort) if m = /((\w). \2. \2. \2.)/.match(line) hands << finish(line, "Four of a Kind", m, 1) throw :found end # ... full house if m = /((\w)\w \2\w \2\w).*((\w)\w \4\w)/.match(line) or m = /((\w)\w \2\w).*((\w)\w \4\w \4\w)/.match(line) hands << finish(line, "Full House", m, 1, 3) throw :found end # ...flush # sort by color line.do!(:sort_by){|card| [card[1],card[0]]} if m = /(\w(\w) \w\2 \w\2 \w\2 \w\2)/.match(line) hands << finish(line, "Flush", m, 1) throw :found end # ...straight line.do!(:sort) RANKS.split(//).each_n(5) do |a,b,c,d,e| r = /(#{a}. #{b}. #{c}. #{d}. #{e}.)/ if m = r.match(line) hands << finish(line, "Straight", m, 1) throw :found end end # ...straight, low ace line.do!(:sort, true) if m = /(5. 4. 3. 2. A.)/.match(line) hands << finish(line, "Straight", m, 1) throw :found end # ... three of a kind line.do!(:sort) if m = /((\w)\w \2\w \2\w)/.match(line) hands << finish(line, "Three of a Kind", m, 1) throw :found end # ... double pair if m = /((\w)\w \2\w).*((\w)\w \4\w)/.match(line) hands << finish(line, "Double Pair", m, 1, 3) throw :found end # ...pair if m = /((\w)\w \2\w)/.match(line) hands << finish(line, "Pair", m, 1) throw :found end # ... high card.. FINISH AT LAST!!! if m = /^(\w\w)/.match(line) hands << finish(line, "High Card", m, 1) throw :found end raise "This program is buggy. Terminating." end end # get the winner hand winner = hands.sort_by {|h| [-PLAYS[h[:name]], -h[:score]] }.first # print the lines hands.each do |h| print h[:hand], " ", h[:name] if winner[:name] != "" && h[:name] == winner[:name] && h[:score] == winner[:score] print " (winner)" end puts end