BWAPI
Skynet/Skynet/BuildingPlacer.cpp
Go to the documentation of this file.
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 &centerType = 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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines