diff --git a/src/main.rs b/src/main.rs index 17a06d6..4b118bd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,19 +1,91 @@ use chess_engine::board::Board; use chess_engine::movegen::generate_pseudo_legal_moves; +use chess_engine::movegen::legal_check::is_king_attacked; use chess_engine::r#move::*; -fn main() { - let mut board = Board::from_fen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"); - let mut move_list = MoveList::new(); - - generate_pseudo_legal_moves(&board, &mut move_list); - - for mv in move_list.iter() { - board = Board::from_fen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"); - println!("--> making move: {}", mv.to_algebraic()); - board.make_move(*mv); - board.pretty_print_ascii(); - println!("---------------------"); +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/move.rs b/src/move.rs index 352a707..e1801d8 100644 --- a/src/move.rs +++ b/src/move.rs @@ -1,5 +1,4 @@ use std::slice; -use std::fmt; use crate::square::Square; use crate::board::PieceType; use crate::square::SQUARES; diff --git a/src/movegen/pawns.rs b/src/movegen/pawns.rs index f87b8e9..fc219f9 100644 --- a/src/movegen/pawns.rs +++ b/src/movegen/pawns.rs @@ -106,7 +106,6 @@ pub fn generate_pawn_moves(board: &Board, list: &mut MoveList) { } // 1.4.2.2 H-side capturing promotion - // CORRECTED: Use PAWN_H_SIDE_CAPTURE_PROMOTION_MASK_WITHE (excludes H-file) let mut promotion_targets_h_side_capture = ((friendly_pawns & PAWN_H_SIDE_CAPTURE_PROMOTION_MASK_WITHE) << 9) & board.occupied[1]; while promotion_targets_h_side_capture > 0 { let to = SQUARES[promotion_targets_h_side_capture.trailing_zeros() as usize]; diff --git a/tests/perft.rs b/tests/perft.rs index bc5511c..efc3a32 100644 --- a/tests/perft.rs +++ b/tests/perft.rs @@ -28,8 +28,8 @@ fn count_legal_moves_recursive(board: &mut Board, depth: u8) -> u64 { #[test] fn perft() { - let mut board = Board::from_fen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"); - println!("{}", count_legal_moves_recursive(&mut board, 4)); + 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)); }