156 lines
3.2 KiB
Common Lisp
156 lines
3.2 KiB
Common Lisp
|
(defpackage :aoc/2024/10
|
||
|
(:use :cl :aoc :alexandria :trivia :lla)
|
||
|
(:export
|
||
|
#:sample-data
|
||
|
#:sample-data2
|
||
|
#:part1
|
||
|
#:part2
|
||
|
))
|
||
|
|
||
|
(in-package :aoc/2024/10)
|
||
|
|
||
|
|
||
|
(defun parse-line (line)
|
||
|
(map 'vector (lambda (c) (or (digit-char-p c) 0)) (coerce line 'list)))
|
||
|
|
||
|
|
||
|
(defun parse-input (lines)
|
||
|
(let ((heights (mapcar #'parse-line lines)))
|
||
|
(make-array `(,(length (first heights)) ,(length heights)) :initial-contents heights))
|
||
|
)
|
||
|
|
||
|
(defparameter input-text (test-input 2024 10))
|
||
|
(defparameter input-data (parse-input input-text))
|
||
|
|
||
|
(defparameter sample-text (aoc:split-lines "89010123
|
||
|
78121874
|
||
|
87430965
|
||
|
96549874
|
||
|
45678903
|
||
|
32019012
|
||
|
01329801
|
||
|
10456732"))
|
||
|
(defparameter sample-data
|
||
|
(parse-input sample-text))
|
||
|
|
||
|
(defparameter sample-data-0 (parse-input (aoc:split-lines "...0...
|
||
|
...1...
|
||
|
...2...
|
||
|
6543456
|
||
|
7.....7
|
||
|
8.....8
|
||
|
9.....9")))
|
||
|
|
||
|
(defparameter sample-data-1 (parse-input (aoc:split-lines "..90..9
|
||
|
...1.98
|
||
|
...2..7
|
||
|
6543456
|
||
|
765.987
|
||
|
876....
|
||
|
987....")))
|
||
|
|
||
|
(defun find-heights(h map)
|
||
|
(loop
|
||
|
for y from 0 below (array-dimension map 1)
|
||
|
append
|
||
|
(loop
|
||
|
for x from 0 below (array-dimension map 1)
|
||
|
if (= h (aref map x y))
|
||
|
collect (cons x y))))
|
||
|
|
||
|
(defun find-trailheads (map)
|
||
|
(find-heights 1 map))
|
||
|
|
||
|
(defun find-trailends (map)
|
||
|
(find-heights 9 map))
|
||
|
|
||
|
(defun get-xy (map x y)
|
||
|
(if (array-in-bounds-p map x y)
|
||
|
(aref map x y)
|
||
|
0))
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
(defun surrounding-paths (trails x y)
|
||
|
(remove-duplicates
|
||
|
(append
|
||
|
(gethash (cons (1+ x) y) trails)
|
||
|
(gethash (cons (1- x) y) trails)
|
||
|
(gethash (cons x (1+ y)) trails)
|
||
|
(gethash (cons x (1- y)) trails)
|
||
|
)))
|
||
|
|
||
|
(defun trails-update (trails map h)
|
||
|
(let ((nt (make-hash-table :test #'equal :size 100)))
|
||
|
(loop
|
||
|
for pt in (find-heights h map)
|
||
|
do (setf
|
||
|
(gethash pt nt)
|
||
|
(if (= h 9)
|
||
|
(list pt)
|
||
|
(surrounding-paths trails (car pt) (cdr pt))))
|
||
|
)
|
||
|
nt))
|
||
|
|
||
|
(defun map-endpoints (map)
|
||
|
(let ((ep-map (make-hash-table :test #'equal)))
|
||
|
(loop
|
||
|
for h from 9 downto 0
|
||
|
do (setf ep-map (trails-update ep-map map h)))
|
||
|
ep-map))
|
||
|
|
||
|
(defun score (map)
|
||
|
(loop
|
||
|
for v being the hash-values in (map-endpoints map)
|
||
|
sum (length v)))
|
||
|
|
||
|
|
||
|
(defun sum-surrounding (map x y)
|
||
|
(+
|
||
|
(get-xy map (1+ x) y)
|
||
|
(get-xy map (1- x) y)
|
||
|
(get-xy map x (1+ y))
|
||
|
(get-xy map x (1- y))
|
||
|
)
|
||
|
)
|
||
|
|
||
|
(defun ratings-update (ratings map h)
|
||
|
(let ((nr (make-array (array-dimensions ratings) :initial-element 0)))
|
||
|
(loop
|
||
|
for pt in (find-heights h map)
|
||
|
do
|
||
|
(let ((x (car pt))
|
||
|
(y (cdr pt)))
|
||
|
(setf (aref nr x y) (if (= h 9) 1 (sum-surrounding ratings x y))))
|
||
|
|
||
|
)
|
||
|
nr))
|
||
|
|
||
|
(defun ratings (map)
|
||
|
(let ((ratings (make-array (array-dimensions map) :initial-element 0)))
|
||
|
(loop
|
||
|
for h from 9 downto 0
|
||
|
do (setf ratings (ratings-update ratings map h)))
|
||
|
ratings))
|
||
|
|
||
|
(defun rating (map)
|
||
|
(loop for r across (aops:flatten (ratings map)) sum r)
|
||
|
)
|
||
|
|
||
|
(defun part1 (data)
|
||
|
(format nil "~A" (score data)))
|
||
|
|
||
|
(defun part2 (data)
|
||
|
(format nil "~A" (rating data)))
|
||
|
|
||
|
(defun solve-day ()
|
||
|
(format t "part1: ~A~%" (part1 input-data))
|
||
|
(format t "part2: ~A~%" (part2 input-data)))
|
||
|
|
||
|
(defun submit ()
|
||
|
(let ((p1 (part1 input-data))
|
||
|
(p2 (part2 input-data)))
|
||
|
(if p1 (submit-part1 2024 10 p1))
|
||
|
(if p2 (submit-part2 2024 10 p2))))
|