When using Shuffle Array # Ruby allows you to use a custom randomizer and even provides a Random class to use it. The following example uses a class with an initial value of 48.
array = [1,2,3,4,5,6,7,8,9,10] array.shuffle(random: Random.new(48))
I wrote a small one-bit test to find out how many times the value appeared first in the shuffled array.
deck = (1..10).to_a counts = Hash.new(0) rng = Random.new 50000.times do counts[deck.shuffle(random: rng).first] += 1 end 1.upto(10) do |card| puts "#{card}:\t#{counts[card]}" end
The result looks something like this:
1: 4942 2: 5100 3: 4938 4: 4960 5: 5024 6: 4992 7: 5184 8: 4930 9: 4916 10: 5014
Suppose I want to replace the pseudo random number generator with a new class. Since Array # shuffle seems to be using Random # rand in the example above, it would be easy to implement a new class to act as an RNG for shuffling. Here I am implementing a new pseudo-random number generator, which is actually just a simple wrapper around rand :
deck = (1..10).to_a counts = Hash.new(0) class FooRandom def rand(max=nil) max.nil? ? Kernel::rand : Kernel::rand(max) end end rng = FooRandom.new 50000.times do counts[deck.shuffle(random: rng).first] += 1 end 1.upto(10) do |card| puts "#{card}:\t#{counts[card]}" end
This, however, does not work as expected. FooRandom#rand is called, but shuffling creates the following distribution:
1: 0 2: 5423 3: 5562 4: 5544 5: 5512 6: 5569 7: 5535 8: 5595 9: 5524 10: 5736
As you can see, the value of array 1 never appears in the first position of the array after shuffling the array. Does anyone have an idea why?