void SC2Map::getShortestPathPredecessors( Base* b0, Base* b1, PathType t, Node** uOut, Node** vOut ) { float dShortest = infinity; for( map<Node*, float>::iterator itr0 = (b0->node2patchDistance[t]).begin(); itr0 != (b0->node2patchDistance[t]).end(); ++itr0 ) { Node* u = itr0->first; float dPatch0 = itr0->second; for( map<Node*, float>::iterator itr1 = (b1->node2patchDistance[t]).begin(); itr1 != (b1->node2patchDistance[t]).end(); ++itr1 ) { Node* v = itr1->first; float dPatch1 = itr1->second; float dRoute = getShortestPathDistance( u, v, t ); if( dPatch0 + dPatch1 + dRoute < dShortest ) { dShortest = dPatch0 + dPatch1 + dRoute; *uOut = u; *vOut = v; } } } }
Node* SC2Map::getShortestPathPredecessor( Node* u, Base* b, PathType t ) { if( !(u->pathsFromThisSrcCalculated) ) { computeShortestPaths( u, t ); u->pathsFromThisSrcCalculated = true; } float dShortest = infinity; Node* pred = NULL; for( map<Node*, float>::iterator itr = (b->node2patchDistance[t]).begin(); itr != (b->node2patchDistance[t]).end(); ++itr ) { Node* v = itr->first; float dPatch = itr->second; float dRoute = getShortestPathDistance( u, v, t ); if( dPatch + dRoute < dShortest ) { dShortest = dPatch + dRoute; pred = v; } } return pred; }
float SC2Map::getShortestPathDistance( Base* b1, Base* b2, PathType t ) { float dShortest = infinity; for( map<Node*, float>::iterator itr1 = (b1->node2patchDistance[t]).begin(); itr1 != (b1->node2patchDistance[t]).end(); ++itr1 ) { Node* u = itr1->first; float dPatch1 = itr1->second; for( map<Node*, float>::iterator itr2 = (b2->node2patchDistance[t]).begin(); itr2 != (b2->node2patchDistance[t]).end(); ++itr2 ) { Node* v = itr2->first; float dPatch2 = itr2->second; float dRoute = getShortestPathDistance( u, v, t ); if( dPatch1 + dPatch2 + dRoute < dShortest ) { dShortest = dPatch1 + dPatch2 + dRoute; } } } return dShortest; }
float SC2Map::getShortestPathDistance( point* p, Base* b, PathType t ) { if( !isPlayableCell( p ) ) { return infinity; } Node* u = getPathNode( p, t ); if( u == NULL ) { return infinity; } return getShortestPathDistance( u, b, t ); }
float SC2Map::getShortestPathDistance( point* src, point* dst, PathType t ) { if( !isPlayableCell( src ) || !isPlayableCell( dst ) ) { return infinity; } Node* u = getPathNode( src, t ); Node* v = getPathNode( dst, t ); if( u == NULL || v == NULL ) { return infinity; } return getShortestPathDistance( u, v, t ); }
void SC2Map::locateChokes() { for( list<StartLoc*>::const_iterator itr1 = startLocs.begin(); itr1 != startLocs.end(); ++itr1 ) { StartLoc* sl1 = *itr1; list<point> possibleChokes; for( list<StartLoc*>::const_iterator itr2 = startLocs.begin(); itr2 != startLocs.end(); ++itr2 ) { StartLoc* sl2 = *itr2; if( sl1 == sl2 ) { continue; } Node* src = getPathNode( &(sl2->loc), pathTypeLocateChokes ); Node* u = getPathNode( &(sl1->loc), pathTypeLocateChokes ); if( src == NULL ) { printError( "Start location %s is in an unpathable cell.\n", sl2->name ); exit( -1 ); } if( u == NULL ) { printError( "Start location %s is in an unpathable cell.\n", sl1->name ); exit( -1 ); } Node* v = getShortestPathPredecessor( src, u, pathTypeLocateChokes ); if( v == NULL ) { // no path, just skip this pairing continue; } // The choke should be closer than 50% of the distance // from a start location to any other start location float dTotal = getShortestPathDistance( src, u, pathTypeLocateChokes ); float dTest = dTotal; point pBest; pBest.mSet( -1000.0f + sl2->loc.mx, -1000.0f + sl2->loc.my ); float dChokeMin = infinity; bool trippedThreshold = false; while( v != NULL && dTest > 0.5f*dTotal ) { float dChoke = chokeDistance( &(v->loc), pathTypeLocateChokes ); if( trippedThreshold && dChoke > dChokeMin ) { // we just got a worse result, kick out break; } if( dChoke < getfConstant( "chokeDetectionThreshold" ) ) { trippedThreshold = true; dChokeMin = dChoke; pBest.set( &(v->loc) ); } u = v; v = getShortestPathPredecessor( src, u, pathTypeLocateChokes ); dTest = getShortestPathDistance ( src, u, pathTypeLocateChokes ); } possibleChokes.push_back( pBest ); } // if the best choke from this location to all others // is reasonably close, take the average bool chokesAgree = true; float xTotal = 0.0f; float yTotal = 0.0f; for( list<point>::iterator itr1 = possibleChokes.begin(); chokesAgree && itr1 != possibleChokes.end(); ++itr1 ) { point c1; c1.pcSet( (*itr1).pcx, (*itr1).pcy ); list<point>::iterator itr2 = itr1; ++itr2; for( ; itr2 != possibleChokes.end(); ++itr2 ) { point c2; c2.pcSet( (*itr2).pcx, (*itr2).pcy ); if( p2pDistance( &c1, &c2 ) > getfConstant( "chokeDetectionAgreement" ) ) { chokesAgree = false; break; } } xTotal += c1.mx; yTotal += c1.my; } if( chokesAgree ) { float xAvg = xTotal / (float)possibleChokes.size(); float yAvg = yTotal / (float)possibleChokes.size(); sl1->mainChoke.mSet( xAvg, yAvg ); } else { printWarning( "Could not locate main choke for start location %s.\n", sl1->name ); sl1->mainChoke.mSet( -1.0f, -1.0f ); } } }