From: file13
Subject: Rolling Dice: Random Number Generation in CL
Date: 
Message-ID: <28d8936a.0202181333.8711b6e@posting.google.com>
Howdy, ye Wizards of Lambda!  I've been tinkering with random number
generation on various CL implementations and I'm basically wondering
if there is a better way to simulate rolling dice--i.e. faster and one
that works on ECL & GCL.  Every CL I've tried except for Clisp dosen't
generate random numbers fast enough on it's own so I tried comparing
random states (via equalp) and simply looped until they were
different.  This worked with most implmentations, but it's pretty damn
slow.

Does any one know a CL based solution to this problem--i.e. without
using something platform specific like /dev/random?

Here's what I've got so far:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;;roll-dice: The basic dice rolling function
;;;
;;;To more accruately simulate rolling multiple dice we generate
multiple
;;;numbers within the specified range and add them to create a total
as
;;;opposed to simply generating a random number within the specified
range.
;;;
;;;In order to verify that we are really getting even pseudom-random
numbers
;;;we compare the random state in a loop with equalp.  This dosen't
always
;;;work on some versions of Lisp and if it does it may be very slow
while
;;;we wait for a new random seed to appear.
;;;
;;;Tests: 2-2002 Slackware 8.0
;;;see test-randomness-1 & -2 below
;;;------------------------
;;;clisp 2.27: works + fast
;;;cmucl 18c: works + slow
;;;sbcl 0.71: works + slow
;;;gcl 2.4.0: dosen't work, but fast!
;;;ecls 0.5: dosen't work, but fast!
;;;allegro 6.1: works + slow
;;;lispworks 4.2.0: works + fast
;;;
;;;Of all of these, CLisp was the only one to generate random numbers 
;;;fast enough to not need to compare random-states.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun roll-dice (number-of-dice sides)
  "Roll a specified number of dice of a specified number of sides:
  (roll-dice number-of-dice sides)"
  (declare (type integer number-of-dice)
	   (type integer sides))
  (let ((random-tmp)
	(total-roll   0)
        (current-roll 0))
    (dotimes (roll number-of-dice total-roll)
      (setf random-tmp (make-random-state t))
      (loop
       (if (equalp random-tmp (make-random-state t)) 
           ();;loop until they are different
         (return)))
      (setf current-roll (1+ (random sides (make-random-state t))))
      (setf total-roll (+ current-roll total-roll)))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; test-randomness-1: 
;;;
;;; Tests if equalp works on random-states and peforms a test with
three six
;;; sided dice.
;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun test-randomness-1 ()
  "Tests the roll-dice function and equalp"
  (let ((random1 (make-random-state t))
	(random2 (make-random-state t)))
    (format t "Random1: ~a~%" random1)
    (format t "Random2: ~a~%" random2)
    (if (equalp random1 random2)
	(format t "~a &~%~a are equal~%" random1 random2)
      (format t "~a &~%~a are not equal~%" random1 random2))
    (dotimes (i 10 (format t "Finished~%"))
      (format t "Number: ~d~%" (+ (roll-dice 3 6))))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; test-randomness-2: 
;;;
;;; Rolls a large variety of dice combinations typically found in role
playing
;;; games.  Simulates rolling a DND character.
;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun test-randomness-2 ()
  "Tests various dice combinations"
  (format t "1d4    : ~d~%" (roll-dice 1 4))
  (format t "2d4    : ~d~%" (roll-dice 2 4))
  (format t "1d6    : ~d~%" (roll-dice 1 6))
  (format t "2d6    : ~d~%" (roll-dice 2 6))
  (format t "1d8    : ~d~%" (roll-dice 1 8))
  (format t "2d8    : ~d~%" (roll-dice 2 8))
  (format t "1d10   : ~d~%" (roll-dice 1 10))
  (format t "2d10   : ~d~%" (roll-dice 2 10))
  (format t "1d12   : ~d~%" (roll-dice 1 12))
  (format t "2d12   : ~d~%" (roll-dice 2 12))
  (format t "1d20   : ~d~%" (roll-dice 1 20))
  (format t "2d20   : ~d~%" (roll-dice 2 20))
  (format t "1d30   : ~d~%" (roll-dice 1 30))
  (format t "2d30   : ~d~%" (roll-dice 2 30))
  (format t "1d100  : ~d~%" (roll-dice 1 100))
  (format t "2d100  : ~d~%" (roll-dice 2 100))
  (format t "1d1000 : ~d~%" (roll-dice 1 1000))
  (format t "2d500  : ~d~%" (roll-dice 2 500))
  (terpri)
  (format t "STR: ~d~%" (roll-dice 3 6))
  (format t "DEX: ~d~%" (roll-dice 3 6))
  (format t "CON: ~d~%" (roll-dice 3 6))
  (format t "INT: ~d~%" (roll-dice 3 6))
  (format t "WIS: ~d~%" (roll-dice 3 6))
  (format t "CHA: ~d~%" (roll-dice 3 6)))
;;;;

Thanks all!

file13
http://www.qlippoth.com/

From: Dan Andreatta
Subject: Re: Rolling Dice: Random Number Generation in CL
Date: 
Message-ID: <Xns91B9BD6FB2C12andreattamailchemsce@12.253.140.251>
······@qlippoth.zzn.com (file13) wrote in
································@posting.google.com: 

> Howdy, ye Wizards of Lambda!  I've been tinkering with random number
> generation on various CL implementations and I'm basically wondering
> if there is a better way to simulate rolling dice--i.e. faster and one
> that works on ECL & GCL.  Every CL I've tried except for Clisp dosen't
> generate random numbers fast enough on it's own so I tried comparing
> random states (via equalp) and simply looped until they were
> different.  This worked with most implmentations, but it's pretty damn
> slow.
> 
> Does any one know a CL based solution to this problem--i.e. without
> using something platform specific like /dev/random?
> 
...snip...

What's wrong with this? Do you have any particular reason not to use 
"random"?

(defun roll-die (sides) (1+ (random sides))

(defun roll-dice (num-dice sides)
  (if (zerop num-dice) 
    '()
    (cons (roll-die faces)
          (roll-dice (1- num-dice) faces))))


-- 
Daniel Andreatta
Univ. of S. Carolina
Chemistry Dept.

Bruce I:   ... American beer is a little like making love in a canoe!
Bruce III: Making love in a canoe? 
Bruce I:   It's f***ing close to water!

--- Monty Python, "The Bruces", Live at the Holliwood Bowl
From: Geoff Summerhayes
Subject: Re: Rolling Dice: Random Number Generation in CL
Date: 
Message-ID: <hlfc8.62605$A44.3599515@news2.calgary.shaw.ca>
"file13" <······@qlippoth.zzn.com> wrote in message
································@posting.google.com...
> Howdy, ye Wizards of Lambda!  I've been tinkering with random number
> generation on various CL implementations and I'm basically wondering
> if there is a better way to simulate rolling dice--i.e. faster and one
> that works on ECL & GCL.  Every CL I've tried except for Clisp dosen't
> generate random numbers fast enough on it's own so I tried comparing
> random states (via equalp) and simply looped until they were
> different.  This worked with most implmentations, but it's pretty damn
> slow.
>
> Does any one know a CL based solution to this problem--i.e. without
> using something platform specific like /dev/random?
>
> Here's what I've got so far:
>
>
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
> ;;;
> ;;;roll-dice: The basic dice rolling function
> ;;;
> ;;;To more accruately simulate rolling multiple dice we generate
> multiple
> ;;;numbers within the specified range and add them to create a total
> as
> ;;;opposed to simply generating a random number within the specified
> range.
> ;;;
> ;;;In order to verify that we are really getting even pseudom-random
> numbers
> ;;;we compare the random state in a loop with equalp.  This dosen't
> always
> ;;;work on some versions of Lisp and if it does it may be very slow
> while
> ;;;we wait for a new random seed to appear.
> ;;;
> ;;;Tests: 2-2002 Slackware 8.0
> ;;;see test-randomness-1 & -2 below
> ;;;------------------------
> ;;;clisp 2.27: works + fast
> ;;;cmucl 18c: works + slow
> ;;;sbcl 0.71: works + slow
> ;;;gcl 2.4.0: dosen't work, but fast!
> ;;;ecls 0.5: dosen't work, but fast!
> ;;;allegro 6.1: works + slow
> ;;;lispworks 4.2.0: works + fast
> ;;;
> ;;;Of all of these, CLisp was the only one to generate random numbers
> ;;;fast enough to not need to compare random-states.
>
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
> (defun roll-dice (number-of-dice sides)
>   "Roll a specified number of dice of a specified number of sides:
>   (roll-dice number-of-dice sides)"
>   (declare (type integer number-of-dice)
>    (type integer sides))
>   (let ((random-tmp)
> (total-roll   0)
>         (current-roll 0))
>     (dotimes (roll number-of-dice total-roll)
>       (setf random-tmp (make-random-state t))
>       (loop
>        (if (equalp random-tmp (make-random-state t))
>            ();;loop until they are different
>          (return)))
>       (setf current-roll (1+ (random sides (make-random-state t))))
>       (setf total-roll (+ current-roll total-roll)))))
>

Why do you insist on constant reseeding? It could actually skew
the randomness of the results. I'd just use:

(defun roll-dice (number-of-sides sides)
  (loop for x below number-of-dice
        summing (1+ (random sides))))

--------

Geoff
From: file13
Subject: Re: Rolling Dice: Random Number Generation in CL
Date: 
Message-ID: <3C718755.3070602@qlippoth.zzn.com>
Geoff Summerhayes wrote:

> ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
> 
>>;;;
>>;;;roll-dice: The basic dice rolling function
>>;;;
>>;;;To more accruately simulate rolling multiple dice we generate
>>multiple
>>;;;numbers within the specified range and add them to create a total
>>as
>>;;;opposed to simply generating a random number within the specified
>>range.
>>;;;
>>;;;In order to verify that we are really getting even pseudom-random
>>numbers
>>;;;we compare the random state in a loop with equalp.  This dosen't
>>always
>>;;;work on some versions of Lisp and if it does it may be very slow
>>while
>>;;;we wait for a new random seed to appear.
>>;;;
>>;;;Tests: 2-2002 Slackware 8.0
>>;;;see test-randomness-1 & -2 below
>>;;;------------------------
>>;;;clisp 2.27: works + fast
>>;;;cmucl 18c: works + slow
>>;;;sbcl 0.71: works + slow
>>;;;gcl 2.4.0: dosen't work, but fast!
>>;;;ecls 0.5: dosen't work, but fast!
>>;;;allegro 6.1: works + slow
>>;;;lispworks 4.2.0: works + fast
>>;;;
>>;;;Of all of these, CLisp was the only one to generate random numbers
>>;;;fast enough to not need to compare random-states.
>>
>>
> ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
> 
>>(defun roll-dice (number-of-dice sides)
>>  "Roll a specified number of dice of a specified number of sides:
>>  (roll-dice number-of-dice sides)"
>>  (declare (type integer number-of-dice)
>>   (type integer sides))
>>  (let ((random-tmp)
>>(total-roll   0)
>>        (current-roll 0))
>>    (dotimes (roll number-of-dice total-roll)
>>      (setf random-tmp (make-random-state t))
>>      (loop
>>       (if (equalp random-tmp (make-random-state t))
>>           ();;loop until they are different
>>         (return)))
>>      (setf current-roll (1+ (random sides (make-random-state t))))
>>      (setf total-roll (+ current-roll total-roll)))))
>>
>>
> 
> Why do you insist on constant reseeding? It could actually skew
> the randomness of the results. I'd just use:
> 
> (defun roll-dice (number-of-sides sides)
>   (loop for x below number-of-dice
>         summing (1+ (random sides))))
> 
> --------
> 
> Geoff

I don't insist at all, I'm just trying to get the damn thing to work.

;)

The above works on ecls and cmucl, (THANKS Geoff!  :) but, if I don't 
seed it it gives the same random numbers every time I run certain CL's.

example on Allegro 6.1

CL-USER(1): (defun roll-dice (number-of-dice sides)
     (loop for x below number-of-dice
           summing (1+ (random sides))))
ROLL-DICE
CL-USER(2): (roll-dice 3 6)
11
CL-USER(3): (roll-dice 3 6)
6
CL-USER(4): (roll-dice 3 6)
14
----
CL-USER(1): (defun roll-dice (number-of-dice sides)
     (loop for x below number-of-dice
           summing (1+ (random sides))))
ROLL-DICE
CL-USER(2): (roll-dice 3 6)
11
CL-USER(3): (roll-dice 3 6)
6
CL-USER(4): (roll-dice 3 6)
14
CL-USER(5): (exit)
; Exiting Lisp

Maybe this is just an Allegro problem....?

Any suggestions to get this to work under Allegro--and possibly others, 
don't have them all to test on this machine....?

file13
http://www.qlippoth.com/
From: Nils Goesche
Subject: Re: Rolling Dice: Random Number Generation in CL
Date: 
Message-ID: <a4s1po$2jter$2@ID-125440.news.dfncis.de>
In article <················@qlippoth.zzn.com>, file13 wrote:
> The above works on ecls and cmucl, (THANKS Geoff!  :) but, if I don't 
> seed it it gives the same random numbers every time I run certain CL's.

Does it help if you execute (setf *random-state* (make-random-state t))
once after starting Lisp?

Regards,
-- 
Nils Goesche
"Don't ask for whom the <CTRL-G> tolls."

PGP key ID 0x42B32FC9
From: file13
Subject: Re: Rolling Dice: Random Number Generation in CL
Date: 
Message-ID: <3C71A741.1040108@qlippoth.zzn.com>
Nils Goesche wrote:
> In article <················@qlippoth.zzn.com>, file13 wrote:
> 
>>The above works on ecls and cmucl, (THANKS Geoff!  :) but, if I don't 
>>seed it it gives the same random numbers every time I run certain CL's.
>>
> 
> Does it help if you execute (setf *random-state* (make-random-state t))
> once after starting Lisp?
> 
> Regards,
> 

It does.  Thank you!  I must have been smoking too much crack when I 
first did this because I have no clue why I missed that...same in every 
other language....  Originally I had it this way--except with not with 
using the above setf and using doloop because the Lisp book I have is 
old and obviously not up to date with these nifty loop extensions you 
speak of.  I guess since Allegro and Clisp (which I use the most at this 
time) both need the *random-state* set every time I had figured that I 
was doing something wrong and probably got side tracked  by

http://www.lisp.org/HyperSpec/Body/fun_random.html#random

Examples:

(<= 0 (random 1000) 1000) => true
(let ((state1 (make-random-state))
        (state2 (make-random-state)))
    (= (random 1000 state1) (random 1000 state2))) => true

Oh well, the light bulb is lit and I thank you all!

file13
http://www.qlippoth.com/
From: Pierre R. Mai
Subject: Re: Rolling Dice: Random Number Generation in CL
Date: 
Message-ID: <87n0y64c5o.fsf@orion.bln.pmsf.de>
······@qlippoth.zzn.com (file13) writes:

> Howdy, ye Wizards of Lambda!  I've been tinkering with random number
> generation on various CL implementations and I'm basically wondering
> if there is a better way to simulate rolling dice--i.e. faster and one
> that works on ECL & GCL.  Every CL I've tried except for Clisp dosen't
> generate random numbers fast enough on it's own so I tried comparing
> random states (via equalp) and simply looped until they were
> different.  This worked with most implmentations, but it's pretty damn
> slow.
> 
> Does any one know a CL based solution to this problem--i.e. without
> using something platform specific like /dev/random?

Since you have no guarantee at all about the source of the "random"
seed that underlies (make-random-state t), I would never trust this
approach to produce true random variables[1].  In fact I think that
(make-random-state t) is rarely -- if ever -- a sensible thing to do.

You will have to decide whether you really need _true_ random
numbers.  If that's the case then the whole random facility of CL is
of no use to you, since it is about _pseudo-random number
generation_.  You will have to use at least something like /dev/random
(or the entropy gathering daemon, which is slightly more portable),
and better still a measurement device that measures a truly random
process, like radioactive decay.  Be prepared to go to great lengths
to get large numbers of true random numbers at high rates.

OTOH I don't see why you'd need true random numbers to usefully
simulate the rolling of dices.  A good quality PRNG, with known
high-dimensional equidistribution, like e.g. MT19337 should suffice.
In that case you can use the random implementations of CMU CL or ACL
out of the box.  Or investigate the underlying algorithms of the PRNGs
in the other implementations, to decide whether they are of sufficient
quality for your experiments.

Regs, Pierre.


Footnotes: 
[1]  It might just be the current unix time, in seconds, or the
     process run-time, etc, which as we all know are not very random
     at all.  That doesn't matter that much for seeding a PRNG, but it
     is truly evil if you repeatedly sample it directly and use those
     samples as some kind of sequence of random numbers.

-- 
Pierre R. Mai <····@acm.org>                    http://www.pmsf.de/pmai/
 The most likely way for the world to be destroyed, most experts agree,
 is by accident. That's where we come in; we're computer professionals.
 We cause accidents.                           -- Nathaniel Borenstein
From: file13
Subject: Re: Rolling Dice: Random Number Generation in CL
Date: 
Message-ID: <3C71A7AA.2080607@qlippoth.zzn.com>
Pierre R. Mai wrote:
> OTOH I don't see why you'd need true random numbers to usefully
> simulate the rolling of dices.  A good quality PRNG, with known
> high-dimensional equidistribution, like e.g. MT19337 should suffice.
> In that case you can use the random implementations of CMU CL or ACL
> out of the box.  Or investigate the underlying algorithms of the PRNGs
> in the other implementations, to decide whether they are of sufficient
> quality for your experiments.

I don't.  I should have mentioned "pseudo-random" instead of inferring 
it by mentioning /dev/random.  My bad.

file13
http://www.qlippoth.com/
From: Harald Hanche-Olsen
Subject: Re: Rolling Dice: Random Number Generation in CL
Date: 
Message-ID: <pcoadu6jpz6.fsf@thoth.math.ntnu.no>
+ ······@qlippoth.zzn.com (file13):

| I've been tinkering with random number generation on various CL
| implementations and I'm basically wondering if there is a better way
| to simulate rolling dice [...]

| (defun roll-dice (number-of-dice sides)
|   "Roll a specified number of dice of a specified number of sides:
|   (roll-dice number-of-dice sides)"
|   (declare (type integer number-of-dice)
| 	   (type integer sides))
|   (let ((random-tmp)
| 	(total-roll   0)
|         (current-roll 0))
|     (dotimes (roll number-of-dice total-roll)
|       (setf random-tmp (make-random-state t))
|       (loop
|        (if (equalp random-tmp (make-random-state t)) 
|            ();;loop until they are different
|          (return)))
|       (setf current-roll (1+ (random sides (make-random-state t))))
|       (setf total-roll (+ current-roll total-roll)))))

Ouch.  You suffer a surprisingly common misunderstanding about what a
pseudo-random number generator supposedly does.  You're supposed to
start it only once (using make-random-state, though even that is
unnecessary - the Lisp system will have done it for you).

So just throw away all the code that messes around with
make-random-state, and simply call (random sides).  It's perhaps
possible (?) that some implementations will always start with the same
random state, in which case I suppose starting your program with

(setf *random-state* (make-random-state t))

should help.

If you need true randomness, rather than pseudo-randomness, there is
not likely to be any fast method available unless you have a dedicated
hardware random number generator attached to your machine.

-- 
* Harald Hanche-Olsen     <URL:http://www.math.ntnu.no/~hanche/>
- Yes it works in practice - but does it work in theory?
From: file13
Subject: Re: Rolling Dice: Random Number Generation in CL
Date: 
Message-ID: <3C71A938.70107@qlippoth.zzn.com>
Harald Hanche-Olsen wrote:
> Ouch.  You suffer a surprisingly common misunderstanding about what a
> pseudo-random number generator supposedly does.  You're supposed to
> start it only once (using make-random-state, though even that is
> unnecessary - the Lisp system will have done it for you).

Well why does:

http://www.lisp.org/HyperSpec/Body/fun_make-random-state.html#make-random-state

set multiple random states in the example and why does random take an 
optional random state if your not supposed to do it?

> So just throw away all the code that messes around with
> make-random-state, and simply call (random sides).  It's perhaps
> possible (?) that some implementations will always start with the same
> random state, in which case I suppose starting your program with
 >
> (setf *random-state* (make-random-state t))
> 
> should help.

It does.  Your karma has increased.  Thank you.  :)

