diff --git a/src/bin/minedmap/main.rs b/src/bin/minedmap/main.rs index 34aa985..8d3bbea 100644 --- a/src/bin/minedmap/main.rs +++ b/src/bin/minedmap/main.rs @@ -1,5 +1,6 @@ mod common; mod metadata_writer; +mod region_group; mod region_processor; mod tile_mipmapper; mod tile_renderer; diff --git a/src/bin/minedmap/region_group.rs b/src/bin/minedmap/region_group.rs new file mode 100644 index 0000000..0a12fd8 --- /dev/null +++ b/src/bin/minedmap/region_group.rs @@ -0,0 +1,80 @@ +use std::iter; + +use anyhow::Result; + +/// A generic array of 3x3 elements +/// +/// A RegionGroup is used to store information about a 3x3 neighbourhood of +/// regions. +/// +/// The center element is always populated, while the 8 adjacent elements may be None. +#[derive(Debug, Clone, Copy)] +pub struct RegionGroup { + center: T, + neighs: [Option; 8], +} + +impl RegionGroup { + pub fn new(f: F) -> Result + where + F: Fn(i8, i8) -> Result, + { + RegionGroup { + center: (0, 0), + neighs: [ + Some((-1, -1)), + Some((-1, 0)), + Some((-1, 1)), + Some((0, -1)), + Some((0, 1)), + Some((1, -1)), + Some((1, 0)), + Some((1, 1)), + ], + } + .try_map(|(x, z)| f(x, z)) + } + + pub fn center(&self) -> &T { + &self.center + } + + pub fn get(&self, x: i8, z: i8) -> Option<&T> { + match (x, z) { + (0, 0) => Some(&self.center), + (-1, -1) => self.neighs[0].as_ref(), + (-1, 0) => self.neighs[1].as_ref(), + (-1, 1) => self.neighs[2].as_ref(), + (0, -1) => self.neighs[3].as_ref(), + (0, 1) => self.neighs[4].as_ref(), + (1, -1) => self.neighs[5].as_ref(), + (1, 0) => self.neighs[6].as_ref(), + (1, 1) => self.neighs[7].as_ref(), + _ => panic!("index out of bounds"), + } + } + + pub fn map(self, mut f: F) -> RegionGroup + where + F: FnMut(T) -> U, + { + RegionGroup { + center: f(self.center), + neighs: self.neighs.map(|entry| entry.map(|v| f(v))), + } + } + + pub fn try_map(self, mut f: F) -> Result> + where + F: FnMut(T) -> Result, + { + let RegionGroup { center, neighs } = self; + let center = f(center)?; + let neighs = neighs.map(|entry| entry.map(|value| f(value).ok()).flatten()); + Ok(RegionGroup { center, neighs }) + } + + pub fn iter(&self) -> impl Iterator { + iter::once(&self.center).chain(self.neighs.iter().filter_map(Option::as_ref)) + } +}