-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDay21.kt
107 lines (98 loc) · 3.95 KB
/
Day21.kt
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
package aoc2020.day21
import java.io.File
fun readInputToMap(path: String): Day21Input {
val lineList = mutableListOf<String>()
File(path).inputStream().bufferedReader().forEachLine { lineList.add(it) }
val recipesWithAllergens = mutableMapOf<String, MutableSet<Int>>()
val canContain = mutableMapOf<String, MutableSet<String>>()
val recipes = mutableListOf<Pair<List<String>, List<String>>>()
for ((index, line) in lineList.withIndex()) {
val split = line.replace(")", "").split("(contains")
val ingredients = split[0].trim().split(" ")
val allergens = split[1].trim().split(", ")
recipes.add(Pair(ingredients, allergens))
for (allergen in allergens) {
for (ingredient in ingredients)
canContain.getOrPut(ingredient, ::mutableSetOf) += allergen
recipesWithAllergens.getOrPut(allergen, ::mutableSetOf) += index
}
}
return Day21Input(recipesWithAllergens, canContain, recipes)
}
fun countTimesSafeIngredientsAppear(input: Day21Input): Int {
val canContain = input.canContain.toMutableMap()
val recipes = reduceCanContain(input, canContain)
var count = 0
canContain.entries
.filter { it.value.size == 0 }
.forEach { entry ->
repeat(recipes.filter {
it.first.contains(entry.key)
}.size) { count++ }
}
return count
}
private fun reduceCanContain(
input: Day21Input,
canContain: MutableMap<String, MutableSet<String>>
): List<Pair<List<String>, List<String>>> {
val recipesWithAllergens = input.recipesWithAllergens
val recipes = input.recipes
for ((ingredients, allergens) in recipes)
for (ingredient in ingredients)
for (allergen in allergens)
if ((canContain[ingredient] ?: error("")).contains(allergen)) {
for (recipeId in recipesWithAllergens[allergen] ?: error("")) {
if (!recipes[recipeId].first.contains(ingredient)) {
canContain[ingredient]!!.remove(allergen)
break
}
}
}
return recipes
}
fun listIngredientsByAlphabeticalAllergen(input: Day21Input): String {
val canContain = input.canContain.toMutableMap()
reduceCanContain(input, canContain)
val allergens = mutableMapOf<String, Set<String>>()
for (entry in canContain) {
if (entry.value.size != 0) allergens[entry.key] = entry.value
}
val reducedAllergens = mutableListOf<String>()
var sumOfPossibleAllergens = allergens.values.sumBy { it.size }
while (sumOfPossibleAllergens > allergens.size) {
for (entry in allergens.entries) {
val allergen = entry.value.toList()[0]
if (entry.value.size == 1 && !reducedAllergens.contains(allergen)) {
reducedAllergens.add(allergen)
}
}
for (allergen in reducedAllergens)
for (entry in allergens.entries)
if (entry.value.size != 1 && entry.value.contains(allergen)) {
val list = allergens[entry.key]!!.toMutableList()
list.remove(allergen)
allergens[entry.key] = list.toSet()
}
sumOfPossibleAllergens = allergens.values.sumBy { it.size }
}
var reversedMap = mutableMapOf<String, String>()
for (item in allergens.entries) {
reversedMap[item.value.toList()[0]] = item.key
}
reversedMap = reversedMap.toSortedMap(compareBy<String> { it })
return reversedMap.values.toString().replace("[", "").replace("]", "").replace(" ", "")
}
// gpgrb = dairy
// tjlz = eggs
// gtjmd = fish
// spbxz = nuts
// pfdkkzp = peanuts
// xcfpc = shellfish
// txzv = soy
// znqbr = wheat
data class Day21Input(
var recipesWithAllergens: Map<String, MutableSet<Int>>,
var canContain: Map<String, MutableSet<String>>,
var recipes: List<Pair<List<String>, List<String>>>
)