95 lines
2.5 KiB
Python
95 lines
2.5 KiB
Python
#!/usr/bin/env python
|
|
|
|
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))
|