advent-of-code-2023

My solutions to AoC 2023
git clone git://git.entf.net/advent-of-code-2023
Log | Files | Refs

day-15.lisp (2486B)


      1 (defpackage #:aoc/day-15
      2   (:use #:cl #:aoc/utils)
      3   (:export #:day-15))
      4 (in-package #:aoc/day-15)
      5 
      6 (defun next-element (input)
      7   (let ((next (loop for char = (read-char input nil)
      8                     while (and char (char/= char #\,))
      9                     when (char/= #\Newline)
     10                       collect char)))
     11     (when next
     12       (coerce next 'string))))
     13 
     14 (defun calculate-hash (element)
     15   (loop with current = 0
     16         for char across element
     17         do (progn
     18              (incf current (char-code char))
     19              (setf current (* current 17))
     20              (setf current (rem current 256)))
     21         finally (return current)))
     22 
     23 (defun parse-element (element)
     24   (loop for char across element
     25         for i from 0
     26         do (cond
     27              ((char= char #\-)
     28               (return (list (subseq element 0 i) :remove)))
     29              ((char= char #\=)
     30               (return (list (subseq element 0 i)
     31                             (parse-integer element :start (1+ i))))))))
     32 
     33 (defun total-focusing-power (boxes)
     34   (loop for lenses across boxes
     35         for box from 1
     36         sum (loop for lens in lenses
     37                   for slot from 1
     38                   sum (* box slot (second lens)))))
     39 
     40 (defun day-15 (input)
     41   (loop with boxes = (make-array 256 :initial-element nil)
     42         for element = (next-element input)
     43         while element
     44         for parsed-element = (parse-element element)
     45         for box = (calculate-hash (first parsed-element))
     46         do (setf (aref boxes box)
     47                  (if (eq (second parsed-element) :remove)
     48                      (remove (first parsed-element)
     49                              (aref boxes box)
     50                              :test #'equal
     51                              :key #'first)
     52                      (let* ((box-content (aref boxes box))
     53                             (existing (find (first parsed-element)
     54                                             box-content
     55                                             :test #'equal
     56                                             :key #'first)))
     57                        (if existing
     58                            (progn
     59                              (setf (second existing) (second parsed-element))
     60                              box-content)
     61                            (nconc box-content
     62                                   (list parsed-element))))))
     63         sum (calculate-hash element) into task-1
     64         finally (return (values task-1
     65                                 (total-focusing-power boxes)))))