grid_math/lib.rs
1//! Basic representation of Grid, Cell, and assosiated mathematical operations. Helpful in CLI-based gamedev.
2//!
3//! This module contains the [`Cell`] type, representing the basic unit of [`Grid`],
4//! the [`Grid`] type, representing a two-dimentional field of [`Cell`]s,
5//! the [`Cells`] type, representing an iterator over every [`Cell`] on the [`Grid`],
6//! the [`Rows`] and the [`Columns`] types, representing iterators over subgrids of [`Grid`],
7//! and the [`GridMap<V>`] type, representing a wrapper around the [`HashMap<Cell, V>`]
8//!
9//! # Usecases
10//!
11//! One of the best usecases of this crate is for developing `CLI` based games:
12//! `Cell` has two fields representing position on the `Grid`, which are both `u8`,
13//! and the `Grid` consists of the `start` and the `end` `Cell`s,
14//! making the largest possible `Grid` to be 255x255, which is enough for most terminal games.
15//!
16//! # Note
17//!
18//! - `Cell`'s global position currently represented in the `u8` for simplicity,
19//! and because this is enough for most terminal games. This may be changed to be a scalar generic in the future.
20//! - Error handling is currently rather stupid (just checks with panic!), but this helps to prevent scary logical bugs.
21//! - Crate is in the "work in progress" state, so the public API may change in the future. Feel free to contribute!
22//!
23//! # Examples
24//!
25//! Perform some basic calculations for `Cell`:
26//! ```
27//! use grid_math::{Cell, Grid};
28//!
29//! let grid = Grid::new(10, 10);
30//! let start = grid.start();
31//! let next = start.saturating_right(grid, 5).wrapping_down(grid, 15).strict_left(grid, 1);
32//!
33//! assert!(next.within(grid));
34//! assert_eq!(next, Cell::new(4, 5));
35//! ```
36//!
37//! Map every `Cell` on the `Grid` to the custom `String` representation:
38//! ```
39//! use grid_math::{Cell, Grid};
40//!
41//! let grid = Grid::new(3, 3);
42//! let grid_string = grid
43//! .rows()
44//! .map(|row| {
45//! row.cells().map(|_| " [#]")
46//! .chain(std::iter::once("\n\n"))
47//! .collect::<String>()
48//! })
49//! .collect::<String>();
50//! assert_eq!(grid_string,
51//! " \
52//! [#] [#] [#]
53//!
54//! [#] [#] [#]
55//!
56//! [#] [#] [#]
57//!
58//! "
59//! );
60//! ```
61//!
62//! Store some actual data on the `Grid`, using `GridMap`:
63//! ```
64//! use grid_math::{Cell, Grid, GridMap};
65//!
66//! let grid = Grid::new(5, 5);
67//! let mut map: GridMap<char> = GridMap::from(grid);
68//! map.insert(map.grid().start(), '#');
69//! map.insert(map.grid().end(), '@');
70//!
71//! assert_eq!(map.len(), 2);
72//! assert_eq!(map.get(&Cell::new(0, 0)).unwrap(), &'#');
73//! ```
74
75use std::collections::HashMap;
76use std::convert::{From, Into};
77use std::fmt;
78use std::ops::{Deref, DerefMut};
79
80/// `Cell` represents the basic unit of `Grid`.
81///
82/// Consists of global positions `global_width: u8` and `global_depth: u8`, alongside with methods implementing
83/// common mathematical operations for safe interactions with grids and other cells
84///
85/// Due to low memory size, `Cell` implements `Copy` trait, so all methods take `self` (copy) as first argument
86///
87/// # Examples
88///
89/// You can create Cell using new(global_width, global_depth):
90/// ```
91/// use grid_math::Cell;
92///
93/// let cell = Cell::new(10, 15);
94/// ```
95///
96/// Or use functionality of implemented `From` and `Into` traits:
97/// ```
98/// use grid_math::Cell;
99///
100/// let cell = Cell::from((9, 9));
101/// let cell: Cell = (6, 7).into();
102/// ```
103///
104/// To read global_width or global_depth values, use getters:
105/// ```
106/// use grid_math::Cell;
107///
108/// let cell = Cell::new(10, 10);
109/// let w = cell.global_width();
110/// let d = cell.global_depth();
111/// ```
112/// Or use `into()` provided by `Into` trait:
113/// ```
114/// use grid_math::Cell;
115///
116/// let cell = Cell::new(10, 10);
117/// let (w, d): (u8, u8) = cell.into();
118/// ```
119///
120/// 'Cell' implements `Display` and `Debug` trait, so you can easily print it out:
121/// ```
122/// use grid_math::Cell;
123///
124/// let cell = Cell::new(10, 10);
125/// println!("Cell: {cell}"); // Cell: (10, 10)
126/// assert_eq!(format!("{cell}"), "(10, 10)");
127/// ```
128///
129/// Other methods involve interactions with `Grid`
130///
131/// `Cell` is designed to not mutate it's contents.
132/// Instead, all operations return new instances of `Cell`
133///
134/// Also worth noting, that all operations on `Cell` are verified to be logically correct,
135/// otherwise logically incorrect operations will be met with panic!
136///
137/// Here is a brief overview of `Cell` and `Grid` interactions:
138///
139/// Check if `Cell` is within the `Grid`:
140/// ```
141/// use grid_math::{Cell, Grid};
142///
143/// let cell = Cell::new(3, 4);
144/// let grid = Grid::new(10, 10); // 10x10 grid starting at (0,0)
145/// assert!(cell.within(grid));
146/// ```
147///
148/// Get relative to the `Grid` position of `Cell`:
149/// (`Grid` can start not only from (0,0))
150/// ```
151/// use grid_math::{Cell, Grid};
152///
153/// let cell = Cell::new(3, 4);
154/// let grid = Grid::indented(8, 8, (2, 1)); // 8x8 grid starting at (2,1)
155/// let (width, depth) = (cell.width(grid), cell.depth(grid));
156/// // cell's width on grid = cell.global_width - grid.start.global_width
157/// // cell's depth on grid = cell.global_depth - grid.start.global_depth
158/// assert_eq!((width, depth), (1, 3));
159/// // get gaps between width and depth grid borders and cell:
160/// let (width_gap, depth_gap) = (cell.width_gap(grid), cell.depth_gap(grid));
161/// assert_eq!((width_gap, depth_gap), (6, 4));
162/// // get member of grid by relative position:
163/// let member = grid.member(width, depth);
164/// assert_eq!(cell, member);
165/// ```
166///
167/// Perform some move calculations of `Cell` on `Grid`:
168/// ```
169/// use grid_math::{Cell, Grid};
170///
171/// let grid = Grid::new(10, 10);
172/// let cell = grid.start(); // get grid's first cell
173/// let next = cell.strict_right(grid, 3); // move to the right by 3, panics if grid bounds overflow occures
174/// assert_eq!(next, Cell::new(3, 0));
175/// let next = cell.saturating_down(grid, 15); // move down by 15, returns grid bound if overflow occures
176/// assert_eq!(next, Cell::new(0, 9));
177/// let next = cell.wrapping_right(grid, 5).strict_left(grid, 2).project_down(grid); // chain of movements
178/// assert_eq!(next, Cell::new(3, 9));
179/// ```
180///
181/// To get more examples, look at `Cell` and `Grid` methods documentation.
182///
183///
184#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
185pub struct Cell {
186 global_width: u8,
187 global_depth: u8,
188}
189
190/// `Grid` represents the field of `Cell`
191///
192/// Consists of `start: Cell` and `end: Cell` fields, alongside with methods implementing
193/// common mathematical operations for safe interactions with cells and other grids
194///
195/// `Grid` has two axis: width, and depth:
196///
197/// (0,0) [#] [#] [#] [#] (5,0)
198///
199/// [#] [#] [#] [#] [#] [#]
200///
201/// [#] [#] [#] [#] [#] [#]
202///
203/// [#] [#] [#] [#] [#] [#]
204///
205/// [#] [#] [#] [#] [#] [#]
206///
207/// (0,5) [#] [#] [#] [#] (5,5)
208///
209/// Due to low memory size, `Grid` implements `Copy` trait, so all methods take `self` (copy) as first argument
210///
211/// # Examples
212///
213/// You can create Grid using new(width, depth) or indented(width, depth, indent):
214/// ```
215/// use grid_math::Grid;
216///
217/// let grid = Grid::new(5, 5); // new 5x5 grid, starting at (0,0)
218/// let grid = Grid::indented(5, 5, (1, 2)); // new 5x5 grid, starting at (1,2)
219/// ```
220///
221/// Or use functionality of implemented `From` and `Into` traits:
222/// ```
223/// use grid_math::{Grid, Cell};
224///
225/// let grid = Grid::from(((1, 2), (5, 6))); // new field where `start` is (1,2), `end` is (5,6)
226/// let grid: Grid = ((1, 2), (5, 6)).into();
227/// //same for (cell, cell):
228/// let grid = Grid::from((Cell::new(1, 2), Cell::new(5, 6)));
229/// let grid: Grid = (Cell::new(1, 2), Cell::new(5, 6)).into();
230/// // backwards:
231/// let (start, end) = grid.into();
232/// assert_eq!((start, end), (Cell::new(1, 2), Cell::new(5, 6)));
233/// let ((w1, d1), (w2, d2)) = grid.into();
234/// assert_eq!(((w1, d1), (w2, d2)), ((1, 2), (5, 6)));
235/// ```
236///
237/// Important:
238/// When creating `Grid` from cells, you specify `start` and `end` cell, not width and depth
239/// This means that if you create grid with `start` (1, 2) and `end` (5, 6),
240/// this will be 5x5 grid, not 4x4 as you can think (5 - 1 = 4, 6 - 2 = 4)
241/// this is because `start` and `end` bounds included, they are actual members of grid,
242/// where the `start` is the first cell on the grid, and `end` is the last cell on grid
243///
244/// To read `start` and `end` fields, or to calculate other common attributes, use getters:
245/// ```
246/// use grid_math::{Grid, Cell};
247///
248/// let grid = Grid::indented(8, 8, (3, 3)); // 8x8 grid, starting at (3,3)
249/// let (start, end) = (grid.start(), grid.end());
250/// assert_eq!((start, end), (Cell::new(3, 3), Cell::new(10, 10)));
251/// let (width, depth) = (grid.width(), grid.depth());
252/// assert_eq!((width, depth), (8, 8));
253/// let size = grid.size();
254/// assert_eq!(size, 64);
255/// ```
256///
257/// 'Grid' implements `Display` and `Debug` trait, so you can easily print it out:
258/// ```
259/// use grid_math::Grid;
260///
261/// let grid = Grid::new(10, 10);
262/// println!("Grid: {grid}"); // Grid: [(0, 0):(9, 9)]
263/// assert_eq!(format!("{grid}"), "[(0, 0):(9, 9)]");
264/// ```
265///
266/// Other advanced operations include interactions with other grids and cells:
267///
268/// Check if cell or subgrid is within grid:
269/// ```
270/// use grid_math::{Grid, Cell};
271///
272/// let grid = Grid::new(10, 10);
273/// let cell = Cell::new(3, 4);
274/// let subgrid = Grid::indented(5, 5, (2, 2));
275/// assert!(subgrid.within(grid));
276/// assert!(cell.within(grid));
277/// ```
278///
279/// Get `Cell` from `Grid` by relative position:
280/// ```
281/// use grid_math::{Grid, Cell};
282///
283/// let grid = Grid::indented(5, 5, (2, 2));
284/// let member = grid.member(2, 2);
285///
286/// assert_eq!(member, Cell::new(4, 4));
287/// ```
288///
289/// Important:
290/// When creating `Grid`, we specify `width` and `depth` in terms of length
291/// But when we address member of `Grid`, we specify `width` and `depth` in terms of indexes
292/// This means that `Grid` with `width` 5, and start at (0,*), will has `end` at (4,*),
293/// because we have (0,*) (1,*) (2,*) (3,*) (4,*), which is 5 elements in total
294/// So we used `width` 5 at `Grid` creation and got `Grid` with last cell (4,*)
295/// But if we use `width` 5 when indexing member of `Grid`, we will get an error, because indexing starts at 0
296///
297/// Get subgrid from `Grid` by relative position:
298/// ```
299/// use grid_math::{Grid, Cell};
300///
301/// let grid = Grid::indented(5, 5, (2, 2));
302/// assert_eq!(format!("{grid}"), "[(2, 2):(6, 6)]");
303/// // get subgrid starting at current grid start, with specified width and depth:
304/// let area = grid.area(3, 3);
305/// assert_eq!(format!("{area}"), "[(2, 2):(4, 4)]");
306/// // get subgrid starting at indent from current grid start and specified width and depth:
307/// let slice = grid.slice(3, 3, (1, 1));
308/// assert_eq!(format!("{slice}"), "[(3, 3):(5, 5)]");
309/// ```
310///
311/// Perform some move calculations of `Cell` on `Grid`:
312/// ```
313/// use grid_math::{Cell, Grid};
314///
315/// let grid = Grid::new(10, 10);
316/// let cell = grid.start(); // get grid's first cell
317/// let next = cell.strict_right(grid, 3); // move to the right by 3, panics if grid bounds overflow occures
318/// assert_eq!(next, Cell::new(3, 0));
319/// let next = cell.saturating_down(grid, 15); // move down by 15, returns grid bound if overflow occures
320/// assert_eq!(next, Cell::new(0, 9));
321/// let next = cell.wrapping_right(grid, 5).strict_left(grid, 2).project_down(grid); // chain of movements
322/// assert_eq!(next, Cell::new(3, 9));
323/// ```
324///
325/// Perform some actually usefull operations, using `Iterator` functionality:
326/// ```
327/// use grid_math::{Cell, Grid};
328///
329/// let grid = Grid::new(3, 3);
330/// let grid_string = grid
331/// .rows()
332/// .map(|row| {
333/// row.cells().map(|_| " [#]")
334/// .chain(std::iter::once("\n\n"))
335/// .collect::<String>()
336/// })
337/// .collect::<String>();
338/// assert_eq!(grid_string,
339/// " \
340/// [#] [#] [#]
341///
342/// [#] [#] [#]
343///
344/// [#] [#] [#]
345///
346/// "
347/// );
348/// ```
349///
350/// To get more examples, look at `Cell` and `Grid` methods documentation.
351///
352///
353#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
354pub struct Grid {
355 start: Cell,
356 end: Cell,
357}
358
359/// `Cells` represents an iterator over every `Cell` on the `Grid`
360///
361/// # Examples
362///
363/// Get every `Cell` on `width` and `depth` axis:
364/// ```
365/// use grid_math::{Cell, Grid};
366///
367/// let grid = Grid::new(3, 3);
368///
369/// let axis_cells: Vec<Cell> = grid
370/// .cells()
371/// .filter(|cell| {
372/// cell.global_width() == grid.start().global_width() || cell.global_depth() == grid.start().global_depth()
373/// })
374/// .collect();
375/// assert_eq!(axis_cells, vec![
376/// Cell::new(0, 0),
377/// Cell::new(1, 0),
378/// Cell::new(2, 0),
379/// Cell::new(0, 1),
380/// Cell::new(0, 2),
381/// ]);
382/// ```
383///
384#[derive(Debug, Clone, Copy, PartialEq, Eq)]
385pub struct Cells {
386 grid: Grid,
387 current: Cell,
388 consumed: bool,
389}
390
391/// `Rows` represents an iterator over every row of `Cell` on the `Grid`
392///
393/// Every element of 'Rows' returns `Grid`
394///
395/// # Examples
396///
397/// Print out `Grid` in custom format:
398/// ```
399/// use grid_math::{Cell, Grid};
400///
401/// let grid = Grid::new(3, 3);
402/// let grid_string = grid
403/// .rows()
404/// .map(|row| {
405/// row.cells().map(|_| " [#]")
406/// .chain(std::iter::once("\n\n"))
407/// .collect::<String>()
408/// })
409/// .collect::<String>();
410/// assert_eq!(grid_string,
411/// " \
412/// [#] [#] [#]
413///
414/// [#] [#] [#]
415///
416/// [#] [#] [#]
417///
418/// "
419/// );
420/// ```
421///
422#[derive(Debug, Clone, Copy, PartialEq, Eq)]
423pub struct Rows {
424 grid: Grid,
425 current: Grid,
426 consumed: bool,
427}
428
429/// `Columns` represents an iterator over every column of `Cell` on the `Grid`
430///
431/// Every element of 'Columns' returns `Grid`
432///
433/// # Examples
434///
435/// Get every `Cell` on the first column of `Grid`:
436/// ```
437/// use grid_math::{Cell, Grid};
438///
439/// let grid = Grid::new(3, 3);
440///
441/// let first_column_cells: Vec<Cell> = grid
442/// .columns()
443/// .next()
444/// .unwrap()
445/// .cells()
446/// .collect();
447///
448/// assert_eq!(first_column_cells, vec![
449/// Cell::new(0, 0),
450/// Cell::new(0, 1),
451/// Cell::new(0, 2),
452/// ]);
453/// ```
454#[derive(Debug, Clone, Copy, PartialEq, Eq)]
455pub struct Columns {
456 grid: Grid,
457 current: Grid,
458 consumed: bool,
459}
460
461/// `GridMap<V>` represents a wrapper around the `HashMap<Cell, V>`
462///
463/// `GridMap` is helpful for storing some actual data on the `Grid`.
464/// It implements `Deref` and `DerefMut` traits, so we can call methods from `HashMap`
465/// directly on the `GridMap`.
466///
467/// The main difference between the `GridMap<V>` and the `HashMap<Cell, V>` is that
468/// the `GridMap<V>` has actual bounds, that are defined by the inner `Grid`.
469///
470/// `GridMap` currently has rather stupid error handling, but this helps to prevent scary logical bugs.
471///
472/// # Examples
473///
474/// ```
475/// use grid_math::{Cell, Grid, GridMap};
476///
477/// let grid = Grid::new(5, 5);
478/// let mut map: GridMap<char> = GridMap::from(grid);
479/// map.insert(map.grid().start(), '#');
480/// map.insert(map.grid().end(), '@');
481/// assert_eq!(map.len(), 2);
482/// assert_eq!(map.get(&Cell::new(0, 0)).unwrap(), &'#');
483/// ```
484///
485/// ```should_panic
486/// use grid_math::{Cell, Grid, GridMap};
487///
488/// let grid = Grid::new(5, 5);
489/// let cell = Cell::new(6, 6);
490/// let mut map: GridMap<char> = GridMap::from(grid);
491/// map.insert(cell, '#'); // panic!
492/// ```
493#[derive(Debug, Clone)]
494pub struct GridMap<V> {
495 grid: Grid,
496 hashmap: HashMap<Cell, V>,
497}
498
499impl Cell {
500 /// Creates new `Cell` with specified `global_width: u8` and `global_depth: u8` global position
501 ///
502 /// # Examples
503 ///
504 /// ```
505 /// use grid_math::Cell;
506 ///
507 /// let cell = Cell::new(10, 15);
508 /// ```
509 pub fn new(global_width: u8, global_depth: u8) -> Self {
510 Self {
511 global_width,
512 global_depth,
513 }
514 }
515
516 /// Checks if the `Cell` is within the given `Grid`
517 ///
518 /// # Examples
519 ///
520 /// ```
521 /// use grid_math::{Cell, Grid};
522 ///
523 /// let grid = Grid::new(10, 10);
524 /// let cell = Cell::new(5, 5);
525 /// assert!(cell.within(grid));
526 ///
527 /// let cell = Cell::new(9, 15);
528 /// assert!(!cell.within(grid));
529 /// ```
530 pub fn within(self, grid: Grid) -> bool {
531 (grid.start.global_width..=grid.end.global_width).contains(&self.global_width)
532 && (grid.start.global_depth..=grid.end.global_depth).contains(&self.global_depth)
533 }
534
535 /// Checks if the `Cell` is within the given `Grid`
536 ///
537 /// # Panics
538 /// Panics if the `Cell` is not within the given `Grid`
539 ///
540 /// # Examples
541 ///
542 /// ```should_panic
543 /// use grid_math::{Cell, Grid};
544 ///
545 /// let grid = Grid::new(10, 10);
546 /// let cell = Cell::new(9, 15);
547 /// cell.within_panic(grid);
548 /// ```
549 pub fn within_panic(self, grid: Grid) {
550 if !self.within(grid) {
551 panic!("cell is not within given grid! cell:{self}, grid:{grid}")
552 }
553 }
554
555 /// Returns `global_width` field of `Cell`
556 ///
557 /// # Examples
558 ///
559 /// ```
560 /// use grid_math::Cell;
561 ///
562 /// let cell = Cell::new(8, 8);
563 /// let w = cell.global_width();
564 /// assert_eq!(w, 8);
565 /// ```
566 pub fn global_width(self) -> u8 {
567 self.global_width
568 }
569
570 /// Returns `global_depth` field of `Cell`
571 ///
572 /// # Examples
573 ///
574 /// ```
575 /// use grid_math::Cell;
576 ///
577 /// let cell = Cell::new(8, 8);
578 /// let d = cell.global_depth();
579 /// assert_eq!(d, 8);
580 /// ```
581 pub fn global_depth(self) -> u8 {
582 self.global_depth
583 }
584
585 /// Calculates the `width` of the `Cell` relative to the given `Grid`
586 /// `width` here means position / index / x of `Cell` on width axis
587 ///
588 /// # Panics
589 /// Panics if the `Cell` is not within the given `Grid`
590 ///
591 /// # Examples
592 ///
593 /// ```
594 /// use grid_math::{Cell, Grid};
595 ///
596 /// let cell = Cell::new(8, 8);
597 /// let grid = Grid::indented(7, 7, (4, 4)); // 7x7 grid starting at (4,4)
598 /// let width = cell.width(grid); // width = 4
599 /// assert_eq!(width, 4);
600 /// ```
601 pub fn width(self, grid: Grid) -> u8 {
602 self.within_panic(grid);
603 self.global_width - grid.start.global_width
604 }
605
606 /// Calculates the gap between the `width` of `Cell` and the `width` of `Grid`
607 ///
608 /// # Panics
609 /// Panics if the `Cell` is not within the given `Grid`
610 ///
611 /// # Examples
612 ///
613 /// ```
614 /// use grid_math::{Cell, Grid};
615 ///
616 /// let cell = Cell::new(8, 8);
617 /// let grid = Grid::indented(7, 7, (4, 4)); // 7x7 grid starting at (4,4)
618 /// let width_gap = cell.width_gap(grid); // width_gap = 2
619 /// assert_eq!(width_gap, 2);
620 /// ```
621 pub fn width_gap(self, grid: Grid) -> u8 {
622 self.within_panic(grid);
623 grid.end.global_width - self.global_width
624 }
625
626 /// Calculates the `depth` of `Cell` relative to the given `Grid`
627 /// `depth` here means position / index / y of `Cell` on depth axis
628 ///
629 /// # Panics
630 /// Panics if the `Cell` is not within the given `Grid`
631 ///
632 /// # Examples
633 ///
634 /// ```
635 /// use grid_math::{Cell, Grid};
636 ///
637 /// let cell = Cell::new(8, 8);
638 /// let grid = Grid::indented(7, 7, (4, 4)); // 7x7 grid starting at (4,4)
639 /// let depth = cell.depth(grid); // depth = 4
640 /// assert_eq!(depth, 4);
641 /// ```
642 pub fn depth(self, grid: Grid) -> u8 {
643 self.within_panic(grid);
644 self.global_depth - grid.start.global_depth
645 }
646
647 /// Calculates the gap between the `depth` of `Cell` and the `depth` of `Grid`
648 ///
649 /// # Panics
650 /// Panics if the `Cell` is not within the given `Grid`
651 ///
652 /// # Examples
653 ///
654 /// ```
655 /// use grid_math::{Cell, Grid};
656 ///
657 /// let cell = Cell::new(8, 8);
658 /// let grid = Grid::indented(7, 7, (4, 4)); // 7x7 grid starting at (4,4)
659 /// let depth_gap = cell.depth_gap(grid); // depth_gap = 2
660 /// assert_eq!(depth_gap, 2);
661 /// ```
662 pub fn depth_gap(self, grid: Grid) -> u8 {
663 self.within_panic(grid);
664 grid.end.global_depth - self.global_depth
665 }
666
667 /// Checks if the `up` operation on `Cell` will violate the given `Grid` upper border
668 ///
669 /// # Panics
670 /// Panics if the `Cell` is not within the given `Grid`
671 ///
672 /// # Examples
673 ///
674 /// ```
675 /// use grid_math::{Cell, Grid};
676 ///
677 /// let grid = Grid::new(10, 10);
678 /// let cell = Cell::new(2, 2);
679 /// assert!(cell.will_underflow_depth(grid, 3));
680 /// assert!(!cell.will_underflow_depth(grid, 2));
681 /// ```
682 pub fn will_underflow_depth(self, grid: Grid, step: u8) -> bool {
683 self.within_panic(grid);
684 self.global_depth < step || self.global_depth - step < grid.start.global_depth
685 }
686
687 /// Checks if the `down` operation on `Cell` will violate the given `Grid` lower border
688 ///
689 /// # Panics
690 /// Panics if the `Cell` is not within the given `Grid`
691 ///
692 /// # Examples
693 ///
694 /// ```
695 /// use grid_math::{Cell, Grid};
696 ///
697 /// let grid = Grid::new(10, 10);
698 /// let cell = Cell::new(7, 7);
699 /// assert!(cell.will_overflow_depth(grid, 3));
700 /// assert!(!cell.will_overflow_depth(grid, 2));
701 /// ```
702 pub fn will_overflow_depth(self, grid: Grid, step: u8) -> bool {
703 self.within_panic(grid);
704 self.global_depth > u8::MAX - step || self.global_depth + step > grid.end.global_depth
705 }
706
707 /// Checks if the `left` operation on `Cell` will violate the given `Grid` left border
708 ///
709 /// # Panics
710 /// Panics if the `Cell` is not within the given `Grid`
711 ///
712 /// # Examples
713 ///
714 /// ```
715 /// use grid_math::{Cell, Grid};
716 ///
717 /// let grid = Grid::new(10, 10);
718 /// let cell = Cell::new(2, 2);
719 /// assert!(cell.will_underflow_width(grid, 3));
720 /// assert!(!cell.will_underflow_width(grid, 2));
721 /// ```
722 pub fn will_underflow_width(self, grid: Grid, step: u8) -> bool {
723 self.within_panic(grid);
724 self.global_width < step || self.global_width - step < grid.start.global_width
725 }
726
727 /// Checks if the `right` operation on `Cell` will violate the given `Grid` right border
728 ///
729 /// # Panics
730 /// Panics if the `Cell` is not within the given `Grid`
731 ///
732 /// # Examples
733 ///
734 /// ```
735 /// use grid_math::{Cell, Grid};
736 ///
737 /// let grid = Grid::new(10, 10);
738 /// let cell = Cell::new(7, 7);
739 /// assert!(cell.will_overflow_width(grid, 3));
740 /// assert!(!cell.will_overflow_width(grid, 2));
741 /// ```
742 pub fn will_overflow_width(self, grid: Grid, step: u8) -> bool {
743 self.within_panic(grid);
744 self.global_width > u8::MAX - step || self.global_width + step > grid.end.global_width
745 }
746
747 /// Moves current `Cell` upwards by `step` relative to the given `Grid`
748 /// This operation does not mutate current `Cell` fields,
749 /// instead it calculates new position and returns new `Cell`
750 ///
751 /// # Panics
752 /// Panics if the `Cell` is not within the given `Grid`
753 /// Panics if this operation will violate the given `Grid` upper border
754 ///
755 /// # Examples
756 ///
757 /// ```
758 /// use grid_math::{Cell, Grid};
759 ///
760 /// let grid = Grid::new(10, 10);
761 /// let cell = Cell::new(2, 2);
762 /// let next = cell.strict_up(grid, 2);
763 /// assert_eq!(next, Cell::new(2, 0));
764 /// ```
765 ///
766 /// ```should_panic
767 /// use grid_math::{Cell, Grid};
768 ///
769 /// let grid = Grid::new(10, 10);
770 /// let cell = Cell::new(2, 2);
771 /// let next = cell.strict_up(grid, 3); // panic!
772 /// ```
773 pub fn strict_up(self, grid: Grid, step: u8) -> Cell {
774 if self.will_underflow_depth(grid, step) {
775 panic!(
776 "this operation will violate grid upper bounds! cell:{self}, grid:{grid}, step:{step}"
777 );
778 }
779 Cell {
780 global_width: self.global_width,
781 global_depth: self.global_depth - step,
782 }
783 }
784
785 /// Moves current `Cell` downwards by `step` relative to the given `Grid`
786 /// This operation does not mutate current `Cell` fields,
787 /// instead it calculates new position and returns new `Cell`
788 ///
789 /// # Panics
790 /// Panics if the `Cell` is not within the given `Grid`
791 /// Panics if this operation will violate the given `Grid` lower border
792 ///
793 /// # Examples
794 ///
795 /// ```
796 /// use grid_math::{Cell, Grid};
797 ///
798 /// let grid = Grid::new(10, 10);
799 /// let cell = Cell::new(7, 7);
800 /// let next = cell.strict_down(grid, 2);
801 /// assert_eq!(next, Cell::new(7, 9));
802 /// ```
803 ///
804 /// ```should_panic
805 /// use grid_math::{Cell, Grid};
806 ///
807 /// let grid = Grid::new(10, 10);
808 /// let cell = Cell::new(7, 7);
809 /// let next = cell.strict_down(grid, 3); // panic!
810 /// ```
811 pub fn strict_down(self, grid: Grid, step: u8) -> Cell {
812 if self.will_overflow_depth(grid, step) {
813 panic!(
814 "this operation will violate grid lower bounds! cell:{self}, grid:{grid}, step:{step}"
815 );
816 }
817 Cell {
818 global_width: self.global_width,
819 global_depth: self.global_depth + step,
820 }
821 }
822
823 /// Moves current `Cell` to the left by `step` relative to the given `Grid`
824 /// This operation does not mutate current `Cell` fields,
825 /// instead it calculates new position and returns new `Cell`
826 ///
827 /// # Panics
828 /// Panics if the `Cell` is not within the given `Grid`
829 /// Panics if this operation will violate the given `Grid` left border
830 ///
831 /// # Examples
832 ///
833 /// ```
834 /// use grid_math::{Cell, Grid};
835 ///
836 /// let grid = Grid::new(10, 10);
837 /// let cell = Cell::new(2, 2);
838 /// let next = cell.strict_left(grid, 2);
839 /// assert_eq!(next, Cell::new(0, 2));
840 /// ```
841 ///
842 /// ```should_panic
843 /// use grid_math::{Cell, Grid};
844 ///
845 /// let grid = Grid::new(10, 10);
846 /// let cell = Cell::new(2, 2);
847 /// let next = cell.strict_left(grid, 3); // panic!
848 /// ```
849 pub fn strict_left(self, grid: Grid, step: u8) -> Cell {
850 if self.will_underflow_width(grid, step) {
851 panic!(
852 "this operation will violate grid left bounds! cell:{self}, grid:{grid}, step:{step}"
853 );
854 }
855 Cell {
856 global_width: self.global_width - step,
857 global_depth: self.global_depth,
858 }
859 }
860
861 /// Moves current `Cell` to the right by `step` relative to the given `Grid`
862 /// This operation does not mutate current `Cell` fields,
863 /// instead it calculates new position and returns new `Cell`
864 ///
865 /// # Panics
866 /// Panics if the `Cell` is not within the given `Grid`
867 /// Panics if this operation will violate the given `Grid` right border
868 ///
869 /// # Examples
870 ///
871 /// ```
872 /// use grid_math::{Cell, Grid};
873 ///
874 /// let grid = Grid::new(10, 10);
875 /// let cell = Cell::new(7, 7);
876 /// let next = cell.strict_right(grid, 2);
877 /// assert_eq!(next, Cell::new(9, 7));
878 /// ```
879 ///
880 /// ```should_panic
881 /// use grid_math::{Cell, Grid};
882 ///
883 /// let grid = Grid::new(10, 10);
884 /// let cell = Cell::new(7, 7);
885 /// let next = cell.strict_right(grid, 3); // panic!
886 /// ```
887 pub fn strict_right(self, grid: Grid, step: u8) -> Cell {
888 if self.will_overflow_width(grid, step) {
889 panic!(
890 "this operation will violate grid right bounds! cell:{self}, grid:{grid}, step:{step}"
891 );
892 }
893 Cell {
894 global_width: self.global_width + step,
895 global_depth: self.global_depth,
896 }
897 }
898
899 /// Moves current `Cell` upwards by `step` relative to the given `Grid`
900 ///
901 /// This operation does not mutate current `Cell` fields,
902 /// instead it calculates new position and returns new `Cell`
903 ///
904 /// If this operation will cross `Grid` upper border,
905 /// returns `Cell` with `depth` = `Grid` upper depth limit
906 ///
907 /// # Panics
908 /// Panics if the `Cell` is not within the given `Grid`
909 ///
910 /// # Examples
911 ///
912 /// ```
913 /// use grid_math::{Cell, Grid};
914 ///
915 /// let grid = Grid::new(10, 10);
916 /// let cell = Cell::new(2, 2);
917 /// let next = cell.saturating_up(grid, 2);
918 /// assert_eq!(next, Cell::new(2, 0));
919 /// let next = cell.saturating_up(grid, 5);
920 /// assert_eq!(next, Cell::new(2, 0));
921 /// ```
922 pub fn saturating_up(self, grid: Grid, step: u8) -> Cell {
923 let next_depth = if self.will_underflow_depth(grid, step) {
924 grid.start.global_depth
925 } else {
926 self.global_depth - step
927 };
928 Cell {
929 global_width: self.global_width,
930 global_depth: next_depth,
931 }
932 }
933
934 /// Moves current `Cell` downwards by `step` relative to the given `Grid`
935 ///
936 /// This operation does not mutate current `Cell` fields,
937 /// instead it calculates new position and returns new `Cell`
938 ///
939 /// If this operation will cross `Grid` lower border,
940 /// returns `Cell` with `depth` = `Grid` lower depth limit
941 ///
942 /// # Panics
943 /// Panics if the `Cell` is not within the given `Grid`
944 ///
945 /// # Examples
946 ///
947 /// ```
948 /// use grid_math::{Cell, Grid};
949 ///
950 /// let grid = Grid::new(10, 10);
951 /// let cell = Cell::new(7, 7);
952 /// let next = cell.saturating_down(grid, 2);
953 /// assert_eq!(next, Cell::new(7, 9));
954 /// let next = cell.saturating_down(grid, 5);
955 /// assert_eq!(next, Cell::new(7, 9));
956 /// ```
957 pub fn saturating_down(self, grid: Grid, step: u8) -> Cell {
958 let next_depth = if self.will_overflow_depth(grid, step) {
959 grid.end.global_depth
960 } else {
961 self.global_depth + step
962 };
963 Cell {
964 global_width: self.global_width,
965 global_depth: next_depth,
966 }
967 }
968
969 /// Moves current `Cell` to the left by `step` relative to the given `Grid`
970 ///
971 /// This operation does not mutate current `Cell` fields,
972 /// instead it calculates new position and returns new `Cell`
973 ///
974 /// If this operation will cross `Grid` left border,
975 /// returns `Cell` with `width` = `Grid` left width limit
976 ///
977 /// # Panics
978 /// Panics if the `Cell` is not within the given `Grid`
979 ///
980 /// # Examples
981 ///
982 /// ```
983 /// use grid_math::{Cell, Grid};
984 ///
985 /// let grid = Grid::new(10, 10);
986 /// let cell = Cell::new(2, 2);
987 /// let next = cell.saturating_left(grid, 2);
988 /// assert_eq!(next, Cell::new(0, 2));
989 /// let next = cell.saturating_left(grid, 5);
990 /// assert_eq!(next, Cell::new(0, 2));
991 /// ```
992 pub fn saturating_left(self, grid: Grid, step: u8) -> Cell {
993 let next_width = if self.will_underflow_width(grid, step) {
994 grid.start.global_width
995 } else {
996 self.global_width - step
997 };
998 Cell {
999 global_width: next_width,
1000 global_depth: self.global_depth,
1001 }
1002 }
1003
1004 /// Moves current `Cell` to the right by `step` relative to the given `Grid`
1005 ///
1006 /// This operation does not mutate current `Cell` fields,
1007 /// instead it calculates new position and returns new `Cell`
1008 ///
1009 /// If this operation will cross `Grid` right border,
1010 /// returns `Cell` with `width` = `Grid` right width limit
1011 ///
1012 /// # Panics
1013 /// Panics if the `Cell` is not within the given `Grid`
1014 ///
1015 /// # Examples
1016 ///
1017 /// ```
1018 /// use grid_math::{Cell, Grid};
1019 ///
1020 /// let grid = Grid::new(10, 10);
1021 /// let cell = Cell::new(7, 7);
1022 /// let next = cell.saturating_right(grid, 2);
1023 /// assert_eq!(next, Cell::new(9, 7));
1024 /// let next = cell.saturating_right(grid, 5);
1025 /// assert_eq!(next, Cell::new(9, 7));
1026 /// ```
1027 pub fn saturating_right(self, grid: Grid, step: u8) -> Cell {
1028 let next_width = if self.will_overflow_width(grid, step) {
1029 grid.end.global_width
1030 } else {
1031 self.global_width + step
1032 };
1033 Cell {
1034 global_width: next_width,
1035 global_depth: self.global_depth,
1036 }
1037 }
1038
1039 /// Moves current `Cell` upwards by `step` relative to the given `Grid`
1040 ///
1041 /// This operation does not mutate current `Cell` fields,
1042 /// instead it calculates new position and returns new `Cell` and `bool`
1043 ///
1044 /// This operation is similar to the overflowing operations on integer types
1045 /// It returns new `Cell` and 'bool' signaling that overflow happened
1046 ///
1047 /// # Panics
1048 /// Panics if the `Cell` is not within the given `Grid`
1049 ///
1050 /// # Examples
1051 ///
1052 /// ```
1053 /// use grid_math::{Cell, Grid};
1054 ///
1055 /// let grid = Grid::new(10, 10);
1056 /// let cell = Cell::new(2, 2);
1057 /// let (next, overflowed) = cell.overflowing_up(grid, 2);
1058 /// assert_eq!((next, overflowed), (Cell::new(2, 0), false));
1059 /// let (next, overflowed) = cell.overflowing_up(grid, 5);
1060 /// assert_eq!((next, overflowed), (Cell::new(2, 7), true));
1061 /// ```
1062 pub fn overflowing_up(self, grid: Grid, step: u8) -> (Cell, bool) {
1063 let underflowed = self.will_underflow_depth(grid, step);
1064 let next_depth = if underflowed {
1065 grid.end.global_depth - ((step - self.depth(grid) - 1) % grid.depth())
1066 } else {
1067 self.global_depth - step
1068 };
1069 (
1070 Cell {
1071 global_width: self.global_width,
1072 global_depth: next_depth,
1073 },
1074 underflowed,
1075 )
1076 }
1077
1078 /// Moves current `Cell` downwards by `step` relative to the given `Grid`
1079 ///
1080 /// This operation does not mutate current `Cell` fields,
1081 /// instead it calculates new position and returns new `Cell` and `bool`
1082 ///
1083 /// This operation is similar to the overflowing operations on integer types
1084 /// It returns new `Cell` and 'bool' signaling that overflow happened
1085 ///
1086 /// # Panics
1087 /// Panics if the `Cell` is not within the given `Grid`
1088 ///
1089 /// # Examples
1090 ///
1091 /// ```
1092 /// use grid_math::{Cell, Grid};
1093 ///
1094 /// let grid = Grid::new(10, 10);
1095 /// let cell = Cell::new(7, 7);
1096 /// let (next, overflowed) = cell.overflowing_down(grid, 2);
1097 /// assert_eq!((next, overflowed), (Cell::new(7, 9), false));
1098 /// let (next, overflowed) = cell.overflowing_down(grid, 5);
1099 /// assert_eq!((next, overflowed), (Cell::new(7, 2), true));
1100 /// ```
1101 pub fn overflowing_down(self, grid: Grid, step: u8) -> (Cell, bool) {
1102 let overflowed = self.will_overflow_depth(grid, step);
1103 let next_depth = if overflowed {
1104 grid.start.global_depth + ((step - self.depth_gap(grid) - 1) % grid.depth())
1105 } else {
1106 self.global_depth + step
1107 };
1108 (
1109 Cell {
1110 global_width: self.global_width,
1111 global_depth: next_depth,
1112 },
1113 overflowed,
1114 )
1115 }
1116
1117 /// Moves current `Cell` to the left by `step` relative to the given `Grid`
1118 ///
1119 /// This operation does not mutate current `Cell` fields,
1120 /// instead it calculates new position and returns new `Cell` and `bool`
1121 ///
1122 /// This operation is similar to the overflowing operations on integer types
1123 /// It returns new `Cell` and 'bool' signaling that overflow happened
1124 ///
1125 /// # Panics
1126 /// Panics if the `Cell` is not within the given `Grid`
1127 ///
1128 /// # Examples
1129 ///
1130 /// ```
1131 /// use grid_math::{Cell, Grid};
1132 ///
1133 /// let grid = Grid::new(10, 10);
1134 /// let cell = Cell::new(2, 2);
1135 /// let (next, overflowed) = cell.overflowing_left(grid, 2);
1136 /// assert_eq!((next, overflowed), (Cell::new(0, 2), false));
1137 /// let (next, overflowed) = cell.overflowing_left(grid, 5);
1138 /// assert_eq!((next, overflowed), (Cell::new(7, 2), true));
1139 /// ```
1140 pub fn overflowing_left(self, grid: Grid, step: u8) -> (Cell, bool) {
1141 let underflowed = self.will_underflow_width(grid, step);
1142 let next_width = if underflowed {
1143 grid.end.global_width - ((step - self.width(grid) - 1) % grid.width())
1144 } else {
1145 self.global_width - step
1146 };
1147 (
1148 Cell {
1149 global_width: next_width,
1150 global_depth: self.global_depth,
1151 },
1152 underflowed,
1153 )
1154 }
1155
1156 /// Moves current `Cell` to the right by `step` relative to the given `Grid`
1157 ///
1158 /// This operation does not mutate current `Cell` fields,
1159 /// instead it calculates new position and returns new `Cell` and `bool`
1160 ///
1161 /// This operation is similar to the overflowing operations on integer types
1162 /// It returns new `Cell` and 'bool' signaling that overflow happened
1163 ///
1164 /// # Panics
1165 /// Panics if the `Cell` is not within the given `Grid`
1166 ///
1167 /// # Examples
1168 ///
1169 /// ```
1170 /// use grid_math::{Cell, Grid};
1171 ///
1172 /// let grid = Grid::new(10, 10);
1173 /// let cell = Cell::new(7, 7);
1174 /// let (next, overflowed) = cell.overflowing_right(grid, 2);
1175 /// assert_eq!((next, overflowed), (Cell::new(9, 7), false));
1176 /// let (next, overflowed) = cell.overflowing_right(grid, 5);
1177 /// assert_eq!((next, overflowed), (Cell::new(2, 7), true));
1178 /// ```
1179 pub fn overflowing_right(self, grid: Grid, step: u8) -> (Cell, bool) {
1180 let overflowed = self.will_overflow_width(grid, step);
1181 let next_width = if overflowed {
1182 grid.start.global_width + ((step - self.width_gap(grid) - 1) % grid.width())
1183 } else {
1184 self.global_width + step
1185 };
1186 (
1187 Cell {
1188 global_width: next_width,
1189 global_depth: self.global_depth,
1190 },
1191 overflowed,
1192 )
1193 }
1194
1195 /// Moves current `Cell` upwards by `step` relative to the given `Grid`
1196 ///
1197 /// This operation is a wrapper around the `overflowing_up()` method,
1198 /// and returns only new `Cell`, without `bool`
1199 ///
1200 /// # Panics
1201 /// Panics if the `Cell` is not within the given `Grid`
1202 ///
1203 /// # Examples
1204 ///
1205 /// ```
1206 /// use grid_math::{Cell, Grid};
1207 ///
1208 /// let grid = Grid::new(10, 10);
1209 /// let cell = Cell::new(2, 2);
1210 /// let next = cell.wrapping_up(grid, 2);
1211 /// assert_eq!(next, Cell::new(2, 0));
1212 /// let next = cell.wrapping_up(grid, 5);
1213 /// assert_eq!(next, Cell::new(2, 7));
1214 /// ```
1215 pub fn wrapping_up(self, grid: Grid, step: u8) -> Cell {
1216 self.overflowing_up(grid, step).0
1217 }
1218
1219 /// Moves current `Cell` downwards by `step` relative to the given `Grid`
1220 ///
1221 /// This operation is a wrapper around the `overflowing_down()` method,
1222 /// and returns only new `Cell`, without `bool`
1223 ///
1224 /// # Panics
1225 /// Panics if the `Cell` is not within the given `Grid`
1226 ///
1227 /// # Examples
1228 ///
1229 /// ```
1230 /// use grid_math::{Cell, Grid};
1231 ///
1232 /// let grid = Grid::new(10, 10);
1233 /// let cell = Cell::new(7, 7);
1234 /// let next = cell.wrapping_down(grid, 2);
1235 /// assert_eq!(next, Cell::new(7, 9));
1236 /// let next = cell.wrapping_down(grid, 5);
1237 /// assert_eq!(next, Cell::new(7, 2));
1238 /// ```
1239 pub fn wrapping_down(self, grid: Grid, step: u8) -> Cell {
1240 self.overflowing_down(grid, step).0
1241 }
1242
1243 /// Moves current `Cell` to the left by `step` relative to the given `Grid`
1244 ///
1245 /// This operation is a wrapper around the `overflowing_left()` method,
1246 /// and returns only new `Cell`, without `bool`
1247 ///
1248 /// # Panics
1249 /// Panics if the `Cell` is not within the given `Grid`
1250 ///
1251 /// # Examples
1252 ///
1253 /// ```
1254 /// use grid_math::{Cell, Grid};
1255 ///
1256 /// let grid = Grid::new(10, 10);
1257 /// let cell = Cell::new(2, 2);
1258 /// let next = cell.wrapping_left(grid, 2);
1259 /// assert_eq!(next, Cell::new(0, 2));
1260 /// let next = cell.wrapping_left(grid, 5);
1261 /// assert_eq!(next, Cell::new(7, 2));
1262 /// ```
1263 pub fn wrapping_left(self, grid: Grid, step: u8) -> Cell {
1264 self.overflowing_left(grid, step).0
1265 }
1266
1267 /// Moves current `Cell` to the right by `step` relative to the given `Grid`
1268 ///
1269 /// This operation is a wrapper around the `overflowing_right()` method,
1270 /// and returns only new `Cell`, without `bool`
1271 ///
1272 /// # Panics
1273 /// Panics if the `Cell` is not within the given `Grid`
1274 ///
1275 /// # Examples
1276 ///
1277 /// ```
1278 /// use grid_math::{Cell, Grid};
1279 ///
1280 /// let grid = Grid::new(10, 10);
1281 /// let cell = Cell::new(7, 7);
1282 /// let next = cell.wrapping_right(grid, 2);
1283 /// assert_eq!(next, Cell::new(9, 7));
1284 /// let next = cell.wrapping_right(grid, 5);
1285 /// assert_eq!(next, Cell::new(2, 7));
1286 /// ```
1287 pub fn wrapping_right(self, grid: Grid, step: u8) -> Cell {
1288 self.overflowing_right(grid, step).0
1289 }
1290
1291 /// Projects current `Cell` onto the top side of the given `Grid`
1292 ///
1293 /// This operation does not mutate current `Cell` fields,
1294 /// instead it calculates new position and returns new `Cell`
1295 ///
1296 /// # Panics
1297 /// Panics if the `Cell` is not within the given `Grid`
1298 ///
1299 /// # Examples
1300 ///
1301 /// ```
1302 /// use grid_math::{Cell, Grid};
1303 ///
1304 /// let grid = Grid::new(10, 10);
1305 /// let cell = Cell::new(2, 2);
1306 /// let next = cell.project_up(grid);
1307 /// assert_eq!(next, Cell::new(2, 0));
1308 /// ```
1309 pub fn project_up(self, grid: Grid) -> Cell {
1310 self.saturating_up(grid, u8::MAX)
1311 }
1312
1313 /// Projects current `Cell` onto the bottom side of the given `Grid`
1314 ///
1315 /// This operation does not mutate current `Cell` fields,
1316 /// instead it calculates new position and returns new `Cell`
1317 ///
1318 /// # Panics
1319 /// Panics if the `Cell` is not within the given `Grid`
1320 ///
1321 /// # Examples
1322 ///
1323 /// ```
1324 /// use grid_math::{Cell, Grid};
1325 ///
1326 /// let grid = Grid::new(10, 10);
1327 /// let cell = Cell::new(7, 7);
1328 /// let next = cell.project_down(grid);
1329 /// assert_eq!(next, Cell::new(7, 9));
1330 /// ```
1331 pub fn project_down(self, grid: Grid) -> Cell {
1332 self.saturating_down(grid, u8::MAX)
1333 }
1334
1335 /// Projects current `Cell` onto the left side of the given `Grid`
1336 ///
1337 /// This operation does not mutate current `Cell` fields,
1338 /// instead it calculates new position and returns new `Cell`
1339 ///
1340 /// # Panics
1341 /// Panics if the `Cell` is not within the given `Grid`
1342 ///
1343 /// # Examples
1344 ///
1345 /// ```
1346 /// use grid_math::{Cell, Grid};
1347 ///
1348 /// let grid = Grid::new(10, 10);
1349 /// let cell = Cell::new(2, 2);
1350 /// let next = cell.project_left(grid);
1351 /// assert_eq!(next, Cell::new(0, 2));
1352 /// ```
1353 pub fn project_left(self, grid: Grid) -> Cell {
1354 self.saturating_left(grid, u8::MAX)
1355 }
1356
1357 /// Projects current `Cell` onto the right side of the given `Grid`
1358 ///
1359 /// This operation does not mutate current `Cell` fields,
1360 /// instead it calculates new position and returns new `Cell`
1361 ///
1362 /// # Panics
1363 /// Panics if the `Cell` is not within the given `Grid`
1364 ///
1365 /// # Examples
1366 ///
1367 /// ```
1368 /// use grid_math::{Cell, Grid};
1369 ///
1370 /// let grid = Grid::new(10, 10);
1371 /// let cell = Cell::new(7, 7);
1372 /// let next = cell.project_right(grid);
1373 /// assert_eq!(next, Cell::new(9, 7));
1374 /// ```
1375 pub fn project_right(self, grid: Grid) -> Cell {
1376 self.saturating_right(grid, u8::MAX)
1377 }
1378
1379 /// Checks if the `Cell` is on the edge of the given `Grid`
1380 ///
1381 /// # Examples
1382 ///
1383 /// ```
1384 /// use grid_math::{Cell, Grid};
1385 ///
1386 /// let grid = Grid::new(10, 10);
1387 /// let cell = Cell::new(7, 9);
1388 /// assert!(cell.on_the_edge(grid));
1389 /// let cell = Cell::new(4, 3);
1390 /// assert!(!cell.on_the_edge(grid));
1391 /// ```
1392 pub fn on_the_edge(self, grid: Grid) -> bool {
1393 self.global_width == grid.start.global_width
1394 || self.global_width == grid.end.global_width
1395 || self.global_depth == grid.start.global_depth
1396 || self.global_depth == grid.end.global_depth
1397 }
1398}
1399
1400impl fmt::Display for Cell {
1401 /// implements display for `Cell`
1402 ///
1403 /// # Examples
1404 ///
1405 /// ```
1406 /// use grid_math::Cell;
1407 ///
1408 /// let cell = Cell::new(5, 6);
1409 /// assert_eq!(format!("{cell}"), "(5, 6)");
1410 /// ```
1411 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1412 write!(
1413 f,
1414 "({w}, {d})",
1415 w = self.global_width,
1416 d = self.global_depth
1417 )
1418 }
1419}
1420
1421impl From<(u8, u8)> for Cell {
1422 /// implements constructor for `Cell` from (u8, u8)
1423 ///
1424 /// # Examples
1425 ///
1426 /// ```
1427 /// use grid_math::Cell;
1428 ///
1429 /// let pos = (5, 6);
1430 /// let cell = Cell::from(pos);
1431 /// assert_eq!((pos.0, pos.1), (cell.global_width(), cell.global_depth()));
1432 /// ```
1433 fn from(value: (u8, u8)) -> Self {
1434 Self {
1435 global_width: value.0,
1436 global_depth: value.1,
1437 }
1438 }
1439}
1440
1441#[allow(clippy::from_over_into)]
1442impl Into<(u8, u8)> for Cell {
1443 /// implements conversion from `Cell` into (u8, u8)
1444 ///
1445 /// # Examples
1446 ///
1447 /// ```
1448 /// use grid_math::Cell;
1449 ///
1450 /// let cell = Cell::new(5, 6);
1451 /// let pos: (u8, u8) = cell.into();
1452 /// assert_eq!((pos.0, pos.1), (cell.global_width(), cell.global_depth()));
1453 /// ```
1454 fn into(self) -> (u8, u8) {
1455 (self.global_width, self.global_depth)
1456 }
1457}
1458
1459impl Grid {
1460 /// Creates new `Grid` with specified `width: u8` and `depth: u8`, starting at (0,0)
1461 ///
1462 /// # Panics
1463 /// Panics if `width` or `depth` parameters < 1
1464 ///
1465 /// # Examples
1466 ///
1467 /// ```
1468 /// use grid_math::Grid;
1469 ///
1470 /// let grid = Grid::new(10, 10);
1471 /// assert_eq!(format!("{grid}"), "[(0, 0):(9, 9)]");
1472 /// ```
1473 pub fn new(width: u8, depth: u8) -> Self {
1474 if width < 1 || depth < 1 {
1475 panic!("can't create grid with width < 0 or depth < 0!")
1476 }
1477 Self {
1478 start: Cell {
1479 global_width: 0,
1480 global_depth: 0,
1481 },
1482 end: Cell {
1483 global_width: width - 1,
1484 global_depth: depth - 1,
1485 },
1486 }
1487 }
1488
1489 /// Creates new `Grid` with specified `width: u8` and `depth: u8`, starting at indent
1490 ///
1491 /// # Panics
1492 /// Panics if `width` or `depth` parameters < 1
1493 ///
1494 /// # Examples
1495 ///
1496 /// ```
1497 /// use grid_math::{Grid, Cell};
1498 ///
1499 /// let grid = Grid::indented(5, 5, (2, 2));
1500 /// assert_eq!(format!("{grid}"), "[(2, 2):(6, 6)]");
1501 ///
1502 /// // use `Cell` as indent:
1503 /// let cell = Cell::new(2, 2);
1504 /// let grid = Grid::indented(5, 5, cell.into());
1505 /// assert_eq!(format!("{grid}"), "[(2, 2):(6, 6)]");
1506 /// ```
1507 pub fn indented(width: u8, depth: u8, indent: (u8, u8)) -> Self {
1508 if width < 1 || depth < 1 {
1509 panic!("can't create grid with width < 0 or depth < 0!")
1510 }
1511 Self {
1512 start: Cell {
1513 global_width: indent.0,
1514 global_depth: indent.1,
1515 },
1516 end: Cell {
1517 global_width: indent.0 + width - 1,
1518 global_depth: indent.1 + depth - 1,
1519 },
1520 }
1521 }
1522
1523 /// Checks if the `Grid` is within the another `Grid`
1524 ///
1525 /// # Examples
1526 ///
1527 /// ```
1528 /// use grid_math::Grid;
1529 ///
1530 /// let grid = Grid::new(10, 10);
1531 /// let subgrid = grid.area(5, 5);
1532 /// assert!(subgrid.within(grid));
1533 ///
1534 /// let subgrid = Grid::new(10, 12);
1535 /// assert!(!subgrid.within(grid));
1536 /// ```
1537 pub fn within(self, grid: Grid) -> bool {
1538 self.start.within(grid) && self.end.within(grid)
1539 }
1540
1541 /// Checks if the `Grid` is within the another `Grid`
1542 ///
1543 /// # Panics
1544 /// Panics if the `Grid` is not within the another `Grid`
1545 ///
1546 /// # Examples
1547 ///
1548 /// ```should_panic
1549 /// use grid_math::Grid;
1550 ///
1551 /// let grid = Grid::new(10, 10);
1552 /// let subgrid = Grid::new(10, 12);
1553 /// subgrid.within_panic(grid);
1554 /// ```
1555 pub fn within_panic(self, grid: Grid) {
1556 if !self.within(grid) {
1557 panic!("subgrid is not within given grid! subgrid:{self}, grid:{grid}")
1558 }
1559 }
1560
1561 /// Returns new `Cell` by `width: u8` and `depth: u8` relative to the current `Grid`
1562 ///
1563 /// # Panics
1564 /// Panics if `width` or `depth` of the requested member exceeds borders of the current `Grid`
1565 ///
1566 /// # Examples
1567 ///
1568 /// ```
1569 /// use grid_math::{Grid, Cell};
1570 ///
1571 /// let grid = Grid::indented(5, 5, (2, 2)); // 5x5 grid, starting at (2,2)
1572 /// let member = grid.member(4, 4);
1573 /// assert_eq!(member, Cell::new(6, 6));
1574 /// ```
1575 pub fn member(self, width: u8, depth: u8) -> Cell {
1576 self.start
1577 .strict_right(self, width)
1578 .strict_down(self, depth)
1579 }
1580
1581 /// Returns new `Grid` with `width: u8` and `depth: u8`, which is a subgrid
1582 /// of current `Grid`, starting at current `Grid` start
1583 ///
1584 /// # Panics
1585 /// Panics if `width` or `depth` parameters < 1
1586 /// Panics if `width` or `depth` of the requested area exceeds borders of the current `Grid`
1587 ///
1588 /// # Examples
1589 ///
1590 /// ```
1591 /// use grid_math::{Grid, Cell};
1592 ///
1593 /// let grid = Grid::indented(5, 5, (2, 2)); // 5x5 grid, starting at (2,2)
1594 /// let area = grid.area(3, 3);
1595 /// assert_eq!(format!("{area}"), "[(2, 2):(4, 4)]");
1596 /// ```
1597 pub fn area(self, width: u8, depth: u8) -> Grid {
1598 if width < 1 || depth < 1 {
1599 panic!("can't create grid with width < 0 or depth < 0!")
1600 }
1601 Grid {
1602 start: self.start,
1603 end: self
1604 .start
1605 .strict_right(self, width - 1)
1606 .strict_down(self, depth - 1),
1607 }
1608 }
1609
1610 /// Returns new `Grid` with `width: u8` and `depth: u8`, which is a subgrid
1611 /// of current `Grid`, starting at current `Grid` start + indent
1612 ///
1613 /// # Panics
1614 /// Panics if `width` or `depth` parameters < 1
1615 /// Panics if `width` or `depth` of the requested slice exceeds borders of the current `Grid`
1616 /// Panics if `indent` of the requested slice exceeds borders of the current `Grid`
1617 ///
1618 /// # Examples
1619 ///
1620 /// ```
1621 /// use grid_math::{Grid, Cell};
1622 ///
1623 /// let grid = Grid::new(10, 10);
1624 /// let slice = grid.slice(3, 3, (2, 2));
1625 /// assert_eq!(format!("{slice}"), "[(2, 2):(4, 4)]");
1626 ///
1627 /// // use `Cell` as indent:
1628 /// let cell = Cell::new(2, 2);
1629 /// let slice = grid.slice(3, 3, cell.into());
1630 /// assert_eq!(format!("{slice}"), "[(2, 2):(4, 4)]");
1631 /// ```
1632 pub fn slice(self, width: u8, depth: u8, indent: (u8, u8)) -> Grid {
1633 if width < 1 || depth < 1 {
1634 panic!("can't create grid with width < 0 or depth < 0!")
1635 }
1636 Grid {
1637 start: self
1638 .start
1639 .strict_right(self, indent.0)
1640 .strict_down(self, indent.1),
1641 end: self
1642 .start
1643 .strict_right(self, indent.0 + width - 1)
1644 .strict_down(self, indent.1 + depth - 1),
1645 }
1646 }
1647
1648 /// Returns `start` cell of `Grid`
1649 ///
1650 /// # Examples
1651 ///
1652 /// ```
1653 /// use grid_math::{Grid, Cell};
1654 ///
1655 /// let grid = Grid::new(10, 10);
1656 /// let start = grid.start();
1657 /// assert_eq!(start, Cell::new(0, 0));
1658 /// ```
1659 pub fn start(self) -> Cell {
1660 self.start
1661 }
1662
1663 /// Returns `end` cell of `Grid`
1664 ///
1665 /// # Examples
1666 ///
1667 /// ```
1668 /// use grid_math::{Grid, Cell};
1669 ///
1670 /// let grid = Grid::new(10, 10);
1671 /// let end = grid.end();
1672 /// assert_eq!(end, Cell::new(9, 9));
1673 /// ```
1674 pub fn end(self) -> Cell {
1675 self.end
1676 }
1677
1678 /// Calculates `width` of `Grid`
1679 ///
1680 /// # Examples
1681 ///
1682 /// ```
1683 /// use grid_math::Grid;
1684 ///
1685 /// let grid = Grid::new(10, 10);
1686 /// let width = grid.width();
1687 /// assert_eq!(width, 10);
1688 /// ```
1689 pub fn width(self) -> u8 {
1690 self.end.global_width - self.start.global_width + 1
1691 }
1692
1693 /// Calculates `depth` of `Grid`
1694 ///
1695 /// # Examples
1696 ///
1697 /// ```
1698 /// use grid_math::Grid;
1699 ///
1700 /// let grid = Grid::new(10, 10);
1701 /// let depth = grid.depth();
1702 /// assert_eq!(depth, 10);
1703 /// ```
1704 pub fn depth(self) -> u8 {
1705 self.end.global_depth - self.start.global_depth + 1
1706 }
1707
1708 /// Calculates `size: u16` of `Grid`
1709 ///
1710 /// # Examples
1711 ///
1712 /// ```
1713 /// use grid_math::Grid;
1714 ///
1715 /// let grid = Grid::new(10, 10);
1716 /// let size = grid.size();
1717 /// assert_eq!(size, 100);
1718 /// ```
1719 pub fn size(self) -> u16 {
1720 self.width() as u16 * self.depth() as u16
1721 }
1722
1723 /// Returns `Cells`, which is an iterator over every cell of the `Grid`
1724 ///
1725 /// # Examples
1726 ///
1727 /// Get every `Cell` on `width` and `depth` axis:
1728 /// ```
1729 /// use grid_math::{Cell, Grid};
1730 ///
1731 /// let grid = Grid::new(3, 3);
1732 ///
1733 /// let axis_cells: Vec<Cell> = grid
1734 /// .cells()
1735 /// .filter(|cell| {
1736 /// cell.global_width() == grid.start().global_width() || cell.global_depth() == grid.start().global_depth()
1737 /// })
1738 /// .collect();
1739 /// assert_eq!(axis_cells, vec![
1740 /// Cell::new(0, 0),
1741 /// Cell::new(1, 0),
1742 /// Cell::new(2, 0),
1743 /// Cell::new(0, 1),
1744 /// Cell::new(0, 2),
1745 /// ]);
1746 /// ```
1747 pub fn cells(self) -> Cells {
1748 Cells::from(self)
1749 }
1750
1751 /// Returns `Rows`, which is an iterator over every row of the `Grid`
1752 ///
1753 /// # Examples
1754 ///
1755 /// Print out `Grid` in custom format:
1756 /// ```
1757 /// use grid_math::{Cell, Grid};
1758 ///
1759 /// let grid = Grid::new(3, 3);
1760 /// let grid_string = grid
1761 /// .rows()
1762 /// .map(|row| {
1763 /// row.cells().map(|_| " [#]")
1764 /// .chain(std::iter::once("\n\n"))
1765 /// .collect::<String>()
1766 /// })
1767 /// .collect::<String>();
1768 /// assert_eq!(grid_string,
1769 /// " \
1770 /// [#] [#] [#]
1771 ///
1772 /// [#] [#] [#]
1773 ///
1774 /// [#] [#] [#]
1775 ///
1776 /// "
1777 /// );
1778 /// ```
1779 pub fn rows(self) -> Rows {
1780 Rows::from(self)
1781 }
1782
1783 /// Returns `Columns`, which is an iterator over every column of the `Grid`
1784 ///
1785 /// # Examples
1786 ///
1787 /// Get every `Cell` on the first column of `Grid`:
1788 /// ```
1789 /// use grid_math::{Cell, Grid};
1790 ///
1791 /// let grid = Grid::new(3, 3);
1792 ///
1793 /// let first_column_cells: Vec<Cell> = grid
1794 /// .columns()
1795 /// .next()
1796 /// .unwrap()
1797 /// .cells()
1798 /// .collect();
1799 ///
1800 /// assert_eq!(first_column_cells, vec![
1801 /// Cell::new(0, 0),
1802 /// Cell::new(0, 1),
1803 /// Cell::new(0, 2),
1804 /// ]);
1805 /// ```
1806 pub fn columns(self) -> Columns {
1807 Columns::from(self)
1808 }
1809}
1810
1811impl From<(Cell, Cell)> for Grid {
1812 /// implements constructor for `Grid` from (Cell, Cell)
1813 ///
1814 /// # Examples
1815 ///
1816 /// ```
1817 /// use grid_math::{Cell, Grid};
1818 ///
1819 /// let cells = (Cell::new(2, 2), Cell::new(5, 5));
1820 /// let grid = Grid::from(cells);
1821 /// assert_eq!((cells.0, cells.1), (grid.start(), grid.end()));
1822 /// ```
1823 fn from(value: (Cell, Cell)) -> Self {
1824 let (start, end) = value;
1825 if start.global_width > end.global_width || start.global_depth > end.global_depth {
1826 panic!("start cell overflows end cell! start:{start}, end:{end}")
1827 }
1828 Self { start, end }
1829 }
1830}
1831
1832#[allow(clippy::from_over_into)]
1833impl Into<(Cell, Cell)> for Grid {
1834 /// implements conversion from `Grid` into (Cell, Cell)
1835 ///
1836 /// # Examples
1837 ///
1838 /// ```
1839 /// use grid_math::{Cell, Grid};
1840 ///
1841 /// let grid = Grid::new(5, 5);
1842 /// let cells: (Cell, Cell) = grid.into();
1843 /// assert_eq!((cells.0, cells.1), (grid.start(), grid.end()));
1844 /// ```
1845 fn into(self) -> (Cell, Cell) {
1846 (self.start, self.end)
1847 }
1848}
1849
1850impl From<((u8, u8), (u8, u8))> for Grid {
1851 /// implements constructor for `Grid` from ((u8, u8), (u8, u8))
1852 ///
1853 /// # Examples
1854 ///
1855 /// ```
1856 /// use grid_math::{Cell, Grid};
1857 ///
1858 /// let vals = ((2, 2), (5, 5));
1859 /// let grid = Grid::from(vals);
1860 /// assert_eq!((Cell::from(vals.0), Cell::from(vals.1)), (grid.start(), grid.end()));
1861 /// ```
1862 fn from(value: ((u8, u8), (u8, u8))) -> Self {
1863 let (start, end): (Cell, Cell) = (value.0.into(), value.1.into());
1864 if start.global_width > end.global_width || start.global_depth > end.global_depth {
1865 panic!("start cell overflows end cell! start:{start}, end:{end}")
1866 }
1867 Self { start, end }
1868 }
1869}
1870
1871#[allow(clippy::from_over_into)]
1872impl Into<((u8, u8), (u8, u8))> for Grid {
1873 /// implements conversion from `Grid` into ((u8, u8), (u8, u8))
1874 ///
1875 /// # Examples
1876 ///
1877 /// ```
1878 /// use grid_math::{Cell, Grid};
1879 ///
1880 /// let grid = Grid::new(5, 5);
1881 /// let vals: ((u8, u8), (u8, u8)) = grid.into();
1882 /// assert_eq!((Cell::from(vals.0), Cell::from(vals.1)), (grid.start(), grid.end()));
1883 /// ```
1884 fn into(self) -> ((u8, u8), (u8, u8)) {
1885 (self.start.into(), self.end.into())
1886 }
1887}
1888
1889impl fmt::Display for Grid {
1890 /// implements display for `Grid`
1891 ///
1892 /// # Examples
1893 ///
1894 /// ```
1895 /// use grid_math::Grid;
1896 ///
1897 /// let grid = Grid::new(5, 6);
1898 /// assert_eq!(format!("{grid}"), "[(0, 0):(4, 5)]");
1899 /// ```
1900 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1901 write!(f, "[{start}:{end}]", start = self.start, end = self.end)
1902 }
1903}
1904
1905impl From<Grid> for Cells {
1906 /// Creates new iterator over every `Cell` on the `Grid`
1907 ///
1908 /// # Examples:
1909 ///
1910 /// ```
1911 /// use grid_math::{Grid, Cells};
1912 ///
1913 /// let grid = Grid::new(5, 5);
1914 /// let cells = Cells::from(grid);
1915 /// ```
1916 fn from(grid: Grid) -> Self {
1917 Self {
1918 grid,
1919 current: grid.start,
1920 consumed: false,
1921 }
1922 }
1923}
1924
1925impl From<Grid> for Columns {
1926 /// Creates new iterator over every column on the `Grid`
1927 ///
1928 /// # Examples:
1929 ///
1930 /// ```
1931 /// use grid_math::{Grid, Columns};
1932 ///
1933 /// let grid = Grid::new(5, 5);
1934 /// let columns = Columns::from(grid);
1935 /// ```
1936 fn from(grid: Grid) -> Self {
1937 Self {
1938 grid,
1939 current: Grid {
1940 start: grid.start,
1941 end: grid.start.project_down(grid),
1942 },
1943 consumed: false,
1944 }
1945 }
1946}
1947
1948impl From<Grid> for Rows {
1949 /// Creates new iterator over every row on the `Grid`
1950 ///
1951 /// # Examples:
1952 ///
1953 /// ```
1954 /// use grid_math::{Grid, Rows};
1955 ///
1956 /// let grid = Grid::new(5, 5);
1957 /// let rows = Rows::from(grid);
1958 /// ```
1959 fn from(grid: Grid) -> Self {
1960 Self {
1961 grid,
1962 current: Grid {
1963 start: grid.start,
1964 end: grid.start.project_right(grid),
1965 },
1966 consumed: false,
1967 }
1968 }
1969}
1970
1971impl Iterator for Cells {
1972 type Item = Cell;
1973 fn next(&mut self) -> Option<Self::Item> {
1974 if self.consumed {
1975 return None;
1976 }
1977 if self.current == self.grid.end {
1978 self.consumed = true;
1979 return Some(self.current);
1980 }
1981 let previous = self.current;
1982 match self.current.overflowing_right(self.grid, 1) {
1983 (next, true) => self.current = next.wrapping_down(self.grid, 1),
1984 (next, false) => self.current = next,
1985 }
1986 Some(previous)
1987 }
1988}
1989
1990impl Iterator for Columns {
1991 type Item = Grid;
1992 fn next(&mut self) -> Option<Self::Item> {
1993 if self.consumed {
1994 return None;
1995 }
1996 if self.current.end == self.grid.end {
1997 self.consumed = true;
1998 return Some(self.current);
1999 }
2000 let previous = self.current;
2001 self.current = Grid {
2002 start: self.current.start.saturating_right(self.grid, 1),
2003 end: self.current.end.saturating_right(self.grid, 1),
2004 };
2005 Some(previous)
2006 }
2007}
2008
2009impl Iterator for Rows {
2010 type Item = Grid;
2011 fn next(&mut self) -> Option<Self::Item> {
2012 if self.consumed {
2013 return None;
2014 }
2015 if self.current.end == self.grid.end {
2016 self.consumed = true;
2017 return Some(self.current);
2018 }
2019 let previous = self.current;
2020 self.current = Grid {
2021 start: self.current.start.saturating_down(self.grid, 1),
2022 end: self.current.end.saturating_down(self.grid, 1),
2023 };
2024 Some(previous)
2025 }
2026}
2027
2028impl<V> From<Grid> for GridMap<V> {
2029 /// Creates new `GridMap` from the given `Grid` with empty `HashMap<Cell, V>`
2030 ///
2031 /// # Examples:
2032 ///
2033 /// ```
2034 /// use grid_math::{Grid, GridMap};
2035 ///
2036 /// let grid = Grid::new(5, 5);
2037 /// let map: GridMap<char> = GridMap::from(grid);
2038 /// ```
2039 fn from(grid: Grid) -> Self {
2040 Self {
2041 grid,
2042 hashmap: HashMap::new(),
2043 }
2044 }
2045}
2046
2047impl<V> From<(Grid, HashMap<Cell, V>)> for GridMap<V> {
2048 /// Creates new `GridMap` from the existing `HashMap<Cell, V>` and the given `Grid`
2049 ///
2050 /// # Panics
2051 /// Panics if the given `HashMap<Cell, V>` contains `Cell`s that are not within the given `Grid`
2052 ///
2053 /// # Examples:
2054 ///
2055 /// ```
2056 /// use grid_math::{Cell, Grid, GridMap};
2057 /// use std::collections::HashMap;
2058 ///
2059 /// let grid = Grid::new(5, 5);
2060 /// let mut hashmap: HashMap<Cell, char> = HashMap::new();
2061 /// let target = Cell::new(1, 2);
2062 /// hashmap.insert(target, '#');
2063 /// let map: GridMap<char> = GridMap::from((grid, hashmap));
2064 /// assert_eq!(map.get(&target), Some(&'#'));
2065 /// ```
2066 ///
2067 /// ```should_panic
2068 /// use grid_math::{Cell, Grid, GridMap};
2069 /// use std::collections::HashMap;
2070 ///
2071 /// let grid = Grid::new(5, 5);
2072 /// let mut hashmap: HashMap<Cell, char> = HashMap::new();
2073 /// let target = Cell::new(6, 2);
2074 /// hashmap.insert(target, '#');
2075 /// let map: GridMap<char> = GridMap::from((grid, hashmap)); // panic!
2076 /// ```
2077 fn from(data: (Grid, HashMap<Cell, V>)) -> Self {
2078 data.1.keys().for_each(|cell| cell.within_panic(data.0));
2079 Self {
2080 grid: data.0,
2081 hashmap: data.1,
2082 }
2083 }
2084}
2085
2086impl<V> GridMap<V> {
2087 /// Creates new `GridMap` with `Grid` of specified sizes, and with empty `HashMap<Cell, V>`
2088 ///
2089 /// # Examples:
2090 ///
2091 /// ```
2092 /// use grid_math::{Grid, GridMap};
2093 ///
2094 /// let map: GridMap<char> = GridMap::new(5, 5);
2095 ///
2096 /// assert_eq!(map.grid(), Grid::new(5, 5));
2097 /// ```
2098 pub fn new(width: u8, depth: u8) -> Self {
2099 Self {
2100 grid: Grid::new(width, depth),
2101 hashmap: HashMap::new(),
2102 }
2103 }
2104
2105 /// Shadows `insert` method from the `HashMap`, and reimplements it
2106 /// so it checks first if the key (`Cell`) is within the `Grid`, and then inserts it into the `HashMap`.
2107 /// This method currently has bad error handling, but this may change in the future
2108 ///
2109 /// # Panics
2110 /// Panics, if the key (`Cell`) is not within the inner `Grid`
2111 ///
2112 /// # Examples:
2113 ///
2114 /// ```
2115 /// use grid_math::{Grid, GridMap};
2116 ///
2117 /// let grid = Grid::new(5, 5);
2118 /// let mut map: GridMap<char> = GridMap::from(grid);
2119 /// map.insert(map.grid().start(), '#');
2120 /// map.insert(map.grid().end(), '@');
2121 /// assert_eq!(map.len(), 2);
2122 /// ```
2123 ///
2124 /// ```should_panic
2125 /// use grid_math::{Cell, Grid, GridMap};
2126 ///
2127 /// let grid = Grid::new(5, 5);
2128 /// let cell = Cell::new(6, 6);
2129 /// let mut map: GridMap<char> = GridMap::from(grid);
2130 /// map.insert(cell, '#'); // panic!
2131 /// ```
2132 pub fn insert(&mut self, cell: Cell, value: V) -> Option<V> {
2133 cell.within_panic(self.grid);
2134 self.hashmap.insert(cell, value)
2135 }
2136
2137 /// Returns the inner `Grid`
2138 ///
2139 /// # Examples:
2140 ///
2141 /// ```
2142 /// use grid_math::{Grid, GridMap};
2143 ///
2144 /// let grid = Grid::new(5, 5);
2145 /// let map: GridMap<char> = GridMap::from(grid);
2146 ///
2147 /// assert_eq!(grid, map.grid());
2148 /// ```
2149 pub fn grid(&self) -> Grid {
2150 self.grid
2151 }
2152
2153 /// Checks if the `Cell` is occupied. This is an alias for `contains_key` method
2154 ///
2155 /// # Panics
2156 /// Panics, if the given `Cell` is not within the inner `Grid`
2157 ///
2158 /// # Examples:
2159 ///
2160 /// ```
2161 /// use grid_math::{Cell, Grid, GridMap};
2162 ///
2163 /// let grid = Grid::new(5, 5);
2164 /// let cell = Cell::new(2, 3);
2165 /// let mut map: GridMap<char> = GridMap::from(grid);
2166 /// map.insert(cell, '#');
2167 ///
2168 /// assert!(map.occupied(cell));
2169 /// assert!(!map.occupied(map.grid().start()))
2170 /// ```
2171 pub fn occupied(&self, cell: Cell) -> bool {
2172 cell.within_panic(self.grid);
2173 self.contains_key(&cell)
2174 }
2175}
2176
2177/// Implements `Deref` trait for GridMap, to return ref to the inner `HashMap`,
2178/// so we can call methods from `HashMap` directly on the `GridMap`
2179///
2180/// # Examples:
2181///
2182/// ```
2183/// use grid_math::{Grid, GridMap};
2184///
2185/// let grid = Grid::new(5, 5);
2186/// let mut map: GridMap<char> = GridMap::from(grid);
2187/// map.insert(map.grid().start(), '#');
2188///
2189/// assert_eq!(map.len(), 1);
2190/// ```
2191impl<V> Deref for GridMap<V> {
2192 type Target = HashMap<Cell, V>;
2193 fn deref(&self) -> &Self::Target {
2194 &self.hashmap
2195 }
2196}
2197
2198/// Implements `DerefMut` trait for GridMap, to return mut ref to the inner `HashMap`,
2199/// so we can call methods from `HashMap` directly on the `GridMap`
2200///
2201/// # Examples:
2202///
2203/// ```
2204/// use grid_math::{Grid, GridMap};
2205///
2206/// let grid = Grid::new(5, 5);
2207/// let mut map: GridMap<char> = GridMap::from(grid);
2208/// map.insert(map.grid().start(), '#');
2209///
2210/// assert_eq!(map.len(), 1);
2211/// ```
2212impl<V> DerefMut for GridMap<V> {
2213 fn deref_mut(&mut self) -> &mut Self::Target {
2214 &mut self.hashmap
2215 }
2216}
2217
2218// 🦀!⭐!!!