Advertisement
hhoppe

Advent of code 2023 day 23

Dec 23rd, 2023
679
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 2.07 KB | None | 0 0
  1. def day23_graph(s, part2):
  2.   grid = np.array([list(line) for line in s.splitlines()])
  3.   start_yx, target_yx = (0, 1), (grid.shape[0] - 1, grid.shape[1] - 2)
  4.  
  5.   def neighbors(yx):
  6.     y, x = yx
  7.     results = []
  8.     for dy, dx, ch in ((0, 1, '<'), (0, -1, '>'), (1, 0, '^'), (-1, 0, 'v')):
  9.       if part2 or grid[yx] != ch:
  10.         y2, x2 = y + dy, x + dx
  11.         if 0 <= y2 < len(grid) and grid[y2, x2] != '#':
  12.           results.append((y2, x2))
  13.     return results
  14.  
  15.   nodes = {yx for yx, ch in np.ndenumerate(grid) if ch != '#' and len(neighbors(yx)) > 2}
  16.   nodes |= {start_yx, target_yx}
  17.  
  18.   def get_paths(yx):
  19.     paths = {}
  20.     for yx2 in neighbors(yx):
  21.       path = [yx]
  22.       while yx2 not in nodes:
  23.         path.append(yx2)
  24.         candidates = [yx3 for yx3 in neighbors(yx2) if yx3 != path[-2]]
  25.         (yx2,) = candidates if candidates else (yx,)  # We use yx to signal no legal path.
  26.       if yx2 != yx:
  27.         paths[yx2] = path[1:] + [yx2]
  28.     return paths
  29.  
  30.   graph_yx = {yx: get_paths(yx) for yx in nodes}
  31.   ordered = sorted(graph_yx)
  32.   graph = [
  33.       [(ordered.index(yx2), len(path)) for yx2, path in graph_yx[yx].items()]
  34.       for i, yx in enumerate(ordered)
  35.   ]
  36.   start, target = ordered.index(start_yx), ordered.index(target_yx)
  37.   return graph, start, target
  38.  
  39.  
  40. @numba.njit
  41. def day23_length_of_longest_path(graph_array, start, target):
  42.   stack = [(start, 0, {start})]
  43.   max_length = 0
  44.  
  45.   while stack:
  46.     node, length, visited = stack.pop()
  47.     if node == target:
  48.       max_length = max(max_length, length)
  49.       continue
  50.     for node2, dist in graph_array[node]:
  51.       if node2 >= 0 and node2 not in visited:
  52.         stack.append((node2, length + dist, visited | {node2}))
  53.  
  54.   return max_length
  55.  
  56.  
  57. def day23(s, *, part2=False):
  58.   graph, start, target = day23_graph(s, part2)
  59.   graph_array = np.full((len(graph), 4, 2), -1)  # np.int16 is no faster.
  60.   for index, index2_paths in enumerate(graph):
  61.     if index2_paths:
  62.       graph_array[index, : len(index2_paths)] = index2_paths
  63.   return day23_length_of_longest_path(graph_array, start, target)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement