aboutsummaryrefslogtreecommitdiffstats
path: root/AoC2023/day19/solver.lisp
diff options
context:
space:
mode:
Diffstat (limited to 'AoC2023/day19/solver.lisp')
-rw-r--r--AoC2023/day19/solver.lisp60
1 files changed, 60 insertions, 0 deletions
diff --git a/AoC2023/day19/solver.lisp b/AoC2023/day19/solver.lisp
new file mode 100644
index 0000000..9c2f0a0
--- /dev/null
+++ b/AoC2023/day19/solver.lisp
@@ -0,0 +1,60 @@
+;;6:51
+;;7:49
+;;
+(ql:quickload '(fiveam cl-ppcre arrows))
+
+(defstruct part
+ x m a s)
+
+(defun part-sum (part)
+ (with-slots (x m a s) part
+ (+ x m a s)))
+
+(defun solve (filename)
+ (let ((workflows (make-hash-table))
+ parts)
+ (loop for line in (uiop:read-file-lines filename)
+ do
+ (cond
+ ((string-equal line ""))
+ ((eq #\{ (aref line 0))
+ (cl-ppcre:register-groups-bind ((#'parse-integer x m a s))
+ ("{x=\(\\d+\),m=\(\\d+\),a=\(\\d+\),s=\(\\d+\)}" line)
+ (push (make-part :x x :m m :a a :s s) parts)))
+ ((multiple-value-bind (name rule) (parse-rule line)
+ (setf (gethash name workflows) rule)))))
+ (reduce #'+ parts :key (alexandria:curry #'test-part workflows))))
+
+(defun parse-tests (line-rule)
+ (loop for test in (cl-ppcre:split "," line-rule)
+ collect
+ (cl-ppcre:register-groups-bind ((#'read-from-string prop op val target))
+ ("\(\\w\)\(<|>\)\(\\d+\):\(\\w+\)" test)
+ (list op prop val target))))
+
+(fiveam:test parts
+ (fiveam:is (equal
+ '((< S 537 GD) (> X 2440 R))
+ (parse-tests "s<537:gd,x>2440:R" ))))
+
+(fiveam:test solutions
+ (fiveam:is (= 19114 (solve "eg-in")))
+ (fiveam:is (= 446517 (solve "input"))))
+
+(defun parse-rule (line)
+ (cl-ppcre:register-groups-bind ((#'read-from-string name) (#'parse-tests tests) (#'read-from-string default))
+ ("\(\\w+\){\(.*\),\(\\w+\)}" line)
+ (values name
+ (lambda (part)
+ (or (loop for (op prop val target) in tests
+ when (funcall op (slot-value part prop) val)
+ do (return target))
+ default)))))
+
+(defun test-part (workflows part &optional (start 'in))
+ (let ((out (funcall (gethash start workflows) part)))
+ (cond ((eq 'A out)
+ (part-sum part))
+ ((eq 'R out) 0)
+ ((test-part workflows part out)))))
+(fiveam:run!)