aoc-cl/src/2024/day06.lisp

129 lines
3 KiB
Common Lisp
Raw Normal View History

2024-12-06 12:45:43 +01:00
(declaim (optimize (speed 3) (debug 0) (safety 0)))
(defpackage :aoc/2024/06
(:use :cl :aoc :alexandria :trivia)
(:export
#:sample-data
#:sample-data2
#:part1
#:part2
))
(in-package :aoc/2024/06)
(defun parse-input (lines)
(let ((l (length lines)))
(make-array (list l l)
:initial-contents (mapcar (lambda (s) (coerce s 'list)) lines))))
(defparameter input-text (test-input 2024 6))
(defparameter input-data
(parse-input (test-input 2024 6)))
(defparameter sample-text (aoc:split-lines "....#.....
.........#
..........
..#.......
.......#..
..........
.#..^.....
........#.
#.........
......#...
"))
(defparameter sample-data
(parse-input sample-text))
(defun make-guard (pos direction)
(list pos direction))
(defun guardp (labo pos)
(eq #\^ (aref labo (second pos) (first pos))))
(defun blockedp (labo pos)
(eq #\# (aref labo (second pos) (first pos))))
(defun find-guard (labo)
(make-guard
(loop for x from 0 to (1- (array-dimension labo 0))
for guard-pos = (loop for y from 0 to (1- (array-dimension labo 1))
for pos = (list x y)
if (guardp labo pos)
return pos)
if guard-pos
return guard-pos)
:north))
(defun move (pos direction)
(destructuring-bind (x y) pos
(case direction
(:north (list x (1- y)))
(:east (list (1+ x) y))
(:south (list x (1+ y)))
(:west (list (1- x) y)))))
(defun out-labop (labo pos)
(destructuring-bind (x y) pos
(or
(< x 0)
(< y 0)
(>= x (array-dimension labo 1))
(>= y (array-dimension labo 1)))))
(defun guard-rotate (guard)
(let ((direction (second guard)))
(make-guard
(first guard)
(case direction
(:north :east)
(:east :south)
(:south :west)
(:west :north)))))
(defun guard-move (labo guard &optional (extra-block nil))
(destructuring-bind (pos dir) guard
(let ((new-pos (move pos dir)))
(cond
((out-labop labo new-pos) nil)
((or (blockedp labo new-pos)
(equal new-pos extra-block))
(guard-move labo (guard-rotate guard) extra-block))
(t (make-guard new-pos dir))))))
(defun guard-path (labo guard &optional (path nil) (extra-block nil))
(cond
((member guard path :test #'equal) nil)
((emptyp guard) (reverse path))
(t (guard-path labo (guard-move labo guard extra-block) (push guard path) extra-block))))
(defun number-squares-covered-by-guard (labo)
(let ((squares (mapcar #'first (guard-path labo (find-guard labo)))))
(length (remove-duplicates squares :test #'equal))))
(defun part1 (data)
(format nil "~A" (number-squares-covered-by-guard data)))
(defun looping-blocks (labo)
(let* ((g (find-guard labo))
(route (guard-path labo g)))
(remove-duplicates
(loop for s in route
for b = (first s)
unless (guard-path labo g '() b)
collect b)
:test #'equal)))
(defun part2 (data)
(let* ((lb (looping-blocks data)))
(format nil "~A" (length lb))))
(defun solve-day ()
(format t "part1: ~A~%" (part1 input-data))
(format t "part2: ~A~%" (part2 input-data)))