2023 #1

Open
aey wants to merge 22 commits from 2023 into main
2 changed files with 156 additions and 0 deletions

View file

@ -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
isnt 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

View 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)