parent
2b4ef27f92
commit
e67a28d110
@ -0,0 +1,139 @@
|
|||||||
|
/// A position in a 2d grid.
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
|
pub struct Position2d {
|
||||||
|
pub x: usize,
|
||||||
|
pub y: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An alignment in a 2d grid.
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum Alignment {
|
||||||
|
Horizontal,
|
||||||
|
Vertical,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A direction in a 2d grid.
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum Direction {
|
||||||
|
Up,
|
||||||
|
Down,
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Alignment {
|
||||||
|
/// Returns the direction to the start of an alignment.
|
||||||
|
pub fn start(self) -> Direction {
|
||||||
|
match self {
|
||||||
|
Alignment::Horizontal => Direction::Left,
|
||||||
|
Alignment::Vertical => Direction::Up,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the direction to the end of an alignment.
|
||||||
|
pub fn end(self) -> Direction {
|
||||||
|
match self {
|
||||||
|
Alignment::Horizontal => Direction::Right,
|
||||||
|
Alignment::Vertical => Direction::Down,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Test if two positions are aligned in this direction.
|
||||||
|
pub fn is_aligned(self, a: Position2d, b: Position2d) -> bool {
|
||||||
|
match self {
|
||||||
|
Alignment::Horizontal => a.x == b.x,
|
||||||
|
Alignment::Vertical => a.y == b.y,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Position2d {
|
||||||
|
pub fn new(x: usize, y: usize) -> Self {
|
||||||
|
Self { x, y }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the position relative to this position in the given direction.
|
||||||
|
/// If the position is out of bounds, returns None.
|
||||||
|
pub fn relative(self, dir: Direction, sized: &impl Grid2d) -> Option<Position2d> {
|
||||||
|
let (x, y) = match dir {
|
||||||
|
Direction::Up => (self.x, self.y.checked_sub(1)?),
|
||||||
|
Direction::Down => (self.x, self.y.checked_add(1)?),
|
||||||
|
Direction::Left => (self.x.checked_sub(1)?, self.y),
|
||||||
|
Direction::Right => (self.x.checked_add(1)?, self.y),
|
||||||
|
};
|
||||||
|
if x < sized.width() && y < sized.height() {
|
||||||
|
Some(Position2d::new(x, y))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<(usize, usize)> for Position2d {
|
||||||
|
fn from((x, y): (usize, usize)) -> Self {
|
||||||
|
Self { x, y }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Trait for elements that have a size.
|
||||||
|
pub trait Grid2d {
|
||||||
|
/// Returns the grid width.
|
||||||
|
fn width(&self) -> usize;
|
||||||
|
|
||||||
|
/// Returns the grid height.
|
||||||
|
fn height(&self) -> usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
struct Rectangle {
|
||||||
|
width: usize,
|
||||||
|
height: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Rectangle {
|
||||||
|
fn new(width: usize, height: usize) -> Self {
|
||||||
|
Self { width, height }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Grid2d for Rectangle {
|
||||||
|
fn width(&self) -> usize {
|
||||||
|
self.width
|
||||||
|
}
|
||||||
|
|
||||||
|
fn height(&self) -> usize {
|
||||||
|
self.height
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_relative() {
|
||||||
|
let rect = Rectangle::new(3, 3);
|
||||||
|
let pos = Position2d::new(0, 0);
|
||||||
|
assert_eq!(pos.relative(Direction::Up, &rect), None);
|
||||||
|
assert_eq!(
|
||||||
|
pos.relative(Direction::Down, &rect),
|
||||||
|
Some(Position2d::new(0, 1))
|
||||||
|
);
|
||||||
|
assert_eq!(pos.relative(Direction::Left, &rect), None);
|
||||||
|
assert_eq!(
|
||||||
|
pos.relative(Direction::Right, &rect),
|
||||||
|
Some(Position2d::new(1, 0))
|
||||||
|
);
|
||||||
|
|
||||||
|
let pos = Position2d::new(2, 2);
|
||||||
|
assert_eq!(
|
||||||
|
pos.relative(Direction::Up, &rect),
|
||||||
|
Some(Position2d::new(2, 1))
|
||||||
|
);
|
||||||
|
assert_eq!(pos.relative(Direction::Down, &rect), None);
|
||||||
|
assert_eq!(
|
||||||
|
pos.relative(Direction::Left, &rect),
|
||||||
|
Some(Position2d::new(1, 2))
|
||||||
|
);
|
||||||
|
assert_eq!(pos.relative(Direction::Right, &rect), None);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue