~shunter/advent2021

63186e1c4825915cef4e89d18e9bc66f456e5250 — Samuel Hunter 2 years ago 32ad10d
Solve Day 15
2 files changed, 112 insertions(+), 0 deletions(-)

A day16.lisp
A input/day16.txt
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