(defclass dice ()
  ((prob-dist :initarg :prob-dist)
   threshold))

(defmethod initialize-instance :after ((dice dice) &rest initargs)
  (with-slots ((prob-dist prob-dist) (threshold threshold)) dice
    (setf threshold
	  (nreverse (let ((sum (apply #'+ prob-dist)))
		      (reduce (lambda (a b) (cons (+ (car a) (/ b sum)) a))
			      prob-dist
			      :initial-value (list 0)))))))

(defmethod roll ((dice dice))
  (position (random 1.0) (slot-value dice 'threshold)
	    :test #'<=))

(defun count-dice (prob-dist)
  (loop with dice = (make-instance 'dice :prob-dist prob-dist)
	with count = (make-array (length prob-dist) :initial-element 0)
	repeat 1e5
	do (incf (elt count (1- (roll dice))))
	finally (loop for c across count
		      for i upfrom 1
		      do (format t "~a: ~a~%" i c))))

(count-dice '(1 2 1 2 1 2))
(count-dice (loop for i from 1 to 4 collect (sqrt i)))