19_robots.py 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354
  1. #!/usr/bin/env python3
  2. import sys
  3. import re
  4. from math import ceil
  5. def parse_blueprint(line):
  6. ore_ore, clay_ore, obs_ore, obs_clay, geo_ore, geo_obs = \
  7. map(int, re.findall(r'\d+', line)[1:])
  8. return (
  9. (0, geo_obs, 0, geo_ore),
  10. (0, 0, obs_clay, obs_ore),
  11. (0, 0, 0, clay_ore),
  12. (0, 0, 0, ore_ore),
  13. )
  14. def max_geo(blueprint, time):
  15. work = [(time, (0, 0, 0, 0), (0, 0, 0, 1))]
  16. best = 0
  17. # We can only make 1 robot per turn so we should only produce the maximum of
  18. # any single material cost per turn.
  19. max_robots = [time] + [max(c[ty] for c in blueprint) for ty in range(1, 4)]
  20. while work:
  21. time, materials, robots = state = work.pop()
  22. final_geo = materials[0] + time * robots[0]
  23. # Best case we'll keep building a geo robot each turn from now on.
  24. # If even that is not enough to improve, ignore the state.
  25. if final_geo + sum(range(1, time)) < best:
  26. continue
  27. # Accumulate geodes in the remaining time, and try to improve by
  28. # building more robots.
  29. best = max(best, final_geo)
  30. for ty, cost in enumerate(blueprint):
  31. # Skip time until we have accumulated the material cost, then wait 1
  32. # turn for production. A very low default denominator approximates
  33. # infinite build time for robots requiring unproduced materials.
  34. build_time = 1 + max(ceil(max(c - m, 0) / (r or 0.0001))
  35. for c, m, r in zip(cost, materials, robots))
  36. if build_time < time and robots[ty] < max_robots[ty]:
  37. newmat = tuple(m + r * build_time - c
  38. for c, m, r in zip(cost, materials, robots))
  39. newrobots = tuple(r + (i == ty) for i, r in enumerate(robots))
  40. work.append((time - build_time, newmat, newrobots))
  41. return best
  42. blueprints = list(map(parse_blueprint, sys.stdin))
  43. print(sum((i + 1) * max_geo(bp, 24) for i, bp in enumerate(blueprints)))
  44. a, b, c = (max_geo(bp, 32) for bp in blueprints[:3])
  45. print(a * b * c)