use std::{
fmt::{self, Display},
ops::{Index, IndexMut},
};
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum GridErr {
OutOfGrid,
RuleFailed,
SubgridOverflow,
}
impl fmt::Display for GridErr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
GridErr::OutOfGrid => write!(f, "value is out of the grid rows and cols"),
GridErr::RuleFailed => write!(f, "failed to meet the rule requirements"),
GridErr::SubgridOverflow => write!(
f,
"the subgrid cols or rows is greater than the parent grid"
),
}
}
}
#[derive(Debug, PartialEq, Eq)]
pub enum MoveDirection {
Right,
Left,
Up,
Down,
}
pub const MOVE_RIGHT: (i32, i32) = (0, 1);
pub const MOVE_LEFT: (i32, i32) = (0, -1);
pub const MOVE_UP: (i32, i32) = (-1, 0);
pub const MOVE_DOWN: (i32, i32) = (1, 0);
pub struct Grid<T: Copy + Clone> {
pub(crate) rows: i32,
pub(crate) cols: i32,
pub(crate) initial_value: T,
pub(crate) cells: Vec<T>,
}
impl<T: Copy + Clone> Grid<T> {
pub fn new(rows: i32, cols: i32, value: T) -> Self
where
T: Clone + Copy,
{
if (rows * cols) == 0 {
panic!("0x0 grid is forbidden")
}
let initial_value = value;
let cells = vec![value; (rows * cols) as usize];
Self {
rows,
cols,
initial_value,
cells,
}
}
pub fn new_from_vector(rows: i32, cols: i32, vec: Vec<T>) -> Self {
if vec.len() % 2 != 0 {
panic!("The vector isn't multiple of 2");
}
if vec.len() == 0 {
panic!("0x0 grid is forbidden")
}
if rows * cols != vec.len() as i32 {
panic!("cols and rows should be same vector size")
}
let initial_value = vec.first().unwrap().clone();
let cells = vec.to_vec();
Self {
rows,
cols,
initial_value,
cells,
}
}
pub fn stamp_subgrid(&mut self, index: (i32, i32), sub_grid: Grid<T>) -> Result<(), GridErr> {
self.check_grid_overflow(&sub_grid)?;
self.check_grid_bounds(index)?;
for sub_index in sub_grid.enumerate() {
if let Ok(subv) = sub_grid.get(sub_index) {
let dest = (index.0 + sub_index.0, index.1 + sub_index.1);
match self.set(dest, &subv) {
Ok(_) => (),
_ => (),
}
}
}
Ok(())
}
pub fn get_subgrid(&self, index: (i32, i32), rows: i32, cols: i32) -> Result<Grid<T>, GridErr> {
self.check_grid_bounds(index)?;
let mut sub_grid = Grid::new(rows, cols, self.initial_value);
self.check_grid_overflow(&sub_grid)?;
for sub_index in sub_grid.enumerate() {
let dest = (index.0 + sub_index.0, index.1 + sub_index.1);
if let Ok(subv) = self.get(dest) {
match sub_grid.set(sub_index, &subv) {
Ok(_) => (),
_ => (),
}
}
}
Ok(sub_grid)
}
pub fn stamp_subgrid_with_rules<R>(
&mut self,
index: (i32, i32),
sub_grid: Grid<T>,
rules: Vec<R>,
) -> Result<(), GridErr>
where
R: Fn((i32, i32), &T) -> Result<(), GridErr>,
{
self.check_grid_overflow(&sub_grid)?;
self.check_grid_bounds(index)?;
for sub_index in sub_grid.enumerate() {
if let Ok(subv) = sub_grid.get(sub_index) {
let dest = (index.0 + sub_index.0, index.1 + sub_index.1);
let destv = self.get(dest)?;
for rule in rules.iter() {
rule(dest, destv)?;
}
match self.set(dest, &subv) {
Ok(_) => (),
_ => (),
}
}
}
Ok(())
}
fn check_grid_overflow(&self, sub_grid: &Grid<T>) -> Result<(), GridErr> {
if sub_grid.cols > self.cols {
return Err(GridErr::SubgridOverflow);
}
if sub_grid.rows > self.rows {
return Err(GridErr::SubgridOverflow);
}
Ok(())
}
fn check_grid_bounds(&self, index: (i32, i32)) -> Result<(), GridErr> {
let (x, y) = index;
if x < 0 || x >= self.rows {
return Err(GridErr::OutOfGrid);
}
if y < 0 || y >= self.cols {
return Err(GridErr::OutOfGrid);
}
Ok(())
}
pub fn set(&mut self, index: (i32, i32), value: &T) -> Result<(), GridErr>
where
T: Copy,
{
let (x, y) = index;
self.check_grid_bounds(index)?;
if let Some(cell) = self.cells.get_mut((x * self.rows + y) as usize) {
*cell = *value;
}
Ok(())
}
pub fn set_with_rules<R>(
&mut self,
index: (i32, i32),
value: &T,
rules: Vec<R>,
) -> Result<(), GridErr>
where
R: Fn((i32, i32), &T) -> Result<(), GridErr>,
{
for rule in rules.iter() {
rule(index, value)?;
}
self.set(index, value)?;
Ok(())
}
pub fn get_mut(&mut self, index: (i32, i32)) -> Result<&mut T, GridErr> {
let (x, y) = index;
self.check_grid_bounds(index)?;
Ok(self.cells.get_mut((x * self.rows + y) as usize).unwrap())
}
pub fn get(&self, index: (i32, i32)) -> Result<&T, GridErr> {
let (x, y) = index;
self.check_grid_bounds(index)?;
Ok(self.cells.get((x * self.rows + y) as usize).unwrap())
}
pub fn mov(&mut self, index: (i32, i32), dest: (i32, i32)) -> Result<(), GridErr> {
self.check_grid_bounds(index)?;
self.check_grid_bounds(dest)?;
let prev = *self.get_mut(index).unwrap();
self.set(index, &self.initial_value.clone())?;
self.set(dest, &prev)?;
Ok(())
}
pub fn mov_with_rules<R>(
&mut self,
index: (i32, i32),
dest: (i32, i32),
rules: Vec<R>,
) -> Result<(), GridErr>
where
R: Fn((i32, i32), &T) -> Result<(), GridErr>,
{
self.check_grid_bounds(index)?;
self.check_grid_bounds(dest)?;
let prev = *self.get_mut(index).unwrap();
let destv = self.get(dest)?;
for rule in rules {
rule(dest, destv)?;
}
self.set(index, &self.initial_value.clone())?;
self.set(dest, &prev)?;
Ok(())
}
pub fn mov_to(&mut self, index: (i32, i32), direction: MoveDirection) -> Result<(), GridErr> {
let (x, y) = index;
self.check_grid_bounds(index)?;
let (xx, yy) = match direction {
MoveDirection::Up => MOVE_UP,
MoveDirection::Down => MOVE_DOWN,
MoveDirection::Left => MOVE_LEFT,
MoveDirection::Right => MOVE_RIGHT,
};
let dest = (x + xx, y + yy);
self.check_grid_bounds(dest)?;
let prev = *self.get_mut(index).unwrap();
self.set(index, &self.initial_value.clone())?;
self.set(dest, &prev)?;
Ok(())
}
pub fn mov_to_with_rules<R>(
&mut self,
index: (i32, i32),
direction: MoveDirection,
rules: Vec<R>,
) -> Result<(), GridErr>
where
R: Fn((i32, i32), &T) -> Result<(), GridErr>,
{
let (x, y) = index;
self.check_grid_bounds(index)?;
let (xx, yy) = match direction {
MoveDirection::Up => MOVE_UP,
MoveDirection::Down => MOVE_DOWN,
MoveDirection::Left => MOVE_LEFT,
MoveDirection::Right => MOVE_RIGHT,
};
let dest = (x + xx, y + yy);
self.check_grid_bounds(dest)?;
let destv = self.get(dest)?;
for rule in rules {
rule(dest, destv)?;
}
let prev = *self.get_mut(index).unwrap();
self.set(index, &self.initial_value.clone())?;
self.set(dest, &prev)?;
Ok(())
}
pub fn size(&self) -> usize {
self.cells.len()
}
pub fn rows(&self) -> i32 {
self.rows
}
pub fn cols(&self) -> i32 {
self.cols
}
pub fn enumerate(&self) -> Vec<(i32, i32)> {
let mut x = 0;
let mut y = 0;
self.cells
.iter()
.enumerate()
.map(|(idx, _)| {
if idx as i32 % self.rows() == 0 && idx > 1 {
x = 0;
y += 1;
}
let res = (x, y);
x += 1;
res
})
.collect::<Vec<_>>()
}
pub fn get_col(&self, col_idx: i32) -> Result<Vec<T>, GridErr> {
let mut vec_result: Vec<T> = vec![];
for idx in (0..self.cols).into_iter() {
let v = self.get((idx, col_idx))?;
vec_result.push(*v);
}
Ok(vec_result)
}
pub fn get_row(&self, row_idx: i32) -> Result<Vec<T>, GridErr> {
let mut vec_result: Vec<T> = vec![];
for idx in (0..self.rows).into_iter() {
let v = self.get((row_idx, idx))?;
vec_result.push(*v);
}
Ok(vec_result)
}
pub fn get_flatten_grid(&self) -> Vec<T> {
self.cells.clone()
}
pub fn fill_grid(&mut self, value: T) {
self.cells.fill(value);
}
#[allow(dead_code)]
pub(crate) fn debug(&self)
where
T: std::fmt::Display,
{
println!("{:?}", self)
}
pub fn fill_subgrid(
&mut self,
index: (i32, i32),
rows: i32,
cols: i32,
value: &T,
) -> Result<Grid<T>, GridErr> {
self.check_grid_bounds(index)?;
let sub_grid = Grid::new(rows, cols, self.initial_value);
self.check_grid_overflow(&sub_grid)?;
for sub_index in sub_grid.enumerate() {
let dest = (index.0 + sub_index.0, index.1 + sub_index.1);
match self.set(dest, value) {
Ok(_) => (),
_ => (),
}
}
Ok(sub_grid)
}
}
impl<'a, T: Copy + Clone> IntoIterator for &'a Grid<T> {
type Item = &'a T;
type IntoIter = std::slice::Iter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.cells.iter()
}
}
impl<'a, T: Copy + Clone> IntoIterator for &'a mut Grid<T> {
type Item = &'a mut T;
type IntoIter = std::slice::IterMut<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.cells.iter_mut()
}
}
impl<T: Copy + Clone> fmt::Display for Grid<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"Grid {{ rows: {}, cols: {}, cells: [...] }}",
self.rows, self.cols
)
}
}
impl<T: Copy + Clone + Display> fmt::Debug for Grid<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut cell_str = String::new();
let mut pos = (0, 0);
for (idx, cell) in self.cells.iter().enumerate() {
if idx as i32 % self.cols == 0 && idx > 0 {
pos.1 = 0;
pos.0 += 1;
cell_str += "\n";
}
cell_str.push_str(&format!("\t{:3} (x: {} y: {})", cell, pos.0, pos.1));
pos.1 += 1
}
write!(
f,
"Grid {{ rows: {}, cols: {}, cells: [\n{}\n] }}",
self.rows, self.cols, cell_str,
)
}
}
impl<T: Copy + Clone> Index<(i32, i32)> for Grid<T> {
type Output = T;
fn index(&self, index: (i32, i32)) -> &T {
self.get(index).unwrap()
}
}
impl<T: Copy + Clone> IndexMut<(i32, i32)> for Grid<T> {
fn index_mut(&mut self, index: (i32, i32)) -> &mut T {
self.get_mut(index).unwrap()
}
}
#[cfg(test)]
mod lib_test;