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