|
@@ -6,7 +6,15 @@ pub struct Game
|
|
|
{
|
|
|
pub pieces: [Bitboard; 12],
|
|
|
pub turn: Side,
|
|
|
- pub en_passant: u8,
|
|
|
+ pub en_passant: Option<u8>,
|
|
|
+
|
|
|
+ ///
|
|
|
+ /// castling rights in the following order
|
|
|
+ /// white kingside, white queenside, black kingside, black queenside
|
|
|
+ ///
|
|
|
+ pub castling_rights: [bool; 4],
|
|
|
+ pub halfmoves_since_last_event: i32,
|
|
|
+ pub turn_number: i32,
|
|
|
}
|
|
|
|
|
|
impl Default for Game {
|
|
@@ -27,61 +35,85 @@ impl Default for Game {
|
|
|
0x08 << 56,
|
|
|
],
|
|
|
turn: WHITE,
|
|
|
- en_passant: 0,
|
|
|
+ en_passant: None,
|
|
|
+ castling_rights: [true, true, true, true],
|
|
|
+ halfmoves_since_last_event: 0,
|
|
|
+ turn_number: 0
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
impl Game {
|
|
|
|
|
|
- pub fn from_fen(fen: &str) -> Option<Game> {
|
|
|
+ pub fn from_fen(fen: &[&str]) -> Option<Game> {
|
|
|
let mut game: Game = Game::default();
|
|
|
let example = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
|
|
|
- let mut fen_parts = fen.split_whitespace();
|
|
|
|
|
|
- match fen_parts.next() {
|
|
|
- Some(position) => {
|
|
|
- let rows = position.split('/');
|
|
|
- let mut row_index = 0;
|
|
|
- for row in rows {
|
|
|
- if row_index >= 8 {
|
|
|
+ let position = fen[0];
|
|
|
+ let turn = fen[1];
|
|
|
+ let castling_rights = fen[2];
|
|
|
+ let en_passant = fen[3];
|
|
|
+ let halfmoves_since_last_event = fen[4];
|
|
|
+ let turn_number = fen[5];
|
|
|
+
|
|
|
+ {
|
|
|
+ let rows = position.split('/');
|
|
|
+ let mut row_index = 0;
|
|
|
+ for row in rows {
|
|
|
+ if row_index >= 8 {
|
|
|
+ return None;
|
|
|
+ }
|
|
|
+ let mut col_index = 0;
|
|
|
+ for c in row.chars() {
|
|
|
+
|
|
|
+ if col_index >= 8 {
|
|
|
return None;
|
|
|
}
|
|
|
- let mut col_index = 0;
|
|
|
- for c in row.chars() {
|
|
|
|
|
|
- if col_index >= 8 {
|
|
|
- return None;
|
|
|
+ let bit_to_set = from_indices(col_index, row_index);
|
|
|
+ match c {
|
|
|
+ 'p' => { *game.pawns_mut(BLACK) |= bit_to_set },
|
|
|
+ 'n' => { *game.knights_mut(BLACK) |= bit_to_set },
|
|
|
+ 'b' => { *game.bishops_mut(BLACK) |= bit_to_set },
|
|
|
+ 'r' => { *game.rooks_mut(BLACK) |= bit_to_set },
|
|
|
+ 'q' => { *game.queens_mut(BLACK) |= bit_to_set },
|
|
|
+ 'k' => { *game.kings_mut(BLACK) |= bit_to_set },
|
|
|
+ 'P' => { *game.pawns_mut(WHITE) |= bit_to_set },
|
|
|
+ 'N' => { *game.knights_mut(WHITE) |= bit_to_set },
|
|
|
+ 'B' => { *game.bishops_mut(WHITE) |= bit_to_set },
|
|
|
+ 'R' => { *game.rooks_mut(WHITE) |= bit_to_set },
|
|
|
+ 'Q' => { *game.queens_mut(WHITE) |= bit_to_set },
|
|
|
+ 'K' => { *game.kings_mut(WHITE) |= bit_to_set },
|
|
|
+ num => {
|
|
|
+ col_index += match num.to_digit(10) { Some(x) => x, None => {
|
|
|
+ return None;
|
|
|
+ }} as u8 - 1;
|
|
|
}
|
|
|
-
|
|
|
- let bit_to_set = from_indices(col_index, row_index);
|
|
|
- match c {
|
|
|
- 'p' => { *game.pawns_mut(BLACK) |= bit_to_set },
|
|
|
- 'n' => { *game.knights_mut(BLACK) |= bit_to_set },
|
|
|
- 'b' => { *game.bishops_mut(BLACK) |= bit_to_set },
|
|
|
- 'r' => { *game.rooks_mut(BLACK) |= bit_to_set },
|
|
|
- 'q' => { *game.queens_mut(BLACK) |= bit_to_set },
|
|
|
- 'k' => { *game.kings_mut(BLACK) |= bit_to_set },
|
|
|
- 'P' => { *game.pawns_mut(WHITE) |= bit_to_set },
|
|
|
- 'N' => { *game.knights_mut(WHITE) |= bit_to_set },
|
|
|
- 'B' => { *game.bishops_mut(WHITE) |= bit_to_set },
|
|
|
- 'R' => { *game.rooks_mut(WHITE) |= bit_to_set },
|
|
|
- 'Q' => { *game.queens_mut(WHITE) |= bit_to_set },
|
|
|
- 'K' => { *game.kings_mut(WHITE) |= bit_to_set },
|
|
|
- num => {
|
|
|
- col_index += match num.to_digit(10) { Some(x) => x, None => {
|
|
|
- return None;
|
|
|
- }} as u8 - 1;
|
|
|
- }
|
|
|
- }
|
|
|
- col_index += 1;
|
|
|
}
|
|
|
+ col_index += 1;
|
|
|
}
|
|
|
- },
|
|
|
- None => return None
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- None
|
|
|
+ // parse castling rights
|
|
|
+ game.castling_rights[0] = castling_rights.contains('K');
|
|
|
+ game.castling_rights[1] = castling_rights.contains('Q');
|
|
|
+ game.castling_rights[2] = castling_rights.contains('k');
|
|
|
+ game.castling_rights[3] = castling_rights.contains('q');
|
|
|
+
|
|
|
+ // parse castling rights
|
|
|
+ game.en_passant = en_passant.parse::<u8>().ok();
|
|
|
+
|
|
|
+ game.halfmoves_since_last_event = halfmoves_since_last_event.parse::<i32>().unwrap_or(0);
|
|
|
+ game.turn_number = turn_number.parse::<i32>().unwrap_or(0);
|
|
|
+
|
|
|
+ Some(game)
|
|
|
+ }
|
|
|
+
|
|
|
+ pub fn from_fen_str(fen: &str) -> Option<Game> {
|
|
|
+ let mut fen_parts = fen.split_whitespace();
|
|
|
+
|
|
|
+ Self::from_fen(fen_parts.collect::<Vec<&str>>().as_slice())
|
|
|
}
|
|
|
|
|
|
pub fn parse_move(&self, mov: &str) -> Result<Move, ()> {
|