Skip to content

Commit a1586d2

Browse files
committed
Day 11
1 parent 4e1a1f7 commit a1586d2

2 files changed

Lines changed: 130 additions & 0 deletions

File tree

src/main/kotlin/y25/Day11.kt

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package y25
2+
3+
import com.google.common.graph.Graph
4+
import com.google.common.graph.GraphBuilder
5+
import com.google.common.graph.Graphs
6+
import common.puzzle.solvePuzzle
7+
import common.puzzle.Input
8+
import common.puzzle.Puzzle
9+
import common.datastructures.*
10+
import common.ext.*
11+
import common.util.*
12+
import java.util.*
13+
import kotlin.math.*
14+
import kotlin.system.exitProcess
15+
16+
17+
fun main() = solvePuzzle(year = 2025, day = 11) { Day11(it) }
18+
19+
@Suppress("UnstableApiUsage")
20+
class Day11(val input: Input) : Puzzle {
21+
22+
private fun parseInput(): Graph<String> {
23+
val graph = GraphBuilder<String>.directed().build<String>()
24+
25+
input.lines.forEach { line ->
26+
val (node, outputs) = line.split(": ")
27+
val outputNodes = outputs.split(" ")
28+
outputNodes.forEach { outputNode ->
29+
graph.putEdge(node, outputNode)
30+
}
31+
}
32+
33+
return graph
34+
}
35+
36+
data class Memoized(
37+
val node: String,
38+
val missingNodes: Set<String>,
39+
)
40+
41+
private fun Graph<String>.pathsToNode(
42+
from: String,
43+
target: String,
44+
requiredNodes: MutableSet<String>,
45+
visited: MutableSet<String> = mutableSetOf(),
46+
cache: MutableMap<Memoized, Long> = mutableMapOf(),
47+
): Long {
48+
if (from == target) return if (requiredNodes.isEmpty()) 1 else 0
49+
50+
if (from in visited) {
51+
// Found cycle, ignore.
52+
return 0
53+
}
54+
visited += from
55+
56+
var addBack = false
57+
if (from in requiredNodes) {
58+
requiredNodes -= from
59+
addBack = true
60+
}
61+
62+
val memo = Memoized(from, requiredNodes.toSet())
63+
val result = cache[memo] ?: successors(from).sumOf { neigh ->
64+
pathsToNode(neigh, target, requiredNodes, visited, cache)
65+
}.also { cache[memo] = it }
66+
67+
if (addBack) {
68+
requiredNodes += from
69+
}
70+
visited -= from
71+
72+
return result
73+
}
74+
75+
override fun solveLevel1(): Any {
76+
val graph = parseInput()
77+
return graph.pathsToNode("you", "out", mutableSetOf())
78+
}
79+
80+
override fun solveLevel2(): Any {
81+
val graph = parseInput()
82+
return graph.pathsToNode("svr", "out", mutableSetOf("dac", "fft"))
83+
}
84+
}

src/test/kotlin/y25/Day11Test.kt

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package y25
2+
3+
import common.puzzle.Input
4+
import org.junit.jupiter.api.Assertions.assertEquals
5+
import org.junit.jupiter.api.Test
6+
7+
internal class Day11Test {
8+
private val sample = Input("""
9+
aaa: you hhh
10+
you: bbb ccc
11+
bbb: ddd eee
12+
ccc: ddd eee fff
13+
ddd: ggg
14+
eee: out
15+
fff: out
16+
ggg: out
17+
hhh: ccc fff iii
18+
iii: out
19+
""".trimIndent())
20+
21+
private val day = Day11(sample)
22+
23+
@Test
24+
fun solveLevel1() {
25+
assertEquals(5L, day.solveLevel1())
26+
}
27+
28+
@Test
29+
fun solveLevel2() {
30+
assertEquals(2L, Day11(Input("""
31+
svr: aaa bbb
32+
aaa: fft
33+
fft: ccc
34+
bbb: tty
35+
tty: ccc
36+
ccc: ddd eee
37+
ddd: hub
38+
hub: fff
39+
eee: dac
40+
dac: fff
41+
fff: ggg hhh
42+
ggg: out
43+
hhh: out
44+
""".trimIndent())).solveLevel2())
45+
}
46+
}

0 commit comments

Comments
 (0)