day19 - p2 in sub 3min; still to be improved

This commit is contained in:
Stefan Harmuth 2022-12-21 16:18:50 +01:00
parent 265f481472
commit 6fdf2d55ff

View File

@ -1,10 +1,9 @@
from collections import defaultdict
from enum import Enum from enum import Enum
from heapq import heappush, heappop from heapq import heappush, heappop
from tools.aoc import AOCDay from tools.aoc import AOCDay
from typing import Any from typing import Any
from tools.int_seq import triangular
class Material(Enum): class Material(Enum):
ORE = 1 ORE = 1
@ -51,6 +50,12 @@ class Inventory:
new_inv.materials = self.materials.copy() new_inv.materials = self.materials.copy()
return new_inv return new_inv
def value(self) -> int:
return self.robots[Material.ORE] \
+ 2 * self.robots[Material.CLAY] \
+ 4 * self.robots[Material.OBSIDIAN] \
+ 8 * self.robots[Material.GEODE]
def __lt__(self, other: 'Inventory') -> bool: def __lt__(self, other: 'Inventory') -> bool:
return self.materials[Material.GEODE] < other.materials[Material.GEODE] return self.materials[Material.GEODE] < other.materials[Material.GEODE]
@ -84,21 +89,33 @@ def pass_minute(bp: Blueprint, inv: Inventory, ignore: list) -> (Inventory, list
return inv, could_build return inv, could_build
def get_bfs_quality(bp: Blueprint, max_time: int = 24) -> int: def get_dfs_quality(bp: Blueprint, max_time: int = 24) -> int:
q = [] q = []
max_geode = 0 max_geode = 0
max_value = defaultdict(int)
heappush(q, (max_time, Inventory(), [], 0)) heappush(q, (max_time, Inventory(), [], 0))
q_count = 0
while q: while q:
q_count += 1
time_left, inv, ignore, no_build = heappop(q) time_left, inv, ignore, no_build = heappop(q)
inv, could_build = pass_minute(bp, inv, ignore) inv, could_build = pass_minute(bp, inv, ignore)
time_left -= 1 time_left -= 1
inv_value = inv.value()
if inv_value < max_value[time_left] // 2.1:
continue
elif inv_value > max_value[time_left]:
max_value[time_left] = inv_value
if time_left == 0: if time_left == 0:
if inv.materials[Material.GEODE] > max_geode: if inv.materials[Material.GEODE] > max_geode:
max_geode = inv.materials[Material.GEODE] max_geode = inv.materials[Material.GEODE]
continue continue
if bp.robots[Material.GEODE] in could_build:
inv.build_robot(bp.robots[Material.GEODE])
heappush(q, (time_left, inv, [], 0))
continue
for robot in could_build: for robot in could_build:
if robot.min_viable > time_left: if robot.min_viable > time_left:
continue continue
@ -109,6 +126,7 @@ def get_bfs_quality(bp: Blueprint, max_time: int = 24) -> int:
if no_build < bp.max_cost[Material.ORE]: if no_build < bp.max_cost[Material.ORE]:
heappush(q, (time_left, inv, could_build, no_build + 1)) heappush(q, (time_left, inv, could_build, no_build + 1))
print(q_count)
return max_geode return max_geode
@ -119,7 +137,7 @@ class Day(AOCDay):
(1616, "input19"), (1616, "input19"),
], ],
[ [
#(56*62, "input19_test"), (3472, "input19_test"),
(8990, "input19"), (8990, "input19"),
] ]
] ]
@ -149,7 +167,7 @@ class Day(AOCDay):
blueprints = self.get_blueprints() blueprints = self.get_blueprints()
score = 0 score = 0
for b in blueprints: for b in blueprints:
quality = get_bfs_quality(b) quality = get_dfs_quality(b)
score += quality * b.bp_id score += quality * b.bp_id
print("BP", b.bp_id, "Q", quality, "S", score) print("BP", b.bp_id, "Q", quality, "S", score)
return score return score
@ -158,7 +176,7 @@ class Day(AOCDay):
blueprints = self.get_blueprints() blueprints = self.get_blueprints()
score = 1 score = 1
for b in blueprints[:3]: for b in blueprints[:3]:
quality = get_bfs_quality(b, 32) quality = get_dfs_quality(b, 32)
score *= quality score *= quality
print("BP", b.bp_id, "Q", quality, "S", score) print("BP", b.bp_id, "Q", quality, "S", score)
return score return score