BWAPI
Skynet/Skynet/TaskManager.cpp
Go to the documentation of this file.
00001 #include "TaskManager.h"
00002 
00003 #include <boost/bind.hpp>
00004 
00005 #include "UnitGroup.h"
00006 #include "ResourceTracker.h"
00007 #include "IdleTask.h"
00008 #include "Logger.h"
00009 
00010 #include "MorphTask.h"
00011 #include "ConstructionTask.h"
00012 #include "TrainTask.h"
00013 #include "UpgradeTask.h"
00014 #include "TechTask.h"
00015 #include "UnitTracker.h"
00016 #include "BuildOrderManager.h"
00017 #include "MacroManager.h"
00018 #include "GameProgressDetection.h"
00019 
00020 TaskManagerClass::TaskManagerClass()
00021 {
00022 }
00023 
00024 void TaskManagerClass::update()
00025 {
00026         for each(const TaskPointer &task in mTasks)
00027         {
00028                 if(task->preUpdate())
00029                 {
00030                         for each(Unit unit in task->getFinishedUnits())
00031                                 removeTask(unit);
00032                 }
00033         }
00034 
00035         // Clear previous reservations
00036         ResourceTracker::Instance().reset();
00037         mReservedUnits.clear();
00038 
00039         for each(TaskType type in getPriorityList())
00040         {
00041                 std::map<TaskType, std::list<TaskPointer>>::iterator l = mTypeTasks.find(type);
00042 
00043                 if(l != mTypeTasks.end())
00044                 {
00045                         for(std::list<TaskPointer>::iterator i = l->second.begin(); i != l->second.end(); ++i)
00046                         {
00047                                 if((*i)->hasEnded())
00048                                         continue;
00049 
00050                                 (*i)->updateRequirements(boost::bind<bool>(&TaskManagerClass::updateRequirement, this, *i, _1));
00051                         }
00052                 }
00053         }
00054 
00055         for(std::map<TaskType, std::list<TaskPointer>>::iterator itFirst = mTypeTasks.begin(); itFirst != mTypeTasks.end(); ++itFirst)
00056         {
00057                 for(std::list<TaskPointer>::iterator it = itFirst->second.begin(); it != itFirst->second.end();)
00058                 {
00059                         if((*it)->update())
00060                         {
00061                                 //TODO: shouldn't have to but don't delete if it has control of units or just assert
00062                                 /*
00063                                 int count = 0;
00064                                 for(std::map<BWAPI::UnitType, std::map<Unit, TaskPointer>>::iterator it2 = mUnitTasks.begin(); it2 != mUnitTasks.end(); ++it2)
00065                                 {
00066                                         for(std::map<Unit, TaskPointer>::iterator it3 = it2->second.begin(); it3 != it2->second.end(); ++it3)
00067                                         {
00068                                                 if(it3->second == *it)
00069                                                 {
00070                                                         ++count;
00071                                                 }
00072                                         }
00073                                 }
00074 
00075                                 if(count > 0)
00076                                 {
00077                                         LOGMESSAGE(String_Builder() << "TaskManager : Task " << (*it)->getTaskName() << " " << (*it)->getOutputName() << " deleted while still controlling " << count << " units");
00078                                 }
00079                                 */
00080 
00081                                 mTasks.erase(*it);
00082                                 itFirst->second.erase(it++);
00083                         }
00084                         else
00085                                 ++it;
00086                 }
00087         }
00088 }
00089 
00090 std::list<TaskType> TaskManagerClass::getPriorityList()
00091 {
00092         std::list<TaskType> returnList;
00093 
00094         //Thing to consider for sorts these:
00095         // If I am vulnerable to counter attack / have no map control, place defense higher
00096         // If I am not behind on army size but its not safe to attack, tech
00097         // If I am not behind on army size but its safe to attack, produce
00098         // If I'm behind on army supply, produce
00099 
00100         StateType currentState = GameProgressDetection::Instance().getState();
00101         
00102         returnList.push_back(TaskType::Highest);
00103         returnList.push_back(TaskType::Supply);
00104         returnList.push_back(TaskType::Worker);
00105         returnList.push_back(TaskType::RefineryManager);
00106         returnList.push_back(TaskType::MacroUrgent);
00107         returnList.push_back(TaskType::Scout);
00108         returnList.push_back(TaskType::Expansion);
00109 
00110         if(currentState == StateType::TechHigh && BuildOrderManager::Instance().getOrder(Order::MacroCanTech))
00111         {
00112                 returnList.push_back(TaskType::BuildOrder);
00113                 returnList.push_back(TaskType::MacroTech);
00114                 returnList.push_back(TaskType::Defense);
00115                 returnList.push_back(TaskType::Army);
00116         }
00117         else
00118         {
00119                 returnList.push_back(TaskType::Army);
00120                 returnList.push_back(TaskType::Defense);
00121                 returnList.push_back(TaskType::BuildOrder);
00122         }
00123         
00124         returnList.push_back(TaskType::Medium);
00125 
00126         if(currentState == StateType::TechNormal && BuildOrderManager::Instance().getOrder(Order::MacroCanTech))
00127                 returnList.push_back(TaskType::MacroTech);
00128 
00129         returnList.push_back(TaskType::MacroExtraProduction);
00130 
00131         if(currentState == StateType::BuildArmy && BuildOrderManager::Instance().getOrder(Order::MacroCanTech))
00132                 returnList.push_back(TaskType::MacroTech);
00133 
00134         returnList.push_back(TaskType::Lowest);
00135 
00136         return returnList;
00137 }
00138 
00139 void TaskManagerClass::onDiscover(Unit unit)
00140 {
00141         if(unit->getPlayer() != BWAPI::Broodwar->self())
00142                 return;
00143 
00144         giveTask(unit);
00145 }
00146 
00147 void TaskManagerClass::onMorphRenegade(Unit unit, Player previousPlayer, BWAPI::UnitType previousType)
00148 {
00149         if(previousPlayer != NULL)
00150         {
00151                 if(previousPlayer == BWAPI::Broodwar->self())
00152                 {
00153                         if(previousType != BWAPI::UnitTypes::None)
00154                         {
00155                                 mUnitTasks[previousType][unit]->returnUnit(unit);
00156                                 if(!mUnitTasks[previousType][unit]->hasEnded())
00157                                         mUnitTasks[previousType][unit]->updateRequirements();
00158                                 mUnitTasks[previousType].erase(unit);
00159                         }
00160                         else
00161                         {
00162                                 mUnitTasks[unit->getType()][unit]->returnUnit(unit);
00163                                 if(!mUnitTasks[unit->getType()][unit]->hasEnded())
00164                                         mUnitTasks[unit->getType()][unit]->updateRequirements();
00165                                 mUnitTasks[unit->getType()].erase(unit);
00166                         }
00167                 }
00168                 else if(unit->getPlayer() == BWAPI::Broodwar->self())
00169                 {
00170                         giveTask(unit);
00171                 }
00172         }
00173         else if(previousType != BWAPI::UnitTypes::None && unit->getPlayer() == BWAPI::Broodwar->self())
00174         {
00175                 if(mUnitTasks[previousType][unit]->morph(unit, previousType))
00176                 {
00177                         mUnitTasks[previousType][unit]->returnUnit(unit);
00178                         if(!mUnitTasks[previousType][unit]->hasEnded())
00179                                 mUnitTasks[previousType][unit]->updateRequirements();
00180                         mUnitTasks[previousType].erase(unit);
00181 
00182                         if(unit->accessibility() == AccessType::Full)
00183                                 giveTask(unit);
00184                 }
00185                 else
00186                 {
00187                         TaskPointer task = mUnitTasks[previousType][unit];
00188                         mUnitTasks[previousType].erase(unit);
00189                         mUnitTasks[unit->getType()][unit] = task;
00190                 }
00191         }
00192 }
00193 
00194 void TaskManagerClass::onDestroy(Unit unit)
00195 {
00196         removeTask(unit);
00197 }
00198 
00199 void TaskManagerClass::removeTask(Unit unit)
00200 {
00201         if(mUnitTasks[unit->getType()].find(unit) == mUnitTasks[unit->getType()].end())
00202                 return;
00203 
00204         LOGMESSAGE(String_Builder() << "TaskManager : Removed Unit " << unit->getType().getName() << " from " << mUnitTasks[unit->getType()][unit]->getTaskName() << " " << mUnitTasks[unit->getType()][unit]->getOutputName());
00205 
00206         mUnitTasks[unit->getType()][unit]->returnUnit(unit);
00207         if(!mUnitTasks[unit->getType()][unit]->hasEnded())
00208                 mUnitTasks[unit->getType()][unit]->updateRequirements();
00209         mUnitTasks[unit->getType()].erase(unit);
00210 
00211         if(unit->accessibility() == AccessType::Full)
00212                 giveTask(unit);
00213 }
00214 
00215 void TaskManagerClass::giveTask(Unit unit)
00216 {
00217         TaskPointer bestTask;
00218         int priority = 0;
00219 
00220         for each(TaskPointer task in mTasks)
00221         {
00222                 if(task->waitingForUnit(unit))
00223                 {
00224                         int thisPriority = task->getPriority(unit);
00225                         if(thisPriority > priority)
00226                         {
00227                                 priority = thisPriority;
00228                                 bestTask = task;
00229                         }
00230                 }
00231         }
00232 
00233         if(bestTask)
00234         {
00235                 LOGMESSAGE(String_Builder() << "TaskManager : Given new unit " << unit->getType().getName() << " to " << bestTask->getTaskName() << " " << bestTask->getOutputName());
00236                 mUnitTasks[unit->getType()][unit] = bestTask;
00237                 bestTask->giveUnit(unit);
00238         }
00239         else
00240         {
00241                 LOGMESSAGE(String_Builder() << "TaskManager : Created idle task for " << unit->getType().getName());
00242                 TaskPointer idleTask(new IdleTask(TaskType::Lowest));
00243                 mUnitTasks[unit->getType()][unit] = idleTask;
00244                 mTasks.insert(idleTask);
00245                 mTypeTasks[idleTask->getType()].push_back(idleTask);
00246                 idleTask->giveUnit(unit);
00247         }
00248 }
00249 
00250 std::map<int, int> TaskManagerClass::earliestFreeTimes(Unit unit, int priority, int lastBlockEnd, int maxTime, int blockTimeNeeded, bool allowAnyBlockLength)
00251 {
00252         std::map<int, int> suitableBlocks;
00253 
00254         // test this priority against the current task to test if we can override it
00255         TaskPointer currentTask = mUnitTasks[unit->getType()][unit];
00256         if(!currentTask)
00257         {
00258                 LOGMESSAGE(String_Builder() << "TaskManager : Tried to access task for unit " << unit->getType().getName() << " that we don't control");
00259                 return suitableBlocks;
00260         }
00261 
00262         if(priority <= currentTask->getPriority(unit))
00263         {
00264                 // If we can't get the end time of the task
00265                 int endTime = currentTask->getEndTime(unit);
00266                 int frametime = BWAPI::Broodwar->getFrameCount();
00267                 assert(endTime >= frametime);
00268 
00269                 // Get the end time of the current task
00270                 lastBlockEnd = std::max(endTime == frametime ? endTime+1 : endTime, lastBlockEnd);
00271         }
00272 
00273         // If it has no end return nothing
00274         if(lastBlockEnd == Requirement::maxTime)
00275                 return suitableBlocks;
00276 
00277         int currentFreeBlockStart = lastBlockEnd;
00278         int currentFreeBlockLength = 0;
00279 
00280         for(std::map<int, std::pair<int, int>>::iterator i = mReservedUnits[unit].begin(); i != mReservedUnits[unit].end(); ++i)
00281         {
00282                 // This is before our current time slot so we don't need to worry about it
00283                 if(i->first + i->second.second < lastBlockEnd)
00284                         continue;
00285 
00286                 // this is after our current time so we should return
00287                 if(i->first > maxTime)
00288                         return suitableBlocks;
00289 
00290                 // We can move this block if we are higher priority
00291                 bool canMoveThisBlock = priority > i->second.first;
00292 
00293                 // How long the current block of time we have to fit in is
00294                 currentFreeBlockLength += i->first - lastBlockEnd;
00295                 
00296                 // How long will this task last
00297                 lastBlockEnd = i->second.second;
00298 
00299                 // If it will last forever....
00300                 if(lastBlockEnd == Requirement::maxTime)
00301                 {
00302                         // If we can move this block, steal its time
00303                         if(canMoveThisBlock)
00304                                 suitableBlocks[currentFreeBlockStart] = Requirement::maxTime;
00305                         
00306                         //return as there is no more time to work with
00307                         return suitableBlocks;
00308                 }
00309                 
00310                 // add the start time so we get the real end
00311                 lastBlockEnd += i->first;
00312 
00313                 // if we cannot move this block
00314                 if(!canMoveThisBlock)
00315                 {
00316                         // If its long enough, or we are looking we are looking for an endless slot
00317                         if(currentFreeBlockLength >= blockTimeNeeded || allowAnyBlockLength)
00318                         {
00319                                 suitableBlocks[currentFreeBlockStart] = currentFreeBlockLength;
00320                         }
00321 
00322                         // reset the block length
00323                         currentFreeBlockLength = 0;
00324                         currentFreeBlockStart = lastBlockEnd;
00325                 }
00326         }
00327 
00328         // If we made it this far we have the rest of the time for this task
00329         suitableBlocks[lastBlockEnd] = Requirement::maxTime;
00330 
00331         return suitableBlocks;
00332 }
00333 
00334 void TaskManagerClass::reserveUnit(Unit unit, int time, int priority, int duration)
00335 {
00336         // TODO: change from a map to a sorted vector or sumin, should be faster at updating times
00337         mReservedUnits[unit][time] = std::pair<int, int>(priority, duration);
00338 
00339         int lastTaskEndTime = 0;
00340         for(std::map<int, std::pair<int, int>>::iterator i = mReservedUnits[unit].begin(); i != mReservedUnits[unit].end();)
00341         {
00342                 if(lastTaskEndTime > i->first)
00343                 {
00344                         std::pair<int, int> tempTask = i->second;
00345                         mReservedUnits[unit].erase(i++);
00346                         mReservedUnits[unit][lastTaskEndTime] = tempTask;
00347 
00348                         lastTaskEndTime += tempTask.second;
00349                 }
00350                 else
00351                 {
00352                         lastTaskEndTime = i->first + i->second.second;
00353                         ++i;
00354                 }
00355         }
00356 }
00357 
00358 void TaskManagerClass::addTask(TaskPointer task)
00359 {
00360         LOGMESSAGE(String_Builder() << "TaskManager : New task added : " << task->getTaskName() << " " << task->getOutputName());
00361 
00362         mTypeTasks[task->getType()].push_back(task);
00363         mTasks.insert(task);
00364 
00365         if(!task->hasEnded())
00366                 task->updateRequirements();
00367 }
00368 
00369 bool TaskManagerClass::updateRequirement(TaskPointer task, RequirementGroup requirement)
00370 {
00371         if(!requirement.empty())
00372         {
00373                 std::pair<int, int> earliestTime = requirement.earliestTime();
00374                 task->setRequiredSatisfyTime(requirement, earliestTime.first, earliestTime.second);
00375 
00376                 if(earliestTime.first - earliestTime.second <= BWAPI::Broodwar->getFrameCount())
00377                 {
00378                         for each(Unit unit in requirement.getUnits())
00379                         {
00380                                 TaskPointer oldTask = mUnitTasks[unit->getType()][unit];
00381                                 oldTask->returnUnit(unit);
00382                                 if(!oldTask->hasEnded())
00383                                         oldTask->updateRequirements();
00384 
00385                                 mUnitTasks[unit->getType()][unit] = task;
00386 
00387                                 LOGMESSAGE(String_Builder() << "TaskManager : Taken " << unit->getType().getName() << " from " << oldTask->getTaskName() << " " << oldTask->getOutputName());
00388                                 LOGMESSAGE(String_Builder() << "TaskManager : Given " << unit->getType().getName() << " to " << task->getTaskName() << " " << task->getOutputName());
00389                                 task->giveUnit(unit);
00390                         }
00391 
00392                         return true;
00393                 }
00394                 else
00395                 {
00396                         requirement.reserve(earliestTime.first);
00397                         //TODO see what can be done to make this task happen sooner
00398                 }
00399         }
00400 
00401         return false;
00402 }
00403 
00404 TaskPointer TaskManagerClass::build(BWAPI::UnitType type, TaskType taskType, BuildingLocation position)
00405 {
00406         if(type == BWAPI::UnitTypes::None || type == BWAPI::UnitTypes::Unknown)
00407                 return TaskPointer();
00408 
00409         if(type.getRace() == BWAPI::Races::Zerg && type.isBuilding() == type.whatBuilds().first.isBuilding())
00410         {
00411                 TaskPointer returnTask = TaskPointer(new MorphTask(taskType, type));
00412                 addTask(returnTask);
00413                 MacroManager::Instance().onBuildTask(returnTask, type);
00414                 return returnTask;
00415         }
00416         else
00417         {
00418                 if(type.isBuilding())
00419                 {
00420                         if(type.isAddon())
00421                         {
00422                                 return TaskPointer(); // NYI
00423                         }
00424                         else
00425                         {
00426                                 TaskPointer returnTask = TaskPointer(new ConstructionTask(taskType, position, type));
00427                                 addTask(returnTask);
00428                                 MacroManager::Instance().onBuildTask(returnTask, type);
00429                                 return returnTask;
00430                         }
00431                 }
00432                 else
00433                 {
00434                         TaskPointer returnTask = TaskPointer(new TrainTask(taskType, type));
00435                         addTask(returnTask);
00436                         MacroManager::Instance().onBuildTask(returnTask, type);
00437                         return returnTask;
00438                 }
00439         }
00440 
00441         return TaskPointer();
00442 }
00443 
00444 TaskPointer TaskManagerClass::upgrade(BWAPI::UpgradeType type, int level, TaskType taskType)
00445 {
00446         TaskPointer returnTask = TaskPointer(new UpgradeTask(taskType, type, level));
00447         addTask(returnTask);
00448         MacroManager::Instance().onUpgradeTask(returnTask, type, level);
00449         return returnTask;
00450 }
00451 
00452 TaskPointer TaskManagerClass::research(BWAPI::TechType type, TaskType taskType)
00453 {
00454         TaskPointer returnTask = TaskPointer(new TechTask(taskType, type));
00455         addTask(returnTask);
00456         MacroManager::Instance().onTechTask(returnTask, type);
00457         return returnTask;
00458 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines