diff --git a/src/aoc2023/Day12.kt b/src/aoc2023/Day12.kt index d5a3166..28627a7 100644 --- a/src/aoc2023/Day12.kt +++ b/src/aoc2023/Day12.kt @@ -72,70 +72,62 @@ fun main() { ?###???????? 3,2,1 """ - fun solve(input: String, preMatch: Int, regs: List, regPos: Int): Int { - var match = preMatch - var comb = 1 - var currRegPos = regPos - for ((i, p) in input.withIndex()) { - when (p) { - '.' -> - if (currRegPos >= 0 && match != regs[currRegPos]) { - return 0 - } else { - if (match > 0) { - currRegPos-- - } - if (i == input.lastIndex) { - return if (currRegPos < 0) comb else 0 - } - } + val memo = HashMap() - '#' -> if (currRegPos < 0) { - return 0 - } else { - match++ - if (match > regs[currRegPos]) { - return 0 - } - } - - '?' -> if (currRegPos < 0) { - return if (input.subSequence(i, input.length).indexOf("#") < 0) comb else 0 - } else { - // if it was a hash - val s1 = if (match + 1 <= regs[currRegPos]) { - solve(input.substring(i + 1), match + 1, regs, currRegPos) - } else { - 0 - } - val s2 = if (match != regs[currRegPos]) { - 0 - } else { - if (i == input.lastIndex) { - if (currRegPos == 0) comb else 0 - } else { - solve(input.substring(i + 1), 0, regs, currRegPos - 1) - } - } - comb *= (s1 + s2) - } - } + fun fits(input: String, regs: IntArray, inputPos: Int, regPos: Int): Boolean { + if (regPos > regs.lastIndex || inputPos + regs[regPos] > input.length) return false + var ip = inputPos + var e = regs[regPos] + if (input[ip] == '.') ip++ + while ((e > 0) && ip <= input.lastIndex && input[ip++] != '.') { + e-- } - return comb + if (e > 0) return false + return ip > input.lastIndex || input[ip] != '#' } - fun part1(input: List): Int { + fun count(input: String, regs: IntArray, inputPos: Int, regPos: Int): Long { + val memVal = memo[inputPos * 1000 + regPos] + if (memVal != null) return memVal + + //println("$inputPos, $regPos, ${input.substring(inputPos)}") + if (inputPos > input.lastIndex && regPos > regs.lastIndex) return 1 + if (inputPos > input.lastIndex) return 0 + var result = 0L + if (input[inputPos] != '#') { + result += count(input, regs, inputPos + 1, regPos).also { memo[(inputPos + 1) * 1000 + regPos] = it } + } + if (input[inputPos] != '.') { + if (fits(input, regs, inputPos, regPos)) { + val p = inputPos + regs[regPos] + 1 + result += count(input, regs, p, regPos + 1).also { memo[p * 1000 + regPos + 1] = it } + } + } + return result + } + + fun part1(input: List): Long { val results = input.map { val (springline, parms) = it.split(" ") - val reduced = springline.replace("..", ".") + "." - val regs = parms.split(",").map { it.toInt() }.reversed().toList() - solve(reduced, 0, regs, regs.lastIndex) + val reduced = springline.replace("\\.+".toRegex(), ".").trim { it == '.' } + val regs = parms.split(",").map { it.toInt() }.toIntArray() + memo.clear() + count(reduced, regs, 0, 0) } return results.sum() } - fun part2(input: List): Int { - return 0 + fun part2(input: List): Long { + val results = input.map { + val (springline, parms) = it.split(" ") + val reduced = springline.replace("\\.+".toRegex(), ".") + val regs = parms.split(",").map { it.toInt() }.toList() + val regs5 = List(5) { regs }.flatten().toIntArray() + val red5 = List(5) { reduced }.joinToString("?").trim { it == '.' } + memo.clear() + count(red5, regs5, 0, 0) + } + return results.sum() } // test if implementation meets criteria from the description, like: @@ -145,8 +137,8 @@ fun main() { println("Part 1 Test: $testInputPart1Result") val testInputPart2Result = part2(testInput) println("Part 2 Test: $testInputPart2Result") - check(testInputPart1Result == 21) - check(testInputPart2Result == 0) + check(testInputPart1Result == 21L) + check(testInputPart2Result == 525152L) val input = readInput("aoc2023/Day12") part1(input).println()