aboutsummaryrefslogtreecommitdiff
path: root/2021/day15
diff options
context:
space:
mode:
authorAria <me@aria.rip>2023-01-02 21:58:56 +0000
committerAria <me@aria.rip>2023-01-02 21:58:56 +0000
commit5eb58ad076f2cd435b11b140820da224b60b73d5 (patch)
tree2a67939595fbf993ff04f69b9cd3f0aa20827d96 /2021/day15
initial commit
Diffstat (limited to '2021/day15')
-rw-r--r--2021/day15/15a.py63
-rw-r--r--2021/day15/15b.py80
2 files changed, 143 insertions, 0 deletions
diff --git a/2021/day15/15a.py b/2021/day15/15a.py
new file mode 100644
index 0000000..d7c984b
--- /dev/null
+++ b/2021/day15/15a.py
@@ -0,0 +1,63 @@
+import heapq
+
+grid = [[int(x) for x in l] for l in open("./input").read().strip().split("\n")]
+
+def in_bounds(c):
+ x, y = c
+ return x >= 0 and y >= 0 and y < len(grid) and x < len(grid[y])
+
+def next_steps(path):
+ sx, sy = path[0]
+ for c in [(sx + 1, sy), (sx - 1, sy), (sx, sy + 1), (sx, sy - 1)]:
+ if c not in path and in_bounds(c):
+ yield c
+
+def step_path(path):
+ for c in next_steps(path):
+ yield [c] + path
+
+def total_risk(path):
+ acc = 0
+ for x, y in path:
+ if (x, y) == (0, 0):
+ continue
+ risk = grid[y][x]
+ acc += risk
+
+ return acc
+
+def manhattan(a, b):
+ dx = abs(a[0] - b[0])
+ dy = abs(a[1] - b[1])
+ return dx + dy
+
+def heuristic(path):
+ return total_risk(path) - manhattan(path[0], (len(grid), len(grid[0])))
+
+class HeapItem:
+ def __init__(self, path):
+ self.heur = heuristic(path)
+ self.path = path
+
+ def __lt__(self, other):
+ return self.heur < other.heur
+
+def find_path(start):
+ q = []
+ visited = set()
+ heapq.heappush(q, HeapItem([start]))
+ while True:
+ path = heapq.heappop(q).path
+ if path[0] == (len(grid) - 1, len(grid[0]) - 1):
+ return path
+
+ if path[0] in visited:
+ continue
+ visited.add(path[0])
+
+ for new in step_path(path):
+ heapq.heappush(q, HeapItem(new))
+
+path = find_path((0, 0))
+print(path)
+print(total_risk(path))
diff --git a/2021/day15/15b.py b/2021/day15/15b.py
new file mode 100644
index 0000000..534eb3f
--- /dev/null
+++ b/2021/day15/15b.py
@@ -0,0 +1,80 @@
+import heapq
+
+grid = [[int(x) for x in l] for l in open("./input").read().strip().split("\n")]
+GRID_SIZE_X = len(grid)
+GRID_SIZE_Y = len(grid[0])
+
+def in_bounds(c, tiles):
+ x, y = c
+ return x >= 0 and y >= 0 and y < (GRID_SIZE_Y * tiles) and x < (GRID_SIZE_X * tiles)
+
+def next_steps(path, tiles):
+ sx, sy = path[0]
+ for c in [(sx + 1, sy), (sx - 1, sy), (sx, sy + 1), (sx, sy - 1)]:
+ if c not in path and in_bounds(c, tiles):
+ yield c
+
+def step_path(path, tiles):
+ for c in next_steps(path, tiles):
+ yield [c] + path
+
+def risk_for(x, y):
+ tile_x = x // GRID_SIZE_X
+ tile_y = y // GRID_SIZE_Y
+ delta = tile_x + tile_y
+ risk = grid[y % GRID_SIZE_Y][x % GRID_SIZE_X] + delta
+ while risk > 9:
+ risk -= 9
+ return risk
+
+def total_risk(path):
+ acc = 0
+ for x, y in path:
+ if (x, y) == (0, 0):
+ continue
+ risk = risk_for(x, y)
+ acc += risk
+
+ return acc
+
+def manhattan(a, b):
+ dx = abs(a[0] - b[0])
+ dy = abs(a[1] - b[1])
+ return dx + dy
+
+def heuristic(path, dst):
+ return total_risk(path) - manhattan(path[0], dst)
+
+class HeapItem:
+ def __init__(self, heur, path):
+ self.heur = heur
+ self.path = path
+
+ def __lt__(self, other):
+ return self.heur < other.heur
+
+def find_path(start, tiles):
+ q = []
+ max_x = (GRID_SIZE_X * tiles) - 1
+ max_y = (GRID_SIZE_Y * tiles) - 1
+ dst = (max_x, max_y)
+ visited = set()
+ heapq.heappush(q, HeapItem(0, [start]))
+ while True:
+ i = heapq.heappop(q)
+ heur = i.heur
+ path = i.path
+ if path[0] == (max_x, max_y):
+ return path
+
+ if path[0] in visited:
+ continue
+ visited.add(path[0])
+
+ for new in step_path(path, tiles):
+ loc = new[0]
+ heapq.heappush(q, HeapItem(heur + risk_for(loc[0], loc[1]), new))
+
+path = find_path((0, 0), 5)
+print(path)
+print(total_risk(path))