code / advent / 2024/02.lisp

1(defpackage #:advent.2024.02
2  (:use #:cl))
3(in-package #:advent.2024.02)
4
5(defvar *input* "02.input")
6
7;;; Part 1
8;; How many lines contain monotonically increasing or decreasing numbers that
9;; are all at least 1 and at most 3 apart?
10
11(defun parse (file)
12  (loop for line in (uiop:read-file-lines file)
13        collect (loop for num in (cl-ppcre:split "\\s+" line)
14                      collect (read-from-string num))))
15
16(defun test-line (line)
17  (and (or (apply #'> line)
18           (apply #'< line))
19       (loop for (a b) on line
20             when (and a b (> (abs (- a b)) 3))
21               do (return nil)
22             finally (return t))))
23
24(defun solve-1 ()
25  (count-if #'test-line (parse *input*)))
26
27;;; Part 2
28;; How many lines meet 1's requirements when able to remove *one* element to
29;; meet them?
30
31(defvar *unsafe*
32  (remove-if #'test-line (parse *input*)))
33
34(defun generate-variations (list)
35  "Generate all variations of LIST with one element removed."
36  (loop for i from 0 to (1- (length list))
37        collect (remove-if (let ((j 0))
38                             (lambda (x)
39                               (declare (ignorable x))
40                               (prog1 (= i j)
41                                 (incf j))))
42                           list)))
43
44(defun solve-2 ()
45  (+ (solve-1)
46     (count-if (lambda (line)
47                 (some #'test-line (generate-variations line)))
48               *unsafe*)))