1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
//! Integer-based coordinates.

use std::{
    convert::TryFrom,
    num::TryFromIntError,
    ops::{Add, AddAssign},
};

/// Unsigned-int coordinates
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct Coord {
    pub x: usize,
    pub y: usize,
}

impl Coord {
    /// Make a new coord.
    pub fn new(x: usize, y: usize) -> Self {
        Self { x, y }
    }

    /// Get this as an index into an array representing a 2d array.
    ///
    /// (AKA, `y * width + x`.)
    pub fn to_2d_idx(self, width: usize) -> usize {
        self.y * width + self.x
    }
}

impl Add for Coord {
    type Output = Self;
    fn add(self, rhs: Self) -> Self::Output {
        Self {
            x: self.x + rhs.x,
            y: self.y + rhs.y,
        }
    }
}

impl AddAssign for Coord {
    fn add_assign(&mut self, rhs: Self) {
        self.x += rhs.x;
        self.y += rhs.y;
    }
}

/// Try to convert an ICoord to a Coord.
/// Will return Error if the ICoord has any negatives in it.
impl TryFrom<ICoord> for Coord {
    type Error = TryFromIntError;
    fn try_from(value: ICoord) -> Result<Self, Self::Error> {
        use std::convert::TryInto;
        Ok(Self {
            x: value.x.try_into()?,
            y: value.y.try_into()?,
        })
    }
}

/// Signed-int coordinates
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct ICoord {
    pub x: isize,
    pub y: isize,
}

impl ICoord {
    /// Create a new ICoord
    pub fn new(x: isize, y: isize) -> Self {
        Self { x, y }
    }

    /// Return the quadrant this coordinate is in.
    ///
    /// - 1: +X, +Y
    /// - 2: -X, +Y
    /// - 3: -X, -Y
    /// - 4: +X, -Y
    ///
    /// Zeroes are treated as positive.
    ///
    /// ```
    /// # use cogs_gamedev::int_coords::ICoord;
    /// assert_eq!(ICoord::new(4, 5).quadrant(), 1);
    /// assert_eq!(ICoord::new(-3, -2).quadrant(), 3);
    /// // Zero is treated as positive
    /// assert_eq!(ICoord::new(0, -8).quadrant(), 4);
    /// assert_eq!(ICoord::new(0, 0).quadrant(), 1);
    /// ```
    pub fn quadrant(self) -> usize {
        match (self.x >= 0, self.y >= 0) {
            (true, true) => 1,
            (false, true) => 2,
            (false, false) => 3,
            (true, false) => 4,
        }
    }
}

impl Add for ICoord {
    type Output = Self;
    fn add(self, rhs: Self) -> Self::Output {
        Self {
            x: self.x + rhs.x,
            y: self.y + rhs.y,
        }
    }
}

impl AddAssign for ICoord {
    fn add_assign(&mut self, rhs: Self) {
        self.x += rhs.x;
        self.y += rhs.y;
    }
}