diff --git a/day18/partboth.clj b/day18/partboth.clj new file mode 100644 index 0000000..b3b97ca --- /dev/null +++ b/day18/partboth.clj @@ -0,0 +1,97 @@ +(require '[clojure.core.reducers :as r]) +(require '[clojure.set :as set]) +(require '[clojure.zip :as z]) + +(defn zip-depth [loc] + (loop [l loc d 0] (if (nil? l) d (recur (z/up l) (inc d))))) + +(defn zip-prev-num [loc] + (loop [l loc] + (if-let [prev (z/prev l)] + (if (not (z/branch? prev)) + prev + (recur prev))))) + +(defn zip-next-num [loc] + (loop [l loc] + (if-let [nxt (z/next l)] + (if (not (z/branch? nxt)) + (when (some? (z/node nxt)) nxt) + (recur nxt))))) + +(defn snailfish-explode [tree] + (loop [node (z/vector-zip tree)] + (if (z/end? node) + node + (if (and (z/branch? node) + (= 2 (count (z/children node))) + (and (not (z/branch? (z/down node))) (not (z/branch? (z/next (z/down node))))) + (> (zip-depth node) 5)) + (let [children (z/children node) + nnode (z/replace node 0)] + (if-let [prev (zip-prev-num nnode)] + (z/root + (let [new-prev (z/edit prev + (first children))] + (if-let [nxt (nth (iterate zip-next-num new-prev) 2)] + (z/edit nxt + (second children)) + new-prev))) + (when-let [nxt (zip-next-num nnode)] + (z/root (z/edit nxt + (second children)))))) + (recur (z/next node)))))) + +(defn snailfish-split [tree] + (loop [node (z/vector-zip tree)] + (if (or (z/end? node) (nil? (z/node node))) + node + (if (and (not (z/branch? node)) (> (z/node node) 9)) + (z/root + (z/replace node + (z/make-node node (z/node node) + (map long [(Math/floor (/ (z/node node) 2)) + (Math/ceil (/ (z/node node) 2))])))) + (recur (z/next node)))))) + +(defn snailfish-magnitude [ntree] + (if (= 2 (count (z/children ntree))) + (let [cl (z/down ntree) cr (z/right cl)] + (+ (* 3 (if (z/branch? cl) (snailfish-magnitude cl) (z/node cl))) + (* 2 (if (z/branch? cr) (snailfish-magnitude cr) (z/node cr))))) + (loop [node (z/down ntree) sum 0] + (if (nil? node) + sum + (recur (z/right node) + (+ sum (if (z/branch? node) (snailfish-magnitude node) (z/node node)))))))) + +(defn snailfish-solve [add-list] + (snailfish-magnitude + (loop [result (z/vector-zip (vec (take 2 add-list))) + next-input (drop 2 add-list)] + (let [explode (snailfish-explode result)] + (if (nil? (second explode)) + (recur explode next-input) + (let [splt (snailfish-split result)] + (if (nil? (second splt)) + (recur splt next-input) + (if (empty? next-input) + result + (recur (z/vector-zip + [(vec (z/children result)) (first next-input)]) + (rest next-input)))))))))) + +; Build input list +(def input (->> (slurp "./in") + clojure.string/split-lines + (map read-string))) + +; Part 1 +(println (snailfish-solve input)) + +; Part 2 +(->> (let [input-set (set input)] + (for [in input in2 (set/difference input-set (set [in]))] + [in in2])) + (into []) + (r/map snailfish-solve) + (r/fold (r/monoid max (constantly 0))) + (println)) +