; a helper function which prints each argument seperated by a space (define output (lambda (. things) (cond ((null? things) (display #\newline)) (else (display (car things)) (display #\space) (apply output (cdr things)))))) ; a helper function which shows arguments before calling them (define explicit-apply (lambda (f . args) (let ((result (apply f args))) (output f args result) result))) ; determine whether or not a given attack roll will hit (define is-hit? (lambda (roll attack ac) (or (= roll 20) (and (< 1 roll) (>= (+ roll attack) ac))))) ; determine whether or not a given attack roll will crit (define is-crit? (lambda (roll attack ac threat) (or (= roll 20) (and (is-hit? roll attack ac) (>= roll threat))))) ; determine the expected damage of a particular attack roll (define roll-dmg (lambda (roll attack ac dmg threat mult) (cond ((is-crit? roll attack ac threat) (* dmg mult)) ((is-hit? roll attack ac) dmg) (else 0)))) ; determine the expected damage across all attack rolls (define expected-dmg (lambda (. args) (define adder (lambda (total roll) (if (> roll 20) total (adder (+ total (apply roll-dmg roll args)) (+ roll 1))))) (/ (adder 0 1) 20))) ; find the best power attack score (and expected damage) versus an AC (define find-best-power (lambda (power-max attack ac dmg threat mult) (define checker (lambda (power best-power best-dmg) (if (> power power-max) (list best-power best-dmg) (let* ((a (- attack power)) (d (+ dmg power)) (ed (expected-dmg a ac d threat mult))) (if (> ed best-dmg) (checker (+ power 1) power ed) (checker (+ power 1) best-power best-dmg)))))) (checker 0 0 0))) ; iterate across a range of armor classes (define iter (let ((max-power 6) (attack 6) (dmg 5.5) (threat 20) (mult 3)) (lambda (ac max-ac) (explicit-apply find-best-power max-power attack ac dmg threat mult) (if (> ac max-ac) #f (iter (+ ac 1) max-ac))))) (iter 10 30)