use crate::{
helpers::hex_grid::axial::{AxialPos, FractionalAxialPos},
tiles::TilePos,
};
use std::ops::{Add, Mul, Sub};
#[derive(Clone, Copy, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct CubePos {
pub q: i32,
pub r: i32,
pub s: i32,
}
impl From<AxialPos> for CubePos {
#[inline]
fn from(axial_pos: AxialPos) -> Self {
let AxialPos { q, r } = axial_pos;
CubePos { q, r, s: -(q + r) }
}
}
impl From<TilePos> for CubePos {
#[inline]
fn from(tile_pos: TilePos) -> Self {
AxialPos::from(tile_pos).into()
}
}
impl Add<CubePos> for CubePos {
type Output = CubePos;
fn add(self, rhs: CubePos) -> Self::Output {
CubePos {
q: self.q + rhs.q,
r: self.r + rhs.r,
s: self.s + rhs.s,
}
}
}
impl Sub<CubePos> for CubePos {
type Output = CubePos;
fn sub(self, rhs: CubePos) -> Self::Output {
CubePos {
q: self.q - rhs.q,
r: self.r - rhs.r,
s: self.s - rhs.s,
}
}
}
impl Add<&CubePos> for CubePos {
type Output = CubePos;
fn add(self, rhs: &CubePos) -> Self::Output {
CubePos {
q: self.q + rhs.q,
r: self.r + rhs.r,
s: self.s + rhs.s,
}
}
}
impl Mul<CubePos> for i32 {
type Output = CubePos;
fn mul(self, rhs: CubePos) -> Self::Output {
CubePos {
q: self * rhs.q,
r: self * rhs.r,
s: self * rhs.s,
}
}
}
impl Mul<CubePos> for u32 {
type Output = CubePos;
fn mul(self, rhs: CubePos) -> Self::Output {
CubePos {
q: (self as i32) * rhs.q,
r: (self as i32) * rhs.r,
s: (self as i32) * rhs.s,
}
}
}
impl CubePos {
pub const fn new(q: i32, r: i32, s: i32) -> Self {
Self { q, r, s }
}
#[inline]
pub fn magnitude(&self) -> i32 {
self.q.abs().max(self.r.abs().max(self.s.abs()))
}
#[inline]
pub fn distance_from(&self, other: &CubePos) -> i32 {
let cube_pos: CubePos = *self - *other;
cube_pos.magnitude()
}
}
#[derive(Clone, Copy, Debug, PartialOrd, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct FractionalCubePos {
q: f32,
r: f32,
s: f32,
}
impl From<FractionalAxialPos> for FractionalCubePos {
fn from(frac_axial_pos: FractionalAxialPos) -> Self {
let FractionalAxialPos { q, r } = frac_axial_pos;
FractionalCubePos { q, r, s: -(q + r) }
}
}
impl FractionalCubePos {
pub const fn new(q: f32, r: f32, s: f32) -> Self {
Self { q, r, s }
}
#[inline]
pub fn round(&self) -> CubePos {
let q_round = self.q.round();
let r_round = self.r.round();
let s_round = self.s.round();
let q_diff = (q_round - self.q).abs();
let r_diff = (r_round - self.r).abs();
let s_diff = (s_round - self.s).abs();
let (q, r, s) = if q_diff > r_diff && q_diff > s_diff {
let r = r_round as i32;
let s = s_round as i32;
let q = -(r + s);
(q, r, s)
} else if r_diff > s_diff {
let q = q_round as i32;
let s = s_round as i32;
let r = -(q + s);
(q, r, s)
} else {
let q = q_round as i32;
let r = r_round as i32;
let s = -(q + r);
(q, r, s)
};
CubePos { q, r, s }
}
}