balanced_direction/ternary.rs
1use crate::Balance;
2use balanced_ternary::Digit;
3use core::ops::{BitAnd, BitOr, BitXor};
4
5impl BitAnd for Balance {
6 type Output = Self;
7 fn bitand(self, rhs: Self) -> Self::Output {
8 let (x1, y1) = self.to_ternary_pair();
9 let (x2, y2) = rhs.to_ternary_pair();
10 Balance::from_ternary_pair(x1 & x2, y1 & y2)
11 }
12}
13
14impl BitOr for Balance {
15 type Output = Self;
16 fn bitor(self, rhs: Self) -> Self::Output {
17 let (x1, y1) = self.to_ternary_pair();
18 let (x2, y2) = rhs.to_ternary_pair();
19 Balance::from_ternary_pair(x1 | x2, y1 | y2)
20 }
21}
22
23impl BitXor for Balance {
24 type Output = Self;
25 fn bitxor(self, rhs: Self) -> Self::Output {
26 let (x1, y1) = self.to_ternary_pair();
27 let (x2, y2) = rhs.to_ternary_pair();
28 Balance::from_ternary_pair(x1 ^ x2, y1 ^ y2)
29 }
30}
31
32impl Balance {
33 /// Converts the `Balance` position into a pair of ternary digits.
34 ///
35 /// # Returns
36 ///
37 /// A tuple containing two `Digit` values. The first element represents
38 /// the x-coordinate and the second represents the y-coordinate of the `Balance`
39 /// position in the ternary numeral system.
40 ///
41 /// The `Digit` values can range from `Neg` (-1), `Zero` (0), to `Pos` (1),
42 /// matching the 3x3 balanced grid's coordinate representation.
43 ///
44 /// # Examples
45 ///
46 /// ```
47 /// use balanced_direction::Balance;
48 /// use balanced_ternary::Digit;
49 ///
50 /// let balance = Balance::Top;
51 /// assert_eq!(balance.to_ternary_pair(), (Digit::Zero, Digit::Neg));
52 ///
53 /// let balance = Balance::Right;
54 /// assert_eq!(balance.to_ternary_pair(), (Digit::Pos, Digit::Zero));
55 /// ```
56 pub const fn to_ternary_pair(self) -> (Digit, Digit) {
57 (Digit::from_i8(self.x()), Digit::from_i8(self.y()))
58 }
59
60 /// Creates a `Balance` instance from a pair of ternary digits.
61 ///
62 /// # Arguments
63 ///
64 /// * `a` - A `Digit` representing the x-coordinate in the ternary numeral system.
65 /// * `b` - A `Digit` representing the y-coordinate in the ternary numeral system.
66 ///
67 /// # Returns
68 ///
69 /// A new `Balance` instance corresponding to the provided ternary coordinates.
70 ///
71 /// The values of `a` and `b` should be valid ternary digits within the range of:
72 /// - `Neg` (-1), `Zero` (0), and `Pos` (1).
73 ///
74 /// This allows for mapping coordinates within the 3x3 grid system used by the `Balance` enum, ensuring
75 /// that any valid pair of ternary digits maps directly to a specific `Balance` position.
76 ///
77 /// # Examples
78 ///
79 /// ```
80 /// use balanced_direction::Balance;
81 /// use balanced_ternary::Digit;
82 ///
83 /// let balance = Balance::from_ternary_pair(Digit::Zero, Digit::Neg);
84 /// assert_eq!(balance, Balance::Top);
85 ///
86 /// let balance = Balance::from_ternary_pair(Digit::Pos, Digit::Zero);
87 /// assert_eq!(balance, Balance::Right);
88 /// ```
89 pub const fn from_ternary_pair(a: Digit, b: Digit) -> Self {
90 Self::from_vector(a.to_i8(), b.to_i8())
91 }
92
93 /// (logic) Checks if the current logical state is `Balance::BottomRight`.
94 pub const fn is_true(self) -> bool {
95 matches!(self, Balance::BottomRight)
96 }
97
98 /// (logic) Checks if the current logical state includes `Balance::Bottom` or `Balance::Right`.
99 pub const fn has_true(self) -> bool {
100 self.x() == 1 || self.y() == 1
101 }
102
103 /// (logic) Checks if the current logical state is contradictory, representing opposing truths (`TopRight` or `BottomLeft`).
104 pub const fn is_contradictory(self) -> bool {
105 matches!(self, Balance::TopRight | Balance::BottomLeft)
106 }
107
108 /// (logic) Checks whether the current logical state has no certain value but is not contradictory.
109 pub const fn has_unknown(self) -> bool {
110 // = self.is_orthogonal().
111 self.x() == 0 || self.y() == 0
112 }
113
114 /// (logic) Checks whether the current logical state is uncertain in terms of logical balance.
115 pub const fn is_uncertain(self) -> bool {
116 !self.is_certain()
117 }
118
119 /// (logic) Returns whether the current logical state represents a certain state in logical balance (one of `is_true()` or `is_false()` is true).
120 pub const fn is_certain(self) -> bool {
121 matches!(self, Balance::BottomRight | Balance::TopLeft)
122 }
123
124 /// (logic) Determines whether the current logical state includes the `Balance::Top` or `Balance::Left` variant.
125 pub const fn has_false(self) -> bool {
126 self.x() == -1 || self.y() == -1
127 }
128
129 /// (logic) Checks if the current logical state is `Balance::TopLeft`.
130 pub const fn is_false(self) -> bool {
131 matches!(self, Balance::TopLeft)
132 }
133
134 /// Converts the `Balance` logical state into a boolean representation.
135 ///
136 /// # Returns
137 ///
138 /// A `bool` value that represents the certainty of the `Balance` logical state.
139 /// - Returns `true` if the position is logically `true` (e.g., `Balance::BottomRight`).
140 /// - Returns `false` if the position is logically `false` (e.g., `Balance::TopLeft`).
141 ///
142 /// # Panics
143 ///
144 /// Panics if the `Balance` logical state is uncertain. Uncertain states include cases
145 /// where the position cannot be determined or does not logically map to `true` or `false`.
146 ///
147 /// > Use [Balance::is_certain] to check certainty of the `Balance` logical state.
148 ///
149 /// # Examples
150 ///
151 /// ```
152 /// use balanced_direction::Balance;
153 ///
154 /// let balance = Balance::BottomRight;
155 /// assert_eq!(balance.to_bool(), true);
156 ///
157 /// let balance = Balance::TopLeft;
158 /// assert_eq!(balance.to_bool(), false);
159 ///
160 /// let balance = Balance::Center;
161 /// // This will panic because `Balance::Center` is an uncertain logical state.
162 /// // balance.to_bool();
163 /// ```
164 pub const fn to_bool(self) -> bool {
165 self.is_true() || {
166 if self.is_false() {
167 false
168 } else {
169 panic!("Cannot convert an uncertain Balance to a boolean value.")
170 }
171 }
172 }
173
174 /// Converts the x-coordinate of the `Balance` position into a boolean representation.
175 ///
176 /// # Returns
177 ///
178 /// A `bool` value representing the logical state of the x-coordinate:
179 /// - Returns `true` if the x-coordinate is logically `true` (1).
180 /// - Returns `false` if the x-coordinate is logically `false` (-1).
181 ///
182 /// # Panics
183 ///
184 /// Panics if the x-coordinate is unknown (i.e., `0`), as it cannot be converted
185 /// into a boolean value.
186 ///
187 /// # Examples
188 ///
189 /// ```
190 /// use balanced_direction::Balance;
191 ///
192 /// let balance = Balance::Right;
193 /// assert_eq!(balance.x_to_bool(), true);
194 ///
195 /// let balance = Balance::Left;
196 /// assert_eq!(balance.x_to_bool(), false);
197 ///
198 /// let balance = Balance::Center;
199 /// // This will panic because the x-coordinate is unknown.
200 /// // balance.x_to_bool();
201 /// ```
202 pub const fn x_to_bool(self) -> bool {
203 self.x() == 1 || {
204 if self.x() == -1 {
205 false
206 } else {
207 panic!("Cannot convert an unknown-x Balance to a boolean value.")
208 }
209 }
210 }
211
212 /// Converts the y-coordinate of the `Balance` position into a boolean representation.
213 ///
214 /// # Returns
215 ///
216 /// A `bool` value representing the logical state of the y-coordinate:
217 /// - Returns `true` if the y-coordinate is logically `true` (1).
218 /// - Returns `false` if the y-coordinate is logically `false` (-1).
219 ///
220 /// # Panics
221 ///
222 /// Panics if the y-coordinate is unknown (i.e., `0`), as it cannot be converted
223 /// into a boolean value.
224 ///
225 /// # Examples
226 ///
227 /// ```
228 /// use balanced_direction::Balance;
229 ///
230 /// let balance = Balance::Top;
231 /// assert_eq!(balance.y_to_bool(), false);
232 ///
233 /// let balance = Balance::Bottom;
234 /// assert_eq!(balance.y_to_bool(), true);
235 ///
236 /// let balance = Balance::Center;
237 /// // This will panic because the y-coordinate is unknown.
238 /// // balance.y_to_bool();
239 /// ```
240 pub const fn y_to_bool(self) -> bool {
241 self.y() == 1 || {
242 if self.y() == -1 {
243 false
244 } else {
245 panic!("Cannot convert an unknown-y Balance to a boolean value.")
246 }
247 }
248 }
249
250 /// Applies [Digit::possibly] on `x` and `y`.
251 pub const fn possibly(self) -> Self {
252 let (x, y) = self.to_ternary_pair();
253 Self::from_ternary_pair(x.possibly(), y.possibly())
254 }
255 /// Applies [Digit::necessary] on `x` and `y`.
256 pub const fn necessary(self) -> Self {
257 let (x, y) = self.to_ternary_pair();
258 Self::from_ternary_pair(x.necessary(), y.necessary())
259 }
260 /// Applies [Digit::contingently] on `x` and `y`.
261 pub const fn contingently(self) -> Self {
262 let (x, y) = self.to_ternary_pair();
263 Self::from_ternary_pair(x.contingently(), y.contingently())
264 }
265 /// Applies [Digit::absolute_positive] on `x` and `y`.
266 pub const fn absolute_positive(self) -> Self {
267 let (x, y) = self.to_ternary_pair();
268 Self::from_ternary_pair(x.absolute_positive(), y.absolute_positive())
269 }
270 /// Applies [Digit::positive] on `x` and `y`.
271 pub const fn positive(self) -> Self {
272 let (x, y) = self.to_ternary_pair();
273 Self::from_ternary_pair(x.positive(), y.positive())
274 }
275 /// Applies [Digit::not_negative] on `x` and `y`.
276 pub const fn not_negative(self) -> Self {
277 let (x, y) = self.to_ternary_pair();
278 Self::from_ternary_pair(x.not_negative(), y.not_negative())
279 }
280 /// Applies [Digit::not_positive] on `x` and `y`.
281 pub const fn not_positive(self) -> Self {
282 let (x, y) = self.to_ternary_pair();
283 Self::from_ternary_pair(x.not_positive(), y.not_positive())
284 }
285 /// Applies [Digit::negative] on `x` and `y`.
286 pub const fn negative(self) -> Self {
287 let (x, y) = self.to_ternary_pair();
288 Self::from_ternary_pair(x.negative(), y.negative())
289 }
290 /// Applies [Digit::absolute_negative] on `x` and `y`.
291 pub const fn absolute_negative(self) -> Self {
292 let (x, y) = self.to_ternary_pair();
293 Self::from_ternary_pair(x.absolute_negative(), y.absolute_negative())
294 }
295 /// Applies [Digit::ht_not] on `x` and `y`.
296 pub const fn ht_not(self) -> Self {
297 let (x, y) = self.to_ternary_pair();
298 Self::from_ternary_pair(x.ht_not(), y.ht_not())
299 }
300 /// Applies [Digit::post] on `x` and `y`.
301 pub const fn post(self) -> Self {
302 let (x, y) = self.to_ternary_pair();
303 Self::from_ternary_pair(x.post(), y.post())
304 }
305 /// Applies [Digit::pre] on `x` and `y`.
306 pub const fn pre(self) -> Self {
307 let (x, y) = self.to_ternary_pair();
308 Self::from_ternary_pair(x.pre(), y.pre())
309 }
310}
311
312#[cfg(test)]
313mod tests {
314 use super::*;
315 #[test]
316 fn test() {
317 let balances = [
318 Balance::TopLeft,
319 Balance::Top,
320 Balance::TopRight,
321 Balance::Left,
322 Balance::Center,
323 Balance::Right,
324 Balance::BottomLeft,
325 Balance::Bottom,
326 Balance::BottomRight,
327 ];
328 for balance in balances.iter() {
329 let result = balance.pre();
330 println!("{:?} -> {:?}", balance, result);
331 }
332 }
333}