[QUIZ] Texas Hold'Em (#24)

The three rules of Ruby Quiz:

1. Please do not post any solutions or spoiler discussion for this quiz until
48 hours have passed from the time on this message.

2. Support Ruby Quiz by submitting ideas as often as you can:

http://www.rubyquiz.com/

3. Enjoy!

···

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

by Matthew D Moss

You work for a cable network; specifically, you are the resident hacker for a
Texas Hold'Em Championship show.

The show's producer has come to you for a favor. It seems the play-by-play
announcers just can't think very fast. All beauty, no brains. The announcers
could certainly flap their jaws well enough, if they just knew what hands the
players were holding and which hand won the round. Since this is live TV, they
need those answers quick. Time to step up to the plate. Bob, the producer,
explains what you need to do.

BOB: Each player's cards for the round will be on a separate line of the input.
Each card is a pair of characters, the first character represents the face, the
second is the suit. Cards are separated by exactly one space. Here's a sample
hand.

  Kc 9s Ks Kd 9d 3c 6d
  9c Ah Ks Kd 9d 3c 6d
  Ac Qc Ks Kd 9d 3c
  9h 5s
  4d 2d Ks Kd 9d 3c 6d
  7s Ts Ks Kd 9d

YOU: Okay, I was going ask what character to use for 10, but I guess 'T' is it.
And 'c', 'd', 'h' and 's' for the suits, makes sense. Why aren't seven cards
listed for every player?

BOB: Well, if a player folds, only his hole cards and the community cards he's
seen so far are shown.

YOU: Right. And why did the fifth player play with a 4 and 2? They're suited,
but geez, talk about risk...

BOB: Stay on topic. Now, the end result of your code should generate output that
looks like this:

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

YOU: Okay, so I repeat the cards, list the rank or nothing if the player folded,
and the word "winner" in parenthesis next to the winning hand. Do you want the
cards rearranged at all?

BOB: Hmmm... we can get by without it, but if you have the time, do it. Don't
bother for folded hands, but for ranked hands, move the cards used to the front
of the line, sorted by face. Kickers follow that, and the two unused cards go at
the end, just before the rank is listed.

YOU: Sounds good. One other thing, I need to brush up on the hand ranks. You
have any good references for Texas Hold'Em?

