1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
// Copyright (C) 2021 Leandro Lisboa Penz <lpenz@lpenz.org>
// This file is subject to the terms and conditions defined in
// file 'LICENSE', which is part of this source code package.

#![warn(rust_2018_idioms)]
#![warn(missing_docs)]
#![deny(rustdoc::broken_intra_doc_links)]

//! *sqrid* provides square grid coordinates and related operations,
//! in a crate with zero dependencies.
//!
//! It's easier to explain the features of this crate in terms of the
//! types it provides:
//! - [`Pos`]: position, as absolute coordinates in a grid of fixed
//!   size. The dimensions of the grid are const generics type
//!   parameters; invalid coordinates can't be created.
//! - [`Dir`]: "movement", relative coordinates. These are the
//!   cardinal (and intercardinal) directions.
//!   Addition is implemented in the form of `Pos + Dir = Option<Pos>`,
//!   which can be `None` if the result is outside the grid.
//! - [`Grid`]: a `Pos`-indexed array.
//! - [`Gridbool`]: a bitmap-backed `Pos`-indexed grid of booleans.
//! - [`Sqrid`]: "factory" type that acts as an entry point to the
//!   fundamental types below and to algorithms.
//!
//! We also have traits that generalize `Grid` and `Gridbool`:
//! - [`MapPos`]: trait that maps `Pos` to parameterized items;
//!   it's implemented by `Grid`, and some `HashMap`/`BTreeMap` based types.
//! - [`SetPos`]: trait that maps each `Pos` to a bool; it's implemented
//!   by `Gridbool`, `HashSet<Pos>` and `BTreeSet<Pos>`.
//!
//! We then use these generalization to implement some grid algorithms:
//! - [`bf`]: breadth-first iteration and search.
//! - [`astar`]: A* search that takes a destination `Pos`.
//! - [`ucs`]: uniform-cost search.
//!
//! All basic types have the standard `iter`, `iter_mut`, `extend`,
//! `as_ref`, and conversion operations that should be expected.
//!
//! # Fundamental types
//!
//! ## `Pos`: absolute coordinates, position
//!
//! The [`Pos`] type represents an absolute position in a square
//! grid. The type itself receives the height and width of the grid as
//! const generic parameter.
//!
//! We should usually create a type alias for the grid size we are using:
//!
//! ```rust
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! use sqrid;
//!
//! type Pos = sqrid::Pos<6, 7>;
//!
//! let pos = Pos::new(3, 3)?;
//! # Ok(()) }
//! ```
//!
//! We can only generate [`Pos`] instances that are inside the passed
//! dimensions.
//!
//! ## `Dir`: relative coordinates, direction, movement
//!
//! The [`Dir`] type represents a relative movement of one square. It
//! can only be one of the 8 cardinal and intercardinal directions:
//! [`Dir::N`], [`Dir::NE`], [`Dir::E`], [`Dir::SE`], [`Dir::S`],
//! [`Dir::SW`], [`Dir::W`], [`Dir::NW`].
//!
//! It's a building block for paths, iterating on a [`Pos`] neighbors,
//! etc. It effectively represents the edges in a graph where the
//! [`Pos`] type represents nodes.
//!
//! All functions that iterate on `Dir` values accept a boolean const
//! argument that specifies whether the intercardinal directions
//! (`NE`, `SE`, `SW`, `NW`) should be considered.
//!
//! ## `Grid`: a `Pos`-indexed array
//!
//! A [`Grid`] is a generic array that can be indexed by a [`Pos`].
//!
//! We can create the type from a suitable [`Sqrid`] type by using the
//! [`grid_create`] macro. We can then interact with specific lines
//! with [`Grid::line`] and [`Grid::line_mut`], or with the whole
//! underlying array with `as_ref` (see [`std::convert::AsRef`]) and
//! `as_mut` (see [`std::convert::AsMut`]).
//!
//! Usage example:
//!
//! ```rust
//! type Sqrid = sqrid::sqrid_create!(3, 3, false);
//! type Pos = sqrid::pos_create!(Sqrid);
//! type Grid = sqrid::grid_create!(Sqrid, i32);
//!
//! // The grid create macro above is currently equivalent to:
//! type Grid2 = sqrid::Grid<i32, { Sqrid::WIDTH }, { Sqrid::HEIGHT },
//!                               { (Sqrid::WIDTH * Sqrid::HEIGHT) as usize }>;
//!
//! // We can create grids from iterators via `collect`:
//! let mut gridnums = (0..9).collect::<Grid>();
//!
//! // Iterate on their members:
//! for i in &gridnums {
//!     println!("i {}", i);
//! }
//!
//! // Change the members in a loop:
//! for i in &mut gridnums {
//!     *i *= 10;
//! }
//!
//! // Iterate on (coordinate, member) tuples:
//! for (pos, &i) in gridnums.iter_pos() {
//!     println!("[{}] = {}", pos, i);
//! }
//!
//! // And we can always use `as_ref` or `as_mut` to interact with the
//! // inner array directly. To reverse it, for example, with the
//! // [`std::slice::reverse`] function:
//! gridnums.as_mut().reverse();
//! ```
//!
//! ## `Gridbool`: a bitmap-backed `Pos`-indexed grid of booleans
//!
//! The [`Gridbool`] is a compact abstraction of a grid of booleans.
//!
//! The type itself can be created with [`gridbool_create`] macro.
//! It's optimized for getting and setting values at specific
//! coordinates, but we can also get all `true`/`false` coordinates
//! with suboptimal performance - in this case, the time is
//! proportional to the size of the grid and not to the quantity of
//! `true`/`false` values.
//!
//! Usage example:
//!
//! ```rust
//! type Sqrid = sqrid::sqrid_create!(3, 3, false);
//! type Pos = sqrid::pos_create!(Sqrid);
//! type Gridbool = sqrid::gridbool_create!(Sqrid);
//!
//! // We can create a gridbool from a Pos iterator via `collect`:
//! let mut gb = Pos::iter().filter(|pos| pos.is_corner()).collect::<Gridbool>();
//!
//! // We can also set values from an iterator:
//! gb.set_iter_t(Pos::iter().filter(|pos| pos.is_side()));
//!
//! // Iterate on the true/false values:
//! for b in gb.iter() {
//!     println!("{}", b);
//! }
//!
//! // Iterate on the true coordinates:
//! for pos in gb.iter_t() {
//!     assert!(pos.is_side());
//! }
//!
//! // Iterate on (coordinate, bool):
//! for (pos, b) in gb.iter_pos() {
//!     println!("[{}] = {}", pos, b);
//! }
//! ```
//!
//! # `Sqrid`: entry point for algorithms
//!
//! The [`Pos`] type and some methods on the [`Dir`] type require const
//! generic arguments that usually don't change inside an application.
//! Both [`Grid`] and [`Gridbool`] also require further arguments that
//! can actually be derived from the width and height of the grid, but
//! that have to be explicitly specified due to some Rust limitations.
//!
//! To make the creation of these types easier, we provide the
//! [`Sqrid`] type, which acumulates all const generic parameters and
//! can be used to create the other types via macros.
//!
//! Example usage:
//!
//! ```rust
//! type Sqrid = sqrid::sqrid_create!(4, 4, false);
//! type Pos = sqrid::pos_create!(Sqrid);
//! type Grid = sqrid::grid_create!(Sqrid, i32);
//! type Gridbool = sqrid::gridbool_create!(Sqrid);
//! ```
//!
//! # Algorithms
//!
//! ## Breadth-first traversal
//!
//! The [`Sqrid::bf_iter`] function instantiates an iterator struct
//! ([`bf::BfIterator`]) that can be used to iterate coordinates in
//! breadth-first order, from a given origin, using a provided
//! function to evaluate a given [`Pos`] position + [`Dir`] direction
//! into the next `Pos` position.
//!
//! Example usage:
//!
//! ```rust
//! type Sqrid = sqrid::sqrid_create!(3, 3, false);
//! type Pos = sqrid::pos_create!(Sqrid);
//!
//! for (pos, dir) in Sqrid::bf_iter(sqrid::mov_eval, &Pos::CENTER)
//!                 .flatten() {
//!     println!("breadth-first pos {} from {}", pos, dir);
//! }
//! ```
//!
//! ## Breadth-first search
//!
//! [`Sqrid::bfs_path`] takes an origin, a movement function and a
//! goal function, and figures out the shortest path to a goal by
//! using a breadth-first iteration.
//!
//! The function returns the [`Pos`] that fulfills the goal and a
//! path in the form of a `Vec<Dir>`.
//!
//! Example usage:
//!
//! ```rust
//! type Sqrid = sqrid::sqrid_create!(3, 3, false);
//! type Pos = sqrid::pos_create!(Sqrid);
//!
//! // Generate the grid of "came from" directions from bottom-right to
//! // top-left:
//! if let Ok((goal, path)) = Sqrid::bfs_path(
//!                               sqrid::mov_eval, &Pos::TOP_LEFT,
//!                               |pos| pos == Pos::BOTTOM_RIGHT) {
//!     println!("goal: {}, path: {:?}", goal, path);
//! }
//! ```
//!
//! ## A* search
//!
//! [`Sqrid::astar_path`] takes a movement function, an origin and a
//! destination, and figures out the shortest path by using A*.
//!
//! The function returns path in the form of a `Vec<Dir>`.
//!
//! Example usage:
//!
//! ```rust
//! type Sqrid = sqrid::sqrid_create!(3, 3, false);
//! type Pos = sqrid::pos_create!(Sqrid);
//!
//! // Generate the grid of "came from" directions from bottom-right to
//! // top-left:
//! if let Ok(path) = Sqrid::astar_path(sqrid::mov_eval, &Pos::TOP_LEFT,
//!                                     &Pos::BOTTOM_RIGHT) {
//!     println!("path: {:?}", path);
//! }
//! ```
//!
//! ## Uniform-cost search
//!
//! [`Sqrid::ucs_path`] takes a movement-cost function, an origin and a
//! destination, and figures out the path with the lowest cost by using
//! uniform-cost search, which is essentially a variation of
//! [Dijkstra](https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm).
//!
//! The function returns path in the form of a `Vec<Dir>`.
//!
//! Example usage:
//!
//! ```rust
//! type Sqrid = sqrid::sqrid_create!(3, 3, false);
//! type Pos = sqrid::pos_create!(Sqrid);
//!
//! fn traverse(position: Pos, direction: sqrid::Dir) -> Option<(Pos, usize)> {
//!     let next_position = (position + direction).ok()?;
//!     let cost = 1;
//!     Some((next_position, cost))
//! }
//!
//! // Generate the grid of "came from" directions from bottom-right to
//! // top-left:
//! if let Ok(path) = Sqrid::ucs_path(traverse, &Pos::TOP_LEFT,
//!                                   &Pos::BOTTOM_RIGHT) {
//!     println!("path: {:?}", path);
//! }
//! ```

mod sqrid;
pub use self::sqrid::*;