BWAPI
Skynet/Skynet/TerrainAnaysis.cpp
Go to the documentation of this file.
00001 #include "TerrainAnaysis.h"
00002 
00003 #include "UnitHelper.h"
00004 #include "MapHelper.h"
00005 #include "BaseTracker.h"
00006 #include "DrawBuffer.h"
00007 #include "UnitGroup.h"
00008 #include "UnitTracker.h"
00009 #include "MapHelper.h"
00010 #include "BuildingPlacer.h"
00011 #include "PathFinder.h"
00012 #include "Logger.h"
00013 #include "Heap.h"
00014 
00015 TerrainAnaysisClass::TerrainAnaysisClass()
00016 {
00017 }
00018 
00019 void TerrainAnaysisClass::analyseBasesAndTerrain()
00020 {
00021         calculateConnectivity();
00022         calculateWalkTileClearance();
00023         createRegions();
00024 
00025         createBases();
00026 
00027         BuildingPlacer::Instance().calculateReservations();
00028         finaliseConnectivity();
00029         BuildingPlacer::Instance().finaliseReservations();
00030 }
00031 
00032 class WalkInRegionComp
00033 {
00034 public:
00035         WalkInRegionComp(Region region) : mRegion(region) {}
00036 
00037         bool operator()(TilePosition location) const
00038         {
00039                 for(int x = location.x()-1; x <= location.x()+1; ++x)
00040                 {
00041                         for(int y = location.y()-1; y <= location.y()+1; ++y)
00042                         {
00043                                 TilePosition tile(x, y);
00044                                 if(!tile.isValid() || TerrainAnaysis::Instance().getRegion(tile) != mRegion || !BuildingPlacer::Instance().isTileWalkable(tile))
00045                                         return false;
00046                         }
00047                 }
00048 
00049                 return true;
00050         }
00051 
00052 private:
00053         Region mRegion;
00054 };
00055 
00056 void TerrainAnaysisClass::finaliseConnectivity()
00057 {
00058         for each(Region region in mRegions)
00059         {
00060                 WalkInRegionComp goCompare(region);
00061 
00062                 for each(Chokepoint chokepoint in mChokepoints)
00063                 {
00064                         TilePosition pos = MapHelper::spiralSearch(TilePosition(chokepoint->getCenter()), goCompare, 24);
00065 
00066                         region->addChokepointTile(chokepoint, pos);
00067                         chokepoint->addChokepointTile(region, pos);
00068                 }
00069         }
00070 }
00071 
00072 void TerrainAnaysisClass::calculateWalkTileClearance()
00073 {
00074         int mapWidth = BWAPI::Broodwar->mapWidth() * 4;
00075         int mapHeight = BWAPI::Broodwar->mapHeight() * 4;
00076 
00077         mTileClearance.resize(mapWidth, mapHeight, -1);
00078         mTileClosestObstacle.resize(mapWidth, mapHeight);
00079 
00080         Heap<WalkPosition, int> unvisitedTiles(true);
00081         for(int x = 0; x < mapWidth; ++x)
00082         {
00083                 for(int y = 0; y < mapHeight; ++y)
00084                 {
00085                         if(!BWAPI::Broodwar->isWalkable(x, y))
00086                         {
00087                                 mTileClearance[x][y] = 0;
00088                                 mTileClosestObstacle[x][y] = WalkPosition(x, y);
00089                                 if(mSmallObstacles.count(mTileConnectivity[x][y]) == 0)
00090                                         unvisitedTiles.set(WalkPosition(x, y), 0);
00091                         }
00092                         else if(x == 0 || y == 0 || x == mapWidth-1 || y == mapHeight-1)
00093                         {
00094                                 mTileClearance[x][y] = 10;
00095                                 mTileClosestObstacle[x][y] = WalkPosition((x == 0 ? -1 : (x == mapWidth-1 ? mapWidth : x)), (y == 0 ? -1 : (y == mapHeight-1 ? mapHeight : y)));
00096                                 unvisitedTiles.set(WalkPosition(x, y), 10);
00097                         }
00098                 }
00099         }
00100 
00101         while(!unvisitedTiles.empty())
00102         {
00103                 WalkPosition tile = unvisitedTiles.top().first;
00104                 const int distance = unvisitedTiles.top().second + 10;
00105                 const int diagDistance = distance + 4;
00106                 unvisitedTiles.pop();
00107 
00108                 const int west = tile.x - 1;
00109                 const int north = tile.y - 1;
00110                 const int east = tile.x + 1;
00111                 const int south = tile.y + 1;
00112 
00113                 const bool canGoWest = west >= 0;
00114                 const bool canGoNorth = north >= 0;
00115                 const bool canGoEast = east < mapWidth;
00116                 const bool canGoSouth = south < mapHeight;
00117 
00118                 const WalkPosition &currentParent = mTileClosestObstacle[tile.x][tile.y];
00119 
00120                 if(canGoWest && (mTileClearance[west][tile.y] == -1 || distance < mTileClearance[west][tile.y]))
00121                 {
00122                         mTileClearance[west][tile.y] = distance;
00123                         mTileClosestObstacle[west][tile.y] = currentParent;
00124                         unvisitedTiles.set(WalkPosition(west, tile.y), distance);
00125                 }
00126 
00127                 if(canGoNorth && (mTileClearance[tile.x][north] == -1 || distance < mTileClearance[tile.x][north]))
00128                 {
00129                         mTileClearance[tile.x][north] = distance;
00130                         mTileClosestObstacle[tile.x][north] = currentParent;
00131                         unvisitedTiles.set(WalkPosition(tile.x, north), distance);
00132                 }
00133 
00134                 if(canGoEast && (mTileClearance[east][tile.y] == -1 || distance < mTileClearance[east][tile.y]))
00135                 {
00136                         mTileClearance[east][tile.y] = distance;
00137                         mTileClosestObstacle[east][tile.y] = currentParent;
00138                         unvisitedTiles.set(WalkPosition(east, tile.y), distance);
00139                 }
00140 
00141                 if(canGoSouth && (mTileClearance[tile.x][south] == -1 || distance < mTileClearance[tile.x][south]))
00142                 {
00143                         mTileClearance[tile.x][south] = distance;
00144                         mTileClosestObstacle[tile.x][south] = currentParent;
00145                         unvisitedTiles.set(WalkPosition(tile.x, south), distance);
00146                 }
00147 
00148                 if(canGoWest && canGoNorth && (mTileClearance[west][north] == -1 || diagDistance < mTileClearance[west][north]))
00149                 {
00150                         mTileClearance[west][north] = diagDistance;
00151                         mTileClosestObstacle[west][north] = currentParent;
00152                         unvisitedTiles.set(WalkPosition(west, north), diagDistance);
00153                 }
00154 
00155                 if(canGoEast && canGoSouth && (mTileClearance[east][south] == -1 || diagDistance < mTileClearance[east][south]))
00156                 {
00157                         mTileClearance[east][south] = diagDistance;
00158                         mTileClosestObstacle[east][south] = currentParent;
00159                         unvisitedTiles.set(WalkPosition(east, south), diagDistance);
00160                 }
00161 
00162                 if(canGoEast && canGoNorth && (mTileClearance[east][north] == -1 || diagDistance < mTileClearance[east][north]))
00163                 {
00164                         mTileClearance[east][north] = diagDistance;
00165                         mTileClosestObstacle[east][north] = currentParent;
00166                         unvisitedTiles.set(WalkPosition(east, north), diagDistance);
00167                 }
00168 
00169                 if(canGoWest && canGoSouth && (mTileClearance[west][south] == -1 || diagDistance < mTileClearance[west][south]))
00170                 {
00171                         mTileClearance[west][south] = diagDistance;
00172                         mTileClosestObstacle[west][south] = currentParent;
00173                         unvisitedTiles.set(WalkPosition(west, south), diagDistance);
00174                 }
00175         }
00176 }
00177 
00178 std::pair<WalkPosition, WalkPosition> TerrainAnaysisClass::findChokePoint(WalkPosition center)
00179 {
00180         WalkPosition side1 = mTileClosestObstacle[center.x][center.y];
00181 
00182         if(side1 == center)
00183                 return std::make_pair(side1, side1);
00184 
00185         Vector side1Direction(side1.x - center.x, side1.y - center.y);
00186         side1Direction.normalise();
00187 
00188         int mapWidth = BWAPI::Broodwar->mapWidth() * 4;
00189         int mapHeight = BWAPI::Broodwar->mapHeight() * 4;
00190 
00191         int x0 = side1.x;
00192         int y0 = side1.y;
00193 
00194         int x1 = center.x;
00195         int y1 = center.y;
00196 
00197         int dx = abs(x1 - x0);
00198         int dy = abs(y1 - y0);
00199 
00200         int sx = x0 < x1 ? 1 : -1;
00201         int sy = y0 < y1 ? 1 : -1;
00202 
00203         x0 = x1;
00204         y0 = y1;
00205 
00206         int error = dx - dy;
00207 
00208         for(;;)
00209         {
00210                 if(x0 < 0 || y0 < 0 || x0 >= mapWidth || y0 >= mapHeight || !BWAPI::Broodwar->isWalkable(x0, y0))
00211                         return std::make_pair(side1, WalkPosition(x0, y0));
00212 
00213                 WalkPosition side2 = mTileClosestObstacle[x0][y0];
00214 
00215                 Vector side2Direction(side2.x - center.x, side2.y - center.y);
00216                 side2Direction.normalise();
00217 
00218                 float dot = side2Direction.dotProduct(side1Direction);
00219                 float angle = acos(dot);
00220                 if(angle > 2.0f)
00221                         return std::make_pair(side1, side2);
00222 
00223                 int e2 = error*2;
00224                 if(e2 > -dy)
00225                 {
00226                         error -= dy;
00227                         x0 += sx;
00228                 }
00229                 if(e2 < dx)
00230                 {
00231                         error += dx;
00232                         y0 += sy;
00233                 }
00234         }
00235 }
00236 
00237 void TerrainAnaysisClass::calculateConnectivity()
00238 {
00239         int mapWidth = BWAPI::Broodwar->mapWidth() * 4;
00240         int mapHeight = BWAPI::Broodwar->mapHeight() * 4;
00241 
00242         int currentRegion = 1;
00243         mTileConnectivity.resize(mapWidth, mapHeight, 0);
00244         for(int x = 0; x < mapWidth; ++x)
00245         {
00246                 for(int y = 0; y < mapHeight; ++y)
00247                 {
00248                         if(mTileConnectivity[x][y] != 0)
00249                                 continue;
00250 
00251                         bool walkable = BWAPI::Broodwar->isWalkable(x, y);
00252                         int tileCount = 0;
00253 
00254                         std::set<WalkPosition> unvisitedTiles;
00255                         unvisitedTiles.insert(WalkPosition(x, y));
00256 
00257                         while(!unvisitedTiles.empty())
00258                         {
00259                                 const std::set<WalkPosition>::iterator &tile = unvisitedTiles.begin();
00260 
00261                                 ++tileCount;
00262                                 mTileConnectivity[tile->x][tile->y] = currentRegion;
00263 
00264                                 if(tile->x > 0 && BWAPI::Broodwar->isWalkable(tile->x-1, tile->y) == walkable && mTileConnectivity[tile->x-1][tile->y] == 0)
00265                                         unvisitedTiles.insert(WalkPosition(tile->x-1, tile->y));
00266                                 if(tile->y > 0 && BWAPI::Broodwar->isWalkable(tile->x, tile->y-1) == walkable && mTileConnectivity[tile->x][tile->y-1] == 0)
00267                                         unvisitedTiles.insert(WalkPosition(tile->x, tile->y-1));
00268 
00269                                 if(tile->x < mapWidth-1 && BWAPI::Broodwar->isWalkable(tile->x+1, tile->y) == walkable && mTileConnectivity[tile->x+1][tile->y] == 0)
00270                                         unvisitedTiles.insert(WalkPosition(tile->x+1, tile->y));
00271                                 if(tile->y < mapHeight-1 && BWAPI::Broodwar->isWalkable(tile->x, tile->y+1) == walkable && mTileConnectivity[tile->x][tile->y+1] == 0)
00272                                         unvisitedTiles.insert(WalkPosition(tile->x, tile->y+1));
00273 
00274                                 unvisitedTiles.erase(tile);
00275                         }
00276 
00277                         if(!walkable && tileCount < 200)
00278                                 mSmallObstacles.insert(currentRegion);
00279 
00280                         ++currentRegion;
00281                 }
00282         }
00283 }
00284 
00285 void TerrainAnaysisClass::createRegions()
00286 {
00287         int mapWidth = BWAPI::Broodwar->mapWidth() * 4;
00288         int mapHeight = BWAPI::Broodwar->mapHeight() * 4;
00289 
00290         // This comment is self explanatory.
00291         mTileToRegion.resize(mapWidth, mapHeight);
00292         std::map<WalkPosition, Chokepoint> chokeTiles;
00293 
00294         for(;;)
00295         {
00296                 int currentRegionClearance = 0;
00297                 WalkPosition currentRegionTile;
00298 
00299                 for(int x = 0; x < mapWidth; ++x)
00300                 {
00301                         for(int y = 0; y < mapHeight; ++y)
00302                         {
00303                                 if(mTileToRegion[x][y])
00304                                         continue;
00305 
00306                                 if(chokeTiles.count(WalkPosition(x, y)) != 0)
00307                                         continue;
00308 
00309                                 const int localMaximaValue = mTileClearance[x][y];
00310                                 if(localMaximaValue > currentRegionClearance)
00311                                 {
00312                                         currentRegionClearance = localMaximaValue;
00313                                         currentRegionTile.x = x;
00314                                         currentRegionTile.y = y;
00315                                 }
00316                         }
00317                 }
00318 
00319                 if(currentRegionClearance == 0)
00320                         break;
00321 
00322                 Region currentRegion(new RegionClass(currentRegionTile.getCenterPosition(), currentRegionClearance));
00323                 mRegions.insert(currentRegion);
00324 
00325                 std::map<WalkPosition, WalkPosition> tileToLastMinima;
00326                 std::map<WalkPosition, std::vector<WalkPosition>> tileToChildren;
00327 
00328                 Heap<WalkPosition, int> unvisitedTiles(false);
00329 
00330                 unvisitedTiles.set(currentRegionTile, currentRegionClearance);
00331                 tileToLastMinima[currentRegionTile] = currentRegionTile;
00332 
00333                 while(!unvisitedTiles.empty())
00334                 {
00335                         WalkPosition currentTile = unvisitedTiles.top().first;
00336                         int currentTileClearance = unvisitedTiles.top().second;
00337                         unvisitedTiles.pop();
00338 
00339                         if(chokeTiles.count(currentTile) != 0)
00340                         {
00341                                 if(chokeTiles[currentTile]->getRegions().second && chokeTiles[currentTile]->getRegions().second != currentRegion)
00342                                 {
00343                                         DrawBuffer::Instance().drawBufferedBox(BWAPI::CoordinateType::Map, currentTile.x * 8, currentTile.y * 8, currentTile.x * 8 + 8, currentTile.y * 8 + 8, 999999, BWAPI::Colors::Red);
00344                                         LOGMESSAGEWARNING("Touched a choke saved to anouther region");
00345                                 }
00346                                 else if(chokeTiles[currentTile]->getRegions().first != currentRegion)
00347                                 {
00348                                         currentRegion->addChokepoint(chokeTiles[currentTile]);
00349                                         chokeTiles[currentTile]->setRegion2(currentRegion);
00350                                 }
00351 
00352                                 continue;
00353                         }
00354 
00355                         if(mTileToRegion[currentTile.x][currentTile.y])
00356                         {
00357                                 LOGMESSAGEWARNING("2 regions possibly connected without a choke");
00358                                 continue;
00359                         }
00360 
00361                         WalkPosition lastMinima = tileToLastMinima[currentTile];
00362                         const int chokeSize = mTileClearance[lastMinima.x][lastMinima.y];
00363 
00364                         bool foundChokepoint = false;
00365                         if(chokeSize < int(float(currentRegionClearance)*0.90f) && chokeSize < int(float(currentTileClearance)*0.80f))
00366                                 foundChokepoint = true;
00367 
00368                         if(foundChokepoint)
00369                         {
00370                                 const int minDistance = 32;
00371                                 if((abs(currentRegionTile.x - lastMinima.x) + abs(currentRegionTile.y - lastMinima.y)) < minDistance)
00372                                         foundChokepoint = false;
00373                                 else if((abs(currentTile.x - lastMinima.x) + abs(currentTile.y - lastMinima.y)) < minDistance)
00374                                         foundChokepoint = false;
00375                                 else if(currentTileClearance < 120)
00376                                         foundChokepoint = false;
00377                         }
00378 
00379                         if(foundChokepoint)
00380                         {
00381                                 const std::pair<WalkPosition, WalkPosition> &chokeSides = findChokePoint(lastMinima);
00382 
00383                                 Chokepoint currentChokepoint(new ChokepointClass(chokeSides.first.getCenterPosition(), chokeSides.second.getCenterPosition(), chokeSize));
00384                                 mChokepoints.insert(currentChokepoint);
00385 
00386                                 currentChokepoint->setRegion1(currentRegion);
00387                                 currentRegion->addChokepoint(currentChokepoint);
00388 
00389                                 int x0 = chokeSides.second.x;
00390                                 int y0 = chokeSides.second.y;
00391 
00392                                 int x1 = chokeSides.first.x;
00393                                 int y1 = chokeSides.first.y;
00394 
00395                                 int dx = abs(x1 - x0);
00396                                 int dy = abs(y1 - y0);
00397 
00398                                 int sx = x0 < x1 ? 1 : -1;
00399                                 int sy = y0 < y1 ? 1 : -1;
00400 
00401                                 int error = dx - dy;
00402 
00403                                 std::set<WalkPosition> chokeChildren;
00404 
00405                                 for(;;)
00406                                 {
00407                                         if(x0 >= 0 && y0 >= 0 && x0 < mapWidth && y0 < mapHeight && mTileClearance[x0][y0] != 0 && !mTileToRegion[x0][y0])
00408                                         {
00409                                                 const WalkPosition thisChokeTile(x0, y0);
00410 
00411                                                 tileToChildren[currentRegionTile].push_back(thisChokeTile);
00412                                                 chokeTiles[thisChokeTile] = currentChokepoint;
00413                                                 chokeChildren.insert(thisChokeTile);
00414                                         }
00415 
00416                                         if(x0 == x1 && y0 == y1)
00417                                                 break;
00418 
00419                                         int e2 = error*2;
00420                                         if(e2 > -dy)
00421                                         {
00422                                                 error -= dy;
00423                                                 x0 += sx;
00424                                         }
00425                                         if(e2 < dx)
00426                                         {
00427                                                 error += dx;
00428                                                 y0 += sy;
00429                                         }
00430                                 }
00431 
00432                                 while(!chokeChildren.empty())
00433                                 {
00434                                         std::set<WalkPosition>::iterator currentTile = chokeChildren.begin();
00435 
00436                                         tileToLastMinima.erase(*currentTile);
00437                                         unvisitedTiles.erase(*currentTile);
00438 
00439                                         for each(WalkPosition nextTile in tileToChildren[*currentTile])
00440                                         {
00441                                                 chokeChildren.insert(nextTile);
00442                                         }
00443                                         tileToChildren.erase(*currentTile);
00444 
00445                                         chokeChildren.erase(currentTile);
00446                                 }
00447                         }
00448                         else
00449                         {
00450                                 if(mTileClearance[currentTile.x][currentTile.y] < chokeSize)
00451                                         lastMinima = currentTile;
00452 
00453                                 for(int i = 0; i < 4; ++i)
00454                                 {
00455                                         int x = (i == 0 ? currentTile.x-1 : (i == 1 ? currentTile.x+1 : currentTile.x));
00456                                         int y = (i == 2 ? currentTile.y-1 : (i == 3 ? currentTile.y+1 : currentTile.y));
00457 
00458                                         if(x < 0 || y < 0 || x >= mapWidth || y >= mapHeight)
00459                                                 continue;
00460 
00461                                         if(mTileClearance[x][y] == 0)
00462                                                 continue;
00463 
00464                                         const WalkPosition nextTile(x, y);
00465                                         if(tileToLastMinima.count(nextTile) == 0)
00466                                         {
00467                                                 tileToLastMinima[nextTile] = lastMinima;
00468                                                 tileToChildren[currentTile].push_back(nextTile);
00469 
00470                                                 unvisitedTiles.set(nextTile, mTileClearance[x][y]);
00471                                         }
00472                                 }
00473                         }
00474                 }
00475 
00476                 std::set<WalkPosition> tileSteps;
00477                 tileSteps.insert(currentRegionTile);
00478                 int regionSize = 1;
00479 
00480                 while(!tileSteps.empty())
00481                 {
00482                         std::set<WalkPosition>::iterator currentTile = tileSteps.begin();
00483                         ++regionSize;
00484 
00485                         for each(WalkPosition nextTile in tileToChildren[*currentTile])
00486                         {
00487                                 tileSteps.insert(nextTile);
00488                         }
00489 
00490                         mTileToRegion[currentTile->x][currentTile->y] = currentRegion;
00491 
00492                         tileSteps.erase(currentTile);
00493                 }
00494 
00495                 currentRegion->setSize(regionSize);
00496         }
00497 
00498         for(std::set<Chokepoint>::iterator it = mChokepoints.begin(); it != mChokepoints.end();)
00499         {
00500                 if(!(*it)->getRegions().first || !(*it)->getRegions().second || (*it)->getRegions().first == (*it)->getRegions().second)
00501                         removeChokepoint(*(it++));
00502                 else
00503                         ++it;
00504         }
00505 }
00506 
00507 //Functor that remembers the closest location tested to the resources
00508 class PossibleLocationCompare
00509 {
00510 public:
00511         PossibleLocationCompare(UnitGroup *resources, TilePosition *bestLocation)
00512                 : mBestLocation(bestLocation)
00513                 , mResources(resources)
00514                 , mBestRating(std::numeric_limits<unsigned int>::max())
00515         {}
00516 
00517         bool operator()(TilePosition &location)
00518         {
00519                 for(int x = location.x(); x < location.x() + BWAPI::UnitTypes::Protoss_Nexus.tileWidth(); ++x)
00520                 {
00521                         for(int y = location.y(); y < location.y() + BWAPI::UnitTypes::Protoss_Nexus.tileHeight(); ++y)
00522                         {
00523                                 if(x < 0 && y < 0 && x >= BWAPI::Broodwar->mapWidth() && y >= BWAPI::Broodwar->mapHeight())
00524                                         return false;
00525 
00526                                 if(!BWAPI::Broodwar->isBuildable(x, y))
00527                                         return false;
00528                         }
00529                 }
00530 
00531                 unsigned int distanceToResources = 0;
00532                 for each(const Unit &resource in *mResources)
00533                 {
00534                         const BWAPI::UnitType &resourceType = resource->getType();
00535                         const TilePosition &resourceTilePosition = resource->getTilePosition();
00536 
00537                         if (resourceTilePosition.x() > location.x() - (resourceType == BWAPI::UnitTypes::Resource_Mineral_Field ? 5 : 7) &&
00538                                 resourceTilePosition.y() > location.y() - (resourceType == BWAPI::UnitTypes::Resource_Mineral_Field ? 4 : 5) &&
00539                                 resourceTilePosition.x() < location.x() + 7 &&
00540                                 resourceTilePosition.y() < location.y() + 6)
00541                         {
00542                                 return false;
00543                         }
00544 
00545                         const Position &resourcePosition = resource->getPosition();
00546 
00547                         int tx = location.x()*32+64;
00548                         int ty = location.y()*32+48;
00549 
00550                         int uLeft       = resourcePosition.x() - resourceType.dimensionLeft();
00551                         int uTop        = resourcePosition.y() - resourceType.dimensionUp();
00552                         int uRight      = resourcePosition.x() + resourceType.dimensionRight() + 1;
00553                         int uBottom     = resourcePosition.y() + resourceType.dimensionDown() + 1;
00554 
00555                         int targLeft    = tx - BWAPI::Broodwar->self()->getRace().getCenter().dimensionLeft();
00556                         int targTop     = ty - BWAPI::Broodwar->self()->getRace().getCenter().dimensionUp();
00557                         int targRight   = tx + BWAPI::Broodwar->self()->getRace().getCenter().dimensionRight() + 1;
00558                         int targBottom  = ty + BWAPI::Broodwar->self()->getRace().getCenter().dimensionDown() + 1;
00559 
00560                         int xDist = uLeft - targRight;
00561                         if(xDist < 0)
00562                         {
00563                                 xDist = targLeft - uRight;
00564                                 if(xDist < 0)
00565                                         xDist = 0;
00566                         }
00567 
00568                         int yDist = uTop - targBottom;
00569                         if(yDist < 0)
00570                         {
00571                                 yDist = targTop - uBottom;
00572                                 if(yDist < 0)
00573                                         yDist = 0;
00574                         }
00575 
00576                         distanceToResources += Position(0,0).getApproxDistance(Position(xDist, yDist));
00577                 }
00578 
00579                 if(distanceToResources < mBestRating)
00580                 {
00581                         mBestRating = distanceToResources;
00582                         *mBestLocation = location;
00583                 }
00584 
00585                 return false;
00586         }
00587 
00588 private:
00589         unsigned int mBestRating;
00590         TilePosition *mBestLocation;
00591         UnitGroup *mResources;
00592 };
00593 
00594 void TerrainAnaysisClass::createBases()
00595 {
00596         //Create a set of all Geysers and all mineral patches with more than 200 minerals
00597         UnitGroup resources = UnitTracker::Instance().getGeysers();
00598         for each(Unit mineral in UnitTracker::Instance().getMinerals())
00599         {
00600                 if(mineral->getResources() > 200)
00601                         resources.insert(mineral);
00602         }
00603 
00604         //Group them into clusters
00605         std::vector<UnitGroup> resourceClusters = UnitHelper::getClusters(resources, 260, 3);
00606 
00607         //TODO: create the bases on the fly rather then collect information then create
00608         std::set<TilePosition> basesToCreate;
00609         std::map<TilePosition, UnitGroup> baseToCreateToMineral;
00610         std::map<TilePosition, bool> baseIsRegionBase;
00611         std::map<TilePosition, bool> baseToCreateIsStartLocation;
00612         std::map<TilePosition, Region> baseToRegion;
00613         std::map<Region, std::set<TilePosition>> baseToCreateFromRegion;
00614 
00615         for each(UnitGroup resourceCluster in resourceClusters)
00616         {
00617                 TilePosition baseLocation;
00618                 PossibleLocationCompare locationCompare(&resourceCluster, &baseLocation);
00619                 MapHelper::spiralSearch(TilePosition(resourceCluster.getCenter()), locationCompare, 18);
00620 
00621                 bool addedToOther = false;
00622                 for(std::map<TilePosition, UnitGroup>::iterator it = baseToCreateToMineral.begin(); it != baseToCreateToMineral.end(); ++it)
00623                 {
00624                         int dx = abs(baseLocation.x() - it->first.x());
00625                         int dy = abs(baseLocation.y() - it->first.y());
00626 
00627                         if(dx <= 4 && dy <= 3)
00628                         {
00629                                 it->second.insert(resourceCluster.begin(), resourceCluster.end());
00630                                 addedToOther = true;
00631                                 break;
00632                         }
00633                 }
00634 
00635                 if(!addedToOther)
00636                 {
00637                         basesToCreate.insert(baseLocation);
00638                         baseToCreateToMineral[baseLocation] = resourceCluster;
00639                 }
00640         }
00641 
00642         for each(TilePosition base in basesToCreate)
00643         {
00644                 Region region = mTileToRegion[base.x() * 4][base.y() * 4];
00645                 if(region)
00646                 {
00647                         baseToCreateFromRegion[region].insert(base);
00648                         baseToRegion[base] = region;
00649                 }
00650         }
00651 
00652         RectangleArray<TilePosition> tileToBase(BWAPI::Broodwar->mapWidth(), BWAPI::Broodwar->mapHeight());
00653         std::map<TilePosition, std::set<TilePosition>> baseToTiles;
00654 
00655         for(int x = 0; x < BWAPI::Broodwar->mapWidth(); ++x)
00656         {
00657                 for(int y = 0; y < BWAPI::Broodwar->mapHeight(); ++y)
00658                 {
00659                         Region region = mTileToRegion[x*4][y*4];
00660 
00661                         //This isn't a region, so find the closest Region
00662                         if(!region || region->getClearance() < 80)
00663                         {
00664                                 int distance = std::numeric_limits<int>::max();
00665                                 for each(Region reg in mRegions)
00666                                 {
00667                                         if(reg->getClearance() < 80)
00668                                                 continue;
00669 
00670                                         int thisDistance = reg->getCenter().getApproxDistance(Position(x*32, y*32));
00671                                         if(thisDistance < distance)
00672                                         {
00673                                                 distance = thisDistance;
00674                                                 region = reg;
00675                                         }
00676                                 }
00677                         }
00678 
00679                         // Still hasn't got a region? something must be wrong with the analysis
00680                         if(!region)
00681                                 return;
00682                         
00683                         // Dont already have a base for this region
00684                         if(baseToCreateFromRegion.count(region) == 0)
00685                         {
00686                                 TilePosition newBase = TilePosition(region->getCenter());
00687 
00688                                 basesToCreate.insert(newBase);
00689                                 baseToCreateFromRegion[region].insert(newBase);
00690                                 baseToRegion[newBase] = region;
00691 
00692                                 tileToBase[x][y] = newBase;
00693                                 baseToTiles[newBase].insert(TilePosition(x, y));
00694                                 baseIsRegionBase[newBase] = true;
00695                         }
00696                         // Have 1 base exactly, use it
00697                         else if(baseToCreateFromRegion[region].size() == 1)
00698                         {
00699                                 TilePosition base = *baseToCreateFromRegion[region].begin();
00700                                 tileToBase[x][y] = base;
00701                                 baseToTiles[base].insert(TilePosition(x, y));
00702                         }
00703                         // Find the closest from the possibilities
00704                         else
00705                         {
00706                                 TilePosition baseToUse;
00707                                 int distance = std::numeric_limits<int>::max();
00708 
00709                                 for each(TilePosition base in baseToCreateFromRegion[region])
00710                                 {
00711                                         int thisDistance = Position(base).getApproxDistance(Position(x*32, y*32));
00712                                         if(thisDistance < distance)
00713                                         {
00714                                                 distance = thisDistance;
00715                                                 baseToUse = base;
00716                                         }
00717                                 }
00718 
00719                                 tileToBase[x][y] = baseToUse;
00720                                 baseToTiles[baseToUse].insert(TilePosition(x, y));
00721                         }
00722                 }
00723         }
00724 
00725         for each(TilePosition startLocation in BWAPI::Broodwar->getStartLocations())
00726         {
00727                 baseToCreateIsStartLocation[tileToBase[startLocation.x()][startLocation.y()]] = true;
00728         }
00729 
00730         for each(TilePosition base in basesToCreate)
00731         {
00732                 Base newBase;
00733                 if(baseIsRegionBase[base])
00734                         newBase = BaseTracker::Instance().createBase(baseToTiles[base], baseToRegion[base], baseToCreateIsStartLocation[base]);
00735                 else
00736                         newBase = BaseTracker::Instance().createBase(baseToTiles[base], baseToRegion[base], baseToCreateIsStartLocation[base], base, baseToCreateToMineral[base]);
00737 
00738                 newBase->getRegion()->addBase(newBase);
00739         }
00740 }
00741 
00742 void TerrainAnaysisClass::removeChokepoint(Chokepoint chokeToRemove)
00743 {
00744         //Removes a chokepoint and if its a real one will merge the 2 regions
00745 
00746         Region reg1 = chokeToRemove->getRegions().first;
00747         Region reg2 = chokeToRemove->getRegions().second;
00748 
00749         if(reg1)
00750                 reg1->removeChokepoint(chokeToRemove);
00751 
00752         if(reg2 && reg2 != reg1)
00753                 reg2->removeChokepoint(chokeToRemove);
00754 
00755         // choke is real, need to merge the regions
00756         if(reg1 && reg2 && reg1 != reg2)
00757         {
00758                 LOGMESSAGEWARNING("Tries to Merge 2 regions but is not implemented");
00759         }
00760 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines