People wrote quite a bit of code to solve this quiz.  I don't think it's all
that tough, but there are quite a few combinations to check for, which seemed to
increase the line count of the solutions.

There was something interesting in all the solutions though, so I do recommend
browsing through them if you haven't already.  I know I'm always saying that.  I
guess it's always true.

I'm going to show Patrick Hurley's solution below.  Patrick resubmitted just to
defend against my rant about how programs should stay within an 80 character
line limit.  My argument wasn't meant as an attack on any submissions, but I
still appreciate Patrick's efforts.  Here's the start of the code:

	#!ruby -w

	class Card
	  SUITS = "cdhs"
	  FACES = "L23456789TJQKA"
	  SUIT_LOOKUP = {
	    'c' => 0,
	    'd' => 1,
	    'h' => 2,
	    's' => 3,
	    'C' => 0,
	    'D' => 1,
	    'H' => 2,
	    'S' => 3,
	  }
	  FACE_VALUES = {
	    'L' =>  1,   # this is a magic low ace
	    '2' =>  2,
	    '3' =>  3,
	    '4' =>  4,
	    '5' =>  5,
	    '6' =>  6,
	    '7' =>  7,
	    '8' =>  8,
	    '9' =>  9,
	    'T' => 10,
	    'J' => 11,
	    'Q' => 12,
	    'K' => 13,
	    'A' => 14,
	  }

	  def Card.face_value(face)
	    if (face)
	      FACE_VALUES[face] - 1
	    else
	      nil
	    end
	  end

	  def build_from_string(card)
	    build_from_face_suit(card[0,1], card[1,1])
	  end

	  def build_from_value(value)
	    @value = value
	    @suit  = value / FACES.size()
	    @face  = (value % FACES.size())
	  end

	  def build_from_face_suit(face, suit)
	    @face  = Card::face_value(face)
	    @suit  = SUIT_LOOKUP[suit]
	    @value = (@suit * FACES.size()) + (@face - 1)
	  end

	  def build_from_face_suit_values(face, suit)
	    build_from_value((face - 1) + (suit * FACES.size()))
	  end

	  # got a little carried away with this constructor ;-)
	  def initialize(*value)
	    if (value.size == 1)
	      if (value[0].respond_to?(:to_str))
	        build_from_string(value[0])
	      elsif (value[0].respond_to?(:to_int))
	        build_from_value(value[0])
	      end
	    elsif (value.size == 2)
	      if (value[0].respond_to?(:to_str) &&
	          value[1].respond_to?(:to_str))
	        build_from_face_suit(value[0], value[1])
	      elsif (value[0].respond_to?(:to_int) &&
	             value[1].respond_to?(:to_int))
	        build_from_face_suit_values(value[0], value[1])
	      end
	    end
	  end

	  attr_reader :suit, :face, :value

	  def to_s
	    FACES[@face].chr + SUITS[@suit].chr
	  end
	end
	
	# ...

That's the Card class Patrick uses for tracking individual cards.  It looks like
a lot of code, but it's mostly a single constructor that accepts many different
forms of initialization.  initialize() breaks down the parameters and hands them
off to the various build_from_... methods.  Those build methods should probably
be private, leaning on initialize() as their interface.  Once you get past
construction, you'll see that Card just contains a suit, face, and value. 
Glance at build_from_face_suit() to see how those break down.

You can see it above and a little more below, but this code has a little
creeping featurism.  Patrick was clearly building for the future with the card
handling classes.  That's probably a safe bet as card quizzes are fairly common.
Dave Burt reused code from his Blackjack solution this time around.  All I'm
saying is, don't be surprised if you see a handful of things in here that never
get used.  Agile purists bare with us...

Let's move on to Deck objects:

	# ...

	class Deck
	  def shuffle
	    deck_size = @cards.size
	    (deck_size * 2).times do
	      pos1, pos2 = rand(deck_size), rand(deck_size)
	      @cards[pos1], @cards[pos2] = @cards[pos2], @cards[pos1]
	    end
	  end

	  def initialize
	    @cards = []
	    Card::SUITS.each_byte do |suit|
	      # careful not to double include the aces...
	      Card::FACES[1..-1].each_byte do |face|
	        @cards.push(Card.new(face.chr, suit.chr))
	      end
	    end
	    shuffle()
	  end

	  def deal
	    @cards.pop
	  end

	  def empty?
	    @cards.empty?
	  end
	end

	# ...

initialize() just creates and shuffles a deck.  deal() pops a card and empty?()
tells you if there are any left.  If you read shuffle(), you'll see that it's
just a bunch of random swaps.  Not sure why Patrick went this way.  I believe
the standard Ruby shuffling idiom is:

	@cards.sort_by { rand }

