2017-08-20 6 views
0

私はtic tacのつま先のペックを終了し、私のコンピュータプレーヤーの改善に取り組んでいました。これは、古いボードオブジェクトから新しいボードオブジェクトのコピーを作成する必要があります。私はボードの深いコピーを作成することに問題があります。ここでオブジェクトのディープコピーRuby

は、問題のコードです:

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を設定すると、なぜ私の現在の実装がうまくいかないのか分かりません。私は、現在のオブジェクトのグリッドを格納して、同じグリッドを持つ新しいオブジェクトを作成する必要があります。何かご意見は?

答えて

1

Rubyでは、dupは浅いクローンを生成し、参照するオブジェクトをコピーしません。 @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]] 

、および1つの場所からそれを変更すると、それを参照するすべてのものを変更します。それは、うまくいけば、コードを助け、明確ではなかったかもしれませんしかし、あなたは「外側」の配列を変更した場合、あなたが期待するように、それが動作:だから

copy[0] = [:updates_correctly] 
copy # => [[:updates_correctly], [:second_row]] 
grid # => [[:test_change], [:second_row]] 

、このすべてを知って、それはあなただけでdupを呼び出す必要があり、あなたがこの問題を解決する方法をうまくいけば少し明確です'内部'の配列。

copy = grid.collect(&:dup) # => [[:test_change], [:second_row]] 
copy[0][0] = :another_change 
copy # => [[:another_change], [:second_row]] 
grid # => [[:test_change], [:second_row]] 

が、これらの配列の要素はまだ」上がらない:私たちはすべてで「外側」アレイ上dupを呼び出す必要がないように私たちは、新しい配列を返し、ここにもcollectを使用します異なるオブジェクトをtは、私たちが代わりに文字列があった場合:

grid = [ ['first row'] ] 
copy = grid.collect(&:dup) 

をし、代わりに文字列を変更し、我々は両方を変更してしまうと思います:

copy[0][0].upcase! 
copy # => [["FIRST ROW"]] 
grid # => [["FIRST ROW"]] 

あなたが行く必要がどのように深く依存あなたの特別なニーズ。

ので、TL; DRあなたが見えるようにnew_stateを変更する必要があります。

def new_state 
    grid = @grid.collect(&:dup) 
    Board.new(grid) 
end 

、それが動作するはずです。

関連する問題