refactor 81 and dijkstra

This commit is contained in:
Dr. Matthias Ratajczak
2022-09-27 13:32:08 +02:00
parent 1b5cacd407
commit ab4b003fcd
3 changed files with 137 additions and 106 deletions
+38 -8
View File
@@ -6,6 +6,30 @@ type Coordinate = (usize, usize);
const START: Coordinate = (0, 0); const START: Coordinate = (0, 0);
pub enum AllowedMovements {
DownRight,
DownRightUp,
}
impl AllowedMovements {
fn get_neighbours(&self, c: &Coordinate) -> Vec<Coordinate> {
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<Coordinate> {
vec![(*x0 + 1, *y0), (*x0, *y0 + 1)]
}
fn get_neighbours_down_right_up(&self, (x0, y0): &Coordinate) -> Vec<Coordinate> {
let mut result = self.get_neighbours_down_right(&(*x0, *y0));
result.push((*x0, *y0 - 1));
result
}
}
pub trait Matrix<T> pub trait Matrix<T>
where where
T: Add + PartialOrd + Debug + Copy, T: Add + PartialOrd + Debug + Copy,
@@ -26,6 +50,7 @@ pub struct Dijkstra<'a, T> {
matrix: &'a mut dyn Matrix<T>, matrix: &'a mut dyn Matrix<T>,
unvisited_with_distance: HashSet<Coordinate>, unvisited_with_distance: HashSet<Coordinate>,
unvisited_without_distance: HashSet<Coordinate>, unvisited_without_distance: HashSet<Coordinate>,
allowed_movements: AllowedMovements,
} }
impl<'a, T> Debug for Dijkstra<'a, T> { impl<'a, T> Debug for Dijkstra<'a, T> {
@@ -40,13 +65,14 @@ impl<'a, T> Dijkstra<'a, T>
where where
T: PartialOrd + Add<Output = T> + Display + Copy + Debug, T: PartialOrd + Add<Output = T> + Display + Copy + Debug,
{ {
pub fn new(matrix: &'a mut dyn Matrix<T>) -> Self { pub fn new(matrix: &'a mut dyn Matrix<T>, allowed_movements: AllowedMovements) -> Self {
let unvisited_with_distance = HashSet::new(); let unvisited_with_distance = HashSet::new();
let unvisited_without_distance = Self::initialize_unvisited_set(&*matrix, START); let unvisited_without_distance = Self::initialize_unvisited_set(&*matrix, START);
Self { Self {
matrix, matrix,
unvisited_with_distance, unvisited_with_distance,
unvisited_without_distance, unvisited_without_distance,
allowed_movements,
} }
} }
@@ -79,15 +105,19 @@ where
} }
fn get_neighbours(&self, coordinate: &Coordinate) -> Vec<Coordinate> { fn get_neighbours(&self, coordinate: &Coordinate) -> Vec<Coordinate> {
let (x0, y0) = coordinate; let possible_neighbours = self.allowed_movements.get_neighbours(coordinate);
let mut result = vec![]; self.remove_out_of_bounds_neighbours(possible_neighbours)
if *x0 < self.matrix.width() - 1 {
result.push((*x0 + 1, *y0));
} }
if *y0 < self.matrix.height() - 1 {
result.push((*x0, *y0 + 1)); fn remove_out_of_bounds_neighbours(&self, neighbours: Vec<Coordinate>) -> Vec<Coordinate> {
neighbours
.into_iter()
.filter(|c| self.is_in_bounds(c))
.collect()
} }
result
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) { fn update_neighbour(&mut self, next: Coordinate, previous: Coordinate, previous_distance: T) {
+94
View File
@@ -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<Vec<Node>>,
}
#[derive(Debug)]
pub struct Node {
value: usize,
distance: Option<usize>,
previous: Option<Coordinate>,
}
impl NodeTrait<usize> for Node {
fn get_value(&self) -> &usize {
&self.value
}
fn get_distance(&self) -> Option<&usize> {
self.distance.as_ref()
}
fn get_previous(&self) -> Option<Coordinate> {
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<usize> for Node {
fn from(value: usize) -> Self {
Self {
value,
distance: None,
previous: None,
}
}
}
impl MatrixTrait<usize> 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<usize>> {
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<usize>> {
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<Vec<_>> = fs::read_to_string(f)
.unwrap()
.split_whitespace()
.map(|line| {
line.split(',')
.into_iter()
.map(|number| number.parse::<usize>().unwrap())
.map(Node::from)
.collect()
})
.collect();
let mut start = &mut data[0][0];
start.distance = Some(start.value);
Self { data }
}
}
+3 -96
View File
@@ -1,6 +1,6 @@
use dijkstra::Dijkstra;
use dijkstra::Matrix as MatrixTrait; use dijkstra::Matrix as MatrixTrait;
use std::fs; use dijkstra::{AllowedMovements, Dijkstra};
use euler81::Matrix;
use std::path::Path; use std::path::Path;
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
@@ -15,102 +15,9 @@ const FILENAME: &str = "p081_test.txt";
#[cfg(not(debug_assertions))] #[cfg(not(debug_assertions))]
const FILENAME: &str = "p081_matrix.txt"; const FILENAME: &str = "p081_matrix.txt";
type Coordinate = (usize, usize);
#[derive(Debug)]
struct Matrix {
data: Vec<Vec<Node>>,
}
#[derive(Debug)]
struct Node {
value: usize,
distance: Option<usize>,
previous: Option<Coordinate>,
}
impl dijkstra::Node<usize> for Node {
fn get_value(&self) -> &usize {
&self.value
}
fn get_distance(&self) -> Option<&usize> {
self.distance.as_ref()
}
fn get_previous(&self) -> Option<Coordinate> {
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<usize> for Node {
fn from(value: usize) -> Self {
Self {
value,
distance: None,
previous: None,
}
}
}
impl MatrixTrait<usize> 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<usize>> {
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<usize>> {
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<Vec<_>> = fs::read_to_string(f)
.unwrap()
.split_whitespace()
.map(|line| {
line.split(',')
.into_iter()
.map(|number| number.parse::<usize>().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() { fn main() {
let mut matrix = Matrix::load(Path::new(FILENAME)); 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(); dijkstra.solve();
let result = matrix let result = matrix
.get((LENGTH - 1, LENGTH - 1)) .get((LENGTH - 1, LENGTH - 1))