-
Notifications
You must be signed in to change notification settings - Fork 45
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Some Position utility methods for approximate offsets #243
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
//! Methods related to approximating positions between other positions. | ||
use crate::objects::HasPosition; | ||
|
||
use super::Position; | ||
|
||
impl Position { | ||
/// Calculates an approximate midpoint between this point and the target. | ||
/// | ||
/// In case of a tie, rounds towards this point. | ||
/// | ||
/// If `distance_towards_target` is bigger than the distance to the target, | ||
/// the target is returned. | ||
pub fn towards<T>(self, target: &T, distance_towards_target: i32) -> Position | ||
where | ||
T: ?Sized + HasPosition, | ||
{ | ||
let target = target.pos(); | ||
|
||
let (offset_x, offset_y) = target - self; | ||
let total_distance = offset_x.abs().max(offset_y.abs()); | ||
if distance_towards_target > total_distance { | ||
return target; | ||
} | ||
|
||
let new_offset_x = (offset_x * distance_towards_target) / total_distance; | ||
let new_offset_y = (offset_y * distance_towards_target) / total_distance; | ||
|
||
self + (new_offset_x, new_offset_y) | ||
} | ||
|
||
/// Calculates an approximate midpoint between this point and the target. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same: |
||
/// | ||
/// In case of a tie, rounds towards the target. | ||
/// | ||
/// If `distance_from_target` is bigger than the distance to the target, | ||
/// this position is returned. | ||
pub fn between<T>(self, target: &T, distance_from_target: i32) -> Position | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Given that the other is |
||
where | ||
T: ?Sized + HasPosition, | ||
{ | ||
target.pos().towards(&self, distance_from_target) | ||
} | ||
|
||
/// Calculates an approximate midpoint between this point and the target. | ||
/// | ||
/// In case of a tie, rounds towards the target. | ||
pub fn midpoint_between<T>(self, target: &T) -> Position | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. suggestion: |
||
where | ||
T: ?Sized + HasPosition, | ||
{ | ||
let target = target.pos(); | ||
|
||
let (offset_x, offset_y) = self - target; | ||
|
||
let new_offset_x = offset_x / 2; | ||
let new_offset_y = offset_y / 2; | ||
|
||
target + (new_offset_x, new_offset_y) | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod test { | ||
use super::Position; | ||
use crate::RoomName; | ||
|
||
fn test_rooms() -> impl Iterator<Item = RoomName> { | ||
["E0N0", "E20N20", "W20N0", "E20S20", "W20S20"] | ||
.iter() | ||
.map(|s| s.parse().unwrap()) | ||
} | ||
|
||
fn pos(room: RoomName, x: u32, y: u32) -> Position { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
Position::new(x, y, room) | ||
} | ||
|
||
#[test] | ||
fn towards_accurate() { | ||
for room in test_rooms() { | ||
let start = pos(room, 10, 10); | ||
assert_eq!(start.towards(&pos(room, 10, 15), 1), pos(room, 10, 11)); | ||
assert_eq!(start.towards(&pos(room, 10, 15), 4), pos(room, 10, 14)); | ||
assert_eq!(start.towards(&pos(room, 10, 15), 10), pos(room, 10, 15)); | ||
assert_eq!(start.towards(&pos(room, 15, 15), 1), pos(room, 11, 11)); | ||
assert_eq!(start.towards(&pos(room, 15, 15), 3), pos(room, 13, 13)); | ||
assert_eq!(start.towards(&pos(room, 15, 20), 2), pos(room, 11, 12)); | ||
assert_eq!(start.towards(&pos(room, 0, 5), 2), pos(room, 8, 9)); | ||
} | ||
} | ||
#[test] | ||
fn towards_approximate() { | ||
for room in test_rooms() { | ||
let start = pos(room, 10, 10); | ||
assert_eq!(start.towards(&pos(room, 15, 20), 1), pos(room, 10, 11)); | ||
assert_eq!(start.towards(&pos(room, 15, 20), 9), pos(room, 14, 19)); | ||
assert_eq!(start.towards(&pos(room, 0, 5), 1), pos(room, 9, 10)); | ||
} | ||
} | ||
#[test] | ||
fn midpoint_accurate() { | ||
for room in test_rooms() { | ||
let start = pos(room, 10, 10); | ||
assert_eq!( | ||
start.midpoint_between(&pos(room, 10, 16)), | ||
pos(room, 10, 13) | ||
); | ||
assert_eq!( | ||
start.midpoint_between(&pos(room, 20, 10)), | ||
pos(room, 15, 10) | ||
); | ||
assert_eq!( | ||
start.midpoint_between(&pos(room, 12, 12)), | ||
pos(room, 11, 11) | ||
); | ||
assert_eq!(start.midpoint_between(&pos(room, 4, 4)), pos(room, 7, 7)); | ||
} | ||
} | ||
#[test] | ||
fn midpoint_approximate() { | ||
for room in test_rooms() { | ||
let start = pos(room, 10, 10); | ||
assert_eq!( | ||
start.midpoint_between(&pos(room, 10, 15)), | ||
pos(room, 10, 13) | ||
); | ||
assert_eq!( | ||
start.midpoint_between(&pos(room, 19, 10)), | ||
pos(room, 15, 10) | ||
); | ||
assert_eq!( | ||
start.midpoint_between(&pos(room, 11, 11)), | ||
pos(room, 11, 11) | ||
); | ||
assert_eq!( | ||
start.midpoint_between(&pos(room, 15, 15)), | ||
pos(room, 13, 13) | ||
); | ||
assert_eq!( | ||
start.midpoint_between(&pos(room, 15, 25)), | ||
pos(room, 13, 18) | ||
); | ||
assert_eq!(start.midpoint_between(&pos(room, 9, 10)), pos(room, 9, 10)); | ||
assert_eq!(start.midpoint_between(&pos(room, 7, 10)), pos(room, 8, 10)); | ||
assert_eq!(start.midpoint_between(&pos(room, 1, 3)), pos(room, 5, 6)); | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not a midpoint (as in, it's not in the middle). It's
distance_towards_target
from this point towards the other point. (with big caveats)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, this line is suspiciously like the first one of the next function 😛
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe:
midpoint
->offset