2023/day12 #1

Merged
mikael.capelle merged 5 commits from 2023/day12 into master 2023-12-12 20:20:27 +00:00
Showing only changes of commit edc50cb9c2 - Show all commits

View File

@ -2,31 +2,100 @@ import itertools
import sys import sys
from collections import defaultdict from collections import defaultdict
from dataclasses import dataclass from dataclasses import dataclass
from typing import Iterator
from tqdm import tqdm from tqdm import tqdm
lines = sys.stdin.read().splitlines() lines = sys.stdin.read().splitlines()
def fn1(pattern: str, counts: list[int]) -> Iterator[tuple[str, list[int]]]:
if not pattern:
yield "", counts
return
if not counts:
if pattern.find("#") == -1:
yield "." * len(pattern), []
return
if sum(counts) + len(counts) - 1 == len(pattern):
c_pattern = ".".join("#" * c for c in counts)
if all(pattern[i] == "?" for i in range(len(pattern)) if c_pattern[i] == "."):
yield c_pattern, []
return
if pattern.find("#") == -1:
yield "." * len(pattern), counts
if len(pattern) < counts[0]:
return
if pattern.find("?") == -1 and counts[0] == len(pattern):
yield pattern, counts[1:]
for i in range(len(pattern)):
c_pattern = "." * i + "#" * counts[0]
if len(c_pattern) > len(pattern):
break
if len(c_pattern) < len(pattern):
c_pattern += "."
# print(">", c_pattern, counts[0])
if all(pattern[i] == "?" for i in range(len(c_pattern)) if c_pattern[i] == "."):
for other_pattern, other_rest in fn1(pattern[len(c_pattern) :], counts[1:]):
# print(">>", other_pattern, other_rest)
yield c_pattern + other_pattern, other_rest
def fn2(
patterns: list[str], counts: list[int], depth: int = 0
) -> Iterator[tuple[str, ...]]:
if not patterns:
yield ()
return
with_hash = sum(1 for p in patterns[1:] if p.find("#") >= 0)
# print(patterns, counts, with_hash, counts[:-with_hash])
to_fit = counts if with_hash == 0 else counts[:-with_hash]
remaining = [] if with_hash == 0 else counts[-with_hash:]
for fp, fc in fn1(patterns[0], to_fit):
if depth == 0:
... # print(fp, fc)
for fp2 in fn2(patterns[1:], fc + remaining, depth + 1):
# print(fp, fc)
yield (fp,) + fp2
# print(list(fn1("??", [1, 1, 3, 1])))
# exit()
repeat = 5
count = 0 count = 0
for line in lines: for i_line, line in enumerate(lines):
parts = line.split(" ") parts = line.split(" ")
pattern = parts[0] pattern = "?".join(parts[0] for _ in range(repeat))
counts = [int(c) for c in parts[1].split(",")] counts = [int(c) for c in parts[1].split(",")] * repeat
missing = [i for i in range(len(pattern)) if pattern[i] == "?"] # print("---")
# print(i_line, parts[0])
# print("--")
print("---")
print(parts[0], counts[: len(counts) // 5])
r1 = list(fn2(list(filter(len, pattern.split("."))), counts))
r2 = set(r1)
print(len(r1), len(r2)) # , r2)
count += len(r1)
for replacements in itertools.product(".#", repeat=len(missing)): # if i_line == 1:
c_pattern = list(pattern) # break
for i_missing, replacement in zip(missing, replacements):
c_pattern[i_missing] = replacement
parts = [p for p in "".join(c_pattern).split(".") if p]
if len(parts) == len(counts) and all(
len(p) == c for p, c in zip(parts, counts)
):
# print("".join(c_pattern), counts)
count += 1
# part 1 # part 1
answer_1 = count answer_1 = count
@ -35,4 +104,3 @@ print(f"answer 1 is {answer_1}")
# part 2 # part 2
answer_2 = ... answer_2 = ...
print(f"answer 2 is {answer_2}") print(f"answer 2 is {answer_2}")
print(f"answer 2 is {answer_2}")