#[cfg(feature = "prettytable")]
#[macro_use] extern crate prettytable;
#[cfg(feature = "prettytable")]
use prettytable::{Table, Row, Cell};
use std::fmt::Debug;
#[derive(Copy, Clone, Debug)]
pub struct GridPt {
pub row: usize,
pub col: usize
}
impl GridPt {
pub fn new(row: usize, col: usize) -> Self {
Self { row, col }
}
pub fn component_dist(pt1: GridPt, pt2: GridPt) -> (usize, usize) {
let rows = if pt1.row > pt2.row { pt1.row - pt2.row }
else { pt2.row - pt1.row };
let cols = if pt1.col > pt2.col { pt1.col - pt2.col }
else { pt2.col - pt1.col };
(rows, cols)
}
pub fn l1_dist(pt1: GridPt, pt2: GridPt) -> usize {
let (rows, cols) = Self::component_dist(pt1, pt2);
rows + cols
}
pub fn l2_dist(pt1: GridPt, pt2: GridPt) -> usize {
let (rows, cols) = Self::component_dist(pt1, pt2);
std::cmp::max(rows, cols)
}
}
#[derive(Debug)]
pub struct Grid<T> {
pub rows: usize,
pub cols: usize,
pub cells: Vec<Vec<T>>,
}
impl<T> Grid<T>
where T: Debug+Clone
{
pub fn new(rows: usize, cols: usize, default: T) -> Self {
Self {
rows,
cols,
cells: vec![vec![default; cols]; rows],
}
}
}
impl<T> Grid<T>
where T: Debug
{
pub fn new_from(data: Vec<Vec<T>>) -> Self {
let rows = data.len();
let cols = data[0].len();
Self {
rows,
cols,
cells: data,
}
}
pub fn iter(&self) -> impl Iterator<Item=&T> {
self.cells.iter().flat_map(|row| row.iter())
}
pub fn rows(&self) -> impl Iterator<Item=&Vec<T>> {
self.cells.iter()
}
pub fn cols<'a>(&'a self) -> impl Iterator<Item=impl Iterator<Item=&'a T>> {
(0..self.cols)
.map(move |col_idx| self.cells.iter().map(move |row| &row[col_idx]))
}
pub fn get(&self, row_index: usize, col_index: usize) -> Option<&T> {
self.cells.get(row_index).and_then(|r| r.get(col_index))
}
pub fn eight_neighbors<'a>(&'a self, row_origin: usize, col_origin: usize)
-> impl Iterator<Item=&'a T>
{
(-1..2 as i32)
.flat_map(|row| std::iter::repeat(row).zip(-1..2 as i32))
.filter(|(row, col)| !(*row == 0 && *col == 0))
.filter_map(move |(row, col)|
self.cells
.get((row_origin as i32 + row) as usize)
.and_then(|r| r.get((col_origin as i32 + col) as usize)))
}
pub fn l1_dist(&self, pt1: GridPt, pt2: GridPt) -> usize {
GridPt::l1_dist(pt1, pt2)
}
pub fn right_from(&self, row: usize, col: usize) -> impl Iterator<Item=&T> {
self.cells[row][col+1..].iter()
}
pub fn left_from(&self, row: usize, col: usize) -> impl Iterator<Item=&T> {
self.cells[row][..col].iter().rev()
}
pub fn up_from(&self, row: usize, col: usize) -> impl Iterator<Item=&T> {
self.cells[..row].iter()
.map(move |row_vec| &row_vec[col])
.rev()
}
pub fn down_from(&self, row: usize, col: usize) -> impl Iterator<Item=&T> {
self.cells[row+1..].iter()
.map(move |row_vec| &row_vec[col])
}
}
#[cfg(feature = "prettytable")]
impl<T> Grid<T>
where T: Clone+Debug+ToString
{
pub fn pretty_table(&self) -> Table {
let mut table = Table::new();
for row in self.rows() {
table.add_row(Row::new(
row.iter().map(|cell| Cell::new(&cell.to_string())).collect()));
}
table
}
}
#[cfg(test)]
mod tests {
#[test]
fn gridpt_component_dist() {
let pt1 = super::GridPt::new(4, 5);
let pt2 = super::GridPt::new(7, 7);
assert_eq!((3, 2), super::GridPt::component_dist(pt1, pt2));
assert_eq!((3, 2), super::GridPt::component_dist(pt2, pt1));
}
#[test]
fn gridpt_l1_dist() {
let pt1 = super::GridPt::new(4, 5);
let pt2 = super::GridPt::new(7, 7);
assert_eq!(5, super::GridPt::l1_dist(pt1, pt2));
assert_eq!(5, super::GridPt::l1_dist(pt2, pt1));
}
#[test]
fn grid_new() {
let rows = 8;
let cols = 10;
let grid = super::Grid::<Option<usize>>::new(rows, cols, None);
assert_eq!(grid.rows, rows);
assert_eq!(grid.cols, cols);
assert_eq!(grid.cells.len(), rows);
assert_eq!(grid.cells[0].len(), cols);
}
#[test]
fn grid_new_from() {
let data = vec![
vec![1, 2, 3, 4],
vec![5, 6, 7, 8],
vec![9, 10, 11, 12],
];
let grid = super::Grid::<usize>::new_from(data);
assert_eq!(grid.rows, 3);
assert_eq!(grid.cols, 4);
assert_eq!(grid.cells.len(), 3);
assert_eq!(grid.cells[0].len(), 4);
}
#[test]
fn grid_iter() {
let rows = 4;
let cols = 5;
let grid = super::Grid::<usize>::new(rows, cols, 1);
assert_eq!(grid.iter().sum::<usize>(), rows*cols);
}
#[test]
fn grid_rows() {
let data = vec![
vec![1, 2, 3, 4],
vec![5, 6, 7, 8],
vec![9, 10, 11, 12],
];
let grid = super::Grid::<usize>::new_from(data);
let mut iter = grid.rows();
assert_eq!(Some(&vec![1,2,3,4]), iter.next());
assert_eq!(Some(&vec![5,6,7,8]), iter.next());
assert_eq!(Some(&vec![9,10,11,12]), iter.next());
assert_eq!(None, iter.next());
}
#[test]
fn grid_cols() {
let data = vec![
vec![1, 2, 3, 4],
vec![5, 6, 7, 8],
vec![9, 10, 11, 12],
];
let grid = super::Grid::<usize>::new_from(data);
let mut iter = grid.cols();
assert_eq!(vec![&1, &5, &9], iter.next().unwrap().collect::<Vec<&usize>>());
assert_eq!(vec![&2, &6, &10], iter.next().unwrap().collect::<Vec<&usize>>());
assert_eq!(vec![&3, &7, &11], iter.next().unwrap().collect::<Vec<&usize>>());
assert_eq!(vec![&4, &8, &12], iter.next().unwrap().collect::<Vec<&usize>>());
assert!(iter.next().is_none());
}
#[test]
fn grid_eight_neighbors() {
let rows = 4;
let cols = 5;
let grid = super::Grid::<usize>::new(rows, cols, 1);
assert_eq!(grid.eight_neighbors(0, 0).sum::<usize>(), 3);
assert_eq!(grid.eight_neighbors(1, 1).sum::<usize>(), 8);
assert_eq!(grid.eight_neighbors(3, 4).sum::<usize>(), 3);
assert_eq!(grid.eight_neighbors(10, 10).sum::<usize>(), 0);
assert_eq!(grid.eight_neighbors(0, 1).sum::<usize>(), 5);
}
#[test]
fn grid_right_from() {
let data = vec![
vec![1, 2, 3, 4],
vec![5, 6, 7, 8],
vec![9, 10, 11, 12],
];
let grid = super::Grid::<usize>::new_from(data);
let mut iter = grid.right_from(2, 1);
assert_eq!(Some(&11), iter.next());
assert_eq!(Some(&12), iter.next());
assert!(iter.next().is_none());
}
#[test]
fn grid_left_from() {
let data = vec![
vec![1, 2, 3, 4],
vec![5, 6, 7, 8],
vec![9, 10, 11, 12],
];
let grid = super::Grid::<usize>::new_from(data);
let mut iter = grid.left_from(1, 2);
assert_eq!(Some(&6), iter.next());
assert_eq!(Some(&5), iter.next());
assert!(iter.next().is_none());
}
#[test]
fn grid_up_from() {
let data = vec![
vec![1, 2, 3, 4],
vec![5, 6, 7, 8],
vec![9, 10, 11, 12],
];
let grid = super::Grid::<usize>::new_from(data);
let mut iter = grid.up_from(2, 1);
assert_eq!(Some(&6), iter.next());
assert_eq!(Some(&2), iter.next());
assert!(iter.next().is_none());
}
#[test]
fn grid_down_from() {
let data = vec![
vec![1, 2, 3, 4],
vec![5, 6, 7, 8],
vec![9, 10, 11, 12],
];
let grid = super::Grid::<usize>::new_from(data);
let mut iter = grid.down_from(0, 2);
assert_eq!(Some(&7), iter.next());
assert_eq!(Some(&11), iter.next());
assert!(iter.next().is_none());
}
}