diff --git a/common/rust/src/vec2.rs b/common/rust/src/vec2.rs index 8b17950..b6fb138 100644 --- a/common/rust/src/vec2.rs +++ b/common/rust/src/vec2.rs @@ -28,6 +28,48 @@ impl Vec2 { pub fn len(self) -> f64 { (f64::from(self.x).powi(2) + f64::from(self.y).powi(2)).sqrt() } + + #[must_use] + pub fn manhattan_dist(self, other: Vec2) -> usize { + let Vec2 { x, y } = (other - self).map(i32::abs); + let x = usize::try_from(x).unwrap(); + let y = usize::try_from(y).unwrap(); + x + y + } + + #[must_use] + pub fn on_x_with_manhattan_dist(self, x: i32, dist: usize) -> Option<(Vec2, Vec2)> { + let dx = usize::try_from((x - self.x).abs()).ok()?; + + let dy = dist.checked_sub(dx)?; + let dy = i32::try_from(dy).ok()?; + + let p1 = Vec2::new(x, self.y - dy); + let p2 = Vec2::new(x, self.y + dy); + + debug_assert!(p1 <= p2); + debug_assert_eq!(self.manhattan_dist(p1), dist); + debug_assert_eq!(self.manhattan_dist(p2), dist); + + Some((p1, p2)) + } + + #[must_use] + pub fn on_y_with_manhattan_dist(self, y: i32, dist: usize) -> Option<(Vec2, Vec2)> { + let dy = usize::try_from((y - self.y).abs()).ok()?; + + let dx = dist.checked_sub(dy)?; + let dx = i32::try_from(dx).ok()?; + + let p1 = Vec2::new(self.x - dx, y); + let p2 = Vec2::new(self.x + dx, y); + + debug_assert!(p1 <= p2); + debug_assert_eq!(self.manhattan_dist(p1), dist); + debug_assert_eq!(self.manhattan_dist(p2), dist); + + Some((p1, p2)) + } } impl fmt::Display for Vec2 {