diff --git a/days/src/main/kotlin/Day19.kt b/days/src/main/kotlin/Day19.kt index a50966b..31a104c 100644 --- a/days/src/main/kotlin/Day19.kt +++ b/days/src/main/kotlin/Day19.kt @@ -4,135 +4,22 @@ import be.vandewalleh.aoc.utils.input.Day import be.vandewalleh.aoc.utils.input.Groups import be.vandewalleh.aoc.utils.input.Input import be.vandewalleh.aoc.utils.input.createDay -import org.slf4j.LoggerFactory - -sealed class Rule { - data class CharRule(val value: Char) : Rule() - data class OrRule(val a: List, val b: List?) : Rule() -} +import java.util.* +import kotlin.collections.ArrayList @Day(19) class Day19(@Groups val input: Input>>) { private val rules = input.value[0] private val messages = input.value[1] - private val logger = LoggerFactory.getLogger("Day19") - - // [[a], [b]] -> [ab] - // [[a], [ab, ba]] -> [aab, aba] - // [[ab, ba], [a]] -> [aba, baa] - // [[a], [b], [c]] -> [abc] - // [[ab], [cd], [e]] -> [abcde] - // [[ab, ba], [cd, e]] -> [abcd, abe, bacd, bae] - // [[ab, ba], [cd, e], [yy, z] -> [abcdyy, abcdz, abeyy, abez, bacdyy, bacdz, baeyy, baez] - private fun combine(lists: List>) = lists.reduce { acc, list -> combine(acc, list) } - - private fun combine(a: List, b: List): MutableList { - val combinations = mutableListOf() - a.forEach { f -> - b.forEach { s -> - combinations.add(f + s) - } + sealed class Rule { + data class CharRule(val value: Char) : Rule() + data class OrRule(val a: List, val b: List?) : Rule() { + val all get() = listOfNotNull(a, b) } - return combinations } - private fun generateSolutions( - chars: MutableMap, - rules: MutableMap>>, - ): Map> { - - val solutions = mutableMapOf>() - - for ((index, char) in chars) { - solutions[index] = mutableListOf(char.toString()) - } - - fun debug() { - if(logger.isDebugEnabled){ - logger.debug("---") - logger.debug(rules.entries.joinToString("\n")) - val prettySolutions = buildString { - append("\nsolutions:") - appendLine() - solutions.entries.forEach { (k, v) -> - append(k) - append(" [") - appendLine() - v.forEach { - append("\t") - append(it) - append("\n") - } - append("]") - appendLine() - } - } - logger.debug(prettySolutions) - } - } - - debug() - - while (rules.isNotEmpty()) { - val mapIterator = rules.iterator() - while (mapIterator.hasNext()) { - val (k, values) = mapIterator.next() - - val valueIterator = values.iterator() - while (valueIterator.hasNext()) { - val value: MutableList = valueIterator.next() - - if (value.any { rules.contains(it) }) continue - - val sol = value.mapNotNull { solutions[it] } - if (sol.size != value.size) continue - - val solution = solutions.computeIfAbsent(k) { mutableListOf() } - - val combined = combine(sol) - solution.addAll(combine(sol)) - - if(logger.isDebugEnabled){ - logger.debug(":::$k") - logger.debug(":::$value") - logger.debug(":::$sol -> $combined") - } - - valueIterator.remove() - } - - if (values.isEmpty()) mapIterator.remove() - } - debug() - } - - return solutions - } - - private fun matches(input: String, solution: List) = solution.any { it == input } - - fun part1(): Int { - val parsedRules = parseRules() - - val chars = mutableMapOf() - val rules = mutableMapOf>>() - - for ((index, rule) in parsedRules) { - when (rule) { - is Rule.CharRule -> chars[index] = rule.value - is Rule.OrRule -> listOfNotNull(rule.a, rule.b) - .forEach { rules.computeIfAbsent(index) { mutableListOf() }.add(it.toMutableList()) } - } - } - - val solutions: Map> = generateSolutions(chars, rules) - val zero = solutions[0]!! - - return messages.count { matches(it, zero) } - } - - private fun parseRules(): MutableMap { + private fun parseRules(): Map { val parsedRules = mutableMapOf() rules.forEach { val parts = it.split(":", limit = 2) @@ -148,9 +35,26 @@ class Day19(@Groups val input: Input>>) { return parsedRules } - fun part2() { + private fun matches(input: String, queue: ArrayDeque, rules: Map): Boolean = + if (queue.isEmpty()) input.isEmpty() + else if (input.isEmpty()) queue.isEmpty() + else when (val rule = rules[queue.pop()]!!) { + is Rule.CharRule -> input[0] == rule.value && matches(input.drop(1), queue, rules) + is Rule.OrRule -> rule.all.any { matches(input, queue.clone().apply { it.asReversed().forEach { addFirst(it) } }, rules) } + } + fun part1(): Int { + val rules = parseRules() + return messages.count { matches(it, ArrayDeque().apply { add(0) }, rules) } } + + fun part2(): Int { + val rules = parseRules().toMutableMap() + rules[8] = Rule.OrRule(listOf(42), listOf(42, 8)) + rules[11] = Rule.OrRule(listOf(42, 31), listOf(42, 11, 31)) + return messages.count { matches(it, ArrayDeque().apply { add(0) }, rules) } + } + } fun main() = with(createDay()) {