use super::*;
use crate::heuristic::r#move::ChangeMove;
use crate::heuristic::selector::EntityReference;
use solverforge_core::domain::{
EntityCollectionExtractor, EntityDescriptor, PlanningSolution, SolutionDescriptor,
};
use solverforge_core::score::SoftScore;
use solverforge_scoring::ScoreDirector;
use std::any::TypeId;
#[derive(Clone, Debug)]
struct Queen {
row: Option<i64>,
}
#[derive(Clone, Debug)]
struct NQueensSolution {
queens: Vec<Queen>,
score: Option<SoftScore>,
}
impl PlanningSolution for NQueensSolution {
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_queens(s: &NQueensSolution) -> &Vec<Queen> {
&s.queens
}
fn get_queens_mut(s: &mut NQueensSolution) -> &mut Vec<Queen> {
&mut s.queens
}
fn get_queen_row(s: &NQueensSolution, idx: usize) -> Option<i64> {
s.queens.get(idx).and_then(|q| q.row)
}
fn set_queen_row(s: &mut NQueensSolution, idx: usize, v: Option<i64>) {
if let Some(queen) = s.queens.get_mut(idx) {
queen.row = v;
}
}
fn create_test_director() -> ScoreDirector<NQueensSolution, ()> {
let solution = NQueensSolution {
queens: vec![Queen { row: None }],
score: None,
};
let extractor = Box::new(EntityCollectionExtractor::new(
"Queen",
"queens",
get_queens,
get_queens_mut,
));
let entity_desc =
EntityDescriptor::new("Queen", TypeId::of::<Queen>(), "queens").with_extractor(extractor);
let descriptor = SolutionDescriptor::new("NQueensSolution", TypeId::of::<NQueensSolution>())
.with_entity(entity_desc);
ScoreDirector::simple(solution, descriptor, |s, _| s.queens.len())
}
type TestMove = ChangeMove<NQueensSolution, i64>;
fn create_placement() -> Placement<NQueensSolution, TestMove> {
let entity_ref = EntityReference::new(0, 0);
let moves: Vec<TestMove> = vec![
ChangeMove::new(0, Some(1i64), get_queen_row, set_queen_row, "row", 0),
ChangeMove::new(0, Some(5i64), get_queen_row, set_queen_row, "row", 0),
ChangeMove::new(0, Some(3i64), get_queen_row, set_queen_row, "row", 0),
];
Placement::new(entity_ref, moves)
}
#[test]
fn test_first_fit_forager() {
let mut director = create_test_director();
let mut placement = create_placement();
let forager = FirstFitForager::<NQueensSolution, TestMove>::new();
let selected_idx = forager.pick_move_index(&placement, &mut director);
assert_eq!(selected_idx, Some(0));
if let Some(idx) = selected_idx {
let m = placement.moves.swap_remove(idx);
m.do_move(&mut director);
}
}
#[test]
fn test_best_fit_forager() {
let mut director = create_test_director();
let mut placement = create_placement();
let forager = BestFitForager::<NQueensSolution, TestMove>::new();
let selected_idx = forager.pick_move_index(&placement, &mut director);
assert!(selected_idx.is_some());
if let Some(idx) = selected_idx {
let m = placement.moves.swap_remove(idx);
m.do_move(&mut director);
let score = director.calculate_score();
assert_eq!(score, SoftScore::of(0));
}
}
#[test]
fn test_empty_placement() {
let mut director = create_test_director();
let placement: Placement<NQueensSolution, TestMove> =
Placement::new(EntityReference::new(0, 0), vec![]);
let forager = FirstFitForager::<NQueensSolution, TestMove>::new();
let selected_idx = forager.pick_move_index(&placement, &mut director);
assert!(selected_idx.is_none());
}
fn value_strength(m: &TestMove) -> i64 {
m.to_value().copied().unwrap_or(0)
}
#[test]
fn test_weakest_fit_forager() {
let mut director = create_test_director();
let mut placement = create_placement();
let forager = WeakestFitForager::<NQueensSolution, TestMove>::new(value_strength);
let selected_idx = forager.pick_move_index(&placement, &mut director);
assert_eq!(selected_idx, Some(0));
if let Some(idx) = selected_idx {
let m = placement.moves.swap_remove(idx);
m.do_move(&mut director);
let score = director.calculate_score();
assert_eq!(score, SoftScore::of(0));
}
}
#[test]
fn test_strongest_fit_forager() {
let mut director = create_test_director();
let mut placement = create_placement();
let forager = StrongestFitForager::<NQueensSolution, TestMove>::new(value_strength);
let selected_idx = forager.pick_move_index(&placement, &mut director);
assert_eq!(selected_idx, Some(1));
if let Some(idx) = selected_idx {
let m = placement.moves.swap_remove(idx);
m.do_move(&mut director);
let score = director.calculate_score();
assert_eq!(score, SoftScore::of(0));
}
}