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}