solverforge_solver/heuristic/move/
change.rs1use std::fmt::Debug;
12
13use solverforge_core::domain::PlanningSolution;
14use solverforge_scoring::ScoreDirector;
15
16use super::Move;
17
18pub struct ChangeMove<S, V> {
27 entity_index: usize,
28 to_value: Option<V>,
29 getter: fn(&S, usize) -> Option<V>,
30 setter: fn(&mut S, usize, Option<V>),
31 variable_name: &'static str,
32 descriptor_index: usize,
33}
34
35impl<S, V: Clone> Clone for ChangeMove<S, V> {
36 fn clone(&self) -> Self {
37 Self {
38 entity_index: self.entity_index,
39 to_value: self.to_value.clone(),
40 getter: self.getter,
41 setter: self.setter,
42 variable_name: self.variable_name,
43 descriptor_index: self.descriptor_index,
44 }
45 }
46}
47
48impl<S, V: Copy> Copy for ChangeMove<S, V> {}
49
50impl<S, V: Debug> Debug for ChangeMove<S, V> {
51 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
52 f.debug_struct("ChangeMove")
53 .field("entity_index", &self.entity_index)
54 .field("descriptor_index", &self.descriptor_index)
55 .field("variable_name", &self.variable_name)
56 .field("to_value", &self.to_value)
57 .finish()
58 }
59}
60
61impl<S, V> ChangeMove<S, V> {
62 pub fn new(
72 entity_index: usize,
73 to_value: Option<V>,
74 getter: fn(&S, usize) -> Option<V>,
75 setter: fn(&mut S, usize, Option<V>),
76 variable_name: &'static str,
77 descriptor_index: usize,
78 ) -> Self {
79 Self {
80 entity_index,
81 to_value,
82 getter,
83 setter,
84 variable_name,
85 descriptor_index,
86 }
87 }
88
89 pub fn entity_index(&self) -> usize {
91 self.entity_index
92 }
93
94 pub fn to_value(&self) -> Option<&V> {
96 self.to_value.as_ref()
97 }
98
99 pub fn getter(&self) -> fn(&S, usize) -> Option<V> {
101 self.getter
102 }
103
104 pub fn setter(&self) -> fn(&mut S, usize, Option<V>) {
106 self.setter
107 }
108}
109
110impl<S, V> Move<S> for ChangeMove<S, V>
111where
112 S: PlanningSolution,
113 V: Clone + PartialEq + Send + Sync + Debug + 'static,
114{
115 fn is_doable<D: ScoreDirector<S>>(&self, score_director: &D) -> bool {
116 let current = (self.getter)(score_director.working_solution(), self.entity_index);
118
119 match (¤t, &self.to_value) {
121 (None, None) => false, (Some(cur), Some(target)) => cur != target, _ => true, }
125 }
126
127 fn do_move<D: ScoreDirector<S>>(&self, score_director: &mut D) {
128 let old_value = (self.getter)(score_director.working_solution(), self.entity_index);
130
131 score_director.before_variable_changed(
133 self.descriptor_index,
134 self.entity_index,
135 self.variable_name,
136 );
137
138 (self.setter)(
140 score_director.working_solution_mut(),
141 self.entity_index,
142 self.to_value.clone(),
143 );
144
145 score_director.after_variable_changed(
147 self.descriptor_index,
148 self.entity_index,
149 self.variable_name,
150 );
151
152 let setter = self.setter;
154 let idx = self.entity_index;
155 score_director.register_undo(Box::new(move |s: &mut S| {
156 setter(s, idx, old_value);
157 }));
158 }
159
160 fn descriptor_index(&self) -> usize {
161 self.descriptor_index
162 }
163
164 fn entity_indices(&self) -> &[usize] {
165 std::slice::from_ref(&self.entity_index)
166 }
167
168 fn variable_name(&self) -> &str {
169 self.variable_name
170 }
171}