diff options
author | Alexandre Jesus <adbjesus@gmail.com> | 2023-12-09 22:40:15 +0000 |
---|---|---|
committer | Alexandre Jesus <adbjesus@gmail.com> | 2023-12-09 22:40:15 +0000 |
commit | 35d1a045681b7132b039d0da1412d1ac3c18bff0 (patch) | |
tree | 31b968c408cbcba974ca418ab9664b035d8f61f9 /day05.lisp | |
download | aoc2023-35d1a045681b7132b039d0da1412d1ac3c18bff0.tar.gz aoc2023-35d1a045681b7132b039d0da1412d1ac3c18bff0.zip |
First 6 days
Diffstat (limited to 'day05.lisp')
-rw-r--r-- | day05.lisp | 100 |
1 files changed, 100 insertions, 0 deletions
diff --git a/day05.lisp b/day05.lisp new file mode 100644 index 0000000..5a5fc4e --- /dev/null +++ b/day05.lisp @@ -0,0 +1,100 @@ +(defun parse-integers (string &key (start 0)) + (loop for i = start then (cadr o) + as o = (multiple-value-list (parse-integer string :start i :junk-allowed t)) + as n = (car o) + while n + collect n)) + +(defstruct problem + seeds + maps) + +(defun parse-map (stream) + ;; Ignore empty lines + title-line + (loop for line = (read-line stream nil 'eof) + until (eq line 'eof) + until (> (length line) 0)) + ;; Read integers for map + (loop for line = (read-line stream nil 'eof) + until (eq line 'eof) + while (> (length line) 0) + collect (parse-integers line))) + +(defun parse-problem (f) + (with-open-file (s f) + (let* ((seeds (let ((str (read-line s))) + (parse-integers str :start (1+ (position #\: str))))) + (maps (loop for map = (parse-map s) + while map + collect map))) + (make-problem :seeds seeds + :maps maps)))) + +(defun map-match (map value) + (let ((aux (loop for range in map + as l = (caddr range) + as s = (cadr range) + as d = (car range) + if (and (>= value s) (< value (+ s l))) + return (+ d (- value s))))) + (if aux + aux + value))) + +(defun seed-to-location (problem seed) + (reduce (lambda (value item) (map-match item value)) + (problem-maps problem) + :initial-value seed)) + +(defun solve1 (f) + (let ((problem (parse-problem f))) + (loop for seed in (problem-seeds problem) + minimize (seed-to-location problem seed)))) + +(defun map-ranges (start length map) + (when (> length 0) + (if map + (let* ((range (car map)) + (rdest (car range)) + (rstart (cadr range)) + (rlength (caddr range)) + (end (1- (+ start length))) + (rend (1- (+ rstart rlength)))) + (cond + ;; no overlap + ((or (< end rstart) (< rend start)) + (map-ranges start length (cdr map))) + ;; inner overlap + ((and (>= start rstart) (<= end rend)) + (list (cons (+ rdest (- start rstart)) length))) + ;; outer overlap + ((and (>= rstart start) (<= rend end)) + (append (map-ranges start (- rstart start) (cdr map)) + (list (cons rdest rlength)) + (map-ranges (1+ rend) (- end rend) (cdr map)))) + ;; right overlap + ((and (>= rstart start) (<= end rend)) + (append (map-ranges start (- rstart start) (cdr map)) + (list (cons rdest (1+ (- end rstart)))))) + ;; left overlap + ((and (>= start rstart) (<= rend end)) + (append (list (cons (+ rdest (- start rstart)) (1+ (- rend start)))) + (map-ranges (1+ rend) (- end rend) (cdr map)))))) + (list (cons start length))))) + +(defun seed-range-to-min-location (start length maps) + (if maps + (loop for range in (map-ranges start length (car maps)) + if range + minimize (seed-range-to-min-location (car range) (cdr range) (cdr maps))) + start)) + +(defun solve2 (f) + (let ((problem (parse-problem f))) + (loop for (start length) on (problem-seeds problem) by #'cddr + minimize (seed-range-to-min-location start length (problem-maps problem))))) + +(print (solve1 "data/05/example.txt")) ;; 35 +(print (solve1 "data/05/input.txt")) ;; 579439039 +(print (solve2 "data/05/example.txt")) ;; 46 +(print (solve2 "data/05/input.txt")) ;; 7873084 |