OptimisationProblem/Assignment.cpp
2023-07-17 01:19:10 +03:00

220 lines
5.6 KiB
C++

#include "Assignment.h"
#include "structures/Center.h"
#include <iostream>
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";
}
}