From 8115b1c8ae674442ddd3069e1496abb7c7dc1747 Mon Sep 17 00:00:00 2001 From: Chris Hodges Date: Tue, 19 Dec 2023 15:28:31 +0100 Subject: [PATCH] Solved Part 2. Change-Id: I5c3cab0446cb4761f9f6b97cc111b132da168475 --- src/aoc2023/Day19.kt | 119 ++++++++++++++++++------------------------- 1 file changed, 50 insertions(+), 69 deletions(-) diff --git a/src/aoc2023/Day19.kt b/src/aoc2023/Day19.kt index 9f98c0a..c42edde 100644 --- a/src/aoc2023/Day19.kt +++ b/src/aoc2023/Day19.kt @@ -78,7 +78,7 @@ hdj{m>838:A,pv} data class RuleCondition(val attr: Int = 0, val isSmaller: Boolean = false, val value: Int = 0, val follow: String) - fun part1(input: List): Int { + fun createMap(input: List): Pair>> { val ruleMap = HashMap>() var p = 0 do { @@ -102,10 +102,16 @@ hdj{m>838:A,pv} if (input[p].isBlank()) break p++ } while (true) + return p to ruleMap + } + fun part1(input: List): Int { + val (p, ruleMap) = createMap(input) var sum = 0 for (pp in p + 1 until input.size) { - val attrs = input[pp].split("=", ",", "x", "m", "a", "s", "{", "}").filter { it.isNotBlank() }.map { it.toInt() }.toIntArray() + val attrs = + input[pp].split("=", ",", "x", "m", "a", "s", "{", "}").filter { it.isNotBlank() }.map { it.toInt() } + .toIntArray() var ruleId = "in" while (ruleId != "A" && ruleId != "R") { val conditions = ruleMap[ruleId]!! @@ -130,74 +136,49 @@ hdj{m>838:A,pv} return sum } - fun part2(input: List): Long { - val ruleMap = HashMap>() - var p = 0 - do { - "([a-z]+)\\{(.*)}".toRegex().matchEntire(input[p])?.destructured - ?.let { (id, rules) -> - val rulesList = rules.split(",").map { - if (it.contains("<")) { - val (attr, rest) = it.split("<") - val (value, branchId) = rest.split(":") - RuleCondition("xmas".indexOf(attr), true, value.toInt(), branchId) - } else if (it.contains(">")) { - val (attr, rest) = it.split(">") - val (value, branchId) = rest.split(":") - RuleCondition("xmas".indexOf(attr), false, value.toInt(), branchId) - } else { - RuleCondition(follow = it) - } - } - ruleMap[id] = rulesList - } - if (input[p].isBlank()) break - p++ - } while (true) - var prod = 1L - for (attridx in 0..3) { - var numaccept = 0 - for (attrvalue in 1..4000) { - val destRules = HashSet() - val destRulesWithCond = HashSet() - val ruleQueue = ArrayDeque() - val ruleWithCondQueue = ArrayDeque() - ruleQueue.add("in") - var rejected = false - while (ruleQueue.isNotEmpty()) { - val ruleId = ruleQueue.removeFirst() - if (ruleId == "R" || ruleId == "A") continue - val conditions = ruleMap[ruleId]!! - for (cond in conditions) { - if (cond.value != 0 && cond.attr == attridx) { - val accept = if (cond.isSmaller) { - attrvalue < cond.value - } else { - attrvalue > cond.value - } - if (accept) { - if (!destRulesWithCond.contains(cond.follow)) { - destRules.add(cond.follow) - destRulesWithCond.add(cond.follow) - ruleQueue.add(cond.follow) - } - } - } else { - if (!destRules.contains(cond.follow)) { - destRules.add(cond.follow) - ruleQueue.add(cond.follow) - } - if (destRulesWithCond.contains(ruleId)) { - destRulesWithCond.add(cond.follow) - } - } - } - } - if (destRulesWithCond.contains("A")) numaccept++ - } - prod *= numaccept + fun recurse(ruleMap: Map>, ranges: List, ruleId: String): Long { + if (ruleId == "A") { + return ranges.map { (it.last - it.first + 1).coerceAtLeast(0).toLong() }.reduce(Long::times) } - return prod + if (ruleId == "R") return 0 + var result = 0L + val conditions = ruleMap[ruleId]!! + var currRanges = ranges + for (cond in conditions) { + if (cond.value != 0) { + if (cond.isSmaller) { + val subRange = currRanges.mapIndexed { index, intRange -> + if (index != cond.attr) intRange else + IntRange(intRange.first, intRange.last.coerceAtMost(cond.value - 1)) + } + result += recurse(ruleMap, subRange, cond.follow) + currRanges = currRanges.mapIndexed { index, intRange -> + if (index != cond.attr) intRange else + IntRange(intRange.first.coerceAtLeast(cond.value), intRange.last) + } + } else { + val subRange = currRanges.mapIndexed { index, intRange -> + if (index != cond.attr) intRange else + IntRange(intRange.first.coerceAtLeast(cond.value + 1), intRange.last) + } + result += recurse(ruleMap, subRange, cond.follow) + currRanges = currRanges.mapIndexed { index, intRange -> + if (index != cond.attr) intRange else + IntRange(intRange.first, intRange.last.coerceAtMost(cond.value)) + } + } + } else { + result += recurse(ruleMap, currRanges, cond.follow) + break + } + } + return result + } + + fun part2(input: List): Long { + val (_, ruleMap) = createMap(input) + val ranges = listOf(IntRange(1, 4000), IntRange(1, 4000), IntRange(1, 4000), IntRange(1, 4000)) + return recurse(ruleMap, ranges, "in") } // test if implementation meets criteria from the description, like: