123 lines
3.2 KiB
Python
123 lines
3.2 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}
|
|
|
|
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):
|
|
rmax = [max(x[i] for x in blueprint.values()) for i in range(3)] + [9999]
|
|
|
|
limit = None
|
|
if minutes >= 32:
|
|
limit = 100000
|
|
|
|
items = list(blueprint.items())
|
|
items.reverse()
|
|
|
|
print(items)
|
|
|
|
buckets = [[] for _ in range(minutes+1)]
|
|
def enqueue(t, robots, resources):
|
|
assert t > 0
|
|
if t <= 0 or t >= len(buckets):
|
|
return
|
|
x = resources[3]
|
|
buckets[t].append((x,robots, resources))
|
|
|
|
enqueue(minutes, robots=[1,0,0,0], resources=[0,0,0,0])
|
|
|
|
max_geodes = 0
|
|
|
|
for _ in range(minutes):
|
|
buckets[minutes].sort(reverse=True)
|
|
#print(minutes, buckets[minutes][:1])
|
|
for _, robots, resources in buckets[minutes][:limit]:
|
|
if robots[3]:
|
|
geodes = robots[3]*minutes + resources[3]
|
|
if geodes > max_geodes:
|
|
max_geodes = geodes
|
|
for robot, cost in 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+1 >= minutes:
|
|
continue
|
|
|
|
new_resources = [x+(wait+1)*r-y for x,y,r in zip(resources, cost, robots)]
|
|
new_robots = list(robots)
|
|
new_robots[i] += 1
|
|
enqueue(minutes-wait-1, new_robots, new_resources)
|
|
|
|
print(minutes, max_geodes, [len(x) for x in buckets[:minutes+1]])
|
|
buckets[minutes] = [] # clear old buckets to save memory
|
|
|
|
minutes -= 1
|
|
|
|
return max_geodes
|
|
|
|
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("blueprint", idx, "max geodes is", 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
|
|
#solve(input)
|
|
solve2(input)
|
|
|