61 lines
2.6 KiB
Rust
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(","));
|
|
}
|