Advertisement
hhoppe

Advent of code 2022 day 16 A* pruning

Dec 16th, 2022
1,820
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 2.19 KB | None | 0 0
  1. def day16(s, *, part2=False):  # With A*-like pruning.
  2.   rate_of_node, dsts_of_node = {}, {}
  3.   for line in s.splitlines():
  4.     node, s_rate, *dsts = re.findall(r'([A-Z][A-Z]|[0-9]+)', line)
  5.     rate_of_node[node] = int(s_rate)
  6.     dsts_of_node[node] = dsts
  7.   assert rate_of_node['AA'] == 0  # As observed in input.
  8.   best_benefit_found = 0
  9.  
  10.   @functools.lru_cache(maxsize=None)
  11.   def possible_paths(node):  # BFS to return {node2: time if rate[node2] > 0}.
  12.     queue = collections.deque([(0, node)])
  13.     result = {}
  14.     while queue:
  15.       distance, node = queue.popleft()
  16.       for node2 in dsts_of_node[node]:
  17.         if node2 not in result:
  18.           result[node2] = distance + 2  # Add extra 1 for "time to turn on the valve".
  19.           queue.append((distance + 1, node2))
  20.     result = {node: time for node, time in result.items() if rate_of_node[node] > 0}
  21.     return result
  22.  
  23.   # Given workers located at `nodes`, with a subset of `enabled` nodes, worker 0 idle,
  24.   # and worker 1 still needing `other_working` time, compute the maximum benefit.
  25.   def compute_benefit(cur_benefit, time_left, enabled, nodes, other_working):
  26.     nonlocal best_benefit_found
  27.     benefit = cur_benefit
  28.     for dst, time in possible_paths(nodes[0]).items():
  29.       if dst not in enabled and time <= time_left:
  30.         nodes2, time_left2, other_working2 = (
  31.             ((nodes[1], dst), time_left - other_working, time - other_working)
  32.             if other_working < time else
  33.             ((dst, nodes[1]), time_left - time, other_working - time))
  34.         cur_benefit2 = cur_benefit + (time_left - time) * rate_of_node[dst]
  35.         optimistic_remaining = ((time_left * 2 - time - other_working + 3) * 40 if part2 else
  36.                                 (time_left - time + 3) * 60)
  37.         if cur_benefit2 + optimistic_remaining < best_benefit_found:  # A*-like pruning.
  38.           continue
  39.         candidate = compute_benefit(
  40.             cur_benefit2, time_left2, enabled | {dst}, nodes2, other_working2)
  41.         benefit = max(benefit, candidate)
  42.     best_benefit_found = max(best_benefit_found, benefit)
  43.     return benefit
  44.  
  45.   return compute_benefit(0, 26 if part2 else 30, set(), ('AA', 'AA'), 0 if part2 else 99)
  46.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement