@@ -10,42 +10,88 @@ object Day17 {
10
10
line.toList().map { it.digitToInt() }
11
11
}
12
12
13
- private fun dijkstra (destinationX : Int , destinationY : Int ): Int {
14
- data class Location (val x : Int , val y : Int , val distance : Int )
13
+ private data class Position (val x : Int , val y : Int ) {
14
+ fun addPair (other : Pair <Int , Int >) =
15
+ Position (x + other.first, y + other.second)
15
16
16
- fun getNeighbors (x : Int , y : Int , distance : Int ): Set <Location > {
17
- val neighbors = mutableSetOf<Location >()
17
+ fun inBounds () =
18
+ x >= 0 && y >= 0 && x < inputs[0 ].size && y < inputs.size
19
+ }
20
+
21
+ private data class Location (
22
+ val position : Position ,
23
+ val distance : Int ,
24
+ val direction : Char ,
25
+ val consecutiveDirection : Int
26
+ )
27
+
28
+ private const val UPWARDS = ' ^'
29
+ private const val DOWNWARDS = ' v'
30
+ private const val LEFTWARDS = ' <'
31
+ private const val RIGHTWARDS = ' >'
32
+
33
+ private val directionVectors = mapOf (
34
+ UPWARDS to Pair (0 , - 1 ),
35
+ DOWNWARDS to Pair (0 , 1 ),
36
+ LEFTWARDS to Pair (- 1 , 0 ),
37
+ RIGHTWARDS to Pair (1 , 0 ),
38
+ )
39
+
40
+ private val possibleDirections = mapOf (
41
+ UPWARDS to setOf (UPWARDS , LEFTWARDS , RIGHTWARDS ),
42
+ DOWNWARDS to setOf (DOWNWARDS , LEFTWARDS , RIGHTWARDS ),
43
+ LEFTWARDS to setOf (LEFTWARDS , DOWNWARDS , UPWARDS ),
44
+ RIGHTWARDS to setOf (RIGHTWARDS , DOWNWARDS , UPWARDS ),
45
+ )
46
+
47
+ private fun getNeighbors (location : Location , maxConsecutive : Int ): Set <Location > {
48
+ val neighbors = mutableSetOf<Location >()
18
49
19
- if (x > 0 ) neighbors.add(Location (x - 1 , y, distance + inputs[y][x - 1 ]))
20
- if (y > 0 ) neighbors.add(Location (x, y - 1 , distance + inputs[y - 1 ][x]))
21
- if (x < inputs[0 ].size - 1 ) neighbors.add(Location (x + 1 , y, distance + inputs[y][x + 1 ]))
22
- if (y < inputs.size - 1 ) neighbors.add(Location (x, y + 1 , distance + inputs[y + 1 ][x]))
50
+ possibleDirections[location.direction]?.forEach { nextDirection ->
51
+ val nextPosition = location.position.addPair(directionVectors[nextDirection]!! )
52
+ val nextConsecutiveDirection = if (location.direction == nextDirection) location.consecutiveDirection + 1 else 1
23
53
24
- return neighbors
54
+ if (nextPosition.inBounds() && nextConsecutiveDirection <= maxConsecutive) {
55
+ val nextDistance = location.distance + inputs[nextPosition.y][nextPosition.x]
56
+ neighbors.add(Location (nextPosition, nextDistance, nextDirection, nextConsecutiveDirection))
57
+ }
25
58
}
26
59
60
+ return neighbors
61
+ }
62
+
63
+ private fun dijkstra (destination : Position ): Int {
27
64
val frontier = PriorityQueue <Location > { loc1, loc2 -> loc1.distance - loc2.distance }
28
- frontier.add(Location (0 , 0 , 0 ))
29
- val minDistances = Array (inputs[0 ].size) {Array <Int ?>(inputs.size) { null } }
30
- minDistances[0 ][0 ] = 0
65
+ frontier.add(Location (Position (0 , 0 ), 0 , RIGHTWARDS , 0 ))
66
+
67
+ val minDistances = mutableMapOf<Position , MutableMap <Char , MutableMap <Int , Int >>>()
68
+ minDistances
69
+ .getOrPut(Position (0 , 0 )) { mutableMapOf () }
70
+ .getOrPut(RIGHTWARDS ) { mutableMapOf () }[0 ] = 0
31
71
32
72
while (frontier.isNotEmpty()) {
33
73
val current = frontier.remove()
34
74
35
- if (current.x == destinationX && current.y == destinationY) return current.distance
75
+ if (current.position == destination) return current.distance
76
+
77
+ getNeighbors(current, 3 ).forEach { neighbor ->
78
+ val currentNeighborMinDistance = minDistances[neighbor.position]?.get(neighbor.direction)?.get(neighbor.consecutiveDirection)
79
+
80
+ if (currentNeighborMinDistance == null || currentNeighborMinDistance > neighbor.distance) {
81
+ minDistances
82
+ .getOrPut(neighbor.position) { mutableMapOf () }
83
+ .getOrPut(neighbor.direction) { mutableMapOf () }
36
84
37
- getNeighbors(current.x, current.y, current.distance).forEach { neighbor ->
38
- if (minDistances[neighbor.x][neighbor.y] == null || minDistances[neighbor.x][neighbor.y]!! > neighbor.distance) {
85
+ minDistances[neighbor.position]!! [neighbor.direction]!! [neighbor.consecutiveDirection] = neighbor.distance
39
86
frontier.add(neighbor)
40
- minDistances[neighbor.x][neighbor.y] = neighbor.distance
41
87
}
42
88
}
43
89
}
44
90
45
91
throw Exception (" Location not found" )
46
92
}
47
93
48
- fun part1 () = println (dijkstra(inputs[0 ].size - 1 , inputs.size - 1 ))
94
+ fun part1 () = println (dijkstra(Position ( inputs[0 ].size - 1 , inputs.size - 1 ) ))
49
95
}
50
96
51
97
fun main () {
0 commit comments