@@ -21,8 +21,10 @@ pub struct Board {
21
21
pub moves : Vec < Move > ,
22
22
pub zobrist_history : Vec < u64 > ,
23
23
pub fen_history : Vec < String > ,
24
+ pub game_state_history : Vec < GameState > ,
24
25
}
25
26
27
+ #[ derive( Debug , Copy , Clone ) ]
26
28
pub struct GameState {
27
29
pub captured_piece : Option < Piece > ,
28
30
pub en_passant_square : Option < usize > ,
@@ -108,6 +110,7 @@ impl Board {
108
110
moves : Vec :: new ( ) ,
109
111
zobrist_history : Vec :: new ( ) ,
110
112
fen_history : Vec :: new ( ) ,
113
+ game_state_history : Vec :: new ( ) ,
111
114
}
112
115
}
113
116
@@ -133,6 +136,7 @@ impl Board {
133
136
self . moves = Vec :: new ( ) ;
134
137
self . zobrist_history = Vec :: new ( ) ;
135
138
self . fen_history = Vec :: new ( ) ;
139
+ self . game_state_history = Vec :: new ( ) ;
136
140
}
137
141
138
142
pub fn set_fen ( & mut self , fen : & str ) {
@@ -206,6 +210,85 @@ impl Board {
206
210
self . game_state . current_zobrist = ZOBRIST . hash ( & self ) ;
207
211
}
208
212
213
+ pub fn to_fen ( & self ) -> String {
214
+ let mut fen = String :: new ( ) ;
215
+
216
+ for row in ( 0 ..BOARD_WIDTH ) . rev ( ) {
217
+ let mut empty = 0 ;
218
+ for col in 0 ..BOARD_WIDTH {
219
+ let index = row * BOARD_WIDTH + col;
220
+
221
+ if self . piece_at ( index) . is_none ( ) {
222
+ empty += 1 ;
223
+ } else {
224
+ if empty > 0 {
225
+ fen. push_str ( & empty. to_string ( ) ) ;
226
+ empty = 0 ;
227
+ }
228
+
229
+ let piece = self . piece_at ( index) . unwrap ( ) ;
230
+ let c = match piece. color {
231
+ Color :: White => piece
232
+ . piece
233
+ . to_string ( )
234
+ . to_uppercase ( )
235
+ . chars ( )
236
+ . next ( )
237
+ . unwrap ( ) ,
238
+ Color :: Black => piece. piece . to_string ( ) . chars ( ) . next ( ) . unwrap ( ) ,
239
+ } ;
240
+ fen. push ( c) ;
241
+ }
242
+ }
243
+
244
+ if empty > 0 {
245
+ fen. push_str ( & empty. to_string ( ) ) ;
246
+ }
247
+
248
+ if row > 0 {
249
+ fen. push ( '/' ) ;
250
+ }
251
+ }
252
+
253
+ fen. push ( ' ' ) ;
254
+ fen. push_str ( match self . turn {
255
+ Color :: White => "w" ,
256
+ Color :: Black => "b" ,
257
+ } ) ;
258
+
259
+ fen. push ( ' ' ) ;
260
+ if self . game_state . castling_rights == 0 {
261
+ fen. push ( '-' ) ;
262
+ } else {
263
+ if self . game_state . castling_rights & CASTLING_WHITE_KING != 0 {
264
+ fen. push ( 'K' ) ;
265
+ }
266
+ if self . game_state . castling_rights & CASTLING_WHITE_QUEEN != 0 {
267
+ fen. push ( 'Q' ) ;
268
+ }
269
+ if self . game_state . castling_rights & CASTLING_BLACK_KING != 0 {
270
+ fen. push ( 'k' ) ;
271
+ }
272
+ if self . game_state . castling_rights & CASTLING_BLACK_QUEEN != 0 {
273
+ fen. push ( 'q' ) ;
274
+ }
275
+ }
276
+
277
+ fen. push ( ' ' ) ;
278
+ match self . game_state . en_passant_square {
279
+ Some ( square) => fen. push_str ( & Board :: index_to_square ( square) ) ,
280
+ None => fen. push ( '-' ) ,
281
+ }
282
+
283
+ fen. push ( ' ' ) ;
284
+ fen. push_str ( & self . game_state . fifty_move_ply_count . to_string ( ) ) ;
285
+
286
+ fen. push ( ' ' ) ;
287
+ fen. push_str ( & ( ( self . ply / 2 ) + 1 ) . to_string ( ) ) ;
288
+
289
+ fen
290
+ }
291
+
209
292
pub fn add_piece ( & mut self , color : Color , piece : Piece , index : usize ) {
210
293
let bb = Bitboard :: from_index ( index) ;
211
294
@@ -384,5 +467,19 @@ impl Board {
384
467
if mv. piece == Piece :: Pawn || mv. capture . is_some ( ) {
385
468
new_fifty_move_ply_count = 0 ;
386
469
}
470
+
471
+ let new_game_state = GameState {
472
+ captured_piece : mv. capture ,
473
+ en_passant_square : new_en_passant_square,
474
+ castling_rights : new_castling_rights,
475
+ fifty_move_ply_count : new_fifty_move_ply_count,
476
+ current_zobrist : new_zobrist,
477
+ } ;
478
+
479
+ self . game_state = new_game_state;
480
+ self . game_state_history . push ( new_game_state) ;
481
+ self . zobrist_history . push ( new_zobrist) ;
482
+ self . fen_history . push ( self . to_fen ( ) ) ;
483
+ self . moves . push ( * mv) ;
387
484
}
388
485
}
0 commit comments