Ruby OOP クラスの相互作用: インスタンス変数を更新する方法はどれですか?

概要

Game と Player の 2 つのクラスがあります。これは三目並べゲームです。

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

プレーヤーとゲームを初期化するコード:

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

プレーヤーが番号を選択するたびに (例: p1.play(game) を使用)、その番号がプレーヤーの選択範囲に保存され、ゲーム内の番号が「x」/「o」で更新されるようにプレーヤーをセットアップします。 。

上記の手順が完了したら、Game の :player_1 と :player_2 を次のように更新します。

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 を実行しても、どちらの方法でも結果は同じです。

そこで、OOP の世界の初心者として、説明を求めたいと思います。私の場合、player_1 / player_2 を更新する正しい方法は何ですか?ありがとう。

解決策

変数はオブジェクトを参照するために使用されます。 = を介して変数に代入することでオブジェクトを設定します。例:

a = "hello"

これで、a を介して「hello」を参照できるようになります。

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 ───────┘

<< ” world” を呼び出すと、オブジェクトが変更されます。つまり、次のようになります。

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

その後 a と b を検査すると、その変更が示されるだけです。

その必要はありません。コードでは、p1 と game.player_1 はすでに同じオブジェクト、つまり Player のインスタンスを参照しています。したがって、プレーヤー インスタンスを更新するだけで済みます。

game.player_1 = p1 の設定は、game.player_1 がすでに p1 を参照しているため、実際には不要です。まったく同じオブジェクトを再割り当てしているだけです。