1use std::fmt;
4use utils::parse_fen;
5
6
7pub type Color = usize;
9
10pub const WHITE: Color = 0;
11pub const BLACK: Color = 1;
12
13
14pub type PieceType = usize;
16
17pub const KING: PieceType = 0;
18pub const QUEEN: PieceType = 1;
19pub const ROOK: PieceType = 2;
20pub const BISHOP: PieceType = 3;
21pub const KNIGHT: PieceType = 4;
22pub const PAWN: PieceType = 5;
23pub const PIECE_NONE: PieceType = 6;
24
25
26pub type Square = usize;
28
29
30pub type Bitboard = u64;
38
39
40#[derive(Clone, Debug)]
42pub struct PiecesPlacement {
43 pub piece_type: [Bitboard; 6],
47
48 pub color: [Bitboard; 2],
52}
53
54impl fmt::Display for PiecesPlacement {
55 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
56 let mut s = String::new();
57 for rank in (0..8).rev() {
58 s.push('\n');
59 for file in 0..8 {
60 let square = Board::square(file, rank);
61 let bb = 1 << square;
62 let piece = match bb {
63 x if x & self.piece_type[KING] != 0 => 'k',
64 x if x & self.piece_type[QUEEN] != 0 => 'q',
65 x if x & self.piece_type[ROOK] != 0 => 'r',
66 x if x & self.piece_type[BISHOP] != 0 => 'b',
67 x if x & self.piece_type[KNIGHT] != 0 => 'n',
68 x if x & self.piece_type[PAWN] != 0 => 'p',
69 _ => '.',
70 };
71 if bb & self.color[WHITE] != 0 {
72 s.push(piece.to_uppercase().next().unwrap());
73 } else {
74 s.push(piece);
75 }
76 }
77 }
78 writeln!(f, "{}", s)
79 }
80}
81
82
83pub type CastlingSide = usize;
85
86pub const QUEENSIDE: CastlingSide = 0;
87pub const KINGSIDE: CastlingSide = 1;
88
89
90#[derive(Clone, Copy, Debug)]
110pub struct CastlingRights(usize);
111
112impl CastlingRights {
113 #[inline]
118 pub fn new(value: usize) -> CastlingRights {
119 CastlingRights(value & 0b1111)
120 }
121
122 #[inline]
124 pub fn value(&self) -> usize {
125 self.0
126 }
127
128 pub fn grant(&mut self, player: Color, side: CastlingSide) -> bool {
134 assert!(player <= 1);
135 assert!(side <= 1);
136 let rights_before = self.0;
137 let granted = 1 << (player << 1) << side;
138 self.0 |= granted;
139
140 granted & !rights_before != 0
141 }
142
143 #[inline]
147 pub fn update(&mut self, orig_square: Square, dest_square: Square) {
148 debug_assert!(orig_square <= 63);
149 debug_assert!(dest_square <= 63);
150 const WQ: usize = (1 << (WHITE << 1) << QUEENSIDE);
151 const WK: usize = (1 << (WHITE << 1) << KINGSIDE);
152 const W: usize = WQ | WK;
153 const BQ: usize = (1 << (BLACK << 1) << QUEENSIDE);
154 const BK: usize = (1 << (BLACK << 1) << KINGSIDE);
155 const B: usize = BQ | BK;
156
157 const CASTLING_RELATION: [usize; 64] = [
162 !WQ, !0, !0, !0, !W, !0, !0, !WK,
163 !0, !0, !0, !0, !0, !0, !0, !0,
164 !0, !0, !0, !0, !0, !0, !0, !0,
165 !0, !0, !0, !0, !0, !0, !0, !0,
166 !0, !0, !0, !0, !0, !0, !0, !0,
167 !0, !0, !0, !0, !0, !0, !0, !0,
168 !0, !0, !0, !0, !0, !0, !0, !0,
169 !BQ, !0, !0, !0, !B, !0, !0, !BK
170 ];
171 self.0 &= CASTLING_RELATION[orig_square] & CASTLING_RELATION[dest_square];
172 }
173
174 #[inline]
177 pub fn can_castle(&self, player: Color, side: CastlingSide) -> bool {
178 debug_assert!(player <= 1);
179 debug_assert!(side <= 1);
180 (1 << (player << 1) << side) & self.0 != 0
181 }
182}
183
184impl fmt::Display for CastlingRights {
185 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
186 let mut value = self.value();
187 for s in ["Q", "K", "q", "k"].iter() {
188 if value & 1 == 1 {
189 try!(f.write_str(s));
190 }
191 value >>= 1;
192 }
193 Ok(())
194 }
195}
196
197
198pub struct IllegalBoard;
200
201
202#[derive(Clone, Debug)]
204pub struct Board {
205 pub pieces: PiecesPlacement,
207
208 pub to_move: Color,
210
211 pub castling_rights: CastlingRights,
213
214 pub enpassant_file: usize,
217
218 pub occupied: Bitboard,
224}
225
226impl Board {
227 pub fn from_fen(fen: &str) -> Result<Board, IllegalBoard> {
229 parse_fen(fen).map(|x| x.0)
230 }
231
232 #[inline]
237 pub fn square(file: usize, rank: usize) -> Square {
238 debug_assert!(file < 8);
239 debug_assert!(rank < 8);
240 (rank << 3) + file
241 }
242
243 #[inline]
247 pub fn file(square: Square) -> usize {
248 debug_assert!(square <= 63);
249 square % 8
250 }
251
252 #[inline]
256 pub fn rank(square: Square) -> usize {
257 debug_assert!(square <= 63);
258 square >> 3
259 }
260}
261
262
263#[cfg(test)]
264mod tests {
265 use super::*;
266 use squares::*;
267
268 #[test]
269 fn castling_rights() {
270 let mut c = CastlingRights::new(0b1110);
271 assert_eq!(c.can_castle(WHITE, QUEENSIDE), false);
272 assert_eq!(c.can_castle(WHITE, KINGSIDE), true);
273 assert_eq!(c.can_castle(BLACK, QUEENSIDE), true);
274 assert_eq!(c.can_castle(BLACK, KINGSIDE), true);
275 c.update(H8, H7);
276 assert_eq!(c.can_castle(WHITE, QUEENSIDE), false);
277 assert_eq!(c.can_castle(WHITE, KINGSIDE), true);
278 assert_eq!(c.can_castle(BLACK, QUEENSIDE), true);
279 assert_eq!(c.can_castle(BLACK, KINGSIDE), false);
280 assert_eq!(c.value(), 0b0110);
281 assert_eq!(c.grant(BLACK, KINGSIDE), true);
282 assert_eq!(c.grant(BLACK, KINGSIDE), false);
283 assert_eq!(c.value(), 0b1110);
284 }
285}