diff --git a/data/examples/19.txt b/data/examples/19.txt new file mode 100644 index 000000000..29648be --- /dev/null +++ b/data/examples/19.txt @@ -0,0 +1,10 @@ +r, wr, b, g, bwu, rb, gb, br + +brwrr +bggr +gbbr +rrbgbr +ubwu +bwurrg +brgr +bbrgwb diff --git a/src/bin/19.rs b/src/bin/19.rs new file mode 100644 index 000000000..68b0a45 --- /dev/null +++ b/src/bin/19.rs @@ -0,0 +1,71 @@ +use hashbrown::{HashMap, HashSet}; + +fn parse_input(input: &str) -> (HashSet<&str>, HashSet<&str>) { + let (upatterns, udesigns) = input.split_once("\n\n").unwrap(); + + let patterns = upatterns.split(", ").collect(); + let designs = udesigns.split('\n').collect(); + + (patterns, designs) +} + +fn count_pattern_designs<'a>( + memo: &mut HashMap<&'a str, usize>, + patterns: &HashSet<&str>, + pattern: &'a str, +) -> usize { + if pattern.is_empty() { + return 1; + } + + if !memo.contains_key(pattern) { + let mut count = 0; + for p in patterns.iter() { + if let Some(stripped) = pattern.strip_prefix(p) { + count += count_pattern_designs(memo, patterns, stripped) + } + } + memo.insert(pattern, count); + } + + memo[pattern] +} + +pub fn part_one(input: &str) -> Option { + let (patterns, designs) = parse_input(input); + + let mut memo = HashMap::new(); + + for d in designs.iter().copied() { + count_pattern_designs(&mut memo, &patterns, d); + } + + designs.into_iter().filter(|x| memo[x] > 0).count().into() +} + +pub fn part_two(input: &str) -> Option { + let (patterns, designs) = parse_input(input); + + let mut memo = HashMap::new(); + + for d in designs.iter().copied() { + count_pattern_designs(&mut memo, &patterns, d); + } + + designs.into_iter().map(|x| memo[x]).sum::().into() +} + +aoc::solution!(19); + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn test_part_one() { + assert_eq!(part_one(&aoc::template::read_file("examples", 19)), Some(6)); + } + #[test] + fn test_part_two() { + assert_eq!(part_two(&aoc::template::read_file("examples", 19)), Some(16)); + } +}