BWAPI
|
00001 #include "Requirement.h" 00002 00003 #include <algorithm> 00004 #include <boost/bind.hpp> 00005 00006 #include "Task.h" 00007 #include "ResourceTracker.h" 00008 #include "UnitTracker.h" 00009 #include "TaskManager.h" 00010 00011 const int Requirement::maxTime = std::numeric_limits<int>::max(); 00012 00013 Requirement::Requirement(RequirementType type, int amount) 00014 : mType(type) 00015 , mAmount(amount) 00016 , mPosition(BWAPI::Positions::None) 00017 , mUnit() 00018 , mUnitFilter() 00019 , mUnitType(BWAPI::UnitTypes::None) 00020 , mTechType(BWAPI::TechTypes::None) 00021 , mUpgradeType(BWAPI::UpgradeTypes::None) 00022 , mTask() 00023 , mPriority(0) 00024 , mDuration(0) 00025 , mDelay(0) 00026 { 00027 } 00028 00029 Requirement::Requirement(int priority, int duration, Unit unit, Position position) 00030 : mType(RequirementType::Unit) 00031 , mAmount(1) 00032 , mPosition(position) 00033 , mUnit(unit) 00034 , mUnitFilter() 00035 , mUnitType(BWAPI::UnitTypes::None) 00036 , mTechType(BWAPI::TechTypes::None) 00037 , mUpgradeType(BWAPI::UpgradeTypes::None) 00038 , mTask() 00039 , mPriority(priority) 00040 , mDuration(duration) 00041 , mDelay(0) 00042 { 00043 } 00044 00045 Requirement::Requirement(int priority, int duration, UnitFilter unitFilter, Position position) 00046 : mType(RequirementType::UnitFilter) 00047 , mAmount(1) 00048 , mPosition(position) 00049 , mUnit() 00050 , mUnitFilter(unitFilter) 00051 , mUnitType(BWAPI::UnitTypes::None) 00052 , mTechType(BWAPI::TechTypes::None) 00053 , mUpgradeType(BWAPI::UpgradeTypes::None) 00054 , mTask() 00055 , mPriority(priority) 00056 , mDuration(duration) 00057 , mDelay(0) 00058 { 00059 } 00060 00061 Requirement::Requirement(TaskPointer task) 00062 : mType(RequirementType::Task) 00063 , mAmount(0) 00064 , mPosition(BWAPI::Positions::None) 00065 , mUnit() 00066 , mUnitFilter() 00067 , mUnitType(BWAPI::UnitTypes::None) 00068 , mTechType(BWAPI::TechTypes::None) 00069 , mUpgradeType(BWAPI::UpgradeTypes::None) 00070 , mTask(task) 00071 , mPriority(0) 00072 , mDuration(0) 00073 , mDelay(0) 00074 { 00075 } 00076 00077 Requirement::Requirement(BWAPI::UnitType unit) 00078 : mType(RequirementType::RequiredForUnit) 00079 , mAmount(0) 00080 , mPosition(BWAPI::Positions::None) 00081 , mUnit() 00082 , mUnitFilter() 00083 , mUnitType(unit) 00084 , mTechType(BWAPI::TechTypes::None) 00085 , mUpgradeType(BWAPI::UpgradeTypes::None) 00086 , mTask() 00087 , mPriority(0) 00088 , mDuration(0) 00089 , mDelay(0) 00090 { 00091 } 00092 00093 Requirement::Requirement(BWAPI::TechType tech) 00094 : mType(RequirementType::RequiredForTech) 00095 , mAmount(0) 00096 , mPosition(BWAPI::Positions::None) 00097 , mUnit() 00098 , mUnitFilter() 00099 , mUnitType(BWAPI::UnitTypes::None) 00100 , mTechType(tech) 00101 , mUpgradeType(BWAPI::UpgradeTypes::None) 00102 , mTask() 00103 , mPriority(0) 00104 , mDuration(0) 00105 , mDelay(0) 00106 { 00107 } 00108 00109 Requirement::Requirement(BWAPI::UpgradeType upgrade, int level) 00110 : mType(RequirementType::RequiredForUpgrade) 00111 , mAmount(level) 00112 , mPosition(BWAPI::Positions::None) 00113 , mUnit() 00114 , mUnitFilter() 00115 , mUnitType(BWAPI::UnitTypes::None) 00116 , mTechType(BWAPI::TechTypes::None) 00117 , mUpgradeType(upgrade) 00118 , mTask() 00119 , mPriority(0) 00120 , mDuration(0) 00121 , mDelay(0) 00122 { 00123 } 00124 00125 bool Requirement::operator==(const Requirement& other) const 00126 { 00127 if(mType != other.mType) 00128 return false; 00129 else if(mAmount != other.mAmount) 00130 return false; 00131 else if(mUnitFilter != other.mUnitFilter) 00132 return false; 00133 else if(mUnit != other.mUnit) 00134 return false; 00135 else if(mPosition != other.mPosition) 00136 return false; 00137 else if(mPriority != other.mPriority) 00138 return false; 00139 else if(mDuration != other.mDuration) 00140 return false; 00141 else if(mDelay != other.mDelay) 00142 return false; 00143 else if(mTask != other.mTask) 00144 return false; 00145 else if(mUnitType != other.mUnitType) 00146 return false; 00147 else if(mTechType != other.mTechType) 00148 return false; 00149 else if(mUpgradeType != other.mUpgradeType) 00150 return false; 00151 else 00152 return true; 00153 } 00154 00155 bool Requirement::operator<(const Requirement& other) const 00156 { 00157 if(mType < other.mType) 00158 return true; 00159 else if(mType != other.mType) 00160 return false; 00161 00162 if(mAmount < other.mAmount) 00163 return true; 00164 else if(mAmount != other.mAmount) 00165 return false; 00166 00167 if(mUnitFilter < other.mUnitFilter) 00168 return true; 00169 else if(mUnitFilter != other.mUnitFilter) 00170 return false; 00171 00172 if(mUnit < other.mUnit) 00173 return true; 00174 else if(mUnit != other.mUnit) 00175 return false; 00176 00177 if(mPosition < other.mPosition) 00178 return true; 00179 else if(mPosition != other.mPosition) 00180 return false; 00181 00182 if(mPriority < other.mPriority) 00183 return true; 00184 else if(mPriority != other.mPriority) 00185 return false; 00186 00187 if(mDuration < other.mDuration) 00188 return true; 00189 else if(mDuration != other.mDuration) 00190 return false; 00191 00192 if(mDelay < other.mDelay) 00193 return true; 00194 else if(mDelay != other.mDelay) 00195 return false; 00196 00197 if(mTask < other.mTask) 00198 return true; 00199 else if(mTask != other.mTask) 00200 return false; 00201 00202 if(mUnitType < other.mUnitType) 00203 return true; 00204 else if(mUnitType != other.mUnitType) 00205 return false; 00206 00207 if(mTechType < other.mTechType) 00208 return true; 00209 else if(mTechType != other.mTechType) 00210 return false; 00211 00212 if(mUpgradeType < other.mUpgradeType) 00213 return true; 00214 else if(mUpgradeType != other.mUpgradeType) 00215 return false; 00216 00217 return false; 00218 } 00219 00220 int Requirement::earliestTime() 00221 { 00222 if(mType == RequirementType::Mineral) 00223 return ResourceTracker::Instance().earliestMineralAvailability(mAmount); 00224 else if(mType == RequirementType::Gas) 00225 return ResourceTracker::Instance().earliestGasAvailability(mAmount); 00226 else if(mType == RequirementType::Supply) 00227 return ResourceTracker::Instance().earliestSupplyAvailability(mAmount); 00228 else if(mType == RequirementType::Time) 00229 return mAmount; 00230 else if(mType == RequirementType::Task) 00231 return mTask->getEndTime(); 00232 else if(mType == RequirementType::RequiredForUnit) 00233 { 00234 int latestTime = 0; 00235 00236 for(std::map<BWAPI::UnitType, int>::const_iterator it = mUnitType.requiredUnits().begin(); it != mUnitType.requiredUnits().end(); ++it) 00237 latestTime = std::max(latestTime, earliestTimeForType(it->first)); 00238 00239 return latestTime; 00240 } 00241 else if(mType == RequirementType::RequiredForUpgrade) 00242 { 00243 int latestTime = earliestTimeForType(mUpgradeType.whatUpgrades()); 00244 00245 if(mAmount > 1) 00246 { 00247 if(mUpgradeType == BWAPI::UpgradeTypes::Protoss_Ground_Weapons || mUpgradeType == BWAPI::UpgradeTypes::Protoss_Ground_Armor) 00248 latestTime = std::max(latestTime, earliestTimeForType(BWAPI::UnitTypes::Protoss_Templar_Archives)); 00249 else if(mUpgradeType == BWAPI::UpgradeTypes::Protoss_Plasma_Shields) 00250 latestTime = std::max(latestTime, earliestTimeForType(BWAPI::UnitTypes::Protoss_Cybernetics_Core)); 00251 else if(mUpgradeType == BWAPI::UpgradeTypes::Protoss_Air_Armor || mUpgradeType == BWAPI::UpgradeTypes::Protoss_Air_Weapons) 00252 latestTime = std::max(latestTime, earliestTimeForType(BWAPI::UnitTypes::Protoss_Fleet_Beacon)); 00253 } 00254 00255 return latestTime; 00256 } 00257 else if(mType == RequirementType::RequiredForTech) 00258 return earliestTimeForType(mTechType.whatResearches()); 00259 00260 return Requirement::maxTime; 00261 } 00262 00263 std::map<int, int> Requirement::earliestUnitTime(int startTime, int endTime, std::set<Unit> ¤tUnits) 00264 { 00265 const bool &allowAnyBlockLength = mDuration == Requirement::maxTime; 00266 00267 if(mType == RequirementType::Unit) 00268 { 00269 if(currentUnits.count(mUnit) > 0) 00270 return std::map<int, int>(); 00271 00272 if(mPosition != BWAPI::Positions::None) 00273 mDelay = int((mUnit->getPosition().getApproxDistance(mPosition) * 1.6) / mUnit->getType().topSpeed()) + 15; 00274 00275 return TaskManager::Instance().earliestFreeTimes(mUnit, mPriority, startTime - mDelay, endTime, mDuration, allowAnyBlockLength); 00276 } 00277 00278 std::map<int, int> bestTimes; 00279 int bestStartTime = Requirement::maxTime; 00280 int bestDelay = Requirement::maxTime; 00281 00282 for each(Unit unit in UnitTracker::Instance().selectAllUnits()) 00283 { 00284 if(currentUnits.count(unit) > 0) 00285 continue; 00286 00287 if(!mUnitFilter.passesFilter(unit))//TODO: only checks if it currently passes the filter, but some it can tell when in the future it will pass, might be worth implementing 00288 continue; 00289 00290 int delay = 0; 00291 if(mPosition != BWAPI::Positions::None) 00292 { 00293 if(!unit->hasPath(mPosition)) 00294 continue; 00295 00296 delay = int((unit->getPosition().getApproxDistance(mPosition) * 1.6) / unit->getType().topSpeed()) + 15; 00297 } 00298 00299 // If the delay for this unit pushes it outside the endtime, continue 00300 if(mDuration != Requirement::maxTime && startTime + mDuration + delay > endTime) 00301 continue; 00302 00303 const std::map<int, int> ¤tTimes = TaskManager::Instance().earliestFreeTimes(unit, mPriority, startTime - delay, endTime, mDuration + delay, allowAnyBlockLength); 00304 if(!currentTimes.empty()) 00305 { 00306 std::map<int, int> currentTimesPlusDelay; 00307 for(std::map<int, int>::const_iterator it = currentTimes.begin(); it != currentTimes.end(); ++it) 00308 currentTimesPlusDelay[it->first + delay] = it->second; 00309 00310 // Find the earliest time in these blocks 00311 std::map<int, int>::const_iterator it = currentTimesPlusDelay.begin(); 00312 if(it != currentTimesPlusDelay.end()) 00313 { 00314 // Save it if its the best we have found, also prefer if the delay is shorter so it 00315 // doesn't choose a unit really far away even though it will make it in time 00316 if(it->first < bestStartTime || (it->first == bestStartTime && delay < bestDelay)) 00317 { 00318 mUnit = unit; 00319 mDelay = delay; 00320 00321 bestTimes = currentTimesPlusDelay; 00322 bestStartTime = it->first; 00323 bestDelay = delay; 00324 } 00325 } 00326 } 00327 } 00328 00329 return bestTimes; 00330 } 00331 00332 void Requirement::reserve(int frameTime) 00333 { 00334 switch(mType.underlying()) 00335 { 00336 case RequirementType::Mineral: 00337 ResourceTracker::Instance().reservePlannedMinerals(frameTime, mAmount); 00338 break; 00339 case RequirementType::Gas: 00340 ResourceTracker::Instance().reservePlannedGas(frameTime, mAmount); 00341 break; 00342 case RequirementType::Supply: 00343 ResourceTracker::Instance().reservePlannedSupply(frameTime, mAmount); 00344 break; 00345 case RequirementType::Unit: 00346 case RequirementType::UnitFilter: 00347 TaskManager::Instance().reserveUnit(mUnit, frameTime, mPriority, mDuration); 00348 break; 00349 } 00350 } 00351 00352 int Requirement::earliestTimeForType(BWAPI::UnitType unitType) 00353 { 00354 int thisTime = Requirement::maxTime; 00355 for each(Unit requiredUnit in UnitTracker::Instance().selectAllUnits(unitType)) 00356 { 00357 if(requiredUnit->isCompleted()) 00358 return BWAPI::Broodwar->getFrameCount(); 00359 else 00360 { 00361 int completeTime = requiredUnit->getCompletedTime(); 00362 if(completeTime < thisTime) 00363 thisTime = completeTime; 00364 } 00365 } 00366 00367 return thisTime; 00368 }