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
//! Compute a shortest path using the [breadth-first search //! algorithm](https://en.wikipedia.org/wiki/Breadth-first_search). use indexmap::map::Entry::Vacant; use indexmap::IndexMap; use std::collections::{HashSet, VecDeque}; use std::hash::Hash; use std::usize; use super::reverse_path; /// Compute a shortest path using the [breadth-first search /// algorithm](https://en.wikipedia.org/wiki/Breadth-first_search). /// /// The shortest path starting from `start` up to a node for which `success` returns `true` is /// computed and returned in a `Some`. If no path can be found, `None` /// is returned instead. /// /// - `start` is the starting node. /// - `successors` returns a list of successors for a given node. /// - `success` checks whether the goal has been reached. It is not a node as some problems require /// a dynamic solution instead of a fixed node. /// /// A node will never be included twice in the path as determined by the `Eq` relationship. /// /// The returned path comprises both the start and end node. /// /// # Example /// /// We will search the shortest path on a chess board to go from (1, 1) to (4, 6) doing only knight /// moves. /// /// The first version uses an explicit type `Pos` on which the required traits are derived. /// /// ``` /// use pathfinding::prelude::bfs; /// /// #[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] /// struct Pos(i32, i32); /// /// impl Pos { /// fn successors(&self) -> Vec<Pos> { /// let &Pos(x, y) = self; /// vec![Pos(x+1,y+2), Pos(x+1,y-2), Pos(x-1,y+2), Pos(x-1,y-2), /// Pos(x+2,y+1), Pos(x+2,y-1), Pos(x-2,y+1), Pos(x-2,y-1)] /// } /// } /// /// static GOAL: Pos = Pos(4, 6); /// let result = bfs(&Pos(1, 1), |p| p.successors(), |p| *p == GOAL); /// assert_eq!(result.expect("no path found").len(), 5); /// ``` /// /// The second version does not declare a `Pos` type, makes use of more closures, /// and is thus shorter. /// /// ``` /// use pathfinding::prelude::bfs; /// /// static GOAL: (i32, i32) = (4, 6); /// let result = bfs(&(1, 1), /// |&(x, y)| vec![(x+1,y+2), (x+1,y-2), (x-1,y+2), (x-1,y-2), /// (x+2,y+1), (x+2,y-1), (x-2,y+1), (x-2,y-1)], /// |&p| p == GOAL); /// assert_eq!(result.expect("no path found").len(), 5); /// ``` pub fn bfs<N, FN, IN, FS>(start: &N, successors: FN, success: FS) -> Option<Vec<N>> where N: Eq + Hash + Clone, FN: FnMut(&N) -> IN, IN: IntoIterator<Item = N>, FS: FnMut(&N) -> bool, { bfs_core(start, successors, success, true) } fn bfs_core<N, FN, IN, FS>( start: &N, mut successors: FN, mut success: FS, check_first: bool, ) -> Option<Vec<N>> where N: Eq + Hash + Clone, FN: FnMut(&N) -> IN, IN: IntoIterator<Item = N>, FS: FnMut(&N) -> bool, { if check_first && success(start) { return Some(vec![start.clone()]); } let mut to_see = VecDeque::new(); let mut parents: IndexMap<N, usize> = IndexMap::new(); to_see.push_back(0); parents.insert(start.clone(), usize::max_value()); while let Some(i) = to_see.pop_front() { let node = parents.get_index(i).unwrap().0; for successor in successors(node) { if success(&successor) { let mut path = reverse_path(&parents, |&p| p, i); path.push(successor); return Some(path); } if let Vacant(e) = parents.entry(successor) { to_see.push_back(e.index()); e.insert(i); } } } None } /// Return one of the shortest loop from start to start if it exists, `None` otherwise. /// /// - `start` is the starting node. /// - `successors` returns a list of successors for a given node. /// /// Except the start node which will be included both at the beginning and the end of /// the path, a node will never be included twice in the path as determined /// by the `Eq` relationship. pub fn bfs_loop<N, FN, IN>(start: &N, successors: FN) -> Option<Vec<N>> where N: Eq + Hash + Clone, FN: FnMut(&N) -> IN, IN: IntoIterator<Item = N>, { bfs_core(start, successors, |n| n == start, false) } /// Visit all nodes that are reachable from a start node. The node will be visited /// in BFS order, starting from the `start` node and following the order returned /// by the `successors` function. /// /// # Examples /// /// The iterator stops when there are no new nodes to visit: /// /// ``` /// use pathfinding::prelude::bfs_reach; /// /// let all_nodes = bfs_reach(3, |_| (1..=5)).collect::<Vec<_>>(); /// assert_eq!(all_nodes, vec![3, 1, 2, 4, 5]); /// ``` /// /// The iterator can be used as a generator. Here are for examples /// the multiples of 2 and 3 (although not in natural order but in /// the order they are discovered by the BFS algorithm): /// /// ``` /// use pathfinding::prelude::bfs_reach; /// /// let mut it = bfs_reach(1, |&n| vec![n*2, n*3]).skip(1); /// assert_eq!(it.next(), Some(2)); // 1*2 /// assert_eq!(it.next(), Some(3)); // 1*3 /// assert_eq!(it.next(), Some(4)); // (1*2)*2 /// assert_eq!(it.next(), Some(6)); // (1*2)*3 /// // (1*3)*2 == 6 which has been seen already /// assert_eq!(it.next(), Some(9)); // (1*3)*3 /// assert_eq!(it.next(), Some(8)); // ((1*2)*2)*2 /// assert_eq!(it.next(), Some(12)); // ((1*2)*2)*3 /// ``` pub fn bfs_reach<N, FN, IN>(start: N, successors: FN) -> BfsReachable<N, FN> where N: Eq + Hash + Clone, FN: FnMut(&N) -> IN, IN: IntoIterator<Item = N>, { let (mut to_see, mut seen) = (VecDeque::new(), HashSet::new()); to_see.push_back(start.clone()); seen.insert(start); BfsReachable { to_see, seen, successors, } } /// Struct returned by [`bfs_reach`](crate::directed::bfs::bfs_reach). pub struct BfsReachable<N, FN> { to_see: VecDeque<N>, seen: HashSet<N>, successors: FN, } impl<N, FN, IN> Iterator for BfsReachable<N, FN> where N: Eq + Hash + Clone, FN: FnMut(&N) -> IN, IN: IntoIterator<Item = N>, { type Item = N; fn next(&mut self) -> Option<Self::Item> { if let Some(n) = self.to_see.pop_front() { for s in (self.successors)(&n) { if !self.seen.contains(&s) { self.to_see.push_back(s.clone()); self.seen.insert(s); } } Some(n) } else { None } } }