From de3922751e4079f35eeb2e9d5d9085c60069fb16 Mon Sep 17 00:00:00 2001
From: Tom Willemse <tom@ryuslash.org>
Date: Fri, 7 Mar 2025 00:00:55 -0800
Subject: [PATCH] 2024/02-2

---
 2024/day-02/stage-2.lisp | 80 ++++++++++++++++++++++++++++++++++++++++
 manifest.scm             |  3 +-
 2 files changed, 82 insertions(+), 1 deletion(-)
 create mode 100644 2024/day-02/stage-2.lisp

diff --git a/2024/day-02/stage-2.lisp b/2024/day-02/stage-2.lisp
new file mode 100644
index 0000000..806ef09
--- /dev/null
+++ b/2024/day-02/stage-2.lisp
@@ -0,0 +1,80 @@
+(asdf:load-system "cl-strings")
+(asdf:load-system "fiveam")
+
+(require :cl-strings)
+(require :fiveam)
+
+(defvar *input*
+  (mapcar (lambda (line)
+            (mapcar (lambda (column) (parse-integer column))
+                    (cl-strings:split line " ")))
+          (uiop:with-safe-io-syntax ()
+            (uiop:read-file-lines "input.txt"))))
+
+(defun diff (record &optional results)
+  (if (null (cdr record))
+      (nreverse results)
+      (diff (cdr record) (cons (- (cadr record)
+                                  (car record))
+                               results))))
+
+(defun safep-1 (diff)
+  (or (every (lambda (n) (< 0 n 4)) diff)
+      (every (lambda (n) (< -4 n 0)) diff)))
+
+(defun delete-nth (n list &optional result)
+  (cond
+    ((null list) (nreverse result))
+    ((= 0 n) (delete-nth (1- n) (cdr list) result))
+    (t (delete-nth (1- n) (cdr list) (cons (car list) result)))))
+
+(defun permutations (list)
+  (labels ((permutations-1 (n results)
+             (if (> 0 n)
+                 results
+                 (permutations-1 (1- n) (cons (delete-nth n list) results)))))
+    (permutations-1 (1- (length list)) '())))
+
+(defun safep (record)
+  (let ((diff (diff record)))
+    (or (safep-1 diff)
+        (some #'safep-1 (mapcar #'diff (permutations record))))))
+
+(length (delete nil (mapcar #'safep *input*)))
+
+(fiveam:def-suite example-suite :description "The example test suite.")
+
+(fiveam:in-suite example-suite)
+
+(fiveam:test empty-list
+  (fiveam:is (safep nil)))
+
+(fiveam:test single-element
+  (fiveam:is (safep '(1))))
+
+(fiveam:test multiple-elements
+  (fiveam:is (safep '(2 1))))
+
+(fiveam:test big-diff-up-is-unsafe
+  (fiveam:is (not (safep '(1 2 7 8 9)))))
+
+(fiveam:test big-diff-down-is-unsafe
+  (fiveam:is (not (safep '(9 7 6 2 1)))))
+
+(fiveam:test a-single-error-is-permitted
+  (fiveam:is (safep '(1 3 2 4 5))))
+
+(fiveam:test another-single-error-is-permitted
+  (fiveam:is (safep '(8 6 4 4 1))))
+
+(fiveam:test safe-record-is-safe
+  (fiveam:is (safep '(1 3 6 7 9))))
+
+(fiveam:test ignored-value-can-be-at-end
+  (fiveam:is (safep '(5 6 7 10 13 16 13))))
+
+(fiveam:test more-than-one-error-is-not-permitted
+  (fiveam:is (not (safep '(17 18 18 19 16)))))
+
+(fiveam:test what-goes-up-cannot-go-down
+  (fiveam:is (not (safep '(51 52 53 50 52)))))
diff --git a/manifest.scm b/manifest.scm
index 4b08502..2f42802 100644
--- a/manifest.scm
+++ b/manifest.scm
@@ -1,3 +1,4 @@
 (specifications->manifest
  (list "sbcl"
-       "sbcl-cl-strings"))
+       "sbcl-cl-strings"
+       "sbcl-fiveam"))