1
0

Day19 part2

This commit is contained in:
Hubert Van De Walle 2020-12-23 23:18:34 +01:00
parent d793a47801
commit 0b1ae6e334

View File

@ -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<Int>, val b: List<Int>?) : Rule()
}
import java.util.*
import kotlin.collections.ArrayList
@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)
}
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)
}
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> {
private fun parseRules(): Map<Int, Rule> {
val parsedRules = mutableMapOf<Int, Rule>()
rules.forEach {
val parts = it.split(":", limit = 2)
@ -148,9 +35,26 @@ class Day19(@Groups val input: Input<List<List<String>>>) {
return parsedRules
}
fun part2() {
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) }
}
}
fun main() = with(createDay<Day19>()) {