Advertisement
illuminati229

AoC Day 15

Dec 16th, 2021
292
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 5.48 KB | None | 0 0
  1. import heapq as hq
  2. import numpy as np
  3. from time import perf_counter
  4.  
  5.  
  6. class Graph:
  7.  
  8.     def __init__(self, directed=False):
  9.         self._outgoing = {}
  10.         self._incoming = {} if directed else self._outgoing
  11.  
  12.     def is_directed(self):
  13.         return self._incoming is not self._outgoing
  14.  
  15.     def vertex_count(self):
  16.         return len(self._outgoing)
  17.  
  18.     def vertices(self):
  19.         return self._outgoing.keys()
  20.  
  21.     def edge_count(self):
  22.         total = sum(len(self.outgoing[v]) for v in self.outgoing)
  23.         return total if self.is_directed() else total // 2
  24.  
  25.     def edges(self):
  26.         result = set()
  27.         for secondary_map in self._outgoing.values():
  28.             result.update(secondary_map.values())
  29.         return result
  30.  
  31.     def get_edge(self, u, v):
  32.         return self._outgoing[u].get(v)
  33.  
  34.     def degree(self, v, outgoing=True):
  35.         adj = self._outgoing if outgoing else self._incoming
  36.         return len(adj([v]))
  37.  
  38.     def incident_edges(self, v, outgoing=True):
  39.         adj = self._outgoing if outgoing else self._incoming
  40.         for edge in adj[v].values():
  41.             yield edge
  42.  
  43.     def insert_vertex(self, x = None):
  44.         v = self.Vertex(x)
  45.         self._outgoing[v] = {}
  46.         if self.is_directed():
  47.             self._incoming[v] = {}
  48.         return v
  49.  
  50.     def insert_edge(self, u, v, x=None):
  51.         e = self.Edge(u, v, x)
  52.         self._outgoing[u][v] = e
  53.         self._incoming[v][u] = e
  54.         return e
  55.  
  56.     class Vertex:
  57.  
  58.         __slots__ = '_element'
  59.  
  60.         def __init__(self, x):
  61.             self._element = x
  62.  
  63.         def element(self):
  64.             return self._element
  65.  
  66.         def __hash__(self):
  67.             return hash(id(self))
  68.  
  69.         def __lt__(a, b):
  70.             if type(a) == type(b):
  71.                 if type(a) == type(tuple()):
  72.                     return a < b.element()
  73.                 elif type(b) == type(tuple()):
  74.                     return a.element() < b
  75.             return False
  76.  
  77.     class Edge:
  78.  
  79.         __slots__ = '_origin', '_destination', '_element'
  80.  
  81.         def __init__(self, u, v, x):
  82.             self._origin = u
  83.             self._destination = v
  84.             self._element = x
  85.  
  86.         def endpoints(self):
  87.             return (self._origin, self._destination)
  88.  
  89.         def opposite(self, v):
  90.             return self._destination if v is self._origin else self._origin
  91.  
  92.         def element(self):
  93.             return self._element
  94.                                  
  95. def get_neighbors(node, max_x, max_y):
  96.    
  97.     dirs = [(1, 0), (0, 1), (-1, 0), (0, -1)]
  98.     result = []
  99.    
  100.     for dx, dy in dirs:
  101.         neighbor = (node[0] + dx, node[1] + dy)
  102.         if 0 <= neighbor[0] < max_x and 0 <= neighbor[1] < max_y:
  103.             result.append(neighbor)
  104.            
  105.     return result
  106.  
  107. def shortest_path_lengths(g, src, end = None):
  108.     d = {}
  109.     cloud = {}
  110.     pq = []
  111.     pqlocator = {}
  112.  
  113.     for v in g.vertices():
  114.         if v is src:
  115.             d[v] = 0
  116.             hq.heappush(pq, (d[v], v))
  117.             pqlocator[v] = (d[v], v)
  118.  
  119.         else:
  120.             d[v]= float('inf')
  121.  
  122.  
  123.     while len(pq):
  124.         key, u = hq.heappop(pq)
  125.        
  126.         cloud[u] = key
  127.  
  128.         if u == end:
  129.             return cloud
  130.        
  131.         for e in g.incident_edges(u):
  132.             v = e.opposite(u)
  133.             if v not in cloud:
  134.                 wgt = e.element()
  135.                 if d[u] + wgt < d[v]:
  136.                     d[v] = d[u] + wgt
  137.                     if v in pqlocator:
  138.                         pq.remove(pqlocator[v])
  139.                         hq.heappush(pq, (d[v], v))
  140.                         pqlocator[v] = (d[v], v)
  141.                     else:
  142.                         pqlocator[v] = (d[v], v)
  143.                         hq.heappush(pq, (d[v],v))
  144.  
  145.            
  146.     return cloud
  147.  
  148. def chiton_route_risk(file_path, map_multi):
  149.    
  150.     with open(file_path) as fin:
  151.         c_map = np.genfromtxt(fin, delimiter = 1)
  152.        
  153.     if map_multi == 1:
  154.         pass
  155.     else:
  156.         new_map = np.zeros((np.shape(c_map)[0] * map_multi, np.shape(c_map)[1] * map_multi))
  157.         for i in range(map_multi):
  158.             for j in range(map_multi):
  159.                 nb = c_map + i + j
  160.                 nb[nb > 9] = nb[nb > 9] % 10 + 1
  161.                 i_r, j_r = np.shape(nb)
  162.                 new_map[i*i_r:i_r*(1+i),j*j_r:j_r*(1+j)] = nb
  163.         c_map = new_map
  164.     g = Graph(True)
  165.  
  166.     max_x, max_y = np.shape(c_map)
  167.  
  168.     v = [[''] * max_y for x in range(max_x)]
  169.  
  170.     for i in range(max_x):
  171.         for j in range(max_y):
  172.             v[i][j] = g.insert_vertex((i,j))
  173.  
  174.     for row in v:
  175.         for entry in row:
  176.             for nb_x, nb_y in get_neighbors(entry.element(),max_x,max_y):
  177.                 g.insert_edge(entry, v[nb_x][nb_y], c_map[(nb_x, nb_y)])
  178.  
  179.     paths = shortest_path_lengths(g, v[0][0], v[-1][-1])
  180.  
  181.     return int(paths[v[-1][-1]])
  182.  
  183. def main():
  184.  
  185.     start = perf_counter()
  186.     assert chiton_route_risk('test_input.txt', 1) == 40
  187.     print('Part 1 Test in:', perf_counter() - start)
  188.    
  189.     start = perf_counter()
  190.     print(chiton_route_risk('input.txt', 1))
  191.     print('Part 1 actual:', perf_counter() - start)
  192.  
  193.     start = perf_counter()
  194.     assert chiton_route_risk('test_input.txt', 5) == 315
  195.     print('Part 2 Test in:', perf_counter() - start)
  196.  
  197.     start = perf_counter()
  198.     print(chiton_route_risk('input.txt', 5))
  199.     print('Part 2 actual:', perf_counter() - start)
  200.  
  201. if __name__ == '__main__':
  202.     main()
  203.  
  204.    
  205.  
  206.              
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement