/// <summary> /// Attempt to assign a task to the required number of crew-members, using a score to select the most fitted crew-members. /// </summary> /// <param name="time">The current simulation time</param> /// <param name="phase">The current phase of the scenario</param> /// <param name="task">The task assigned</param> /// <param name="tasksInterruptedCallback">A delegate method to call when having to interrupt tasks occupying the resource</param> /// <returns>A Simulation time at which the task assignment will not be valid anymore, or a negative value (e.g. SimulationTime.MinValue) if the task assignment was not successful</returns> public abstract SimulationTime TaskAssignment(SimulationTime time, Phase phase, SimulationTask task, Simulator.TasksInterruptedCallback tasksInterruptedCallback);
public override SimulationTime TaskAssignment(SimulationTime time, Phase phase, SimulationTask task, Simulator.TasksInterruptedCallback tasksInterruptedCallback) { //TODO: Implement multitasking Debug.Assert(task.IsAllowedTime(time), "Task assignment must be within allowed daily hours!"); if (task.NumberOfCrewmenNeeded == 0) { base.TriggerTaskAssignment(time, phase, null, task); return(SimulationTime.MaxValue); } var priority = task.Priority; var scores = new BinaryHeap <ScoreEntry>(); foreach (var qualification in task.simulationCurrentQualifications) { var crewman = qualification.Key; var qualificationLevel = qualification.Value; var currentPriority = crewman.TasksAssigned.Count > 0 ? crewman.TasksAssigned[0].Priority : 0; //No multitasking implemented: right now, each crewman has only 1 task at a time Debug.Assert(currentPriority <= 0 || crewman.TasksAssigned[0].simulationCrewmenAssigned.Any(cm => cm.Id == crewman.Id), "If a crewman is assigned to a task, the symetric link should also be true, i.e. the task should be assigned to the same crewman!"); if ((currentPriority == 0) || (priority / 100 > currentPriority / 100) || crewman.TasksAssigned.Contains(task)) { crewman.RefreshStatus(time); var scoreEntry = new ScoreEntry((qualificationLevel * (int)AssignmentCoefficiant.Qualification) + (crewman.CumulatedWorkTime.TotalHours * (int)AssignmentCoefficiant.CumulatedWorkHours), crewman); if (task.NumberOfCrewmenNeeded > scores.Count) { scores.Add(scoreEntry); } else if (scores.Peek().score < scoreEntry.score) { scores.Remove(); //Remove the current minimal score scores.Add(scoreEntry); } } } if (scores.Count < task.NumberOfCrewmenNeeded) { scores.Clear(); return(SimulationTime.MinValue); //The assignment was not successful } for (var i = scores.Count - 1; i >= 0; i--) { var scoreEntry = scores[i]; var crewman = scoreEntry.crewman; if (crewman.TasksAssigned.Count > 0) { var currentTasks = crewman.TasksAssigned.ToList(); tasksInterruptedCallback(currentTasks, tryAssignmentAgainNow: true); //Do not clear the crew-members assigned before calling the interruption crewman.DismissAllTasks(time, phase); //Currently not compatible with multitasking Debug.Assert(!currentTasks.Any(t => t.simulationCrewmenAssigned.Count > 0), "Nobody should remain assigned to a task that has been interrupted!"); } crewman.AssignTask(time, phase, task); task.simulationCrewmenAssigned.Add(crewman); base.TriggerTaskAssignment(time, phase, crewman, task); } scores.Clear(); return(time + assignmentExpiry); }