1717
1818package com.lambda.pathing.dstar
1919
20+ import com.lambda.util.world.FastVector
2021import kotlin.math.min
2122
2223/* *
@@ -34,20 +35,20 @@ import kotlin.math.min
3435 */
3536class DStarLite (
3637 private val graph : Graph ,
37- private val heuristic : (Int , Int ) -> Double ,
38- var start : Int ,
39- val goal : Int
38+ private val heuristic : (FastVector , FastVector ) -> Double ,
39+ var start : FastVector ,
40+ private val goal : FastVector
4041) {
4142 private val INF = Double .POSITIVE_INFINITY
4243
4344 // gMap[u], rhsMap[u] store g(u) and rhs(u) or default to ∞ if not present
44- private val gMap = mutableMapOf<Int , Double >()
45- private val rhsMap = mutableMapOf<Int , Double >()
45+ private val gMap = mutableMapOf<FastVector , Double >()
46+ private val rhsMap = mutableMapOf<FastVector , Double >()
4647
47- // Priority queue
48+ // Priority queue holding inconsistent vertices.
4849 private val U = PriorityQueueDStar ()
4950
50- // Heuristic shift
51+ // km accumulates heuristic differences as the start changes.
5152 private var km = 0.0
5253
5354 init {
@@ -67,37 +68,36 @@ class DStarLite(
6768 U .insertOrUpdate(goal, calculateKey(goal))
6869 }
6970
70- private fun g (u : Int ): Double = gMap[u] ? : INF
71- private fun setG (u : Int , value : Double ) {
72- gMap[u] = value
73- }
71+ private fun g (u : FastVector ): Double = gMap[u] ? : INF
72+ private fun setG (u : FastVector , value : Double ) { gMap[u] = value }
7473
75- private fun rhs (u : Int ): Double = rhsMap[u] ? : INF
76- private fun setRHS (u : Int , value : Double ) {
77- rhsMap[u] = value
78- }
74+ private fun rhs (u : FastVector ): Double = rhsMap[u] ? : INF
75+ private fun setRHS (u : FastVector , value : Double ) { rhsMap[u] = value }
7976
8077 /* *
81- * Key(u) = ( min(g(u), rhs(u)) + h(start, u) + km , min(g(u), rhs(u)) ).
78+ * Calculates the key for vertex u.
79+ * Key(u) = ( min(g(u), rhs(u)) + h(start, u) + km, min(g(u), rhs(u)) )
8280 */
83- private fun calculateKey (u : Int ): Key {
81+ private fun calculateKey (u : FastVector ): Key {
8482 val minGRHS = min(g(u), rhs(u))
8583 return Key (minGRHS + heuristic(start, u) + km, minGRHS)
8684 }
8785
8886 /* *
89- * UpdateVertex(u):
90- * 1) If u != goal, rhs(u) = min_{v in Pred(u)} [g(v) + cost(v,u)]
91- * 2) Remove u from U
92- * 3) If g(u) != rhs(u), insertOrUpdate(u, calculateKey(u))
87+ * Updates the vertex u.
88+ *
89+ * If u != goal, then:
90+ * rhs(u) = min_{v in Pred(u)} [g(v) + cost(v,u)]
91+ *
92+ * Then u is removed from the queue and reinserted if it is inconsistent.
9393 */
94- fun updateVertex (u : Int ) {
94+ fun updateVertex (u : FastVector ) {
9595 if (u != goal) {
9696 var tmp = INF
97- graph.predecessors(u).forEach { (pred, c ) ->
98- val valCandidate = g(pred) + c
99- if (valCandidate < tmp) {
100- tmp = valCandidate
97+ graph.predecessors(u).forEach { (pred, cost ) ->
98+ val candidate = g(pred) + cost
99+ if (candidate < tmp) {
100+ tmp = candidate
101101 }
102102 }
103103 setRHS(u, tmp)
@@ -109,15 +109,13 @@ class DStarLite(
109109 }
110110
111111 /* *
112+ * Propagates changes until the start is locally consistent.
112113 * computeShortestPath():
113114 * While the queue top is "less" than calculateKey(start)
114115 * or g(start) < rhs(start), pop and process.
115116 */
116117 fun computeShortestPath () {
117- while (
118- (U .topKey() < calculateKey(start)) ||
119- (g(start) < rhs(start))
120- ) {
118+ while ((U .topKey() < calculateKey(start)) || (g(start) < rhs(start))) {
121119 val u = U .top() ? : break
122120 val oldKey = U .topKey()
123121 val newKey = calculateKey(u)
@@ -126,24 +124,21 @@ class DStarLite(
126124 // Priority out-of-date; update it
127125 U .insertOrUpdate(u, newKey)
128126 } else {
129- // Remove it from queue
130127 U .pop()
131128 if (g(u) > rhs(u)) {
132129 // We found a better path for u
133130 setG(u, rhs(u))
134- // Update successors of u
135- graph.successors(u).forEach { (s, _) ->
136- updateVertex(s)
131+ graph.successors(u).forEach { (succ, _) ->
132+ updateVertex(succ)
137133 }
138134 } else {
139- // g(u) <= rhs(u)
140- val gOld = g(u)
135+ val oldG = g(u)
141136 setG(u, INF )
142137 updateVertex(u)
143138 // Update successors that may have relied on old g(u)
144- graph.successors(u).forEach { (s , _) ->
145- if (rhs(s ) == gOld + graph.cost(u, s )) {
146- updateVertex(s )
139+ graph.successors(u).forEach { (succ , _) ->
140+ if (rhs(succ ) == oldG + graph.cost(u, succ )) {
141+ updateVertex(succ )
147142 }
148143 }
149144 }
@@ -152,16 +147,15 @@ class DStarLite(
152147 }
153148
154149 /* *
155- * Called when the robot moves from oldStart to newStart.
156- * We increase km by h(oldStart, newStart), then re-key all queued vertices.
150+ * When the robot moves, update the start.
151+ * The variable km is increased by h(oldStart, newStart) and
152+ * all vertices in the queue are re-keyed.
157153 */
158- fun updateStart (newStart : Int ) {
154+ fun updateStart (newStart : FastVector ) {
159155 val oldStart = start
160156 start = newStart
161157 km + = heuristic(oldStart, start)
162-
163- // Re-key everything in U
164- val tmpList = mutableListOf<Int >()
158+ val tmpList = mutableListOf<FastVector >()
165159 while (! U .isEmpty()) {
166160 U .top()?.let { tmpList.add(it) }
167161 U .pop()
@@ -172,34 +166,29 @@ class DStarLite(
172166 }
173167
174168 /* *
175- * Returns a path from 'start' to 'goal' by always choosing
176- * the successor s of the current vertex that minimizes g(s)+cost(current->s).
177- * If no path is found, the path ends prematurely.
169+ * Retrieves a path from start to goal by always choosing the successor
170+ * with the lowest g + cost value. If no path is found, the path stops early.
178171 */
179- fun getPath (): List <Int > {
180- val path = mutableListOf<Int >()
172+ fun getPath (): List <FastVector > {
173+ val path = mutableListOf<FastVector >()
181174 var current = start
182175 path.add(current)
183-
184176 while (current != goal) {
185177 val successors = graph.successors(current)
186178 if (successors.isEmpty()) break
187-
188- var bestNext: Int? = null
179+ var bestNext: FastVector ? = null
189180 var bestVal = INF
190- for ((s, c ) in successors) {
191- val valCandidate = g(s ) + c
192- if (valCandidate < bestVal) {
193- bestVal = valCandidate
194- bestNext = s
181+ for ((succ, cost ) in successors) {
182+ val candidate = g(succ ) + cost
183+ if (candidate < bestVal) {
184+ bestVal = candidate
185+ bestNext = succ
195186 }
196187 }
197188 // No path
198189 if (bestNext == null ) break
199190 current = bestNext
200191 path.add(current)
201-
202- // Safety net to avoid infinite loops
203192 if (path.size > 100000 ) break
204193 }
205194 return path
0 commit comments