Skip to content

Commit f3fb646

Browse files
committed
Day16, part 1: Fix the neighbours: Either turn or go forward in a single step
1 parent bb184ed commit f3fb646

File tree

2 files changed

+13
-33
lines changed

2 files changed

+13
-33
lines changed

src/main/kotlin/Day16.kt

Lines changed: 8 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -59,19 +59,7 @@ fun main() {
5959
)
6060

6161
val input = readInput(day)
62-
printAndCheck(input, ::part1, 89471)
63-
// too high: 89472
64-
// too high: 89471
65-
// not right: 88971
66-
// not right: 88721
67-
// too low: 88472
68-
69-
70-
println("$day part 2")
71-
72-
fun part2(input: List<String>) = input.size
73-
74-
printAndCheck(input, ::part2, 6512)
62+
printAndCheck(input, ::part1, 89460)
7563
}
7664

7765
private class ReindeerMaze(input: List<String>) : Grid<Char>(input) {
@@ -80,15 +68,6 @@ private class ReindeerMaze(input: List<String>) : Grid<Char>(input) {
8068
override fun Char.toElementType() = this
8169

8270
data class Node(val direction: Direction, val position: Coordinates) {
83-
// hashCode and equals are used to determine if a Node was already visited.
84-
// -> don't distinguish directions
85-
override fun hashCode() = position.hashCode()
86-
override fun equals(other: Any?): Boolean {
87-
if (other !is Node) {
88-
return false
89-
}
90-
return position == other.position
91-
}
9271
override fun toString() = "$position$direction"
9372
}
9473

@@ -102,23 +81,22 @@ private class ReindeerMaze(input: List<String>) : Grid<Char>(input) {
10281
val goal = Node(Direction.EAST, Coordinates(1, width - 2))
10382

10483
val neighbours: (Node) -> List<Node> = { n ->
105-
n.position.directedNeighbours()
106-
.filter { !it.first.isOpposite(n.direction) } // don't go back
107-
.filter { getAt(it.second) != wall }
108-
.map { Node(it.first, it.second) }
84+
listOf(
85+
Node(n.direction, n.position + n.direction),
86+
Node(n.direction.turnLeft(), n.position),
87+
Node(n.direction.turnRight(), n.position)
88+
).filter { getAt(it.position) != wall }
10989
}
11090

11191
val d: (Node, Node) -> Int = { a, b ->
112-
require(a.position in b.position.neighbours())
11392
if (a.position == goal.position && b.position == goal.position) {
11493
// direction at goal doesn't care
11594
0
116-
} else if (a.direction - b.direction == 0) {
95+
} else if (a.direction == b.direction) {
11796
// straight ahead
11897
1
11998
} else {
120-
// turn left, right or u-turn -> turn cost + move cost
121-
(a.direction - b.direction) * 1000 + 1
99+
1000
122100
}
123101
}
124102

src/main/kotlin/de/ronny_h/extensions/ShortestPath.kt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ private fun <N> reconstructPath(cameFrom: Map<N, N>, last: N): List<N> {
1818

1919
data class ShortestPath<N>(val path: List<N>, val distance: Int)
2020

21+
private const val LARGE_VALUE = MAX_VALUE / 2
22+
2123
/**
2224
* A* finds a path from `start` to `goal`.
2325
* @param start the start node
@@ -35,7 +37,7 @@ fun <N> aStar(start: N, goal: N, neighbors: (N) -> List<N>, d: (N, N) -> Int, h:
3537
// The set of discovered nodes that may need to be (re-)expanded.
3638
// Initially, only the start node is known.
3739
// This is usually implemented as a min-heap or priority queue rather than a hash-set.
38-
val openSet = PriorityQueue<N> { a, b -> fScore.getValue(a).compareTo(fScore.getValue(b)) }
40+
val openSet = PriorityQueue<N> { a, b -> fScore.getOrDefault(a, LARGE_VALUE).compareTo(fScore.getOrDefault(b, LARGE_VALUE)) }
3941
openSet.add(start)
4042

4143
// For node n, cameFrom[n] is the node immediately preceding it on the cheapest path from the start
@@ -59,8 +61,8 @@ fun <N> aStar(start: N, goal: N, neighbors: (N) -> List<N>, d: (N, N) -> Int, h:
5961
for (neighbor in neighbors(current)) {
6062
// d(current,neighbor) is the weight of the edge from current to neighbor
6163
// tentative_gScore is the distance from start to the neighbor through current
62-
val tentativeGScore = gScore.getOrDefault(current, MAX_VALUE) + d(current, neighbor)
63-
if (tentativeGScore < gScore.getOrDefault(neighbor, MAX_VALUE)) {
64+
val tentativeGScore = gScore.getOrDefault(current, LARGE_VALUE) + d(current, neighbor)
65+
if (tentativeGScore < gScore.getOrDefault(neighbor, LARGE_VALUE)) {
6466
// This path to neighbor is better than any previous one. Record it!
6567
cameFrom[neighbor] = current
6668
gScore[neighbor] = tentativeGScore

0 commit comments

Comments
 (0)