From e92259937222eb387d9a053f11bc90d62a816651 Mon Sep 17 00:00:00 2001 From: Zynh0722 Date: Wed, 24 Apr 2024 12:34:07 -0700 Subject: [PATCH] finished? --- Cargo.lock | 16 ++++++ Cargo.toml | 1 + src/airport.rs | 6 +- src/float_ordering.rs | 9 +-- src/main.rs | 128 ++++++++++++++++++++++++++++++++++++------ 5 files changed, 135 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cc1575e..5f23369 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -28,9 +28,25 @@ name = "dijkstras-algo-wu" version = "0.1.0" dependencies = [ "csv", + "itertools", "serde", ] +[[package]] +name = "either" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" + +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.11" diff --git a/Cargo.toml b/Cargo.toml index a066823..9f1cb16 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,4 +7,5 @@ edition = "2021" [dependencies] csv = "1.3.0" +itertools = "0.12.1" serde = { version = "1.0.198", features = ["derive"] } diff --git a/src/airport.rs b/src/airport.rs index 4f6f7b7..d71317c 100644 --- a/src/airport.rs +++ b/src/airport.rs @@ -2,9 +2,9 @@ pub(crate) struct Airport { pub(crate) id: usize, pub(crate) code: String, - pub(crate) name: String, - pub(crate) city: String, - pub(crate) country: String, + pub(crate) _name: String, + pub(crate) _city: String, + pub(crate) _country: String, pub(crate) lat: f64, pub(crate) lon: f64, } diff --git a/src/float_ordering.rs b/src/float_ordering.rs index bbc0608..9745a80 100644 --- a/src/float_ordering.rs +++ b/src/float_ordering.rs @@ -1,16 +1,17 @@ use std::cmp::Ordering; -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialOrd)] pub struct NonNan(pub f64); impl Eq for NonNan {} -impl PartialOrd for NonNan { - fn partial_cmp(&self, other: &Self) -> Option { - Some(other.cmp(self)) +impl PartialEq for NonNan { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 } } +#[allow(clippy::derive_ord_xor_partial_ord)] impl Ord for NonNan { fn cmp(&self, other: &NonNan) -> Ordering { self.partial_cmp(other).unwrap() diff --git a/src/main.rs b/src/main.rs index da1114b..f5dd09c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,3 @@ -#![allow(dead_code)] - mod airport; mod cmd; mod distance; @@ -8,13 +6,18 @@ mod parse; use std::{ cell::RefCell, - collections::{hash_map::Entry, HashMap}, + collections::{hash_map::Entry, BTreeSet, HashMap}, env, + error::Error, f64::INFINITY, + fs::File, + io::BufReader, + ops::Deref, rc::Rc, }; use float_ordering::NonNan; +use itertools::Itertools; use parse::Record; type NodePointer = Rc>; @@ -25,23 +28,60 @@ type Airports = HashMap>; struct Node { origin: Rc, destinations: Vec, - visited: bool, source_distance: NonNan, previous_node: Option, } +#[derive(Clone)] +struct PathFollower { + next_node: Option, +} + +impl Iterator for PathFollower { + type Item = NodePointer; + + fn next(&mut self) -> Option { + if let Some(node) = self.next_node.take() { + self.next_node = node.borrow().previous_node.clone(); + return Some(node); + } + + None + } +} + impl Node { fn new(origin: Rc, destinations: Vec) -> Self { Node { destinations, origin, - visited: false, source_distance: NonNan(INFINITY), previous_node: None, } } } +impl Eq for Node {} +impl PartialEq for Node { + fn eq(&self, other: &Self) -> bool { + other.origin.id == self.origin.id + } +} + +impl Ord for Node { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.source_distance + .cmp(&other.source_distance) + .then_with(|| self.origin.id.cmp(&other.origin.id)) + } +} + +impl PartialOrd for Node { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + #[derive(Clone)] struct Destination { node: NodePointer, @@ -76,9 +116,9 @@ fn insert_airports_from_record(airports: &mut Airports, record: &Record) { entry.insert(Rc::new(airport::Airport { id: record.origin_airport_id, code: record.origin_airport_code.clone(), - name: record.origin_airport.clone(), - city: record.origin_city.clone(), - country: record.origin_country.clone(), + _name: record.origin_airport.clone(), + _city: record.origin_city.clone(), + _country: record.origin_country.clone(), lat: record.origin_airport_latitude, lon: record.origin_airport_longitude, })); @@ -88,18 +128,18 @@ fn insert_airports_from_record(airports: &mut Airports, record: &Record) { entry.insert(Rc::new(airport::Airport { id: record.destination_airport_id, code: record.destination_airport_code.clone(), - name: record.destination_airport.clone(), - city: record.destination_city.clone(), - country: record.destination_country.clone(), + _name: record.destination_airport.clone(), + _city: record.destination_city.clone(), + _country: record.destination_country.clone(), lat: record.destination_airport_latitude, lon: record.destination_airport_longitude, })); } } -fn main() { +fn main() -> Result<(), Box> { // Read all data lines in, ignoring errors - let data: Vec = csv::Reader::from_reader(std::io::stdin()) + let data: Vec = csv::Reader::from_reader(BufReader::new(File::open("routes.csv")?)) .deserialize() .flatten() .collect(); @@ -130,10 +170,9 @@ fn main() { // Populate Edges for record in data { let destination = record.get_destination(&airports, &graph); - if let Entry::Occupied(mut entry) = graph.entry(record.origin_airport_id) { - let mut entry = entry.get_mut().borrow_mut(); - - entry.destinations.push(destination); + if let Entry::Occupied(entry) = graph.entry(record.origin_airport_id) { + let mut node = entry.get().deref().borrow_mut(); + node.destinations.push(destination); }; } @@ -145,5 +184,58 @@ fn main() { let origin = graph[&origin_id].clone(); let destination = graph[&destination_id].clone(); - println!("{:#?} {:#?}", graph[&origin_id], graph[&destination_id]); + origin.deref().borrow_mut().source_distance = NonNan(0.0); + + #[allow(clippy::mutable_key_type)] + let mut unvisited: BTreeSet = BTreeSet::new(); + + for node in graph.values() { + unvisited.insert(node.clone()); + } + + while let Some(current_node) = unvisited.pop_first() { + if current_node.borrow().deref() == destination.borrow().deref() { + break; + } + + for target in ¤t_node.borrow().destinations { + let new_distance = current_node.borrow().source_distance.0 + target.distance; + if new_distance < target.node.borrow().source_distance.0 { + let destination_node = unvisited.take(&target.node).unwrap(); + + { + let mut node_ref = destination_node.deref().borrow_mut(); + node_ref.previous_node = Some(current_node.clone()); + node_ref.source_distance = NonNan(new_distance); + } + + unvisited.insert(destination_node); + } + } + } + + let follower = PathFollower { + next_node: Some(destination.clone()), + }; + + let reversed_path: Vec = follower.collect(); + let path: Vec = reversed_path.into_iter().rev().collect(); + + if path.len() > 1 { + println!( + "Total Distance: {}", + path[path.len() - 1].borrow().source_distance.0 + ); + + println!( + "{}", + path.iter() + .map(|node| node.borrow().origin.code.clone()) + .join("->") + ); + } else { + println!("Path Not Found") + } + + Ok(()) }