;;; Port of https://en.wikipedia.org/wiki/ModernPascal#Code_Sample[3]. ;;; And then to CL. ;;; I prefer my version. (defconstant +max-probability+ 1000) ;; Because this is a simple enum and not a full sum/product type, ;; I use symbols instead of CLOS. (defconstant +loot-type+ (vector 'bloodstone 'copper 'emeraldite 'gold 'heronite 'platinum 'shadownite 'silver 'soranite 'umbrarite 'cobalt 'iron 'nothing)) (defclass () ((probabilities :accessor probabilities))) (defgeneric choose (self)) (defmethod choose ((self )) (let ((random-value (random (- +max-probability+ 1)))) (do ((loop 0 (+ loop 1))) ((>= (elt (probabilities self) (mod loop 13)) random-value) (elt +loot-type+ (mod loop 13)))))) (defmethod initialize-instance :after ((self ) &rest initargs) (setf (probabilities self) (vector 10 77 105 125 142 159 172 200 201 202 216 282 +max-probability+))) (defun as-string (l) ;; Could use assoc here, but this is closer to the original. ;; Also saves translating nil to "". (case l ((bloodstone) "Bloodstone") ((copper) "Copper") ((emeraldite) "Emeraldite") ((gold) "Gold") ((heronite) "Heronite") ((platinum) "Platinum") ((shadownite) "Shadownite") ((silver) "Silver") ((soranite) "Soranite") ((umbrarite) "Umbrarite") ((cobalt) "Cobalt") ((iron) "Iron") (t ""))) (defun main () (let ((loot (make-instance (find-class ')))) (do ((n 0 (+ n 1))) ((> n 99)) (format *standard-output* "~A~%" (as-string (choose loot)))))) (main)