code / advent / 2024/03.lisp

1(defpackage #:advent.2024.03
2  (:use #:cl))
3(in-package #:advent.2024.03)
4
5(defvar *input* "03.input")
6
7;;; Part 1
8;; parse a file for mul(\d\d?\d?,\d\d?\d?), multiply the numbers, then add the results
9
10(defun solve1 ()
11  (let ((in (uiop:read-file-string *input*)))
12    (solve1/string in)))
13
14(defvar *mul-regex*  "mul\\((\\d\\d?\\d?),(\\d\\d?\\d?)\\)")
15
16(defun solve1/string (in)
17  (let ((sum 0))
18    (ppcre:do-scans (ms me rs re "mul\\((\\d\\d?\\d?),(\\d\\d?\\d?)\\)" in sum)
19      ;; (format t "~A/~A || ~A/~A~&" ms me rs re)
20      (let ((a (parse-integer in :start (elt rs 0) :end (elt re 0)))
21            (b (parse-integer in :start (elt rs 1) :end (elt re 1))))
22        (incf sum (* a b)))
23      sum)))
24
25;;; Part 2
26;; start with mul() enabled; on don't(), disable it; on do(), enable. add only
27;; enabled mul()s.
28
29(defvar *do-regex* "do\\(\\)")
30(defvar *dont-regex* "don't\\(\\)")
31
32;; I get to do this the long way round
33
34(defun solve2 ()
35  (let ((s (uiop:read-file-string *input*)))
36    (solve2/string s)))
37
38(defun solve2/string (in)
39  (let ((mulp t)
40        (sum 0))
41    (cl-ppcre:do-matches-as-strings (m (format nil "~A|~A|~A" *mul-regex*
42                                               *dont-regex* *do-regex*)
43                                     in sum)
44      (cond
45        ((and (ppcre:scan *mul-regex* m)
46              mulp)
47         (ppcre:do-register-groups (a b) ; this warning is .. fine???
48             (*mul-regex* m nil :sharedp t)
49           (incf sum (* (parse-integer a) (parse-integer b)))))
50        ((ppcre:scan *dont-regex* m)
51         (setf mulp nil))
52        ((ppcre:scan *do-regex* m)
53         (setf mulp t))))
54    sum))