aboutsummaryrefslogtreecommitdiff
path: root/src/grossmeister/move_generation.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/grossmeister/move_generation.rs')
-rw-r--r--src/grossmeister/move_generation.rs262
1 files changed, 0 insertions, 262 deletions
diff --git a/src/grossmeister/move_generation.rs b/src/grossmeister/move_generation.rs
deleted file mode 100644
index ea40d18..0000000
--- a/src/grossmeister/move_generation.rs
+++ /dev/null
@@ -1,262 +0,0 @@
-use std::cmp::Ordering;
-
-use crate::{moves::{Move, MoveKind}, board::{color::Color, piece::Piece, CastlingSide}, bitboard::BitboardFns, square::Square};
-
-use super::Grossmeister;
-
-
-impl Grossmeister {
- pub fn generate_pseudolegal_moves(&self) -> Vec<Move> {
- let mut result = Vec::new();
- result.append(&mut self.generate_moves_core(true));
- result.append(&mut self.generate_moves_core(false));
- result
- }
-
- fn generate_moves_core(&self, tactical_only: bool) -> Vec<Move> {
- let color = self.board.color();
- let player_pieces = self.board.pieces_by_color(color);
- let mut moves = Vec::with_capacity(256);
- let empty = self.board.empty();
-
- let targets = if tactical_only {
- self.board.color_occupancy(color.flip()) ^ match color {
- // Exclude opponent king because we can't capture it
- Color::White => self.board.piece_sets[Piece::KingBlack as usize],
- Color::Black => self.board.piece_sets[Piece::King as usize],
- }
- } else {
- empty
- };
-
- let kind = if tactical_only {
- MoveKind::Capture
- } else {
- MoveKind::Quiet
- };
-
- for (piece_id, piece) in player_pieces.iter().enumerate() {
- for source in piece.serialize() {
- let piece_type = Piece::from(piece_id);
- let move_targets = match piece_type {
- Piece::Bishop => self.attacks.bishop(self.board.occupancy, source),
- Piece::Rook => self.attacks.rook(self.board.occupancy, source),
- Piece::Queen => self.attacks.queen(self.board.occupancy, source),
- Piece::Knight => self.attacks.knight[source as usize],
- Piece::King => self.attacks.king[source as usize],
- Piece::Pawn => if tactical_only {
- self.attacks.pawn[color as usize][source as usize]
- } else {
- self.attacks.pawn_pushes[color as usize][source as usize]
- },
- _ => panic!("Incorrect piece type"),
- };
-
- // 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 {
- 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)})
- }
- } else if target.rank() == 0 {
- for promo_type in [Piece::BishopBlack, Piece::KnightBlack, Piece::RookBlack, Piece::QueenBlack] {
- moves.push(Move { source, target, kind: MoveKind::Promotion(promo_type)})
- }
- }
- }
- }
-
- // En Passant
- if piece_type == Piece::Pawn && tactical_only {
- for target in (move_targets & self.board.ep_bitboard()).serialize() {
- moves.push(Move { source, target, kind: MoveKind::EnPassant });
- }
- }
- }
- }
-
- if !tactical_only {
- // Double Pushes
- // Make sure no blocking piece is standing in front of the pawns
- // that are potential double-push sources
- let able_to_double_push_mask = match color {
- Color::White => empty >> 8,
- Color::Black => empty << 8,
- };
- for source in (player_pieces[Piece::Pawn as usize] & able_to_double_push_mask).serialize() {
- for target in (self.attacks.pawn_double_pushes[color as usize][source as usize] & empty).serialize() {
- moves.push(Move { source, target, kind: MoveKind::DoublePush });
- };
- }
-
- // Castling
- let king_home_position = match color {
- Color::White => Square::E1,
- Color::Black => Square::E8,
- };
- if player_pieces[Piece::King as usize].bitscan() == king_home_position {
- for rook_square in player_pieces[Piece::Rook as usize]
- .serialize()
- .iter()
- .filter(|rook_square| rook_square.rank() == king_home_position.rank())
- {
- match rook_square.file() {
- 0 => {
- let all_empty = [
- king_home_position.west_one(),
- king_home_position.west_one().west_one(),
- king_home_position.west_one().west_one().west_one(),
-
- ].iter().all(|square| empty & square.to_bitboard() > 0);
-
- let any_checks = [
- king_home_position,
- king_home_position.west_one(),
- king_home_position.west_one().west_one(),
- ].iter().any(|square| self.board.is_square_attacked(*square, color.flip()));
-
- if all_empty && !any_checks && self.board.castling_rights[color as usize][CastlingSide::Queen as usize] {
- moves.push(Move {
- source: king_home_position,
- target: king_home_position.west_one().west_one(),
- kind: MoveKind::Castle,
- })
- }
- },
- 7 => {
- let all_empty = [
- king_home_position.east_one(),
- king_home_position.east_one().east_one(),
-
- ].iter().all(|square| empty & square.to_bitboard() > 0);
-
- let any_checks = [
- king_home_position,
- king_home_position.east_one(),
- king_home_position.east_one().east_one(),
- ].iter().any(|square| self.board.is_square_attacked(*square, color.flip()));
-
- if all_empty && !any_checks && self.board.castling_rights[color as usize][CastlingSide::King as usize] {
- moves.push(Move {
- source: king_home_position,
- target: king_home_position.east_one().east_one(),
- kind: MoveKind::Castle,
- })
- }
- },
- _ => {},
- }
- }
- }
- }
- moves
- }
-
- /// Evaluate move for move ordering, prioritizing efficient captures
- /// where low-value pieces capture high-value pieces
- fn eval_move(&self, m: Move) -> f32 {
- if m.is_tactical() {
- let [source_eval, target_eval] = [m.source, m.target]
- .map(|sq| self.board.piece_by_square(sq))
- .map(|p| {
- match p {
- Some(p) => p.static_eval(),
- None => 0.,
- }
- });
- return 2. * target_eval - source_eval
- }
- 0.0
- }
-
- pub fn order_moves(&self, moves: Vec<Move>, killer_moves: Vec<Move>) -> Vec<Move> {
- let mut moves_with_eval: Vec<(Move, f32)> = moves
- .iter()
- .map(|m| (*m, self.eval_move(*m)))
- .collect();
-
- moves_with_eval.sort_unstable_by(|(a, a_eval), (b, b_eval)| {
- if *a_eval == 0.0 && *b_eval == 0.0 {
- // Prioritize equal captures over non-captures
- if a.is_tactical() && !b.is_tactical() {
- return Ordering::Less
- }
- if b.is_tactical() && !a.is_tactical() {
- return Ordering::Greater
- }
- }
- a_eval.total_cmp(b_eval).reverse()
- });
-
- let mut ordered_moves: Vec<Move> = moves_with_eval.iter().map(|(m, _)| *m).collect();
-
- // Insert killer moves after winning captures
- let equal_capture_index = moves_with_eval
- .iter()
- .position(|(m, eval)| m.is_tactical() && *eval == 0.0)
- .unwrap_or(0);
-
- for killer in killer_moves {
- if let Some(index) = ordered_moves.iter().position(|m| *m == killer) {
- let mov = ordered_moves.remove(index);
- ordered_moves.insert(equal_capture_index, mov);
- }
- }
-
- if let Some(transposition) = self.transposition() {
- ordered_moves.insert(0, transposition.mov);
- }
-
- ordered_moves
- }
-
-}
-
-#[cfg(test)]
-mod tests {
- use crate::board::{Board, io::IO};
-
- use super::*;
-
- #[test]
- fn generate_pseudolegal_moves_starting_position() {
- let board = Board::new();
- let mut gm = Grossmeister::new(board);
- let moves = gm.generate_pseudolegal_moves();
- gm.board.ply += 1;
- let black_moves = gm.generate_pseudolegal_moves();
-
- assert_eq!(moves.len(), 20);
- assert_eq!(black_moves.len(), 20);
-
- for mov in moves {
- mov.print();
- }
- }
-
-
- #[test]
- fn moved_king_castle() {
- let fen = String::from("4k2r/ppp1n3/8/4R1Pp/5P2/q1P5/P1P1BP2/1K1R4 b - - 2 22");
- let board = Board::from_FEN(fen);
- let mut gm = Grossmeister::new(board);
- gm.board.ply += 1;
-
- // Shuffle kings around, returning to the same position
- gm.board.make_move(Move { source: Square::E8, target: Square::F8, kind: MoveKind::Quiet });
- gm.board.make_move(Move { source: Square::B1, target: Square::A1, kind: MoveKind::Quiet });
- gm.board.make_move(Move { source: Square::F8, target: Square::E8, kind: MoveKind::Quiet });
- gm.board.make_move(Move { source: Square::A1, target: Square::B1, kind: MoveKind::Quiet });
- gm.board.print();
-
- let moves = gm.generate_pseudolegal_moves();
-
- let castle = moves.iter().find(|m| **m == Move { source: Square::E8, target: Square::G8, kind: MoveKind::Castle });
- println!("{:?}", board.castling_rights);
- assert!(castle.is_none(), "Castle should not be allowed after king has moved");
- }
-}