chess_move_gen/
castling_rights.rs

1use crate::castle::*;
2use crate::side::Side;
3use std::fmt;
4
5type Internal = u8;
6
7/// Represents the right to castle in a particular director for a particular side
8#[derive(PartialEq, Copy, Clone)]
9pub struct CastlingRights(pub Internal);
10
11pub const WHITE_QS: CastlingRights = CastlingRights(1);
12pub const BLACK_QS: CastlingRights = CastlingRights(2);
13pub const WHITE_KS: CastlingRights = CastlingRights(4);
14pub const BLACK_KS: CastlingRights = CastlingRights(8);
15
16pub const NO_RIGHTS: CastlingRights = CastlingRights(0);
17pub const ALL_RIGHTS: CastlingRights = CastlingRights(1 | 2 | 4 | 8);
18pub const WHITE_RIGHTS: CastlingRights = CastlingRights(1 | 4);
19
20const CASTLING_RIGHTS_CHARS: [char; 4] = ['Q', 'q', 'K', 'k'];
21
22impl CastlingRights {
23    pub fn to_usize(self) -> usize {
24        self.0 as usize
25    }
26
27    pub fn has(self, right: CastlingRights) -> bool {
28        self.0 & right.0 != 0
29    }
30
31    #[allow(dead_code)]
32    pub fn add(&mut self, castle: Castle, side: Side) {
33        self.0 |= CastlingRights::from(castle, side).0
34    }
35
36    pub fn set(&mut self, rights: CastlingRights) {
37        self.0 |= rights.0;
38    }
39
40    pub fn clear_side(&mut self, side: Side) {
41        let rights = WHITE_RIGHTS.0 << side.raw();
42        self.0 &= !rights;
43    }
44
45    pub fn clear(&mut self, rights: CastlingRights) {
46        self.0 &= !rights.0;
47    }
48
49    #[allow(dead_code)]
50    pub fn side_can(self, side: Side) -> bool {
51        let rights = WHITE_RIGHTS.0 << side.raw();
52        self.0 & rights != 0
53    }
54
55    pub fn any(self) -> bool {
56        self.0 != 0
57    }
58
59    pub fn from(castle: Castle, side: Side) -> CastlingRights {
60        CastlingRights(1 << (castle.to_usize() * 2 + side.0))
61    }
62
63    pub fn parse(chr: char) -> Result<CastlingRights, String> {
64        for (i, &c) in CASTLING_RIGHTS_CHARS.iter().enumerate() {
65            if c == chr {
66                return Ok(CastlingRights(1 << i));
67            }
68        }
69        Err(format!("Invalid castle: {}", chr))
70    }
71}
72
73impl fmt::Display for CastlingRights {
74    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
75        let mut string = String::new();
76
77        if !self.any() {
78            return write!(f, "-");
79        }
80
81        for (i, &c) in CASTLING_RIGHTS_CHARS.iter().enumerate() {
82            let right = CastlingRights(1 << i);
83            if self.has(right) {
84                string.push(c);
85            }
86        }
87
88        write!(f, "{}", string)
89    }
90}
91
92impl fmt::Debug for CastlingRights {
93    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
94        let mut string = String::new();
95
96        if !self.any() {
97            return write!(f, "-");
98        }
99
100        for (i, &c) in CASTLING_RIGHTS_CHARS.iter().enumerate() {
101            let right = CastlingRights(1 << i);
102            if self.has(right) {
103                string.push(c);
104            }
105        }
106
107        write!(f, "{}", string)
108    }
109}
110
111#[cfg(test)]
112mod test {
113    use super::*;
114    use crate::side::*;
115
116    #[test]
117    fn can_1() {
118        let rights = WHITE_QS;
119        assert_eq!(rights.has(WHITE_QS), true);
120        assert_eq!(rights.has(BLACK_QS), false);
121        assert_eq!(rights.has(WHITE_KS), false);
122        assert_eq!(rights.has(BLACK_KS), false);
123    }
124
125    #[test]
126    fn can_2() {
127        let rights = BLACK_QS;
128        assert_eq!(rights.has(WHITE_QS), false);
129        assert_eq!(rights.has(BLACK_QS), true);
130        assert_eq!(rights.has(WHITE_KS), false);
131        assert_eq!(rights.has(BLACK_KS), false);
132    }
133
134    #[test]
135    fn can_3() {
136        let rights = WHITE_KS;
137        assert_eq!(rights.has(WHITE_QS), false);
138        assert_eq!(rights.has(BLACK_QS), false);
139        assert_eq!(rights.has(WHITE_KS), true);
140        assert_eq!(rights.has(BLACK_KS), false);
141    }
142
143    #[test]
144    fn can_4() {
145        let rights = BLACK_KS;
146        assert_eq!(rights.has(WHITE_QS), false);
147        assert_eq!(rights.has(BLACK_QS), false);
148        assert_eq!(rights.has(WHITE_KS), false);
149        assert_eq!(rights.has(BLACK_KS), true);
150    }
151
152    #[test]
153    fn can_5() {
154        let mut rights = BLACK_KS;
155        rights.add(QUEEN_SIDE, WHITE);
156        assert_eq!(rights.has(WHITE_QS), true);
157        assert_eq!(rights.has(BLACK_QS), false);
158        assert_eq!(rights.has(WHITE_KS), false);
159        assert_eq!(rights.has(BLACK_KS), true);
160    }
161
162    #[test]
163    fn can_6() {
164        assert_eq!(NO_RIGHTS.has(WHITE_QS), false);
165        assert_eq!(NO_RIGHTS.has(BLACK_QS), false);
166        assert_eq!(NO_RIGHTS.has(WHITE_KS), false);
167        assert_eq!(NO_RIGHTS.has(BLACK_KS), false);
168    }
169
170    #[test]
171    fn can_7() {
172        assert_eq!(ALL_RIGHTS.has(WHITE_QS), true);
173        assert_eq!(ALL_RIGHTS.has(BLACK_QS), true);
174        assert_eq!(ALL_RIGHTS.has(WHITE_KS), true);
175        assert_eq!(ALL_RIGHTS.has(BLACK_KS), true);
176    }
177
178    #[test]
179    fn side_can_1() {
180        let rights = BLACK_KS;
181
182        assert_eq!(rights.side_can(WHITE), false);
183        assert_eq!(rights.side_can(BLACK), true);
184    }
185
186    #[test]
187    fn side_can_2() {
188        let mut rights = WHITE_KS;
189        rights.add(QUEEN_SIDE, WHITE);
190
191        assert_eq!(rights.side_can(WHITE), true);
192        assert_eq!(rights.side_can(BLACK), false);
193
194        assert_eq!(NO_RIGHTS.side_can(WHITE), false);
195        assert_eq!(NO_RIGHTS.side_can(BLACK), false);
196
197        assert_eq!(ALL_RIGHTS.side_can(WHITE), true);
198        assert_eq!(ALL_RIGHTS.side_can(BLACK), true);
199    }
200
201    #[test]
202    fn any() {
203        assert_eq!(CastlingRights::from(KING_SIDE, WHITE).any(), true);
204        assert_eq!(NO_RIGHTS.any(), false);
205    }
206
207    #[test]
208    fn char_1() {
209        assert_eq!(WHITE_QS.to_string(), "Q");
210    }
211
212    #[test]
213    fn char_2() {
214        assert_eq!(BLACK_QS.to_string(), "q");
215    }
216
217    #[test]
218    fn char_3() {
219        assert_eq!(WHITE_KS.to_string(), "K");
220    }
221
222    #[test]
223    fn char_4() {
224        assert_eq!(BLACK_KS.to_string(), "k");
225    }
226}