(defvar *initialized-p* nil)

(defun ensure-positive (number)
  (if (< number 0)
      (- number)
      number))

(defun ensure-initialized ()
  (when (not *initialized-p*)
    (setq *random-state* (make-random-state t)
          *initialized-p* t)
    (dotimes (number (ensure-positive (random 100)))
      (dotimes (other (ensure-positive (random (1+ number))))
        (dotimes (yet-another (ensure-positive (random (1+ other))))
          (ensure-positive (random (1+ yet-another))))))))

(defun flip-coin (stream number)
  (ensure-initialized)
  (format stream "Flipping ~a coins.~&" number)
  (dotimes (n number)
    (if (= (mod (random 100) 2) 0)
        (format stream "Heads.~&")
        (format stream "Tails.~&"))))

(defun roll-die (stream number type)
  (ensure-initialized)
  (format stream "Rolling a ~a-sided die ~a times.~&" type number)
  (dotimes (n number)
    (let ((die (1+ (mod (ensure-positive (random (* 100 type))) type))))
      (format stream "You rolled a ~a.~&" die))))

(defun main ()
  (let ((type (if (not (null (second *posix-argv*)))
                  (intern (string-upcase (second *posix-argv*)) "KEYWORD")))
        (times (if (and (not (null (second *posix-argv*)))
                      (not (null (third *posix-argv*))))
                   (parse-integer (third *posix-argv*) :junk-allowed t)
                   1)))
    (case type
      (:die
       (roll-die *standard-output* times (if (not (null (fourth *posix-argv*)))
                                             (parse-integer (fourth *posix-argv*) :junk-allowed t)
                                             6)))
      (:coin
       (flip-coin *standard-output* times))
      (t
       (format *standard-output*
               "decide [ die [ times [ type ] ] | coin [ times ] ]~&")))))
