unleashed
unleashed

Reputation: 21

Better way of initializing a deck of cards

Is there an easier way of doing this instead of inserting each element into the array manually

stack_of_cards << Card.new("A", "Spades", 1)
stack_of_cards << Card.new("2", "Spades", 2)
stack_of_cards << Card.new("3", "Spades", 3)
stack_of_cards << Card.new("4", "Spades", 4)
stack_of_cards << Card.new("5", "Spades", 5)
stack_of_cards << Card.new("6", "Spades", 6)
stack_of_cards << Card.new("7", "Spades", 7)
stack_of_cards << Card.new("8", "Spades", 8)
stack_of_cards << Card.new("9", "Spades", 9)
stack_of_cards << Card.new("10", "Spades", 10)
stack_of_cards << Card.new("J", "Spades", 11)
stack_of_cards << Card.new("Q", "Spades", 12)
stack_of_cards << Card.new("K", "Spades", 13)

stack_of_cards << Card.new("A", "Hearts", 1)
stack_of_cards << Card.new("2", "Hearts", 2)
stack_of_cards << Card.new("3", "Hearts", 3)
stack_of_cards << Card.new("4", "Hearts", 4)
stack_of_cards << Card.new("5", "Hearts", 5)
stack_of_cards << Card.new("6", "Hearts", 6)
stack_of_cards << Card.new("7", "Hearts", 7)
stack_of_cards << Card.new("8", "Hearts", 8)
stack_of_cards << Card.new("9", "Hearts", 9)
stack_of_cards << Card.new("10", "Hearts", 10)
stack_of_cards << Card.new("J", "Hearts", 11)
stack_of_cards << Card.new("Q", "Hearts", 12)
stack_of_cards << Card.new("K", "Hearts", 13)

stack_of_cards << Card.new("A", "Diamonds", 1)
stack_of_cards << Card.new("2", "Diamonds", 2)
stack_of_cards << Card.new("3", "Diamonds", 3)
stack_of_cards << Card.new("4", "Diamonds", 4)
stack_of_cards << Card.new("5", "Diamonds", 5)
stack_of_cards << Card.new("6", "Diamonds", 6)
stack_of_cards << Card.new("7", "Diamonds", 7)
stack_of_cards << Card.new("8", "Diamonds", 8)
stack_of_cards << Card.new("9", "Diamonds", 9)
stack_of_cards << Card.new("10", "Diamonds", 10)
stack_of_cards << Card.new("J", "Diamonds", 11)
stack_of_cards << Card.new("Q", "Diamonds", 12)
stack_of_cards << Card.new("K", "Diamonds", 13)

stack_of_cards << Card.new("A", "Clubs", 1)
stack_of_cards << Card.new("2", "Clubs", 2)
stack_of_cards << Card.new("3", "Clubs", 3)
stack_of_cards << Card.new("4", "Clubs", 4)
stack_of_cards << Card.new("5", "Clubs", 5)
stack_of_cards << Card.new("6", "Clubs", 6)
stack_of_cards << Card.new("7", "Clubs", 7)
stack_of_cards << Card.new("8", "Clubs", 8)
stack_of_cards << Card.new("9", "Clubs", 9)
stack_of_cards << Card.new("10", "Clubs", 10)
stack_of_cards << Card.new("J", "Clubs", 11)
stack_of_cards << Card.new("Q", "Clubs", 12)
stack_of_cards << Card.new("K", "Clubs", 13)

Upvotes: 2

Views: 6036

Answers (7)

ckib16
ckib16

Reputation: 383

Here are two ways to make a card deck in Ruby.

1. An array of arrays

...easier, but may be tougher if you need to compare cards against each other (courtesy code project from Tealeaf Academy)

values = ["A", 2, 3, 4, 5, 6, 7, 8, 9, 10, "J", "Q", "K" ]
suits = [ "hearts", "spades", "clubs", "diamonds" ]
deck = values.product(suits)

