fixed perft

This commit is contained in:
Moritz 2025-11-14 22:30:42 +01:00
parent e3edb21111
commit af2178abad
4 changed files with 105 additions and 96 deletions

22
helper_scripts/test Normal file
View file

@ -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

View file

@ -4,88 +4,6 @@ use chess_engine::movegen::legal_check::is_king_attacked;
use chess_engine::r#move::*; 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() { fn main() {
perft();
} }

View file

@ -58,7 +58,7 @@ pub fn generate_pawn_moves(board: &Board, list: &mut MoveList) {
// 1.3 Captures // 1.3 Captures
// 1.3.1 A-Side Capture (omitted promotion 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 { while a_side_capture_targets > 0 {
let to = SQUARES[a_side_capture_targets.trailing_zeros() as usize]; 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) // 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 { while h_side_capture_targets > 0 {
let to = SQUARES[h_side_capture_targets.trailing_zeros() as usize]; 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); let en_passant_target_bb: u64 = 1_u64 << (en_passant_target_square as u64);
// 1. Check A-Side capture (<< 7, e.g., D5 -> C6) // 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 { if (attacker_mask_a_side & friendly_pawns) > 0 {
let from = en_passant_target_square - 7; let from = en_passant_target_square - 7;
list.push(Move::new(from, en_passant_target_square, MOVE_FLAG_EN_PASSANT)); list.push(Move::new(from, en_passant_target_square, MOVE_FLAG_EN_PASSANT));
} }
// 2. Check H-Side capture (<< 9, e.g., B5 -> C6) // 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 { if (attacker_mask_h_side & friendly_pawns) > 0 {
let from = en_passant_target_square - 9; let from = en_passant_target_square - 9;
list.push(Move::new(from, en_passant_target_square, MOVE_FLAG_EN_PASSANT)); list.push(Move::new(from, en_passant_target_square, MOVE_FLAG_EN_PASSANT));

View file

@ -28,15 +28,84 @@ fn count_legal_moves_recursive(board: &mut Board, depth: u8) -> u64 {
#[test] #[test]
fn perft() { 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"); 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");
// 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");
} }
// "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"