use super::*;
#[derive(Clone, Debug)]
struct Employee {
id: usize,
shift: Option<i32>,
}
#[derive(Clone, Debug)]
struct ScheduleSolution {
employees: Vec<Employee>,
score: Option<SoftScore>,
}
impl PlanningSolution for ScheduleSolution {
type Score = SoftScore;
fn score(&self) -> Option<Self::Score> {
self.score
}
fn set_score(&mut self, score: Option<Self::Score>) {
self.score = score;
}
}
fn get_shift(s: &ScheduleSolution, idx: usize) -> Option<i32> {
s.employees.get(idx).and_then(|e| e.shift)
}
fn set_shift(s: &mut ScheduleSolution, idx: usize, v: Option<i32>) {
if let Some(e) = s.employees.get_mut(idx) {
e.shift = v;
}
}
fn create_director(employees: Vec<Employee>) -> ScoreDirector<ScheduleSolution, ()> {
let solution = ScheduleSolution {
employees,
score: None,
};
let extractor = Box::new(EntityCollectionExtractor::new(
"Employee",
"employees",
|s: &ScheduleSolution| &s.employees,
|s: &mut ScheduleSolution| &mut s.employees,
));
let entity_desc = EntityDescriptor::new("Employee", TypeId::of::<Employee>(), "employees")
.with_extractor(extractor);
let descriptor = SolutionDescriptor::new("ScheduleSolution", TypeId::of::<ScheduleSolution>())
.with_entity(entity_desc);
ScoreDirector::simple(solution, descriptor, |s, _| s.employees.len())
}
#[test]
fn test_pillar_change_all_entities() {
let mut director = create_director(vec![
Employee {
id: 0,
shift: Some(1),
},
Employee {
id: 1,
shift: Some(1),
},
Employee {
id: 2,
shift: Some(2),
},
]);
let m = PillarChangeMove::<ScheduleSolution, i32>::new(
vec![0, 1],
Some(5),
get_shift,
set_shift,
"shift",
0,
);
assert!(m.is_doable(&director));
assert_eq!(m.pillar_size(), 2);
{
let mut recording = RecordingDirector::new(&mut director);
m.do_move(&mut recording);
assert_eq!(get_shift(recording.working_solution(), 0), Some(5));
assert_eq!(get_shift(recording.working_solution(), 1), Some(5));
assert_eq!(get_shift(recording.working_solution(), 2), Some(2));
recording.undo_changes();
}
assert_eq!(get_shift(director.working_solution(), 0), Some(1));
assert_eq!(get_shift(director.working_solution(), 1), Some(1));
assert_eq!(get_shift(director.working_solution(), 2), Some(2));
let solution = director.working_solution();
assert_eq!(solution.employees[0].id, 0);
assert_eq!(solution.employees[1].id, 1);
assert_eq!(solution.employees[2].id, 2);
}
#[test]
fn test_pillar_change_same_value_not_doable() {
let director = create_director(vec![
Employee {
id: 0,
shift: Some(5),
},
Employee {
id: 1,
shift: Some(5),
},
]);
let m = PillarChangeMove::<ScheduleSolution, i32>::new(
vec![0, 1],
Some(5),
get_shift,
set_shift,
"shift",
0,
);
assert!(!m.is_doable(&director));
}
#[test]
fn test_pillar_change_empty_pillar_not_doable() {
let director = create_director(vec![Employee {
id: 0,
shift: Some(1),
}]);
let m = PillarChangeMove::<ScheduleSolution, i32>::new(
vec![],
Some(5),
get_shift,
set_shift,
"shift",
0,
);
assert!(!m.is_doable(&director));
}
#[test]
fn test_pillar_change_entity_indices() {
let m = PillarChangeMove::<ScheduleSolution, i32>::new(
vec![1, 3, 5],
Some(5),
get_shift,
set_shift,
"shift",
0,
);
assert_eq!(m.entity_indices(), &[1, 3, 5]);
}