advent-of-code/2023/src/day10.clj
2023-12-10 14:04:05 -05:00

126 lines
3.9 KiB
Clojure

(ns day10
(:require
[clojure.math :as math]
[core :refer [get-puzzle-input]]))
(def input (get-puzzle-input 10))
(def pipe-out-types {:left #{\- \7 \J \S}
:right #{\- \F \L \S}
:up #{\| \L \J \S}
:down #{\| \7 \F \S}})
(def char-map
(->> input
(map-indexed (fn [row line]
(map-indexed (fn [col c]
[[row col] c])
line)))
(apply concat)
(into {})))
(def opposite-dir {:left :right
:right :left
:up :down
:down :up})
(def start (->> char-map
(filter #(= \S (second %)))
ffirst))
(defn follow-dir [loc dir]
(condp = dir
:up (update loc 0 dec)
:down (update loc 0 inc)
:left (update loc 1 dec)
:right (update loc 1 inc)))
(def char-dir-map {\| [:up :down]
\- [:left :right]
\L [:right :up]
\F [:right :down]
\J [:left :up]
\7 [:left :down]})
(defn follow-pipe [loc from]
(let [c (char-map loc)]
(if (and (not (nil? c))
(not= \. c))
(let [dir (->> c
(char-dir-map)
(filter #(not= from %))
(first))
new-loc (follow-dir loc dir)]
(if ((pipe-out-types (opposite-dir dir)) (char-map new-loc))
[new-loc dir]
nil))
nil)))
;; part 1
(->> (for [start-dir [:up :down :left :right]]
(loop [loc (follow-dir start start-dir)
cnt 0
from (opposite-dir start-dir)
visited #{}]
(if (or (= loc nil) (= loc start))
cnt
(let [res (follow-pipe loc from)]
(if (or (= res nil)
(visited (first res)))
nil
(recur (first res)
(inc cnt)
(opposite-dir (second res))
(conj visited loc)))))))
(filter (comp not nil?))
(map #(/ % 2))
(map math/round)
(into #{})
(apply max))
;; part 2
(let [path (->> (for [start-dir [:right :left :up :down]]
(loop [loc (follow-dir start start-dir)
route []
from (opposite-dir start-dir)
visited #{}]
(if (or (= loc nil) (= loc start))
route
(let [res (follow-pipe loc from)]
(if (or (= res nil)
(visited (first res)))
nil
(recur (first res)
(conj route loc)
(opposite-dir (second res))
(conj visited loc)))))))
(filter (comp not nil?))
(sort-by #(/ (count %) 2) >)
first
(into #{})
(#(conj % start)))
by-row (->> path
(group-by first)
(map #(update % 1 (partial map second)))
(map #(update % 1 sort))
(into {}))
by-col (->> path
(group-by second)
(map #(update % 1 (partial map first)))
(map #(update % 1 sort))
(into {}))
coords (->> char-map
(map first)
(filter (comp not path)))]
(->> coords
(filter (fn [[row col]]
(or (->> row
by-row
(partition 2)
(some #(< (first %) col (second %))))
(->> col
by-col
(partition 2)
(some #(< (first %) row (second %)))))))
count))