about summary refs log tree commit diff
path: root/day16.clj
diff options
context:
space:
mode:
Diffstat (limited to 'day16.clj')
-rw-r--r--day16.clj101
1 files changed, 101 insertions, 0 deletions
diff --git a/day16.clj b/day16.clj
new file mode 100644
index 0000000..a4d8925
--- /dev/null
+++ b/day16.clj
@@ -0,0 +1,101 @@
+(ns org.vuxu.aoc2021.day16
+  (:require [clojure.string :as str]
+            [clojure.pprint :refer [cl-format]]))
+
+(defn hex2bin [hex]
+  (map #(Character/digit % 2)
+       (mapcat #(cl-format nil "~4,'0B" (Character/digit % 16)) hex)))
+
+(defn bin2int [bin]
+  (Integer/parseInt (apply str bin) 2))
+
+(def data
+  (->> (slurp "day16")
+       str/trim-newline
+       hex2bin))
+
+(declare parse-all)
+(declare parse-n)
+
+(defn parse [bin]
+  (let [[version bin] (split-at 3 bin)
+        [type bin] (split-at 3 bin)
+        version (bin2int version)
+        type (bin2int type)
+        
+        [content bin] (if (= type 4)
+                        (loop [bin bin
+                               lit 0]
+                          (let [[cont bin] (split-at 1 bin)
+                                [data bin] (split-at 4 bin)
+                                lit (bit-or (bit-shift-left lit 4)
+                                            (bin2int data))]
+                            (if (= cont [1])
+                              (recur bin lit)
+                              [{:literal lit} bin])))
+                        (let [[length-type bin] (split-at 1 bin)
+                              [inner-packets bin]
+                              (if (= length-type [0])
+                                (let [[l bin] (split-at 15 bin)
+                                      [packets bin]
+                                      (split-at (bin2int l) bin)]
+                                  [(parse-all packets) bin])
+                                (let [[n bin] (split-at 11 bin)]
+                                  (parse-n bin (bin2int n))))
+                              ]
+                          [{:operator inner-packets} bin]))
+        ]
+    [(into {:version version :type type} content)
+     bin]))
+
+(defn parse-all [bin]
+  (loop [bin bin
+         parsed []]
+    (if (seq bin)
+      (let [[item bin] (parse bin)]
+        (recur bin (conj parsed item)))
+      parsed)))
+
+(defn parse-n [bin n]
+  (loop [bin bin
+         n n
+         parsed []]
+    (if (zero? n)
+      [parsed bin]
+      (let [[item bin] (parse bin)]
+        (recur bin (dec n) (conj parsed item))))))
+
+(defn sum-version [packet]
+  (if (:literal packet)
+    (:version packet)
+    (+ (:version packet)
+       (apply + (map sum-version (:operator packet))))))
+
+(def part1
+  (sum-version (first (parse data))))
+;; => 981
+
+(defn eval-packet [packet]
+  (prn packet)
+  (case (:type packet)
+    0 (apply + (map eval-packet (:operator packet)))
+    1 (apply * (map eval-packet (:operator packet)))
+    2 (apply min (map eval-packet (:operator packet)))
+    3 (apply max (map eval-packet (:operator packet)))
+    4 (:literal packet)
+    5 (if (> (eval-packet (first (:operator packet)))
+             (eval-packet (second (:operator packet))))
+        1
+        0)
+    6 (if (< (eval-packet (first (:operator packet)))
+             (eval-packet (second (:operator packet))))
+        1
+        0)
+    7 (if (= (eval-packet (first (:operator packet)))
+             (eval-packet (second (:operator packet))))
+        1
+        0)))
+
+(def part2
+  (eval-packet (first (parse data))))
+;; => 299227024091