bestagon 0.7.0

An engine for discrete stuff in hexagonal grids
Documentation
use crate::{distance::Distance, lerp::LinearInterpolation};

pub trait GridLine {
  type Iter: Iterator<Item = Self>;
  fn grid_line(&self, to: &Self) -> Self::Iter;
}

// This trait is automatically implemented for structs that implement the
// `LinearInterpolation`, `Distance` & `Copy` traits.
impl<T> GridLine for T
where
  T: LinearInterpolation,
  T: Distance<isize>,
  T: Copy,
{
  type Iter = GridLineIterator<T>;
  fn grid_line(&self, to: &T) -> Self::Iter
  where
    T: Sized,
  {
    GridLineIterator {
      from: *self,
      to: *to,
      dist: self.dist(to),
      current: 0,
    }
  }
}

pub struct GridLineIterator<T> {
  from: T,
  to: T,
  dist: isize,
  current: isize,
}

impl<T> Iterator for GridLineIterator<T>
where
  T: LinearInterpolation,
  T: Distance<isize>,
{
  type Item = T;

  fn next(&mut self) -> Option<Self::Item> {
    if self.current > self.dist {
      return None;
    }

    self.current += 1;
    Some(
      self
        .from
        .lerp(&self.to, (self.current - 1) as f32 / self.dist as f32),
    )
  }
}

#[cfg(test)]
mod test {
  use super::*;
  use crate::hex::*;

  #[test]
  fn grid_line_case_0() {
    let a = HexCb::new(0, 0, 0);
    let b = HexCb::new(3, -2, -1);
    verify_grid_line(&a.grid_line(&b).collect(), &a, &b);
  }

  #[test]
  fn grid_line_case_1() {
    let a = HexCb::new(-4, 4, 0);
    let b = HexCb::new(4, -4, 0);
    verify_grid_line(&a.grid_line(&b).collect(), &a, &b);
  }

  fn verify_grid_line(path: &Vec<HexCb>, from: &HexCb, to: &HexCb) {
    // Assert that the path starts at `from`.
    assert_eq!(from, path.first().unwrap());
    // Assert that the path ends at `to`.
    assert_eq!(to, path.last().unwrap());

    // Assert that all subsequent coordinates have distance 1.
    let mut prev = path.first().unwrap();
    for x in path[1..].iter() {
      assert_eq!(1, x.dist(prev));
      prev = x;
    }

    // Assert that the line takes as many steps as the in-grid distance.
    assert_eq!(path.len(), from.dist(to) as usize + 1);
  }
}