Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby private instance variables, with exceptions

I am making a card game in ruby.

I have the Game class, which has an array of Player objects.

 array_of_players = Array[
  Player.new("Ben"),
  Player.new("Adam"),
  Player.new("Peter"),
  Player.new("Fred"),
 ]
 my_game = Game.new(array_of_players)

 puts my_game.players[2].name #=> Peter

Each player also has access to the Game, so that they can access the important bits of the game like so

self.game.last_card_dealt

Each player also has cards (Player.cards), and I want to make sure that players can't access each other's cards. However, the Game does need access to the cards, so I don't think using private is appropriate, and the players need access to some of each other's information, so I don't think I want that to be private either...

Basically, I want these to work.

self.cards #where self is a Player object
self.players[0].cards #where self is the Game
self.game.players[0].name #where self is a Player object

And this to fail:

self.hand.players[0].cards  #=> Nice try sucker! Cheating is for losers.

How are more complex permissions like this handled? Thanks.

like image 962
doctororange Avatar asked Feb 28 '23 11:02

doctororange


1 Answers

This is more practical than my other answer, and uses the Game object as a delegate to all information in the game itself (Players, Cards, etc.). Note that you still have to trust the caller to pass themselves, but seriously where do you draw the line?

class Player
  attr_reader :name

  def initialize(name)
    @name = name
  end
end

class Cards
  attr_accessor :cards
end

class Game
  attr_reader :name, :players

  def initialize(players)
    @name = "Game Master"
    @hands = []
    @players = players.each do |p|
      puts "Added %s to game." % p.name
      @hands << {:player => p, :cards => Cards.new}
    end
  end

  def view_hand(player, caller)
    @hands.each do |hand|
      if hand[:player] == player
        if hand[:player] == caller or caller == self
          puts "%s: You can access all these cards: %s" % [caller.name, hand[:cards]]
        else
          # Do something to only display limited cards depending on this caller's view capabilities
          puts "%s: You can only access the cards I will let you see: %s" % [caller.name, hand[:cards]]
        end
      end
    end
  end

  def my_cards(player)
    @hands.each do |hand|
      puts "%s's cards: %s" % [player.name, hand[:cards]] if hand[:player] == player
    end
  end

end

g = Game.new([Player.new('Bob'), Player.new('Ben')])

puts "\nCalling each Player's cards as each Player:\n\n"
g.players.each do |gp|
  g.players.each do |p|
    g.view_hand(gp, p)
  end
end

puts "\nCalling each Player's cards as Game:\n\n"
g.players.each do |p|
  g.view_hand(p, g)
end

puts "\nEach Player calls for their own cards:\n\n"
g.players.each do |p|
  g.my_cards(p)
end

The output:

    Added Bob to game.
    Added Ben to game.

    Calling each Player's cards as each Player:

    Bob: You can access all these cards: #<Cards:0x100121c58>
    Ben: You can only access the cards I will let you see: #<Cards:0x100121c58>
    Bob: You can only access the cards I will let you see: #<Cards:0x100121bb8>
    Ben: You can access all these cards: #<Cards:0x100121bb8>

    Calling each Player's cards as Game:

    Game Master: You can access all these cards: #<Cards:0x100121c58>
    Game Master: You can access all these cards: #<Cards:0x100121bb8>

    Each Player calls for their own cards:

    Bob's cards: #<Cards:0x100121c58>
    Ben's cards: #<Cards:0x100121bb8>
like image 118
bojo Avatar answered Mar 07 '23 16:03

bojo