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