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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
use crate::Balance;
use core::ops::{Add, Mul, Neg, Not, Sub};
impl Balance {
/// Moves the current position upwards in the 3x3 grid while staying within bounds.
///
/// # Returns
///
/// The `Balance` variant representing the position directly above the current one.
/// If the current position is at the top edge, the result will stay at the edge.
///
/// # Examples
///
/// ```
/// use balanced_direction::Balance;
///
/// let balance = Balance::Center;
/// assert_eq!(balance.up(), Balance::Top);
///
/// let balance = Balance::Top;
/// assert_eq!(balance.up(), Balance::Top);
/// ```
pub const fn up(self) -> Self {
let (x, y) = self.to_vector();
Self::from_vector(x, if y == -1 { -1 } else { y - 1 })
}
/// Moves the current position downwards in the 3x3 grid while staying within bounds.
///
/// # Returns
///
/// The `Balance` variant representing the position directly below the current one.
/// If the current position is at the bottom edge, the result will stay at the edge.
///
/// # Examples
///
/// ```
/// use balanced_direction::Balance;
///
/// let balance = Balance::Center;
/// assert_eq!(balance.down(), Balance::Bottom);
///
/// let balance = Balance::Bottom;
/// assert_eq!(balance.down(), Balance::Bottom);
/// ```
pub const fn down(self) -> Self {
let (x, y) = self.to_vector();
Self::from_vector(x, if y == 1 { 1 } else { y + 1 })
}
/// Moves the current position to the left in the 3x3 grid while staying within bounds.
///
/// # Returns
///
/// The `Balance` variant representing the position directly to the left of the current one.
/// If the current position is at the left edge, the result will stay at the edge.
///
/// # Examples
///
/// ```
/// use balanced_direction::Balance;
///
/// let balance = Balance::Center;
/// assert_eq!(balance.left(), Balance::Left);
///
/// let balance = Balance::Left;
/// assert_eq!(balance.left(), Balance::Left);
/// ```
pub const fn left(self) -> Self {
let (x, y) = self.to_vector();
Self::from_vector(if x == -1 { -1 } else { x - 1 }, y)
}
/// Moves the current position to the right in the 3x3 grid while staying within bounds.
///
/// # Returns
///
/// The `Balance` variant representing the position directly to the right of the current one.
/// If the current position is at the right edge, the result will stay at the edge.
///
/// # Examples
///
/// ```
/// use balanced_direction::Balance;
///
/// let balance = Balance::Center;
/// assert_eq!(balance.right(), Balance::Right);
///
/// let balance = Balance::Right;
/// assert_eq!(balance.right(), Balance::Right);
/// ```
pub const fn right(self) -> Self {
let (x, y) = self.to_vector();
Self::from_vector(if x == 1 { 1 } else { x + 1 }, y)
}
/// Moves the position upwards in the 3x3 grid with wrapping behavior.
pub const fn up_wrap(self) -> Self {
let (x, y) = self.to_vector();
Self::from_vector(x, if y == -1 { 1 } else { y - 1 })
}
/// Moves the position downwards in the 3x3 grid with wrapping behavior.
pub const fn down_wrap(self) -> Self {
let (x, y) = self.to_vector();
Self::from_vector(x, if y == 1 { -1 } else { y + 1 })
}
/// Moves the position leftwards in the 3x3 grid with wrapping behavior.
pub const fn left_wrap(self) -> Self {
let (x, y) = self.to_vector();
Self::from_vector(if x == -1 { 1 } else { x - 1 }, y)
}
/// Moves the position rightwards in the 3x3 grid with wrapping behavior.
pub const fn right_wrap(self) -> Self {
let (x, y) = self.to_vector();
Self::from_vector(if x == 1 { -1 } else { x + 1 }, y)
}
/// Flips the current position horizontally in the 3x3 grid.
///
/// # Returns
///
/// The `Balance` variant that is mirrored horizontally across
/// the vertical axis. For example, flipping `Balance::Left` results
/// in `Balance::Right`, and vice-versa. Positions on the vertical axis
/// (like `Balance::Center` or `Balance::Top`) remain unchanged.
///
/// # Examples
///
/// ```
/// use balanced_direction::Balance;
///
/// let balance = Balance::Left;
/// assert_eq!(balance.flip_h(), Balance::Right);
///
/// let balance = Balance::Center;
/// assert_eq!(balance.flip_h(), Balance::Center);
/// ```
pub const fn flip_h(self) -> Self {
let (x, y) = self.to_vector();
Self::from_vector(-x, y)
}
/// Flips the current position vertically in the 3x3 grid.
///
/// # Returns
///
/// The `Balance` variant that is mirrored vertically across
/// the horizontal axis. For example, flipping `Balance::Top`
/// results in `Balance::Bottom`, and vice-versa. Positions on the horizontal axis
/// (like `Balance::Center` or `Balance::Left`) remain unchanged.
///
/// # Examples
///
/// ```
/// use balanced_direction::Balance;
///
/// let balance = Balance::Top;
/// assert_eq!(balance.flip_v(), Balance::Bottom);
///
/// let balance = Balance::Center;
/// assert_eq!(balance.flip_v(), Balance::Center);
/// ```
pub const fn flip_v(self) -> Self {
let (x, y) = self.to_vector();
Self::from_vector(x, -y)
}
/// Rotates the current position 90 degrees counterclockwise in the 3x3 grid.
///
/// # Returns
///
/// The `Balance` variant representing the position after a 90-degree counterclockwise
/// rotation around the center. For example, rotating `Balance::Right` counterclockwise
/// will result in `Balance::Top`, and `Balance::Top` will result in `Balance::Left`.
/// The center position (`Balance::Center`) remains unchanged.
///
/// # Examples
///
/// ```
/// use balanced_direction::Balance;
///
/// let balance = Balance::Right;
/// assert_eq!(balance.rotate_left(), Balance::Top);
///
/// let balance = Balance::Center;
/// assert_eq!(balance.rotate_left(), Balance::Center);
///
/// let balance = Balance::Top;
/// assert_eq!(balance.rotate_left(), Balance::Left);
/// ```
pub const fn rotate_left(self) -> Self {
let (x, y) = self.to_vector();
Self::from_vector(y, -x)
}
/// Rotates the current position 90 degrees clockwise in the 3x3 grid.
///
/// # Returns
///
/// The `Balance` variant representing the position after a 90-degree clockwise
/// rotation around the center. For example, rotating `Balance::Top` clockwise
/// results in `Balance::Right`, and `Balance::Right` will result in `Balance::Bottom`.
/// The center position (`Balance::Center`) remains unchanged.
///
/// # Examples
///
/// ```
/// use balanced_direction::Balance;
///
/// let balance = Balance::Top;
/// assert_eq!(balance.rotate_right(), Balance::Right);
///
/// let balance = Balance::Center;
/// assert_eq!(balance.rotate_right(), Balance::Center);
///
/// let balance = Balance::Right;
/// assert_eq!(balance.rotate_right(), Balance::Bottom);
/// ```
pub const fn rotate_right(self) -> Self {
let (x, y) = self.to_vector();
Self::from_vector(-y, x)
}
/// Centers the current position horizontally in the 3x3 grid by setting the x-coordinate to 0.
///
/// # Returns
///
/// A `Balance` variant where the x-coordinate is always 0, keeping the same y-coordinate.
/// This effectively moves the current position to the vertical axis of the grid.
///
/// # Examples
///
/// ```
/// use balanced_direction::Balance;
///
/// let balance = Balance::Left;
/// assert_eq!(balance.center_h(), Balance::Center);
///
/// let balance = Balance::BottomLeft;
/// assert_eq!(balance.center_h(), Balance::Bottom);
/// ```
pub const fn center_h(self) -> Self {
let (_, y) = self.to_vector();
Self::from_vector(0, y)
}
/// Centers the current position vertically in the 3x3 grid by setting the y-coordinate to 0.
///
/// # Returns
///
/// A `Balance` variant where the y-coordinate is always 0, keeping the same x-coordinate.
/// This effectively moves the current position to the horizontal axis of the grid.
///
/// # Examples
///
/// ```
/// use balanced_direction::Balance;
///
/// let balance = Balance::Top;
/// assert_eq!(balance.center_v(), Balance::Center);
///
/// let balance = Balance::TopRight;
/// assert_eq!(balance.center_v(), Balance::Right);
/// ```
pub const fn center_v(self) -> Self {
let (x, _) = self.to_vector();
Self::from_vector(x, 0)
}
}
impl Not for Balance {
type Output = Self;
fn not(self) -> Self::Output {
let (x, y) = self.to_vector();
Self::from_vector(y, x)
}
}
impl Neg for Balance {
type Output = Self;
fn neg(self) -> Self::Output {
let (x, y) = self.to_vector();
Balance::from_vector(-x, -y)
}
}
impl Add for Balance {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
let (x1, y1) = self.to_vector();
let (x2, y2) = rhs.to_vector();
Balance::from_vector((x1 + x2).clamp(-1, 1), (y1 + y2).clamp(-1, 1))
}
}
impl Mul for Balance {
type Output = Self;
fn mul(self, rhs: Self) -> Self::Output {
let (x1, y1) = self.to_vector();
let (x2, y2) = rhs.to_vector();
Balance::from_vector(x1 * x2, y1 * y2)
}
}
impl Sub for Balance {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
let (x1, y1) = self.to_vector();
let (x2, y2) = rhs.to_vector();
Self::from_vector((x1 - x2).clamp(-1, 1), (y1 - y2).clamp(-1, 1))
}
}