AoC 2024 day 16
P=puzzle.splitlines() M=defaultdict(); S=-1; E=-1; inf=999999 # maze map, some infinite value for j,r in enumerate(P): # for each row for i,c in enumerate(r): # for each maze cell p=i+1j*j; M[p]=[c,inf] # memorize the contents with some infinite cost if c=='S': S=p # memorize the Start position if c=='E': E=p # memorize the End position def travel(): # travel from S to E at cheapest cost q=[]; v=defaultdict(lambda: inf); x=0 # queue of paths, visited position/direction pairs, counter best=inf; bestpp=defaultdict(lambda: []) # best cost, best paths positions heapq.heappush(q,[0,x:=x+1,[S],1]) # heapq for auto-sort, queue initial cost/path/direction while (q): # while we still have paths to explore c,_,pp,d=heapq.heappop(q); p=pp[-1] # pop the queued path/direction of lowest cost, last position of path if c<=best: # no need to test this path if its cost greater than best score if p==E: best=c; bestpp[c]+=pp # record a best score and its path positions, if we reach End position v[(p,d)]=c # record the cost at current position/direction visited pair (to later avoid greater ones) for nd in [1,1j,-1,-1j]: # for each neighbour directions np=p+nd # position of the neighbour if M[np][0]!='#' and np not in pp: # if the neighbour cell is empty and not already in current path nc=c+(1 if nd==d else 1001) # calculate the cost to go to move to this neighbour cell if v[(np,nd)]>nc: # queue this neighbour new cost/path/direction unless it was visited at lower cost heapq.heappush(q,[nc,x:=x+1,pp+[np],nd]) # we use x unique counter before pp argument that contains non-hashable complex numbers return(best,bestpp) # return the best score and all positions of all paths with this score (could be multiple) def part1(): best,_=travel() # travel the maze for best score print(best) # display the best score def part2(): best,bestpp=travel() # travel the maze for best score, best paths' positions print(len(set(bestpp[best]))) # display the number of unique positions of all paths with the best score
Leave a Comment