(ql:quickload "split-sequence") (defun read-data (path) (with-open-file (stream path) (loop for line = (read-line stream nil) while line collect line))) (defparameter *input-source* (cadr *posix-argv*)) ;; Useful in testing ;; (defparameter *input-source* "example_input") ;; (defparameter *input-source* "input") (defun parse-digit (d) (- (char-code d) (char-code #\0))) (defun parse-line (line) (map 'list #'parse-digit line)) (defun parse-input (lines) (let ((numbers (map 'list #'parse-line lines))) (make-array (list (length numbers) (length (car numbers))) :initial-contents numbers))) (defparameter *data* (parse-input (read-data *input-source*))) (defun within-grid-p (max-x max-y x y) (and (>= x 0) (< x max-x) (>= y 0) (< y max-y))) (defun neighbours (grid x y i j) (loop for (a b) in '((1 0) (-1 0) (0 1) (0 -1)) when (within-grid-p x y (+ i a) (+ j b)) collect (aref grid (+ i a) (+ j b)))) (defun local-minimum-p (grid x y i j) (every (lambda (neighbour) (< (aref grid i j) neighbour)) (neighbours grid x y i j))) (defun low-points (grid) (destructuring-bind (x y) (array-dimensions grid) (loop for i from 0 below x nconcing (loop for j from 0 below y when (local-minimum-p grid x y i j) collect (list i j))))) (defun part1 (grid) (reduce #'+ (mapcar (lambda (coordinate) (1+ (apply #'aref grid coordinate))) (low-points grid)))) (defun flood (hash grid x y) (destructuring-bind (max-x max-y) (array-dimensions grid) (if (and (not (gethash (list x y) hash)) (within-grid-p max-x max-y x y) (/= 9 (aref grid x y))) (progn (setf (gethash (list x y) hash) T) (+ 1 (flood hash grid (1+ x) y) (flood hash grid (1- x) y) (flood hash grid x (1+ y)) (flood hash grid x (1- y)))) 0))) (defun basin (grid low-point) (let ((hash (make-hash-table :test #'equal))) (flood hash grid (car low-point) (cadr low-point)) (hash-table-count hash))) (defun part2 (grid) (reduce #'* (subseq (sort (mapcar (lambda (point) (basin grid point)) (low-points grid)) #'>) 0 3))) (format t "===== Part 1 =====") (format t "Result: ~A~%~%" (time (part1 *data*))) (format t "===== Part 2 =====") (format t "Result: ~A~%" (time (part2 *data*)))