diff --git a/21/main.go b/21/main.go new file mode 100644 index 0000000..9913102 --- /dev/null +++ b/21/main.go @@ -0,0 +1,138 @@ +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) + } + } + + // formatting the result correctly is left as an exercise for the reader + // because I don't want to deal with go's map order randomization + fmt.Println(trueAllergens) +}