use super::{Direction4, Direction8};
use itertools::Itertools;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use std::{
convert::TryFrom,
convert::TryInto,
fmt::Display,
num::TryFromIntError,
ops::{Add, AddAssign, Mul, MulAssign, Sub, SubAssign},
};
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Coord {
pub x: usize,
pub y: usize,
}
impl Coord {
pub fn new(x: usize, y: usize) -> Self {
Self { x, y }
}
pub fn to_2d_idx(self, width: usize) -> usize {
self.y * width + self.x
}
pub fn to_icoord(self) -> ICoord {
self.into()
}
pub fn neighbors4(self) -> Vec<Coord> {
Direction4::DIRECTIONS
.iter()
.filter_map(|dir| {
let iself = self.to_icoord();
let ineighbor = iself + *dir;
ineighbor.to_coord() })
.collect_vec()
}
pub fn neighbors8(self) -> Vec<Coord> {
Direction8::DIRECTIONS
.iter()
.filter_map(|dir| {
let iself = self.to_icoord();
let ineighbor = iself + *dir;
ineighbor.to_coord() })
.collect_vec()
}
}
impl Add for Coord {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self {
x: self.x + rhs.x,
y: self.y + rhs.y,
}
}
}
impl AddAssign for Coord {
fn add_assign(&mut self, rhs: Self) {
self.x += rhs.x;
self.y += rhs.y;
}
}
impl Sub for Coord {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Self {
x: self.x - rhs.x,
y: self.y - rhs.y,
}
}
}
impl SubAssign for Coord {
fn sub_assign(&mut self, rhs: Self) {
self.x -= rhs.x;
self.y -= rhs.y;
}
}
impl Mul<usize> for Coord {
type Output = Self;
fn mul(self, rhs: usize) -> Self::Output {
Self {
x: self.x * rhs,
y: self.y * rhs,
}
}
}
impl MulAssign<usize> for Coord {
fn mul_assign(&mut self, rhs: usize) {
self.x *= rhs;
self.y *= rhs;
}
}
impl TryFrom<ICoord> for Coord {
type Error = TryFromIntError;
fn try_from(value: ICoord) -> Result<Self, Self::Error> {
Ok(Self {
x: value.x.try_into()?,
y: value.y.try_into()?,
})
}
}
impl Display for Coord {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "({}, {})", self.x, self.y)
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct ICoord {
pub x: isize,
pub y: isize,
}
impl ICoord {
pub fn new(x: isize, y: isize) -> Self {
Self { x, y }
}
pub fn quadrant(self) -> usize {
match (self.x >= 0, self.y >= 0) {
(true, true) => 1,
(false, true) => 2,
(false, false) => 3,
(true, false) => 4,
}
}
pub fn to_coord(self) -> Option<Coord> {
self.try_into().ok()
}
pub fn neighbors4(self) -> [ICoord; 4] {
[
self + Direction4::North,
self + Direction4::East,
self + Direction4::South,
self + Direction4::West,
]
}
pub fn neighbors8(self) -> [ICoord; 8] {
[
self + Direction8::North,
self + Direction8::NorthEast,
self + Direction8::East,
self + Direction8::SouthEast,
self + Direction8::South,
self + Direction8::SouthWest,
self + Direction8::West,
self + Direction8::NorthWest,
]
}
}
impl Add for ICoord {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self {
x: self.x + rhs.x,
y: self.y + rhs.y,
}
}
}
impl AddAssign for ICoord {
fn add_assign(&mut self, rhs: Self) {
self.x += rhs.x;
self.y += rhs.y;
}
}
impl Sub for ICoord {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Self {
x: self.x - rhs.x,
y: self.y - rhs.y,
}
}
}
impl SubAssign for ICoord {
fn sub_assign(&mut self, rhs: Self) {
self.x -= rhs.x;
self.y -= rhs.y;
}
}
impl Add<Direction4> for ICoord {
type Output = Self;
fn add(self, rhs: Direction4) -> Self::Output {
self + rhs.deltas()
}
}
impl AddAssign<Direction4> for ICoord {
fn add_assign(&mut self, rhs: Direction4) {
*self += rhs.deltas();
}
}
impl Add<Direction8> for ICoord {
type Output = Self;
fn add(self, rhs: Direction8) -> Self::Output {
self + rhs.deltas()
}
}
impl AddAssign<Direction8> for ICoord {
fn add_assign(&mut self, rhs: Direction8) {
*self += rhs.deltas();
}
}
impl Mul<isize> for ICoord {
type Output = Self;
fn mul(self, rhs: isize) -> Self::Output {
Self {
x: self.x * rhs,
y: self.y * rhs,
}
}
}
impl MulAssign<isize> for ICoord {
fn mul_assign(&mut self, rhs: isize) {
self.x *= rhs;
self.y *= rhs;
}
}
impl From<Coord> for ICoord {
fn from(value: Coord) -> Self {
Self {
x: value.x as isize,
y: value.y as isize,
}
}
}
impl Display for ICoord {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "({}, {})", self.x, self.y)
}
}