From ab4b003fcd8b67be5e9495643b69d014678c3e35 Mon Sep 17 00:00:00 2001 From: "Dr. Matthias Ratajczak" Date: Tue, 27 Sep 2022 13:32:08 +0200 Subject: [PATCH] refactor 81 and dijkstra --- lib/dijkstra/src/lib.rs | 50 ++++++++++++++++----- src/euler81/src/lib.rs | 94 ++++++++++++++++++++++++++++++++++++++ src/euler81/src/main.rs | 99 ++--------------------------------------- 3 files changed, 137 insertions(+), 106 deletions(-) create mode 100644 src/euler81/src/lib.rs diff --git a/lib/dijkstra/src/lib.rs b/lib/dijkstra/src/lib.rs index 7dd66f7..8ba2e6b 100644 --- a/lib/dijkstra/src/lib.rs +++ b/lib/dijkstra/src/lib.rs @@ -6,6 +6,30 @@ type Coordinate = (usize, usize); const START: Coordinate = (0, 0); +pub enum AllowedMovements { + DownRight, + DownRightUp, +} + +impl AllowedMovements { + fn get_neighbours(&self, c: &Coordinate) -> Vec { + match self { + Self::DownRight => self.get_neighbours_down_right(c), + Self::DownRightUp => self.get_neighbours_down_right_up(c), + } + } + + fn get_neighbours_down_right(&self, (x0, y0): &Coordinate) -> Vec { + vec![(*x0 + 1, *y0), (*x0, *y0 + 1)] + } + + fn get_neighbours_down_right_up(&self, (x0, y0): &Coordinate) -> Vec { + let mut result = self.get_neighbours_down_right(&(*x0, *y0)); + result.push((*x0, *y0 - 1)); + result + } +} + pub trait Matrix where T: Add + PartialOrd + Debug + Copy, @@ -26,6 +50,7 @@ pub struct Dijkstra<'a, T> { matrix: &'a mut dyn Matrix, unvisited_with_distance: HashSet, unvisited_without_distance: HashSet, + allowed_movements: AllowedMovements, } impl<'a, T> Debug for Dijkstra<'a, T> { @@ -40,13 +65,14 @@ impl<'a, T> Dijkstra<'a, T> where T: PartialOrd + Add + Display + Copy + Debug, { - pub fn new(matrix: &'a mut dyn Matrix) -> Self { + pub fn new(matrix: &'a mut dyn Matrix, allowed_movements: AllowedMovements) -> Self { let unvisited_with_distance = HashSet::new(); let unvisited_without_distance = Self::initialize_unvisited_set(&*matrix, START); Self { matrix, unvisited_with_distance, unvisited_without_distance, + allowed_movements, } } @@ -79,15 +105,19 @@ where } fn get_neighbours(&self, coordinate: &Coordinate) -> Vec { - let (x0, y0) = coordinate; - let mut result = vec![]; - if *x0 < self.matrix.width() - 1 { - result.push((*x0 + 1, *y0)); - } - if *y0 < self.matrix.height() - 1 { - result.push((*x0, *y0 + 1)); - } - result + let possible_neighbours = self.allowed_movements.get_neighbours(coordinate); + self.remove_out_of_bounds_neighbours(possible_neighbours) + } + + fn remove_out_of_bounds_neighbours(&self, neighbours: Vec) -> Vec { + neighbours + .into_iter() + .filter(|c| self.is_in_bounds(c)) + .collect() + } + + fn is_in_bounds(&self, (x, y): &Coordinate) -> bool { + *x < self.matrix.width() && *y < self.matrix.height() } fn update_neighbour(&mut self, next: Coordinate, previous: Coordinate, previous_distance: T) { diff --git a/src/euler81/src/lib.rs b/src/euler81/src/lib.rs new file mode 100644 index 0000000..414d0bc --- /dev/null +++ b/src/euler81/src/lib.rs @@ -0,0 +1,94 @@ +use dijkstra::{Matrix as MatrixTrait, Node as NodeTrait}; +use std::fs; +use std::path::Path; + +type Coordinate = (usize, usize); + +#[derive(Debug)] +pub struct Matrix { + data: Vec>, +} + +#[derive(Debug)] +pub struct Node { + value: usize, + distance: Option, + previous: Option, +} + +impl NodeTrait 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 NodeTrait> { + 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 NodeTrait> { + if x < self.width() && y < self.height() { + Some(self.data.get_mut(y).unwrap().get_mut(x).unwrap()) + } else { + None + } + } +} + +impl Matrix { + pub fn load(f: &Path) -> Self { + let mut data: Vec> = fs::read_to_string(f) + .unwrap() + .split_whitespace() + .map(|line| { + line.split(',') + .into_iter() + .map(|number| number.parse::().unwrap()) + .map(Node::from) + .collect() + }) + .collect(); + let mut start = &mut data[0][0]; + start.distance = Some(start.value); + Self { data } + } +} diff --git a/src/euler81/src/main.rs b/src/euler81/src/main.rs index 11bad4f..3f57ab5 100644 --- a/src/euler81/src/main.rs +++ b/src/euler81/src/main.rs @@ -1,6 +1,6 @@ -use dijkstra::Dijkstra; use dijkstra::Matrix as MatrixTrait; -use std::fs; +use dijkstra::{AllowedMovements, Dijkstra}; +use euler81::Matrix; use std::path::Path; #[cfg(debug_assertions)] @@ -15,102 +15,9 @@ const FILENAME: &str = "p081_test.txt"; #[cfg(not(debug_assertions))] 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) - .unwrap() - .split_whitespace() - .map(|line| { - line.split(',') - .into_iter() - .map(|number| number.parse::().unwrap()) - .map(Node::from) - .collect() - }) - .collect(); - let mut start = &mut data[0][0]; - start.distance = Some(start.value); - assert_eq!(data.len(), LENGTH); - assert!(data.iter().all(|subvec| subvec.len() == LENGTH)); - Self { data } - } -} - fn main() { let mut matrix = Matrix::load(Path::new(FILENAME)); - let mut dijkstra = Dijkstra::new(&mut matrix); + let mut dijkstra = Dijkstra::new(&mut matrix, AllowedMovements::DownRight); dijkstra.solve(); let result = matrix .get((LENGTH - 1, LENGTH - 1))