Specify move type using new MoveType enum and update tests
This commit is contained in:
26
src/board.rs
26
src/board.rs
@@ -5,6 +5,11 @@ use crate::attack::{
|
|||||||
get_rook_attacks,
|
get_rook_attacks,
|
||||||
};
|
};
|
||||||
use crate::game::State;
|
use crate::game::State;
|
||||||
|
use crate::movegen::{
|
||||||
|
bishop_pseudo_moves, king_pseudo_moves, knight_pseudo_moves, pawn_pseudo_moves,
|
||||||
|
queen_pseudo_moves, rook_pseudo_moves,
|
||||||
|
};
|
||||||
|
use crate::r#move::{Move, MoveType, Promote};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub struct Board {
|
pub struct Board {
|
||||||
@@ -12,10 +17,6 @@ pub struct Board {
|
|||||||
pub black_pieces: [Piece; 6],
|
pub black_pieces: [Piece; 6],
|
||||||
pub state: State,
|
pub state: State,
|
||||||
}
|
}
|
||||||
use crate::movegen::{
|
|
||||||
bishop_pseudo_moves, king_pseudo_moves, knight_pseudo_moves, pawn_pseudo_moves,
|
|
||||||
queen_pseudo_moves, rook_pseudo_moves, Move,
|
|
||||||
};
|
|
||||||
|
|
||||||
impl Board {
|
impl Board {
|
||||||
pub const fn new() -> Self {
|
pub const fn new() -> Self {
|
||||||
@@ -100,6 +101,21 @@ impl Board {
|
|||||||
|| enemy[Kind::King.idx()].bitboard & get_king_attacks(sq) != 0
|
|| enemy[Kind::King.idx()].bitboard & get_king_attacks(sq) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_move_legit(&self, square: usize, opponent_color: Color) -> bool {
|
||||||
|
!self.is_attacked(square, opponent_color)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pseudo_moves_all(&self, color: Color) -> Vec<Move> {
|
||||||
|
let mut moves = vec![];
|
||||||
|
moves.extend(self.pseudo_moves(color, Kind::Pawn));
|
||||||
|
moves.extend(self.pseudo_moves(color, Kind::Knight));
|
||||||
|
moves.extend(self.pseudo_moves(color, Kind::Bishop));
|
||||||
|
moves.extend(self.pseudo_moves(color, Kind::Rook));
|
||||||
|
moves.extend(self.pseudo_moves(color, Kind::Queen));
|
||||||
|
moves.extend(self.pseudo_moves(color, Kind::King));
|
||||||
|
moves
|
||||||
|
}
|
||||||
|
|
||||||
pub fn pseudo_moves(&self, color: Color, kind: Kind) -> Vec<Move> {
|
pub fn pseudo_moves(&self, color: Color, kind: Kind) -> Vec<Move> {
|
||||||
let all_occupancies = self.get_all_occupancies();
|
let all_occupancies = self.get_all_occupancies();
|
||||||
let (pieces, enemy_occupancies, own_occupancies) = match color {
|
let (pieces, enemy_occupancies, own_occupancies) = match color {
|
||||||
@@ -123,7 +139,7 @@ impl Board {
|
|||||||
self.state.get_en_passant_target_square(),
|
self.state.get_en_passant_target_square(),
|
||||||
color,
|
color,
|
||||||
),
|
),
|
||||||
Kind::Knight => knight_pseudo_moves(pieces, own_occupancies),
|
Kind::Knight => knight_pseudo_moves(pieces, all_occupancies, own_occupancies),
|
||||||
Kind::Bishop => bishop_pseudo_moves(pieces, all_occupancies, own_occupancies),
|
Kind::Bishop => bishop_pseudo_moves(pieces, all_occupancies, own_occupancies),
|
||||||
Kind::Rook => rook_pseudo_moves(pieces, all_occupancies, own_occupancies),
|
Kind::Rook => rook_pseudo_moves(pieces, all_occupancies, own_occupancies),
|
||||||
Kind::Queen => queen_pseudo_moves(pieces, all_occupancies, own_occupancies),
|
Kind::Queen => queen_pseudo_moves(pieces, all_occupancies, own_occupancies),
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ pub mod board;
|
|||||||
pub mod fen;
|
pub mod fen;
|
||||||
pub mod game;
|
pub mod game;
|
||||||
pub mod magic;
|
pub mod magic;
|
||||||
|
pub mod r#move;
|
||||||
pub mod movegen;
|
pub mod movegen;
|
||||||
|
|
||||||
use game::Game;
|
use game::Game;
|
||||||
|
|||||||
46
src/move.rs
Normal file
46
src/move.rs
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
|
||||||
|
pub enum Promote {
|
||||||
|
Knight,
|
||||||
|
Rook,
|
||||||
|
Bishop,
|
||||||
|
Queen,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
|
||||||
|
pub enum MoveType {
|
||||||
|
Quiet,
|
||||||
|
Capture,
|
||||||
|
DoublePush,
|
||||||
|
Promotion(Promote),
|
||||||
|
PromotionCapture(Promote),
|
||||||
|
EnPassant,
|
||||||
|
Castle,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
|
||||||
|
pub struct Move {
|
||||||
|
pub source: u32,
|
||||||
|
pub target: u32,
|
||||||
|
pub move_type: MoveType,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Move {
|
||||||
|
pub const fn new(source: u32, target: u32) -> Self {
|
||||||
|
Self {
|
||||||
|
source,
|
||||||
|
target,
|
||||||
|
move_type: MoveType::Quiet,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn new_with_type(source: u32, target: u32, move_type: MoveType) -> Self {
|
||||||
|
Self {
|
||||||
|
source,
|
||||||
|
target,
|
||||||
|
move_type,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {}
|
||||||
220
src/movegen.rs
220
src/movegen.rs
@@ -4,6 +4,7 @@ use crate::attack::{
|
|||||||
};
|
};
|
||||||
use crate::board::{Board, Color};
|
use crate::board::{Board, Color};
|
||||||
use crate::game::Castle;
|
use crate::game::Castle;
|
||||||
|
use crate::r#move::{Move, MoveType, Promote};
|
||||||
use u64 as Bitboard;
|
use u64 as Bitboard;
|
||||||
|
|
||||||
const NOT_A_FILE: Bitboard = 0xfefefefefefefefe;
|
const NOT_A_FILE: Bitboard = 0xfefefefefefefefe;
|
||||||
@@ -11,18 +12,6 @@ const NOT_H_FILE: Bitboard = 0x7f7f7f7f7f7f7f7f;
|
|||||||
const RANK_4: Bitboard = 0x00000000FF000000;
|
const RANK_4: Bitboard = 0x00000000FF000000;
|
||||||
const RANK_5: Bitboard = 0x000000FF00000000;
|
const RANK_5: Bitboard = 0x000000FF00000000;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
|
||||||
pub struct Move {
|
|
||||||
pub source: u32,
|
|
||||||
pub target: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Move {
|
|
||||||
pub const fn new(source: u32, target: u32) -> Self {
|
|
||||||
Self { source, target }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn pawn_pseudo_moves(
|
pub fn pawn_pseudo_moves(
|
||||||
pawns: Bitboard,
|
pawns: Bitboard,
|
||||||
all_occupancies: Bitboard,
|
all_occupancies: Bitboard,
|
||||||
@@ -30,7 +19,7 @@ pub fn pawn_pseudo_moves(
|
|||||||
en_passant_square: Option<u8>,
|
en_passant_square: Option<u8>,
|
||||||
color: Color,
|
color: Color,
|
||||||
) -> Vec<Move> {
|
) -> Vec<Move> {
|
||||||
let mut moves: Vec<Move> = vec![];
|
let mut moves = vec![];
|
||||||
match color {
|
match color {
|
||||||
Color::White => {
|
Color::White => {
|
||||||
moves.extend(white_pawn_quiet_moves(pawns, all_occupancies));
|
moves.extend(white_pawn_quiet_moves(pawns, all_occupancies));
|
||||||
@@ -41,26 +30,36 @@ pub fn pawn_pseudo_moves(
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
Color::Black => {
|
Color::Black => {
|
||||||
|
moves.extend(black_pawn_quiet_moves(pawns, all_occupancies));
|
||||||
moves.extend(black_pawn_capture_moves(
|
moves.extend(black_pawn_capture_moves(
|
||||||
pawns,
|
pawns,
|
||||||
enemy_occupancies,
|
enemy_occupancies,
|
||||||
en_passant_square,
|
en_passant_square,
|
||||||
));
|
));
|
||||||
moves.extend(black_pawn_quiet_moves(pawns, all_occupancies));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
moves
|
moves
|
||||||
}
|
}
|
||||||
|
|
||||||
fn white_pawn_quiet_moves(pawns: Bitboard, occupancies: Bitboard) -> Vec<Move> {
|
fn white_pawn_quiet_moves(pawns: Bitboard, occupancies: Bitboard) -> Vec<Move> {
|
||||||
let mut moves: Vec<Move> = vec![];
|
let mut moves = vec![];
|
||||||
let empty = !occupancies;
|
let empty = !occupancies;
|
||||||
|
|
||||||
let mut single_push_targets = (pawns << 8) & empty;
|
let mut single_push_targets = (pawns << 8) & empty;
|
||||||
while single_push_targets != 0 {
|
while single_push_targets != 0 {
|
||||||
let to = single_push_targets.trailing_zeros();
|
let to = single_push_targets.trailing_zeros();
|
||||||
let from = to - 8;
|
let from = to - 8;
|
||||||
moves.push(Move::new(from, to));
|
|
||||||
|
if from as u64 & 0xff000000000000 != 0 {
|
||||||
|
moves.extend([
|
||||||
|
Move::new_with_type(from, to, MoveType::Promotion(Promote::Knight)),
|
||||||
|
Move::new_with_type(from, to, MoveType::Promotion(Promote::Bishop)),
|
||||||
|
Move::new_with_type(from, to, MoveType::Promotion(Promote::Rook)),
|
||||||
|
Move::new_with_type(from, to, MoveType::Promotion(Promote::Queen)),
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
moves.push(Move::new(from, to));
|
||||||
|
}
|
||||||
single_push_targets &= single_push_targets - 1;
|
single_push_targets &= single_push_targets - 1;
|
||||||
}
|
}
|
||||||
let single_push_targets = (pawns << 8) & empty;
|
let single_push_targets = (pawns << 8) & empty;
|
||||||
@@ -68,29 +67,40 @@ fn white_pawn_quiet_moves(pawns: Bitboard, occupancies: Bitboard) -> Vec<Move> {
|
|||||||
while double_push_targets != 0 {
|
while double_push_targets != 0 {
|
||||||
let to = double_push_targets.trailing_zeros();
|
let to = double_push_targets.trailing_zeros();
|
||||||
let from = to - 16;
|
let from = to - 16;
|
||||||
moves.push(Move::new(from, to));
|
moves.push(Move::new_with_type(from, to, MoveType::DoublePush));
|
||||||
double_push_targets &= double_push_targets - 1;
|
double_push_targets &= double_push_targets - 1;
|
||||||
}
|
}
|
||||||
moves
|
moves
|
||||||
}
|
}
|
||||||
|
|
||||||
fn black_pawn_quiet_moves(pawns: Bitboard, occupancies: Bitboard) -> Vec<Move> {
|
fn black_pawn_quiet_moves(pawns: Bitboard, occupancies: Bitboard) -> Vec<Move> {
|
||||||
let mut moves: Vec<Move> = vec![];
|
let mut moves = vec![];
|
||||||
let empty = !occupancies;
|
let empty = !occupancies;
|
||||||
|
|
||||||
let mut single_push_targets = (pawns >> 8) & empty;
|
let mut single_push_targets = (pawns >> 8) & empty;
|
||||||
while single_push_targets != 0 {
|
while single_push_targets != 0 {
|
||||||
let to = single_push_targets.trailing_zeros();
|
let to = single_push_targets.trailing_zeros();
|
||||||
let from = to + 8;
|
let from = to + 8;
|
||||||
moves.push(Move::new(from, to));
|
|
||||||
|
if from as u64 & 0xff000000000000 != 0 {
|
||||||
|
moves.extend([
|
||||||
|
Move::new_with_type(from, to, MoveType::Promotion(Promote::Knight)),
|
||||||
|
Move::new_with_type(from, to, MoveType::Promotion(Promote::Bishop)),
|
||||||
|
Move::new_with_type(from, to, MoveType::Promotion(Promote::Rook)),
|
||||||
|
Move::new_with_type(from, to, MoveType::Promotion(Promote::Queen)),
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
moves.push(Move::new(from, to));
|
||||||
|
}
|
||||||
single_push_targets &= single_push_targets - 1;
|
single_push_targets &= single_push_targets - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
let single_push_targets = (pawns >> 8) & empty;
|
let single_push_targets = (pawns >> 8) & empty;
|
||||||
let mut double_push_targets = (single_push_targets >> 8) & empty & RANK_5;
|
let mut double_push_targets = (single_push_targets >> 8) & empty & RANK_5;
|
||||||
while double_push_targets != 0 {
|
while double_push_targets != 0 {
|
||||||
let to = double_push_targets.trailing_zeros();
|
let to = double_push_targets.trailing_zeros();
|
||||||
let from = to + 16;
|
let from = to + 16;
|
||||||
moves.push(Move::new(from, to));
|
moves.push(Move::new_with_type(from, to, MoveType::DoublePush));
|
||||||
double_push_targets &= double_push_targets - 1;
|
double_push_targets &= double_push_targets - 1;
|
||||||
}
|
}
|
||||||
moves
|
moves
|
||||||
@@ -101,27 +111,51 @@ fn white_pawn_capture_moves(
|
|||||||
enemy_occupancies: Bitboard,
|
enemy_occupancies: Bitboard,
|
||||||
en_passant_square: Option<u8>,
|
en_passant_square: Option<u8>,
|
||||||
) -> Vec<Move> {
|
) -> Vec<Move> {
|
||||||
let mut moves: Vec<Move> = vec![];
|
let mut moves = vec![];
|
||||||
let mut w_pawns_capture_east = pawns & ((enemy_occupancies >> 9) & NOT_H_FILE);
|
let mut w_pawns_capture_east = pawns & ((enemy_occupancies >> 9) & NOT_H_FILE);
|
||||||
let mut w_pawns_capture_west = pawns & ((enemy_occupancies >> 7) & NOT_A_FILE);
|
let mut w_pawns_capture_west = pawns & ((enemy_occupancies >> 7) & NOT_A_FILE);
|
||||||
|
|
||||||
while w_pawns_capture_east != 0 {
|
while w_pawns_capture_east != 0 {
|
||||||
let from = w_pawns_capture_east.trailing_zeros();
|
let from = w_pawns_capture_east.trailing_zeros();
|
||||||
let to = from + 9;
|
let to = from + 9;
|
||||||
moves.push(Move::new(from, to));
|
|
||||||
|
if from as u64 & 0xff000000000000 != 0 {
|
||||||
|
moves.extend([
|
||||||
|
Move::new_with_type(from, to, MoveType::PromotionCapture(Promote::Knight)),
|
||||||
|
Move::new_with_type(from, to, MoveType::PromotionCapture(Promote::Bishop)),
|
||||||
|
Move::new_with_type(from, to, MoveType::PromotionCapture(Promote::Rook)),
|
||||||
|
Move::new_with_type(from, to, MoveType::PromotionCapture(Promote::Queen)),
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
moves.push(Move::new_with_type(from, to, MoveType::Capture));
|
||||||
|
}
|
||||||
w_pawns_capture_east &= w_pawns_capture_east - 1;
|
w_pawns_capture_east &= w_pawns_capture_east - 1;
|
||||||
}
|
}
|
||||||
while w_pawns_capture_west != 0 {
|
while w_pawns_capture_west != 0 {
|
||||||
let from = w_pawns_capture_west.trailing_zeros();
|
let from = w_pawns_capture_west.trailing_zeros();
|
||||||
let to = from + 7;
|
let to = from + 7;
|
||||||
moves.push(Move::new(from, to));
|
|
||||||
|
if from as u64 & 0xff000000000000 != 0 {
|
||||||
|
moves.extend([
|
||||||
|
Move::new_with_type(from, to, MoveType::PromotionCapture(Promote::Knight)),
|
||||||
|
Move::new_with_type(from, to, MoveType::PromotionCapture(Promote::Bishop)),
|
||||||
|
Move::new_with_type(from, to, MoveType::PromotionCapture(Promote::Rook)),
|
||||||
|
Move::new_with_type(from, to, MoveType::PromotionCapture(Promote::Queen)),
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
moves.push(Move::new_with_type(from, to, MoveType::Capture));
|
||||||
|
}
|
||||||
w_pawns_capture_west &= w_pawns_capture_west - 1;
|
w_pawns_capture_west &= w_pawns_capture_west - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(en_passant_square) = en_passant_square {
|
if let Some(en_passant_square) = en_passant_square {
|
||||||
let attacked_from = get_pawn_attacks(en_passant_square as usize, Color::Black);
|
let attacked_from = get_pawn_attacks(en_passant_square as usize, Color::Black);
|
||||||
let result = attacked_from & pawns;
|
let result = attacked_from & pawns;
|
||||||
moves.push(Move::new(result.trailing_zeros(), en_passant_square as u32));
|
moves.push(Move::new_with_type(
|
||||||
|
result.trailing_zeros(),
|
||||||
|
en_passant_square as u32,
|
||||||
|
MoveType::EnPassant,
|
||||||
|
));
|
||||||
};
|
};
|
||||||
moves
|
moves
|
||||||
}
|
}
|
||||||
@@ -131,44 +165,74 @@ fn black_pawn_capture_moves(
|
|||||||
enemy_occupancies: Bitboard,
|
enemy_occupancies: Bitboard,
|
||||||
en_passant_square: Option<u8>,
|
en_passant_square: Option<u8>,
|
||||||
) -> Vec<Move> {
|
) -> Vec<Move> {
|
||||||
let mut moves: Vec<Move> = vec![];
|
let mut moves = vec![];
|
||||||
let mut b_pawns_capture_east = pawns & ((enemy_occupancies << 7) & NOT_H_FILE);
|
let mut b_pawns_capture_east = pawns & ((enemy_occupancies << 7) & NOT_H_FILE);
|
||||||
let mut b_pawns_capture_west = pawns & ((enemy_occupancies << 9) & NOT_A_FILE);
|
let mut b_pawns_capture_west = pawns & ((enemy_occupancies << 9) & NOT_A_FILE);
|
||||||
|
|
||||||
while b_pawns_capture_east != 0 {
|
while b_pawns_capture_east != 0 {
|
||||||
let from = b_pawns_capture_east.trailing_zeros();
|
let from = b_pawns_capture_east.trailing_zeros();
|
||||||
let to = from - 7;
|
let to = from - 7;
|
||||||
moves.push(Move::new(from, to));
|
if from as u64 & 0xff00 != 0 {
|
||||||
|
moves.extend([
|
||||||
|
Move::new_with_type(from, to, MoveType::PromotionCapture(Promote::Knight)),
|
||||||
|
Move::new_with_type(from, to, MoveType::PromotionCapture(Promote::Bishop)),
|
||||||
|
Move::new_with_type(from, to, MoveType::PromotionCapture(Promote::Rook)),
|
||||||
|
Move::new_with_type(from, to, MoveType::PromotionCapture(Promote::Queen)),
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
moves.push(Move::new_with_type(from, to, MoveType::Capture));
|
||||||
|
}
|
||||||
b_pawns_capture_east &= b_pawns_capture_east - 1;
|
b_pawns_capture_east &= b_pawns_capture_east - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
while b_pawns_capture_west != 0 {
|
while b_pawns_capture_west != 0 {
|
||||||
let from = b_pawns_capture_west.trailing_zeros();
|
let from = b_pawns_capture_west.trailing_zeros();
|
||||||
let to = from - 9;
|
let to = from - 9;
|
||||||
moves.push(Move::new(from, to));
|
if from as u64 & 0xff00 != 0 {
|
||||||
|
moves.extend([
|
||||||
|
Move::new_with_type(from, to, MoveType::PromotionCapture(Promote::Knight)),
|
||||||
|
Move::new_with_type(from, to, MoveType::PromotionCapture(Promote::Bishop)),
|
||||||
|
Move::new_with_type(from, to, MoveType::PromotionCapture(Promote::Rook)),
|
||||||
|
Move::new_with_type(from, to, MoveType::PromotionCapture(Promote::Queen)),
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
moves.push(Move::new_with_type(from, to, MoveType::Capture));
|
||||||
|
}
|
||||||
b_pawns_capture_west &= b_pawns_capture_west - 1;
|
b_pawns_capture_west &= b_pawns_capture_west - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(en_passant_square) = en_passant_square {
|
if let Some(en_passant_square) = en_passant_square {
|
||||||
let attacked_from = get_pawn_attacks(en_passant_square as usize, Color::White);
|
let attacked_from = get_pawn_attacks(en_passant_square as usize, Color::White);
|
||||||
let result = attacked_from & pawns;
|
let result = attacked_from & pawns;
|
||||||
moves.push(Move::new(result.trailing_zeros(), en_passant_square as u32));
|
moves.push(Move::new_with_type(
|
||||||
|
result.trailing_zeros(),
|
||||||
|
en_passant_square as u32,
|
||||||
|
MoveType::EnPassant,
|
||||||
|
));
|
||||||
};
|
};
|
||||||
moves
|
moves
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn knight_pseudo_moves(mut knights: Bitboard, occupancies: Bitboard) -> Vec<Move> {
|
pub fn knight_pseudo_moves(
|
||||||
let mut moves: Vec<Move> = vec![];
|
mut knights: Bitboard,
|
||||||
let empty = !occupancies;
|
all_occupancies: Bitboard,
|
||||||
|
own_occupancies: Bitboard,
|
||||||
|
) -> Vec<Move> {
|
||||||
|
let mut moves = vec![];
|
||||||
|
let enemy_occupancies = all_occupancies ^ own_occupancies;
|
||||||
|
|
||||||
while knights != 0 {
|
while knights != 0 {
|
||||||
let knight_square = knights.trailing_zeros() as usize;
|
let knight_square = knights.trailing_zeros() as usize;
|
||||||
let from = knight_square as u32;
|
let from = knight_square as u32;
|
||||||
let mut attacks = get_knight_attacks(knight_square) & empty;
|
let mut attacks = get_knight_attacks(knight_square) & !own_occupancies;
|
||||||
|
|
||||||
while attacks != 0 {
|
while attacks != 0 {
|
||||||
moves.push(Move::new(from, attacks.trailing_zeros()));
|
let attack_sq = attacks.trailing_zeros();
|
||||||
|
if (1_u64 << attack_sq) & enemy_occupancies != 0 {
|
||||||
|
moves.push(Move::new_with_type(from, attack_sq, MoveType::Capture));
|
||||||
|
} else {
|
||||||
|
moves.push(Move::new(from, attack_sq));
|
||||||
|
}
|
||||||
attacks &= attacks - 1;
|
attacks &= attacks - 1;
|
||||||
}
|
}
|
||||||
knights &= knights - 1;
|
knights &= knights - 1;
|
||||||
@@ -181,16 +245,21 @@ pub fn bishop_pseudo_moves(
|
|||||||
all_occupancies: Bitboard,
|
all_occupancies: Bitboard,
|
||||||
own_occupancies: Bitboard,
|
own_occupancies: Bitboard,
|
||||||
) -> Vec<Move> {
|
) -> Vec<Move> {
|
||||||
let mut moves: Vec<Move> = vec![];
|
let mut moves = vec![];
|
||||||
let empty = !own_occupancies;
|
let enemy_occupancies = all_occupancies ^ own_occupancies;
|
||||||
|
|
||||||
while bishops != 0 {
|
while bishops != 0 {
|
||||||
let bishop_square = bishops.trailing_zeros() as usize;
|
let bishop_square = bishops.trailing_zeros() as usize;
|
||||||
let from = bishop_square as u32;
|
let from = bishop_square as u32;
|
||||||
let mut attacks = get_bishop_attacks(all_occupancies, bishop_square) & empty;
|
let mut attacks = get_bishop_attacks(all_occupancies, bishop_square) & !own_occupancies;
|
||||||
|
|
||||||
while attacks != 0 {
|
while attacks != 0 {
|
||||||
moves.push(Move::new(from, attacks.trailing_zeros()));
|
let attack_sq = attacks.trailing_zeros();
|
||||||
|
if (1_u64 << attack_sq) & enemy_occupancies != 0 {
|
||||||
|
moves.push(Move::new_with_type(from, attack_sq, MoveType::Capture));
|
||||||
|
} else {
|
||||||
|
moves.push(Move::new(from, attack_sq));
|
||||||
|
}
|
||||||
attacks &= attacks - 1;
|
attacks &= attacks - 1;
|
||||||
}
|
}
|
||||||
bishops &= bishops - 1;
|
bishops &= bishops - 1;
|
||||||
@@ -203,16 +272,21 @@ pub fn rook_pseudo_moves(
|
|||||||
all_occupancies: Bitboard,
|
all_occupancies: Bitboard,
|
||||||
own_occupancies: Bitboard,
|
own_occupancies: Bitboard,
|
||||||
) -> Vec<Move> {
|
) -> Vec<Move> {
|
||||||
let mut moves: Vec<Move> = vec![];
|
let mut moves = vec![];
|
||||||
let empty = !own_occupancies;
|
let enemy_occupancies = all_occupancies ^ own_occupancies;
|
||||||
|
|
||||||
while rooks != 0 {
|
while rooks != 0 {
|
||||||
let rook_square = rooks.trailing_zeros() as usize;
|
let rook_square = rooks.trailing_zeros() as usize;
|
||||||
let from = rook_square as u32;
|
let from = rook_square as u32;
|
||||||
let mut attacks = get_rook_attacks(all_occupancies, rook_square) & empty;
|
let mut attacks = get_rook_attacks(all_occupancies, rook_square) & !own_occupancies;
|
||||||
|
|
||||||
while attacks != 0 {
|
while attacks != 0 {
|
||||||
moves.push(Move::new(from, attacks.trailing_zeros()));
|
let attack_sq = attacks.trailing_zeros();
|
||||||
|
if (1_u64 << attack_sq) & enemy_occupancies != 0 {
|
||||||
|
moves.push(Move::new_with_type(from, attack_sq, MoveType::Capture));
|
||||||
|
} else {
|
||||||
|
moves.push(Move::new(from, attack_sq));
|
||||||
|
}
|
||||||
attacks &= attacks - 1;
|
attacks &= attacks - 1;
|
||||||
}
|
}
|
||||||
rooks &= rooks - 1;
|
rooks &= rooks - 1;
|
||||||
@@ -225,16 +299,21 @@ pub fn queen_pseudo_moves(
|
|||||||
all_occupancies: Bitboard,
|
all_occupancies: Bitboard,
|
||||||
own_occupancies: Bitboard,
|
own_occupancies: Bitboard,
|
||||||
) -> Vec<Move> {
|
) -> Vec<Move> {
|
||||||
let mut moves: Vec<Move> = vec![];
|
let mut moves = vec![];
|
||||||
let empty = !own_occupancies;
|
let enemy_occupancies = all_occupancies ^ own_occupancies;
|
||||||
|
|
||||||
while queens != 0 {
|
while queens != 0 {
|
||||||
let queen_square = queens.trailing_zeros() as usize;
|
let queen_square = queens.trailing_zeros() as usize;
|
||||||
let from = queen_square as u32;
|
let from = queen_square as u32;
|
||||||
let mut attacks = get_queen_attacks(all_occupancies, queen_square) & empty;
|
let mut attacks = get_queen_attacks(all_occupancies, queen_square) & !own_occupancies;
|
||||||
|
|
||||||
while attacks != 0 {
|
while attacks != 0 {
|
||||||
moves.push(Move::new(from, attacks.trailing_zeros()));
|
let attack_sq = attacks.trailing_zeros();
|
||||||
|
if (1_u64 << attack_sq) & enemy_occupancies != 0 {
|
||||||
|
moves.push(Move::new_with_type(from, attack_sq, MoveType::Capture));
|
||||||
|
} else {
|
||||||
|
moves.push(Move::new(from, attack_sq));
|
||||||
|
}
|
||||||
attacks &= attacks - 1;
|
attacks &= attacks - 1;
|
||||||
}
|
}
|
||||||
queens &= queens - 1;
|
queens &= queens - 1;
|
||||||
@@ -249,14 +328,19 @@ pub fn king_pseudo_moves(
|
|||||||
board: &Board,
|
board: &Board,
|
||||||
color: Color,
|
color: Color,
|
||||||
) -> Vec<Move> {
|
) -> Vec<Move> {
|
||||||
let mut moves: Vec<Move> = vec![];
|
let mut moves = vec![];
|
||||||
let empty: u64 = !own_occupancies;
|
|
||||||
let king_square = king.trailing_zeros() as usize;
|
let king_square = king.trailing_zeros() as usize;
|
||||||
let from = king_square as u32;
|
let from = king_square as u32;
|
||||||
let mut attacks = get_king_attacks(king_square) & empty;
|
let mut attacks = get_king_attacks(king_square) & !own_occupancies;
|
||||||
|
let enemy_occupancies = all_occupancies ^ own_occupancies;
|
||||||
|
|
||||||
while attacks != 0 {
|
while attacks != 0 {
|
||||||
moves.push(Move::new(from, attacks.trailing_zeros()));
|
let attack_sq = attacks.trailing_zeros();
|
||||||
|
if (1_u64 << attack_sq) & enemy_occupancies != 0 {
|
||||||
|
moves.push(Move::new_with_type(from, attack_sq, MoveType::Capture));
|
||||||
|
} else {
|
||||||
|
moves.push(Move::new(from, attack_sq));
|
||||||
|
}
|
||||||
attacks &= attacks - 1;
|
attacks &= attacks - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -273,7 +357,7 @@ fn king_castling_moves(board: &Board, color: Color, all_occupancies: Bitboard) -
|
|||||||
|
|
||||||
let mut add_move_if_empty_path = |path_mask, king_to| {
|
let mut add_move_if_empty_path = |path_mask, king_to| {
|
||||||
if all_occupancies & path_mask != 0 {
|
if all_occupancies & path_mask != 0 {
|
||||||
moves.push(Move::new(king_from, king_to))
|
moves.push(Move::new_with_type(king_from, king_to, MoveType::Castle))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -331,19 +415,19 @@ mod tests {
|
|||||||
let new_game = from_fen(FEN_PAWN_MOVES)?;
|
let new_game = from_fen(FEN_PAWN_MOVES)?;
|
||||||
let expected = vec![
|
let expected = vec![
|
||||||
Move::new(9, 17),
|
Move::new(9, 17),
|
||||||
Move::new(9, 25),
|
Move::new_with_type(9, 25, MoveType::DoublePush),
|
||||||
Move::new(10, 18),
|
Move::new(10, 18),
|
||||||
Move::new(10, 26),
|
Move::new_with_type(10, 26, MoveType::DoublePush),
|
||||||
Move::new(14, 22),
|
Move::new(14, 22),
|
||||||
Move::new(14, 30),
|
Move::new_with_type(14, 30, MoveType::DoublePush),
|
||||||
Move::new(15, 23),
|
Move::new(15, 23),
|
||||||
Move::new(15, 31),
|
Move::new_with_type(15, 31, MoveType::DoublePush),
|
||||||
Move::new(29, 37),
|
Move::new(29, 37),
|
||||||
Move::new(32, 40),
|
Move::new(32, 40),
|
||||||
Move::new(32, 41),
|
Move::new_with_type(32, 41, MoveType::Capture),
|
||||||
Move::new(36, 43),
|
Move::new_with_type(36, 43, MoveType::Capture),
|
||||||
Move::new(36, 44),
|
Move::new(36, 44),
|
||||||
Move::new(36, 45),
|
Move::new_with_type(36, 45, MoveType::Capture),
|
||||||
];
|
];
|
||||||
|
|
||||||
let mut actual = new_game.board.pseudo_moves(Color::White, Kind::Pawn);
|
let mut actual = new_game.board.pseudo_moves(Color::White, Kind::Pawn);
|
||||||
@@ -351,12 +435,12 @@ mod tests {
|
|||||||
assert_eq!(expected, actual);
|
assert_eq!(expected, actual);
|
||||||
|
|
||||||
let expected = vec![
|
let expected = vec![
|
||||||
Move::new(41, 32),
|
Move::new_with_type(41, 32, MoveType::Capture),
|
||||||
Move::new(41, 33),
|
Move::new(41, 33),
|
||||||
Move::new(43, 35),
|
Move::new(43, 35),
|
||||||
Move::new(43, 36),
|
Move::new_with_type(43, 36, MoveType::Capture),
|
||||||
Move::new(48, 40),
|
Move::new(48, 40),
|
||||||
Move::new(55, 39),
|
Move::new_with_type(55, 39, MoveType::DoublePush),
|
||||||
Move::new(55, 47),
|
Move::new(55, 47),
|
||||||
];
|
];
|
||||||
let mut actual = new_game.board.pseudo_moves(Color::Black, Kind::Pawn);
|
let mut actual = new_game.board.pseudo_moves(Color::Black, Kind::Pawn);
|
||||||
@@ -380,7 +464,7 @@ mod tests {
|
|||||||
Move::new(21, 11),
|
Move::new(21, 11),
|
||||||
Move::new(21, 31),
|
Move::new(21, 31),
|
||||||
Move::new(21, 36),
|
Move::new(21, 36),
|
||||||
Move::new(21, 38),
|
Move::new_with_type(21, 38, MoveType::Capture),
|
||||||
];
|
];
|
||||||
let mut actual = new_game.board.pseudo_moves(Color::White, Kind::Knight);
|
let mut actual = new_game.board.pseudo_moves(Color::White, Kind::Knight);
|
||||||
actual.sort();
|
actual.sort();
|
||||||
@@ -403,7 +487,7 @@ mod tests {
|
|||||||
Move::new(26, 35),
|
Move::new(26, 35),
|
||||||
Move::new(26, 40),
|
Move::new(26, 40),
|
||||||
Move::new(26, 44),
|
Move::new(26, 44),
|
||||||
Move::new(26, 53),
|
Move::new_with_type(26, 53, MoveType::Capture),
|
||||||
];
|
];
|
||||||
let mut actual = new_game.board.pseudo_moves(Color::White, Kind::Bishop);
|
let mut actual = new_game.board.pseudo_moves(Color::White, Kind::Bishop);
|
||||||
actual.sort();
|
actual.sort();
|
||||||
@@ -424,14 +508,14 @@ mod tests {
|
|||||||
Move::new(11, 35),
|
Move::new(11, 35),
|
||||||
Move::new(11, 43),
|
Move::new(11, 43),
|
||||||
Move::new(11, 51),
|
Move::new(11, 51),
|
||||||
Move::new(11, 59),
|
Move::new_with_type(11, 59, MoveType::Capture),
|
||||||
Move::new(12, 13),
|
Move::new(12, 13),
|
||||||
Move::new(12, 14),
|
Move::new(12, 14),
|
||||||
Move::new(12, 15),
|
Move::new(12, 15),
|
||||||
Move::new(12, 20),
|
Move::new(12, 20),
|
||||||
Move::new(12, 28),
|
Move::new(12, 28),
|
||||||
Move::new(12, 36),
|
Move::new(12, 36),
|
||||||
Move::new(12, 44),
|
Move::new_with_type(12, 44, MoveType::Capture),
|
||||||
];
|
];
|
||||||
let mut actual = new_game.board.pseudo_moves(Color::White, Kind::Rook);
|
let mut actual = new_game.board.pseudo_moves(Color::White, Kind::Rook);
|
||||||
actual.sort();
|
actual.sort();
|
||||||
@@ -454,7 +538,7 @@ mod tests {
|
|||||||
Move::new(17, 25),
|
Move::new(17, 25),
|
||||||
Move::new(17, 33),
|
Move::new(17, 33),
|
||||||
Move::new(17, 41),
|
Move::new(17, 41),
|
||||||
Move::new(17, 49),
|
Move::new_with_type(17, 49, MoveType::Capture),
|
||||||
];
|
];
|
||||||
let mut actual = new_game.board.pseudo_moves(Color::White, Kind::Queen);
|
let mut actual = new_game.board.pseudo_moves(Color::White, Kind::Queen);
|
||||||
actual.sort();
|
actual.sort();
|
||||||
@@ -487,7 +571,7 @@ mod tests {
|
|||||||
assert_eq!(expected, actual);
|
assert_eq!(expected, actual);
|
||||||
|
|
||||||
let new_game_2 = from_fen(FEN_KING_MOVES[1])?;
|
let new_game_2 = from_fen(FEN_KING_MOVES[1])?;
|
||||||
let expected = vec![Move::new(4, 2), Move::new(4, 3)];
|
let expected = vec![Move::new_with_type(4, 2, MoveType::Castle), Move::new(4, 3)];
|
||||||
let mut actual = new_game_2.board.pseudo_moves(Color::White, Kind::King);
|
let mut actual = new_game_2.board.pseudo_moves(Color::White, Kind::King);
|
||||||
actual.sort();
|
actual.sort();
|
||||||
assert_eq!(expected, actual);
|
assert_eq!(expected, actual);
|
||||||
@@ -498,7 +582,7 @@ mod tests {
|
|||||||
Move::new(60, 53),
|
Move::new(60, 53),
|
||||||
Move::new(60, 59),
|
Move::new(60, 59),
|
||||||
Move::new(60, 61),
|
Move::new(60, 61),
|
||||||
Move::new(60, 62),
|
Move::new_with_type(60, 62, MoveType::Castle),
|
||||||
];
|
];
|
||||||
let mut actual = new_game_3.board.pseudo_moves(Color::Black, Kind::King);
|
let mut actual = new_game_3.board.pseudo_moves(Color::Black, Kind::King);
|
||||||
actual.sort();
|
actual.sort();
|
||||||
|
|||||||
Reference in New Issue
Block a user