From 0d4692295723ec606b6d8e1ff05c0589e922eab6 Mon Sep 17 00:00:00 2001 From: Andrew Ekstedt Date: Sat, 24 Dec 2022 11:11:32 -0800 Subject: [PATCH] day 24 python optimization --- day24/sol.py | 63 +++++++++++++++++++++++++++++----------------------- 1 file changed, 35 insertions(+), 28 deletions(-) diff --git a/day24/sol.py b/day24/sol.py index 0cdcf30..8ba9f5c 100644 --- a/day24/sol.py +++ b/day24/sol.py @@ -83,34 +83,23 @@ def blocked(x,y,t): return False start = (data[0].index('.'), 0) -goal = (data[-1].index('.'), len(data)-1) -leg_distance = abs(start[0] - goal[0]) + abs(start[1] - goal[1]) +end = (data[-1].index('.'), len(data)-1) +leg_distance = abs(start[0] - end[0]) + abs(start[1] - end[1]) -def is_goal(node): - x, y, t, legs = node - return (x,y) == goal and legs == 0 +def is_goal(node, goal=end): + x, y, t = node + return (x,y) == goal -def heuristic(node): - x, y, t, legs = node - if legs == 0: - return 0 - if legs % 2 == 1: - g = goal - else: - g = start - return (legs-1)*leg_distance + abs(g[0] - x) + abs(g[1] - y) +def heuristic(node, goal=end): + x, y, t = node + return abs(goal[0] - x) + abs(goal[1] - y) def neighbors(node): - x, y, t, legs = node + x, y, t = node n = [] - if legs % 2 == 1: - g = goal - else: - g = start def check(dx,dy): if not blocked(x+dx,y+dy,t+1): - l = legs - ((x+dx,y+dy) == g) - n.append((1, (x+dx, y+dy, t+1, l))) + n.append((1, (x+dx, y+dy, t+1))) check(+1,0) check(0,+1) check(-1,0) @@ -122,14 +111,32 @@ 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() -start_node = start + (0, 1) -print(astar.search(start_node, is_goal, neighbors, heuristic)) + +# 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() -start_node = start + (0, 3) -print(astar.search(start_node, is_goal, neighbors, heuristic)) - -print("part 1", t2 - t1) -print("part 2", time.time() - t2) +print("part 1", d1, t1 - t0) +print("part 2", d1+d2+d3, t2 - t0, "(%+f)"%(t2-t1))