On to the Hand class, but let's take this one in slices:

	# ...

	class Hand
	  def initialize(cards = [])
	    if (cards.respond_to?(:to_str))
	      @hand = cards.scan(/\S\S/).map { |str| Card.new(str) }
	    else
	      @hand = cards
	    end
	  end
	  attr_reader :hand

	  # ...

initialize() just builds new Hand objects from the lines of input in the quiz by
scan()ing for the two character format.  You can also build a Hand from an Array
of Card objects.  Then there's the accessor to get them back.

	  # ...
	
	  def face_values
	    @hand.map { |c| c.face }
	  end
      
	  def by_suit
	    Hand.new(@hand.sort_by { |c| [c.suit, c.face] }.reverse)
	  end
      
	  def by_face
	    Hand.new(@hand.sort_by { |c| [c.face, c.suit] }.reverse)
	  end

	  # ...

You can use the above methods to request hands by face_values(), by_suit(), or
by_face(). Note that both of the by_... sorts also sort by the other value, as a
secondary condition.

	  # ...
      
	  def =~ (re)
	    re.match(@hand.join(' '))
	  end
      
	  def arrange_hand(md)
	      hand = if (md.respond_to?(:to_str))
	        md
	      else
	        md[0] + ' ' + md.pre_match + md.post_match
	      end
	      hand.gsub!(/\s+/, ' ')
	      hand.gsub(/\s+$/,'')
	  end
      
	  # ...

The first method here is an operator overload to allow using regular expressions
on Hand objects.  The second method returns a hand string in an order specified
by a MatchData object (the else clause).  Whatever cards were matched are put
first, follow by cards preceding the match, and finally trailing cards.  This
floats a matched "hand" to the front of the string while keeping the ordering
for any non-matched cards.  arrange_hand() can also be called with a string
order (the if clause), but it doesn't do much in these cases except clean up
spacing issues.

From here, we start to get into hand matching code:

	  # .. 
	  
	  def royal_flush?
	    if (md = (by_suit =~ /A(.) K\1 Q\1 J\1 T\1/))
	      [[10], arrange_hand(md)]
	    else
	      false
	    end
	  end
	  
	  # ...

This method looks for the coveted royal flush.  First it calls by_suit() to
order the cards.  Remember that will order suits first, then faces.  That makes
it trivial to spot the pattern with a Regexp.  When found, royal_flush?()
returns a hand ranking number and the properly arranged hand in an Array, which
is of course a true value in Ruby.  false is used when no match is found.

The code then pauses to define a couple more helper methods for spotting the
other hands:

	  # ...
	  
	  def delta_transform(use_suit = false)
	    aces = @hand.select { |c| c.face == Card::face_value('A') }
	    aces.map! { |c| Card.new(1,c.suit) }
      
	    base = if (use_suit)
	      (@hand + aces).sort_by { |c| [c.suit, c.face] }.reverse
	    else
	      (@hand + aces).sort_by { |c| [c.face, c.suit] }.reverse
	    end
      
	    result = base.inject(['',nil]) do |(delta_hand, prev_card), card|
	      if (prev_card)
	        delta = prev_card - card.face
	      else
	        delta = 0
	      end
	      # does not really matter for my needs
	      delta = 'x' if (delta > 9 || delta < 0)
	      delta_hand += delta.to_s + card.to_s + ' '
	      [delta_hand, card.face]
	    end
      
	    # we just want the delta transform, not the last cards face too
	    result[0].chop
	  end
	  
	  # ...

Dave Burt asked on Ruby Talk what delta_transform() does.  Here's the author's
own response:

	The delta transform creates a version of the cards where the delta
	between card values is in the string, so a regexp can then match a
	straight and/or straight flush - I used regexp to match all my cases
	with appropriate sort and/or transforms.

Because that's probably easier to understand when you see it, here's a typical
return value from delta_tranform():

	"0Jh 38h xJd 38d 44d 13d x8c"

The extra character preceding each card shows the drop from the previous card
rank.  The jack is the first card, so it shows a 0 drop.  The eight is then down
3, as shown.  Tracking increases isn't needed in the solution, so the code just
punts with an x character, as seen with the next jack.  All this is just
building up a handy string for pattern matching.

Note that the first couple of lines of delta_transform() add a "low ace" to the
back of the hand for each ace found in the hand.  This is for spotting low
straights, but the magic must eventually be undone by:

	  # ...
	  
	  def fix_low_ace_display(arranged_hand)
	    # remove card deltas (this routine is only used for straights)
	    arranged_hand.gsub!(/\S(\S\S)\s*/, "\\1 ")
      
	    # Fix "low aces"
	    arranged_hand.gsub!(/L(\S)/, "A\\1")
      
	    # Remove duplicate aces (this will not work if you have
	    # multiple decks or wild cards)
	    arranged_hand.gsub!(/((A\S).*)\2/, "\\1")
      
	    # cleanup white space
	    arranged_hand.gsub!(/\s+/, ' ')
	    # careful to use gsub as gsub! can return nil here
	    arranged_hand.gsub(/\s+$/, '')
	  end
	  
	  # ...

