Advertisement
HexTree

Advent of Code 2022 Day 19

Dec 19th, 2022
1,277
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 5.51 KB | Source Code | 0 0
  1. import re
  2. import math
  3.  
  4. class Mineral:
  5.     def __init__(self, ore=0, clay=0, obsidian=0):
  6.         self.ore = ore
  7.         self.clay = clay
  8.         self.obsidian = obsidian
  9.     def __le__(self, other):
  10.         return self.ore <= other.ore and self.clay <= other.clay and self.obsidian <= other.obsidian
  11.     def __add__(self, other):
  12.         return Mineral(self.ore + other.ore, self.clay + other.clay, self.obsidian + other.obsidian)
  13.     def __sub__(self, other):
  14.         return Mineral(self.ore - other.ore, self.clay - other.clay, self.obsidian - other.obsidian)
  15.     def __eq__(self, other):
  16.         return self.ore == other.ore and self.clay == other.clay and self.obsidian == other.obsidian
  17.     def __hash__(self):
  18.         return hash((self.ore, self.clay, self.obsidian))
  19.     def __mul__(self, other):
  20.         return Mineral(self.ore * other, self.clay * other, self.obsidian * other)
  21.  
  22. highest_time_so_far = 1
  23.  
  24. def quality_level(idnum, orebot_cost, claybot_cost, obsidianbot_cost, geodebot_cost, start_time):
  25.     global highest_time_so_far
  26.     harvest_rate = Mineral(ore=1)
  27.     highest_time_so_far = 1
  28.     table = {}
  29.     def max_geodes(harvest_rate, stock, remaining_time):
  30.         global highest_time_so_far
  31.         if remaining_time <= 0:
  32.             return 0
  33.         if (harvest_rate, stock, remaining_time) in table:
  34.             return table[(harvest_rate, stock, remaining_time)]
  35.         geode_yields = []
  36.         # geodebot
  37.         if harvest_rate.obsidian > 0:
  38.             time_until_build = max(int(math.ceil((geodebot_cost.ore - stock.ore) / harvest_rate.ore)),
  39.                                    int(math.ceil((geodebot_cost.obsidian - stock.obsidian) / harvest_rate.obsidian)))
  40.             time_until_build = max(0, time_until_build)
  41.             if time_until_build <= (remaining_time-2):
  42.                 geode_yields.append(remaining_time - (time_until_build+1) + max_geodes(harvest_rate, stock - geodebot_cost + harvest_rate*(time_until_build+1), remaining_time-(time_until_build+1)))
  43.         # obsidianbot
  44.         if harvest_rate.clay > 0:
  45.             time_until_build = max(int(math.ceil((obsidianbot_cost.ore - stock.ore) / harvest_rate.ore)),
  46.                                    int(math.ceil((obsidianbot_cost.clay - stock.clay) / harvest_rate.clay)))
  47.             time_until_build = max(0, time_until_build)
  48.             if time_until_build <= (remaining_time-4):
  49.                 geode_yields.append(max_geodes(harvest_rate+Mineral(obsidian=1), stock - obsidianbot_cost + harvest_rate*(time_until_build+1), remaining_time-(time_until_build+1)))
  50.         # claybot
  51.         if harvest_rate.clay <= max(cost.clay for cost in (orebot_cost, claybot_cost, obsidianbot_cost, geodebot_cost)):
  52.             time_until_build = int(math.ceil((claybot_cost.ore - stock.ore) / harvest_rate.ore))
  53.             time_until_build = max(0, time_until_build)
  54.             if time_until_build <= (remaining_time - 6):
  55.                 geode_yields.append(max_geodes(harvest_rate+Mineral(clay=1), stock - claybot_cost + harvest_rate*(time_until_build+1), remaining_time - (time_until_build+1)))
  56.         # orebot
  57.         if harvest_rate.ore <= max(cost.ore for cost in (orebot_cost, claybot_cost, obsidianbot_cost, geodebot_cost)):
  58.             time_until_build = int(math.ceil((orebot_cost.ore - stock.ore) / harvest_rate.ore))
  59.             time_until_build = max(0, time_until_build)
  60.             if time_until_build <= (remaining_time - 4):
  61.                 geode_yields.append(max_geodes(harvest_rate+Mineral(ore=1), stock - orebot_cost + harvest_rate*(time_until_build+1), remaining_time - (time_until_build+1)))
  62.  
  63.         best = max(geode_yields, default=0)
  64.         table[(harvest_rate, stock, remaining_time)] = best
  65.         # if remaining_time > highest_time_so_far:
  66.         #     print("time:", remaining_time)
  67.         #     highest_time_so_far = remaining_time
  68.         return best
  69.  
  70.     return idnum * max_geodes(harvest_rate, Mineral(), start_time)
  71.  
  72. # part 1
  73. total = 0
  74. pattern = r"Blueprint (\d+): Each ore robot costs (\d+) ore. Each clay robot costs (\d+) ore. Each obsidian robot costs (\d+) ore and (\d+) clay. Each geode robot costs (\d+) ore and (\d+) obsidian."
  75. with open('input', 'r') as f:
  76.     for line in f.readlines():
  77.         capture = re.search(pattern, line)
  78.         numbers = [int(x) for x in capture.groups()]
  79.         idnum = numbers[0]
  80.         orebot_cost = Mineral(ore=numbers[1])
  81.         claybot_cost = Mineral(ore=numbers[2])
  82.         obsidianbot_cost = Mineral(ore=numbers[3], clay=numbers[4])
  83.         geodebot_cost = Mineral(ore=numbers[5], obsidian=numbers[6])
  84.  
  85.         qual = quality_level(idnum, orebot_cost, claybot_cost, obsidianbot_cost, geodebot_cost, 24)
  86.         # print(idnum, qual)
  87.         total += qual
  88.  
  89. print("part 1:", total)
  90.  
  91. # part 2
  92. total = 1
  93. pattern = r"Blueprint (\d+): Each ore robot costs (\d+) ore. Each clay robot costs (\d+) ore. Each obsidian robot costs (\d+) ore and (\d+) clay. Each geode robot costs (\d+) ore and (\d+) obsidian."
  94. with open('input', 'r') as f:
  95.     for line in f.readlines()[:3]:
  96.         capture = re.search(pattern, line)
  97.         numbers = [int(x) for x in capture.groups()]
  98.         orebot_cost = Mineral(ore=numbers[1])
  99.         claybot_cost = Mineral(ore=numbers[2])
  100.         obsidianbot_cost = Mineral(ore=numbers[3], clay=numbers[4])
  101.         geodebot_cost = Mineral(ore=numbers[5], obsidian=numbers[6])
  102.  
  103.         qual = quality_level(1, orebot_cost, claybot_cost, obsidianbot_cost, geodebot_cost, 32)
  104.         # print(qual)
  105.         total *= qual
  106.  
  107. print("part 2:", total)
  108.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement