Идиоматически глубокий дубликат экземпляра пользовательского класса в 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
Спасибо за помощь. Пожалуйста, отредактируйте вопрос, если необходимо, так как я считаю, что это полезное упражнение.