usesbiggerwords

AoC 2021 Day 15

Dec 16th, 2021
743
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.93 KB | None | 0 0
  1. # chiton.py
  2.  
  3. import heapq
  4. import os
  5. import sys
  6. from functools import total_ordering
  7.  
  8. import numpy as np
  9.  
  10.  
  11. @total_ordering
  12. class Node:
  13.     def __init__(self, coor: complex, value: int, parent):
  14.         self.value = value
  15.         self.coor = coor
  16.         self.parent = parent
  17.         self.h = 0
  18.         self.g = 0
  19.         self.f = 0
  20.  
  21.     def __repr__(self):
  22.         return repr((self.coor, self.value))
  23.  
  24.     def __eq__(self, other):
  25.         if isinstance(other, Node):
  26.             return self.coor == other.coor
  27.         elif isinstance(other, complex):
  28.             return self.coor == other
  29.         else:
  30.             return False
  31.  
  32.     def __lt__(self, other):
  33.         if isinstance(other, Node):
  34.             return (self.coor.real < other.coor.real) and (self.coor.imag < other.coor.imag)
  35.         elif isinstance(other, complex):
  36.             return (self.coor.real < other.real) and (self.coor.imag < other.imag)
  37.         else:
  38.             return False
  39.  
  40.     def __hash__(self):
  41.         return hash(self.coor)
  42.  
  43.     def add(self, other, value):
  44.         return Node(complex(self.coor.real + other.real, self.coor.imag + other.imag), value, self)
  45.  
  46.  
  47. def read_and_init(fn):
  48.     with open(fn, 'r') as fo:
  49.         lines = fo.read().splitlines()
  50.     cave = {}
  51.     for y in range(len(lines)):
  52.         for x in range(len(lines[0])):
  53.             cave[x + 1j * y] = int(lines[y][x])
  54.     return cave
  55.  
  56.  
  57. def np_cycle_inc(arr: np.ndarray, addend: int):
  58.     new_arr = np.copy(arr)
  59.     for _ in range(addend):
  60.         new_arr += 1
  61.         new_arr = np.where(new_arr > 9, 1, new_arr)
  62.     return new_arr
  63.  
  64.  
  65. def map_expander(cave) -> dict:
  66.     changes = [[0, 1, 2, 3, 4],
  67.                [1, 2, 3, 4, 5],
  68.                [2, 3, 4, 5, 6],
  69.                [3, 4, 5, 6, 7],
  70.                [4, 5, 6, 7, 8]]
  71.     changes = np.array(changes, dtype=np.int32)
  72.     cell = np.zeros((int(max(k.imag for k in cave)) + 1, int(max(k.real for k in cave)) + 1), dtype=np.int32)
  73.     for y in range(int(max(k.imag for k in cave)) + 1):
  74.         for x in range(int(max(k.real for k in cave)) + 1):
  75.             cell[y, x] = cave[x + 1j * y]
  76.     new_cave = None
  77.     for row in range(5):
  78.         new_row = np_cycle_inc(cell, changes[row, 0])
  79.         for col in range(1, 5):
  80.             new_cell = np_cycle_inc(cell, changes[row, col])
  81.             new_row = np.concatenate((new_row, new_cell), axis=1)
  82.         if row == 0:
  83.             new_cave = new_row
  84.         else:
  85.             new_cave = np.concatenate((new_cave, new_row), axis=0)
  86.     return {col+1j*row: new_cave[row, col] for row in range(new_cave.shape[0]) for col in range(new_cave.shape[1])}
  87.  
  88.  
  89. def in_bounds(cave, location: complex, x_max: int, y_max: int) -> bool:
  90.     return (0 <= location.real < x_max) and (0 <= location.imag < y_max)
  91.  
  92.  
  93. def display(cave):
  94.     buffer = []
  95.     for y in range(int(max(k.imag for k in cave)) + 1):
  96.         line = ''
  97.         for x in range(int(max(k.real for k in cave)) + 1):
  98.             line += str(cave[x+1j*y])
  99.         buffer.append(line)
  100.     for line in buffer:
  101.         print(line)
  102.  
  103.  
  104. def dijkstra(cave: dict, start: complex, end: complex):
  105.     distance = {k: sys.maxsize for k in cave}
  106.     distance[start] = 0
  107.     previous = {k: None for k in cave}
  108.     visited = set()
  109.     queue = []
  110.     vecs = (0 - 1j, -1 + 0j, 1 + 0j, 0 + 1j)
  111.     x_max, y_max = int(max(k.real for k in cave)) + 1, int(max(k.imag for k in cave)) + 1
  112.     start_node = Node(start, cave[start], None)
  113.     heapq.heappush(queue, (distance[start], start_node))
  114.     while queue:
  115.         _, current = heapq.heappop(queue)
  116.         visited.add(current)
  117.         if current.coor == end:
  118.             break
  119.         neighbors = [current.add(vec, cave[current.coor + vec]) for vec in vecs if in_bounds(cave,
  120.                                                                                              current.coor + vec,
  121.                                                                                              x_max,
  122.                                                                                              y_max)]
  123.         for neighbor in neighbors:
  124.             if neighbor not in visited:
  125.                 neighbor.f = current.f + cave[neighbor.coor]
  126.                 if neighbor.f < distance[neighbor.coor]:
  127.                     distance[neighbor.coor] = neighbor.f
  128.                     previous[neighbor.coor] = current.coor
  129.                     heapq.heappush(queue, (distance[neighbor.coor], neighbor))
  130.     return distance[end]
  131.  
  132.  
  133. def part1(cave):
  134.     start = 0j
  135.     end = complex(max(k.real for k in cave), max(k.imag for k in cave))
  136.     min_dist = dijkstra(cave, start, end)
  137.     print('Part 1:', min_dist)
  138.  
  139.  
  140. def part2(cave):
  141.     cave = map_expander(cave)
  142.     start = 0j
  143.     end = complex(max(k.real for k in cave), max(k.imag for k in cave))
  144.     min_dist = dijkstra(cave, start, end)
  145.     print('Part 2:', min_dist)
  146.  
  147.  
  148. c = read_and_init(os.path.dirname(__file__) + '\\in.txt')
  149. part1(c)
  150. part2(c)
  151.  
Add Comment
Please, Sign In to add comment