🎄 Advent of Clerk: Day 8

(ns advent-of-clerk.day-08
(:require [nextjournal.clerk :as clerk]
[advent-of-clerk.utils :as utils]
[clojure.set :as cset]
[clojure.string :as cstr]))
(def input (->> (utils/load-input "day_08.txt")
(cstr/split-lines)))
["
0021000302223413032321152215243115022004032344522041252513450244235444433051424119 more elided"
"
1020303223411433302442330130520254534220054153046554262064522513102140553140240319 more elided"
"
0030122034040114301201345543145524416350016410502114062046211141020215431445141019 more elided"
"
3303134230020341400350012104411565545456250422626513565565442025004461214551124319 more elided"
"
3312031211312300020551134302446100626540345201063634621552012103556011535423013219 more elided"
"
2322012310210032543554114023103262066250115641141252022635044514512126001553514219 more elided"
"
0330333333010115235440232061361455053042243256060203600062064555645135535120543519 more elided"
"
1322010322343340442513342203453604024565416622535563757546623232652016415141211019 more elided"
"
3143223413221044022350202065650442253635276177675745244754217635043410615511542519 more elided"
"
1013230430234305433424405323243264136556575272156611166234556136643210051343002219 more elided"
"
3204042425141221115250434445306254176567731172475127124443157674224121303515055119 more elided"
"
2212041232051331420440562456542052317343715466167532173215564722236540440436125519 more elided"
"
3403101552254521522166356343527125413663123262722621435223471111666467360013601019 more elided"
"
0124040035150024164225001632442713662527115316153334373524614547773111421320001419 more elided"
"
3324345523022034455035434245233274643625266572516876347455365217465231547175316419 more elided"
"
0201303124253163626111304622171254254355452654677252563327772331371415243146311019 more elided"
"
1121151245120023460113424331461245423568454838627563227855452836527237472767764019 more elided"
"
3323540131010030310530222454312746276546773436386726434425634487827374643375465419 more elided"
"
2203153201420641614065343652623772683737435277845752463255646762388167337673313419 more elided"
"
1020411535260006014023256257665345435278824766533667275734487277756771463657324319 more elided"
79 more elided]
(def ex-input
["30373"
"25512"
"65332"
"33549"
"35390"])
["
30373"
"
25512"
"
65332"
"
33549"
"
35390"]

row number == column number:

(== (count input) (count (first input)))
true

Part 1

(defn parse [input]
(map #(map (comp parse-long str) %) input))
#object[advent_of_clerk.day_08$parse 0x24e50b74 "
advent_of_clerk.day_08$parse@24e50b74"
]
(defn make-grid [xss]
(let [rows (map-indexed
(fn [y row] (map-indexed (fn [x n] [[x y] n]) row))
xss)
cols (apply map vector rows)]
[rows cols]))
#object[advent_of_clerk.day_08$make_grid 0x2379f977 "
advent_of_clerk.day_08$make_grid@2379f977"
]
(defn find-visible [[rows cols]]
(loop [[lmax l2 & lr] cols [rmax r2 & rr] (reverse cols)
[tmax t2 & tr] rows [bmax b2 & br] (reverse rows)
visible (into {} (concat lmax rmax tmax bmax))]
(let [sel-visible #(if (< (second %1) (second %2)) %2 %1)
[lmax rmax
tmax bmax] (map (partial apply map sel-visible)
[[lmax l2] [rmax r2] [tmax t2] [bmax b2]])
visible (apply merge visible (into {} (concat lmax rmax tmax bmax)))]
(if (empty? lr)
visible
(recur (cons lmax lr) (cons rmax rr)
(cons tmax tr) (cons bmax br)
visible)))))
#object[advent_of_clerk.day_08$find_visible 0x6dadcf34 "
advent_of_clerk.day_08$find_visible@6dadcf34"
]
(defn solve-1
[input]
(->> input
parse
make-grid
find-visible
count))
#object[advent_of_clerk.day_08$solve_1 0x4ec35e4a "
advent_of_clerk.day_08$solve_1@4ec35e4a"
]

