-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
The three rules of Ruby Q. 2:
-
Please do not post any solutions or spoiler discussion for this
quiz until 48 hours have passed from the time on this message. -
Support Ruby Q. 2 by submitting ideas as often as you can! (A
permanent, new website is in the works for Ruby Q. 2. Until then,
please visit the temporary website at -
Enjoy!
Suggestion: A [QUIZ] in the subject of emails about the problem
helps everyone on Ruby T. follow the discussion. Please reply to
the original quiz message, if you can.
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Not So Random (#173)
As part of Ruby’s standard library, we have access to a good
pseudorandom number generator (PRNG), the Mersenne twister. (In
particular, the MT19937 variant.) Ruby provides two kernel functions
to make use of this generator: srand and rand. This week’s quiz
involves generating random numbers in a predictable manner.
The first part is to create a wrapper around the random number
generator rand, supporting the appropriate parameter (i.e. the
parameter intrinsic to rand). Your wrapper should implement two
additional functions: next which returns the next random number, and
reset which restarts the sequence. So, for example:
irb> x = Random.new(100)
=> #<Random:...>
irb> Array.new(5) { x.next }
=> [51, 92, 14, 71, 60]
irb> Array.new(5) { x.next }
=> [20, 82, 86, 74, 74]
irb> x.reset
=> nil
irb> Array.new(5) { x.next }
=> [51, 92, 14, 71, 60] # after reset, sequence restarts
You may do this as a class, as depicted here, or as a function,
lambda, code block… whatever you like.
The second part is a little trickier: creating multiple, concurrent,
reproducible sequences of pseudorandom numbers isn’t so easy. As
convenient as the built-in generator is, there is only one seed. For
example, assume we have two Random objects, created as shown above,
x and y.
irb> x = Random.new(100)
=> #<Random:...>
irb> Array.new(6) { x.next }
=> [51, 92, 14, 71, 60, 20]
irb> y = Random.new(100)
=> #<random:...>
irb> Array.new(6) { y.next }
=> [66, 92, 98, 17, 83, 57]
irb> x.reset
=> nil
irb> Array.new(2) { x.next }
=> [51, 92] # ok: sequence restarted as requested
irb> Array.new(2) { y.next }
=> [14, 71] # fail: this is part of _x_ sequence
irb> Array.new(2) { x.next }
=> [60, 20] # more fail: _x_ is now [51, 92, 60, 20]? wrong...
The reason for the failure should be obvious: my current
implementation of Random just blindly uses srand and rand
without considering that there may be multiple instances of Random.
So, for this second part, expand your wrapper to support concurrent
use. Please note that you are required to make use of the built-in
generator: you should not implement your own PRNG.
One final note… It is up to you whether the seed for each wrapper
will be user-settable or hidden (as in my examples above). However, if
hidden, each wrapper should have a different seed. (Generated
randomly, perhaps?)
This language is a new discovery and it fascinates me,