use crate::Point;
use std::fmt::Debug;
pub trait Neighborhood: Clone + Debug {
fn get_all_neighbors(&self, point: Point) -> Box<dyn Iterator<Item = Point>>;
fn heuristic(&self, point: Point, goal: Point) -> usize;
}
#[derive(Clone, Copy, Debug)]
pub struct ManhattanNeighborhood {
width: usize,
height: usize,
}
impl ManhattanNeighborhood {
pub fn new(width: usize, height: usize) -> ManhattanNeighborhood {
ManhattanNeighborhood { width, height }
}
}
impl Neighborhood for ManhattanNeighborhood {
fn get_all_neighbors(&self, point: Point) -> Box<dyn Iterator<Item = Point>> {
let (width, height) = (self.width, self.height);
let iter = [(0isize, -1isize), (1, 0), (0, 1), (-1, 0)]
.iter()
.map(move |(dx, dy)| (point.0 as isize + dx, point.1 as isize + dy))
.filter(move |(x, y)| {
*x >= 0 && *y >= 0 && (*x as usize) < width && (*y as usize) < height
})
.map(|(x, y)| (x as usize, y as usize));
Box::new(iter)
}
fn heuristic(&self, point: Point, goal: Point) -> usize {
let diff_0 = if goal.0 > point.0 {
goal.0 - point.0
} else {
point.0 - goal.0
};
let diff_1 = if goal.1 > point.1 {
goal.1 - point.1
} else {
point.1 - goal.1
};
diff_0 + diff_1
}
}
#[derive(Clone, Copy, Debug)]
pub struct MooreNeighborhood {
width: usize,
height: usize,
}
impl MooreNeighborhood {
pub fn new(width: usize, height: usize) -> MooreNeighborhood {
MooreNeighborhood { width, height }
}
}
impl Neighborhood for MooreNeighborhood {
fn get_all_neighbors(&self, point: Point) -> Box<dyn Iterator<Item = Point>> {
let (width, height) = (self.width, self.height);
let iter = [(0isize, -1isize), (1, -1), (1, 0), (1, 1), (0, 1), (-1, 1), (-1, 0), (-1, -1)]
.iter()
.map(move |(dx, dy)| (point.0 as isize + dx, point.1 as isize + dy))
.filter(move |(x, y)| {
*x >= 0 && *y >= 0 && (*x as usize) < width && (*y as usize) < height
})
.map(|(x, y)| (x as usize, y as usize));
Box::new(iter)
}
fn heuristic(&self, point: Point, goal: Point) -> usize {
let diff_0 = if goal.0 > point.0 {
goal.0 - point.0
} else {
point.0 - goal.0
};
let diff_1 = if goal.1 > point.1 {
goal.1 - point.1
} else {
point.1 - goal.1
};
diff_0.max(diff_1)
}
}
#[test]
fn test_manhattan_get_all_neighbors() {
let neighborhood = ManhattanNeighborhood::new(5, 5);
assert_eq!(
neighborhood.get_all_neighbors((0, 2)).collect::<Vec<_>>(),
vec![(0, 1), (1, 2), (0, 3)],
);
}
#[test]
fn test_manhattan_heuristic() {
let neighborhood = ManhattanNeighborhood::new(5, 5);
assert_eq!(neighborhood.heuristic((3, 1), (0, 0)), 3 + 1);
}
#[test]
fn test_moore_get_all_neighbors() {
let neighborhood = MooreNeighborhood::new(5, 5);
assert_eq!(
neighborhood.get_all_neighbors((0, 2)).collect::<Vec<_>>(),
vec![(0, 1), (1, 1), (1, 2), (1, 3), (0, 3)],
);
}
#[test]
fn test_moore_heuristic() {
let neighborhood = MooreNeighborhood::new(5, 5);
assert_eq!(neighborhood.heuristic((3, 1), (0, 0)), 3);
}