aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoreug-vs <eugene@eug-vs.xyz>2023-08-31 14:58:40 +0300
committereug-vs <eugene@eug-vs.xyz>2023-08-31 15:22:52 +0300
commitea63c58ce7e9dbc0e1c0e1cb679a89c038e2edd3 (patch)
tree737b0dab341a8b3ab45097be739c8d6a203612b6
parentb60569d4b1c1342ca33e6b4bf1a2cfcd7d77960c (diff)
downloadchessnost-ea63c58ce7e9dbc0e1c0e1cb679a89c038e2edd3.tar.gz
fix: consider promotion a tactical move
-rw-r--r--src/board/move_generation.rs15
-rw-r--r--src/grossmeister/move_selector.rs2
-rw-r--r--src/moves.rs6
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)
}
}