advent24-llm / day06 /solution_jerpint.py
jerpint's picture
Add solution files
a4da721
from dataclasses import dataclass
file = "input.txt"
with open(file) as f:
data = f.readlines()
grid = []
for line in data:
line = line.strip("\n")
grid.append(list(line))
M = len(grid)
N = len(grid[0])
@dataclass
class Position:
i: int
j: int
direction: str
def rotate_90(self):
directions = ["^", ">", "v", "<"]
new_idx = (directions.index(self.direction) + 1) % len(directions)
self.direction = directions[new_idx]
def is_in_bounds(self, grid):
M = len(grid)
N = len(grid[0])
return self.i in range(M) and self.j in range(N)
def get_next_pos(position: Position):
i, j, direction = position.i, position.j, position.direction
if direction == "^":
# Up
i -= 1
elif direction == "v":
# Down
i += 1
elif direction == "<":
# Left
j -= 1
elif direction == ">":
# Right
j += 1
return Position(i, j, direction)
def get_start_pos(grid):
M = len(grid)
N = len(grid[0])
for i in range(M):
for j in range(N):
if grid[i][j] == "^":
return Position(i, j, "^")
def count_Xs(grid):
total = 0
for i in range(M):
for j in range(N):
if grid[i][j] == "X":
total += 1
return total
def pprint(grid, pos = None):
grid_copy = grid.copy()
if pos:
# Print the current position
grid_copy[pos.i][pos.j] = pos.direction
grid_str = ""
for line in grid_copy:
grid_str += "".join(line)
grid_str += "\n"
print("*"*20)
print()
print(grid_str)
print()
print("*"*20)
pos = get_start_pos(grid)
grid[pos.i][pos.j] = "X" # Mark starting point as visited
in_bounds = True
while in_bounds:
# pprint(grid, pos)
next_pos = get_next_pos(pos)
if next_pos.is_in_bounds(grid):
if grid[next_pos.i][next_pos.j] in [".", "X"]:
# Valid next mode, mark as visited and move
grid[pos.i][pos.j] = "X"
pos = next_pos
else:
# Otherwise, rotate
pos.rotate_90()
else:
# Out of bounds, game over
in_bounds = False
grid[pos.i][pos.j] = "X"
pos = None
# pprint(grid, pos)
print(count_Xs(grid))
### Part 2
prev_grid = grid.copy()
def load_grid(file):
with open(file) as f:
data = f.readlines()
grid = []
for line in data:
line = line.strip("\n")
grid.append(list(line))
return grid
def check_is_infinite(grid):
pos = get_start_pos(grid)
grid[pos.i][pos.j] = "X" # Mark starting point as visited
visited = set() # Keep track of positions and orientations
in_bounds = True
infinite_loop = False
while in_bounds and not infinite_loop:
# pprint(grid, pos)
next_pos = get_next_pos(pos)
if next_pos.is_in_bounds(grid):
if grid[next_pos.i][next_pos.j] in [".", "X"]:
# Valid next mode, mark as visited and move
grid[pos.i][pos.j] = "X"
pos = next_pos
else:
# Otherwise, rotate
pos.rotate_90()
set_pos = (pos.i, pos.j, pos.direction)
if set_pos in visited:
infinite_loop = True
else:
visited.add(set_pos)
else:
# Out of bounds, game over
in_bounds = False
grid[pos.i][pos.j] = "X"
pos = None
return infinite_loop
file = "input.txt"
# Load first to get stats
# grid = load_grid(file)
M = len(grid)
N = len(grid[0])
# This is a very brute-force solution, takes long to run...
# For every point, place an obstacle, run the game, check if it gets stuck in infinite loop or not
# Surely, there must be a quicker way, but it works
total = 0
for i in range(M):
for j in range(N):
# Reset grid
grid = load_grid(file)
start_pos = get_start_pos(grid)
if start_pos.i == i and start_pos.j == j:
# Can't set obstacle on starting point, ignore
continue
if prev_grid[i][j] != "X":
# It never passed by there, so we can ignore
continue
# print(i, j)
grid[i][j] = "O" # Set Obstacle
if check_is_infinite(grid):
total += 1
print(total)