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>) { 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, val b: List?) : Rule() { val all get() = listOfNotNull(a, b) } } private fun parseRules(): Map { 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 } 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) } } }