59 lines
2.3 KiB
Kotlin
59 lines
2.3 KiB
Kotlin
package be.vandewalleh.aoc.days
|
|
|
|
import be.vandewalleh.aoc.utils.input.Day
|
|
import be.vandewalleh.aoc.utils.input.Input
|
|
import be.vandewalleh.aoc.utils.input.Lines
|
|
import org.eclipse.collections.api.factory.Bags
|
|
import org.eclipse.collections.api.multimap.set.MutableSetMultimap
|
|
import org.eclipse.collections.impl.factory.Multimaps
|
|
|
|
@Day(21)
|
|
class Day21(@Lines val input: Input<List<String>>) {
|
|
private val foods = input.value.map { line ->
|
|
val parOpen = line.indexOf('(')
|
|
val ingredients = line.substring(0 until parOpen - 1).split(" ")
|
|
val allergens = line.substring(parOpen + 1 until line.length - 1).removePrefix("contains ").split(", ")
|
|
ingredients to allergens
|
|
}
|
|
|
|
private val allIngredients = foods.flatMap { it.first }.toSet()
|
|
private val allAllergens = foods.flatMap { it.second }.toSet()
|
|
private val dangerousIngredients = dangerousIngredients()
|
|
|
|
fun part1(): Int {
|
|
val occurrences = Bags.mutable.empty<String>()
|
|
foods.forEach { (ingredients) -> occurrences.addAll(ingredients) }
|
|
return allIngredients.filter { !dangerousIngredients.containsValue(it) }
|
|
.map { ingredient -> occurrences.count { it == ingredient } }
|
|
.sum()
|
|
}
|
|
|
|
fun part2(): String {
|
|
while (!dangerousIngredients.multiValuesView().all { it.size() == 1 }) {
|
|
dangerousIngredients.multiValuesView()
|
|
.filter { it.size() == 1 }
|
|
.map { it.first() }
|
|
.forEach { removeMe ->
|
|
dangerousIngredients.keyMultiValuePairsView()
|
|
.filter { it.two.size() != 1 && it.two.contains(removeMe) }
|
|
.forEach { dangerousIngredients.remove(it.one, removeMe) }
|
|
}
|
|
}
|
|
return dangerousIngredients.keySet().sorted().joinToString(",") { dangerousIngredients.get(it).first() }
|
|
}
|
|
|
|
private fun dangerousIngredients(): MutableSetMultimap<String, String> {
|
|
val map = Multimaps.mutable.set.empty<String, String>()
|
|
allAllergens.forEach { map.putAll(it, allIngredients) }
|
|
|
|
foods.forEach { (ingredients, allergens) ->
|
|
allergens.forEach { allergen ->
|
|
allIngredients.forEach {
|
|
if (!ingredients.contains(it)) map.remove(allergen, it)
|
|
}
|
|
}
|
|
}
|
|
return map
|
|
}
|
|
}
|