Solve 2018 day 22 and 2019 day 20
This commit is contained in:
parent
db383c7cfa
commit
6c3aec3d6e
89
2018/d22.py
Normal file
89
2018/d22.py
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
from lib import get_data, str_to_ints, A_Star
|
||||||
|
|
||||||
|
data = get_data(__file__)
|
||||||
|
|
||||||
|
depth, x_target, y_target = str_to_ints(data)
|
||||||
|
# depth, x_target, y_target = 510, 10, 10
|
||||||
|
# depth, x_target, y_target = 9171, 7, 721
|
||||||
|
# print(depth, x_target, y_target)
|
||||||
|
|
||||||
|
x_area_max = x_target * 10
|
||||||
|
y_area_max = y_target * 10
|
||||||
|
|
||||||
|
maze = [[None for _ in range(x_area_max + 1)] for _ in range(y_area_max + 1)]
|
||||||
|
|
||||||
|
maze[0][0] = 0
|
||||||
|
maze[y_target][x_target] = 0
|
||||||
|
|
||||||
|
mod = 20183
|
||||||
|
for x in range(x_area_max + 1):
|
||||||
|
maze[0][x] = x * 16807 % mod
|
||||||
|
|
||||||
|
for y in range(y_area_max + 1):
|
||||||
|
maze[y][0] = y * 48271 % mod
|
||||||
|
|
||||||
|
for y in range(1, y_area_max + 1):
|
||||||
|
for x in range(1, x_area_max + 1):
|
||||||
|
if x == x_target and y == y_target:
|
||||||
|
continue
|
||||||
|
assert maze[y][x] is None
|
||||||
|
geo_index = ((maze[y][x - 1] + depth) * (maze[y - 1][x] + depth)) % mod
|
||||||
|
maze[y][x] = geo_index
|
||||||
|
|
||||||
|
t = 0
|
||||||
|
for y in range(y_target + 1):
|
||||||
|
for x in range(x_target + 1):
|
||||||
|
t += ((maze[y][x] + depth) % mod) % 3
|
||||||
|
print(t)
|
||||||
|
|
||||||
|
for y in range(y_area_max + 1):
|
||||||
|
for x in range(x_area_max + 1):
|
||||||
|
maze[y][x] = ((maze[y][x] + depth) % mod) % 3
|
||||||
|
|
||||||
|
|
||||||
|
def allowed(area, tool):
|
||||||
|
# 0 = rocky, 1 = wet, 2 = narrow
|
||||||
|
# 0 = torch, 1 = climbing, 2 = neither
|
||||||
|
return (
|
||||||
|
(area == 0 and (tool in [0, 1]))
|
||||||
|
or (area == 1 and (tool in [1, 2]))
|
||||||
|
or (area == 2 and (tool in [0, 2]))
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def neighbors(state):
|
||||||
|
x, y, tool = state
|
||||||
|
r = []
|
||||||
|
area = maze[y][x]
|
||||||
|
for t in range(3):
|
||||||
|
if allowed(area, t) and t != tool:
|
||||||
|
r.append((x, y, t))
|
||||||
|
|
||||||
|
for dx, dy in [(0, 1), (0, -1), (1, 0), (-1, 0)]:
|
||||||
|
nx, ny = x + dx, y + dy
|
||||||
|
if not (nx >= 0 and nx < x_area_max and ny >= 0 and ny < y_area_max):
|
||||||
|
continue
|
||||||
|
if not allowed(maze[ny][nx], tool):
|
||||||
|
continue
|
||||||
|
r.append((nx, ny, tool))
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
def distance(a, b):
|
||||||
|
if a == 0:
|
||||||
|
return 0
|
||||||
|
elif a[2] != b[2]:
|
||||||
|
assert a[0] == b[0] and a[1] == b[1]
|
||||||
|
return 7
|
||||||
|
else:
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
a = A_Star(
|
||||||
|
starts=[(0, 0, 0)],
|
||||||
|
is_goal=lambda s: s[0] == x_target and s[1] == y_target and s[2] == 0,
|
||||||
|
h=lambda s: abs(s[0] - x_target) + abs(s[1] - y_target),
|
||||||
|
d=distance,
|
||||||
|
neighbors=neighbors,
|
||||||
|
)
|
||||||
|
print(a.cost)
|
154
2019/d20.py
Normal file
154
2019/d20.py
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
from lib import get_data, Grid2D, LETTERS_UPPER
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
|
data = get_data(__file__)
|
||||||
|
|
||||||
|
g = Grid2D(data)
|
||||||
|
|
||||||
|
start = None
|
||||||
|
end = None
|
||||||
|
warps = defaultdict(list)
|
||||||
|
|
||||||
|
inner = set()
|
||||||
|
outer = set()
|
||||||
|
|
||||||
|
for row in range(g.n_rows - 2):
|
||||||
|
for col in range(g.n_cols - 2):
|
||||||
|
a, b, c = g[(row, col)], g[(row, col + 1)], g[(row, col + 2)]
|
||||||
|
x, y, z = g[(row, col)], g[(row + 1, col)], g[(row + 2, col)]
|
||||||
|
if a in LETTERS_UPPER and b in LETTERS_UPPER and c == ".":
|
||||||
|
warps[a + b].append((row, col + 2))
|
||||||
|
if col == 0:
|
||||||
|
outer.add((row, col + 2))
|
||||||
|
else:
|
||||||
|
inner.add((row, col + 2))
|
||||||
|
elif a == "." and b in LETTERS_UPPER and c in LETTERS_UPPER:
|
||||||
|
warps[b + c].append((row, col))
|
||||||
|
if col + 3 == g.n_cols:
|
||||||
|
outer.add((row, col))
|
||||||
|
else:
|
||||||
|
inner.add((row, col))
|
||||||
|
|
||||||
|
if x in LETTERS_UPPER and y in LETTERS_UPPER and z == ".":
|
||||||
|
if x + y == "AA":
|
||||||
|
start = (row + 2, col)
|
||||||
|
else:
|
||||||
|
warps[x + y].append((row + 2, col))
|
||||||
|
if row == 0:
|
||||||
|
outer.add((row + 2, col))
|
||||||
|
else:
|
||||||
|
inner.add((row + 2, col))
|
||||||
|
elif x == "." and y in LETTERS_UPPER and z in LETTERS_UPPER:
|
||||||
|
if y + z == "ZZ":
|
||||||
|
end = (row, col)
|
||||||
|
else:
|
||||||
|
warps[y + z].append((row, col))
|
||||||
|
if row + 3 == g.n_rows:
|
||||||
|
outer.add((row, col))
|
||||||
|
else:
|
||||||
|
inner.add((row, col))
|
||||||
|
|
||||||
|
|
||||||
|
graph = defaultdict(list)
|
||||||
|
allnodes = set([start, end])
|
||||||
|
for key, (a, b) in warps.items():
|
||||||
|
graph[a].append((b, 1))
|
||||||
|
graph[b].append((a, 1))
|
||||||
|
allnodes.add(a)
|
||||||
|
allnodes.add(b)
|
||||||
|
|
||||||
|
for startnode in allnodes:
|
||||||
|
to_visit = [startnode]
|
||||||
|
steps = 0
|
||||||
|
seen = set()
|
||||||
|
while to_visit:
|
||||||
|
steps += 1
|
||||||
|
new_to_visit = []
|
||||||
|
for node in to_visit:
|
||||||
|
if node in seen:
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
seen.add(node)
|
||||||
|
|
||||||
|
assert node is not None
|
||||||
|
for nb in g.neighbors_ort(node):
|
||||||
|
if nb in seen:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if nb in allnodes:
|
||||||
|
if not (nb, steps) in graph[startnode]:
|
||||||
|
graph[startnode].append((nb, steps))
|
||||||
|
if not (startnode, steps) in graph[nb]:
|
||||||
|
graph[nb].append((startnode, steps))
|
||||||
|
seen.add(nb)
|
||||||
|
elif g[nb] == ".":
|
||||||
|
new_to_visit.append(nb)
|
||||||
|
to_visit = new_to_visit
|
||||||
|
|
||||||
|
shortest = {start: 0}
|
||||||
|
to_visit = [start]
|
||||||
|
seen = set()
|
||||||
|
|
||||||
|
while to_visit:
|
||||||
|
to_visit.sort(key=lambda node: shortest[node], reverse=True)
|
||||||
|
current = to_visit.pop()
|
||||||
|
if current in seen:
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
seen.add(current)
|
||||||
|
|
||||||
|
for nb, dist in graph[current]:
|
||||||
|
new_dist = shortest[current] + dist
|
||||||
|
if not nb in shortest:
|
||||||
|
shortest[nb] = new_dist
|
||||||
|
elif new_dist < shortest[nb]:
|
||||||
|
shortest[nb] = new_dist
|
||||||
|
if nb not in seen:
|
||||||
|
to_visit.append(nb)
|
||||||
|
|
||||||
|
print(shortest[end])
|
||||||
|
|
||||||
|
shortest = {(start, 0): 0}
|
||||||
|
to_visit = [(start, 0)]
|
||||||
|
seen = set()
|
||||||
|
|
||||||
|
while to_visit:
|
||||||
|
to_visit.sort(key=lambda node: shortest[node], reverse=True)
|
||||||
|
current, level = to_visit.pop()
|
||||||
|
|
||||||
|
if (current, level) in seen:
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
seen.add((current, level))
|
||||||
|
|
||||||
|
for nb, dist in graph[current]:
|
||||||
|
new_dist = shortest[(current, level)] + dist
|
||||||
|
|
||||||
|
if nb == end and level == 0:
|
||||||
|
print(new_dist)
|
||||||
|
to_visit = None
|
||||||
|
break
|
||||||
|
elif nb == end:
|
||||||
|
continue
|
||||||
|
elif nb == start:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if dist == 1:
|
||||||
|
if current in inner:
|
||||||
|
new_level = level + 1
|
||||||
|
elif current in outer:
|
||||||
|
new_level = level - 1
|
||||||
|
else:
|
||||||
|
assert False
|
||||||
|
else:
|
||||||
|
new_level = level
|
||||||
|
|
||||||
|
if new_level < 0:
|
||||||
|
continue
|
||||||
|
|
||||||
|
nn = (nb, new_level)
|
||||||
|
if not nn in shortest:
|
||||||
|
shortest[nn] = new_dist
|
||||||
|
elif new_dist < shortest[nn]:
|
||||||
|
shortest[nn] = new_dist
|
||||||
|
to_visit.append(nn)
|
@ -109,7 +109,8 @@ Solutions and utility script for Advent of Code challenges in Python.
|
|||||||
- Day 19: days, super fun, but hard for me
|
- Day 19: days, super fun, but hard for me
|
||||||
- Day 20:
|
- Day 20:
|
||||||
- Day 21: 28:40 (16th - brute force but still not so bad)
|
- Day 21: 28:40 (16th - brute force but still not so bad)
|
||||||
- Day 22:
|
- Day 22: 185:00 (should not have been so slow but was fun)
|
||||||
|
- Day 23:
|
||||||
|
|
||||||
## AoC 2019
|
## AoC 2019
|
||||||
|
|
||||||
@ -131,8 +132,9 @@ Solutions and utility script for Advent of Code challenges in Python.
|
|||||||
- 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: days (Slow and slow algorithm.)
|
- 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: days (Not actually that hard but I struggled for no reason.)
|
||||||
|
- Day 21:
|
||||||
|
|
||||||
## AoC 2020
|
## AoC 2020
|
||||||
|
|
||||||
|
4
lib.py
4
lib.py
@ -229,6 +229,7 @@ class A_Star(object):
|
|||||||
"""
|
"""
|
||||||
open_set = []
|
open_set = []
|
||||||
g_score = {}
|
g_score = {}
|
||||||
|
self.cost = None
|
||||||
|
|
||||||
for start in starts:
|
for start in starts:
|
||||||
heapq.heappush(open_set, (h(start), start))
|
heapq.heappush(open_set, (h(start), start))
|
||||||
@ -237,7 +238,8 @@ class A_Star(object):
|
|||||||
while open_set:
|
while open_set:
|
||||||
current_f_score, current = heapq.heappop(open_set)
|
current_f_score, current = heapq.heappop(open_set)
|
||||||
if is_goal(current):
|
if is_goal(current):
|
||||||
self.cost = current_f_score
|
assert current_f_score == g_score[current]
|
||||||
|
self.cost = g_score[current]
|
||||||
break
|
break
|
||||||
|
|
||||||
for neighbor in neighbors(current):
|
for neighbor in neighbors(current):
|
||||||
|
Loading…
Reference in New Issue
Block a user