illuminati229

AoC 2022 Day 19

Dec 27th, 2022
1,405
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 3.84 KB | None | 0 0
  1. from time import time
  2. from math import ceil, prod
  3. import numpy as np
  4. import re
  5.  
  6. ALL_BOTS = np.array([np.array([1, 0, 0, 0], dtype=int),
  7.                      np.array([0, 1, 0, 0], dtype=int),
  8.                      np.array([0, 0, 1, 0], dtype=int),
  9.                      np.array([0, 0, 0, 1], dtype=int)])
  10.  
  11.  
  12. def timer_func(func):
  13.     # This function shows the execution time of
  14.     # the function object passed
  15.     def wrap_func(*args, **kwargs):
  16.         t1 = time()
  17.         result = func(*args, **kwargs)
  18.         t2 = time()
  19.         print(f'Function {func.__name__!r} executed in {(t2 - t1):.4f}s')
  20.         return result
  21.  
  22.     return wrap_func
  23.  
  24.  
  25. @timer_func
  26. def day19(filepath, part2=False):
  27.     with open(filepath) as fin:
  28.         lines = fin.readlines()
  29.  
  30.     blueprints = {}
  31.     for line in lines:
  32.         r = re.findall(r'(\d+)', line)
  33.         cost_matrix = np.zeros((4, 4))
  34.         cost_matrix[0, 0] = int(r[1])
  35.         cost_matrix[0, 1] = int(r[2])
  36.         cost_matrix[0, 2] = int(r[3])
  37.         cost_matrix[1, 2] = int(r[4])
  38.         cost_matrix[0, 3] = int(r[5])
  39.         cost_matrix[2, 3] = int(r[6])
  40.         blueprints[int(r[0])] = cost_matrix
  41.  
  42.     max_geodes = []
  43.     for bp_id, cost_matrix in blueprints.items():
  44.         current_max = 0
  45.         if part2 and bp_id == 4:
  46.             break
  47.         resources = np.array([0, 0, 0, 0], dtype=int)
  48.         bots = np.array([1, 0, 0, 0], dtype=int)
  49.         if not part2:
  50.             initial_state = (24, resources, bots, None)
  51.         else:
  52.             initial_state = (32, resources, bots, None)
  53.         states = set()
  54.         q = [initial_state]
  55.         while q:
  56.             time_left, resources, bots, next_bot = q.pop()
  57.             if next_bot is not None:
  58.                 cost_for_next_bot = cost_matrix @ next_bot
  59.                 res_for_next_bot = cost_for_next_bot - resources
  60.                 time_for_next_bot = int(
  61.                     max([ceil(c / d) if (c > 0 and d > 0) else 0 for c, d in zip(res_for_next_bot, bots)])) + 1
  62.                 if time_left - time_for_next_bot <= 0:
  63.                     resources = resources + bots * time_left
  64.                     if resources[-1] > 0:
  65.                         states.add((time_left, tuple(resources.tolist()), tuple(bots.tolist())))
  66.                         current_max = max(current_max, resources[-1])
  67.                     continue
  68.                 resources = resources + time_for_next_bot * bots - cost_for_next_bot
  69.                 time_left = time_left - time_for_next_bot
  70.                 bots = bots + next_bot
  71.             if (time_left > 0 and
  72.                (resources[-1] + bots[-1] * time_left + (time_left - 1) * (time_left) // 2) > current_max):
  73.                 available_bots = ALL_BOTS[:((bots > 0).sum() + 1 if (bots > 0).sum() < 4 else 4)]
  74.                 rows_to_remove = []
  75.                 if bots[0] >= cost_matrix[0].max():
  76.                     rows_to_remove.append(0)
  77.                 if bots[1] >= cost_matrix[1, 2]:
  78.                     rows_to_remove.append(1)
  79.                 if bots[2] >= cost_matrix[2, 3]:
  80.                     rows_to_remove.append(2)
  81.                 available_bots = np.delete(available_bots, rows_to_remove, 0)
  82.                 for bot in available_bots:
  83.                     q.append((time_left, resources, bots, bot))
  84.         max_geode = int(max([res[3] for _, res, _ in states] + [0]))
  85.         if part2:
  86.             max_geodes.append(max_geode)
  87.         else:
  88.             max_geodes.append(bp_id * max_geode)
  89.     if not part2:
  90.         return sum(max_geodes)
  91.     else:
  92.         return prod(max_geodes)
  93.  
  94.  
  95. def main():
  96.     assert day19('test19') == 33
  97.     print(f"Part 1: {day19('input19')}")
  98.  
  99.     assert day19('test19', True) == 56 * 62
  100.     # print(f"Part 2 test: {day19('test19', True)}")
  101.     print(f"Part 2: {day19('input19', True)}")
  102.  
  103.  
  104. if __name__ == '__main__':
  105.     main()
  106.  
Advertisement
Add Comment
Please, Sign In to add comment