Studies

(def grid (make-grid (parse ex-input)))
[(([[0 0] 3] [[1 0] 0] [[2 0] 3] [[3 0] 7] [[4 0] 3]) ([[0 1] 2] [[1 1] 5] [[2 1] 5] [[3 1] 1] [[4 1] 2]) ([[0 2] 6] [[1 2] 5] [[2 2] 3] [[3 2] 3] [[4 2] 2]) ([[0 3] 3] [[1 3] 3] [[2 3] 5] [[3 3] 4] [[4 3] 9]) ([[0 4] 3] [[1 4] 5] [[2 4] 3] [[3 4] 9] [[4 4] 0])) ([[[0 0] 3] [[0 1] 2] [[0 2] 6] [[0 3] 3] [[0 4] 3]] [[[1 0] 0] [[1 1] 5] [[1 2] 5] [[1 3] 3] [[1 4] 5]] [[[2 0] 3] [[2 1] 5] [[2 2] 3] [2 more elided] [2 more elided]] [5 more elided] [5 more elided])]
(def visible-heights (find-visible grid))
{[0 0] 3 [0 1] 2 [0 2] 6 [0 3] 3 [0 4] 3 [1 0] 0 [1 1] 5 [1 2] 5 [1 4] 5 [2 0] 3 11 more elided}
(count visible-heights)
21

Observations

  • it doesn’t matter from which direction a tree is visible to be visible
  • visibility checks from each direction are independent from each other
  • if a tree is marked as visible, it doesn’t need any further checks
  • a tree can block a tree of the same height
  • all edge-trees have to be counted since they are all visible

Part 2

(defn calc-scenic-scores [[rows cols]]
(let [init-heights (partial map (comp vector second))
cons-heights (fn [xs acc-heights]
(map (fn [[_ n] heights] (cons n heights))
xs acc-heights))
calc-score (fn [self-height heights-in-dir]
(reduce (fn [sum height] (if (< height self-height)
(inc sum)
(reduced (inc sum))))
0 heights-in-dir))
[min max] [0 (dec (count rows))]]
(loop [[lhts l & lr] (cons (init-heights (first cols)) (rest cols))
[rhts r & rr] (cons (init-heights (last cols)) (rest (reverse cols)))
[thts t & tr] (cons (init-heights (first rows)) (rest rows))
[bhts b & br] (cons (init-heights (last rows)) (rest (reverse rows)))
coord->score {}]
(let [scores (map (fn [xs xhts]
(into {} (map (fn [[[x y :as coords] n] heights]
(when (and (> x min) (> y min)
(< x max) (< y max))
[coords (calc-score n heights)]))
xs xhts)))
[l r t b] [lhts rhts thts bhts])
coord->score (apply merge-with * coord->score scores)]
(if (< (count lr) 2) ;; omit first/last row/col
coord->score
(recur (cons (cons-heights l lhts) lr)
(cons (cons-heights r rhts) rr)
(cons (cons-heights t thts) tr)
(cons (cons-heights b bhts) br)
coord->score))))))
#object[advent_of_clerk.day_08$calc_scenic_scores 0x42f1524d "
advent_of_clerk.day_08$calc_scenic_scores@42f1524d"
]
(defn solve-2
[input]
(->> input
parse
make-grid
calc-scenic-scores
vals
(apply max)))
#object[advent_of_clerk.day_08$solve_2 0x2eafa925 "
advent_of_clerk.day_08$solve_2@2eafa925"
]

Studies

(def coord->score (calc-scenic-scores grid))
{[1 1] 1 [1 2] 6 [1 3] 1 [2 1] 4 [2 2] 1 [2 3] 8 [3 1] 1 [3 2] 2 [3 3] 3}
(apply max (vals coord->score))
8

Observations

  • trees on the edges will always have a scenic score of 0, so they can be ignored
  • seems like we cannot make use of the results of part 1
(comment
)
nil