111 lines
3.4 KiB
Rust
111 lines
3.4 KiB
Rust
use crate::prelude::*;
|
|
|
|
pub trait Transformable {
|
|
fn transform(&self, t: Transformation) -> Self;
|
|
}
|
|
|
|
#[derive(Clone, Copy, Debug)]
|
|
pub struct Transformation {
|
|
rot: Direction,
|
|
pos: Position,
|
|
}
|
|
|
|
impl Transformation {
|
|
pub fn new(rot: Direction, pos: Position) -> Self {
|
|
Self { rot, pos }
|
|
}
|
|
|
|
pub fn rot(&self) -> Direction {
|
|
self.rot
|
|
}
|
|
|
|
pub fn invert(self) -> Self {
|
|
Self::new(
|
|
match self.rot {
|
|
Direction::Up => Direction::Up,
|
|
Direction::Right => Direction::Left,
|
|
Direction::Down => Direction::Down,
|
|
Direction::Left => Direction::Right,
|
|
},
|
|
match self.rot {
|
|
Direction::Up => Position::new(-self.pos.x, -self.pos.y),
|
|
Direction::Right => Position::new(-self.pos.y, self.pos.x),
|
|
Direction::Down => self.pos,
|
|
Direction::Left => Position::new(self.pos.y, -self.pos.x),
|
|
},
|
|
)
|
|
}
|
|
|
|
pub fn chain(self, other: Self) -> Self {
|
|
Self::new(self.rot.transform(other), self.pos.transform(other))
|
|
}
|
|
}
|
|
|
|
impl Transformable for Position {
|
|
fn transform(&self, t: Transformation) -> Self {
|
|
(match t.rot {
|
|
Direction::Up => *self,
|
|
Direction::Right => Position::new(-self.y, self.x),
|
|
Direction::Down => Position::new(-self.x, -self.y),
|
|
Direction::Left => Position::new(self.y, -self.x),
|
|
}) + t.pos
|
|
}
|
|
}
|
|
|
|
impl Transformable for Direction {
|
|
fn transform(&self, t: Transformation) -> Self {
|
|
match (t.rot, self) {
|
|
(Direction::Up, _) => *self,
|
|
(Direction::Right, Direction::Up) => Direction::Right,
|
|
(Direction::Right, Direction::Right) => Direction::Down,
|
|
(Direction::Right, Direction::Down) => Direction::Left,
|
|
(Direction::Right, Direction::Left) => Direction::Up,
|
|
(Direction::Down, Direction::Up) => Direction::Down,
|
|
(Direction::Down, Direction::Right) => Direction::Left,
|
|
(Direction::Down, Direction::Down) => Direction::Up,
|
|
(Direction::Down, Direction::Left) => Direction::Right,
|
|
(Direction::Left, Direction::Up) => Direction::Left,
|
|
(Direction::Left, Direction::Right) => Direction::Up,
|
|
(Direction::Left, Direction::Down) => Direction::Right,
|
|
(Direction::Left, Direction::Left) => Direction::Down,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod test {
|
|
use crate::prelude::*;
|
|
use proptest::{prop_assert_eq, proptest};
|
|
|
|
#[test]
|
|
fn position() {
|
|
let p = Position::new(3, 5);
|
|
|
|
let t = Transformation::new(Direction::Up, Position::new(-3, -5));
|
|
assert_eq!(p.transform(t), Position::new(0, 0));
|
|
|
|
let t = Transformation::new(Direction::Down, Position::new(-3, -5));
|
|
assert_eq!(p.transform(t), Position::new(-6, -10));
|
|
}
|
|
|
|
proptest! {
|
|
#[test]
|
|
fn invert(dir: Direction, pos: Position) {
|
|
let o = Transformation::new(dir, pos);
|
|
|
|
let i = o.invert();
|
|
let c = o.chain(i);
|
|
|
|
prop_assert_eq!(c.rot, Direction::Up, "o: {:?}, i: {:?}, c: {:?}", o, i, c);
|
|
prop_assert_eq!(
|
|
c.pos,
|
|
Position::new(0, 0),
|
|
"o: {:?}, i: {:?}, c: {:?}",
|
|
o,
|
|
i,
|
|
c
|
|
);
|
|
|
|
}
|
|
}
|
|
}
|