Skip to content

Commit 83fe62e

Browse files
committed
Add 2023 Day 17 Part 1 solution
1 parent e5cfee7 commit 83fe62e

File tree

1 file changed

+63
-17
lines changed

1 file changed

+63
-17
lines changed

adventofcode2023/Day17.kt

Lines changed: 63 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,42 +10,88 @@ object Day17 {
1010
line.toList().map { it.digitToInt() }
1111
}
1212

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)
1516

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>()
1849

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
2353

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+
}
2558
}
2659

60+
return neighbors
61+
}
62+
63+
private fun dijkstra(destination: Position): Int {
2764
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
3171

3272
while (frontier.isNotEmpty()) {
3373
val current = frontier.remove()
3474

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() }
3684

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
3986
frontier.add(neighbor)
40-
minDistances[neighbor.x][neighbor.y] = neighbor.distance
4187
}
4288
}
4389
}
4490

4591
throw Exception("Location not found")
4692
}
4793

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)))
4995
}
5096

5197
fun main() {

0 commit comments

Comments
 (0)