> If you need true randomness, rather than pseudo-randomness, there is
> not likely to be any fast method available unless you have a dedicated
> hardware random number generator attached to your machine.

Again, my bad, pseudo-random.  This isen't cryptography.  Just a silly 
function....  ;)

file13
http://www.qlippoth.com/portal.html
From: Christopher Browne
Subject: Re: Rolling Dice: Random Number Generation in CL
Date: 
Message-ID: <m3it8u9o2x.fsf@chvatal.cbbrowne.com>
In an attempt to throw the authorities off his trail, file13 <······@qlippoth.zzn.com> transmitted:
> Harald Hanche-Olsen wrote:
>> Ouch.  You suffer a surprisingly common misunderstanding about what
>> a pseudo-random number generator supposedly does.  You're supposed
>> to start it only once (using make-random-state, though even that is
>> unnecessary - the Lisp system will have done it for you).

> Well why does:

> http://www.lisp.org/HyperSpec/Body/fun_make-random-state.html#make-random-state

> set multiple random states in the example and why does random take
> an optional random state if your not supposed to do it?

You're supposed to introduce a a new random state when you _need_ to.

The example in the HyperSpec is there to show the various ways seeding
can happen; ignoring rs4, which is kind of the pathological case, the
others largely involve copying and aliasing RNG seeds.  And note that
for most of the states, they wind up using 10 values without any
reseeding.

