Guest User

AoC 2022 - Day 24

a guest
Jan 4th, 2023
288
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 3.04 KB | None | 0 0
  1. """
  2. Advent of Code 2022 Day 24
  3. """
  4. import sys
  5.  
  6. from collections import namedtuple
  7. from itertools import cycle
  8.  
  9. from advent_tools import get_daily_input
  10.  
  11. DAY = 24
  12.  
  13. TEST = sys.argv[1] == "test" if len(sys.argv) > 1 else False
  14.  
  15. TEST_DATA = """
  16. #.######
  17. #>>.<^<#
  18. #.<..<<#
  19. #>v.><>#
  20. #<^v^^>#
  21. ######.#
  22. """
  23.  
  24. if TEST:
  25.     def get_daily_input(_):
  26.         for line in TEST_DATA.strip().split("\n"):
  27.             yield line.strip("\n")
  28.  
  29.  
  30. class BlizzardBasin:
  31.     Position = namedtuple("Position", "x y")
  32.  
  33.     def __init__(self, map_state: list[list[str]]) -> None:
  34.         self.map_frames = self.prerender_frames(map_state)
  35.         self.map_frame_cycle = cycle(self.map_frames)
  36.         self.height, self.width = len(map_state), len(map_state[0])
  37.         self.start = self.Position(0, map_state[0].index("."))
  38.         self.end = self.Position(len(map_state) - 1, map_state[-1].index("."))
  39.  
  40.     def walk(self, a: Position, b: Position) -> int:
  41.         steps = 0
  42.         reachable = {a: 0}
  43.         while b not in reachable:
  44.             next_reachable = {}
  45.             steps += 1
  46.             frame = next(self.map_frame_cycle)
  47.             for k, v in reachable.items():
  48.                 for x, y in [(-1, 0), (1, 0), (0, -1), (0, 1), (0, 0)]:
  49.                     pos = self.Position(k.x + x, k.y + y)
  50.                     if (pos.x < self.height and pos.y < self.width
  51.                             and frame[pos.x][pos.y] == "."):
  52.                         next_reachable[pos] = v + 1
  53.             reachable = next_reachable
  54.         return steps
  55.  
  56.     @classmethod
  57.     def get_next(cls, map_state: list[list[str]]) -> list[list[str]]:
  58.         cropped_map = [[r[-2]] + r[1:-1] + [r[1]]
  59.                        for r in [map_state[-2]] + map_state[1:-1] + [map_state[1]]]
  60.         new_data = [map_state[0]]
  61.         for i in range(1, len(cropped_map) - 1):
  62.             new_row = ["#"]
  63.             for j in range(1, len(cropped_map[i]) - 1):
  64.                 new_row.append(".".join([w for w, x, y in
  65.                                          [("v", -1, 0), ("^", 1, 0),
  66.                                           (">", 0, -1), ("<", 0, 1)] if
  67.                                          w in cropped_map[i + x][j + y]]) or ".")
  68.             new_data.append(new_row + ["#"])
  69.         return new_data + [map_state[-1]]
  70.  
  71.     @classmethod
  72.     def prerender_frames(cls, map_state: list[list[str]]) -> list[list[list[str]]]:
  73.         frames: list[list[list[str]]] = []
  74.         next_data = cls.get_next(map_state)
  75.         while next_data != map_state:
  76.             frames.append(next_data)
  77.             next_data = cls.get_next(next_data)
  78.         frames.append(map_state)
  79.         return frames
  80.  
  81.  
  82. def load_data() -> list[list[str]]:
  83.     return [[c for c in i] for i in get_daily_input(DAY)]
  84.  
  85.  
  86. def main():
  87.     bb = BlizzardBasin(load_data())
  88.  
  89.     part_1 = bb.walk(bb.start, bb.end)
  90.     print(f"Part 1: {part_1}")
  91.  
  92.     part_2 = part_1 + bb.walk(bb.end, bb.start) + bb.walk(bb.start, bb.end)
  93.     print(f"Part 2: {part_2}")
  94.  
  95.  
  96. if __name__ == "__main__":
  97.     main()
  98.  
Advertisement
Add Comment
Please, Sign In to add comment