Commit Diff


commit - c3dc0bc1b9d10e1cb15b5e7b3de92896523afbb5
commit + c1af0e38b7b56e77082a3f44eaa249842a057535
blob - eb6aa41de116b76751c296c92e52e2364779df10
blob + 5e22aada04da225e73955a5d23c96538b55149fd
--- src/day-14.lisp
+++ src/day-14.lisp
@@ -1,6 +1,8 @@
 (defpackage #:aoc/day-14
   (:use #:cl #:aoc/utils)
-  (:export #:day-14))
+  (:export
+   #:day-14
+   #:*minimum-pattern-length*))
 (in-package #:aoc/day-14)
 
 (defun point-x-constructor (y)
@@ -90,7 +92,28 @@
                   when (char= (map-cell map (cons x y)) #\O)
                     sum load-multiplier)))
 
+(defun spin-cycle (map &optional (cycle '(:north :west :south :east)))
+  (loop for direction in cycle
+        do (slide-rocks map direction)))
+
+(defparameter *minimum-pattern-length* 100)
+
 (defun day-14 (input)
-  (let ((map (make-map input)))
+  (let ((map (make-map input))
+        task-1 task-2)
     (slide-rocks map :north)
-    (total-load map)))
+    (setf task-1 (total-load map))
+    (spin-cycle map '(:west :south :east))
+    (loop with history = nil
+          for cycles from 1
+          do (spin-cycle map)
+          do (push (total-load map) history)
+          do (let ((pattern-length (find-pattern history *minimum-pattern-length*)))
+               (when pattern-length
+                 (setf task-2
+                       (elt history
+                            (1+ (- pattern-length
+                                   (- (mod 1000000000 pattern-length)
+                                      (- cycles (* pattern-length 2)))))))
+                 (return))))
+    (values task-1 task-2)))
blob - 77b9695adb09e11531523101ac2139a83dba208d
blob + 4cb420b7bb4d2867654f0ba805b6e4d9358f268d
--- src/utils.lisp
+++ src/utils.lisp
@@ -20,7 +20,8 @@
    #:point-neighbours
    #:manhattan-distance
    #:do-map-neighbours
-   #:read-number-list))
+   #:read-number-list
+   #:find-pattern))
 (in-package #:aoc/utils)
 
 (defun normalize-type (type)
@@ -196,3 +197,11 @@
                                    :junk-allowed t)
                   (setf i end)
                   number)))
+
+(defun find-pattern (list &optional (minimum-length 5))
+  (loop for length from minimum-length to (floor (/ (length list) 2))
+        when (loop for i below length
+                   for c-1 = (elt list i)
+                   for c-2 = (elt list (+ i length))
+                   always (= c-1 c-2))
+          do (return-from find-pattern length)))
blob - 674d3e70818397bead7fd08ea24a375d792df4bf
blob + bc301508974173263f53c6a3f0e089cefb438bfd
--- t/day-14.lisp
+++ t/day-14.lisp
@@ -4,8 +4,9 @@
 
 (define-test test-day-14
     ()
-  (multiple-value-bind (task-1)
-      (aoc:run-day 14 "O....#....
+  (let ((aoc/day-14:*minimum-pattern-length* 5))
+    (multiple-value-bind (task-1 task-2)
+        (aoc:run-day 14 "O....#....
 O.OO#....#
 .....##...
 OO.#O....O
@@ -15,4 +16,5 @@ O.#..O.#.#
 .......O..
 #....###..
 #OO..#....")
-    (assert= 136 task-1)))
+      (assert= 136 task-1)
+      (assert= 64 task-2))))