Login
7 branches 0 tags
Ben (X13/Arch) Simplified things a little 0643405 9 days ago 1260 Commits
nujel / tests / fast / day8.nuj
#!/usr/bin/env nujel

(def lines (split (file/read "tests/fast/day8.dat") "\n"))
(def counts (-> (:alloc Array 10) (array/fill! 0)))

(defn output/count (entry)
       (def len (:length entry))
       (case len
             (2 (array/++ counts 1))
             (3 (array/++ counts 7))
             (4 (array/++ counts 4))
             (7 (array/++ counts 8))
             (otherwise #f)))

(defn find/by-length (vals arr len pos)
       (if-not vals #nil
               (if (= len (popcount (car vals)))
                   (do (set! arr pos (car vals))
                       (find/by-length (cdr vals) arr len pos))
                   (cons (car vals)
                         (find/by-length (cdr vals) arr len pos)))))

(defn find/six (vals numbers)
       (def ret (-> vals
                (filter (fn (α) (= (popcount α) 6)))
                (filter (fn (α) (= (popcount (bit-and α (ref numbers 1))) 1)))
       ))
       (when (> (:length ret) 1) (stacktrace))
       (set! numbers 6 (car ret))
       (filter vals (fn (α) (not= α (car ret)))))

(defn find/five (vals numbers)
       (def ret (-> vals
                (filter (fn (α) (= (popcount α) 5)))
                (filter (fn (α) (= α (bit-and α (ref numbers 6)))))))
       (when (> (:length ret) 1) (stacktrace))
       (set! numbers 5 (car ret))
       (filter vals (fn (α) (not= α (car ret)))))

(defn find/nine (vals numbers)
       (def ret (-> vals
                (filter (fn (α) (= (popcount α) 6)))
                (filter (fn (α) (= α (bit-or α (ref numbers 4)))))))
       (when (> (:length ret) 1) (stacktrace))
       (set! numbers 9 (car ret))
       (filter vals (fn (α) (not= α (car ret)))))

(defn find/zero (vals numbers)
       (def ret (-> vals
                (filter (fn (α) (= (popcount α) 6)))))
       (when (> (:length ret) 1) (stacktrace))
       (set! numbers 0 (car ret))
       (filter vals (fn (α) (not= α (car ret)))))

(defn find/three (vals numbers)
       (def ret (-> vals
                (filter (fn (α) (= (popcount α) 5)))
                (filter (fn (α) (= α (bit-or α (ref numbers 1)))))))
       (when (> (:length ret) 1) (stacktrace))
       (set! numbers 3 (car ret))
       (filter vals (fn (α) (not= α (car ret)))))

(defn find/two (vals numbers)
       (def ret (-> vals
                (filter (fn (α) (= (popcount α) 5)))
                (filter (fn (α) (not= α (bit-or α (ref numbers 1)))))))
       (when (> (:length ret) 1) (stacktrace))
       (set! numbers 2 (car ret))
       (filter vals (fn (α) (not= α (car ret)))))

(defn seven-seg->binary (str)
       (reduce (split str "")
               (fn (α β) (bit-or α (case β ("a" #x01)
                                          ("b" #x02)
                                          ("c" #x04)
                                          ("d" #x08)
                                          ("e" #x10)
                                          ("f" #x20)
                                          ("g" #x40)))) 0))

(defn translate (vals out-vals)
       (def numbers (-> (:alloc Array 10)
                        (array/fill! #nil)))

       (-> (map vals seven-seg->binary)
           (find/by-length numbers 2 1)
           (find/by-length numbers 3 7)
           (find/by-length numbers 4 4)
           (find/by-length numbers 7 8)
           (find/six numbers)
           (find/five numbers)
           (find/nine numbers)
           (find/zero numbers)
           (find/three numbers)
           (find/two numbers))

       (defn translate/val (val i)
              (when-not i (def i 0))
              (when (> i 10) (throw (list :error "")))
              (if (= (ref numbers i) val)
                  i
                  (translate/val val (+ 1 i))))
       (reduce (map (map out-vals seven-seg->binary) translate/val) (fn (α β) (+ (* α 10) β)) 0))

(def part-2 (reduce lines (fn (Σ line)
          (def split-args (split line "|"))
          (def output-raw (map (read (cadr split-args)) :string))
          (for-each output-raw output/count)
          (def table-raw (map (read (car split-args)) :string))
          (def output-sum (translate table-raw output-raw))
          (+ Σ output-sum)) 0))

(def result (sum counts))
(when (not= result 532)
      (throw (list :wrong-result "Wrong result" result)))
(def result part-2)
(when (not= result 1011284)
      (throw (list :wrong-result "Wrong result" result)))

(return :success)