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
use super::{Position, HALF_WORLD_SIZE};
impl Position {
#[inline]
pub fn world_x(self) -> i32 {
self.room_x() * 50 + (self.x() as i32)
}
#[inline]
pub fn world_y(self) -> i32 {
self.room_y() * 50 + (self.y() as i32)
}
#[inline]
pub fn world_coords(self) -> (i32, i32) {
(self.world_x(), self.world_y())
}
#[inline]
pub fn from_world_coords(x: i32, y: i32) -> Self {
assert!(
(-HALF_WORLD_SIZE * 50..HALF_WORLD_SIZE * 50).contains(&x),
"out of bounds world x: {}",
x
);
assert!(
(-HALF_WORLD_SIZE * 50..HALF_WORLD_SIZE * 50).contains(&y),
"out of bounds world y: {}",
y
);
let pos_x = (x + HALF_WORLD_SIZE * 50) as u32;
let pos_y = (y + HALF_WORLD_SIZE * 50) as u32;
let room_x = pos_x / 50;
let room_y = pos_y / 50;
let x = pos_x % 50;
let y = pos_y % 50;
Self::from_coords_and_world_coords_adjusted(x, y, room_x, room_y)
}
}
#[cfg(test)]
mod test {
use super::Position;
const TEST_ROOM_NAMES: &[&str] = &[
"E1N1", "E20N0", "W0N0", "E0N0", "W0S0", "E0S0", "W0N0", "E0N0", "W0S0", "E0S0", "W50S20",
"W127S127", "W127N127", "E127S127", "E127N127",
];
const TEST_COORDS: &[u32] = &[0, 21, 44, 49];
#[test]
fn world_coords_round_trip() {
for room_name in TEST_ROOM_NAMES {
for x in TEST_COORDS.iter().cloned() {
for y in TEST_COORDS.iter().cloned() {
let original_pos = Position::new(x, y, room_name.parse().unwrap());
let (wx, wy) = original_pos.world_coords();
let new = Position::from_world_coords(wx, wy);
assert_eq!(original_pos, new);
}
}
}
}
}