100 lines
2.6 KiB
Python
100 lines
2.6 KiB
Python
#!/usr/bin/env python
|
|
|
|
# https://adventofcode.com/2025/day/7
|
|
|
|
|
|
def read_input(filename: str = "day07input.txt") -> list[list[str]]:
|
|
f = open(filename, "r")
|
|
lines = [l.strip("\n") for l in f.readlines()]
|
|
return [list(line) for line in lines]
|
|
|
|
|
|
# for part 1 we're using a top-down approach
|
|
def beam1(row: int, col: int) -> int:
|
|
# make sure we're inside the field
|
|
assert 0 <= row <= len(field) - 1
|
|
assert 0 <= col <= len(field[0])
|
|
|
|
split_count = 0
|
|
|
|
while row < len(field):
|
|
# continue down from starting position
|
|
if field[row][col] == "S":
|
|
row += 1
|
|
# continue down through empty space
|
|
elif field[row][col] == ".":
|
|
field[row][col] = "|"
|
|
row += 1
|
|
# stop if we're hitting a previous beam
|
|
elif field[row][col] == "|":
|
|
break
|
|
|
|
# split beam
|
|
elif field[row][col] == "^":
|
|
# print(f"splitting beam at {row=} and {col=}")
|
|
split_count += 1
|
|
# left beam
|
|
if col > 0:
|
|
split_count += beam1(row, col - 1)
|
|
# right beam
|
|
if col + 1 < len(field[0]):
|
|
split_count += beam1(row, col + 1)
|
|
# stop current beam
|
|
break
|
|
|
|
else:
|
|
raise Exception(f"unknown character {field[row][col]} in position {row=} and {col=}!")
|
|
|
|
return split_count
|
|
|
|
|
|
# solving part 2 with a bottm-up approach b/c top-down runs in O(2^n)
|
|
def beam2(_field: list[list[str]]) -> int:
|
|
|
|
# count the number of paths from a specific position
|
|
def count_paths(r: int, c: int) -> int:
|
|
# return
|
|
for k in range(r+1, len(_field)):
|
|
# if we encounter a splitter, return its path count
|
|
if isinstance(_field[k][c], int):
|
|
return _field[k][c]
|
|
elif _field[k][c] == "^":
|
|
raise Exception(f"I missed a splitter at row={k} and col={c}!")
|
|
|
|
# if we hit the edge there is only one path
|
|
return 1
|
|
|
|
# loop over all rows that can contain splitters
|
|
for row in range(len(_field) - 2, 0, -2):
|
|
# loop over columns in row
|
|
for col in range(len(_field[row])):
|
|
# if we encounter a splitter, replace it with the number of existing paths starting at its position
|
|
if _field[row][col] == "^":
|
|
field[row][col] = count_paths(row, col - 1) + count_paths(row, col + 1)
|
|
|
|
# print final field
|
|
for line in _field:
|
|
print("".join([str(c) for c in line]))
|
|
|
|
# return the first splitter's path count
|
|
for c in _field[2]:
|
|
if isinstance(c, int):
|
|
return c
|
|
|
|
# part 1
|
|
field = read_input()
|
|
#field = read_input("testinput.txt")
|
|
row, col = 0, field[0].index("S")
|
|
print(beam1(row, col))
|
|
|
|
# print final field
|
|
#for line in field:
|
|
# print("".join(line))
|
|
|
|
|
|
# part 2
|
|
field = read_input()
|
|
#field = read_input("testinput.txt")
|
|
print(beam2(field))
|
|
|