Undefined function make_card Ruby - 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

Related

Possible moves on a chess board, using instance from one class in another.

I'm working on making a chess game. I want to keep everything that has to do with possible moves inside each type of pieces class. In order to do this I need to refer back to #board[][]. The commented section of code in the possible_moves method is what I would like to do, except it does not work and throws an error.
class Board
attr_accessor :board, :choice
def initialize
#board = Array.new(8){Array.new(8," ")}
#choice = choice
end
def set_board
#board[0][2] = Bishop.new([0,2],false)
end
end
class Bishop
attr_accessor :x_position, :y_position, :piece, :color, :moves
def initialize(position,is_white)
#x_position = position[0]
#y_position = position[1]
#piece = is_white ? "♝" : "♗"
#color = is_white ? "white" : "black"
#moves = [[+1,-1],
[+1,+1],
[-1,+1],
[-1,-1]]
end
def possible_moves
move_list = Array.new
#moves.each do |moves|
x = #x_position
y = #y_position
loop do
x += moves[0]
y += moves[1]
break if x.between?(0,7) == false
break if y.between?(0,7) == false
# This is where I want to refer back to #board from the Board class.
# if #board[x][y].color.....
move_list << [x,y]
#end
end
end
p move_list
end
end
You can pass the board into the Bishop constructor:
class Bishop
attr_reader :board
# etc.
def initialize(position,is_white,board)
#board = board.board # or just #board = board and you can fetch the matrix later
# etc.
end
end
class Board
# etc.
def set_board
#board[0][2] = Bishop.new([0,2],false, self)
end
end

Find product's frequency in this CashRegister class

I have 3 simple classes CashRegister, Bill and Position. A CashRegister is composed of Bill objects and a Bill object is composed of Position objects. They're implemented as followed
class CashRegister
def initialize
#bills = []
end
def product_frequency
#???
end
def << bill
#bills << bill
self
end
end
class Bill
attr_reader :positions,:nr
protected :positions
def initialize(nr)
#nr = nr
#positions = []
end
def << pos
#positions << pos
self
end
end
class Position
attr_reader :product,:quantity,:price
def initialize(product,quantity,single_price)
#product = product
#quantity = quantity
#price = single_price * quantity
end
end
I want to write a product_frequency method that calculates how often a product is bought in the CashRegister. This method returns a hash as a result, with the product as key, and the frequency as value.
An example would be:
pos1 = Position.new('Chicken', 5, 12)
pos2 = Position.new('Soup', 6, 24)
pos3 = Position.new('Burger', 3, 19)
pos4 = Position.new('Chicken', 2, 12)
pos5 = Position.new('Soup', 8, 24)
pos6 = Position.new('Burger', 9, 19)
bill1 = Bill.new(1) << pos1 << pos2 << pos3 #Chicken: 5;Soup: 6;Burger: 3
bill2 = Bill.new(2) << pos4 << pos3 << pos2 #Chicken: 2;Soup: 6;Burger: 3
bill3 = Bill.new(3) << pos6 << pos6 << pos6 #Chicken: 0;Soup: 0;Burger: 27
bill4 = Bill.new(4) << pos4 << pos5 << pos4 #Chicken: 4;Soup: 8;Burger: 0
my_cash_register = CashRegister.new << bill1 << bill2 << bill3 << bill4
my_cash_register.product_frequency #{'Chicken' => 11, 'Soup' => 20, 'Burger' => 33}
How can I accomplish that result?
Taken mostly from the solution of Bartosz Bonisławski. But since positionen in bill is protected, we first have to make it accessible by defining an each function in Bill that takes in a block and applies it to every position of positions. We also do the same for CashRegister.
class CashRegister
def initialize
#bills = []
end
def each(&block)
#bills.each(&block)
end
def product_frequency
result = {}
each { |bill|
bill.each { |position|
result[position.product] ||= 0
result[position.product] += position.quantity
}
}
result
end
def << bill
#bills << bill
self
end
end
class Bill
attr_reader :positions,:nr
protected :positions
def initialize(nr)
#nr = nr
#positions = []
end
def each(&block)
#positions.each(&block)
end
def << pos
#positions << pos
self
end
end
class Position
attr_reader :product,:quantity,:price
def initialize(product,quantity,single_price)
#product = product
#quantity = quantity
#price = single_price * quantity
end
end
If you just want to count how many times each product was bought, then here it is:
def product_frequency
product_frequency = {}
#bills.each do |bill|
bill.positionen.each do |position|
#product_frequency[position.product] ||= 0
#product_frequency[position.product] += position.quantity
end
end
product_frequency
end
It's just one way of doing it. Code is pretty easy, so I think you can figure how it works
You could define #frequency for each nested class and then recursively collect hashes.
class Hash
def additive_merge!(hash)
hash.each { |k,v| self[k] ? self[k] += v : self[k] = v }
self
end
end
class CashRegister
def initialize
#bills = []
end
def product_frequency
#bills.map(&:frequency).reduce(&:additive_merge!)
end
def << bill
#bills << bill
self
end
end
class Bill
attr_reader :positionen,:nr
protected :positionen
def initialize(nr)
#nr = nr
#positions = []
end
def << pos
#positions << pos
self
end
def frequency
#positions.map(&:frequency).reduce(&:additive_merge!)
end
end
class Position
attr_reader :product,:quantity,:price
def initialize(product,quantity,single_price)
#product = product
#quantity = quantity
#price = single_price * quantity
end
def frequency
{ product => quantity }
end
end

