On Fri, Aug 15, 2008 at 11:33 AM, Matthew Moss <matthew.moss / gmail.com> wrote: > ## Not So Random (#173) > > 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. > > 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. Since a single Ruby process only has one PRNG, slave off an extra process for each Random class: #!/usr/bin/env ruby require 'rubygems' require 'slave' class Random def initialize(ceiling, seed = nil) @ceiling = ceiling @seed = seed || rand(2112) @slave = Slave::new{ lambda {|reset| if reset srand(@seed) else rand(@ceiling) end } } self.reset end def next @slave.object.call(false) end def reset @slave.object.call(true) end end require 'test/unit' class RandomTest < Test::Unit::TestCase def test_001 x = Random.new(100, 2112) assert_equal( [38, 1, 5, 57, 11], Array.new(5) { x.next }) assert_equal( [ 1, 31, 3, 56, 14], Array.new(5) { x.next }) x.reset assert_equal( [38, 1, 5, 57, 11], Array.new(5) { x.next }) end def test_002 x = Random.new(100, 2112) assert_equal( [38, 1, 5, 57, 11], Array.new(5) { x.next }) y = Random.new(100, 1221) assert_equal( [ 5, 99, 88, 48, 86], Array.new(5) { y.next }) x.reset assert_equal( [38, 1, 5, 57, 11], Array.new(5) { x.next }) assert_equal( [34, 28, 72, 77, 87], Array.new(5) { y.next }) assert_equal( [ 1, 31, 3, 56, 14], Array.new(5) { x.next }) end end Loaded suite foo Started .. Finished in 0.251163 seconds. 2 tests, 8 assertions, 0 failures, 0 errors