24.py 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. from queue import PriorityQueue
  2. lines = [line.strip() for line in open("24.input")]
  3. blizzards = set()
  4. size = (len(lines[0]), len(lines))
  5. DIRS = {
  6. "<": (-1, 0),
  7. ">": (1, 0),
  8. "v": (0, 1),
  9. "^": (0, -1),
  10. }
  11. for y, line in enumerate(lines):
  12. for x, c in enumerate(line):
  13. if c in ("<", ">", "v", "^"):
  14. blizzards.add((x, y, c))
  15. def show(grid):
  16. for y in range(size[1]):
  17. for x in range(size[0]):
  18. if x == 0 or y == 0 or x == size[0] - 1 or y == size[1] - 1:
  19. print("#", end="")
  20. continue
  21. blizz = [c for (x_, y_, c) in grid if x == x_ and y == y_]
  22. if len(blizz) > 1:
  23. print(len(blizz), end="")
  24. elif len(blizz) == 1:
  25. print(blizz[0], end="")
  26. else:
  27. print(".", end="")
  28. print("")
  29. print("-" * 20)
  30. def in_bound(pos):
  31. start = (1, 0)
  32. end = (size[0] - 2, size[1] - 1)
  33. if pos in [start, end]:
  34. return True
  35. nx, ny = pos
  36. if nx <= 0:
  37. return False
  38. if nx >= size[0] - 1:
  39. return False
  40. if ny <= 0:
  41. return False
  42. if ny >= size[1] - 1:
  43. return False
  44. return True
  45. def next_map(current):
  46. new = set()
  47. for (x, y, d) in current:
  48. dx, dy = DIRS[d]
  49. nx, ny = x + dx, y + dy
  50. if nx == 0:
  51. nx = size[0] - 2
  52. if nx == size[0] - 1:
  53. nx = 1
  54. if ny == 0:
  55. ny = size[1] - 2
  56. if ny == size[1] - 1:
  57. ny = 1
  58. new.add((nx, ny, d))
  59. return new
  60. def search(grid_cache, runs):
  61. start = (1, 0)
  62. end = (size[0] - 2, size[1] - 1)
  63. q = PriorityQueue()
  64. q.put((0, start, 0))
  65. dist_cache = {(0, start, 0): 0}
  66. while not q.empty():
  67. tick, pos, run = q.get()
  68. #print(tick, pos, run)
  69. nxt_map = grid_cache[(tick + 1) % len(grid_cache)]
  70. if pos == start and run == 1:
  71. q.put((tick, pos, 2))
  72. if pos == end:
  73. if run == runs:
  74. return tick
  75. elif run == 0:
  76. q.put((tick, pos, run + 1))
  77. for dx, dy in [(1, 0), (0, 1), (-1, 0), (0, -1), (0, 0)]:
  78. dest = (pos[0] + dx, pos[1] + dy)
  79. if not in_bound(dest):
  80. continue
  81. if dest not in nxt_map:
  82. new_state = ((tick + 1) % len(grid_cache), dest, run)
  83. if dist_cache.get(new_state, 100000000) > tick + 1:
  84. dist_cache[new_state] = tick + 1
  85. q.put((tick + 1, dest, run))
  86. grid_cache = []
  87. current = blizzards
  88. while True:
  89. grid_cache.append(current)
  90. current = next_map(current)
  91. if current in grid_cache:
  92. break
  93. grid_cache = [set((x, y) for (x, y, c) in current) for current in grid_cache]
  94. print(search(grid_cache, 0))
  95. print(search(grid_cache, 2))