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