generated from kotlin-hands-on/advent-of-code-kotlin-template
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDay08.kt
125 lines (105 loc) · 3.28 KB
/
Day08.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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package year2023.`08`
import readInput
import utils.lcm
import utils.printlnDebug
private const val CURRENT_DAY = "08"
private data class Node(
val data: String,
val left: String,
val right: String,
)
private fun parseLineIntoNode(line: String): Node {
val a = line.substring(0, 3)
val b = line.substring(7, 10)
val c = line.substring(12, 15)
return Node(a, b, c).also {
printlnDebug { it }
}
}
private fun countStepsUntilFound(
destinations: Map<String, Node>,
directions: String,
initNode: Node,
isFound: (String) -> Boolean,
): Int {
var directionsIterator = directions.iterator()
printlnDebug { "INIT NODE : $initNode" }
var count = 0
var currentNode = initNode
while (directionsIterator.hasNext() && isFound(currentNode.data).not()) {
count++
currentNode = step(
direction = directionsIterator.next(),
destinations = destinations,
currentNode = currentNode,
)
printlnDebug { "NEW NODE : $currentNode" }
if (isFound(currentNode.data)) {
printlnDebug { "FOUND NODE: $currentNode" }
return count
}
if (directionsIterator.hasNext().not()) {
directionsIterator = directions.iterator()
}
}
error("it should never arrive there")
}
private fun step(
direction: Char,
destinations: Map<String, Node>,
currentNode: Node,
): Node {
val nextKey = when (direction) {
'R' -> currentNode.right
'L' -> currentNode.left
else -> error("Illegal step $direction")
}
return destinations[nextKey] ?: error("step: $nextKey is not found")
}
private fun prepareDestinations(input: List<String>): Map<String, Node> {
val destinations = mutableMapOf<String, Node>()
input
.drop(2)
.map { parseLineIntoNode(it) }
.onEach { destinations[it.data] = it }
return destinations
}
fun main() {
fun part1(input: List<String>): Int {
val destinations = prepareDestinations(input)
val firstLine = input.first()
return countStepsUntilFound(
destinations = destinations,
directions = firstLine,
initNode = destinations["AAA"]!!,
isFound = { it == "ZZZ" }
)
}
fun part2(input: List<String>): Long {
val destinations = prepareDestinations(input)
val directionsLine = input.first()
val allFoundCounts = destinations.values
.filter { it.data.endsWith("A") }
.map { node ->
countStepsUntilFound(
destinations = destinations,
directions = directionsLine,
initNode = node,
isFound = { cur -> cur.endsWith("Z") }
)
.also { printlnDebug { "node $node count = $it" } }
}
.map { it.toLong() }
return allFoundCounts.fold(allFoundCounts.first()) { acc, i -> lcm(acc, i) }
}
// test if implementation meets criteria from the description, like:
val input = readInput("Day$CURRENT_DAY")
// Part 1
val part1 = part1(input)
println(part1)
check(part1 == 19951)
// Part 2
val part2 = part2(input)
println(part2)
check(part2 == 16342438708751)
}