use std::collections::HashMap; use regex::Regex; fn main() { let input = advent::read_lines(16); let search = HashMap::from([ ("children", 3), ("cats", 7), ("samoyeds", 2), ("pomeranians", 3), ("akitas", 0), ("vizslas", 0), ("goldfish", 5), ("trees", 3), ("cars", 2), ("perfumes", 1), ]); println!("16a: {}", find_aunt(&input, &search, false)); println!("16b: {}", find_aunt(&input, &search, true)); } struct Aunt { name: u16, attributes: HashMap, } impl Aunt { fn new(input: &str) -> Aunt { let re = Regex::new(r"([a-z]+): ([0-9]+)").unwrap(); let re_aunt = Regex::new(r"^Sue ([0-9]+):").unwrap(); let name = re_aunt.captures(input).unwrap()[1].parse::().unwrap(); let mut aunt = Aunt { name, attributes: HashMap::new(), }; for cap in re.captures_iter(input) { let attribute = cap[1].to_string(); let amount = cap[2].parse::().unwrap(); aunt.attributes.insert(attribute, amount); } aunt } fn has_attributes(&self, attributes: &HashMap<&str, u8>, outdated: bool) -> bool { if outdated { self.has_attributes_v2(attributes) } else { self.has_attributes_v1(attributes) } } fn has_attributes_v1(&self, attributes: &HashMap<&str, u8>) -> bool { for (attr, val) in attributes { if let Some(myval) = self.attributes.get(*attr) { if myval != val { /* found non-matching attribute */ return false; } } } true } fn has_attributes_v2(&self, attributes: &HashMap<&str, u8>) -> bool { for (attr, val) in attributes { if let Some(myval) = self.attributes.get(*attr) { match attr { x if ["cats", "trees"].contains(x) => if myval <= val { return false; }, x if ["pomeranians", "goldfish"].contains(x) => if myval >= val { return false; }, _ => if myval != val { return false; } } } } true } } fn find_aunt(input: &[String], search: &HashMap<&str, u8>, outdated: bool) -> u16 { input.iter() .map(|x| Aunt::new(x)) .find(|x| x.has_attributes(search, outdated)) .unwrap() .name }