BWAPI
Skynet/Skynet/Requirement.cpp
Go to the documentation of this file.
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> &currentUnits)
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> &currentTimes = 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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines