Идиоматически глубокий дубликат экземпляра пользовательского класса в Ruby

Я понимаю, как дублировать большинство вещей в Ruby, но я не так хорош, чтобы придумать "способ Ruby", чтобы делать вещи. В этом суть этого вопроса, в основном.

Я строю игру в шахматы (хотя этот вопрос, я думаю, относится к любому пользовательскому классу с кучей экземпляров vars), и для того, чтобы сделать, а затем проверить гипотетические ходы, мне нужно глубоко продублировать мой объект ChessBoard, который включает в себя глубокое дублирование каждого из моих произведений. Каждый кусок наследуется от класса Piece (через промежуточный подкласс) и имеет следующие переменные экземпляра:

@position, который является массивом координат [x,y]
@color, который является символом, либо :w или же :b
@opponent, который является противоположным значением как @color@board, который является ссылкой на объект ChessBoard (2d массив).

Я пытаюсь найти элегантный (или, по крайней мере, идиоматически Ruby) и эффективный способ скопировать каждую из моих частей; т.е. я пытаюсь реализовать Piece#dup,

Другие вопросы предлагают способы сделать это, которые включают неосновные библиотеки (Marshal, YAML, что-то под названием MessagePack, или что-то еще. Этот очень полезный поток показывает сравнение нескольких тестов, и самый эффективный метод (согласно потоку) НЕ любой Таким образом, я пытаюсь найти способ сделать это, который не использует никакие не-stdlib методы / библиотеки.

Вот некоторый соответствующий код для вашей справки. Я думаю, что следующее - это все, что вам нужно, но во что бы то ни стало, просите большего, если нужно, и в этом случае я прошу прощения! Остальная часть кода для проекта (которая никак не делается) находится здесь, если вы чувствуете, что должны ее увидеть.

Не стесняйтесь, но не обязаны отменять любой предоставленный код, который не Piece#dup также.

NB: я подтвердил в pry, что вызов ChessBoard#dup (очевидно, загрузив остаток кода, который находится на ссылке Github) делает копию экземпляра платы и всех частей на нем, все с разными идентификаторами объектов из оригиналы.

  • Доска (от которой наследует ChessBoard) переопределена классом [] а также []= методы, которые позволяют получить доступ к квадратам на доске с board_instance[[x,y]]

    def [](pos)  
      x,y = pos[0], pos[1]
      @rows[x][y]
    end
    
    def [](pos, obj)
      x,y = pos[0], pos[1]
      @rows[x][y] = obj
    end
    
  • CHESSBOARD # DUP

    def dup
      new_board = self.class.new
      (0..7).each do |row_idx| 
        (0..7).each do |col_idx| 
          position = [row_idx, col_idx]
          if self[position].nil?
            new_board[position] = nil
          else
            new_board[position] = self[position].dup(new_board)
            # invokes Piece#dup, passing in the new_board Board obj
          end
        end
      end 
      new_board
    end  
    
  • Моя собственная попытка Piece # dup

    def dup(board)
    
      original_instance_vars = []  
    
      self.instance_variables.each do |var| #works
        original_instance_vars << self.instance_variable_get(var)
      end  
    
      # original_instance_vars is now the values for
      # [@position, @color, @opponent, @board] in that order 
    
      piece_dup = self.class.new(board, original_instance_vars[1])
      # need to instantiate piece dup with a board (idx 3) and color (idx 1)
    
      piece_dup.instance_variables.each_with_index do |var, i|
        # dup each thing
        next if i == 3 || i==1
        # but skip the board, and color, because those are added in #new
        begin
          var_dup = original_instance_vars[i].dup 
        rescue TypeError
          # this for the two ivars which are symbols and can't be dup'd
          var_dup = original_instance_vars[i]
        end
    
        piece_dup.instance_variable_set(var, var_dup) 
    
      end  
    
      piece_dup  
    end
    

Спасибо за помощь. Пожалуйста, отредактируйте вопрос, если необходимо, так как я считаю, что это полезное упражнение.

0 ответов

Другие вопросы по тегам