(ql:quickload '(fiveam uiop)) (defun line-of-sight (direction p width height) (case direction (right (loop for l from (1+ p) below (* width (1+ (floor p width))) collect l)) (left (loop for l downfrom (1- p) to (* width (floor p width)) collect l)) (bottom (loop for l from (+ p width) below (* width height) by width collect l)) (top (loop for l downfrom (- p width) to 0 by width collect l)))) (defun forest (data) (let ((width (length (car data))) (height (length data))) (values width height (map 'vector (lambda (x) (- (char-code x) 48)) (apply #'concatenate 'string data))))) (defun solver-p1 (filename) "Count how many trees are visible from the outside. A tree is visible if all other trees between it and the edge of the grid are shorter." (multiple-value-bind (width height forest) (forest (uiop:read-file-lines filename)) (loop for base across forest and p from 0 count (some (lambda (direction) (loop for l in (line-of-sight direction p width height) for tree-height = (aref forest l) always (< tree-height base))) '(right left top bottom))))) (defun solver-p2 (filename) "A scenic score is the product of the viewing distance in each direction. The viewing distance is the lenght until a tree of equal height appears." (multiple-value-bind (width height forest) (forest (uiop:read-file-lines filename)) (loop for base across forest and p from 0 maximize (apply #'* (mapcar (lambda (direction) (loop for l in (line-of-sight direction p width height) for tree-height = (aref forest l) count l until (>= tree-height base))) '(right left top bottom)))))) (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"))))