A day16.lisp => day16.lisp +111 -0
@@ 0,0 1,111 @@
+(defpackage #:advent2021.day16
+ (:use #:cl #:alexandria #:cl-ppcre #:queues #:advent2021.util)
+ (:export #:solve-part-1 #:solve-part-2))
+
+(in-package #:advent2021.day16)
+
+
+
+(defun hex2val (c)
+ (if (<= (char-code #\0) (char-code c) (char-code #\9))
+ (- (char-code c) (char-code #\0))
+ (- (char-code (char-upcase c)) (char-code #\A) -10)))
+
+(defparameter +input+
+ (loop :with line := (with-puzzle-file (stream)
+ (read-line stream))
+ :with array := (make-array (* 4 (length line))
+ :element-type 'bit)
+ :for c :across line
+ :for nybble := (hex2val c)
+ :for i :upfrom 0 :by 4
+ :do (setf (aref array i) (logand 1 (ash nybble -3)))
+ :do (setf (aref array (+ 1 i)) (logand 1 (ash nybble -2)))
+ :do (setf (aref array (+ 2 i)) (logand 1 (ash nybble -1)))
+ :do (setf (aref array (+ 3 i)) (logand 1 (ash nybble -0)))
+ :finally (return array)))
+
+(defun reader ()
+ (cons 0 nil))
+
+(defun pos (reader)
+ (car reader))
+
+(defun (setf pos) (new-value reader)
+ (setf (car reader) new-value))
+
+(defun read-bits (reader size)
+ (loop :with start := (pos reader)
+ :with result := 0
+ :for i :from start :below (+ start size)
+ :do (setf result (+ (ash result 1)
+ (aref +input+ i)))
+ :finally (incf (pos reader) size)
+ (return result)))
+
+(defun read-literal (reader)
+ (loop :with result := 0
+ :for group := (read-bits reader 5)
+ :do (setf result (logior (ash result 4)
+ (logand group #b1111)))
+ :while (= (logand #b10000 group) #b10000)
+ :finally (return result)))
+
+(defun read-subpackets-to-length (reader length)
+ (loop :with start := (pos reader)
+ :collect (read-packet reader)
+ :while (< (- (pos reader) start) length)))
+
+(defun read-packet (reader)
+ (let ((version (read-bits reader 3))
+ (type (read-bits reader 3)))
+ (cond
+ ((= type 4)
+ (list :version version :type type
+ :value (read-literal reader)))
+ ((= 0 (read-bits reader 1))
+ (list :version version :type type
+ :subpackets (read-subpackets-to-length
+ reader (read-bits reader 15))))
+ (t
+ (list :version version :type type
+ :subpackets (loop :repeat (read-bits reader 11)
+ :collect (read-packet reader)))))))
+
+(defun sum-versions (packet)
+ (if (= 4 (getf packet :type))
+ (getf packet :version)
+ (+ (getf packet :version)
+ (loop :for subpacket :in (getf packet :subpackets)
+ :sum (sum-versions subpacket)))))
+
+(defun solve-part-1 ()
+ (sum-versions (read-packet (reader))))
+
+(defun packet-type (packet)
+ (getf packet :type))
+
+(defun subpackets (packet)
+ (getf packet :subpackets))
+
+(defun eval-packet (packet)
+ (eswitch (packet :key #'packet-type)
+ (0 (reduce #'+ (mapcar #'eval-packet (subpackets packet))))
+ (1 (reduce #'* (mapcar #'eval-packet (subpackets packet))))
+ (2 (reduce #'min (mapcar #'eval-packet (subpackets packet))))
+ (3 (reduce #'max (mapcar #'eval-packet (subpackets packet))))
+ (4 (getf packet :value))
+ (5 (if (> (eval-packet (first (subpackets packet)))
+ (eval-packet (second (subpackets packet))))
+ 1 0))
+ (6 (if (< (eval-packet (first (subpackets packet)))
+ (eval-packet (second (subpackets packet))))
+ 1 0))
+ (7 (if (= (eval-packet (first (subpackets packet)))
+ (eval-packet (second (subpackets packet))))
+ 1 0))))
+
+(defun solve-part-2 ()
+ (eval-packet (read-packet (reader))))
+
+
A input/day16.txt => input/day16.txt +1 -0
@@ 0,0 1,1 @@
+00569F4A0488043262D30B333FCE6938EC5E5228F2C78A017CD78C269921249F2C69256C559CC01083BA00A4C5730FF12A56B1C49A480283C0055A532CF2996197653005FC01093BC4CE6F5AE49E27A7532200AB25A653800A8CAE5DE572EC40080CD26CA01CAD578803CBB004E67C573F000958CAF5FC6D59BC8803D1967E0953C68401034A24CB3ACD934E311004C5A00A4AB9CAE99E52648401F5CC4E91B6C76801F59DA63C1F3B4C78298014F91BCA1BAA9CBA99006093BFF916802923D8CC7A7A09CA010CD62DF8C2439332A58BA1E495A5B8FA846C00814A511A0B9004C52F9EF41EC0128BF306E4021FD005CD23E8D7F393F48FA35FCE4F53191920096674F66D1215C98C49850803A600D4468790748010F8430A60E1002150B20C4273005F8012D95EC09E2A4E4AF7041004A7F2FB3FCDFA93E4578C0099C52201166C01600042E1444F8FA00087C178AF15E179802F377EC695C6B7213F005267E3D33F189ABD2B46B30042655F0035300042A0F47B87A200EC1E84306C801819B45917F9B29700AA66BDC7656A0C49DB7CAEF726C9CEC71EC5F8BB2F2F37C9C743A600A442B004A7D2279125B73127009218C97A73C4D1E6EF64A9EFDE5AF4241F3FA94278E0D9005A32D9C0DD002AB2B7C69B23CCF5B6C280094CE12CDD4D0803CF9F96D1F4012929DA895290FF6F5E2A9009F33D796063803551006E3941A8340008743B8D90ACC015C00DDC0010B873052320002130563A4359CF968000B10258024C8DF2783F9AD6356FB6280312EBB394AC6FE9014AF2F8C381008CB600880021B0AA28463100762FC1983122D2A005CBD11A4F7B9DADFD110805B2E012B1F4249129DA184768912D90B2013A4001098391661E8803D05612C731007216C768566007280126005101656E0062013D64049F10111E6006100E90E004100C1620048009900020E0006DA0015C000418000AF80015B3D938