advent_of_code/year2015/
day19.rs1use crate::input::Input;
2use std::collections::{HashMap, HashSet};
3
4pub fn solve(input: &Input) -> Result<u32, String> {
5 let mut mappings = HashMap::new();
6 let molecule;
7
8 let mut lines = input.text.lines();
9 loop {
10 if let Some(line) = lines.next() {
11 if line.is_empty() {
12 } else if let Some((part1, part2)) = line.split_once(" => ") {
14 mappings.entry(part1).or_insert_with(Vec::new).push(part2);
15 } else {
16 molecule = line.to_string();
17 break;
18 }
19 } else {
20 return Err("Invalid input".to_string());
21 }
22 }
23
24 if input.is_part_one() {
25 let mut distinct_molecules = HashSet::new();
26 for (&key, values) in mappings.iter() {
27 for (start_idx, _) in molecule.match_indices(key) {
28 for &value in values.iter() {
29 let new_molecule = format!(
30 "{}{}{}",
31 &molecule[..start_idx],
32 value,
33 &molecule[start_idx + key.len()..],
34 );
35 distinct_molecules.insert(new_molecule);
36 }
37 }
38 }
39 Ok(distinct_molecules.len() as u32)
40 } else {
41 let mut count = 0;
42 let mut reversed_molecule = molecule.chars().rev().collect::<String>();
43 let reversed_mappings: Vec<(String, String)> = mappings
44 .into_iter()
45 .flat_map(|(key, values)| {
46 let reversed_key: String = key.chars().rev().collect();
47 values.into_iter().map(move |value| {
48 let reversed_value = value.chars().rev().collect::<String>();
49 (reversed_value, reversed_key.clone())
50 })
51 })
52 .collect();
53
54 while reversed_molecule.len() != 1 {
55 if let Some((idx, key, value)) = reversed_mappings
56 .iter()
57 .filter_map(|(key, value)| reversed_molecule.find(key).map(|idx| (idx, key, value)))
58 .min()
59 {
60 reversed_molecule = format!(
61 "{}{}{}",
62 &reversed_molecule[..idx],
63 value,
64 &reversed_molecule[(idx + key.len())..]
65 );
66 count += 1;
67 } else {
68 return Err(format!("Stuck after {count} steps"));
69 }
70 }
71
72 Ok(count)
73 }
74}
75
76#[test]
77pub fn tests() {
78 let real_input = include_str!("day19_input.txt");
79 test_part_one!(real_input => 509);
80 test_part_two!(real_input => 195);
81}