BWAPI
|
00001 #include "BuildingPlacer.h" 00002 00003 #include <boost/bind.hpp> 00004 00005 #include "BaseTracker.h" 00006 #include "UnitHelper.h" 00007 #include "MapHelper.h" 00008 #include "UnitTracker.h" 00009 #include "TerrainAnaysis.h" 00010 #include "DrawBuffer.h" 00011 #include "WallTracker.h" 00012 #include "BorderTracker.h" 00013 #include "ScoutManager.h" 00014 #include "PylonPowerTracker.h" 00015 00016 BuildingPlacerClass::BuildingPlacerClass() 00017 { 00018 } 00019 00020 void BuildingPlacerClass::calculateReservations() 00021 { 00022 const BWAPI::UnitType ¢erType = BWAPI::Broodwar->self()->getRace().getCenter(); 00023 const BWAPI::UnitType &refineryType = BWAPI::Broodwar->self()->getRace().getRefinery(); 00024 00025 // first reserve all wall positions 00026 mPermanentReserved = WallTracker::Instance().getWallTiles(); 00027 00028 // for each base that has resources 00029 for each(Base base in BaseTracker::Instance().getResourceBases()) 00030 { 00031 // reserve the base location 00032 for(int x = base->getCenterBuildLocation().x(); x < base->getCenterBuildLocation().x()+centerType.tileWidth(); ++x) 00033 for(int y = base->getCenterBuildLocation().y(); y < base->getCenterBuildLocation().y()+centerType.tileHeight(); ++y) 00034 mPermanentReserved[TilePosition(x, y)] = centerType; 00035 00036 // if its zerg, also reserve the area the larva hang out 00037 if(BWAPI::Broodwar->self()->getRace() == BWAPI::Races::Zerg) 00038 { 00039 for(int x = base->getCenterBuildLocation().x() - 1; x < base->getCenterBuildLocation().x()+centerType.tileWidth()+1; ++x) 00040 for(int y = base->getCenterBuildLocation().y() - 1; y < base->getCenterBuildLocation().y()+centerType.tileHeight()+1; ++y) 00041 mPermanentReserved[TilePosition(x, y)] = centerType; 00042 } 00043 00044 // and reserve the geyser space just so it doesn't get included in the resource reserved space 00045 for each(Unit geyser in base->getGeysers()) 00046 { 00047 for(int x = geyser->getTilePosition().x(); x < geyser->getTilePosition().x()+geyser->getType().tileWidth(); ++x) 00048 for(int y = geyser->getTilePosition().y(); y < geyser->getTilePosition().y()+geyser->getType().tileHeight(); ++y) 00049 mPermanentReserved[TilePosition(x, y)] = refineryType; 00050 } 00051 00052 reserveResourceSpace(base->getMinerals(), base); 00053 reserveResourceSpace(base->getGeysers(), base); 00054 } 00055 } 00056 00057 void BuildingPlacerClass::finaliseReservations() 00058 { 00059 // Reserve the tiles around the choke for general use 00060 // TODO: perhaps only in a path between the two sides 00061 for each(Chokepoint choke in TerrainAnaysis::Instance().getChokepoints()) 00062 { 00063 int minX = std::min(choke->getBuildTiles().first.x(), choke->getBuildTiles().second.x()); 00064 int maxX = std::max(choke->getBuildTiles().first.x(), choke->getBuildTiles().second.x()); 00065 00066 int minY = std::min(choke->getBuildTiles().first.y(), choke->getBuildTiles().second.y()); 00067 int maxY = std::max(choke->getBuildTiles().first.y(), choke->getBuildTiles().second.y()); 00068 00069 for(int x = minX; x <= maxX; ++x) 00070 for(int y = minY; y <= maxY; ++y) 00071 if(mPermanentReserved.count(TilePosition(x, y)) == 0) 00072 mPermanentReserved[TilePosition(x, y)] = BWAPI::UnitTypes::None; 00073 } 00074 } 00075 00076 void BuildingPlacerClass::reserveResourceSpace(const UnitGroup &resources, Base base) 00077 { 00078 for each(Unit resource in resources) 00079 { 00080 int distanceBetween = (resource->getPosition().getApproxDistance(base->getCenterLocation()) / 32) + 1; 00081 for(int x = resource->getTilePosition().x() - int(distanceBetween); x < resource->getTilePosition().x() + int(distanceBetween) + 4; ++x) 00082 { 00083 for(int y = resource->getTilePosition().y() - int(distanceBetween); y < resource->getTilePosition().y() + int(distanceBetween) + 3; ++y) 00084 { 00085 int distanceToResource = Position(x*32+16, y*32+16).getApproxDistance(resource->getPosition()) / 32; 00086 int distanceToBase = Position(x*32+16, y*32+16).getApproxDistance(base->getCenterLocation()) / 32; 00087 00088 if(distanceToResource + distanceToBase < distanceBetween && mPermanentReserved.count(TilePosition(x, y)) == 0) 00089 { 00090 if(resource->getType().isMineralField()) 00091 mResources[resource].insert(TilePosition(x, y)); 00092 00093 ++mResourceReserved[TilePosition(x, y)]; 00094 } 00095 } 00096 } 00097 } 00098 } 00099 00100 void BuildingPlacerClass::update() 00101 { 00102 for(std::set<ReservedLocation>::iterator it = mReservedLocations.begin(); it != mReservedLocations.end();) 00103 { 00104 if((*it)->update()) 00105 mReservedLocations.erase(it++); 00106 else 00107 ++it; 00108 } 00109 00110 // for(std::map<TilePosition, BWAPI::UnitType>::iterator it = mPermanentReserved.begin(); it != mPermanentReserved.end(); ++it) 00111 // { 00112 // BWAPI::Broodwar->drawBox(BWAPI::CoordinateType::Map, it->first.x() * 32, it->first.y() * 32, it->first.x() * 32 + 32, it->first.y() * 32 + 32, BWAPI::Colors::Red); 00113 // } 00114 // for(std::map<TilePosition, int>::iterator it = mResourceReserved.begin(); it != mResourceReserved.end(); ++it) 00115 // { 00116 // BWAPI::Broodwar->drawCircle(BWAPI::CoordinateType::Map, it->first.x()*32+16, it->first.y()*32+16, 16, BWAPI::Colors::Blue); 00117 // } 00118 // for(std::map<TilePosition, ReservedLocation>::iterator it = mReservedTiles.begin(); it != mReservedTiles.end(); ++it) 00119 // { 00120 // BWAPI::Broodwar->drawBox(BWAPI::CoordinateType::Map, it->first.x() * 32, it->first.y() * 32, it->first.x() * 32 + 32, it->first.y() * 32 + 32, BWAPI::Colors::Red); 00121 // } 00122 } 00123 00124 void BuildingPlacerClass::onDestroy(Unit unit) 00125 { 00126 if(mResources.count(unit) != 0) 00127 { 00128 for each(TilePosition tile in mResources[unit]) 00129 { 00130 --mResourceReserved[tile]; 00131 if(mResourceReserved[tile] == 0) 00132 mResourceReserved.erase(tile); 00133 } 00134 00135 mResources.erase(unit); 00136 } 00137 } 00138 00139 void BuildingPlacerClass::reserve(ReservedLocation location) 00140 { 00141 int startx = location->getTilePosition().x(); 00142 int starty = location->getTilePosition().y(); 00143 00144 int endx = startx + location->getUnitType().tileWidth(); 00145 int endy = starty + location->getUnitType().tileHeight(); 00146 00147 if(UnitHelper::hasAddon(location->getUnitType())) 00148 endx += 2; 00149 00150 for(int x = startx; x < endx; ++x) 00151 for(int y = starty; y < endy; ++y) 00152 mReservedTiles[TilePosition(x, y)] = location; 00153 } 00154 00155 void BuildingPlacerClass::free(ReservedLocation location) 00156 { 00157 int startx = location->getTilePosition().x(); 00158 int starty = location->getTilePosition().y(); 00159 00160 int endx = startx + location->getUnitType().tileWidth(); 00161 int endy = starty + location->getUnitType().tileHeight(); 00162 00163 if(UnitHelper::hasAddon(location->getUnitType())) 00164 endx += 2; 00165 00166 for(int x = startx; x < endx; ++x) 00167 for(int y = starty; y < endy; ++y) 00168 mReservedTiles.erase(TilePosition(x, y)); 00169 } 00170 00171 ReservedLocation BuildingPlacerClass::getLandingReservation(Unit unit) 00172 { 00173 ReservedLocation location(new ReservedLocationClass(unit)); 00174 mReservedLocations.insert(location); 00175 return location; 00176 } 00177 00178 ReservedLocation BuildingPlacerClass::getBuildingReservation(BuildingLocation position, BWAPI::UnitType type) 00179 { 00180 ReservedLocation location(new ReservedLocationClass(type, position)); 00181 mReservedLocations.insert(location); 00182 return location; 00183 } 00184 00185 bool BuildingPlacerClass::isReserved(TilePosition position) const 00186 { 00187 return mReservedTiles.find(position) != mReservedTiles.end(); 00188 } 00189 00190 bool BuildingPlacerClass::isReserved(int x, int y) const 00191 { 00192 return isReserved(TilePosition(x, y)); 00193 } 00194 00195 bool BuildingPlacerClass::isResourceReserved(TilePosition position) const 00196 { 00197 return mResourceReserved.find(position) != mResourceReserved.end(); 00198 } 00199 00200 bool BuildingPlacerClass::isResourceReserved(int x, int y) const 00201 { 00202 return isResourceReserved(TilePosition(x, y)); 00203 } 00204 00205 std::pair<TilePosition, Base> BuildingPlacerClass::buildingLocationToTile(BuildingLocation position, BWAPI::UnitType type) const 00206 { 00207 if(type.isRefinery()) 00208 return getRefineryLocation(); 00209 00210 if(type.requiresPsi()) 00211 { 00212 bool atleastone = false; 00213 for each(Unit pylon in UnitTracker::Instance().selectAllUnits(BWAPI::UnitTypes::Protoss_Pylon)) 00214 { 00215 if(pylon->isCompleted()) 00216 atleastone = true; 00217 } 00218 if(!atleastone) 00219 return std::make_pair(BWAPI::TilePositions::None, Base()); 00220 } 00221 00222 switch(position.underlying()) 00223 { 00224 case BuildingLocation::BaseChoke: 00225 { 00226 TilePosition pos = WallTracker::Instance().getWallPosition(type); 00227 if(pos != BWAPI::TilePositions::None) 00228 return std::make_pair(pos, BaseTracker::Instance().getBase(pos)); 00229 } 00230 case BuildingLocation::BaseParimeter: 00231 case BuildingLocation::Base: 00232 { 00233 for each(Base base in baseToBuildAtOrder(type)) 00234 { 00235 TilePosition pos = getBuildLocation(base, type); // TODO : flags of some sort so certain units can be build in minerals etc 00236 00237 if(pos != BWAPI::TilePositions::None) 00238 return std::make_pair(pos, base); 00239 } 00240 break; 00241 } 00242 case BuildingLocation::Expansion: 00243 return getExpandLocation(); 00244 case BuildingLocation::ExpansionGas: 00245 return getExpandLocation(true); 00246 case BuildingLocation::Proxy: 00247 //TODO: find a location that isn't on the path between any base to any other base start locations closest to potential enemy locations 00248 case BuildingLocation::Manner: 00249 //TODO: build in a location that harms the enemy, engineering bay in expand location, pylon in mineral line, gas steal etc 00250 break; 00251 } 00252 00253 return std::make_pair(BWAPI::TilePositions::None, Base()); 00254 } 00255 00256 std::pair<TilePosition, Base> BuildingPlacerClass::getlandingLocation(Unit unit) const 00257 { 00258 // TODO : NYI 00259 return std::make_pair(BWAPI::TilePositions::None, Base()); 00260 //return BuildingPlacer::Instance().getBuildLocation(unit->getTilePosition() + TilePosition(0, 1)); 00261 } 00262 00263 class BuildLocationCompare 00264 { 00265 public: 00266 BuildLocationCompare(Base base, BWAPI::UnitType type) : mBase(base), mType(type) {} 00267 00268 bool operator()(TilePosition location) const 00269 { 00270 if(BaseTracker::Instance().getBase(location) != mBase) 00271 return false; 00272 00273 return BuildingPlacer::Instance().isLocationNonBlocking(location, mType); 00274 } 00275 00276 private: 00277 Base mBase; 00278 BWAPI::UnitType mType; 00279 }; 00280 00281 TilePosition BuildingPlacerClass::getBuildLocation(Base base, BWAPI::UnitType type) const 00282 { 00283 return MapHelper::spiralSearch(base->getCenterBuildLocation(), BuildLocationCompare(base, type)); 00284 } 00285 00286 class RegionChokeCompare 00287 { 00288 public: 00289 RegionChokeCompare(bool ignoreReservations, Region region) 00290 : mIgnoreReservations(ignoreReservations) 00291 , mRegion(region) 00292 {} 00293 00294 bool operator()(TilePosition &location) 00295 { 00296 return BuildingPlacer::Instance().isTileWalkable(location, mIgnoreReservations) && TerrainAnaysis::Instance().getRegion(location) == mRegion; 00297 } 00298 00299 private: 00300 bool mIgnoreReservations; 00301 Region mRegion; 00302 }; 00303 00304 bool BuildingPlacerClass::isLocationNonBlocking(TilePosition position, BWAPI::UnitType type, bool ignoreReservations) const 00305 { 00306 if(!isLocationBuildable(position, type, ignoreReservations)) 00307 return false; 00308 00309 std::set<TilePosition> targets = getSurroundingTiles(position, type, ignoreReservations); 00310 00311 /* If there are no surrounding tiles, it's probably impossible to reach the build site */ 00312 if(targets.empty()) 00313 return false; 00314 00315 /* Don't build on choke tiles, they are vital for the calculation */ 00316 Region region = TerrainAnaysis::Instance().getRegion(position); 00317 const std::set<TilePosition> &chokeTiles = region->getChokepointTiles(); 00318 for each(TilePosition tile in chokeTiles) 00319 { 00320 if(tile.x() >= position.x() && tile.x() < position.x() + type.tileWidth() && tile.y() >= position.y() && tile.y() < position.y() + type.tileHeight()) 00321 return false; 00322 00323 targets.insert(tile); 00324 } 00325 00326 /* Start from one of the chokes */ 00327 TilePosition startTile = *chokeTiles.begin(); 00328 00329 /* Ignore the tiles we are building on as we cant path though this building */ 00330 std::set<TilePosition> ignoreTiles; 00331 for(int x = position.x(); x < position.x() + type.tileWidth(); ++x) 00332 for(int y = position.y(); y < position.y() + type.tileHeight(); ++y) 00333 ignoreTiles.insert(TilePosition(x, y)); 00334 00335 /* Don't block other buildings */ 00336 for each(Unit unit in UnitTracker::Instance().getAllUnits()) 00337 { 00338 if(unit->exists() && !unit->getType().canProduce()) 00339 continue; 00340 00341 /* Refineries are ok as they will be protected by resource reservation */ 00342 if(unit->getType().isRefinery()) 00343 continue; 00344 00345 if(UnitHelper::unitProducesGround(unit->getType())) 00346 { 00347 /* 2 is no location found yet */ 00348 int isBlocked = 2; 00349 for each(TilePosition tile in getSurroundingTiles(unit->getTilePosition(), unit->getType(), ignoreReservations)) 00350 { 00351 if(TerrainAnaysis::Instance().getRegion(tile) == region) 00352 { 00353 /* If this location is touching this building, ensure we don't block all exits */ 00354 if(ignoreTiles.find(tile) != ignoreTiles.end()) 00355 isBlocked = (isBlocked==0?0:1); 00356 else 00357 { 00358 /* This tile is not blocked, we can touch this building here */ 00359 targets.insert(tile); 00360 isBlocked = 0; 00361 } 00362 } 00363 } 00364 00365 /* Building here will stop units being able to exit this building */ 00366 if(isBlocked == 1) 00367 return false; 00368 } 00369 } 00370 00371 /* Check which tiles can be reached */ 00372 targets = MapHelper::floodFill(startTile, RegionChokeCompare(ignoreReservations, region), targets, ignoreTiles); 00373 00374 /* If there are no remaining targets, there are all reachable */ 00375 if(targets.empty()) 00376 return true; 00377 00378 /* Check if we could reach these positions before */ 00379 std::set<TilePosition> newTargets = MapHelper::floodFill(startTile, RegionChokeCompare(ignoreReservations, region), targets); 00380 00381 /* If they are the same, they were never reachable */ 00382 if(targets == newTargets) 00383 { 00384 //if(m_bShowDebugInfo) 00385 // { 00386 // DrawBuffer::Instance().clearBuffer(BufferedCategory::BuildingPlacer); 00387 // for each(TilePosition tile in targets) 00388 // DrawBuffer::Instance().drawBufferedCircle(BWAPI::CoordinateType::Map, tile.x()*32+16, tile.y()*32+16, 16, 240, BWAPI::Colors::Red, false, BufferedCategory::BuildingPlacer); 00389 // 00390 // for(int x = position.x(); x < position.x() + type.tileWidth(); ++x) 00391 // for(int y = position.y(); y < position.y() + type.tileHeight(); ++y) 00392 // DrawBuffer::Instance().drawBufferedCircle(BWAPI::CoordinateType::Map, x*32+16, y*32+16, 16, 240, BWAPI::Colors::White, false, BufferedCategory::BuildingPlacer); 00393 // } 00394 00395 return true; 00396 } 00397 00398 //if(m_bShowDebugInfo) 00399 // { 00400 // DrawBuffer::Instance().clearBuffer(BufferedCategory::BuildingPlacer); 00401 // for each(TilePosition tile in targets) 00402 // DrawBuffer::Instance().drawBufferedCircle(BWAPI::CoordinateType::Map, tile.x()*32+16, tile.y()*32+16, 16, 240, BWAPI::Colors::Red, false, BufferedCategory::BuildingPlacer); 00403 // 00404 // for each(TilePosition tile in newTargets) 00405 // DrawBuffer::Instance().drawBufferedCircle(BWAPI::CoordinateType::Map, tile.x()*32+16, tile.y()*32+16, 16, 240, BWAPI::Colors::Yellow, false, BufferedCategory::BuildingPlacer); 00406 // 00407 // for(int x = position.x(); x < position.x() + type.tileWidth(); ++x) 00408 // for(int y = position.y(); y < position.y() + type.tileHeight(); ++y) 00409 // DrawBuffer::Instance().drawBufferedCircle(BWAPI::CoordinateType::Map, x*32+16, y*32+16, 16, 240, BWAPI::Colors::White, false, BufferedCategory::BuildingPlacer); 00410 // 00411 // DrawBuffer::Instance().drawBufferedCircle(BWAPI::CoordinateType::Map, startTile.x()*32+16, startTile.y()*32+16, 16, 240, BWAPI::Colors::Green, false, BufferedCategory::BuildingPlacer); 00412 // } 00413 00414 return false; 00415 } 00416 00417 bool BuildingPlacerClass::isLocationBuildable(TilePosition position, BWAPI::UnitType type, bool ignoreReservations) const 00418 { 00419 if(type.isRefinery()) 00420 { 00421 for each(Unit geyser in UnitTracker::Instance().getGeysers()) 00422 { 00423 if(geyser->getTilePosition() == position) 00424 { 00425 if(!ignoreReservations) 00426 { 00427 for(int x = position.x(); x < position.x() + type.tileWidth(); ++x) 00428 { 00429 for(int y = position.y(); y < position.y() + type.tileHeight(); ++y) 00430 { 00431 if(isReserved(x, y)) 00432 return false; 00433 } 00434 } 00435 } 00436 00437 return true; 00438 } 00439 } 00440 00441 return false; 00442 } 00443 00444 for(int x = position.x(); x < position.x() + type.tileWidth(); ++x) 00445 { 00446 for(int y = position.y(); y < position.y() + type.tileHeight(); ++y) 00447 { 00448 if(!isTileBuildable(TilePosition(x, y), type, ignoreReservations)) 00449 return false; 00450 } 00451 } 00452 00453 if(type.isResourceDepot()) 00454 { 00455 for each(Unit mineral in UnitTracker::Instance().getMinerals()) 00456 { 00457 if(mineral->accessibility() != AccessType::Dead) 00458 { 00459 if (mineral->getTilePosition().x() > position.x() - 5 && 00460 mineral->getTilePosition().y() > position.y() - 4 && 00461 mineral->getTilePosition().x() < position.x() + 7 && 00462 mineral->getTilePosition().y() < position.y() + 6) 00463 { 00464 return false; 00465 } 00466 } 00467 } 00468 for each(Unit geyser in UnitTracker::Instance().getGeysers()) 00469 { 00470 if(geyser->accessibility() != AccessType::Dead) 00471 { 00472 if (geyser->getTilePosition().x() > position.x() - 7 && 00473 geyser->getTilePosition().y() > position.y() - 5 && 00474 geyser->getTilePosition().x() < position.x() + 7 && 00475 geyser->getTilePosition().y() < position.y() + 6) 00476 { 00477 return false; 00478 } 00479 } 00480 } 00481 } 00482 00483 if(type.requiresPsi()) 00484 { 00485 if(!PylonPowerTracker::Instance().hasPower(position, type)) 00486 return false; 00487 } 00488 00489 /* If this has an addon, make sure there is space to build it */ 00490 if(UnitHelper::hasAddon(type) && !isAddonBuildable(position)) 00491 return false; 00492 00493 /* Put some extra space between the first 6 pylons*/ 00494 /*if(type == BWAPI::UnitTypes::Protoss_Pylon) 00495 { 00496 UnitGroup ug = SelectAll(BWAPI::UnitTypes::Protoss_Pylon); 00497 if(ug.size() < 6) 00498 { 00499 ug = ug.inRadius(8 * 32, position); 00500 00501 if(ug.size() != 0) 00502 return false; 00503 } 00504 }*/ 00505 00506 return true; 00507 } 00508 00509 bool BuildingPlacerClass::isTileBlocked(TilePosition tile, BWAPI::UnitType type, bool ignoreReservations) const 00510 { 00511 if(!ignoreReservations) 00512 { 00513 if(isReserved(tile) || (!UnitHelper::isStaticDefense(type) && isResourceReserved(tile))) 00514 return true; 00515 00516 std::map<TilePosition, BWAPI::UnitType>::const_iterator it = mPermanentReserved.find(tile); 00517 if(it != mPermanentReserved.end()) 00518 if(it->second != type) 00519 return true; 00520 } 00521 00522 for each(Unit unit in UnitTracker::Instance().getUnitsOnTile(tile.x(), tile.y())) 00523 { 00524 if(!unit->exists()) 00525 continue; 00526 00527 if(unit->getType().isBuilding() && !unit->isLifted()) 00528 return true; 00529 00530 if(!type.isRefinery() && unit->getType() == BWAPI::UnitTypes::Resource_Vespene_Geyser) 00531 return true; 00532 00533 if(!unit->getType().canMove()) 00534 return true; 00535 } 00536 00537 if(BWAPI::Broodwar->self()->getRace() == BWAPI::Races::Terran && !type.isAddon()) 00538 { 00539 if(tile.x()-1 >= 0) 00540 if(isAddonBuilder(tile.x()-1, tile.y())) 00541 return true; 00542 if(tile.x()-2 >= 0) 00543 if(isAddonBuilder(tile.x()-2, tile.y())) 00544 return true; 00545 } 00546 00547 return false; 00548 } 00549 00550 bool BuildingPlacerClass::isTileBuildable(TilePosition tile, BWAPI::UnitType type, bool ignoreReservations) const 00551 { 00552 if(!BWAPI::Broodwar->isBuildable(tile)) 00553 return false; 00554 00555 if(type.getRace() == BWAPI::Races::Zerg) 00556 { 00557 if(!type.isResourceDepot() && !BWAPI::Broodwar->hasCreep(tile)) 00558 return false; 00559 } 00560 else if(BWAPI::Broodwar->hasCreep(tile)) 00561 return false; 00562 00563 return !isTileBlocked(tile, type, ignoreReservations); 00564 } 00565 00566 bool BuildingPlacerClass::isTileWalkable(TilePosition tile, bool ignoreReservations) const 00567 { 00568 if(!MapHelper::isTileWalkable(tile)) 00569 return false; 00570 00571 return !isTileBlocked(tile, BWAPI::UnitTypes::None, ignoreReservations); 00572 } 00573 00574 std::pair<TilePosition, Base> BuildingPlacerClass::getRefineryLocation() const 00575 { 00576 for each(Base base in baseToBuildAtOrder()) 00577 { 00578 for each(Unit geyser in base->getGeysers()) 00579 { 00580 if(!isReserved(geyser->getTilePosition())) 00581 return std::make_pair(geyser->getTilePosition(), base); 00582 } 00583 } 00584 00585 return std::make_pair(BWAPI::TilePositions::None, Base()); 00586 } 00587 00588 bool baseCompare(const Base &i, const Base &j) 00589 { 00590 if(BWAPI::Broodwar->getFrameCount() < 12000) 00591 { 00592 if(i->isStartLocation()) 00593 { 00594 if(!j->isStartLocation()) 00595 return true; 00596 } 00597 else if(j->isStartLocation()) 00598 return false; 00599 } 00600 00601 return (i->getNumberOfTechBuildings() > j->getNumberOfTechBuildings()); 00602 } 00603 00604 bool baseComparePylon(const Base &i, const Base &j) 00605 { 00606 // Prioritise a base without a depot the lowest 00607 if(i->getResourceDepot()) 00608 { 00609 if(!j->getResourceDepot()) 00610 return true; 00611 } 00612 else if(!j->getResourceDepot()) 00613 return false; 00614 00615 // Next prioritise the base that doesn't have a pylon 00616 int iCount = 0; 00617 for each(Unit building in i->getBuildings()) 00618 { 00619 if(building->getType() == BWAPI::UnitTypes::Protoss_Pylon && building->getPlayer() == BWAPI::Broodwar->self()) 00620 ++iCount; 00621 } 00622 00623 int jCount = 0; 00624 for each(Unit building in j->getBuildings()) 00625 { 00626 if(building->getType() == BWAPI::UnitTypes::Protoss_Pylon && building->getPlayer() == BWAPI::Broodwar->self()) 00627 ++jCount; 00628 } 00629 00630 if(iCount == 0) 00631 { 00632 if(jCount != 0) 00633 return true; 00634 } 00635 else if(jCount == 0) 00636 return false; 00637 00638 // Finally prioritise using the default sort 00639 return baseCompare(i, j); 00640 } 00641 00642 bool baseCompareDefense(const Base &i, const Base &j, BWAPI::UnitType type) 00643 { 00644 int iCount = 0; 00645 for each(Unit building in i->getBuildings()) 00646 { 00647 if(building->getType() == type && building->getPlayer() == BWAPI::Broodwar->self()) 00648 ++iCount; 00649 } 00650 00651 int jCount = 0; 00652 for each(Unit building in j->getBuildings()) 00653 { 00654 if(building->getType() == type && building->getPlayer() == BWAPI::Broodwar->self()) 00655 ++jCount; 00656 } 00657 00658 return jCount > iCount; 00659 } 00660 00661 std::vector<Base> BuildingPlacerClass::baseToBuildAtOrder(BWAPI::UnitType type) const 00662 { 00663 std::vector<Base> basesOrder = baseToBuildAtOrder(); 00664 00665 if(type == BWAPI::UnitTypes::Protoss_Pylon) 00666 { 00667 std::sort(basesOrder.begin(), basesOrder.end(), baseComparePylon); 00668 } 00669 else if(type == BWAPI::UnitTypes::Protoss_Photon_Cannon || type == BWAPI::UnitTypes::Terran_Missile_Turret) 00670 { 00671 std::vector<Base> newBasesOrder; 00672 for each(Base base in basesOrder) 00673 { 00674 if(base->getMinerals().empty()) 00675 continue; 00676 00677 bool hasPylon = type.requiresPsi() ? false : true; 00678 00679 if(!hasPylon) 00680 { 00681 std::set<Unit> buildings = base->getBuildings(); 00682 for each(Unit building in buildings) 00683 { 00684 if(building->getType() == BWAPI::UnitTypes::Protoss_Pylon && building->getPlayer() == BWAPI::Broodwar->self() && building->isCompleted()) 00685 hasPylon = true; 00686 } 00687 } 00688 00689 if(hasPylon) 00690 newBasesOrder.push_back(base); 00691 } 00692 00693 std::sort(newBasesOrder.begin(), newBasesOrder.end(), boost::bind<bool>(&baseCompareDefense, _1, _2, type)); 00694 00695 return newBasesOrder; 00696 } 00697 00698 return basesOrder; 00699 } 00700 00701 std::vector<Base> BuildingPlacerClass::baseToBuildAtOrder() const 00702 { 00703 std::vector<Base> returnValue; 00704 00705 for each(Base base in BaseTracker::Instance().getPlayerBases()) 00706 { 00707 if(!base->isUnderAttack()) 00708 returnValue.push_back(base); 00709 } 00710 00711 std::sort(returnValue.begin(), returnValue.end(), baseCompare); 00712 00713 return returnValue; 00714 } 00715 bool BuildingPlacerClass::isAddonBuilder(int x, int y) const 00716 { 00717 std::map<TilePosition, BWAPI::UnitType>::const_iterator it = mPermanentReserved.find(TilePosition(x, y)); 00718 if(it != mPermanentReserved.end()) 00719 { 00720 if(UnitHelper::hasAddon(it->second)) 00721 return true; 00722 } 00723 00724 for each(Unit unit in UnitTracker::Instance().getUnitsOnTile(x, y)) 00725 { 00726 if(!unit->isLifted() && UnitHelper::hasAddon(unit->getType())) 00727 return true; 00728 } 00729 00730 return false; 00731 } 00732 00733 bool BuildingPlacerClass::isAddonBuildable(TilePosition position) const 00734 { 00735 for(int x = position.x() + 4; x < position.x() + 6; ++x) 00736 for(int y = position.y() + 1; y < position.y() + 3; ++y) 00737 if(!isTileBuildable(TilePosition(x, y), BWAPI::UnitTypes::Terran_Machine_Shop)) 00738 return false; 00739 00740 return true; 00741 } 00742 00743 std::pair<TilePosition, Base> BuildingPlacerClass::getExpandLocation(bool gas) const 00744 { 00745 std::set<Base> enemyBases = BaseTracker::Instance().getEnemyBases(); 00746 00747 Base basePos; 00748 int closestDistance = std::numeric_limits<int>::max(); 00749 int furthestDistance = std::numeric_limits<int>::min(); 00750 ExpandType type = ExpandType::expNone; 00751 00752 std::set<BorderPosition> myRegions = BorderTracker::Instance().getBorderPositions(PositionType::BotControlRegion); 00753 std::set<BorderPosition> enemyRegions = BorderTracker::Instance().getBorderPositions(PositionType::EnemyControlRegion); 00754 00755 for(std::set<BorderPosition>::const_iterator it = myRegions.begin(); it != myRegions.end(); ++it) 00756 { 00757 for each(Base base in it->mRegion->getBases()) 00758 { 00759 rememberBestExpandLocation(base, basePos, closestDistance, furthestDistance, type, gas, enemyBases); 00760 } 00761 } 00762 00763 if(type == ExpandType::expNone) 00764 { 00765 for each(Base base in BaseTracker::Instance().getAllBases()) 00766 { 00767 if(enemyRegions.count(BorderPosition(PositionType::EnemyControlRegion, base->getRegion())) != 0) 00768 continue; 00769 00770 rememberBestExpandLocation(base, basePos, closestDistance, furthestDistance, type, gas, enemyBases); 00771 } 00772 } 00773 00774 if(type == ExpandType::expNone) 00775 { 00776 for each(Base base in BaseTracker::Instance().getAllBases()) 00777 { 00778 rememberBestExpandLocation(base, basePos, closestDistance, furthestDistance, type, gas, enemyBases); 00779 } 00780 } 00781 00782 if(type != ExpandType::expNone) 00783 return std::make_pair(basePos->getCenterBuildLocation(), basePos); 00784 else 00785 return std::make_pair(BWAPI::TilePositions::None, Base()); 00786 } 00787 00788 std::set<TilePosition> BuildingPlacerClass::getSurroundingTiles(TilePosition position, BWAPI::UnitType type, bool ignoreReservations) const 00789 { 00790 std::set<TilePosition> tiles; 00791 int y1 = position.y() + type.tileHeight(); 00792 int x1 = position.x() - 1; 00793 int y2 = position.y() + type.tileHeight() - 1; 00794 int x2 = position.x() - 1; 00795 00796 while(true) 00797 { 00798 TilePosition t1(x1, y1); 00799 if(isTileWalkable(t1, ignoreReservations)) 00800 tiles.insert(t1); 00801 00802 TilePosition t2(x2, y2); 00803 if(isTileWalkable(t2, ignoreReservations)) 00804 tiles.insert(t2); 00805 00806 if(x1 < position.x() + type.tileWidth()) 00807 x1++; 00808 else 00809 y1--; 00810 00811 if(y1 == y2 && x1 == x2) 00812 break; 00813 00814 if(y2 > position.y() - 1) 00815 y2--; 00816 else 00817 x2++; 00818 } 00819 00820 return tiles; 00821 } 00822 00823 void BuildingPlacerClass::rememberBestExpandLocation(Base base, Base& bestBase, int& closestDistance, int& furthestDistance, ExpandType& type, bool gas, std::set<Base> enemyBases) const 00824 { 00825 if(base->getPlayer() == NULL || (!base->isActive() && base->getPlayer() == BWAPI::Broodwar->self())) 00826 { 00827 if(base->getCenterBuildLocation() == BWAPI::TilePositions::None) 00828 return; 00829 00830 if(gas && base->getGeysers().empty() && base->getRefineries().empty()) 00831 return; 00832 00833 if(base->isMinedOut()) 00834 return; 00835 00836 if(base->isMyBase() && base->isUnderAttack()) 00837 return; 00838 00839 ScoutType lastScoutType = ScoutManager::Instance().getLastScoutType(base); 00840 int lastScoutTime = ScoutManager::Instance().getLastScoutTime(base); 00841 if(BWAPI::Broodwar->getFrameCount() > 6200 && (lastScoutType == ScoutType::FailedWithGroundLow || lastScoutType == ScoutType::FailedWithGroundHigh || lastScoutType == ScoutType::FailedWithAir)) 00842 return; 00843 00844 //TODO: when we have transport code, remove this if we have a transport 00845 bool isConnected = false; 00846 for each(Unit unit in UnitTracker::Instance().selectAllUnits(BWAPI::Broodwar->self()->getRace().getWorker())) 00847 { 00848 if(unit->hasPath(Position(base->getCenterBuildLocation()))) 00849 { 00850 isConnected = true; 00851 break; 00852 } 00853 } 00854 00855 if(!isConnected) 00856 return; 00857 00858 if(isLocationBuildable(base->getCenterBuildLocation(), BWAPI::Broodwar->self()->getRace().getCenter())) 00859 { 00860 for each(Base myBase in BaseTracker::Instance().getPlayerBases()) 00861 { 00862 if(myBase->getCenterBuildLocation() == BWAPI::TilePositions::None) 00863 continue; 00864 00865 int tDistance = MapHelper::getGroundDistance(base->getCenterLocation(), myBase->getCenterLocation()); 00866 if(tDistance >= 1450 && type != ExpandType::expCloseToMe && !enemyBases.empty()) 00867 { 00868 for each(Base enemyBase in enemyBases) 00869 { 00870 int enemyDistance = MapHelper::getGroundDistance(base->getCenterLocation(), enemyBase->getCenterLocation()); 00871 if(enemyDistance > furthestDistance) 00872 { 00873 furthestDistance = enemyDistance; 00874 bestBase = base; 00875 type = ExpandType::expFurthestFromEnemy; 00876 } 00877 } 00878 } 00879 else if(tDistance < closestDistance) 00880 { 00881 closestDistance = tDistance; 00882 bestBase = base; 00883 type = ExpandType::expCloseToMe; 00884 } 00885 } 00886 } 00887 } 00888 }