chessfriend/position/tests/peterellisjones.rs
Eryn Wells e3d17219ad [board, position] Simplify check methods
Only one check-testing method, Board::is_in_check(), that tests if the current
active player is in check. It doesn't make sense to test if the non-active player
is in check.
2025-06-29 09:25:08 -07:00

166 lines
4.1 KiB
Rust

// Eryn Wells <eryn@erynwells.me>
//! Move generator tests based on board positions described in [Peter Ellis
//! Jones][1]' excellent [blog post][2] on generated legal chess moves.
//!
//! [1]: https://peterellisjones.com
//! [2]: https://peterellisjones.com/posts/generating-legal-chess-moves-efficiently/
use chessfriend_core::Color;
use chessfriend_moves::{
Move, assert_move_list, assert_move_list_contains, assert_move_list_does_not_contain, ply,
};
use chessfriend_position::test_position;
use std::collections::HashSet;
#[test]
fn pseudo_legal_move_generation() {
let pos = test_position!(Black, [
Black King on E8,
White King on E1,
White Rook on F5,
]);
let king_moves: HashSet<_> = pos.all_legal_moves(Some(Color::Black)).collect();
assert_move_list_does_not_contain!(king_moves, [ply!(E8 - F8), ply!(E8 - F7)]);
}
#[test]
fn gotcha_king_moves_away_from_checking_slider() {
let position = test_position!(Black, [
Black King on E7,
White King on E1,
White Rook on E4,
]);
let king_moves: HashSet<Move> = position.all_legal_moves(None).map(Move::from).collect();
assert_move_list_does_not_contain!(king_moves, [ply!(E7 - E8)]);
}
#[test]
fn check_evasions_1() {
let pos = test_position!(Black, [
Black King on E8,
White King on E1,
White Knight on F6,
]);
let generated_moves = pos.all_legal_moves(Some(Color::Black));
assert_move_list!(
generated_moves,
[ply!(E8 - D8), ply!(E8 - E7), ply!(E8 - F7), ply!(E8 - F8),]
);
}
#[test]
fn check_evasions_double_check() {
let pos = test_position!(Black, [
Black King on E8,
Black Bishop on F6,
White King on E1,
White Knight on G7,
White Rook on E5,
]);
let generated_moves = pos.all_legal_moves(Some(Color::Black));
assert_move_list!(
generated_moves,
[ply!(E8 - D8), ply!(E8 - D7), ply!(E8 - F7), ply!(E8 - F8),]
);
}
#[test]
fn single_check_with_blocker() {
let pos = test_position!(Black, [
Black King on E8,
Black Knight on G6,
White King on E1,
White Rook on E5,
]);
let generated_moves = pos.all_legal_moves(Some(Color::Black));
assert_move_list!(
generated_moves,
[
// King moves
ply!(E8 - D8),
ply!(E8 - D7),
ply!(E8 - F7),
ply!(E8 - F8),
// Knight moves
ply!(G6 - E7),
ply!(G6 x E5),
]
);
}
#[test]
fn en_passant_check_capture() {
let pos = test_position!(Black, [
Black King on C5,
Black Pawn on E4,
White Pawn on D4,
], D3);
assert!(pos.board().is_in_check());
let generated_moves: HashSet<_> = pos.all_legal_moves(Some(Color::Black)).collect();
assert_move_list_contains!(generated_moves, [ply!(E4 x D3 e.p.)]);
}
#[test]
fn en_passant_check_block() {
let pos = test_position!(Black, [
Black King on B5,
Black Pawn on E4,
White Pawn on D4,
White Queen on F1,
], D3);
assert!(pos.board().is_in_check());
let generated_moves: HashSet<_> = pos.all_legal_moves(Some(Color::Black)).collect();
assert_move_list_contains!(generated_moves, [ply!(E4 x D3 e.p.)]);
}
#[test]
fn pinned_pieces_rook_cannot_move_out_of_pin() {
let pos = test_position!(Black, [
Black King on E8,
Black Rook on E6,
White Queen on E3,
White King on C1,
]);
assert!(!pos.board().is_in_check());
let rook_moves: HashSet<_> = pos.all_legal_moves(None).collect();
assert_move_list_does_not_contain!(rook_moves, [ply!(E6 - D6), ply!(E6 - F6)]);
assert_move_list_contains!(
rook_moves,
[ply!(E6 x E3), ply!(E6 - E4), ply!(E6 - E5), ply!(E6 - E7)]
);
}
#[test]
fn en_passant_discovered_check() {
let pos = test_position!(Black, [
Black King on A4,
Black Pawn on E4,
White Pawn on D4,
White Queen on H4,
], D3);
let generated_moves: HashSet<_> = pos.all_legal_moves(Some(Color::Black)).collect();
assert_move_list_does_not_contain!(generated_moves, [ply!(E4 x D3 e.p.)]);
}