diff --git a/src/gamemanager/legal_moves.rs b/src/gamemanager/legal_moves.rs index a7ac53b..1b0ffdd 100644 --- a/src/gamemanager/legal_moves.rs +++ b/src/gamemanager/legal_moves.rs @@ -71,17 +71,21 @@ impl GameManager { } // Increment the halfmove counter every quiet/non-pawn move. + // En passant target always equals an empty string unless the + // move was a double pawn push. use MoveType::*; match mv.3 { QuietMove | KingCastle | QueenCastle => { modified_gm.halfmoves += 1; modified_gm.en_passant_target = String::new(); // Made a quiet move instead of EPCapture. } - EPCapture => { + DoublePawnPush => { + modified_gm.halfmoves = 0; // Leave en passant target alone; it was set by the color-specific function. + } + _ => { modified_gm.halfmoves = 0; - modified_gm.en_passant_target = String::new() + modified_gm.en_passant_target = String::new(); } - _ => modified_gm.halfmoves = 0, } // TODO: Test mask and king intersection. @@ -93,6 +97,30 @@ impl GameManager { }, ); + // Test that the castle is not castling through/out of check. + use Square::*; + match mv.3 { + KingCastle => { + if color == Color::Black + && (E8.to_u64() | F8.to_u64() | G8.to_u64()) & enemy_attacked != 0 + || color == Color::White + && (E1.to_u64() | F1.to_u64() | G1.to_u64()) & enemy_attacked != 0 + { + continue; // We don't want this move! + } + } + QueenCastle => { + if color == Color::Black + && (E8.to_u64() | D8.to_u64() | C8.to_u64()) & enemy_attacked != 0 + || color == Color::White + && (E1.to_u64() | D1.to_u64() | C1.to_u64()) & enemy_attacked != 0 + { + continue; // Ditto. + } + } + _ => {} + } + match color { Color::Black => { if modified_gm.bitboard.king_black & enemy_attacked == 0 { @@ -224,7 +252,10 @@ impl GameManager { | Square::F8.to_u64(), ..self.bitboard }, - castling_rights: self.castling_rights.clone(), + castling_rights: CastlingRecord { + black: CastlingRights::Neither, + ..self.castling_rights + }, en_passant_target: self.en_passant_target.clone(), ..*self @@ -233,10 +264,13 @@ impl GameManager { bitboard: BitBoard { king_black: (self.bitboard.king_black ^ from.to_u64()) | to.to_u64(), rooks_black: (self.bitboard.rooks_black ^ Square::A8.to_u64()) - | Square::C8.to_u64(), + | Square::D8.to_u64(), ..self.bitboard }, - castling_rights: self.castling_rights.clone(), + castling_rights: CastlingRecord { + black: CastlingRights::Neither, + ..self.castling_rights + }, en_passant_target: self.en_passant_target.clone(), ..*self @@ -669,7 +703,10 @@ impl GameManager { | Square::F1.to_u64(), ..self.bitboard }, - castling_rights: self.castling_rights.clone(), + castling_rights: CastlingRecord { + white: CastlingRights::Neither, + ..self.castling_rights + }, en_passant_target: self.en_passant_target.clone(), ..*self @@ -678,10 +715,13 @@ impl GameManager { bitboard: BitBoard { king_white: (self.bitboard.king_white ^ from.to_u64()) | to.to_u64(), rooks_white: (self.bitboard.rooks_white ^ Square::A1.to_u64()) - | Square::C1.to_u64(), + | Square::D1.to_u64(), ..self.bitboard }, - castling_rights: self.castling_rights.clone(), + castling_rights: CastlingRecord { + white: CastlingRights::Neither, + ..self.castling_rights + }, en_passant_target: self.en_passant_target.clone(), ..*self diff --git a/src/gamemanager/legal_moves/perft.rs b/src/gamemanager/legal_moves/perft.rs index fe3f871..0838d7e 100644 --- a/src/gamemanager/legal_moves/perft.rs +++ b/src/gamemanager/legal_moves/perft.rs @@ -1,3 +1,5 @@ +use crate::types::Square; + use super::{GameManager, MoveTable, NoArc}; use rayon::prelude::*; @@ -11,3 +13,24 @@ pub fn perft(depth: u16, maxdepth: u16, gm: GameManager, tbl: &NoArc) .sum::() } } + +pub fn printing_perft(depth: u16, maxdepth: u16, gm: GameManager, tbl: &NoArc) { + for mv in gm.legal_moves(tbl) { + if mv.1 == Square::E1 && mv.2 == Square::C1 { + println!("--- MOVE E1C1:"); + printing_perft(depth + 1, maxdepth, mv.4, tbl); + println!("--- END E1C1."); + } else if mv.1 == Square::A6 && mv.2 == Square::B5 { + println!("--- MOVE A6B5:"); + printing_perft(depth + 1, maxdepth, mv.4, tbl); + println!("--- END A6B5."); + } else { + println!( + "{}{}: {}", + mv.1.to_str().to_ascii_lowercase(), + mv.2.to_str().to_ascii_lowercase(), + perft(depth, maxdepth, mv.4, tbl) + ) + } + } +} diff --git a/src/gamemanager/pseudolegal_moves/kings.rs b/src/gamemanager/pseudolegal_moves/kings.rs index 31fb191..fe42f40 100644 --- a/src/gamemanager/pseudolegal_moves/kings.rs +++ b/src/gamemanager/pseudolegal_moves/kings.rs @@ -55,7 +55,6 @@ pub fn pseudolegal_king_moves( ) -> Vec { let mut king_pseudo_legal_moves = Vec::new(); - // TODO: Check that castling paths are not attacked. match color { Color::Black => { for king in king_locations { @@ -117,7 +116,7 @@ pub fn pseudolegal_king_moves( king_pseudo_legal_moves.push(( PieceType::King, Square::E8, - Square::B8, + Square::C8, MoveType::QueenCastle, )); } @@ -182,7 +181,7 @@ pub fn pseudolegal_king_moves( king_pseudo_legal_moves.push(( PieceType::King, Square::E1, - Square::B1, + Square::C1, MoveType::QueenCastle, )); } @@ -254,7 +253,7 @@ mod tests { D7.to_u64(), E7.to_u64(), F7.to_u64(), - B8.to_u64(), // Queen-side castling. + C8.to_u64(), // Queen-side castling. G8.to_u64(), // King-side castling. ] .iter() @@ -286,7 +285,7 @@ mod tests { D2.to_u64(), E2.to_u64(), F2.to_u64(), - B1.to_u64(), // Queen-side castling. + C1.to_u64(), // Queen-side castling. G1.to_u64(), // King-side castling. ] .iter() diff --git a/src/main.rs b/src/main.rs index a263703..488ade4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,9 @@ #![allow(dead_code)] -use gamemanager::{legal_moves::perft::perft, GameManager}; +use gamemanager::{ + legal_moves::perft::{perft, printing_perft}, + GameManager, +}; use movetable::{noarc, MoveTable}; mod bitboard; @@ -14,6 +17,7 @@ fn main() { let gm = GameManager::default(); println!("Searched {} nodes.", perft(0, 6, gm, &tbl)); + //printing_perft(0, 2, gm, &tbl); } #[cfg(test)]