For day 18, we have a maze again, but this time the input is given as coordinate pairs of where the walls go. The start and goal are the upper left and lower right respectively.
(in-package "ADVENT2024/DAY18")
(defun read-input (file grid n-bytes)
(iterate ((coord (#M(lambda (line)
(apply #’coord (map ’list #’parse-integer (str:split #\, line))))
(cotruncate (scan-file file #’read-line)
(scan-range :below n-bytes)))))
(setf (grid-ref grid coord) ’\#))
(setf (grid-ref grid (coord 0 0)) ’|S|)
(setf (grid-ref grid (coord (1- (grid-height grid)) (1- (grid-width grid)))) ’|E|))
(defun sample-input ()
(let ((grid (make-array (list 7 7) :initial-element ’|.|)))
(read-input (sample-input-pathname) grid 12)
grid))
(defun input (n-bytes)
(let ((grid (make-grid 71 71 :initial-element ’|.|)))
(read-input (input-pathname) grid n-bytes)
grid))
The bulk of the solution simply reuses the Dijkstra’s algorithm from day 16. I won’t reproduce the code here. We just adjust the path scorer to not penalize for turns.
For part 1, we load the first 1024 walls and find a shortest path.
(defun part-1 ()
(let* ((grid (input 1024))
(solutions (solve-maze grid)))
(score-path (car solutions))))
For part 2, we want to find the first wall in the list of walls that prevents us from reaching the goal. Binary search time.
(defun total-walls ()
(collect-length (scan-file (input-pathname) #’read-line)))
(defun binary-search (pass fail)
(if (= (1+ pass) fail)
(list pass fail)
(let* ((mid (floor (+ pass fail) 2))
(grid (input mid)))
(let ((solutions (solve-maze grid)))
(if (null solutions)
(binary-search pass mid)
(binary-search mid fail))))))
(defun get-coord (n)
(collect-nth n (scan-file (input-pathname) #’read-line)))
(defun part-2 ()
(collect-nth (car (binary-search 1024 (total-walls)))
(scan-file (input-pathname) #’read-line)))
No comments:
Post a Comment