-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathday17.py
89 lines (63 loc) · 2.13 KB
/
day17.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
"""
Advent of Code 2023, Day 17: Clumsy Crucible.
"""
import sys
from queue import PriorityQueue
from typing import TextIO
def minimize_heat_loss(
grid: list[str], min_path_length: int, max_path_length: int
) -> int:
"""
Finds the path through the grid that minimizes the total heat loss.
:param grid: The grid to navigate
:param min_path_length: The minimum distance to travel in one direction before being able to turn.
:param max_path_length: The maximum distance to travel in one direction before having to turn.
:return: The heat loss incurred by following the path
"""
max_x, max_y = len(grid[0]) - 1, len(grid) - 1
visited = set()
todo = PriorityQueue()
# cost, x, y, dx, dy, segment length
todo.put((0, 0, 0, 1, 0, 1))
todo.put((0, 0, 0, 0, 1, 1))
while todo:
cost, x, y, dx, dy, c = todo.get()
if (x, y, dx, dy, c) in visited:
continue
visited.add((x, y, dx, dy, c))
if x == max_x and y == max_y:
return cost
x += dx
y += dy
if not (0 <= x <= max_x and 0 <= y <= max_y):
continue
cost += int(grid[y][x])
if c < max_path_length:
todo.put((cost, x, y, dx, dy, c + 1))
if c >= min_path_length:
todo.put((cost, x, y, dy, dx, 1))
todo.put((cost, x, y, -dy, -dx, 1))
return -1
def part_one(file: TextIO) -> int:
"""
Solve part one of the puzzle.
"""
grid = list(line.strip() for line in file)
return minimize_heat_loss(grid, min_path_length=1, max_path_length=3)
def part_two(file: TextIO) -> int:
"""
Solve part two of the puzzle.
"""
grid = list(line.strip() for line in file)
return minimize_heat_loss(grid, min_path_length=4, max_path_length=10)
def main():
"""
The main entrypoint for the script.
"""
filename = sys.argv[0].replace(".py", ".txt")
with open(filename, encoding="utf-8") as file:
print("Part one:", part_one(file))
with open(filename, encoding="utf-8") as file:
print("Part two:", part_two(file))
if __name__ == "__main__":
main()