(ns edition2022.day8
(:require [clojure.string :as str]
[clojure.math.combinatorics :as comb]))
(def example-in "30373\n25512\n65332\n33549\n35390")
(def example-lines (str/split-lines example-in))
(defn read-in-lines []
(str/split-lines (slurp "resources/day8.in")))
(defn int-row [row]
(map #(- (int %) 48) (seq row)))
(defn append-columns [row columns]
(->> (map vector row)
(interleave columns)
(partition 2)
(map #(apply concat %)))
)
(defn columns-from-rows [lines]
(loop [rows (map seq lines)
columns (take (count (first rows)) (iterate identity []))]
(if (empty? rows)
columns
(recur (rest rows) (append-columns (first rows) columns)))))
(defn all-tree-positions [size]
(comb/cartesian-product (range size) (range size)))
(defn tree-with-neighbours [pos rows cols]
{:pos pos,
:row (nth rows (first pos)),
:col (nth cols (second pos))})
(defn trees-with-neighbours [lines]
(let [rows (map int-row lines)
cols (columns-from-rows rows)
positions (all-tree-positions (count rows))]
(map #(tree-with-neighbours % rows cols) positions)))
(defn highest-tree? [tree neighbours]
(empty? (drop-while #(> tree %) neighbours)))
(defn visible-tree-from-one-direction? [idx row]
(let [tree (nth row idx)
left-side (take idx row)
right-side (drop (+ idx 1) row)
]
(or
(= 0 idx)
(= (- (count row) 1) idx)
(highest-tree? tree left-side)
(highest-tree? tree right-side))))
(defn visible-tree? [tree-with-neighbours]
(let [pos (:pos tree-with-neighbours)
x (second pos)
y (first pos)
row (:row tree-with-neighbours)
col (:col tree-with-neighbours)
]
(or
(visible-tree-from-one-direction? x row)
(visible-tree-from-one-direction? y col))))
(defn count-visible-trees [trees-with-neighbours]
;(map #(vector (visible-tree? %) %) trees-with-neighbours)
(count (filter visible-tree? trees-with-neighbours))
)
(defn solution-part-1 []
(->> (read-in-lines)
(trees-with-neighbours)
(count-visible-trees)))
(defn view-distance [tree neighbours]
(let [smaller-trees-count (count (take-while #(> tree %) neighbours))
neighbours-count (count neighbours)
blocking-tree (nth neighbours smaller-trees-count nil)]
(cond
(not (nil? blocking-tree)) (+ smaller-trees-count 1)
:else smaller-trees-count)))
(defn scenic-score-from-one-direction [idx row]
(let [tree (nth row idx)
left-side (reverse (take idx row))
right-side (drop (+ idx 1) row)]
(cond
(= 0 idx) 0
(= (- (count row) 1) idx) 0
:else
(*
(view-distance tree left-side)
(view-distance tree right-side)))))
(defn scenic-score [tree-with-neighbours]
(let [pos (:pos tree-with-neighbours)
x (second pos)
y (first pos)
row (:row tree-with-neighbours)
col (:col tree-with-neighbours)
]
(*
(scenic-score-from-one-direction x row)
(scenic-score-from-one-direction y col))))
(defn max-scenic-score [trees-with-neighbours]
(->> trees-with-neighbours
(map scenic-score)
(reduce max)
)
)
(defn solution-part-2 []
(->> (read-in-lines)
(trees-with-neighbours)
(max-scenic-score)))
(comment
(append-columns [1 2 3 4] [[0] [0] [0] [0]])
example-lines
(columns-from-rows example-lines)
(all-tree-positions 4)
(count (all-tree-positions 3))
(count (all-tree-positions 5))
(trees-with-neighbours example-lines)
(visible-tree-from-one-direction? 4 '(3 0 3 7 3))
(visible-tree? {:pos '(1 1), :row '(2 5 5 1 2), :col '(0 5 5 3 5)})
(scenic-score {:pos '(1 1), :row '(2 5 5 1 2), :col '(0 5 5 3 5)})
(scenic-score {:pos '(3 2), :row '(3 3 5 4 9), :col '(3 5 3 5 3)})
(scenic-score-from-one-direction 2 '(3 3 5 4 9))
(view-distance 5 [3 3])
(view-distance 5 [4 9])
(scenic-score-from-one-direction 3 '(3 5 3 5 3))
(count-visible-trees (trees-with-neighbours example-lines))
(max-scenic-score (trees-with-neighbours example-lines))
(solution-part-1)
(solution-part-2)
)