board_game/
pov.rs

1use crate::board::Player;
2
3/// Trait to convert an absolute outcome to a relative one.
4pub trait NonPov: Sized {
5    type Output: Pov<Output = Self>;
6
7    /// View this outcome from the POV of `pov`.
8    fn pov(self, pov: Player) -> Self::Output;
9
10    /// Flip this outcome.
11    fn flip(self) -> Self {
12        // this is kind of cursed
13        self.pov(Player::A).un_pov(Player::B)
14    }
15}
16
17/// The opposite of [NonPov].
18pub trait Pov: Sized {
19    type Output: NonPov<Output = Self>;
20
21    /// The opposite of [NonPov::pov];
22    fn un_pov(self, pov: Player) -> Self::Output;
23
24    /// Flip this outcome.
25    fn flip(self) -> Self {
26        // this is kind of cursed
27        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}