1use config::*;
2use direction::*;
3use error::*;
4use grid::*;
5use metadata::*;
6use num_traits::Zero;
7use path;
8use search::*;
9use std::ops::Add;
10
11impl<Cost: Copy + Add<Cost> + PartialOrd<Cost> + Zero> SearchContext<Cost> {
12 pub fn dijkstra<G, V, D>(
13 &mut self,
14 grid: &G,
15 start: Coord,
16 goal: Coord,
17 directions: D,
18 config: SearchConfig,
19 path: &mut Vec<Direction>,
20 ) -> Result<SearchMetadata<Cost>, Error>
21 where
22 G: CostGrid<Cost = Cost>,
23 V: Into<Direction>,
24 D: Copy + IntoIterator<Item = V>,
25 {
26 self.search_general(
27 grid,
28 start,
29 goal,
30 directions,
31 |_, _| Zero::zero(),
32 config,
33 path,
34 )
35 }
36
37 pub fn dijkstra_predicate<G, V, D, F>(
38 &mut self,
39 grid: &G,
40 start: Coord,
41 predicate: F,
42 directions: D,
43 config: SearchConfig,
44 path: &mut Vec<Direction>,
45 ) -> Result<SearchMetadata<Cost>, Error>
46 where
47 G: CostGrid<Cost = Cost>,
48 V: Into<Direction>,
49 D: Copy + IntoIterator<Item = V>,
50 F: Fn(Coord) -> bool,
51 {
52 let initial_entry = match self.init(start, &predicate, grid, config, path) {
53 Ok(initial_entry) => initial_entry,
54 Err(result) => return result,
55 };
56
57 self.priority_queue.push(initial_entry);
58
59 let mut num_nodes_visited = 0;
60
61 while let Some(current_entry) = self.priority_queue.pop() {
62 num_nodes_visited += 1;
63
64 let (current_coord, current_cost) = {
65 let node = &mut self.node_grid[current_entry.node_index];
66
67 if node.visited == self.seq {
68 continue;
69 }
70 node.visited = self.seq;
71 (node.coord, node.cost)
72 };
73
74 if predicate(current_coord) {
75 path::make_path_all_adjacent(&self.node_grid, current_entry.node_index, path);
76 return Ok(SearchMetadata {
77 num_nodes_visited,
78 cost: current_cost,
79 length: path.len(),
80 });
81 }
82
83 for d in directions {
84 let direction = d.into();
85 let neighbour_coord = current_coord + direction.coord();
86
87 let neighbour_cost =
88 if let Some(CostCell::Cost(cost)) = grid.cost(neighbour_coord, direction) {
89 cost
90 } else {
91 continue;
92 };
93
94 let index = self
95 .node_grid
96 .index_of_coord(neighbour_coord)
97 .ok_or(Error::VisitOutsideContext)?;
98
99 let cost = current_cost + neighbour_cost;
100 let node = &mut self.node_grid[index];
101
102 if node.seen != self.seq || node.cost > cost {
103 node.from_parent = Some(direction);
104 node.seen = self.seq;
105 node.cost = cost;
106
107 let entry = PriorityEntry::new(index, cost);
108 self.priority_queue.push(entry);
109 }
110 }
111 }
112
113 Err(Error::NoPath)
114 }
115}