Ruby - 更新一个类实例无意中更新了另一个类实例

时间:2016-04-12 17:04:40

标签: ruby

我正在尝试在Ruby中构建一个简单的tic tac toe程序。我遇到一个问题,在一个类实例上调用一个方法更新另一个类实例。问题出在我的Game类中,如下所示:

class Game
    attr_accessor :turn_count, :all_positions_occupied, :winner, :rows, :columns, :diagonals

    def initialize
        @turn_count = 0

        @all_positions_occupied =  {1 => "*", 2 => "*", 3 => "*",
                                    4 => "*", 5 => "*", 6 => "*",
                                    7 => "*", 8 => "*", 9 => "*"}

        @winner = nil

        @rows = { 1 => [1, 2, 3], 2 => [4, 5, 6], 3 => [7, 8, 9] }

        @columns = { 1 => [1, 4, 7], 2 => [2, 5, 8], 3 => [3, 6, 9] }

        @diagonals = { 1 => [1, 5, 9], 2 => [3, 5, 7] } 
    end

    def refresh_line(line, item, symbol)
        line.each do |key, value|
            if value.include?(item)
                value[(value.index(item))] = symbol
            end
        end
    end

    def occupy_selected(selection, symbol)
        @all_positions_occupied[selection] = symbol 

        # Refresh rows, columns, and diagonals

        refresh_line(@rows, selection, symbol)
        refresh_line(@columns, selection, symbol)
        refresh_line(@diagonals, selection, symbol)
    end

    def copy_onto_virtual_board(virtual_game)
        virtual_game.all_positions_occupied = @all_positions_occupied.clone
        virtual_game.rows = @rows.clone
        virtual_game.columns = @columns.clone
        virtual_game.diagonals = @diagonals.clone
    end
end

我正在尝试创建试图阻止玩家获胜的计算机行为。在我的主代码中,我想创建一个“real_game”和一个“virtual_game”。每当计算机轮到我的时候,我想运行以下方法:

def block_win(virtual_game)
        # Copy Real Board Onto Virtual Board Using 'copy_onto_virtual_board(virtual_game)'
        # Create Array of Available Positions
        # Cycle Through Array of Available -> 'available_positions.each do |position|'
            # Occupy 'position' on the Virtual Board with 'X' using 'occupy_selected(position, 'X')
            # If 'virtual_game.check_for_winner' is not nil
                # Have Computer Occupy that Position with 'O', effectively blocking 'X' from taking that position and winning
            # Else
                # Re-Copy Real Board Onto the Virtual Board Using 'copy_onto_virtual_board(virtual_game)' 
    end

但是,一旦我使用real_game.copy_onto_virtual_board(virtual_game)real_gamevirtual_game会以某种方式链接起来,这样无论何时我在virtual_game上使用occupy_selected(position, "X"),它都会将相同的方法应用于real_game同样。这违背了将virtual_game与real_game分开的全部目的。只要我不使用copy_onto_virtual_board方法,这两个游戏就会分开运作。

关于为什么会发生这种情况的任何想法?我知道这是一个令人费解的解释,所以请告诉我您可能需要的其他信息。

感谢您的帮助。

更新-----------

根据以下engineermnky给出的答案,我更新了以下方法:

def copy_onto_virtual_board(virtual_game)
        virtual_game.all_positions_occupied = @all_positions_occupied.clone
        virtual_game.rows = @rows.keys.zip(@rows.values.map(&:clone)).to_h
        virtual_game.columns = @columns.keys.zip(@columns.values.map(&:clone)).to_h
        virtual_game.diagonals = @diagonals.keys.zip(@diagonals.values.map(&:clone)).to_h
end

设置block_win方法以返回阻塞位置(如果有)。否则,它会根据available_positions数组返回一个随机位置。

1 个答案:

答案 0 :(得分:0)

原因是你没有深刻复制哈希。这意味着通过使用#clone,您创建一个新哈希,其键指向相同的数组。

您可以使用Marshal.load(Marshal.dump(hash))代替hash.clone在ruby中制作深层副本。这将创建所有引用对象的完整副本。

但我不能推荐它,并鼓励你检查你的设计,以便你不需要。