void OpenQueue::Push( PathNode* pNode ) { MPASSERT( pNode->inOpen == 0 ); MPASSERT( pNode->inClosed == 0 ); #ifdef DEBUG_PATH_DEEP printf( "Open Push: " ); graph->PrintStateInfo( pNode->state ); printf( " total=%.1f\n", pNode->totalCost ); #endif // Add sorted. Lowest to highest cost path. Note that the sentinel has // a value of FLT_MAX, so it should always be sorted in. MPASSERT( pNode->totalCost < FLT_MAX ); PathNode* iter = sentinel->next; while ( true ) { if ( pNode->totalCost < iter->totalCost ) { iter->AddBefore( pNode ); pNode->inOpen = 1; break; } iter = iter->next; } MPASSERT( pNode->inOpen ); // make sure this was actually added. #ifdef DEBUG sentinel->CheckList(); #endif }
void OpenQueue::Update( PathNode* pNode ) { #ifdef DEBUG_PATH_DEEP printf( "Open Update: " ); graph->PrintStateInfo( pNode->state ); printf( " total=%.1f\n", pNode->totalCost ); #endif MPASSERT( pNode->inOpen ); // If the node now cost less than the one before it, // move it to the front of the list. if ( pNode->prev != sentinel && pNode->totalCost < pNode->prev->totalCost ) { pNode->Unlink(); sentinel->next->AddBefore( pNode ); } // If the node is too high, move to the right. if ( pNode->totalCost > pNode->next->totalCost ) { PathNode* it = pNode->next; pNode->Unlink(); while ( pNode->totalCost > it->totalCost ) it = it->next; it->AddBefore( pNode ); #ifdef DEBUG sentinel->CheckList(); #endif } }
int MicroPather::SolveForNearStates( void* startState, std::vector< StateCost >* near, float maxCost ) { /* http://en.wikipedia.org/wiki/Dijkstra%27s_algorithm 1 function Dijkstra(Graph, source): 2 for each vertex v in Graph: // Initializations 3 dist[v] := infinity // Unknown distance function from source to v 4 previous[v] := undefined // Previous node in optimal path from source 5 dist[source] := 0 // Distance from source to source 6 Q := the set of all nodes in Graph // All nodes in the graph are unoptimized - thus are in Q 7 while Q is not empty: // The main loop 8 u := vertex in Q with smallest dist[] 9 if dist[u] = infinity: 10 break // all remaining vertices are inaccessible from source 11 remove u from Q 12 for each neighbor v of u: // where v has not yet been removed from Q. 13 alt := dist[u] + dist_between(u, v) 14 if alt < dist[v]: // Relax (u,v,a) 15 dist[v] := alt 16 previous[v] := u 17 return dist[] */ ++frame; OpenQueue open( graph ); // nodes to look at ClosedSet closed( graph ); nodeCostVec.resize(0); stateCostVec.resize(0); PathNode closedSentinel; closedSentinel.Clear(); closedSentinel.Init( frame, 0, FLT_MAX, FLT_MAX, 0 ); closedSentinel.next = closedSentinel.prev = &closedSentinel; PathNode* newPathNode = pathNodePool.GetPathNode( frame, startState, 0, 0, 0 ); open.Push( newPathNode ); while ( !open.Empty() ) { PathNode* node = open.Pop(); // smallest dist closed.Add( node ); // add to the things we've looked at closedSentinel.AddBefore( node ); if ( node->totalCost > maxCost ) continue; // Too far away to ever get here. GetNodeNeighbors( node, &nodeCostVec ); for( int i=0; i<node->numAdjacent; ++i ) { MPASSERT( node->costFromStart < FLT_MAX ); float newCost = node->costFromStart + nodeCostVec[i].cost; PathNode* inOpen = nodeCostVec[i].node->inOpen ? nodeCostVec[i].node : 0; PathNode* inClosed = nodeCostVec[i].node->inClosed ? nodeCostVec[i].node : 0; MPASSERT( !( inOpen && inClosed ) ); PathNode* inEither = inOpen ? inOpen : inClosed; MPASSERT( inEither != node ); if ( inEither && inEither->costFromStart <= newCost ) { continue; // Do nothing. This path is not better than existing. } // Groovy. We have new information or improved information. PathNode* child = nodeCostVec[i].node; MPASSERT( child->state != newPathNode->state ); // should never re-process the parent. child->parent = node; child->costFromStart = newCost; child->estToGoal = 0; child->totalCost = child->costFromStart; if ( inOpen ) { open.Update( inOpen ); } else if ( !inClosed ) { open.Push( child ); } } } near->clear(); for( PathNode* pNode=closedSentinel.next; pNode != &closedSentinel; pNode=pNode->next ) { if ( pNode->totalCost <= maxCost ) { StateCost sc; sc.cost = pNode->totalCost; sc.state = pNode->state; near->push_back( sc ); } } #ifdef DEBUG for( unsigned i=0; i<near->size(); ++i ) { for( unsigned k=i+1; k<near->size(); ++k ) { MPASSERT( near->at(i).state != near->at(k).state ); } } #endif return SOLVED; }