#include "Assignment.h" #include "structures/Center.h" #include float Assignment::cost() { if (this->getCompetenceTotal() == 0) return 1; return 1.f / this->getCompetenceTotal(); } int Assignment::getPreviousId() { return this->getPreviousId(this->missions.size()); } int Assignment::getPreviousId(int index) { int id = 0; if (index == 0) // if no missions have been assigned, the center will be the first location id = this->employee->center->id; else // else use the latest mission id = this->missions[index-1]->id; return id; } Mission* Assignment::getLastMission(int day) { Mission* last = nullptr; for (Mission* mission : this->missions) { if (mission->day == day && (last == nullptr || last->end <= mission->start)) last = mission; } return last; } MissionList* Assignment::getMissions(int day) { MissionList* list = new MissionList {}; for (Mission* mission : this->missions) { if (mission->day == day) list->push_back(mission); } return list; } // TODO: Make this maintain a sorted list, done void Assignment::addMission(Mission* mission) { // Find index of where to insert int index = 0; for (index; index < this->missions.size(); index++) { Mission* m = this->missions[index]; if (mission->day > m->day) continue; else if (mission->day < m->day) break; if (m->day == mission->day) { if (m->start > mission->end) { // m starts after mission, insert mission before m break; } else if(mission->start > m->end) { // mission starts after m ends, insert after m index++; break; } else { throw std::runtime_error("No free slots for mission"); } } } this->missions.insert(this->missions.begin() + index, mission); } Mission* Assignment::removeMission(int i) { Mission* mission = this->missions[i]; this->missions.erase(this->missions.begin() + i); return mission; } // TODO: Improve these functions to account for the time void Assignment::replaceMission(int i, MissionList* missions) { Mission* oldMission = this->removeMission(i); // this->missions[i]; std::cout << "Removing: "; oldMission->print(); /*std::cout << this->getTotalWorkTime() << "/" << Employee::MaxWorkTimeWeek << " " << this->getWorkTime(oldMission->day) << "/" << Employee::MaxWorkTime << "\n"; for (Mission* m : *missions) { if (m->day == oldMission->day) m->print(); }*/ //this->missions.erase(this->missions.begin() + i); Mission* mission = NULL; int index = this->getSuitableMission(oldMission->day, missions, &mission); // Even if a mission isn't available, remove the mission and put it back into the available mission pool missions->push_back(oldMission); // Sometimes there just aren't any available missions for the employee's profession if (index == -1) return; this->missions.push_back(mission); missions->erase(missions->begin() + index); } int Assignment::getSuitableMission(int day, MissionList* missions, Mission** mission) { MissionList* list = this->getSuitableMissions(day, missions); if (list->size() == 0) return -1; int index = rand() % list->size(); *mission = (*list)[index]; return index; } MissionList* Assignment::getSuitableMissions(int day, MissionList* missions) { MissionList* list = new MissionList {}; for (int index = 0; index < missions->size(); index++) { Mission* mission = (*missions)[index]; if (mission->day != day) continue; // TODO: Make sure mission fits in empty slot // Take previous mission and check end time vs selected mission // Take next mission in list and check vs selected /*Mission* lastMission = this->getLastMission(day); if (lastMission != nullptr && lastMission->end > mission->start) continue;*/ float dailyWorkTime = this->getWorkTime(day); float workTime = this->getTotalWorkTime(mission); if (mission->profession == employee->profession && Employee::MaxWorkTime >= dailyWorkTime && Employee::MaxWorkTimeWeek >= workTime) list->push_back(mission); } return list; } int Assignment::getCompetenceTotal() { int total = 0; for (Mission* mission : this->missions) { if (this->employee->competence == mission->competence) total += 1; } return total; } float Assignment::getTravelDistance() { int size = this->missions.size(); if (size == 0) return 0.f; float distance = 0.f; // this->distances->getDistance(this->employee->center->id, this->missions[0]->id); for (int i = 0; i < size; i++) { int prev = this->getPreviousId(i); Mission* m = this->missions[i]; distance += this->distances->getDistance(prev, m->id); } return distance; } float Assignment::getWorkTime(int day) { float workTime = 0.f; for (Mission* mission : this->missions) { if (mission->day == day) workTime += mission->getDuration(); } return workTime; } float Assignment::getTotalWorkTime() { //float total = this->workTime; float total = 0.f; for (Mission* mission : this->missions) total += mission->getDuration(); total += this->getTravelDistance() / 55 * 60; return total; } float Assignment::getTotalWorkTime(Mission* mission) { return this->getTotalWorkTime() + mission->getDuration() + this->distances->getTravelTime(this->getPreviousId(), mission->id); } void Assignment::print() { std::cout << "Employee " << this->employee->id << " (" << employee->profession << ", " << employee->competence << ") work schedule " << this->getTotalWorkTime() / 60 << " work hours\n"; for (int day = 1; day < 6; day ++) { std::cout << "Day " << day << ": "; for (Mission* mission : this->missions) { if (mission->day != day) continue; std::cout << "[" << mission->id << "] (" << mission->start << ", " << mission->end << ") " << mission->competence << ", "; } std::cout << "\n"; } }