use serde::{Serialize, Deserialize};
use std::fmt;
use std::convert::TryFrom;
use crate::cell::MazeType;
#[repr(u32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum Direction {
Up, Right, Down, Left,
UpperRight, LowerRight, LowerLeft, UpperLeft,
}
impl fmt::Display for Direction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let s = match self {
Direction::Up => "Up",
Direction::Right => "Right",
Direction::Down => "Down",
Direction::Left => "Left",
Direction::UpperRight => "UpperRight",
Direction::LowerRight => "LowerRight",
Direction::LowerLeft => "LowerLeft",
Direction::UpperLeft => "UpperLeft",
};
write!(f, "{}", s)
}
}
impl TryFrom<&str> for Direction {
type Error = crate::Error;
fn try_from(s: &str) -> Result<Self, Self::Error> {
Ok(match s {
"Up" => Direction::Up,
"Right" => Direction::Right,
"Down" => Direction::Down,
"Left" => Direction::Left,
"UpperRight" => Direction::UpperRight,
"LowerRight" => Direction::LowerRight,
"LowerLeft" => Direction::LowerLeft,
"UpperLeft" => Direction::UpperLeft,
other =>
return Err(crate::Error::InvalidDirection { direction: other.to_string() }),
})
}
}
impl TryFrom<u32> for Direction {
type Error = crate::Error;
fn try_from(code: u32) -> Result<Self, Self::Error> {
use Direction::*;
Ok(match code {
0 => Up,
1 => Right,
2 => Down,
3 => Left,
4 => UpperRight,
5 => LowerRight,
6 => LowerLeft,
7 => UpperLeft,
_ => return Err(crate::Error::InvalidDirection { direction: code.to_string() }),
})
}
}
impl Direction {
pub fn valid_for(&self, maze_type: MazeType) -> bool {
use Direction::*;
match maze_type {
MazeType::Orthogonal => matches!(self, Up | Right | Down | Left),
MazeType::Sigma => matches!(self, Up | Right | Down | Left | UpperRight | LowerRight | LowerLeft | UpperLeft),
MazeType::Delta => matches!(self, Up | Down | UpperLeft | UpperRight | LowerLeft | LowerRight),
MazeType::Upsilon => matches!(self, Up | Right | Down | Left | UpperRight | LowerRight | LowerLeft | UpperLeft),
MazeType::Rhombic => matches!(self, UpperRight | LowerRight | LowerLeft | UpperLeft),
}
}
pub fn all() -> &'static [Direction] {
use Direction::*;
&[
Up, Right, Down, Left,
UpperRight, LowerRight, LowerLeft, UpperLeft,
]
}
pub fn sigma_neighbors() -> &'static [Direction] {
use Direction::*;
&[ Up, UpperRight, LowerRight, Down, LowerLeft, UpperLeft ]
}
pub fn offset_delta(&self, is_odd_column: bool) -> (isize, isize) {
match self {
Direction::Up => ( 0, -1),
Direction::Down => ( 0, 1),
Direction::UpperRight => {
if is_odd_column { (1, 0) } else { (1, -1) }
}
Direction::LowerRight => {
if is_odd_column { (1, 1) } else { (1, 0) }
}
Direction::UpperLeft => {
if is_odd_column { (-1, 0) } else { (-1, -1) }
}
Direction::LowerLeft => {
if is_odd_column { (-1, 1) } else { (-1, 0) }
}
_ => (0, 0),
}
}
pub fn opposite(&self) -> Direction {
match self {
Direction::Up => Direction::Down,
Direction::Down => Direction::Up,
Direction::UpperRight => Direction::LowerLeft,
Direction::LowerLeft => Direction::UpperRight,
Direction::LowerRight => Direction::UpperLeft,
Direction::UpperLeft => Direction::LowerRight,
Direction::Right => Direction::Left,
Direction::Left => Direction::Right,
}
}
pub fn vertex_indices(&self) -> (usize, usize) {
match self {
Direction::Up => (0, 1),
Direction::UpperRight => (1, 2),
Direction::LowerRight => (2, 3),
Direction::Down => (3, 4),
Direction::LowerLeft => (4, 5),
Direction::UpperLeft => (5, 0),
_ => (0, 0),
}
}
}