|
| 1 | +from collections import deque |
| 2 | + |
| 3 | +import numpy |
| 4 | + |
| 5 | +from . import SeparateRunner |
| 6 | + |
| 7 | + |
| 8 | +class DayRunner(SeparateRunner): |
| 9 | + @classmethod |
| 10 | + def part1(cls, input: str) -> int: |
| 11 | + grid = numpy.array( |
| 12 | + [[int(v) for v in line] for line in input.strip().split("\n")] |
| 13 | + ) |
| 14 | + |
| 15 | + width, height = grid.shape |
| 16 | + |
| 17 | + start_x, start_y = numpy.nonzero(grid == 0) |
| 18 | + |
| 19 | + todo = [] |
| 20 | + |
| 21 | + reachable = 0 |
| 22 | + |
| 23 | + for sx, sy in zip(start_x, start_y): |
| 24 | + todo.append((sx, sy)) |
| 25 | + ways = numpy.zeros_like(grid, dtype=bool) |
| 26 | + |
| 27 | + def enqueue(x: int, y: int, val: int) -> None: |
| 28 | + if grid[x, y] == val + 1: |
| 29 | + if not ways[x, y]: |
| 30 | + todo.append((x, y)) |
| 31 | + ways[x, y] += True |
| 32 | + |
| 33 | + while todo: |
| 34 | + x, y = todo.pop() |
| 35 | + val = grid[x, y] |
| 36 | + if val == 9: |
| 37 | + reachable += 1 |
| 38 | + continue |
| 39 | + |
| 40 | + if x > 0: |
| 41 | + enqueue(x - 1, y, val) |
| 42 | + if y > 0: |
| 43 | + enqueue(x, y - 1, val) |
| 44 | + if x < width - 1: |
| 45 | + enqueue(x + 1, y, val) |
| 46 | + if y < height - 1: |
| 47 | + enqueue(x, y + 1, val) |
| 48 | + |
| 49 | + return reachable |
| 50 | + |
| 51 | + @classmethod |
| 52 | + def part2(cls, input: str) -> int: |
| 53 | + grid = numpy.array( |
| 54 | + [[int(v) for v in line] for line in input.strip().split("\n")] |
| 55 | + ) |
| 56 | + ways = numpy.zeros_like(grid) |
| 57 | + |
| 58 | + width, height = grid.shape |
| 59 | + |
| 60 | + start_x, start_y = numpy.nonzero(grid == 9) |
| 61 | + ways[grid == 9] = 1 |
| 62 | + |
| 63 | + todo = deque((x, y) for x, y in zip(start_x, start_y)) |
| 64 | + |
| 65 | + def enqueue(x: int, y: int, val: int, cur: int) -> None: |
| 66 | + if grid[x, y] == val - 1: |
| 67 | + if ways[x, y] == 0: |
| 68 | + todo.append((x, y)) |
| 69 | + ways[x, y] += cur |
| 70 | + |
| 71 | + while todo: |
| 72 | + x, y = todo.popleft() |
| 73 | + val = grid[x, y] |
| 74 | + cur = ways[x, y] |
| 75 | + |
| 76 | + if x > 0: |
| 77 | + enqueue(x - 1, y, val, cur) |
| 78 | + if y > 0: |
| 79 | + enqueue(x, y - 1, val, cur) |
| 80 | + if x < width - 1: |
| 81 | + enqueue(x + 1, y, val, cur) |
| 82 | + if y < height - 1: |
| 83 | + enqueue(x, y + 1, val, cur) |
| 84 | + |
| 85 | + return ways[grid == 0].sum() |
0 commit comments