Skip to content

Commit 9f15095

Browse files
committed
Day 19 solution
1 parent 40dd2d2 commit 9f15095

File tree

1 file changed

+137
-0
lines changed

1 file changed

+137
-0
lines changed

solutions/day19.py

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
from typing import Dict, List, Tuple
2+
3+
from aoc.models.base import SolutionBase
4+
5+
6+
class TowelSorter:
7+
"""Solution helper for arranging towel patterns.
8+
9+
This class processes towel arrangements where each towel has a specific pattern of
10+
colored stripes. It determines whether sequences can be created using available
11+
towel patterns and counts the number of unique ways to arrange towels to match
12+
desired sequences.
13+
14+
Attributes:
15+
towels (List[str]): Available towel patterns
16+
sequences (List[str]): Desired stripe sequences to match
17+
cache (Dict[str, int]): Memoization cache for sequence arrangements
18+
"""
19+
20+
def __init__(self, towels: List[str], sequences: List[str]) -> None:
21+
"""Initialize TowelSorter with available patterns and target sequences.
22+
23+
Args:
24+
towels (List[str]): List of available towel patterns
25+
sequences (List[str]): List of sequences to match
26+
"""
27+
self.towels = towels
28+
self.sequences = sequences
29+
self.cache: Dict[str, int] = {}
30+
31+
def count_ways(self, seq: str) -> int:
32+
"""Count number of unique ways to arrange towels to match a sequence.
33+
34+
Uses dynamic programming with memoization to efficiently count arrangements
35+
without building complete arrangement lists.
36+
37+
Args:
38+
seq (str): Target sequence to match
39+
40+
Returns:
41+
int: Number of unique ways to arrange towels to match sequence
42+
"""
43+
if not seq:
44+
return 1
45+
46+
if seq in self.cache:
47+
return self.cache[seq]
48+
49+
total = 0
50+
for towel in self.towels:
51+
if seq.startswith(towel):
52+
total += self.count_ways(seq[len(towel) :])
53+
54+
self.cache[seq] = total
55+
return total
56+
57+
def is_possible(self, seq: str) -> bool:
58+
"""Check if a sequence can be created using available towel patterns.
59+
60+
Args:
61+
seq (str): Sequence to check
62+
63+
Returns:
64+
bool: True if sequence can be created, False otherwise
65+
"""
66+
return self.count_ways(seq) > 0
67+
68+
def part1(self) -> int:
69+
"""Count how many sequences are possible with available towel patterns.
70+
71+
Returns:
72+
int: Number of sequences that can be created
73+
"""
74+
return sum(1 for seq in self.sequences if self.is_possible(seq))
75+
76+
def part2(self) -> int:
77+
"""Sum up the number of unique ways each sequence can be created.
78+
79+
Returns:
80+
int: Total number of possible arrangements across all sequences
81+
"""
82+
return sum(self.count_ways(seq) for seq in self.sequences)
83+
84+
85+
class Solution(SolutionBase):
86+
"""Solution for Advent of Code 2023 - Day 19: Linen Layout.
87+
88+
This class solves a puzzle about arranging towels with colored stripe patterns.
89+
Part 1 determines which sequences are possible to create, while Part 2 counts
90+
the total number of unique ways to arrange towels for each sequence.
91+
92+
Input format:
93+
- First line: comma-separated list of available towel patterns
94+
- Blank line
95+
- Remaining lines: sequences to match using available patterns
96+
97+
This class inherits from `SolutionBase` and provides methods to parse input data,
98+
check sequence possibility, and count unique arrangements.
99+
"""
100+
101+
def parse_data(self, data: List[str]) -> Tuple[List[str], List[str]]:
102+
"""Parse input data into towel patterns and target sequences.
103+
104+
Args:
105+
data (List[str]): Raw input lines
106+
107+
Returns:
108+
Tuple[List[str], List[str]]: Tuple of (towel patterns, sequences to match)
109+
"""
110+
towels, seq = "\n".join(data).split("\n\n")
111+
return towels.split(", "), [row for row in seq.split("\n") if row]
112+
113+
def part1(self, data: List[str]) -> int:
114+
"""Solve part 1: Count possible sequences.
115+
116+
Args:
117+
data (List[str]): Input data lines
118+
119+
Returns:
120+
int: Number of sequences that can be created with available patterns
121+
"""
122+
towels, seq = self.parse_data(data)
123+
towel_sorter = TowelSorter(towels, seq)
124+
return towel_sorter.part1()
125+
126+
def part2(self, data: List[str]) -> int:
127+
"""Solve part 2: Count total possible arrangements.
128+
129+
Args:
130+
data (List[str]): Input data lines
131+
132+
Returns:
133+
int: Sum of possible arrangements for all sequences
134+
"""
135+
towels, seq = self.parse_data(data)
136+
towel_sorter = TowelSorter(towels, seq)
137+
return towel_sorter.part2()

0 commit comments

Comments
 (0)