summaryrefslogtreecommitdiffstats
path: root/19/py/d18.py
diff options
context:
space:
mode:
Diffstat (limited to '19/py/d18.py')
-rw-r--r--19/py/d18.py105
1 files changed, 62 insertions, 43 deletions
diff --git a/19/py/d18.py b/19/py/d18.py
index 1c25b12..144eb4e 100644
--- a/19/py/d18.py
+++ b/19/py/d18.py
@@ -1,5 +1,6 @@
import collections
import heapq as heap
+import sys
def neighbours(p):
return [(p[0]+1, p[1]), (p[0]-1, p[1]), \
@@ -47,7 +48,6 @@ def path(start: tuple, end:tuple, board:dict, keys={}, doors={}, draw_search=Fal
heap.heappush(h, (0, start, collections.deque()))
while True:
if len(h) == 0:
- print(visited)
return
cur = heap.heappop(h)
for n in neighbours(cur[1]):
@@ -66,11 +66,8 @@ def path(start: tuple, end:tuple, board:dict, keys={}, doors={}, draw_search=Fal
heap.heappush(h, (cur[0] + 1, n, new_path))
if draw_search:
time.sleep(0.0075)
- print(draw(board, keys=keys, doors=doors, path=new_path, visited=visited))
- print(end)
- print(n)
-def avail(map, start, items, dead):
+def avail(map, start, items, dead, ignore=set(), ignore_except=set()):
visited = set()
avail = []
q = collections.deque()
@@ -83,6 +80,8 @@ def avail(map, start, items, dead):
avail.append((dist, pos, items[pos]))
continue
for n in neighbours(pos):
+ if n in ignore and n not in ignore_except:
+ continue
if n in map and map[n] == "#":
continue
if n in dead:
@@ -93,12 +92,6 @@ def avail(map, start, items, dead):
q.append((dist+1, n))
return avail
-def seen_before(keys, paths):
- for path in paths:
- if set(keys) == set(path) and keys[-1] == path[-1]:
- return True
- return False
-
input = open("../input/18", "r").readlines()
map = {}
@@ -143,7 +136,7 @@ for _ in range(10):
ends.add(tile)
elif num_walls < 2:
intersections.add(tile)
-
+
for end in ends:
cur = end
while cur not in intersections and cur not in map_keys and cur not in map_doors:
@@ -154,6 +147,7 @@ for _ in range(10):
if n not in walls and n not in dead:
cur = n
break
+
paths = {} # every path available between a door and a key
start_paths = {} # every path available from the starting point
@@ -162,46 +156,71 @@ for ent, s in map_keys_doors.items():
for a in avail(map, ent, map_keys_doors, dead):
paths[(s, a[2])] = a[0]
graph[s] = graph.get(s, []) + [(a[2], a[0])]
-for a in avail(map, start, map_keys, dead):
+for a in avail(map, start, map_keys, dead, map_doors):
start_paths[("@", map_keys[a[1]])] = a[0]
+def v_from_k(items: dict, item: str):
+ for k,v in items.items():
+ if item == v:
+ return k
+ return None
+
+def pos_from_item(item, keys, doors):
+ return v_from_k((keys if item.islower() else doors), item)
+
+def avail_keys(map, keys, doors, graph, start, keys_left, unlocked_doors):
+ visited = set()
+ avail = []
+ h = []
+ heap.heappush(h, (0, start))
+ while len(h) > 0:
+ dist, cur_key = heap.heappop(h)
+ if cur_key != start and cur_key.islower() and cur_key in keys_left:
+ avail.append((dist, cur_key))
+ continue
+ for n in graph[cur_key]:
+ if n[0].isupper() and n[0] not in unlocked_doors:
+ continue
+ if n[0] in visited:
+ continue
+ visited.add(n[0])
+ heap.heappush(h, (dist + n[1], n[0]))
+ return avail
+
h = []
for path, dist in start_paths.items():
cur = path[1]
- keys = [path[1]]
+ keys_left = set(map_keys.values()).copy()
+ keys_left.remove(cur)
unlocked = set()
unlocked.add(cur.upper())
- heap.heappush(h, (dist, cur, keys, unlocked))
+ key_path = [cur]
+ heap.heappush(h, (dist, cur, keys_left, unlocked, key_path))
-m = 0
-seen = []
+best = len(map_keys)
+seen = set()
while True:
- print(len(h))
- candidate = heap.heappop(h)
- dist = candidate[0]
- cur = candidate[1]
- keys = candidate[2]
- unlocked = candidate[3]
-
- # if seen_before
- if seen_before(keys, seen):
+ dist, key, keys_left, unlocked, key_path = heap.heappop(h)
+ #print("\nnode", dist, key, keys_left, unlocked, key_path)
+ if (frozenset(key_path), key) in seen:
+ #print("skipping", key_path, key)
continue
- seen.append(keys)
-
- if len(unlocked) > m:
- m = len(unlocked)
- print(m, keys)
- if len(unlocked) == len(map_doors):
- break
-
- for n in graph[cur]:
- if n[0].isupper() and n[0] not in unlocked:
- continue
- keys = keys.copy()
- unlocked = unlocked.copy()
- if n[0].islower():
- keys.append(n[0])
- unlocked.add(n[0].upper())
- heap.heappush(h, (dist+n[1], n[0], keys, unlocked))
+ seen.add((frozenset(key_path), key))
+ if len(keys_left) == 0:
+ print(dist, "with path", key_path)
+ sys.exit()
+ if len(keys_left) < best:
+ best = len(keys_left)
+ print("best", len(unlocked), "with dist", dist, "and path", key_path)
+ for new_dist, new_key in avail_keys(map, map_keys, map_doors, graph, key, keys_left, unlocked):
+ #print("edge", new_dist, new_key)
+ new_keys_left = keys_left.copy()
+ new_keys_left.remove(new_key)
+ new_unlocked = unlocked.copy()
+ new_unlocked.add(new_key.upper())
+ new_key_path = key_path.copy()
+ new_key_path.append(new_key)
+ #print("adding", dist+new_dist, new_key, new_keys_left, new_unlocked, new_key_path)
+ heap.heappush(h, (dist + new_dist, new_key, new_keys_left, new_unlocked, new_key_path))