Commit Diff


commit - aea08906c977042acf39efeca6007b925df85f0c
commit + d7b2a01d551e821e13e7d0e2dfd2e37f6c8adf63
blob - 67d845acd66e1f25681e5798dc21a6333fc6397b
blob + 7b6b99733404380fd9984b5760721bebac2e3302
--- src/day-14.lisp
+++ src/day-14.lisp
@@ -2,7 +2,7 @@
   (:use #:cl #:aoc/utils)
   (:export
    #:parse-robots
-   #:run
+   #:task-1
    #:day-14))
 (in-package #:aoc/day-14)
 
@@ -20,51 +20,42 @@
     (list (cons (first p) (second p))
           (cons (first v) (second v)))))
 
-(defun safety-factor (robots width height)
-  (loop with hmiddle = (floor width 2)
+(declaim (inline robot-after))
+
+(defun robot-after (robot seconds bounds)
+  (point-mod (point+ (first robot)
+                     (point* (second robot) (cons seconds seconds)))
+             bounds))
+
+(defun task-1 (robots width height)
+  (loop with bounds = (cons width height)
+        with hmiddle = (floor width 2)
         with vmiddle = (floor height 2)
-        with ul = 0
-        with ur = 0
-        with bl = 0
-        with br = 0
+        with quadrants = (list 0 0 0 0)
         for robot in robots
-        for pos = (first robot)
-        for x = (point-x pos)
-        for y = (point-y pos)
-        do (cond
-             ((and (< x hmiddle) (< y vmiddle))
-              (incf ul))
-             ((and (> x hmiddle) (< y vmiddle))
-              (incf ur))
-             ((and (< x hmiddle) (> y vmiddle))
-              (incf bl))
-             ((and (> x hmiddle) (> y vmiddle))
-              (incf br)))
-        finally (return (* ul ur bl br))))
+        for new-pos = (robot-after robot 100 bounds)
+        for x = (point-x new-pos)
+        for y = (point-y new-pos)
+        unless (or (= x hmiddle) (= y vmiddle))
+          do (incf (nth (+ (* (round x width) 2)
+                           (round y height))
+                        quadrants))
+        finally (return (apply #'* quadrants))))
 
-(defun run (robots width height &optional with-task-2)
-  (loop with task-1 = nil
-        for i from 1
-        for overlap-set = (make-hash-table :test #'equal)
-        for overlaps? = nil
-        do (loop for robot in robots
-                 for pos = (first robot)
-                 for velocity = (second robot)
-                 for new-pos = (point+ pos velocity)
-                 do (setf (point-x new-pos)
-                          (mod (point-x new-pos) width)
-                          (point-y new-pos)
-                          (mod (point-y new-pos) height)
-                          (first robot) new-pos)
-                    (unless overlaps?
-                      (setf overlaps? (gethash new-pos overlap-set)
-                            (gethash new-pos overlap-set) t)))
-        unless overlaps?
-          do (return (values task-1 i))
-        when (= i 100)
-          do (setf task-1 (safety-factor robots width height))
-          and unless with-task-2
-                do (return task-1)))
+(defun task-2 (robots width height)
+  (loop with bounds = (cons width height)
+        for seconds from 1
+        for map = (make-hash-table :test #'equal)
+        when (loop for robot in robots
+                   for new-pos = (robot-after robot seconds bounds)
+                   when (gethash new-pos map)
+                     do (return nil)
+                   do (setf (gethash new-pos map) t)
+                   finally (return t))
+          do (return seconds)))
 
 (defun day-14 (input)
-  (run (parse-robots input) 101 103 t))
+  (let ((robots (parse-robots input)))
+    (values
+     (task-1 robots 101 103)
+     (task-2 robots 101 103))))
blob - 301e42acbe7d39a8348bc4388b6bd83cedf60f0b
blob + 809269e5478f7d5ea951c7fbd5102d7c567bfb8e
--- src/utils.lisp
+++ src/utils.lisp
@@ -18,6 +18,8 @@
    #:map-integer-at
    #:point+
    #:point-
+   #:point*
+   #:point-mod
    #:point-x
    #:point-y
    #:point-in-bounds-p
@@ -116,7 +118,7 @@
   (loop for y from 0 below (input-map-height map)
         do (format stream "~A~%" (aref (input-map-data map) y))))
 
-(declaim (inline point+ point- point-x point-y)
+(declaim (inline point+ point- point* point-mod point-x point-y)
          (ftype (function (cons) fixnum) point-x point-y))
 
 (defun point-x (point)
@@ -142,7 +144,19 @@
                        (point-x point-b)))
         (the fixnum (- (point-y point-a)
                        (point-y point-b)))))
+
+(defun point* (point-a point-factor)
+  (cons (the fixnum (* (point-x point-a)
+                       (point-x point-factor)))
+        (the fixnum (* (point-y point-a)
+                       (point-y point-factor)))))
 
+(defun point-mod (point-a point-divisor)
+  (cons (the fixnum (mod (point-x point-a)
+                         (point-x point-divisor)))
+        (the fixnum (mod (point-y point-a)
+                         (point-y point-divisor)))))
+
 (declaim (inline point-in-bounds-p point-in-map-p))
 (defun point-in-bounds-p (point width height)
   (destructuring-bind (x . y) point
blob - b6bf4141e65370e1e053ac181ea2876a2551e831
blob + b2bd3956f1d8cd4735fe80051b6440dd72dd7f91
--- t/day-14.lisp
+++ t/day-14.lisp
@@ -17,4 +17,4 @@ p=9,3 v=2,3
 p=7,3 v=-1,2
 p=2,4 v=2,-3
 p=9,5 v=-3,-3")
-    (assert= 12 (aoc/day-14:run (aoc/day-14:parse-robots s) 11 7))))
+    (assert= 12 (aoc/day-14:task-1 (aoc/day-14:parse-robots s) 11 7))))