1pub mod fen;
2pub mod make;
3
4use self::fen::*;
5use super::util::grid_to_string_with_props;
6use crate::bb::*;
7use crate::castling_rights::*;
8use crate::hash::{DEFAULT_ZOBRISH_HASH, Zobrist};
9use crate::mv_list::PieceSquareTable;
10use crate::piece::*;
11use crate::side::Side;
12use crate::side::*;
13use crate::square::{Square, SquareInternal};
14use std::fmt;
15
16use std;
17
18pub const STARTING_POSITION_FEN: &str = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w QqKk - 0 1";
19
20#[derive(Debug, Clone, Copy)]
22pub struct State {
23 pub castling_rights: CastlingRights,
24 pub ep_square: Option<Square>,
25 pub stm: Side,
26 pub full_move_number: u16,
27 pub half_move_clock: u8,
28}
29
30impl Default for State {
31 fn default() -> Self {
32 State {
33 castling_rights: NO_RIGHTS,
34 ep_square: None,
35 stm: WHITE,
36 full_move_number: 1,
37 half_move_clock: 0,
38 }
39 }
40}
41
42pub struct Position {
44 grid: [Piece; 64],
46 bb_sides: [BB; 2],
48 bb_pieces: [BB; 12],
50 state: State,
52
53 key: u64,
54
55 hash: &'static Zobrist,
56}
57
58impl std::clone::Clone for Position {
59 fn clone(&self) -> Self {
60 Position {
61 grid: self.grid,
62 bb_sides: self.bb_sides,
63 bb_pieces: self.bb_pieces,
64 state: self.state.clone(),
65 key: self.key,
66 hash: self.hash,
67 }
68 }
69}
70
71impl fmt::Debug for Position {
72 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
73 write!(f, "{}", self.to_string())
74 }
75}
76
77impl fmt::Display for Position {
78 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
79 let props = vec![
80 (" side to move", self.state.stm.to_str().to_string()),
81 (" castling rights", self.state.castling_rights.to_string()),
82 (
83 " en-passant",
84 self.state
85 .ep_square
86 .map_or("-".to_string(), |s| s.to_string()),
87 ),
88 (" half-move clock", self.state.half_move_clock.to_string()),
89 ("full-move number", self.state.full_move_number.to_string()),
90 (" FEN", self.to_fen()),
91 (" KEY", format!("{:016X}", self.key)),
92 ];
93 let s = grid_to_string_with_props(
94 |sq: Square| -> char {
95 let pc = self.at(sq);
96 if pc.is_none() { '.' } else { pc.to_char() }
97 },
98 props.as_slice(),
99 );
100
101 write!(f, "{}", &s)
102 }
103}
104
105impl Position {
106 pub fn new(grid: [Piece; 64], state: State) -> Position {
107 let mut bb_pieces = [EMPTY; 12];
108 let mut bb_sides = [EMPTY; 2];
109
110 for (idx, pc) in grid.iter().enumerate().filter(|&(_, &pc)| pc.is_some()) {
111 let bb_mask = BB::new(Square::new(idx as SquareInternal));
112 bb_sides[pc.side().raw()] |= bb_mask;
113 bb_pieces[pc.to_usize()] |= bb_mask;
114 }
115
116 let hash = &DEFAULT_ZOBRISH_HASH;
117 let key = hash.position(&grid, &state);
118
119 Position {
120 grid,
121 bb_pieces,
122 bb_sides,
123 state,
124 hash: &DEFAULT_ZOBRISH_HASH,
125 key,
126 }
127 }
128
129 pub fn from_fen(fen: &str) -> Result<Position, String> {
131 from_fen(fen).map(|(grid, state)| Position::new(grid, state))
132 }
133
134 pub fn to_fen(&self) -> String {
136 to_fen(&self.grid, &self.state)
137 }
138
139 pub fn hash_key(&self) -> u64 {
140 self.key
141 }
142
143 pub fn state(&self) -> &State {
145 &self.state
146 }
147
148 pub fn grid(&self) -> &[Piece; 64] {
150 &self.grid
151 }
152
153 pub fn at(&self, sq: Square) -> Piece {
155 unsafe { return *self.grid.get_unchecked(sq.to_usize()) }
156 }
157
158 pub fn king_square(&self, side: Side) -> Square {
159 let pc = KING.pc(side);
160 self.bb_pc(pc).bitscan()
161 }
162
163 fn put_piece(&mut self, pc: Piece, sq: Square) {
164 debug_assert!(self.at(sq).is_none());
165
166 let bb_mask = BB::new(sq);
167
168 self.update_grid(sq, pc);
169
170 debug_assert_eq!(self.bb_pc(pc) & bb_mask, EMPTY);
171 debug_assert_eq!(self.bb_side(pc.side()) & bb_mask, EMPTY);
172
173 unsafe {
174 *self.bb_pieces.get_unchecked_mut(pc.to_usize()) ^= bb_mask;
175 *self.bb_sides.get_unchecked_mut(pc.side().to_usize()) ^= bb_mask;
176 }
177 }
178
179 fn remove_piece(&mut self, sq: Square) {
180 debug_assert!(self.at(sq).is_some());
181
182 let pc = self.at(sq);
183 let bb_mask = BB::new(sq);
184
185 self.update_grid(sq, NULL_PIECE);
186
187 debug_assert_eq!(self.bb_pc(pc) & bb_mask, bb_mask);
188 debug_assert_eq!(self.bb_side(pc.side()) & bb_mask, bb_mask);
189
190 unsafe {
191 *self.bb_pieces.get_unchecked_mut(pc.to_usize()) ^= bb_mask;
192 *self.bb_sides.get_unchecked_mut(pc.side().to_usize()) ^= bb_mask;
193 }
194 }
195
196 fn move_piece(&mut self, from: Square, to: Square) -> BB {
197 debug_assert!(self.at(from).is_some());
198 debug_assert!(self.at(to).is_none());
199
200 let pc = self.at(from);
201 let bb_mask = BB::new(from) | BB::new(to);
202
203 debug_assert_eq!(self.bb_pc(pc) & BB::new(from), BB::new(from));
204 debug_assert_eq!(self.bb_side(pc.side()) & BB::new(from), BB::new(from));
205 debug_assert_eq!(self.bb_pc(pc) & BB::new(to), EMPTY);
206 debug_assert_eq!(self.bb_side(pc.side()) & BB::new(to), EMPTY);
207
208 self.update_grid(from, NULL_PIECE);
209 self.update_grid(to, pc);
210
211 unsafe {
212 *self.bb_pieces.get_unchecked_mut(pc.to_usize()) ^= bb_mask;
213 *self.bb_sides.get_unchecked_mut(pc.side().to_usize()) ^= bb_mask;
214 }
215
216 bb_mask
217 }
218
219 fn promote_piece(&mut self, sq: Square, new_pc: Piece) {
220 let old_pc = self.at(sq);
221 let bb_mask = BB::new(sq);
222
223 debug_assert!(old_pc.is_some());
224 debug_assert_eq!(old_pc.side(), new_pc.side());
225
226 self.update_grid(sq, new_pc);
227
228 debug_assert_eq!(self.bb_pc(old_pc) & bb_mask, bb_mask);
229 debug_assert_eq!(self.bb_pc(new_pc) & bb_mask, EMPTY);
230 debug_assert_eq!(self.bb_side(old_pc.side()) & bb_mask, bb_mask);
231
232 unsafe {
233 *(self.bb_pieces.get_unchecked_mut(old_pc.to_usize())) ^= bb_mask;
234 *(self.bb_pieces.get_unchecked_mut(new_pc.to_usize())) |= bb_mask;
235 }
236 }
237
238 pub fn bb_side(&self, side: Side) -> BB {
240 unsafe { return *self.bb_sides.get_unchecked(side.to_usize() & 1) }
241 }
242
243 pub fn bb_pc(&self, pc: Piece) -> BB {
245 unsafe { return *self.bb_pieces.get_unchecked(pc.to_usize()) }
246 }
247
248 pub fn piece_iter(&self, pc: Piece) -> BBIterator {
249 self.bb_pieces[pc.to_usize()].iter()
250 }
251
252 pub fn bb_sliders(&self, side: Side) -> (BB, BB) {
254 let queens = self.bb_pc(QUEEN.pc(side));
255 let rooks = self.bb_pc(ROOK.pc(side));
256 let bishops = self.bb_pc(BISHOP.pc(side));
257 (queens | bishops, queens | rooks)
258 }
259
260 pub fn bb_occupied(&self) -> BB {
262 self.bb_side(WHITE) | self.bb_side(BLACK)
263 }
264
265 pub fn bb_empty(&self) -> BB {
267 !self.bb_occupied()
268 }
269
270 fn update_grid(&mut self, sq: Square, pc: Piece) {
271 unsafe {
272 *(self.grid.get_unchecked_mut(sq.to_usize())) = pc;
273 }
274 }
275
276 pub fn piece_square_score(&self, piece_square_table: &PieceSquareTable) -> i16 {
277 let mut score = 0i16;
278
279 for (idx, &pc) in self.grid().iter().enumerate() {
280 if pc.is_some() {
281 let piece_square_value =
282 piece_square_table.score(pc.kind(), Square(idx).from_side(pc.side()));
283
284 score += if self.state().stm == pc.side() {
285 piece_square_value
286 } else {
287 -piece_square_value
288 }
289 }
290 }
291
292 score
293 }
294}
295
296#[cfg(test)]
297mod test {
298 use super::*;
299 use unindent;
300
301 #[test]
302 fn test_is_not_too_big() {
303 assert_eq!(std::mem::size_of::<Position>(), 224);
304 }
305
306 #[test]
307 fn test_to_string() {
308 let position =
309 &Position::from_fen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w").unwrap();
310
311 let expected = unindent::unindent(
312 "
313 ABCDEFGH
314 8|rnbqkbnr|8 side to move: white
315 7|pppppppp|7 castling rights: QqKk
316 6|........|6 en-passant: -
317 5|........|5 half-move clock: 0
318 4|........|4 full-move number: 1
319 3|........|3 FEN: rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w QqKk - 0 1
320 2|PPPPPPPP|2 KEY: 0674AFC18BB45C18
321 1|RNBQKBNR|1
322 ABCDEFGH
323 ",
324 );
325 assert_eq!(position.to_string(), expected);
326 }
327}