use std::{fmt, ops::{Add, AddAssign, Mul, Neg, Sub, SubAssign}};
use rand::{thread_rng, Rng};
use serde::{Deserialize, Serialize};
use super::{Sqrt, Unity, Zero};
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct Vec2<T> {
pub x: T,
pub y: T,
}
impl<T> Vec2<T> {
pub const fn new(x: T, y: T) -> Self {
Self { x, y }
}
pub fn map<U>(self, mut f: impl FnMut(T) -> U) -> Vec2<U> {
Vec2 {
x: f(self.x),
y: f(self.y),
}
}
}
impl<T> Zero for Vec2<T> where T: Zero {
const ZERO: Self = Self::new(T::ZERO, T::ZERO);
}
impl<T> Vec2<T> where T: Zero + Unity {
pub const LEFT: Self = Self::new(T::NEG_ONE, T::ZERO);
pub const UP: Self = Self::new(T::ZERO, T::NEG_ONE);
pub const RIGHT: Self = Self::new(T::ONE, T::ZERO);
pub const DOWN: Self = Self::new(T::ZERO, T::ONE);
pub fn random_cardinal_with(rng: &mut impl Rng) -> Self {
match rng.gen_range(0..4) {
0 => Self::LEFT,
1 => Self::UP,
2 => Self::RIGHT,
3 => Self::DOWN,
_ => unreachable!(),
}
}
pub fn random_cardinal() -> Self {
Self::random_cardinal_with(&mut thread_rng())
}
}
impl<T> Vec2<T> where T: Add<Output = T> + Mul<Output = T> + Sqrt + Copy {
pub fn length(&self) -> T {
(self.x * self.x + self.y * self.y).sqrt()
}
}
impl<T> fmt::Display for Vec2<T> where T: fmt::Display {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "({}, {})", self.x, self.y)
}
}
impl<T> Add for Vec2<T> where T: Add<Output = T> {
type Output = Self;
fn add(self, rhs: Vec2<T>) -> Self {
Self::new(self.x + rhs.x, self.y + rhs.y)
}
}
impl<T> Neg for Vec2<T> where T: Neg<Output = T> {
type Output = Self;
fn neg(self) -> Self {
Self::new(-self.x, -self.y)
}
}
impl<T> Sub for Vec2<T> where T: Sub<Output = T> {
type Output = Self;
fn sub(self, rhs: Vec2<T>) -> Self {
Self::new(self.x - rhs.x, self.y - rhs.y)
}
}
impl<T> AddAssign<Self> for Vec2<T> where T: AddAssign<T> {
fn add_assign(&mut self, rhs: Vec2<T>) {
self.x += rhs.x;
self.y += rhs.y;
}
}
impl<T> SubAssign<Self> for Vec2<T> where T: SubAssign<T> {
fn sub_assign(&mut self, rhs: Vec2<T>) {
self.x -= rhs.x;
self.y -= rhs.y;
}
}
pub type Pos<T> = Vec2<T>;
pub type Delta<T> = Vec2<T>;