BWAPI
BasicAIModule/source/BFSBuildingPlacer.cpp
Go to the documentation of this file.
00001 #include <BWSAL/BFSBuildingPlacer.h>
00002 #include <BWSAL/ReservedMap.h>
00003 #include <BWSAL/Heap.h>
00004 #include <algorithm>  // max/min
00005 
00006 using std::max;
00007 using std::min;
00008 
00009 namespace BWSAL
00010 {
00011   BFSBuildingPlacer::BFSBuildingPlacer()
00012   {
00013     m_reducedWalkability.resize( BWAPI::Broodwar->mapWidth(), BWAPI::Broodwar->mapHeight() );
00014     m_reducedWalkability.setTo( true );
00015     for ( int x = 0; x < BWAPI::Broodwar->mapWidth() * 4; x++ )
00016     {
00017       for ( int y = 0; y < BWAPI::Broodwar->mapHeight() * 4; y++ )
00018       {
00019         m_reducedWalkability[x/4][y/4] &= BWAPI::Broodwar->isWalkable( x, y );
00020       }
00021     }
00022   }
00023   BWAPI::TilePosition BFSBuildingPlacer::findBuildLocation( ReservedMap *reserveMap, BWAPI::UnitType unitType, BWAPI::TilePosition seedLocation, BWAPI::Unit* builder )
00024   {
00025     return getBuildLocationNear( reserveMap, seedLocation, unitType, builder, 1 );
00026   }
00027 
00028   BWAPI::TilePosition BFSBuildingPlacer::getBuildLocationNear( ReservedMap *reserveMap, BWAPI::TilePosition position, BWAPI::UnitType type, BWAPI::Unit* builder, int buildDist ) const
00029   {
00030     // returns a valid build location near the specified tile position.
00031     if ( type.isAddon() )
00032     {
00033       type = type.whatBuilds().first;
00034     }
00035     Heap< BWAPI::TilePosition, int > searchHeap( true );
00036     searchHeap.push( std::make_pair( position, 0 ) );
00037     std::set< BWAPI::TilePosition > closed;
00038 
00039     // Do a breadth first search to find a nearby valid build location with space
00040     while ( searchHeap.empty() == false )
00041     {
00042       BWAPI::TilePosition t = searchHeap.top().first;
00043       int s = searchHeap.top().second;
00044       searchHeap.pop();
00045       if ( canBuildHereWithSpace( reserveMap, t, type, builder, buildDist ) )
00046       {
00047         // We can build here with space so return this tile position
00048         return t;
00049       }
00050       int tx = t.x();
00051       int ty = t.y();
00052       int minx = max( tx - 1, 0 );
00053       int maxx = min( tx + 1, BWAPI::Broodwar->mapWidth() - 1 );
00054       int miny = max( ty - 1, 0 );
00055       int maxy = min( ty + 1, BWAPI::Broodwar->mapHeight() - 1 );
00056 
00057       for ( int x = minx; x <= maxx; x++ )
00058       {
00059         for ( int y = miny; y <= maxy; y++ )
00060         {
00061           if ( m_reducedWalkability[x][y] )
00062           {
00063             BWAPI::TilePosition t2( x, y );
00064             if ( closed.find( t2 ) == closed.end() )
00065             {
00066               int ds = 10;
00067               if ( x != tx && y != ty )
00068               {
00069                 ds = 14; // diagonal distance, approximation of 10*sqrt( 2 )
00070               }
00071               closed.insert( t2);
00072               searchHeap.push( std::make_pair( t2, s + ds ) );
00073             }
00074           }
00075         }
00076       }
00077     }
00078     // We didn't find a build position, try looking for one with less space
00079     if ( buildDist > 0 )
00080     {
00081       return getBuildLocationNear( reserveMap, position, type, builder, buildDist - 1 );
00082     }
00083     return BWAPI::TilePositions::None;
00084   }
00085 
00086   bool BFSBuildingPlacer::canBuildHereWithSpace( ReservedMap *reserveMap, BWAPI::TilePosition position, BWAPI::UnitType type, BWAPI::Unit* builder, int buildDist ) const
00087   {
00088     if ( type.isAddon() )
00089     {
00090       type = type.whatBuilds().first;
00091     }
00092     // returns true if we can build this type of unit here with the specified amount of space.
00093     // space value is stored in this->buildDistance.
00094 
00095     // if we can't build here, we of course can't build here with space
00096     if ( !reserveMap->canBuildHere( builder, position, type ) )
00097     {
00098       return false;
00099     }
00100     if ( type.isRefinery() )
00101     {
00102       return true;
00103     }
00104 
00105     int width = type.tileWidth();
00106     int height = type.tileHeight();
00107 
00108     // make sure we leave space for add - ons. These types of units can have addons:
00109     if ( type == BWAPI::UnitTypes::Terran_Command_Center ||
00110          type == BWAPI::UnitTypes::Terran_Factory || 
00111          type == BWAPI::UnitTypes::Terran_Starport ||
00112          type == BWAPI::UnitTypes::Terran_Science_Facility )
00113     {
00114       width += 2;
00115     }
00116     int startx = position.x() - buildDist;
00117     if ( startx < 0 )
00118     {
00119       return false;
00120     }
00121     int starty = position.y() - buildDist;
00122     if ( starty < 0 )
00123     {
00124       return false;
00125     }
00126     int endx = position.x() + width + buildDist;
00127     if ( endx > BWAPI::Broodwar->mapWidth() )
00128     {
00129       return false;
00130     }
00131     int endy = position.y() + height + buildDist;
00132     if ( endy > BWAPI::Broodwar->mapHeight() )
00133     {
00134       return false;
00135     }
00136 
00137     for ( int x = startx; x < endx; x++ )
00138     {
00139       for ( int y = starty; y < endy; y++ )
00140       {
00141         if ( !isBuildable( builder, x, y ) || reserveMap->isReserved( x, y ) )
00142         {
00143           return false;
00144         }
00145       }
00146     }
00147 
00148     if ( position.x() > 3 )
00149     {
00150       int startx2 = max( startx - 2, 0 );
00151       for ( int x = startx2; x < startx; x++ )
00152       {
00153         for ( int y = starty; y < endy; y++ )
00154         {
00155           for each ( BWAPI::Unit* u in BWAPI::Broodwar->getUnitsOnTile( x, y ) )
00156           {
00157             if ( !u->isLifted() && u != builder )
00158             {
00159               BWAPI::UnitType type = u->getType();
00160               if ( type == BWAPI::UnitTypes::Terran_Command_Center ||
00161                    type == BWAPI::UnitTypes::Terran_Factory || 
00162                    type == BWAPI::UnitTypes::Terran_Starport ||
00163                    type == BWAPI::UnitTypes::Terran_Science_Facility )
00164               {
00165                 return false;
00166               }
00167             }
00168           }
00169         }
00170       }
00171     }
00172     return true;
00173   }
00174   bool BFSBuildingPlacer::isBuildable( BWAPI::Unit* builder, int x, int y ) const
00175   {
00176     // returns true if this tile is currently buildable, takes into account units on tile
00177     if ( !BWAPI::Broodwar->isBuildable( x, y ) )
00178     {
00179       return false;
00180     }
00181     for each ( BWAPI::Unit* u in BWAPI::Broodwar->getUnitsOnTile( x, y ) )
00182     {
00183       if ( u->getType().isBuilding() && !u->isLifted() && !u->getType().isFlyer() && u != builder )
00184       {
00185         return false;
00186       }
00187     }
00188     return true;
00189   }
00190 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines