use crate::Point;
use std::fmt::Debug;
pub trait Neighborhood: Clone + Debug {
fn get_all_neighbors(&self, point: Point, target: &mut Vec<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, target: &mut Vec<Point>) {
let (width, height) = (self.width, self.height);
#[rustfmt::skip]
static ALL_DELTAS: [(isize, isize); 4] = [(0, -1), (1, 0), (0, 1), (-1, 0)];
for (dx, dy) in ALL_DELTAS.iter() {
let x = point.0 as isize + dx;
let y = point.1 as isize + dy;
if x >= 0 && x < width as isize && y >= 0 && y < height as isize {
target.push((x as usize, y as usize))
}
}
}
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, target: &mut Vec<Point>) {
let (width, height) = (self.width, self.height);
#[rustfmt::skip]
static ALL_DELTAS: [(isize, isize); 8] = [(0, -1), (1, -1), (1, 0), (1, 1), (0, 1), (-1, 1), (-1, 0), (-1, -1)];
for (dx, dy) in ALL_DELTAS.iter() {
let x = point.0 as isize + dx;
let y = point.1 as isize + dy;
if x >= 0 && x < width as isize && y >= 0 && y < height as isize {
target.push((x as usize, y as usize))
}
}
}
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)
}
}
#[cfg(test)]
mod tests {
use super::*;
mod manhattan {
use super::*;
#[test]
fn get_all_neighbors() {
let neighborhood = ManhattanNeighborhood::new(5, 5);
let mut target = vec![];
neighborhood.get_all_neighbors((0, 2), &mut target);
assert_eq!(target, vec![(0, 1), (1, 2), (0, 3)],);
}
#[test]
fn heuristic() {
let neighborhood = ManhattanNeighborhood::new(5, 5);
assert_eq!(neighborhood.heuristic((3, 1), (0, 0)), 3 + 1);
}
}
mod moore {
use super::*;
#[test]
fn get_all_neighbors() {
let neighborhood = MooreNeighborhood::new(5, 5);
let mut target = vec![];
neighborhood.get_all_neighbors((0, 2), &mut target);
assert_eq!(target, vec![(0, 1), (1, 1), (1, 2), (1, 3), (0, 3)],);
}
#[test]
fn heuristic() {
let neighborhood = MooreNeighborhood::new(5, 5);
assert_eq!(neighborhood.heuristic((3, 1), (0, 0)), 3);
}
}
}