import re from lib import get_data, str_to_ints from math import ceil data = get_data(__file__) p1 = 0 p2 = 1 for line in data.splitlines(): id = str_to_ints(line)[0] bps = [] maxmin = [0, 0, 0] for part in line.split(". "): bp = [] for amount, mineral in re.findall(r"(\d+) (\w+)", part): amount = int(amount) mi = ["ore", "clay", "obsidian", "geode"].index(mineral) bp.append((amount, mi)) maxmin[mi] = max(maxmin[mi], amount) bps.append(bp) def dfs(time, mins, bots, cache): if time == 0: return mins[3] key = (time, *mins, *bots) if key in cache: return cache[key] maxv = mins[3] + time * bots[3] for bi, recipe in enumerate(bps): if bi != 3 and bots[bi] >= maxmin[bi]: continue wait = 0 for ra, ri in recipe: if bots[ri] == 0: break wait = max(ceil((ra - mins[ri]) / bots[ri]), wait) else: remtime = time - wait - 1 if remtime <= 0: continue bots_ = list(bots) mins_ = [m + b * (wait + 1) for m, b in zip(mins, bots)] for ra, ri in recipe: mins_[ri] -= ra bots_[bi] += 1 for i in range(3): mins_[i] = min(mins_[i], maxmin[i] * remtime) v = dfs(remtime, tuple(mins_), tuple(bots_), cache) maxv = max(v, maxv) key = (time, *mins, *bots) cache[key] = maxv return maxv p1 += id * dfs(24, (0, 0, 0, 0), (1, 0, 0, 0), {}) if id < 4: p2 *= dfs(32, (0, 0, 0, 0), (1, 0, 0, 0), {}) print(p1) print(p2)