Advent of Code '23 - day 6

Table of Contents

An easier puzzle this time! This time I was able to solve it with pure math, with the only loop involved being in the input parser for part 1.

Input

Example

Time:      7  15   30
Distance:  9  40  200

Part 1

I was able to reduce the calculation into a single formula without loops, except for input parsing and adding everything together of course. I've split the formula into several methods as I expected a twist for part two.

The complete formula for the answer is as follows:

\begin{equation} answer(t,d)=t-\left(\lfloor \left(\frac{t}{2}- \sqrt{\left(\frac{t}{2}\right)^2 - d}\right) +1 \rfloor *2\right)+1 \end{equation}

I'm no mathematician so it might be optimized somehow, but I don't know.

(defun aoc23/parse-input (string)
  (let* ((lines (string-split (string-trim string)
                              "\n"))
         (times (car lines))
         (times (string-trim (cadr (string-split times
                                                 ":"))))
         (times (string-split times
                              " +"))
         (times (mapcar 'string-to-number
                        times))
         (dists (cadr lines))
         (dists (string-trim (cadr (string-split dists
                                                 ":"))))
         (dists (string-split dists
                              " +"))
         (dists (mapcar 'string-to-number
                        dists))
         (output '()))

    (while times
      (setq output (append output
                           `((,(car times) . ,(car dists)))))
      (setq times (cdr times))
      (setq dists (cdr dists)))

    output))

(defun aoc23/calc-dist (time-pressed time-available)
  (* time-pressed (- time-available
                     time-pressed))
  )

(defun aoc23/calc-max-dist (time-available)
  (* (/ time-available 2.0)
     (/ time-available 2.0)))

(defun aoc23/calc-min-time (time-available min-distance)
  (floor (1+ (- (/ time-available 2.0)
                (sqrt (- (aoc23/calc-max-dist time-available)
                         min-distance))))))

(defun aoc23/calc-number-options (time-available min-distance)
  (1+ (- time-available
         (* 2
            (aoc23/calc-min-time time-available
                                 min-distance)))))

(defun aoc23/get-answer (input)
  (apply '*
         (mapcar (lambda (c)
                   (aoc23/calc-number-options (car c) (cdr c)))
                 (aoc23/parse-input input))))

(aoc23/get-answer input)

Part 2

This part only required a different input-parser, yay!

(defun aoc23/parse-input (string)
  (let* ((lines (string-split (string-trim string) "\n"))
         (parse (lambda (input)
                  (let* ((output input)
                         (output (string-trim (cadr (string-split output ":"))))
                         (output (string-split output " +"))
                         (output (apply 'concat output)))
                    (string-to-number output))))
         (times (funcall parse (car lines)))
         (dists (funcall parse (cadr lines))))
      `((,times . ,dists))))

(aoc23/get-answer input)