blob: 5a5fc4ed8a3dbdc8690ae4b0f4109b1c359d2112 (
plain) (
tree)
|
|
(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
|