BWAPI
|
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 }