Make from_fen return Result<Board, FenError>
This commit is contained in:
58
src/fen.rs
58
src/fen.rs
@@ -2,39 +2,39 @@ use crate::board::{Board, Color, Kind, Piece};
|
|||||||
use crate::game::{Game, State};
|
use crate::game::{Game, State};
|
||||||
use String as FenError;
|
use String as FenError;
|
||||||
|
|
||||||
pub fn from_fen(fen: &str) -> Game {
|
pub fn from_fen(fen: &str) -> Result<Game, FenError> {
|
||||||
let mut board = Board::empty_board();
|
|
||||||
let fen_parts: Vec<_> = fen.split_whitespace().collect();
|
let fen_parts: Vec<_> = fen.split_whitespace().collect();
|
||||||
|
|
||||||
piece_placement(fen_parts[0], &mut board);
|
let board = piece_placement(fen_parts[0])?;
|
||||||
|
|
||||||
let side_to_move = side_to_move(fen_parts[1]);
|
let side_to_move = side_to_move(fen_parts[1])?;
|
||||||
|
|
||||||
let castling_ability = castling_ability(fen_parts[2]);
|
let castling_ability = castling_ability(fen_parts[2])?;
|
||||||
|
|
||||||
let en_passant_target_square: Result<u8, FenError> = en_passant_target_square(fen_parts[3]);
|
let en_passant_target_square = en_passant_target_square(fen_parts[3])?;
|
||||||
|
|
||||||
let halfmove_clock = halfmove_clock(fen_parts[4]);
|
let halfmove_clock = halfmove_clock(fen_parts[4])?;
|
||||||
|
|
||||||
let fullmove_counter = fullmove_counter(fen_parts[5]);
|
let fullmove_counter = fullmove_counter(fen_parts[5])?;
|
||||||
|
|
||||||
Game {
|
Ok(Game {
|
||||||
board,
|
board,
|
||||||
state: State::load_state(
|
state: State::load_state(
|
||||||
side_to_move.unwrap(),
|
side_to_move,
|
||||||
castling_ability.unwrap(),
|
castling_ability,
|
||||||
en_passant_target_square.unwrap(),
|
en_passant_target_square,
|
||||||
halfmove_clock.unwrap(),
|
halfmove_clock,
|
||||||
fullmove_counter.unwrap(),
|
fullmove_counter,
|
||||||
),
|
),
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn piece_placement(pieces: &str, board: &mut Board) {
|
fn piece_placement(pieces: &str) -> Result<Board, FenError> {
|
||||||
|
let mut board = Board::empty_board();
|
||||||
let (mut file, mut rank): (u8, u8) = (0, 7);
|
let (mut file, mut rank): (u8, u8) = (0, 7);
|
||||||
|
|
||||||
for c in pieces.chars() {
|
for c in pieces.chars() {
|
||||||
let square: u8 = rank * 8 + file;
|
let square = rank * 8 + file;
|
||||||
let color = if c.is_ascii_lowercase() {
|
let color = if c.is_ascii_lowercase() {
|
||||||
Color::Black
|
Color::Black
|
||||||
} else {
|
} else {
|
||||||
@@ -57,13 +57,18 @@ fn piece_placement(pieces: &str, board: &mut Board) {
|
|||||||
rank %= n.to_digit(10).unwrap_or(0) as u8;
|
rank %= n.to_digit(10).unwrap_or(0) as u8;
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => {
|
||||||
|
return Err(FenError::from(
|
||||||
|
"Error while parsing board piece state from FEN",
|
||||||
|
))
|
||||||
|
}
|
||||||
} {
|
} {
|
||||||
board.set_piece(Piece::new(1 << square, kind, color));
|
board.set_piece(Piece::new(1 << square, kind, color));
|
||||||
};
|
};
|
||||||
|
|
||||||
file += 1;
|
file += 1;
|
||||||
}
|
}
|
||||||
|
Ok(board)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn side_to_move(side: &str) -> Result<Color, FenError> {
|
fn side_to_move(side: &str) -> Result<Color, FenError> {
|
||||||
@@ -152,20 +157,25 @@ fn fullmove_counter(fullmove: &str) -> Result<u8, FenError> {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
const FEN_EXAMPLE: [&str; 4] = [
|
const FEN_EXAMPLE: [&str; 5] = [
|
||||||
"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1",
|
"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1",
|
||||||
"rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1",
|
"rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1",
|
||||||
"rnbqkbnr/pp1ppppp/8/2p5/4P3/8/PPPP1PPP/RNBQKBNR w KQkq c6 0 2",
|
"rnbqkbnr/pp1ppppp/8/2p5/4P3/8/PPPP1PPP/RNBQKBNR w KQkq c6 0 2",
|
||||||
"rnbqkbnr/pp1ppppp/8/2p5/4P3/5N2/PPPP1PPP/RNBQKB1R b KQkq - 1 2 ",
|
"rnbqkbnr/pp1ppppp/8/2p5/4P3/5N2/PPPP1PPP/RNBQKB1R b KQkq - 1 2 ",
|
||||||
|
"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR x KQkq - 0 1",
|
||||||
];
|
];
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_sqrt() -> Result<(), String> {
|
fn test_from_fen() -> Result<(), String> {
|
||||||
let game = from_fen(FEN_EXAMPLE[3]);
|
let new_game = from_fen(FEN_EXAMPLE[0])?;
|
||||||
println!("{}\n{}", game.board, game.state);
|
assert_eq!(new_game, Game::new());
|
||||||
|
|
||||||
assert_eq!(from_fen(FEN_EXAMPLE[0]), Game::new());
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic]
|
||||||
|
fn test_fen_error() -> () {
|
||||||
|
from_fen(FEN_EXAMPLE[4]).unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ use crate::{
|
|||||||
board::{Board, Color},
|
board::{Board, Color},
|
||||||
fen::from_fen,
|
fen::from_fen,
|
||||||
};
|
};
|
||||||
|
use String as FenError;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct Game {
|
pub struct Game {
|
||||||
@@ -17,7 +18,7 @@ impl Game {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_from_fen(fen: &str) -> Game {
|
pub fn new_from_fen(fen: &str) -> Result<Game, FenError> {
|
||||||
from_fen(fen)
|
from_fen(fen)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,7 +76,7 @@ impl fmt::Display for State {
|
|||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
writeln!(f,
|
writeln!(f,
|
||||||
"side_to_move: {:?}\ncastling_ability: {:b}\nen_passant_target_square: {:b}\nhalfmove_clock: {}\nfullmove_counter: {}\n",
|
"side_to_move: {:?}\ncastling_ability: {:b}\nen_passant_target_square: {:b}\nhalfmove_clock: {}\nfullmove_counter: {}\n",
|
||||||
self.side_to_move, self.castling_ability, 1u64 << self.en_passant_target_square, self.halfmove_clock, self.fullmove_counter)
|
self.side_to_move, self.castling_ability, 1_u64 << self.en_passant_target_square, self.halfmove_clock, self.fullmove_counter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user