///|
fn full_horizon(days : Int) -> TimeRange {
TimeRange::new(0, days * 1440)
}
///|
fn day_shift(day : Int, prefix : String) -> Shift {
let start = day * 1440 + 8 * 60
Shift::new(
prefix + "-day-" + (day + 1).to_string(),
"Day " + (day + 1).to_string(),
start,
start + 8 * 60,
2,
)
.with_kind(Day)
.with_weekend(day % 7 == 5 || day % 7 == 6)
}
///|
fn evening_shift(day : Int, prefix : String) -> Shift {
let start = day * 1440 + 16 * 60
Shift::new(
prefix + "-evening-" + (day + 1).to_string(),
"Evening " + (day + 1).to_string(),
start,
start + 6 * 60,
1,
)
.with_kind(Evening)
.with_weekend(day % 7 == 5 || day % 7 == 6)
}
///|
fn night_shift(day : Int, prefix : String) -> Shift {
let start = day * 1440 + 22 * 60
Shift::new(
prefix + "-night-" + (day + 1).to_string(),
"Night " + (day + 1).to_string(),
start,
start + 8 * 60,
1,
)
.with_kind(Night)
.with_weekend(day % 7 == 5 || day % 7 == 6)
}
///|
fn standard_worker(
id : String,
name : String,
days : Int,
target : Int,
) -> Worker {
Worker::new(id, name)
.add_availability(full_horizon(days))
.with_limits(0, target, target + 960)
.with_rest_rules(5, 600)
}
///|
pub fn clinic_scenario() -> PlanningProblem {
let days = 7
let nurse = Skill::new("nurse", "Registered nurse")
let triage = Skill::new("triage", "Triage")
let lead = Skill::new("lead", "Shift leadership")
let workers : Array[Worker] = [
standard_worker("ada", "Ada", days + 1, 2400)
.add_skill(WorkerSkill::new("nurse", Expert))
.add_skill(WorkerSkill::new("triage", Advanced))
.add_skill(WorkerSkill::new("lead", Advanced)),
standard_worker("grace", "Grace", days + 1, 2400)
.add_skill(WorkerSkill::new("nurse", Advanced))
.add_skill(WorkerSkill::new("triage", Expert)),
standard_worker("linus", "Linus", days + 1, 2160)
.add_skill(WorkerSkill::new("nurse", Qualified))
.add_skill(WorkerSkill::new("lead", Qualified)),
standard_worker("margaret", "Margaret", days + 1, 2160)
.add_skill(WorkerSkill::new("nurse", Expert))
.add_skill(WorkerSkill::new("triage", Qualified)),
standard_worker("alan", "Alan", days + 1, 1920).add_skill(
WorkerSkill::new("nurse", Qualified),
),
standard_worker("barbara", "Barbara", days + 1, 1920)
.add_skill(WorkerSkill::new("nurse", Advanced))
.add_skill(WorkerSkill::new("lead", Expert)),
standard_worker("edsger", "Edsger", days + 1, 1920)
.add_skill(WorkerSkill::new("nurse", Qualified))
.add_skill(WorkerSkill::new("triage", Advanced)),
]
let mut problem = PlanningProblem::new("Community clinic weekly roster")
.add_skill(nurse)
.add_skill(triage)
.add_skill(lead)
for worker in workers {
problem = problem.add_worker(worker)
}
for day = 0; day < days; day = day + 1 {
let daytime = day_shift(day, "clinic")
.add_requirement(SkillRequirement::new("nurse", Qualified, 2))
.add_requirement(SkillRequirement::new("triage", Qualified, 1))
let evening = evening_shift(day, "clinic").add_requirement(
SkillRequirement::new("nurse", Qualified, 1),
)
let overnight = night_shift(day, "clinic").add_requirement(
SkillRequirement::new("nurse", Qualified, 1),
)
problem = problem.add_shift(daytime).add_shift(evening).add_shift(overnight)
}
problem
}
///|
pub fn volunteer_scenario() -> PlanningProblem {
let days = 3
let registration = Skill::new("registration", "Registration desk")
let first_aid = Skill::new("first-aid", "First aid")
let logistics = Skill::new("logistics", "Logistics")
let workers : Array[Worker] = [
standard_worker("v1", "Xiaoming", days, 720).add_skill(
WorkerSkill::new("registration", Advanced),
),
standard_worker("v2", "Xiaohong", days, 720).add_skill(
WorkerSkill::new("first-aid", Qualified),
),
standard_worker("v3", "Xiaolan", days, 720).add_skill(
WorkerSkill::new("logistics", Expert),
),
standard_worker("v4", "Xiaoyu", days, 720)
.add_skill(WorkerSkill::new("registration", Qualified))
.add_skill(WorkerSkill::new("first-aid", Qualified)),
standard_worker("v5", "Xiaozhou", days, 720).add_skill(
WorkerSkill::new("logistics", Advanced),
),
standard_worker("v6", "Xiaoli", days, 720).add_skill(
WorkerSkill::new("registration", Expert),
),
]
let mut problem = PlanningProblem::new("Three-day community event")
.add_skill(registration)
.add_skill(first_aid)
.add_skill(logistics)
for worker in workers {
problem = problem.add_worker(worker)
}
for day = 0; day < days; day = day + 1 {
let morning_start = day * 1440 + 8 * 60
let afternoon_start = day * 1440 + 13 * 60
let morning = Shift::new(
"event-morning-" + day.to_string(),
"Event morning " + (day + 1).to_string(),
morning_start,
morning_start + 4 * 60,
2,
)
.with_kind(Morning)
.add_requirement(SkillRequirement::new("registration", Qualified, 1))
let afternoon = Shift::new(
"event-afternoon-" + day.to_string(),
"Event afternoon " + (day + 1).to_string(),
afternoon_start,
afternoon_start + 5 * 60,
2,
)
.with_kind(Day)
.add_requirement(SkillRequirement::new("first-aid", Qualified, 1))
.add_requirement(SkillRequirement::new("logistics", Qualified, 1))
problem = problem.add_shift(morning).add_shift(afternoon)
}
problem
}
///|
pub fn operations_scenario() -> PlanningProblem {
let days = 5
let linux = Skill::new("linux", "Linux operations")
let database = Skill::new("database", "Database operations")
let incident = Skill::new("incident", "Incident command")
let workers : Array[Worker] = [
standard_worker("op-ada", "Ada", days + 1, 1800)
.add_skill(WorkerSkill::new("linux", Expert))
.add_skill(WorkerSkill::new("incident", Advanced)),
standard_worker("op-grace", "Grace", days + 1, 1800)
.add_skill(WorkerSkill::new("database", Expert))
.add_skill(WorkerSkill::new("incident", Qualified)),
standard_worker("op-linus", "Linus", days + 1, 1800).add_skill(
WorkerSkill::new("linux", Expert),
),
standard_worker("op-ken", "Ken", days + 1, 1800)
.add_skill(WorkerSkill::new("linux", Advanced))
.add_skill(WorkerSkill::new("database", Advanced)),
standard_worker("op-margaret", "Margaret", days + 1, 1800)
.add_skill(WorkerSkill::new("database", Qualified))
.add_skill(WorkerSkill::new("incident", Expert)),
]
let mut problem = PlanningProblem::new("Operations on-call rotation")
.add_skill(linux)
.add_skill(database)
.add_skill(incident)
for worker in workers {
problem = problem.add_worker(worker)
}
for day = 0; day < days; day = day + 1 {
let start = day * 1440 + 18 * 60
let primary = Shift::new(
"primary-" + day.to_string(),
"Primary on-call " + (day + 1).to_string(),
start,
start + 12 * 60,
1,
)
.with_kind(OnCall)
.add_requirement(SkillRequirement::new("linux", Advanced, 1))
let backup = Shift::new(
"backup-" + day.to_string(),
"Backup on-call " + (day + 1).to_string(),
start,
start + 12 * 60,
1,
)
.with_kind(OnCall)
.add_requirement(SkillRequirement::new("database", Qualified, 1))
problem = problem.add_shift(primary).add_shift(backup)
}
problem
}
///|
pub fn scenario_by_name(name : String) -> PlanningProblem? {
match name.trim().to_lower() {
"clinic" => Some(clinic_scenario())
"volunteer" => Some(volunteer_scenario())
"operations" => Some(operations_scenario())
_ => None
}
}
///|
pub fn scenario_names() -> Array[String] {
["clinic", "volunteer", "operations"]
}