with import ../../util.nix; let input = map (line: map toInt (stringToCharacters line)) (splitString "\n" (readFile ./input)); input' = transpose input; visibleTrees = let # counts the number of trees visible from a starting hiddenTreesLineDir = l: (foldl (acc: x: if x > acc.highest then { highest = x; out = acc.out ++ [true]; } # visible else { inherit (acc) highest; out = acc.out ++ [false]; }) # hidden { highest = -1; out = []; } l).out; hiddenTreesLine = l: mergeLists or (hiddenTreesLineDir l) (reverseList (hiddenTreesLineDir (reverseList l))); hiddenTreesGrid = map hiddenTreesLine; hiddenTreesRows = hiddenTreesGrid input; hiddenTreesCols = hiddenTreesGrid input'; mergeGrid = f: let w = length hiddenTreesCols; h = length hiddenTreesRows; in genList (i: genList (j: f (elemAt (elemAt hiddenTreesCols i) j) (elemAt (elemAt hiddenTreesRows j) i) ) h) w; in mergeGrid or; countVisibleRow = l: sum (map boolToInt l); countVisible = sum (map countVisibleRow visibleTrees); # number of trees visible from each point as a score visibleScore = let getCol = x: map (l: elemAt l x) input; getRow = y: elemAt input y; left = x: l: reverseList (take x l); right = x: l: drop (x+1) l; visibleCountDir = treeHeight: l: (foldl (acc: x: if acc.stop == false then if x >= treeHeight then { cnt = acc.cnt +1; stop = true; } else { cnt = acc.cnt +1; stop = false; } else acc) { cnt = 0; stop = false; } l).cnt; treeScore = x: y: v: (visibleCountDir v (left x (getRow y))) * (visibleCountDir v (right x (getRow y))) * (visibleCountDir v (left y (getCol x))) * (visibleCountDir v (right y (getCol x))); in map2D treeScore input; maxVisibleScore = foldr (x: max (maxList x)) 0 visibleScore; in rec { part1 = countVisible; part2 = maxVisibleScore; }