package aoc2023 import println import readInput /* --- Day 12: Hot Springs --- https://adventofcode.com/2023/day/12 */ fun main() { val inlineTestInput = """ ???.### 1,1,3 .??..??...?##. 1,1,3 ?#?#?#?#?#?#?#? 1,3,1,6 ????.#...#... 4,1,1 ????.######..#####. 1,6,5 ?###???????? 3,2,1 """ val memo = HashMap() 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-- } if (e > 0) return false return ip > input.lastIndex || input[ip] != '#' } 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("\\.+".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): 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: val testInput = inlineTestInput.trim().reader().readLines() //val testInput = readInput("aoc2023/Day12_test") val testInputPart1Result = part1(testInput) println("Part 1 Test: $testInputPart1Result") val testInputPart2Result = part2(testInput) println("Part 2 Test: $testInputPart2Result") check(testInputPart1Result == 21L) check(testInputPart2Result == 525152L) val input = readInput("aoc2023/Day12") part1(input).println() part2(input).println() }