From 64338f7ae089954bffd14f30c3dd01c575d590cb Mon Sep 17 00:00:00 2001 From: Matteo Landi Date: Thu, 1 Feb 2024 23:08:37 +0100 Subject: [PATCH] Refactor 2023/24 - Use DEFINE-SOLUTION, DEFINE-TEST - Extract some functions to better explain what's going on -- for part 2 in particular --- src/2023/day24.lisp | 77 +++++++++++++++++++++++++++------------------ 1 file changed, 47 insertions(+), 30 deletions(-) diff --git a/src/2023/day24.lisp b/src/2023/day24.lisp index 35bf8a4..a7e6d1d 100644 --- a/src/2023/day24.lisp +++ b/src/2023/day24.lisp @@ -3,9 +3,8 @@ (defun hailstone (s) (extract-integers s)) -#+#:excluded (hailstone "248315803897794, 386127890875011, 326651351825022 @ -89, -119, 32") -(defun parse-input (&optional (strings (uiop:read-file-lines #P"src/2023/day24.txt"))) +(defun parse-input (&optional (strings (aoc::read-problem-input 2023 24))) (mapcar #'hailstone strings)) @@ -21,13 +20,19 @@ (list (/ xnum den) (/ ynum den))))) +(defun ignore-axis (n h) + (destructuring-bind (x y z vx vy vz) h + (ecase n + (0 (list y z vy vz)) + (1 (list x z vx vz)) + (2 (list x y vx vy))))) + (defun in-the-future? (x1 y1 x2 y2 x3 y3) (bnd* ((dx21 (- x2 x1)) (dx31 (- x3 x1)) (dy21 (- y2 y1)) (dy31 (- y3 y1))) (and (>= (* dx21 dx31) 0) (>= (* dy21 dy31) 0)))) - (defun all-intersections (&optional (hh (parse-input))) (looping (dosublists (((x1 y1 vx1 vy1) . rest) hh) @@ -40,42 +45,54 @@ (in-the-future? x3 y3 x4 y4 x y)) (collect! (list x y))))))))))) -(defun ignore-axis (n h) - (destructuring-bind (x y z vx vy vz) h - (ecase n - (0 (list y z vy vz)) - (1 (list x z vx vz)) - (2 (list x y vx vy))))) -#+#:excluded (length (all-intersections)) (defun part1 (&optional (hh (parse-input))) (looping (doseq ((x y) (all-intersections (mapcar [ignore-axis 2 _] hh))) (count! (and (<= 200000000000000 x 400000000000000) (<= 200000000000000 y 400000000000000)))))) -#+#:excluded (part1 7 27) -#+#:excluded (part1 ) -; 24999 nope -; 16779 !!! + +;; We know a position exists such that, if we throw a hail rock with +;; velocity , eventually it will collide with all the other rocks. +;; This means that if we subtract from each rock in our input, +;; eventually the rocks will all collide in . +;; +;; So the idea is to take a few rocks from our input, brute-force a bunch of +;; velocities along each axis, adjust rocks velocities, and see where the rocks +;; collide. +;; +;; Re-using the logic from part1, we can find first where the rocks collide +;; along x and y first, and then along x and z. +;; +;; Kudos to: https://www.youtube.com/watch?v=nP2ahZs40U8 (defun adjust-velocity (dvx dvy h) (destructuring-bind (x y vx vy) h (list x y (+ vx dvx) (+ vy dvy)))) -#+#:excluded (untrace adjust-velocity) + +(defun find-single-intersection (hh) + (dorangei (vx -250 250) + (dorangei (vy -250 250) + (bnd1 (points (all-intersections (mapcar [adjust-velocity vx vy _] + hh))) + (when (and (> (length points) 1) + (= (length (remove-duplicates points :test #'equal)) 1)) + (return-from find-single-intersection (first points))))))) (defun part2 (&optional (hh (parse-input))) - (flet ((magic (axis &aux ) - (bnd1 (hh (mapcar [ignore-axis axis _] (subseq hh 0 3))) - (dorangei (vx -300 300) - (dorangei (vy -300 300) - (bnd1 (points (all-intersections (mapcar [adjust-velocity vx vy _] - hh))) - (when (and (> (length points) 1) - (= (length (remove-duplicates points :test #'equal)) 1)) - (return-from magic (first points))))))))) - (destructuring-bind (px1 py) (magic 2) - (destructuring-bind (px2 pz) (magic 1) - (assert (= px1 px2)) - (+ px1 py pz))))) -#+#:excluded (time (part2)) -; 871983857253169 + (recursively ((hh (copy-seq hh))) + (setf hh (shuffle hh)) + (bnd1 (sample (subseq hh 0 3)) + (awhen (find-single-intersection (mapcar [ignore-axis 2 _] sample)) + (destructuring-bind (px1 py) it + (awhen (find-single-intersection (mapcar [ignore-axis 1 _] sample)) + (destructuring-bind (px2 pz) it + (assert (= px1 px2)) + (return-from recur (+ px1 py pz))))))) + (recur hh))) + + +(define-solution (2023 24) (hh parse-input) + (values (part1 hh) (part2 hh))) + +(define-test (2023 24) (16779 871983857253169))