1use std::fmt::Debug;
8
9use solverforge_core::domain::PlanningSolution;
10use solverforge_scoring::Director;
11
12use super::{
13 KOptMove, ListChangeMove, ListMultiSwapMove, ListPermuteMove, ListReverseMove, ListRuinMove,
14 ListSwapMove, Move, MoveTabuSignature, SublistChangeMove, SublistSwapMove,
15};
16
17#[allow(clippy::large_enum_variant)]
31pub enum ListMoveUnion<S, V> {
32 ListChange(ListChangeMove<S, V>),
33 ListSwap(ListSwapMove<S, V>),
34 ListMultiSwap(ListMultiSwapMove<S, V>),
35 ListPermute(ListPermuteMove<S, V>),
36 SublistChange(SublistChangeMove<S, V>),
37 SublistSwap(SublistSwapMove<S, V>),
38 ListReverse(ListReverseMove<S, V>),
39 KOpt(KOptMove<S, V>),
40 ListRuin(ListRuinMove<S, V>),
41}
42
43pub enum ListMoveUnionUndo<S, V>
44where
45 S: PlanningSolution,
46 V: Clone + PartialEq + Send + Sync + Debug + 'static,
47{
48 ListChange(<ListChangeMove<S, V> as Move<S>>::Undo),
49 ListSwap(<ListSwapMove<S, V> as Move<S>>::Undo),
50 ListMultiSwap(<ListMultiSwapMove<S, V> as Move<S>>::Undo),
51 ListPermute(<ListPermuteMove<S, V> as Move<S>>::Undo),
52 SublistChange(<SublistChangeMove<S, V> as Move<S>>::Undo),
53 SublistSwap(<SublistSwapMove<S, V> as Move<S>>::Undo),
54 ListReverse(<ListReverseMove<S, V> as Move<S>>::Undo),
55 KOpt(<KOptMove<S, V> as Move<S>>::Undo),
56 ListRuin(<ListRuinMove<S, V> as Move<S>>::Undo),
57}
58
59impl<S, V> Clone for ListMoveUnion<S, V>
60where
61 S: PlanningSolution,
62 V: Clone + PartialEq + Send + Sync + Debug + 'static,
63{
64 fn clone(&self) -> Self {
65 match self {
66 Self::ListChange(m) => Self::ListChange(*m),
67 Self::ListSwap(m) => Self::ListSwap(*m),
68 Self::ListMultiSwap(m) => Self::ListMultiSwap(m.clone()),
69 Self::ListPermute(m) => Self::ListPermute(m.clone()),
70 Self::SublistChange(m) => Self::SublistChange(*m),
71 Self::SublistSwap(m) => Self::SublistSwap(*m),
72 Self::ListReverse(m) => Self::ListReverse(*m),
73 Self::KOpt(m) => Self::KOpt(m.clone()),
74 Self::ListRuin(m) => Self::ListRuin(m.clone()),
75 }
76 }
77}
78
79impl<S, V> Debug for ListMoveUnion<S, V>
80where
81 S: PlanningSolution,
82 V: Clone + PartialEq + Send + Sync + Debug + 'static,
83{
84 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
85 match self {
86 Self::ListChange(m) => m.fmt(f),
87 Self::ListSwap(m) => m.fmt(f),
88 Self::ListMultiSwap(m) => m.fmt(f),
89 Self::ListPermute(m) => m.fmt(f),
90 Self::SublistChange(m) => m.fmt(f),
91 Self::SublistSwap(m) => m.fmt(f),
92 Self::ListReverse(m) => m.fmt(f),
93 Self::KOpt(m) => m.fmt(f),
94 Self::ListRuin(m) => m.fmt(f),
95 }
96 }
97}
98
99impl<S, V> Move<S> for ListMoveUnion<S, V>
100where
101 S: PlanningSolution,
102 V: Clone + PartialEq + Send + Sync + Debug + 'static,
103{
104 type Undo = ListMoveUnionUndo<S, V>;
105
106 fn is_doable<D: Director<S>>(&self, score_director: &D) -> bool {
107 match self {
108 Self::ListChange(m) => m.is_doable(score_director),
109 Self::ListSwap(m) => m.is_doable(score_director),
110 Self::ListMultiSwap(m) => m.is_doable(score_director),
111 Self::ListPermute(m) => m.is_doable(score_director),
112 Self::SublistChange(m) => m.is_doable(score_director),
113 Self::SublistSwap(m) => m.is_doable(score_director),
114 Self::ListReverse(m) => m.is_doable(score_director),
115 Self::KOpt(m) => m.is_doable(score_director),
116 Self::ListRuin(m) => m.is_doable(score_director),
117 }
118 }
119
120 fn do_move<D: Director<S>>(&self, score_director: &mut D) -> Self::Undo {
121 match self {
122 Self::ListChange(m) => {
123 m.do_move(score_director);
124 ListMoveUnionUndo::ListChange(())
125 }
126 Self::ListSwap(m) => {
127 m.do_move(score_director);
128 ListMoveUnionUndo::ListSwap(())
129 }
130 Self::ListMultiSwap(m) => {
131 m.do_move(score_director);
132 ListMoveUnionUndo::ListMultiSwap(())
133 }
134 Self::ListPermute(m) => ListMoveUnionUndo::ListPermute(m.do_move(score_director)),
135 Self::SublistChange(m) => {
136 m.do_move(score_director);
137 ListMoveUnionUndo::SublistChange(())
138 }
139 Self::SublistSwap(m) => {
140 m.do_move(score_director);
141 ListMoveUnionUndo::SublistSwap(())
142 }
143 Self::ListReverse(m) => {
144 m.do_move(score_director);
145 ListMoveUnionUndo::ListReverse(())
146 }
147 Self::KOpt(m) => ListMoveUnionUndo::KOpt(m.do_move(score_director)),
148 Self::ListRuin(m) => ListMoveUnionUndo::ListRuin(m.do_move(score_director)),
149 }
150 }
151
152 fn undo_move<D: Director<S>>(&self, score_director: &mut D, undo: Self::Undo) {
153 match (self, undo) {
154 (Self::ListChange(m), ListMoveUnionUndo::ListChange(undo)) => {
155 m.undo_move(score_director, undo)
156 }
157 (Self::ListSwap(m), ListMoveUnionUndo::ListSwap(undo)) => {
158 m.undo_move(score_director, undo)
159 }
160 (Self::ListMultiSwap(m), ListMoveUnionUndo::ListMultiSwap(undo)) => {
161 m.undo_move(score_director, undo)
162 }
163 (Self::ListPermute(m), ListMoveUnionUndo::ListPermute(undo)) => {
164 m.undo_move(score_director, undo)
165 }
166 (Self::SublistChange(m), ListMoveUnionUndo::SublistChange(undo)) => {
167 m.undo_move(score_director, undo)
168 }
169 (Self::SublistSwap(m), ListMoveUnionUndo::SublistSwap(undo)) => {
170 m.undo_move(score_director, undo)
171 }
172 (Self::ListReverse(m), ListMoveUnionUndo::ListReverse(undo)) => {
173 m.undo_move(score_director, undo)
174 }
175 (Self::KOpt(m), ListMoveUnionUndo::KOpt(undo)) => m.undo_move(score_director, undo),
176 (Self::ListRuin(m), ListMoveUnionUndo::ListRuin(undo)) => {
177 m.undo_move(score_director, undo)
178 }
179 _ => panic!("list move undo shape must match move shape"),
180 }
181 }
182
183 fn descriptor_index(&self) -> usize {
184 match self {
185 Self::ListChange(m) => m.descriptor_index(),
186 Self::ListSwap(m) => m.descriptor_index(),
187 Self::ListMultiSwap(m) => m.descriptor_index(),
188 Self::ListPermute(m) => m.descriptor_index(),
189 Self::SublistChange(m) => m.descriptor_index(),
190 Self::SublistSwap(m) => m.descriptor_index(),
191 Self::ListReverse(m) => m.descriptor_index(),
192 Self::KOpt(m) => m.descriptor_index(),
193 Self::ListRuin(m) => m.descriptor_index(),
194 }
195 }
196
197 fn entity_indices(&self) -> &[usize] {
198 match self {
199 Self::ListChange(m) => m.entity_indices(),
200 Self::ListSwap(m) => m.entity_indices(),
201 Self::ListMultiSwap(m) => m.entity_indices(),
202 Self::ListPermute(m) => m.entity_indices(),
203 Self::SublistChange(m) => m.entity_indices(),
204 Self::SublistSwap(m) => m.entity_indices(),
205 Self::ListReverse(m) => m.entity_indices(),
206 Self::KOpt(m) => m.entity_indices(),
207 Self::ListRuin(m) => m.entity_indices(),
208 }
209 }
210
211 fn variable_name(&self) -> &str {
212 match self {
213 Self::ListChange(m) => m.variable_name(),
214 Self::ListSwap(m) => m.variable_name(),
215 Self::ListMultiSwap(m) => m.variable_name(),
216 Self::ListPermute(m) => m.variable_name(),
217 Self::SublistChange(m) => m.variable_name(),
218 Self::SublistSwap(m) => m.variable_name(),
219 Self::ListReverse(m) => m.variable_name(),
220 Self::KOpt(m) => m.variable_name(),
221 Self::ListRuin(m) => m.variable_name(),
222 }
223 }
224
225 fn telemetry_label(&self) -> &'static str {
226 match self {
227 Self::ListChange(m) => m.telemetry_label(),
228 Self::ListSwap(m) => m.telemetry_label(),
229 Self::ListMultiSwap(m) => m.telemetry_label(),
230 Self::ListPermute(m) => m.telemetry_label(),
231 Self::SublistChange(m) => m.telemetry_label(),
232 Self::SublistSwap(m) => m.telemetry_label(),
233 Self::ListReverse(m) => m.telemetry_label(),
234 Self::KOpt(m) => m.telemetry_label(),
235 Self::ListRuin(m) => m.telemetry_label(),
236 }
237 }
238
239 fn requires_hard_improvement(&self) -> bool {
240 match self {
241 Self::ListChange(m) => m.requires_hard_improvement(),
242 Self::ListSwap(m) => m.requires_hard_improvement(),
243 Self::ListMultiSwap(m) => m.requires_hard_improvement(),
244 Self::ListPermute(m) => m.requires_hard_improvement(),
245 Self::SublistChange(m) => m.requires_hard_improvement(),
246 Self::SublistSwap(m) => m.requires_hard_improvement(),
247 Self::ListReverse(m) => m.requires_hard_improvement(),
248 Self::KOpt(m) => m.requires_hard_improvement(),
249 Self::ListRuin(m) => m.requires_hard_improvement(),
250 }
251 }
252
253 fn requires_score_improvement(&self) -> bool {
254 match self {
255 Self::ListChange(m) => m.requires_score_improvement(),
256 Self::ListSwap(m) => m.requires_score_improvement(),
257 Self::ListMultiSwap(m) => m.requires_score_improvement(),
258 Self::ListPermute(m) => m.requires_score_improvement(),
259 Self::SublistChange(m) => m.requires_score_improvement(),
260 Self::SublistSwap(m) => m.requires_score_improvement(),
261 Self::ListReverse(m) => m.requires_score_improvement(),
262 Self::KOpt(m) => m.requires_score_improvement(),
263 Self::ListRuin(m) => m.requires_score_improvement(),
264 }
265 }
266
267 fn tabu_signature<D: Director<S>>(&self, score_director: &D) -> MoveTabuSignature {
268 match self {
269 Self::ListChange(m) => m.tabu_signature(score_director),
270 Self::ListSwap(m) => m.tabu_signature(score_director),
271 Self::ListMultiSwap(m) => m.tabu_signature(score_director),
272 Self::ListPermute(m) => m.tabu_signature(score_director),
273 Self::SublistChange(m) => m.tabu_signature(score_director),
274 Self::SublistSwap(m) => m.tabu_signature(score_director),
275 Self::ListReverse(m) => m.tabu_signature(score_director),
276 Self::KOpt(m) => m.tabu_signature(score_director),
277 Self::ListRuin(m) => m.tabu_signature(score_director),
278 }
279 }
280}