From af2178abadd478ba4049b12ab94f8f1c4934534c Mon Sep 17 00:00:00 2001 From: Moritz Date: Fri, 14 Nov 2025 22:30:42 +0100 Subject: [PATCH] fixed perft --- helper_scripts/test | 22 +++++++++++ src/main.rs | 84 +----------------------------------------- src/movegen/pawns.rs | 8 ++-- tests/perft.rs | 87 +++++++++++++++++++++++++++++++++++++++----- 4 files changed, 105 insertions(+), 96 deletions(-) create mode 100644 helper_scripts/test diff --git a/helper_scripts/test b/helper_scripts/test new file mode 100644 index 0000000..312a7ff --- /dev/null +++ b/helper_scripts/test @@ -0,0 +1,22 @@ +a2a3 380 +b2b3 420 +c2c3 420 +d2d3 539 +e2e3 599 +f2f3 380 +g2g3 420 +h2h3 380 +a2a4 420 +b2b4 421 +c2c4 441 +d2d4 560 +e2e4 600 +f2f4 401 +g2g4 421 +h2h4 420 +b1a3 400 +b1c3 440 +g1f3 440 +g1h3 400 + +Total8902 \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 4b118bd..e4ecfb3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,88 +4,6 @@ use chess_engine::movegen::legal_check::is_king_attacked; use chess_engine::r#move::*; -fn count_legal_moves_recursive(board: &mut Board, depth: u8) -> u64 { - if depth == 0 { - return 1_u64; - } - - let mut list = MoveList::new(); - generate_pseudo_legal_moves(&board, &mut list); - - let mut leaf_nodes = 0_u64; - for mv in list.iter() { - let undo_info = board.make_move(*mv); - if !is_king_attacked(board) { - leaf_nodes += count_legal_moves_recursive(board, depth - 1); - } - board.undo_move(undo_info); - } - leaf_nodes -} - -fn perft() { - // TalkChess PERFT Tests (by Martin Sedlak) - //--Illegal ep move #1 - let mut board = Board::from_fen("3k4/3p4/8/K1P4r/8/8/8/8 b - - 0 1"); - assert_eq!(count_legal_moves_recursive(&mut board, 6), 1134888); - - //--Illegal ep move #2 - let mut board = Board::from_fen("8/8/4k3/8/2p5/8/B2P2K1/8 w - - 0 1"); - assert_eq!(count_legal_moves_recursive(&mut board, 6), 1015133); - - //--EP Capture Checks Opponent - let mut board = Board::from_fen("8/8/1k6/2b5/2pP4/8/5K2/8 b - d3 0 1"); - assert_eq!(count_legal_moves_recursive(&mut board, 6), 1440467); - - //--Short Castling Gives Check - let mut board = Board::from_fen("5k2/8/8/8/8/8/8/4K2R w K - 0 1"); - assert_eq!(count_legal_moves_recursive(&mut board, 6), 661072); - - //--Long Castling Gives Check - let mut board = Board::from_fen("3k4/8/8/8/8/8/8/R3K3 w Q - 0 1"); - assert_eq!(count_legal_moves_recursive(&mut board, 6), 803711); - - //--Castle Rights - let mut board = Board::from_fen("r3k2r/1b4bq/8/8/8/8/7B/R3K2R w KQkq - 0 1"); - assert_eq!(count_legal_moves_recursive(&mut board, 4), 1274206); - - //--Castling Prevented - let mut board = Board::from_fen("r3k2r/8/3Q4/8/8/5q2/8/R3K2R b KQkq - 0 1"); - assert_eq!(count_legal_moves_recursive(&mut board, 4), 1720476); - - //--Promote out of Check - let mut board = Board::from_fen("2K2r2/4P3/8/8/8/8/8/3k4 w - - 0 1"); - assert_eq!(count_legal_moves_recursive(&mut board, 6), 3821001); - - //--Discovered Check - let mut board = Board::from_fen("8/8/1P2K3/8/2n5/1q6/8/5k2 b - - 0 1"); - assert_eq!(count_legal_moves_recursive(&mut board, 5), 1004658); - - //--Promote to give check - let mut board = Board::from_fen("4k3/1P6/8/8/8/8/K7/8 w - - 0 1"); - assert_eq!(count_legal_moves_recursive(&mut board, 6), 217342); - - //--Under Promote to give check - let mut board = Board::from_fen("8/P1k5/K7/8/8/8/8/8 w - - 0 1"); - assert_eq!(count_legal_moves_recursive(&mut board, 6), 92683); - - //--Self Stalemate - let mut board = Board::from_fen("K1k5/8/P7/8/8/8/8/8 w - - 0 1"); - assert_eq!(count_legal_moves_recursive(&mut board, 6), 2217); - - //--Stalemate & Checkmate - let mut board = Board::from_fen("8/k1P5/8/1K6/8/8/8/8 w - - 0 1"); - assert_eq!(count_legal_moves_recursive(&mut board, 7), 567584); - - //--Stalemate & Checkmate - let mut board = Board::from_fen("8/8/2k5/5q2/5n2/8/5K2/8 b - - 0 1"); - assert_eq!(count_legal_moves_recursive(&mut board, 4), 23527); - - // Standard position - let mut board = Board::from_fen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"); - assert_eq!(count_legal_moves_recursive(&mut board, 3), 8902); -} - fn main() { - perft(); + } diff --git a/src/movegen/pawns.rs b/src/movegen/pawns.rs index fc219f9..0f58cc9 100644 --- a/src/movegen/pawns.rs +++ b/src/movegen/pawns.rs @@ -58,7 +58,7 @@ pub fn generate_pawn_moves(board: &Board, list: &mut MoveList) { // 1.3 Captures // 1.3.1 A-Side Capture (omitted promotion captures) - let mut a_side_capture_targets = (friendly_pawns & PAWN_H_SIDE_CAPTURE_MASK_WITHE) << 7 & opponent_occupied; + let mut a_side_capture_targets = (friendly_pawns & PAWN_A_SIDE_CAPTURE_MASK_WITHE) << 7 & opponent_occupied; while a_side_capture_targets > 0 { let to = SQUARES[a_side_capture_targets.trailing_zeros() as usize]; @@ -68,7 +68,7 @@ pub fn generate_pawn_moves(board: &Board, list: &mut MoveList) { } // 1.3.2 H-Side Capture (omitted promotion captures) - let mut h_side_capture_targets = (friendly_pawns & PAWN_A_SIDE_CAPTURE_MASK_WITHE) << 9 & opponent_occupied; + let mut h_side_capture_targets = (friendly_pawns & PAWN_H_SIDE_CAPTURE_MASK_WITHE) << 9 & opponent_occupied; while h_side_capture_targets > 0 { let to = SQUARES[h_side_capture_targets.trailing_zeros() as usize]; @@ -124,14 +124,14 @@ pub fn generate_pawn_moves(board: &Board, list: &mut MoveList) { let en_passant_target_bb: u64 = 1_u64 << (en_passant_target_square as u64); // 1. Check A-Side capture (<< 7, e.g., D5 -> C6) - let attacker_mask_a_side = (en_passant_target_bb >> 7) & PAWN_H_SIDE_CAPTURE_MASK_WITHE; + let attacker_mask_a_side = (en_passant_target_bb >> 7) & PAWN_A_SIDE_CAPTURE_MASK_WITHE; if (attacker_mask_a_side & friendly_pawns) > 0 { let from = en_passant_target_square - 7; list.push(Move::new(from, en_passant_target_square, MOVE_FLAG_EN_PASSANT)); } // 2. Check H-Side capture (<< 9, e.g., B5 -> C6) - let attacker_mask_h_side = (en_passant_target_bb >> 9) & PAWN_A_SIDE_CAPTURE_MASK_WITHE; + let attacker_mask_h_side = (en_passant_target_bb >> 9) & PAWN_H_SIDE_CAPTURE_MASK_WITHE; if (attacker_mask_h_side & friendly_pawns) > 0 { let from = en_passant_target_square - 9; list.push(Move::new(from, en_passant_target_square, MOVE_FLAG_EN_PASSANT)); diff --git a/tests/perft.rs b/tests/perft.rs index efc3a32..fb4d2bd 100644 --- a/tests/perft.rs +++ b/tests/perft.rs @@ -28,15 +28,84 @@ fn count_legal_moves_recursive(board: &mut Board, depth: u8) -> u64 { #[test] fn perft() { + // TalkChess PERFT Tests (by Martin Sedlak) + // Illegal ep move #1 + let mut board = Board::from_fen("3k4/3p4/8/K1P4r/8/8/8/8 b - - 0 1"); + assert_eq!(count_legal_moves_recursive(&mut board, 6), 1134888, "Illegal ep move #1"); + + // Illegal ep move #2 + let mut board = Board::from_fen("8/8/4k3/8/2p5/8/B2P2K1/8 w - - 0 1"); + assert_eq!(count_legal_moves_recursive(&mut board, 6), 1015133, "Illegal ep move #2"); + + // EP Capture Checks Opponent + let mut board = Board::from_fen("8/8/1k6/2b5/2pP4/8/5K2/8 b - d3 0 1"); + assert_eq!(count_legal_moves_recursive(&mut board, 6), 1440467, "EP Capture Checks Opponent"); + + // Short Castling Gives Check + let mut board = Board::from_fen("5k2/8/8/8/8/8/8/4K2R w K - 0 1"); + assert_eq!(count_legal_moves_recursive(&mut board, 6), 661072, "Short Castling Gives Check"); + + // Long Castling Gives Check + let mut board = Board::from_fen("3k4/8/8/8/8/8/8/R3K3 w Q - 0 1"); + assert_eq!(count_legal_moves_recursive(&mut board, 6), 803711, "Long Castling Gives Check"); + + // Castle Rights + let mut board = Board::from_fen("r3k2r/1b4bq/8/8/8/8/7B/R3K2R w KQkq - 0 1"); + assert_eq!(count_legal_moves_recursive(&mut board, 4), 1274206, "Castle Rights"); + + // Castling Prevented + let mut board = Board::from_fen("r3k2r/8/3Q4/8/8/5q2/8/R3K2R b KQkq - 0 1"); + assert_eq!(count_legal_moves_recursive(&mut board, 4), 1720476, "Castling Prevented"); + + // Promote out of Check + let mut board = Board::from_fen("2K2r2/4P3/8/8/8/8/8/3k4 w - - 0 1"); + assert_eq!(count_legal_moves_recursive(&mut board, 6), 3821001, "Promote out of Check"); + + // Discovered Check + let mut board = Board::from_fen("8/8/1P2K3/8/2n5/1q6/8/5k2 b - - 0 1"); + assert_eq!(count_legal_moves_recursive(&mut board, 5), 1004658, "Discovered Check"); + + // Promote to give check + let mut board = Board::from_fen("4k3/1P6/8/8/8/8/K7/8 w - - 0 1"); + assert_eq!(count_legal_moves_recursive(&mut board, 6), 217342, "Promote to give check"); + + // Under Promote to give check + let mut board = Board::from_fen("8/P1k5/K7/8/8/8/8/8 w - - 0 1"); + assert_eq!(count_legal_moves_recursive(&mut board, 6), 92683, "Under Promote to give check"); + + // Self Stalemate + let mut board = Board::from_fen("K1k5/8/P7/8/8/8/8/8 w - - 0 1"); + assert_eq!(count_legal_moves_recursive(&mut board, 6), 2217, "Self Stalemate"); + + // Stalemate & Checkmate + let mut board = Board::from_fen("8/k1P5/8/1K6/8/8/8/8 w - - 0 1"); + assert_eq!(count_legal_moves_recursive(&mut board, 7), 567584, "Stalemate & Checkmate"); + + // Stalemate & Checkmate + let mut board = Board::from_fen("8/8/2k5/5q2/5n2/8/5K2/8 b - - 0 1"); + assert_eq!(count_legal_moves_recursive(&mut board, 4), 23527, "Stalemate & Checkmate"); + + // Standard position + let mut board = Board::from_fen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"); + assert_eq!(count_legal_moves_recursive(&mut board, 6), 119060324, "Standard position"); + + // Kiwipete let mut board = Board::from_fen("r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1"); - println!("{}", count_legal_moves_recursive(&mut board, 1)); -} + assert_eq!(count_legal_moves_recursive(&mut board, 5), 193690690, "Kiwipete"); + // Position 3 + let mut board = Board::from_fen("8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - - 0 1"); + assert_eq!(count_legal_moves_recursive(&mut board, 5), 674624, "Position 3"); -// "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" \ No newline at end of file + // Position 4 + let mut board = Board::from_fen("r2q1rk1/pP1p2pp/Q4n2/bbp1p3/Np6/1B3NBn/pPPP1PPP/R3K2R b KQ - 0 1"); + assert_eq!(count_legal_moves_recursive(&mut board, 5), 15833292, "Position 4"); + + // Position 5 + let mut board = Board::from_fen("rnbq1k1r/pp1Pbppp/2p5/8/2B5/8/PPP1NnPP/RNBQK2R w KQ - 1 8"); + assert_eq!(count_legal_moves_recursive(&mut board, 4), 2103487, "Position 5"); + + // Position 6 + let mut board = Board::from_fen("r4rk1/1pp1qppp/p1np1n2/2b1p1B1/2B1P1b1/P1NP1N2/1PP1QPPP/R4RK1 w - - 0 10"); + assert_eq!(count_legal_moves_recursive(&mut board, 5), 164075551, "Position 6"); +} \ No newline at end of file