Skip to content

Commit

Permalink
removed commented-out earlier attempts of day 12, back to long
Browse files Browse the repository at this point in the history
  • Loading branch information
norganos committed Dec 12, 2023
1 parent a2129ea commit d7d3383
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 147 deletions.
140 changes: 10 additions & 130 deletions src/main/kotlin/de/linkel/aoc/Day12.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,63 +3,37 @@ package de.linkel.aoc
import de.linkel.aoc.base.AbstractLinesAdventDay
import de.linkel.aoc.base.QuizPart
import jakarta.inject.Singleton
import java.math.BigInteger
import kotlin.math.max
import kotlin.math.min

@Singleton
class Day12: AbstractLinesAdventDay<BigInteger>() {
class Day12: AbstractLinesAdventDay<Long>() {
override val day = 12

override fun process(part: QuizPart, lines: Sequence<String>): BigInteger {
override fun process(part: QuizPart, lines: Sequence<String>): Long {
return lines
// .take(20)
.map { it.substringBefore(' ') to it.substringAfter(' ').split(",").map(String::toInt).toList() }
.map { (mask, groups) ->
if (part == QuizPart.A) mask to groups
else List(5) { mask }.joinToString("?") to List(5) { groups }.flatten()
}
.sumOf { (mask, groups) ->
val totalHashes = groups.sum()
val filter = mask.replace(".", "\\.").replace("?", ".").toRegex()
val r = countPossibilities2(mask, groups).toBigInteger()
// val r = countPossibilities(mask, 0, groups, totalHashes, filter).toLong()
// val b = bruteForce(mask, groups, filter)
// if (r != b) {
// println("-------------------------------")
// println("$mask ${groups.joinToString(",")}")
// println("algo => $r")
// println("force => $b")
// }
r
countPossibilities(mask, groups)
}
}

private val cache = mutableMapOf<Pair<String,String>,Int>()
private val cache2 = mutableMapOf<String,Long>()
private val groupChars = "?#".toCharArray()
private val cache = mutableMapOf<String,Long>()

// private fun bruteForce(input: String, groups: List<Int>, filter: Regex): Int {
// return if (!input.contains('?')) {
// if (filter.matchEntire(input) != null && input.split(".").filter { it.isNotEmpty() }.map { it.length }.toList() == groups) 1
// else 0
// } else {
// bruteForce(input.replaceFirst('?', '.'), groups, filter) + bruteForce(input.replaceFirst('?', '#'), groups, filter)
// }
// }

private fun countPossibilities2(mask: String, groups: List<Int>): Long {
private fun countPossibilities(mask: String, groups: List<Int>): Long {
return if (mask.isEmpty())
if (groups.isEmpty()) 1L else 0L
else {
val cacheKey = mask + groups.joinToString(",")
cache2[cacheKey] ?: when(mask[0]) {
'.' -> countPossibilities2(mask.substring(1), groups)
cache[cacheKey] ?: when(mask[0]) {
'.' -> countPossibilities(mask.substring(1), groups)
'#' -> consumeGroup(mask, groups)
'?' -> consumeGroup(mask, groups) + countPossibilities2(mask.substring(1), groups)
'?' -> consumeGroup(mask, groups) + countPossibilities(mask.substring(1), groups)
else -> throw Exception("unexpected char...")
}.also {
cache2[cacheKey] = it
cache[cacheKey] = it
}
}
}
Expand All @@ -72,102 +46,8 @@ class Day12: AbstractLinesAdventDay<BigInteger>() {
else if (mask.substring(0, group).contains('.')) 0L
else if (mask.length == group) if (groups.size == 1) 1L else 0L
else if (mask[group] != '#')
countPossibilities2(mask.substring(group+1), groups.drop(1))
countPossibilities(mask.substring(group+1), groups.drop(1))
else 0L
}
}

private fun countPossibilities(mask: String, start: Int, groups: List<Int>, totalHash: Int, filter: Regex): Int {
val groupStart = mask.indexOfAny(groupChars, start)
if (groupStart == -1) {
if (groups.isEmpty()) {
// println("$mask ${groups.joinToString(",")} @$start -> 1 (no group found and nothing to place left)")
return 1
} else {
// println("$mask ${groups.joinToString(",")} @$start -> 0 (no group found but still need to place something)")
return 0
}
}
val groupEnd = mask.indexOf('.', groupStart).let { if (it == -1) mask.length else it }
if (groups.isEmpty()) {
if (mask.substring(groupStart, groupEnd).contains("#")) {
// println("$mask ${groups.joinToString(",")} @$start -> 0 (nothing to place left but group contains #)")
return 0
} else {
// println("$mask ${groups.joinToString(",")} @$start -> 1 (nothing to place left and group can be filled with dots)")
return 1
}
// val groupStart = mask.lastIndexOfAny(groupDelimiters, firstQ)
}
val maxGroupLength = groupEnd - groupStart
val dotsToPlace = mask.length - totalHash - mask.count { it == '.' }
val group = groups.first()
return (
if (maxGroupLength <= dotsToPlace) {
val replacement = ".".repeat(maxGroupLength)
val tailMask = "${mask.substring(0, groupStart)}${replacement}${mask.substring(groupStart+replacement.length)}"

if (filter.matchEntire(tailMask) == null || tailMask.count { it == '#' || it == '?' } < totalHash) {
// println("$tailMask ${groups.joinToString(",")} @${groupStart + replacement.length} -> 0 (does not match pattern / maximum reachable # count too low)")
0
} else {
val cacheKey = tailMask.substring(groupStart + replacement.length) to groups.joinToString(",")
cache[cacheKey] ?: countPossibilities(tailMask, groupStart + replacement.length, groups, totalHash, filter).also { cache[cacheKey] = it }
}
} else 0
) + if (group <= maxGroupLength) {
val potentialDotsInFront = max(min(dotsToPlace, maxGroupLength), 0)
.let {
if (mask[groupStart] == '#') 0 else it // if we have a hash in front of the first question mark, we can't place a dot there
}
(0 until potentialDotsInFront + 1)
.sumOf { dots ->
val replacement = "${".".repeat(dots)}${"#".repeat(group)}".let { if (it.length < maxGroupLength) "$it." else it }
val tailMask = "${mask.substring(0, groupStart)}${replacement}${mask.substring(groupStart+replacement.length)}"
val tailGroup = groups.drop(1)

if (filter.matchEntire(tailMask) == null || tailMask.count { it == '#' || it == '?' } < totalHash || tailMask.count { it == '#' } > totalHash) {
// println("$tailMask ${tailGroup.joinToString(",")} @${groupStart + replacement.length} -> 0 (does not match pattern / maximum reachable # count too low)")
0
} else {
val cacheKey = tailMask.substring(groupStart + replacement.length) to tailGroup.joinToString(",")
cache[cacheKey] ?: countPossibilities(tailMask, groupStart + replacement.length, tailGroup, totalHash, filter).also { cache[cacheKey] = it }
}
}
} else 0
// return groups.toSet().sumOf { group ->
// if (group <= maxGroupLength) {
// val potentialDotsInFront = max(min(dotsToPlace, maxGroupLength - group), 0)
// .let {
// if (firstQ != groupStart) 0 else it // if we have a hash in front of the first question mark, we can't place a dot there
// }
// (0 until potentialDotsInFront + 1)
// .sumOf { dots ->
// val replacement = "${".".repeat(dots)}${"#".repeat(group)}".let { if (it.length < maxGroupLength) "$it." else it }
// val tailMask = "${mask.substring(0, groupStart)}${replacement}${mask.substring(groupStart+replacement.length)}"
// val groupIndex = groups.indexOf(group)
// val tailGroup = groups.filterIndexed { i, _ -> i != groupIndex}
// countPossibilities(tailMask, tailGroup, totalHash, filter)
// }
// } else 0
// }
}
}

fun <T> allPermutations(set: List<T>): Set<List<T>> {
if (set.isEmpty()) return emptySet()

fun <T> _allPermutations(list: List<T>): Set<List<T>> {
if (list.isEmpty()) return setOf(emptyList())

val result: MutableSet<List<T>> = mutableSetOf()
for (i in list.indices) {
_allPermutations(list - list[i]).forEach {
item -> result.add(item + list[i])
}
}
return result
}

return _allPermutations(set)
}
22 changes: 5 additions & 17 deletions src/test/kotlin/de/linkel/aoc/Day12Test.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package de.linkel.aoc

import java.math.BigInteger

class Day12Test: AbstractDayTest<BigInteger>() {
class Day12Test: AbstractDayTest<Long>() {
override val exampleA = """
???.### 1,1,3
.??..??...?##. 1,1,3
Expand All @@ -11,21 +9,11 @@ class Day12Test: AbstractDayTest<BigInteger>() {
????.######..#####. 1,6,5
?###???????? 3,2,1
""".trimIndent()
override val exampleSolutionA = 21L.toBigInteger()
override val solutionA = 7344L.toBigInteger()
override val exampleSolutionA = 21L
override val solutionA = 7344L

override val exampleSolutionB = 525152L.toBigInteger()
override val solutionB = 1379793119L.toBigInteger()
override val exampleSolutionB = 525152L
override val solutionB = 1088006519007L

override val implementation = Day12()
}
/* wrong:
6193
7358
7344
22854629599L
22854629599L
22854629599
1379793119L
1088006519007
*/

0 comments on commit d7d3383

Please sign in to comment.