summaryrefslogtreecommitdiffstats
path: root/15.py
diff options
context:
space:
mode:
Diffstat (limited to '15.py')
-rw-r--r--15.py54
1 files changed, 29 insertions, 25 deletions
diff --git a/15.py b/15.py
index ab369f5..231f5e8 100644
--- a/15.py
+++ b/15.py
@@ -1,21 +1,34 @@
from collections import defaultdict
-from utils import open_day
+from utils import open_day, Point2D, adjacent_bounded
from heapq import heappop, heappush
def a_star(start, goal, neighbours, h, d):
+ vtoi = dict()
+ itov = dict()
+ i = 0
+ def intern(v):
+ nonlocal i
+ ret = vtoi.get(v)
+ if ret is None:
+ ret = i
+ vtoi[v] = i
+ itov[i] = v
+ i += 1
+ return ret
open_set = {start}
- open_heapq = [(0, start)]
+ open_heapq = [(0, intern(start))]
came_from = dict()
g_score = defaultdict(lambda: float('inf'))
g_score[start] = 0
f_score = defaultdict(lambda: float('inf'))
f_score[start] = h(start)
-
while open_set:
- f, current = open_heapq[0]
+ while True:
+ f, current = heappop(open_heapq)
+ current = itov[current]
+ if current in open_set: break
if current == goal:
return f
- heappop(open_heapq)
open_set.remove(current)
for neighbour in neighbours(current):
tentative_g = g_score[current] + d(current, neighbour)
@@ -23,31 +36,22 @@ def a_star(start, goal, neighbours, h, d):
came_from[neighbour] = current
g_score[neighbour] = tentative_g
f_score[neighbour] = tentative_g + h(neighbour)
- if neighbour not in open_set:
- open_set.add(neighbour)
- heappush(open_heapq, (f_score[neighbour], neighbour))
+ open_set.add(neighbour)
+ heappush(open_heapq, (f_score[neighbour], intern(neighbour)))
return None
with open_day(15) as f:
inp = [[int(c) for c in l.rstrip()] for l in f]
-def neighbours(p, dim):
- for dx, dy in ((-1, 0), (1, 0), (0, -1), (0, 1)):
- px, py = p[0] + dx, p[1] + dy
- if px < 0 or py < 0 or px >= dim[0] or py >= dim[1]: continue
- yield px, py
-
-def manhattan(a, b): return abs(a[0] - b[0]) + abs(a[1] - b[1])
def d(a, b):
- x, y = b
- add = x // len(inp[0]) + y // len(inp)
- x, y = x % len(inp[0]), y % len(inp)
+ add = b.x // len(inp[0]) + b.y // len(inp)
+ x, y = b.x % len(inp[0]), b.y % len(inp)
return (inp[y][x] + add - 1) % 9 + 1
-start = (0, 0)
-goal1 = (len(inp[0]) - 1, len(inp) - 1)
-neighbours1 = lambda p: neighbours(p, (len(inp[0]), len(inp)))
-print(a_star(start, goal1, neighbours1, lambda p: manhattan(p, goal1), d))
-goal2 = (len(inp[0]) * 5 - 1, len(inp) * 5 - 1)
-neighbours2 = lambda p: neighbours(p, (len(inp[0]) * 5, len(inp) * 5))
-print(a_star(start, goal2, neighbours2, lambda p: manhattan(p, goal2), d))
+start = Point2D(0, 0)
+goal1 = Point2D(len(inp[0]) - 1, len(inp) - 1)
+neighbours1 = lambda p: adjacent_bounded(p, Point2D(len(inp[0]), len(inp)), False)
+print(a_star(start, goal1, neighbours1, lambda p: 0, d))
+goal2 = Point2D(len(inp[0]) * 5 - 1, len(inp) * 5 - 1)
+neighbours2 = lambda p: adjacent_bounded(p, Point2D(len(inp[0]) * 5, len(inp) * 5), False)
+print(a_star(start, goal2, neighbours2, lambda p: 0, d))