aoc2023/day21.py

92 lines
2.7 KiB
Python

import math
from collections import deque, defaultdict
from tools.aoc import AOCDay
from tools.coordinate import Coordinate, Line
from tools.grid import Grid
from tools.visualization import Window
from typing import Any
def walk(grid: Grid, start: Coordinate, steps: int) -> int:
q = deque()
q.append((start, 0))
s_mod = steps % 2
v = set()
v2 = set()
while q:
coord, dist = q.popleft()
# print("check ", coord, dist)
if coord in v or coord in v2:
# print(" -> in v")
continue
if dist % 2 == s_mod:
# print(f" -> add to v because {dist} even or == {steps}")
v.add(coord)
else:
v2.add(coord)
if dist >= steps:
# print(f" -> >= {steps}")
continue
for n in coord.getNeighbours(includeDiagonal=False):
if grid.get(n % (grid.maxX + 1)):
q.append((n, dist + 1))
# print([x for x in v])
return len(v)
class Day(AOCDay):
inputs = [
[
(16, "input21_test"),
(3562, "input21"),
],
[
# (16733044, "input21_test"),
(None, "input21"),
],
]
def parse_input(self) -> (Grid, Coordinate):
grid = Grid().from_data(self.getInput(), translate={".": True, "#": False})
start = None
for x in grid.find("S"):
start = x
grid.set(x, True)
break # there is only one S
return grid, start
def part1(self) -> Any:
needed_steps = 6 if self.is_test() else 64
grid, start = self.parse_input()
return walk(grid, start, needed_steps)
def part2(self) -> Any:
grid, start = self.parse_input()
print(grid.getOnCount())
for i in [Coordinate(0, 65), Coordinate(65, 0), Coordinate(130, 65), Coordinate(65, 130)]:
t = walk(grid, i, 131) # this always yields 14746 ... coincidence?
print(f"{i} = {t}")
for i in [Coordinate(0, 0), Coordinate(130, 0), Coordinate(0, 130), Coordinate(130, 130)]:
t = walk(grid, i, 65)
print(f"{i} = {t}")
needed_steps = 5000 if self.is_test() else 26501365
t = walk(grid, start, 64)
k = walk(grid, start, len(self.getInput()) + 65)
g = walk(grid, start, 2 * len(self.getInput()) + 65)
# v = walk(grid, start, (3 * len(self.getInput())) - 1)
print(f"65={t}, 196={k}, 327={g}, {math.log(k)=}, {math.log(g)=}")
print(((k - t) / 14746) * 3)
print((g - t) / 14746)
print((g - k) / 14746)
print(g % k)
print(k / t)
return ""
if __name__ == "__main__":
day = Day(2023, 21)
day.run(verbose=True)