use std::fmt;
#[derive(Copy, Clone, PartialEq)]
struct Node(&'static str, i32, i32);
impl Node {
pub fn distance(&self, other: &Self) -> u32 {
let x = (other.1 - self.1) as f32;
let y = (other.2 - self.2) as f32;
(x*x + y*y).sqrt() as u32
}
}
impl transiter::IntoTransIter<Path> for Node {
fn trans_iter_with<F: FnMut(&Path) -> I, I: IntoIterator<Item = Path>>(
self,
recursion: F
) -> transiter::TransIter<F, I, Path> {
Path::new(self).trans_iter_with(recursion)
}
}
#[derive(Clone)]
struct Path {
data: Vec<Node>
}
impl Path {
pub fn new(first: Node) -> Self {
Self {data: vec![first]}
}
pub fn last(&self) -> Node {
self.data.last().unwrap().clone()
}
pub fn with(&self, next: Node) -> Self {
let mut data = self.data.clone();
data.push(next);
Self {data}
}
pub fn len(&self) -> u32 {
self.data.windows(2).map(|p| p[0].distance(&p[1])).sum()
}
}
impl fmt::Display for Path {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.data.iter().try_for_each(|n| n.0.fmt(f))
}
}
impl Ord for Path {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
Ord::cmp(&other.len(), &self.len())
}
}
impl PartialOrd for Path {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
PartialOrd::partial_cmp(&other.len(), &self.len())
}
}
impl Eq for Path {}
impl PartialEq for Path {
fn eq(&self, other: &Self) -> bool {
PartialEq::eq(&self.len(), &other.len())
}
}
fn main() {
use transiter::IntoTransIter;
let mut nodes = vec![
Node("A", 45, 59),
Node("B", 68, 69),
Node("C", 32, 78),
Node("D", 15, 65),
Node("E", 45, 12),
Node("F", 98, 80),
];
let range = 50;
let path = Node("S", 0, 0)
.trans_prio_queue_with(move |path: &Path| {
let current = path.last();
let in_range = |next: &Node| current.distance(next) < range;
let res: Vec<_> = nodes.iter().filter(|n| in_range(n)).map(|n| path.with(*n)).collect();
nodes.retain(|n| !in_range(n));
res
})
.inspect(|path| eprintln!("{} {}", path, path.len()))
.find(|path| path.last().0 == "F")
.expect("Could not find path");
println!("S->F: {}, length: {}", path, path.len());
}