Login
7 branches 0 tags
Ben (X13/Arch) Removed (macro-apply) 89d505b 2 years ago 989 Commits
nujel / tests / ridiculous / day18.nuj
#!/usr/bin/env nujel

(defn snail/read-line (line)
      (read/single (join (split line ",") " . ")))

(defn snail/parse-list (l d)
      (cond ((nil? l) #nil)
            ((int? l) {:v l})
            (#t {:r (snail/parse-list (cdr l)) :l (snail/parse-list (car l))})))

(defn snail/read (line)
      (snail/parse-list (snail/read-line line)))

(defn snail/int? (l)
      (and l (ref l :v)))

(defn snail->str (l)
      (cond ((snail/int? l) (string (ref l :v)))
            (#t (cat "(" (snail->str (ref l :l))  "," (snail->str (ref l :r)) ")"))))

(defn snail/find (root needle as bs)
      (def last #nil)
      (defn rec (t root needle)

            (cond ((snail/int? t) (set! last t) #f)
                  ((= needle t) last)
                  (#t (or (rec (ref t as) root needle)
                          (rec (ref t bs) root needle)))))
      (rec root root needle))

(defn snail/find/previous (root needle)
      (snail/find root needle :l :r))

(defn snail/find/next (root needle)
      (snail/find root needle :r :l))

(defn snail/explode (t root)
      (def p (snail/find/previous root t))
      (when p (tree/+= p :v (ref (ref t :l) :v)))
      (def n (snail/find/next root t))
      (when n (tree/+= n :v (ref (ref t :r) :v)))
      (-> t
          (tree/set! :v 0)
          (tree/set! :l #nil)
          (tree/set! :r #nil)))

(defn snail/split (t root)
      (def lv (div/int (ref t :v) 2))
      (-> t
          (tree/set! :l {:v lv})
          (tree/set! :r {:v (- (ref t :v) lv)})
          (tree/set! :v #nil)))

(defn snail/explode/maybe (t root d)
      (cond ((snail/int? t) #f)
            ((>= d 4) (snail/explode t root))
            ((snail/explode/maybe (ref t :l) root (+ 1 d)) #t)
            (#t (snail/explode/maybe (ref t :r) root (+ 1 d)))))

(defn snail/split/maybe (t root d)
      (cond ((snail/int? t) (and (>= (ref t :v) 10)
                                 (snail/split t root) #t))
            ((snail/split/maybe (ref t :l) root (+ 1 d)) #t)
            (#t (snail/split/maybe (ref t :r) root (+ 1 d)))))

(defn snail/reduce (t)
      (while (or (snail/explode/maybe t t 0)
                 (snail/split/maybe t t 0))) t)

(defn snail/add (a b)
      (snail/reduce {:l a :r b}))

(defn snail/sum (lines)
      (def vals (map (split lines "\n") snail/read))
      (reduce (cdr vals) snail/add (car vals)))

(defn snail/mag (t)
      (cond ((snail/int? t) (ref t :v))
            (#t (+ (* (snail/mag (ref t :l)) 3)
                   (* (snail/mag (ref t :r)) 2)))))

(defn snail/find-biggest (lines)
      (def vals (apply array/new (split lines "\n")))
      (def cmax 0)
      (dotimes (a 100)
               (dotimes (b 100)
                        (when (not= a b)
                              (def cs (snail/add (snail/read (ref vals a)) (snail/read (ref vals b))))
                              (set! cmax (max cmax (snail/mag cs)))
                              (def cs (snail/add (snail/read (ref vals b)) (snail/read (ref vals a))))
                              (set! cmax (max cmax (snail/mag cs))))))
      cmax)

(def res-p1 (snail/mag (snail/sum (file/read "tests/slow/day18.input"))))
(when (not= res-p1 3725)
      (throw (list :wrong-result "Wrong result" res-p1)))
(def res-p2 (snail/find-biggest (file/read "tests/slow/day18.input")))
(when (not= res-p2 4832)
      (throw (list :wrong-result "Wrong result" res-p2)))

(return :success)