summaryrefslogblamecommitdiffstats
path: root/src/grid.rs
blob: 63fab03956fac3f099c427c5fabd124baacb3b1b (plain) (tree)
1
2
3
4
5
6
7
8
9
10


                                                                      
                          
 


                                                                      

                          











                                                













                                                






                                              













                                                






                                              



























                                                



























                                                



























                                                



































                                                                      






                                               













                                                






                                               



























                                                



























                                                
                                                     
                                                                 


                  
                                                              


                                                            



                                               

 

                                                                      
 





                                                

                                                                         
 




                                                            

                                                              


                          


                                                                       
     
 
 
                                                           



                                                  



                               






                                                                            



                                               



                                     






                                                                            



                                                              



                                                        





































                                                                            

















                                                                 

 








                                                                        












                                                           



                                                                     
 







                                             

                                                                     
 













                                        

                                                                      
 





                                                

                                                                         
 




                                                            


                                                           



                                       
                              
                                                                           










                                           


     

                                                           
 














                                                       
                                                                    


                         

           





                                

                                                   





















































                                                            
#[derive(
    Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Debug, Default,
)]
pub struct Row(pub usize);

#[derive(
    Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Debug, Default,
)]
pub struct Col(pub usize);

impl Row {
    pub fn abs_diff(self, other: Self) -> Self {
        Self(self.0.abs_diff(other.0))
    }
}

impl Col {
    pub fn abs_diff(self, other: Self) -> Self {
        Self(self.0.abs_diff(other.0))
    }
}

impl std::ops::Add<usize> for Row {
    type Output = Self;
    fn add(self, other: usize) -> Self::Output {
        Self(self.0 + other)
    }
}

impl std::ops::Add<Row> for usize {
    type Output = Row;
    fn add(self, other: Row) -> Self::Output {
        Row(self + other.0)
    }
}

impl std::ops::Add<Row> for Row {
    type Output = Row;
    fn add(self, other: Row) -> Self::Output {
        Row(self.0 + other.0)
    }
}

impl std::ops::Add<usize> for Col {
    type Output = Self;
    fn add(self, other: usize) -> Self::Output {
        Self(self.0 + other)
    }
}

impl std::ops::Add<Col> for usize {
    type Output = Col;
    fn add(self, other: Col) -> Self::Output {
        Col(self + other.0)
    }
}

impl std::ops::Add<Col> for Col {
    type Output = Col;
    fn add(self, other: Col) -> Self::Output {
        Col(self.0 + other.0)
    }
}

impl std::ops::Sub<usize> for Row {
    type Output = Self;
    fn sub(self, other: usize) -> Self::Output {
        Self(self.0 - other)
    }
}

impl std::ops::Sub<Row> for usize {
    type Output = Row;
    fn sub(self, other: Row) -> Self::Output {
        Row(self - other.0)
    }
}

impl std::ops::Sub<usize> for Col {
    type Output = Self;
    fn sub(self, other: usize) -> Self::Output {
        Self(self.0 - other)
    }
}

impl std::ops::Sub<Col> for usize {
    type Output = Col;
    fn sub(self, other: Col) -> Self::Output {
        Col(self - other.0)
    }
}

impl std::ops::Mul<usize> for Row {
    type Output = Self;
    fn mul(self, other: usize) -> Self::Output {
        Self(self.0 * other)
    }
}

impl std::ops::Mul<Row> for usize {
    type Output = Row;
    fn mul(self, other: Row) -> Self::Output {
        Row(self * other.0)
    }
}

impl std::ops::Mul<usize> for Col {
    type Output = Self;
    fn mul(self, other: usize) -> Self::Output {
        Self(self.0 * other)
    }
}

impl std::ops::Mul<Col> for usize {
    type Output = Col;
    fn mul(self, other: Col) -> Self::Output {
        Col(self * other.0)
    }
}

impl std::ops::Rem<usize> for Row {
    type Output = Self;
    fn rem(self, other: usize) -> Self::Output {
        Self(self.0 % other)
    }
}

impl std::ops::Rem<Row> for usize {
    type Output = Row;
    fn rem(self, other: Row) -> Self::Output {
        Row(self % other.0)
    }
}

