1use std::fmt::Debug;
8use std::marker::PhantomData;
9
10use solverforge_core::domain::PlanningSolution;
11use solverforge_scoring::Director;
12
13use crate::heuristic::r#move::{ChangeMove, Move};
14use crate::heuristic::selector::{EntityReference, EntitySelector, ValueSelector};
15
16use super::ConstructionSlotId;
17
18pub struct Placement<S, M>
25where
26 S: PlanningSolution,
27 M: Move<S>,
28{
29 pub entity_ref: EntityReference,
31 pub moves: Vec<M>,
33 keep_current_legal: bool,
35 slot_id: Option<ConstructionSlotId>,
36 _phantom: PhantomData<fn() -> S>,
37}
38
39impl<S, M> Placement<S, M>
40where
41 S: PlanningSolution,
42 M: Move<S>,
43{
44 pub fn new(entity_ref: EntityReference, moves: Vec<M>) -> Self {
45 Self {
46 entity_ref,
47 moves,
48 keep_current_legal: false,
49 slot_id: None,
50 _phantom: PhantomData,
51 }
52 }
53
54 pub fn is_empty(&self) -> bool {
55 self.moves.is_empty()
56 }
57
58 pub fn with_keep_current_legal(mut self, legal: bool) -> Self {
59 self.keep_current_legal = legal;
60 self
61 }
62
63 pub fn keep_current_legal(&self) -> bool {
64 self.keep_current_legal
65 }
66
67 pub(crate) fn with_slot_id(mut self, slot_id: ConstructionSlotId) -> Self {
68 self.slot_id = Some(slot_id);
69 self
70 }
71
72 pub(crate) fn slot_id(&self) -> Option<ConstructionSlotId> {
73 self.slot_id
74 }
75
76 pub fn take_move(&mut self, index: usize) -> M {
80 self.moves.swap_remove(index)
81 }
82}
83
84impl<S, M> Debug for Placement<S, M>
85where
86 S: PlanningSolution,
87 M: Move<S>,
88{
89 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
90 f.debug_struct("Placement")
91 .field("entity_ref", &self.entity_ref)
92 .field("move_count", &self.moves.len())
93 .field("keep_current_legal", &self.keep_current_legal)
94 .field("slot_id", &self.slot_id)
95 .finish()
96 }
97}
98
99pub trait EntityPlacer<S, M>: Send + Debug
108where
109 S: PlanningSolution,
110 M: Move<S>,
111{
112 fn get_placements<D: Director<S>>(&self, score_director: &D) -> Vec<Placement<S, M>>;
114}
115
116pub struct QueuedEntityPlacer<S, V, ES, VS>
127where
128 S: PlanningSolution,
129 ES: EntitySelector<S>,
130 VS: ValueSelector<S, V>,
131{
132 entity_selector: ES,
134 value_selector: VS,
136 getter: fn(&S, usize, usize) -> Option<V>,
138 setter: fn(&mut S, usize, usize, Option<V>),
140 variable_index: usize,
141 variable_name: &'static str,
143 descriptor_index: usize,
145 allows_unassigned: bool,
147 _phantom: PhantomData<fn() -> V>,
148}
149
150impl<S, V, ES, VS> QueuedEntityPlacer<S, V, ES, VS>
151where
152 S: PlanningSolution,
153 ES: EntitySelector<S>,
154 VS: ValueSelector<S, V>,
155{
156 pub fn new(
157 entity_selector: ES,
158 value_selector: VS,
159 getter: fn(&S, usize, usize) -> Option<V>,
160 setter: fn(&mut S, usize, usize, Option<V>),
161 descriptor_index: usize,
162 variable_index: usize,
163 variable_name: &'static str,
164 ) -> Self {
165 Self {
166 entity_selector,
167 value_selector,
168 getter,
169 setter,
170 variable_index,
171 variable_name,
172 descriptor_index,
173 allows_unassigned: false,
174 _phantom: PhantomData,
175 }
176 }
177
178 pub fn with_allows_unassigned(mut self, allows_unassigned: bool) -> Self {
179 self.allows_unassigned = allows_unassigned;
180 self
181 }
182}
183
184impl<S, V, ES, VS> Debug for QueuedEntityPlacer<S, V, ES, VS>
185where
186 S: PlanningSolution,
187 ES: EntitySelector<S> + Debug,
188 VS: ValueSelector<S, V> + Debug,
189{
190 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
191 f.debug_struct("QueuedEntityPlacer")
192 .field("entity_selector", &self.entity_selector)
193 .field("value_selector", &self.value_selector)
194 .field("variable_name", &self.variable_name)
195 .field("allows_unassigned", &self.allows_unassigned)
196 .finish()
197 }
198}
199
200impl<S, V, ES, VS> EntityPlacer<S, ChangeMove<S, V>> for QueuedEntityPlacer<S, V, ES, VS>
201where
202 S: PlanningSolution,
203 V: Clone + PartialEq + Send + Sync + Debug + 'static,
204 ES: EntitySelector<S>,
205 VS: ValueSelector<S, V>,
206{
207 fn get_placements<D: Director<S>>(
208 &self,
209 score_director: &D,
210 ) -> Vec<Placement<S, ChangeMove<S, V>>> {
211 let variable_name = self.variable_name;
212 let descriptor_index = self.descriptor_index;
213 let getter = self.getter;
214 let setter = self.setter;
215 let variable_index = self.variable_index;
216 let allows_unassigned = self.allows_unassigned;
217
218 self.entity_selector
219 .iter(score_director)
220 .filter_map(|entity_ref| {
221 let current_value = getter(
223 score_director.working_solution(),
224 entity_ref.entity_index,
225 variable_index,
226 );
227
228 if current_value.is_some() {
230 return None;
231 }
232
233 let moves: Vec<ChangeMove<S, V>> = self
235 .value_selector
236 .iter(
237 score_director,
238 entity_ref.descriptor_index,
239 entity_ref.entity_index,
240 )
241 .map(|value| {
242 ChangeMove::new(
243 entity_ref.entity_index,
244 Some(value),
245 getter,
246 setter,
247 variable_index,
248 variable_name,
249 descriptor_index,
250 )
251 })
252 .collect();
253
254 if moves.is_empty() {
255 None
256 } else {
257 Some(
258 Placement::new(entity_ref, moves)
259 .with_keep_current_legal(allows_unassigned),
260 )
261 }
262 })
263 .collect()
264 }
265}
266
267pub struct SortedEntityPlacer<S, M, Inner>
310where
311 S: PlanningSolution,
312 M: Move<S>,
313 Inner: EntityPlacer<S, M>,
314{
315 inner: Inner,
316 comparator: fn(&S, usize, usize) -> std::cmp::Ordering,
318 _phantom: PhantomData<fn() -> (S, M)>,
319}
320
321impl<S, M, Inner> SortedEntityPlacer<S, M, Inner>
322where
323 S: PlanningSolution,
324 M: Move<S>,
325 Inner: EntityPlacer<S, M>,
326{
327 pub fn new(inner: Inner, comparator: fn(&S, usize, usize) -> std::cmp::Ordering) -> Self {
333 Self {
334 inner,
335 comparator,
336 _phantom: PhantomData,
337 }
338 }
339}
340
341impl<S, M, Inner> Debug for SortedEntityPlacer<S, M, Inner>
342where
343 S: PlanningSolution,
344 M: Move<S>,
345 Inner: EntityPlacer<S, M>,
346{
347 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
348 f.debug_struct("SortedEntityPlacer")
349 .field("inner", &self.inner)
350 .finish()
351 }
352}
353
354impl<S, M, Inner> EntityPlacer<S, M> for SortedEntityPlacer<S, M, Inner>
355where
356 S: PlanningSolution,
357 M: Move<S>,
358 Inner: EntityPlacer<S, M>,
359{
360 fn get_placements<D: Director<S>>(&self, score_director: &D) -> Vec<Placement<S, M>> {
361 let mut placements = self.inner.get_placements(score_director);
362 let solution = score_director.working_solution();
363 let cmp = self.comparator;
364
365 placements.sort_by(|a, b| {
366 cmp(
367 solution,
368 a.entity_ref.entity_index,
369 b.entity_ref.entity_index,
370 )
371 });
372
373 placements
374 }
375}
376
377#[cfg(test)]
378mod tests;