1use crate::board::Player;
2
3pub trait NonPov: Sized {
5 type Output: Pov<Output = Self>;
6
7 fn pov(self, pov: Player) -> Self::Output;
9
10 fn flip(self) -> Self {
12 self.pov(Player::A).un_pov(Player::B)
14 }
15}
16
17pub trait Pov: Sized {
19 type Output: NonPov<Output = Self>;
20
21 fn un_pov(self, pov: Player) -> Self::Output;
23
24 fn flip(self) -> Self {
26 self.un_pov(Player::A).pov(Player::B)
28 }
29}
30
31impl<I: NonPov> NonPov for Option<I> {
32 type Output = Option<I::Output>;
33 fn pov(self, pov: Player) -> Option<I::Output> {
34 self.map(|inner| inner.pov(pov))
35 }
36}
37
38impl<I: Pov> Pov for Option<I> {
39 type Output = Option<I::Output>;
40 fn un_pov(self, pov: Player) -> Option<I::Output> {
41 self.map(|inner| inner.un_pov(pov))
42 }
43}
44
45#[derive(Default, Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
46pub struct ScalarAbs<V> {
47 pub value_a: V,
48}
49
50impl<V> ScalarAbs<V> {
51 pub fn new(value_a: V) -> Self {
52 Self { value_a }
53 }
54}
55
56#[derive(Default, Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
57pub struct ScalarPov<V> {
58 pub value: V,
59}
60
61impl<V> ScalarPov<V> {
62 pub fn new(value: V) -> Self {
63 Self { value }
64 }
65}
66
67impl<V: std::ops::Neg<Output = V>> NonPov for ScalarAbs<V> {
68 type Output = ScalarPov<V>;
69 fn pov(self, pov: Player) -> Self::Output {
70 match pov {
71 Player::A => ScalarPov::new(self.value_a),
72 Player::B => ScalarPov::new(-self.value_a),
73 }
74 }
75}
76
77impl<V: std::ops::Neg<Output = V>> Pov for ScalarPov<V> {
78 type Output = ScalarAbs<V>;
79 fn un_pov(self, pov: Player) -> Self::Output {
80 match pov {
81 Player::A => ScalarAbs::new(self.value),
82 Player::B => ScalarAbs::new(-self.value),
83 }
84 }
85}
86
87impl<V: std::ops::Add<V, Output = V>> std::ops::Add<ScalarAbs<V>> for ScalarAbs<V> {
88 type Output = ScalarAbs<V>;
89
90 fn add(self, rhs: ScalarAbs<V>) -> Self::Output {
91 ScalarAbs::new(self.value_a + rhs.value_a)
92 }
93}
94
95impl<V: Copy + std::ops::Sub<V, Output = V>> std::ops::Sub<ScalarAbs<V>> for ScalarAbs<V> {
96 type Output = ScalarAbs<V>;
97
98 fn sub(self, rhs: ScalarAbs<V>) -> Self::Output {
99 ScalarAbs::new(self.value_a - rhs.value_a)
100 }
101}
102
103impl<V: Copy + std::ops::Add<V, Output = V>> std::ops::AddAssign<ScalarAbs<V>> for ScalarAbs<V> {
104 fn add_assign(&mut self, rhs: ScalarAbs<V>) {
105 *self = *self + rhs;
106 }
107}
108
109impl<V: Copy + std::ops::Mul<V, Output = V>> std::ops::Mul<V> for ScalarAbs<V> {
110 type Output = ScalarAbs<V>;
111
112 fn mul(self, rhs: V) -> Self::Output {
113 ScalarAbs::new(self.value_a * rhs)
114 }
115}
116
117impl<V: Copy + std::ops::Div<V, Output = V>> std::ops::Div<V> for ScalarAbs<V> {
118 type Output = ScalarAbs<V>;
119
120 fn div(self, rhs: V) -> Self::Output {
121 ScalarAbs::new(self.value_a / rhs)
122 }
123}
124
125impl<V: std::ops::Add<V, Output = V>> std::ops::Add<ScalarPov<V>> for ScalarPov<V> {
126 type Output = ScalarPov<V>;
127
128 fn add(self, rhs: ScalarPov<V>) -> Self::Output {
129 ScalarPov::new(self.value + rhs.value)
130 }
131}
132
133impl<V: Copy + std::ops::Sub<V, Output = V>> std::ops::Sub<ScalarPov<V>> for ScalarPov<V> {
134 type Output = ScalarPov<V>;
135
136 fn sub(self, rhs: ScalarPov<V>) -> Self::Output {
137 ScalarPov::new(self.value - rhs.value)
138 }
139}
140
141impl<V: Copy + std::ops::Add<V, Output = V>> std::ops::AddAssign<ScalarPov<V>> for ScalarPov<V> {
142 fn add_assign(&mut self, rhs: ScalarPov<V>) {
143 *self = *self + rhs;
144 }
145}
146
147impl<V: Copy + std::ops::Mul<V, Output = V>> std::ops::Mul<V> for ScalarPov<V> {
148 type Output = ScalarPov<V>;
149
150 fn mul(self, rhs: V) -> Self::Output {
151 ScalarPov::new(self.value * rhs)
152 }
153}
154
155impl<V: Copy + std::ops::Div<V, Output = V>> std::ops::Div<V> for ScalarPov<V> {
156 type Output = ScalarPov<V>;
157
158 fn div(self, rhs: V) -> Self::Output {
159 ScalarPov::new(self.value / rhs)
160 }
161}