add neighbour and cardinal iterators to grid
This commit is contained in:
@@ -7,6 +7,21 @@ use std::{
|
||||
str::FromStr,
|
||||
};
|
||||
|
||||
/// NW, N, NE, W, E, SW, S, SE
|
||||
const ADJACENT_OFFSETS: [&(i64, i64); 8] = [
|
||||
&(-1, -1),
|
||||
&(0, -1),
|
||||
&(1, -1),
|
||||
&(-1, 0),
|
||||
&(1, 0),
|
||||
&(-1, 1),
|
||||
&(0, 1),
|
||||
&(1, 1),
|
||||
];
|
||||
|
||||
/// NESW
|
||||
const CARDINAL_OFFSETS: [&(i64, i64); 4] = [&(0, -1), &(-1, 0), &(1, 0), &(0, 1)];
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||
pub struct Coord2d {
|
||||
pub x: i64,
|
||||
@@ -29,7 +44,10 @@ impl<T: AsCoord2d> Sub<T> for &Coord2d {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AsCoord2d> Add<T> for &Coord2d {
|
||||
impl<T: AsCoord2d> Add<T> for &Coord2d
|
||||
where
|
||||
T: Copy,
|
||||
{
|
||||
type Output = Coord2d;
|
||||
fn add(self, rhs: T) -> Self::Output {
|
||||
Coord2d {
|
||||
@@ -39,7 +57,7 @@ impl<T: AsCoord2d> Add<T> for &Coord2d {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AsCoord2d> Add<&T> for Coord2d {
|
||||
impl<T: AsCoord2d + ?Sized> Add<&T> for Coord2d {
|
||||
type Output = Coord2d;
|
||||
fn add(self, rhs: &T) -> Self::Output {
|
||||
Coord2d {
|
||||
@@ -150,7 +168,7 @@ impl<'a, T: Clone + Eq + PartialEq + Debug> Iterator for CoordIter<'a, T> {
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.pos < self.grid.data.len() {
|
||||
self.pos += 1;
|
||||
self.grid.coord(self.pos as i64 - 1).into()
|
||||
self.grid.coord(self.pos as i64 - 1)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@@ -163,6 +181,7 @@ pub struct ItemIter<'a, T> {
|
||||
grid: &'a Grid<T>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct Item<'a, T> {
|
||||
pub pos: Coord2d,
|
||||
pub value: &'a T,
|
||||
@@ -216,6 +235,31 @@ impl<'a, T: Clone + Eq + PartialEq + Debug> Iterator for GridColIter<'a, T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct OffsetsIter<'a, T> {
|
||||
grid: &'a Grid<T>,
|
||||
origin: Coord2d,
|
||||
cur: usize,
|
||||
offsets: &'a [&'a (i64, i64)],
|
||||
}
|
||||
|
||||
impl<'a, T: Clone + Eq + PartialEq + Debug> Iterator for OffsetsIter<'a, T> {
|
||||
type Item = Item<'a, T>;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
while self.cur < self.offsets.len() {
|
||||
let pos = self.origin + self.offsets[self.cur];
|
||||
self.cur += 1;
|
||||
if let Some(value) = self.grid.get(&pos) {
|
||||
return Some(Item { pos, value });
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
(0, Some(self.offsets.len() - self.cur))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Eq, PartialEq, Debug)]
|
||||
pub struct Grid<T> {
|
||||
pub data: Vec<T>,
|
||||
@@ -266,7 +310,7 @@ impl<T: Clone + Eq + PartialEq + Debug> Grid<T> {
|
||||
if c.y() < 0 || c.y() as usize >= self.height() {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
true
|
||||
}
|
||||
fn valid_pos<C: AsCoord2d>(&self, c: &C) -> Option<usize> {
|
||||
if c.x() < 0 || c.x() >= self.width {
|
||||
@@ -331,11 +375,7 @@ impl<T: Clone + Eq + PartialEq + Debug> Grid<T> {
|
||||
}
|
||||
|
||||
pub fn col(&self, x: i64) -> Option<Vec<&T>> {
|
||||
if let Some(iter) = self.col_iter(x) {
|
||||
Some(iter.collect())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
self.col_iter(x).map(|iter| iter.collect())
|
||||
}
|
||||
|
||||
pub fn col_iter<'a>(&'a self, x: i64) -> Option<GridColIter<'a, T>> {
|
||||
@@ -390,27 +430,37 @@ impl<T: Clone + Eq + PartialEq + Debug> Grid<T> {
|
||||
}
|
||||
|
||||
/// Return the count of neighbours (8 directions) matching predicate p
|
||||
pub fn neighbours_count<C: AsCoord2d, P>(&self, c: C, mut p: P) -> usize
|
||||
pub fn neighbours_count<C: AsCoord2d + Copy, P>(&self, c: &C, mut p: P) -> usize
|
||||
where
|
||||
P: FnMut(&T) -> bool,
|
||||
{
|
||||
const DIRECTIONS: [(i64, i64); 8] = [
|
||||
(-1, -1),
|
||||
(0, -1),
|
||||
(1, -1),
|
||||
(-1, 0),
|
||||
(1, 0),
|
||||
(1, 1),
|
||||
(0, 1),
|
||||
(-1, 1),
|
||||
];
|
||||
DIRECTIONS
|
||||
ADJACENT_OFFSETS
|
||||
.iter()
|
||||
.map(|d| (c.x() + d.0, c.y() + d.1))
|
||||
.filter(|c| self.get(c).is_some_and(|x| p(x)))
|
||||
.map(|d| c.to_coord() + *d)
|
||||
.filter(|c| self.get(c).is_some_and(&mut p))
|
||||
.count()
|
||||
}
|
||||
|
||||
/// Return an iterator over the 8 neighbours of c. The iterator skips neighbouring positions outside of the grid.
|
||||
pub fn neighbours_iter<C: AsCoord2d + Copy>(&self, c: &C) -> OffsetsIter<T> {
|
||||
OffsetsIter {
|
||||
grid: self,
|
||||
origin: c.to_coord(),
|
||||
cur: 0,
|
||||
offsets: &ADJACENT_OFFSETS,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return an iterator over the 4 cardinal neighbours of c. The iterator skips neighbouring positions outside of the grid.
|
||||
pub fn cardinal_iter<C: AsCoord2d + Copy>(&self, c: &C) -> OffsetsIter<T> {
|
||||
OffsetsIter {
|
||||
grid: self,
|
||||
origin: c.to_coord(),
|
||||
cur: 0,
|
||||
offsets: &CARDINAL_OFFSETS,
|
||||
}
|
||||
}
|
||||
|
||||
// fn window_compare_impl<const REV: bool>(&self, needle: &[T]) -> Vec<(i64, i64)> {
|
||||
// if (self.width as usize) < needle.len() {
|
||||
// return Vec::new();
|
||||
@@ -582,6 +632,58 @@ FBCG";
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn neighbours_iter() {
|
||||
let grid = unchecked_load();
|
||||
assert_eq!(
|
||||
grid.neighbours_iter(&(0, 1)).collect::<Vec<_>>(),
|
||||
[
|
||||
Item {
|
||||
pos: Coord2d { x: 0, y: 0 },
|
||||
value: &b'A'
|
||||
},
|
||||
Item {
|
||||
pos: Coord2d { x: 1, y: 0 },
|
||||
value: &b'B'
|
||||
},
|
||||
Item {
|
||||
pos: Coord2d { x: 1, y: 1 },
|
||||
value: &b'F'
|
||||
},
|
||||
Item {
|
||||
pos: Coord2d { x: 0, y: 2 },
|
||||
value: &b'I'
|
||||
},
|
||||
Item {
|
||||
pos: Coord2d { x: 1, y: 2 },
|
||||
value: &b'J'
|
||||
},
|
||||
]
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cardinal_iter() {
|
||||
let grid = unchecked_load();
|
||||
assert_eq!(
|
||||
grid.cardinal_iter(&(0, 1)).collect::<Vec<_>>(),
|
||||
[
|
||||
Item {
|
||||
pos: Coord2d { x: 0, y: 0 },
|
||||
value: &b'A'
|
||||
},
|
||||
Item {
|
||||
pos: Coord2d { x: 1, y: 1 },
|
||||
value: &b'F'
|
||||
},
|
||||
Item {
|
||||
pos: Coord2d { x: 0, y: 2 },
|
||||
value: &b'I'
|
||||
}
|
||||
]
|
||||
)
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// fn window_compare() {
|
||||
// let grid = unchecked_load();
|
||||
|
||||
Reference in New Issue
Block a user