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
use ;
use crate::;
/// Searches a Graph using the [A* Algorithm](https://en.wikipedia.org/wiki/A*_search_algorithm).
///
/// The Generic type Parameter `Point` is supposed to uniquely identify a Node in the Graph.
/// This may be a Number, String, a Grid position, ... as long as it can be compared, hashed and copied.
/// Note that it is advised to choose a short representation for the Point, since it will be copied several times.
///
/// ## Examples
/// Basic usage:
/// ```
/// # use hierarchical_pathfinding::generics::grid::a_star_search;
/// # use hierarchical_pathfinding::{prelude::*, Point};
/// // create and initialize Grid
/// // 0 = empty, 1 = swamp, 2 = wall
/// let mut grid = [
/// [0, 2, 0, 0, 0],
/// [0, 2, 2, 2, 2],
/// [0, 1, 0, 0, 0],
/// [0, 1, 0, 2, 0],
/// [0, 0, 0, 2, 0],
/// ];
/// let (width, height) = (grid.len(), grid[0].len());
///
/// let neighborhood = ManhattanNeighborhood::new(width, height);
///
/// const COST_MAP: [isize; 3] = [1, 10, -1];
///
/// fn cost_fn<'a>(grid: &'a [[usize; 5]; 5]) -> impl 'a + FnMut(Point) -> isize {
/// move |(x, y)| COST_MAP[grid[y][x]]
/// }
///
/// let start = (0, 0);
/// let goal = (4, 4);
///
/// let path = a_star_search(
/// |point| neighborhood.get_all_neighbors(point),
/// cost_fn(&grid),
/// start,
/// goal,
/// |point| neighborhood.heuristic(point, goal),
/// );
///
/// assert!(path.is_some());
/// let path = path.unwrap();
///
/// assert_eq!(path.cost(), 12);
/// ```
///
/// If the Goal cannot be reached, None is returned:
/// ```
/// # use hierarchical_pathfinding::generics::grid::a_star_search;
/// # use hierarchical_pathfinding::{prelude::*, Point};
/// # // create and initialize Grid
/// # // 0 = empty, 1 = swamp, 2 = wall
/// # let mut grid = [
/// # [0, 2, 0, 0, 0],
/// # [0, 2, 2, 2, 2],
/// # [0, 1, 0, 0, 0],
/// # [0, 1, 0, 2, 0],
/// # [0, 0, 0, 2, 0],
/// # ];
/// # let (width, height) = (grid.len(), grid[0].len());
/// #
/// # let neighborhood = ManhattanNeighborhood::new(width, height);
/// #
/// # const COST_MAP: [isize; 3] = [1, 10, -1];
/// #
/// # fn cost_fn<'a>(grid: &'a [[usize; 5]; 5]) -> impl 'a + FnMut(Point) -> isize {
/// # move |(x, y)| COST_MAP[grid[y][x]]
/// # }
/// #
/// let start = (0, 0);
/// let goal = (2, 0);
///
/// let path = a_star_search(
/// |point| neighborhood.get_all_neighbors(point),
/// cost_fn(&grid),
/// start,
/// goal,
/// |point| neighborhood.heuristic(point, goal),
/// );
///
/// assert!(path.is_none());
/// ```
///
/// ## Solid Goals
/// It is possible to calculate the shortest Path to for example a Wall and other non-walkable
/// Nodes using this function. To do that, simply supply a Function to the `is_walkable` Parameter
/// that returns `false` for Nodes that should not be used as part of an actual Path. If there are
/// no such Nodes in the Graph, `is_walkable` may simply be set to `|_| true`.
/// In the case that a Path to a non-walkable Goal is requested, the neighbor of that Goal with the
/// shortest Path from the Start is returned, if any is reachable. "neighbor" in this context is
/// a Node for which `get_all_neighbors` contains the Goal.
///
/// ## Arguments
/// - `get_all_neighbors` - a Function that takes a Node and returns all other Nodes reachable from that Node.
/// The returned value is the `Point` of the neighbor.
/// - `get_cost` - a Function that takes a Node and returns the Cost required to walk across that Node.
/// Negative values indicate Nodes that cannot be walked across.
/// - `start` - the starting Node
/// - `goal` - the Goal that this function is supposed to search for
/// - `heuristic` - the Heuristic Function of the A* Algorithm
///
/// ## Returns
/// the Path, if one was found, or None if the `goal` is unreachable.
/// The first Node in the Path is always the `start` and the last is the `goal`