Skip to content

Commit 85ef06a

Browse files
committed
Solution Day 20, part two (Race Condition)
* Shortcuts can now take up to 20 picosenconds * This solution also drastically speeds up part one
1 parent 67eed65 commit 85ef06a

File tree

1 file changed

+25
-38
lines changed

1 file changed

+25
-38
lines changed

src/main/kotlin/Day20.kt

Lines changed: 25 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,19 @@
11
import de.ronny_h.extensions.*
2-
import de.ronny_h.extensions.Direction.*
32

43
fun main() {
54
val day = "Day20"
65

7-
fun part1(input: List<String>, minPicosecondsSaved: Int): Int {
6+
fun part1(input: List<String>, minPicosecondsSaved: Int, shortcutMaxLength: Int): Int {
87
val track = RaceTrack(input)
98
track.printGrid()
10-
val baseline = track.shortestPath().distance
11-
return track.countAllShortcutsShorterThan(baseline - minPicosecondsSaved)
9+
return track.countAllShortcutsSavingAtLeast(minPicosecondsSaved, shortcutMaxLength)
1210
}
1311

14-
fun part1Small(input: List<String>) = part1(input, 10)
15-
fun part1Large(input: List<String>) = part1(input, 100)
12+
fun part1Small(input: List<String>) = part1(input, 10, 2)
13+
fun part1Large(input: List<String>) = part1(input, 100, 2)
1614

17-
fun part2(input: List<String>): Int {
18-
return input.size
19-
}
15+
fun part2Small(input: List<String>) = part1(input, 76, 20)
16+
fun part2Large(input: List<String>) = part1(input, 100, 20)
2017

2118
println("$day part 1")
2219

@@ -45,13 +42,12 @@ fun main() {
4542

4643
println("$day part 2")
4744

48-
printAndCheck(testInput, ::part2, 31)
49-
printAndCheck(input, ::part2, 18805872)
45+
printAndCheck(testInput, ::part2Small, 3)
46+
printAndCheck(input, ::part2Large, 1026446)
5047
}
5148

5249
private class RaceTrack(input: List<String>) : Grid<Char>(input, '#') {
5350
private val wall = nullElement
54-
private val free = '.'
5551
override fun Char.toElementType(): Char = this
5652

5753
private val start = find('S')
@@ -82,32 +78,23 @@ private class RaceTrack(input: List<String>) : Grid<Char>(input, '#') {
8278
return aStar(start, goal, neighbours, d, h)
8379
}
8480

85-
fun countAllShortcutsShorterThan(picoseconds: Int): Int =
86-
forEachCoordinates { pos, elem ->
87-
when {
88-
elem != wall -> null
89-
pos.isOnTheBorder() -> null
90-
pos.canNotBeCrossed() -> null
91-
else -> pos
92-
}
93-
}
94-
.filterNotNull()
95-
.map { coord ->
96-
setAt(coord, free)
97-
val pathWithShortcut = shortestPath()
98-
setAt(coord, wall)
99-
pathWithShortcut.distance
100-
}
101-
.filter { it <= picoseconds }
102-
.count()
103-
104-
private fun Coordinates.isOnTheBorder(): Boolean {
105-
return row == 0 || row == (height - 1) || col == 0 || col == width - 1
106-
}
81+
fun countAllShortcutsSavingAtLeast(minToSave: Int, shortcutMaxLength: Int): Int {
82+
val shortestPath = shortestPath()
83+
val distances = shortestPath.path.reversed().mapIndexed { distanceToGoal, position ->
84+
position to distanceToGoal
85+
}.toMap()
10786

108-
private fun Coordinates.canNotBeCrossed(): Boolean {
109-
return (getAt(this + NORTH) == wall || getAt(this + SOUTH) == wall) &&
110-
(getAt(this + EAST) == wall || getAt(this + WEST) == wall)
111-
}
87+
fun Coordinates.isInShortcutRangeFrom(position: Coordinates): Boolean =
88+
this taxiDistanceTo position <= shortcutMaxLength
89+
90+
fun Coordinates.isShorterToGoalThan(position: Coordinates): Boolean =
91+
distances.getValue(this) + (this taxiDistanceTo position) <= distances.getValue(position) - minToSave
11292

93+
return shortestPath.path.flatMap { position ->
94+
shortestPath
95+
.path
96+
.filter { it.isInShortcutRangeFrom(position) }
97+
.filter { it.isShorterToGoalThan(position) }
98+
}.size
99+
}
113100
}

0 commit comments

Comments
 (0)