morkovmap_rc 0.4.1

A data-driven, Markov Chain-based tilemap generator library and app. Single-thread-flavored.
Documentation
use std::rc::{Rc};
use std::cell::{RefCell};
use std::cmp::Ordering;
use std::marker::PhantomData;
use serde;
use crate::adjacency::AdjacencyGenerator;
use crate::position::{MapPosition};
use crate::sampler::{DistributionKey, MultinomialDistribution};

#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
pub enum MapNodeState<K: DistributionKey> {
    Undecided(MultinomialDistribution<K>),
    Finalized(K)
}

impl<K: DistributionKey> MapNodeState<K> {
    pub fn undecided(possibilities: MultinomialDistribution<K>) -> Self {
        Self::Undecided(possibilities)
    }

    pub fn finalized(assignment: K) -> Self {
        Self::Finalized(assignment)
    }

    pub fn is_assigned(&self) -> bool {
        match self {
            Self::Undecided(_) => false,
            Self::Finalized(_) => true
        }
    }
}

impl<K: DistributionKey> From<MultinomialDistribution<K>> for MapNodeState<K> {
    fn from(value: MultinomialDistribution<K>) -> Self {
        Self::undecided(value)
    }
}

impl<K: DistributionKey> From<K> for MapNodeState<K> {
    fn from(value: K) -> Self {
        Self::finalized(value)
    }
}


#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
pub struct Map2DNode<AG: AdjacencyGenerator<2>, K: DistributionKey, MP: MapPosition<2>> {
    pub(crate) position: MP,
    pub(crate) state: MapNodeState<K>,
    adjacency_phantom: PhantomData<AG>,
}

impl<AG: AdjacencyGenerator<2>, K: DistributionKey, MP: MapPosition<2>> Map2DNode<AG, K, MP>
{
    pub fn with_possibilities(position: MP, possibilities: MultinomialDistribution<K>) -> Self {
        Self {
            position,
            state: MapNodeState::undecided(possibilities),
            adjacency_phantom: PhantomData
        }
    }

    pub fn with_assignment(position: MP, assignment: K) -> Self {
        Self {
            position,
            state: MapNodeState::finalized(assignment),
            adjacency_phantom: PhantomData
        }
    }

    pub fn entropy(&self) -> f32 {
        match &self.state {
            MapNodeState::Finalized(_) => f32::INFINITY,
            MapNodeState::Undecided(possibilities) => possibilities.entropy()
        }
    }

    pub fn get_position(&self) -> MP {
        self.position
    }
}

#[derive(Clone, serde::Serialize, serde::Deserialize)]
pub enum MapNodeWrapper<AG: AdjacencyGenerator<2>, K: DistributionKey, MP: MapPosition<2>> {
    Raw(Map2DNode<AG, K, MP>),
    Rc(Rc<RefCell<Map2DNode<AG, K, MP>>>)
}

impl<AG: AdjacencyGenerator<2>, K: DistributionKey, MP: MapPosition<2>> MapNodeWrapper<AG, K, MP>
{
    pub fn position(&self) -> MP {
        match self {
            Self::Raw(node) => node.position,
            Self::Rc(arc_node) => arc_node.try_borrow().unwrap().position
        }
    }
}

#[derive(serde::Serialize, serde::Deserialize)]
pub struct MapNodeEntropyOrdering<AG: AdjacencyGenerator<2>, K: DistributionKey, MP: MapPosition<2>> {
    pub node: MapNodeWrapper<AG, K, MP>
}

impl<AG: AdjacencyGenerator<2>, K: DistributionKey, MP: MapPosition<2>> From<Map2DNode<AG, K, MP>> for MapNodeEntropyOrdering<AG, K, MP> {
    fn from(value: Map2DNode<AG, K, MP>) -> Self {
        Self {
            node: MapNodeWrapper::Raw(value)
        }
    }
}

impl<AG: AdjacencyGenerator<2>, K: DistributionKey, MP: MapPosition<2>> From<Rc<RefCell<Map2DNode<AG, K, MP>>>> for MapNodeEntropyOrdering<AG, K, MP> {
    fn from(value: Rc<RefCell<Map2DNode<AG, K, MP>>>) -> Self {
        Self {
            node: MapNodeWrapper::Rc(value)
        }
    }
}

impl<AG: AdjacencyGenerator<2>, K: DistributionKey, MP: MapPosition<2>> PartialEq<Self> for MapNodeEntropyOrdering<AG, K, MP> {
    fn eq(&self, other: &Self) -> bool {
        let my_entropy = match &self.node {
            MapNodeWrapper::Raw(node_data) => node_data.entropy(),
            MapNodeWrapper::Rc(node_data) => node_data.try_borrow().unwrap().entropy(),
        };

        let other_entropy = match &other.node {
            MapNodeWrapper::Raw(node_data) => node_data.entropy(),
            MapNodeWrapper::Rc(node_data) => node_data.try_borrow().unwrap().entropy(),
        };

        my_entropy == other_entropy
    }
}

impl<AG: AdjacencyGenerator<2>, K: DistributionKey, MP: MapPosition<2>> Eq for MapNodeEntropyOrdering<AG, K, MP> {}

impl<AG: AdjacencyGenerator<2>, K: DistributionKey, MP: MapPosition<2>> PartialOrd for MapNodeEntropyOrdering<AG, K, MP> {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        let my_entropy = match &self.node {
            MapNodeWrapper::Raw(node_data) => node_data.entropy(),
            MapNodeWrapper::Rc(node_data) => node_data.try_borrow().unwrap().entropy(),
        };

        let other_entropy = match &other.node {
            MapNodeWrapper::Raw(node_data) => node_data.entropy(),
            MapNodeWrapper::Rc(node_data) => node_data.try_borrow().unwrap().entropy(),
        };

        match my_entropy == other_entropy {
            true => Some(Ordering::Equal),
            false => match my_entropy > other_entropy {
                true => Some(Ordering::Less),
                false => Some(Ordering::Greater)
            }
        }
    }
}

impl<AG: AdjacencyGenerator<2>, K: DistributionKey, MP: MapPosition<2>> Ord for MapNodeEntropyOrdering<AG, K, MP> {
    fn cmp(&self, other: &Self) -> Ordering {
        self.partial_cmp(other).unwrap()
    }
}

pub type ThreadsafeNodeRef<AG, K, MP> = Rc<RefCell<Map2DNode<AG, K, MP>>>;