AoC2020/src/day21.rs

61 lines
2.6 KiB
Rust

use std::io::BufRead;
use std::collections::{HashSet, HashMap};
fn parse_input<F: BufRead> (input: F) -> (HashMap<String, u32>, HashMap<String, HashSet<String>>) {
let mut all_ingredients: HashMap<String, u32> = HashMap::new();
let mut alergenes: HashMap<String, HashSet<String>> = HashMap::new();
for line in input.lines().map(|l| l.unwrap()) {
let splited: Vec<_> = line.split('(').collect();
let ingredients: HashSet<_> = splited[0].trim().split(' ').map(String::from).collect();
for ingredient in ingredients.iter() {
let count = all_ingredients.entry(ingredient.to_string()).or_insert(0);
*count += 1;
}
for alergene in splited[1][9..].trim_end_matches(')').split(' ').map(|v| String::from(v.trim_end_matches(','))) {
if alergenes.contains_key(&alergene) {
let current_ingredients = alergenes.remove(&alergene).unwrap();
alergenes.insert(alergene, current_ingredients.intersection(&ingredients).map(String::from).collect());
} else {
alergenes.insert(alergene, ingredients.clone());
}
}
}
(all_ingredients, alergenes)
}
pub fn part1<F: BufRead> (input: F) {
let (all_ingredients, alergenes) = parse_input(input);
let has_alergenes: HashSet<_> = alergenes.values().flat_map(|v| v.iter()).collect();
let ingredients_set: HashSet<_> = all_ingredients.keys().collect();
println!("{}", ingredients_set.difference(&has_alergenes).map(|i| all_ingredients[*i]).sum::<u32>());
}
pub fn part2<F: BufRead> (input: F) {
let (_, mut alergenes) = parse_input(input);
let mut ingredients_set: HashSet<String> = HashSet::new();
while ingredients_set.len() != alergenes.len() {
let mut new_alergenes = HashMap::new();
for (alergene, ingredients) in alergenes {
if ingredients.len() == 1 {
ingredients_set.insert(ingredients.iter().cloned().next().unwrap());
new_alergenes.insert(alergene.clone(), ingredients);
} else {
let new_ingredients: HashSet<String> = ingredients.difference(&ingredients_set).map(String::from).collect();
new_alergenes.insert(alergene.clone(), new_ingredients);
}
}
alergenes = new_alergenes;
}
let mut alergenes = alergenes.drain().map(|(a, mut i)| (a, i.drain().next().unwrap())).collect::<Vec<_>>();
alergenes.sort_by_key(|(a, _)| String::from(a));
let ingredients = alergenes.drain(..).map(|(_, i)| i).collect::<Vec<_>>();
println!("{}", ingredients.join(","));
}