(require '[clojure.set]) (defn get-adj "Gets vector of coords surrounding (x, y)." [y x] [[(dec y) x] [(inc y) x] [y (dec x)] [y (inc x)]]) (defn basin-continues? "Determines if `b` is a continuation of the basin that includes `a`." [a b] (and (some? b) (not= b 9) (> b a))) (defn basin-bottom? "Determines if point `p` in `hmap` is the bottom of a basin surrounded by points `adj`." [hmap p adj] (every? #(let [q (get-in hmap %)] (or (nil? q) (< (get-in hmap p) q))) adj )) (defn find-basin "If point `yx` in `hmap` is in a basin (determined using `adj`), return a list of points in the basin that are above `yx`." [hmap yx adj] (let [res (filter #(basin-continues? (get-in hmap yx) (get-in hmap %)) adj)] (apply (partial clojure.set/union res) (map #(set (find-basin hmap % (apply get-adj %))) res) ))) (->> (slurp "./in") (clojure.string/split-lines) (mapv vec) (mapv (partial mapv #(- (int %) 48))) (#(for [y (range 0 (count %)) x (range 0 (count (first %))) :let [adj (get-adj y x)] :when (basin-bottom? % [y x] adj)] (inc (count (find-basin % [y x] adj))))) (sort >) (take 3) (apply *) (println) )