diff --git a/src/2024/day11.lisp b/src/2024/day11.lisp index f782a3c..4ff9fb1 100644 --- a/src/2024/day11.lisp +++ b/src/2024/day11.lisp @@ -6,30 +6,125 @@ #:sample-data2 #:part1 #:part2 + #:parse-line + #:evolve-stone + #:evolve-stones )) (in-package :aoc/2024/11) (defun parse-line (line) - line) + (mapcar #'parse-integer (cl-ppcre:split " " line))) (defun parse-input (lines) - (mapcar #'parse-line lines)) + (parse-line lines)) (defparameter input-text (first (test-input 2024 11))) (defparameter input-data (parse-input input-text)) -(defparameter sample-text (aoc:split-lines "")) +(defparameter sample-text "125 17") (defparameter sample-data - (parse-input sample-text)) + (parse-input sample-text)) + + +(defun n-digits (x) + (ceiling (log (1+ x) 10))) + +(defun evolve-stone (stone) + (let* ((n (n-digits stone)) + (split-factor (expt 10 (/ n 2)))) + (cond + ((= 0 stone) (list 1)) + ((evenp n) (list + (floor (/ stone split-factor)) + (mod stone split-factor))) + (t (list (* 2024 stone))))) + ) +(defun evolve-stones (stones) + (loop for stone in stones + append (evolve-stone stone))) + +(defun evolve-stones-n (stones n) + (loop for i from 1 to n + do (setf stones (evolve-stones stones)) + finally (return stones))) + +(defun number-stones-after-n-evolutions (stones n) + (length (evolve-stones-n stones n)) + ) + + +(defparameter stone-map-25-cache (make-hash-table :size 1000)) + +(defun map-stone-25 (stone) + (let ((rslt (gethash stone stone-map-25-cache))) + (or rslt + (let ((stones (evolve-stones-n (list stone) 25)) + (stone-map (make-hash-table))) + (loop for s in stones + do (incf (gethash s stone-map 0))) + (setf (gethash stone stone-map-25-cache) stone-map))))) + +(defun merge-stone-map (map1 map2 &optional (multiplier 1)) + (let ((result (copy-hash-table map1))) + (loop + for k being the hash-keys of map2 + for v being the hash-values of map2 + do (incf (gethash k result 0) (* v multiplier))) + result)) + + +(defun evolve-stone-map-25 (stone-map) + (let ((result (make-hash-table :size 1000))) + (loop + for k being the hash-keys of stone-map + for v being the hash-values of stone-map + do (setf result (merge-stone-map result (map-stone-25 k) v))) + result)) + +(defun stones-to-stone-map (stones) + (let ((result (make-hash-table :size (length stones)))) + (loop + for k in stones + do (setf (gethash k result) 1)) + result)) + +(defun total-stones (stone-map) + (loop for v being the hash-values of stone-map sum v)) + +(defparameter stone-map-cache (make-hash-table :size 1000)) +(defun map-stone (stone) + (let ((rslt (gethash stone stone-map-cache))) + (or rslt + (let ((stones (evolve-stone stone)) + (stone-map (make-hash-table))) + (loop for s in stones + do (incf (gethash s stone-map 0))) + (setf (gethash stone stone-map-cache) stone-map))))) + +(defun evolve-stone-map (stone-map) + (let ((result (make-hash-table :size 1000))) + (loop + for k being the hash-keys of stone-map + for v being the hash-values of stone-map + do (setf result (merge-stone-map result (map-stone k) v))) + result)) + +(defun evolve-stone-map-n (stone-map n) + (loop + for i from 1 to n + with sm = stone-map + do (setf sm (evolve-stone-map sm)) + finally (return sm))) (defun part1 (data) - nil) + (format nil "~A" (total-stones (evolve-stone-map-n (stones-to-stone-map data) 25)))) (defun part2 (data) - nil) + (format nil "~A" (total-stones (evolve-stone-map-n (stones-to-stone-map data) 75)))) + (defun solve-day () (format t "part1: ~A~%" (part1 input-data)) diff --git a/tests/2024/day11-test.lisp b/tests/2024/day11-test.lisp index f7fccf6..10f4474 100644 --- a/tests/2024/day11-test.lisp +++ b/tests/2024/day11-test.lisp @@ -7,20 +7,41 @@ ;:parent suite-2024 ) -(define-test test-foo - :parent suite-2024-11 - ) +(define-test test-parse-line + :parent suite-2024-11 + (is equal '(125 17) (parse-line "125 17")) + ) -(define-test test-bar - :parent suite-2024-11 - ) + +(defparameter example-evolution + '((125 17) + (253000 1 7) + (253 0 2024 14168) + (512072 1 20 24 28676032) + (512 72 2024 2 0 2 4 2867 6032) + (1036288 7 2 20 24 4048 1 4048 8096 28 67 60 32) + (2097446912 14168 4048 2 0 2 4 40 48 2024 40 48 80 96 2 8 6 7 6 0 3 2))) + +(define-test test-evolve-stone + :parent suite-2024-11 + (is equal '(1) (evolve-stone 0)) + (is equal '(9 9) (evolve-stone 99)) + (is equal '(2024) (evolve-stone 1))) + +(define-test test-evolve-stones + :parent suite-2024-11 + (loop + for case in example-evolution + for expected in (subseq example-evolution 1) + do (is equal expected (evolve-stones case)) ) + ) (define-test+run test-part1 - :parent suite-2024-11 - (is equal nil (part1 sample-data))) + :parent suite-2024-11 + (is equal "55312" (part1 sample-data))) (define-test+run test-part2 :parent suite-2024-11