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