solverforge_solver/heuristic/move/
swap.rs1use std::fmt::Debug;
12
13use solverforge_core::domain::PlanningSolution;
14use solverforge_scoring::Director;
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: Director<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: Director<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(self.descriptor_index, self.left_entity_index);
147 score_director.before_variable_changed(self.descriptor_index, self.right_entity_index);
148
149 (self.setter)(
151 score_director.working_solution_mut(),
152 self.left_entity_index,
153 right_value.clone(),
154 );
155 (self.setter)(
156 score_director.working_solution_mut(),
157 self.right_entity_index,
158 left_value.clone(),
159 );
160
161 score_director.after_variable_changed(self.descriptor_index, self.left_entity_index);
163 score_director.after_variable_changed(self.descriptor_index, self.right_entity_index);
164
165 let setter = self.setter;
167 let left_idx = self.left_entity_index;
168 let right_idx = self.right_entity_index;
169 score_director.register_undo(Box::new(move |s: &mut S| {
170 setter(s, left_idx, left_value);
172 setter(s, right_idx, right_value);
173 }));
174 }
175
176 fn descriptor_index(&self) -> usize {
177 self.descriptor_index
178 }
179
180 fn entity_indices(&self) -> &[usize] {
181 &self.indices
182 }
183
184 fn variable_name(&self) -> &str {
185 self.variable_name
186 }
187}