Commit Diff


commit - be08f67cded6e0367aeb15c08edd637f31e98965
commit + 5ebe82fbf80d12d57735a7ddd314db7ecc3e132f
blob - 4169f872e275615cd5868bf159c7d1de0478d337
blob + 146ba36404a2684aecfd0cfba9c183c8880615f7
--- src/day-2.lisp
+++ src/day-2.lisp
@@ -3,36 +3,35 @@
   (:export #:day-2))
 (in-package #:aoc/day-2)
 
-(defun report-safe-p (report)
-  (loop with dir = (if (> (first report) (second report)) #'> #'<)
-        with last = (first report)
-        for current in (cdr report)
-        for diff = (abs (- last current))
-        unless (funcall dir last current)
-          do (return nil)
-        unless (<= diff 3)
-          do (return nil)
-        do (setf last current)
+(defun report-safe-p (report &key direction allow-skip)
+  (when (null direction)
+    (return-from report-safe-p
+      (or (report-safe-p report :direction #'< :allow-skip allow-skip)
+          (report-safe-p report :direction #'> :allow-skip allow-skip))))
+  (when (null (cdr report))
+    (return-from report-safe-p t))
+  (loop with last = nil
+        for cdr on report
+        until (null (cdr cdr))
+        for left = (car cdr)
+        for right = (cadr cdr)
+        for diff = (abs (- left right))
+        for cdir = (funcall direction left right)
+        unless (and cdir (<= diff 3))
+          do (return (when allow-skip
+                       (or (report-safe-p (cons left (cddr cdr)) :direction direction)
+                           (if (null last)
+                               (report-safe-p (cdr cdr) :direction direction)
+                               (report-safe-p (cons (car last) (cdr cdr)) :direction direction)))))
+        do (setf last cdr)
         finally (return t)))
 
-(defun remove-nth (n list)
-  (concatenate 'list
-               (subseq list 0 n)
-               (subseq list (1+ n))))
-
-(defun report-somewhat-safe-p (report)
-  (or (report-safe-p report)
-      (loop for i from 0 below (length report)
-            for nr = (remove-nth i report)
-            when (report-safe-p nr)
-              do (return t))))
-
 (defun day-2 (input)
   (loop for line = (read-line input nil)
         until (null line)
         for report = (read-number-list line)
         when (report-safe-p report)
           sum 1 into task-1
-        when (report-somewhat-safe-p report)
+        when (report-safe-p report :allow-skip t)
           sum 1 into task-2
         finally (return (values task-1 task-2))))
blob - 24d79613f13689146fab0aecbfb92ffc84abf984
blob + 17bd3b5b674bdf909b561a6d8cd0b6806e626c2f
--- t/day-2.lisp
+++ t/day-2.lisp
@@ -4,6 +4,14 @@
 
 (define-test test-day-2
     ()
+  ;;; Test resets
+  ;; Report where the first item needs to be skipped
+  (assert (aoc/day-2::report-safe-p (list 30 24 25 28 31 33 35) :allow-skip t))
+  ;; Report where the second item needs to be skipped
+  (assert (aoc/day-2::report-safe-p (list 24 21 25 28 31 33 35) :allow-skip t))
+  ;; Report where reset target needs to be removed
+  (assert (aoc/day-2::report-safe-p (list 25 22 19 21 20 17 14 13) :allow-skip t))
+  ;;; Test task 1 & 2
   (multiple-value-bind (task-1 task-2)
       (aoc:run-day 2 "7 6 4 2 1
 1 2 7 8 9