aboutsummaryrefslogtreecommitdiffstats
path: root/AoC2023/day03/solver.lisp
blob: 6f9c7999796931b3e57e2cb11958606a4d95fb93 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
(ql:quickload '(fiveam cl-ppcre))

(defparameter eg-input "467..114..
...*......
..35..633.
......#...
617*......
.....+.58.
..592.....
......755.
...$.*....
.664.598..")


(defun inbounds (row-max col-max)
  (lambda (cell)
    (destructuring-bind (row . col) cell
      (and (<= 0 row row-max)
           (<= 0 col col-max)))))

(defun contour (row start end)
  (list*
   (cons row (1- start))
   (cons row end)
   (loop for i from (1- start) to end
         collect (cons (1- row) i)
         collect (cons (1+ row) i))))

(defun is-relevant (limits rows)
  (lambda(row start end)
    (some
     (lambda (cell)
       (and (funcall limits cell)
            (destructuring-bind (row . col) cell
              (let ((char (aref (aref rows row) col)))
                (not (or (digit-char-p char)
                         (eq #\. char)))))))
     (contour row start end))))


(defun solver1 (lines)
  (let* ((rows (make-array (length lines) :initial-contents lines
                                          :adjustable t))
         (limits (inbounds (1- (length lines))
                           (1- (length (car lines)))))
         (keep (is-relevant limits rows))
         (sum 0))
    (loop for row below (length lines)
          for content = (aref rows row) do
            (cl-ppcre:do-scans (start end _rs _re "\\d+" content)
              (when (funcall keep row start end)
                ;; (format t "~a ~a ~a~%" start end (subseq content start end))
                (incf sum (parse-integer (subseq content start end))))))
    sum))


(defun adjacent-numbers (line gear-start)
  (loop for (num-start num-end) on (cl-ppcre:all-matches "\\d+" line) by #'cddr
        when (<= (1- num-start) gear-start num-end)
          collect (parse-integer (subseq line num-start num-end))))


(defun solver2 (lines)
  (let* ((rows (make-array (length lines) :initial-contents lines
                                          :adjustable t))
         (limits (inbounds (1- (length lines))
                           (1- (length (car lines)))))
         (sum 0))
    (loop for row below (length lines)
          for content = (aref rows row) do
            (loop for (gear-start end) on (cl-ppcre:all-matches "\\*" content) by #'cddr do
              (let ((ratios
                      (append
                       (when (funcall limits (cons (1- row) gear-start))
                         (adjacent-numbers (aref rows (1- row)) gear-start))
                       (adjacent-numbers content gear-start)
                       (when (funcall limits (cons (1+ row) gear-start))
                         (adjacent-numbers (aref rows (1+ row)) gear-start)))))
                (when (= 2 (length ratios))
                  (incf sum (* (car ratios) (cadr ratios)))))))
    sum))

(fiveam:test solutions
  (fiveam:is (= 4361 (solver1 (uiop:split-string eg-input :separator '(#\Newline)))))
  (fiveam:is (= 467835  (solver2 (uiop:split-string eg-input :separator '(#\Newline)))))
  (fiveam:is (= 531561 (solver1 (uiop:read-file-lines "input"))))
  (fiveam:is (= 83279367(solver2 (uiop:read-file-lines "input")))))