advent-of-code-2025/day04.py

97 lines
2.5 KiB
Python

#!/usr/bin/env python
# https://adventofcode.com/2025/day/4
f = open("day04input.txt", "r")
#f = open("testinput.txt", "r")
d = [l.strip() for l in f.readlines()]
def day04(data: list[str], remove_rolls: bool = False) -> int:
row_no = len(data)
col_no = len(data[0])
data_list = list("".join(data))
assert row_no * col_no == len(data_list)
offsets = {-col_no - 1, -col_no, -col_no + 1, -1, 1, col_no - 1, col_no, col_no + 1}
offset_l = {-col_no - 1, -1, col_no - 1}
offset_r = {-col_no + 1, 1, col_no + 1}
offset_t = {-col_no - 1, -col_no, -col_no + 1}
offset_b = {col_no - 1, col_no, col_no + 1}
# little debug function that prints the current floor plan
def field_to_str(data_list: list) -> str:
field = ""
for j in range(col_no):
field += "".join(data_list[j*col_no:(j+1)*col_no-1]) + "\n"
return field
# print(f"initial state")
# print(field_to_str(data_list))
def count_rolls(data_list: list) -> int:
iteration_rolls = 0
# loop over data
for i in range(len(data_list)):
# skip if there's no roll on this position
if data_list[i] == ".":
continue
local_offsets = offsets.copy()
# check left edge
if i % col_no == 0:
local_offsets -= offset_l
# check right edge
if i % col_no == col_no - 1:
local_offsets -= offset_r
# check top edge
if i - col_no < 0:
local_offsets -= offset_t
# check bottom edge
if i + col_no >= len(data_list):
local_offsets -= offset_b
assert len(local_offsets) in (3, 5, 8)
# loop over adjacent positions
adjacent_rolls = 0
for o in local_offsets:
# adjacent position is empty
if (c := data_list[i + o]) == ".":
continue
# adjacent position is a roll
elif c in "x@":
adjacent_rolls += 1
# adjacent position is unknown character
else:
raise Exception("arrgh!")
# mark roll as removable
if adjacent_rolls < 4:
iteration_rolls += 1
data_list[i] = "x"
return iteration_rolls
# solve part 1
if not remove_rolls:
return count_rolls(data_list)
# solve part 2
total_rolls = 0
while True:
iteration_rolls = count_rolls(data_list)
if iteration_rolls > 0:
# increase number of removed rolls
total_rolls += iteration_rolls
# remove marked rolls
data_list = list(map(lambda c: "." if c == "x" else c, data_list))
else:
return total_rolls
print(day04(d))
print(day04(d, True))