generated from kotlin-hands-on/advent-of-code-kotlin-template
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDay12.kt
78 lines (71 loc) Β· 2.95 KB
/
Day12.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
data class Cave(val name: String) {
fun isSmall() = name.all { it.isLowerCase() }
val neighbours = mutableListOf<Cave>()
}
typealias Caves = MutableMap<String, Cave>
fun main() {
fun readCaves(input: List<String>): MutableMap<String, Cave> {
return mutableMapOf<String, Cave>().apply {
input.map {
val (cave1, cave2) = it.split("-")
computeIfAbsent(cave1) { Cave(it) }.neighbours += computeIfAbsent(cave2) { Cave(it) }
get(cave2)!!.neighbours += get(cave1)!!
}
}
}
fun countPaths(start: Cave, end: Cave, cantVisit: Set<Cave>): Int {
return start.neighbours.filter { it !in cantVisit }.sumOf {
if (it == end) 1 else countPaths(it, end, cantVisit + if (it.isSmall()) setOf(it) else emptySet())
}
}
fun countPaths2(
start: Cave,
end: Cave,
cantVisit: Set<Cave>,
visitedTwice: Boolean,
pathSoFar: String,
allPaths: MutableSet<String>,
): Int {
return start.neighbours.filter { it !in cantVisit }.sumOf {
if (it == end) {
val finalPath = "$pathSoFar,end"
if (finalPath !in allPaths) {
allPaths += finalPath
1
} else 0
} else if (it.isSmall()) {
if (visitedTwice) {
// Some small cave already visited twice
countPaths2(it, end, cantVisit + it, true, "$pathSoFar,${it.name}", allPaths)
} else {
// These two cases can lead to the same path in some cases, so need to collect paths in a set
// Visit this small cave again
countPaths2(it, end, cantVisit, true, "$pathSoFar,${it.name}", allPaths) +
// Visit some upcoming small cave again
countPaths2(it, end, cantVisit + it, false, "$pathSoFar,${it.name}", allPaths)
}
} else {
countPaths2(it, end, cantVisit, visitedTwice, "$pathSoFar,${it.name}", allPaths)
}
}
}
fun part1(input: Caves): Int {
return countPaths(input["start"]!!, input["end"]!!, setOf(input["start"]!!))
}
fun part2(input: Caves): Int {
return countPaths2(input["start"]!!, input["end"]!!, setOf(input["start"]!!), false, "start", mutableSetOf())
}
// test if implementation meets criteria from the description, like:
val testInput = readCaves(readInput("Day12_test"))
check(part1(testInput) == 10)
check(part2(testInput) == 36)
val testInput2 = readCaves(readInput("Day12_test2"))
check(part1(testInput2) == 19)
check(part2(testInput2) == 103)
val testInput3 = readCaves(readInput("Day12_test3"))
check(part1(testInput3) == 226)
check(part2(testInput3) == 3509)
val input = readCaves(readInput("Day12"))
println(part1(input))
println(part2(input))
}