=> [["A", "hearts"], ["A", "spades"], ["A", "clubs"], ["A", "diamonds"] #etc...

You can also add on .shuffle or .shuffle! to the deck

deck = values.product(suits).shuffle

=> [[9, "diamonds"], [2, "clubs"], [7, "spades"], [4, "clubs"] #etc...

2. An array of hashes with numerical scores associated with each card

...so you can easily sort or compare cards via "scores" (courtesy @amaseda at General Assembly DC)

def deck_o_cards
  values = [2, 3, 4, 5, 6, 7, 8, 9, 10, 'J', 'Q', 'K', 'A']
  suits = ['hearts', 'diamonds', 'clubs', 'spades']
  deck = []

  values.each_with_index do |v, i|
    suits.each do |s|
      deck.push({
        score: i,
        value: v,
        suit: s,
      })
    end
  end

  return deck.shuffle
end

=> [{:score=>8, :value=>10, :suit=>"hearts"}, {:score=>4, :value=>6, :suit=>"diamonds"}, #etc...

Upvotes: 0

thebugfinder
thebugfinder

Reputation: 334

Card = Struct.new(:name, :suit,:number) 
stack_of_cards = []
%w{'Spades Hearts Diamonds Clubs'}.each do |suit|
    %w{'A 2 3 4 5 6 7 8 9 10 J Q K'}.each_with_index do |name, i|
        stack_of_cards << Card.new(name, suit, i+1) 
    end
end
p stack_of_cards

Upvotes: 0

michaelmichael
michaelmichael

Reputation: 14125

David A. Black's The Well Grounded Rubyist uses deck initialization as a way to demonstrate the cycle method. I think the resulting code is clever, and very simple:

class Card 
  SUITS = %w{ clubs diamonds hearts spades } 
  RANKS=%w{2345678910JQKA}
  class Deck 
    attr_reader :cards
    def initialize(n=1) 
      @cards = [] SUITS.cycle(n) do |s|
        RANKS.cycle(1) do |r| @cards << "#{r} of #{s}"
        end
      end
    end 
  end
end

Also, the Ruby Quiz #1: The Solitaire Cipher involved using a deck of cards to encode a message. Check out the solutions. You'll see a few different ways used to tackle this problem.

Upvotes: 0

J&#246;rg W Mittag
J&#246;rg W Mittag

Reputation: 369536

First off: why do you represent the rank and the value of a card separately? Is there ever an instance where, say, a Jack does not have the value 11? For example, why do you have

Card.new("7", "Spades", 7)

instead of just

Card.new(7, "Spades")

and is there ever an instance where you would have

Card.new("7", "Spades", 42)

If not, then those two should be packaged together into an object.

Also, why are the suits represented as strings and not as Suits or at least as symbols?

I'd probably do something like this:

Rank = Struct.new(:rank, :value) do
  def to_s; rank end
  alias_method :inspect, :to_s
end

Card = Struct.new(:rank, :suit) do
  def to_s; "#{rank} of #{suit.capitalize}" end
  alias_method :inspect, :to_s
end

ranks = %w[Ace 2 3 4 5 6 7 8 9 10 Jack Queen King].map.with_index {|rank, value|
  Rank.new(rank, value + 1)
}

suits = [:spades, :hearts, :diamonds, :clubs]

deck = suits.product(ranks).map {|suit, rank| Card.new(rank, suit) }

Upvotes: 1

khelll
khelll

Reputation: 24010

Building on Mark Rushakoff solution and using Ruby 1.9

Card = Struct.new(:rank, :suit,:rank_id) 
ranks = %w{A 2 3 4 5 6 7 8 9 10 J Q K}
suits = %w{Spades Hearts Diamonds Clubs}
stack_of_cards = suits.each_with_object([]) do |suit,res|
  ranks.size.times do |i|
    res << Card.new(ranks[i], suit,i + 1)
  end
end
puts stack_of_cards.inspect

Upvotes: 0

Mark Rushakoff
Mark Rushakoff

Reputation: 258358

Just loop over both ranks and suits.

ranks = %w{A 2 3 4 5 6 7 8 9 10 J Q K}
suits = %w{Spades Hearts Diamonds Clubs}
suits.each do |suit|
  ranks.size.times do |i|
    stack_of_cards << Card.new( ranks[i], suit, i+1 )
  end
end

Upvotes: 6

sepp2k
sepp2k

Reputation: 370357

Yes, there is: Create an array of faces and an array of suits then iterate over them in a nested loop. Also change the Card class so that you don't need to specify the face as a string an integer as that is redundant. It's most convenient if you only need to specify the int parameter.

This way the code would look like this:

faces = 1..13
suits = %w(Spades Hearts Diamonds Clubs)
cards = suits.flat_map do |suit|
  faces.map |face_int_value|
    Card.new(suit, face_int_value)
  end
end

Or in ruby before 1.9.2:

faces = 1..13
suits = %w(Spades Hearts Diamonds Clubs)
cards = suits.map do |suit|
  faces.map |face_int_value|
    Card.new(suit, face_int_value)
  end
end.flatten

Upvotes: 2

Related Questions