diff --git a/aoc.asd b/aoc.asd index ba4aeb8..fbea7a7 100644 --- a/aoc.asd +++ b/aoc.asd @@ -1,34 +1,37 @@ (defsystem "aoc" - :long-name "Advent of Code" - :version "0.1.0" - :author "Peter Tillemans" - :maintainer "Peter Tillemans" - :mailto "pti@snamellit.com" - :license "MIT" - :homepage "https://forge.snamellit.com/pti/aoc-cl" - :bug-tracker "https://forge.snamellit.com/pti/aoc-cl/issues" - :source-control "https://forge.snamellit.com/pti/aoc-cl" - :depends-on (#:dexador - #:cl-cookie - #:plump - #:lquery - #:3d-vectors - #:array-operations - #:lla - #:queues.simple-queue - #:bt-semaphore) - :components ((:module "src" - :components - ((:file "main") - (:file "2018/day06") - (:file "2018/day07") - (:file "2024/day01") - (:file "2024/day02") - (:file "2024/day03") - ))) - :description "Advent of Code challenges and solutions." - :long-description "Solutions for the AOC challenges." - :in-order-to ((test-op (test-op "aoc/tests")))) + :long-name "Advent of Code" + :version "0.1.0" + :author "Peter Tillemans" + :maintainer "Peter Tillemans" + :mailto "pti@snamellit.com" + :license "MIT" + :homepage "https://forge.snamellit.com/pti/aoc-cl" + :bug-tracker "https://forge.snamellit.com/pti/aoc-cl/issues" + :source-control "https://forge.snamellit.com/pti/aoc-cl" + :depends-on (#:dexador + #:cl-cookie + #:plump + #:lquery + #:3d-vectors + #:array-operations + #:lla + #:queues.simple-queue + #:bt-semaphore ; threads higher level lib + #:trivia ; community standard pattern matching + ) + :components ((:module "src" + :components + ((:file "main") + (:file "2018/day06") + (:file "2018/day07") + (:file "2024/day01") + (:file "2024/day02") + (:file "2024/day03") + (:file "2024/day04") + ))) + :description "Advent of Code challenges and solutions." + :long-description "Solutions for the AOC challenges." + :in-order-to ((test-op (test-op "aoc/tests")))) (defsystem "aoc/tests" :author "Peter Tillemans" @@ -40,8 +43,11 @@ ((:file "main") (:file "2018/day06-test") (:file "2018/day07-test") + (:file "2024/main") (:file "2024/day01-test") (:file "2024/day02-test") + (:file "2024/day03-test") + (:file "2024/day04-test") ))) :description "Test system for aoc" :perform (test-op (op c) (symbol-call :parachute :test :aoc/tests))) diff --git a/src/2024/day04.lisp b/src/2024/day04.lisp new file mode 100644 index 0000000..4454389 --- /dev/null +++ b/src/2024/day04.lisp @@ -0,0 +1,145 @@ +(defpackage :aoc/2024/04 + (:use :cl :aoc :alexandria :trivia) + (:export + #:sample-data + #:sample-data2 + #:part1 + #:part2 + #:lil-xmas-state-machine + #:count-xmas-in-line + #:count-xmas + #:transpose + #:diagonals + )) + +(in-package :aoc/2024/04) + +(defun parse-line (s) + s) + +(defvar input-data '()) +(setf input-data (map 'list #'parse-line (test-input 2024 4))) + +(defvar sample-text "") +(setf sample-text (aoc:split-lines "MMMSXXMASM +MSAMXMSMSA +AMXSXMAAMM +MSAMASMSMX +XMASAMXAMM +XXAMMXXAMA +SMSMSASXSS +SAXAMASAAA +MAMMMXMMMM +MXMXAXMASX")) + +(defvar sample-data '()) +(setf sample-data (map 'list #'parse-line sample-text)) + +(defun lil-xmas-state-machine (state x) + (let ((cnt (car state)) + (last (cdr state))) + (match (cons last x) + ((cons _ #\X) (cons cnt :x)) + ((cons :x #\M) (cons cnt :m)) + ((cons :m #\A) (cons cnt :a)) + ((cons :a #\S) (cons (1+ cnt) nil)) + ((cons _ _) (cons cnt nil)) + ))) + +(defun count-xmas-in-line- (line) + (car + (reduce #'lil-xmas-state-machine line :initial-value (cons 0 nil)))) + +(defun count-xmas-in-line (line) + (+ (count-xmas-in-line- line) + (count-xmas-in-line- (reverse line)))) + +(defun transpose (lines) + (loop for i from 0 to (1- (length (first lines))) + collect (format nil "~{~A~}" + (loop for l in lines collect (subseq l i (1+ i)))))) + +(defun diag-coords (len) + (let ((l (1- len))) + (loop for i from (- l) to l + collect (if (< i 0) + (loop for x from 0 to l + for y from (- i) to l + collect (list x y)) + (loop for x from i to l + for y from 0 to l + collect (list x y)))))) + +(defun get-xy (cell lines) + (let ((x (first cell)) + (y (second cell))) + (subseq (nth y lines) x (1+ x)))) + +(defun diagonals (lines) + (loop for diag in (diag-coords (length lines)) + collect (format nil "~{~A~}" + (loop for cell in diag + collect (get-xy cell lines))))) + +(defun count-xmas (data) + (let ((lines (append data + (transpose data) + (diagonals data) + (diagonals (mapcar #'reverse data))))) + (loop for line in lines + sum (count-xmas-in-line line)))) + +(defun part1 (data) + (format nil "~A" (count-xmas data))) + + +(defvar sample-input2 ".M.S...... +..A..MSMS. +.M.S.MAA.. +..A.ASMSM. +.M.S.M.... +.......... +S.S.S.S.S. +.A.A.A.A.. +M.M.M.M.M. +.......... +") +(defvar sample-data2 ()) +(setf sample-data2 (map 'list #'parse-line sample-text)) + +(defun find-a-cells (data) + (loop for y from 1 to (- (length data) 2) + append (loop for x from 1 to (- (length data) 2) + if (equal "A" (get-xy (list x y) data)) + collect (list x y)))) + +(defun cell-crossp (cell data) + (let* ((x (first cell)) + (y (second cell)) + (tl (get-xy (list (1- x) (1- y)) data)) + (tr (get-xy (list (1+ x) (1- y)) data)) + (bl (get-xy (list (1- x) (1+ y)) data)) + (br (get-xy (list (1+ x) (1+ y)) data)) + (all-ms-p (every + (lambda (x) + (member x (list "M" "S") :test #'equal)) + (list tl tr bl br)))) + (format t "~A ~A ~A ~A ~%" tl tr bl br ) + (format t "x: ~A y: ~A ms: ~A~%" x y all-ms-p) + (format t "tl-br: ~A, tr-bl: ~A ~%" (equal tl br) (equal tr bl) ) + (and + all-ms-p + (not (equal tl br)) + (not (equal tr bl))))) + +(defun count-x-mas (data) + (loop for a in (find-a-cells data) + count (cell-crossp a data))) + +(defun part2 (data) + (format nil "~A" (count-x-mas data))) + +(defun solve-day () + (format t "part1: ~A~%" (part1 input-data)) + (format t "part2: ~A~%" (part2 input-data))) + diff --git a/tests/2018/day06-test.lisp b/tests/2018/day06-test.lisp index 22ccd8b..f3d29e2 100644 --- a/tests/2018/day06-test.lisp +++ b/tests/2018/day06-test.lisp @@ -10,7 +10,8 @@ (in-package :aoc/2018/06/tests) (define-test suite-2018-06 - :parent suite-2018) + ;:parent suite-2018 + ) (define-test+run test-find-top-left :parent suite-2018-06 diff --git a/tests/2024/day03-tests.lisp b/tests/2024/day03-test.lisp similarity index 100% rename from tests/2024/day03-tests.lisp rename to tests/2024/day03-test.lisp diff --git a/tests/2024/day04-test.lisp b/tests/2024/day04-test.lisp new file mode 100644 index 0000000..e4542b5 --- /dev/null +++ b/tests/2024/day04-test.lisp @@ -0,0 +1,42 @@ +(defpackage :aoc/2024/04/tests + (:use :cl :aoc :aoc/tests :aoc/2024/tests :parachute :aoc/2024/04)) + +(in-package :aoc/2024/04/tests) + +(define-test suite-2024-04 + ;:parent suite-2024 + ) + +(define-test test-lil-xmas-state-machine + :parent suite-2024-04 + (is equal (cons 0 nil) (lil-xmas-state-machine (cons 0 nil) #\a)) + (is equal (cons 0 :x) (lil-xmas-state-machine (cons 0 nil) #\X)) + (is equal (cons 0 :m) (lil-xmas-state-machine (cons 0 :x) #\M)) + (is equal (cons 0 :a) (lil-xmas-state-machine (cons 0 :m) #\A)) + (is equal (cons 1 nil) (lil-xmas-state-machine (cons 0 :a) #\S)) + ) + +(define-test test-count-xmas-in-line + :parent suite-2024-04 + (is = 0 (count-xmas-in-line "FOOBAR")) + (is = 1 (count-xmas-in-line "XMAS")) + (is = 2 (count-xmas-in-line "XMASZXMAS")) + (is = 2 (count-xmas-in-line (reverse "XMASZXMAS")))) + +(define-test test-transpose + :parent suite-2024-04 + (is equal (list "147" "258" "369") (transpose (list "123" "456" "789")))) + +(define-test test-diagonals + :parent suite-2024-04 + (is equal (list "7" "48" "159" "26" "3") (diagonals (list "123" "456" "789")))) + +(define-test+run test-part1 + :parent suite-2024-04 + (true (equalp "18" (part1 sample-data)))) + +(define-test+run test-part2 + :parent suite-2024-04 + (true (equalp "9" (part2 sample-data2)))) + +