Advertisement
illuminati229

AoC 2023 Day 17

Dec 19th, 2023
1,247
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.16 KB | None | 0 0
  1. from time import time
  2. from heapq import heappop, heappush
  3.  
  4.  
  5. def timer_func(func):
  6.     # This function shows the execution time of
  7.     # the function object passed
  8.     def wrap_func(*args, **kwargs):
  9.         t1 = time()
  10.         result = func(*args, **kwargs)
  11.         t2 = time()
  12.         print(f'Function {func.__name__!r} executed in {(t2 - t1):.4f}s')
  13.         return result
  14.  
  15.     return wrap_func
  16.  
  17.  
  18. class Grid2d:
  19.     def __init__(self, grid):
  20.         self.grid = grid
  21.         self.height = len(grid)
  22.         self.width = len(grid[0])
  23.  
  24.     def __getitem__(self, item):
  25.         # returns None if outside the grid
  26.         if len(item) > 2:
  27.             raise ValueError('Grid2D expected a list like of length 2. Length of item longer than expected')
  28.         x, y = item
  29.         if 0 <= x < self.height:
  30.             if 0 <= y < self.width:
  31.                 return self.grid[x][y]
  32.         return None
  33.  
  34.  
  35. def opposites(a, b):
  36.     if (a, b) in [('r', 'l'), ('l', 'r')]:
  37.         return True
  38.     if (a, b) in [('u', 'd'), ('d', 'u')]:
  39.         return True
  40.     return False
  41.  
  42.  
  43. @timer_func
  44. def day17(filepath, part2=False):
  45.     with open(filepath) as fin:
  46.         lines = [line.strip() for line in fin.readlines()]
  47.     dirs = {'r': (0, 1),
  48.             'd': (1, 0),
  49.             'l': (0, -1),
  50.             'u': (-1, 0)}
  51.     grid = Grid2d(lines)
  52.     h = [(0, (0, 0), ('r', 0))]  # heap (heat loss, (x, y), (current direction, steps taken in that direction)
  53.     if part2:
  54.         heappush(h, (0, (0, 0), ('d', 0)))
  55.     v = {((0, 0), ('r', 0)): 0}  # visited nodes
  56.  
  57.     while h:
  58.         hl, (x, y), (hd, hs) = heappop(h)
  59.         # check in all directions
  60.         for d, (dx, dy) in dirs.items():
  61.             # get the grid value in that direction
  62.             w = grid[(x + dx, y + dy)]
  63.             # if the grid value exists
  64.             if w:
  65.                 w = int(w)
  66.                 if part2:
  67.                     if (d == hd and hs == 10) or opposites(d, hd):
  68.                         # skip this heading if we have taken the 10 steps already
  69.                         continue
  70.                     if hs < 4 and d != hd:
  71.                         continue
  72.                 else:
  73.                     # check to see if we have done three steps in that direction already
  74.                     # or if the direction is the opposite of the current heading
  75.                     if (d == hd and hs == 3) or opposites(d, hd):
  76.                         # skip this heading if we have taken the 3 steps already
  77.                         continue
  78.                     # check to see if we are heading in the same direction
  79.                 if d == hd:
  80.                     # increase the heading step by 1
  81.                     nhs = hs + 1
  82.                 else:
  83.                     # reset to 1 if a different direction
  84.                     nhs = 1
  85.                 if ((x + dx, y + dy), (d, nhs)) in v:
  86.                     # get the current hl value
  87.                     chl = v[((x + dx, y + dy), (d, nhs))]
  88.                 else:
  89.                     # else the value is inf
  90.                     chl = float('inf')
  91.                 # check to see if this value is lower than the current
  92.                 # (looking at a new point will always trip this, since its value is inf
  93.                 if hl + w < chl:
  94.                     # if it is heading the same direction
  95.                     if d == hd:
  96.                         # increase the heading step by 1
  97.                         nhs = hs + 1
  98.                     else:
  99.                         # reset to 1 if a different direction
  100.                         nhs = 1
  101.                     # add/update the visited points
  102.                     v[(x + dx, y + dy), (d, nhs)] = hl + w
  103.                     # add the point to the heap
  104.                     heappush(h, (hl + w, (x + dx, y + dy), (d, nhs)))
  105.  
  106.     ends = [hl for ((x, y), _), hl in v.items() if (x, y) == (grid.height - 1, grid.width - 1)]
  107.     ans = min(ends)
  108.     return ans
  109.  
  110.  
  111. def main():
  112.     assert day17('test17') == 102
  113.     print(f"Part 1: {day17('input17')}")
  114.  
  115.     assert day17('test17', True) == 94
  116.     print(f"Part 2: {day17('input17', True)}")
  117.  
  118.  
  119. if __name__ == '__main__':
  120.     main()
  121.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement