use std::{collections::HashMap, str::FromStr}; use itertools::Itertools; #[derive(Clone)] pub struct Polymer { pub first: char, pub last: char, pub map: HashMap<(char, char), usize>, } impl FromStr for Polymer { type Err = &'static str; fn from_str(s: &str) -> Result { let mut map = HashMap::new(); for neighbours in s.chars().tuple_windows::<(char, char)>() { map.entry(neighbours) .and_modify(|count| *count += 1) .or_insert(1); } let first = s.chars().next().unwrap(); let last = s.chars().last().unwrap(); Ok(Self { first, last, map }) } } #[derive(Copy, Clone)] pub struct Rule { pub neighbours: (char, char), pub separator: char, } pub struct Rules { pub map: HashMap<(char, char), char>, } impl TryFrom> for Rules { type Error = &'static str; fn try_from(rule_vec: Vec) -> Result { if rule_vec.is_empty() { return Err("rule set can't be empty"); } let mut rules = Rules { map: Default::default(), }; for rule in rule_vec { if rules.map.contains_key(&rule.neighbours) { return Err("ambigous rule set"); } rules.map.insert(rule.neighbours, rule.separator); } Ok(rules) } } impl Polymer { pub fn apply(&mut self, rules: &Rules) { let mut new_map = HashMap::new(); for (neighbours, count) in self.map.iter() { if let Some(separator) = rules.map.get(neighbours) { new_map .entry((neighbours.0, *separator)) .and_modify(|old_count| *old_count += count) .or_insert(*count); new_map .entry((*separator, neighbours.1)) .and_modify(|old_count| *old_count += count) .or_insert(*count); } else { new_map .entry(*neighbours) .and_modify(|old_count| *old_count += count) .or_insert(*count); } } self.map = new_map } pub fn element_counts(&self) -> HashMap { let mut map = HashMap::new(); map.insert(self.first, 1); map.insert(self.last, 1); for ((left, right), count) in self.map.iter() { map.entry(*left) .and_modify(|old_count| *old_count += count) .or_insert(*count); map.entry(*right) .and_modify(|old_count| *old_count += count) .or_insert(*count); } map.iter() .map(|(element, count)| (*element, count / 2)) .collect() } } pub struct Input { pub polymer: Polymer, pub rules: Rules, }