|
| 1 | +""" |
| 2 | +Day 21: Step Counter |
| 3 | +""" |
| 4 | + |
| 5 | +SAMPLE_INPUT = """ |
| 6 | +........... |
| 7 | +.....###.#. |
| 8 | +.###.##..#. |
| 9 | +..#.#...#.. |
| 10 | +....#.#.... |
| 11 | +.##..S####. |
| 12 | +.##..#...#. |
| 13 | +.......##.. |
| 14 | +.##.#.####. |
| 15 | +.##..##.##. |
| 16 | +........... |
| 17 | +""" |
| 18 | + |
| 19 | + |
| 20 | +def _count(grid, start, n): |
| 21 | + frontier, visited, acc = {start}, set(), 0 |
| 22 | + for d in range(n): |
| 23 | + if not (d ^ n) & 1: |
| 24 | + acc += len(frontier) |
| 25 | + visited |= frontier |
| 26 | + frontier = { |
| 27 | + (y1, x1) |
| 28 | + for y0, x0 in frontier |
| 29 | + for y1, x1 in [(y0 - 1, x0), (y0, x0 - 1), (y0, x0 + 1), (y0 + 1, x0)] |
| 30 | + if 0 <= y1 < len(grid) |
| 31 | + and 0 <= x1 < len(grid[y1]) |
| 32 | + and grid[y1][x1] != "#" |
| 33 | + and (y1, x1) not in visited |
| 34 | + } |
| 35 | + return acc + len(frontier) |
| 36 | + |
| 37 | + |
| 38 | +def part1(data, n=64): |
| 39 | + """ |
| 40 | + >>> part1(SAMPLE_INPUT, n=1) |
| 41 | + 2 |
| 42 | + >>> part1(SAMPLE_INPUT, n=2) |
| 43 | + 4 |
| 44 | + >>> part1(SAMPLE_INPUT, n=3) |
| 45 | + 6 |
| 46 | + >>> part1(SAMPLE_INPUT, n=6) |
| 47 | + 16 |
| 48 | + """ |
| 49 | + grid = [line for line in data.splitlines() if line] |
| 50 | + (start,) = ( |
| 51 | + (y, x) for y, line in enumerate(grid) for x, c in enumerate(line) if c == "S" |
| 52 | + ) |
| 53 | + return _count(grid, start, n) |
| 54 | + |
| 55 | + |
| 56 | +def part2(data, n=26501365): |
| 57 | + """ |
| 58 | + >>> part2(SAMPLE_INPUT, n=6) # doctest: +SKIP |
| 59 | + 16 |
| 60 | + >>> part2(SAMPLE_INPUT, n=10) # doctest: +SKIP |
| 61 | + 50 |
| 62 | + >>> part2(SAMPLE_INPUT, n=50) # doctest: +SKIP |
| 63 | + 1594 |
| 64 | + >>> part2(SAMPLE_INPUT, n=100) # doctest: +SKIP |
| 65 | + 6536 |
| 66 | + >>> part2(SAMPLE_INPUT, n=500) # doctest: +SKIP |
| 67 | + 167004 |
| 68 | + >>> part2(SAMPLE_INPUT, n=1000) # doctest: +SKIP |
| 69 | + 668697 |
| 70 | + >>> part2(SAMPLE_INPUT, n=5000) # doctest: +SKIP |
| 71 | + 16733044 |
| 72 | + """ |
| 73 | + grid = [line for line in data.splitlines() if line] |
| 74 | + m = len(grid) |
| 75 | + q, r = n // m, n % m |
| 76 | + ((y0, x0),) = ( |
| 77 | + (y, x) for y, line in enumerate(grid) for x, c in enumerate(line) if c == "S" |
| 78 | + ) |
| 79 | + a, b, c, d = ( |
| 80 | + _count( |
| 81 | + [line * (2 * i + 1) for line in grid] * (2 * i + 1), |
| 82 | + (y0 + i * m, x0 + i * m), |
| 83 | + r + i * m, |
| 84 | + ) |
| 85 | + for i in range(4) |
| 86 | + ) |
| 87 | + assert d == a - 3 * b + 3 * c |
| 88 | + return a + (b - a) * q + (c - 2 * b + a) * (q * (q - 1) // 2) |
| 89 | + |
| 90 | + |
| 91 | +parts = (part1, part2) |
0 commit comments