Files
aoc2020/twentyone/day_twentyone.go
James Griffin 9b3b8011df Day 21: Part 1
Signed-off-by: James Griffin <james@unsupervised.ca>
2020-12-21 19:42:24 -04:00

128 lines
2.9 KiB
Go

package twentyone
import (
"bufio"
"fmt"
"os"
"strings"
)
type food struct {
ingredients map[string]bool
allergens []string
}
type list struct {
foods []food
allergens map[string]bool
possibleIngredientAllergens map[string][]string
}
func (l *list) load(filename string) error {
file, err := os.Open(filename)
if err != nil {
return err
}
defer file.Close()
l.allergens = map[string]bool{}
l.possibleIngredientAllergens = map[string][]string{}
scanner := bufio.NewScanner(file)
for scanner.Scan() {
f := food{
ingredients: map[string]bool{},
allergens: []string{},
}
foodParts := strings.Split(scanner.Text(), " (contains ")
if len(foodParts) != 2 {
return fmt.Errorf("Unable to parse %s", scanner.Text())
}
ingredients := strings.Split(foodParts[0], " ")
for _, i := range ingredients {
f.ingredients[i] = true
l.possibleIngredientAllergens[i] = []string{}
}
allergens := strings.Split(foodParts[1], ")")
f.allergens = strings.Split(allergens[0], ", ")
for _, a := range f.allergens {
l.allergens[a] = true
}
l.foods = append(l.foods, f)
}
return nil
}
func (l *list) isolateIngredientAllergens() {
// For each allergen iterate through the foods to find the possible ingredients
for allergen := range l.allergens {
possibleFoods := []food{}
possibleIngredients := map[string]bool{}
// Check food for allergen
for _, f := range l.foods {
for _, a := range f.allergens {
if allergen == a {
possibleFoods = append(possibleFoods, f)
for i := range f.ingredients {
possibleIngredients[i] = true
}
}
}
}
// Go through foods and eliminate ingredients that aren't present
for _, p := range possibleFoods {
for pi := range possibleIngredients {
if !p.ingredients[pi] {
possibleIngredients[pi] = false
}
}
}
for i, cause := range possibleIngredients {
if cause {
l.possibleIngredientAllergens[i] = append(l.possibleIngredientAllergens[i], allergen)
}
}
}
}
func (l *list) countAllergenFreeAppearances() (int, []string) {
count := 0
// Find allergen free ingredients
ingredients := []string{}
for ingredient, allergens := range l.possibleIngredientAllergens {
if len(allergens) == 0 {
ingredients = append(ingredients, ingredient)
}
}
// Count the appearances of the allergen free ingredients in all foods
for _, i := range ingredients {
for _, f := range l.foods {
for ingredient := range f.ingredients {
if i == ingredient {
count++
}
}
}
}
return count, ingredients
}
// PartOne How many times do allergen free ingredients appear
func PartOne() string {
l := list{}
l.load("twentyone/input.txt")
l.isolateIngredientAllergens()
count, ingredients := l.countAllergenFreeAppearances()
return fmt.Sprintf("There are %d appearances of %d allergen free ingredients", count, len(ingredients))
}