void Map::FindBestPathToTile( const Unit* unit, const Vec2s& tilePos, Path& result ) { std::vector< PrimaryDirection > reverseDirections; int searchIndex = ReserveSearchIndex(); // Clear the list of results. result.Clear(); result.SetOrigin( unit->GetTilePos() ); // Clear the open list. mOpenList.clear(); // Get the Unit's current Tile and type. Iterator originTile = unit->GetTile(); UnitType* unitType = unit->GetUnitType(); MovementType* movementType = unit->GetMovementType(); // Get the starting movement range of the Unit. int movementRange = unit->GetMovementRange(); // Add the origin tile to the open list. originTile->Open( searchIndex ); originTile->SetPreviousTileDirection( PrimaryDirection::NONE ); originTile->SetBestTotalCostToEnter( 0 ); mOpenList.insert( 0, originTile ); while( !mOpenList.isEmpty() ) { // Pop the first element off the open list. Map::Iterator tile = mOpenList.popMinElement(); if( tile.GetPosition() != tilePos ) { // If this isn't the goal tile, close it. tile->Close( searchIndex ); for( int i = 0; i < CARDINAL_DIRECTION_COUNT; ++i ) { // Determine the direction to search. PrimaryDirection direction = CARDINAL_DIRECTIONS[ i ]; // If the adjacent tile isn't in the previous direction, get the adjacent tile. Iterator adjacent = tile.GetAdjacent( direction ); if( adjacent.IsValid() && !adjacent->IsClosed( searchIndex ) ) { // If the adjacent tile is valid and isn't already closed, get the TerrainType of the adjacent tile. TerrainType* adjacentTerrainType = adjacent->GetTerrainType(); if( movementType->CanMoveAcrossTerrain( adjacentTerrainType ) ) { // If the adjacent tile is passable, find the total cost of entering the tile. int costToEnterAdjacent = movementType->GetMovementCostAcrossTerrain( adjacentTerrainType ); int adjacentTotalCost = ( tile->GetBestTotalCostToEnter() + costToEnterAdjacent ); int distanceToGoal = ( originTile.GetPosition().GetManhattanDistanceTo( tilePos ) ); int adjacentWeight = ( adjacentTotalCost + distanceToGoal ); if( adjacentTotalCost <= movementRange ) { if( !adjacent->IsOpen( searchIndex ) ) { // If the tile info isn't already on the open list, add it. adjacent->SetPreviousTileDirection( direction.GetOppositeDirection() ); adjacent->SetBestTotalCostToEnter( adjacentTotalCost ); mOpenList.insert( adjacentWeight, adjacent ); } else if( adjacentTotalCost < adjacent->GetBestTotalCostToEnter() ) { // If the node is already on the open list but has a larger total cost, // update the value. adjacent->SetPreviousTileDirection( direction.GetOppositeDirection() ); adjacent->SetBestTotalCostToEnter( adjacentTotalCost ); mOpenList.update( adjacentWeight, adjacent ); } } } } } } else { // If this is the goal tile, construct the path to the location. PrimaryDirection previousDirection = tile->GetPreviousTileDirection(); while( previousDirection != PrimaryDirection::NONE ) { // Construct the list of directions from the goal back to the origin tile. reverseDirections.push_back( previousDirection ); tile = tile.GetAdjacent( previousDirection ); previousDirection = tile->GetPreviousTileDirection(); } // End the search. break; } } for( auto it = reverseDirections.rbegin(); it != reverseDirections.rend(); ++it ) { // Construct the path by reversing the directions from the goal to the origin. PrimaryDirection direction = *it; result.AddDirection( direction.GetOppositeDirection() ); } }
void Map::FindReachableTiles( const Unit* unit, TileSet& result ) { int searchIndex = ReserveSearchIndex(); // Clear the list of results. result.clear(); // Clear the open list. mOpenList.clear(); // Get the Unit's current Tile and type. Iterator originTile = unit->GetTile(); UnitType* unitType = unit->GetUnitType(); MovementType* movementType = unit->GetMovementType(); // Get the starting movement range of the Unit. int movementRange = unit->GetMovementRange(); // Add the origin tile to the open list. originTile->Open( searchIndex ); originTile->SetPreviousTileDirection( PrimaryDirection::NONE ); originTile->SetBestTotalCostToEnter( 0 ); mOpenList.insert( 0, originTile ); while( !mOpenList.isEmpty() ) { // Pop the first element off the open list. Map::Iterator tile = mOpenList.popMinElement(); // Close the tile and add it to the result. tile->Close( searchIndex ); result.insert( tile ); for( int i = 0; i < CARDINAL_DIRECTION_COUNT; ++i ) { // Determine the direction to search. PrimaryDirection direction = CARDINAL_DIRECTIONS[ i ]; // If the adjacent tile isn't in the previous direction, get the adjacent tile. Iterator adjacent = tile.GetAdjacent( direction ); if( adjacent.IsValid() && !adjacent->IsClosed( searchIndex ) ) { // If the adjacent tile is valid and isn't already closed, get the TerrainType of the adjacent tile. TerrainType* adjacentTerrainType = adjacent->GetTerrainType(); if( movementType->CanMoveAcrossTerrain( adjacentTerrainType ) ) { // If the adjacent tile is passable, find the total cost of entering the tile. int costToEnterAdjacent = movementType->GetMovementCostAcrossTerrain( adjacentTerrainType ); int adjacentTotalCost = ( tile->GetBestTotalCostToEnter() + costToEnterAdjacent ); if( adjacentTotalCost <= movementRange ) { if( !adjacent->IsOpen( searchIndex ) ) { // If the tile info isn't already on the open list, add it. adjacent->SetPreviousTileDirection( direction.GetOppositeDirection() ); adjacent->SetBestTotalCostToEnter( adjacentTotalCost ); mOpenList.insert( adjacentTotalCost, adjacent ); } else if( adjacentTotalCost < adjacent->GetBestTotalCostToEnter() ) { // If the node is already on the open list but has a larger total cost, // update the value. adjacent->SetPreviousTileDirection( direction.GetOppositeDirection() ); adjacent->SetBestTotalCostToEnter( adjacentTotalCost ); mOpenList.update( adjacentTotalCost, adjacent ); } } } } } } }