bestagon 0.5.0

An engine for discrete stuff in hexagonal grids
Documentation
use std::{collections::HashSet, hash::Hash};

use crate::{distance::*, edge::*, neighbours::*, node::Node};

/// A Hex represents the face of a single hexagon in the grid.
pub trait Hex:
  Eq + Hash + Neighbour + Distance<isize> + Into<HexCb> + Into<HexAx> + From<HexAx> + Copy
{
  fn edges<T>(&self) -> HashSet<T>
  where
    T: Edge,
  {
    self
      .neighbours()
      .map(|n| EdgeAx::between(self, &n).into())
      .collect()
  }

  fn nodes<T>(&self) -> HashSet<T>
  where
    T: Node,
  {
    self
      .edges()
      .into_iter()
      .flat_map(|e: EdgeAx| e.nodes())
      .collect()
  }
}

#[derive(Eq, PartialEq, Debug, Copy, Clone, Hash)]
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 Neighbour for HexAx {
  fn get_neighbour(&self, n: u8) -> Option<HexAx> {
    match n {
      0 => Some(HexAx::new(self.q, self.r + 1)),
      1 => Some(HexAx::new(self.q + 1, self.r)),
      2 => Some(HexAx::new(self.q + 1, self.r - 1)),
      3 => Some(HexAx::new(self.q, self.r - 1)),
      4 => Some(HexAx::new(self.q - 1, self.r)),
      5 => Some(HexAx::new(self.q - 1, self.r + 1)),
      _ => None,
    }
  }
}

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 Neighbour for HexCb {
  fn get_neighbour(&self, n: u8) -> Option<HexCb> {
    match n {
      0 => Some(HexCb::new(self.q, self.r + 1, self.s - 1)),
      1 => Some(HexCb::new(self.q + 1, self.r, self.s - 1)),
      2 => Some(HexCb::new(self.q + 1, self.r - 1, self.s)),
      3 => Some(HexCb::new(self.q, self.r - 1, self.s + 1)),
      4 => Some(HexCb::new(self.q - 1, self.r, self.s + 1)),
      5 => Some(HexCb::new(self.q - 1, self.r + 1, self.s)),
      _ => None,
    }
  }
}

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 super::*;

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

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

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

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