use std::fmt::Debug;
use solverforge_core::domain::PlanningSolution;
use solverforge_core::score::Score;
use super::Acceptor;
pub struct GreatDelugeAcceptor<S: PlanningSolution> {
rain_speed: f64,
water_level: Option<S::Score>,
initial_abs_score: Option<S::Score>,
}
impl<S: PlanningSolution> Debug for GreatDelugeAcceptor<S> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("GreatDelugeAcceptor")
.field("rain_speed", &self.rain_speed)
.finish()
}
}
impl<S: PlanningSolution> Clone for GreatDelugeAcceptor<S> {
fn clone(&self) -> Self {
Self {
rain_speed: self.rain_speed,
water_level: self.water_level,
initial_abs_score: self.initial_abs_score,
}
}
}
impl<S: PlanningSolution> GreatDelugeAcceptor<S> {
pub fn new(rain_speed: f64) -> Self {
Self {
rain_speed,
water_level: None,
initial_abs_score: None,
}
}
}
impl<S: PlanningSolution> Default for GreatDelugeAcceptor<S> {
fn default() -> Self {
Self::new(0.001)
}
}
impl<S: PlanningSolution> Acceptor<S> for GreatDelugeAcceptor<S> {
fn is_accepted(&mut self, last_step_score: &S::Score, move_score: &S::Score) -> bool {
if move_score > last_step_score {
return true;
}
match &self.water_level {
Some(water_level) => move_score >= water_level,
None => true, }
}
fn phase_started(&mut self, initial_score: &S::Score) {
self.water_level = Some(*initial_score);
self.initial_abs_score = Some(initial_score.abs());
}
fn step_ended(&mut self, _step_score: &S::Score) {
if let (Some(water), Some(abs_score)) = (&self.water_level, &self.initial_abs_score) {
let increment = abs_score.multiply(self.rain_speed);
self.water_level = Some(*water + increment);
}
}
fn phase_ended(&mut self) {
self.water_level = None;
self.initial_abs_score = None;
}
}
#[cfg(test)]
mod tests {
use super::*;
use solverforge_core::score::SoftScore;
#[derive(Clone)]
struct TestSolution {
score: Option<SoftScore>,
}
impl PlanningSolution for TestSolution {
type Score = SoftScore;
fn score(&self) -> Option<Self::Score> {
self.score
}
fn set_score(&mut self, score: Option<Self::Score>) {
self.score = score;
}
}
#[test]
fn test_accepts_improving_moves() {
let mut acceptor = GreatDelugeAcceptor::<TestSolution>::new(0.001);
acceptor.phase_started(&SoftScore::of(-100));
assert!(acceptor.is_accepted(&SoftScore::of(-100), &SoftScore::of(-50)));
}
#[test]
fn test_accepts_above_water_level() {
let mut acceptor = GreatDelugeAcceptor::<TestSolution>::new(0.001);
acceptor.phase_started(&SoftScore::of(-100));
assert!(acceptor.is_accepted(&SoftScore::of(-100), &SoftScore::of(-100)));
assert!(acceptor.is_accepted(&SoftScore::of(-100), &SoftScore::of(-90)));
}
#[test]
fn test_rejects_below_water_level() {
let mut acceptor = GreatDelugeAcceptor::<TestSolution>::new(0.001);
acceptor.phase_started(&SoftScore::of(-100));
assert!(!acceptor.is_accepted(&SoftScore::of(-100), &SoftScore::of(-110)));
}
#[test]
fn test_water_rises_over_time() {
let mut acceptor = GreatDelugeAcceptor::<TestSolution>::new(0.1);
acceptor.phase_started(&SoftScore::of(-100));
assert!(acceptor.is_accepted(&SoftScore::of(-100), &SoftScore::of(-100)));
assert!(!acceptor.is_accepted(&SoftScore::of(-100), &SoftScore::of(-101)));
acceptor.step_ended(&SoftScore::of(-100));
assert!(acceptor.is_accepted(&SoftScore::of(-90), &SoftScore::of(-90)));
assert!(!acceptor.is_accepted(&SoftScore::of(-90), &SoftScore::of(-91)));
acceptor.step_ended(&SoftScore::of(-90));
assert!(acceptor.is_accepted(&SoftScore::of(-80), &SoftScore::of(-80)));
assert!(!acceptor.is_accepted(&SoftScore::of(-80), &SoftScore::of(-81)));
}
#[test]
fn test_phase_reset() {
let mut acceptor = GreatDelugeAcceptor::<TestSolution>::new(0.1);
acceptor.phase_started(&SoftScore::of(-100));
acceptor.step_ended(&SoftScore::of(-100));
acceptor.phase_ended();
acceptor.phase_started(&SoftScore::of(-50));
assert!(acceptor.is_accepted(&SoftScore::of(-50), &SoftScore::of(-50)));
assert!(!acceptor.is_accepted(&SoftScore::of(-50), &SoftScore::of(-51)));
}
}