You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

98 lines
3.2 KiB
Clojure

(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))