BOB: Yeah, check out these Poker Hand Rankings
(http://www.thepokerforum.com/pokerhands.htm). And if you need it, here are the
Rules of Texas Hold'Em (http://www.thepokerforum.com/texasholdem.htm). While
ranking, don't forget the kicker, the next highest card in their hand if
player's are tied. And of course, if -- even after the kicker -- player's are
still tied, put "(winner)" on each appropriate line of output.

YOU: Ok. I still don't understand one thing...

BOB: What's that?

YOU: Why he stayed in with only the 4 and 2 of diamonds? That's just...

BOB: Hey! Show's on in ten minutes! Get to work!

[ Editor's Note:

Matthew included a script for generating test games with his quiz. Here's that
code:

  #!/usr/bin/env ruby

  FACES = "AKQJT98765432"
  SUITS = "cdhs"

  srand

  # build a deck
  deck = []
  FACES.each_byte do |f|
    SUITS.each_byte do |s|
      deck.push(f.chr + s.chr)
    end
  end

  # shuffle deck
  3.times do
    shuf = []
    deck.each do |c|
      loc = rand(shuf.size + 1)
      shuf.insert(loc, c)
    end
    deck = shuf.reverse
  end

  # deal common cards
  common = Array.new(5) { deck.pop }

  # deal player's hole cards
  hole = Array.new(8) { Array.new(2) { deck.pop } }

  # output hands
  hands = []
  all_fold = true
  while all_fold do
    hands = []
    hole.each do |h|
      num_common = [0, 3, 4, 5][rand(4)]
      if num_common == 5
        all_fold = false
      end
      if num_common > 0
        hand = h + common[0 ... num_common]
      else
        hand = h
      end
      hands.push(hand.join(' '))
    end
  end

  hands.each { |h| puts h }

-JEG2 ]

YOU: Okay, I was going ask what character to use for 10, but I guess 'T' is it.

T is what people usually use for 10 when discussing the hands online.

YOU: Why he stayed in with only the 4 and 2 of diamonds? That's just...

This is a bit of didacticism nobody wants, but: 42s is a pretty lousy starting hand, but maybe:

1. You're in the button or one off, late position makes a lot of marginal hands playable.
2. You were in the big blind and nobody bet over the blind, or you were in the little blind, and you figured that the small amount you'd have to pay to see the flop would be worth it.
3. You're on an exceptionally loose-passive table, so maybe you won't have to pay much to draw to a flush or low straight, and when you do nail your hand you'll be able to raise to make your bet payoff. These tables do happen, though if you're being televised, your opponents are probably all better players than this ...
4. Or maybe you're going in with the occasional pure, ludicrous bluff, hoping to show terrible cards at the end to advertise the fact that you're looser than you actually are.

Francis Hwang

···

On Mar 18, 2005, at 9:41 AM, Ruby Quiz wrote:

YOU: Okay, I was going ask what character to use for 10, but I guess

'T' is it.

And 'c', 'd', 'h' and 's' for the suits, makes sense. Why aren't seven

cards

listed for every player?

BOB: Well, if a player folds, only his hole cards and the community

cards he's

seen so far are shown.

How do we know if a player folded on the river? (For the ones who
didn't read the rules or aren't hold'em junkies like myself, the river
is the 5th community card -- a player could fold here and muck his hand)

Or do we just not care? i.e. say he won anyways even though he mucked it.

Good quiz :slight_smile:

Derek

#!/usr/bin/ruby -w

···

#
# Quiz 24: Texas Hold'em
# Solution by Glenn Parker

module Combine
   # Generate all combinations of +pick+ elements from +items+ array.
   def Combine.pick(pick, items, &block)
     combine([], 0, pick, items, &block)
   end

   private

   def Combine.combine(set, index, pick, items, &block)
     if pick == 0 or index == items.length
       yield set
     else
       set.push(items[index])
       combine(set, index + 1, pick - 1, items, &block)
       set.pop
       combine(set, index + 1, pick, items, &block) if
         pick < items.length - index
     end
   end
end

# One card, with a face [2-9TJQKA] and a suit [shdc].
class Card
   attr_reader :face, :suit

   Face_Ranks = {
     :A => 12, :K => 11, :Q => 10, :J => 9,
     :T => 8, :"9" => 7, :"8" => 6, :"7" => 5,
     :"6" => 4, :"5" => 3, :"4" => 2, :"3" => 1,
     :"2" => 0
   }

   Suit_Ranks = {
     :s => 3, :h => 2, :d => 1, :c => 0
   }

   def initialize(face_suit)
     @face = face_suit[0].chr.to_sym
     raise "Invalid face \"#{@face}\"" unless Face_Ranks.has_key?(@face)
     @suit = face_suit[1].chr.to_sym
     raise "Invalid suit \"#{@suit}\"" unless Suit_Ranks.has_key?(@suit)
     freeze
   end

   def rank # Overall ranking in the deck.
     index * 4 + Suit_Ranks[@suit]
   end

   def index # Ranking, independent of suit.
     Face_Ranks[@face]
   end

   def to_s
     @face.to_s + @suit.to_s
   end
end

# A typed collection of up to five cards.
class Hand
   include Comparable # Hands can be compared.

   attr_reader :hand_type, :cards

   Hand_Names = [
     "Folded",
     "High Card",
     "Pair",
     "Two Pair",
     "Three of a Kind",
     "Straight",
     "Flush",
     "Full House",
     "Four of a Kind",
     "Straight Flush",
     "Royal Flush"
   ]

   # Define constants by converting "High Card" to Hand::High_Card = 0.
   Hand_Names.each_with_index do |n, i|
     const_set(n.tr(" ", "_"), i)
   end

   def initialize(hand_type, cards)
     @hand_type = hand_type
     @cards = cards.dup
     freeze
   end

   def to_s
     @cards.join(" ") + " " + Hand_Names[@hand_type]
   end

   def <=>(other)
     if @hand_type != other.hand_type
       # Hand ranking dominates.
       return @hand_type <=> other.hand_type

     elsif @hand_type == Flush
       # Compare corresponding cards, highest to lowest.
       @cards.reverse.zip(other.cards.reverse) do |a, b|
         return a.index <=> b.index if a.index != b.index
       end
       return 0

     elsif @hand_type == Two_Pair
       # Compare the two highest pairs, then the remaining pairs
       self_indices = [@cards[0].index, @cards[2].index].sort!
       other_indices = [other.cards[0].index, other.cards[2].index].sort!
       if self_indices[1] != other_indices[1]
         return self_indices[1] <=> other_indices[1]
       else
         return self_indices[0] <=> other_indices[0]
       end

     else
       # All others types of hand are compared using their first card.
       return @cards[0].index <=> other.cards[0].index
     end
   end
end

# A collection of seven cards, from which Hands are extracted.
class Deal
   attr_reader :all_cards, :best_hand, :kickers

   def initialize(card_string)
     # Parse and sort the cards. The sorting order chosen here is
     # important when extracting and comparing hands later.
     @all_cards = card_string.split(/ /).collect do |face_suit|
       Card.new(face_suit)
     end.sort_by { |card| card.rank }
     @hands = []
     if @all_cards.length == 7
       # Extract all possible hands if we got 7 cards.
       find_high_card
       find_groups
       find_two_pairs_and_full_house
       find_straight_and_flush
     else
       # Otherwise, make a folded hand.
       add_hand(Hand::Folded, @all_cards)
     end
     # Pick the best possible hand and determine the kickers.
     @best_hand = @hands.max
     @kickers = (@all_cards - @best_hand.cards).sort_by do |card|
       -card.rank
     end
   end

   private

   def add_hand(hand_type, cards)
     @hands << Hand.new(hand_type, cards)
   end

   def find_high_card
     add_hand(Hand::High_Card, [ @all_cards[-1] ])
   end

   def find_groups
     # Find the longest run of each face in @all_cards.
     start = 0
     while @all_cards[start]
       for stop in ((start + 1)..@all_cards.length)
         next if @all_cards[stop] and
           (@all_cards[start].face == @all_cards[stop].face)
         case (stop - start)
         when 4:
      add_hand(Hand::Four_of_a_Kind, @all_cards[start...stop])
         when 3:
      add_hand(Hand::Three_of_a_Kind, @all_cards[start...stop])
         when 2:
      add_hand(Hand::Pair, @all_cards[start...stop])
         end
         break
       end
       start = stop
     end
   end

   def find_two_pairs_and_full_house
     pairs = @hands.find_all do |h|
       h.hand_type == Hand::Pair
     end
     threes = @hands.find_all do |h|
       h.hand_type == Hand::Three_of_a_Kind
     end
     # Find up to three combinations of two pairs.
     if (pairs.length > 1)
       Combine.pick(2, pairs) do |pair_hands|
         add_hand(Hand::Two_Pair,
     pair_hands[0].cards + pair_hands[1].cards)
       end
     end
     # Each combination of a pair and three-of-a-kind is a full house.
     pairs.each do |pair|
       threes.each do |three|
         add_hand(Hand::Full_House, three.cards + pair.cards)
       end
     end
     # Two three-of-a-kinds yield two possible full-houses.
     if (threes.length > 1)
       add_hand(Hand::Full_House,
         threes[0].cards + threes[1].cards[0..1])
       add_hand(Hand::Full_House,
         threes[1].cards + threes[0].cards[0..1])
     end
     # We could combine four-of-a-kind and a pair for a full-house
     # but four-of-a-kind already beats a full-house.
   end

   def find_straight_and_flush
     # Examine all combinations of five cards
     Combine.pick(5, @all_cards) do |cards|
       is_flush = true
       is_straight = true
       1.upto(4) do |i|
         is_straight = false if
    (cards[i].index != cards[i - 1].index + 1)
         is_flush = false if
    (cards[i].suit != cards[0].suit)
       end
       # Add the best hand found in this iteration.
       case
       when (is_straight and is_flush and cards[0].face == :"T")
         add_hand(Hand::Royal_Flush, cards)
       when (is_straight and is_flush)
         add_hand(Hand::Straight_Flush, cards)
       when (is_flush)
         add_hand(Hand::Flush, cards)
       when (is_straight)
         add_hand(Hand::Straight, cards)
       end
     end
   end

end

# A card player that holds a Hand and some kickers.
class Player
   attr_reader :hand, :kickers
   attr_accessor :wins

   def initialize(hand, kickers)
     @hand = hand
     @kickers = kickers
     @wins = false
   end

   # Return <=> value comparing kickers from another Player.
   def compare_kickers(other)
     @kickers.zip(other.kickers) do |a_kicker, b_kicker|
       return 1 if a_kicker.index > b_kicker.index
       return -1 if a_kicker.index < b_kicker.index
     end
     return 0
   end
end

# Read the input.

players = []
while line = gets
   line.chomp!
   # Take first 20 chars only, making it easy to use previously
   # printed results as input for re-testing.
   deal = Deal.new(line[0, 20])
   players << Player.new(deal.best_hand, deal.kickers)
end

# Find the winner(s).

winners = []
players.each do |player|
   if winners.empty?
     winners << player
   elsif player.hand > winners[0].hand
     winners.clear
     winners << player
   elsif player.hand == winners[0].hand
     # Try to resolve ties based on kickers.
     comparison = player.compare_kickers(winners[0])
     if comparison >= 0
       winners.clear if comparison > 0
       winners << player
     end
   end
end
winners.each { |player| player.wins = true }

# Report the results.

players.each do |player|
   # Print cards sorted by face with kickers at the end.
   print((player.hand.cards + player.kickers).join(" "))
   # Print description of hand and (winner) flag
   if player.hand.hand_type > 0
     print " ", Hand::Hand_Names[player.hand.hand_type]
     print " (winner)" if player.wins
   end
   print "\n"
end

I'll add my (partial, again) solution... I didn't get a whole lot of
time to work on it, despite having written the original proposal. But
it was fun, so I may work a bit more on it. In any case, just to add
my ideas and approach, my current code determines the rank of each
hand, but that's it -- didn't get to refactoring and determining the
actual winner or sorting cards, checking high, kickers, etc.

#!/usr/bin/env ruby

SUITS = %w(c d h s)
FACES = %w(A K Q J T 9 8 7 6 5 4 3 2)

RANKS = {
  :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',
  :high_card => 'High Card',
  :fold => ''
}

class Hand
  def initialize(line)
    @cards = line.split

    @faces = Hash.new { [] }
    @suits = Hash.new { [] }
    @count = Hash.new { [] }

    @cards.each do |card|
      f = FACES.index(card[0].chr)
      s = SUITS.index(card[1].chr)
      @faces[f] = @faces[f] << s
      @suits[s] = @suits[s] << f
    end

    @faces.keys.each do |face|
      n = @faces[face].size
      @count[n] = @count[n] << face
    end

    @rank = rank_hand
  end

  def rank_hand
    return :fold if @cards.size < 7

    return :royal_flush if @suits.keys.any? do |suit|
      (0..5).all? do |face|
        @suits[suit].include? face
      end
    end

    return :straight_flush if @suits.keys.any? do |suit|
      high = @suits[suit].min
      (high..high+5).all? do |face|
        @suits[suit].include? face
      end
    end

    return :four_of_a_kind if not @count[4].empty?

    return :full_house if @count[3].size == 2 or (@count[3].size == 1
and not @count[2].empty?)

    return :flush if @suits.keys.any? do |suit|
      @suits[suit].size >= 5
    end

    return :straight if @faces.keys.any? do |high|
      (high..high+5).all? do |face|
        @faces.keys.include? face
      end
    end

    return :three_of_a_kind if @count[3].size == 1

    return :two_pair if @count[2].size >= 2

    return :pair if @count[2].size == 1

    :high_card
  end

  attr_reader :cards, :rank
end

def main
  hands = $<.collect { |l| Hand.new(l.chomp) }
  hands.each do |h|
    puts "#{h.cards.join(' ')} #{RANKS[h.rank]}"
  end
end

main

http://www.dave.burt.id.au/poker.rb

(requires card.rb in the same directory)

An explanation (and comments) will come later tonight.

Cheers,
Dave

Francis Hwang wrote:

YOU: Okay, I was going ask what character to use for 10, but I guess 'T' is it.

T is what people usually use for 10 when discussing the hands online.

YOU: Why he stayed in with only the 4 and 2 of diamonds? That's just...

This is a bit of didacticism nobody wants, but: 42s is a pretty lousy starting hand, but maybe:

1. You're in the button or one off, late position makes a lot of marginal hands playable.
2. You were in the big blind and nobody bet over the blind, or you were in the little blind, and you figured that the small amount you'd have to pay to see the flop would be worth it.
3. You're on an exceptionally loose-passive table, so maybe you won't have to pay much to draw to a flush or low straight, and when you do nail your hand you'll be able to raise to make your bet payoff. These tables do happen, though if you're being televised, your opponents are probably all better players than this ...
4. Or maybe you're going in with the occasional pure, ludicrous bluff, hoping to show terrible cards at the end to advertise the fact that you're looser than you actually are.

That is the most amazing domain-specific reply I have ever seen.

So Mr. Lafcadio is also a cardsharp? Who'd have guessed...

Hal

···

On Mar 18, 2005, at 9:41 AM, Ruby Quiz wrote:

Hmm, the quiz doesn't seem to account for this, so we should probably just score it, in my non Texas Hold'em Junkie opinion. :wink:

James Edward Gray II

···

On Mar 18, 2005, at 12:02 PM, Derek Wyatt wrote:

How do we know if a player folded on the river? (For the ones who
didn't read the rules or aren't hold'em junkies like myself, the river
is the 5th community card -- a player could fold here and muck his hand)

Or do we just not care? i.e. say he won anyways even though he mucked it.

I apologise for posting the URL incorrectly. It's really:
http://www.dave.burt.id.au/ruby/poker.rb

This is a pretty long project. Here are some highlights:

# each hand type has a name and a function taking a hand and returning it,
# sorted, or nil if the hand doesn't match this type.
HandTypes = [
  ['Royal Flush', proc {|hand|
   if hand.find_all{|c|c.value >= 10}.map(:suit).frequencies(5).size >= 1
    Poker.find_straight(hand)
   end }],
  ['Straight Flush', proc {|hand|
   suit, count = *hand.map(:suit).frequencies(5)[0]
   if count && count >= 1
    if straight = Poker.find_straight(hand.find_all {|card| card.suit ==
suit })
     result = hand.dup
     result.delete_if {|card| straight.include?(card) }
     straight + result.sort_by_most_frequent(:value)
    end
   end }],
  ['Four of a Kind', proc {|hand|
   if hand.map(:value).frequencies(2).size >= 4
    hand.sort_by_most_frequent :value
   end }],
  ['Flush', proc {|hand|
   if hand.map(:suit).frequencies(5).size >= 1
    hand.sort_by_most_frequent :suit
   end }],
  ['Straight', proc {|hand|
   Poker.find_straight(hand) }],
  ['Three of a Kind', proc {|hand|
   if hand.map(:value).frequencies(3).size >= 1
    hand.sort_by_most_frequent :value
   end }],
  ['Two Pair', proc {|hand|
   if hand.map(:value).frequencies(2).size >= 2
    hand.sort_by_most_frequent :value
   end }],
  ['Pair', proc {|hand|
   if hand.map(:value).frequencies(2).size >= 1
    hand.sort_by_most_frequent :value
   end }],
  ['High Card', proc {|hand|
   hand.sort.reverse }]
]

···

#
# Returns [n, "Hand type", ordered_cards]
# The n at the front is bigger for better hands, so that
# you can sort by hand_value.
#
def self.hand_value(cards, min_cards = 7) # self #=> Poker:Module
  if cards.size >= min_cards
   HandTypes.each_with_index do |hand_type, index|
    hand_match = hand_type[1].call(cards)
    if hand_match
     # return EvaluatedHand.new(hand_match, hand_type[0], [HandTypes.size -
index, hand_match])
     return [
      HandTypes.size - index,
      hand_type[0],
      hand_match
     ]
    end
   end
  end
  [0, '', cards.sort_by_most_frequent(:value)]
