Skip to content

Commit

Permalink
2023 - Day12 - part 1 - dynamic programming - phuuuu
Browse files Browse the repository at this point in the history
  • Loading branch information
fmmr committed Dec 12, 2023
1 parent 996b246 commit c1532eb
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 16 deletions.
83 changes: 72 additions & 11 deletions src/main/kotlin/no/rodland/advent_2023/Day12.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,82 @@ import no.rodland.advent.Day
// template generated: 12/12/2023
// Fredrik Rødland 2023

class Day12(val input: List<String>) : Day<Int, Long, List<Pair<String, List<Int>>>> {
class Day12(val input: List<String>) : Day<Int, Long, List<Day12.Springs>> {

private val parsed = input.parse()

override fun partOne(): Int {
return parsed.sumOf { (candidates, numbers) ->
expand(candidates)
.map { candidate -> candidate.split("\\.+".toRegex()).filterNot { it.isEmpty() } }
.filter { it.size == numbers.size }
.map { strings -> strings.map { it.length } }
.count { it == numbers }
return parsed.sumOf { (pattern, numbers) ->
count(pattern, numbers).toInt()
}
}

override fun partTwo(): Long {
return 2
return parsed.map { it.expand() }.sumOf { (pattern, numbers) ->
count(pattern, numbers)
}
}

private val cache = mutableMapOf<Pair<String, List<Int>>, Long>()
private fun count(pattern: String, groups: List<Int>): Long {
return cache.getOrPut(pattern to groups) {
if (pattern.isEmpty()) {
return if (groups.isEmpty()) 1L else 0L
}
when (pattern[0]) {
'.' -> count(pattern.drop(1), groups)
'#' -> countHash(pattern, groups)
'?' -> count(pattern.drop(1), groups) + count(pattern.replaceFirst('?', '#'), groups)
else -> error("Should not happen")
}
}
}

private fun countHash(pattern: String, groups: List<Int>): Long {
if (groups.isEmpty()) return 0L
val number = groups.first()
return when {
groups.isEmpty() -> 0L
pattern.length < number -> 0L
'.' in pattern.substring(0..<number) -> 0L
pattern.length == number && groups.size == 1 -> 1L
pattern.length == number && groups.size != 1 -> 0L
pattern[number] == '#' -> 0L
else -> count(pattern.drop(number + 1), groups.drop(1))
}
}


// https://www.reddit.com/r/adventofcode/comments/18ge41g/comment/kd0wo99/
// https://github.com/eagely/adventofcode/blob/main/src/main/kotlin/solutions/y2023/Day12.kt
private val mem = hashMapOf<Pair<String, List<Int>>, Long>()

@Suppress("unused")
private fun eagely(config: String, groups: List<Int>): Long {
if (groups.isEmpty()) return if ("#" in config) 0 else 1
if (config.isEmpty()) return 0

return mem.getOrPut(config to groups) {
var result = 0L
if (config.first() in ".?")
result += eagely(config.drop(1), groups)
if (config.first() in "#?" && groups.first() <= config.length && "." !in config.take(groups.first()) && (groups.first() == config.length || config[groups.first()] != '#'))
result += eagely(config.drop(groups.first() + 1), groups.drop(1))
result
}
}

@Suppress("unused")
fun bruteForce(): Int {
return parsed.sumOf { (patterns, numbers) ->
expand(patterns)
.map { pattern -> pattern.split("\\.+".toRegex()).filterNot { it.isEmpty() } }
.filter { it.size == numbers.size }
.map { strings -> strings.map { it.length } }
.count { it == numbers }
}
}

fun expand(input: String): List<String> {
val count = input.count { it == '?' }
val numChars = 1 shl count // 2^count
Expand All @@ -33,14 +90,18 @@ class Day12(val input: List<String>) : Day<Int, Long, List<Pair<String, List<Int
.replace("1", "#")

return (0..<numChars)
.map { boolean -> boolean.toMapString() }
.map { width -> width.toMapString() }
.map { mask -> mask.fold(input) { acc: String, c: Char -> acc.replaceFirst("?", c.toString()) } }
}

override fun List<String>.parse(): List<Pair<String, List<Int>>> {
data class Springs(val pattern: String, val numbers: List<Int>) {
fun expand() = Springs(List(5) { pattern }.joinToString("?"), List(5) { numbers }.flatten())
}

override fun List<String>.parse(): List<Springs> {
return map { line ->
val (first, second) = line.split(" ")
first to second.split(",").map { it.toInt() }
Springs(first, second.split(",").map { it.toInt() })
}
}

Expand Down
10 changes: 5 additions & 5 deletions src/test/kotlin/no/rodland/advent_2023/Day12Test.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ internal class Day12Test {
private val test12 = "2023/input_12_test.txt".readFile()

private val resultTestOne = 21
private val resultTestTwo = 2L
private val resultTestTwo = 525152L
private val resultOne = 7163
private val resultTwo = 2L
private val resultTwo = 17788038834112L

val test = defaultTestSuiteParseOnInit(
Day12(data12),
Expand All @@ -29,8 +29,8 @@ internal class Day12Test {
resultTwo,
{ Day12(data12) },
{ Day12(test12) },
numTestPart1 = 1,
numTestPart2 = 1,
numTestPart1 = 50,
numTestPart2 = 50,
)

@Nested
Expand Down Expand Up @@ -108,7 +108,7 @@ internal class Day12Test {
}

@Test
@Slow(10000)
// @Slow(10000)
fun `12,1,live,1`() {
report(test.livePart1)
}
Expand Down

0 comments on commit c1532eb

Please sign in to comment.