Game
has an array of ten Frame
instances
class Frame
attr_accessor :rolls
def initialize
@rolls = ""
end
end
class Game
attr_accessor :frames
def initialize
@frames = Array.new(10, Frame.new)
end
def print_frames
@frames.each_with_index do |frame, idx|
p "Frame ##{idx+1}: #{frame.rolls}"
end
end
end
game = Game.new
rolls = [5, 5, 3, 7, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2]
curr = 0
rolls.each_with_index do |roll|
game.frames[curr].rolls << roll.to_s
if game.frames[curr].rolls.size == 2
curr += 1
end
end
p "Total rolls: #{rolls.size}"
p game.print_frames
I expect 10 lines to be printed, each line has a frame id with a string of 2 numbers however, the following is returned
"Total rolls: 20"
"Frame #1: 55374000000000000022"
"Frame #2: 55374000000000000022"
"Frame #3: 55374000000000000022"
"Frame #4: 55374000000000000022"
"Frame #5: 55374000000000000022"
"Frame #6: 55374000000000000022"
"Frame #7: 55374000000000000022"
"Frame #8: 55374000000000000022"
"Frame #9: 55374000000000000022"
"Frame #10: 55374000000000000022"
[#<Frame:0x0000565402e40528 @rolls="55374000000000000022">, #<Frame:0x0000565402e40528 @rolls="55374000000000000022">, #<Frame:0x0000565402e40528 @rolls="55374000000000000022">, #<Frame:0x0000565402e40528 @rolls="55374000000000000022">, #<Frame:0x0000565402e40528 @rolls="55374000000000000022">, #<Frame:0x0000565402e40528 @rolls="55374000000000000022">, #<Frame:0x0000565402e40528 @rolls="55374000000000000022">, #<Frame:0x0000565402e40528 @rolls="55374000000000000022">, #<Frame:0x0000565402e40528 @rolls="55374000000000000022">, #<Frame:0x0000565402e40528 @rolls="55374000000000000022">]
instance variable is acting like class variables shared between frames. all 20 rolls numbers are concatenated instead of each frame owning a pair.
what is wrong with the code? is it because the Game
or Frame
object is not instantiated correctly?
Array.new(10, Frame.new)
Creates an array with 10 elements all pointing to a single Frame
instance. To create an array with 10 separate Frame
instances you should use the block form.
Array.new(10) { Frame.new }
This executes the block 10 times and assigns the result of each execution to the cosponsoring index.
See: Creating Arrays
An array can also be created by explicitly calling
::new
with zero, one (the initial size of theArray
) or two arguments (the initial size and a default object).ary = Array.new #=> [] Array.new(3) #=> [nil, nil, nil] Array.new(3, true) #=> [true, true, true]
Note that the second argument populates the array with references to the same object. Therefore, it is only recommended in cases when you need to instantiate arrays with natively immutable objects such as Symbols, numbers, true or false.
To create an array with separate objects a block can be passed instead. This method is safe to use with mutable objects such as hashes, strings or other arrays:
Array.new(4) {Hash.new} #=> [{}, {}, {}, {}] Array.new(4) {|i| i.to_s } #=> ["0", "1", "2", "3"]