diff options
author | eug-vs <eugene@eug-vs.xyz> | 2023-08-31 14:58:40 +0300 |
---|---|---|
committer | eug-vs <eugene@eug-vs.xyz> | 2023-08-31 15:22:52 +0300 |
commit | ea63c58ce7e9dbc0e1c0e1cb679a89c038e2edd3 (patch) | |
tree | 737b0dab341a8b3ab45097be739c8d6a203612b6 | |
parent | b60569d4b1c1342ca33e6b4bf1a2cfcd7d77960c (diff) | |
download | chessnost-ea63c58ce7e9dbc0e1c0e1cb679a89c038e2edd3.tar.gz |
fix: consider promotion a tactical move
-rw-r--r-- | src/board/move_generation.rs | 15 | ||||
-rw-r--r-- | src/grossmeister/move_selector.rs | 2 | ||||
-rw-r--r-- | src/moves.rs | 6 |
3 files changed, 16 insertions, 7 deletions
diff --git a/src/board/move_generation.rs b/src/board/move_generation.rs index 7669b85..abc603a 100644 --- a/src/board/move_generation.rs +++ b/src/board/move_generation.rs @@ -55,9 +55,15 @@ impl Board { // Generalized attack/move pattern for all pieces for target in (move_targets & targets).serialize() { moves.push(Move { source, target, kind }); + } + + // Promotions + if piece_type == Piece::Pawn && tactical_only { + // All promotions are tactical, but target square can be empty + let iter_captures = (move_targets & targets).serialize(); + let iter_pushes = (self.attacks.pawn_pushes[color as usize][source as usize] & empty).serialize(); - // Promotions - if piece_type == Piece::Pawn { + for target in iter_pushes.chain(iter_captures) { if target.rank() == 7 { for promo_type in [Piece::Bishop, Piece::Knight, Piece::Rook, Piece::Queen] { moves.push(Move { source, target, kind: MoveKind::Promotion(promo_type)}) @@ -152,6 +158,7 @@ impl Board { } } } + moves } } @@ -164,7 +171,7 @@ mod tests { #[test] fn generate_pseudolegal_moves_starting_position() { - let mut board = Board::new(); + let board = Board::new(); let moves = board.generate_pseudolegal_moves(); let black_moves = board.generate_pseudolegal_moves(); @@ -212,6 +219,7 @@ mod tests { // Make sure tactical_only and true_tactical are identical sets for mov in tactical_only.iter() { assert!(true_tactical.iter().any(|m| *m == *mov)); + assert!(mov.is_tactical()); } for mov in true_tactical { assert!(tactical_only.iter().any(|m| *m == mov)); @@ -219,6 +227,7 @@ mod tests { // Make sure quiet_only and true_quiet are identical sets for mov in quiet_only.iter() { + assert!(!mov.is_tactical()); assert!(true_quiet.iter().any(|m| *m == *mov)); } for mov in true_quiet { diff --git a/src/grossmeister/move_selector.rs b/src/grossmeister/move_selector.rs index fa113ce..33f836b 100644 --- a/src/grossmeister/move_selector.rs +++ b/src/grossmeister/move_selector.rs @@ -220,7 +220,7 @@ impl Grossmeister { if self.move_selector().stage_moves.moves.is_empty() { let new_stage = self.move_selector().tactical_moves.iter() - .filter(|(m, score)| m.is_tactical() && *score < 0.0) + .filter(|(_, score)| *score < 0.0) .copied() .collect(); self.init_stage(new_stage); diff --git a/src/moves.rs b/src/moves.rs index da66247..b338afe 100644 --- a/src/moves.rs +++ b/src/moves.rs @@ -27,7 +27,7 @@ impl Move { /// Tactical move is a move that changes material score pub fn is_tactical(&self) -> bool { - matches!(self.kind, MoveKind::Capture | MoveKind::EnPassant) + matches!(self.kind, MoveKind::Capture | MoveKind::EnPassant | MoveKind::Promotion(_)) } pub fn from_notation(mut notation: Chars) -> Self { @@ -39,7 +39,7 @@ impl Move { 'r' => Piece::Rook, 'q' => Piece::Queen, 'b' => Piece::Bishop, - 'k' => Piece::Knight, + 'n' => Piece::Knight, _ => panic!("Illegal promotion piece: {:?}", promotion) }; return Move { source, target, kind: MoveKind::Promotion(piece) } @@ -56,7 +56,7 @@ impl Display for Move { Piece::Rook => "r", Piece::Queen => "q", Piece::Bishop => "b", - Piece::Knight => "k", + Piece::Knight => "n", _ => panic!("Illegal promotion piece: {:?}", piece) } } |