day-20.lisp (2027B)
1 (defpackage #:aoc/day-20 2 (:use #:cl #:aoc/utils) 3 (:export #:day-20)) 4 (in-package #:aoc/day-20) 5 6 (defparameter *directions* '((1 . 0) (-1 . 0) 7 (0 . 1) (0 . -1))) 8 9 (defun find-start-end (map) 10 (loop with start = nil 11 with end = nil 12 for y from 0 below (input-map-height map) 13 thereis (loop for x from 0 below (input-map-width map) 14 for pos = (cons x y) 15 for cell = (map-cell map pos) 16 when (char= #\S cell) 17 do (setf start pos) 18 when (char= #\E cell) 19 do (setf end pos)) 20 finally (return (values start end)))) 21 22 (defun day-20 (input) 23 (loop with map = (make-map input) 24 with (start end) = (multiple-value-list (find-start-end map)) 25 with width = (input-map-width map) 26 with height = (input-map-height map) 27 with pos = start 28 with last = nil 29 with steps = nil 30 with task-1 fixnum = 0 31 with task-2 fixnum = 0 32 for picoseconds fixnum from 0 33 do (loop for (pos-2 . picoseconds-2) in steps 34 for distance = (manhattan-distance pos pos-2) 35 for saved fixnum = (- picoseconds (+ (the fixnum picoseconds-2) distance)) 36 do (when (>= saved 100) 37 (when (<= distance 2) 38 (incf task-1)) 39 (when (<= distance 20) 40 (incf task-2)))) 41 (push (cons pos picoseconds) steps) 42 when (equal pos end) 43 do (return (values task-1 task-2)) 44 do (psetf last pos 45 pos (loop for dir in *directions* 46 for next = (point+ pos dir) 47 when (and (point-in-bounds-p next width height) 48 (not (equal last next)) 49 (char/= (map-cell map next) #\#)) 50 do (return next)))))