entropy-base 0.2.8

entropy-game shared library
Documentation
use rand::{rngs::SmallRng, Rng, RngCore, SeedableRng};
use serde::{de, ser::SerializeTupleStruct, Deserialize, Serialize, Serializer};
use std::{fmt, ops::Deref};

pub const NODE_MAX_SIZE: usize = 16 * 1024; // 16KiB

//         ^UP
//         |
// LEFT <-   -> RIGHT
//         |
//         vDOWN
pub mod navi {
    pub type Direction = (i16, i16);
    pub const SITU: (i16, i16) = (0, 0);
    pub const UP: (i16, i16) = (0, 1);
    pub const DOWN: (i16, i16) = (0, -1);
    pub const LEFT: (i16, i16) = (-1, 0);
    pub const RIGHT: (i16, i16) = (1, 0);
}

/// y
/// ^ 0,1,2
/// | 3,4,5,
/// | 6,7,8
/// |------> x
pub const INDEXED_NAVI: [(i16, i16); 9] = [
    (-1, 1),
    (0, 1),
    (1, 1),
    (-1, 0),
    (0, 0),
    (1, 0),
    (-1, -1),
    (0, -1),
    (1, -1),
];

pub const ALLOWED_NAVI: [(i16, i16); 4] = [(-1, 0), (1, 0), (0, -1), (0, 1)];

#[derive(
    Debug, Default, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash,
)]
pub struct NodeID(i16, i16);
impl NodeID {
    pub const UP_LEFT: Self = NodeID(i16::MIN, i16::MAX);
    pub const UP_MIDDLE: Self = NodeID(0, i16::MAX);
    pub const UP_RIGHT: Self = NodeID(i16::MAX, i16::MAX);
    pub const LEFT_MIDDLE: Self = NodeID(i16::MIN, 0);
    pub const SITU: Self = NodeID(0, 0);
    pub const ORIGIN: Self = NodeID(0, 0);
    pub const RIGHT_MIDDLE: Self = NodeID(i16::MAX, 0);
    pub const DOWN_LEFT: Self = NodeID(i16::MIN, i16::MIN);
    pub const DOWN_MIDDLE: Self = NodeID(0, i16::MIN);
    pub const DOWN_RIGHT: Self = NodeID(i16::MAX, i16::MIN);

    pub fn new((x, y): (i16, i16)) -> Self {
        NodeID(x, y)
    }

    pub fn from_i32(value: i32) -> Self {
        FlatID::from_i32(value).into_node_id()
    }

    pub fn from_xy(x: i16, y: i16) -> Self {
        Self(x, y)
    }

    pub fn into_tuple(self) -> (i16, i16) {
        self.into()
    }

    pub fn into_i32(self) -> i32 {
        self.into_flat().0
    }

    pub fn into_flat(self) -> FlatID {
        self.into()
    }

    pub fn navi_to(&mut self, to: navi::Direction) -> NodeID {
        self.0 = self.0.wrapping_add(to.0);
        self.1 = self.1.wrapping_add(to.1);
        self.clone()
    }
}