impl std::ops::Rem<usize> for Col {
    type Output = Self;
    fn rem(self, other: usize) -> Self::Output {
        Self(self.0 % other)
    }
}

impl std::ops::Rem<Col> for usize {
    type Output = Col;
    fn rem(self, other: Col) -> Self::Output {
        Col(self % other.0)
    }
}

#[derive(
    Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Debug, Default,
)]
pub struct IRow(pub isize);

#[derive(
    Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Debug, Default,
)]
pub struct ICol(pub isize);

impl IRow {
    pub fn abs_diff(self, other: Self) -> Row {
        Row(self.0.abs_diff(other.0))
    }
}

impl ICol {
    pub fn abs_diff(self, other: Self) -> Col {
        Col(self.0.abs_diff(other.0))
    }
}

impl std::ops::Add<isize> for IRow {
    type Output = Self;
    fn add(self, other: isize) -> Self::Output {
        Self(self.0 + other)
    }
}

impl std::ops::Add<IRow> for isize {
    type Output = IRow;
    fn add(self, other: IRow) -> Self::Output {
        IRow(self + other.0)
    }
}

impl std::ops::Add<IRow> for IRow {
    type Output = IRow;
    fn add(self, other: IRow) -> Self::Output {
        IRow(self.0 + other.0)
    }
}

impl std::ops::Add<isize> for ICol {
    type Output = Self;
    fn add(self, other: isize) -> Self::Output {
        Self(self.0 + other)
    }
}

impl std::ops::Add<ICol> for isize {
    type Output = ICol;
    fn add(self, other: ICol) -> Self::Output {
        ICol(self + other.0)
    }
}

impl std::ops::Add<ICol> for ICol {
    type Output = ICol;
    fn add(self, other: ICol) -> Self::Output {
        ICol(self.0 + other.0)
    }
}

impl std::ops::Sub<isize> for IRow {
    type Output = Self;
    fn sub(self, other: isize) -> Self::Output {
        Self(self.0 - other)
    }
}

impl std::ops::Sub<IRow> for isize {
    type Output = IRow;
    fn sub(self, other: IRow) -> Self::Output {
        IRow(self - other.0)
    }
}

impl std::ops::Sub<isize> for ICol {
    type Output = Self;
    fn sub(self, other: isize) -> Self::Output {
        Self(self.0 - other)
    }
}

impl std::ops::Sub<ICol> for isize {
    type Output = ICol;
    fn sub(self, other: ICol) -> Self::Output {
        ICol(self - other.0)
    }
}

impl std::ops::Mul<isize> for IRow {
    type Output = Self;
    fn mul(self, other: isize) -> Self::Output {
        Self(self.0 * other)
    }
}

impl std::ops::Mul<IRow> for isize {
    type Output = IRow;
    fn mul(self, other: IRow) -> Self::Output {
        IRow(self * other.0)
    }
}

impl std::ops::Mul<isize> for ICol {
    type Output = Self;
    fn mul(self, other: isize) -> Self::Output {
        Self(self.0 * other)
    }
}

impl std::ops::Mul<ICol> for isize {
    type Output = ICol;
    fn mul(self, other: ICol) -> Self::Output {
        ICol(self * other.0)
    }
}

#[derive(Default, Clone, Debug, Eq, PartialEq, Hash)]
pub struct GridRow<T: Clone + Eq + PartialEq + std::hash::Hash> {
    cells: Vec<T>,
}

impl<T: Clone + Eq + PartialEq + std::hash::Hash> GridRow<T> {
    pub fn iter(&self) -> impl Iterator<Item = &T> + Clone {
        self.cells.iter()
    }

    pub fn get(&self, col: Col) -> Option<&T> {
        self.cells.get(col.0)
    }
}

impl<T: Clone + Eq + PartialEq + std::hash::Hash> std::ops::Index<Col>
    for GridRow<T>
{
    type Output = T;
    fn index(&self, col: Col) -> &Self::Output {
        &self.cells[col.0]
    }
}

impl<T: Clone + Eq + PartialEq + std::hash::Hash> std::ops::IndexMut<Col>
    for GridRow<T>
{
    fn index_mut(&mut self, col: Col) -> &mut Self::Output {
        &mut self.cells[col.0]
    }
}