This just restores the ace back to its usual display.

Now we can see both of those methods put to good use:

	  # ...
	  
	  def straight_flush?
	    if (md = (/.(.)(.)(?: 1.\2){4}/.match(delta_transform(true))))
	      high_card = Card::face_value(md[1])
	      arranged_hand = fix_low_ace_display(md[0] + ' ' +
	          md.pre_match + ' ' + md.post_match)
	      [[9, high_card], arranged_hand]
	    else
	      false
	    end
	  end
	  
	  # ...

This is similar in function to royal_flush?(), but you can see that it uses
delta_transform() to make it easy to match a straight.  fix_low_ace_display() is
called on the result, before the method returns.

The rest of the hand methods are very similar.  Sort the cards, match a pattern,
return rank and hand or false.  Here they are, without further explanation:

	  # ...
	  
	  def four_of_a_kind?
	    if (md = (by_face =~ /(.). \1. \1. \1./))
	      # get kicker
	      (md.pre_match + md.post_match).match(/(\S)/)
	      [
	        [8, Card::face_value(md[1]), Card::face_value($1)],
	        arrange_hand(md)
	      ]
	    else
	      false
	    end
	  end
      
	  def full_house?
	    if (md = (by_face =~ /(.). \1. \1. (.*)(.). \3./))
	      arranged_hand = arrange_hand(md[0] + ' ' +
	          md.pre_match + ' ' + md[2] + ' ' + md.post_match)
	      [
	        [7, Card::face_value(md[1]), Card::face_value(md[3])],
	        arranged_hand
	      ]
	    elsif (md = (by_face =~ /((.). \2.) (.*)((.). \5. \5.)/))
	      arranged_hand = arrange_hand(md[4] + ' '  + md[1] + ' ' +
	          md.pre_match + ' ' + md[3] + ' ' + md.post_match)
	      [
	        [7, Card::face_value(md[5]), Card::face_value(md[2])],
	        arranged_hand
	      ]
	    else
	      false
	    end
	  end
      
	  def flush?
	    if (md = (by_suit =~ /(.)(.) (.)\2 (.)\2 (.)\2 (.)\2/))
	      [
	        [
	          6,
	          Card::face_value(md[1]),
	          *(md[3..6].map { |f| Card::face_value(f) })
	        ],
	        arrange_hand(md)
	      ]
	    else
	      false
	    end
	  end
      
	  def straight?
	    result = false
	    if hand.size > 5
	      transform = delta_transform
	      # note we can have more than one delta 0 that we
	      # need to shuffle to the back of the hand
	      until transform.match(/^\S{3}( [1-9x]\S\S)+( 0\S\S)*$/) do
	        transform.gsub!(/(\s0\S\S)(.*)/, "\\2\\1")
	      end
	      if (md = (/.(.). 1.. 1.. 1.. 1../.match(transform)))
	        high_card = Card::face_value(md[1])
	        arranged_hand = fix_low_ace_display(md[0] + ' ' +
	            md.pre_match + ' ' + md.post_match)
	        result = [[5, high_card], arranged_hand]
	      end
	    end
	  end
      
	  def three_of_a_kind?
	    if (md = (by_face =~ /(.). \1. \1./))
	      # get kicker
	      arranged_hand = arrange_hand(md)
	      arranged_hand.match(/(?:\S\S ){3}(\S)\S (\S)/)
	      [
	        [
	          4,
	          Card::face_value(md[1]),
	          Card::face_value($1),
	          Card::face_value($2)
	        ],
	        arranged_hand
	      ]
	    else
	      false
	    end
	  end
      
	  def two_pair?
	    if (md = (by_face =~ /(.). \1.(.*) (.). \3./))
	      # get kicker
	      arranged_hand = arrange_hand(md[0] + ' ' +
	          md.pre_match + ' ' + md[2] + ' ' + md.post_match)
	      arranged_hand.match(/(?:\S\S ){4}(\S)/)
	      [
	        [
	          3,
	          Card::face_value(md[1]),
	          Card::face_value(md[3]),
	          Card::face_value($1)
	        ],
	        arranged_hand
	      ]
	    else
	      false
	    end
	  end
      
	  def pair?
	    if (md = (by_face =~ /(.). \1./))
	      # get kicker
	      arranged_hand = arrange_hand(md)
	      arranged_hand.match(/(?:\S\S ){2}(\S)\S\s+(\S)\S\s+(\S)/)
	      [
	        [
	          2,
	          Card::face_value(md[1]),
	          Card::face_value($1),
	          Card::face_value($2),
	          Card::face_value($3)
	        ],
	        arranged_hand
	      ]
	    else
	      false
	    end
	  end
      
	  def highest_card?
	    result = by_face
	    [[1, *result.face_values[0..4]], result.hand.join(' ')]
	  end
	  
	  # ...

