2023/day12/common.py

73 lines
2.2 KiB
Python

from __future__ import annotations
from dataclasses import dataclass
from typing import NamedTuple, NewType, Self
import re
import logging
def im_replace(line: str, mask: str) -> str:
idx = 0
new_line = ""
for c in line:
if c != "?":
new_line += c
else:
new_line += mask[idx]
idx += 1
return new_line
class SpringLine(NamedTuple):
line: str
groups: tuple[int, ...]
def arrangments(self) -> list[str]:
count_im = self.line.count("?")
logging.debug(count_im)
possibles = []
for i in range(pow(2, count_im)):
debug_str = ""
rep_str = f"{i:b}".rjust(count_im, "0").replace("0", ".").replace("1", "#")
debug_str += rep_str + " / "
tentative = im_replace(self.line, rep_str)
possible = SpringLine(tentative, self.groups)
debug_str += str(possible) + ": "
if possible.is_valid():
possibles.append(im_replace(self.line, rep_str))
debug_str += "valid"
else:
debug_str += "invalid"
logging.debug(debug_str)
return possibles
def is_valid(self) -> bool:
pattern = "^\.*" + "\.+".join(["#" * i for i in self.groups]) + "\.*$"
# logging.debug(pattern)
return re.match(pattern, self.line)
def unfold(self) -> SpringLine:
new_line = []
new_groups = []
for i in range(5):
new_line.append(self.line)
new_groups += self.groups
return SpringLine("?".join(new_line), new_groups)
Spring = NewType("Spring", list[SpringLine])
def parse(input_file: str) -> Spring:
spring_lines = []
with open(input_file, "r", encoding="utf-8") as inputfd:
while line := inputfd.readline():
if match := re.match("([?#.]+)\s([0-9,]+)", line):
# logging.debug(match.group(0))
spring_lines.append(
SpringLine(
match.group(1),
tuple(map(lambda c: int(c), match.group(2).split(","))),
)
)
return Spring(spring_lines)