basic_pathfinding/
pathfinding.rs1use crate::coord::Coord;
2use crate::grid::Grid;
3use crate::search::Search;
4pub use crate::search::SearchOpts;
5use std::collections::HashMap;
6
7#[derive(Clone, Serialize, Deserialize, Debug)]
8pub struct ReachableResult {
9 pub stoppable: Vec<Coord>,
10 pub walkable: Vec<Coord>,
11}
12
13pub fn find_path(grid: &Grid, start: Coord, end: Coord, opts: SearchOpts) -> Option<Vec<Coord>> {
14 let end_on_unstoppable = opts.end_on_unstoppable;
15 let end_coords = match opts.path_adjacent {
16 true => {
17 let mut coords = vec![];
18 for coord in grid.get_adjacent(&end) {
19 if end_on_unstoppable | grid.is_coord_stoppable(coord.x, coord.y) {
20 coords.push(coord);
21 }
22 }
23 coords
24 }
25 false => vec![end],
26 };
27
28 println!("{:?}", end_coords);
29
30 if end_coords.contains(&start) {
31 Some(vec![])
32 } else if end_coords
33 .iter()
34 .find(|c| grid.is_coord_stoppable(c.x, c.y))
35 .is_none()
36 & !end_on_unstoppable
37 {
38 None
39 } else {
40 let mut search = Search::new(start, end_coords.clone(), Some(end), opts);
41 let start_node = search.coordinate_to_node(None, start.x, start.y, 0);
42 search.push(start_node);
43
44 calculate(&mut search, &grid);
45
46 match search.pop() {
47 None => None,
48 Some(node) => Some(node.format_path(&search)),
49 }
50 }
51}
52
53pub fn find_reachable(grid: &Grid, source: Vec<Coord>, opts: SearchOpts) -> ReachableResult {
54 let mut search = Search::new(*source.first().unwrap(), vec![], None, opts);
55
56 for coord in source {
57 let node = search.coordinate_to_node(None, coord.x, coord.y, 0);
58 search.push(node);
59 }
60
61 calculate(&mut search, &grid);
62
63 let mut stoppable = vec![];
64 let mut walkable = vec![];
65 for node in search.traversed_nodes() {
66 if grid.is_coord_stoppable(node.x, node.y) {
67 stoppable.push(Coord::new(node.x, node.y));
68 } else if grid.is_coord_walkable(node.x, node.y) {
69 walkable.push(Coord::new(node.x, node.y));
70 }
71 }
72 stoppable.sort();
73 walkable.sort();
74
75 ReachableResult {
76 stoppable: stoppable,
77 walkable: walkable,
78 }
79}
80
81pub fn to_coord_map(mut hash: HashMap<i32, HashMap<i32, bool>>, coords: Vec<Coord>) -> HashMap<i32, HashMap<i32, bool>> {
82 for Coord { x, y } in coords {
83 match hash.get_mut(&y) {
84 None => {
85 let mut inner_hash = HashMap::new();
86 inner_hash.insert(x, true);
87 hash.insert(y, inner_hash);
88 }
89 Some(inner_hash) => {
90 inner_hash.insert(x, true);
91 }
92 };
93 }
94 hash.to_owned()
95}
96
97fn calculate(search: &mut Search, grid: &Grid) {
98 match search.size() {
99 0 => (),
100 _ => {
101 if search.reached_destination() {
102 ()
103 } else {
104 let mut node = search.pop().unwrap();
105 node.visited = true;
106 search.cache(node);
107
108 if grid.in_grid(node.x, node.y - 1) {
110 search.check_adjacent_node(grid, &node, 0, -1)
111 }
112 if !grid.is_cardinal() & grid.in_grid(node.x + 1, node.y - 1) {
114 search.check_adjacent_node(grid, &node, 1, -1)
115 }
116 if grid.in_grid(node.x + 1, node.y) {
118 search.check_adjacent_node(grid, &node, 1, 0)
119 }
120 if grid.is_intercardinal() & grid.in_grid(node.x + 1, node.y + 1) {
122 search.check_adjacent_node(grid, &node, 1, 1)
123 }
124 if grid.in_grid(node.x, node.y + 1) {
126 search.check_adjacent_node(grid, &node, 0, 1)
127 }
128 if !grid.is_cardinal() & grid.in_grid(node.x - 1, node.y + 1) {
130 search.check_adjacent_node(grid, &node, -1, 1)
131 }
132 if grid.in_grid(node.x - 1, node.y) {
134 search.check_adjacent_node(grid, &node, -1, 0)
135 }
136 if grid.is_intercardinal() & grid.in_grid(node.x - 1, node.y - 1) {
138 search.check_adjacent_node(grid, &node, -1, -1)
139 }
140
141 calculate(search, grid)
142 }
143 }
144 }
145}