#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct Grid<T: Clone + Eq + PartialEq + std::hash::Hash> {
    rows: Vec<GridRow<T>>,
}

impl<T: Clone + Eq + PartialEq + std::hash::Hash> Default for Grid<T> {
    fn default() -> Self {
        Self { rows: vec![] }
    }
}

impl<T: Clone + Eq + PartialEq + std::hash::Hash> Grid<T> {
    pub fn unshift_rows(&mut self, count: usize) {
        self.rows = self.rows.split_off(count);
    }

    pub fn rows(&self) -> Row {
        Row(self.rows.len())
    }

    pub fn each_row(
        &self,
    ) -> impl Iterator<Item = Row> + DoubleEndedIterator + ExactSizeIterator
    {
        (0..self.rows().0).map(Row)
    }

    pub fn row_vec(&self, row: Row) -> Vec<T> {
        self.rows[row.0].cells.clone()
    }

    pub fn cols(&self) -> Col {
        Col(self.rows[0].cells.len())
    }

    pub fn each_col(
        &self,
    ) -> impl Iterator<Item = Col> + DoubleEndedIterator + ExactSizeIterator
    {
        (0..self.cols().0).map(Col)
    }

    pub fn col_vec(&self, col: Col) -> Vec<T> {
        self.rows.iter().map(|row| row[col].clone()).collect()
    }

    pub fn get(&self, row: Row) -> Option<&GridRow<T>> {
        self.rows.get(row.0)
    }

    pub fn cells(&self) -> impl Iterator<Item = &T> {
        self.rows.iter().flat_map(|row| row.cells.iter())
    }

    pub fn cells_mut(&mut self) -> impl Iterator<Item = &mut T> {
        self.rows.iter_mut().flat_map(|row| row.cells.iter_mut())
    }

    pub fn indexed_cells(&self) -> impl Iterator<Item = ((Row, Col), &T)> {
        self.rows.iter().enumerate().flat_map(|(i, row)| {
            row.cells
                .iter()
                .enumerate()
                .map(move |(j, cell)| ((Row(i), Col(j)), cell))
        })
    }

    pub fn indexed_cells_mut(
        &mut self,
    ) -> impl Iterator<Item = ((Row, Col), &mut T)> {
        self.rows.iter_mut().enumerate().flat_map(|(i, row)| {
            row.cells
                .iter_mut()
                .enumerate()
                .map(move |(j, cell)| ((Row(i), Col(j)), cell))
        })
    }

    pub fn adjacent(&self, row: Row, col: Col, diagonal: bool) -> Adjacent {
        Adjacent {
            row: row.0,
            col: col.0,
            rows: self.rows().0,
            cols: self.cols().0,
            diagonal,
            pos: 0,
        }
    }

    pub fn flood_fill(
        &mut self,
        row: Row,
        col: Col,
        fill: &T,
        diagonal: bool,
    ) {
        let mut todo = vec![(row, col)];
        while let Some((row, col)) = todo.pop() {
            self[row][col] = fill.clone();
            for (row, col) in self.adjacent(row, col, diagonal) {
                if self[row][col] != *fill {
                    todo.push((row, col));
                }
            }
        }
    }
}

impl<T: Default + Clone + Eq + PartialEq + std::hash::Hash> Grid<T> {
    pub fn grow(&mut self, rows: Row, cols: Col) {
        self.rows
            .resize_with(rows.0.max(self.rows.len()), GridRow::default);
        for row in &mut self.rows {
            row.cells
                .resize_with(cols.0.max(row.cells.len()), T::default);
        }
    }

    pub fn insert_row(&mut self, row: Row) {
        let mut cells = vec![];
        cells.resize_with(self.cols().0, Default::default);
        self.rows.insert(row.0, GridRow { cells });
    }

    pub fn insert_col(&mut self, col: Col) {
        for row in self.each_row() {
            let row = &mut self[row];
            row.cells.insert(col.0, Default::default());
        }
    }
}

