refactor 81 and dijkstra
This commit is contained in:
+38
-8
@@ -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) {
|
||||||
|
|||||||
@@ -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
@@ -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))
|
||||||
|
|||||||
Reference in New Issue
Block a user