Reinitialize repository and add working move generation for all pieces
This commit is contained in:
commit
951a8bbec6
28 changed files with 3373 additions and 0 deletions
85
tests/bishop_move_generation.rs
Normal file
85
tests/bishop_move_generation.rs
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
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);
|
||||
}
|
||||
76
tests/board_to_fen_conversion.rs
Normal file
76
tests/board_to_fen_conversion.rs
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
use chess_engine::board::*;
|
||||
|
||||
#[test]
|
||||
fn test_fen_roundtrip_standard() {
|
||||
let fen_standard = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
|
||||
assert_eq!(Board::from_fen(fen_standard).to_fen(), fen_standard);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fen_roundtrip_kiwipete() {
|
||||
let fen_kiwipete = "r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1";
|
||||
assert_eq!(Board::from_fen(fen_kiwipete).to_fen(), fen_kiwipete);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fen_roundtrip_en_passant() {
|
||||
let fen_en_passant = "rnbqkbnr/pppppp1p/8/8/p7/4P3/PPPP1PPP/RNBQKBNR w KQkq e3 0 1";
|
||||
assert_eq!(Board::from_fen(fen_en_passant).to_fen(), fen_en_passant);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fen_roundtrip_castle() {
|
||||
let fen_castle = "r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/q4N2/Pp1P2PP/R2QK2R b - - 0 1";
|
||||
assert_eq!(Board::from_fen(fen_castle).to_fen(), fen_castle);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fen_roundtrip_just_kings() {
|
||||
let fen_just_kings = "8/k7/8/8/8/8/7K/8 w - - 0 1";
|
||||
assert_eq!(Board::from_fen(fen_just_kings).to_fen(), fen_just_kings);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fen_roundtrip_high_move_values() {
|
||||
let fen_high_move_values = "8/P1k5/K7/8/8/8/8/8 w - - 0 78";
|
||||
assert_eq!(Board::from_fen(fen_high_move_values).to_fen(), fen_high_move_values);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fen_roundtrip_empty_count1() {
|
||||
let fen_empty_count1 = "1n6/8/8/8/8/8/8/8 w - - 0 1";
|
||||
assert_eq!(Board::from_fen(fen_empty_count1).to_fen(), fen_empty_count1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fen_roundtrip_empty_count2() {
|
||||
let fen_empty_count2 = "6n1/8/8/8/8/8/8/8 w - - 0 1";
|
||||
assert_eq!(Board::from_fen(fen_empty_count2).to_fen(), fen_empty_count2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_board_fen_state() {
|
||||
let fen_standard = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
|
||||
let board = Board::from_fen(fen_standard);
|
||||
assert_eq!(board.pieces[PieceType::Pawn as usize][Color::White as usize], 65280);
|
||||
assert_eq!(board.pieces[PieceType::Pawn as usize][Color::Black as usize], 71776119061217280);
|
||||
assert_eq!(board.pieces[PieceType::Knight as usize][Color::White as usize], 66);
|
||||
assert_eq!(board.pieces[PieceType::Knight as usize][Color::Black as usize], 4755801206503243776);
|
||||
assert_eq!(board.pieces[PieceType::Bishop as usize][Color::White as usize], 36);
|
||||
assert_eq!(board.pieces[PieceType::Bishop as usize][Color::Black as usize], 2594073385365405696);
|
||||
assert_eq!(board.pieces[PieceType::Rook as usize][Color::White as usize], 129);
|
||||
assert_eq!(board.pieces[PieceType::Rook as usize][Color::Black as usize], 9295429630892703744);
|
||||
assert_eq!(board.pieces[PieceType::Queen as usize][Color::White as usize], 8);
|
||||
assert_eq!(board.pieces[PieceType::Queen as usize][Color::Black as usize], 576460752303423488);
|
||||
assert_eq!(board.pieces[PieceType::King as usize][Color::White as usize], 16);
|
||||
assert_eq!(board.pieces[PieceType::King as usize][Color::Black as usize], 1152921504606846976);
|
||||
|
||||
assert_eq!(board.occupied[0], 65535);
|
||||
assert_eq!(board.occupied[1], 18446462598732840960);
|
||||
assert_eq!(board.all_occupied, 18446462598732906495);
|
||||
|
||||
assert_eq!(board.castling_rights, 15);
|
||||
assert_eq!(board.en_passant_target, None);
|
||||
assert_eq!(board.halfmove_clock, 0);
|
||||
assert_eq!(board.fullmove_number, 1);
|
||||
}
|
||||
145
tests/king_move_generation.rs
Normal file
145
tests/king_move_generation.rs
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
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(), "");
|
||||
}
|
||||
96
tests/knight_move_generation.rs
Normal file
96
tests/knight_move_generation.rs
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
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(), "");
|
||||
}
|
||||
92
tests/move_to_algebraic_conversion.rs
Normal file
92
tests/move_to_algebraic_conversion.rs
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
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_CAP_B);
|
||||
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_CAP_N);
|
||||
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");
|
||||
}
|
||||
142
tests/pawn_move_generation.rs
Normal file
142
tests/pawn_move_generation.rs
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
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");
|
||||
}
|
||||
12
tests/perft.rs
Normal file
12
tests/perft.rs
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
use chess_engine::board::Board;
|
||||
use chess_engine::movegen::generate_pseudo_legal_moves;
|
||||
use chess_engine::r#move::MoveList;
|
||||
|
||||
|
||||
// "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1" 7 3195901860 "false"
|
||||
// "r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq -" 5 193690690 "false"
|
||||
// "8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - -" 7 178633661 "false"
|
||||
// "r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/q4N2/Pp1P2PP/R2Q1RK1 w kq - 0 1" 6 706045033 "false"
|
||||
// "rnbq1k1r/pp1Pbppp/2p5/8/2B5/8/PPP1NnPP/RNBQK2R w KQ - 1 8" 5 89941194 "false"
|
||||
// "r4rk1/1pp1qppp/p1np1n2/2b1p1B1/2B1P1b1/P1NP1N2/1PP1QPPP/R4RK1 w - - 0 10" 5 164075551 "false"
|
||||
// "r7/4p3/5p1q/3P4/4pQ2/4pP2/6pp/R3K1kr w Q - 1 3" 5 11609488 "false"
|
||||
93
tests/queen_move_generation.rs
Normal file
93
tests/queen_move_generation.rs
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
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);
|
||||
}
|
||||
101
tests/rook_move_generation.rs
Normal file
101
tests/rook_move_generation.rs
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
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