1use core::board::{MultiBoard, PieceMap};
4use core::misc::Contained;
5use core::mv::{self, MoveVec};
6use prelude::*;
7
8mod state;
9pub use self::state::*;
10
11mod mv_gen;
12pub use self::mv_gen::*;
13
14#[cfg(all(test, nightly))]
15mod benches;
16
17#[derive(Clone)]
19pub struct Position {
20 state: State,
22
23 pieces: PieceMap,
25
26 board: MultiBoard,
28
29 player: Color,
31}
32
33impl PartialEq for Position {
34 fn eq(&self, other: &Position) -> bool {
35 self.pieces == other.pieces &&
37 self.player == other.player &&
38 self.state == other.state
39 }
40}
41
42impl Eq for Position {}
43
44impl Default for Position {
45 #[inline]
46 fn default() -> Position {
47 const STANDARD: Position = Position {
48 state: State::STANDARD,
49 pieces: PieceMap::STANDARD,
50 board: MultiBoard::STANDARD,
51 player: Color::White,
52 };
53 STANDARD
54 }
55}
56
57impl Position {
58 #[inline]
60 pub fn pieces(&self) -> &PieceMap {
61 &self.pieces
62 }
63
64 #[inline]
66 pub fn board(&self) -> &MultiBoard {
67 &self.board
68 }
69
70 #[inline]
84 pub fn gen<'a, 'b>(&'a self, moves: &'b mut MoveVec) -> MoveGen<'a, 'b> {
85 MoveGen { pos: self, buf: moves }
86 }
87
88 pub fn is_legal(&self, mv: Move) -> bool {
90 use self::mv::Matches;
91
92 let src = mv.src();
93 let dst = mv.dst();
94
95 let player = self.player();
96 let king = self.king_square(player);
97 let board = self.board();
98 let checked = board.is_attacked(king, player);
99
100 match mv.matches() {
101 Matches::Castle(mv) => {
102 if checked {
104 return false;
105 }
106
107 let right = mv.right();
108 if player != right.color() || !self.rights().contains(right) {
109 return false;
110 }
111
112 for sq in right.path_iter() {
114 if board.is_attacked(sq, player) {
115 return false;
116 }
117 }
118
119 true
120 },
121 _ => unimplemented!(),
122 }
123 }
124
125 #[inline]
127 pub fn contains<'a, T: Contained<&'a Self>>(&'a self, value: T) -> bool {
128 value.contained_in(self)
129 }
130
131 #[inline]
133 pub fn player(&self) -> Color {
134 self.player
135 }
136
137 #[inline]
139 pub fn player_bitboard(&self) -> Bitboard {
140 self.board().bitboard(self.player())
141 }
142
143 #[inline]
145 pub fn opponent(&self) -> Color {
146 !self.player()
147 }
148
149 #[inline]
151 pub fn opponent_bitboard(&self) -> Bitboard {
152 self.board().bitboard(self.opponent())
153 }
154
155 #[inline]
157 pub fn en_passant(&self) -> Option<Square> {
158 self.state.en_passant()
159 }
160
161 #[inline]
163 pub fn rights(&self) -> Rights {
164 self.state.rights()
165 }
166
167 #[inline]
169 pub fn king_square(&self, color: Color) -> Square {
170 let piece = Piece::new(Role::King, color);
171 let board = self.board().bitboard(piece);
172
173 debug_assert!(!board.is_empty(), "{:?} not found", piece);
175
176 unsafe { board.lsb_unchecked() }
177 }
178}
179
180impl<'a> Contained<&'a Position> for Square {
181 #[inline]
182 fn contained_in(self, pos: &Position) -> bool {
183 pos.pieces().contains(self)
184 }
185}
186
187macro_rules! impl_contained {
188 ($($t:ty),+) => {
189 $(impl<'a> Contained<&'a Position> for $t {
190 #[inline]
191 fn contained_in(self, pos: &Position) -> bool {
192 !pos.board().bitboard(self).is_empty()
193 }
194 })+
195 }
196}
197
198impl_contained! { Piece, Role, Color }
199
200#[cfg(test)]
201mod tests {
202 use super::*;
203
204 #[test]
205 fn initial_pieces() {
206 let pos = Position::default();
207 let all = pos.board().all_bits();
208
209 for square in Square::ALL {
210 if let Some(&piece) = pos.pieces().get(square) {
211 assert!(all.contains(square));
212
213 let board = pos.board();
214 assert!(board.contains(square, piece));
215 assert!(board.contains(square, piece.role()));
216 assert!(board.contains(square, piece.color()));
217 } else {
218 let (a, b) = pos.board.split();
219 for &slice in &[&a[..], &b[..]] {
220 for &bitboard in slice {
221 assert!(!bitboard.contains(square));
222 }
223 }
224 }
225 }
226 }
227}