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