Advertisement
Guest User

Untitled

a guest
Dec 14th, 2022
294
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 2.82 KB | None | 0 0
  1. from collections import defaultdict
  2.  
  3.  
  4. class Point:
  5.  
  6.     def __init__(self, x:int, y:int):
  7.         self.x = x
  8.         self.y = y
  9.  
  10.     def __add__(self, other):
  11.         return (self.x + other.x, self.y + other.y)
  12.  
  13.     def delta(self, x=0, y=0):
  14.         return Point(self.x + x, self.y + y)
  15.  
  16.     def __eq__(self, other):
  17.         return self.x == other.x and self.y == other.y
  18.  
  19.     def __hash__(self):
  20.         return hash(f"{self.x},{self.y}")
  21.  
  22.     def __repr__(self):
  23.         return f"Vector({self.x},{self.y})"
  24.  
  25.  
  26. def get_limits(point_sequence)->tuple:
  27.     return (
  28.         min([i.x for i in point_sequence]),
  29.         max([i.x for i in point_sequence]),
  30.         min([i.y for i in point_sequence]),
  31.         max([i.y for i in point_sequence]),
  32.     )
  33.  
  34.  
  35. def get_map(path:str, start:Point)->defaultdict:
  36.     the_map = defaultdict(lambda: '.')
  37.     the_map[start] = '.'
  38.  
  39.     for l in open(path).readlines():
  40.         l = l.strip()
  41.         points = [[int(y) for y in x.split(',')] for x in l.split(' -> ')]
  42.  
  43.         for start, end in zip(points[:-1], points[1:]):
  44.             xmin, xmax, ymin, ymax = get_limits((Point(*start), Point(*end)))
  45.  
  46.             for x in range(xmin, xmax + 1):
  47.                 for y in range(ymin, ymax + 1):
  48.                     the_map[Point(x, y)] = '#'
  49.  
  50.     return the_map
  51.  
  52.  
  53. def visualize(the_map:defaultdict)->None:
  54.     xmin, xmax, ymin, ymax = get_limits(the_map.keys())
  55.  
  56.     for y in range(ymin, ymax + 1):
  57.         row = []
  58.         for x in range(xmin, xmax + 1):
  59.             row.append(the_map[Point(x, y)])
  60.  
  61.         print(*row, sep='')
  62.  
  63.  
  64. def add_sand_block(the_map:defaultdict, start:Point, max_depth:int=0)->bool:
  65.     if start.y >= max_depth:
  66.         the_map[start] = '#'
  67.         return False
  68.  
  69.     for c in (0, -1, 1):
  70.         target = start.delta(x=c, y=1)
  71.         if the_map[target] == '.':
  72.             return add_sand_block(the_map, target, max_depth)
  73.  
  74.     the_map[start] = 'O'
  75.     return True
  76.  
  77.  
  78. def part1(path:str, do_visualize:bool):
  79.     start = Point(500, 0)
  80.     the_map = get_map(path, start)
  81.     ymax = get_limits(the_map)[-1]
  82.     while add_sand_block(the_map, start, ymax):
  83.         pass
  84.  
  85.     if do_visualize:
  86.         visualize(the_map)
  87.  
  88.     print(count_sand(the_map))
  89.  
  90.  
  91. def count_sand(the_map:defaultdict)->int:
  92.     return len([i for i in the_map.values() if i == 'O'])
  93.  
  94.  
  95. def part2(path:str, do_visualize:bool):
  96.     start = Point(500, 0)
  97.     the_map = get_map(path, start)
  98.     ymax = get_limits(the_map)[-1]
  99.     while the_map[start] == '.':
  100.         add_sand_block(the_map, start, ymax + 2)
  101.  
  102.     if do_visualize:
  103.         visualize(the_map)
  104.     print(count_sand(the_map))
  105.  
  106.  
  107. if __name__ == '__main__':
  108.     part1('day14-example.txt', False),
  109.     part1('day14-real.txt', False)
  110.     part2('day14-example.txt', True),
  111.     part2('day14-real.txt', False),
  112.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement