diff --git a/2020/day21.go b/2020/day21.go new file mode 100644 index 0000000..24a2922 --- /dev/null +++ b/2020/day21.go @@ -0,0 +1,134 @@ +package main + +import ( + "fmt" + "os" + "regexp" + "sort" + "strings" + + "git.annabunch.es/annabunches/adventofcode/2020/lib/util" +) + +// could optimize this better with maps, but we'll just do this. Our data set should be small enough +func intersection(a, b []string) (result []string) { + result = make([]string, 0) + for _, av := range a { + for _, bv := range b { + if av == bv { + result = append(result, av) + break + } + } + } + return +} + +func includes(list []string, item string) bool { + for _, cmp := range list { + if cmp == item { + return true + } + } + return false +} + +func remove(list []string, item string) []string { + for i, cmp := range list { + if cmp == item { + return append(list[:i], list[i+1:]...) + } + } + return list +} + +func parseInput(input []string) (ingredients map[string]int, allergens map[string][]string) { + re := regexp.MustCompile("^(.*) \\(contains (.*)\\)") + allergens = make(map[string][]string) + ingredients = make(map[string]int) + for _, line := range input { + data := re.FindStringSubmatch(line) + is := strings.Split(data[1], " ") + as := strings.Split(data[2], ", ") + + for _, ingredient := range is { + ingredients[ingredient]++ + } + + for _, allergen := range as { + if ingredients, ok := allergens[allergen]; ok { + allergens[allergen] = intersection(is, ingredients) + } else { + allergens[allergen] = is + } + } + } + + return +} + +func findUniqueSolution(aMap map[string][]string) { + done := false + for !done { + done = true + for a1, is1 := range aMap { + if len(is1) == 1 { + ingredient := is1[0] + for a2, is2 := range aMap { + if a1 == a2 { + continue + } + aMap[a2] = remove(is2, ingredient) + } + } + } + + for _, is := range aMap { + if len(is) > 1 { + done = false + break + } + } + } +} + +func main() { + step := os.Args[1] + values := util.InputParserStrings(os.Args[2]) + ingredients, allergenMap := parseInput(values) + + switch step { + case "1": + loose := make([]string, 0) + for ingredient, _ := range ingredients { + found := false + for _, is := range allergenMap { + if includes(is, ingredient) { + found = true + break + } + } + if !found { + loose = append(loose, ingredient) + } + } + + total := 0 + for _, i := range loose { + total += ingredients[i] + } + fmt.Println(total) + case "2": + findUniqueSolution(allergenMap) + keys := make([]string, 0) + for k, _ := range allergenMap { + keys = append(keys, k) + } + result := "" + sort.Strings(keys) + for _, k := range keys { + result = result + "," + allergenMap[k][0] + } + fmt.Println(strings.Trim(result, ",")) + } +}