point-buy.el
(defun d (x y)
"Roll XdY."
(let ((total 0))
(dotimes (i x)
(setq total (+ total 1 (random y))))
total))
;; (d 1 20) => 13
(defun roll (d)
"Roll 3d6, or 4d6 and drop the lowest dice."
(cond ((= d 3)
(d 3 6))
((= d 4)
(let ((rolls (mapcar (lambda (i) (d 1 6)) '(1 2 3 4))))
(- (apply '+ rolls) (apply 'min rolls))))
(t (error "Only takes 3 or 4 as an argument"))))
;; (mapcar (lambda (ignore) (roll 4)) (make-list 10 nil))
;; => (12 13 16 14 10 9 13 14 14 8)
(defun bonus (ability)
"Return the ABILITY bonus."
(- (/ ability 2) 5))
;; (mapcar 'bonus '(6 7 8 9 10 11 12 13 14 15 16 17 18))
;; => (-2 -2 -1 -1 0 0 1 1 2 2 3 3 4)
(defun abilities ()
"Return a list of six ability scores."
(let* ((scores (mapcar (lambda (ability) (roll 4))
'(str con dex int wis cha)))
(avg-bonus (apply '+ (mapcar 'bonus scores)))
(max-score (apply 'max scores)))
(if (or (<= avg-bonus 0)
(<= max-score 13))
(abilities); recursive
scores)))
;; (abilities) => (13 12 11 13 14 14)
(defun points (ability)
"Return the points ABILITY is worth."
(let ((doubles (min 2 (max 0 (- ability 14))))
(triples (max 0 (- ability 16))))
(+ (- ability doubles triples)
(* 2 doubles)
(* 3 triples)
-8)))
;; (mapcar 'points '(8 9 10 11 12 13 14 15 16 17 18))
;; => (0 1 2 3 4 5 6 8 10 13 16)
;; (mapcar 'points '(3 4 5 6 7)) => (-5 -4 -3 -2 -1)
(defun avg (&rest list)
"Average of a list of numbers."
(/ (apply '+ list) 1.0 (length list)))
;; (avg 1 2 3) => 2.0
(defun test (num)
(interactive "nNumber of characters to generate? ")
(message "%S"
(apply 'avg (mapcar
(lambda (ignore)
(apply '+ (mapcar 'points (abilities))))
(make-list num nil)))))