use crate::grid::{
Cell, Grid, GridSize, WorldSizeType, direction::Direction, offset_coordinate::OffsetCoordinate,
};
use super::{Size, WrapFlags};
mod square;
pub use square::*;
#[derive(Clone, Copy)]
pub struct SquareGrid {
pub size: Size,
pub layout: SquareLayout,
pub wrap_flags: WrapFlags,
}
impl SquareGrid {
pub const fn new(size: Size, layout: SquareLayout, wrap_flags: WrapFlags) -> Self {
Self {
size,
layout,
wrap_flags,
}
}
pub const fn with_resized_layout(&self, layout_size: [f32; 2]) -> Self {
Self {
layout: SquareLayout {
size: layout_size,
..self.layout
},
..*self
}
}
}
impl Grid for SquareGrid {
type GridCoordinateType = Square;
type DirectionArrayType = [Direction; 4];
fn edge_direction_array(&self) -> Self::DirectionArrayType {
self.layout.orientation.edge_direction()
}
fn corner_direction_array(&self) -> Self::DirectionArrayType {
self.layout.orientation.corner_direction()
}
fn size(&self) -> Size {
self.size
}
fn wrap_flags(&self) -> WrapFlags {
self.wrap_flags
}
fn center(&self) -> [f32; 2] {
let width = self.size.width;
let height = self.size.height;
let min_offset = self.layout.square_to_pixel(Square::new(0, 0));
let max_offset = self
.layout
.square_to_pixel(Square::new(width as i32 - 1, height as i32 - 1));
((min_offset + max_offset) / 2.0).into()
}
fn left_bottom(&self) -> [f32; 2] {
self.layout.square_to_pixel(Square::new(0, 0)).to_array()
}
fn right_top(&self) -> [f32; 2] {
let width = self.size.width;
let height = self.size.height;
self.layout
.square_to_pixel(Square::new(width as i32 - 1, height as i32 - 1))
.to_array()
}
fn offset_to_pixel(&self, offset: OffsetCoordinate) -> [f32; 2] {
let square = Square::from_offset(offset);
self.layout.square_to_pixel(square).to_array()
}
fn pixel_to_offset(&self, pixel: [f32; 2]) -> OffsetCoordinate {
let square = self.layout.pixel_to_square(pixel);
square.to_offset()
}
fn grid_coordinate_to_cell(&self, grid_coordinate: Self::GridCoordinateType) -> Option<Cell> {
let offset_coordinate = grid_coordinate.to_offset();
self.offset_to_cell(offset_coordinate).ok()
}
fn distance_to(&self, start: Cell, dest: Cell) -> i32 {
let start = self.cell_to_offset(start);
let dest = self.cell_to_offset(dest);
let [mut dest_x, mut dest_y] = dest.to_array();
let [x, y] = (dest.0 - start.0).to_array();
if self.wrap_x() {
if x > self.width() as i32 / 2 {
dest_x -= self.width() as i32;
}
if x < -(self.width() as i32) / 2 {
dest_x += self.width() as i32;
}
}
if self.wrap_y() {
if y > self.height() as i32 / 2 {
dest_y -= self.height() as i32;
}
if y < -(self.height() as i32) / 2 {
dest_y += self.height() as i32;
}
}
let dest = OffsetCoordinate::new(dest_x, dest_y);
let dest_square = Square::from_offset(dest);
let start_square = Square::from_offset(start);
start_square.distance_to(dest_square)
}
fn neighbor(self, center: Cell, direction: Direction) -> Option<Cell> {
let center = self.cell_to_offset(center);
let center_square = Square::from_offset(center);
let neighbor_offset_coordinate = center_square
.neighbor(self.layout.orientation, direction)
.to_offset();
self.offset_to_cell(neighbor_offset_coordinate).ok()
}
fn cells_at_distance(self, center: Cell, distance: u32) -> impl Iterator<Item = Cell> {
let center = self.cell_to_offset(center);
let center_square = Square::from_offset(center);
center_square
.squares_at_distance(distance)
.into_iter()
.filter_map(move |square| self.grid_coordinate_to_cell(square))
}
fn cells_within_distance(self, center: Cell, distance: u32) -> impl Iterator<Item = Cell> {
let center = self.cell_to_offset(center);
let center_square = Square::from_offset(center);
center_square
.squares_in_distance(distance)
.into_iter()
.filter_map(move |square| self.grid_coordinate_to_cell(square))
}
fn estimate_direction(&self, start: Cell, dest: Cell) -> Option<Direction> {
let start = self.cell_to_offset(start);
let dest = self.cell_to_offset(dest);
if start == dest {
return None;
}
let [mut dest_x, mut dest_y] = dest.to_array();
let [x, y] = (dest.0 - start.0).to_array();
if self.wrap_x() {
if x > self.width() as i32 / 2 {
dest_x -= self.width() as i32;
}
if x < -(self.width() as i32) / 2 {
dest_x += self.width() as i32;
}
}
if self.wrap_y() {
if y > self.height() as i32 / 2 {
dest_y -= self.height() as i32;
}
if y < -(self.height() as i32) / 2 {
dest_y += self.height() as i32;
}
}
let dest = OffsetCoordinate::new(dest_x, dest_y);
let dest_square = Square::from_offset(dest);
let start_square = Square::from_offset(start);
let estimate_vector = (dest_square - start_square).into_inner();
let edge_direction_array = self.edge_direction_array();
let origin = Square::new(0, 0);
edge_direction_array.into_iter().max_by_key(|&direction| {
let unit_direction_vector = origin
.neighbor(self.layout.orientation, direction)
.into_inner();
estimate_vector.dot(unit_direction_vector)
})
}
}
impl GridSize for SquareGrid {
fn default_size(world_size_type: WorldSizeType) -> Size {
match world_size_type {
WorldSizeType::Duel => Size {
width: 48,
height: 32,
},
WorldSizeType::Tiny => Size {
width: 60,
height: 40,
},
WorldSizeType::Small => Size {
width: 72,
height: 48,
},
WorldSizeType::Standard => Size {
width: 96,
height: 64,
},
WorldSizeType::Large => Size {
width: 120,
height: 80,
},
WorldSizeType::Huge => Size {
width: 144,
height: 96,
},
}
}
}