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