Determining a poker hand with two arrays - ruby

I want to create a simple multiplayer poker program in ruby, but I feel like I'm reinventing the wheel:
table = [card1, card2, card3, card4, card5]
mike = [card6, card7]
john = [card8, card9]
card6.face = "A"
card6.suit = "spades"
I'm having a hard time writing an algorithm to decide which of the possible hands each player has.
For example, in order to determine if a player was dealt a flush I wrote something like this:
together = table + hand
# Populate hash with number of times each suit was found
$suits.each do |suit|
matched[suit] = together.select{|card| card.suit == suit}.size
end
matched.each do |k,v|
if v == 5
puts "#{k} were seen five times, looks like a flush."
end
end
This doesn't seem very comprehensive (No way to tell if it's an Ace-high or a 6-high flush) nor very ruby-like.
Is there a more obvious way to determine hands in poker?

It's probably far from perfect, but I wrote some methods to detect poker hands to solve a project euler problem. Maybe it can give you some ideas ; full code is here: https://github.com/aherve/Euler/blob/master/pb54.rb
In a nutshell, Hand is defined by an array of Card, that respond to Card.value and Card.type:
def royal_flush?
return #cards if straight_flush? and #cards.map(&:value).max == Poker::values.max
end
def straight_flush?
return #cards if straight? and #cards.map(&:type).uniq.size == 1
end
def four_of_a_kind?
x_of_a_kind?(4)
end
def full_house?
return #hand if three_of_a_kind? and Hand.new(#cards - three_of_a_kind?).one_pair?
return nil
end
def flush?
return #cards if #cards.map(&:type).uniq.size == 1
end
def straight?
return #cards if (vs = #cards.map(&:value).sort) == (vs.min..vs.max).to_a
end
def three_of_a_kind?
x_of_a_kind?(3)
end
def two_pairs?
if (first_pair = one_pair?) and (second = Hand.new(#cards - one_pair?).one_pair?)
return first_pair + second
else
return false
end
end
def one_pair?
x_of_a_kind?(2)
end
def high_card?
#cards.sort_by{|c| c.value}.last
end
private
def x_of_a_kind?(x)
Poker::values.each do |v|
if (ary = #cards.select{|c| c.value == v}).size == x
return ary
end
end
return false
end
end

Related

Comparing values in a card game

I want to make a card game program that compares the values of cards assigned to player_value and dealer_value. If player_value is greater than dealer_value, it should display "you win". Here is my code:
def get_card (card)
type = case ((card-1)/13)
when 0 then "of clubs"
when 1 then "of diamonds"
when 2 then "of hearts"
when 3 then "of spades"
end
card = case (card%13)
when 0 then "king #{type}"
when 1 then "ace #{type}"
when 11 then "jack #{type}"
when 12 then "queen #{type}"
else card%13
end
"#{card} #{type}"
end
def deal_cards
total_cards = (1..52).to_a.shuffle
player_value = [total_cards.pop, total_cards.pop]
dealer_value = [total_cards.pop, total_cards.pop]
puts "Your cards are #{get_card(player_value[0]).to_s} and #{get_card(player_value[1]).to_s}"
puts "The dealer shows #{get_card(dealer_value[0])}"
if(dealer_value > player_value)
puts "You lose"
else (player_value > dealer_value)
puts "You win"
end
end
deal_cards()
It is not clear to me why this is not working, and I would appreciate any help with this.
I don't really understand why you assign an array to player_value and dealer_value, but you can't compare an array using > or <.
You have to retrieve the element from the array that you want to compare, and then use it in the if-else clause.
Also an else clause does not take another condition. An else will be used if all previous conditions fail. In your case, you should use elsif.
e.g.:
if(dealer_value[0] > player_value[0])
puts "You lose"
elsif (player_value[0] > dealer_value[0])
puts "You win"
end
Let me offer this object oriented solution to the same problem, since this is where Ruby really shines, and seeing it used in a procedural way really irks me. Object orientation adds a few more lines for scaffolding, but adds so much more in terms of legibility, reusability, and conceptual clarity.
We can represent the domain using three basic building blocks.
First, we need a Card object, able to hold some data (a rank and a suit) about itself, as well as the ability to represent itself as a string:
class Card
SUITS = [:clubs, :diamonds, :spades, :hearts]
RANKS = [:ace, *2..10, :jack, :queen, :king]
attr_reader :suit, :rank
def initialize(n)
#suit = (n - 1) / 13
#rank = (n - 1) % 13
end
def to_s
"#{ RANKS[#rank] } of #{ SUITS[#suit] }"
end
end
Next, we need a Hand object. Basically a collection of cards that can compare its strength to other hands, and also represent itself as a string:
class Hand
attr_reader :cards
def initialize(cards)
#cards = cards
end
def <=>(other_hand)
#cards.strength <=> other_hand.strength
end
def to_s
#cards.map(&:to_s).join(", ")
end
private
def strength
#cards.map(&:rank).inject(:+)
end
end
It is not clear from the question, how hand strength is determined. In this primitive implementation, it is simply the sum of the ranks of the cards in the hand.
Lastly, we need a Deck object. Something from which we can draw cards. We'll go with a standard 52-card deck:
class Deck
def initialize
#cards = (1..52).map { |n| Card.new(n) }.shuffle
end
def draw(number_of_cards = 1)
[*#cards.pop(number_of_cards)]
end
end
Now that we have our basic building blocks set up, using them is trivial:
def deal_cards
deck = Deck.new
player_hand = Hand.new(deck.draw(2))
dealer_hand = Hand.new(deck.draw(2))
puts "Your have: #{ player_hand }"
puts "The dealer has: #{ dealer_hand }"
if(player_hand > dealer_hand)
puts "You win!"
elsif(dealer_hand < player_hand)
puts "Aw. You lose."
else
puts "Woah! It's a tie!"
end
end
Notably this solution lacks error handling, for cases like passing an unknown n to the Card constructor, or drawing from an empty deck, but can easily be added in.

ruby: Rock Scissors Paper program. How to make algorithm function properly?

I'm creating a rock, scissors, paper program for my first program with ruby.
I'm thinking of using a hash called #wins to determine if a certain combination wins. If both hands are the same, the result is a Draw!. Otherwise, the result is Lose!.
I'm struggling to implement the algorithm to judge the results. How do I check if a given combination exists within the #wins hash to judge wether it's a win or now?
class Hand
attr_accessor :shape
##shapes = [:rock, :scissors, :paper]
def generate
#shape = ##shapes[rand(3)]
end
end
class Game
#wins = {rock: :scissors, scissors: :paper, paper: :rock}
def judge(p1, p2)
'Win!' if (a way to see if a given combination exists within a #wins hash) # Not working
'Draw!' if p1 == p2 # Not working
else 'Lose!'
end
end
player_hand = Hand.new
player_hand.shape = ARGV.join.to_sym
puts player_hand.shape # Debug
computer_hand = Hand.new
computer_hand.shape = computer_hand.generate
puts computer_hand.shape # Debug
game = Game.new
puts game.judge(player_hand.shape, computer_hand.shape)
def judge(p1, p2)
case
when #wins[p1] == p2 then "Win"
when #wins[p2] == p1 then "Lose"
else "Draw"
end
end

Using random number generator and percentages?

Is there a better way to write this code?
I want 47.37 percent of the time the number should be "odd". 47.37 percent of the time the number should be "even".
random_no = rand*100
if (random_no <= 47.37)
number = "odd"
elsif (random_no <= 94.74)
number = "even"
else
number = "other"
end
This may be a solution:
{'odd'=> 47.37, 'even'=> 94.74, 'other'=> 100}
.find{|key, value| rand* 100 <= value}.first
I like Vidaica's answer if you're going for a one liner. But why? I think your code is easier to understand. Alternatively you could save three lines by using a case statement:
number = case rand*100
when 0...47.37 then 'odd'
when 47.37...94.74 then 'even'
else 'other'
end
I also like Cary's comment, about using integers for performance. You could combine that with any of the above solutions.
Now that I know it's for a roulette game, I'd go about it differently, using rand(38) to pick a number and then seeing whether it's odd, even or 'other'. To illustrate an OO approach to this:
class Roulette
def initialize
spin
end
def spin
#number_showing = rand(38)
end
def odd_even?
if #number_showing == 0 || #number_showing == 37
return 'other'
elsif #number_showing.odd?
return 'odd'
else
return 'even'
end
end
def number_showing
if #number_showing == 37
return '00'
else
return #number_showing.to_s
end
end
end
wheel = Roulette.new
10.times do
wheel.spin
puts wheel.number_showing
puts wheel.odd_even?
puts
end

Ruby - elegantly call a method on the elements of two arrays

I am comparing arrays of objects and I have a method that determines whether or not two elements are equivalent. I want to to call this method on each pair of elements from both arrays, is there an elegant way of doing this to find a truth value (i.e true if all elements in each array were equivalent, false otherwise)
this is what I have currently:
c = false
self.children.zip(other.children).each do |s,o|
c = s.equiv o # I need a good way to store this result
break if not c
end
I was hoping I could do something like this:
c = self.children.zip(other.children).each{|s,o| s.equiv o}
Any help would be appreciated.
Well you have Enumerable#all?
c = self.children.zip(other.children).all? {|s,o| s.equiv o}
How about using all?
c = self.children.zip(other.children).all?{|s,o| s.equiv o}
A better solution is to just define == on your objects. Then you can use Array#== to do your work because it already does an all-pairs comparison.
Here's a simple example:
class Widget
attr_reader :name
def initialize(name)
#name = name
end
def ==(other)
#name == other.name
end
end
if $0 == __FILE__
require 'minitest/autorun'
describe 'widget arrays' do
let(:some_widgets) { %w(foo bar baz).map { |name| Widget.new(name) } }
let(:diff_widgets) { %w(bar baz spam).map { |name| Widget.new(name) } }
it 'returns true if the widget arrays are the same' do
(some_widgets == some_widgets).must_equal true
end
it 'returns false if the widget arrays are different' do
(some_widgets == diff_widgets).must_equal false
end
end
end
You just call some_widgets == my_other_widgets to compare each element.
I think if you replace each by map, c will be the array you're looking for. I can't be 100% sure, because I can't test right away, and I know there is some issues with zip.

Refactoring respond_to? call in if-elsif-else condition

I have the following method and want to make it more readable:
def value_format(value)
if value.respond_to? :to_actor
value.to_actor
elsif value.respond_to? :to_subject
value.to_subject
elsif value.respond_to? :to_json
value.to_json
elsif value.respond_to? :to_hash
value.to_hash
else
value.inspect
end
end
This is my solution. What do you think?
def value_format(value)
methods = [:to_actor, :to_subject, :to_json, :to_hash, :inspect]
value.send(methods.find_all { |m| m if value.respond_to? m }.first)
end
Your solution looks fine, but you might as well use find instead of find_all:
METHODS = [:to_actor, :to_subject, :to_json, :to_hash, :inspect]
def value_format(value)
value.send(METHODS.find { |m| value.respond_to? m })
end
Using a constant has the advantage of not creating a new array every time value_format is ran.
Seems there's a pretty simple optimization to your solution:
def value_format(value)
methods = [:to_actor, :to_subject, :to_json, :to_hash]
value.send(methods.find(:inspect) { |m| value.respond_to? m })
end
The facets gem provides an elegant solution (I think) to this problem. It combines the two steps of checking if an object responds to a method and actually calling that method into a single step.
So your example could be rewritten as this:
require 'facets/kernel/respond'
def value_format(v)
v.respond.to_actor || v.respond.to_subject || v.respond.to_json || v.respond.to_hash || v.respond.inspect
end
Note that this method only works if it is safe to assume that none of these methods are going to return nil or false (because respond returns nil if the object doesn't respond, that is what allows us to chain it together with a bunch of ors).
Since all of the methods you listed should return strings, I believe this approach would work fine in your example.
Documentation:
# Like #respond_to? but returns the result of the call
# if it does indeed respond.
#
# class RespondExample
# def f; "f"; end
# end
#
# x = RespondExample.new
# x.respond(:f) #=> "f"
# x.respond(:g) #=> nil
#
# or
#
# x.respond.f #=> "f"
# x.respond.g #=> nil

Resources