M 2022/aoc-2022.asd => 2022/aoc-2022.asd +2 -1
@@ 10,4 10,5 @@
(:file "day08")
(:file "day09")
(:file "day10")
- (:file "day11")))
+ (:file "day11")
+ (:file "day12")))
A 2022/day12.lisp => 2022/day12.lisp +85 -0
@@ 0,0 1,85 @@
+(defpackage :aoc-2022-day12
+ (:use :cl))
+(in-package :aoc-2022-day12)
+
+(defparameter *test-input* "Sabqponm
+abcryxxl
+accszExk
+acctuvwj
+abdefghi")
+
+(defun read-input (input)
+ (let* ((g (aoc:dense-grid-from-string input))
+ (start (aoc:grid-find #\S g :test #'char=))
+ (end (aoc:grid-find #\E g :test #'char=)))
+ (setf (aoc:grid-xy g (car start) (cdr start)) #\a)
+ (setf (aoc:grid-xy g (car end) (cdr end)) #\z)
+ (list :grid g
+ :start start
+ :end end)))
+
+(defun part1 (data)
+ (let* ((g (getf data :grid))
+ (start (getf data :start))
+ (end (getf data :end))
+ (bb (aoc:grid-bounding-box g))
+ (width (1+ (nth 2 bb)))
+ (height (1+ (nth 3 bb)))
+ (moves (aoc:make-dense-grid width height)))
+ (setf (aoc:grid-xy moves (car end) (cdr end)) 0)
+ (loop with next = (list end)
+ while next
+ while (null (aoc:grid-xy moves (car start) (cdr start)))
+ for m from 1
+ do (loop with changed = nil
+ for (px . py) in next
+ for ph = (- (char-code (aoc:grid-xy g px py))
+ (char-code #\a))
+ do (loop for (nx . ny) in (aoc:grid-neighbors g px py)
+ for nh = (- (char-code (aoc:grid-xy g nx ny))
+ (char-code #\a))
+ when (and (null (aoc:grid-xy moves nx ny))
+ (>= nh (1- ph)))
+ do (setf (aoc:grid-xy moves nx ny) m)
+ (pushnew (cons nx ny) changed :test #'equal))
+ finally (setf next changed)))
+ (aoc:grid-xy moves (car start) (cdr start))))
+
+(defun part2 (data)
+ (let* ((g (getf data :grid))
+ (end (getf data :end))
+ (bb (aoc:grid-bounding-box g))
+ (width (1+ (nth 2 bb)))
+ (height (1+ (nth 3 bb)))
+ (moves (aoc:make-dense-grid width height)))
+ (setf (aoc:grid-xy moves (car end) (cdr end)) 0)
+ (block outer
+ (loop with next = (list end)
+ while next
+ for m from 1
+ do (loop with changed = nil
+ for (px . py) in next
+ for ph = (- (char-code (aoc:grid-xy g px py))
+ (char-code #\a))
+ do (loop for (nx . ny) in (aoc:grid-neighbors g px py)
+ for nv = (aoc:grid-xy g nx ny)
+ for nh = (- (char-code nv)
+ (char-code #\a))
+ when (and (null (aoc:grid-xy moves nx ny))
+ (>= nh (1- ph)))
+ do (setf (aoc:grid-xy moves nx ny) m)
+ (pushnew (cons nx ny) changed :test #'equal)
+ (when (char= nv #\a) (return-from outer m)))
+ finally (setf next changed))))))
+
+
+(aoc:defpuzzle day12
+ :test-data (list *test-input*)
+ :test-results-part1 '(31)
+ :test-results-part2 '(29)
+ :read-input #'read-input
+ :part1 #'part1
+ :part2 #'part2)
+
+;; (day12 :test)
+;; (day12)
A 2022/inputs/12 => 2022/inputs/12 +41 -0
@@ 0,0 1,41 @@
+abccccccccccccccccccaaaaaaaaacccccccccccccccccccccccccccccccccccccaaaa
+abcccccccccccccccaaaaaaaaaaacccccccccccccccccccccccccccccccccccccaaaaa
+abcaaccaacccccccccaaaaaaaaaacccccccccccccccccccccaaacccccccccccccaaaaa
+abcaaaaaaccccccccaaaaaaaaaaaaacccccccccccccccccccaacccccccccccccaaaaaa
+abcaaaaaacccaaacccccaaaaaaaaaaaccccccccccccccccccaaaccccccccccccccccaa
+abaaaaaaacccaaaaccccaaaaaacaaaacccccccccccaaaacjjjacccccccccccccccccca
+abaaaaaaaaccaaaaccccaaaaaaccccccaccccccccccaajjjjjkkcccccccccccccccccc
+abaaaaaaaaccaaacccccccaaaccccccaaccccccccccajjjjjjkkkaaacccaaaccaccccc
+abccaaacccccccccccccccaaccccaaaaaaaacccccccjjjjoookkkkaacccaaaaaaccccc
+abcccaacccccccccccccccccccccaaaaaaaaccccccjjjjoooookkkkcccccaaaaaccccc
+abcccccccaacccccccccccccccccccaaaacccccccijjjoooooookkkkccaaaaaaaccccc
+abccaaccaaaccccccccccccccccccaaaaacccccciijjooouuuoppkkkkkaaaaaaaacccc
+abccaaaaaaaccccccccccaaaaacccaacaaaccciiiiiooouuuuupppkkklllaaaaaacccc
+abccaaaaaacccccccccccaaaaacccacccaaciiiiiiqooouuuuuupppkllllllacaccccc
+abcccaaaaaaaacccccccaaaaaaccccaacaiiiiiqqqqoouuuxuuupppppplllllccccccc
+abccaaaaaaaaaccaaaccaaaaaaccccaaaaiiiiqqqqqqttuxxxuuuppppppplllccccccc
+abccaaaaaaaacccaaaaaaaaaaacccaaaahiiiqqqttttttuxxxxuuuvvpppplllccccccc
+abcaaaaaaacccaaaaaaaaaaacccccaaaahhhqqqqtttttttxxxxuuvvvvvqqlllccccccc
+abcccccaaaccaaaaaaaaaccccccccacaahhhqqqttttxxxxxxxyyyyyvvvqqlllccccccc
+abcccccaaaccaaaaaaaacccccccccccaahhhqqqtttxxxxxxxyyyyyyvvqqqlllccccccc
+SbcccccccccccaaaaaaaaaccccccccccchhhqqqtttxxxxEzzzyyyyvvvqqqmmlccccccc
+abcccccccccccaaaaaaaacccaacccccccchhhppptttxxxxyyyyyvvvvqqqmmmcccccccc
+abccccccccccaaaaaaaaaaccaacccccccchhhpppptttsxxyyyyyvvvqqqmmmccccccccc
+abcaacccccccaaaaaaacaaaaaaccccccccchhhppppsswwyyyyyyyvvqqmmmmccccccccc
+abaaaacccccccaccaaaccaaaaaaacccccccchhhpppsswwyywwyyyvvqqmmmddcccccccc
+abaaaaccccccccccaaaccaaaaaaacccccccchhhpppsswwwwwwwwwvvqqqmmdddccccccc
+abaaaacccccccccaaaccaaaaaaccccccccccgggpppsswwwwrrwwwwvrqqmmdddccccccc
+abccccccaaaaaccaaaacaaaaaaccccccaacccggpppssswwsrrrwwwvrrqmmdddacccccc
+abccccccaaaaaccaaaacccccaaccccaaaaaacggpppssssssrrrrrrrrrnmmdddaaccccc
+abcccccaaaaaaccaaaccccccccccccaaaaaacggppossssssoorrrrrrrnnmdddacccccc
+abcccccaaaaaaccccccccaaaaccccccaaaaacgggoooossoooonnnrrnnnnmddaaaacccc
+abccccccaaaaaccccccccaaaacccccaaaaaccgggoooooooooonnnnnnnnndddaaaacccc
+abccccccaaaccccccccccaaaacccccaaaaacccgggoooooooffennnnnnnedddaaaacccc
+abcccccccccccccccccccaaacccccccaacccccggggffffffffeeeeeeeeeedaaacccccc
+abccccccccccccccccccaaacccccaccaaccccccggfffffffffeeeeeeeeeecaaacccccc
+abccccccccccccccccccaaaacccaaaaaaaaaccccfffffffaaaaaeeeeeecccccccccccc
+abccccccccaacaaccccaaaaaacaaaaaaaaaaccccccccccaaaccaaaaccccccccccccccc
+abccccccccaaaaacccaaaaaaaaaaacaaaaccccccccccccaaaccccaaccccccccccaaaca
+abcccccccaaaaaccccaaaaaaaaaaacaaaaacccccccccccaaaccccccccccccccccaaaaa
+abcccccccaaaaaacccaaaaaaaaaacaaaaaacccccccccccaaccccccccccccccccccaaaa
+abcccccccccaaaaccaaaaaaaaaaaaaaccaaccccccccccccccccccccccccccccccaaaaa
M utils/grid.lisp => utils/grid.lisp +54 -2
@@ 61,7 61,8 @@
(width (- end start -1)))
(make-array width
:displaced-to data
- :displaced-index-offset (array-row-major-index data y start)))))
+ :displaced-index-offset (array-row-major-index data y start)
+ :element-type (array-element-type data)))))
(defgeneric grid-column (grid x &key up-from down-from)
(:documentation "Return a column from the grid.")
@@ 101,7 102,7 @@
(list 0 0 (1- width) (1- height)))))
(defgeneric grid-size (grid)
- (:documentation "Reutnr the number of set points in the grid.")
+ (:documentation "Return the number of set points in the grid.")
(:method ((g sparse-grid))
(hash-table-count (sparse-grid-data g))))
@@ 118,3 119,54 @@
(otherwise grid-value))
do (format out "~a~a" value h-space)
finally (format out "~%"))))))
+
+(defun dense-grid-from-string (s)
+ "Build a dense grid from a string."
+ (let ((lines (str:lines s)))
+ (loop with g = (make-dense-grid (length (car lines)) (length lines))
+ for line in lines
+ for y from 0
+ do (loop for char across line
+ for x from 0
+ do (setf (grid-xy g x y) char))
+ finally (return g))))
+
+(defgeneric grid-find-if (predicate grid)
+ (:documentation "Return the coords of the first value in GRID that satisfies PREDICATE.")
+ (:method (predicate (g sparse-grid))
+ (loop for coords being the hash-keys in (sparse-grid-data g) using (hash-value value)
+ when (funcall predicate value) do
+ (return (cons (realpart value)
+ (imagpart value)))
+ finally (return nil)))
+ (:method (predicate (g dense-grid))
+ (alexandria:when-let* ((data (dense-grid-data g))
+ (idx (position-if predicate
+ (make-array (array-total-size data)
+ :displaced-to data
+ :element-type (array-element-type data)))))
+ (multiple-value-bind (y x) (floor idx (array-dimension data 1))
+ (cons x y)))))
+
+(defun grid-find (item grid &key (test #'eql))
+ "Return the coords of the first instance of ITEM in GRID."
+ (grid-find-if (lambda (it) (funcall test it item)) grid))
+
+(defgeneric grid-neighbors (grid x y)
+ (:documentation "Return the coords of all neighbors.")
+ (:method ((g sparse-grid) x y)
+ (list (cons (1+ x) y)
+ (cons (1- x) y)
+ (cons x (1+ y))
+ (cons x (1- y))))
+ (:method ((g dense-grid) x y)
+ (loop with dim = (array-dimensions (dense-grid-data g))
+ for (xx . yy) in (list (cons (1+ x) y)
+ (cons (1- x) y)
+ (cons x (1+ y))
+ (cons x (1- y)))
+ when (and (>= xx 0)
+ (>= yy 0)
+ (< xx (cadr dim))
+ (< yy (car dim)))
+ collect (cons xx yy))))
M utils/packages.lisp => utils/packages.lisp +4 -0
@@ 24,6 24,10 @@
#:grid-bounding-box
#:grid-size
#:grid-print
+ #:dense-grid-from-string
+ #:grid-find-if
+ #:grid-find
+ #:grid-neighbors
;; sequence
#:chunks