generated from Jadarma/advent-of-code-kotlin-template
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathY2015D14.kt
56 lines (44 loc) · 2.12 KB
/
Y2015D14.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
package aockt.y2015
import io.github.jadarma.aockt.core.Solution
object Y2015D14 : Solution {
private data class Reindeer(val name: String, val speed: Int, val sprint: Int, val rest: Int)
private val inputRegex =
Regex("""(\w+) can fly (\d+) km/s for (\d+) seconds, but then must rest for (\d+) seconds\.""")
/** Parses a single line of input and returns a [Reindeer] and its statistics. */
private fun parseInput(input: String): Reindeer {
val (name, speed, sprint, rest) = inputRegex.matchEntire(input)!!.destructured
return Reindeer(name, speed.toInt(), sprint.toInt(), rest.toInt())
}
/** Calculates the total distance this [Reindeer] travelled after exactly this many [seconds]. */
private fun Reindeer.distanceAfter(seconds: Int): Int {
val cycle = sprint + rest
val completeCycles = seconds / cycle
val moduloSprint = minOf(sprint, seconds % cycle)
return (completeCycles * sprint + moduloSprint) * speed
}
/** Races the [contestants], returning their associated scores after each increment (in seconds). */
private fun reindeerRace(contestants: List<Reindeer>) = sequence<Map<Reindeer, Int>> {
val currentScore = contestants.associateWithTo(mutableMapOf()) { 0 }
var seconds = 0
yield(currentScore)
while (true) {
seconds += 1
val reindeerDistances = contestants.associateWith { it.distanceAfter(seconds) }
val maxDistance = reindeerDistances.maxOf { it.value }
reindeerDistances
.filter { it.value == maxDistance }
.forEach { (reindeer, _) -> currentScore[reindeer] = currentScore[reindeer]!! + 1 }
yield(currentScore)
}
}
override fun partOne(input: String) =
input
.lineSequence()
.map(this::parseInput)
.map { it.distanceAfter(seconds = 2503) }
.maxOrNull()!!
override fun partTwo(input: String): Int {
val contestants = input.lines().map(this::parseInput)
return reindeerRace(contestants).elementAt(2503).maxOf { it.value }
}
}