From 85e6093f37e532af3080968f5b33e2aac2de0e3d Mon Sep 17 00:00:00 2001 From: CoCoSol007 Date: Fri, 16 Feb 2024 10:08:20 +0100 Subject: [PATCH] add doc --- crates/border-wars/src/map/hex.rs | 139 ++++++++++++++++++++++++++---- 1 file changed, 124 insertions(+), 15 deletions(-) diff --git a/crates/border-wars/src/map/hex.rs b/crates/border-wars/src/map/hex.rs index 55647f2..15d9ce4 100644 --- a/crates/border-wars/src/map/hex.rs +++ b/crates/border-wars/src/map/hex.rs @@ -1,8 +1,8 @@ //! 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, -}}; +}; use paste::paste; @@ -65,6 +65,12 @@ pub trait Number: /// Converts an `f32` to `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. @@ -93,6 +99,14 @@ macro_rules! number_impl { 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. +/// We use the axial coordinate system explained in this +/// [documentation](https://www.redblobgames.com/grids/hexagons/#coordinates). #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct HexPosition(pub T, pub T); @@ -130,7 +146,16 @@ pub enum 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(self) -> HexPosition { match self { Self::Right => HexPosition(T::ONE, T::ZERO), @@ -211,6 +236,7 @@ impl Iterator for HexSpiral { type Item = HexPosition; fn next(&mut self) -> Option { + // The origin of the spiral. if self.index == 0 { self.index += 1; return Some(self.origin); @@ -229,12 +255,24 @@ impl Iterator for HexSpiral { } impl HexPosition { - /// Creates a new hexagonal position. - pub const fn new(x: T, y: T) -> Self { - Self(x, y) - } - - /// Returns the pixel coordinates of the hexagonal position. + /// Converts the current [HexPosition] into a pixel coordinate. + /// Input: The size of the hexagon in pixels (witdh, height). + /// + /// If you want to learn more about pixel coordinates conversion, + /// you can check the + /// [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) { ( size.0 @@ -245,23 +283,79 @@ impl HexPosition { ) } - /// 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 { let Self(x, y) = self - other; x.abs() + y.abs() + (x + y).abs() / T::TWO } - pub fn range(&self, range: T) -> HashSet { - let mut result_positions = HashSet::new(); - for q in num::range_inclusive(-range, range) { - for r in num::range_inclusive((-range, -q - range), min(range, -q + range)) { - result_positions.insert(Self { q, r }); + /// Returns all positions within a given `range` from the current + /// `HexPosition`. + /// + /// This function iterates over the possible q and r values within the + /// 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 { + 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 } /// 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 { HexRing { current: self + HexDirection::DownLeft.to_vector() * T::from_usize(radius), @@ -272,6 +366,21 @@ impl HexPosition { } /// 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 { HexSpiral { origin: self,