def dijkstra(panels): source = (0, 0) dists = {} prevs = {} Q = set() for p in panels: dists[p] = 99999999999 prevs[p] = None Q.add(p) dists[source] = 0 while len(Q) > 0: minv = None for q in Q: if minv == None: minv = q else: if dists[minv] > dists[q]: minv = q Q.remove(minv) for q in util.adj4(minv): if q in Q: alt = dists[minv] + 1 if alt < dists[q]: dists[q] = alt return dists
def min_dist_to_finish(currloc, graph, keylocs, doorlocs, depth, rope): if rope != None and rope < 0: return None if rope != None and key_set_min_dist(keylocs.values(), currloc) > rope: return None if len(keylocs) == 0: return 0 min_dist = None descendants = nx.descendants(graph, currloc) # print(zipped) for k in keylocs: if keylocs[k] in descendants: # print(depth) # if depth == 0: # print(min_dist) if depth < 18 and min_dist != None: print("depth:",depth,"dist:",min_dist) # print("locs",keylocs) # try: path = nx.bidirectional_dijkstra(graph, currloc, keylocs[k]) pathlen = path[0] # pathlen = util.manhattan_dist(currloc, keylocs[k]) keylocs_val = keylocs[k] keylocs.pop(k) doorlocs_val = None edges_added = [] if k.upper() in doorlocs: free_pos = doorlocs[k.upper()] for loc in util.adj4(free_pos): if loc in graph.nodes and not loc in doorlocs.values(): edges_added.append((free_pos, loc)) graph.add_edges_from(edges_added, weight=1) doorlocs_val = doorlocs[k.upper()] doorlocs.pop(k.upper()) ropetogive = None if min_dist == None: if rope != None: ropetogive = rope - pathlen else: ropetogive = min_dist - pathlen res = min_dist_to_finish(keylocs_val, graph, keylocs, doorlocs, depth + 1, ropetogive) if res != None: new_min_dist = pathlen + res if min_dist == None or new_min_dist < min_dist: min_dist = new_min_dist keylocs[k] = keylocs_val if doorlocs_val != None: for e in edges_added: graph.remove_edges_from(edges_added) doorlocs[k.upper()] = doorlocs_val # except nx.NetworkXNoPath: # print("fail") # continue return min_dist
def get_input_seq(panels, loc): dest = None prev = None for key in panels: if panels[key][0] != 1: for loc2 in util.adj4(key): if not loc2 in panels: dest = loc2 prev = key break if dest != None: break if dest == None: return None, None rel = get_dir(prev, dest) seq = list(reversed([get_back(x) for x in panels[loc][1] ])) + panels[prev][1] + [get_dir(prev, dest)] return seq, panels[prev][1] + [get_dir(prev, dest)]
if c == "@": currloc = key elif c.islower(): keylocs[c] = key else: assert c.isupper() doorlocs[c] = key G.add_node(key) def invalid(c): return c.isupper() for node in G.nodes: for node2 in util.adj4(node): if node2 in G.nodes: G.add_edge(node, node2, weight=1) key_map = get_key_map(G, keylocs) for node in G.nodes: for node2 in util.adj4(node): if node2 in G.nodes and (invalid(locs[node]) or invalid(locs[node2])): if (node, node2) in G.edges: G.remove_edge(node, node2) # print(currloc) # print(G.nodes) # print(G.edges)
filtered_panels = {} oxygen_loc = None for loc in panels: if panels[loc][0] != 1: filtered_panels[loc] = panels[loc][0] if panels[loc][0] == 2: oxygen_loc = loc util.print_at_loc((1, 42), "Part 1") util.print_at_loc((1, 43), dijkstra(filtered_panels)[oxygen_loc]) util.print_at_loc((1, 44), "Part 2") oxygen = set() oxygen.add(oxygen_loc) no_oxygen = set() for p in filtered_panels: no_oxygen.add(p) no_oxygen.remove(oxygen_loc) mins = 0 while len(no_oxygen) > 0: possible_new = set() for o in oxygen: for n in util.adj4(o): possible_new.add(n) actual_new = no_oxygen.intersection(possible_new) for o in actual_new: no_oxygen.remove(o) oxygen.add(o) mins += 1 util.print_at_loc((1, 45), mins)
import networkx as nx # Fun puzzle! I'm getting a lot more comfortable with networkx. Pretty # much all of my bugs today were with off-by-one errors or typos, so # it went pretty smoothly. fn = "./in.txt" l = util.filetorawlist(fn) G = nx.Graph() for r in range(len(l)): for c in range(len(l[r])): if l[r][c] == ".": G.add_node((r, c)) for node in G.nodes: for node2 in util.adj4(node): if node2 in G.nodes: G.add_edge(node, node2) inner_portals = {} outer_portals = {} for r in range(2, len(l) - 2): for c in range(2, len(l[r]) - 2): if l[r][c] == ".": portal_text = None if l[r][c - 1].isupper() and l[r][c - 2].isupper(): portal_text = l[r][c - 2] + l[r][c - 1] elif l[r][c + 1].isupper() and l[r][c + 2].isupper(): portal_text = l[r][c + 1] + l[r][c + 2] elif l[r - 1][c].isupper() and l[r - 2][c].isupper(): portal_text = l[r - 2][c] + l[r - 1][c]
# second part of tuple is list of [completed, backtrack dir] panels = {(0, 0): (0, [False, None])} util.clear_terminal() while not panels[loc][1][0] or panels[loc][1][1] != None: # add in this line to watch the logic of the maze construction time.sleep(maze_tic_speed) old_loc = loc new_panel = None if panels[loc][1][0]: # backtrack _, = c.calc([panels[loc][1][1].value]) loc = get_move(loc, panels[loc][1][1]) else: # explore next_place = None for new_place in util.adj4(loc): if not new_place in panels: next_place = new_place break if next_place == None: panels[loc][1][0] = True else: step = get_dir(loc, next_place) out, = c.calc([step.value]) if out == 0: panels[next_place] = (1, [True, get_back(step)]) new_panel = (next_place, "#") else: loc = next_place panels[loc] = (0, [False, get_back(step)]) if out == 1 else ( 2, [False, get_back(step)])
while True: val = comp.calc() if val == None: break if val == 10: r += 1 c = 0 else: char = str(chr(val)) a[(c, r)] = char c += 1 tot = 0 for k in a: intersection = True for adj in util.adj4(k): if not adj in a: intersection = False break if a[adj] == ".": intersection = False break if intersection: tot += k[0] * k[1] print("Part 1") print(tot) print("Part 2") A = "L,12,L,12,R,12" B = "L,8,L,8,R,12,L,8,L,8"