Implement and test Card and Deck classes in Ruby - ruby

I am having a little trouble getting my code to run and have been at it for at least 4 hours...I can't seem to figure it out. BTW I am a newb at programming.
This is the UML diagram for the card/deck
http://imgur.com/lBJw2z0
class Card
#Cards rank from lowest to highest
VALUE = %w(2 3 4 5 6 7 8 9 10 J Q K A)
SUITS = %w(C D H S)
#(Club Diamond Heart Spade)
def initialize(the_rank, the_suit)
[#rank = the_rank]
[#suit = the_suit]
[#symbols = [nil, nil, '2', '3', '4', '5', '6', '7',
'8', '9', '10', 'J', 'Q', 'K', 'A']
end
def rank
[return #symbols[#rank]]
end
def suit
return #suit
end
def to_s
"#{rank()}#{suit()}"
end
end
#double loop for Deck#initialize
#cards = [ ]
for rank in 2..14
for suit in ['C', 'D', 'H', 'S']
# create a new card with the specified rank
# and suit and append it to the array.
end
end
suits.each do |suit|
(ranks.size).times do |i|
#cards.push(Card.new(ranks[i], suit,(i+1)))
end
end
#Remove a card from the top
def deal
[#cards.pop()](1)
end
#Add card to the bottom of the deck
def add_to_bottom(the_card)
#cards.insert(0, the_card)
end
#Add card to the top of the deck
def add_to_top(the_card)
#cards << the_card
end
#Shuffle the Card objects in the deck
def shuffle!
#cards.shuffle!
end
def count()
#cards.count()
end
def empty?
#cards.length == 0
end
def to_s
string = ""
#cards.each do |card|
string += card.to_s + " "
end
end
def cards
#cards
end
end

I haven't tested this very thoroughly, but it basically implements the UML diagram you linked to:
class Deck
def initialize
#ranks = %w(2 3 4 5 6 7 8 9 10 J Q K A)
#suits = %w(Clubs Diamonds Hearts Spades)
#cards = []
#ranks.each do |rank|
#suits.each do |suit|
#cards << Card.new(rank, suit)
end
end
end
def deal
#cards.shift
end
def add_to_bottom(card)
#cards.unshift(card)
end
def add_to_top(card)
#cards << card
end
def count
#cards.count
end
def empty?
#cards.empty?
end
def shuffle!
#cards.shuffle
end
def to_s
result = ''
#cards.each do |card|
result = result + card.to_s + "\n"
end
return result
end
end
class Card
attr_reader :rank, :suit, :color
def initialize(rank, suit)
#rank = rank
#suit = suit
if #rank == 'Clubs' || #rank == 'Spades'
#color = 'black'
else
#color = 'red'
end
end
def to_s
"Card: #{#color} #{#rank} of #{#suit}"
end
end
# Run it, and try some stuff...
my_deck = Deck.new
puts my_deck.to_s
my_deck.deal
my_deck.count
my_deck.shuffle!
puts my_deck.to_s
my_deck.deal
my_deck.count

Now I am trying to figure how the testing method. I have the first working
d = Deck.new
d.cards.each do |card|
puts "#{card.rank} #{card.suit}"
end
And the second method that needs to test:
tests both the Card and Deck classes using the unit test framework with assert_equal methods. Write unit tests for all methods in the Card class, but you only have to test these methods in the Deck class: new, deal, add_to_bottom, add_to_top, count, empty?

Related

Undefined function make_card Ruby

I am doing a practice problem black jack card game in ruby, references I am using are
https://medium.com/quick-code/using-ruby-classes-to-implement-a-game-of-blackjack-535a786c417
I am getting error that says undefined method "make_card"
Code for my Deck Class
class Deck
def initialize
#faces = [*(2..10),'Jack','Queen','King','Ace']
#suits = ['clubs','spades','hearts','diamonds']
#cards = []
#faces.each do |face|
if face.class == "Integer"
value = face
elsif face == 'Ace'
value = 11
else
value = 10
end
#suits.each do |suit|
#cards << Card.new(face,suit,value)
end
end
#cards.shuffle!
end
def make_card(participant)
fresh_card = Card.new(face,suit,value)
participant.turn << fresh_card
participant.total = participant.total + fresh_card.value
end
def deal(number,participant)
number.times{#cards.shift.make_card(participant)}
end
end
As both methods are in same class I am still getting that error
Solved it by placing method in Card class and accessing it via its instance variable
class Card
attr_accessor :face, :suit, :value
def initialize(face,suit,value)
#face = face
#suit = suit
#value = value
end
def make_card(participant)
fresh_card = Card.new(face,suit,value)
participant.turn << fresh_card
participant.total = participant.total + fresh_card.value
end
end
class Deck
def initialize
#faces = [*(2..10),'Jack','Queen','King','Ace']
#suits = ['clubs','spades','hearts','diamonds']
#cards = []
#faces.each do |face|
if face.class == Integer
value = face
elsif face == 'Ace'
value = 11
else
value = 10
end
#suits.each do |suit|
#cards << Card.new(face,suit,value)
end
end
#cards.shuffle!
end
def deal(number,participant)
number.times{#cards.shift.make_card(participant)}
end
end

Deck of cards that deals a number of cards to a number of players

I built a deck of cards:
class Card
attr_accessor :rank, :suit
def initialize(rank, suit)
#rank = rank
#suit = suit
end
def output_card
puts "#{self.rank} of #{self.suit}"
end
end
class Deck
def initialize
#cards = []
#ranks = ["Ace", 2, 3, 4, 5, 6, 7, 8, 9, 10, "Jack", "Queen", "King"]
#suits = [:hearts, :spades, :diamonds, :clubs]
#suits.each do |suit|
#ranks.each do |rank|
#cards << Card.new(rank, suit)
end
end
end
def shuffle
#cards.shuffle!
end
def deal
#cards.shift
end
def output_deck
#cards.each do |card|
card.output_card
end
end
end
deck = Deck.new
deck.shuffle
deck.deal
deck.output_deck
puts "Show top card:"
deck.deal.output_card
I am struggling to add Dealer class to deal a specified number of cards to a specified number of players.
If anyone would explain that, I would greatly appreciate it.
class Player
attr_accessor :name, :cards
def initialize(name)
#name = name
#cards = []
end
end
class HoldEmPoker
def cards_per_player
2
end
end
class Dealer
def initialize(deck, game)
#deck = deck
#game = game
end
def deal_to(player)
#game.cards_per_player.times do
player.cards << #deck.deal
end
end
end
p1 = Player.new("Negreanu")
p2 = Player.new("Ivey")
p3 = Player.new("Hellmuth")
players = [p1, p2, p3]
deck = Deck.new
deck.shuffle
game = HoldEmPoker.new
dealer = Dealer.new(deck, game)
players.each { |p| dealer.deal_to(p) }
p1.cards #=> an array with two Card objects
If you want, you can add a deal method to Dealer class
def deal(players)
players.each do |player|
#game.cards_per_player.times do
player.cards << #deck.deal
end
end
end
players = [...]
dealer.deal(players)

A nil class when trying to initialize a deck of cards

The following code is resulting in nil and I can't figure out why. Is there something wrong with my initialization?
class Card
VALUES = %w(2 3 4 5 6 7 8 9 10 J Q K A)
SUITS = %w(S H D C)
def initialize(suit, value)
#suit = suit
#value = value
end
end
class Deck
attr_accessor :cards
def initialize
#cards = []
Card::SUITS.each do |suit|
Card::VALUES.each do |value|
#cards << Card.new(suit, value)
end
end
end
end
Deck.new
p #cards
#cards is not known outside the object. Outside the class Deck it is a instance variable of the top-level scope in Ruby.
You have to use the accessor method to get the content:
class Card
VALUES = %w(2 3 4 5 6 7 8 9 10 J Q K A)
SUITS = %w(S H D C)
def initialize(suit, value)
#suit = suit
#value = value
end
end
class Deck
attr_accessor :cards
def initialize
#cards = []
Card::SUITS.each do |suit|
Card::VALUES.each do |value|
#cards << Card.new(suit, value)
end
end
end
end
deck = Deck.new #<--- Store object in a variable
p deck.cards #<--- Use accessor
or just:
my_deck = Deck.new
p my_deck.cards
In short, instance variables can only be seen by other methods from within the same class. I believe what you're trying to do is:
new_deck = Deck.new
p new_deck.cards
Calling the cards method on new_deck returns #cards.
You create a new object Deck.new, but you don't print the value of its cards - you print a #cards instance variable which in this context is nil.
You probably wanted something like p Deck.new.cards.
Currently your output for #cards array is difficult to read and contains object info. I thought I'd offer an alternative I've just conjoured up, hope it helps:
class Deck
attr_writer :suits, :values
attr_accessor :deck
def initialize
suits
values
generate_deck
shuffle
end
def generate_deck
#deck = []
#suits.each do |suit|
#values.each { |value| #deck << [suit, value] }
end
end
def suits
#suits = ['Clubs', 'Diamonds', 'Hearts', 'Spades' ]
end
def values
#values = ('2'..'10').to_a + ['J','Q','K','A']
end
#just in case you want to shuffle your deck
def shuffle
#deck.shuffle!
end
end
require 'pp' #this makes the output prettier
new_deck = Deck.new
pp new_deck.deck #calls your current deck so you can see it
Output example:
$ ruby yourfilename.rb
[["Hearts", "K"],
["Spades", "5"],
["Clubs", "7"],
#code omitted... (the rest of your cards would be here)
["Clubs", "K"],
["Hearts", "5"],
["Diamonds", "J"],
["Hearts", "7"]]

Calling a method from a method in another class

It's a fairly well know one. Determining the rank of a poker hand. I created the following classes: Card:
class Card
attr_accessor :suite, :rank, :value
def initialize(suite, rank, value)
#suite = suite
#rank = rank
#value = value
end
def to_s
puts "#{#value}, #{#suite}, #{#rank}"
end
end
Deck:
class Deck
def initialize()
#cardsInDeck = 52
#deck = Array.new()
end
def add_card(card)
#deck.push(card)
end
def deck_size
#deck.length
end
def to_s
#deck.each do |card|
"#{card.rank}, #{card.suite}"
end
end
def shuffle_cards
#deck.shuffle!
end
def deal_cards
#Here I create a new hand object, and when popping cards from the deck
# stack I insert the card into the hand. However, when I want to print
# the cards added to the hand I get the following error:
# : undefined method `each' for #<Hand:0x007fa51c02fd50> (NoMethodError)from
# driver.rb:36:in `<main>'
#hand = Hand.new
for i in 0..51 do
card = #deck.pop
#cardsInDeck -= 1
puts "#{card.value}, #{card.rank}, #{card.suite}"
#hand.add_cards(card)
end
#hand.each do |index|
"#{index.value}, #{index.rank}, #{index.suite}"
end
puts "Cards In Deck: #{#cardsInDeck}"
end
end
Hand
require_relative 'deck'
require_relative 'card'
class Hand
def initialize()
#hand = Array.new()
end
def to_s
count = 0
#hand.each do |card|
"#{card.value}, #{card.rank}, #{card.suite}"
count += 1
end
end
def add_cards(card)
#hand.push(card)
end
def hand_size()
#hand.length
end
end
and Driver File:
require 'logger'
require_relative 'card'
require_relative 'deck'
require_relative 'hand'
suite = ["Hearts", "Diamonds", "Clubs", "Spades"]
rank = ["Ace", 2, 3, 4, 5, 6, 7, 8, 9, 10, "Jack", "Queen", "King"]
deck = Deck.new()
suite.each do |i|
v = 1
rank.each do |j|
deck.add_card(Card.new(i, j, v))
v += 1
end
end
In the Deck class, the deal_card method, I do not understand why looping for an array causes a method error
#hand.each do |index|
"#{index.value}, #{index.rank}, #{index.suite}"
end
puts "Cards In Deck: #{#cardsInDeck}"
#hand is an instance of Hand, and there is no instance method each defined for Hand, so that is why #hand.each is generating an undefined method error.
My answer is not very direct on the error but could hopefully help you in this case.
You method deal_cards is where Dependency Injection can play its role. By the original design Deck has a hard dependency on Hand which is not good and harder to test. You need to change it like
def deal_cards(hand=nil)
#hand = hand || Hand.new
# Others
end
By this you can accept instance outside of Hand, say Foot as long as somebody can play cards by feet!
You can also unit testing this method without writing Hand class at all.
Better to unit test the class instead of manual checking, then you can inject any instance you like into this method during testing.

can instances of a super class communicate with each other just as instances of a normal class

Instances of a class can access methods of other instances, but is it possible to do this for two distinct subclasses of a class with different methods? Or must the methods accessed be included in the super class?
It sounds like you need to keep track of your associations by passing in the Deck instance to the individual Hand instances. Here is an example based on the scenario you described:
class Card
attr_accessor :suit, :value
def initialize(suit, value)
#suit = suit
#value = value
end
end
class Deck
SUITS = ["Spades", "Clubs", "Diamonds", "Hearts"]
VALUES = [2, 3, 4, 5, 6, 7, 8, 9, 10, "J", "Q", "K", "A"]
HAND_SIZE = 5
attr_accessor :cards
def initialize
shuffle
end
def shuffle
#cards = []
SUITS.each do |suit|
VALUES.each do |value|
#cards << Card.new(suit, value)
end
end
#cards.shuffle!
end
def deal_hand
shuffle if #cards.size < (HAND_SIZE + 1)
hand = #cards[0...HAND_SIZE]
#cards = #cards.drop(HAND_SIZE)
hand
end
end
class Player
attr_accessor :deck
attr_accessor :hand
def initialize(deck)
#deck = deck
end
def draw!
#hand = #deck.deal_hand
end
end
# initialize
the_deck = Deck.new
players = []
players << (player1 = Player.new(the_deck))
players << (player2 = Player.new(the_deck))
players << (player3 = Player.new(the_deck))
players << (player4 = Player.new(the_deck))
# draw
players.each do |player|
player.draw!
end
# play
# ...
Hope this helps.

Resources