Now what we really need to know is which one of those hands was found.  The code
for that isn't overly complex:

      # ...
      
      OPS = [
        ['Royal Flush',     :royal_flush? ],
        ['Straight Flush',  :straight_flush? ],
        ['Four of a kind',  :four_of_a_kind? ],
        ['Full house',      :full_house? ],
        ['Flush',           :flush? ],
        ['Straight',        :straight? ],
        ['Three of a kind', :three_of_a_kind?],
        ['Two pair',        :two_pair? ],
        ['Pair',            :pair? ],
        ['Highest Card',    :highest_card? ],
      ]
      
      def hand_rating
        OPS.map { |op|
          (method(op[1]).call()) ? op[0] : false
        }.find { |v| v }
      end
      
      def score
        OPS.map { |op|
          method(op[1]).call()
        }.find([0]) { |score| score }
      end
      
      # ...

The OPS Array maps hand names to the method that will spot them.  With that, you
call call either hand_rating() or score() which will walk the whole list of
tests, then return the first one that was true.  hand_rating() returns the name
while score() returns the rank and hand Array from the hand method call.

Finally, Hand has a few more very basic helper methods:

	  # ...
	
	  def take_card(card)
	    @hand.push(card)
	  end

	  def arranged_hand
	    score[1] + " (#{hand_rating})"
	  end

	  def just_cards
	    @hand.join(" ")
	  end

	  def to_s
	    just_cards + " (" + hand_rating + ")"
	  end
	end
	
	# ...

The only thing to notice there is the arranged_hand() is just a shell over
score() and hand_rating() and to_s() is a shell over just_cards() and
hand_rating().

The rest of Patrick's code goes on to build a complete game of Texas Hold'Em
that plays itself out round by round and displays results as it goes.  This is
very interesting stuff, but it doesn't solve the quiz, the way I read it. 
Luckily, a solution is easy to finish off from here.  Here's my solution to the
quiz, using Partick's classes:

	# ...
	
	### code by JEG2 ###
	if __FILE__ == $0
		best = nil
		results = []
		
		ARGF.each_line do |line|
			if line.length < 20                                # they folded
				results << line.chomp
			else
				hand            = Hand.new(line)               # rank hand
				name            = hand.hand_rating
				score, arranged = hand.score
				
				if best.nil? or (score[0] <=> best[0]) == 1    # track best
					best = [score[0], results.size]
				end

				results << "#{arranged} #{name}"
			end
		end
		
		# show results
		results.each_with_index do |e, index|
			puts(if index == best[1] then "#{e} (winner)" else e end)
		end
	end

That should be pretty straight forward by this point.  I setup variables to
track the best hand and the complete results, parse input, handle folds, score
each hand, remembering to track the best so far, and finally out the results. 
That funny compare, (score[0] <=> best[0]) == 1, is because the grade returned
by score is actually an Array of values and Array implements <=> but not >; go
figure.  That gets me the following output for the quiz example:

	Ks Kd Kc 9s 9d 6d 3c Full house (winner)
	Ks Kd 9d 9c Ah 6d 3c Two pair
	Ac Qc Ks Kd 9d 3c
	9h 5s
	Kd 9d 6d 4d 2d Ks 3c Flush
	7s Ts Ks Kd 9d

While I'm showing output, check out this neat variation by Derek Wyatt:

	9d 9s Kd Ks Kc 3c 6d  Full House (Kings over Nines) (winner)
	9d 9c Kd Ks Ah 3c 6d  Two Pair (Kings and Nines)
	Ac Qc Ks Kd 9d 3c     
	9h 5s                 
	Ks Kd 2d 4d 3c 6d 9d  Pair (Kings)
	7s Ts Ks Kd 9d        

I love the way it gives you extra details about the hand, but as you can see we
don't agree on hand number four.  Don't sweat that though, seems everyone had a
good round of bug hunting for this one.

My thanks to all the card sharks out there.  I also want to thank Patrick for
writing code I could figure out how to hijack.  This summary was definitely a
team effort.

Tomorrow, Tymothy Byrd will hit you with a brain bender you and Ruby can work
together to solve...