impl<T: Clone + Eq + PartialEq + std::hash::Hash + std::fmt::Display>
    Grid<T>
{
    pub fn display_packed<F: Fn(&T) -> char>(
        &self,
        f: F,
    ) -> DisplayPacked<T, F> {
        DisplayPacked(self, f)
    }
}

impl<T: Clone + Eq + PartialEq + std::hash::Hash + std::fmt::Display>
    std::fmt::Display for Grid<T>
{
    fn fmt(
        &self,
        f: &mut std::fmt::Formatter<'_>,
    ) -> Result<(), std::fmt::Error> {
        for row in &self.rows {
            for col in &row.cells {
                write!(f, "{} ", col)?;
            }
            writeln!(f)?;
        }
        Ok(())
    }
}

impl<T: Clone + Eq + PartialEq + std::hash::Hash> std::ops::Index<Row>
    for Grid<T>
{
    type Output = GridRow<T>;
    fn index(&self, row: Row) -> &Self::Output {
        &self.rows[row.0]
    }
}

impl<T: Clone + Eq + PartialEq + std::hash::Hash> std::ops::IndexMut<Row>
    for Grid<T>
{
    fn index_mut(&mut self, row: Row) -> &mut Self::Output {
        &mut self.rows[row.0]
    }
}

impl<T: Default + Clone + Eq + PartialEq + std::hash::Hash>
    FromIterator<Vec<T>> for Grid<T>
{
    fn from_iter<I>(iter: I) -> Self
    where
        I: IntoIterator<Item = Vec<T>>,
    {
        let mut self_ = Self {
            rows: iter.into_iter().map(|v| GridRow { cells: v }).collect(),
        };
        let nrows = self_.rows.len();
        let ncols = self_
            .rows
            .iter()
            .map(|row| row.cells.len())
            .max()
            .unwrap_or(0);
        self_.grow(Row(nrows), Col(ncols));

        self_
    }
}

impl<T: Default + Clone + Eq + PartialEq + std::hash::Hash>
    FromIterator<((Row, Col), T)> for Grid<T>
{
    fn from_iter<I>(iter: I) -> Self
    where
        I: IntoIterator<Item = ((Row, Col), T)>,
    {
        let mut self_ = Self::default();
        for ((row, col), cell) in iter {
            self_.grow(Row(row.0 + 1), Col(col.0 + 1));
            self_[row][col] = cell;
        }
        self_
    }
}

pub struct DisplayPacked<
    'a,
    T: Clone + Eq + PartialEq + std::hash::Hash + std::fmt::Display,
    F: Fn(&'a T) -> char,
>(&'a Grid<T>, F);

impl<
        'a,
        T: Default
            + Clone
            + Eq
            + PartialEq
            + std::hash::Hash
            + std::fmt::Display,
        F: Fn(&'a T) -> char,
    > std::fmt::Display for DisplayPacked<'a, T, F>
{
    fn fmt(
        &self,
        f: &mut std::fmt::Formatter<'_>,
    ) -> Result<(), std::fmt::Error> {
        for row in &self.0.rows {
            for col in &row.cells {
                write!(f, "{}", self.1(col))?;
            }
            writeln!(f)?;
        }
        Ok(())
    }
}

pub struct Adjacent {
    row: usize,
    col: usize,
    rows: usize,
    cols: usize,
    diagonal: bool,
    pos: u8,
}

impl Iterator for Adjacent {
    type Item = (Row, Col);

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            if self.pos >= 9 {
                return None;
            }
            let pos_row = self.pos / 3;
            let pos_col = self.pos - pos_row * 3;
            self.pos += 1;
            if pos_row == 0 && self.row == 0
                || pos_col == 0 && self.col == 0
                || pos_row == 2 && self.row == self.rows - 1
                || pos_col == 2 && self.col == self.cols - 1
                || pos_row == 1 && pos_col == 1
                || (!self.diagonal
                    && ((pos_row == pos_col)
                        || (pos_row == 2 && pos_col == 0)
                        || (pos_row == 0 && pos_col == 2)))
            {
                continue;
            }
            return Some((
                Row(self.row + usize::from(pos_row) - 1),
                Col(self.col + usize::from(pos_col) - 1),
            ));
        }
    }
}