import math import re sample = { 1:{ 'ore': [4, 0, 0, 0], 'clay': [2, 0, 0, 0], 'obsidian': [3, 14, 0, 0], 'geode': [2, 0, 7, 0], }, 2:{ 'ore': [2, 0, 0, 0], 'clay': [3, 0, 0, 0], 'obsidian': [3, 8, 0, 0], 'geode': [3, 0, 12, 0], }} robot_number = {'ore': 0, 'clay': 1, 'obsidian': 2, 'geode': 3, 'nothing': 99} def parse(line): line = re.sub(r'[^\d]+', ' ', line) idx, ore1, ore2, ore3, clay3, ore4, obs4 = map(int, line.split()) return idx, { 'ore': [ore1, 0,0,0], 'clay': [ore2, 0,0,0], 'obsidian': [ore3,clay3,0,0], 'geode': [ore4,0,obs4,0], } def simulate(blueprint, minutes=24): B = blueprint resources = [0]*4 robots = [1,0,0,0] rmax = [max(x[i] for x in B.values()) for i in range(3)] + [99] worth = {} worth['ore'] = 1 worth['clay'] = worth['ore']*B['clay'][0] worth['obsidian'] = worth['ore']*B['obsidian'][0] + worth['clay']*B['obsidian'][1] worth['geode'] = worth['ore']*B['geode'][0] + worth['obsidian']*B['geode'][2] print(worth) B_items = list(B.items()) B_items.reverse() #B_items.append(('nothing', [0,0,0,0])) print(B_items) buckets = [[] for _ in range(minutes+1)] def enqueue(t, robots, resources): if t < 0 or t >= len(buckets): return #x = (resources[3], max(resources[3], robots[3]), max(resources[2], robots[2]), max(resources[1], robots[1]), max(resources[0], robots[0])) x = resources[3] #w = sum(worth[r]*robots[robot_number[r]] for r in worth) #x = tuple(reversed(resources+robots+[resources[3]])) #x = (resources[3], robots) #n = sum(x==0 for x in robots) #if n == 3: # x = (resources[0], robots[0]) #elif n == 2: # x = (resources[1], resources[0], robots[1], robots[0]) #elif n == 1: # x = (robots[3], min(resources[2],resources[0]), max(resources[2],resources[1]), robots[2], robots[1],robots[0]) #else: # x = (resources[3], min(resources[2],resources[0]), max(resources[2],resources[0]), resources[1]) buckets[t].append((x,robots, resources)) enqueue(minutes, robots, resources) del resources del robots max_geodes = 0 for _ in range(minutes): #next = [[] for _ in range(4)] buckets[minutes].sort(reverse=True) print(minutes, buckets[minutes][:1]) for _, robots, resources in buckets[minutes][:100000]: can_build = 0 if robots[3]: geodes = robots[3]*minutes + resources[3] if geodes > max_geodes: max_geodes = geodes for robot, cost in B_items: i = robot_number[robot] if robots[i] >= rmax[i]: # don't build more of 1 robot than we can spend in 1 minute continue # figure out how soon we can afford it wait = 0 for x,y,r in zip(resources, cost, robots): if y == 0: continue if r <= 0: wait = 9999 break if y > x: wait = max(wait, int(math.ceil((y - x)/r))) if wait > minutes: continue new_resources = [x+(wait+1)*r-y for x,y,r in zip(resources, cost, robots)] if robot != 'nothing': new_robots = list(robots) new_robots[i] += 1 else: new_robots = robots enqueue(minutes-wait-1, new_robots, new_resources) #print(len(next)) #limit = 2500 #q = [] #for bucket in next: # bucket.sort(reverse=True) # q.extend(bucket[:limit]) #count = sum(len(b) for b in next) #print(count, q[:1]) print(minutes, [len(x) for x in buckets]) buckets[minutes] = [] minutes -= 1 #print(buckets) #q = buckets[0] #print(q[0]) #return q[0][-1][-1] return max_geodes #simulate(blueprints[1]) input = {} with open('input') as f: for line in f: idx, bp = parse(line) input[idx] = bp def solve(input): t = 0 for idx, B in input.items(): g = simulate(B) t += idx*g print(idx, g) print("---") print(t) return t def solve2(input): t = 1 for idx, B in input.items(): if idx <= 3: g = simulate(B, minutes=32) t *= g print(t) return t #assert solve(sample) == 33 solve2(input)