This was a fun one
I'm looking forward to seeing other solutions.
Regs,
Derek
holdem.rb (10.5 KB)
I will concur this one was fun, although it took me more like 4 hours
than the one I planned on spending on it. I think this a complete
solution. There is no smarts in the folding logic, but the player
class is the place to make it smarter. It displays each round
(unranked, but with current "score/status" and then when the game is
over it rearranges the hands to display them based upon their best
hand and ranks them from best to worst (folded hands are just randomly
layed out at the bottom.
Thanks as always for the quiz.
Patrick
----------------------------------------------------------------------------------
#!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
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
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
聽聽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
聽聽def =~ (re)
聽聽聽聽re.match(@hand.join(' '))
聽聽end
聽聽def royal_flush?
聽聽聽聽if (md = (by_suit =~ /A(.) K\1 Q\1 J\1 T\1/))
聽聽聽聽聽聽[[10], (md[0] + ' ' + md.pre_match + ' ' +
md.post_match).gsub(/\s+/, ' ')]
聽聽聽聽else
聽聽聽聽聽聽false
聽聽聽聽end
聽聽end
聽聽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
聽聽聽聽聽聽delta = 'x' if (delta > 9 || delta < 0) # does not really
matter for my needs
聽聽聽聽聽聽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]
聽聽end
聽聽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+/, ' ')
聽聽聽聽arranged_hand.gsub(/\s+$/, '') # careful to use gsub as gsub!
can return nil here
聽聽end
聽聽def straight_flush?
聽聽聽聽if (md = (/.(.)(.) 1.\2 1.\2 1.\2 1.\2/.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
聽聽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
聽聽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?
聽聽聽聽if (md = (/.(.). 1.. 1.. 1.. 1../.match(delta_transform)))
聽聽聽聽聽聽high_card = Card::face_value(md[1])
聽聽聽聽聽聽arranged_hand = fix_low_ace_display(md[0] + ' ' + md.pre_match +
' ' + md.post_match)
聽聽聽聽聽聽[[5, high_card], arranged_hand]
聽聽聽聽else
聽聽聽聽聽聽false
聽聽聽聽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)/)
聽聽聽聽聽聽# (' ' + md.pre_match + md.post_match).match(/^\s+(\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
聽聽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
聽聽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
class Player
聽聽def initialize(name, deck)
聽聽聽聽@name = name
聽聽聽聽@hand = Hand.new
聽聽聽聽2.times { @hand.take_card(deck.deal()) }
聽聽聽聽@folded = false
聽聽end
聽聽def folded?
聽聽聽聽@folded
聽聽end
聽聽def take_card(card)
聽聽聽聽@hand.take_card(card)
聽聽end
聽聽def fold?(players)
聽聽聽聽unless (folded?)
聽聽聽聽聽聽if (players)
聽聽聽聽聽聽聽聽folded_count = players.inject(0) { |count, p| (p.folded?) ?
count + 1 : count }
聽聽聽聽聽聽聽聽@folded = rand(players.size - folded_count) > (folded_count)
聽聽聽聽聽聽else
聽聽聽聽聽聽聽聽@folded = (rand(10) <= 1)
聽聽聽聽聽聽end
聽聽聽聽end
聽聽聽聽folded?
聽聽end
聽聽def score
聽聽聽聽(folded?) ? [[0]] : @hand.score
聽聽end
聽聽def arranged_hand
聽聽聽聽@name + ' ' +
聽聽聽聽if (folded?)
聽聽聽聽聽聽@hand.just_cards + ' (folded)'
聽聽聽聽else
聽聽聽聽聽聽@hand.arranged_hand
聽聽聽聽end
聽聽end
聽聽def to_s
聽聽聽聽@name + ' ' +
聽聽聽聽if (folded?)
聽聽聽聽聽聽@hand.just_cards + ' (folded)'
聽聽聽聽else
聽聽聽聽聽聽@hand.to_s
聽聽聽聽end
聽聽end
聽聽def <=>(other)
聽聽聽聽score <=> other.score
聽聽end
end
class TexasHoldEm
聽聽def initialize(player_count)
聽聽聽聽@deck = Deck.new
聽聽聽聽@common_cards = Array.new(5) { @deck.deal }
聽聽聽聽@players = (1..player_count).inject([]) { |players, num| players
<< Player.new("Player #{num}", @deck) }
聽聽end
聽聽def game_over?
聽聽聽聽@common_cards.empty?
聽聽end
聽聽def play_round
聽聽聽聽unless game_over?
聽聽聽聽聽聽card = @common_cards.pop
聽聽聽聽聽聽@players.each do |p|
聽聽聽聽聽聽聽聽unless p.fold?(@players)
聽聽聽聽聽聽聽聽聽聽p.take_card(card)
聽聽聽聽聽聽聽聽end
聽聽聽聽聽聽end
聽聽聽聽end
聽聽聽聽game_over?
聽聽end
聽聽def rank_players!
聽聽聽聽@players = @players.sort.reverse
聽聽end
聽聽def arranged_players
聽聽聽聽@players.inject('') { |result, player| result +=
player.arranged_hand + "\n" }
聽聽end
聽聽def to_s
聽聽聽聽@players.join("\n")
聽聽end
end
if __FILE__ == $0
聽聽srand
聽聽game = TexasHoldEm.new(5)
聽聽round = 1
聽聽until game.game_over?
聽聽聽聽puts "\nRound #{round}"
聽聽聽聽puts game
聽聽聽聽game.play_round
聽聽聽聽round += 1
聽聽end
聽聽puts "\nRound #{round}"
聽聽puts game
聽聽game.rank_players!
聽聽puts "\nFinal Ranking"
聽聽puts game.arranged_players
end
Find below a very slightly modified version of my quiz submission
where none of the lines exceed 72 charaters in width. I have become
"lazy" in that my editors on my 20" LCDs have no difficulty with lines
exceeding 100 chars. I have also sometime since I got those new
monitors started printing code in landscape.
Alas I have forgotton other people and so to make amends here is the
reformatted quiz submission.
Grinning
Patrick
----------------------------------------------------------------------------------------------------------------
#!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
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
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
聽聽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
聽聽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
聽聽def royal_flush?
聽聽聽聽if (md = (by_suit =~ /A(.) K\1 Q\1 J\1 T\1/))
聽聽聽聽聽聽[[10], arrange_hand(md)]
聽聽聽聽else
聽聽聽聽聽聽false
聽聽聽聽end
聽聽end
聽聽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]
聽聽end
聽聽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
聽聽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
聽聽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?
聽聽聽聽if (md = (/.(.). 1.. 1.. 1.. 1../.match(delta_transform)))
聽聽聽聽聽聽high_card = Card::face_value(md[1])
聽聽聽聽聽聽arranged_hand = fix_low_ace_display(md[0] + ' ' +
聽聽聽聽聽聽聽聽聽聽md.pre_match + ' ' + md.post_match)
聽聽聽聽聽聽[[5, high_card], arranged_hand]
聽聽聽聽else
聽聽聽聽聽聽false
聽聽聽聽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
聽聽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
聽聽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
class Player
聽聽def initialize(name, deck)
聽聽聽聽@name = name
聽聽聽聽@hand = Hand.new
聽聽聽聽2.times { @hand.take_card(deck.deal()) }
聽聽聽聽@folded = false
聽聽end
聽聽def folded?
聽聽聽聽@folded
聽聽end
聽聽def take_card(card)
聽聽聽聽@hand.take_card(card)
聽聽end
聽聽def fold?(players)
聽聽聽聽unless (folded?)
聽聽聽聽聽聽if (players)
聽聽聽聽聽聽聽聽folded_count = players.inject(0) { |count, p|
聽聽聽聽聽聽聽聽聽聽(p.folded?) ? count + 1 : count
聽聽聽聽聽聽聽聽}
聽聽聽聽聽聽聽聽@folded = rand(players.size - folded_count) > (folded_count)
聽聽聽聽聽聽else
聽聽聽聽聽聽聽聽@folded = (rand(10) <= 1)
聽聽聽聽聽聽end
聽聽聽聽end
聽聽聽聽folded?
聽聽end
聽聽def score
聽聽聽聽(folded?) ? [[0]] : @hand.score
聽聽end
聽聽def arranged_hand
聽聽聽聽@name + ' ' +
聽聽聽聽if (folded?)
聽聽聽聽聽聽@hand.just_cards + ' (folded)'
聽聽聽聽else
聽聽聽聽聽聽@hand.arranged_hand
聽聽聽聽end
聽聽end
聽聽def to_s
聽聽聽聽@name + ' ' +
聽聽聽聽if (folded?)
聽聽聽聽聽聽@hand.just_cards + ' (folded)'
聽聽聽聽else
聽聽聽聽聽聽@hand.to_s
聽聽聽聽end
聽聽end
聽聽def <=>(other)
聽聽聽聽score <=> other.score
聽聽end
end
class TexasHoldEm
聽聽def initialize(player_count)
聽聽聽聽@deck = Deck.new
聽聽聽聽@common_cards = Array.new(5) { @deck.deal }
聽聽聽聽@players = (1..player_count).inject([]) { |players, num|
聽聽聽聽聽聽players << Player.new("Player #{num}", @deck)
聽聽聽聽}
聽聽end
聽聽def game_over?
聽聽聽聽@common_cards.empty?
聽聽end
聽聽def play_round
聽聽聽聽unless game_over?
聽聽聽聽聽聽card = @common_cards.pop
聽聽聽聽聽聽@players.each do |p|
聽聽聽聽聽聽聽聽unless p.fold?(@players)
聽聽聽聽聽聽聽聽聽聽p.take_card(card)
聽聽聽聽聽聽聽聽end
聽聽聽聽聽聽end
聽聽聽聽end
聽聽聽聽game_over?
聽聽end
聽聽def rank_players!
聽聽聽聽@players = @players.sort.reverse
聽聽end
聽聽def arranged_players
聽聽聽聽@players.inject('') { |result, player|
聽聽聽聽聽聽result += player.arranged_hand + "\n"
聽聽聽聽}
聽聽end
聽聽def to_s
聽聽聽聽@players.join("\n")
聽聽end
end
if __FILE__ == $0
聽聽srand
聽聽game = TexasHoldEm.new(5)
聽聽round = 1
聽聽until game.game_over?
聽聽聽聽puts "\nRound #{round}"
聽聽聽聽puts game
聽聽聽聽game.play_round
聽聽聽聽round += 1
聽聽end
聽聽puts "\nRound #{round}"
聽聽puts game
聽聽game.rank_players!
聽聽puts "\nFinal Ranking"
聽聽puts game.arranged_players
end
[Patrick Hurley <phurley@gmail.com>, 2005-03-23 03.39 CET]
Find below a very slightly modified version of my quiz submission
[...]
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")
Why not just delete the low aces (gsub!(/L./, ""))? What am I missing?
BTW, I liked how you detected straights using the delta transform. Clever
idea (for me at least :).
# cleanup white space
arranged_hand.gsub!(/\s+/, ' ')
# careful to use gsub as gsub! can return nil here
arranged_hand.gsub(/\s+$/, '')
end
Thanks - I need to keep the low aces so that they appear in the
correct position in the rearranged hand - if I had just deleted them,
straights with the aces low would have been displayed with the ace out
of order.
I liked the delta transform as well, of course it was the cause of the
bug (delta 0 when pairs were encountered) - if fixed it by shuffling
the delta zeros (excluding the first card) to the back of the hand.
Patrick
On Wed, 23 Mar 2005 23:02:00 +0900, Carlos <angus@quovadis.com.ar> wrote:
[Patrick Hurley <phurley@gmail.com>, 2005-03-23 03.39 CET]
> Find below a very slightly modified version of my quiz submission
[...]
> 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")Why not just delete the low aces (gsub!(/L./, ""))? What am I missing?
BTW, I liked how you detected straights using the delta transform. Clever
idea (for me at least :).>
> # cleanup white space
> arranged_hand.gsub!(/\s+/, ' ')
> # careful to use gsub as gsub! can return nil here
> arranged_hand.gsub(/\s+$/, '')
> end
And since I never saw that version of the program hit the list, here it is:
#!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
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
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
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
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
def royal_flush?
if (md = (by_suit =~ /A(.) K\1 Q\1 J\1 T\1/))
[[10], arrange_hand(md)]
else
false
end
end
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
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
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
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
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
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
class Player
def initialize(name, deck)
@name = name
@hand = Hand.new
2.times { @hand.take_card(deck.deal()) }
@folded = false
end
def folded?
@folded
end
def take_card(card)
@hand.take_card(card)
end
def fold?(players)
unless (folded?)
if (players)
folded_count = players.inject(0) { |count, p|
(p.folded?) ? count + 1 : count
}
@folded = rand(players.size - folded_count) > (folded_count)
else
@folded = (rand(10) <= 1)
end
end
folded?
end
def score
(folded?) ? [[0]] : @hand.score
end
def arranged_hand
@name + ' ' +
if (folded?)
@hand.just_cards + ' (folded)'
else
@hand.arranged_hand
end
end
def to_s
@name + ' ' +
if (folded?)
@hand.just_cards + ' (folded)'
else
@hand.to_s
end
end
def <=>(other)
score <=> other.score
end
end
class TexasHoldEm
def initialize(player_count)
@deck = Deck.new
@common_cards = Array.new(5) { @deck.deal }
@players = (1..player_count).inject() { |players, num|
players << Player.new("Player #{num}", @deck)
}
end
def game_over?
@common_cards.empty?
end
def play_round
unless game_over?
card = @common_cards.pop
@players.each do |p|
unless p.fold?(@players)
p.take_card(card)
end
end
end
game_over?
end
def rank_players!
@players = @players.sort.reverse
end
def arranged_players
@players.inject('') { |result, player|
result += player.arranged_hand + "\n"
}
end
def to_s
@players.join("\n")
end
end
if __FILE__ == $0
srand
game = TexasHoldEm.new(5)
round = 1
until game.game_over?
puts "\nRound #{round}"
puts game
game.play_round
round += 1
end
puts "\nRound #{round}"
puts game
game.rank_players!
puts "\nFinal Ranking"
puts game.arranged_players
end
__END__
James Edward Gray II
On Mar 23, 2005, at 8:20 AM, Patrick Hurley wrote:
I liked the delta transform as well, of course it was the cause of the
bug (delta 0 when pairs were encountered) - if fixed it by shuffling
the delta zeros (excluding the first card) to the back of the hand.