|
4 | 4 | # |
5 | 5 |
|
6 | 6 | import sys |
| 7 | +from functools import cache |
7 | 8 |
|
8 | 9 | from aoc.common import InputData |
9 | 10 | from aoc.common import SolutionBase |
10 | 11 | from aoc.common import aoc_samples |
11 | | -from aoc.common import log |
12 | 12 |
|
13 | | -Input = tuple[set[str], list[str]] |
| 13 | +Input = tuple[tuple[str, ...], list[str]] |
14 | 14 | Output1 = int |
15 | 15 | Output2 = int |
16 | 16 |
|
|
32 | 32 | class Solution(SolutionBase[Input, Output1, Output2]): |
33 | 33 | def parse_input(self, input_data: InputData) -> Input: |
34 | 34 | lines = list(input_data) |
35 | | - return set(lines[0].split(", ")), lines[2:] |
| 35 | + return tuple(lines[0].split(", ")), lines[2:] |
| 36 | + |
| 37 | + @cache |
| 38 | + def count(self, design: str, towels: tuple[str]) -> int: |
| 39 | + if len(design) == 0: |
| 40 | + return 1 |
| 41 | + return sum( |
| 42 | + self.count(design[len(towel) :], towels) # noqa E203 |
| 43 | + for towel in towels |
| 44 | + if design.startswith(towel) |
| 45 | + ) |
36 | 46 |
|
37 | 47 | def part_1(self, input: Input) -> Output1: |
38 | 48 | towels, designs = input |
39 | | - possible = set[str](towels) |
40 | | - |
41 | | - def find(w: str, pos: int) -> bool: |
42 | | - if pos == len(w): |
43 | | - return True |
44 | | - pp = [p for p in possible if w[pos:].startswith(p)] |
45 | | - for ppp in pp: |
46 | | - possible.add(w[:pos + len(ppp)]) |
47 | | - return any(find(w, pos + len(ppp)) for ppp in pp) |
48 | | - |
49 | | - ans = 0 |
50 | | - for design in designs: |
51 | | - if find(design, 0): |
52 | | - ans += 1 |
53 | | - return ans |
| 49 | + return sum(self.count(design, towels) > 0 for design in designs) |
54 | 50 |
|
55 | 51 | def part_2(self, input: Input) -> Output2: |
56 | 52 | towels, designs = input |
57 | | - possible = set[str](towels) |
58 | | - |
59 | | - def find(w: str, pos: tuple[int], poss: set[tuple[str, ...]]) -> None: |
60 | | - if sum(pos) == len(w): |
61 | | - ii = 0 |
62 | | - lst = list[str]() |
63 | | - for i in range(1, len(pos)): |
64 | | - lst.append(w[ii:ii+pos[i]]) |
65 | | - ii += pos[i] |
66 | | - if all(_ in towels for _ in lst): |
67 | | - poss.add(tuple(_ for _ in lst)) |
68 | | - return |
69 | | - pp = [p for p in possible if w[sum(pos):].startswith(p)] |
70 | | - for ppp in pp: |
71 | | - possible.add(w[:sum(pos) + len(ppp)]) |
72 | | - tmp = list(pos[:]) + [len(ppp)] |
73 | | - new_pos = tuple(_ for _ in tmp) |
74 | | - find(w, new_pos, poss) |
75 | | - |
76 | | - ans = 0 |
77 | | - for design in designs: |
78 | | - log(f"{design=}") |
79 | | - poss = set[tuple[str, ...]]() |
80 | | - find(design, (0, ), poss) |
81 | | - log(f"{design=}: {len(poss)}: {poss}") |
82 | | - ans += len(poss) |
83 | | - return ans |
| 53 | + return sum(self.count(design, towels) for design in designs) |
84 | 54 |
|
85 | 55 | @aoc_samples( |
86 | 56 | ( |
|
0 commit comments