adventofcode2022/day24/sol.py

136 lines
3.3 KiB
Python

data = []
for line in open("input"):
data.append(line.strip())
import sys, os; sys.path.append(os.path.join(os.path.dirname(__file__), "../lib"))
import astar
#print(*data, sep="\n")
def show(t):
H = len(data)-2
for y in range(len(data)):
s = []
W = len(data[y])-2
for x in range(len(data[y])):
c = data[y][x]
if c == '#':
s.append(c)
else:
bliz = []
u = 1 + ((x - t)-1)%W
if data[y][u] == '>':
bliz.append('>')
u = 1 + ((x + t)-1)%W
if data[y][u] == '<':
bliz.append('<')
v = 1 + ((y - t)-1)%H
if data[v][x] == 'v':
bliz.append('v')
v = 1 + ((y + t)-1)%H
if data[v][x] == '^':
bliz.append('^')
if len(bliz) == 0:
s.append('.')
elif len(bliz) == 1:
s.append(bliz[0])
elif len(bliz) < 10:
s.append(str(len(bliz)))
else:
s.append('*')
print(''.join(s))
def blocked(x,y,t):
if not 0 <= y < len(data):
return True
if not 0 <= x < len(data[y]):
return True
if data[y][x] == '#':
return True
H = len(data)-2
W = len(data[y])-2
u = 1 + ((x - t)-1)%W
if data[y][u] == '>':
return True
u = 1 + ((x + t)-1)%W
if data[y][u] == '<':
return True
v = 1 + ((y - t)-1)%H
if data[v][x] == 'v':
return True
v = 1 + ((y + t)-1)%H
if data[v][x] == '^':
return True
return False
start = (data[0].index('.'), 0)
end = (data[-1].index('.'), len(data)-1)
leg_distance = abs(start[0] - end[0]) + abs(start[1] - end[1])
def is_goal(node, goal=end):
x, y, t = node
return (x,y) == goal
def heuristic(node, goal=end):
x, y, t = node
return abs(goal[0] - x) + abs(goal[1] - y)
def neighbors(node):
x, y, t = node
n = []
def check(dx,dy):
if not blocked(x+dx,y+dy,t+1):
n.append((1, (x+dx, y+dy, t+1)))
check(+1,0)
check(0,+1)
check(-1,0)
check(0,-1)
check(0,0)
return n
show(0)
show(1)
#show((len(data)-2)*(len(data[0])-2))
from functools import partial
import time
t0 = time.time()
# part 1
d1 = astar.search(start+(0,), is_goal, neighbors, heuristic)[0]
t1 = time.time()
# part 2
# we can always take the best path for each leg,
# rather than trying to compute it over the whole trip.
# suppose there is a better overall path B = d1' + d2 + d3
# with d1' > d1. we can "sync up" with this path by simply
# waiting at the end square for d1'-d1 steps at the beginning
# of the next leg. (A* will check this possibility for us.)
# (the start and end squares are never blocked by blizzards.)
# therefore even if we can complete later legs faster by
# starting later, there is no downside to taking the shortest
# path for all the previous legs.
is_start = partial(is_goal, goal=start)
heuristic2 = partial(heuristic, goal=start)
d2 = astar.search(end+(d1,), is_start, neighbors, heuristic2)[0]
d3 = astar.search(start+(d1+d2,), is_goal, neighbors, heuristic)[0]
t2 = time.time()
print("part 1", d1, t1 - t0)
print("part 2", d1+d2+d3, t2 - t0, "(%+f)"%(t2-t1))