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