aboutsummaryrefslogtreecommitdiffstats
path: root/AoC2022/03/solver.lisp
diff options
context:
space:
mode:
Diffstat (limited to 'AoC2022/03/solver.lisp')
0 files changed, 0 insertions, 0 deletions
/a> 57 58
(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"))))))