Advent of Code 2022 day 24
Use breadth-first search. Wasn’t as painful as I had anticipated. Luckily I had abstracted enough in part 1 so that part 2 didn’t require any change to the underlying logic.
with open("24.txt") as f:
data = f.read()
def get_board(data):
return [
list(line) for line in data.splitlines()
]
def get_blizzards(board):
blizzards = dict()
for row in range(len(board)):
for col in range(len(board[0])):
if board[row][col] in (">", "v", "<", "^"):
blizzards[(row, col)] = {board[row][col]}
return blizzards
def get_walls(board):
return [
(row, col)
for row in range(len(board))
for col in range(len(board[0]))
if board[row][col] == "#"
]
blizzard_movement = {
">": (0, 1),
"v": (1, 0),
"<": (0, -1),
"^": (-1, 0),
" ": (0, 0),
}
def add_movement(x, y):
a, b = x
c, d = y
return (a+c, b+d)
def get_answer(board, blizzards, walls):
def is_within_board(pos):
row, col = pos
if row < 0 or row >= len(board):
return False
elif col < 0 or col >= len(board[0]):
return False
return True
def within_board(pos):
row, col = pos
if row < 0 or row >= len(board):
return (row % len(board), col)
elif col < 0 or col >= len(board[0]):
return (row, col % len(board[0]))
return pos
def move_blizzard(pos, blizzard):
new_pos = within_board(add_movement(pos, blizzard_movement[blizzard]))
if new_pos in walls:
return move_blizzard(new_pos, blizzard)
return new_pos
def move_blizzards(blizzard_positions):
new_blizzards = dict()
for pos, blizzards in blizzard_positions.items():
for blizzard in blizzards:
new_pos = move_blizzard(pos, blizzard)
if new_pos in new_blizzards:
new_blizzards[new_pos].add(blizzard)
else:
new_blizzards[new_pos] = {blizzard}
return new_blizzards
def valid_moves(pos):
for move in ">v<^ ":
to = add_movement(pos, blizzard_movement[move])
if (
is_within_board(to) and
pos not in walls and
pos not in blizzards
):
yield to
def get_paths(paths):
new_paths = set()
for pos in paths:
for new_pos in valid_moves(pos):
new_paths.add(new_pos)
return new_paths
start = (0, 1)
end = (len(board)-1, len(board[0])-2)
time = 1
paths = {(start)}
going = True
while going:
time += 1
blizzards = move_blizzards(blizzards)
paths = get_paths(paths)
going = not any(path == end for path in paths)
# # Uncomment this for part 2
# paths = {(end)}
# returning = True
# while returning:
# time += 1
# blizzards = move_blizzards(blizzards)
# paths = get_paths(paths)
# returning = not any(path == start for path in paths)
# paths = {(start)}
# going_back = True
# while going_back:
# time += 1
# blizzards = move_blizzards(blizzards)
# paths = get_paths(paths)
# going_back = not any(path == end for path in paths)
return time
board = get_board(data)
blizzards = get_blizzards(board)
walls = get_walls(board)
print(get_answer(board, blizzards, walls))