Advertisement
kupuguy

Advent of Code 2024 Day 16

Dec 16th, 2024
172
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 2.56 KB | Source Code | 0 0
  1. from pathlib import Path
  2. from collections import deque
  3. from pprint import pprint
  4.  
  5. TEST = """**REDACTED**"""
  6.  
  7. DIRECTIONS = (1, -1, 1j, -1j)
  8.  
  9.  
  10. def parse(input: str) -> tuple[complex, complex, set[complex]]:
  11.     walls: set[complex] = set()
  12.     start: complex = 0j
  13.     end: complex = 0j
  14.     for y, row in enumerate(input.splitlines()):
  15.         for x, c in enumerate(row):
  16.             match c:
  17.                 case "#":
  18.                     walls.add(complex(x, y))
  19.                 case "S":
  20.                     start = complex(x, y)
  21.                 case "E":
  22.                     end = complex(x, y)
  23.                 case _:
  24.                     pass
  25.     return start, end, walls
  26.  
  27.  
  28. def walk(
  29.     start: complex, end: complex, walls: set[complex]
  30. ) -> dict[complex, dict[complex, int]]:
  31.     scores: dict[complex, dict[complex, int]] = {1: {start: 0}, -1: {}, 1j: {}, -1j: {}}
  32.     points: deque[tuple[complex, complex]] = deque([(start, 1)])
  33.     while points:
  34.         p, d = points.popleft()
  35.         score = scores[d][p]
  36.         for move, dir, cost in [(p + d, d, 1), (p, d * -1j, 1000), (p, d * 1j, 1000)]:
  37.             if move in walls:
  38.                 continue
  39.             if move in scores[dir] and scores[dir][move] <= score + cost:
  40.                 continue
  41.             scores[dir][move] = score + cost
  42.             points.append((move, dir))
  43.     return scores
  44.  
  45.  
  46. def part1(input: str) -> int:
  47.     start, end, walls = parse(input)
  48.     scores = walk(start, end, walls)
  49.     return min(scores[d][end] for d in DIRECTIONS if end in scores[d])
  50.  
  51.  
  52. assert part1(TEST) == 7036
  53.  
  54. INPUT = Path("input/day16.txt").read_text()
  55. part1_total = part1(INPUT)
  56. print(f"{part1_total=:,}")  # 106,512
  57.  
  58.  
  59. def part2(input: str) -> int:
  60.     start, end, walls = parse(input)
  61.     scores = walk(start, end, walls)
  62.     path: set[complex] = {start, end}
  63.     cost = min(scores[d][end] for d in DIRECTIONS if end in scores[d])
  64.     points: deque[complex, complex, int] = deque(
  65.         [
  66.             (end, d, cost)
  67.             for d in DIRECTIONS
  68.             if end in scores[d] and scores[d][end] == cost
  69.         ]
  70.     )
  71.     while points:
  72.         p, d, cost = points.popleft()
  73.         for move, dir, c1 in [
  74.             (p - d, d, cost - 1),
  75.             (p, d * 1j, cost - 1000),
  76.             (p, d * -1j, cost - 1000),
  77.         ]:
  78.             if move in scores[dir] and scores[dir][move] == c1:
  79.                 path.add(move)
  80.                 points.append((move, dir, c1))
  81.     return len(path)
  82.  
  83.  
  84. assert part2(TEST) == 45
  85. part2_total = part2(INPUT)
  86. print(f"{part2_total=:,}")  # 563
  87.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement