2019 day 18

This commit is contained in:
2024-09-10 18:58:58 -04:00
parent bf88f13791
commit 9cd17279d9
2 changed files with 200 additions and 1 deletions

199
2019/d18.py Normal file
View File

@@ -0,0 +1,199 @@
from lib import get_data, Grid2D, LETTERS_UPPER, LETTERS_LOWER, add2
from collections import defaultdict
LETTERS = LETTERS_UPPER + LETTERS_LOWER
data = """#############
#g#f.D#..h#l#
#F###e#E###.#
#dCba...BcIJ#
#####.@.#####
#nK.L...G...#
#M###N#H###.#
#o#m..#i#jk.#
#############"""
def part_1(data):
g = Grid2D(data)
(start,) = g.find("@")
starts = [start]
graph = defaultdict(set)
starts_seen = set()
while starts:
start = starts.pop()
if start in starts_seen:
continue
else:
starts_seen.add(start)
start_symbol = g[start]
xs = [start]
seen = set()
for steps in range(1_000):
nxs = []
for x in xs:
if x in seen:
continue
else:
seen.add(x)
for nb in g.neighbors_ort(x):
if g[nb] == ".":
nxs.append(nb)
elif g[nb] in LETTERS:
symbol = g[nb]
if symbol != start_symbol:
graph[symbol].add((start_symbol, steps + 1))
graph[start_symbol].add((symbol, steps + 1))
starts.append(nb)
xs = nxs
if len(xs) == 0:
break
all_keys = [g[p] for p in g.find(LETTERS_LOWER)]
poss = [(0, 0, tuple("@"), "@")]
best: dict[tuple[tuple, str], int] = {(("@",), "@"): 0}
min_dist = 10**9
while poss:
current_distance, key_count, keys, symbol = poss.pop()
# print(current_distance, key_count, keys, symbol)
if key_count - 1 == len(all_keys):
min_dist = min(min_dist, current_distance)
continue
for next_symbol, distance in graph[symbol]:
if next_symbol in LETTERS_UPPER and not next_symbol.lower() in keys:
continue
if next_symbol in LETTERS_LOWER:
new_keys = set(keys)
new_keys.add(next_symbol)
new_keys = tuple(sorted(new_keys))
new_key_count = len(new_keys)
else:
new_keys = keys
new_key_count = key_count
new_distance = current_distance + distance
key = (new_keys, next_symbol)
if (key not in best) or (key in best and best[key] > new_distance):
best[key] = new_distance
poss.append((new_distance, new_key_count, new_keys, next_symbol))
print(min_dist)
def part_2(data):
g = Grid2D(data)
(start,) = g.find("@")
g[start] = "#"
g[add2(start, (-1, 0))] = "#"
g[add2(start, (1, 0))] = "#"
g[add2(start, (0, 1))] = "#"
g[add2(start, (0, -1))] = "#"
g[add2(start, (-1, -1))] = "0"
g[add2(start, (-1, 1))] = "1"
g[add2(start, (1, 1))] = "2"
g[add2(start, (1, -1))] = "3"
starts = g.find("0") + g.find("1") + g.find("2") + g.find("3")
graph = defaultdict(set)
starts_seen = set()
while starts:
start = starts.pop()
if start in starts_seen:
continue
else:
starts_seen.add(start)
start_symbol = g[start]
xs = [start]
seen = set()
for steps in range(1_000):
nxs = []
for x in xs:
if x in seen:
continue
else:
seen.add(x)
for nb in g.neighbors_ort(x):
if g[nb] == ".":
nxs.append(nb)
elif g[nb] in LETTERS:
symbol = g[nb]
if symbol != start_symbol:
graph[start].add((nb, steps + 1))
graph[nb].add((start, steps + 1))
starts.append(nb)
xs = nxs
if len(xs) == 0:
break
# g.print()
all_keys = [g[p] for p in g.find(LETTERS_LOWER)]
robots = tuple(g.find("0") + g.find("1") + g.find("2") + g.find("3"))
poss = [(0, tuple(), robots)]
best: dict[tuple[tuple, tuple], int] = {(tuple(), tuple()): 0}
min_dist = 10**9
while poss:
current_distance, keys, robots = poss.pop()
if len(keys) == len(all_keys):
min_dist = min(min_dist, current_distance)
# print(min_dist)
continue
# print(current_distance, keys, robots)
for robot_i in range(len(robots)):
robot = robots[robot_i]
# robot_symbol = g[robot]
for next_pos, distance in graph[robot]:
next_symbol = g[next_pos]
if next_symbol in LETTERS_UPPER and not next_symbol.lower() in keys:
continue
if next_symbol in LETTERS_LOWER:
new_keys = set(keys)
new_keys.add(next_symbol)
new_keys = tuple(sorted(new_keys))
else:
new_keys = keys
new_distance = current_distance + distance
new_robots = list(robots)
new_robots[robot_i] = next_pos
new_robots = tuple(new_robots)
key = (new_keys, new_robots)
if (key not in best) or (key in best and best[key] > new_distance):
best[key] = new_distance
poss.append((new_distance, new_keys, new_robots))
poss = sorted(poss, key=lambda xs: (xs[0], -len(xs[1])), reverse=True)
poss = poss[-10000:]
print(min_dist)
def main():
data = get_data(__file__)
part_1(data)
part_2(data)
if __name__ == "__main__":
main()

View File

@@ -129,7 +129,7 @@ Solutions and utility script for Advent of Code challenges in Python.
- Day 15: >120:00 (I am really weak at the moment.) - Day 15: >120:00 (I am really weak at the moment.)
- Day 16: days (Wow. Just too hard for me to solve quickly?) - Day 16: days (Wow. Just too hard for me to solve quickly?)
- Day 17: days (Fun but too tricky for me to be fast.) - Day 17: days (Fun but too tricky for me to be fast.)
- Day 18: - Day 18: days (Slow and slow algorithm.)
- Day 19: 40:00 (Way too slow! Oversight error. Come on.) - Day 19: 40:00 (Way too slow! Oversight error. Come on.)
- Day 20: - Day 20: