Skip to content

Latest commit

 

History

History
170 lines (128 loc) · 5.77 KB

24.md

File metadata and controls

170 lines (128 loc) · 5.77 KB

Day 24

Part 1 Part 2 Total
Time 23:58:57 >24h >24h

This is YET another day that I didn't stay up until midnight to do the problem when it came out. I started at 10PM on 12/24 and finished around

Part 1

I first precompute the blizzard patterns, which turns out to be marginally helpful as my paths are only a little longer than the blizzard cycle (300 for me). Then I just bruteforce simulate with BFS and use position and blizzard state as caching. It takes pretty long to run (multiple tens of minutes), perhaps I will come back to it later and optimize because some of the r/adventofcode solutions run in milliseconds.

from helpers.datagetter import data_in, submit
from collections import defaultdict

ans = 0
din = data_in(split=True, numbers=False)
grid = defaultdict(list)
bounds = [len(din[0])-2, len(din)-2]
print(bounds)

for i in range(len(din)):
    for j in range(len(din[0])):
        if din[i][j] not in ["#", "."]:
            grid[(j-1, i-1)].append(din[i][j])

goal = [len(din[0]) - 3, len(din) - 2]
print(goal)
stored_grid = [grid]


def move(grid):
    new_grid = defaultdict(list)
    for key, val in grid.items():
        for bliz in val:
            if bliz == ">":
                new_grid[((key[0] + 1) % bounds[0], (key[1]) % bounds[1])].append(bliz)
            if bliz == "<":
                new_grid[((key[0] - 1) % bounds[0], (key[1]) % bounds[1])].append(bliz)
            if bliz == "^":
                new_grid[((key[0]) % bounds[0], (key[1] - 1) % bounds[1])].append(bliz)
            if bliz == "v":
                new_grid[((key[0]) % bounds[0], (key[1] + 1) % bounds[1])].append(bliz)
    found = new_grid in stored_grid
    if not found:
        stored_grid.append(new_grid)
    return found


while not move(stored_grid[-1]):
    None

start = [0, -1, 1]
new_queue = [[start]]
visited = []

while True:
    queue = new_queue.copy()

    print("QUEUE", len(queue), "PATH", len(queue[0]), "VISITED", len(visited))
    new_queue = []
    while queue:
        path = queue.pop(0)
        node = path[-1]

        grid = stored_grid[node[2] % len(stored_grid)]

        for i in range(-1, 2):
            for j in range(-1, 2):
                if abs(i + j) == 1 or (i == 0 and j == 0):
                    if [node[0] + i, node[1] + j] == goal:
                        print(path + [[node[0] + i, node[1] + j]])
                        print(len(path))
                        exit()

                    if (node[0] + i < 0 or node[0] + i >= bounds[0] or node[1] + j < 0 or node[1] + j >= bounds[1]) and [node[0] + i, node[1] + j] != start[0:2]:
                        continue

                    if grid[(node[0] + i, node[1] + j)] == [] and [node[0] + i, node[1] + j, (node[2] + 1) % len(stored_grid)] not in visited:
                        new_queue.append(path + [[node[0] + i, node[1] + j, (node[2] + 1) % len(stored_grid)]])
                        visited.append([node[0] + i, node[1] + j, (node[2] + 1) % len(stored_grid)])


print(ans)
submit(ans)

Part 2

I turned the search into a function and ran it 3 times, making sure to start at the correct blizzard pattern. It's still running as I type this, but I'm confident it'll produce the correct result. Edit: It did. I skipped doing the first Start to End because we already know the answer. Finished around 1:02 AM on 12/25.

from helpers.datagetter import data_in, submit
from collections import defaultdict

ans = 0
din = data_in(split=True, numbers=False)
grid = defaultdict(list)
bounds = [len(din[0])-2, len(din)-2]
print(bounds)

for i in range(len(din)):
    for j in range(len(din[0])):
        if din[i][j] not in ["#", "."]:
            grid[(j-1, i-1)].append(din[i][j])

goal = [len(din[0]) - 3, len(din) - 2]
print(goal)
stored_grid = [grid]


def move(grid):
    new_grid = defaultdict(list)
    for key, val in grid.items():
        for bliz in val:
            if bliz == ">":
                new_grid[((key[0] + 1) % bounds[0], (key[1]) % bounds[1])].append(bliz)
            if bliz == "<":
                new_grid[((key[0] - 1) % bounds[0], (key[1]) % bounds[1])].append(bliz)
            if bliz == "^":
                new_grid[((key[0]) % bounds[0], (key[1] - 1) % bounds[1])].append(bliz)
            if bliz == "v":
                new_grid[((key[0]) % bounds[0], (key[1] + 1) % bounds[1])].append(bliz)
    found = new_grid in stored_grid
    if not found:
        stored_grid.append(new_grid)
    return found


while not move(stored_grid[-1]):
    None


def bfs(name, start, goal):
    new_queue = [[start]]
    visited = []

    while True:
        queue = new_queue.copy()

        print(name, "QUEUE", len(queue), "PATH", len(queue[0]), "VISITED", len(visited))
        new_queue = []
        while queue:
            path = queue.pop(0)
            node = path[-1]

            grid = stored_grid[node[2] % len(stored_grid)]

            for i in range(-1, 2):
                for j in range(-1, 2):
                    if abs(i + j) == 1 or (i == 0 and j == 0):
                        if [node[0] + i, node[1] + j] == goal:
                            return len(path)

                        if (node[0] + i < 0 or node[0] + i >= bounds[0] or node[1] + j < 0 or node[1] + j >= bounds[1]) and [node[0] + i, node[1] + j] != start[0:2]:
                            continue

                        if grid[(node[0] + i, node[1] + j)] == [] and [node[0] + i, node[1] + j, (node[2] + 1) % len(stored_grid)] not in visited:
                            new_queue.append(path + [[node[0] + i, node[1] + j, (node[2] + 1) % len(stored_grid)]])
                            visited.append([node[0] + i, node[1] + j, (node[2] + 1) % len(stored_grid)])


ans += bfs("First", [0, -1, 1], goal)
ans += bfs("Second", goal + [ans + 1], [0, -1])
ans += bfs("Third", [0, -1, ans + 1], goal)

print(ans)
submit(ans)