solverforge_solver/heuristic/move/
swap.rs1use std::fmt::Debug;
12
13use solverforge_core::domain::PlanningSolution;
14use solverforge_scoring::ScoreDirector;
15
16use super::Move;
17
18pub struct SwapMove<S, V> {
50 left_entity_index: usize,
51 right_entity_index: usize,
52 getter: fn(&S, usize) -> Option<V>,
54 setter: fn(&mut S, usize, Option<V>),
56 variable_name: &'static str,
57 descriptor_index: usize,
58 indices: [usize; 2],
60}
61
62impl<S, V> Clone for SwapMove<S, V> {
63 fn clone(&self) -> Self {
64 *self
65 }
66}
67
68impl<S, V> Copy for SwapMove<S, V> {}
69
70impl<S, V: Debug> Debug for SwapMove<S, V> {
71 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
72 f.debug_struct("SwapMove")
73 .field("left_entity_index", &self.left_entity_index)
74 .field("right_entity_index", &self.right_entity_index)
75 .field("descriptor_index", &self.descriptor_index)
76 .field("variable_name", &self.variable_name)
77 .finish()
78 }
79}
80
81impl<S, V> SwapMove<S, V> {
82 pub fn new(
92 left_entity_index: usize,
93 right_entity_index: usize,
94 getter: fn(&S, usize) -> Option<V>,
95 setter: fn(&mut S, usize, Option<V>),
96 variable_name: &'static str,
97 descriptor_index: usize,
98 ) -> Self {
99 Self {
100 left_entity_index,
101 right_entity_index,
102 getter,
103 setter,
104 variable_name,
105 descriptor_index,
106 indices: [left_entity_index, right_entity_index],
107 }
108 }
109
110 pub fn left_entity_index(&self) -> usize {
112 self.left_entity_index
113 }
114
115 pub fn right_entity_index(&self) -> usize {
117 self.right_entity_index
118 }
119}
120
121impl<S, V> Move<S> for SwapMove<S, V>
122where
123 S: PlanningSolution,
124 V: Clone + PartialEq + Send + Sync + Debug + 'static,
125{
126 fn is_doable<D: ScoreDirector<S>>(&self, score_director: &D) -> bool {
127 if self.left_entity_index == self.right_entity_index {
129 return false;
130 }
131
132 let left_val = (self.getter)(score_director.working_solution(), self.left_entity_index);
134 let right_val = (self.getter)(score_director.working_solution(), self.right_entity_index);
135
136 left_val != right_val
138 }
139
140 fn do_move<D: ScoreDirector<S>>(&self, score_director: &mut D) {
141 let left_value = (self.getter)(score_director.working_solution(), self.left_entity_index);
143 let right_value = (self.getter)(score_director.working_solution(), self.right_entity_index);
144
145 score_director.before_variable_changed(
147 self.descriptor_index,
148 self.left_entity_index,
149 self.variable_name,
150 );
151 score_director.before_variable_changed(
152 self.descriptor_index,
153 self.right_entity_index,
154 self.variable_name,
155 );
156
157 (self.setter)(
159 score_director.working_solution_mut(),
160 self.left_entity_index,
161 right_value.clone(),
162 );
163 (self.setter)(
164 score_director.working_solution_mut(),
165 self.right_entity_index,
166 left_value.clone(),
167 );
168
169 score_director.after_variable_changed(
171 self.descriptor_index,
172 self.left_entity_index,
173 self.variable_name,
174 );
175 score_director.after_variable_changed(
176 self.descriptor_index,
177 self.right_entity_index,
178 self.variable_name,
179 );
180
181 let setter = self.setter;
183 let left_idx = self.left_entity_index;
184 let right_idx = self.right_entity_index;
185 score_director.register_undo(Box::new(move |s: &mut S| {
186 setter(s, left_idx, left_value);
188 setter(s, right_idx, right_value);
189 }));
190 }
191
192 fn descriptor_index(&self) -> usize {
193 self.descriptor_index
194 }
195
196 fn entity_indices(&self) -> &[usize] {
197 &self.indices
198 }
199
200 fn variable_name(&self) -> &str {
201 self.variable_name
202 }
203}