end

# then it all comes together like this:

hands =

# get hands from input and evaluate them
input.each do |line|
  hands << line.to_cards.poker_value
end

# determine the winner
winner = hands.inject() do |memo, hand|
  [memo, hand].max
end

# output each hand and its value
hands.each do |hand|
  puts "#{hand[2]} #{hand[1]} #{'(winner)' if hand == winner}"
end

That plus a Poker::find_straight and Array#frequencies and that's pretty
much all there is to my answer.

Cheers,
Dave

"Dave Burt" <dave@burt.id.au> faked:

http://www.dave.burt.id.au/poker.rb

(requires card.rb in the same directory)

An explanation (and comments) will come later tonight.

Cheers,
Dave

Hal Fulton wrote:

...

That is the most amazing domain-specific reply I have ever seen.

So Mr. Lafcadio is also a cardsharp? Who'd have guessed...

Hmm. I'll keep this in mind at the next RubyConf.

Which is going to be in Vegas, right David?

:slight_smile:

James

I don't know if you could call me a cardsharp yet, otherwise I wouldn't have to write code for a living ...

Francis Hwang

···

On Mar 18, 2005, at 11:49 AM, Hal Fulton wrote:

So Mr. Lafcadio is also a cardsharp? Who'd have guessed...

Dave I am still looking over your code, but since I got your test data
last week here is some for you). This was a tough one, lots of
combinations - now I know why I don't gamble. Your card abstraction
seems very complete, did it come from some place else? I did some of
the same, but realized I was getting too far afield for the quiz alone
and stopped myself (I can be accused of over engineering sometimes :slight_smile:

Patrick

Input:
As Ks Qs Js Ts 9s 8s
Ad Ks Qs Js Ts 9s Ac
Ts 9d 9s 3s 9h 9c 2s
3s 9d 9s 4s 9h 9c 2s
3s 9d 9s 4s 9h 9c 3d
3s 3d 2s 2c 2h 9c 4s
3s 3d Ts 2s 2h 9c 3h
8d 6d Ts 7d 5d Jd Kd
8d Qs Th 7h 9s Js Kd
Ad 2s 3h 4h 5s Js Kd
Js Ts 8c 7d 9s Td 4d
Js Ts 8c 7d 9s Td Tc
3s 3d Ts As 2h 9c 3h
3s 3d Ts As 2h 9c 2s
3s 3d Ts As 4h 9c 2s
8d 6s Th 7h 5s Js Kd

Output:
As Ks Qs Js Ts 9s 8s Royal Flush (winner)
Ks Qs Js Ts 9s Ad Ac Straight Flush
9h 9d 9c 9s 2s 3s Ts Full House *** should be 4 of a kind
9h 9d 9c 9s 2s 3s 4s Full House *** should be 4 of a kind
9h 9d 9c 9s 3s 3d 4s Full House *** should be 4 of a kind
2c 2h 2s 3s 3d 4s 9c Full House
3s 3d 3h 2s 2h 9c Ts Full House
8d 6d Kd Jd 5d 7d Ts Flush
Kd Qs Js Th 9s 8d 7h Straight
Ad Kd Js 5s 4h 3h 2s High Card *** Should be a straight Ace low
Js Td 9s 8c 7d 4d Straight
Tc Ts Td 7d 8c 9s Js Full House *** Should be a straight (this one
threw my first cut)
3s 3d 3h 2h 9c Ts As Full House *** Should be 3 of a kind
2s 2h 3d 3s 9c Ts As Two Pair
3s 3d 2s 4h 9c Ts As Pair
Kd Js Th 8d 7h 6s 5s High Card

I bet it is.

Michel.

···

On Sat, 19 Mar 2005 02:37:46 +0900, James Britt <jamesUNDERBARb@neurogami.com> wrote:

Which is going to be in Vegas, right David?

:slight_smile:

"Patrick Hurley" <phurley@gmail.com> tested:

Dave I am still looking over your code, but since I got your test data
last week here is some for you). This was a tough one, lots of
combinations - now I know why I don't gamble. Your card abstraction
seems very complete, did it come from some place else? I did some of
the same, but realized I was getting too far afield for the quiz alone
and stopped myself (I can be accused of over engineering sometimes :slight_smile:

Patrick

Input:
<snip reams of testing :))>

