use num::cast::ToPrimitive;
use std::cmp::Ordering;
use std::convert::TryFrom;
use std::error::Error;
use std::fmt;
use std::fmt::{Display, Formatter};
use std::ops::{
Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Vec2 {
pub x: i32,
pub y: i32,
}
impl Vec2 {
pub fn zero() -> Vec2 {
Vec2 { x: 0, y: 0 }
}
pub fn xy<T1: ToPrimitive, T2: ToPrimitive>(x: T1, y: T2) -> Vec2 {
Vec2 {
x: x.to_i32().unwrap(),
y: y.to_i32().unwrap(),
}
}
pub fn x<T: ToPrimitive>(x: T) -> Vec2 {
Vec2 {
x: x.to_i32().unwrap(),
y: 0,
}
}
pub fn y<T: ToPrimitive>(y: T) -> Vec2 {
Vec2 {
x: 0,
y: y.to_i32().unwrap(),
}
}
pub fn clear(&mut self) {
self.x = 0;
self.y = 0;
}
}
impl Display for Vec2 {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "({}, {})", self.x, self.y)
}
}
impl Add for Vec2 {
type Output = Vec2;
fn add(self, other: Vec2) -> Vec2 {
Vec2 {
x: self.x + other.x,
y: self.y + other.y,
}
}
}
impl Sub for Vec2 {
type Output = Vec2;
fn sub(self, other: Vec2) -> Vec2 {
Vec2 {
x: self.x - other.x,
y: self.y - other.y,
}
}
}
impl Mul for Vec2 {
type Output = Vec2;
fn mul(self, other: Vec2) -> Vec2 {
Vec2 {
x: self.x * other.x,
y: self.y * other.y,
}
}
}
impl Div for Vec2 {
type Output = Vec2;
fn div(self, other: Vec2) -> Vec2 {
Vec2 {
x: self.x / other.x,
y: self.y / other.y,
}
}
}
impl<T: ToPrimitive> Mul<T> for Vec2 {
type Output = Vec2;
fn mul(self, scalar: T) -> Vec2 {
let scalar = scalar.to_i32().unwrap();
Vec2 {
x: self.x * scalar,
y: self.y * scalar,
}
}
}
impl<T: ToPrimitive> Div<T> for Vec2 {
type Output = Vec2;
fn div(self, scalar: T) -> Vec2 {
let scalar = scalar.to_i32().unwrap();
Vec2 {
x: self.x / scalar,
y: self.y / scalar,
}
}
}
impl Neg for Vec2 {
type Output = Vec2;
fn neg(self) -> Vec2 {
Vec2 {
x: -self.x,
y: -self.y,
}
}
}
impl AddAssign for Vec2 {
fn add_assign(&mut self, other: Vec2) {
*self = *self + other
}
}
impl SubAssign for Vec2 {
fn sub_assign(&mut self, other: Vec2) {
*self = *self - other
}
}
impl MulAssign for Vec2 {
fn mul_assign(&mut self, other: Vec2) {
*self = *self * other
}
}
impl DivAssign for Vec2 {
fn div_assign(&mut self, other: Vec2) {
*self = *self / other
}
}
impl<T: ToPrimitive> MulAssign<T> for Vec2 {
fn mul_assign(&mut self, scalar: T) {
*self = *self * scalar
}
}
impl<T: ToPrimitive> DivAssign<T> for Vec2 {
fn div_assign(&mut self, scalar: T) {
*self = *self / scalar
}
}
impl<T> Index<Vec2> for Vec<Vec<T>> {
type Output = T;
fn index(&self, index: Vec2) -> &Self::Output {
&self[index.x as usize][index.y as usize]
}
}
impl<T> IndexMut<Vec2> for Vec<Vec<T>> {
fn index_mut(&mut self, index: Vec2) -> &mut Self::Output {
&mut self[index.x as usize][index.y as usize]
}
}
impl From<Direction> for Vec2 {
fn from(value: Direction) -> Self {
match value {
Direction::Up => Vec2::y(-1),
Direction::Down => Vec2::y(1),
Direction::Right => Vec2::x(1),
Direction::Left => Vec2::x(-1),
Direction::None => Vec2::zero(),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Direction {
Up,
Down,
Right,
Left,
None,
}
impl Direction {
pub fn opposite(&self) -> Direction {
match *self {
Direction::Up => Direction::Down,
Direction::Down => Direction::Up,
Direction::Right => Direction::Left,
Direction::Left => Direction::Right,
Direction::None => Direction::None,
}
}
}
impl TryFrom<Vec2> for Direction {
type Error = TryFromVec2Error;
fn try_from(value: Vec2) -> Result<Self, Self::Error> {
match (value.x.cmp(&0), value.y.cmp(&0)) {
(Ordering::Less, Ordering::Equal) => Ok(Direction::Left),
(Ordering::Greater, Ordering::Equal) => Ok(Direction::Right),
(Ordering::Equal, Ordering::Greater) => Ok(Direction::Down),
(Ordering::Equal, Ordering::Less) => Ok(Direction::Up),
(Ordering::Equal, Ordering::Equal) => Ok(Direction::None),
_ => Err(TryFromVec2Error { value }),
}
}
}
#[derive(Debug)]
pub struct TryFromVec2Error {
value: Vec2,
}
impl fmt::Display for TryFromVec2Error {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(
f,
"displacement vector ({}, {}) is not orthogonal",
self.value.x, self.value.y
)
}
}
impl Error for TryFromVec2Error {}