Created
December 13, 2020 14:24
-
-
Save death/4b85fdb0cf6be02c55623caeded7ca40 to your computer and use it in GitHub Desktop.
aoc2020 day13
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| ;;;; +----------------------------------------------------------------+ | |
| ;;;; | Advent of Code 2020 | | |
| ;;;; +----------------------------------------------------------------+ | |
| (defpackage #:snippets/aoc2020/day13 | |
| (:use #:cl) | |
| (:import-from | |
| #:split-sequence | |
| #:split-sequence) | |
| (:import-from | |
| #:snippets/egcd | |
| #:chinese) | |
| (:export | |
| #:day13)) | |
| (in-package #:snippets/aoc2020/day13) | |
| (defun parse (input) | |
| (values (parse-integer (first input)) | |
| (mapcar (lambda (string) | |
| (parse-integer string :junk-allowed t)) | |
| (split-sequence #\, (second input))))) | |
| (defun product (sequence) | |
| (reduce #'* sequence)) | |
| (defun in-service (buses) | |
| (remove-if-not #'numberp buses)) | |
| (defun time-to-wait (bus arrival) | |
| (- (nth-value 1 (ceiling arrival bus)))) | |
| (defun earlier (best bus arrival) | |
| (let ((w (time-to-wait bus arrival))) | |
| (if (or (null best) | |
| (< w (second best))) | |
| (list bus w) | |
| best))) | |
| (defun earliest (buses arrival) | |
| (reduce (lambda (best bus) | |
| (earlier best bus arrival)) | |
| (in-service buses) | |
| :initial-value nil)) | |
| (defun contest (buses) | |
| (chinese (in-service buses) | |
| (loop for bus in buses | |
| for i downfrom 0 | |
| when bus | |
| collect i))) | |
| (defun day13 (input) | |
| (multiple-value-bind (arrival buses) | |
| (parse input) | |
| (list (product (earliest buses arrival)) | |
| (contest buses)))) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| (defpackage #:snippets/egcd | |
| (:use #:cl) | |
| (:export | |
| #:egcd | |
| #:chinese)) | |
| (in-package #:snippets/egcd) | |
| ;; Following TAOCP chapter 1 | |
| (defun egcd (m n) | |
| "Extended gcd. Returns d, a, and b such that am+bn=d." | |
| (let ((ap 1) (b 1) | |
| (a 0) (bp 0) | |
| (c m) (d n)) | |
| (loop | |
| (multiple-value-bind (q r) (floor c d) | |
| (if (zerop r) | |
| (return-from egcd (values d a b)) | |
| (psetf c d | |
| d r | |
| ap a | |
| a (- ap (* q a)) | |
| bp b | |
| b (- bp (* q b)))))))) | |
| ;; Algorithm from | |
| ;; https://www.omnicalculator.com/math/chinese-remainder | |
| (defun chinese (ns as) | |
| "Return a number that satisfies each of the congruences defined by | |
| coprime moduli ns and remainders as." | |
| (let* ((N (reduce #'* ns)) | |
| (ms (mapcar (lambda (x) (/ N x)) ns)) | |
| (vs (mapcar (lambda (n m) | |
| (multiple-value-bind (d u v) | |
| (egcd n m) | |
| (declare (ignore u)) | |
| (assert (= d 1)) | |
| v)) | |
| ns | |
| ms)) | |
| (es (mapcar #'* vs ms))) | |
| (mod (reduce #'+ (mapcar #'* es as)) N))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment