advent-of-code-2023

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

day-8.lisp (2617B)


      1 (defpackage #:aoc/day-8
      2   (:use #:cl #:aoc/utils)
      3   (:export #:day-8))
      4 (in-package #:aoc/day-8)
      5 
      6 (declaim (ftype (function (simple-string) fixnum) convert-field-to-number))
      7 (defun convert-field-to-number (field)
      8   (loop for char across field
      9         for shift fixnum from 0
     10         sum (the fixnum (ash (- (char-code char) (if (char>= char #\A) 65 48))
     11                              (the fixnum (* shift 5)))) fixnum))
     12 
     13 (declaim (ftype (function (simple-string) list) parse-line))
     14 (defun parse-line (line)
     15   (let* ((equal-pos (position #\= line))
     16          (key (subseq line 0 (1- equal-pos)))
     17          (paren-open-pos (position #\( line :start equal-pos))
     18          (comma-pos (position #\, line :start paren-open-pos))
     19          (left (subseq line (1+ paren-open-pos) comma-pos))
     20          (paren-close-pos (position #\) line :start comma-pos))
     21          (right (subseq line (+ comma-pos 2) paren-close-pos)))
     22     (list (convert-field-to-number key)
     23           (list (convert-field-to-number left)
     24                 (convert-field-to-number right)))))
     25 
     26 (declaim (ftype (function (stream) (simple-array list)) read-map))
     27 (defun read-map (input)
     28   (read-line input)
     29   (loop with map = (make-array 26426 :initial-element nil)
     30         for line = (read-line input nil)
     31         while line
     32         for (key left-right) = (parse-line line)
     33         do (setf (aref map key) left-right)
     34         finally (return map)))
     35 
     36 (declaim (ftype (function (simple-string
     37                            (simple-array list)
     38                            fixnum
     39                            &optional (or null fixnum))
     40                           fixnum)
     41                 walk-to-destination))
     42 (defun walk-to-destination (instructions map starting-point &optional destination)
     43   (loop with current fixnum = starting-point
     44         for steps fixnum from 0
     45         for direction = (aref instructions (mod steps (length instructions)))
     46         for (left right) = (aref map current)
     47         do (setf current
     48                  (ecase direction
     49                    (#\L left)
     50                    (#\R right)))
     51         when (if destination
     52                  (= current destination)
     53                  (>= current 25600))
     54           do (return (1+ steps))))
     55 
     56 (defun day-8 (input)
     57   (let ((instructions (read-line input))
     58         (map (read-map input)))
     59     (values (if (aref map 0)
     60                 (walk-to-destination instructions map 0 26425)
     61                 0)
     62             (apply #'lcm
     63                    (loop for field fixnum from 0 to 825
     64                          when (aref map field)
     65                            collect (walk-to-destination instructions map field))))))