2023 #1
2 changed files with 156 additions and 0 deletions
|
|
@ -80,3 +80,59 @@ def vdbg(seen, h, w):
|
|||
"""Print-debug visited positions of a matrix"""
|
||||
for r in range(h):
|
||||
print("".join(["#" if (r, c) in seen else "." for c in range(w)]))
|
||||
|
||||
|
||||
"""
|
||||
1. Create an array that holds the distance of each vertex from the starting
|
||||
vertex. Initially, set this distance to infinity for all vertices except
|
||||
the starting vertex which should be set to 0.
|
||||
2. Create a priority queue (heap) and insert the starting vertex with its
|
||||
distance of 0.
|
||||
3. While there are still vertices left in the priority queue, select the vertex
|
||||
with the smallest recorded distance from the starting vertex and visit its
|
||||
neighboring vertices.
|
||||
4. For each neighboring vertex, check if it is visited already or not. If it
|
||||
isn’t visited yet, calculate its tentative distance by adding its weight
|
||||
to the smallest distance found so far for its parent/previous node
|
||||
(starting vertex in case of first-level vertices).
|
||||
5. If this tentative distance is smaller than previously recorded value
|
||||
(if any), update it in our ‘distances’ array.
|
||||
6. Finally, add this visited vertex with its updated distance to our priority
|
||||
queue and repeat step-3 until we have reached our destination or exhausted
|
||||
all nodes.
|
||||
"""
|
||||
|
||||
|
||||
# https://pieriantraining.com/understanding-dijkstras-algorithm-in-python/
|
||||
def dijkstra_algorithm(graph, start_node):
|
||||
def min_distance(distances, visited):
|
||||
min_val = float("inf")
|
||||
min_index = -1
|
||||
|
||||
for i in range(len(distances)):
|
||||
if distances[i] < min_val and i not in visited:
|
||||
min_val = distances[i]
|
||||
min_index = i
|
||||
|
||||
return min_index
|
||||
|
||||
num_nodes = len(graph)
|
||||
|
||||
distances = [float("inf")] * num_nodes
|
||||
visited = []
|
||||
|
||||
distances[start_node] = 0
|
||||
|
||||
for i in range(num_nodes):
|
||||
current_node = min_distance(distances, visited)
|
||||
|
||||
visited.append(current_node)
|
||||
|
||||
for j in range(num_nodes):
|
||||
if graph[current_node][j] != 0:
|
||||
|
||||
new_distance = distances[current_node] + graph[current_node][j]
|
||||
|
||||
if new_distance < distances[j]:
|
||||
distances[j] = new_distance
|
||||
return distances
|
||||
|
|
|
|||
100
2023-python/output/day_17.py
Normal file
100
2023-python/output/day_17.py
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
from heapq import heappop, heappush
|
||||
|
||||
from output import answer # D, DD, ADJ, ints, mhd, mdbg, vdbg
|
||||
|
||||
n = 17
|
||||
title = "Clumsy Crucible"
|
||||
|
||||
|
||||
@answer(1, "Using std crucible, least heat loss incured: {}")
|
||||
def part_1(presolved):
|
||||
return presolved[0]
|
||||
|
||||
|
||||
@answer(2, "Using ultra crucible, least heat loss incured: {}")
|
||||
def part_2(presolved):
|
||||
return presolved[1]
|
||||
|
||||
|
||||
def solve(data):
|
||||
grid = {
|
||||
(r, c): int(col)
|
||||
for r, row in enumerate(data.split())
|
||||
for c, col in enumerate(row)
|
||||
}
|
||||
p1 = least_heat_loss(grid, 1, 3)
|
||||
p2 = least_heat_loss(grid, 4, 10)
|
||||
return p1, p2
|
||||
|
||||
|
||||
def least_heat_loss(grid, minsteps, maxsteps):
|
||||
target = max(grid)
|
||||
seen = set()
|
||||
queue = [(0, (0, 0), (0, 1), 0)]
|
||||
while queue:
|
||||
cost, pos, direction, steps = heappop(queue)
|
||||
y, x = pos
|
||||
dy, dx = direction
|
||||
|
||||
if pos == target:
|
||||
return cost
|
||||
|
||||
if ((pos, direction, steps)) in seen:
|
||||
continue
|
||||
|
||||
seen.add((pos, direction, steps))
|
||||
|
||||
if steps >= minsteps:
|
||||
cwdy, cwdx = clockwise(*direction)
|
||||
if (cw := (y + cwdy, x + cwdx)) in grid:
|
||||
cwy, cwx = cw
|
||||
heappush(queue, (cost + grid[cw], (cwy, cwx), (cwdy, cwdx), 1))
|
||||
|
||||
ccwdy, ccwdx = counterclockwise(*direction)
|
||||
if (ccw := (y + ccwdy, x + ccwdx)) in grid:
|
||||
ccwy, ccwx = ccw
|
||||
heappush(queue, (cost + grid[ccw], (ccwy, ccwx), (ccwdy, ccwdx), 1))
|
||||
|
||||
if steps < maxsteps and (fwd := (y + dy, x + dx)) in grid:
|
||||
fwdy, fwdx = fwd
|
||||
heappush(queue, (cost + grid[fwd], (fwdy, fwdx), direction, steps + 1))
|
||||
|
||||
return -1
|
||||
|
||||
|
||||
def clockwise(y, x):
|
||||
"""
|
||||
>>> clockwise(-1, 0)
|
||||
(0, 1)
|
||||
>>> clockwise(0, 1)
|
||||
(1, 0)
|
||||
>>> clockwise(1, 0)
|
||||
(0, -1)
|
||||
>>> clockwise(0, -1)
|
||||
(-1, 0)
|
||||
"""
|
||||
return (x, y) if y == 0 else (x, -y)
|
||||
|
||||
|
||||
def counterclockwise(y, x):
|
||||
"""
|
||||
>>> counterclockwise(-1, 0)
|
||||
(0, -1)
|
||||
>>> counterclockwise(0, -1)
|
||||
(1, 0)
|
||||
>>> counterclockwise(1, 0)
|
||||
(0, 1)
|
||||
>>> counterclockwise(0, 1)
|
||||
(-1, 0)
|
||||
"""
|
||||
return (x, y) if x == 0 else (-x, y)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
with open("./input/17.txt", "r") as f:
|
||||
inp = f.read().strip()
|
||||
|
||||
inp = solve(inp)
|
||||
|
||||
a = part_1(inp)
|
||||
b = part_2(inp)
|
||||
Loading…
Add table
Reference in a new issue