das_grid/
lib.rs

1/*!
2# Das Grid
3
4**Das Grid** is a 2D grid library which serves as fundamental building block for any 2D game built on the concept of grid
5
6Famous games built on 2d grid concept:
7
8* Draughts/Checkers
9* Chess
10* Scrabble
11* Tetris
12* Bejeweled
13* Shinning Force (while battle)
14
15Das Grid offers:
16
17* Generic grid type, you can use any type you want to be the grid cell
18* Helpers to make easy the move of values inside the grid
19* Based on 2D top/left to bottom/right concept (which can be updated in the future)
20
21## Using **Das Grid**
22
23### Creating the grid
24
25```rust
26// Creates a 10x10 grid with 0 as default value for each cell
27let mut g = das_grid::Grid::new(10, 10, 0);
28
29// Set the the value 1 at position x: 5 and y: 5
30g.set((5, 5), &1);
31```
32
33### Bring your own type
34
35```rust
36// Using &str instead of i32
37let mut g: das_grid::Grid<&str> = das_grid::Grid::new(10, 10, "a");
38g.get((0, 0)).unwrap(); // ouputs: "a"
39```
40
41```rust
42use std::fmt::Display;
43
44// Your own enum, much better to track grid values
45#[derive(Clone, Copy, PartialEq, Eq)]
46enum Pawn {
47    None,
48    Player,
49    Enemy,
50}
51
52impl std::fmt::Display for Pawn {
53    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
54        match *self {
55            Pawn::None => write!(f, "None"),
56            Pawn::Player => write!(f, "Player"),
57            Pawn::Enemy => write!(f, "Enemy"),
58        }
59    }
60}
61
62// Initialize empty grid
63let mut g: das_grid::Grid<Pawn> = das_grid::Grid::new(10, 10, Pawn::None);
64
65// Set the Player on position 5,5
66g.set((5, 5), &Pawn::Player);
67
68// Move the player to right
69if let Ok(()) = g.mov_to((5, 5), das_grid::MoveDirection::Right) {
70    // "The pawn on 6,5 is Player"
71    println!("The pawn on 6,5 is {}", g.get((6, 5)).unwrap());
72}
73
74```
75
76> The `mov_to` function can returns `Result<(), Err>` if the attept of move is out of the bounds of the grid
77
78### Moving cells
79
80Each tile of the grid is called cell and each cell is the type that you want, because it is a 2D structure each cell has an address which consists of X and Y
81
82```rust
83// Creates a 5x5 grid with 0 as default value for each cell
84let mut g = das_grid::Grid::new(5, 5, 0);
85
86// Print with special {:?} to see the contents of the grid
87println!("{:?}", g);
88// outputs:
89// Grid { rows: 5, cols: 5, cells: [
90//  0 (x: 0 y: 0) 0 (x: 1 y: 0) 0 (x: 2 y: 0) 0 (x: 3 y: 0) 0 (x: 4 y: 0)
91//  0 (x: 0 y: 1) 0 (x: 1 y: 1) 0 (x: 2 y: 1) 0 (x: 3 y: 1) 0 (x: 4 y: 1)
92//  0 (x: 0 y: 2) 0 (x: 1 y: 2) 0 (x: 2 y: 2) 0 (x: 3 y: 2) 0 (x: 4 y: 2)
93//  0 (x: 0 y: 3) 0 (x: 1 y: 3) 0 (x: 2 y: 3) 0 (x: 3 y: 3) 0 (x: 4 y: 3)
94//  0 (x: 0 y: 4) 0 (x: 1 y: 4) 0 (x: 2 y: 4) 0 (x: 3 y: 4) 0 (x: 4 y: 4)
95// ] }
96```
97
98## License
99
100```text
101MIT License
102
103Copyright (c) 2021 Eduardo Pereira
104
105Permission is hereby granted, free of charge, to any person obtaining a copy
106of this software and associated documentation files (the "Software"), to deal
107in the Software without restriction, including without limitation the rights
108to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
109copies of the Software, and to permit persons to whom the Software is
110furnished to do so, subject to the following conditions:
111
112The above copyright notice and this permission notice shall be included in all
113copies or substantial portions of the Software.
114
115THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
116IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
117FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
118AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
119LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
120OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
121SOFTWARE.
122```
123*/
124
125use std::{
126    fmt::{self, Display},
127    ops::{Index, IndexMut},
128};
129
130/// Err represents the errors that can happen on the Das Grid module
131///
132/// GridErr::OutOfGrid when the attempt of move or set a value
133/// is beyond the bounds of grid
134///
135/// GridErr::RuleFailed when some rule failed to applied
136///
137/// GridErr::SubgridOverflow when the subgrid 0x0 is greater than the parent grid
138#[derive(Debug, Clone, PartialEq, Eq)]
139pub enum GridErr {
140    OutOfGrid,
141    RuleFailed,
142    SubgridOverflow,
143}
144
145impl fmt::Display for GridErr {
146    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
147        match *self {
148            GridErr::OutOfGrid => write!(f, "value is out of the grid rows and cols"),
149            GridErr::RuleFailed => write!(f, "failed to meet the rule requirements"),
150            GridErr::SubgridOverflow => write!(
151                f,
152                "the subgrid cols or rows is greater than the parent grid"
153            ),
154        }
155    }
156}
157
158/// Represents the possible direction to move
159///
160/// MoveDirection::Right
161/// MoveDirection::Left
162/// MoveDirection::Up
163/// MoveDirection::Down
164#[derive(Debug, PartialEq, Eq)]
165pub enum MoveDirection {
166    Right,
167    Left,
168    Up,
169    Down,
170}
171
172/// Represent move to right position on Das Grid (0, 1)
173pub const MOVE_RIGHT: (i32, i32) = (0, 1);
174
175/// Represent move to left position on Das Grid (0, -1)
176pub const MOVE_LEFT: (i32, i32) = (0, -1);
177
178/// Represent move to up position on Das Grid (-1, 0)
179pub const MOVE_UP: (i32, i32) = (-1, 0);
180
181/// Represent move to down position on Das Grid (1, 0)
182pub const MOVE_DOWN: (i32, i32) = (1, 0);
183
184/// Stores the grid values and the cells
185/// The grid itself representation is a flatten vector which is transformed
186/// for 2D representation when called by the user
187///
188/// The cells are internally manage by a `Vec<T>`
189///
190/// So to create a grid with 4x4 (collums and rows)
191///
192/// ```.rust
193/// let grid = das_grid::Grid::new(4, 4, 0);
194/// assert_eq!(grid.size(), 16);
195/// ```
196///
197/// Or if you like let's say a Tetris style grid
198///
199/// ```.rust
200/// let grid = das_grid::Grid::new(10, 20, 0);
201///
202/// // And it will have 200 cells!
203/// assert_eq!(grid.size(), 200);
204/// ```
205
206pub struct Grid<T: Copy + Clone> {
207    pub(crate) rows: i32,
208    pub(crate) cols: i32,
209    pub(crate) initial_value: T,
210    pub(crate) cells: Vec<T>,
211}
212
213impl<T: Copy + Clone> Grid<T> {
214    /// Creates a grid of size rows x columns with default value passed on the third parameter
215    /// For example this will generate a 2x2 grid of value 1:
216    /// ```.rust
217    /// let grid = das_grid::Grid::new(2, 2, 1);
218    /// assert_eq!(grid.size(), 4);
219    /// ```
220    pub fn new(rows: i32, cols: i32, value: T) -> Self
221    where
222        T: Clone + Copy,
223    {
224        if (rows * cols) == 0 {
225            panic!("0x0 grid is forbidden")
226        }
227
228        let initial_value = value;
229        let cells = vec![value; (rows * cols) as usize];
230
231        Self {
232            rows,
233            cols,
234            initial_value,
235            cells,
236        }
237    }
238
239    /// Creates a grid from a given vector with quadratic size
240    /// For example this will generate a 2x2 grid
241    /// ```.rust
242    /// let mut grid = das_grid::Grid::new_from_vector(2, 2, vec![1, 2, 3, 4]);
243    /// assert_eq!(grid.size(), 4);
244    /// ```
245    pub fn new_from_vector(rows: i32, cols: i32, vec: Vec<T>) -> Self {
246        if vec.len() % 2 != 0 {
247            panic!("The vector isn't multiple of 2");
248        }
249
250        if vec.len() == 0 {
251            panic!("0x0 grid is forbidden")
252        }
253
254        if rows * cols != vec.len() as i32 {
255            panic!("cols and rows should be same vector size")
256        }
257
258        let initial_value = vec.first().unwrap().clone();
259        let cells = vec.to_vec();
260
261        Self {
262            rows,
263            cols,
264            initial_value,
265            cells,
266        }
267    }
268
269    /// Stamps the subgrid into the destiny grid, merging both
270    ///
271    /// If the sub grid is greater than the main grid it return an error of GridErr::SubgridOverflow
272    /// Or if the dest x, y grid is out of bounds it return error GridErr::OutOfGrid
273    ///
274    /// ```.rust
275    /// let mut grid: das_grid::Grid<i32> = das_grid::Grid::new(10, 10, 0);
276    /// let sub_grid: das_grid::Grid<i32> = das_grid::Grid::new(2, 2, 1);
277    /// assert!(grid.stamp_subgrid((5, 5), sub_grid).is_ok());
278    /// assert_eq!(grid.get((5, 5)).unwrap(), &1);
279    /// assert_eq!(grid.get((5, 6)).unwrap(), &1);
280    /// assert_eq!(grid.get((6, 5)).unwrap(), &1);
281    /// assert_eq!(grid.get((6, 6)).unwrap(), &1);
282    /// ```
283    pub fn stamp_subgrid(&mut self, index: (i32, i32), sub_grid: Grid<T>) -> Result<(), GridErr> {
284        self.check_grid_overflow(&sub_grid)?;
285        self.check_grid_bounds(index)?;
286
287        for sub_index in sub_grid.enumerate() {
288            if let Ok(subv) = sub_grid.get(sub_index) {
289                // Sum origin of subgrid and dest cells
290                let dest = (index.0 + sub_index.0, index.1 + sub_index.1);
291
292                // Ok if the subgrid bleeds
293                match self.set(dest, &subv) {
294                    Ok(_) => (),
295                    _ => (),
296                }
297            }
298        }
299
300        Ok(())
301    }
302
303    /// Creates the a new grid which is a snapshot of the main grid on the given position and size
304    ///
305    /// If the sub grid is greater than the main grid it return an error of GridErr::SubgridOverflow
306    ///
307    /// Or if the dest x, y grid is out of bounds it return error GridErr::OutOfGrid
308    ///
309    /// ```.rust
310    /// let mut grid = das_grid::Grid::new_from_vector(4, 4, (1..=16).collect());
311    /// let sub_grid = grid.get_subgrid((2, 2), 2, 2).unwrap();
312    /// assert_eq!(sub_grid.get_flatten_grid(), vec![11, 12, 15, 16]);
313    /// ```
314    pub fn get_subgrid(&self, index: (i32, i32), rows: i32, cols: i32) -> Result<Grid<T>, GridErr> {
315        self.check_grid_bounds(index)?;
316        let mut sub_grid = Grid::new(rows, cols, self.initial_value);
317        self.check_grid_overflow(&sub_grid)?;
318
319        for sub_index in sub_grid.enumerate() {
320            let dest = (index.0 + sub_index.0, index.1 + sub_index.1);
321            if let Ok(subv) = self.get(dest) {
322                match sub_grid.set(sub_index, &subv) {
323                    Ok(_) => (),
324                    _ => (),
325                }
326            }
327        }
328
329        Ok(sub_grid)
330    }
331
332    /// Stamps the subgrid into the destiny grid, merging both
333    /// Only if no rule return error
334    ///
335    /// If the sub grid is greater than the main grid it return an error of GridErr::SubgridOverflow
336    ///
337    /// Or if the dest x, y grid is out of bounds it return error GridErr::OutOfGrid
338    ///
339    /// And if a rule some rule failed it will return GridErr::RuleFailed
340    ///
341    /// ```.rust
342    /// let mut grid: das_grid::Grid<i32> = das_grid::Grid::new(10, 10, 1);
343    /// let sub_grid: das_grid::Grid<i32> = das_grid::Grid::new(2, 2, 1);
344    ///
345    /// let rule_not_1 = |_: (i32, i32), value: &i32| -> Result<(), das_grid::GridErr> {
346    ///     if *value == 1 {
347    ///         return Err(das_grid::GridErr::RuleFailed);
348    ///     }
349    ///     Ok(())
350    /// };
351    ///
352    /// assert!(grid
353    ///     .stamp_subgrid_with_rules((5, 5), sub_grid, vec![rule_not_1])
354    ///     .is_err());
355    /// ```
356    pub fn stamp_subgrid_with_rules<R>(
357        &mut self,
358        index: (i32, i32),
359        sub_grid: Grid<T>,
360        rules: Vec<R>,
361    ) -> Result<(), GridErr>
362    where
363        R: Fn((i32, i32), &T) -> Result<(), GridErr>,
364    {
365        self.check_grid_overflow(&sub_grid)?;
366        self.check_grid_bounds(index)?;
367
368        for sub_index in sub_grid.enumerate() {
369            if let Ok(subv) = sub_grid.get(sub_index) {
370                // Sum origin of subgrid and dest cells
371                let dest = (index.0 + sub_index.0, index.1 + sub_index.1);
372
373                // Get the destiny
374                let destv = self.get(dest)?;
375
376                // Test rules on dest pos and value
377                for rule in rules.iter() {
378                    rule(dest, destv)?;
379                }
380
381                // Ok if the subgrid bleeds
382                match self.set(dest, &subv) {
383                    Ok(_) => (),
384                    _ => (),
385                }
386            }
387        }
388
389        Ok(())
390    }
391
392    // Check if subgrid isn't bigger than the destiny grid
393    fn check_grid_overflow(&self, sub_grid: &Grid<T>) -> Result<(), GridErr> {
394        if sub_grid.cols > self.cols {
395            return Err(GridErr::SubgridOverflow);
396        }
397
398        if sub_grid.rows > self.rows {
399            return Err(GridErr::SubgridOverflow);
400        }
401
402        Ok(())
403    }
404
405    /// Internally checks if the index (x, y) is inside of the bounds of the grid
406    fn check_grid_bounds(&self, index: (i32, i32)) -> Result<(), GridErr> {
407        let (x, y) = index;
408
409        if x < 0 || x >= self.rows {
410            return Err(GridErr::OutOfGrid);
411        }
412
413        if y < 0 || y >= self.cols {
414            return Err(GridErr::OutOfGrid);
415        }
416
417        Ok(())
418    }
419
420    /// Sets a given value to the position (x, y)
421    ///
422    /// Be careful if the value is out of the bounds of grid it will return an error
423    /// with the type of GridErr::OutOfGrid
424    ///
425    /// ```.rust
426    /// let mut grid = das_grid::Grid::new(2, 2, 1);
427    /// assert!(grid.set((0, 0), &1).is_ok());
428    /// ```
429    pub fn set(&mut self, index: (i32, i32), value: &T) -> Result<(), GridErr>
430    where
431        T: Copy,
432    {
433        let (x, y) = index;
434
435        self.check_grid_bounds(index)?;
436
437        if let Some(cell) = self.cells.get_mut((x * self.rows + y) as usize) {
438            *cell = *value;
439        }
440
441        Ok(())
442    }
443
444    /// Sets a given value to the position (x, y)
445    /// Only if no rule return error
446    ///
447    /// ```.rust
448    /// let mut grid = das_grid::Grid::new(2, 2, 0);
449    /// assert!(grid.set((0, 1), &1).is_ok());
450    ///
451    /// let rule_not_1 = |_: (i32, i32), value: &i32| -> Result<(), das_grid::GridErr> {
452    ///     if *value == 1 {
453    ///         return Err(das_grid::GridErr::RuleFailed);
454    ///     }
455    ///     Ok(())
456    /// };
457    ///
458    /// assert!(
459    ///     grid.set_with_rules((0, 1), &1, vec![rule_not_1])
460    ///         .err()
461    ///         .unwrap()
462    ///         == das_grid::GridErr::RuleFailed
463    /// );
464    /// ```
465    pub fn set_with_rules<R>(
466        &mut self,
467        index: (i32, i32),
468        value: &T,
469        rules: Vec<R>,
470    ) -> Result<(), GridErr>
471    where
472        R: Fn((i32, i32), &T) -> Result<(), GridErr>,
473    {
474        for rule in rules.iter() {
475            rule(index, value)?;
476        }
477        self.set(index, value)?;
478        Ok(())
479    }
480
481    /// Gets a give value to the position (x, y) as mutable
482    ///
483    /// Be careful if the value is out of the bounds of grid it will return an error
484    /// with the type of GridErr::OutOfGrid
485    ///
486    /// ```.rust
487    /// let mut grid = das_grid::Grid::new(2, 2, 1);
488    /// let mut v = grid.get_mut((0, 0)).expect("cannnot get pos at (0, 0)");
489    /// *v = 50;
490    /// assert_eq!(grid.get((0, 0)).unwrap_or(&0), &50);
491    /// ```
492    pub fn get_mut(&mut self, index: (i32, i32)) -> Result<&mut T, GridErr> {
493        let (x, y) = index;
494
495        self.check_grid_bounds(index)?;
496
497        Ok(self.cells.get_mut((x * self.rows + y) as usize).unwrap())
498    }
499
500    /// Gets a give value to the position (x, y)
501    ///
502    /// Be careful if the value is out of the bounds of grid it will return an error
503    /// with the type of GridErr::OutOfGrid
504    ///
505    /// ```.rust
506    /// let grid = das_grid::Grid::new(2, 2, 1);
507    /// let v = grid.get((0, 0));
508    /// assert_eq!(v, Ok(&1));
509    /// ```
510    pub fn get(&self, index: (i32, i32)) -> Result<&T, GridErr> {
511        let (x, y) = index;
512
513        self.check_grid_bounds(index)?;
514
515        Ok(self.cells.get((x * self.rows + y) as usize).unwrap())
516    }
517
518    /// Moves a given value from position (x, y) to destiny position (x, y)
519    ///
520    /// Be careful if the value is out of the bounds of grid it will return an error
521    /// with the type of GridErr::OutOfGrid
522    ///
523    /// ```.rust
524    /// let mut grid = das_grid::Grid::new(2, 2, 1);
525    /// assert_eq!(grid.mov((0, 0), (1, 1)), Ok(()));
526    /// ```
527    pub fn mov(&mut self, index: (i32, i32), dest: (i32, i32)) -> Result<(), GridErr> {
528        self.check_grid_bounds(index)?;
529        self.check_grid_bounds(dest)?;
530        let prev = *self.get_mut(index).unwrap();
531        self.set(index, &self.initial_value.clone())?;
532        self.set(dest, &prev)?;
533
534        Ok(())
535    }
536
537    /// Moves a given value from position (x, y) to destiny position (x, y)
538    /// Only if no rule return error
539    ///
540    /// Be careful if the value is out of the bounds of grid it will return an error
541    /// with the type of GridErr::OutOfGrid
542    ///
543    /// And if a rule some rule failed it will return GridErr::RuleFailed
544    ///
545    /// ```.rust
546    /// let mut grid = das_grid::Grid::new(2, 2, 0);
547    /// assert!(grid.set((0, 1), &1).is_ok());
548    ///
549    /// let rule_not_1 = |_: (i32, i32), value: &i32| -> Result<(), das_grid::GridErr> {
550    ///     if *value == 1 {
551    ///         return Err(das_grid::GridErr::RuleFailed);
552    ///     }
553    ///     Ok(())
554    /// };
555    ///
556    /// assert!(
557    ///     grid.mov_with_rules((0, 0), (0, 1), vec![rule_not_1])
558    ///         .err()
559    ///         .unwrap()
560    ///         == das_grid::GridErr::RuleFailed
561    /// );
562    /// ```
563    pub fn mov_with_rules<R>(
564        &mut self,
565        index: (i32, i32),
566        dest: (i32, i32),
567        rules: Vec<R>,
568    ) -> Result<(), GridErr>
569    where
570        R: Fn((i32, i32), &T) -> Result<(), GridErr>,
571    {
572        self.check_grid_bounds(index)?;
573        self.check_grid_bounds(dest)?;
574        let prev = *self.get_mut(index).unwrap();
575
576        let destv = self.get(dest)?;
577        for rule in rules {
578            rule(dest, destv)?;
579        }
580
581        self.set(index, &self.initial_value.clone())?;
582        self.set(dest, &prev)?;
583
584        Ok(())
585    }
586
587    /// Moves a given value from position (x, y) to another position based on the direction
588    ///
589    /// The directions can be Left, Right, Top, Down:
590    /// * DasGrid::MoveDirection::Left, translates to (0, -1)
591    /// * DasGrid::MoveDirection::Right, translates to (0, 1)
592    /// * DasGrid::MoveDirection::Top, translates to (-1, 0)
593    /// * DasGrid::MoveDirection::Down, translates to (1, 0)
594    ///
595    /// Be careful if the value is out of the bounds of grid it will return an error
596    /// with the type of GridErr::OutOfGrid
597    ///
598    /// ```.rust
599    /// let mut grid = das_grid::Grid::new(2, 2, 1);
600    /// assert_eq!(grid.mov_to((0, 0), das_grid::MoveDirection::Right), Ok(()));
601    /// ```
602    pub fn mov_to(&mut self, index: (i32, i32), direction: MoveDirection) -> Result<(), GridErr> {
603        let (x, y) = index;
604        self.check_grid_bounds(index)?;
605
606        let (xx, yy) = match direction {
607            MoveDirection::Up => MOVE_UP,
608            MoveDirection::Down => MOVE_DOWN,
609            MoveDirection::Left => MOVE_LEFT,
610            MoveDirection::Right => MOVE_RIGHT,
611        };
612
613        let dest = (x + xx, y + yy);
614        self.check_grid_bounds(dest)?;
615
616        let prev = *self.get_mut(index).unwrap();
617        self.set(index, &self.initial_value.clone())?;
618        self.set(dest, &prev)?;
619
620        Ok(())
621    }
622
623    /// Moves a given value from position (x, y) to another position based on the direction
624    /// Only if no rule return error
625    ///
626    /// if the dest x, y grid is out of bounds it return error GridErr::OutOfGrid
627    ///
628    /// And if a rule some rule failed it will return GridErr::RuleFailed
629    ///
630    /// The directions can be Left, Right, Top, Down:
631    /// * DasGrid::MoveDirection::Left, translates to (0, -1)
632    /// * DasGrid::MoveDirection::Right, translates to (0, 1)
633    /// * DasGrid::MoveDirection::Top, translates to (-1, 0)
634    /// * DasGrid::MoveDirection::Down, translates to (1, 0)
635    ///
636    /// Be careful if the value is out of the bounds of grid it will return an error
637    /// with the type of GridErr::OutOfGrid
638    ///
639    /// ```.rust
640    /// let mut g = das_grid::Grid::new(2, 2, 0);
641    /// g.set((0, 1), &1);
642    /// let rule_not_1 = |_: (i32, i32), value: &i32| -> Result<(), das_grid::GridErr> {
643    ///     if *value == 1 {
644    ///         return Err(das_grid::GridErr::RuleFailed);
645    ///     }
646    ///     Ok(())
647    /// };
648    /// let ret = g.mov_to_with_rules((0, 0), das_grid::MoveDirection::Right, vec![rule_not_1]);
649    /// assert!(ret.is_err());
650    /// ```
651    pub fn mov_to_with_rules<R>(
652        &mut self,
653        index: (i32, i32),
654        direction: MoveDirection,
655        rules: Vec<R>,
656    ) -> Result<(), GridErr>
657    where
658        R: Fn((i32, i32), &T) -> Result<(), GridErr>,
659    {
660        let (x, y) = index;
661        self.check_grid_bounds(index)?;
662
663        let (xx, yy) = match direction {
664            MoveDirection::Up => MOVE_UP,
665            MoveDirection::Down => MOVE_DOWN,
666            MoveDirection::Left => MOVE_LEFT,
667            MoveDirection::Right => MOVE_RIGHT,
668        };
669
670        let dest = (x + xx, y + yy);
671        self.check_grid_bounds(dest)?;
672
673        let destv = self.get(dest)?;
674        for rule in rules {
675            rule(dest, destv)?;
676        }
677
678        let prev = *self.get_mut(index).unwrap();
679        self.set(index, &self.initial_value.clone())?;
680        self.set(dest, &prev)?;
681
682        Ok(())
683    }
684
685    /// Get the size of grid based on cells length
686    ///
687    /// For instance a 10x10 grid will return the size of 100
688    ///
689    /// ```.rust
690    /// let mut grid = das_grid::Grid::new(2, 2, 1);
691    /// assert_eq!(grid.size(), 4);
692    /// ```
693    pub fn size(&self) -> usize {
694        self.cells.len()
695    }
696
697    /// The rows of the grid
698    /// ```.rust
699    /// let mut grid = das_grid::Grid::new(3, 2, 1);
700    /// assert_eq!(grid.rows(), 3);
701    /// ```
702    pub fn rows(&self) -> i32 {
703        self.rows
704    }
705
706    /// The cols of the grid
707    /// ```.rust
708    /// let mut grid = das_grid::Grid::new(3, 2, 1);
709    /// assert_eq!(grid.cols(), 2);
710    /// ```
711    pub fn cols(&self) -> i32 {
712        self.cols
713    }
714
715    /// Returns the grid as a tuple of (x, y)
716    ///
717    /// ```.rust
718    /// let mut grid = das_grid::Grid::new(3, 2, 1);
719    /// for (x, y) in grid.enumerate() {
720    ///     println!("x {} y {}", x, y);
721    /// }
722    /// ```
723    pub fn enumerate(&self) -> Vec<(i32, i32)> {
724        let mut x = 0;
725        let mut y = 0;
726        self.cells
727            .iter()
728            .enumerate()
729            .map(|(idx, _)| {
730                if idx as i32 % self.rows() == 0 && idx > 1 {
731                    x = 0;
732                    y += 1;
733                }
734                let res = (x, y);
735                x += 1;
736                res
737            })
738            .collect::<Vec<_>>()
739    }
740
741    /// Returns the type vector with the values from the col
742    ///
743    /// If the col idx is wrong it can return the error GridErr::OutOfGrid
744    ///
745    /// ```.rust
746    /// let mut g = das_grid::Grid::new_from_vector(2, 2, vec![1, 2, 3, 4]);
747    /// let col = g.get_col(1).unwrap();
748    /// assert_eq!(col, vec![2, 4]);
749    /// ```
750    pub fn get_col(&self, col_idx: i32) -> Result<Vec<T>, GridErr> {
751        let mut vec_result: Vec<T> = vec![];
752        for idx in (0..self.cols).into_iter() {
753            let v = self.get((idx, col_idx))?;
754            vec_result.push(*v);
755        }
756        Ok(vec_result)
757    }
758
759    /// Returns the type vector with the values from the row
760    ///
761    /// If the row idx is wrong it can return the error GridErr::OutOfGrid
762    ///
763    /// ```.rust
764    /// let mut g = das_grid::Grid::new_from_vector(2, 2, vec![1, 2, 3, 4]);
765    /// let row = g.get_row(1).unwrap();
766    /// assert_eq!(row, vec![3, 4]);
767    /// ```
768    pub fn get_row(&self, row_idx: i32) -> Result<Vec<T>, GridErr> {
769        let mut vec_result: Vec<T> = vec![];
770        for idx in (0..self.rows).into_iter() {
771            let v = self.get((row_idx, idx))?;
772            vec_result.push(*v);
773        }
774        Ok(vec_result)
775    }
776
777    /// Returns a clone of the internal representation of the grid
778    ///
779    /// ```.rust
780    /// let mut g = das_grid::Grid::new_from_vector(2, 2, vec![1, 2, 3, 4]);
781    /// assert_eq!(g.get_flatten_grid(), vec![1,2,3,4]);
782    /// ```
783    pub fn get_flatten_grid(&self) -> Vec<T> {
784        self.cells.clone()
785    }
786
787    /// Fill the grid with the given value
788    ///
789    /// ```.rust
790    ///
791    /// ```
792    pub fn fill_grid(&mut self, value: T) {
793        self.cells.fill(value);
794    }
795
796    #[allow(dead_code)]
797    pub(crate) fn debug(&self)
798    where
799        T: std::fmt::Display,
800    {
801        println!("{:?}", self)
802    }
803
804    /// Fills the certain area of the grid with a given value
805    ///
806    /// If the area is greater than the main grid it return an error of GridErr::SubgridOverflow
807    ///
808    /// ```.rust
809    /// let mut grid = das_grid::Grid::new_from_vector(4, 4, (1..=16).collect());
810    /// grid.fill_subgrid((1, 1), 2, 2, &0);
811    /// assert!(grid.get((1, 1)).unwrap() == &0);
812    /// assert!(grid.get((1, 2)).unwrap() == &0);
813    /// assert!(grid.get((2, 1)).unwrap() == &0);
814    /// assert!(grid.get((2, 2)).unwrap() == &0);
815    /// ```
816    pub fn fill_subgrid(
817        &mut self,
818        index: (i32, i32),
819        rows: i32,
820        cols: i32,
821        value: &T,
822    ) -> Result<Grid<T>, GridErr> {
823        self.check_grid_bounds(index)?;
824        let sub_grid = Grid::new(rows, cols, self.initial_value);
825        self.check_grid_overflow(&sub_grid)?;
826
827        for sub_index in sub_grid.enumerate() {
828            let dest = (index.0 + sub_index.0, index.1 + sub_index.1);
829            match self.set(dest, value) {
830                Ok(_) => (),
831                _ => (),
832            }
833        }
834
835        Ok(sub_grid)
836    }
837}
838
839impl<'a, T: Copy + Clone> IntoIterator for &'a Grid<T> {
840    type Item = &'a T;
841    type IntoIter = std::slice::Iter<'a, T>;
842    fn into_iter(self) -> Self::IntoIter {
843        self.cells.iter()
844    }
845}
846
847impl<'a, T: Copy + Clone> IntoIterator for &'a mut Grid<T> {
848    type Item = &'a mut T;
849    type IntoIter = std::slice::IterMut<'a, T>;
850    fn into_iter(self) -> Self::IntoIter {
851        self.cells.iter_mut()
852    }
853}
854
855impl<T: Copy + Clone> fmt::Display for Grid<T> {
856    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
857        write!(
858            f,
859            "Grid {{ rows: {}, cols: {}, cells: [...] }}",
860            self.rows, self.cols
861        )
862    }
863}
864
865impl<T: Copy + Clone + Display> fmt::Debug for Grid<T> {
866    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
867        let mut cell_str = String::new();
868
869        let mut pos = (0, 0);
870        for (idx, cell) in self.cells.iter().enumerate() {
871            if idx as i32 % self.cols == 0 && idx > 0 {
872                pos.1 = 0;
873                pos.0 += 1;
874                cell_str += "\n";
875            }
876            cell_str.push_str(&format!("\t{:3} (x: {} y: {})", cell, pos.0, pos.1));
877            pos.1 += 1
878        }
879
880        write!(
881            f,
882            "Grid {{ rows: {}, cols: {}, cells: [\n{}\n] }}",
883            self.rows, self.cols, cell_str,
884        )
885    }
886}
887
888impl<T: Copy + Clone> Index<(i32, i32)> for Grid<T> {
889    type Output = T;
890    fn index(&self, index: (i32, i32)) -> &T {
891        self.get(index).unwrap()
892    }
893}
894
895impl<T: Copy + Clone> IndexMut<(i32, i32)> for Grid<T> {
896    fn index_mut(&mut self, index: (i32, i32)) -> &mut T {
897        self.get_mut(index).unwrap()
898    }
899}
900
901#[cfg(test)]
902mod lib_test;