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}