solverforge-solver 0.8.5

Solver engine for SolverForge
Documentation
use super::*;
use solverforge_core::domain::{EntityCollectionExtractor, EntityDescriptor, SolutionDescriptor};
use solverforge_core::score::SoftScore;
use solverforge_scoring::ScoreDirector;
use std::any::TypeId;

#[derive(Clone, Debug)]
struct Task {
    id: usize,
}

#[derive(Clone, Debug)]
struct TaskSchedule {
    tasks: Vec<Task>,
    score: Option<SoftScore>,
}

impl PlanningSolution for TaskSchedule {
    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_tasks(s: &TaskSchedule) -> &Vec<Task> {
    &s.tasks
}

fn get_tasks_mut(s: &mut TaskSchedule) -> &mut Vec<Task> {
    &mut s.tasks
}

fn create_director(tasks: Vec<Task>) -> ScoreDirector<TaskSchedule, ()> {
    let solution = TaskSchedule { tasks, score: None };
    let extractor = Box::new(EntityCollectionExtractor::new(
        "Task",
        "tasks",
        get_tasks,
        get_tasks_mut,
    ));
    let entity_desc =
        EntityDescriptor::new("Task", TypeId::of::<Task>(), "tasks").with_extractor(extractor);
    let descriptor = SolutionDescriptor::new("TaskSchedule", TypeId::of::<TaskSchedule>())
        .with_entity(entity_desc);
    ScoreDirector::simple(solution, descriptor, |s, _| s.tasks.len())
}

#[derive(Debug)]
struct AddTask {
    id: usize,
}

impl ProblemChange<TaskSchedule> for AddTask {
    fn apply(&self, score_director: &mut dyn Director<TaskSchedule>) {
        score_director
            .working_solution_mut()
            .tasks
            .push(Task { id: self.id });
    }
}

#[test]
fn struct_problem_change() {
    let mut director = create_director(vec![Task { id: 0 }]);

    let change = AddTask { id: 1 };
    change.apply(&mut director);

    assert_eq!(director.working_solution().tasks.len(), 2);
    assert_eq!(director.working_solution().tasks[1].id, 1);
}

#[test]
fn closure_problem_change() {
    let mut director = create_director(vec![Task { id: 0 }]);

    let change = ClosureProblemChange::<TaskSchedule, _>::new("remove_all", |sd| {
        sd.working_solution_mut().tasks.clear();
    });

    change.apply(&mut director);

    assert!(director.working_solution().tasks.is_empty());
}