You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

67 lines
2.4 KiB

4 years ago
4 years ago
(in-package :cl-rng)
4 years ago
4 years ago
(defparameter *default-precision* 1
4 years ago
"Default precision for the default RNG provider")
4 years ago
(defparameter *default-randomness-provider* #'(lambda (&rest args) (apply #'crandom (append `(:precision ,*default-precision*) args)))
4 years ago
"The default randomness provider used by cl-rng functions")
4 years ago
4 years ago
(defun chance (fraction &key (provider *default-randomness-provider*))
4 years ago
"Returns T if chance fraction is met"
4 years ago
(< (funcall provider) fraction))
4 years ago
4 years ago
(defun weighted (weights &key (default nil) (provider *default-randomness-provider*))
4 years ago
"Interpret weights as an alist where the key is the item and the value is the chance. If no chances are met, return default"
4 years ago
(let ((previous 0)
(result (funcall provider))
(rval default))
(mapc (lambda (x)
(let ((value (car x))
(weight (cdr x)))
(and (>= result previous)
(<= result (+ previous weight))
(setf rval value))
(incf previous weight)))
weights)
(values rval result)))
4 years ago
(export 'weighted)
4 years ago
(defun shuffle! (sequence &key (provider *default-randomness-provider*))
4 years ago
"In-place shuffle a sequence"
4 years ago
(if (listp sequence)
(loop for i from (1- (length sequence)) above 0 do
(rotatef (nth i sequence)
(nth (funcall provider :limit i :transform #'floor) sequence)))
(loop for i from (1- (length sequence)) above 0 do
(rotatef (aref sequence i)
(aref sequence (funcall provider :limit i :transform #'floor)))))
sequence)
4 years ago
(defun within (sequence &key (provider *default-randomness-provider*))
"A random value withing a sequence. Can be setf()'d"
(if (listp sequence)
(nth (funcall provider :limit (1- (length sequence)) :transform 'round) sequence)
(aref sequence (funcall provider :limit (1- (length sequence)) :transform 'round))))
(defun within-set (sequence value)
(let ((index (funcall *default-randomness-provider* :limit (1- (length sequence)) :transform 'round)))
(if (listp sequence)
(setf (nth index sequence) value)
(setf (aref sequence index) value))))
4 years ago
4 years ago
(defun range (start end &key (integral nil) (provider *default-randomness-provider*))
"A random number in a range"
(+ start (funcall provider :limit (- end start) :transform (if integral 'round 'identity))))
;; Exports
(export '*default-randomness-provider*)
4 years ago
(export '*default-precision*)
4 years ago
(defsetf within within-set)
(export 'range)
(export 'within)
(export 'shuffle!)
(export 'chance)