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