我完成了tic tac toe的佩奇,正在努力改进我的电脑播放器。这需要从旧板对象创建新板对象的副本。我无法创建电路板的深层副本。
以下是相关代码:
Class Board
attr_accessor :grid
def initialize(grid = Array.new(3){ Array.new(3)})
@grid = grid
end
def place_mark(cords, sym)
self[cords] = sym
@grid
end
def [](pos)
row, col = pos
@grid[row][col]
end
def []=(pos, mark)
row, col = pos
@grid[row][col] = mark
end
def new_state
grid = @grid.dup
Board.new(grid)
end
end
board = Board.new
new_state = board.new_state # ==> A different object
new_state.place_mark([0,0], :X) # ==> Object with x placed at 0,0
board # ==> Object with x placed at 0,0
现在,当我实现new_state然后在new_state上放置一个标记时,它还会在重复的状态上放置一个标记。
我明白为什么如果我设置我的new_state只是复制对象它就行不通。但我不明白为什么我当前的实现不起作用。我应该存储当前对象的网格,然后使用相同的网格创建一个新对象。有什么想法吗?
答案 0 :(得分:1)
在Ruby中,dup
生成一个浅层克隆,并且不会复制它们引用的对象。由于entropy
是一个数组数组,因此不会复制@grid
数组中的每个数组。这可能不太清楚,所以希望代码有所帮助:
@grid
所以内部数组是同一个对象,从一个地方修改它会修改引用它的所有内容。但是,如果你修改了'外部'数组,它的工作方式与您期望的一样:
grid = [ [:first_row], [:second_row] ]
copy = grid.dup
grid.object_id == copy.object_id # => false, so you have a different array
grid[0].object_id == copy[0].object_id # => true, so the inner array is the same
copy[0][0] = :test_change
grid # => [[:test_change], [:second_row]]
copy # => [[:test_change], [:second_row]]
所以,了解这一切,希望你能更清楚地解决这个问题,你只需要打电话给copy[0] = [:updates_correctly]
copy # => [[:updates_correctly], [:second_row]]
grid # => [[:test_change], [:second_row]]
内部'阵列。我们也会在这里使用dup
,这会返回一个新的数组,因此我们不需要在外部'上调用collect
。数组:
dup
但是如果我们改为使用字符串,那些数组的元素仍然不是不同的对象:
copy = grid.collect(&:dup) # => [[:test_change], [:second_row]]
copy[0][0] = :another_change
copy # => [[:another_change], [:second_row]]
grid # => [[:test_change], [:second_row]]
并修改了字符串,我们最终改变了两者:
grid = [ ['first row'] ]
copy = grid.collect(&:dup)
你需要走多远取决于你的特殊需求。
所以, TL; DR 您需要将copy[0][0].upcase!
copy # => [["FIRST ROW"]]
grid # => [["FIRST ROW"]]
更改为:
new_state
它应该有用。