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))))))