use super::*;
use std::io::{self, Error, ErrorKind};
struct WNodes {
nodes: Vec<Node>,
weight: u32,
}
pub fn path<'a>(
network: &'a Network<Node>,
a: &str,
b: &str,
algorithm: &Fn(&Network<Node>, Node, Node) -> io::Result<Vec<Node>>,
) -> io::Result<Vec<Node>> {
let opt_goal = network.get(b);
let opt_start = network.get(a);
if opt_goal.is_none() || opt_start.is_none() {
Err(Error::new(
ErrorKind::Other,
"Start or Goal path does not exist in Network",
))
} else {
algorithm(&network, opt_start.unwrap(), opt_goal.unwrap())
}
}
pub fn get(network: &Network<Node>, element: &str) -> Option<Node> {
let hash = node!(element, 0, 0).hash;
for (i, elem) in network.hash_map.iter().enumerate() {
if elem.is_some() && i == hash as usize % consts::NETWORK_REM {
return network.hash_map[i];
}
}
None
}
pub fn path_shortest_leg<'a>(
network: &'a Network<Node>,
start: Node,
goal: Node,
) -> io::Result<Vec<Node>> {
let format = |mut nodes: Vec<Node>, link: &HL, acc: u32| -> WNodes {
let node = network.hash_map[link.t as usize % consts::NETWORK_REM].unwrap();
let weight = acc + coordinate::distance(nodes.first().unwrap().geo, node.geo);
nodes.insert(0, node);
WNodes { weight, nodes }
};
let mut queue: Vec<WNodes> = start
.links()
.iter()
.filter(|x| x.is_connected())
.map(|x| format(vec![start], x, 0))
.collect::<Vec<_>>();
while !queue.is_empty() {
queue.sort_by_key(|wn| wn.weight);
let wnodes = queue.remove(0);
let current = wnodes.nodes.first().unwrap();
if current.hash == goal.hash {
return Ok(wnodes.nodes);
}
let _ = current
.links()
.iter()
.filter(|x| x.is_connected())
.map(|x| queue.push(format(wnodes.nodes.clone(), x, wnodes.weight)))
.collect::<Vec<_>>();
}
Err(Error::new(ErrorKind::Other, "not a valid path"))
}
#[cfg(test)]
mod tests {
use super::*;
fn nodes() -> Vec<Node> {
let nodes = Node::from_list(&[(0, 0), (10, 10), (20, 20), (30, 30)]);
Node::linked_list(nodes)
}
fn network() -> Network<Node> {
Network::new(nodes())
}
#[test]
fn simple_network_shortest_leg() {
let network = network();
let path = path(&network, "D", "A", &path_shortest_leg).unwrap();
assert_eq!(path.len(), 4);
}
#[test]
fn simple_network() {
let path = network().path("A", "D").unwrap();
assert_eq!(path.len(), 4);
}
#[test]
fn simple_network_start_in_the_middle() {
let path = network().path("C", "D").unwrap();
assert_eq!(path.len(), 2);
}
#[test]
fn simple_network_end_in_the_middle() {
let path = network().path("C", "D").unwrap();
assert_eq!(path.len(), 2);
}
#[test]
fn simple_networks_have_same_path() {
let net = network();
let mut path_sl = path(&net, "D", "A", &path_shortest_leg).unwrap();
let path = net.path("A", "D").unwrap();
path_sl.reverse();
let f = |&p: &Node| p.geo;
let v1 = path.iter().map(f).collect::<Vec<_>>();
let v2 = path_sl.iter().map(f).collect::<Vec<_>>();
assert_eq!(v1, v2);
}
#[test]
fn valid_gets() {
let network = network();
for l in ["A", "B", "C", "D"].iter() {
assert!(get(&network, l).is_some());
}
}
#[test]
fn invalid_gets() {
let network = network();
for l in ["", "<>", "Test", "E", "AA", "EE", "f", "a"].iter() {
assert!(get(&network, l).is_none());
}
}
#[test]
fn invalid_network_1() {
assert!(network().path("B", "E").is_err());
}
#[test]
fn invalid_network_2() {
assert!(network().path("Testing", "One, two, Three.").is_err());
}
#[test]
fn invalid_network_3() {
assert!(network().path("", "<").is_err());
}
#[test]
fn invalid_network_4() {
assert!(network().path("<html>", "{json:test}").is_err());
}
}