Skip to content

Commit 85f5489

Browse files
committed
ShortestPaths: neighbourPredicate, allow no path to be found
* neighbourPredicate makes the accessible grid cells customizable * if no path can be found, let aStarAllPaths() return an empty list of paths
1 parent c5f0eab commit 85f5489

File tree

5 files changed

+36
-6
lines changed

5 files changed

+36
-6
lines changed

src/main/kotlin/de/ronny_h/aoc/extensions/graphs/ShortestPaths.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,5 +86,5 @@ fun <N> aStarAllPaths(
8686
}
8787

8888
// Open set is empty but goal was never reached
89-
error("No path found from $start to goal")
89+
return emptyList()
9090
}

src/main/kotlin/de/ronny_h/aoc/extensions/grids/Grid.kt

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -183,20 +183,24 @@ abstract class Grid<T>(
183183
} else {
184184
writer.print(element)
185185
}
186-
if (position.col == width - 1) writer.println()
186+
if (position.col == width - 1) writer.print('\n')
187187
}.last()
188188
}
189189

190190
/**
191191
* Determines all shortest paths possible from [start] to [goal] with the following conditions:
192-
* - The Grid's [nullElement] is the obstacle.
192+
* - The [neighbourPredicate] defines the cells that are no obstacle - the obstacle defaults to the Grid's [nullElement].
193193
* - No path outside the Grid is possible.
194194
* - Only direct neighbours (no diagonal ones) are considered.
195195
* - The cost of moving to a neighbour equals 1.
196196
*/
197-
fun shortestPaths(start: Coordinates, goal: Coordinates): List<ShortestPath<Coordinates>> {
197+
fun shortestPaths(
198+
start: Coordinates,
199+
goal: Coordinates,
200+
neighbourPredicate: (Coordinates) -> Boolean = { getAt(it) != nullElement }
201+
): List<ShortestPath<Coordinates>> {
198202
val neighbours: (Coordinates) -> List<Coordinates> = { position ->
199-
position.neighbours().filter { getAt(it) != nullElement }
203+
position.neighbours().filter(neighbourPredicate)
200204
}
201205

202206
val d: (Coordinates, Coordinates) -> Int = { a, b ->

src/test/kotlin/de/ronny_h/aoc/extensions/graphs/ShortestPathTest.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,4 +177,14 @@ class ShortestPathTest : StringSpec({
177177
aStar(start, goal::positionEquals, { n -> neighbours.getValue(n) }, d, h) shouldBe
178178
ShortestPath(listOf(start, a, b, goal), 9)
179179
}
180+
181+
"When there is no path at all, aStarAllPaths returns an empty list" {
182+
val start = Node(At(0, 0))
183+
val goal = Node(At(0, 10))
184+
185+
val d: (Node, Node) -> Int = { _, _ -> 0 }
186+
val h: (Node) -> Int = { n -> n.position taxiDistanceTo goal.position }
187+
188+
aStarAllPaths(start, goal::positionEquals, { emptyList() }, d, h) shouldBe emptyList()
189+
}
180190
})

src/test/kotlin/de/ronny_h/aoc/extensions/grids/GridTest.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import io.kotest.matchers.shouldNotBe
1111

1212
class GridTest : StringSpec() {
1313

14-
private val newLine: String = System.lineSeparator()
14+
private val newLine = '\n'
1515

1616
init {
1717
"a grid can be constructed from List of String" {

src/test/kotlin/de/ronny_h/aoc/extensions/grids/SimpleCharGridTest.kt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,22 @@ class SimpleCharGridTest : StringSpec({
109109
)
110110
}
111111

112+
"customized obstacles are not part of the shortest path" {
113+
val grid = SimpleCharGrid(listOf("0X2", "3#5", "678"), '#')
114+
grid.shortestPaths(
115+
start = Coordinates(0, 0),
116+
goal = Coordinates(0, 2),
117+
neighbourPredicate = { grid.getAt(it) !in listOf('X', '#') }
118+
) shouldBe listOf(
119+
ShortestPath(
120+
listOf(
121+
Coordinates(0, 0), Coordinates(1, 0), Coordinates(2, 0),
122+
Coordinates(2, 1), Coordinates(2, 2), Coordinates(1, 2), Coordinates(0, 2)
123+
), 6
124+
),
125+
)
126+
}
127+
112128
"cluster regions of same char with a single region" {
113129
val input = """
114130
xx

0 commit comments

Comments
 (0)