lighthouse_protocol/utils/
direction.rs1use std::{fmt::Debug, ops::Neg};
2
3use rand::{prelude::Distribution, distributions::Standard};
4use serde::{Deserialize, Serialize};
5
6use super::{Vec2, Unity, Zero};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
10pub enum Direction {
11 Up,
12 Down,
13 Left,
14 Right,
15}
16
17impl Direction {
18 pub fn approximate_from<T>(vec2: Vec2<T>) -> Option<Self> where T: Zero + Unity + PartialEq + Neg<Output = T> + PartialOrd + Copy {
19 if vec2 == Vec2::ZERO {
20 return None;
21 }
22
23 let Vec2 { x, y } = vec2;
27 let left_or_up = x < -y;
28 let right_or_up = -x < -y;
29 Some(
30 match (left_or_up, right_or_up) {
31 (true, true) => Direction::Up,
32 (true, false) => Direction::Left,
33 (false, true) => Direction::Right,
34 (false, false) => Direction::Down,
35 }
36 )
37 }
38}
39
40impl<T> TryFrom<Vec2<T>> for Direction where T: Zero + Unity + PartialEq + Debug {
41 type Error = String;
42
43 fn try_from(vec2: Vec2<T>) -> Result<Self, Self::Error> {
44 if vec2 == Vec2::UP {
45 Ok(Direction::Up)
46 } else if vec2 == Vec2::DOWN {
47 Ok(Direction::Down)
48 } else if vec2 == Vec2::LEFT {
49 Ok(Direction::Left)
50 } else if vec2 == Vec2::RIGHT {
51 Ok(Direction::Right)
52 } else {
53 Err(format!("Not a direction: {:?}", vec2))
54 }
55 }
56}
57
58impl<T> From<Direction> for Vec2<T> where T: Zero + Unity {
59 fn from(direction: Direction) -> Self {
60 match direction {
61 Direction::Up => Vec2::UP,
62 Direction::Down => Vec2::DOWN,
63 Direction::Left => Vec2::LEFT,
64 Direction::Right => Vec2::RIGHT,
65 }
66 }
67}
68
69impl Distribution<Direction> for Standard {
70 fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> Direction {
71 match rng.gen_range(0..4) {
72 0 => Direction::Up,
73 1 => Direction::Down,
74 2 => Direction::Left,
75 3 => Direction::Right,
76 _ => unreachable!(),
77 }
78 }
79}