Draget
12/11/2020, 2:25 PMdestructedDraget
12/11/2020, 2:28 PMDraget
12/11/2020, 3:09 PM^(x)*$Draget
12/11/2020, 3:11 PMDraget
12/11/2020, 3:22 PMJoris PZ
12/11/2020, 4:27 PMDraget
12/11/2020, 5:08 PMDraget
12/11/2020, 5:09 PMDraget
12/11/2020, 5:10 PMobject Day07 {
    private const val MAX_DEPTH = 99
    private const val SHINY_BAG = "shiny gold"
    private const val colors = """\w+ \w+"""
    private const val noBags = "no other bags"
    private val rule = Regex("""^($colors) bags contain (.*).$""")
    private val rulePart = Regex("""(\d+) ($colors) bags?|$noBags""")
    private fun rulePartsToColors(ruleParts: String): List<String> =
        if (ruleParts.equals(noBags)) listOf() else rulePart.findAll(ruleParts)
            .mapNotNull { it.destructured }
            .map { (_, allowedColor) -> allowedColor }
            .toList()
    private fun canReachShiny(ruleMap: Map<String, List<String>>, query: String): Boolean =
        canReachShinyRecursive(ruleMap, query, 0)
    private fun canReachShinyRecursive(ruleMap: Map<String, List<String>>, query: String, depth: Int): Boolean {
        if (depth > MAX_DEPTH) throw IllegalStateException("Rules to deep! Depth at $depth")
        if (ruleMap[query]?.contains(SHINY_BAG) == true) return true
        return (ruleMap[query]?.any { canReachShinyRecursive(ruleMap, it, depth + 1) } == true)
    }
    fun solve(inputs: List<String>): Int {
        val ruleMap = inputs.mapNotNull { rule.matchEntire(it)?.destructured }
            .map { (subject, ruleParts) -> subject to rulePartsToColors(ruleParts) }
            .toMap()
        return ruleMap.keys.count { canReachShiny(ruleMap, it) }
    }
}