BWAPI
Skynet/Skynet/UnitGroup.cpp
Go to the documentation of this file.
00001 #include "UnitGroup.h"
00002 
00003 #include <limits>
00004 
00005 #include "TerrainAnaysis.h"
00006 
00007 UnitGroup::UnitGroup()
00008 {
00009 }
00010 
00011 int UnitGroup::countCompletedBy(int time) const
00012 {
00013         const int &timeNow = BWAPI::Broodwar->getFrameCount();
00014 
00015         int total = 0;
00016         for each(Unit unit in mUnits)
00017         {
00018                 if(unit->isCompleted() || unit->getCompletedTime() <= time)
00019                         ++total;
00020         }
00021         return total;
00022 }
00023 
00024 std::set<Unit>::iterator UnitGroup::begin()
00025 {
00026         return mUnits.begin();
00027 }
00028 
00029 std::set<Unit>::const_iterator UnitGroup::begin() const
00030 {
00031         return mUnits.begin();
00032 }
00033 
00034 std::set<Unit>::iterator UnitGroup::end()
00035 {
00036         return mUnits.end();
00037 }
00038 
00039 std::set<Unit>::const_iterator UnitGroup::end() const
00040 {
00041         return mUnits.end();
00042 }
00043 
00044 void UnitGroup::clear()
00045 {
00046         mUnits.clear();
00047 }
00048 
00049 std::set<Unit>::size_type UnitGroup::count(Unit const &unit) const
00050 {
00051         return mUnits.count(unit);
00052 }
00053 
00054 bool UnitGroup::empty() const
00055 {
00056         return mUnits.empty();
00057 }
00058 
00059 void UnitGroup::erase(std::set<Unit>::iterator position)
00060 {
00061         mUnits.erase(position);
00062 }
00063 
00064 std::set<Unit>::size_type UnitGroup::erase(Unit const &unit)
00065 {
00066         return mUnits.erase(unit);
00067 }
00068 
00069 void UnitGroup::erase(std::set<Unit>::iterator first, std::set<Unit>::iterator last)
00070 {
00071         mUnits.erase(first, last);
00072 }
00073 
00074 std::set<Unit>::iterator UnitGroup::find(Unit const &unit)
00075 {
00076         return mUnits.find(unit);
00077 }
00078 
00079 std::set<Unit>::const_iterator UnitGroup::find(Unit const &unit) const
00080 {
00081         return mUnits.find(unit);
00082 }
00083 
00084 std::pair<std::set<Unit>::iterator, bool> UnitGroup::insert(Unit const &unit)
00085 {
00086         return mUnits.insert(unit);
00087 }
00088 
00089 std::set<Unit>::iterator UnitGroup::insert(std::set<Unit>::iterator position, Unit const &unit)
00090 {
00091         return mUnits.insert(position, unit);
00092 }
00093 
00094 void UnitGroup::insert(std::set<Unit>::const_iterator first, std::set<Unit>::const_iterator last)
00095 {
00096         mUnits.insert(first, last);
00097 }
00098 
00099 std::set<Unit>::size_type UnitGroup::size() const
00100 {
00101         return mUnits.size();
00102 }
00103 
00104 UnitGroup::operator std::set<Unit>() const
00105 {
00106         return mUnits;
00107 }
00108 
00109 int UnitGroup::ratingDifference(const UnitGroup &other) const
00110 {
00111         // not sure about this, along the right lines with using time to kill as that in turns considers weapon damage, terrain, health etc but bad atm
00112         if(mUnits.empty() && other.mUnits.empty())
00113                 return 0;
00114         else if(mUnits.empty())
00115                 return -100;
00116         else if(other.mUnits.empty())
00117                 return 100;
00118 
00119         int OtherKillThisTime = 0;
00120         int ThisKillOtherTime = 0;
00121         for each(Unit thisUnit in mUnits)
00122         {
00123                 for each(Unit otherUnit in other.mUnits)
00124                 {
00125                         if(otherUnit->canAttack(thisUnit) && !thisUnit->isUnderDarkSwarm() && otherUnit->getDistance(thisUnit) < 600)
00126                         {
00127                                 int killTime = otherUnit->getTimeToKill(thisUnit);
00128                                 if(otherUnit->getType().groundWeapon().outerSplashRadius() > 15)
00129                                         killTime /= 2;
00130 
00131                                 OtherKillThisTime += std::min(killTime, 500);
00132                         }
00133                         else
00134                                 OtherKillThisTime += 500;
00135 
00136                         if(thisUnit->canAttack(otherUnit) && !otherUnit->isUnderDarkSwarm() && thisUnit->getDistance(otherUnit) < 600)
00137                                 ThisKillOtherTime += std::min(thisUnit->getTimeToKill(otherUnit), 500);
00138                         else
00139                                 ThisKillOtherTime += 500;
00140                 }
00141         }
00142 
00143         OtherKillThisTime /= other.mUnits.size();
00144         ThisKillOtherTime /= mUnits.size();
00145 
00146         int ratingTotal = std::max(OtherKillThisTime, ThisKillOtherTime) - std::min(OtherKillThisTime, ThisKillOtherTime);
00147         if(OtherKillThisTime < ThisKillOtherTime)
00148                 ratingTotal = 0 - ratingTotal;
00149 
00150         return ratingTotal;
00151 }
00152 
00153 Position UnitGroup::getCenter() const
00154 {
00155         if(empty())
00156                 return BWAPI::Positions::None;
00157 
00158         if(size() == 1)
00159                 return (*begin())->getPosition();
00160 
00161         Vector position;
00162 
00163         for each(Unit unit in mUnits)
00164         {
00165                 position += Vector(unit->getPosition());
00166         }
00167 
00168         return position / float(size());
00169 }
00170 
00171 bool UnitGroup::operator==(const UnitGroup &other) const
00172 {
00173         return mUnits == other.mUnits;
00174 }
00175 
00176 bool UnitGroup::operator!=(const UnitGroup &other) const
00177 {
00178         return mUnits != other.mUnits;
00179 }
00180 
00181 UnitGroup &UnitGroup::operator+=(const UnitGroup &other)
00182 {
00183         for each(Unit unit in other)
00184         {
00185                 insert(unit);
00186         }
00187 
00188         return *this;
00189 }
00190 
00191 UnitGroup UnitGroup::getBestFittingToCircle(int circleSize, int inFramesTime) const
00192 {
00193         UnitGroup circleUnits(*this);
00194         bool removed = false;
00195         do
00196         {
00197                 removed = false;
00198                 Position center = circleUnits.getCenter();
00199 
00200                 Unit furthestUnit;
00201                 int furthestDistance = 0;
00202 
00203                 for each(Unit unit in circleUnits)
00204                 {
00205                         int distanceToCenter;
00206                         if(inFramesTime == 0)
00207                                 distanceToCenter = unit->getDistance(center);
00208                         else
00209                                 distanceToCenter = unit->getDistance(center, inFramesTime);
00210 
00211                         if(distanceToCenter > circleSize && distanceToCenter > furthestDistance)
00212                         {
00213                                 furthestUnit = unit;
00214                                 furthestDistance = distanceToCenter;
00215                         }
00216                 }
00217 
00218                 if(furthestUnit)
00219                 {
00220                         circleUnits.erase(furthestUnit);
00221                         removed = true;
00222                 }
00223         }
00224         while(removed);
00225 
00226         return circleUnits;
00227 }
00228 
00229 Unit UnitGroup::getClosestUnit(Unit unit) const
00230 {
00231         Unit closestUnit;
00232         int closestDistance = std::numeric_limits<int>::max();
00233 
00234         for each(Unit groupUnit in mUnits)
00235         {
00236                 int thisDistance = unit->getDistance(groupUnit);
00237                 if(thisDistance < closestDistance)
00238                 {
00239                         closestDistance = thisDistance;
00240                         closestUnit = groupUnit;
00241                 }
00242         }
00243 
00244         return closestUnit;
00245 }
00246 
00247 Unit UnitGroup::getClosestUnit(Position position) const
00248 {
00249         Unit closestUnit;
00250         int closestDistance = std::numeric_limits<int>::max();
00251 
00252         for each(Unit groupUnit in mUnits)
00253         {
00254                 int thisDistance = groupUnit->getDistance(position);
00255                 if(thisDistance < closestDistance)
00256                 {
00257                         closestDistance = thisDistance;
00258                         closestUnit = groupUnit;
00259                 }
00260         }
00261 
00262         return closestUnit;
00263 }
00264 
00265 bool UnitGroup::isAnyInRange(const UnitGroup &otherGroup) const
00266 {
00267         for each(Unit groupUnit in mUnits)
00268         {
00269                 for each(Unit otherGroupUnit in otherGroup)
00270                 {
00271                         if(groupUnit->isInRange(otherGroupUnit))
00272                                 return true;
00273                 }
00274         }
00275 
00276         return false;
00277 }
00278 
00279 int UnitGroup::minDistanceBetween(const UnitGroup &otherGroup) const
00280 {
00281         int minDistance = std::numeric_limits<int>::max();
00282         for each(Unit groupUnit in mUnits)
00283         {
00284                 for each(Unit otherGroupUnit in otherGroup)
00285                 {
00286                         int thisDistance = otherGroupUnit->getDistance(groupUnit);
00287                         if(thisDistance < minDistance)
00288                                 minDistance = thisDistance;
00289                 }
00290         }
00291         return minDistance;
00292 }
00293 
00294 UnitGroup UnitGroup::operator+(const UnitGroup &other) const
00295 {
00296         UnitGroup ret(*this);
00297         ret += other;
00298 
00299         return ret;
00300 }
00301 
00302 int UnitGroup::getBuildScore() const
00303 {
00304         int rating = 0;
00305         for each(Unit unit in mUnits)
00306         {
00307                 rating += unit->getType().buildScore();
00308         }
00309 
00310         return rating;
00311 }
00312 
00313 bool UnitGroup::isWorthEngaging(const UnitGroup &other) const
00314 {
00315         // Don't chase after a faster group
00316         double thisAverageSpeed = getAverageSpeed();
00317         double otherAverageSpeed = other.getAverageSpeed();
00318         if(otherAverageSpeed >= thisAverageSpeed)
00319                 return false;
00320 
00321         size_t thisFlyingCount = getFlyingCount();
00322         double thisFlyingAverage = 0.0;
00323         if(!empty())
00324                 thisFlyingAverage = thisFlyingCount / size();
00325 
00326         size_t otherFlyingCount = other.getFlyingCount();
00327         double otherFlyingAverage = 0.0;
00328         if(!other.empty())
00329                 otherFlyingAverage = otherFlyingCount / other.size();
00330 
00331         if((thisFlyingAverage + 0.3) < otherFlyingAverage)
00332                 return false;
00333 
00334         Region thisRegion = getMajorityRegion();
00335         Region otherRegion = other.getMajorityRegion();
00336         if(thisRegion && thisRegion != otherRegion)
00337         {
00338                 // dont try attacking a group that isnt connected without a majority of flying units
00339                 if(!otherRegion || thisRegion->isConnected(otherRegion))
00340                 {
00341                         if(thisFlyingAverage > 0.5)
00342                                 return false;
00343                 }
00344         }
00345 
00346         size_t otherCloakedCount = other.getCloakedCount();
00347         if(!hasDetection() && otherCloakedCount > 0)
00348         {
00349                 size_t thisCloakedCount = getCloakedCount();
00350                 if(!other.hasDetection() && thisCloakedCount > 0)
00351                 {
00352                         if(thisCloakedCount < otherCloakedCount)
00353                                 return false;
00354                 }
00355                 else if(otherCloakedCount > 0)
00356                         return false;
00357         }
00358 
00359         if(otherFlyingAverage > 0.2 && !canAttackAir())
00360                 return false;
00361 
00362         return true;
00363 }
00364 
00365 int UnitGroup::getAverageTerrainHeight() const
00366 {
00367         int height = 0;
00368         for each(Unit unit in mUnits)
00369         {
00370                 height += BWAPI::Broodwar->getGroundHeight(unit->getTilePosition());
00371         }
00372 
00373         return height / mUnits.size();
00374 }
00375 
00376 double UnitGroup::getAverageSpeed() const
00377 {
00378         double averageSpeed = 0;
00379         for each(Unit unit in mUnits)
00380         {
00381                 averageSpeed += unit->getType().topSpeed();
00382         }
00383 
00384         return averageSpeed / double(mUnits.size());
00385 }
00386 
00387 Region UnitGroup::getMajorityRegion() const
00388 {
00389         int currentCount = 1;
00390         Region currentCandidate;
00391 
00392         for each(Unit unit in mUnits)
00393         {
00394                 const Region &thisRegion = TerrainAnaysis::Instance().getRegion(unit->getPosition());
00395                 if(thisRegion == currentCandidate)
00396                         ++currentCount;
00397                 else
00398                         --currentCount;
00399 
00400                 if(currentCount == 0)
00401                 {
00402                         currentCandidate = thisRegion;
00403                         currentCount = 1;
00404                 }
00405         }
00406 
00407         return currentCandidate;
00408 }
00409 
00410 bool UnitGroup::hasDetection() const
00411 {
00412         for each(Unit unit in mUnits)
00413         {
00414                 if(unit->getType().isDetector())
00415                         return true;
00416         }
00417 
00418         return false;
00419 }
00420 
00421 std::set<Unit>::size_type UnitGroup::getCloakedCount() const
00422 {
00423         std::set<Unit>::size_type cloakedCount = 0;
00424         for each(Unit unit in mUnits)
00425         {
00426                 if(unit->getType().hasPermanentCloak() || unit->isCloaked())
00427                         ++cloakedCount;
00428         }
00429 
00430         return cloakedCount;
00431 }
00432 
00433 std::set<Unit>::size_type UnitGroup::getFlyingCount() const
00434 {
00435         std::set<Unit>::size_type flyingCount = 0;
00436         for each(Unit unit in mUnits)
00437         {
00438                 if(unit->getType().isFlyer() || unit->isLifted())
00439                         ++flyingCount;
00440         }
00441 
00442         return flyingCount;
00443 }
00444 
00445 bool UnitGroup::canAttackAir() const
00446 {
00447         for each(Unit unit in mUnits)
00448         {
00449                 if(unit->canAttackAir())
00450                         return true;
00451         }
00452 
00453         return false;
00454 }
00455 
00456 bool UnitGroup::canAttackGround() const
00457 {
00458         for each(Unit unit in mUnits)
00459         {
00460                 if(unit->canAttackGround())
00461                         return true;
00462         }
00463 
00464         return false;
00465 }
00466 
00467 bool UnitGroup::canMajorityAttack(const UnitGroup &other) const
00468 {
00469         if(empty() || other.empty())
00470                 return false;
00471 
00472         double thisGroupAttackCount = 0.0;
00473         for each(Unit thisUnit in mUnits)
00474         {
00475                 for each(Unit otherUnit in other)
00476                 {
00477                         if(thisUnit->canAttack(otherUnit))
00478                                 ++thisGroupAttackCount;
00479                 }
00480         }
00481 
00482         thisGroupAttackCount /= other.size();
00483         thisGroupAttackCount /= size();
00484 
00485         return thisGroupAttackCount > 0.5;
00486 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines