86 lines
2.3 KiB
Python
86 lines
2.3 KiB
Python
|
import sys
|
||
|
|
||
|
|
||
|
def read_data(filepath):
|
||
|
"""Reads the data from the given file."""
|
||
|
try:
|
||
|
with open(filepath, "r") as file:
|
||
|
return file.read().strip().split("\n")
|
||
|
except IOError as e:
|
||
|
print(f"Error reading file '{filepath}': {e}")
|
||
|
sys.exit(1)
|
||
|
|
||
|
|
||
|
def unfold_record(record):
|
||
|
"""Unfolds the record according to the puzzle rules."""
|
||
|
dots, blocks = record.split()
|
||
|
dots = "?".join([dots] * 5)
|
||
|
blocks = ",".join([blocks] * 5)
|
||
|
return dots, [int(x) for x in blocks.split(",")]
|
||
|
|
||
|
|
||
|
def count_arrangements(dots, blocks, i=0, bi=0, current=0, memo=None):
|
||
|
"""Counts valid arrangements using dynamic programming."""
|
||
|
if memo is None:
|
||
|
memo = {}
|
||
|
|
||
|
key = (i, bi, current)
|
||
|
if key in memo:
|
||
|
return memo[key]
|
||
|
|
||
|
if i == len(dots):
|
||
|
if bi == len(blocks) and current == 0:
|
||
|
return 1
|
||
|
elif bi == len(blocks) - 1 and blocks[bi] == current:
|
||
|
return 1
|
||
|
else:
|
||
|
return 0
|
||
|
|
||
|
ans = 0
|
||
|
for c in [".", "#"]:
|
||
|
if dots[i] == c or dots[i] == "?":
|
||
|
if c == ".":
|
||
|
if current == 0:
|
||
|
ans += count_arrangements(dots, blocks, i + 1, bi, 0, memo)
|
||
|
elif current > 0 and bi < len(blocks) and blocks[bi] == current:
|
||
|
ans += count_arrangements(dots, blocks, i + 1, bi + 1, 0, memo)
|
||
|
elif c == "#":
|
||
|
ans += count_arrangements(dots, blocks, i + 1, bi, current + 1, memo)
|
||
|
|
||
|
memo[key] = ans
|
||
|
return ans
|
||
|
|
||
|
|
||
|
def solve_puzzle(lines):
|
||
|
"""Solves the puzzle for the given input lines."""
|
||
|
total = 0
|
||
|
for line in lines:
|
||
|
print(f"Processing: {line}")
|
||
|
dots, blocks = unfold_record(line)
|
||
|
total += count_arrangements(dots, blocks)
|
||
|
return total
|
||
|
|
||
|
|
||
|
def test_puzzle():
|
||
|
"""Runs the puzzle solution on test data."""
|
||
|
test_data = read_data("../test.txt")
|
||
|
print("Running tests...")
|
||
|
test_result = solve_puzzle(test_data)
|
||
|
print(f"Test result: {test_result}")
|
||
|
assert test_result == 525152, "Test failed!"
|
||
|
print("Test passed.")
|
||
|
|
||
|
|
||
|
def main():
|
||
|
"""Main function to run the puzzle solution."""
|
||
|
test_puzzle()
|
||
|
|
||
|
input_data = read_data("../input.txt")
|
||
|
print("Processing input data...")
|
||
|
result = solve_puzzle(input_data)
|
||
|
print(f"Final result: {result}")
|
||
|
|
||
|
|
||
|
if __name__ == "__main__":
|
||
|
main()
|