(in-package :ca.mhcat.advent2022) ;; --- Day 8: Treetop Tree House --- ;; The expedition comes across a peculiar patch of tall ;; trees all planted carefully in a grid. The Elves explain ;; that a previous expedition planted these trees as a ;; reforestation effort. Now, they're curious if this would ;; be a good location for a tree house. ;; First, determine whether there is enough tree cover here ;; to keep a tree house hidden. To do this, you need to ;; count the number of trees that are visible from outside ;; the grid when looking directly along a row or column. ;; The Elves have already launched a quadcopter to generate ;; a map with the height of each tree (your puzzle input). ;; For example: ;; 30373 ;; 25512 ;; 65332 ;; 33549 ;; 35390 ;; Each tree is represented as a single digit whose value is ;; its height, where 0 is the shortest and 9 is the tallest. ;; A tree is visible if all of the other trees between it ;; and an edge of the grid are shorter than it. Only ;; consider trees in the same row or column; that is, only ;; look up, down, left, or right from any given tree. ;; All of the trees around the edge of the grid are visible ;; - since they are already on the edge, there are no trees ;; to block the view. In this example, that only leaves the ;; interior nine trees to consider: ;; The top-left 5 is visible from the left and top. (It ;; isn't visible from the right or bottom since other ;; trees of height 5 are in the way.) ;; The top-middle 5 is visible from the top and right. ;; The top-right 1 is not visible from any direction; ;; for it to be visible, there would need to only be ;; trees of height 0 between it and an edge. ;; The left-middle 5 is visible, but only from the right. ;; The center 3 is not visible from any direction; for ;; it to be visible, there would need to be only trees ;; of at most height 2 between it and an edge. ;; The right-middle 3 is visible from the right. ;; In the bottom row, the middle 5 is visible, but the 3 ;; and 4 are not. ;; With 16 trees visible on the edge and another 5 visible ;; in the interior, a total of 21 trees are visible in this ;; arrangement. ;; Consider your map; how many trees are visible from ;; outside the grid? (defparameter day8/test-data '("30373" "25512" "65332" "33549" "35390")) (defun day8/visible-from-end (lst) (not (find-if (lambda (tree) (>= tree (car lst))) (cdr lst)))) (defun day8/parse-data (lst) (loop for line in lst collect (mapcar (lambda (ch) (- (char-int ch) (char-int #\0))) (coerce line 'list)))) (defun day8/process-row (row mkcoordf) (loop for subl on row for idx from 0 below (length row) when (day8/visible-from-end subl) collect (funcall mkcoordf idx))) (defun day8/process-grid (data mkcoordf1 mkcoordf2) (loop for row in data for idx from 0 below (length data) collect (append (day8/process-row row (funcall mkcoordf1 idx)) (day8/process-row (reverse row) (funcall mkcoordf2 idx))) into results finally (return (apply #'append results)))) ;; Table rotation bits (defun day8/rotate (data) "Rotates the table 90 degrees clockwise" (let ((row-size (length (car data)))) (loop for idx from 0 below row-size collect (reverse (apply #'list (mapcar (lambda (row) (nth idx row)) data)))))) ;; These are function constructors for addressing the ;; coordinate space from within code that does not know the ;; orientation of the table. (defun tblr (width height) "y = top to bottom, x = left to right" (lambda (y) (lambda (x) (list x y)))) (defun tbrl (width height) "y = top to bottom, x = right to left" (lambda (y) (lambda (x) (list (- width x 1) y)))) (defun lrbt (width height) "y = left to right, x = bottom to top" (lambda (y) (lambda (x) (list y (- height x 1))))) (defun lrtb (width height) "y = left to right, x = top to bottom" (lambda (y) (lambda (x) (list y x)))) ;; Part 1 (defun day8/compute-part1 (lst) (let* ((data (day8/parse-data lst)) (height (length data)) (width (length (car data)))) (remove-duplicates (append (day8/process-grid data (tblr width height) (tbrl width height)) (day8/process-grid (day8/rotate data) (lrbt width height) (lrtb width height))) :test #'equal))) (defun day8/part1 () (length (day8/compute-part1 (load-lines "day8.txt")))) ;; --- Part Two --- ;; Content with the amount of tree cover available, the ;; Elves just need to know the best spot to build their tree ;; house: they would like to be able to see a lot of trees. ;; To measure the viewing distance from a given tree, look ;; up, down, left, and right from that tree; stop if you ;; reach an edge or at the first tree that is the same ;; height or taller than the tree under consideration. (If a ;; tree is right on the edge, at least one of its viewing ;; distances will be zero.) ;; The Elves don't care about distant trees taller than ;; those found by the rules above; the proposed tree house ;; has large eaves to keep it dry, so they wouldn't be able ;; to see higher than the tree house anyway. ;; In the example above, consider the middle 5 in the second ;; row: ;; 30373 ;; 25512 ;; 65332 ;; 33549 ;; 35390 ;; Looking up, its view is not blocked; it can see 1 ;; tree (of height 3). ;; Looking left, its view is blocked immediately; it can ;; see only 1 tree (of height 5, right next to it). ;; Looking right, its view is not blocked; it can see 2 ;; trees. ;; Looking down, its view is blocked eventually; it can ;; see 2 trees (one of height 3, then the tree of height ;; 5 that blocks its view). ;; A tree's scenic score is found by multiplying together ;; its viewing distance in each of the four directions. For ;; this tree, this is 4 (found by multiplying 1 * 1 * 2 * ;; 2). ;; However, you can do even better: consider the tree of ;; height 5 in the middle of the fourth row: ;; 30373 ;; 25512 ;; 65332 ;; 33549 ;; 35390 ;; Looking up, its view is blocked at 2 trees (by ;; another tree with a height of 5). ;; Looking left, its view is not blocked; it can see 2 ;; trees. ;; Looking down, its view is also not blocked; it can ;; see 1 tree. ;; Looking right, its view is blocked at 2 trees (by a ;; massive tree of height 9). ;; This tree's scenic score is 8 (2 * 2 * 1 * 2); this is ;; the ideal spot for the tree house. ;; Consider each tree on your map. What is the highest ;; scenic score possible for any tree? (defun day8/trees-visible-from-here (lst) (let ((pos (position-if (lambda (tree) (>= tree (car lst))) (cdr lst)))) (or (and pos (1+ pos)) (length (cdr lst))))) (defun day8/row-wise-view (lst) (loop for row in lst collect (mapcar #'* (maplist #'day8/trees-visible-from-here row) (reverse (maplist #'day8/trees-visible-from-here (reverse row)))))) (defun day8/compute-part2 (lst) (apply #'max (apply #'append (mapcar (lambda (v1 v2) (mapcar #'* v1 v2)) (day8/row-wise-view lst) (day8/rotate (day8/rotate (day8/rotate (day8/row-wise-view (day8/rotate lst))))))))) (defun day8/part2 () (day8/compute-part2 (day8/parse-data (load-lines "day8.txt"))))