#![no_std]
use core::iter::{Skip, StepBy, Take, repeat};
#[derive(Copy, Debug)]
pub struct GridIter<I: Iterator<Item = T>, T> {
inner: I,
columns: usize,
rows: Option<usize>,
}
impl<I: Iterator<Item = T> + Clone, T> Clone for GridIter<I, T> {
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
columns: self.columns,
rows: self.rows,
}
}
}
impl<I: Iterator<Item = T> + Clone, T: core::fmt::Display> core::fmt::Display for GridIter<I, T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.clone().iter_rows().for_each(|col| {
col.for_each(|ch| write!(f, "{}\t", ch).unwrap());
writeln!(f).unwrap();
});
Ok(())
}
}
pub trait IntoGridIter<I: Iterator<Item = T>, T> {
fn into_grid_iter(self, columns: usize) -> GridIter<I, T>;
}
impl<I: Iterator<Item = T>, T> IntoGridIter<I, T> for I {
fn into_grid_iter(self, columns: usize) -> GridIter<I, T> {
GridIter {
inner: self,
columns,
rows: None,
}
}
}
pub type Get<T> = Take<Skip<T>>;
pub type RowIter<T> = Take<Skip<T>>;
pub type ColIter<T> = StepBy<Skip<T>>;
pub type DiagBwdIter<T> = Take<StepBy<Skip<T>>>;
pub type DiagFwdIter<T> = Take<StepBy<Skip<T>>>;
impl<I: Iterator<Item = T>, T> GridIter<I, T> {
pub fn iter_col(self, column_index: usize) -> ColIter<I> {
assert!(column_index < self.columns);
self.inner.skip(column_index).step_by(self.columns)
}
pub fn iter_row(self, row_index: usize) -> RowIter<I> {
self.inner.skip(row_index * self.columns).take(self.columns)
}
pub fn get(self, col_index: usize, row_index: usize) -> Option<<I as IntoIterator>::Item> {
self.inner
.skip(grid_index_to_flat(self.columns, col_index, row_index))
.take(1)
.next()
}
pub fn get_kernel(
self,
column_index: usize,
row_index: usize,
) -> Option<[<I as IntoIterator>::Item; 9]> {
if column_index == 0 || column_index == self.columns - 1 || row_index == 0 {
None
} else {
let mut iter = self.inner.skip(grid_index_to_flat(
self.columns,
column_index - 1,
row_index - 1,
));
Some([
iter.next()?,
iter.next()?,
iter.next()?,
{
(0..self.columns - 3).for_each(|_| {
iter.next();
});
iter.next()?
},
iter.next()?,
iter.next()?,
{
(0..self.columns - 3).for_each(|_| {
iter.next();
});
iter.next()?
},
iter.next()?,
iter.next()?,
])
}
}
pub fn position<P: FnMut(I::Item) -> bool>(mut self, pred: P) -> Option<(usize, usize)> {
self.inner
.position(pred)
.map(|flat| flat_index_to_grid(self.columns, flat))
}
pub fn iter_diag_fwd(self, column_index: usize, row_index: usize) -> DiagFwdIter<I> {
let col_max = self.columns - 1;
let (skip, take) = if column_index + row_index > self.columns - 1 {
(
grid_index_to_flat(self.columns, col_max, row_index - (col_max - column_index)),
self.columns,
)
} else {
(
grid_index_to_flat(self.columns, row_index + column_index, 0),
row_index + column_index + 1,
)
};
self.inner.skip(skip).step_by(col_max).take(take)
}
pub fn iter_diag_bwd(self, column_index: usize, row_index: usize) -> DiagBwdIter<I> {
let diff = column_index.abs_diff(row_index);
let (skip, take) = if column_index > row_index {
(
grid_index_to_flat(self.columns, diff, 0),
self.columns - diff,
)
} else {
(grid_index_to_flat(self.columns, 0, diff), self.columns)
};
self.inner.skip(skip).step_by(self.columns + 1).take(take)
}
}
impl<I: Iterator<Item = T> + Clone, T> GridIter<I, T> {
fn calc_rows(&mut self) -> usize {
if let Some(rows) = self.rows {
rows
} else {
assert!(self.columns != 0);
let rows = self.clone().inner.count().div_ceil(self.columns);
self.rows = Some(rows);
rows
}
}
pub fn iter_rows(mut self) -> impl Iterator<Item = RowIter<I>> {
let rows = self.calc_rows();
repeat(self)
.enumerate()
.take(rows)
.map(|(r, s)| s.iter_row(r))
}
pub fn iter_cols(self) -> impl Iterator<Item = ColIter<I>> {
let columns = self.columns;
repeat(self)
.enumerate()
.take(columns)
.map(|(c, s)| s.iter_col(c))
}
pub fn iter_diags_bwd(mut self) -> impl Iterator<Item = DiagBwdIter<I>> {
let rows = self.calc_rows();
(0..self.columns)
.rev()
.zip(repeat(self.clone()))
.map(|(c, s)| s.iter_diag_bwd(c, 0))
.chain(
(1..rows)
.zip(repeat(self))
.map(|(r, s)| s.iter_diag_bwd(0, r)),
)
}
pub fn iter_diags_fwd(mut self) -> impl Iterator<Item = DiagFwdIter<I>> {
let rows = self.calc_rows();
let col_max = self.columns - 1;
(0..self.columns)
.zip(repeat(self.clone()))
.map(|(c, s)| s.iter_diag_fwd(c, 0))
.chain(
(1..rows)
.zip(repeat(self))
.map(move |(r, s)| s.iter_diag_fwd(col_max, r)),
)
}
pub fn iter_kernels(mut self) -> impl Iterator<Item = [T; 9]> {
let row_max = self.calc_rows() - 1;
let col_max = self.columns - 1;
repeat(self).zip(1..row_max).flat_map(move |(iter, r)| {
(1..col_max).filter_map(move |c| iter.clone().get_kernel(c, r))
})
}
}
fn flat_index_to_grid(grid_columns: usize, flat_index: usize) -> (usize, usize) {
assert!(grid_columns != 0, "Columns set to 0! Cant calculate index");
(flat_index % grid_columns, flat_index / grid_columns)
}
fn grid_index_to_flat(grid_columns: usize, column_index: usize, row_index: usize) -> usize {
grid_columns * row_index + column_index
}
#[cfg(test)]
mod tests {
use crate::{flat_index_to_grid, grid_index_to_flat};
#[test]
fn test_index() {
let (grid_col, flat_index) = (5123, 55);
let (col, row) = flat_index_to_grid(grid_col, flat_index);
let flat_index2 = grid_index_to_flat(grid_col, col, row);
assert_eq!(flat_index, flat_index2);
}
}