attr_accessor - Accessing an objects attributes from another class

I want to access the ogre's object's swings attribute from the Human's class. However, all I am getting is:
NameError: undefined local variable or method ogre for
**<Human:0x007fdb452fb4f8 #encounters=3, #saw_ogre=true>
Most likely a simple solution, and my brain is just not operating this morning. I am running tests with minitest. The test and classes are below:
ogre_test.rb
def test_it_swings_the_club_when_the_human_notices_it
ogre = Ogre.new('Brak')
human = Human.new
ogre.encounter(human)
assert_equal 0, ogre.swings
refute human.notices_ogre?
ogre.encounter(human)
ogre.encounter(human)
assert_equal 1, ogre.swings
assert human.notices_ogre?
end
ogre.rb
class Ogre
attr_accessor :swings
def initialize(name, home='Swamp')
#name = name
#home = home
#encounters = 0
#swings = 0
end
def name
#name
end
def home
#home
end
def encounter(human)
human.encounters
end
def encounter_counter
#encounters
end
def swing_at(human)
#swings += 1
end
def swings
#swings
end
end
class Human
def initialize(encounters=0)
#encounters = encounters
#saw_ogre = false
end
def name
"Jane"
end
def encounters
#encounters += 1
if #encounters % 3 == 0 and #encounters != 0
#saw_ogre = true
else
#saw_ogre = false
end
if #saw_ogre == true
ogre.swings += 1 # <----issue
end
end
def encounter_counter
#encounters
end
def notices_ogre?
#saw_ogre
end
end
The easy fix would be to pass the ogre object as an argument to encounters - assuming encounters isn't used anywhere else without the argument.
class Ogre
...
def encounter(human)
human.encounters(self)
end
...
end
class Human
...
def encounters(ogre)
#encounters += 1
if #encounters % 3 == 0 and #encounters != 0
#saw_ogre = true
else
#saw_ogre = false
end
if #saw_ogre == true
ogre.swings += 1 # <----issue
end
end
...
end

