159 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			159 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| 
 | |
| 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):
 | |
|     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)
 | |
| 
 | |
|     minutes = 24
 | |
|     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]:
 | |
|             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])
 | |
| 
 | |
|         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
 | |
| 
 | |
| assert solve(sample) == 33
 | |
| solve(input)
 | |
| 
 |