-
Notifications
You must be signed in to change notification settings - Fork 0
/
day21.go
146 lines (132 loc) · 3.96 KB
/
day21.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
package main
import (
"fmt"
"io/ioutil"
"os"
"sort"
"strings"
)
func main() {
i, err := ioutil.ReadFile("input.txt")
if err != nil {
os.Exit(1)
}
input := string(i)
fmt.Printf("Part 1: %v\n", SolveDay21Part1(stringListToSlice(input)))
fmt.Printf("Part 2: %v\n", SolveDay21Part2(stringListToSlice(input)))
}
//SolveDay21Part1 counts the listed ingredient that are not a allergen
func SolveDay21Part1(input []string) (s int) {
allergenTranslate, ingredientsList := readIngredientList(input)
ingredientCache := make(map[string]bool)
//count each non allergen ingredient
for _, ingredient := range ingredientsList {
if _, ok := ingredientCache[ingredient]; ok {
if !ingredientCache[ingredient] {
s++
}
continue
}
var found bool
for _, allergen := range allergenTranslate {
if ingredient == allergen {
found = true
ingredientCache[ingredient] = true
break
}
}
if !found {
ingredientCache[ingredient] = false
s++
}
}
return s
}
//SolveDay21Part2 returns comma separated list of the allergens (sort alphabetically by the english name)
func SolveDay21Part2(input []string) (list string) {
allergenTranslate, _ := readIngredientList(input)
var keys []string
for k := range allergenTranslate {
keys = append(keys, k)
}
sort.Strings(keys)
// generate list
for _, key := range keys {
list += allergenTranslate[key]
list += ","
}
list = strings.TrimSuffix(list, ",")
return
}
//readIngredientList reads the input an returns a dict of allergen [english]otherLang and a list of all ingredients
func readIngredientList(input []string) (allergenDictionary map[string]string, ingredientsList []string) {
var allergenTranslateCandidates map[string][]string
//read input
ingredientsPerAllergen := make(map[string][]string)
for _, line := range input {
splitLine := strings.Split(line, " (contains ")
for _, ingredient := range strings.Split(splitLine[0], " ") {
ingredientsList = append(ingredientsList, ingredient)
}
allergensList := strings.Split(strings.Trim(splitLine[1], ")"), ", ")
for _, allergen := range allergensList {
ingredientsPerAllergen[allergen] = append(ingredientsPerAllergen[allergen], splitLine[0])
}
}
//find the possible translation candidates for each allergen
allergenTranslateCandidates = make(map[string][]string)
for allergenEnglish, allergen := range ingredientsPerAllergen {
tmp := make(map[string]int)
for _, ingredientList := range allergen {
for _, ingredient := range strings.Split(ingredientList, " ") {
tmp[ingredient]++
}
}
for ingredient, count := range tmp {
if count == len(allergen) {
allergenTranslateCandidates[allergenEnglish] = append(allergenTranslateCandidates[allergenEnglish], ingredient)
}
}
}
// resolve allergen translation
allergenDictionary = make(map[string]string)
allergenSize := len(allergenTranslateCandidates)
for {
for english, otherLang := range allergenTranslateCandidates {
if len(otherLang) == 1 {
allergenDictionary[english] = otherLang[0]
}
}
if len(allergenDictionary) == allergenSize {
break
}
newAllergenTranslateCandidates := make(map[string][]string)
for english, otherLangList := range allergenTranslateCandidates {
for _, otherLang := range otherLangList {
found := false
for _, alreadyFound := range allergenDictionary {
if otherLang == alreadyFound {
found = true
break
}
}
if !found {
newAllergenTranslateCandidates[english] = append(newAllergenTranslateCandidates[english], otherLang)
}
}
}
allergenTranslateCandidates = make(map[string][]string)
for i, val := range newAllergenTranslateCandidates {
allergenTranslateCandidates[i] = val
}
}
return allergenDictionary, ingredientsList
}
//Helper functions
//stringListToSlice converts the list of strings (each string one row) to a slice
func stringListToSlice(list string) (s []string) {
for _, line := range strings.Split(strings.TrimSuffix(list, "\n"), "\n") {
s = append(s, line)
}
return
}