// Eryn Wells //! 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::{ assert_move_list, assert_move_list_contains, assert_move_list_does_not_contain, ply, Move, }; 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 = 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.active_color_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.active_color_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.active_color_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.)]); }