1 use std::{
2     cmp::{max, Ordering},
3     fmt::{self, Display, Error, Formatter},
4     ops::{Add, AddAssign, Div, Mul, Sub},
5 };
6 
7 use serde::{Deserialize, Serialize};
8 
9 #[derive(Copy, Clone, Default, Hash, PartialEq, Eq, Serialize, Deserialize)]
10 pub struct Point {
11     pub x: i32,
12     pub y: i32,
13 }
14 
15 // NOTE: Custom formatter that's always on 1 line even when pretty-printing
16 impl fmt::Debug for Point {
fmt(&self, f: &mut Formatter<'_>) -> fmt::Result17     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
18         write!(f, "Point{{x: {}, y: {}}}", self.x, self.y)
19     }
20 }
21 
22 impl Point {
new(x: i32, y: i32) -> Self23     pub fn new(x: i32, y: i32) -> Self {
24         Point { x, y }
25     }
26 
from_i32(x: i32) -> Self27     pub fn from_i32(x: i32) -> Self {
28         Point::new(x, x)
29     }
30 
zero() -> Self31     pub fn zero() -> Self {
32         Point::new(0, 0)
33     }
34 
distance<P: Into<Point>>(self, other: P) -> f3235     pub fn distance<P: Into<Point>>(self, other: P) -> f32 {
36         let other = other.into();
37         let a = (self.x - other.x).pow(2);
38         let b = (self.y - other.y).pow(2);
39         ((a + b) as f32).sqrt()
40     }
41 
tile_distance<P: Into<Point>>(self, other: P) -> i3242     pub fn tile_distance<P: Into<Point>>(self, other: P) -> i32 {
43         let other = other.into();
44         max((self.x - other.x).abs(), (self.y - other.y).abs())
45     }
46 }
47 
48 impl Into<Point> for (i32, i32) {
into(self) -> Point49     fn into(self) -> Point {
50         Point {
51             x: self.0,
52             y: self.1,
53         }
54     }
55 }
56 
57 impl Into<Point> for (u32, u32) {
into(self) -> Point58     fn into(self) -> Point {
59         Point {
60             x: self.0 as i32,
61             y: self.1 as i32,
62         }
63     }
64 }
65 
66 impl Display for Point {
fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>67     fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
68         write!(f, "({}, {})", self.x, self.y)
69     }
70 }
71 
72 impl Add for Point {
73     type Output = Self;
74 
add(self, rhs: Self) -> Self75     fn add(self, rhs: Self) -> Self {
76         Point {
77             x: self.x + rhs.x,
78             y: self.y + rhs.y,
79         }
80     }
81 }
82 
83 impl AddAssign for Point {
add_assign(&mut self, rhs: Self)84     fn add_assign(&mut self, rhs: Self) {
85         *self = *self + rhs;
86     }
87 }
88 
89 impl Sub for Point {
90     type Output = Self;
91 
sub(self, rhs: Self) -> Self92     fn sub(self, rhs: Self) -> Self {
93         self + Point::new(-rhs.x, -rhs.y)
94     }
95 }
96 
97 impl PartialOrd for Point {
partial_cmp(&self, _other: &Point) -> Option<Ordering>98     fn partial_cmp(&self, _other: &Point) -> Option<Ordering> {
99         // NOTE: I don't know that's the difference between this one
100         // and the more explicit fn below. So let's just crash here
101         // and see if and when we ever hit this.
102         unimplemented!();
103     }
104 
lt(&self, other: &Point) -> bool105     fn lt(&self, other: &Point) -> bool {
106         self.x < other.x && self.y < other.y
107     }
108 
le(&self, other: &Point) -> bool109     fn le(&self, other: &Point) -> bool {
110         self.x <= other.x && self.y <= other.y
111     }
112 
gt(&self, other: &Point) -> bool113     fn gt(&self, other: &Point) -> bool {
114         self.x > other.x && self.y > other.y
115     }
116 
ge(&self, other: &Point) -> bool117     fn ge(&self, other: &Point) -> bool {
118         self.x >= other.x && self.y >= other.y
119     }
120 }
121 
122 impl Add<(i32, i32)> for Point {
123     type Output = Self;
124 
add(self, rhs: (i32, i32)) -> Self125     fn add(self, rhs: (i32, i32)) -> Self {
126         let rhs: Point = rhs.into();
127         self + rhs
128     }
129 }
130 
131 impl AddAssign<(i32, i32)> for Point {
add_assign(&mut self, rhs: (i32, i32))132     fn add_assign(&mut self, rhs: (i32, i32)) {
133         let rhs: Point = rhs.into();
134         *self = self.add(rhs);
135     }
136 }
137 
138 impl Sub<(i32, i32)> for Point {
139     type Output = Self;
140 
sub(self, rhs: (i32, i32)) -> Self141     fn sub(self, rhs: (i32, i32)) -> Self {
142         let rhs: Point = rhs.into();
143         self - rhs
144     }
145 }
146 
147 impl PartialEq<(i32, i32)> for Point {
eq(&self, other: &(i32, i32)) -> bool148     fn eq(&self, other: &(i32, i32)) -> bool {
149         let other: Point = (*other).into();
150         self == &other
151     }
152 }
153 
154 impl PartialOrd<(i32, i32)> for Point {
partial_cmp(&self, other: &(i32, i32)) -> Option<Ordering>155     fn partial_cmp(&self, other: &(i32, i32)) -> Option<Ordering> {
156         let other: Point = (*other).into();
157         self.partial_cmp(&other)
158     }
159 
lt(&self, other: &(i32, i32)) -> bool160     fn lt(&self, other: &(i32, i32)) -> bool {
161         let other: Point = (*other).into();
162         self < &other
163     }
164 
le(&self, other: &(i32, i32)) -> bool165     fn le(&self, other: &(i32, i32)) -> bool {
166         let other: Point = (*other).into();
167         self <= &other
168     }
169 
gt(&self, other: &(i32, i32)) -> bool170     fn gt(&self, other: &(i32, i32)) -> bool {
171         let other: Point = (*other).into();
172         self > &other
173     }
174 
ge(&self, other: &(i32, i32)) -> bool175     fn ge(&self, other: &(i32, i32)) -> bool {
176         let other: Point = (*other).into();
177         self >= &other
178     }
179 }
180 
181 impl Mul<i32> for Point {
182     type Output = Self;
183 
mul(self, rhs: i32) -> Self184     fn mul(self, rhs: i32) -> Self {
185         Point::new(self.x * rhs, self.y * rhs)
186     }
187 }
188 
189 impl Div<i32> for Point {
190     type Output = Self;
191 
div(self, rhs: i32) -> Self192     fn div(self, rhs: i32) -> Self {
193         Point::new(self.x / rhs, self.y / rhs)
194     }
195 }
196 
197 pub struct CircularArea {
198     pos: Point,
199     center: Point,
200     radius: i32,
201     initial_x: i32,
202     max: Point,
203 }
204 
205 impl CircularArea {
new<P: Into<Point>>(center: P, radius: i32) -> Self206     pub fn new<P: Into<Point>>(center: P, radius: i32) -> Self {
207         let center = center.into();
208         CircularArea {
209             pos: center - (radius, radius),
210             center,
211             radius,
212             initial_x: center.x - radius,
213             max: center + (radius, radius),
214         }
215     }
216 }
217 
218 impl Iterator for CircularArea {
219     type Item = Point;
220 
next(&mut self) -> Option<Point>221     fn next(&mut self) -> Option<Point> {
222         loop {
223             if (self.pos.y > self.max.y) || (self.pos.x > self.max.x) {
224                 return None;
225             }
226             let current_point = self.pos;
227             self.pos.x += 1;
228             if self.pos.x > self.max.x {
229                 self.pos.x = self.initial_x;
230                 self.pos.y += 1;
231             }
232             if self.center.distance(current_point) < self.radius as f32 {
233                 return Some(current_point);
234             } else {
235                 // Keep looping for another point
236             }
237         }
238     }
239 }
240 
241 /// A square area defined by its "half_side" or radius.
242 /// A half_side of 0 means no points. Radius of 1 means the centre point.
243 /// Radius of 2 means a square of 9 points, and so on.
244 pub struct SquareArea {
245     pos: Point,
246     min_x: i32,
247     max: Point,
248     radius: i32,
249 }
250 
251 impl SquareArea {
new<P: Into<Point>>(center: P, radius: i32) -> Self252     pub fn new<P: Into<Point>>(center: P, radius: i32) -> Self {
253         let center = center.into();
254         let half_side = radius - 1;
255         SquareArea {
256             radius,
257             pos: center - (half_side, half_side),
258             min_x: center.x - half_side,
259             max: center + (half_side, half_side),
260         }
261     }
262 }
263 
264 impl Iterator for SquareArea {
265     type Item = Point;
266 
next(&mut self) -> Option<Point>267     fn next(&mut self) -> Option<Point> {
268         if self.radius == 0 {
269             return None;
270         }
271 
272         if self.pos.y > self.max.y {
273             return None;
274         }
275         let current_point = self.pos;
276         self.pos.x += 1;
277         if self.pos.x > self.max.x {
278             self.pos.y += 1;
279             self.pos.x = self.min_x;
280         }
281         Some(current_point)
282     }
283 }
284 
285 pub struct Line {
286     inner: line_drawing::Bresenham<i32>,
287 }
288 
289 impl Line {
new<P: Into<Point>, Q: Into<Point>>(from: P, to: Q) -> Self290     pub fn new<P: Into<Point>, Q: Into<Point>>(from: P, to: Q) -> Self {
291         let from = from.into();
292         let to = to.into();
293         Line {
294             inner: line_drawing::Bresenham::new((from.x, from.y), (to.x, to.y)),
295         }
296     }
297 }
298 
299 impl Iterator for Line {
300     type Item = Point;
301 
302     /// Draw a line between two points. Uses Bresenham's line
303     /// algorithm:
304     /// https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm
next(&mut self) -> Option<Point>305     fn next(&mut self) -> Option<Point> {
306         self.inner.next().map(Into::into)
307     }
308 }
309 
310 #[cfg(test)]
311 mod test {
312     use super::{Point, SquareArea};
313     use std::f32::EPSILON;
314     use std::iter::FromIterator;
315 
316     #[test]
test_tile_distance()317     fn test_tile_distance() {
318         assert_eq!(Point { x: 0, y: 0 }.tile_distance((0, 0)), 0);
319 
320         assert_eq!(Point { x: 0, y: 0 }.tile_distance((1, 0)), 1);
321         assert_eq!(Point { x: 0, y: 0 }.tile_distance((-1, 0)), 1);
322         assert_eq!(Point { x: 0, y: 0 }.tile_distance((1, 1)), 1);
323         assert_eq!(Point { x: 0, y: 0 }.tile_distance((-1, 1)), 1);
324         assert_eq!(Point { x: 0, y: 0 }.tile_distance((0, 1)), 1);
325         assert_eq!(Point { x: 0, y: 0 }.tile_distance((0, -1)), 1);
326         assert_eq!(Point { x: 0, y: 0 }.tile_distance((1, 1)), 1);
327         assert_eq!(Point { x: 0, y: 0 }.tile_distance((1, -1)), 1);
328 
329         assert_eq!(Point { x: 0, y: 0 }.tile_distance((2, 2)), 2);
330         assert_eq!(Point { x: 0, y: 0 }.tile_distance((-2, -2)), 2);
331         assert_eq!(Point { x: 0, y: 0 }.tile_distance((0, 2)), 2);
332         assert_eq!(Point { x: 0, y: 0 }.tile_distance((2, 0)), 2);
333 
334         assert_eq!(Point { x: -3, y: -3 }.tile_distance((10, 10)), 13);
335         assert_eq!(Point { x: -3, y: -3 }.tile_distance((5, -2)), 8);
336     }
337 
338     #[test]
test_euclidean_distance()339     fn test_euclidean_distance() {
340         let actual = Point { x: 0, y: 0 }.distance((0, 0));
341         let expected = 0.0;
342         assert!((actual - expected).abs() <= EPSILON);
343 
344         let actual = Point { x: 0, y: 0 }.distance((10, 10));
345         let expected = 14.142136;
346         assert!((actual - expected).abs() <= EPSILON);
347 
348         let actual = Point { x: 0, y: 0 }.distance((10, -10));
349         let expected = 14.142136;
350         assert!((actual - expected).abs() <= EPSILON);
351 
352         let actual = Point { x: 0, y: 0 }.distance((-10, 10));
353         let expected = 14.142136;
354         assert!((actual - expected).abs() <= EPSILON);
355 
356         let actual = Point { x: 0, y: 0 }.distance((10, -10));
357         let expected = 14.142136;
358         assert!((actual - expected).abs() <= EPSILON);
359 
360         let actual = Point { x: 0, y: 0 }.distance((3, 4));
361         let expected = 5.0;
362         assert!((actual - expected).abs() <= EPSILON);
363 
364         let actual = Point { x: 0, y: 0 }.distance((-3, 4));
365         let expected = 5.0;
366         assert!((actual - expected).abs() <= EPSILON);
367 
368         let actual = Point { x: 0, y: 0 }.distance((3, -4));
369         let expected = 5.0;
370         assert!((actual - expected).abs() <= EPSILON);
371 
372         let actual = Point { x: 0, y: 0 }.distance((-3, -4));
373         let expected = 5.0;
374         assert!((actual - expected).abs() <= EPSILON);
375     }
376 
377     #[test]
test_points_within_radius_of_zero()378     fn test_points_within_radius_of_zero() {
379         let actual: Vec<Point> = FromIterator::from_iter(SquareArea::new((3, 3), 0));
380         let expected: [Point; 0] = [];
381         assert_eq!(actual, expected);
382     }
383 
384     #[test]
test_points_within_radius_of_one()385     fn test_points_within_radius_of_one() {
386         let actual: Vec<Point> = FromIterator::from_iter(SquareArea::new((3, 3), 1));
387         assert_eq!(actual, [(3, 3)]);
388     }
389 
390     #[test]
test_points_within_radius_of_two()391     fn test_points_within_radius_of_two() {
392         let actual: Vec<Point> = FromIterator::from_iter(SquareArea::new((0, 0), 2));
393         let expected = [
394             (-1, -1),
395             (0, -1),
396             (1, -1),
397             (-1, 0),
398             (0, 0),
399             (1, 0),
400             (-1, 1),
401             (0, 1),
402             (1, 1),
403         ];
404         assert_eq!(actual, expected);
405     }
406 
407     #[test]
test_points_within_radius_of_five()408     fn test_points_within_radius_of_five() {
409         let actual: Vec<Point> = FromIterator::from_iter(SquareArea::new((0, 0), 5));
410 
411         let mut expected = Vec::new();
412         for y in -4..5 {
413             for x in -4..5 {
414                 expected.push(Point { x: x, y: y });
415             }
416         }
417         assert_eq!(actual, expected);
418     }
419 
420     #[test]
test_point_comparison()421     fn test_point_comparison() {
422         assert!(Point::new(1, 1) > Point::new(0, 0));
423         assert!(Point::new(0, 0) < Point::new(1, 1));
424 
425         assert!(Point::new(1, 1) >= Point::new(0, 0));
426         assert!(Point::new(1, 1) <= Point::new(1, 1));
427 
428         assert_eq!(Point::new(1, 0) > Point::new(0, 1), false);
429         assert_eq!(Point::new(0, 1) > Point::new(1, 0), false);
430         assert_eq!(Point::new(1, 0) >= Point::new(0, 1), false);
431         assert_eq!(Point::new(0, 1) >= Point::new(1, 0), false);
432 
433         assert_eq!(Point::new(1, 0) > Point::new(0, 0), false);
434         assert_eq!(Point::new(0, 1) > Point::new(0, 0), false);
435 
436         assert_eq!(Point::new(1, 0) >= Point::new(0, 0), true);
437         assert_eq!(Point::new(0, 1) >= Point::new(0, 0), true);
438     }
439 
440     #[test]
test_point_tuple_comparison()441     fn test_point_tuple_comparison() {
442         assert!(Point::new(1, 1) > (0, 0));
443         assert!(Point::new(0, 0) < (1, 1));
444 
445         assert!(Point::new(1, 1) >= (0, 0));
446         assert!(Point::new(1, 1) <= (1, 1));
447 
448         assert_eq!(Point::new(1, 0) > (0, 1), false);
449         assert_eq!(Point::new(0, 1) > (1, 0), false);
450         assert_eq!(Point::new(1, 0) >= (0, 1), false);
451         assert_eq!(Point::new(0, 1) >= (1, 0), false);
452 
453         assert_eq!(Point::new(1, 0) > (0, 0), false);
454         assert_eq!(Point::new(0, 1) > (0, 0), false);
455 
456         assert_eq!(Point::new(1, 0) >= (0, 0), true);
457         assert_eq!(Point::new(0, 1) >= (0, 0), true);
458     }
459 
460     #[test]
test_point_bound_checking()461     fn test_point_bound_checking() {
462         let top_left_corner = Point::new(0, 0);
463         let display_size = Point::new(10, 10);
464         let within_bounds = |pos| pos >= top_left_corner && pos < display_size;
465 
466         assert_eq!(within_bounds(Point::new(0, 0)), true);
467         assert_eq!(within_bounds(Point::new(1, 0)), true);
468         assert_eq!(within_bounds(Point::new(0, 1)), true);
469         assert_eq!(within_bounds(Point::new(1, 1)), true);
470         assert_eq!(within_bounds(Point::new(3, 4)), true);
471         assert_eq!(within_bounds(Point::new(9, 9)), true);
472         assert_eq!(within_bounds(Point::new(2, 9)), true);
473         assert_eq!(within_bounds(Point::new(9, 2)), true);
474 
475         assert_eq!(within_bounds(Point::new(-1, 0)), false);
476         assert_eq!(within_bounds(Point::new(0, -1)), false);
477         assert_eq!(within_bounds(Point::new(-1, -1)), false);
478         assert_eq!(within_bounds(Point::new(1, 10)), false);
479         assert_eq!(within_bounds(Point::new(10, 1)), false);
480         assert_eq!(within_bounds(Point::new(10, 10)), false);
481     }
482 }
483