1
0
Files
Advent-of-Code/days/src/main/kotlin/Day19.kt
T
2020-12-19 23:00:37 +01:00

160 lines
5.0 KiB
Kotlin

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<Int>, val b: List<Int>?) : Rule()
}
@Day(19)
class Day19(@Groups val input: Input<List<List<String>>>) {
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<List<String>>) = lists.reduce { acc, list -> combine(acc, list) }
private fun combine(a: List<String>, b: List<String>): MutableList<String> {
val combinations = mutableListOf<String>()
a.forEach { f ->
b.forEach { s ->
combinations.add(f + s)
}
}
return combinations
}
private fun generateSolutions(
chars: MutableMap<Int, Char>,
rules: MutableMap<Int, MutableList<MutableList<Int>>>,
): Map<Int, List<String>> {
val solutions = mutableMapOf<Int, MutableList<String>>()
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<Int> = 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<String>) = solution.any { it == input }
fun part1(): Int {
val parsedRules = parseRules()
val chars = mutableMapOf<Int, Char>()
val rules = mutableMapOf<Int, MutableList<MutableList<Int>>>()
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<Int, List<String>> = generateSolutions(chars, rules)
val zero = solutions[0]!!
return messages.count { matches(it, zero) }
}
private fun parseRules(): MutableMap<Int, Rule> {
val parsedRules = mutableMapOf<Int, Rule>()
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<Day19>()) {
println(part1())
println(part2())
}