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> Debug for ScalarMoveUnion<S, V>
51where
52 S: PlanningSolution,
53 V: Clone + PartialEq + Send + Sync + Debug + 'static,
54{
55 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
56 match self {
57 Self::Change(m) => m.fmt(f),
58 Self::Swap(m) => m.fmt(f),
59 Self::PillarChange(m) => m.fmt(f),
60 Self::PillarSwap(m) => m.fmt(f),
61 Self::RuinRecreate(m) => m.fmt(f),
62 Self::CompoundScalar(m) => m.fmt(f),
63 Self::ConflictRepair(m) => m.fmt(f),
64 Self::RuntimeCompound(m) => m.fmt(f),
65 }
66 }
67}
68
69impl<S, V> Move<S> for ScalarMoveUnion<S, V>
70where
71 S: PlanningSolution,
72 V: Clone + PartialEq + Send + Sync + Debug + 'static,
73{
74 type Undo = ScalarMoveUnionUndo<S, V>;
75
76 fn is_doable<D: Director<S>>(&self, score_director: &D) -> bool {
77 match self {
78 Self::Change(m) => m.is_doable(score_director),
79 Self::Swap(m) => m.is_doable(score_director),
80 Self::PillarChange(m) => m.is_doable(score_director),
81 Self::PillarSwap(m) => m.is_doable(score_director),
82 Self::RuinRecreate(m) => m.is_doable(score_director),
83 Self::CompoundScalar(m) => m.is_doable(score_director),
84 Self::ConflictRepair(m) => m.is_doable(score_director),
85 Self::RuntimeCompound(m) => m.is_doable(score_director),
86 }
87 }
88
89 fn do_move<D: Director<S>>(&self, score_director: &mut D) -> Self::Undo {
90 match self {
91 Self::Change(m) => ScalarMoveUnionUndo::Change(m.do_move(score_director)),
92 Self::Swap(m) => ScalarMoveUnionUndo::Swap(m.do_move(score_director)),
93 Self::PillarChange(m) => ScalarMoveUnionUndo::PillarChange(m.do_move(score_director)),
94 Self::PillarSwap(m) => ScalarMoveUnionUndo::PillarSwap(m.do_move(score_director)),
95 Self::RuinRecreate(m) => ScalarMoveUnionUndo::RuinRecreate(m.do_move(score_director)),
96 Self::CompoundScalar(m) => {
97 ScalarMoveUnionUndo::CompoundScalar(m.do_move(score_director))
98 }
99 Self::ConflictRepair(m) => {
100 ScalarMoveUnionUndo::ConflictRepair(m.do_move(score_director))
101 }
102 Self::RuntimeCompound(m) => {
103 ScalarMoveUnionUndo::RuntimeCompound(m.do_move(score_director))
104 }
105 }
106 }
107
108 fn undo_move<D: Director<S>>(&self, score_director: &mut D, undo: Self::Undo) {
109 match (self, undo) {
110 (Self::Change(m), ScalarMoveUnionUndo::Change(undo)) => {
111 m.undo_move(score_director, undo)
112 }
113 (Self::Swap(m), ScalarMoveUnionUndo::Swap(undo)) => m.undo_move(score_director, undo),
114 (Self::PillarChange(m), ScalarMoveUnionUndo::PillarChange(undo)) => {
115 m.undo_move(score_director, undo)
116 }
117 (Self::PillarSwap(m), ScalarMoveUnionUndo::PillarSwap(undo)) => {
118 m.undo_move(score_director, undo)
119 }
120 (Self::RuinRecreate(m), ScalarMoveUnionUndo::RuinRecreate(undo)) => {
121 m.undo_move(score_director, undo)
122 }
123 (Self::CompoundScalar(m), ScalarMoveUnionUndo::CompoundScalar(undo)) => {
124 m.undo_move(score_director, undo)
125 }
126 (Self::ConflictRepair(m), ScalarMoveUnionUndo::ConflictRepair(undo)) => {
127 m.undo_move(score_director, undo)
128 }
129 (Self::RuntimeCompound(m), ScalarMoveUnionUndo::RuntimeCompound(undo)) => {
130 m.undo_move(score_director, undo)
131 }
132 _ => panic!("scalar move undo shape must match move shape"),
133 }
134 }
135
136 fn descriptor_index(&self) -> usize {
137 match self {
138 Self::Change(m) => m.descriptor_index(),
139 Self::Swap(m) => m.descriptor_index(),
140 Self::PillarChange(m) => m.descriptor_index(),
141 Self::PillarSwap(m) => m.descriptor_index(),
142 Self::RuinRecreate(m) => m.descriptor_index(),
143 Self::CompoundScalar(m) => m.descriptor_index(),
144 Self::ConflictRepair(m) => m.descriptor_index(),
145 Self::RuntimeCompound(m) => m.descriptor_index(),
146 }
147 }
148
149 fn entity_indices(&self) -> &[usize] {
150 match self {
151 Self::Change(m) => m.entity_indices(),
152 Self::Swap(m) => m.entity_indices(),
153 Self::PillarChange(m) => m.entity_indices(),
154 Self::PillarSwap(m) => m.entity_indices(),
155 Self::RuinRecreate(m) => m.entity_indices(),
156 Self::CompoundScalar(m) => m.entity_indices(),
157 Self::ConflictRepair(m) => m.entity_indices(),
158 Self::RuntimeCompound(m) => m.entity_indices(),
159 }
160 }
161
162 fn variable_name(&self) -> &str {
163 match self {
164 Self::Change(m) => m.variable_name(),
165 Self::Swap(m) => m.variable_name(),
166 Self::PillarChange(m) => m.variable_name(),
167 Self::PillarSwap(m) => m.variable_name(),
168 Self::RuinRecreate(m) => m.variable_name(),
169 Self::CompoundScalar(m) => m.variable_name(),
170 Self::ConflictRepair(m) => m.variable_name(),
171 Self::RuntimeCompound(m) => m.variable_name(),
172 }
173 }
174
175 fn telemetry_label(&self) -> &'static str {
176 match self {
177 Self::Change(m) => m.telemetry_label(),
178 Self::Swap(m) => m.telemetry_label(),
179 Self::PillarChange(m) => m.telemetry_label(),
180 Self::PillarSwap(m) => m.telemetry_label(),
181 Self::RuinRecreate(m) => m.telemetry_label(),
182 Self::CompoundScalar(m) => m.telemetry_label(),
183 Self::ConflictRepair(m) => m.telemetry_label(),
184 Self::RuntimeCompound(m) => m.telemetry_label(),
185 }
186 }
187
188 fn requires_hard_improvement(&self) -> bool {
189 match self {
190 Self::Change(m) => m.requires_hard_improvement(),
191 Self::Swap(m) => m.requires_hard_improvement(),
192 Self::PillarChange(m) => m.requires_hard_improvement(),
193 Self::PillarSwap(m) => m.requires_hard_improvement(),
194 Self::RuinRecreate(m) => m.requires_hard_improvement(),
195 Self::CompoundScalar(m) => m.requires_hard_improvement(),
196 Self::ConflictRepair(m) => m.requires_hard_improvement(),
197 Self::RuntimeCompound(m) => m.requires_hard_improvement(),
198 }
199 }
200
201 fn requires_score_improvement(&self) -> bool {
202 match self {
203 Self::Change(m) => m.requires_score_improvement(),
204 Self::Swap(m) => m.requires_score_improvement(),
205 Self::PillarChange(m) => m.requires_score_improvement(),
206 Self::PillarSwap(m) => m.requires_score_improvement(),
207 Self::RuinRecreate(m) => m.requires_score_improvement(),
208 Self::CompoundScalar(m) => m.requires_score_improvement(),
209 Self::ConflictRepair(m) => m.requires_score_improvement(),
210 Self::RuntimeCompound(m) => m.requires_score_improvement(),
211 }
212 }
213
214 fn borrowed_tabu_signature(&self) -> Option<&MoveTabuSignature> {
215 match self {
216 Self::Change(m) => m.borrowed_tabu_signature(),
217 Self::Swap(m) => m.borrowed_tabu_signature(),
218 Self::PillarChange(m) => m.borrowed_tabu_signature(),
219 Self::PillarSwap(m) => m.borrowed_tabu_signature(),
220 Self::RuinRecreate(m) => m.borrowed_tabu_signature(),
221 Self::CompoundScalar(m) => m.borrowed_tabu_signature(),
222 Self::ConflictRepair(m) => m.borrowed_tabu_signature(),
223 Self::RuntimeCompound(m) => m.borrowed_tabu_signature(),
224 }
225 }
226
227 fn tabu_signature<D: Director<S>>(&self, score_director: &D) -> MoveTabuSignature {
228 match self {
229 Self::Change(m) => m.tabu_signature(score_director),
230 Self::Swap(m) => m.tabu_signature(score_director),
231 Self::PillarChange(m) => m.tabu_signature(score_director),
232 Self::PillarSwap(m) => m.tabu_signature(score_director),
233 Self::RuinRecreate(m) => m.tabu_signature(score_director),
234 Self::CompoundScalar(m) => m.tabu_signature(score_director),
235 Self::ConflictRepair(m) => m.tabu_signature(score_director),
236 Self::RuntimeCompound(m) => m.tabu_signature(score_director),
237 }
238 }
239
240 fn candidate_trace_identity(&self) -> Option<CandidateTraceIdentity> {
241 match self {
242 Self::Change(m) => m.candidate_trace_identity(),
243 Self::Swap(m) => m.candidate_trace_identity(),
244 Self::PillarChange(m) => m.candidate_trace_identity(),
245 Self::PillarSwap(m) => m.candidate_trace_identity(),
246 Self::RuinRecreate(m) => m.candidate_trace_identity(),
247 Self::CompoundScalar(m) => m.candidate_trace_identity(),
248 Self::ConflictRepair(m) => m.candidate_trace_identity(),
249 Self::RuntimeCompound(m) => m.candidate_trace_identity(),
250 }
251 }
252
253 fn for_each_affected_entity<W: FnMut(super::MoveAffectedEntity<'_>)>(&self, visitor: &mut W) {
254 match self {
255 Self::Change(m) => m.for_each_affected_entity(visitor),
256 Self::Swap(m) => m.for_each_affected_entity(visitor),
257 Self::PillarChange(m) => m.for_each_affected_entity(visitor),
258 Self::PillarSwap(m) => m.for_each_affected_entity(visitor),
259 Self::RuinRecreate(m) => m.for_each_affected_entity(visitor),
260 Self::CompoundScalar(m) => m.for_each_affected_entity(visitor),
261 Self::ConflictRepair(m) => m.for_each_affected_entity(visitor),
262 Self::RuntimeCompound(m) => m.for_each_affected_entity(visitor),
263 }
264 }
265}