use std::{collections::HashSet, marker::PhantomData, sync::Arc};
use crate::grid::{
coordinate_system::CoordinateSystem,
direction::DirectionIndex,
grid::{Grid, GridData, NodeRef},
};
use crate::{GeneratorBuilderError, NodeIndex};
use super::{
model::ModelVariantIndex,
node_heuristic::NodeSelectionHeuristic,
observer::{GenerationUpdate, QueuedObserver, QueuedStatefulObserver},
rules::{ModelVariantRef, Rules},
Collector, GeneratedNode, Generator, ModelSelectionHeuristic, RngMode,
};
pub const DEFAULT_RETRY_COUNT: u32 = 50;
#[derive(Copy, Clone)]
pub struct Set;
#[derive(Copy, Clone)]
pub struct Unset;
#[derive(Clone)]
pub struct GeneratorBuilder<G, R, C: CoordinateSystem, T: Grid<C>> {
rules: Option<Arc<Rules<C>>>,
grid: Option<T>,
max_retry_count: u32,
node_selection_heuristic: NodeSelectionHeuristic,
model_selection_heuristic: ModelSelectionHeuristic,
rng_mode: RngMode,
observers: Vec<crossbeam_channel::Sender<GenerationUpdate>>,
initial_nodes: Vec<(NodeIndex, ModelVariantIndex)>,
border_zones: HashSet<(NodeIndex, DirectionIndex)>,
typestate: PhantomData<(G, R)>,
}
impl<C: CoordinateSystem, G: Grid<C>> GeneratorBuilder<Unset, Unset, C, G> {
pub fn new() -> Self {
Self {
rules: None,
grid: None,
max_retry_count: DEFAULT_RETRY_COUNT,
node_selection_heuristic: NodeSelectionHeuristic::MinimumRemainingValue,
model_selection_heuristic: ModelSelectionHeuristic::WeightedProbability,
rng_mode: RngMode::RandomSeed,
observers: Vec::new(),
initial_nodes: Vec::new(),
border_zones: HashSet::new(),
typestate: PhantomData,
}
}
}
impl<C: CoordinateSystem, G: Grid<C>> GeneratorBuilder<Unset, Unset, C, G> {
pub fn with_rules(self, rules: Rules<C>) -> GeneratorBuilder<Unset, Set, C, G> {
GeneratorBuilder {
rules: Some(Arc::new(rules)),
grid: self.grid,
max_retry_count: self.max_retry_count,
node_selection_heuristic: self.node_selection_heuristic,
model_selection_heuristic: self.model_selection_heuristic,
rng_mode: self.rng_mode,
observers: self.observers,
initial_nodes: self.initial_nodes,
border_zones: self.border_zones,
typestate: PhantomData,
}
}
pub fn with_shared_rules(self, rules: Arc<Rules<C>>) -> GeneratorBuilder<Unset, Set, C, G> {
GeneratorBuilder {
rules: Some(rules),
grid: self.grid,
max_retry_count: self.max_retry_count,
node_selection_heuristic: self.node_selection_heuristic,
model_selection_heuristic: self.model_selection_heuristic,
rng_mode: self.rng_mode,
observers: self.observers,
initial_nodes: self.initial_nodes,
border_zones: self.border_zones,
typestate: PhantomData,
}
}
}
impl<C: CoordinateSystem, G: Grid<C>> GeneratorBuilder<Unset, Set, C, G> {
pub fn with_grid(self, grid: G) -> GeneratorBuilder<Set, Set, C, G> {
GeneratorBuilder {
grid: Some(grid),
rules: self.rules,
max_retry_count: self.max_retry_count,
node_selection_heuristic: self.node_selection_heuristic,
model_selection_heuristic: self.model_selection_heuristic,
rng_mode: self.rng_mode,
observers: self.observers,
initial_nodes: self.initial_nodes,
border_zones: self.border_zones,
typestate: PhantomData,
}
}
}
impl<G, R, C: CoordinateSystem, T: Grid<C>> GeneratorBuilder<G, R, C, T> {
pub fn with_max_retry_count(mut self, max_retry_count: u32) -> Self {
self.max_retry_count = max_retry_count;
self
}
pub fn with_node_heuristic(mut self, heuristic: NodeSelectionHeuristic) -> Self {
self.node_selection_heuristic = heuristic;
self
}
pub fn with_model_heuristic(mut self, heuristic: ModelSelectionHeuristic) -> Self {
self.model_selection_heuristic = heuristic;
self
}
pub fn with_rng(mut self, rng_mode: RngMode) -> Self {
self.rng_mode = rng_mode;
self
}
pub fn with_border_zones(mut self, zones: Vec<(NodeIndex, DirectionIndex)>) -> Self {
self.border_zones.extend(zones);
self
}
pub fn with_initial_nodes_raw(
mut self,
initial_nodes: Vec<(NodeIndex, ModelVariantIndex)>,
) -> Self {
self.initial_nodes.extend(initial_nodes);
self
}
}
impl<C: CoordinateSystem, R, G: Grid<C>> GeneratorBuilder<Set, R, C, G> {
pub fn add_queued_stateful_observer(&mut self) -> QueuedStatefulObserver<C, G> {
let (sender, receiver) = crossbeam_channel::unbounded();
self.observers.push(sender);
let grid = self.grid.clone().unwrap();
QueuedStatefulObserver::create(receiver, &grid)
}
pub fn add_queued_observer(&mut self) -> QueuedObserver {
let (sender, receiver) = crossbeam_channel::unbounded();
self.observers.push(sender);
QueuedObserver::create(receiver)
}
pub fn with_initial_grid_raw<M: ModelVariantRef<C>>(
mut self,
data: GridData<C, Option<ModelVariantIndex>, G>,
) -> Result<Self, GeneratorBuilderError> {
let grid = self.grid.as_ref().unwrap();
if grid.total_size() != data.grid().total_size() {
return Err(GeneratorBuilderError::InvalidGridSize(
data.grid().total_size(),
grid.total_size(),
));
} else {
for (node_index, node) in data.iter().enumerate() {
match node {
Some(model_var_index) => {
self.initial_nodes.push((node_index, *model_var_index))
}
None => (),
}
}
Ok(self)
}
}
}
impl<C: CoordinateSystem, G: Grid<C>> GeneratorBuilder<Set, Set, C, G> {
pub fn with_initial_nodes<N: NodeRef<C, G>, M: ModelVariantRef<C>>(
mut self,
initial_nodes: Vec<(N, M)>,
) -> Result<Self, GeneratorBuilderError> {
let grid = self.grid.as_ref().unwrap();
let rules = self.rules.as_ref().unwrap();
for (node_ref, model_ref) in initial_nodes {
self.initial_nodes
.push((node_ref.to_index(grid), model_ref.to_index(rules)?));
}
Ok(self)
}
pub fn with_initial_grid<M: ModelVariantRef<C>>(
mut self,
data: GridData<C, Option<M>, G>,
) -> Result<Self, GeneratorBuilderError> {
let grid = self.grid.as_ref().unwrap();
let rules = self.rules.as_ref().unwrap();
if grid.total_size() != data.grid().total_size() {
return Err(GeneratorBuilderError::InvalidGridSize(
data.grid().total_size(),
grid.total_size(),
));
} else {
for (node_index, node) in data.iter().enumerate() {
match node {
Some(model_ref) => self
.initial_nodes
.push((node_index, model_ref.to_index(rules)?)),
None => (),
}
}
Ok(self)
}
}
pub fn build(self) -> Result<Generator<C, G>, GeneratorBuilderError> {
self.internal_build(&mut None)
}
pub fn build_collected(
self,
) -> Result<(Generator<C, G>, Vec<GeneratedNode>), GeneratorBuilderError> {
let mut generated_nodes = Vec::new();
let res = self.internal_build(&mut Some(&mut generated_nodes))?;
Ok((res, generated_nodes))
}
fn internal_build(
self,
collector: &mut Collector,
) -> Result<Generator<C, G>, GeneratorBuilderError> {
let rules = self.rules.unwrap();
let grid = self.grid.unwrap();
Ok(Generator::create(
rules,
grid,
self.initial_nodes,
self.max_retry_count,
self.node_selection_heuristic,
self.model_selection_heuristic,
self.rng_mode,
self.observers,
self.border_zones,
collector,
)?)
}
}