package main import ( "bufio" "flag" "fmt" "io" "os" "sort" "strings" ) // Food ... type Food struct { Ingredients []string Allergens []string } func inSlice(s []string, a string) bool { for i := range s { if s[i] == a { return true } } return false } func delFromSlice(s []string, a string) []string { result := make([]string, 0, 10) for i := range s { if s[i] != a { result = append(result, s[i]) } } return result } func intersectSlice(a, b []string) []string { result := make([]string, 0, 10) for i := range a { if inSlice(b, a[i]) && !inSlice(result, a[i]) { result = append(result, a[i]) } } for i := range b { if inSlice(a, b[i]) && !inSlice(result, b[i]) { result = append(result, b[i]) } } return result } func compileIngredients(input []Food) map[string]int { result := make(map[string]int) for _, in := range input { for _, i := range in.Ingredients { result[i]++ } } return result } func findAllergens(input []Food) map[string][]string { result := make(map[string][]string) for { stop := true for _, in := range input { for _, a := range in.Allergens { if _, ok := result[a]; !ok { result[a] = append(result[a], in.Ingredients...) } else { result[a] = intersectSlice(result[a], in.Ingredients) } } } for a, all := range result { if len(all) == 1 { for i := range result { if i != a { result[i] = delFromSlice(result[i], all[0]) } } } else { stop = false } } if stop { break } } return result } // Task1 ... func Task1(input []Food, debug bool) int { ingredients := compileIngredients(input) allergens := findAllergens(input) var result int for i, c := range ingredients { var found bool for _, a := range allergens { if i == a[0] { found = true break } } if !found { result += c } } if debug { fmt.Printf("%+v\n", ingredients) fmt.Printf("%+v\n", allergens) } return result } // Task2 ... func Task2(input []Food, debug bool) string { allergens := findAllergens(input) sorted := make([]string, 0, len(allergens)) for a := range allergens { sorted = append(sorted, a) } sort.Strings(sorted) ingredients := make([]string, 0, len(sorted)) for _, a := range sorted { ingredients = append(ingredients, allergens[a][0]) } return strings.Join(ingredients, ",") } func readInput(reader io.Reader) []Food { input := make([]Food, 0, 10) scanner := bufio.NewScanner(reader) for scanner.Scan() { parts := strings.Split(scanner.Text(), "(contains ") ingredients := strings.Split(strings.TrimSpace(parts[0]), " ") allergens := strings.Split(parts[1][:len(parts[1])-1], ", ") input = append(input, Food{ Ingredients: ingredients, Allergens: allergens, }) } return input } func main() { var debug bool flag.BoolVar(&debug, "debug", false, "debug") flag.Parse() var input []Food file, _ := os.Open("input.txt") input = readInput(file) file.Close() result1 := Task1(input, debug) fmt.Printf("Task 1: %d\n", result1) result2 := Task2(input, debug) fmt.Printf("Task 2: %s\n", result2) }