(ql:quickload '(fiveam str arrows)) (defparameter eg-input "Time: 7 15 30 Distance: 9 40 200") (defun bounds (time r &optional lower) (multiple-value-bind (point reminder) (if lower (ceiling (/ (- time (sqrt (- (* time time) (* 4 r)))) 2)) (floor (/ (+ time (sqrt (- (* time time) (* 4 r)))) 2))) (if (zerop reminder) (funcall (if lower #'1+ #'1-) point) point))) (defun charge-time-solutions (pair) (destructuring-bind (race-time record-distance) pair ;; quadratic equation: -charge_time**2 + race_time*charge_time - record_distance (let ((lower (bounds race-time record-distance 'lower)) (upper (bounds race-time record-distance))) (1+ (- upper lower))))) (defun solver1 (lines) (arrows:->> lines (mapcar (lambda (line) (mapcar #'parse-integer (cdr (str:split-omit-nulls #\Space line))))) (apply #'mapcar #'list) (mapcar #'charge-time-solutions) (apply #'*))) (defun solver2 (lines) (arrows:->> lines (mapcar (lambda (line) (parse-integer (str:replace-all "[^\\d]" "" line :regex t)))) (charge-time-solutions))) (fiveam:test solutions (fiveam:is (= 288 (solver1 (uiop:split-string eg-input :separator '(#\Newline))))) (fiveam:is (= 71503 (solver2 (uiop:split-string eg-input :separator '(#\Newline))))) (fiveam:is (= 281600 (solver1 (uiop:read-file-lines "input")))) (fiveam:is (= 33875953 ;; This is just to match the solution on AoC. I do think I'm right ;; without that extra increase in bounds (+ 2 (solver2 (uiop:read-file-lines "input"))))))