make dijkstra generic
breaks 81
This commit is contained in:
+41
-64
@@ -6,34 +6,41 @@ type Coordinate = (usize, usize);
|
|||||||
|
|
||||||
const START: Coordinate = (0, 0);
|
const START: Coordinate = (0, 0);
|
||||||
|
|
||||||
pub trait MatrixInner<T>
|
pub trait Matrix<T>
|
||||||
where
|
where
|
||||||
T: Add + PartialOrd + Debug + Copy,
|
T: Add + PartialOrd + Debug + Copy,
|
||||||
{
|
{
|
||||||
fn height(&self) -> usize;
|
fn height(&self) -> usize;
|
||||||
fn width(&self) -> usize;
|
fn width(&self) -> usize;
|
||||||
fn get(&self, coordinate: &Coordinate) -> &Option<Node<T>>;
|
fn get(&self, coordinate: Coordinate) -> Option<&dyn Node<T>>;
|
||||||
fn get_mut(&mut self, coordinate: &Coordinate) -> &mut Option<Node<T>>;
|
fn get_mut(&mut self, coordinate: Coordinate) -> Option<&mut dyn Node<T>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Matrix<T>: MatrixInner<T> + Debug
|
impl<T> Debug for dyn Matrix<T> {
|
||||||
where
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
T: Add + PartialOrd + Debug + Copy,
|
todo!()
|
||||||
{
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
pub struct Dijkstra<'a, T> {
|
||||||
pub struct Dijkstra<T> {
|
matrix: Box<&'a mut dyn Matrix<T>>,
|
||||||
matrix: Box<dyn Matrix<T>>,
|
|
||||||
unvisited: HashSet<Coordinate>,
|
unvisited: HashSet<Coordinate>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Dijkstra<T>
|
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
|
where
|
||||||
T: PartialOrd + Add<Output = T> + Display + Copy + Debug,
|
T: PartialOrd + Add<Output = T> + Display + Copy + Debug,
|
||||||
{
|
{
|
||||||
pub fn new(matrix: Box<dyn Matrix<T>>) -> Self {
|
pub fn new(matrix: Box<&'a mut dyn Matrix<T>>) -> Self {
|
||||||
let unvisited = Self::initialize_unvisited_set(&*matrix, START);
|
let unvisited = Self::initialize_unvisited_set(*matrix, START);
|
||||||
Self { matrix, unvisited }
|
Self { matrix, unvisited }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,14 +48,7 @@ where
|
|||||||
while !self.unvisited.is_empty() {
|
while !self.unvisited.is_empty() {
|
||||||
let coord = self.get_unvisited_coord_with_smallest_distance_from_start();
|
let coord = self.get_unvisited_coord_with_smallest_distance_from_start();
|
||||||
let neighbours = self.get_neighbours(&coord);
|
let neighbours = self.get_neighbours(&coord);
|
||||||
let previous_distance = *self
|
let previous_distance = *self.matrix.get(coord).unwrap().get_distance().unwrap();
|
||||||
.matrix
|
|
||||||
.get(&coord)
|
|
||||||
.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.distance
|
|
||||||
.as_ref()
|
|
||||||
.unwrap();
|
|
||||||
for neighbour in neighbours {
|
for neighbour in neighbours {
|
||||||
self.update_neighbour(neighbour, coord, previous_distance);
|
self.update_neighbour(neighbour, coord, previous_distance);
|
||||||
}
|
}
|
||||||
@@ -60,8 +60,8 @@ where
|
|||||||
.unvisited
|
.unvisited
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|c| {
|
.filter_map(|c| {
|
||||||
let node = self.matrix.get(c).as_ref().unwrap();
|
let node = self.matrix.get(*c).unwrap();
|
||||||
node.distance.map(|value| (c, value))
|
node.get_distance().map(|value| (c, value))
|
||||||
})
|
})
|
||||||
.reduce(|(c0, v0), (c1, v1)| if v0 < v1 { (c0, v0) } else { (c1, v1) })
|
.reduce(|(c0, v0), (c1, v1)| if v0 < v1 { (c0, v0) } else { (c1, v1) })
|
||||||
.map(|(c, _)| *c)
|
.map(|(c, _)| *c)
|
||||||
@@ -83,33 +83,16 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn update_neighbour(&mut self, next: Coordinate, previous: Coordinate, previous_distance: T) {
|
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 next_node = self.matrix.get_mut(next).unwrap();
|
||||||
let new_distance = previous_distance + next_node.value;
|
let new_distance = previous_distance + *next_node.get_value();
|
||||||
match next_node.distance {
|
if let Some(old_distance) = next_node.get_distance() {
|
||||||
None => {
|
if new_distance < *old_distance {
|
||||||
next_node.distance = Some(new_distance);
|
Self::update_node(next_node, new_distance, previous);
|
||||||
next_node.previous = Some(previous);
|
|
||||||
}
|
}
|
||||||
Some(old_distance) => {
|
} else {
|
||||||
if new_distance < old_distance {
|
Self::update_node(next_node, new_distance, previous);
|
||||||
next_node.distance = Some(new_distance);
|
|
||||||
next_node.previous = Some(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<T>, start: Coordinate) -> HashSet<Coordinate> {
|
fn initialize_unvisited_set(matrix: &dyn Matrix<T>, start: Coordinate) -> HashSet<Coordinate> {
|
||||||
let unvisited: HashSet<_> = (0..matrix.height())
|
let unvisited: HashSet<_> = (0..matrix.height())
|
||||||
@@ -118,27 +101,21 @@ where
|
|||||||
.collect();
|
.collect();
|
||||||
unvisited
|
unvisited
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn update_node(next_node: &mut dyn Node<T>, new_distance: T, previous: (usize, usize)) {
|
||||||
|
next_node.set_distance(new_distance);
|
||||||
|
next_node.set_previous(previous);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Hash, Debug)]
|
pub trait Node<T>
|
||||||
pub struct Node<T>
|
|
||||||
where
|
where
|
||||||
T: Add + PartialOrd,
|
T: Add + PartialOrd,
|
||||||
{
|
{
|
||||||
value: T,
|
fn get_value(&self) -> &T;
|
||||||
distance: Option<T>,
|
fn get_distance(&self) -> Option<&T>;
|
||||||
previous: Option<Coordinate>,
|
fn get_previous(&self) -> Option<Coordinate>;
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> From<T> for Node<T>
|
fn set_distance(&mut self, distance: T);
|
||||||
where
|
fn set_previous(&mut self, coord: Coordinate);
|
||||||
T: Add + PartialOrd,
|
|
||||||
{
|
|
||||||
fn from(value: T) -> Self {
|
|
||||||
Node {
|
|
||||||
value,
|
|
||||||
distance: None,
|
|
||||||
previous: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,3 +6,4 @@ edition = "2021"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
dijkstra = {version = "*", path = "../../lib/dijkstra"}
|
||||||
|
|||||||
+73
-104
@@ -1,4 +1,5 @@
|
|||||||
use std::collections::HashSet;
|
use dijkstra::Dijkstra;
|
||||||
|
use dijkstra::Matrix as MatrixTrait;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
@@ -16,10 +17,76 @@ const FILENAME: &str = "p081_matrix.txt";
|
|||||||
|
|
||||||
type Coordinate = (usize, usize);
|
type Coordinate = (usize, usize);
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
struct Matrix {
|
struct Matrix {
|
||||||
data: Vec<Vec<Node>>,
|
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 {
|
impl Matrix {
|
||||||
fn load(f: &Path) -> Self {
|
fn load(f: &Path) -> Self {
|
||||||
let mut data: Vec<Vec<_>> = fs::read_to_string(f)
|
let mut data: Vec<Vec<_>> = fs::read_to_string(f)
|
||||||
@@ -28,7 +95,7 @@ impl Matrix {
|
|||||||
.map(|line| {
|
.map(|line| {
|
||||||
line.split(',')
|
line.split(',')
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|number| number.parse::<u32>().unwrap())
|
.map(|number| number.parse::<usize>().unwrap())
|
||||||
.map(Node::from)
|
.map(Node::from)
|
||||||
.collect()
|
.collect()
|
||||||
})
|
})
|
||||||
@@ -39,110 +106,12 @@ impl Matrix {
|
|||||||
assert!(data.iter().all(|subvec| subvec.len() == LENGTH));
|
assert!(data.iter().all(|subvec| subvec.len() == LENGTH));
|
||||||
Self { data }
|
Self { data }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get(&self, c: &Coordinate) -> &Node {
|
|
||||||
&self.data[c.0][c.1]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let matrix = Matrix::load(Path::new(FILENAME));
|
let mut data = Matrix::load(Path::new(FILENAME));
|
||||||
let mut dijkstra = Dijkstra::new(matrix);
|
let mut dijkstra = Dijkstra::new(Box::new(&mut data));
|
||||||
dijkstra.solve();
|
dijkstra.solve();
|
||||||
dijkstra.show();
|
let result = data.get((LENGTH - 1, LENGTH - 1)).unwrap().get_value();
|
||||||
}
|
println!("{result}");
|
||||||
|
|
||||||
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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user