use crate::distance::*;
use crate::errors::*;
use crate::gate::*;
use crate::mesh::*;
use crate::mesh_2d::index_2d::*;
use crate::mesh_2d::shape_2d::*;
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Full2D {
width: usize,
height: usize,
}
impl Full2D {
pub fn new(width: usize, height: usize) -> Self {
Self { width, height }
}
pub fn unique(self) -> Self {
self
}
#[inline]
pub(crate) fn successors(width: usize, height: usize, from: usize, backward: bool) -> std::vec::IntoIter<Gate> {
let mut peers = Vec::<Gate>::with_capacity(8);
if let Ok(xy) = Self::index_to_xy(width, height, from) {
let (x, y) = xy;
if x < width - 1 {
peers.push(Gate::new(from + 1, DISTANCE_STRAIGHT));
if y < height - 1 {
peers.push(Gate::new(from + 1 + width, DISTANCE_DIAGONAL));
}
}
if y < height - 1 {
peers.push(Gate::new(from + width, DISTANCE_STRAIGHT));
if x > 0 {
peers.push(Gate::new(from - 1 + width, DISTANCE_DIAGONAL));
}
}
if x > 0 {
peers.push(Gate::new(from - 1, DISTANCE_STRAIGHT));
if y > 0 {
peers.push(Gate::new(from - 1 - width, DISTANCE_DIAGONAL));
}
}
if y > 0 {
peers.push(Gate::new(from - width, DISTANCE_STRAIGHT));
if x < width - 1 {
peers.push(Gate::new(from + 1 - width, DISTANCE_DIAGONAL));
}
}
}
if backward {
peers.reverse();
}
peers.into_iter()
}
#[inline]
pub(crate) fn len(width: usize, height: usize) -> usize {
width * height
}
#[inline]
pub(crate) fn index_to_xy(width: usize, height: usize, index: usize) -> Result<(usize, usize)> {
if index >= width * height {
return Err(Error::invalid_index(index));
}
Ok((index % width, index / width))
}
#[inline]
pub(crate) fn xy_to_index(width: usize, height: usize, x: usize, y: usize) -> Result<usize> {
if x >= width || y >= height {
return Err(Error::invalid_xy(x, y));
}
Ok(y * width + x)
}
#[inline]
pub(crate) fn shape(width: usize, height: usize) -> (usize, usize) {
(width, height)
}
}
impl Mesh for Full2D {
type IntoIter = std::vec::IntoIter<Gate>;
fn successors(&self, from: usize, backward: bool) -> std::vec::IntoIter<Gate> {
Self::successors(self.width, self.height, from, backward)
}
fn len(&self) -> usize {
Self::len(self.width, self.height)
}
}
impl Index2D for Full2D {
fn index_to_xy(&self, index: usize) -> Result<(usize, usize)> {
Self::index_to_xy(self.width, self.height, index)
}
fn xy_to_index(&self, x: usize, y: usize) -> Result<usize> {
Self::xy_to_index(self.width, self.height, x, y)
}
}
impl Shape2D for Full2D {
fn shape(&self) -> (usize, usize) {
Self::shape(self.width, self.height)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_xy_w0() {
let r = Full2D::new(0, 10);
r.xy_to_index(0, 0).expect_err("out of bound");
r.xy_to_index(0, 1).expect_err("out of bound");
r.xy_to_index(1, 0).expect_err("out of bound");
r.xy_to_index(1, 1).expect_err("out of bound");
}
#[test]
fn test_xy_h0() {
let r = Full2D::new(10, 0);
r.xy_to_index(0, 0).expect_err("out of bound");
r.xy_to_index(0, 1).expect_err("out of bound");
r.xy_to_index(1, 0).expect_err("out of bound");
r.xy_to_index(1, 1).expect_err("out of bound");
}
#[test]
fn test_xy_w0h0() {
let r = Full2D::new(0, 0);
r.xy_to_index(0, 0).expect_err("out of bound");
r.xy_to_index(0, 1).expect_err("out of bound");
r.xy_to_index(1, 0).expect_err("out of bound");
r.xy_to_index(1, 1).expect_err("out of bound");
}
#[test]
fn test_xy_w4h3() {
let r = Full2D::new(4, 3);
assert_eq!(0, r.xy_to_index(0, 0).expect("out of bound"));
assert_eq!(11, r.xy_to_index(3, 2).expect("out of bound"));
assert_eq!(3, r.xy_to_index(3, 0).expect("out of bound"));
assert_eq!(8, r.xy_to_index(0, 2).expect("out of bound"));
r.xy_to_index(4, 0).expect_err("out of bound");
r.xy_to_index(0, 3).expect_err("out of bound");
}
#[test]
fn test_index_w0() {
let r = Full2D::new(0, 10);
r.index_to_xy(0).expect_err("out of bound");
r.index_to_xy(1).expect_err("out of bound");
}
#[test]
fn test_index_h0() {
let r = Full2D::new(10, 0);
r.index_to_xy(0).expect_err("out of bound");
r.index_to_xy(1).expect_err("out of bound");
}
#[test]
fn test_index_w0h0() {
let r = Full2D::new(0, 0);
r.index_to_xy(0).expect_err("out of bound");
r.index_to_xy(1).expect_err("out of bound");
}
#[test]
fn test_index_w4h3() {
let r = Full2D::new(4, 3);
assert_eq!((0, 0), r.index_to_xy(0).expect("out of bound"));
assert_eq!((3, 2), r.index_to_xy(11).expect("out of bound"));
assert_eq!((3, 0), r.index_to_xy(3).expect("out of bound"));
assert_eq!((0, 2), r.index_to_xy(8).expect("out of bound"));
r.index_to_xy(12).expect_err("out of bound");
}
#[test]
fn test_full_rectangle_basic_w4h3() {
let r = Full2D::new(4, 3);
assert_eq!(
vec![
Gate::new(1, DISTANCE_STRAIGHT),
Gate::new(5, DISTANCE_DIAGONAL),
Gate::new(4, DISTANCE_STRAIGHT)
],
r.successors(0, false).collect::<Vec<Gate>>()
);
assert_eq!(
vec![
Gate::new(2, DISTANCE_STRAIGHT),
Gate::new(6, DISTANCE_DIAGONAL),
Gate::new(5, DISTANCE_STRAIGHT),
Gate::new(4, DISTANCE_DIAGONAL),
Gate::new(0, DISTANCE_STRAIGHT)
],
r.successors(1, false).collect::<Vec<Gate>>(),
);
assert_eq!(
vec![
Gate::new(3, DISTANCE_STRAIGHT),
Gate::new(7, DISTANCE_DIAGONAL),
Gate::new(6, DISTANCE_STRAIGHT),
Gate::new(5, DISTANCE_DIAGONAL),
Gate::new(1, DISTANCE_STRAIGHT)
],
r.successors(2, false).collect::<Vec<Gate>>()
);
assert_eq!(
vec![
Gate::new(7, DISTANCE_STRAIGHT),
Gate::new(6, DISTANCE_DIAGONAL),
Gate::new(2, DISTANCE_STRAIGHT)
],
r.successors(3, false).collect::<Vec<Gate>>()
);
assert_eq!(
vec![
Gate::new(5, DISTANCE_STRAIGHT),
Gate::new(9, DISTANCE_DIAGONAL),
Gate::new(8, DISTANCE_STRAIGHT),
Gate::new(0, DISTANCE_STRAIGHT),
Gate::new(1, DISTANCE_DIAGONAL)
],
r.successors(4, false).collect::<Vec<Gate>>()
);
assert_eq!(
vec![
Gate::new(6, DISTANCE_STRAIGHT),
Gate::new(10, DISTANCE_DIAGONAL),
Gate::new(9, DISTANCE_STRAIGHT),
Gate::new(8, DISTANCE_DIAGONAL),
Gate::new(4, DISTANCE_STRAIGHT),
Gate::new(0, DISTANCE_DIAGONAL),
Gate::new(1, DISTANCE_STRAIGHT),
Gate::new(2, DISTANCE_DIAGONAL)
],
r.successors(5, false).collect::<Vec<Gate>>()
);
assert_eq!(
vec![
Gate::new(7, DISTANCE_STRAIGHT),
Gate::new(11, DISTANCE_DIAGONAL),
Gate::new(10, DISTANCE_STRAIGHT),
Gate::new(9, DISTANCE_DIAGONAL),
Gate::new(5, DISTANCE_STRAIGHT),
Gate::new(1, DISTANCE_DIAGONAL),
Gate::new(2, DISTANCE_STRAIGHT),
Gate::new(3, DISTANCE_DIAGONAL)
],
r.successors(6, false).collect::<Vec<Gate>>()
);
assert_eq!(
vec![
Gate::new(11, DISTANCE_STRAIGHT),
Gate::new(10, DISTANCE_DIAGONAL),
Gate::new(6, DISTANCE_STRAIGHT),
Gate::new(2, DISTANCE_DIAGONAL),
Gate::new(3, DISTANCE_STRAIGHT)
],
r.successors(7, false).collect::<Vec<Gate>>()
);
assert_eq!(
vec![
Gate::new(9, DISTANCE_STRAIGHT),
Gate::new(4, DISTANCE_STRAIGHT),
Gate::new(5, DISTANCE_DIAGONAL)
],
r.successors(8, false).collect::<Vec<Gate>>()
);
assert_eq!(
vec![
Gate::new(10, DISTANCE_STRAIGHT),
Gate::new(8, DISTANCE_STRAIGHT),
Gate::new(4, DISTANCE_DIAGONAL),
Gate::new(5, DISTANCE_STRAIGHT),
Gate::new(6, DISTANCE_DIAGONAL)
],
r.successors(9, false).collect::<Vec<Gate>>()
);
assert_eq!(
vec![
Gate::new(11, DISTANCE_STRAIGHT),
Gate::new(9, DISTANCE_STRAIGHT),
Gate::new(5, DISTANCE_DIAGONAL),
Gate::new(6, DISTANCE_STRAIGHT),
Gate::new(7, DISTANCE_DIAGONAL)
],
r.successors(10, false).collect::<Vec<Gate>>()
);
assert_eq!(
vec![
Gate::new(10, DISTANCE_STRAIGHT),
Gate::new(6, DISTANCE_DIAGONAL),
Gate::new(7, DISTANCE_STRAIGHT)
],
r.successors(11, false).collect::<Vec<Gate>>()
);
}
#[test]
fn test_successors_backward() {
let r = Full2D::new(4, 3);
let forward = r.successors(5, false).collect::<Vec<Gate>>();
let backward = r.successors(5, true).collect::<Vec<Gate>>();
assert_eq!(forward.len(), backward.len());
assert_eq!(forward.len(), 8);
let mut forward_reversed = forward.clone();
forward_reversed.reverse();
assert_eq!(forward_reversed, backward);
let forward_corner = r.successors(0, false).collect::<Vec<Gate>>();
let backward_corner = r.successors(0, true).collect::<Vec<Gate>>();
assert_eq!(forward_corner.len(), backward_corner.len());
assert_eq!(forward_corner.len(), 3);
let mut forward_corner_reversed = forward_corner.clone();
forward_corner_reversed.reverse();
assert_eq!(forward_corner_reversed, backward_corner);
}
#[test]
#[cfg(feature = "serde")]
fn test_serde() {
let mesh = Full2D::new(10, 8);
let json = serde_json::to_string(&mesh).unwrap();
let deserialized: Full2D = serde_json::from_str(&json).unwrap();
assert_eq!(mesh.len(), deserialized.len());
assert_eq!(mesh.shape(), deserialized.shape());
}
}