package be.vandewalleh.aoc.days 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() } @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) } } 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 { val parsedRules = mutableMapOf() rules.forEach { val parts = it.split(":", limit = 2) val index = parts[0].toInt() val rule = if ("\"" !in parts[1]) { val p = parts[1].split('|', limit = 2).map { it.trim().split(" ").mapTo(ArrayList(2)) { it.toInt() } } Rule.OrRule(p[0], if (p.size == 2) p[1] else null) } else { Rule.CharRule(parts[1].trim().replace("\"", "")[0]) } parsedRules[index] = rule } return parsedRules } fun part2() { } } fun main() = with(createDay()) { println(part1()) println(part2()) }