add doc
Some checks failed
Rust Checks / checks (push) Has been cancelled

This commit is contained in:
CoCo_Sol 2024-02-16 10:08:20 +01:00
parent 7c79938212
commit 85e6093f37

View file

@ -1,8 +1,8 @@
//! All functions related to calculations in a hexagonal grid. //! All functions related to calculations in a hexagonal grid.
use std::{collections::HashSet, ops::{ use std::ops::{
Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign, Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign,
}}; };
use paste::paste; use paste::paste;
@ -65,6 +65,12 @@ pub trait Number:
/// Converts an `f32` to `Self`. /// Converts an `f32` to `Self`.
fn from_f32(value: f32) -> Self; fn from_f32(value: f32) -> Self;
/// Converts `self` to an `isize`.
fn to_isize(self) -> isize;
/// Converts an `isize` to `Self`.
fn from_isize(value: isize) -> Self;
} }
/// Implements the `Number` trait for the given types. /// Implements the `Number` trait for the given types.
@ -93,6 +99,14 @@ macro_rules! number_impl {
value as $t value as $t
} }
fn to_isize(self) -> isize {
self as isize
}
fn from_isize(value: isize) -> Self {
value as $t
}
} }
)*}}; )*}};
@ -104,6 +118,8 @@ number_impl! {
} }
/// Represents a position in a hexagonal grid. /// Represents a position in a hexagonal grid.
/// We use the axial coordinate system explained in this
/// [documentation](https://www.redblobgames.com/grids/hexagons/#coordinates).
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct HexPosition<T: Number>(pub T, pub T); pub struct HexPosition<T: Number>(pub T, pub T);
@ -130,7 +146,16 @@ pub enum HexDirection {
} }
impl HexDirection { impl HexDirection {
/// Returns the vector of the direction. /// Returns the vector ([HexPosition]) of the direction.
///
/// # Example
///
/// ```no_run
/// use border_wars::map::hex::{HexDirection, HexPosition};
///
/// let direction = HexDirection::Right;
/// assert_eq!(direction.to_vector(), HexPosition(1, 0));
/// ```
pub const fn to_vector<T: Number>(self) -> HexPosition<T> { pub const fn to_vector<T: Number>(self) -> HexPosition<T> {
match self { match self {
Self::Right => HexPosition(T::ONE, T::ZERO), Self::Right => HexPosition(T::ONE, T::ZERO),
@ -211,6 +236,7 @@ impl<T: Number> Iterator for HexSpiral<T> {
type Item = HexPosition<T>; type Item = HexPosition<T>;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
// The origin of the spiral.
if self.index == 0 { if self.index == 0 {
self.index += 1; self.index += 1;
return Some(self.origin); return Some(self.origin);
@ -229,12 +255,24 @@ impl<T: Number> Iterator for HexSpiral<T> {
} }
impl<T: Number> HexPosition<T> { impl<T: Number> HexPosition<T> {
/// Creates a new hexagonal position. /// Converts the current [HexPosition] into a pixel coordinate.
pub const fn new(x: T, y: T) -> Self { /// Input: The size of the hexagon in pixels (witdh, height).
Self(x, y) ///
} /// If you want to learn more about pixel coordinates conversion,
/// you can check the
/// Returns the pixel coordinates of the hexagonal position. /// [documentation](https://www.redblobgames.com/grids/hexagons/#hex-to-pixel).
///
/// # Example
///
/// ```no_run
/// use border_wars::map::hex::HexPosition;
///
/// let position = HexPosition(1, 0);
/// assert_eq!(
/// position.to_pixel_coordinates((1.0, 1.0)),
/// (3f32.sqrt(), 0.0)
/// );
/// ```
pub fn to_pixel_coordinates(&self, size: (f32, f32)) -> (f32, f32) { pub fn to_pixel_coordinates(&self, size: (f32, f32)) -> (f32, f32) {
( (
size.0 size.0
@ -245,23 +283,79 @@ impl<T: Number> HexPosition<T> {
) )
} }
/// Returns the distance between two hexagonal positions. /// Returns the distance between two [HexPosition]s.
///
/// # How it works
///
/// In the hexagonal grid, using the
/// [cube coordinate system](https://www.redblobgames.com/grids/hexagons/#coordinates),
/// it's akin to a cube in 3D space.
/// The Manhattan distance between two positions is equal to half of
/// the sum of abs(dx) + abs(dy) + abs(dz).
/// However, in hexagonal grids, z is defined as -q - r.
///
/// # Example
///
/// ```no_run
/// use border_wars::map::hex::HexPosition;
///
/// let a = HexPosition(0, 0);
/// let b = HexPosition(1, 1);
///
/// assert_eq!(a.distance(b), 2);
/// ```
pub fn distance(self, other: Self) -> T { pub fn distance(self, other: Self) -> T {
let Self(x, y) = self - other; let Self(x, y) = self - other;
x.abs() + y.abs() + (x + y).abs() / T::TWO x.abs() + y.abs() + (x + y).abs() / T::TWO
} }
pub fn range(&self, range: T) -> HashSet<Self> { /// Returns all positions within a given `range` from the current
let mut result_positions = HashSet::new(); /// `HexPosition`.
for q in num::range_inclusive(-range, range) { ///
for r in num::range_inclusive((-range, -q - range), min(range, -q + range)) { /// This function iterates over the possible q and r values within the
result_positions.insert(Self { q, r }); /// specified range.
/// Note that the original position is also returned.
///
/// For more details, refer to: https://www.redblobgames.com/grids/hexagons/#range
///
/// # Example
///
/// ```no_run
/// use border_wars::map::hex::HexPosition;
///
/// let position = HexPosition(0, 0);
/// let range = 1;
///
/// let positions = position.range(range);
///
/// assert_eq!(positions.len(), 7);
/// ```
pub fn range(&self, range: isize) -> Vec<Self> {
let mut result_positions = Vec::new();
for q in -range..=range {
for r in Number::min(-range, -q - range)..=Number::min(range, -q + range) {
result_positions.push(Self(T::from_isize(q), T::from_isize(r)));
} }
} }
result_positions result_positions
} }
/// Returns the hexagonal ring of the given radius. /// Returns the hexagonal ring of the given radius.
/// If you want to learn more about hexagonal grids, check the
/// [documentation](https://www.redblobgames.com/grids/hexagons/#rings)
///
/// # Example
///
/// ```no_run
/// use border_wars::map::hex::HexPosition;
///
/// let position = HexPosition(0, 0);
/// let radius = 1;
///
/// for ring_position in position.ring(radius) {
/// println!("{:?}", ring_position);
/// }
/// ```
pub fn ring(self, radius: usize) -> HexRing<T> { pub fn ring(self, radius: usize) -> HexRing<T> {
HexRing { HexRing {
current: self + HexDirection::DownLeft.to_vector() * T::from_usize(radius), current: self + HexDirection::DownLeft.to_vector() * T::from_usize(radius),
@ -272,6 +366,21 @@ impl<T: Number> HexPosition<T> {
} }
/// Returns the hexagonal spiral of the given radius. /// Returns the hexagonal spiral of the given radius.
/// If you want to learn more about hexagonal grids, check the
/// [documentation](https://www.redblobgames.com/grids/hexagons/#rings-spiral)
///
/// # Example
///
/// ```no_run
/// use border_wars::map::hex::HexPosition;
///
/// let position = HexPosition(0, 0);
/// let radius = 1;
///
/// for spiral_position in position.spiral(radius) {
/// println!("{:?}", spiral_position);
/// }
/// ```
pub fn spiral(self, radius: usize) -> HexSpiral<T> { pub fn spiral(self, radius: usize) -> HexSpiral<T> {
HexSpiral { HexSpiral {
origin: self, origin: self,