G = [] for line in open("input"): words = line.split() valve = words[1] rate = int(''.join(x for x in words[4] if x.isdigit())) edges = [x.strip(", ") for x in words[9:]] G.append((valve, rate, edges)) #print(G) import sys, os; sys.path.append(os.path.join(os.path.dirname(__file__), "../lib")) import astar def search(): V = sorted(v for v,_,_ in G) # vertices B = {v: 1< b R = {B[v]: r for v,r,_ in G} # rewards: R[b] = reward all_closed = sum(B.values()) all_open = 0 minutes = 30 start = (B['AA'], minutes, all_closed) # A* search minimizes costs # it can't maxmize anything # so we'll borrow an idea from https://github.com/morgoth1145/advent-of-code/blob/2bf7c157e37b3e0a65deedc6c88e42297d813d1d/2022/16/solution.py # and instead say that the cost of moving from one node to the next # is equal to the potential pressure we could have released from the closed pipes # or, in other words, we'll keep track of how much pressure builds up in # closed pipes instead of how much pressure is released from open pipes # let's shink the graph by finding the shortest path between # every pair of rooms (floyd-warshall), and then building a graph which only has # paths from the starting room to rooms with a valve # and from any room with a valve to any other room with a valve # our heuristic cost has to be <= the actual cost of getting to the goal # here's a simple one: # we know it takes at least 1 minute to open a valve, # and at least another minute to walk to the valve # so we can assign at least cost 2*pressure(closed_valves) to this node # (unless there is only 1 minute left) def heuristic(node): v, minutes, closed = node if closed == all_open: m = minutes else: m = min(minutes,1) return m*pressure(closed) def pressure(bits): pressure = 0 for v,r in R.items(): if bits&v: pressure += r return pressure def is_goal(n): v, minutes, closed = n return minutes == 0 info = {} def neighbors(n): v, minutes, closed = n if minutes not in info: print(info) info[minutes] = 0 info[minutes] += 1 if minutes <= 0: pass elif closed == all_open: c = pressure(closed) * minutes yield c, (v, 0, closed) else: c = pressure(closed) if v&closed and R[v]: yield c, (v, minutes-1, closed & ~v) for e in E[v]: yield c, (e, minutes-1, closed) c, _, path = astar.search(start, is_goal, neighbors, heuristic) print(c) print(pressure(all_closed)*30 - c) #maxpair = [] #def pairs(): # O = sorted(best.keys()) # for i in range(len(O)): # for j in range(i,len(O)): # if not O[i] & O[j]: # yield(best[O[i]]+best[O[j]]) #print(max(pairs())) search()