use crate::scoring;
use crate::{create_network, City};
use log::{debug, info};
use std::collections::HashMap;
use std::collections::HashSet;
pub fn traverse(source: City) -> HashMap<u32, Vec<City>> {
let mut routes: HashMap<u32, Vec<City>> = HashMap::new();
let mut route_id: u32 = 0;
let mut current_route: Vec<City> = Vec::new();
let mut trains: u8 = 45;
let graph = create_network();
let mut current_city: City = source.clone();
debug!("Current city {:?}", current_city);
let mut visited: HashMap<City, HashSet<City>> = HashMap::new();
let mut backtracking: bool = false;
current_route.push(current_city);
debug!("current_route {:?}", current_route);
visited.insert(current_city, HashSet::new());
while !current_route.is_empty() {
let mut destinations = graph
.get(¤t_city)
.unwrap()
.iter()
.filter(|city| match city {
(k, _) => {
!visited[¤t_city].contains(k) && !current_route.iter().any(|i| i == *k)
}
});
let dest = destinations.next();
debug!("Destination: {:?}", dest);
match dest {
Some((next, distance)) => {
backtracking = false;
if trains >= *distance {
visited
.entry(*next)
.or_insert(HashSet::new())
.insert(current_city);
visited
.entry(current_city)
.or_insert(HashSet::new())
.insert(*next);
current_city = *next;
current_route.push(current_city);
debug!("current_route: {:?}", current_route);
trains -= *distance;
} else {
visited
.entry(current_city)
.or_insert(HashSet::new())
.insert(*next);
}
}
None => {
if backtracking == false {
if scoring::big_ticket_score(¤t_route) != 0 && trains <= 2 {
debug!("current_route before added to routes: {:?}", current_route);
routes.insert(route_id, current_route.clone());
route_id += 1;
}
backtracking = true;
}
let dead_end = current_route.pop().unwrap();
visited.insert(dead_end, HashSet::new());
match current_route.last() {
Some(city) => {
current_city = *city;
trains += graph.get(¤t_city).unwrap()[&dead_end];
}
None => info!("Route {:?} is the last one", route_id),
};
}
}
}
routes
}
pub fn dijkstra(
source: City,
arrival: City,
stop: bool,
) -> (HashMap<City, u8>, HashMap<City, City>) {
let graph = create_network();
let mut dist: HashMap<City, u8> = HashMap::new();
let mut prev: HashMap<City, City> = HashMap::new();
let mut q: Vec<City> = Vec::new();
let mut u: City;
for (city, _) in graph.iter() {
dist.insert(*city, 100);
q.push(*city);
}
dist.insert(source, 0);
while !q.is_empty() {
u = q[0];
for city in q.iter() {
if dist.get(&city).unwrap() < dist.get(&u).unwrap() {
u = *city;
}
}
if u == arrival && stop == true {
break;
}
let index = q.iter().position(|&x| x == u).unwrap();
q.remove(index);
let destinations = graph.get(&u).unwrap();
for (destination, distance) in destinations.iter() {
if q.iter().any(|i| i == destination) {
let alt = dist.get(&u).unwrap() + *distance;
if alt < *dist.get(&destination).unwrap() && alt <= 45 {
dist.insert(*destination, alt);
prev.insert(*destination, u);
}
}
}
}
return (dist, prev);
}