balanced_direction/operations.rs
1use crate::Balance;
2use core::ops::{Add, Mul, Neg, Not, Sub};
3
4impl Balance {
5 /// Moves the current position upwards in the 3x3 grid while staying within bounds.
6 ///
7 /// # Returns
8 ///
9 /// The `Balance` variant representing the position directly above the current one.
10 /// If the current position is at the top edge, the result will stay at the edge.
11 ///
12 /// # Examples
13 ///
14 /// ```
15 /// use balanced_direction::Balance;
16 ///
17 /// let balance = Balance::Center;
18 /// assert_eq!(balance.up(), Balance::Top);
19 ///
20 /// let balance = Balance::Top;
21 /// assert_eq!(balance.up(), Balance::Top);
22 /// ```
23 pub const fn up(self) -> Self {
24 let (x, y) = self.to_vector();
25 Self::from_vector(x, if y == -1 { -1 } else { y - 1 })
26 }
27
28 /// Moves the current position downwards in the 3x3 grid while staying within bounds.
29 ///
30 /// # Returns
31 ///
32 /// The `Balance` variant representing the position directly below the current one.
33 /// If the current position is at the bottom edge, the result will stay at the edge.
34 ///
35 /// # Examples
36 ///
37 /// ```
38 /// use balanced_direction::Balance;
39 ///
40 /// let balance = Balance::Center;
41 /// assert_eq!(balance.down(), Balance::Bottom);
42 ///
43 /// let balance = Balance::Bottom;
44 /// assert_eq!(balance.down(), Balance::Bottom);
45 /// ```
46 pub const fn down(self) -> Self {
47 let (x, y) = self.to_vector();
48 Self::from_vector(x, if y == 1 { 1 } else { y + 1 })
49 }
50
51 /// Moves the current position to the left in the 3x3 grid while staying within bounds.
52 ///
53 /// # Returns
54 ///
55 /// The `Balance` variant representing the position directly to the left of the current one.
56 /// If the current position is at the left edge, the result will stay at the edge.
57 ///
58 /// # Examples
59 ///
60 /// ```
61 /// use balanced_direction::Balance;
62 ///
63 /// let balance = Balance::Center;
64 /// assert_eq!(balance.left(), Balance::Left);
65 ///
66 /// let balance = Balance::Left;
67 /// assert_eq!(balance.left(), Balance::Left);
68 /// ```
69 pub const fn left(self) -> Self {
70 let (x, y) = self.to_vector();
71 Self::from_vector(if x == -1 { -1 } else { x - 1 }, y)
72 }
73
74 /// Moves the current position to the right in the 3x3 grid while staying within bounds.
75 ///
76 /// # Returns
77 ///
78 /// The `Balance` variant representing the position directly to the right of the current one.
79 /// If the current position is at the right edge, the result will stay at the edge.
80 ///
81 /// # Examples
82 ///
83 /// ```
84 /// use balanced_direction::Balance;
85 ///
86 /// let balance = Balance::Center;
87 /// assert_eq!(balance.right(), Balance::Right);
88 ///
89 /// let balance = Balance::Right;
90 /// assert_eq!(balance.right(), Balance::Right);
91 /// ```
92 pub const fn right(self) -> Self {
93 let (x, y) = self.to_vector();
94 Self::from_vector(if x == 1 { 1 } else { x + 1 }, y)
95 }
96
97 /// Moves the position upwards in the 3x3 grid with wrapping behavior.
98 pub const fn up_wrap(self) -> Self {
99 let (x, y) = self.to_vector();
100 Self::from_vector(x, if y == -1 { 1 } else { y - 1 })
101 }
102
103 /// Moves the position downwards in the 3x3 grid with wrapping behavior.
104 pub const fn down_wrap(self) -> Self {
105 let (x, y) = self.to_vector();
106 Self::from_vector(x, if y == 1 { -1 } else { y + 1 })
107 }
108
109 /// Moves the position leftwards in the 3x3 grid with wrapping behavior.
110 pub const fn left_wrap(self) -> Self {
111 let (x, y) = self.to_vector();
112 Self::from_vector(if x == -1 { 1 } else { x - 1 }, y)
113 }
114
115 /// Moves the position rightwards in the 3x3 grid with wrapping behavior.
116 pub const fn right_wrap(self) -> Self {
117 let (x, y) = self.to_vector();
118 Self::from_vector(if x == 1 { -1 } else { x + 1 }, y)
119 }
120
121 /// Flips the current position horizontally in the 3x3 grid.
122 ///
123 /// # Returns
124 ///
125 /// The `Balance` variant that is mirrored horizontally across
126 /// the vertical axis. For example, flipping `Balance::Left` results
127 /// in `Balance::Right`, and vice-versa. Positions on the vertical axis
128 /// (like `Balance::Center` or `Balance::Top`) remain unchanged.
129 ///
130 /// # Examples
131 ///
132 /// ```
133 /// use balanced_direction::Balance;
134 ///
135 /// let balance = Balance::Left;
136 /// assert_eq!(balance.flip_h(), Balance::Right);
137 ///
138 /// let balance = Balance::Center;
139 /// assert_eq!(balance.flip_h(), Balance::Center);
140 /// ```
141 pub const fn flip_h(self) -> Self {
142 let (x, y) = self.to_vector();
143 Self::from_vector(-x, y)
144 }
145
146 /// Flips the current position vertically in the 3x3 grid.
147 ///
148 /// # Returns
149 ///
150 /// The `Balance` variant that is mirrored vertically across
151 /// the horizontal axis. For example, flipping `Balance::Top`
152 /// results in `Balance::Bottom`, and vice-versa. Positions on the horizontal axis
153 /// (like `Balance::Center` or `Balance::Left`) remain unchanged.
154 ///
155 /// # Examples
156 ///
157 /// ```
158 /// use balanced_direction::Balance;
159 ///
160 /// let balance = Balance::Top;
161 /// assert_eq!(balance.flip_v(), Balance::Bottom);
162 ///
163 /// let balance = Balance::Center;
164 /// assert_eq!(balance.flip_v(), Balance::Center);
165 /// ```
166 pub const fn flip_v(self) -> Self {
167 let (x, y) = self.to_vector();
168 Self::from_vector(x, -y)
169 }
170
171 /// Rotates the current position 90 degrees counterclockwise in the 3x3 grid.
172 ///
173 /// # Returns
174 ///
175 /// The `Balance` variant representing the position after a 90-degree counterclockwise
176 /// rotation around the center. For example, rotating `Balance::Right` counterclockwise
177 /// will result in `Balance::Top`, and `Balance::Top` will result in `Balance::Left`.
178 /// The center position (`Balance::Center`) remains unchanged.
179 ///
180 /// # Examples
181 ///
182 /// ```
183 /// use balanced_direction::Balance;
184 ///
185 /// let balance = Balance::Right;
186 /// assert_eq!(balance.rotate_left(), Balance::Top);
187 ///
188 /// let balance = Balance::Center;
189 /// assert_eq!(balance.rotate_left(), Balance::Center);
190 ///
191 /// let balance = Balance::Top;
192 /// assert_eq!(balance.rotate_left(), Balance::Left);
193 /// ```
194 pub const fn rotate_left(self) -> Self {
195 let (x, y) = self.to_vector();
196 Self::from_vector(y, -x)
197 }
198
199 /// Rotates the current position 90 degrees clockwise in the 3x3 grid.
200 ///
201 /// # Returns
202 ///
203 /// The `Balance` variant representing the position after a 90-degree clockwise
204 /// rotation around the center. For example, rotating `Balance::Top` clockwise
205 /// results in `Balance::Right`, and `Balance::Right` will result in `Balance::Bottom`.
206 /// The center position (`Balance::Center`) remains unchanged.
207 ///
208 /// # Examples
209 ///
210 /// ```
211 /// use balanced_direction::Balance;
212 ///
213 /// let balance = Balance::Top;
214 /// assert_eq!(balance.rotate_right(), Balance::Right);
215 ///
216 /// let balance = Balance::Center;
217 /// assert_eq!(balance.rotate_right(), Balance::Center);
218 ///
219 /// let balance = Balance::Right;
220 /// assert_eq!(balance.rotate_right(), Balance::Bottom);
221 /// ```
222 pub const fn rotate_right(self) -> Self {
223 let (x, y) = self.to_vector();
224 Self::from_vector(-y, x)
225 }
226
227 /// Centers the current position horizontally in the 3x3 grid by setting the x-coordinate to 0.
228 ///
229 /// # Returns
230 ///
231 /// A `Balance` variant where the x-coordinate is always 0, keeping the same y-coordinate.
232 /// This effectively moves the current position to the vertical axis of the grid.
233 ///
234 /// # Examples
235 ///
236 /// ```
237 /// use balanced_direction::Balance;
238 ///
239 /// let balance = Balance::Left;
240 /// assert_eq!(balance.center_h(), Balance::Center);
241 ///
242 /// let balance = Balance::BottomLeft;
243 /// assert_eq!(balance.center_h(), Balance::Bottom);
244 /// ```
245 pub const fn center_h(self) -> Self {
246 let (_, y) = self.to_vector();
247 Self::from_vector(0, y)
248 }
249
250 /// Centers the current position vertically in the 3x3 grid by setting the y-coordinate to 0.
251 ///
252 /// # Returns
253 ///
254 /// A `Balance` variant where the y-coordinate is always 0, keeping the same x-coordinate.
255 /// This effectively moves the current position to the horizontal axis of the grid.
256 ///
257 /// # Examples
258 ///
259 /// ```
260 /// use balanced_direction::Balance;
261 ///
262 /// let balance = Balance::Top;
263 /// assert_eq!(balance.center_v(), Balance::Center);
264 ///
265 /// let balance = Balance::TopRight;
266 /// assert_eq!(balance.center_v(), Balance::Right);
267 /// ```
268 pub const fn center_v(self) -> Self {
269 let (x, _) = self.to_vector();
270 Self::from_vector(x, 0)
271 }
272}
273
274impl Not for Balance {
275 type Output = Self;
276
277 fn not(self) -> Self::Output {
278 let (x, y) = self.to_vector();
279 Self::from_vector(y, x)
280 }
281}
282
283impl Neg for Balance {
284 type Output = Self;
285
286 fn neg(self) -> Self::Output {
287 let (x, y) = self.to_vector();
288 Balance::from_vector(-x, -y)
289 }
290}
291
292impl Add for Balance {
293 type Output = Self;
294
295 fn add(self, rhs: Self) -> Self::Output {
296 let (x1, y1) = self.to_vector();
297 let (x2, y2) = rhs.to_vector();
298 Balance::from_vector((x1 + x2).clamp(-1, 1), (y1 + y2).clamp(-1, 1))
299 }
300}
301
302impl Mul for Balance {
303 type Output = Self;
304 fn mul(self, rhs: Self) -> Self::Output {
305 let (x1, y1) = self.to_vector();
306 let (x2, y2) = rhs.to_vector();
307 Balance::from_vector(x1 * x2, y1 * y2)
308 }
309}
310
311impl Sub for Balance {
312 type Output = Self;
313 fn sub(self, rhs: Self) -> Self::Output {
314 let (x1, y1) = self.to_vector();
315 let (x2, y2) = rhs.to_vector();
316 Self::from_vector((x1 - x2).clamp(-1, 1), (y1 - y2).clamp(-1, 1))
317 }
318}