1
0
aoc-2020/21/main.py
2022-05-22 10:38:50 +00:00

79 lines
2.5 KiB
Python

from dataclasses import dataclass
@dataclass
class Food:
ingredients: list[str]
allergens: list[str]
def parse_food(line: str) -> Food:
delim = line.find(" (contains ")
return Food(
ingredients=line[:delim].split(" "),
allergens=line[delim+11:-2].split(", ")
)
def read_input(filename: str) -> list[Food]:
with open(filename, "r") as f:
return list(parse_food(line) for line in f.readlines())
def count_ingredient_occurences(foods: list[Food]) -> dict[str, int]:
ingredient_counts = {}
for food in foods:
for ingredient in food.ingredients:
ingredient_counts[ingredient] = ingredient_counts.get(ingredient, 0) + 1
return ingredient_counts
def get_allergen_map(foods: list[Food]) -> dict[str, set[str]]:
allergen_map = {}
for food in foods:
for allergen in food.allergens:
if allergen in allergen_map:
allergen_map[allergen] = allergen_map[allergen]&set(food.ingredients)
else:
allergen_map[allergen] = set(food.ingredients)
return allergen_map
def part1(foods: list[Food]) -> int:
allergen_map = get_allergen_map(foods)
allergen_ingredients = set()
for ingredients in allergen_map.values():
allergen_ingredients.update(ingredients)
count = 0
ingredient_counts = count_ingredient_occurences(foods)
for ingredient in ingredient_counts.keys():
if ingredient not in allergen_ingredients:
count += ingredient_counts[ingredient]
return count
def find_with_one_ingredient(allergen_map: dict[str, set[str]]) -> tuple[str, str]|None:
for allergen, ingredients in allergen_map.items():
if len(ingredients) == 1:
# `min` is used just, because you can't use indexing on sets
return (allergen, min(ingredients))
def part2(foods: list[Food]) -> str:
allergen_map = get_allergen_map(foods)
allergens = []
while True:
pair = find_with_one_ingredient(allergen_map)
if pair == None:
break
allergens.append(pair)
allergen, ingredient = pair
del allergen_map[allergen]
for ingredients in allergen_map.values():
if ingredient in ingredients:
ingredients.remove(ingredient)
allergens.sort(key=lambda p: p[0])
return ",".join(a[1] for a in allergens)
if __name__ == "__main__":
foods = read_input("input.txt")
print("part1: ", part1(foods))
print("part2: ", part2(foods))