advent-of-code-2025/day07.py
Tobias Radloff 710fe3f3b2 Day 7
2025-12-07 13:47:14 +01:00

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))