Thanks Pat, I will look at this later today when I get the time. I will add
some more tests than that, too, to try and trap another suspected bug: I
fear Two pairs are not evaluated correctly by highest pair then second pair.
These example output lines show this:
2s 2h 3d 3s 9c Ts As Two Pair # from your test
9c 9d Ks Kd 3c 6d Ah Two Pair # from the quiz definition
That's what you get for programming after bed-time.

I had already written card.rb for an implementation of blackjack
(blackjack.rb).

I haven't had a chance to look over any solutions in detail yet, but I saw
your "delta transform" and its use and am intrigued - what is that?

Cheers,
Dave

Michel Martens wrote:

Which is going to be in Vegas, right David?

:slight_smile:

I bet it is.

Oh, that might be a bad bet:

http://www.rubycentral.org/conference/

Oct. 14 - Oct. 16, 2005
(Facility TBA)
San Diego, CA

But still within driving distance for me. Nice.

James

···

On Sat, 19 Mar 2005 02:37:46 +0900, James Britt > <jamesUNDERBARb@neurogami.com> wrote:

--

http://catapult.rubyforge.com
http://orbjson.rubyforge.com
http://ooo4r.rubyforge.com
http://www.jamesbritt.com

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.

Patrick

···

On Thu, 24 Mar 2005 05:40:01 +0900, Dave Burt <dave@burt.id.au> wrote:

