import lib from functools import lru_cache EXAMPLE = """ ???.### 1,1,3 .??..??...?##. 1,1,3 ?#?#?#?#?#?#?#? 1,3,1,6 ????.#...#... 4,1,1 ????.######..#####. 1,6,5 ?###???????? 3,2,1 """ @lru_cache def count(elems, groups): if not elems and not groups: return 1 elif elems and not groups: if all(e in ['.', '?'] for e in elems): return 1 return 0 elif not elems and groups: return 0 r = 0 if elems[0] in ['?', '.']: r += count(elems[1:], groups) g = groups[0] if len(elems) < g: return 0 es, rest = elems[:g], elems[g:] if all(e in ['?', '#'] for e in es) and (len(rest) == 0 or rest[0] in ['.', '?']): r += count(rest[1:], groups[1:]) return r def solve(lines: list[str], repeat=1): all = [] for (_, line) in enumerate(lines): springs, numbers = line.split() numbers = tuple(lib.str_to_int_list(numbers)) ns = "?".join([springs for _ in range(repeat)]) all.append((tuple(ns), numbers * repeat)) res = 0 for a in all: # print(a, count(*a)) res += count(*a) # 28:00 # 50:00 total return res def main(): lines = lib.str_to_lines_no_empty(EXAMPLE) print("Example 1:", solve(lines)) lines = lib.str_to_lines_no_empty(open("i12.txt").read()) print("Solution 1:", solve(lines)) lines = lib.str_to_lines_no_empty(EXAMPLE) print("Example 2:", solve(lines, 5)) lines = lib.str_to_lines_no_empty(open("i12.txt").read()) print("Solution 2:", solve(lines, 5)) if __name__ == "__main__": main()