diff --git a/lib/dijkstra/src/lib.rs b/lib/dijkstra/src/lib.rs index 1e49f09..f5084ab 100644 --- a/lib/dijkstra/src/lib.rs +++ b/lib/dijkstra/src/lib.rs @@ -6,34 +6,41 @@ type Coordinate = (usize, usize); const START: Coordinate = (0, 0); -pub trait MatrixInner +pub trait Matrix where T: Add + PartialOrd + Debug + Copy, { fn height(&self) -> usize; fn width(&self) -> usize; - fn get(&self, coordinate: &Coordinate) -> &Option>; - fn get_mut(&mut self, coordinate: &Coordinate) -> &mut Option>; + fn get(&self, coordinate: Coordinate) -> Option<&dyn Node>; + fn get_mut(&mut self, coordinate: Coordinate) -> Option<&mut dyn Node>; } -pub trait Matrix: MatrixInner + Debug -where - T: Add + PartialOrd + Debug + Copy, -{ +impl Debug for dyn Matrix { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + todo!() + } } -#[derive(Debug)] -pub struct Dijkstra { - matrix: Box>, +pub struct Dijkstra<'a, T> { + matrix: Box<&'a mut dyn Matrix>, unvisited: HashSet, } -impl Dijkstra +impl<'a, T> Debug for Dijkstra<'a, T> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Dijkstra") + .field("unvisited", &self.unvisited) + .finish() + } +} + +impl<'a, T> Dijkstra<'a, T> where T: PartialOrd + Add + Display + Copy + Debug, { - pub fn new(matrix: Box>) -> Self { - let unvisited = Self::initialize_unvisited_set(&*matrix, START); + pub fn new(matrix: Box<&'a mut dyn Matrix>) -> Self { + let unvisited = Self::initialize_unvisited_set(*matrix, START); Self { matrix, unvisited } } @@ -41,14 +48,7 @@ where while !self.unvisited.is_empty() { let coord = self.get_unvisited_coord_with_smallest_distance_from_start(); let neighbours = self.get_neighbours(&coord); - let previous_distance = *self - .matrix - .get(&coord) - .as_ref() - .unwrap() - .distance - .as_ref() - .unwrap(); + let previous_distance = *self.matrix.get(coord).unwrap().get_distance().unwrap(); for neighbour in neighbours { self.update_neighbour(neighbour, coord, previous_distance); } @@ -60,8 +60,8 @@ where .unvisited .iter() .filter_map(|c| { - let node = self.matrix.get(c).as_ref().unwrap(); - node.distance.map(|value| (c, value)) + let node = self.matrix.get(*c).unwrap(); + node.get_distance().map(|value| (c, value)) }) .reduce(|(c0, v0), (c1, v1)| if v0 < v1 { (c0, v0) } else { (c1, v1) }) .map(|(c, _)| *c) @@ -83,34 +83,17 @@ where } fn update_neighbour(&mut self, next: Coordinate, previous: Coordinate, previous_distance: T) { - let mut next_node = self.matrix.get_mut(&next).as_mut().unwrap(); - let new_distance = previous_distance + next_node.value; - match next_node.distance { - None => { - next_node.distance = Some(new_distance); - next_node.previous = Some(previous); - } - Some(old_distance) => { - if new_distance < old_distance { - next_node.distance = Some(new_distance); - next_node.previous = Some(previous); - } + let next_node = self.matrix.get_mut(next).unwrap(); + let new_distance = previous_distance + *next_node.get_value(); + if let Some(old_distance) = next_node.get_distance() { + if new_distance < *old_distance { + Self::update_node(next_node, new_distance, previous); } + } else { + Self::update_node(next_node, new_distance, previous); } } - pub fn show(&self) { - let result = self - .matrix - .get(&(self.matrix.height() - 1, self.matrix.width() - 1)) - .as_ref() - .unwrap() - .distance - .as_ref() - .unwrap(); - println!("{}", result); - } - fn initialize_unvisited_set(matrix: &dyn Matrix, start: Coordinate) -> HashSet { let unvisited: HashSet<_> = (0..matrix.height()) .flat_map(|x| (0..matrix.width()).zip([x].into_iter().cycle())) @@ -118,27 +101,21 @@ where .collect(); unvisited } -} -#[derive(PartialEq, Eq, Hash, Debug)] -pub struct Node -where - T: Add + PartialOrd, -{ - value: T, - distance: Option, - previous: Option, -} - -impl From for Node -where - T: Add + PartialOrd, -{ - fn from(value: T) -> Self { - Node { - value, - distance: None, - previous: None, - } + fn update_node(next_node: &mut dyn Node, new_distance: T, previous: (usize, usize)) { + next_node.set_distance(new_distance); + next_node.set_previous(previous); } } + +pub trait Node +where + T: Add + PartialOrd, +{ + fn get_value(&self) -> &T; + fn get_distance(&self) -> Option<&T>; + fn get_previous(&self) -> Option; + + fn set_distance(&mut self, distance: T); + fn set_previous(&mut self, coord: Coordinate); +} diff --git a/src/euler81/Cargo.toml b/src/euler81/Cargo.toml index db46247..8c33d0c 100644 --- a/src/euler81/Cargo.toml +++ b/src/euler81/Cargo.toml @@ -6,3 +6,4 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +dijkstra = {version = "*", path = "../../lib/dijkstra"} diff --git a/src/euler81/src/main.rs b/src/euler81/src/main.rs index 4c2a100..205c18d 100644 --- a/src/euler81/src/main.rs +++ b/src/euler81/src/main.rs @@ -1,4 +1,5 @@ -use std::collections::HashSet; +use dijkstra::Dijkstra; +use dijkstra::Matrix as MatrixTrait; use std::fs; use std::path::Path; @@ -16,10 +17,76 @@ const FILENAME: &str = "p081_matrix.txt"; type Coordinate = (usize, usize); +#[derive(Debug)] struct Matrix { data: Vec>, } +#[derive(Debug)] +struct Node { + value: usize, + distance: Option, + previous: Option, +} + +impl dijkstra::Node for Node { + fn get_value(&self) -> &usize { + &self.value + } + + fn get_distance(&self) -> Option<&usize> { + self.distance.as_ref() + } + + fn get_previous(&self) -> Option { + self.previous + } + + fn set_distance(&mut self, distance: usize) { + self.distance = Some(distance); + } + + fn set_previous(&mut self, coord: Coordinate) { + self.previous = Some(coord) + } +} + +impl From for Node { + fn from(value: usize) -> Self { + Self { + value, + distance: None, + previous: None, + } + } +} + +impl MatrixTrait for Matrix { + fn height(&self) -> usize { + self.data.len() + } + + fn width(&self) -> usize { + self.data[0].len() + } + + fn get(&self, (x, y): Coordinate) -> Option<&dyn dijkstra::Node> { + if x < self.width() && y < self.height() { + Some(&self.data[y][x]) + } else { + None + } + } + + fn get_mut(&mut self, (x, y): Coordinate) -> Option<&mut dyn dijkstra::Node> { + if x < self.width() && y < self.height() { + Some(self.data.get_mut(y).unwrap().get_mut(x).unwrap()) + } else { + None + } + } +} + impl Matrix { fn load(f: &Path) -> Self { let mut data: Vec> = fs::read_to_string(f) @@ -28,7 +95,7 @@ impl Matrix { .map(|line| { line.split(',') .into_iter() - .map(|number| number.parse::().unwrap()) + .map(|number| number.parse::().unwrap()) .map(Node::from) .collect() }) @@ -39,110 +106,12 @@ impl Matrix { assert!(data.iter().all(|subvec| subvec.len() == LENGTH)); Self { data } } - - fn get(&self, c: &Coordinate) -> &Node { - &self.data[c.0][c.1] - } } fn main() { - let matrix = Matrix::load(Path::new(FILENAME)); - let mut dijkstra = Dijkstra::new(matrix); + let mut data = Matrix::load(Path::new(FILENAME)); + let mut dijkstra = Dijkstra::new(Box::new(&mut data)); dijkstra.solve(); - dijkstra.show(); -} - -struct Dijkstra { - matrix: Matrix, - unvisited: HashSet, -} - -impl Dijkstra { - fn new(matrix: Matrix) -> Self { - let unvisited: HashSet<_> = (0..LENGTH) - .flat_map(|x| (0..LENGTH).zip([x].into_iter().cycle())) - .filter(|value| *value != (0, 0)) - .collect(); - assert_eq!(unvisited.len(), LENGTH * LENGTH - 1); - Self { matrix, unvisited } - } - - fn solve(&mut self) { - while !self.unvisited.is_empty() { - let coord = self.get_unvisited_coord_with_smallest_distance_from_start(); - let neighbours = self.get_neighbours(&coord); - let previous_distance = self.matrix.get(&coord).distance.unwrap(); - for neighbour in neighbours { - self.update_neighbour(neighbour, coord, previous_distance); - } - } - } - - fn get_unvisited_coord_with_smallest_distance_from_start(&mut self) -> Coordinate { - let coord = self - .unvisited - .iter() - .filter_map(|c| { - let node = self.matrix.get(c); - node.distance.map(|value| (c, value)) - }) - .reduce(|(c0, v0), (c1, v1)| if v0 < v1 { (c0, v0) } else { (c1, v1) }) - .map(|(c, _)| *c) - .unwrap_or((0, 0)); - self.unvisited.remove(&coord); - coord - } - - fn get_neighbours(&self, coordinate: &Coordinate) -> Vec { - let (x0, y0) = coordinate; - let mut result = vec![]; - if *x0 < LENGTH - 1 { - result.push((*x0 + 1, *y0)); - } - if *y0 < LENGTH - 1 { - result.push((*x0, *y0 + 1)); - } - result - } - - fn update_neighbour(&mut self, next: Coordinate, previous: Coordinate, previous_distance: u32) { - let mut next_node = &mut self.matrix.data[next.0][next.1]; - let new_distance = previous_distance + next_node.value; - match next_node.distance { - None => { - next_node.distance = Some(new_distance); - next_node.previous = Some(previous); - } - Some(old_distance) => { - if new_distance < old_distance { - next_node.distance = Some(new_distance); - next_node.previous = Some(previous); - } - } - } - } - - fn show(&self) { - println!( - "{}", - self.matrix.data[LENGTH - 1][LENGTH - 1].distance.unwrap() - ); - } -} - -#[derive(PartialEq, Eq, Hash)] -struct Node { - value: u32, - distance: Option, - previous: Option, -} - -impl From for Node { - fn from(value: u32) -> Self { - Node { - value, - distance: None, - previous: None, - } - } + let result = data.get((LENGTH - 1, LENGTH - 1)).unwrap().get_value(); + println!("{result}"); }