diff --git a/2023-python/output/__init__.py b/2023-python/output/__init__.py index 3a034d6..1ca7273 100644 --- a/2023-python/output/__init__.py +++ b/2023-python/output/__init__.py @@ -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 diff --git a/2023-python/output/day_17.py b/2023-python/output/day_17.py new file mode 100644 index 0000000..3c62d90 --- /dev/null +++ b/2023-python/output/day_17.py @@ -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)