(load "functionals-base.lsp")
(load "functionals.lsp")

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Random number exercise
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Using a random number generator you can simulate throws of a die.
;; Consider an experiment that throws a die n times and counts the number of
;; times each die value (1 ..6) occurs in the list.  Write a series
;; of functions that culminates in a function trials that produces the
;; results of trying the experiment p times with each experiment throwing
;; the die q times. 

;; Generate a random number from  0 < seed < 1.0
;; Many Lisps have random builtin, including Clisp.  You should use the
;; built-in function as this one is not that good.

(defun random-0 (seed)
 (funcall #'(lambda (r) (- r (float (floor r))))
     (* seed 147.0)
))

;; Generate a sequence of length n of random numbers in the range
;; 0 < number < 1.0 beginning with a seed value such as sin(0.1).

(defun randlist-0 (n seed) (genlist seed 'random-0 n))

;; Generate an integer in the range i..j from a random number r,
;; such that 0 < r < 1.0.  r gives the proportional distance from i to j.
;; This is a uniform distribution.

(defun randint-0 (i j r) (+ i (floor (* r (1+ (- j i))))))

;; Generate a random list of length n of integers in the range p..q
;; starting with a seed such that 0 < seed < 1.0 .
;; Notice the use of the general purpose curry functional to bind the
;; parameters i and j of randint-0 to the values p and q.  Two calls to
;; curry are needed as each call binds one parameter value.

(defun randintlist (p q n seed)
 (mapcar (curry (curry 'randint-0 1 3 p) 1 2 q)
         (randlist-0 n seed)))

;; Generate a list of length n of random seed values so that a list of
;; lists of random numbers can be generated.  One list for each
;; experimental run.

(defun seedlist (n) (mapcar (comp 'abs 'sin) (range 1 n)))

;; Generate the result of one experimental run of die throws.  The function
;; uses the more general purpose randintist function and hides the
;; arguments specific to the values on a die.

(defun die-throws (n seed) (randintlist 1 6 n seed))

;; Count the number of times each die value occurs in a list of die throws.

(defun count-die-values (throws)
  (mapcar (bu (rev 'count) throws) (range 1 6)))

;; Generate a list of n trials of some experiment (a function to apply)
;; with each trial starting with a different seed value.

(defun trials (experiment n)
  (mapcar experiment (seedlist n)))

;; Finaly, do 3 experimental runs of die throws, each run is 100 throws.

(trials (comp 'count-die-values (bu 'die-throws 100)) 3)



