aoc/src/day21.rs
2020-12-21 11:15:18 -08:00

76 lines
2.5 KiB
Rust

use crate::split_once;
use aoc_runner_derive::aoc;
use std::collections::{HashMap, HashSet};
#[derive(Debug)]
struct Food<'a> {
ingredients: HashSet<&'a str>,
allergens: HashSet<&'a str>,
}
impl<'a> Food<'a> {
fn parse(input: &'a str) -> Option<Self> {
let (ingredients, allergens) = split_once(input, " (contains ")?;
let allergens = allergens.strip_suffix(")")?;
Some(Food {
ingredients: ingredients.split(" ").collect(),
allergens: allergens.split(", ").collect(),
})
}
}
#[aoc(day21, part1)]
fn solve_d2_p1(input: &str) -> usize {
//let input = EXAMPLE;
let foods: Vec<_> = input.split('\n').map(|l| Food::parse(l).unwrap()).collect();
let mut allergen_causes = HashMap::new();
for food in &foods {
for &allergen in &food.allergens {
let ingredients = allergen_causes
.entry(allergen)
.or_insert_with(|| food.ingredients.clone());
ingredients.retain(|ingredient| food.ingredients.contains(ingredient));
}
}
let possible_allergens: HashSet<_> = allergen_causes.values().flatten().collect();
foods
.iter()
.flat_map(|food| &food.ingredients)
.filter(|ingredient| !possible_allergens.contains(ingredient))
.count()
}
#[aoc(day21, part2)]
fn solve_d2_p2(input: &str) -> String {
let foods: Vec<_> = input.split('\n').map(|l| Food::parse(l).unwrap()).collect();
let mut allergen_causes = HashMap::new();
for food in &foods {
for &allergen in &food.allergens {
let ingredients = allergen_causes
.entry(allergen)
.or_insert_with(|| food.ingredients.clone());
ingredients.retain(|ingredient| food.ingredients.contains(ingredient));
}
}
let mut dangerous_ingredients = Vec::new();
while let Some(&allergen) = allergen_causes
.iter()
.find(|(_k, v)| v.len() == 1)
.map(|(k, _v)| k)
{
let (allergen, mut ingredient) = allergen_causes.remove_entry(allergen).unwrap();
let ingredient = ingredient.drain().next().unwrap();
dangerous_ingredients.push((allergen, ingredient));
for ingredient_set in allergen_causes.values_mut() {
ingredient_set.remove(&ingredient);
}
}
dangerous_ingredients.sort_by(|(a, _), (b, _)| a.cmp(b));
dangerous_ingredients
.into_iter()
.map(|(_allergen, ingredient)| ingredient)
.collect::<Vec<_>>()
.join(",")
}