impl From<(i16, i16)> for NodeID {
    fn from(value: (i16, i16)) -> Self {
        NodeID(value.0, value.1)
    }
}
impl Into<(i16, i16)> for NodeID {
    fn into(self) -> (i16, i16) {
        (self.0, self.1)
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct NodeData(Vec<i8>);
impl NodeData {
    pub fn random() -> Self {
        let mut rng = SmallRng::from_entropy();
        let length = rng.gen_range(0..NODE_MAX_SIZE);
        let mut rnt = vec![0u8; length];
        rng.fill_bytes(&mut rnt);
        let rnt = rnt
            .into_iter()
            .map(|cell| i8::from_be_bytes([cell]))
            .collect();
        Self(rnt)
    }
    pub fn get(&self, index: usize) -> Option<i8> {
        self.0.get(index).map(|x| *x)
    }
    pub fn set(&mut self, index: usize, value: i8) -> Option<()> {
        self.0.get_mut(index).map(|cell| *cell = value)
    }
    pub fn to_bytes(self) -> Vec<u8> {
        self.0
            .into_iter()
            .map(|cell| cell.to_be_bytes()[0])
            .collect()
    }
    pub fn from_bytes(value: impl AsRef<[u8]>) -> Self {
        value.into()
    }
}

/// Default big endian encoding
impl Into<Vec<u8>> for NodeData {
    fn into(self) -> Vec<u8> {
        self.to_bytes()
    }
}

impl<T: AsRef<[u8]>> From<T> for NodeData {
    fn from(value: T) -> Self {
        Self(
            value
                .as_ref()
                .iter()
                .map(|b| i8::from_be_bytes([*b]))
                .collect(),
        )
    }
}

impl Deref for NodeData {
    type Target = Vec<i8>;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Node {
    pub id: NodeID,
    pub data: NodeData,
}
impl Node {
    pub fn new((x, y): (i16, i16), data: impl AsRef<[u8]>) -> Self {
        Node {
            id: NodeID(x, y),
            data: NodeData::from(data),
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct FlatID(
    #[serde(
        serialize_with = "crate::grid::ser_flat",
        deserialize_with = "crate::grid::de_flat"
    )]
    i32,
);
impl FlatID {
    pub fn into_node_id(self) -> NodeID {
        self.into()
    }

    pub fn into_tuple(self) -> (i16, i16) {
        self.into_node_id().into_tuple()
    }

    pub fn from_i32(value: i32) -> Self {
        Self::from(value)
    }

    pub fn from_xy(x: i16, y: i16) -> Self {
        NodeID::from_xy(x, y).into()
    }
}

impl From<i32> for FlatID {
    fn from(value: i32) -> Self {
        Self(value)
    }
}
impl Into<i32> for FlatID {
    fn into(self) -> i32 {
        self.0
    }
}
impl From<NodeID> for FlatID {
    fn from(value: NodeID) -> Self {
        let [x1, x2] = value.0.to_be_bytes();
        let [y1, y2] = value.1.to_be_bytes();
        let f = i32::from_be_bytes([x1, x2, y1, y2]);
        FlatID(f)
    }
}
impl Into<NodeID> for FlatID {
    fn into(self) -> NodeID {
        let [x1, x2, y1, y2] = self.0.to_be_bytes();
        NodeID::from_xy(i16::from_be_bytes([x1, x2]), i16::from_be_bytes([y1, y2]))
    }
}

pub fn ser_flat<S>(id: &i32, serializer: S) -> Result<S::Ok, S::Error>
where
    S: Serializer,
{
    let (x, y) = FlatID::from(*id).into_tuple();
    let mut tuple = serializer.serialize_tuple_struct("FlatID", 4)?;
    tuple.serialize_field(&x)?;
    tuple.serialize_field(&y)?;
    tuple.end()
}

pub fn de_flat<'de, D>(deserializer: D) -> Result<i32, D::Error>
where
    D: serde::Deserializer<'de>,
{
    #[derive(Debug)]
    struct FlatIDVisitor;

    impl<'de> de::Visitor<'de> for FlatIDVisitor {
        type Value = i32;

        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("a tuple of two i32 values")
        }

        fn visit_seq<A>(self, mut seq: A) -> Result<i32, A::Error>
        where
            A: de::SeqAccess<'de>,
        {
            let x = seq
                .next_element()?
                .ok_or_else(|| de::Error::invalid_length(0, &self))?;
            let y = seq
                .next_element()?
                .ok_or_else(|| de::Error::invalid_length(1, &self))?;

            if seq.next_element::<()>()?.is_some() {
                return Err(de::Error::invalid_length(2, &self));
            }

            Ok(FlatID::from_xy(x, y).into())
        }
    }

    deserializer.deserialize_tuple_struct("FlatID", 2, FlatIDVisitor)
}