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