(ql:quickload '(fiveam str)) (defparameter eg-input "seeds: 79 14 55 13 seed-to-soil map: 50 98 2 52 50 48 soil-to-fertilizer map: 0 15 37 37 52 2 39 0 15 fertilizer-to-water map: 49 53 8 0 11 42 42 0 7 57 7 4 water-to-light map: 88 18 7 18 25 70 light-to-temperature map: 45 77 23 81 45 19 68 64 13 temperature-to-humidity map: 0 69 1 1 0 69 humidity-to-location map: 60 56 37 56 93 4") (defun translate (rules value) (dolist (rule rules) (destructuring-bind (dest source span) rule (when (<= source value (+ source (1- span))) (return-from translate (+ (- value source) dest))))) value) (defun segment-translate (rules segments) (let ((sorted-rules (sort rules #'< :key #'cadr))) (mapcan (lambda (segment) (destructuring-bind (start . end) segment (loop for (dest-start source-start span) in sorted-rules ))) segments))) (sort '((50 98 2) (52 50 48)) #'< :key #'cadr) (fiveam:test parts (let ((rules '((50 98 2) (52 50 48)))) (fiveam:is (= 9 (translate rules 9))) (fiveam:is (= 61 (translate rules 59))) (fiveam:is (= 51 (translate rules 99))))) (defun translator (translate-chain translator-rules) (lambda (value) (reduce (lambda (acc fn) (translate (gethash fn translator-rules) acc)) translate-chain :initial-value value))) (defun parser (lines) (let (seeds maps-stack (translators (make-hash-table))) (dolist (line lines) (cond ((str:emptyp line)) ((str:starts-with? "seeds:" line) (setf seeds (mapcar #'parse-integer (cdr (str:split-omit-nulls #\Space line))))) ((str:ends-with-p "map:" line) (push (read-from-string line) maps-stack)) ((push (mapcar #'parse-integer (str:split-omit-nulls #\Space line)) (gethash (car maps-stack) translators))))) (values (translator (nreverse maps-stack) translators) seeds))) (defun solver1 (lines) (multiple-value-bind (translator seeds) (parser lines) (apply #'min (mapcar translator seeds)))) (defun solver2 (lines) (multiple-value-bind (translator seeds) (parser lines) (loop for (start span) on seeds by #'cddr minimize (loop for i from start below (+ start span) minimize (funcall translator i))))) (fiveam:test solutions (fiveam:is (= 35 (solver1 (uiop:split-string eg-input :separator '(#\Newline))))) (fiveam:is (= 46 (solver2 (uiop:split-string eg-input :separator '(#\Newline))))) (fiveam:is (= 662197086 (solver1 (uiop:read-file-lines "input")))) (fiveam:is (= 52510809 (solver2 (uiop:read-file-lines "input")))))