"Patrick Hurley" <phurley@gmail.com> tested:
> Dave I am still looking over your code, but since I got your test data
> last week here is some for you). This was a tough one, lots of
> combinations - now I know why I don't gamble. Your card abstraction
> seems very complete, did it come from some place else? I did some of
> the same, but realized I was getting too far afield for the quiz alone
> and stopped myself (I can be accused of over engineering sometimes :slight_smile:
>
> Patrick
>
> Input:
> <snip reams of testing :))>

Thanks Pat, I will look at this later today when I get the time. I will add
some more tests than that, too, to try and trap another suspected bug: I
fear Two pairs are not evaluated correctly by highest pair then second pair.
These example output lines show this:
2s 2h 3d 3s 9c Ts As Two Pair # from your test
9c 9d Ks Kd 3c 6d Ah Two Pair # from the quiz definition
That's what you get for programming after bed-time.

I had already written card.rb for an implementation of blackjack
(blackjack.rb).

I haven't had a chance to look over any solutions in detail yet, but I saw
your "delta transform" and its use and am intrigued - what is that?

Cheers,
Dave

I'd love to be able to say the same.

Michel

Hint: living in Mar del Plata, Argentina. Earning pesos instead of
dollars or euros.

···

On Sun, 20 Mar 2005 15:21:16 +0900, James Britt <jamesUNDERBARb@neurogami.com> wrote:

Oh, that might be a bad bet:

http://www.rubycentral.org/conference/

Oct. 14 - Oct. 16, 2005
(Facility TBA)
San Diego, CA

But still within driving distance for me. Nice.

James
--

http://www.ruby-doc.org