Взаимодействие классов ООП Ruby: как обновить переменные экземпляра?

У меня есть 2 класса: Game и Player. Это игра «Крестики-нолики».

class Game
    attr_accessor :player_1, :player_2, :numbers, :board

    def initialize(player_1, player_2)
        @player_1 = player_1
        @player_2 = player_2
        @numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]
    end
end
class Player

    attr_reader :name
    attr_accessor :selection

    def initialize(name)
        @name = name
        @selection = []
    end

    def play(game)
        print "#{name}, please pick a number: "
        number = gets.chomp.to_i
        print "#{name} selected #{number}"
        puts
        
        selection << number
        index = game.numbers.find_index(number)

        if (name == 'player_1')
            game.numbers[index] = 'X'
        else
            game.numbers[index] = 'O'
        end
    end
end

Коды для инициализации Player и Game:

p1 = Player.new('player_1')
p2 = Player.new('player_2')
game = Game.new(p1, p2)

Я настраиваю проигрыватель таким образом, что всякий раз, когда игрок выбирает номер (пример: с помощью p1.play(game)), номер будет сохраняться в selection из Player, а numbers в Game будет обновляться с помощью «x» / «o».

После выполнения вышеуказанных шагов я обновляю :player_1 и :player_2 в Game, используя:

game.player_1 = p1 и game.player_2 = p2

Распечатайте game.player_1.selection и ожидаемый результат. Однако я один раз по ошибке пропустил game.player_1 = p1 и game.player_2 = p2 и снова напечатал game.player_1.selection. К моему удивлению, результат для обоих способов один и тот же, независимо от того, я выполняю game.player_1 = p1 и game.player_2 = p2.

Итак, я хотел бы получить разъяснения, как новичок в мире ООП; как правильно обновить player_1/player_2 в моем случае? Спасибо.

game.player_1 есть p1 – оба относятся к одному и тому же объекту. Если вы измените объект, это изменение отразится на них обоих (и на любой другой переменной, которая также может ссылаться на этот объект).
Stefan 27.04.2024 08:58

@Стефан, ты имеешь в виду, что game.player_1 будет автоматически обновляться, как только я позвоню p1.play(game)?

Ong K.S 27.04.2024 09:02

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

Stefan 27.04.2024 09:16

Не имеет отношения к делу, но учтите, что вы можете определить, выиграет ли какой-либо игрок в любой момент, с помощью чего-то вроде def win?(board) [[0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 3, 6], [1, 4, 6], [2, 5, 8], [0, 4, 8], [2, 4, 6].all? { |a| board.values_at(*a).uniq.size == 1; end.

Cary Swoveland 28.04.2024 01:57
Пошаговое руководство по созданию собственного Slackbot: От установки до развертывания
Пошаговое руководство по созданию собственного Slackbot: От установки до развертывания
Шаг 1: Создание приложения Slack Чтобы создать Slackbot, вам необходимо создать приложение Slack. Войдите в свою учетную запись Slack и перейдите на...
0
4
67
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Переменные используются для ссылки на объекты. Вы устанавливаете объект, присваивая его переменной через =, например:

a = "hello"

Теперь вы можете обращаться к "hello" через a, например.

a << " world"

a #=> "hello world"

Из-за такого использования вы можете подумать, что вы изменили a. Но это не совсем правильно. Вы фактически изменили объект, на который ссылается a, то есть строку "hello", которая затем стала "hello world".

Это различие важно, когда вы присваиваете объект более чем одной переменной, например:

a = "hello"
b = a

a << " world"

a #=> "hello world"
b #=> "hello world"

b = a заставит b ссылаться на тот же объект, на который ссылается a. Я думаю об этом как:

variable  object
   a ───────┐
          "hello"
   b ───────┘

При вызове a << " world" объект модифицируется, т.е.:

variable  object
   a ───────┐
          "hello world"
   b ───────┘

Последующая проверка a и b просто показывает эту модификацию.


как правильно обновить player_1/player_2 в моем случае?

Вам не обязательно. В вашем коде p1 и game.player_1 уже относятся к одному и тому же объекту, экземпляру Player. Поэтому обновление этого экземпляра проигрывателя — это все, что вам нужно сделать.

Установка game.player_1 = p1 на самом деле излишняя, поскольку game.player_1 уже упоминалось p1. Вы просто переназначали один и тот же объект.

TQ @Stefan за подробное объяснение.

Ong K.S 27.04.2024 14:54

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