generated from tipragot/rust
Add utils for hexagonal grild #50
74
Cargo.lock
generated
74
Cargo.lock
generated
|
@ -1316,6 +1316,8 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bevy",
|
"bevy",
|
||||||
"bevy_egui",
|
"bevy_egui",
|
||||||
|
"num",
|
||||||
|
"partial-min-max",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2993,6 +2995,40 @@ dependencies = [
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af"
|
||||||
|
dependencies = [
|
||||||
|
"num-bigint",
|
||||||
|
"num-complex",
|
||||||
|
"num-integer",
|
||||||
|
"num-iter",
|
||||||
|
"num-rational",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-bigint"
|
||||||
|
version = "0.4.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-complex"
|
||||||
|
version = "0.4.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "23c6602fda94a57c990fe0df199a035d83576b496aa29f4e634a8ac6004e68a6"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-derive"
|
name = "num-derive"
|
||||||
version = "0.3.3"
|
version = "0.3.3"
|
||||||
|
@ -3004,6 +3040,38 @@ dependencies = [
|
||||||
"syn 1.0.109",
|
"syn 1.0.109",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-integer"
|
||||||
|
version = "0.1.46"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-iter"
|
||||||
|
version = "0.1.44"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d869c01cc0c455284163fd0092f1f93835385ccab5a98a0dcc497b2f8bf055a9"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-rational"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-bigint",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-traits"
|
name = "num-traits"
|
||||||
version = "0.2.18"
|
version = "0.2.18"
|
||||||
|
@ -3261,6 +3329,12 @@ dependencies = [
|
||||||
"windows-targets 0.48.5",
|
"windows-targets 0.48.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "partial-min-max"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6448add382c60bbbc64f9dab41309a12ec530c05191601042f911356ac09758c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "paste"
|
name = "paste"
|
||||||
version = "1.0.14"
|
version = "1.0.14"
|
||||||
|
|
|
@ -13,3 +13,5 @@ workspace = true
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bevy = "0.12.1"
|
bevy = "0.12.1"
|
||||||
bevy_egui = "0.24.0"
|
bevy_egui = "0.24.0"
|
||||||
|
num = "0.4.1"
|
||||||
|
partial-min-max = "0.4.0"
|
||||||
|
|
126
crates/border-wars/src/hex.rs
Normal file
126
crates/border-wars/src/hex.rs
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
//! All functions related to calculations in a hexagonal grid.
|
||||||
|
|
||||||
|
use std::collections::HashSet;
|
||||||
|
use std::hash::Hash;
|
||||||
|
use std::ops::{Add, AddAssign, Sub, SubAssign};
|
||||||
|
|
||||||
|
use num::{FromPrimitive, Signed};
|
||||||
|
use partial_min_max::{max, min};
|
||||||
|
|
||||||
|
/// Represents a number that can be used in a hexagonal grid.
|
||||||
|
pub trait HexNumber: Signed + PartialEq + Copy + PartialOrd + FromPrimitive {}
|
||||||
|
|
||||||
|
impl<T: Signed + PartialEq + Copy + PartialOrd + FromPrimitive> HexNumber for T {}
|
||||||
|
|
||||||
|
/// Represents a position in a hexagonal grid.
|
||||||
|
/// We use the axial coordinate system explained in this
|
||||||
CoCo_Sol marked this conversation as resolved
Outdated
|
|||||||
|
/// [documentation](https://www.redblobgames.com/grids/hexagons/#coordinates).
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct HexPosition<T: HexNumber> {
|
||||||
|
/// Q coordinate.
|
||||||
|
pub q: T,
|
||||||
|
|
||||||
|
/// R coordinate.
|
||||||
|
pub r: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: HexNumber> HexPosition<T> {
|
||||||
|
/// 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::hex::HexPosition;
|
||||||
|
///
|
||||||
|
/// let a = HexPosition { q: 0, r: 0 };
|
||||||
|
/// let b = HexPosition { q: 1, r: 1 };
|
||||||
|
///
|
||||||
|
/// assert_eq!(a.distance_to(&b), 2);
|
||||||
|
/// ```
|
||||||
|
pub fn distance_to(&self, other: &Self) -> T {
|
||||||
|
// Calculate the difference between the q and r coordinates.
|
||||||
|
let dq = (self.q - other.q).abs();
|
||||||
|
let dr = (self.r - other.r).abs();
|
||||||
|
let ds = dq + dr;
|
||||||
|
|
||||||
|
// Manhattan distance = (abs(dq) + abs(dr) + abs(ds)) / 2
|
||||||
|
(dq + dr + ds) / (T::one() + T::one())
|
||||||
CoCo_Sol marked this conversation as resolved
Outdated
tipragot
commented
dz = -dq - dr dz = -dq - dr
|
|||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: HexNumber + Eq + Hash + std::cmp::PartialOrd + num::ToPrimitive> HexPosition<T> {
|
||||||
|
/// 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
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use border_wars::hex::HexPosition;
|
||||||
|
///
|
||||||
|
/// let position = HexPosition { q: 0, r: 0 };
|
||||||
|
///
|
||||||
|
/// let positions = position.range(1);
|
||||||
|
///
|
||||||
|
/// assert_eq!(positions.len(), 7);
|
||||||
|
/// ```
|
||||||
|
pub fn range(&self, range: T) -> HashSet<Self> {
|
||||||
|
let mut result_positions = HashSet::new();
|
||||||
|
for q in num::range_inclusive(-range, range) {
|
||||||
|
for r in num::range_inclusive(max(-range, -q - range), min(range, -q + range)) {
|
||||||
|
result_positions.insert(Self { q, r });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result_positions
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: HexNumber> Add<Self> for HexPosition<T> {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn add(self, other: Self) -> Self::Output {
|
||||||
|
Self {
|
||||||
|
q: self.q + other.q,
|
||||||
|
r: self.r + other.r,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: HexNumber + AddAssign> AddAssign<Self> for HexPosition<T> {
|
||||||
|
fn add_assign(&mut self, other: Self) {
|
||||||
|
self.q += other.q;
|
||||||
|
self.r += other.r;
|
||||||
|
}
|
||||||
|
}
|
||||||
CoCo_Sol marked this conversation as resolved
Outdated
tipragot
commented
Don't make a new allocation. Use the += operator Don't make a new allocation. Use the += operator
|
|||||||
|
|
||||||
|
impl<T: HexNumber> Sub<Self> for HexPosition<T> {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn sub(self, other: Self) -> Self {
|
||||||
|
Self {
|
||||||
|
q: self.q - other.q,
|
||||||
|
r: self.r - other.r,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: HexNumber + SubAssign> SubAssign<Self> for HexPosition<T> {
|
||||||
|
fn sub_assign(&mut self, other: Self) {
|
||||||
|
self.q -= other.q;
|
||||||
|
self.r -= other.r;
|
||||||
|
}
|
||||||
CoCo_Sol marked this conversation as resolved
Outdated
tipragot
commented
Don't make a new allocation. Use the += operator Don't make a new allocation. Use the += operator
|
|||||||
|
}
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
|
|
||||||
|
pub mod hex;
|
||||||
pub mod scenes;
|
pub mod scenes;
|
||||||
|
|
||||||
/// The current scene of the game.
|
/// The current scene of the game.
|
||||||
|
|
Loading…
Reference in a new issue
I think we should be more generic over the type used. You can use the num crate to do so. And you could still make a specific type using the
type
keyword.