--- a/package.lisp Sun Dec 16 21:30:28 2018 -0500
+++ b/package.lisp Sun Dec 16 22:50:57 2018 -0500
@@ -22,6 +22,7 @@
:nth-digit
:unique
:positions-if
+ :digits
:ring
:ring-prev
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/2018/day-14.lisp Sun Dec 16 22:50:57 2018 -0500
@@ -0,0 +1,50 @@
+(defpackage :advent/2018/14 #.cl-user::*advent-use*)
+(in-package :advent/2018/14)
+
+(defun combine (recipes elves)
+ (digits (summation elves :key (curry #'aref recipes)) :from-end t))
+
+(defun move-elves (recipes elves)
+ (do-array (elf elves)
+ (setf elf (mod (+ elf (aref recipes elf) 1)
+ (length recipes)))))
+
+(defun format-output (scores)
+ (str:join "" (coerce scores 'list)))
+
+(define-problem (2018 14) (data read)
+ #+sbcl (sb-ext:gc :full t)
+ (iterate
+ (with recipes = (make-array 2
+ :adjustable t
+ :fill-pointer t
+ :initial-contents '(3 7)))
+ (with elves = (make-array 2 :initial-contents '(0 1)))
+ (with part-1 = nil)
+ (with part-2 = nil)
+ (with target = (digits data :from-end t :result-type 'vector))
+ (with target-length = (length target))
+
+ (until (and part-1 part-2))
+
+ (unless part-1
+ (when (>= (length recipes) (+ 10 data))
+ (setf part-1 (format-output (subseq recipes data (+ data 10))))))
+
+ (iterate (for new-recipe :in (combine recipes elves))
+ (vector-push-extend new-recipe recipes)
+ (for len = (length recipes))
+ (for left = (- len target-length))
+ (unless part-2
+ (when (and (not (minusp left))
+ (search target recipes :start2 left))
+ (setf part-2 left))))
+
+ (move-elves recipes elves)
+
+ (finally (return (values part-1 part-2)))))
+
+(1am:test test-2018/14
+ (multiple-value-bind (part1 part2) (run)
+ (1am:is (string= "3610281143" part1))
+ (1am:is (= 20211326 part2))))
--- a/src/utils.lisp Sun Dec 16 21:30:28 2018 -0500
+++ b/src/utils.lisp Sun Dec 16 22:50:57 2018 -0500
@@ -362,3 +362,24 @@
:end end
:key key
:initial-value nil))))
+
+
+(defun digits (n &key (radix 10) from-end (result-type 'list))
+ "Return a fresh list of the digits of `n` in base `radix`.
+
+ By default, the digits are returned high-order first, as you would read them.
+ Use `from-end` to get them low-order first:
+
+ (digits 123) ; => (1 2 3)
+ (digits 123 :from-end t) ; => (3 2 1)
+
+ "
+ (coerce
+ (funcall
+ (if from-end #'nreverse #'identity)
+ (iterate
+ (for (values remaining digit) = (truncate n radix))
+ (collect digit)
+ (setf n remaining)
+ (until (zerop n))))
+ result-type))