If you're running a Monte-Carlo simulation, for instance, and want to
have it be repeatable, you'll be regularly reseeding at the start of
each run that is to be repeatable.  That's exactly the kind of
scenario where precise manipulation of *random-state* is necessary; if
you're trying to make things "maximally random," reseeding continually
is certainly NOT the way to go...

>> So just throw away all the code that messes around with
>> make-random-state, and simply call (random sides).  It's perhaps
>> possible (?) that some implementations will always start with the same
>> random state, in which case I suppose starting your program with
>  >
>> (setf *random-state* (make-random-state t))
>> should help.
>
> It does.  Your karma has increased.  Thank you.  :)
>
>> If you need true randomness, rather than pseudo-randomness, there is
>> not likely to be any fast method available unless you have a dedicated
>> hardware random number generator attached to your machine.
>
> Again, my bad, pseudo-random.  This isen't cryptography.  Just a silly
> function....  ;)

... And when I want things to _definitely_ not repeat, I grab a few
bytes from my system's /dev/urandom device, and use that to modify the
state a little bit.

(defun seed-random-generator-a-little ()
  "Evaluate a random number of items"
  (let ((randfile (make-pathname 
		   :directory '(:absolute "dev") 
		   :name "urandom")))
    (if (probe-file randfile)
      (with-open-file
       (rfs randfile :element-type 'unsigned-byte)
       (let* 
;	   ((seed (char-code (read-char rfs))))
	   ((seed (read-byte rfs)))
	 ;(format t "Randomizing!~%")
	 (loop
	  for item from 1 to seed
	  do (loop
	       for it from 0 to (+ (read-byte rfs) 5)
	       do (random 65536))))))))

And doing a 
  (setf *random-state* (make-random-state t))
after running (seed-random-generator-a-little) will eliminate any
randomness that could possibly have been introduced by that...
-- 
(reverse (concatenate 'string ···········@" "enworbbc"))
http://www3.sympatico.ca/cbbrowne/oses.html
"...  They are  not ``end  users'' until  someone presupposes  them as
such, as witless cattle." -- <·····@onshore.com>
From: file13
Subject: Re: Rolling Dice: Random Number Generation in CL
Date: 
Message-ID: <3C726DDB.4090000@qlippoth.zzn.com>
Christopher Browne wrote:
> In an attempt to throw the authorities off his trail, file13 <······@qlippoth.zzn.com> transmitted:
> 
>>Harald Hanche-Olsen wrote:
>>
>>>Ouch.  You suffer a surprisingly common misunderstanding about what
>>>a pseudo-random number generator supposedly does.  You're supposed
>>>to start it only once (using make-random-state, though even that is
>>>unnecessary - the Lisp system will have done it for you).
>>>
> 
>>Well why does:
>>
> 
>>http://www.lisp.org/HyperSpec/Body/fun_make-random-state.html#make-random-state
>>
> 
>>set multiple random states in the example and why does random take
>>an optional random state if your not supposed to do it?
>>
> 
> You're supposed to introduce a a new random state when you _need_ to.
> 
> The example in the HyperSpec is there to show the various ways seeding
> can happen; ignoring rs4, which is kind of the pathological case, the
> others largely involve copying and aliasing RNG seeds.  And note that
> for most of the states, they wind up using 10 values without any
> reseeding.
> 
> If you're running a Monte-Carlo simulation, for instance, and want to
> have it be repeatable, you'll be regularly reseeding at the start of
> each run that is to be repeatable.  That's exactly the kind of
> scenario where precise manipulation of *random-state* is necessary; if
> you're trying to make things "maximally random," reseeding continually
> is certainly NOT the way to go...
> 
> 
>>>So just throw away all the code that messes around with
>>>make-random-state, and simply call (random sides).  It's perhaps
>>>possible (?) that some implementations will always start with the same
>>>random state, in which case I suppose starting your program with
>>>
>> >
>>
>>>(setf *random-state* (make-random-state t))
>>>should help.
>>>
>>It does.  Your karma has increased.  Thank you.  :)
>>
>>
>>>If you need true randomness, rather than pseudo-randomness, there is
>>>not likely to be any fast method available unless you have a dedicated
>>>hardware random number generator attached to your machine.
>>>
>>Again, my bad, pseudo-random.  This isen't cryptography.  Just a silly
>>function....  ;)
>>
> 
> ... And when I want things to _definitely_ not repeat, I grab a few
> bytes from my system's /dev/urandom device, and use that to modify the
> state a little bit.
> 
> (defun seed-random-generator-a-little ()
>   "Evaluate a random number of items"
>   (let ((randfile (make-pathname 
> 		   :directory '(:absolute "dev") 
> 		   :name "urandom")))
>     (if (probe-file randfile)
>       (with-open-file
>        (rfs randfile :element-type 'unsigned-byte)
>        (let* 
> ;	   ((seed (char-code (read-char rfs))))
> 	   ((seed (read-byte rfs)))
> 	 ;(format t "Randomizing!~%")
> 	 (loop
> 	  for item from 1 to seed
> 	  do (loop
> 	       for it from 0 to (+ (read-byte rfs) 5)
> 	       do (random 65536))))))))
> 
> And doing a 
>   (setf *random-state* (make-random-state t))
> after running (seed-random-generator-a-little) will eliminate any
> randomness that could possibly have been introduced by that...
> 

Thank you Christopher!  The example of /dev/urandom is a great touch. 
Hopefully many other apprentices won't have to stumble over the same 
stuff in the future on our long road to Lambda Wizardry....  :)

And thanks all for your input.

file13
http://www.qlippoth.com/
From: Tim Bradshaw
Subject: Re: Rolling Dice: Random Number Generation in CL
Date: 
Message-ID: <ey3lmdqz1n5.fsf@cley.com>
* file13  wrote:
> Well why does:

> http://www.lisp.org/HyperSpec/Body/fun_make-random-state.html#make-random-state

> set multiple random states in the example and why does random take an
> optional random state if your not supposed to do it?

This is all so you can repeat sequences of pseudorandom numbers, which
is useful if you want to, say test algorithms on *identical* but
randomly-distributed data.

--tim
From: Thomas A. Russ
Subject: Re: Rolling Dice: Random Number Generation in CL
Date: 
Message-ID: <ymieljhf1i7.fsf@sevak.isi.edu>
······@qlippoth.zzn.com (file13):

| I've been tinkering with random number generation on various CL
| implementations and I'm basically wondering if there is a better way
| to simulate rolling dice [...]

| (defun roll-dice (number-of-dice sides)
|   "Roll a specified number of dice of a specified number of sides:
|   (roll-dice number-of-dice sides)"
|   (declare (type integer number-of-dice)
| 	   (type integer sides))
|   (let ((random-tmp)
| 	(total-roll   0)
|         (current-roll 0))
|     (dotimes (roll number-of-dice total-roll)
|       (setf random-tmp (make-random-state t))
|       (loop
|        (if (equalp random-tmp (make-random-state t)) 
|            ();;loop until they are different
|          (return)))
|       (setf current-roll (1+ (random sides (make-random-state t))))
|       (setf total-roll (+ current-roll total-roll)))))

Hmmm.  Wouldn't the following be a much simpler solution?  Note that I
changed the declaration of the types to be fixnum rather than integer.
Since integer allows both fixnums and bignums, it is normally not
optimized by most Lisp compilers.

(defun roll-dice (number-of-dice sides)
   "Roll a specified number of dice of a specified number of sides:
    (roll-dice number-of-dice sides)"
  (declare (type fixnum number-of-dice sides))
  (let ((total-roll 0))
    (declare (type fixnum total-roll))
    (dotimes (roll number-of-dice)
      ;; 1+ since random returns an integer in 0 .. (sides - 1)
      (incf total-roll (1+ (the fixnum (random sides)))))))

-- 
Thomas A. Russ,  USC/Information Sciences Institute          ···@isi.edu    
From: Gareth McCaughan
Subject: Re: Rolling Dice: Random Number Generation in CL
Date: 
Message-ID: <slrna765dn.3fc.Gareth.McCaughan@g.local>
file13 wrote:

> Howdy, ye Wizards of Lambda!  I've been tinkering with random number
> generation on various CL implementations and I'm basically wondering
> if there is a better way to simulate rolling dice--i.e. faster and one
> that works on ECL & GCL.  Every CL I've tried except for Clisp dosen't
> generate random numbers fast enough on it's own so I tried comparing
> random states (via equalp) and simply looped until they were
> different.  This worked with most implmentations, but it's pretty damn
> slow.

Other people have already commented on the fact that reseeding
all the time is a Bad Idea. I'm puzzling about something else.
Your sample code makes it look as if this is for a role-playing
game or something, in which case why on earth do you care how
fast it is? (I can imagine it would matter if rolling each die
took, say, a second, but surely it can't be close to that slow
even if you reseed each time, can it?)

-- 
Gareth McCaughan  ················@pobox.com
.sig under construc
From: file13
Subject: Re: Rolling Dice: Random Number Generation in CL
Date: 
Message-ID: <3C73C88E.4080305@qlippoth.zzn.com>
Gareth McCaughan wrote:
> file13 wrote:
>  This worked with most implmentations, but it's pretty damn
>>slow.
>>
> 
> Other people have already commented on the fact that reseeding
> all the time is a Bad Idea. I'm puzzling about something else.
> Your sample code makes it look as if this is for a role-playing
> game or something, in which case why on earth do you care how
> fast it is? (I can imagine it would matter if rolling each die
> took, say, a second, but surely it can't be close to that slow
> even if you reseed each time, can it?


Uh, it's pretty damn slow on Allegro & CMUCL--especially on my ghetto 
fabulous 166mhz Slackware box (try it!  :)  This should probably go down 
as one of the worst, most round about ways to do something in 
Lisp--outside of say using stuff like symbol-function instead of defun 
to make it even more absurd....  ;)

It's not for anything important.  We all write silly little functions 
when learning a new language and that's all this is.  I really don't 
care if it's a bit slow, but at the same time I know that it should NOT 
be THIS slow and therefore I must be doing something wrong--i.e. the 
design is crap.

Overall Lisp has been very pleasant (and lots of fun) to learn and I 
haven't run into any snags that I couldn't figure out on my own--with my 
books or online--besides this one.  There's really not much mystery to 
it.  I just got off on a tangent and totally missed the simple fact that 
one needs to seed the global *random-state*--which is pretty much the 
same concept in any other language when generating pseudo-random numbers

srand(time(0));  /* in C */
Seed : Generator;  -- in Ada
Random.self_init();;  (* in Ocaml *)

I think the brain cell where that data resided must have gotten wipped 
out at the pub....  ;)

but everyone at CLL has been great and I appreciate all the input.  It's 
always nice touch to have a cool community--especially for such a kick 
ass language as Lisp.

file13
http://www.qlippoth.com/