use std::ops::{Add, Mul, Sub};
pub type Coord = (usize, usize);
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Offset {
pub col_offset: i32,
pub row_offset: i32,
}
impl Add for Offset {
type Output = Self;
fn add(self, other: Self) -> Self::Output {
Self {
col_offset: self.col_offset + other.col_offset,
row_offset: self.row_offset + other.row_offset,
}
}
}
impl Sub for Offset {
type Output = Self;
fn sub(self, other: Self) -> Self::Output {
Self {
col_offset: self.col_offset - other.col_offset,
row_offset: self.row_offset - other.row_offset,
}
}
}
impl Mul<i32> for Offset {
type Output = Self;
fn mul(self, scalar: i32) -> Self::Output {
Self {
col_offset: scalar * self.col_offset,
row_offset: scalar * self.row_offset,
}
}
}
impl Mul<Offset> for i32 {
type Output = Offset;
fn mul(self, vec: Offset) -> Self::Output {
vec * self
}
}
impl From<(i32, i32)> for Offset {
fn from((c, r): (i32, i32)) -> Self {
Self {
col_offset: c,
row_offset: r,
}
}
}
impl Offset {
pub const NORTH: Offset = Offset {
col_offset: 0,
row_offset: -1,
};
pub const EAST: Offset = Offset {
col_offset: 1,
row_offset: 0,
};
pub const SOUTH: Offset = Offset {
col_offset: 0,
row_offset: 1,
};
pub const WEST: Offset = Offset {
col_offset: -1,
row_offset: 0,
};
pub fn cardinal_sum(n: i32, e: i32, s: i32, w: i32) -> Self {
Offset::NORTH * n
+ Offset::EAST * e
+ Offset::SOUTH * s
+ Offset::WEST * w
}
pub fn rcoord(&self, (col, row): Coord) -> Option<Coord> {
let c = self.col_offset + (col as i32);
let r = self.row_offset + (row as i32);
if c >= 0 && r >= 0 {
Some((c as usize, r as usize))
} else {
None
}
}
}
#[derive(Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Grid<T> {
col_count: usize,
row_count: usize,
data: Vec<T>,
}
impl<T> Grid<T>
where
T: Copy,
{
pub fn new(col_count: usize, row_count: usize, default: T) -> Self
{
let capactiy = row_count * col_count;
Self {
col_count: col_count,
row_count: row_count,
data: vec![default; capactiy],
}
}
pub fn square(side_len: usize, default: T) -> Self
{
Self::new(side_len, side_len, default)
}
pub fn transpose(&self) -> Self {
if let Some(&val) = self.get((0, 0)) {
let mut new_grid = Self::new(self.row_count, self.col_count, val);
for src_row in 0..self.row_count {
for src_col in 0..self.col_count {
if let Some(&val) = self.get((src_col, src_row)) {
new_grid.set((src_row, src_col), val)
}
}
}
new_grid
} else {
Self {
col_count: 0,
row_count: 0,
data: Vec::new(),
}
}
}
}
impl<T> Grid<T> {
fn flat_index(&self, (col, row): Coord) -> usize {
col + self.col_count * row
}
pub fn col_count(&self) -> usize {
self.col_count
}
pub fn row_count(&self) -> usize {
self.row_count
}
pub fn get(&self, coord: Coord) -> Option<&T>
{
if self.contains(coord) {
let index = self.flat_index(coord);
Some(&self.data[index])
} else {
None
}
}
pub fn get_mut(&mut self, coord: Coord) -> Option<&mut T> {
if self.contains(coord) {
let index = self.flat_index(coord);
Some(&mut self.data[index])
} else {
None
}
}
pub fn rget(&self, anchor: Coord, vec: Offset) -> Option<&T> {
match vec.rcoord(anchor) {
Some(coord) => self.get(coord),
_ => None,
}
}
pub fn rget_mut(&mut self, anchor: Coord, vec: Offset) -> Option<&mut T> {
match vec.rcoord(anchor) {
Some(coord) => self.get_mut(coord),
_ => None,
}
}
pub fn set(&mut self, coord: Coord, new_val: T) {
match self.get_mut(coord) {
Some(val) => {
*val = new_val;
}
None => (),
}
}
pub fn rset(&mut self, coord: Coord, vec: Offset, new_val: T) {
if let Some(rcoord) = vec.rcoord(coord) {
self.set(rcoord, new_val);
}
}
pub fn contains(&self, (col, row): Coord) -> bool {
col < self.col_count && row < self.row_count
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_get_mut() {
let mut grid = Grid::new(1, 1, 'a');
let value = grid.get_mut((0, 0)).unwrap();
assert_eq!(&'a', value);
*value = 'b';
assert_eq!(&'b', value);
}
#[test]
fn test_get_set() {
let mut grid = Grid::new(5, 5, 'a');
assert_eq!(Some(&'a'), grid.get((2, 3)));
assert_eq!(Some(&'a'), grid.get((3, 3)));
assert_eq!(Some(&'a'), grid.get((3, 4)));
grid.set((2, 3), 'b');
grid.set((3, 3), 'c');
grid.set((3, 4), 'd');
assert_eq!(Some(&'b'), grid.get((2, 3)));
assert_eq!(Some(&'c'), grid.get((3, 3)));
assert_eq!(Some(&'d'), grid.get((3, 4)));
}
#[test]
fn test_rget() {
let mut grid = Grid::new(5, 5, 'a');
assert_eq!(Some(&'a'), grid.get((2, 3)));
grid.set((2, 3), 'b');
assert_eq!(Some(&'b'), grid.rget((2, 4), Offset::NORTH));
assert_eq!(Some(&mut 'b'), grid.rget_mut((2, 4), Offset::NORTH));
}
#[test]
fn test_rset() {
let mut grid = Grid::new(5, 5, 'a');
assert_eq!(Some(&'a'), grid.get((2, 3)));
grid.rset((1, 1), Offset::from((1, 2)), 'b');
assert_eq!(Some(&'b'), grid.rget((2, 4), Offset::NORTH));
assert_eq!(Some(&mut 'b'), grid.rget_mut((2, 4), Offset::NORTH));
}
#[test]
fn test_transpose() {
let src_col = 3;
let src_row = 4;
let mut grid = Grid::new(src_col, src_row, (0, 0));
for i in 0..src_col {
for j in 0..src_row {
grid.set((i, j), (i, j));
}
}
let tgrid = grid.transpose();
assert_eq!(4, tgrid.col_count());
assert_eq!(3, tgrid.row_count());
for i in 0..src_col {
for j in 0..src_row {
assert_eq!(tgrid.get((j, i)), grid.get((i, j)));
}
}
}
}