src/2019/days/day-12.lisp @ e41337e3b59b
Accessors
author |
Steve Losh <steve@stevelosh.com> |
date |
Wed, 15 Dec 2021 23:10:57 -0500 |
parents |
f524273415d0 |
children |
(none) |
(advent:defpackage* :advent/2019/12)
(in-package :advent/2019/12)
(defclass* moon () (pos vel))
(defun make-moon (x y z)
(make-instance 'moon
:pos (vector x y z)
:vel (vector 0 0 0)))
(defun parse-moons (data)
(mapcar (curry #'apply #'make-moon) data))
(defun apply-gravity (moon other)
(map-into (vel moon) (lambda (v m o)
(+ v (signum (- o m))))
(vel moon)
(pos moon)
(pos other)))
(defun apply-all-gravity (moons)
(alexandria:map-permutations (curry #'apply #'apply-gravity)
moons :length 2 :copy nil))
(defun vincf (vec delta)
(map-into vec #'+ vec delta))
(defun apply-velocity (moon)
(vincf (pos moon) (vel moon)))
(defun apply-all-velocity (moons)
(map nil #'apply-velocity moons))
(defun tick (moons &optional (n 1))
(do-repeat n
(apply-all-gravity moons)
(apply-all-velocity moons)))
(defmethod energy ((moon moon))
(* (summation (pos moon) :key #'abs)
(summation (vel moon) :key #'abs)))
(defmethod energy ((moons sequence))
(summation moons :key #'energy))
(defun velocity-zeroed-p (moons axis)
(iterate (for moon :in moons)
(always (zerop (aref (vel moon) axis)))))
(defun part2 (moons)
;; Clever trick from https://www.reddit.com/r/adventofcode/comments/e9nqpq/day_12_part_2_2x_faster_solution/
(iterate
(for tick :from 1)
(tick moons)
(finding-first tick :such-that (velocity-zeroed-p moons 0) :into x)
(finding-first tick :such-that (velocity-zeroed-p moons 1) :into y)
(finding-first tick :such-that (velocity-zeroed-p moons 2) :into z)
(until (and x y z))
(returning (* 2 (lcm x y z)))))
(define-problem (2019 12) (data read-lines-of-numbers-and-garbage) (14780 279751820342592)
(values
(let ((moons (parse-moons data)))
(tick moons 1000)
(energy moons))
(part2 (parse-moons data))))
#; Scratch --------------------------------------------------------------------
(defparameter *a* (make-moon '(0 0 0)))
(defparameter *b* (make-moon '(1 0 -2)))
(run '((-1 0 2)
(2 -10 -7)
(4 -8 8)
(3 5 -1)))