From 9d15c56597c8f14e380c07799eaa2b8bb7d1949c Mon Sep 17 00:00:00 2001 From: Bruno BELANYI Date: Thu, 22 May 2025 00:23:54 +0100 Subject: [PATCH] 2015: d19: ex1: add solution --- 2015/d19/ex1/ex1.py | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100755 2015/d19/ex1/ex1.py diff --git a/2015/d19/ex1/ex1.py b/2015/d19/ex1/ex1.py new file mode 100755 index 0000000..4f038b2 --- /dev/null +++ b/2015/d19/ex1/ex1.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python + +import collections +import sys +from collections.abc import Iterator + + +def solve(input: str) -> int: + def parse(input: str) -> tuple[dict[str, list[str]], str]: + raw_replacements, molecule = input.strip().split("\n\n") + res: dict[str, list[str]] = collections.defaultdict(list) + for start, end in ( + line.split(" => ") for line in raw_replacements.splitlines() + ): + res[start].append(end) + return res, molecule + + def replace_needle(input: str, needle: str, to: str) -> Iterator[str]: + assert needle in input # Sanity check + i = input.find(needle) + while i != -1: + yield input[:i] + to + input[i + len(needle) :] + i = input.find(needle, i + 1) + + def do_replacements( + replacements: dict[str, list[str]], molecule: str + ) -> Iterator[str]: + for needle, vals in replacements.items(): + if needle not in molecule: + continue + for to in vals: + yield from replace_needle(molecule, needle, to) + + replacements, molecule = parse(input) + new_molecules = set(do_replacements(replacements, molecule)) + return len(new_molecules) + + +def main() -> None: + input = sys.stdin.read() + print(solve(input)) + + +if __name__ == "__main__": + main()