src/2023/days/day-05.lisp @ 59d313b4c898
Commit some 2023 days
author |
Steve Losh <steve@stevelosh.com> |
date |
Wed, 06 Dec 2023 08:17:12 -0500 |
parents |
(none) |
children |
861dab6dff4c |
(advent:defpackage* :advent/2022/05)
(in-package :advent/2022/05)
;; Not really mentioned in the problem, but the maps come in sorted, i.e. the're
;; in the correct order. So we don't need to bohter making a hash table of
;; {from: to: [...]} but can just process the maps in the order they're given.
(defstruct (mapping (:constructor make-mapping%))
src-start src-end dst-start)
(defun make-mapping (src dst len)
(make-mapping% :src-start src :src-end (+ src len) :dst-start dst))
(defun parse-seeds (string)
;; seeds: 79 14 55 13
(mapcar #'parse-integer (rest (str:words string))))
(defun parse-body-range (string)
;; 50 98 2
(destructuring-bind (dst src len) (mapcar #'parse-integer (str:words string))
(make-mapping src dst len)))
(defun parse-body (strings)
;; 50 98 2
;; 52 50 48
(sort (mapcar #'parse-body-range strings) #'< :key #'mapping-src-start))
(defun parse-map (string)
;; seed-to-soil map:
;; 50 98 2
;; 52 50 48
(parse-body (rest (str:lines string))))
(defun parse (data)
(destructuring-bind (seeds . maps) (str:split (format nil "~2%") data)
(values (parse-seeds seeds)
(mapcar #'parse-map maps))))
(defun src->dst (mapping n)
(+ (mapping-dst-start mapping)
(- n (mapping-src-start mapping))))
(defun map-single-range (input ranges)
(iterate
(with (start . end) = input)
(with n = start)
(with r = (pop ranges))
(while (< n end))
(when (null r)
(collect (cons n end))
(finish))
(for rs = (mapping-src-start r))
(for re = (mapping-src-end r))
(cond ((< n rs)
(let ((bound (min end rs)))
(collect (cons n bound))
(setf n bound)))
((>= n re)
(setf r (pop ranges)))
(t (let ((stop (min end re)))
(collect (cons (src->dst r n)
(src->dst r stop)))
(setf n stop))))))
(defun map-ranges (inputs ranges)
(iterate (for input :in inputs)
(appending (map-single-range input ranges))))
(defun traverse (almanac seeds)
(reduce #'map-ranges almanac :initial-value seeds))
;; (defun map-number (n ranges)
;; (let ((r (bisect-right #'> ranges n :key #'mapping-src-start)))
;; (if (or (null r) (>= n (mapping-src-end r)))
;; n
;; (let ((i (- n (mapping-src-start r))))
;; (+ (mapping-dst-start r) i)))))
;; (defun traverse (almanac seed)
;; (reduce #'map-number almanac :initial-value seed))
(define-problem (2023 5) (data alexandria:read-stream-content-into-string) (324724204)
(multiple-value-bind (seeds almanac) (parse data)
(let ((part-1 (iterate (for seed :in seeds)
(collect (cons seed (1+ seed)))))
(part-2 (iterate (for (start length) :on seeds :by #'cddr)
(collect (cons start (+ start length))))))
(values (reduce #'min (mapcar #'car (traverse almanac part-1)))
(reduce #'min (mapcar #'car (traverse almanac part-2)))))))
#; Scratch --------------------------------------------------------------------