package main import ( "bufio" "fmt" "os" "strings" "time" ) func main() { start := time.Now() partOne() duration := time.Since(start) partTwo() duration2 := time.Since(start) fmt.Printf("p1: %s, p2: %s\n", duration, duration2-duration) } type food struct { allergens []string ingredients []string } func intersection(a, b []string) []string { // special-case starting out if len(a) == 0 { return b } else if len(b) == 0 { return a } result := []string{} for _, s := range b { for _, t := range a { if s == t { result = append(result, s) } } } return result } func countSafeIngredients(f food, allergens map[string][]string) int { for c, i := range f.ingredients { for _, l := range allergens { for _, a := range l { if i == a { f.ingredients[c] = "" } } } } result := 0 for _, i := range f.ingredients { if i != "" { result = result + 1 } } return result } func remove(ingredients []string, ingredient string) []string { for i, j := range ingredients { if j == ingredient { ingredients[i] = ingredients[len(ingredients)-1] ingredients[len(ingredients)-1] = "" return ingredients[:len(ingredients)-1] } } return ingredients } func partOne() { f, _ := os.Open("input") reader := bufio.NewReader(f) scanner := bufio.NewScanner(reader) foods := []food{} allergens := map[string][]string{} for scanner.Scan() { line := strings.Split(scanner.Text(), " (contains ") f := food{ ingredients: strings.Split(line[0], " "), allergens: strings.Split(strings.TrimSuffix(line[1], ")"), ", "), } foods = append(foods, f) for _, a := range f.allergens { allergens[a] = intersection(f.ingredients, allergens[a]) } } sum := 0 for _, f := range foods { sum = sum + countSafeIngredients(f, allergens) } fmt.Println(sum) } func partTwo() { f, _ := os.Open("input") reader := bufio.NewReader(f) scanner := bufio.NewScanner(reader) foods := []food{} allergens := map[string][]string{} for scanner.Scan() { line := strings.Split(scanner.Text(), " (contains ") f := food{ ingredients: strings.Split(line[0], " "), allergens: strings.Split(strings.TrimSuffix(line[1], ")"), ", "), } foods = append(foods, f) for _, a := range f.allergens { allergens[a] = intersection(f.ingredients, allergens[a]) } } // hey, this is the same reduction logic as day 16! trueAllergens := map[string]string{} var lastAllergenSolved string for i := 0; i < len(allergens); i = i + 1 { for i, a := range allergens { if len(a) == 1 { trueAllergens[i] = a[0] lastAllergenSolved = a[0] } } for i := range allergens { allergens[i] = remove(allergens[i], lastAllergenSolved) } } formatted := "" // in theory we shouldn't hard-code this allergen order... for _, a := range []string{"dairy", "eggs", "fish", "nuts", "peanuts", "sesame", "soy", "wheat"} { formatted = formatted + trueAllergens[a] + "," } fmt.Println(strings.TrimSuffix(formatted, ",")) }