use endgame_direction::{Direction, DirectionSet};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::fmt::{Debug, Display};
use std::hash::Hash;
use std::ops::{RangeBounds, RangeFull, RangeTo, RangeToInclusive};
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum DirectionType {
#[default]
Face,
Vertex,
}
impl Display for DirectionType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
use DirectionType::*;
match self {
Face => write!(f, "Face"),
Vertex => write!(f, "Vertex"),
}
}
}
impl std::ops::Not for DirectionType {
type Output = Self;
fn not(self) -> Self::Output {
use DirectionType::*;
match self {
Face => Vertex,
Vertex => Face,
}
}
}
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum Color {
One = 1,
Two = 2,
Three = 3,
Four = 4,
}
impl TryFrom<usize> for Color {
type Error = String;
fn try_from(value: usize) -> Result<Self, Self::Error> {
let color = match value {
1 => Color::One,
2 => Color::Two,
3 => Color::Three,
4 => Color::Four,
_ => {
return Err(format!(
"Color value must be in the range 1..=4, got {value}"
));
}
};
Ok(color)
}
}
impl Display for Color {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
use Color::*;
let str = match self {
One => "One",
Two => "Two",
Three => "Three",
Four => "Four",
};
write!(f, "{}", str)
}
}
pub trait Coord: PartialEq + Eq + Clone + Hash + Debug + Display + Sync + Send {
type Axes: Clone + Copy + PartialEq + Eq + Hash + Debug + Display;
fn is_origin(&self) -> bool;
fn distance(&self, other: &Self) -> usize;
fn angle_to_direction(&self, dir_type: DirectionType, angle: f32) -> Direction;
fn direction_angle(&self, dir_type: DirectionType, dir: Direction) -> Option<f32>;
fn move_in_direction(&self, dir_type: DirectionType, dir: Direction) -> Option<Self>;
fn move_on_axis(&self, axis: Self::Axes, positive: bool) -> Self;
fn direction_iterator<RB: AllowedCoordIterRange>(
&self,
dir_type: DirectionType,
dir: Direction,
range: RB,
) -> impl Iterator<Item=Self>;
fn path_iterator(&self, other: &Self) -> impl Iterator<Item=Self>;
fn axis_iterator<RB: AllowedCoordIterRange>(
&self,
axis: Self::Axes,
positive: bool,
range: RB,
) -> impl Iterator<Item=Self>;
fn allowed_direction(&self, dir_type: DirectionType, dir: Direction) -> bool;
fn allowed_directions(&self, dir_type: DirectionType) -> DirectionSet;
fn grid_to_array_offset(&self) -> (isize, isize);
fn to_color(&self) -> Color;
fn rotate_clockwise(&self) -> Self;
fn rotate_counterclockwise(&self) -> Self;
fn rotate(&self, steps: isize) -> Self {
let mut result = self.clone();
if steps > 0 {
for _ in 0..steps {
result = result.rotate_clockwise();
}
} else {
for _ in 0..(-steps) {
result = result.rotate_counterclockwise();
}
}
result
}
fn reflect(&self, axis: Self::Axes) -> Self;
}
pub trait ModuleCoord:
Coord
+ Default + std::ops::Neg<Output=Self>
+ std::ops::Add<Output=Self>
+ std::ops::Sub<Output=Self>
+ std::ops::AddAssign
+ std::ops::SubAssign
+ std::ops::Mul<isize, Output=Self>
+ std::ops::MulAssign<isize>
where
for<'a> Self: std::ops::Add<&'a Self, Output=Self>,
for<'a, 'b> &'a Self: std::ops::Add<&'b Self, Output=Self>,
for<'a> Self: std::ops::AddAssign<&'a Self>,
for<'a> Self: std::ops::Sub<&'a Self, Output=Self>,
for<'a, 'b> &'a Self: std::ops::Sub<&'b Self, Output=Self>,
for<'a> Self: std::ops::SubAssign<&'a Self>,
{
fn offset_in_direction(&self, dir_type: DirectionType, dir: Direction) -> Option<Self>;
fn offset_on_axis(&self, axis: Self::Axes, positive: bool) -> Self;
}
pub trait AllowedCoordIterRange: RangeBounds<usize> {
fn complete(&self, index: usize) -> bool {
match self.end_bound() {
std::ops::Bound::Included(&end) => index > end,
std::ops::Bound::Excluded(&end) => index >= end,
std::ops::Bound::Unbounded => false,
}
}
}
impl AllowedCoordIterRange for RangeFull {}
impl AllowedCoordIterRange for RangeTo<usize> {}
impl AllowedCoordIterRange for RangeToInclusive<usize> {}
type Point = glam::Vec2;
pub trait SizedGrid {
type Coord: Coord;
fn inradius(&self) -> f32;
fn circumradius(&self) -> f32;
fn edge_length(&self) -> f32;
fn vertices(&self, coord: &Self::Coord) -> Vec<Point>;
fn edges(&self, coord: &Self::Coord) -> HashMap<Direction, (Point, Point)>;
fn grid_to_screen(&self, coord: &Self::Coord) -> Point;
fn screen_to_grid(&self, point: Point) -> Self::Coord;
fn screen_rect_to_grid(
&self,
min: Point,
max: Point,
) -> Option<impl Iterator<Item=Self::Coord>>;
fn coord_contains(&self, coord: &Self::Coord, point: Point) -> bool {
self.grid_to_screen(coord) == point
}
fn coord_intersects_rect(&self, coord: &Self::Coord, min: Point, max: Point) -> bool {
utils::convex_poly_intersects_rect(&self.vertices(coord), min, max)
}
}
pub trait Shape<C: Coord>:
Debug + Clone + PartialEq + Eq + Hash + IntoIterator + std::ops::Sub<Output=Self>
where
for<'a> Self: std::ops::Sub<&'a Self, Output=Self>,
{
type Iterator<'a>: ShapeIterator<'a, C>
where
Self: 'a,
C: 'a;
fn new() -> Self;
fn contains(&self, coord: &C) -> bool;
fn is_subshape(&self, other: &Self) -> bool;
fn is_supershape(&self, other: &Self) -> bool;
fn is_disjoint(&self, other: &Self) -> bool;
fn is_empty(&self) -> bool;
fn union<'a>(&'a self, other: &'a Self) -> Self
where
C: 'a;
fn iter<'a>(&'a self) -> Self::Iterator<'a>
where
C: 'a;
}
pub trait ShapeIterator<'a, C: Coord + 'a>: Iterator<Item=&'a C> {}
pub trait ModuleShape<MC: ModuleCoord>: Shape<MC>
where
for<'a, 'b> &'a MC: std::ops::Add<&'b MC, Output=MC>,
for<'a, 'b> &'a MC: std::ops::Sub<&'b MC, Output=MC>,
{
fn translate(&self, offset: &MC) -> Self;
}
pub trait ShapeContainer<C: Coord, V>:
Debug + Clone + PartialEq + Eq + Hash + IntoIterator
where
V: Debug + Clone + PartialEq + Eq + Hash,
{
type Iterator<'a>: ShapeContainerIterator<'a, C, V>
where
Self: 'a,
C: 'a,
V: 'a;
fn contains(&self, coord: &C) -> bool;
fn get(&self, coord: &C) -> Option<&V>;
fn get_mut(&mut self, coord: &C) -> Option<&mut V>;
fn insert(&mut self, coord: C, value: V) -> Option<V>;
fn is_empty(&self) -> bool;
fn as_shape(&self) -> impl Shape<C>;
fn iter<'a>(&'a self) -> Self::Iterator<'a>
where
C: 'a,
V: 'a;
}
pub trait ShapeContainerIterator<'a, C: Coord + 'a, V: 'a>:
Iterator<Item=(&'a C, &'a V)>
{}
pub trait ModuleShapeContainer<MC: ModuleCoord, V>: ShapeContainer<MC, V>
where
V: Debug + Clone + PartialEq + Eq + Hash,
for<'a, 'b> &'a MC: std::ops::Add<&'b MC, Output=MC>,
for<'a, 'b> &'a MC: std::ops::Sub<&'b MC, Output=MC>,
{
fn translate(&self, offset: &MC) -> Self;
}
pub mod dynamic;
pub mod hex;
pub mod shape;
pub mod square;
pub mod triangle;
mod utils;