rubymarkdown

Ruby Koans : Test two different sets of dices who have same values


I am working through the Ruby Koans(A tutorial project of Ruby). In the About_Dice_Project, it's demanded to create a class named DiceSet. I succeed, but there is a interesting question.

Here's the code :

class DiceSet

  # Attribute reader
  attr_reader :values

  # Initializer
  def initialize
    @values = []
  end

  # Roll method
  def roll(dice_amount)
    @values = Array.new(dice_amount) { rand(1..6) }
  end
end

And this test is interesting :

def test_dice_values_should_change_between_rolls
    dice = DiceSet.new

    dice.roll(5)
    first_time = dice.values

    dice.roll(5)
    second_time = dice.values

    assert_not_equal first_time, second_time,
      "Two rolls should not be equal"
  end

THINK ABOUT IT:

If the rolls are random, then it is possible (although not likely) that two consecutive rolls are equal. What would be a better way to test this?

My idea is to test the object_id of first_time and second_time, using assert_not_equal first_time.object_id, second_time.object_id. It works but am i right ? As a beginner in Ruby and programming, what is an object_id indeed ? By the way, is it possible to justify the text in markdown ?

Any help will be appreciated !


Solution

  • object_ids and equality

    You shouldn't compare object_ids, but values.

    a = [1, 2, 3]
    b = [1, 2, 3]
    
    puts a == b
    #=> true
    puts a.object_id == b.object_id
    #=> false
    

    By comparing object_ids, you're testing if variables refer to the exact same object. In your case, first_time and second_time are created independently from each others, so they cannot reference the same object. They can have the same values, though.

    Think about it

    One way to ensure that no two consecutive rolls are equal would be to use a while loop :

    class DiceSet
      # Attribute reader
      attr_reader :values
    
      # Initializer
      def initialize
        @values = []
        @last_values = []
      end
    
      # Roll method
      def roll(dice_amount)
        while @values == @last_values
          @values = Array.new(dice_amount) { rand(1..6) }
        end
        @last_values = @values
        @values
      end
    end
    
    dice = DiceSet.new
    
    dice.roll(5)
    first_time = dice.values
    
    dice.roll(5)
    second_time = dice.values # <-- cannot be equal to first_time