basic uci protocol
This commit is contained in:
parent
9d527634eb
commit
66cea5a2bf
16 changed files with 94 additions and 942 deletions
|
|
@ -1,85 +0,0 @@
|
|||
use chess_engine::board::Board;
|
||||
use chess_engine::movegen::sliders::generate_bishop_moves;
|
||||
use chess_engine::r#move::MoveList;
|
||||
|
||||
/// Compares two move list strings ignoring the order of moves.
|
||||
fn assert_moves_equal(actual_str: &str, expected_str: &str) {
|
||||
let mut actual_moves: Vec<&str> = actual_str.split_whitespace().collect();
|
||||
let mut expected_moves: Vec<&str> = expected_str.split_whitespace().collect();
|
||||
|
||||
actual_moves.sort();
|
||||
expected_moves.sort();
|
||||
|
||||
assert_eq!(actual_moves, expected_moves);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bishop_moves_single() {
|
||||
let fen_standard = "8/8/8/1p1p4/2B5/8/8/8 w - - 0 1";
|
||||
let board = Board::from_fen(fen_standard);
|
||||
let mut list = MoveList::new();
|
||||
generate_bishop_moves(&board, &mut list);
|
||||
assert_moves_equal(&list.to_string(), "c4b5 c4d5 c4b3 c4d3 c4a2 c4e2 c4f1");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bishop_moves_empty_board_center() {
|
||||
// Läufer in der Mitte (e4) auf einem leeren Brett
|
||||
let fen = "8/8/8/8/4B3/8/8/8 w - - 0 1";
|
||||
let board = Board::from_fen(fen);
|
||||
let mut list = MoveList::new();
|
||||
generate_bishop_moves(&board, &mut list);
|
||||
|
||||
let expected = "e4d3 e4c2 e4b1 e4f5 e4g6 e4h7 e4d5 e4c6 e4b7 e4a8 e4f3 e4g2 e4h1";
|
||||
assert_moves_equal(&list.to_string(), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bishop_moves_from_corner() {
|
||||
// Läufer in der Ecke (a1) auf einem leeren Brett
|
||||
let fen = "8/8/8/8/8/8/8/B7 w - - 0 1";
|
||||
let board = Board::from_fen(fen);
|
||||
let mut list = MoveList::new();
|
||||
generate_bishop_moves(&board, &mut list);
|
||||
|
||||
let expected = "a1b2 a1c3 a1d4 a1e5 a1f6 a1g7 a1h8";
|
||||
assert_moves_equal(&list.to_string(), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bishop_moves_friendly_blockers() {
|
||||
// Läufer auf c1, blockiert von EIGENEN Bauern auf b2 und d2.
|
||||
// Darf b2/d2 NICHT schlagen und nicht darüber springen.
|
||||
let fen = "8/8/8/8/8/8/1P1P4/2B5 w - - 0 1";
|
||||
let board = Board::from_fen(fen);
|
||||
let mut list = MoveList::new();
|
||||
generate_bishop_moves(&board, &mut list);
|
||||
|
||||
// Es sollten KEINE Züge generiert werden.
|
||||
assert_moves_equal(&list.to_string(), "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bishop_moves_mixed_blockers_and_captures() {
|
||||
let fen = "8/8/1p3P2/8/3B4/8/1p3P2/8 w - - 0 1";
|
||||
let board = Board::from_fen(fen);
|
||||
let mut list = MoveList::new();
|
||||
generate_bishop_moves(&board, &mut list);
|
||||
|
||||
let expected = "d4c3 d4e3 d4b2 d4c5 d4b6 d4e5";
|
||||
assert_moves_equal(&list.to_string(), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bishop_moves_black_turn() {
|
||||
// Schwarzer Läufer auf c5, weiße Bauern auf b4 und d4.
|
||||
let fen = "8/8/8/2b5/1P1P4/8/8/8 b - - 0 1";
|
||||
let board = Board::from_fen(fen);
|
||||
let mut list = MoveList::new();
|
||||
generate_bishop_moves(&board, &mut list);
|
||||
|
||||
// Schlagzüge: b4, d4
|
||||
// Ruhige Züge: b6, a7, d6, e7, f8
|
||||
let expected = "c5b4 c5d4 c5b6 c5a7 c5d6 c5e7 c5f8";
|
||||
assert_moves_equal(&list.to_string(), expected);
|
||||
}
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
use chess_engine::board::{Board, Color};
|
||||
use chess_engine::movegen::legal_check::is_square_attacked;
|
||||
use chess_engine::square::Square;
|
||||
|
||||
|
||||
fn assert_square_attacked(board: &mut Board, square: Square, white: bool, black: bool) {
|
||||
assert_eq!(is_square_attacked(board, square, Color::White), white, "{}", square);
|
||||
assert_eq!(is_square_attacked(board, square, Color::Black), black, "{}", square);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_attacked_kiwipete() {
|
||||
let mut board = Board::from_fen("r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1");
|
||||
assert_square_attacked(&mut board, Square::B1, true, false);
|
||||
assert_square_attacked(&mut board, Square::C1, true, false);
|
||||
assert_square_attacked(&mut board, Square::D1, true, false);
|
||||
assert_square_attacked(&mut board, Square::F1, true, false);
|
||||
assert_square_attacked(&mut board, Square::G1, true, false);
|
||||
|
||||
assert_square_attacked(&mut board, Square::A3, true, true);
|
||||
assert_square_attacked(&mut board, Square::B3, true, false);
|
||||
assert_square_attacked(&mut board, Square::D3, true, true);
|
||||
assert_square_attacked(&mut board, Square::E3, true, false);
|
||||
assert_square_attacked(&mut board, Square::G3, true, false);
|
||||
|
||||
assert_square_attacked(&mut board, Square::A4, true, true);
|
||||
assert_square_attacked(&mut board, Square::C4, true, true);
|
||||
assert_square_attacked(&mut board, Square::D4, false, false);
|
||||
assert_square_attacked(&mut board, Square::F4, true, false);
|
||||
assert_square_attacked(&mut board, Square::G4, true, true);
|
||||
assert_square_attacked(&mut board, Square::H4, false, true);
|
||||
|
||||
assert_square_attacked(&mut board, Square::A5, false, false);
|
||||
assert_square_attacked(&mut board, Square::B5, true, true);
|
||||
assert_square_attacked(&mut board, Square::C5, false, true);
|
||||
assert_square_attacked(&mut board, Square::F5, true, true);
|
||||
assert_square_attacked(&mut board, Square::G5, true, false);
|
||||
assert_square_attacked(&mut board, Square::H5, true, true);
|
||||
|
||||
assert_square_attacked(&mut board, Square::C6, true, true);
|
||||
assert_square_attacked(&mut board, Square::D6, false, true);
|
||||
assert_square_attacked(&mut board, Square::H6, true, true);
|
||||
|
||||
assert_square_attacked(&mut board, Square::B7, false, true);
|
||||
assert_square_attacked(&mut board, Square::H7, false, true);
|
||||
|
||||
assert_square_attacked(&mut board, Square::B8, false, true);
|
||||
assert_square_attacked(&mut board, Square::C8, false, true);
|
||||
assert_square_attacked(&mut board, Square::D8, false, true);
|
||||
assert_square_attacked(&mut board, Square::F8, false, true);
|
||||
assert_square_attacked(&mut board, Square::G8, false, true);
|
||||
}
|
||||
|
|
@ -1,145 +0,0 @@
|
|||
use chess_engine::board::Board;
|
||||
use chess_engine::movegen::non_sliders::generate_king_moves;
|
||||
use chess_engine::r#move::MoveList;
|
||||
|
||||
/// Compares two move list strings ignoring the order of moves.
|
||||
fn assert_moves_equal(actual_str: &str, expected_str: &str) {
|
||||
let mut actual_moves: Vec<&str> = actual_str.split_whitespace().collect();
|
||||
let mut expected_moves: Vec<&str> = expected_str.split_whitespace().collect();
|
||||
|
||||
actual_moves.sort();
|
||||
expected_moves.sort();
|
||||
|
||||
assert_eq!(actual_moves, expected_moves);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_king_moves_start_pos_blocked() {
|
||||
let fen_standard = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
|
||||
let board = Board::from_fen(fen_standard);
|
||||
let mut list = MoveList::new();
|
||||
generate_king_moves(&board, &mut list);
|
||||
// King is completely blocked in the start position
|
||||
assert_moves_equal(&list.to_string(), "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_king_moves_center() {
|
||||
let fen = "8/8/8/8/4K3/8/8/8 w - - 0 1"; // King on e4
|
||||
let board = Board::from_fen(fen);
|
||||
let mut list = MoveList::new();
|
||||
generate_king_moves(&board, &mut list);
|
||||
// 8 moves from e4
|
||||
assert_moves_equal(&list.to_string(), "e4d3 e4d4 e4d5 e4e3 e4e5 e4f3 e4f4 e4f5");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_king_moves_corner() {
|
||||
let fen = "K7/8/8/8/8/8/8/8 w - - 0 1"; // King on a8
|
||||
let board = Board::from_fen(fen);
|
||||
let mut list = MoveList::new();
|
||||
generate_king_moves(&board, &mut list);
|
||||
// 3 moves from a8
|
||||
assert_moves_equal(&list.to_string(), "a8a7 a8b7 a8b8");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_king_moves_blocked_friendly() {
|
||||
// King on d4, surrounded by friendly pawns
|
||||
let fen = "8/8/8/3P1P2/3K4/3P1P2/8/8 w - - 0 1";
|
||||
let board = Board::from_fen(fen);
|
||||
let mut list = MoveList::new();
|
||||
generate_king_moves(&board, &mut list);
|
||||
// d3, d5, f3, f5 are blocked.
|
||||
// c3, c4, c5, e3, e4, e5 are free.
|
||||
assert_moves_equal(&list.to_string(), "d4c3 d4c4 d4c5 d4e3 d4e4 d4e5");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_king_moves_capture_and_blocked() {
|
||||
// King on d4
|
||||
// Friendly: c3, e5
|
||||
// Enemy: c5, e3
|
||||
let fen = "8/8/8/2p1P3/3K4/2P1p3/8/8 w - - 0 1";
|
||||
let board = Board::from_fen(fen);
|
||||
let mut list = MoveList::new();
|
||||
generate_king_moves(&board, &mut list);
|
||||
// Blocked: c3, e5
|
||||
// Captures: c5, e3
|
||||
// Empty: c4, d3, d5, e4, f3, f4, f5
|
||||
// Note: f3, f4, f5 are valid moves
|
||||
assert_moves_equal(&list.to_string(), "d4c4 d4d3 d4d5 d4e4 d4c5 d4e3");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_king_moves_black() {
|
||||
let fen = "8/8/8/8/4k3/8/8/8 b - - 0 1"; // Black king on e4
|
||||
let board = Board::from_fen(fen);
|
||||
let mut list = MoveList::new();
|
||||
generate_king_moves(&board, &mut list);
|
||||
// 8 moves from e4
|
||||
assert_moves_equal(&list.to_string(), "e4d3 e4d4 e4d5 e4e3 e4e5 e4f3 e4f4 e4f5");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_king_moves_castling_white_all() {
|
||||
// King on e1, rooks on a1, h1. All rights. No pieces between.
|
||||
let fen = "r3k2r/8/8/8/8/8/8/R3K2R w KQkq - 0 1";
|
||||
let board = Board::from_fen(fen);
|
||||
let mut list = MoveList::new();
|
||||
generate_king_moves(&board, &mut list);
|
||||
// 5 standard moves + 2 castling moves (e1g1, e1c1)
|
||||
assert_moves_equal(&list.to_string(), "e1d1 e1d2 e1e2 e1f1 e1f2 O-O O-O-O");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_king_moves_castling_black_all() {
|
||||
// King on e8, rooks on a8, h8. All rights. No pieces between.
|
||||
let fen = "r3k2r/8/8/8/8/8/8/R3K2R b KQkq - 0 1";
|
||||
let board = Board::from_fen(fen);
|
||||
let mut list = MoveList::new();
|
||||
generate_king_moves(&board, &mut list);
|
||||
// 5 standard moves + 2 castling moves (e8g8, e8c8)
|
||||
assert_moves_equal(&list.to_string(), "O-O O-O-O e8d8 e8e7 e8f8 e8d7 e8f7");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_king_moves_castling_blocked_pieces_white() {
|
||||
// White: Queenside blocked by knight
|
||||
let fen = "r3k2r/8/8/8/8/8/8/RN2K2R w KQkq - 0 1";
|
||||
let board = Board::from_fen(fen);
|
||||
let mut list = MoveList::new();
|
||||
generate_king_moves(&board, &mut list);
|
||||
// Should only get Kingside castling (e1g1) and standard moves
|
||||
assert_moves_equal(&list.to_string(), "e1d1 e1d2 e1e2 e1f1 e1f2 O-O");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_king_moves_castling_blocked_pieces_black() {
|
||||
// Black: Kingside blocked by bishop
|
||||
let fen = "r3kb1r/8/8/8/8/8/8/R3K2R b KQkq - 0 1";
|
||||
let board = Board::from_fen(fen);
|
||||
let mut list = MoveList::new();
|
||||
generate_king_moves(&board, &mut list);
|
||||
assert_moves_equal(&list.to_string(), "e8d8 e8d7 e8e7 e8f7 O-O-O");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_king_moves_castling_no_rights() {
|
||||
// Same as `test_king_moves_castling_white_all` but no castling rights
|
||||
let fen = "r3k2r/8/8/8/8/8/8/R3K2R w - - 0 1";
|
||||
let board = Board::from_fen(fen);
|
||||
let mut list = MoveList::new();
|
||||
generate_king_moves(&board, &mut list);
|
||||
// 5 standard moves, 0 castling
|
||||
assert_moves_equal(&list.to_string(), "e1d1 e1d2 e1e2 e1f1 e1f2");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_king_moves_empty_board() {
|
||||
let fen = "8/8/8/8/8/8/8/8 w - - 0 1";
|
||||
let board = Board::from_fen(fen);
|
||||
let mut list = MoveList::new();
|
||||
generate_king_moves(&board, &mut list);
|
||||
assert_moves_equal(&list.to_string(), "");
|
||||
}
|
||||
|
|
@ -1,96 +0,0 @@
|
|||
use chess_engine::board::Board;
|
||||
use chess_engine::movegen::non_sliders::generate_knight_moves;
|
||||
use chess_engine::r#move::MoveList;
|
||||
|
||||
/// Compares two move list strings ignoring the order of moves.
|
||||
fn assert_moves_equal(actual_str: &str, expected_str: &str) {
|
||||
let mut actual_moves: Vec<&str> = actual_str.split_whitespace().collect();
|
||||
let mut expected_moves: Vec<&str> = expected_str.split_whitespace().collect();
|
||||
|
||||
actual_moves.sort();
|
||||
expected_moves.sort();
|
||||
|
||||
assert_eq!(actual_moves, expected_moves);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_knight_move_generation() {
|
||||
let fen_standard = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
|
||||
let board = Board::from_fen(fen_standard);
|
||||
let mut list = MoveList::new();
|
||||
generate_knight_moves(&board, &mut list);
|
||||
assert_moves_equal(&list.to_string(), "b1a3 b1c3 g1f3 g1h3");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_knight_move_generation_black() {
|
||||
let fen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR b KQkq - 0 1";
|
||||
let board = Board::from_fen(fen);
|
||||
let mut list = MoveList::new();
|
||||
generate_knight_moves(&board, &mut list);
|
||||
assert_moves_equal(&list.to_string(), "b8a6 b8c6 g8f6 g8h6");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_knight_moves_center() {
|
||||
let fen = "8/8/8/3N4/8/8/8/8 w - - 0 1";
|
||||
let board = Board::from_fen(fen);
|
||||
let mut list = MoveList::new();
|
||||
generate_knight_moves(&board, &mut list);
|
||||
// 8 moves from d5
|
||||
assert_moves_equal(&list.to_string(), "d5b4 d5b6 d5c3 d5c7 d5e3 d5e7 d5f4 d5f6");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_knight_moves_capture() {
|
||||
// Black knight on e5, white pawn on d3
|
||||
let fen = "8/8/8/4n3/8/3P4/8/8 b - - 0 1";
|
||||
let board = Board::from_fen(fen);
|
||||
let mut list = MoveList::new();
|
||||
generate_knight_moves(&board, &mut list);
|
||||
// 8 moves, including capture on d3
|
||||
assert_moves_equal(&list.to_string(), "e5c4 e5c6 e5d3 e5d7 e5f3 e5f7 e5g4 e5g6");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_knight_moves_blocked_friendly() {
|
||||
// Knight on d4, some moves are blocked, some are not.
|
||||
let fen = "8/8/3P1P2/3P1P2/3N4/3P1P2/3P1P2/8 w - - 0 1";
|
||||
let board = Board::from_fen(fen);
|
||||
let mut list = MoveList::new();
|
||||
generate_knight_moves(&board, &mut list);
|
||||
// f3, f5, d3, d5, d6, f6 are blocked.
|
||||
// c2, e2, b3, b5, c6, e6 are free.
|
||||
assert_moves_equal(&list.to_string(), "d4c2 d4e2 d4b3 d4b5 d4c6 d4e6");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_knight_moves_corner() {
|
||||
let fen = "N7/8/8/8/8/8/8/8 w - - 0 1";
|
||||
let board = Board::from_fen(fen);
|
||||
let mut list = MoveList::new();
|
||||
generate_knight_moves(&board, &mut list);
|
||||
// 2 moves from a8
|
||||
assert_moves_equal(&list.to_string(), "a8b6 a8c7");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_knight_moves_capture_and_blocked() {
|
||||
// White knights on b1 and g1.
|
||||
// b1: a3 (friendly), c3 (friendly), d2 (enemy)
|
||||
// g1: f3 (empty), h3 (empty), e2 (empty)
|
||||
let fen = "8/8/8/8/8/P1P5/3p4/1N4NR w K - 0 1";
|
||||
let board = Board::from_fen(fen);
|
||||
let mut list = MoveList::new();
|
||||
generate_knight_moves(&board, &mut list);
|
||||
assert_moves_equal(&list.to_string(), "b1d2 g1e2 g1f3 g1h3");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_knight_moves_empty_board() {
|
||||
let fen = "8/8/8/8/8/8/8/8 w - - 0 1";
|
||||
let board = Board::from_fen(fen);
|
||||
let mut list = MoveList::new();
|
||||
generate_knight_moves(&board, &mut list);
|
||||
assert_moves_equal(&list.to_string(), "");
|
||||
}
|
||||
|
|
@ -1,108 +0,0 @@
|
|||
use chess_engine::board::Board;
|
||||
use chess_engine::movegen::generate_pseudo_legal_moves;
|
||||
use chess_engine::r#move::MoveList;
|
||||
|
||||
/// Helper function to run the make/undo integrity check for any given board state.
|
||||
/// This avoids code duplication in all the specific test cases.
|
||||
fn assert_make_undo_integrity(board: &mut Board) {
|
||||
let mut list = MoveList::new();
|
||||
generate_pseudo_legal_moves(&board, &mut list);
|
||||
|
||||
// If no moves are generated (e.g., stalemate/checkmate), the test passes.
|
||||
if list.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
for mv in list.iter() {
|
||||
let board_before_make = board.to_fen();
|
||||
let undo_obj = board.make_move(*mv);
|
||||
let board_after_make = board.to_fen();
|
||||
|
||||
// Ensure the board actually changed
|
||||
assert_ne!(
|
||||
board_before_make, board_after_make,
|
||||
"Board did not change after make_move for move: {:?}", mv
|
||||
);
|
||||
|
||||
board.undo_move(undo_obj);
|
||||
let board_after_undo = board.to_fen();
|
||||
|
||||
// Ensure the board is perfectly restored
|
||||
assert_eq!(
|
||||
board_before_make, board_after_undo,
|
||||
"Board state mismatch after undo_move for move: {:?}", mv
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_make_undo_standard() {
|
||||
let fen_standard = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
|
||||
let mut board = Board::from_fen(fen_standard);
|
||||
assert_make_undo_integrity(&mut board);
|
||||
}
|
||||
|
||||
#[test]
|
||||
/// Tests a complex, mid-game position with many interactions.
|
||||
/// This is the famous "Kiwipete" FEN used for perft testing.
|
||||
fn test_make_undo_kiwipete() {
|
||||
let fen = "r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1";
|
||||
let mut board = Board::from_fen(fen);
|
||||
assert_make_undo_integrity(&mut board);
|
||||
}
|
||||
|
||||
#[test]
|
||||
/// Tests the en passant capture for White (e.g., e5xd6).
|
||||
/// This ensures the black pawn on d5 is correctly removed and restored.
|
||||
fn test_make_undo_en_passant_white() {
|
||||
// Position after 1. e4 e6 2. e5 d5
|
||||
let fen = "rnbqkbnr/ppp1p1pp/8/3pPp2/8/8/PPP2PPP/RNBQKBNR w KQkq d6 0 3";
|
||||
let mut board = Board::from_fen(fen);
|
||||
assert_make_undo_integrity(&mut board);
|
||||
}
|
||||
|
||||
#[test]
|
||||
/// Tests the en passant capture for Black (e.g., d5xe6).
|
||||
/// This ensures the white pawn on e5 is correctly removed and restored.
|
||||
fn test_make_undo_en_passant_black() {
|
||||
// Position after 1. d4 c5 2. d5 e5
|
||||
let fen = "rnbqkbnr/pp1p1ppp/8/2pPp3/8/8/PPP1PPPP/RNBQKBNR b KQkq e6 0 3";
|
||||
let mut board = Board::from_fen(fen);
|
||||
assert_make_undo_integrity(&mut board);
|
||||
}
|
||||
|
||||
#[test]
|
||||
/// Tests White's kingside (O-O) and queenside (O-O-O) castling.
|
||||
/// Ensures both rook and king moves are correctly undone.
|
||||
fn test_make_undo_castling_white() {
|
||||
let fen = "r3k2r/pppppppp/8/8/8/8/PPPPPPPP/R3K2R w KQkq - 0 1";
|
||||
let mut board = Board::from_fen(fen);
|
||||
assert_make_undo_integrity(&mut board);
|
||||
}
|
||||
|
||||
#[test]
|
||||
/// Tests Black's kingside (O-O) and queenside (O-O-O) castling.
|
||||
/// Ensures both rook and king moves are correctly undone.
|
||||
fn test_make_undo_castling_black() {
|
||||
let fen = "r3k2r/pppppppp/8/8/8/8/PPPPPPPP/R3K2R b KQkq - 0 1";
|
||||
let mut board = Board::from_fen(fen);
|
||||
assert_make_undo_integrity(&mut board);
|
||||
}
|
||||
|
||||
#[test]
|
||||
/// Tests white pawn promotions (quiet and capture) to Q, R, B, N.
|
||||
fn test_make_undo_promotions_white() {
|
||||
// White pawn on c7, black rooks on b8 and d8 to test capture-promotions
|
||||
let fen = "1r1rkb1r/2Ppppb1/8/8/8/8/1PPPPPP1/RNBQKBNR w KQk - 0 1";
|
||||
let mut board = Board::from_fen(fen);
|
||||
assert_make_undo_integrity(&mut board);
|
||||
}
|
||||
|
||||
#[test]
|
||||
/// Tests black pawn promotions (quiet and capture) to q, r, b, n.
|
||||
fn test_make_undo_promotions_black() {
|
||||
// Black pawn on g2, white rooks on f1 and h1 to test capture-promotions
|
||||
let fen = "RNBQKBNR/1PPPPP2/8/8/8/8/6p1/R4RK1 b Qkq - 0 1";
|
||||
let mut board = Board::from_fen(fen);
|
||||
assert_make_undo_integrity(&mut board);
|
||||
}
|
||||
|
|
@ -1,92 +0,0 @@
|
|||
use chess_engine::r#move::*;
|
||||
use chess_engine::square::Square;
|
||||
|
||||
#[test]
|
||||
fn test_quiet_move_white_pawn() {
|
||||
// Test 1: Standard Quiet Move (White Pawn)
|
||||
// (from: E2, to: E4)
|
||||
// NOTE: This was MOVE_TYPE_FLAG_QUIET, but in the new system it's a specific flag.
|
||||
// The algebraic notation is the same, so we test with the new specific flag.
|
||||
let m_quiet = Move::new(Square::E2, Square::E4, MOVE_FLAG_QUIET);
|
||||
assert_eq!(m_quiet.to_algebraic(), "e2e4");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_quiet_move_black_knight() {
|
||||
// Test 2: Standard Quiet Move (Black Knight)
|
||||
// (from: B8, to: C6)
|
||||
let m_knight = Move::new(Square::B8, Square::C6, MOVE_FLAG_QUIET);
|
||||
assert_eq!(m_knight.to_algebraic(), "b8c6");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_en_passant_move() {
|
||||
// Test 3: En Passant Move (Notation is same as quiet move)
|
||||
// (from: E5, to: F6)
|
||||
let m_ep = Move::new(Square::E5, Square::F6, MOVE_FLAG_EN_PASSANT);
|
||||
assert_eq!(m_ep.to_algebraic(), "e5f6");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_promotion_to_queen() {
|
||||
// Test 4: Promotion to Queen (Push)
|
||||
// (from: E7, to: E8)
|
||||
let m_promo_q = Move::new(Square::E7, Square::E8, MOVE_FLAG_PROMO_Q);
|
||||
assert_eq!(m_promo_q.to_algebraic(), "e7e8q");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_promotion_to_rook() {
|
||||
// Test 5: Promotion to Rook (Push)
|
||||
// (from: A7, to: A8)
|
||||
let m_promo_r = Move::new(Square::A7, Square::A8, MOVE_FLAG_PROMO_R);
|
||||
assert_eq!(m_promo_r.to_algebraic(), "a7a8r");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_promotion_to_bishop() {
|
||||
// Test 6: Promotion to Bishop (Capture)
|
||||
// (from: G2, to: H1)
|
||||
let m_promo_b = Move::new(Square::G2, Square::H1, MOVE_FLAG_PROMO_B_CAP);
|
||||
assert_eq!(m_promo_b.to_algebraic(), "g2h1b");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_promotion_to_knight() {
|
||||
// Test 7: Promotion to Knight (Capture)
|
||||
// (from: G7, to: F8)
|
||||
let m_promo_n = Move::new(Square::G7, Square::F8, MOVE_FLAG_PROMO_N_CAP);
|
||||
assert_eq!(m_promo_n.to_algebraic(), "g7f8n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_white_kingside_castling() {
|
||||
// Test 8: White Kingside Castling
|
||||
// (from: E1, to: G1)
|
||||
let m_castle_wk = Move::new(Square::E1, Square::G1, MOVE_FLAG_WK_CASTLE);
|
||||
assert_eq!(m_castle_wk.to_algebraic(), "O-O");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_white_queenside_castling() {
|
||||
// Test 9: White Queenside Castling
|
||||
// (from: E1, to: C1)
|
||||
let m_castle_wq = Move::new(Square::E1, Square::C1, MOVE_FLAG_WQ_CASTLE);
|
||||
assert_eq!(m_castle_wq.to_algebraic(), "O-O-O");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_black_kingside_castling() {
|
||||
// Test 10: Black Kingside Castling
|
||||
// (from: E8, to: G8)
|
||||
let m_castle_bk = Move::new(Square::E8, Square::G8, MOVE_FLAG_BK_CASTLE);
|
||||
assert_eq!(m_castle_bk.to_algebraic(), "O-O");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_black_queenside_castling() {
|
||||
// Test 11: Black Queenside Castling
|
||||
// (from: E8, to: C8)
|
||||
let m_castle_bq = Move::new(Square::E8, Square::C8, MOVE_FLAG_BQ_CASTLE);
|
||||
assert_eq!(m_castle_bq.to_algebraic(), "O-O-O");
|
||||
}
|
||||
|
|
@ -1,142 +0,0 @@
|
|||
use chess_engine::board::Board;
|
||||
use chess_engine::movegen::pawns::generate_pawn_moves;
|
||||
use chess_engine::r#move::MoveList;
|
||||
|
||||
/// Compares two move list strings ignoring the order of moves.
|
||||
fn assert_moves_equal(actual_str: &str, expected_str: &str) {
|
||||
let mut actual_moves: Vec<&str> = actual_str.split_whitespace().collect();
|
||||
let mut expected_moves: Vec<&str> = expected_str.split_whitespace().collect();
|
||||
|
||||
actual_moves.sort();
|
||||
expected_moves.sort();
|
||||
|
||||
assert_eq!(actual_moves, expected_moves);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pawn_moves_start_pos() {
|
||||
let fen_standard = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
|
||||
let board = Board::from_fen(fen_standard);
|
||||
let mut list = MoveList::new();
|
||||
generate_pawn_moves(&board, &mut list);
|
||||
assert_moves_equal(&list.to_string(), "a2a3 a2a4 b2b3 b2b4 c2c3 c2c4 d2d3 d2d4 e2e3 e2e4 f2f3 f2f4 g2g3 g2g4 h2h3 h2h4");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pawn_moves_black_start_pos() {
|
||||
let fen_standard = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR b KQkq - 0 1";
|
||||
let board = Board::from_fen(fen_standard);
|
||||
let mut list = MoveList::new();
|
||||
generate_pawn_moves(&board, &mut list);
|
||||
assert_moves_equal(&list.to_string(), "a7a6 a7a5 b7b6 b7b5 c7c6 c7c5 d7d6 d7d5 e7e6 e7e5 f7f6 f7f5 g7g6 g7g5 h7h6 h7h5");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pawn_moves_black_blocked_and_captures() {
|
||||
// Black pawns on a7, c7, e7, g7. White pawns on b6, d6, f6.
|
||||
let fen = "8/p1p1p1p1/1P1P1P2/8/8/8/8/8 b - - 0 1";
|
||||
let board = Board::from_fen(fen);
|
||||
let mut list = MoveList::new();
|
||||
generate_pawn_moves(&board, &mut list);
|
||||
assert_moves_equal(&list.to_string(), "a7a6 a7a5 a7b6 c7c6 c7c5 c7b6 c7d6 e7e6 e7e5 e7d6 e7f6 g7g6 g7g5 g7f6");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pawn_moves_black_side_captures() {
|
||||
// Test captures on A and H files (no wrap-around)
|
||||
let fen = "8/8/8/8/8/1p4p1/P6P/8 b - - 0 1";
|
||||
let board = Board::from_fen(fen);
|
||||
let mut list = MoveList::new();
|
||||
generate_pawn_moves(&board, &mut list);
|
||||
assert_moves_equal(&list.to_string(), "b3b2 b3a2 g3g2 g3h2");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pawn_moves_white_side_captures() {
|
||||
// Test captures on A and H files (no wrap-around)
|
||||
let fen = "8/p6p/1P4P1/8/8/8/8/8 w - - 0 1";
|
||||
let board = Board::from_fen(fen);
|
||||
let mut list = MoveList::new();
|
||||
generate_pawn_moves(&board, &mut list);
|
||||
assert_moves_equal(&list.to_string(), "b6b7 b6a7 g6g7 g6h7");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pawn_moves_black_en_passant() {
|
||||
// White just moved e2e4, en passant target is e3. Black pawn on d4.
|
||||
let fen = "rnbqkbnr/ppp1pppp/8/8/3pP3/8/PPP2PPP/RNBQKBNR b KQkq e3 0 1";
|
||||
let board = Board::from_fen(fen);
|
||||
let mut list = MoveList::new();
|
||||
generate_pawn_moves(&board, &mut list);
|
||||
assert_moves_equal(&list.to_string(), "a7a6 a7a5 b7b6 b7b5 c7c6 c7c5 d4d3 d4e3 e7e6 e7e5 f7f6 f7f5 g7g6 g7g5 h7h6 h7h5");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pawn_moves_white_en_passant() {
|
||||
// Black just moved d7d5, en passant target is d6. White pawn on e5.
|
||||
let fen = "rnbqkbnr/ppp1pppp/8/3pP3/8/8/PPPP1PPP/RNBQKBNR w KQkq d6 0 1";
|
||||
let board = Board::from_fen(fen);
|
||||
let mut list = MoveList::new();
|
||||
generate_pawn_moves(&board, &mut list);
|
||||
assert_moves_equal(&list.to_string(), "a2a3 a2a4 b2b3 b2b4 c2c3 c2c4 d2d3 d2d4 e5e6 e5d6 f2f3 f2f4 g2g3 g2g4 h2h3 h2h4");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pawn_moves_black_promotion() {
|
||||
let fen = "8/8/8/8/8/8/p1p1p1p1/8 b - - 0 1";
|
||||
let board = Board::from_fen(fen);
|
||||
let mut list = MoveList::new();
|
||||
generate_pawn_moves(&board, &mut list);
|
||||
assert_moves_equal(&list.to_string(),
|
||||
"a2a1q a2a1r a2a1b a2a1n c2c1q c2c1r c2c1b c2c1n e2e1q e2e1r e2e1b e2e1n g2g1q g2g1r g2g1b g2g1n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pawn_moves_white_promotion() {
|
||||
let fen = "8/P1P1P1P1/8/8/8/8/8/8 w - - 0 1";
|
||||
let board = Board::from_fen(fen);
|
||||
let mut list = MoveList::new();
|
||||
generate_pawn_moves(&board, &mut list);
|
||||
assert_moves_equal(&list.to_string(),
|
||||
"a7a8q a7a8r a7a8b a7a8n c7c8q c7c8r c7c8b c7c8n e7e8q e7e8r e7e8b e7e8n g7g8q g7g8r g7g8b g7g8n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pawn_moves_black_promotion_capture() {
|
||||
// Black pawn on b2. White rooks on a1 and c1.
|
||||
let fen = "8/8/8/8/8/8/1p6/R1R5 b - - 0 1";
|
||||
let board = Board::from_fen(fen);
|
||||
let mut list = MoveList::new();
|
||||
generate_pawn_moves(&board, &mut list);
|
||||
assert_moves_equal(&list.to_string(),
|
||||
"b2b1q b2b1r b2b1b b2b1n b2a1q b2a1r b2a1b b2a1n b2c1q b2c1r b2c1b b2c1n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pawn_moves_white_promotion_capture() {
|
||||
// White pawn on a7. Black rooks on b8 and d8.
|
||||
let fen = "1r1r4/P7/8/8/8/8/8/8 w - - 0 1";
|
||||
let board = Board::from_fen(fen);
|
||||
let mut list = MoveList::new();
|
||||
generate_pawn_moves(&board, &mut list);
|
||||
assert_moves_equal(&list.to_string(),
|
||||
"a7a8q a7a8r a7a8b a7a8n a7b8q a7b8r a7b8b a7b8n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pawn_moves_black_midgame_random() {
|
||||
let fen = "r1bqkb1r/1p2pppp/p1n2n2/3p4/2BNP3/2N5/PPP2PPP/R1BQK2R b KQkq - 1 6";
|
||||
let board = Board::from_fen(fen);
|
||||
let mut list = MoveList::new();
|
||||
generate_pawn_moves(&board, &mut list);
|
||||
assert_moves_equal(&list.to_string(), "a6a5 b7b6 b7b5 d5c4 d5e4 e7e6 e7e5 g7g6 g7g5 h7h6 h7h5");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pawn_moves_white_midgame_random() {
|
||||
let fen = "r1bqk2r/2ppbppp/p1n2n2/1p2p3/B1P1P3/5N2/PP1P1PPP/RNBQR1K1 w kq - 0 7";
|
||||
let board = Board::from_fen(fen);
|
||||
let mut list = MoveList::new();
|
||||
generate_pawn_moves(&board, &mut list);
|
||||
assert_moves_equal(&list.to_string(), "a2a3 b2b3 b2b4 c4c5 c4b5 d2d3 d2d4 g2g3 g2g4 h2h3 h2h4");
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
use chess_engine::board::Board;
|
||||
use chess_engine::movegen::generate_pseudo_legal_moves;
|
||||
use chess_engine::movegen::legal_check::is_king_attacked;
|
||||
use chess_engine::movegen::legal_check::is_other_king_attacked;
|
||||
use chess_engine::r#move::MoveList;
|
||||
|
||||
fn count_legal_moves_recursive(board: &mut Board, depth: u8) -> u64 {
|
||||
|
|
@ -16,7 +16,7 @@ fn count_legal_moves_recursive(board: &mut Board, depth: u8) -> u64 {
|
|||
// Store the undo info when making the move
|
||||
let undo_info = board.make_move(*mv);
|
||||
|
||||
if !is_king_attacked(board) {
|
||||
if !is_other_king_attacked(board) {
|
||||
leaf_nodes += count_legal_moves_recursive(board, depth - 1);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,93 +0,0 @@
|
|||
use chess_engine::board::Board;
|
||||
use chess_engine::movegen::sliders::generate_queen_moves;
|
||||
use chess_engine::r#move::MoveList;
|
||||
|
||||
/// Compares two move list strings ignoring the order of moves.
|
||||
fn assert_moves_equal(actual_str: &str, expected_str: &str) {
|
||||
let mut actual_moves: Vec<&str> = actual_str.split_whitespace().collect();
|
||||
let mut expected_moves: Vec<&str> = expected_str.split_whitespace().collect();
|
||||
|
||||
actual_moves.sort();
|
||||
expected_moves.sort();
|
||||
|
||||
assert_eq!(actual_moves, expected_moves);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_queen_moves_single_rook() {
|
||||
let fen_standard = "8/1Q2p3/8/8/8/8/6p1/8 w - - 0 1";
|
||||
let board = Board::from_fen(fen_standard);
|
||||
let mut list = MoveList::new();
|
||||
generate_queen_moves(&board, &mut list);
|
||||
assert_moves_equal(&list.to_string(), "b7a8 b7a7 b7a6 b7b8 b7b6 b7b5 b7b4 b7b3 b7b2 b7b1 b7c8 b7c7 b7c6 b7d7 b7e7 b7d5 b7e4 b7f3 b7g2");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_queen_center_open() {
|
||||
// Queen in the center, open board, should generate 27 moves
|
||||
let fen = "4k3/8/8/8/3Q4/8/8/4K3 w - - 0 1";
|
||||
let board = Board::from_fen(fen);
|
||||
let mut list = MoveList::new();
|
||||
generate_queen_moves(&board, &mut list);
|
||||
let expected = "d4a1 d4b2 d4c3 d4e5 d4f6 d4g7 d4h8 \
|
||||
d4a4 d4b4 d4c4 d4e4 d4f4 d4g4 d4h4 \
|
||||
d4d1 d4d2 d4d3 d4d5 d4d6 d4d7 d4d8 \
|
||||
d4a7 d4b6 d4c5 d4e3 d4f2 d4g1";
|
||||
assert_moves_equal(&list.to_string(), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_queen_corner_blocked_friendly() {
|
||||
// Queen in corner, completely blocked by friendly pieces
|
||||
let fen = "rnbqkbnr/pppppppp/8/8/8/8/PP1PP1PP/QNBQKBNR w Kkq - 0 1";
|
||||
let board = Board::from_fen(fen);
|
||||
let mut list = MoveList::new();
|
||||
generate_queen_moves(&board, &mut list);
|
||||
assert_moves_equal(&list.to_string(), "d1a4 d1b3 d1c2");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_queen_multiple_captures_black() {
|
||||
// Black queen on h8, with multiple white pieces to capture
|
||||
let fen = "q3k3/P1P1P1P1/8/8/8/P1P1P1P1/8/4K3 b - - 0 1";
|
||||
let board = Board::from_fen(fen);
|
||||
let mut list = MoveList::new();
|
||||
generate_queen_moves(&board, &mut list);
|
||||
let expected = "a8b8 a8c8 a8d8 a8a7 a8b7 a8c6 a8d5 a8e4 a8f3 a8g2 a8h1";
|
||||
assert_moves_equal(&list.to_string(), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_multiple_queens() {
|
||||
let fen = "4k3/8/8/8/8/8/8/Q3K2Q w - - 0 1";
|
||||
let board = Board::from_fen(fen);
|
||||
let mut list = MoveList::new();
|
||||
generate_queen_moves(&board, &mut list);
|
||||
let expected = "a1a2 a1a3 a1a4 a1a5 a1a6 a1a7 a1a8 a1b1 a1c1 a1d1 a1b2 a1c3 a1d4 a1e5 a1f6 a1g7 a1h8 \
|
||||
h1h2 h1h3 h1h4 h1h5 h1h6 h1h7 h1h8 h1g1 h1f1 h1g2 h1f3 h1e4 h1d5 h1c6 h1b7 h1a8";
|
||||
assert_moves_equal(&list.to_string(), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_queen_rook_only() {
|
||||
// Queen on d4, bishop moves blocked by friendly pawns
|
||||
let fen = "4k3/8/8/2P1P3/3Q4/2P1P3/8/4K3 w - - 0 1";
|
||||
let board = Board::from_fen(fen);
|
||||
let mut list = MoveList::new();
|
||||
generate_queen_moves(&board, &mut list);
|
||||
let expected = "d4a4 d4b4 d4c4 d4e4 d4f4 d4g4 d4h4 \
|
||||
d4d1 d4d2 d4d3 d4d5 d4d6 d4d7 d4d8";
|
||||
assert_moves_equal(&list.to_string(), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_queen_bishop_only() {
|
||||
// Queen on d4, rook moves blocked by friendly pawns
|
||||
let fen = "4k3/8/8/3P4/2PQP3/3P4/8/4K3 w - - 0 1";
|
||||
let board = Board::from_fen(fen);
|
||||
let mut list = MoveList::new();
|
||||
generate_queen_moves(&board, &mut list);
|
||||
let expected = "d4a1 d4b2 d4c3 d4e5 d4f6 d4g7 d4h8 \
|
||||
d4a7 d4b6 d4c5 d4e3 d4f2 d4g1";
|
||||
assert_moves_equal(&list.to_string(), expected);
|
||||
}
|
||||
|
|
@ -1,101 +0,0 @@
|
|||
use chess_engine::board::Board;
|
||||
use chess_engine::movegen::sliders::generate_rook_moves;
|
||||
use chess_engine::r#move::MoveList;
|
||||
|
||||
/// Compares two move list strings ignoring the order of moves.
|
||||
fn assert_moves_equal(actual_str: &str, expected_str: &str) {
|
||||
let mut actual_moves: Vec<&str> = actual_str.split_whitespace().collect();
|
||||
let mut expected_moves: Vec<&str> = expected_str.split_whitespace().collect();
|
||||
|
||||
actual_moves.sort();
|
||||
expected_moves.sort();
|
||||
|
||||
assert_eq!(actual_moves, expected_moves);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rook_moves_single_rook() {
|
||||
let fen_standard = "8/8/8/2b5/2Rb4/2b5/8/8 w - - 0 1";
|
||||
let board = Board::from_fen(fen_standard);
|
||||
let mut list = MoveList::new();
|
||||
generate_rook_moves(&board, &mut list);
|
||||
// This FEN has a White Rook at c4, and Black Bishops at c5, d4, and c3.
|
||||
// It should be able to capture all three and move left to a4/b4.
|
||||
assert_moves_equal(&list.to_string(), "c4a4 c4b4 c4c3 c4c5 c4d4");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rook_moves_empty_board() {
|
||||
let fen = "8/8/8/8/3R4/8/8/8 w - - 0 1";
|
||||
let board = Board::from_fen(fen);
|
||||
let mut list = MoveList::new();
|
||||
generate_rook_moves(&board, &mut list);
|
||||
let expected = "d4d1 d4d2 d4d3 d4d5 d4d6 d4d7 d4d8 d4a4 d4b4 d4c4 d4e4 d4f4 d4g4 d4h4";
|
||||
assert_moves_equal(&list.to_string(), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rook_moves_corner_blocked_black() {
|
||||
let fen = "r6k/1p6/8/8/8/8/8/K7 b - - 0 1";
|
||||
let board = Board::from_fen(fen);
|
||||
let mut list = MoveList::new();
|
||||
generate_rook_moves(&board, &mut list);
|
||||
// Black rook at a8. Friendly king at h8, friendly pawn at b7.
|
||||
// Rook can move down the a-file and right along the 8th rank, stopping before h8.
|
||||
let expected = "a8a7 a8a6 a8a5 a8a4 a8a3 a8a2 a8a1 a8b8 a8c8 a8d8 a8e8 a8f8 a8g8";
|
||||
assert_moves_equal(&list.to_string(), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rook_moves_double_rooks_friendly_block() {
|
||||
let fen = "8/8/8/8/R3R3/8/8/8 w - - 0 1";
|
||||
let board = Board::from_fen(fen);
|
||||
let mut list = MoveList::new();
|
||||
generate_rook_moves(&board, &mut list);
|
||||
// Rooks at a4 and e4. They block each other horizontally.
|
||||
// Rook a4 moves a1-a8 and b4, c4, d4.
|
||||
// Rook e4 moves e1-e8, f4, g4, h4 AND d4, c4, b4.
|
||||
let expected = "a4a1 a4a2 a4a3 a4a5 a4a6 a4a7 a4a8 a4b4 a4c4 a4d4 \
|
||||
e4e1 e4e2 e4e3 e4e5 e4e6 e4e7 e4e8 e4f4 e4g4 e4h4 \
|
||||
e4d4 e4c4 e4b4";
|
||||
assert_moves_equal(&list.to_string(), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rook_moves_capture_stops_movegen() {
|
||||
let fen = "r7/P7/8/8/8/8/8/8 b - - 0 1";
|
||||
let board = Board::from_fen(fen);
|
||||
let mut list = MoveList::new();
|
||||
generate_rook_moves(&board, &mut list);
|
||||
// Black rook at a8, White pawn at a7.
|
||||
// The rook can capture at a7, but cannot move past it.
|
||||
// It can still move horizontally.
|
||||
let expected = "a8a7 a8b8 a8c8 a8d8 a8e8 a8f8 a8g8 a8h8";
|
||||
assert_moves_equal(&list.to_string(), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rook_moves_completely_blocked_friendly() {
|
||||
let fen = "8/8/8/1P6/PRP5/1P6/8/8 w - - 0 1";
|
||||
let board = Board::from_fen(fen);
|
||||
let mut list = MoveList::new();
|
||||
generate_rook_moves(&board, &mut list);
|
||||
// White rook at b4.
|
||||
// Blocked by P(b5), P(b3), P(a4), P(c4).
|
||||
// Should have 0 moves.
|
||||
assert_moves_equal(&list.to_string(), "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rook_moves_ignores_absolute_pin() {
|
||||
let fen = "r3k3/8/8/8/R3K3/8/8/8 w - - 0 1";
|
||||
let board = Board::from_fen(fen);
|
||||
let mut list = MoveList::new();
|
||||
generate_rook_moves(&board, &mut list);
|
||||
// White rook at a4 is absolutely pinned to King at e4 by Black rook at a8.
|
||||
// A pseudo-legal generator should *ignore* the pin.
|
||||
// It should generate vertical moves (including capture at a8)
|
||||
// and horizontal moves (stopping before the friendly King at e4).
|
||||
let expected = "a4a1 a4a2 a4a3 a4a5 a4a6 a4a7 a4a8 a4b4 a4c4 a4d4";
|
||||
assert_moves_equal(&list.to_string(), expected);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue