use std::collections::{LinkedList, HashMap, VecDeque};
use std::cmp::{PartialOrd, Ord, Ordering};
#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct Graph(HashMap<String, Vec<(String, usize)>>);
impl Graph {
pub fn new(map: HashMap<String, Vec<(String, usize)>>) -> Self {
Self(map)
}
pub fn find_ways<'t>(&'t self, src: &'t str, dest: &'t str) -> LinkedList<Way> {
let mut ways = LinkedList::from([Way::new(src)]);
while ways.iter().any(|w| w.last().unwrap_or_default() != dest) {
let mut new_ways = LinkedList::new();
for way in ways {
if way.last().unwrap() == dest {
new_ways.push_back(way);
continue;
}
for (neighbor, neighbor_edge) in &self.0[way.last().unwrap()] {
if !way.goes_through(neighbor) {
new_ways.push_back(Way::merge(&way, *neighbor_edge, &Way::new(neighbor)));
}
}
}
ways = new_ways;
}
ways
}
}
#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct Way<'a> {
goes_through: VecDeque<&'a str>,
len: usize,
}
impl<'a> Way<'a> {
pub fn new(node: &'a str) -> Self {
Self {
goes_through: VecDeque::from([node]),
len: 0,
}
}
pub fn length(&self) -> usize { self.len }
pub fn last(&self) -> Option<&'a str> {
self.goes_through.back().copied()
}
pub fn merge(lhs: &Way<'a>, lhs_rhs_edge_w: usize, rhs: &Way<'a>) -> Way<'a> {
let mut new_way = lhs.clone();
new_way.goes_through.extend(&rhs.goes_through);
new_way.len += rhs.len + lhs_rhs_edge_w;
new_way
}
pub fn goes_through(&self, node: &'a str) -> bool {
self.goes_through.contains(&node)
}
}
impl<'a> PartialOrd for Way<'a> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.length().partial_cmp(&other.length())
}
}
impl<'a> Ord for Way<'a> {
fn cmp(&self, other: &Self) -> Ordering {
self.length().cmp(&other.length())
}
}