|
@@ -0,0 +1,121 @@
|
|
|
+from queue import PriorityQueue
|
|
|
+
|
|
|
+lines = [line.strip() for line in open("24.input")]
|
|
|
+
|
|
|
+blizzards = set()
|
|
|
+
|
|
|
+size = (len(lines[0]), len(lines))
|
|
|
+
|
|
|
+DIRS = {
|
|
|
+ "<": (-1, 0),
|
|
|
+ ">": (1, 0),
|
|
|
+ "v": (0, 1),
|
|
|
+ "^": (0, -1),
|
|
|
+ }
|
|
|
+
|
|
|
+for y, line in enumerate(lines):
|
|
|
+ for x, c in enumerate(line):
|
|
|
+ if c in ("<", ">", "v", "^"):
|
|
|
+ blizzards.add((x, y, c))
|
|
|
+
|
|
|
+def show(grid):
|
|
|
+ for y in range(size[1]):
|
|
|
+ for x in range(size[0]):
|
|
|
+ if x == 0 or y == 0 or x == size[0] - 1 or y == size[1] - 1:
|
|
|
+ print("#", end="")
|
|
|
+ continue
|
|
|
+ blizz = [c for (x_, y_, c) in grid if x == x_ and y == y_]
|
|
|
+ if len(blizz) > 1:
|
|
|
+ print(len(blizz), end="")
|
|
|
+ elif len(blizz) == 1:
|
|
|
+ print(blizz[0], end="")
|
|
|
+ else:
|
|
|
+ print(".", end="")
|
|
|
+ print("")
|
|
|
+ print("-" * 20)
|
|
|
+
|
|
|
+def in_bound(pos):
|
|
|
+
|
|
|
+ start = (1, 0)
|
|
|
+ end = (size[0] - 2, size[1] - 1)
|
|
|
+ if pos in [start, end]:
|
|
|
+ return True
|
|
|
+
|
|
|
+ nx, ny = pos
|
|
|
+ if nx <= 0:
|
|
|
+ return False
|
|
|
+ if nx >= size[0] - 1:
|
|
|
+ return False
|
|
|
+ if ny <= 0:
|
|
|
+ return False
|
|
|
+ if ny >= size[1] - 1:
|
|
|
+ return False
|
|
|
+ return True
|
|
|
+
|
|
|
+def next_map(current):
|
|
|
+ new = set()
|
|
|
+ for (x, y, d) in current:
|
|
|
+ dx, dy = DIRS[d]
|
|
|
+ nx, ny = x + dx, y + dy
|
|
|
+ if nx == 0:
|
|
|
+ nx = size[0] - 2
|
|
|
+ if nx == size[0] - 1:
|
|
|
+ nx = 1
|
|
|
+ if ny == 0:
|
|
|
+ ny = size[1] - 2
|
|
|
+ if ny == size[1] - 1:
|
|
|
+ ny = 1
|
|
|
+ new.add((nx, ny, d))
|
|
|
+ return new
|
|
|
+
|
|
|
+def search(grid_cache, runs):
|
|
|
+
|
|
|
+ start = (1, 0)
|
|
|
+ end = (size[0] - 2, size[1] - 1)
|
|
|
+
|
|
|
+ q = PriorityQueue()
|
|
|
+ q.put((0, start, 0))
|
|
|
+
|
|
|
+ dist_cache = {(0, start, 0): 0}
|
|
|
+
|
|
|
+ while not q.empty():
|
|
|
+ tick, pos, run = q.get()
|
|
|
+ #print(tick, pos, run)
|
|
|
+
|
|
|
+ nxt_map = grid_cache[(tick + 1) % len(grid_cache)]
|
|
|
+
|
|
|
+ if pos == start and run == 1:
|
|
|
+ q.put((tick, pos, 2))
|
|
|
+
|
|
|
+ if pos == end:
|
|
|
+ if run == runs:
|
|
|
+ return tick
|
|
|
+ elif run == 0:
|
|
|
+ q.put((tick, pos, run + 1))
|
|
|
+
|
|
|
+ for dx, dy in [(1, 0), (0, 1), (-1, 0), (0, -1), (0, 0)]:
|
|
|
+ dest = (pos[0] + dx, pos[1] + dy)
|
|
|
+ if not in_bound(dest):
|
|
|
+ continue
|
|
|
+
|
|
|
+ if dest not in nxt_map:
|
|
|
+ new_state = ((tick + 1) % len(grid_cache), dest, run)
|
|
|
+ if dist_cache.get(new_state, 100000000) > tick + 1:
|
|
|
+ dist_cache[new_state] = tick + 1
|
|
|
+ q.put((tick + 1, dest, run))
|
|
|
+
|
|
|
+
|
|
|
+grid_cache = []
|
|
|
+
|
|
|
+current = blizzards
|
|
|
+
|
|
|
+while True:
|
|
|
+ grid_cache.append(current)
|
|
|
+ current = next_map(current)
|
|
|
+ if current in grid_cache:
|
|
|
+ break
|
|
|
+
|
|
|
+grid_cache = [set((x, y) for (x, y, c) in current) for current in grid_cache]
|
|
|
+
|
|
|
+print(search(grid_cache, 0))
|
|
|
+print(search(grid_cache, 2))
|