make dijkstra generic

breaks 81
This commit is contained in:
Dr. Matthias Ratajczak
2022-09-26 18:16:46 +02:00
parent 6e30da5371
commit 2986c3f860
3 changed files with 119 additions and 172 deletions
+1
View File
@@ -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"}
+73 -104
View File
@@ -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<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)
@@ -28,7 +95,7 @@ impl Matrix {
.map(|line| {
line.split(',')
.into_iter()
.map(|number| number.parse::<u32>().unwrap())
.map(|number| number.parse::<usize>().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<Coordinate>,
}
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<Coordinate> {
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<u32>,
previous: Option<Coordinate>,
}
impl From<u32> 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}");
}