Ruby - problems with nilClass [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
I am having trouble getting this to work. The error I get is:
114 in 'numberstash' : undefined method 'cards' for nil:Nilclass (No Method Error).
It is for a Blackjack game. I spent several hours trying to fix this code, including making a bunch of test scripts to figure it out. However, I have had no luck. This works on my test script, however it doesn't work on the current script:
class Card
attr_accessor :suit, :value
def initialize(suit, value)
#suit = suit
#value = value
end
def to_s
"#{value} of #{suit}"
end
end
class Deck
attr_accessor :cards
def initialize(number_of_decks)
#cards = []
num = number_of_decks
counter = 0
while counter < num
['H','C', 'S', 'D'].product(['2','3','4','5','6','7','8','9','10','J','K','Q','A']).each do |arr|
#cards << Card.new(arr[0], arr[1])
end
counter += 1
end
end
end
class Player
attr_accessor :cards, :testvalue
def initialize
#cards = []
end
end
class Dealer
attr_accessor :cards
#cards = []
end
class Blackjack
attr_accessor :deck, :player, :dealer
def calculate arr
new = arr.map { |e| e[1] }
sum = 0
ace = 0
new.each { |value|
if value == 'A'
sum += 1
ace = 1
elsif value.to_i == 0
sum += 10
else
sum += value.to_i
end
}
if ace = 1 && sum + 10 <= 21
ace = 0
sum = sum + 10
end
end
def initialize
deck = Deck.new(4)
##deck = #deck.shuffle
player = Player.new()
dealer = Dealer.new()
end
def dealcards
#puts 'dealcards'
#player.cards << deck.cards.pop
#dealer.cards << deck.cards.pop
end
def start
#dealcards
#player_turn
#dealer_turn
#compare?
#play again?
numberstash
end
def numberstash
#player.cards << deck.cards.pop
puts player.cards
#dealer.cards << deck.cards.pop
end
end
game = Blackjack.new()
game.start
My question is, why am I getting the above mentioned error?
Everywhere in Blackjack that you use player, you mean #player, for example in Blackjack#initialize:
#player = Player.new()
and Blackjack#numberstash:
puts #player.cards
# identifies instance variables, the kinds of thing accessed by attr_accessor.

Object that can be coerced to either String, Fixnum, or Float?

Is there a way to define an object that can be coerced to either a String or a Fixnum or a Float? This is for use in a system that collects values and evaluates a restricted set of simple expressions with them.
I tried:
class EmptyValue < Numeric
def to_s; ''; end
def to_str; ''; end
def to_i; 0; end
def to_int; 0; end
def to_f; 0.0; end
end
but this fails for
1 + e
TypeError: EmptyValue can't be coerced into Fixnum
A little more poking and this worked for all my use cases:
class EmptyValue < Numeric
def to_s; ''; end
def to_str; ''; end
def to_i; 0; end
def to_int; 0; end
def to_f; 0.0; end
def +(other)
case other
when String
to_s + other
when Fixnum
to_i + other
when Float
to_f + other
end
end
end
This is what I've done long time ago:
class NullObject
attr_reader :null_object_type, :recorded_messages
alias ρ recorded_messages
def initialize( type_of_null_object = nil )
#null_object_type = type_of_null_object
#recorded_messages = []
end
def null_object? null_type = nil
null_object_type == null_type
end
alias null? null_object?
def to_a; [] end
def to_s; "null #{null_object_type}".strip end
def to_f; 0.0 end
def to_i; 0 end
def present?; false end
def empty?; true end
def blank?; true end
def inspect
"NullObject #{null_object_type}".strip
end
def method_missing ß, *aj, &b # :nodoc:
#recorded_messages << [ ß, aj, b ]; self
end
def respond_to? ß, *aj, &b # :nodoc:
true
end
protected
def == other # :nodoc:
null_object_type == other.null_object_type
end
end # class NullObject
# Strong zero.
#
ZERO = NullObject.new
ZERO.instance_exec {
ɪ = self
singleton_class.class_exec do
define_method :zero do ɪ end
end
def * other; other.class.zero end
def / other
self unless other.zero?
raise ZeroDivisionError, "The divisor is zero! (#{other})"
end
def + other; other end
def - other; -other end
def coerce other
return other, other.class.zero
end
def zero?; true end
def to_s; "∅" end
def inspect; to_s end
def to_f; 0.0 end
def to_i; 0 end
def == other
z = begin
other.class.zero
rescue NoMethodError
return false
end
other == z
end
}
class << Numeric; def zero; 0.0 end end
class << Integer; def zero; 0 end end
class << Float; def zero; 0.0 end end
class << Rational; def zero; Rational 0, 1 end end
class << Complex; def zero; Complex 0, 0 end end
class << String; def zero; '' end end
class << Array; def zero; [] end end
class << Hash; def zero; {} end end
So, now you have 0 + ZERO #=> 0. I called this "strong zero". But it was a hack. I have a gut feeling, that this is not such a good practice.

Resources