diff --git a/aoc.asd b/aoc.asd index afe12c3..c276ba4 100644 --- a/aoc.asd +++ b/aoc.asd @@ -19,6 +19,9 @@ #:bt-semaphore ; threads higher level lib #:trivia ; community standard pattern matching #:transducers + #:smug + #:fset + #:arrow-macros ) :components ((:module "src" :components diff --git a/src/2024/day13.lisp b/src/2024/day13.lisp index 1678c74..880d300 100644 --- a/src/2024/day13.lisp +++ b/src/2024/day13.lisp @@ -1,6 +1,6 @@ (defpackage :aoc/2024/13 - (:use :cl :aoc :alexandria :trivia :lla) + (:use :cl :aoc :alexandria :trivia :lla :smug :arrow-macros) (:export #:sample-data #:sample-data2 @@ -11,25 +11,105 @@ (in-package :aoc/2024/13) -(defun parse-line (line) - line) + +(defun button-parser (s) + (ppcre:register-groups-bind (x y) + ("Button .: X\\+(.+), Y\\+(.+)" s) + (list (parse-integer x) (parse-integer y)))) + +(defun prize-parser (s) + (ppcre:register-groups-bind (x y) + ("Prize: X=(.+), Y=(.+)" s) + (list (parse-integer x) (parse-integer y)))) + +(defstruct machine a b prize) + +(defun parse-machine (lines) + (if (emptyp lines) + nil + (make-machine + :a (button-parser (first lines)) + :b (button-parser (second lines)) + :prize (prize-parser (third lines))))) (defun parse-input (lines) - (mapcar #'parse-line lines)) + (if (< (length lines) 4) + (list (parse-machine lines)) + (cons (parse-machine lines) (parse-input (subseq lines 4))))) -(defparameter input-text (first (test-input 2024 13))) +(defparameter input-text (test-input 2024 13)) (defparameter input-data (parse-input input-text)) -(defparameter sample-text (aoc:split-lines "")) +(defparameter sample-text (aoc:split-lines "Button A: X+94, Y+34 +Button B: X+22, Y+67 +Prize: X=8400, Y=5400 + +Button A: X+26, Y+66 +Button B: X+67, Y+21 +Prize: X=12748, Y=12176 + +Button A: X+17, Y+86 +Button B: X+84, Y+37 +Prize: X=7870, Y=6450 + +Button A: X+69, Y+23 +Button B: X+27, Y+71 +Prize: X=18641, Y=10279")) (defparameter sample-data - (parse-input sample-text)) + (parse-input sample-text)) + +(defun button-presses (machine) + (let ((a (machine-a machine)) + (b (machine-b machine)) + (prize (machine-prize machine))) + (let ((A (aops:permute '(1 0) (make-array '(2 2) :initial-contents (list a b)))) + (b (coerce prize 'vector))) + (lla:solve A b)))) + +(defparameter *tol* 0.001) +(defun to-integer (f) + (multiple-value-bind (i err) (round f) + (if (< (abs err) *tol*) + i + nil))) + +(defun integer-presses (x) + (let ((a (to-integer (aref x 0))) + (b (to-integer (aref x 1)))) + (if (and a b) + (vector a b) + nil))) + +(defun tokens (x) + (round (lla:dot x (vector 3 1)))) + +(defun solve-part1 (data) + (->> data + (mapcar #'button-presses) + (mapcar #'integer-presses) + (remove-if #'emptyp) + (mapcar #'tokens) + (reduce #'+) + )) + +(defun move-prize-f (amount) + (lambda (m) + (let ((a (machine-a m)) + (b (machine-b m)) + (prize (machine-prize m))) + (make-machine + :a a :b b + :prize (list (+ amount (first prize)) (+ amount (second prize))))))) + +(defun solve-part2 (data) + (solve-part1 (mapcar (move-prize-f 10000000000000) data))) (defun part1 (data) - nil) + (format nil "~A" (solve-part1 data))) (defun part2 (data) - nil) + (format nil "~A" (solve-part2 data))) (defun solve-day () (format t "part1: ~A~%" (part1 input-data)) diff --git a/tests/2024/day13-test.lisp b/tests/2024/day13-test.lisp index c606d8a..fca5fd1 100644 --- a/tests/2024/day13-test.lisp +++ b/tests/2024/day13-test.lisp @@ -5,23 +5,14 @@ (define-test suite-2024-13 ;:parent suite-2024 - ) - -(define-test test-foo - :parent suite-2024-13 - ) + ) -(define-test test-bar - :parent suite-2024-13 - ) (define-test+run test-part1 - :parent suite-2024-13 - (is equal nil (part1 sample-data))) + :parent suite-2024-13 + (is equal "480" (part1 sample-data))) + -(define-test+run test-part2 - :parent suite-2024-13 - (is equal nil (part2 sample-data)))