From f0556c6afe3fc5957206aaa349319d29fcd5df6a Mon Sep 17 00:00:00 2001 From: Bert Peters Date: Mon, 16 Dec 2024 08:56:04 +0100 Subject: [PATCH] Implement 2024 day 16 part 1 --- 2024/src/aoc/days/day16.py | 56 +++++++++++++++++++++++++++++++++++++ 2024/tests/samples/16.1.txt | 15 ++++++++++ 2024/tests/samples/16.2.txt | 17 +++++++++++ 2024/tests/test_day16.py | 16 +++++++++++ 4 files changed, 104 insertions(+) create mode 100644 2024/src/aoc/days/day16.py create mode 100644 2024/tests/samples/16.1.txt create mode 100644 2024/tests/samples/16.2.txt create mode 100644 2024/tests/test_day16.py diff --git a/2024/src/aoc/days/day16.py b/2024/src/aoc/days/day16.py new file mode 100644 index 0000000..05ebdf0 --- /dev/null +++ b/2024/src/aoc/days/day16.py @@ -0,0 +1,56 @@ +import heapq + +import numpy + +from . import SeparateRunner + +TURNS = ( + (-1, 1), + (1, -1), +) + + +class DayRunner(SeparateRunner): + @classmethod + def part1(cls, input: str) -> int: + grid = numpy.array([list(line) for line in input.strip().split("\n")]) + + y, x = numpy.where(grid == "S") + x, y = x[0], y[0] + + todo = [(0, x, y, 1, 0)] + best = { + (x, y, 1, 0): 0, + } + + def enqueue(dist, x, y, dx, dy): + if grid[y, x] == "#": + return + + if (x, y, dx, dy) not in best or best[x, y, dx, dy] > dist: + best[x, y, dx, dy] = dist + heapq.heappush(todo, (dist, x, y, dx, dy)) + + while todo: + dist, x, y, dx, dy = heapq.heappop(todo) + + if best[x, y, dx, dy] < dist: + continue + + if grid[y, x] == "E": + return dist + + enqueue(dist + 1, x + dx, y + dy, dx, dy) + enqueue(dist + 2001, x - dx, y - dy, dx, dy) + + for tx, ty in TURNS: + ndx = dy * ty + ndy = dx * ty + + enqueue(dist + 1001, x + ndx, y + ndy, ndx, ndy) + + raise ValueError("Did not find path to exit") + + @classmethod + def part2(cls, input: str) -> int: + pass diff --git a/2024/tests/samples/16.1.txt b/2024/tests/samples/16.1.txt new file mode 100644 index 0000000..2c21676 --- /dev/null +++ b/2024/tests/samples/16.1.txt @@ -0,0 +1,15 @@ +############### +#.......#....E# +#.#.###.#.###.# +#.....#.#...#.# +#.###.#####.#.# +#.#.#.......#.# +#.#.#####.###.# +#...........#.# +###.#.#####.#.# +#...#.....#.#.# +#.#.#.###.#.#.# +#.....#...#.#.# +#.###.#.#.#.#.# +#S..#.....#...# +############### diff --git a/2024/tests/samples/16.2.txt b/2024/tests/samples/16.2.txt new file mode 100644 index 0000000..bc61c57 --- /dev/null +++ b/2024/tests/samples/16.2.txt @@ -0,0 +1,17 @@ +################# +#...#...#...#..E# +#.#.#.#.#.#.#.#.# +#.#.#.#...#...#.# +#.#.#.#.###.#.#.# +#...#.#.#.....#.# +#.#.#.#.#.#####.# +#.#...#.#.#.....# +#.#.#####.#.###.# +#.#.#.......#...# +#.#.###.#####.### +#.#.#...#.....#.# +#.#.#.#####.###.# +#.#.#.........#.# +#.#.#.#########.# +#S#.............# +################# diff --git a/2024/tests/test_day16.py b/2024/tests/test_day16.py new file mode 100644 index 0000000..843e4c2 --- /dev/null +++ b/2024/tests/test_day16.py @@ -0,0 +1,16 @@ +import pytest + +from aoc.days.day16 import DayRunner + +from . import get_data + + +@pytest.mark.parametrize( + "data,result", + [ + (get_data(16, 1), 7036), + (get_data(16, 2), 11048), + ], +) +def test_sample_part1(data: str, result: int) -> None: + assert DayRunner.part1(data) == result