Skip to main content

solverforge_solver/builder/context/scalar/
group.rs

1use std::fmt;
2
3use super::value_source::ValueSource;
4use super::variable::{ScalarGetter, ScalarSetter, ScalarVariableContext};
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub struct ScalarGroupLimits {
8    pub value_candidate_limit: Option<usize>,
9    pub group_candidate_limit: Option<usize>,
10    pub max_moves_per_step: Option<usize>,
11}
12
13#[derive(Debug, Clone, PartialEq, Eq, Hash)]
14pub struct ScalarGroupEdit {
15    pub descriptor_index: usize,
16    pub entity_index: usize,
17    pub variable_name: &'static str,
18    pub to_value: Option<usize>,
19}
20
21impl ScalarGroupEdit {
22    pub fn set_scalar(
23        descriptor_index: usize,
24        entity_index: usize,
25        variable_name: &'static str,
26        to_value: Option<usize>,
27    ) -> Self {
28        Self {
29            descriptor_index,
30            entity_index,
31            variable_name,
32            to_value,
33        }
34    }
35}
36
37#[derive(Debug, Clone, PartialEq, Eq, Hash)]
38pub struct ScalarGroupCandidate {
39    pub reason: &'static str,
40    pub edits: Vec<ScalarGroupEdit>,
41    pub construction_slot_key: Option<usize>,
42    pub construction_entity_order_key: Option<i64>,
43    pub construction_value_order_key: Option<i64>,
44}
45
46impl ScalarGroupCandidate {
47    pub fn new(reason: &'static str, edits: Vec<ScalarGroupEdit>) -> Self {
48        Self {
49            reason,
50            edits,
51            construction_slot_key: None,
52            construction_entity_order_key: None,
53            construction_value_order_key: None,
54        }
55    }
56
57    pub fn with_construction_slot_key(mut self, key: usize) -> Self {
58        self.construction_slot_key = Some(key);
59        self
60    }
61
62    pub fn with_construction_entity_order_key(mut self, key: i64) -> Self {
63        self.construction_entity_order_key = Some(key);
64        self
65    }
66
67    pub fn with_construction_value_order_key(mut self, key: i64) -> Self {
68        self.construction_value_order_key = Some(key);
69        self
70    }
71}
72
73pub type ScalarGroupCandidateProvider<S> = fn(&S, ScalarGroupLimits) -> Vec<ScalarGroupCandidate>;
74
75pub struct ScalarGroupMember<S> {
76    pub descriptor_index: usize,
77    pub variable_index: usize,
78    pub entity_type_name: &'static str,
79    pub variable_name: &'static str,
80    pub getter: ScalarGetter<S>,
81    pub setter: ScalarSetter<S>,
82    pub value_source: ValueSource<S>,
83    pub allows_unassigned: bool,
84}
85
86impl<S> Clone for ScalarGroupMember<S> {
87    fn clone(&self) -> Self {
88        *self
89    }
90}
91
92impl<S> Copy for ScalarGroupMember<S> {}
93
94impl<S> ScalarGroupMember<S> {
95    pub fn from_scalar_context(context: ScalarVariableContext<S>) -> Self {
96        Self {
97            descriptor_index: context.descriptor_index,
98            variable_index: context.variable_index,
99            entity_type_name: context.entity_type_name,
100            variable_name: context.variable_name,
101            getter: context.getter,
102            setter: context.setter,
103            value_source: context.value_source,
104            allows_unassigned: context.allows_unassigned,
105        }
106    }
107
108    pub fn current_value(&self, solution: &S, entity_index: usize) -> Option<usize> {
109        (self.getter)(solution, entity_index, self.variable_index)
110    }
111
112    pub fn value_is_legal(
113        &self,
114        solution: &S,
115        entity_index: usize,
116        candidate: Option<usize>,
117    ) -> bool {
118        let Some(value) = candidate else {
119            return self.allows_unassigned;
120        };
121        match self.value_source {
122            ValueSource::Empty => false,
123            ValueSource::CountableRange { from, to } => from <= value && value < to,
124            ValueSource::SolutionCount {
125                count_fn,
126                provider_index,
127            } => value < count_fn(solution, provider_index),
128            ValueSource::EntitySlice { values_for_entity } => {
129                values_for_entity(solution, entity_index, self.variable_index).contains(&value)
130            }
131        }
132    }
133}
134
135impl<S> fmt::Debug for ScalarGroupMember<S> {
136    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
137        f.debug_struct("ScalarGroupMember")
138            .field("descriptor_index", &self.descriptor_index)
139            .field("variable_index", &self.variable_index)
140            .field("entity_type_name", &self.entity_type_name)
141            .field("variable_name", &self.variable_name)
142            .field("value_source", &self.value_source)
143            .field("allows_unassigned", &self.allows_unassigned)
144            .finish()
145    }
146}
147
148pub struct ScalarGroupContext<S> {
149    pub group_name: &'static str,
150    pub members: Vec<ScalarGroupMember<S>>,
151    pub candidate_provider: ScalarGroupCandidateProvider<S>,
152}
153
154impl<S> ScalarGroupContext<S> {
155    pub fn new(
156        group_name: &'static str,
157        members: Vec<ScalarGroupMember<S>>,
158        candidate_provider: ScalarGroupCandidateProvider<S>,
159    ) -> Self {
160        Self {
161            group_name,
162            members,
163            candidate_provider,
164        }
165    }
166
167    pub fn member_for_edit(&self, edit: &ScalarGroupEdit) -> Option<ScalarGroupMember<S>> {
168        self.members.iter().copied().find(|member| {
169            member.descriptor_index == edit.descriptor_index
170                && member.variable_name == edit.variable_name
171        })
172    }
173}
174
175impl<S> Clone for ScalarGroupContext<S> {
176    fn clone(&self) -> Self {
177        Self {
178            group_name: self.group_name,
179            members: self.members.clone(),
180            candidate_provider: self.candidate_provider,
181        }
182    }
183}
184
185impl<S> fmt::Debug for ScalarGroupContext<S> {
186    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
187        f.debug_struct("ScalarGroupContext")
188            .field("group_name", &self.group_name)
189            .field("members", &self.members)
190            .finish_non_exhaustive()
191    }
192}