bestagon 0.7.0

An engine for discrete stuff in hexagonal grids
Documentation
#[cfg(feature = "bevy")]
use bevy_ecs::prelude::Component;
#[cfg(feature = "bevy")]
use bevy_reflect::Reflect;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use std::hash::Hash;

use crate::{Node, NodeAx, distance::*};

/// A Hex represents the face of a single hexagon in the grid.
pub trait Hex:
  Eq + Hash + Distance<isize> + Into<HexCb> + Into<HexAx> + From<HexAx> + Copy
{
  fn n_south_west(&self) -> impl Node {
    let ax: HexAx = (*self).into();
    NodeAx::new(ax.q * 3 - 1, ax.r * 3 - 1)
  }

  fn n_south_east(&self) -> impl Node {
    let ax: HexAx = (*self).into();
    NodeAx::new(ax.q * 3 + 1, ax.r * 3 - 2)
  }

  fn n_east(&self) -> impl Node {
    let ax: HexAx = (*self).into();
    NodeAx::new(ax.q * 3 + 2, ax.r * 3 - 1)
  }

  fn n_north_east(&self) -> impl Node {
    let ax: HexAx = (*self).into();
    NodeAx::new(ax.q * 3 + 1, ax.r * 3 + 1)
  }

  fn n_north_west(&self) -> impl Node {
    let ax: HexAx = (*self).into();
    NodeAx::new(ax.q * 3 - 1, ax.r * 3 + 2)
  }

  fn n_west(&self) -> impl Node {
    let ax: HexAx = (*self).into();
    NodeAx::new(ax.q * 3 - 2, ax.r * 3 + 1)
  }
}

#[derive(Eq, PartialEq, Debug, Copy, Clone, Hash, Default)]
#[cfg_attr(feature = "bevy", derive(Reflect, Component))]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct HexAx {
  pub q: isize,
  pub r: isize,
}

impl HexAx {
  pub fn new(q: isize, r: isize) -> Self {
    HexAx { q, r }
  }
}

impl From<HexCb> for HexAx {
  fn from(cb: HexCb) -> Self {
    HexAx::new(cb.q, cb.r)
  }
}

impl Hex for HexAx {}

pub struct FHexAx {
  pub q: f32,
  pub r: f32,
}

impl FHexAx {
  pub fn new(q: f32, r: f32) -> Self {
    FHexAx { q, r }
  }
}

impl From<&HexAx> for FHexAx {
  fn from(value: &HexAx) -> Self {
    FHexAx::new(value.q as f32, value.r as f32)
  }
}

#[derive(Eq, PartialEq, Debug, Copy, Clone, Hash)]
pub struct HexCb {
  pub q: isize,
  pub r: isize,
  pub s: isize,
}

impl HexCb {
  pub fn new(q: isize, r: isize, s: isize) -> HexCb {
    HexCb { q, r, s }
  }
}

impl From<HexAx> for HexCb {
  fn from(ax: HexAx) -> Self {
    HexCb::new(ax.q, ax.r, -ax.q - ax.r)
  }
}

impl Hex for HexCb {}

#[derive(PartialEq, Debug, Copy, Clone)]
pub struct FHexCb {
  pub q: f32,
  pub r: f32,
  pub s: f32,
}

impl FHexCb {
  pub fn new(q: f32, r: f32, s: f32) -> FHexCb {
    FHexCb { q, r, s }
  }
}

impl From<&FHexAx> for FHexCb {
  fn from(value: &FHexAx) -> Self {
    FHexCb::new(value.q, value.r, -value.q - value.r)
  }
}

#[cfg(test)]
mod test {
  use crate::neighbours::Hexes;

  use super::*;

  #[test]
  fn coords_of_cube_sum_to_0() {
    let x = HexAx::new(0, 0);
    let x_cb = HexCb::from(x);

    // Compute the neighbours.
    let neighbours: Vec<HexAx> = x.hexes().collect();

    // There should be six of those.
    assert_eq!(neighbours.len(), 6);

    // They should all...
    for (i, y) in neighbours.iter().map(|ax| HexCb::from(*ax)).enumerate() {
      // ...sum to zero
      assert_eq!(y.q + y.r + y.s, 0);
      // ...be unequal to the origin
      assert_ne!(y, x_cb);
      // ...have distance 1 to the origin
      assert_eq!(y.dist(&x_cb), 1);
      // ...and be unequal to all others
      for z in neighbours[i + 1..].iter().map(|ax| HexCb::from(*ax)) {
        assert_ne!(y, z);
      }
    }
  }
}