Skip to main content

advent_of_code/year2015/
day19.rs

1use 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                // Blank line before last.
13            } 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}