BWAPI
|
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 ¤tParent = 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 }