solved day 14

This commit is contained in:
Peter Tillemans 2024-12-14 13:30:59 +01:00
parent 45e33c3438
commit bcab2ab698
2 changed files with 182 additions and 20 deletions

View file

@ -1,7 +1,13 @@
(defpackage :aoc/2024/14 (defpackage :aoc/2024/14
(:use :cl :aoc :alexandria :trivia :lla) (:use :cl :aoc :alexandria :lla :ppcre)
(:export (:export
#:parse-line
#:make-robot
#:quadrant
#:robot-at-position
#:robot-at-time
#:safety-factor
#:sample-text
#:sample-data #:sample-data
#:sample-data2 #:sample-data2
#:part1 #:part1
@ -10,9 +16,46 @@
(in-package :aoc/2024/14) (in-package :aoc/2024/14)
(defstruct robot px py vx vy)
(defun robot-position (r)
(vector (robot-px r) (robot-py r)))
(defun robot-velocity (r)
(vector (robot-vx r) (robot-vy r)))
(defun robot-at-position (r p)
(let* ((v (robot-velocity r)))
(make-robot
:px (aref p 0)
:py (aref p 1)
:vx (aref v 0)
:vy (aref v 1)
)))
(defun robot-at-time (r n grid)
(let* ((p (robot-position r))
(v (robot-velocity r))
(np (aops:vectorize (p v grid)
(mod (+ p (* n v)) grid))))
(make-robot
:px (aref np 0)
:py (aref np 1)
:vx (aref v 0)
:vy (aref v 1)
)))
(defun parse-line (line) (defun parse-line (line)
line) (let ((numbers nil))
(do-matches-as-strings
(s "-?\\d+" line)
(push (parse-integer s) numbers))
(make-robot
:px (nth 3 numbers)
:py (nth 2 numbers)
:vx (nth 1 numbers)
:vy (nth 0 numbers)
)))
(defun parse-input (lines) (defun parse-input (lines)
@ -21,15 +64,113 @@
(defparameter input-text (test-input 2024 14)) (defparameter input-text (test-input 2024 14))
(defparameter input-data (parse-input input-text)) (defparameter input-data (parse-input input-text))
(defparameter sample-text (aoc:split-lines "")) (defparameter sample-text (aoc:split-lines "p=0,4 v=3,-3
(defparameter sample-data p=6,3 v=-1,-3
(parse-input sample-text)) p=10,3 v=-1,2
p=2,0 v=2,-1
p=0,0 v=1,3
p=3,0 v=-2,-2
p=7,6 v=-1,-3
p=3,0 v=-1,-2
p=9,3 v=2,3
p=7,3 v=-1,2
p=2,4 v=2,-3
p=9,5 v=-3,-3
"))
(defun part1 (data) (defparameter sample-data
(length data)) (parse-input sample-text))
(defun quadrant (position gridsize)
(let ((mx (/ (1- (aref gridsize 0)) 2))
(my (/ (1- (aref gridsize 1)) 2))
(x (aref position 0))
(y (aref position 1)))
(if (or (= x mx) (= y my))
nil
(+
(if (< x mx) 0 1)
(if (< y my) 0 2)))))
(defun robots-at-time (robots n grid)
(mapcar
(lambda (r) (robot-at-time r n grid))
robots))
(defun map-robots (robots gridsize)
(let ((map (make-array (reverse (coerce gridsize 'list)) :initial-element 0)))
(loop
for r in robots
do (incf (aref map (robot-py r) (robot-px r))))
map))
(defun show-robots (robots gridsize)
(defun render (n)
(if (= n 0) "." (format nil "~A" n)))
(let ((map (map-robots robots gridsize)))
(loop
for y from 0 below (array-dimension map 0)
do (loop
for x from 0 below (array-dimension map 1)
do (format t "~A" (render (aref map y x))))
do (format t "~%"))))
(defun safety-factor (robots grid)
(let ((qs (make-array '(4) :initial-element 0))
(rp-100 (lambda (r) (robot-at-time r 100 grid))))
(loop
for p in (mapcar rp-100 robots)
for q = (quadrant (robot-position p) grid)
if q
do (incf (aref qs q))
finally
(return (aops:vectorize-reduce #'* (qs) (identity qs))))))
(defun robots-symmetry-score (robots grid)
(let ((m (map-robots robots grid)))
(loop
for y from 0 below (array-dimension m 0)
sum (loop
for x1 from 0 below (/ (1- (array-dimension m 1)) 2)
for x2 from (1- (array-dimension m 1)) downto 0
sum (if (and
(not (zerop (aref m y x1)))
(not (zerop (aref m y x2))))
1 0)
))))
(defun sqr (x) (* x x))
(defun robots-variance-score (robots grid)
(let* ((n (length robots))
(mx (/ (loop for r in robots sum (robot-px r)) n))
(my (/ (loop for r in robots sum (robot-py r)) n))
(vx (/ (loop for r in robots sum (sqr (- (robot-px r) mx))) n))
(vy (/ (loop for r in robots sum (sqr (- (robot-py r) my))) n)))
(list (round mx) (round my) (sqrt vx) (sqrt vy))))
(defun find-t-with-symmetry-higher (max-t min-symmetry robots grid)
(loop for n from 0 to max-t
for score = (robots-symmetry-score (robots-at-time robots n grid) grid)
if (> score min-symmetry)
collect n))
(defun first-t-with-variance-lower (max-t max-s robots grid)
(loop for n from 0 to max-t
for score = (robots-variance-score (robots-at-time robots n grid) grid)
for sx = (nth 2 score)
for sy = (nth 3 score)
until (and (< sx max-s) (< sy max-s))
finally (return (list n sx sy))))
(defun part1 (data &optional (grid #(101 103)))
(format nil "~A" (safety-factor data grid)))
(defun part2 (data) (defun part2 (data)
(length data)) (let ((stats (first-t-with-variance-lower 50000 20 data #(101 103))))
(format nil "~A" (first stats))))
(defun solve-day () (defun solve-day ()
(format t "part1: ~A~%" (part1 input-data)) (format t "part1: ~A~%" (part1 input-data))

View file

@ -7,21 +7,42 @@
;:parent suite-2024 ;:parent suite-2024
) )
(define-test test-foo (define-test test-parse-line
:parent suite-2024-14 :parent suite-2024-14
) (is equalp (make-robot :px 0 :py 4 :vx 3 :vy -3) (parse-line "p=0,4 v=3,-3" ))
)
(define-test test-robot-position
:parent suite-2024-14
(let ((r (make-robot :px 2 :py 4 :vx 2 :vy -3))
(g #(11 7)))
(is equalp (robot-at-position r #(4 1)) (robot-at-time r 1 g))
(is equalp (robot-at-position r #(6 5)) (robot-at-time r 2 g))
(is equalp (robot-at-position r #(8 2)) (robot-at-time r 3 g))
(is equalp (robot-at-position r #(10 6)) (robot-at-time r 4 g))
(is equalp (robot-at-position r #(1 3)) (robot-at-time r 5 g))
(is equalp (robot-at-position r #(4 5)) (robot-at-time r 100 g))
))
(define-test test-bar (define-test test-quadrant
:parent suite-2024-14 :parent suite-2024-14
) (false (quadrant #(5 1) #(11 7)))
(false (quadrant #(8 3) #(11 7)))
(is = 0 (quadrant #(0 0) #(11 7)))
(is = 1 (quadrant #(7 2) #(11 7)))
(is = 2 (quadrant #(4 4) #(11 7)))
(is = 3 (quadrant #(6 4) #(11 7)))
)
(define-test test-safety-factor
:parent suite-2024-14
(is = 12 (safety-factor sample-data #(11 7)))
)
(define-test+run test-part1 (define-test+run test-part1
:parent suite-2024-14 :parent suite-2024-14
(is equal nil (part1 sample-data))) (is equal "12" (part1 sample-data #(11 7))))
(define-test+run test-part2
:parent suite-2024-14
(is equal nil (part2 sample-data)))