Compare commits
7 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
ddebd26db2 | ||
|
01300e23b2 | ||
|
b8e2faa8c9 | ||
|
ea5b757180 | ||
|
89a71c175f | ||
|
9ffb332dea | ||
|
8167ab34c7 |
@@ -33,25 +33,28 @@ class Pipe(NamedTuple):
|
||||
return self.name
|
||||
|
||||
|
||||
def breadth_first_search(pipes: dict[str, Pipe], pipe_1: Pipe, pipe_2: Pipe) -> int:
|
||||
def breadth_first_search(pipes: dict[str, Pipe], pipe: Pipe) -> dict[Pipe, int]:
|
||||
"""
|
||||
Runs a BFS from the given pipe and return the shortest distance (in term of hops)
|
||||
to all other pipes.
|
||||
"""
|
||||
queue = [(0, pipe_1)]
|
||||
visited = set()
|
||||
distances: dict[Pipe, int] = {}
|
||||
|
||||
while queue:
|
||||
while len(distances) < len(pipes):
|
||||
distance, current = heapq.heappop(queue)
|
||||
|
||||
if current in visited:
|
||||
continue
|
||||
|
||||
visited.add(current)
|
||||
|
||||
if current == pipe_2:
|
||||
return distance
|
||||
distances[current] = distance
|
||||
|
||||
for tunnel in current.tunnels:
|
||||
heapq.heappush(queue, (distance + 1, pipes[tunnel]))
|
||||
|
||||
return -1
|
||||
return distances
|
||||
|
||||
|
||||
def update_with_better(
|
||||
@@ -141,8 +144,12 @@ for line in lines:
|
||||
# compute distances from one valve to any other
|
||||
distances: dict[tuple[Pipe, Pipe], int] = {}
|
||||
for pipe_1 in pipes.values():
|
||||
for pipe_2 in pipes.values():
|
||||
distances[pipe_1, pipe_2] = breadth_first_search(pipes, pipe_1, pipe_2)
|
||||
distances.update(
|
||||
{
|
||||
(pipe_1, pipe_2): distance
|
||||
for pipe_2, distance in breadth_first_search(pipes, pipe_1).items()
|
||||
}
|
||||
)
|
||||
|
||||
# valves with flow
|
||||
relevant_pipes = frozenset(pipe for pipe in pipes.values() if pipe.flow > 0)
|
||||
|
125
2022/day17.py
Normal file
125
2022/day17.py
Normal file
@@ -0,0 +1,125 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
|
||||
import sys
|
||||
from typing import Sequence, TypeVar
|
||||
|
||||
import numpy as np
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
def print_tower(tower: np.ndarray, out: str = "#"):
|
||||
print("-" * (tower.shape[1] + 2))
|
||||
non_empty = False
|
||||
for row in reversed(range(1, tower.shape[0])):
|
||||
if not non_empty and not tower[row, :].any():
|
||||
continue
|
||||
non_empty = True
|
||||
print("|" + "".join(out if c else "." for c in tower[row, :]) + "|")
|
||||
print("+" + "-" * tower.shape[1] + "+")
|
||||
|
||||
|
||||
def tower_height(tower: np.ndarray) -> int:
|
||||
return int(tower.shape[0] - tower[::-1, :].argmax(axis=0).min() - 1)
|
||||
|
||||
|
||||
def next_cycle(sequence: Sequence[T], index: int) -> tuple[T, int]:
|
||||
t = sequence[index]
|
||||
index = (index + 1) % len(sequence)
|
||||
return t, index
|
||||
|
||||
|
||||
ROCKS = [
|
||||
np.array([(0, 0), (0, 1), (0, 2), (0, 3)]),
|
||||
np.array([(0, 1), (1, 0), (1, 1), (1, 2), (2, 1)]),
|
||||
np.array([(0, 0), (0, 1), (0, 2), (1, 2), (2, 2)]),
|
||||
np.array([(0, 0), (1, 0), (2, 0), (3, 0)]),
|
||||
np.array([(0, 0), (0, 1), (1, 0), (1, 1)]),
|
||||
]
|
||||
|
||||
WIDTH = 7
|
||||
START_X = 2
|
||||
|
||||
EMPTY_BLOCKS = np.zeros((10, WIDTH), dtype=bool)
|
||||
|
||||
|
||||
def build_tower(
|
||||
n_rocks: int,
|
||||
jets: str,
|
||||
early_stop: bool = False,
|
||||
init: np.ndarray = np.ones(WIDTH, dtype=bool),
|
||||
) -> tuple[np.ndarray, int, int, dict[int, int]]:
|
||||
|
||||
tower = EMPTY_BLOCKS.copy()
|
||||
tower[0, :] = init
|
||||
|
||||
done_at: dict[tuple[int, int], int] = {}
|
||||
heights: dict[int, int] = {}
|
||||
i_jet, i_rock = 0, 0
|
||||
rock_count = 0
|
||||
|
||||
for rock_count in range(n_rocks):
|
||||
|
||||
if early_stop:
|
||||
if i_rock == 0 and (i_rock, i_jet) in done_at:
|
||||
break
|
||||
done_at[i_rock, i_jet] = rock_count
|
||||
|
||||
y_start = tower.shape[0] - tower[::-1, :].argmax(axis=0).min() + 3
|
||||
rock, i_rock = next_cycle(ROCKS, i_rock)
|
||||
|
||||
rock_y = rock[:, 0] + y_start
|
||||
rock_x = rock[:, 1] + START_X
|
||||
|
||||
if rock_y.max() >= tower.shape[0]:
|
||||
tower = np.concatenate([tower, EMPTY_BLOCKS], axis=0)
|
||||
|
||||
while True:
|
||||
|
||||
jet, i_jet = next_cycle(jets, i_jet)
|
||||
|
||||
dx = 0
|
||||
if jet == ">" and rock_x.max() < WIDTH - 1:
|
||||
dx = 1
|
||||
elif jet == "<" and rock_x.min() > 0:
|
||||
dx = -1
|
||||
|
||||
if dx != 0 and not tower[rock_y, rock_x + dx].any():
|
||||
rock_x = rock_x + dx
|
||||
|
||||
# move down
|
||||
rock_y -= 1
|
||||
|
||||
if tower[rock_y, rock_x].any():
|
||||
rock_y += 1
|
||||
break
|
||||
|
||||
heights[rock_count] = tower_height(tower)
|
||||
tower[rock_y, rock_x] = True
|
||||
|
||||
return tower, rock_count, done_at.get((i_rock, i_jet), -1), heights
|
||||
|
||||
|
||||
line = sys.stdin.read().strip()
|
||||
|
||||
tower, *_ = build_tower(2022, line)
|
||||
answer_1 = tower_height(tower)
|
||||
print(f"answer 1 is {answer_1}")
|
||||
|
||||
TOTAL_ROCKS = 1_000_000_000_000
|
||||
tower_1, n_rocks_1, prev_1, heights_1 = build_tower(TOTAL_ROCKS, line, True)
|
||||
assert prev_1 > 0
|
||||
|
||||
# 2767 1513
|
||||
remaining_rocks = TOTAL_ROCKS - n_rocks_1
|
||||
n_repeat_rocks = n_rocks_1 - prev_1
|
||||
n_repeat_towers = remaining_rocks // n_repeat_rocks
|
||||
|
||||
base_height = heights_1[prev_1]
|
||||
repeat_height = heights_1[prev_1 + n_repeat_rocks - 1] - heights_1[prev_1]
|
||||
remaining_height = (
|
||||
heights_1[prev_1 + remaining_rocks % n_repeat_rocks] - heights_1[prev_1]
|
||||
)
|
||||
|
||||
answer_2 = base_height + (n_repeat_towers + 1) * repeat_height + remaining_height
|
||||
print(f"answer 2 is {answer_2}")
|
53
2022/day18.py
Normal file
53
2022/day18.py
Normal file
@@ -0,0 +1,53 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
|
||||
import sys
|
||||
from typing import FrozenSet
|
||||
|
||||
import numpy as np
|
||||
|
||||
xyz = np.asarray(
|
||||
[
|
||||
tuple(int(x) for x in row.split(",")) # type: ignore
|
||||
for row in sys.stdin.read().splitlines()
|
||||
]
|
||||
)
|
||||
|
||||
xyz = xyz - xyz.min(axis=0) + 1
|
||||
|
||||
cubes = np.zeros(xyz.max(axis=0) + 3, dtype=bool)
|
||||
cubes[xyz[:, 0], xyz[:, 1], xyz[:, 2]] = True
|
||||
|
||||
n_dims = len(cubes.shape)
|
||||
|
||||
faces = [(-1, 0, 0), (1, 0, 0), (0, -1, 0), (0, 1, 0), (0, 0, -1), (0, 0, 1)]
|
||||
|
||||
answer_1 = sum(
|
||||
1 for x, y, z in xyz for dx, dy, dz in faces if not cubes[x + dx, y + dy, z + dz]
|
||||
)
|
||||
print(f"answer 1 is {answer_1}")
|
||||
|
||||
visited = np.zeros_like(cubes, dtype=bool)
|
||||
queue = [(0, 0, 0)]
|
||||
|
||||
n_faces = 0
|
||||
while queue:
|
||||
x, y, z = queue.pop(0)
|
||||
|
||||
if visited[x, y, z]:
|
||||
continue
|
||||
|
||||
visited[x, y, z] = True
|
||||
|
||||
for dx, dy, dz in faces:
|
||||
nx, ny, nz = x + dx, y + dy, z + dz
|
||||
if not all(n >= 0 and n < cubes.shape[i] for i, n in enumerate((nx, ny, nz))):
|
||||
continue
|
||||
|
||||
if visited[nx, ny, nz]:
|
||||
continue
|
||||
|
||||
if cubes[nx, ny, nz]:
|
||||
n_faces += 1
|
||||
else:
|
||||
queue.append((nx, ny, nz))
|
||||
print(f"answer 2 is {n_faces}")
|
487
2022/day19.py
Normal file
487
2022/day19.py
Normal file
@@ -0,0 +1,487 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
|
||||
import heapq
|
||||
import math
|
||||
import sys
|
||||
import time
|
||||
from collections import defaultdict
|
||||
from typing import Literal, TypedDict
|
||||
|
||||
import numpy as np
|
||||
from tqdm import tqdm
|
||||
|
||||
Reagent = Literal["ore", "clay", "obsidian", "geode"]
|
||||
REAGENTS: tuple[Reagent] = (
|
||||
"ore",
|
||||
"clay",
|
||||
"obsidian",
|
||||
"geode",
|
||||
)
|
||||
|
||||
IntOfReagent = dict[Reagent, int]
|
||||
|
||||
lines = sys.stdin.read().splitlines()
|
||||
|
||||
blueprints: list[dict[Reagent, IntOfReagent]] = [
|
||||
{
|
||||
"ore": {"ore": 4},
|
||||
"clay": {"ore": 2},
|
||||
"obsidian": {"ore": 3, "clay": 14},
|
||||
"geode": {"ore": 2, "obsidian": 7},
|
||||
},
|
||||
{
|
||||
"ore": {"ore": 2},
|
||||
"clay": {"ore": 3},
|
||||
"obsidian": {"ore": 3, "clay": 8},
|
||||
"geode": {"ore": 3, "obsidian": 12},
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
class State:
|
||||
robots: IntOfReagent
|
||||
reagents: IntOfReagent
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
robots: IntOfReagent | None = None,
|
||||
reagents: IntOfReagent | None = None,
|
||||
):
|
||||
if robots is None:
|
||||
assert reagents is None
|
||||
self.reagents = {reagent: 0 for reagent in REAGENTS}
|
||||
self.robots = {reagent: 0 for reagent in REAGENTS}
|
||||
self.robots["ore"] = 1
|
||||
else:
|
||||
assert robots is not None and reagents is not None
|
||||
self.robots = robots
|
||||
self.reagents = reagents
|
||||
|
||||
def __eq__(self, other) -> bool:
|
||||
return (
|
||||
isinstance(other, State)
|
||||
and self.robots == other.robots
|
||||
and self.reagents == other.reagents
|
||||
)
|
||||
|
||||
def __lt__(self, other) -> bool:
|
||||
return isinstance(other, State) and tuple(
|
||||
(self.robots[r], self.reagents[r]) for r in REAGENTS
|
||||
) > tuple((other.robots[r], other.reagents[r]) for r in REAGENTS)
|
||||
|
||||
def __hash__(self) -> int:
|
||||
return hash(tuple((self.robots[r], self.reagents[r]) for r in REAGENTS))
|
||||
|
||||
def __str__(self) -> str:
|
||||
return "State({}, {})".format(
|
||||
"/".join(str(self.robots[k]) for k in REAGENTS),
|
||||
"/".join(str(self.reagents[k]) for k in REAGENTS),
|
||||
)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return str(self)
|
||||
|
||||
|
||||
def dominates(lhs: State, rhs: State):
|
||||
return all(
|
||||
lhs.robots[r] >= rhs.robots[r] and lhs.reagents[r] >= rhs.reagents[r]
|
||||
for r in REAGENTS
|
||||
)
|
||||
|
||||
|
||||
MAX_TIME = 24
|
||||
blueprint = blueprints[1]
|
||||
|
||||
# parents: dict[State, tuple[State | None, int]] = {State(): (None, 0)}
|
||||
# queue = [(0, State())]
|
||||
# visited: set[State] = set()
|
||||
# at_time: dict[int, list[State]] = defaultdict(lambda: [])
|
||||
|
||||
# while queue:
|
||||
# time, state = heapq.heappop(queue)
|
||||
# if state in visited:
|
||||
# continue
|
||||
|
||||
# print(time, state)
|
||||
|
||||
# visited.add(state)
|
||||
|
||||
# at_time[time].append(state)
|
||||
|
||||
# if time > MAX_TIME:
|
||||
# continue
|
||||
|
||||
# if len(queue) % 200 == 0:
|
||||
# print(len(queue), len(visited), time)
|
||||
|
||||
# can_build_any: bool = False
|
||||
# for reagent in REAGENTS:
|
||||
# needed = blueprint[reagent]
|
||||
|
||||
# if any(state.robots[r] == 0 for r in needed):
|
||||
# continue
|
||||
|
||||
# time_to_complete = max(
|
||||
# max(
|
||||
# math.ceil((needed[r] - state.reagents[r]) / state.robots[r])
|
||||
# for r in needed
|
||||
# ),
|
||||
# 0,
|
||||
# )
|
||||
|
||||
# # if time_to_complete != 0:
|
||||
# # continue
|
||||
|
||||
# if time + time_to_complete + 1 > MAX_TIME:
|
||||
# continue
|
||||
|
||||
# wait = time_to_complete + 1
|
||||
|
||||
# reagents = {
|
||||
# r: state.reagents[r] + wait * state.robots[r] - needed.get(r, 0)
|
||||
# for r in REAGENTS
|
||||
# }
|
||||
|
||||
# robots = state.robots.copy()
|
||||
# robots[reagent] += 1
|
||||
|
||||
# state_2 = State(reagents=reagents, robots=robots)
|
||||
|
||||
# if state_2 in visited:
|
||||
# continue
|
||||
|
||||
# if any(dominates(state_v, state_2) for state_v in at_time[time + wait]):
|
||||
# continue
|
||||
|
||||
# # print(time + wait)
|
||||
# # if any(dominates(state_3, state_2) for state_3 in at_time[time + wait]):
|
||||
# # print("?")
|
||||
# # continue
|
||||
|
||||
# if state_2 not in parents or parents[state_2][1] > time + wait:
|
||||
# parents[state_2] = (state, time + wait)
|
||||
# heapq.heappush(queue, (time + wait, state_2))
|
||||
# can_build_any = True
|
||||
# at_time[time + wait].append(state_2)
|
||||
|
||||
# if not can_build_any:
|
||||
# state_2 = State(
|
||||
# reagents={
|
||||
# r: state.reagents[r] + state.robots[r] * (MAX_TIME - time)
|
||||
# for r in REAGENTS
|
||||
# },
|
||||
# robots=state.robots,
|
||||
# )
|
||||
|
||||
# if state_2 in visited:
|
||||
# continue
|
||||
|
||||
# if state_2 not in parents or parents[state_2][1] > time + wait:
|
||||
# parents[state_2] = (state, MAX_TIME)
|
||||
# heapq.heappush(queue, (MAX_TIME, state_2))
|
||||
|
||||
# print(len(visited))
|
||||
# print(max(state.reagents["geode"] for state in visited))
|
||||
|
||||
# exit()
|
||||
|
||||
# while states:
|
||||
# state = states.pop()
|
||||
# processed.append(state)
|
||||
|
||||
# if state.time > MAX_TIME:
|
||||
# continue
|
||||
|
||||
# if len(states) % 100 == 0:
|
||||
# print(len(states), len(processed), min((s.time for s in states), default=1))
|
||||
|
||||
# can_build_any: bool = False
|
||||
# for reagent in REAGENTS:
|
||||
# needed = blueprint[reagent]
|
||||
|
||||
# if any(state.robots[r] == 0 for r in needed):
|
||||
# continue
|
||||
|
||||
# time_to_complete = max(
|
||||
# max(
|
||||
# math.ceil((needed[r] - state.reagents[r]) / state.robots[r])
|
||||
# for r in needed
|
||||
# ),
|
||||
# 0,
|
||||
# )
|
||||
|
||||
# if state.time + time_to_complete + 1 > MAX_TIME:
|
||||
# continue
|
||||
|
||||
# wait = time_to_complete + 1
|
||||
|
||||
# reagents = {
|
||||
# r: state.reagents[r] + wait * state.robots[r] - needed.get(r, 0)
|
||||
# for r in REAGENTS
|
||||
# }
|
||||
|
||||
# robots = state.robots.copy()
|
||||
# robots[reagent] += 1
|
||||
|
||||
# can_build_any = True
|
||||
# state_2 = State(time=state.time + wait, reagents=reagents, robots=robots)
|
||||
# # print(f"{state} -> {state_2}")
|
||||
# states.add(state_2)
|
||||
|
||||
# if not any(dominates(s2, state_2) for s2 in states):
|
||||
# states.add(state)
|
||||
|
||||
# # print(f"can build {reagent} in {time_to_complete}")
|
||||
|
||||
# if not can_build_any:
|
||||
# states.add(
|
||||
# State(
|
||||
# time=MAX_TIME + 1,
|
||||
# reagents={
|
||||
# r: state.reagents[r] + state.robots[r] * (MAX_TIME - state.time)
|
||||
# for r in REAGENTS
|
||||
# },
|
||||
# robots=state.robots,
|
||||
# )
|
||||
# )
|
||||
|
||||
# if len(states) % 1000 == 0:
|
||||
# print("filtering")
|
||||
# states = {
|
||||
# s1
|
||||
# for s1 in states
|
||||
# if not any(dominates(s2, s1) for s2 in states if s2 is not s1)
|
||||
# }
|
||||
|
||||
# # if len(states) > 4:
|
||||
# # break
|
||||
|
||||
# # break
|
||||
|
||||
# print(len(processed))
|
||||
# print(max(state.reagents["geode"] for state in processed))
|
||||
|
||||
# exit()
|
||||
|
||||
# for t in range(1, 25):
|
||||
# states = set()
|
||||
# for state in state_after_t[t - 1]:
|
||||
# robots_that_can_be_built = [
|
||||
# robot
|
||||
# for robot in REAGENTS
|
||||
# if all(
|
||||
# state.reagents[reagent] >= blueprint[robot].get(reagent, 0)
|
||||
# for reagent in REAGENTS
|
||||
# )
|
||||
# ]
|
||||
|
||||
# new_states = set()
|
||||
|
||||
# # new reagents
|
||||
# reagents = {
|
||||
# reagent: state.reagents[reagent] + state.robots[reagent]
|
||||
# for reagent in REAGENTS
|
||||
# }
|
||||
|
||||
# # if we can build anything, there is no point in waiting
|
||||
# if len(robots_that_can_be_built) != len(REAGENTS):
|
||||
# new_states.add(State(robots=state.robots, reagents=reagents))
|
||||
|
||||
# for robot in robots_that_can_be_built:
|
||||
# robots = state.robots.copy()
|
||||
# robots[robot] += 1
|
||||
# reagents = {
|
||||
# reagent: state.reagents[reagent]
|
||||
# + state.robots[reagent]
|
||||
# - blueprint[robot].get(reagent, 0)
|
||||
# for reagent in REAGENTS
|
||||
# }
|
||||
# new_states.add(State(robots=robots, reagents=reagents))
|
||||
|
||||
# new_states = [
|
||||
# s1
|
||||
# for s1 in new_states
|
||||
# if not any(s1 is not s2 and dominates(s2, s1) for s2 in new_states)
|
||||
# ]
|
||||
|
||||
# states = {
|
||||
# s1 for s1 in states if not any(dominates(s2, s1) for s2 in new_states)
|
||||
# }
|
||||
# states.update(new_states)
|
||||
|
||||
# state_after_t[t] = states
|
||||
|
||||
# exit()
|
||||
|
||||
|
||||
MAX_TIME = 24
|
||||
blueprint = blueprints[0]
|
||||
|
||||
state_after_t: dict[int, list[State]] = {0: [State()]}
|
||||
|
||||
for t in range(1, 25):
|
||||
print(t, len(state_after_t[t - 1]))
|
||||
|
||||
bests_for_robots: dict[tuple[int, ...], list[State]] = {}
|
||||
bests_for_reagents: dict[tuple[int, ...], list[State]] = {}
|
||||
|
||||
state_after_t[t] = []
|
||||
|
||||
t1 = time.time()
|
||||
|
||||
for state in state_after_t[t - 1]:
|
||||
robots_that_can_be_built = [
|
||||
robot
|
||||
for robot in REAGENTS
|
||||
if all(
|
||||
state.reagents[reagent] >= blueprint[robot].get(reagent, 0)
|
||||
for reagent in REAGENTS
|
||||
)
|
||||
]
|
||||
|
||||
# print(t, robots_that_can_be_built)
|
||||
new_states: set[State] = set()
|
||||
|
||||
# new reagents
|
||||
reagents = {
|
||||
reagent: state.reagents[reagent] + state.robots[reagent]
|
||||
for reagent in REAGENTS
|
||||
}
|
||||
|
||||
# if we can build anything, there is no point in waiting
|
||||
new_states.add(State(robots=state.robots, reagents=reagents))
|
||||
|
||||
for robot in robots_that_can_be_built:
|
||||
robots = state.robots.copy()
|
||||
robots[robot] += 1
|
||||
reagents = {
|
||||
reagent: state.reagents[reagent]
|
||||
+ state.robots[reagent]
|
||||
- blueprint[robot].get(reagent, 0)
|
||||
for reagent in REAGENTS
|
||||
}
|
||||
new_states.add(State(robots=robots, reagents=reagents))
|
||||
|
||||
for s1 in new_states:
|
||||
r1 = tuple(s1.robots[r] for r in REAGENTS)
|
||||
if r1 not in bests_for_robots:
|
||||
bests_for_robots[r1] = [s1]
|
||||
else:
|
||||
is_dominated = False
|
||||
for s2 in bests_for_robots[r1]:
|
||||
if all(s2.reagents[r] >= s1.reagents[r] for r in REAGENTS):
|
||||
is_dominated = True
|
||||
break
|
||||
if not is_dominated:
|
||||
bests_for_robots[r1].append(s1)
|
||||
|
||||
r2 = tuple(s1.reagents[r] for r in REAGENTS)
|
||||
if r2 not in bests_for_reagents:
|
||||
bests_for_reagents[r2] = [s1]
|
||||
else:
|
||||
is_dominated = False
|
||||
for s2 in bests_for_reagents[r2]:
|
||||
if all(s2.robots[r] >= s1.robots[r] for r in REAGENTS):
|
||||
is_dominated = True
|
||||
break
|
||||
if not is_dominated:
|
||||
bests_for_reagents[r2].append(s1)
|
||||
# state_after_t[t].extend(new_states)
|
||||
|
||||
t2 = time.time()
|
||||
|
||||
for bests in bests_for_robots.values():
|
||||
dominated = [False for _ in range(len(bests))]
|
||||
for i_s1, s1 in enumerate(bests):
|
||||
if dominated[i_s1]:
|
||||
continue
|
||||
for i_s2, s2 in enumerate(bests[i_s1 + 1 :], start=i_s1 + 1):
|
||||
if dominated[i_s2]:
|
||||
continue
|
||||
if all(s1.reagents[r] >= s2.reagents[r] for r in REAGENTS):
|
||||
dominated[i_s2] = True
|
||||
state_after_t[t].extend(
|
||||
s1 for i_s1, s1 in enumerate(bests) if not dominated[i_s1]
|
||||
)
|
||||
for bests in bests_for_reagents.values():
|
||||
dominated = [False for _ in range(len(bests))]
|
||||
for i_s1, s1 in enumerate(bests):
|
||||
if dominated[i_s1]:
|
||||
continue
|
||||
for i_s2, s2 in enumerate(bests[i_s1 + 1 :], start=i_s1 + 1):
|
||||
if dominated[i_s2]:
|
||||
continue
|
||||
if all(s1.robots[r] >= s2.robots[r] for r in REAGENTS):
|
||||
dominated[i_s2] = True
|
||||
state_after_t[t].extend(
|
||||
s1 for i_s1, s1 in enumerate(bests) if not dominated[i_s1]
|
||||
)
|
||||
|
||||
t3 = time.time()
|
||||
|
||||
np_states = np.array(
|
||||
[
|
||||
[state.robots[r] for r in REAGENTS] + [state.reagents[r] for r in REAGENTS]
|
||||
for state in state_after_t[t]
|
||||
]
|
||||
)
|
||||
dominated = np.zeros(len(np_states), dtype=bool)
|
||||
|
||||
t4 = time.time()
|
||||
|
||||
# c = (np_states[None, :, :] <= np_states[:, None, :]).all(axis=-1)
|
||||
# c[np.arange(len(np_states)), np.arange(len(np_states))] = False
|
||||
# dominated = c.any(axis=0)
|
||||
|
||||
for i in range(len(np_states)):
|
||||
if dominated[i]:
|
||||
continue
|
||||
dominated[i] = not (np_states[i + 1 :] <= np_states[i]).any(axis=1)
|
||||
|
||||
dominated[i + 1 :] = (np_states[i + 1 :] <= np_states[i]).all(axis=1)
|
||||
|
||||
t5 = time.time()
|
||||
|
||||
state_after_t[t] = list(np.array(state_after_t[t])[~dominated])
|
||||
|
||||
t6 = time.time()
|
||||
|
||||
print(
|
||||
"->",
|
||||
t,
|
||||
len(state_after_t[t]),
|
||||
dominated.sum(),
|
||||
t2 - t1,
|
||||
t3 - t2,
|
||||
t4 - t3,
|
||||
t5 - t4,
|
||||
t6 - t5,
|
||||
)
|
||||
|
||||
# print("->", len(state_after_t[t]))
|
||||
|
||||
# dominated = [False for _ in range(len(state_after_t[t]))]
|
||||
# keep = set()
|
||||
# for i_s1, s1 in enumerate(tqdm(state_after_t[t])):
|
||||
# if dominated[i_s1]:
|
||||
# continue
|
||||
# for i_s2, s2 in enumerate(state_after_t[t][i_s1 + 1 :], start=i_s1 + 1):
|
||||
# if dominated[i_s2]:
|
||||
# continue
|
||||
|
||||
# if dominates(s1, s2):
|
||||
# dominated[i_s2] = True
|
||||
# elif dominates(s2, s1):
|
||||
# dominated[i_s1] = True
|
||||
# break
|
||||
|
||||
# if not dominated[i_s1]:
|
||||
# keep.add(s1)
|
||||
|
||||
# state_after_t[t] = list(keep)
|
||||
|
||||
# print(len(state_after_t[t]))
|
||||
# print(sum(dominated))
|
||||
# break
|
||||
|
||||
print(max(state.reagents["geode"] for state in state_after_t[24]))
|
1
2022/inputs/day17.txt
Normal file
1
2022/inputs/day17.txt
Normal file
File diff suppressed because one or more lines are too long
2150
2022/inputs/day18.txt
Normal file
2150
2022/inputs/day18.txt
Normal file
File diff suppressed because it is too large
Load Diff
1
2022/tests/day17.txt
Normal file
1
2022/tests/day17.txt
Normal file
@@ -0,0 +1 @@
|
||||
>>><<><>><<<>><>>><<<>>><<<><<<>><>><<>>
|
13
2022/tests/day18.txt
Normal file
13
2022/tests/day18.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
2,2,2
|
||||
1,2,2
|
||||
3,2,2
|
||||
2,1,2
|
||||
2,3,2
|
||||
2,2,1
|
||||
2,2,3
|
||||
2,2,4
|
||||
2,2,6
|
||||
1,2,5
|
||||
3,2,5
|
||||
2,1,5
|
||||
2,3,5
|
2
2022/tests/day19.txt
Normal file
2
2022/tests/day19.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
Blueprint 1: Each ore robot costs 4 ore. Each clay robot costs 2 ore. Each obsidian robot costs 3 ore and 14 clay. Each geode robot costs 2 ore and 7 obsidian.
|
||||
Blueprint 2: Each ore robot costs 2 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 8 clay. Each geode robot costs 3 ore and 12 obsidian.
|
Reference in New Issue
Block a user