use std::collections::{HashMap, HashSet, VecDeque};
use std::hash::Hash;
pub fn bfs_distances<Node, F>(start: Node, neighbors: F) -> HashMap<Node, u32>
where
Node: Eq + Hash + Copy,
F: Fn(Node) -> Vec<Node>,
{
let mut distances = HashMap::new();
let mut queue = VecDeque::new();
distances.insert(start, 0);
queue.push_back(start);
while let Some(current) = queue.pop_front() {
let current_distance = distances[¤t];
for neighbor in neighbors(current) {
if !distances.contains_key(&neighbor) {
distances.insert(neighbor, current_distance + 1);
queue.push_back(neighbor);
}
}
}
distances
}
pub fn get_path<Node, F>(
start: Node,
goal: Node,
distances: &HashMap<Node, u32>,
neighbors: F,
) -> Option<Vec<Node>>
where
Node: Eq + Hash + Copy,
F: Fn(Node) -> Vec<Node>,
{
if !distances.contains_key(&goal) {
return None;
}
let mut path = Vec::new();
let mut current = goal;
path.push(current);
while current != start {
let current_distance = distances[¤t];
let prev_opt = neighbors(current)
.into_iter()
.find(|&n| distances.get(&n).map_or(false, |&d| d == current_distance - 1));
if let Some(prev) = prev_opt {
path.push(prev);
current = prev;
} else {
return None;
}
}
path.reverse();
Some(path)
}
pub fn all_connected<Node, F>(start: Node, neighbors: F) -> HashSet<Node>
where
Node: Eq + Hash + Copy,
F: Fn(Node) -> Vec<Node>,
{
let mut connected = HashSet::new();
let mut queue = VecDeque::new();
connected.insert(start);
queue.push_back(start);
while let Some(current) = queue.pop_front() {
for neighbor in neighbors(current) {
if connected.insert(neighbor) {
queue.push_back(neighbor);
}
}
}
connected
}