advent-of-code-2023

My solutions to AoC 2023
git clone git://git.entf.net/advent-of-code-2023
Log | Files | Refs

commit 569b1ebc8e00e62547e3ab388d3668368f86823c
parent 1b302a53c5470abd327425fc42f12f543436a7e9
Author: Lukas Henkel <lh@entf.net>
Date:   Thu, 21 Dec 2023 13:59:04 +0100

Day 21 task 2

Diffstat:
Msrc/day-21.lisp | 44++++++++++++++++++++++++++++++--------------
Mt/day-21.lisp | 23+++++++++++++++++------
2 files changed, 47 insertions(+), 20 deletions(-)

diff --git a/src/day-21.lisp b/src/day-21.lisp @@ -10,19 +10,22 @@ when (char= (map-cell map point) #\S) do (return-from find-start-position point)))) +(defun neighbouring-positions (position) + (destructuring-bind (x . y) + position + (let (ps) + (push (cons (1- x) y) ps) + (push (cons (1+ x) y) ps) + (push (cons x (1- y)) ps) + (push (cons x (1+ y)) ps) + ps))) + (defun neighbouring-gardens (map width height position) - (loop for nd in (let (nds) - (when (> (point-x position) 0) - (push (cons -1 0) nds)) - (when (< (point-x position) (1- width)) - (push (cons 1 0) nds)) - (when (> (point-y position) 0) - (push (cons 0 -1) nds)) - (when (< (point-y position) (1- height)) - (push (cons 0 1) nds)) - nds) - for n = (point+ position nd) - for cell = (map-cell map n) + (loop for n in (neighbouring-positions position) + for cell = (map-cell map (destructuring-bind (x . y) + n + (cons (mod x width) + (mod y height)))) when (or (char= cell #\.) (char= cell #\S)) collect n)) @@ -40,7 +43,20 @@ nconc (neighbouring-gardens map width height position)) :test #'equal)))) -(defun day-21 (input &optional (steps 64)) +(defun task-2 (map start-pos final-steps) + (let* ((width (input-map-width map)) + (target (mod final-steps width)) + (f (floor final-steps width)) + (y0 (step-through-garden map start-pos target)) + (y1 (step-through-garden map start-pos (+ width target))) + (y2 (step-through-garden map start-pos (+ (* width 2) target))) + (b0 y0) + (b1 (- y1 y0)) + (b2 (- y2 y1))) + (+ (* (* f (/ (1- f) 2)) (- b2 b1)) (* b1 f) b0))) + +(defun day-21 (input &optional (steps-1 64) (steps-2 26501365)) (let* ((map (make-map input)) (start-pos (find-start-position map))) - (step-through-garden map start-pos steps))) + (values (step-through-garden map start-pos steps-1) + (task-2 map start-pos steps-2)))) diff --git a/t/day-21.lisp b/t/day-21.lisp @@ -2,10 +2,7 @@ (:use #:cl #:lisp-unit2)) (in-package #:aoc-test/day-21) -(define-test test-day-21 - () - (multiple-value-bind (task-1) - (aoc:run-day 21 "........... +(defparameter *test-map* "........... .....###.#. .###.##..#. ..#.#...#.. @@ -15,5 +12,19 @@ .......##.. .##.#.####. .##..##.##. -..........." 6) - (assert= 16 task-1))) +...........") + +(define-test test-day-21 + () + (multiple-value-bind (task-1 task-2) + (aoc:run-day 21 *test-map* 6 6) + (assert= 16 task-1) + (assert= 16 task-2)) + ;; Tests don't work for task 2 + #+nil(loop for (expected steps) in '((50 10) + (1594 50) + (6536 100) + (167004 500) + (668697 1000) + (16733044 5000)) + do (assert= expected (nth-value 1 (aoc:run-day 21 *test-map* 0 steps)))))