0

For our assignment, we were meant to create tic-tac-toe on a board of any size and accept an array as the input. I still am not fully grasping the attr_accessor module, and I'm pretty sure I used it incorrectly.

class Board
  attr_accessor :grid

  def initialize(grid = nil)
    if grid.nil?
      @grid = Array.new(3, Array.new(3, nil))
    else
      @grid = grid
    end
  end

  def place_mark(pos, mark)
    @grid[pos[0]][pos[1]] = mark
  end

 end

My main problem is even though it seems 'place_mark' should be placing the input in just one position. I get the following:

game.place_mark([0,0], :X) #=> [[:X, nil, nil], [:X, nil, nil], [:X, nil, nil]]

When I recreated this outside of a class, it worked just as I thought it should. What did I mess up?

2

1 Answer 1

1

There is nothing wrong with the Board class nor with attr_accessor. The initialization of the grid however does not work. @grid = Array.new(3, Array.new(3, nil)) is the culprit. The fourth code sample in the docs shows how it should be done, the text above it explains why OP's code behaves like it does. Every Ruby student gets trapped by this at least once.

Sign up to request clarification or add additional context in comments.

3 Comments

Oh, thanks for the help. Does Ruby do this to be efficient or are there useful tricks associated with creating nested arrays referencing the same object?
@SeanChowdhury It's harder than it sounds to do it the way you expected it to work - when you're not passing a block, the inner call to Array.new has already happened, it's exactly the same as inner = Array.new(3,nil); @grid = Array.new(3,inner). So we don't have the option of executing that code more than once like we do with a block. So, if we wanted to get different objects in each spot, we'd have to duplicate the one passed in. Do we do a shallow copy or a deep copy? Either will sometimes be wrong. The non-block syntax is only provided as a convenience for immutable values like 2.
To elaborate on the shallow vs deep issue, consider inner = [Person.new('Jane'),Person.new('Bill'),Person.new('Sally'); outer = Array.new(3,inner). Would you want the end result to involve 9 people (some of which share the same name)? Three different lists that happen to contain the same people? Or the same list three times? The 'obvious' answer will be different depending on the example you use, and depending on who you ask.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.