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;