56 lines
2.0 KiB
Kotlin
56 lines
2.0 KiB
Kotlin
package be.vandewalleh.aoc.days
|
|
|
|
import be.vandewalleh.aoc.utils.input.Day
|
|
import be.vandewalleh.aoc.utils.input.Groups
|
|
import java.util.*
|
|
|
|
@Day(19)
|
|
class Day19(@Groups val input: List<List<String>>) {
|
|
private val rules = input[0]
|
|
private val messages = input[1]
|
|
|
|
sealed class Rule {
|
|
data class CharRule(val value: Char) : Rule()
|
|
data class OrRule(val a: List<Int>, val b: List<Int>?) : Rule() {
|
|
val all get() = listOfNotNull(a, b)
|
|
}
|
|
}
|
|
|
|
private fun parseRules(): Map<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
|
|
}
|
|
|
|
private fun matches(input: String, queue: ArrayDeque<Int>, rules: Map<Int, Rule>): 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<Int>().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<Int>().apply { add(0) }, rules) }
|
|
}
|
|
|
|
}
|