(ql:quickload '(fiveam uiop)) (defun coord-x-minor (width height) (lambda (x y) (when (and (< -1 x width) (< -1 y height)) (+ x (* y width))))) (defun coord-y-minor (width height) (let ((xminor (coord-x-minor width height))) (lambda (y x) (funcall xminor x y)))) (defun flatten-data (data) (apply #'vector (mapcan (lambda (row) (map 'list (lambda (x) (- (char-code x) 48)) row)) data))) (defun forest (data) (let ((width (length (car data))) (height (length data))) (values (flatten-data data) width height))) (defun solver-p1 (filename) (multiple-value-bind (forest-arr width height) (forest (uiop:read-file-lines filename)) (let ((visibility-mask (make-array (* width height) :initial-element nil)) (location-x (coord-x-minor width height)) (location-y (coord-y-minor width height))) (flet ((toggle-visibility (major minor location reverse) (let ((range (if reverse (loop for i downfrom (1- minor) to 0 collect i) (loop for i below minor collect i)))) (dotimes (m major) (loop for n in range for maxh = -1 then (max maxh tree-height) for tree-height = (aref forest-arr (funcall location n m)) when (> tree-height maxh) do (setf (aref visibility-mask (funcall location n m)) t)))))) (toggle-visibility height width location-x nil) (toggle-visibility height width location-x t) (toggle-visibility width height location-y nil) (toggle-visibility width height location-y t)) (loop for v across visibility-mask counting v)))) (defun solver-p2 (filename) (multiple-value-bind (forest-arr width height) (forest (uiop:read-file-lines filename)) (let ((score (make-array (* width height))) (location-x (coord-x-minor width height))) (flet ((score-direction (base dir) (loop for l in dir for tree-height = (aref forest-arr l) count l until (>= tree-height base)))) (dotimes (y height) (dotimes (x width) (let ((base (aref forest-arr (funcall location-x x y)))) (setf (aref score (funcall location-x x y)) (* (score-direction base (loop for l from (1+ x) below width collect (funcall location-x l y))) ;; to right (score-direction base (loop for l from (1+ y) below height collect (funcall location-x x l))) ;; to bottom (score-direction base (loop for l downfrom (1- x) to 0 collect (funcall location-x l y))) ;; to left (score-direction base (loop for l downfrom (1- y) to 0 collect (funcall location-x x l)))))))) ;; to top (loop for v across score maximize v))))) (fiveam:test solutions (fiveam:is (= 21 (solver-p1 "eg-in"))) (fiveam:is (= 1672 (solver-p1 "input"))) (fiveam:is (= 8 (solver-p2 "eg-in"))) (fiveam:is (= 327180 (solver-p2 "input")))) (fiveam:run-all-tests)