+(asdf:load-system :adventofcode2020)
+(in-package #:adventofcode2020)
+(named-readtables:in-readtable fn-reader)
+
+(defun make-preambled-list (list k i)
+ (subseq list (- i k) (1+ i)))
+
+(defun check-consistency (list)
+ (let ((preamble (butlast list))
+ (checksum (car (last list))))
+ (block find-sum
+ (dolist (i preamble)
+ (dolist (j preamble)
+ (unless (= i j)
+ (when (= (+ i j) checksum)
+ (return-from find-sum '(i j)))))))))
+
+(defun test-preambled-lists (list preamble)
+ (loop for i upfrom preamble below (length list)
+ unless (check-consistency (make-preambled-list list preamble i))
+ return (nth i list)))
+
+(defun find-sum-list (list checksum)
+ (labels ((test-bounds (i j)
+ (let ((sum (apply #'+ (subseq list i j))))
+ (cond ((< sum checksum) :lt)
+ ((= sum checksum) :eq)
+ ((> sum checksum) :gt))))
+ (find-bounds (i j)
+ (case (test-bounds i j)
+ (:lt (find-bounds i (1+ j)))
+ (:eq (subseq list i j))
+ (:gt (find-bounds (1+ i) j)))))
+ (find-bounds 0 1)))
+
+(day 09 input
+ (let ((numbers (int-list-from input)))
+ (part1 (test-preambled-lists numbers 25))
+ (part2 (let ((sum-list (find-sum-list numbers (test-preambled-lists numbers 25))))
+ (+ (apply #'min sum-list)
+ (apply #'max sum-list))))))
+
+(def-suite day09)
+(in-suite day09)
+
+(defvar *simple-numbers*
+ '(35 20 15 25 47 40 62 55
+ 65 95 102 117 150 182
+ 127 219 299 277 309 576))
+
+(test make-preambled-lists
+ (is (equal
+ '(35 20 15 25 47 40)
+ (make-preambled-list *simple-numbers* 5 5)))
+ (is (equal
+ '(40 62 55 65 95 102)
+ (make-preambled-list *simple-numbers* 5 10))))
+
+(test check-list-consistencies
+ (is-true (check-consistency '(35 20 15 25 47 40)))
+ (is-false (check-consistency '(95 102 117 150 182 127))))
+
+(test test-preambled-lists
+ (is (equal 127 (test-preambled-lists *simple-numbers* 5))))
+
+(test find-sum-lists
+ (is (equal
+ '(15 25 47 40)
+ (find-sum-list *simple-numbers*
+ (test-preambled-lists *simple-numbers* 5)))))
+
+(run! 'day09)