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}