finished make_move
This commit is contained in:
parent
b72e1e55eb
commit
5e19c1e494
6 changed files with 399 additions and 130 deletions
427
src/board.rs
427
src/board.rs
|
|
@ -1,20 +1,27 @@
|
||||||
use crate::square::Square;
|
|
||||||
use std::mem;
|
|
||||||
use crate::r#move::*;
|
use crate::r#move::*;
|
||||||
|
use crate::square::{Square, SQUARES};
|
||||||
|
use std::mem;
|
||||||
use std::ops::Not;
|
use std::ops::Not;
|
||||||
|
|
||||||
pub const CASTLING_WK: u8 = 1;
|
pub const CASTLING_WK_FLAG: u8 = 1;
|
||||||
pub const CASTLING_WK_MASK: u64 = 96; // F1 G1
|
pub const CASTLING_WK_MASK: u64 = 96; // F1 G1
|
||||||
|
pub const CASTLING_WK_K_POS_MASK: u64 = 16; // E1
|
||||||
|
pub const CASTLING_WK_R_POS_MASK: u64 = 128; // H1
|
||||||
|
|
||||||
pub const CASTLING_WQ: u8 = 2;
|
pub const CASTLING_WQ_FLAG: u8 = 2;
|
||||||
pub const CASTLING_WQ_MASK: u64 = 14; // B1 C1 D1
|
pub const CASTLING_WQ_MASK: u64 = 14; // B1 C1 D1
|
||||||
|
pub const CASTLING_WQ_K_POS_MASK: u64 = 16; // E1
|
||||||
|
pub const CASTLING_WQ_R_POS_MASK: u64 = 1; // A1
|
||||||
|
|
||||||
pub const CASTLING_BK: u8 = 4;
|
pub const CASTLING_BK_FLAG: u8 = 4;
|
||||||
pub const CASTLING_BK_MASK: u64 = 6917529027641081856; // F8 G8
|
pub const CASTLING_BK_MASK: u64 = 6917529027641081856; // F8 G8
|
||||||
|
pub const CASTLING_BK_K_POS_MASK: u64 = 1152921504606846976; // E8
|
||||||
|
pub const CASTLING_BK_R_POS_MASK: u64 = 9223372036854775808; // H8
|
||||||
|
|
||||||
pub const CASTLING_BQ: u8 = 8;
|
pub const CASTLING_BQ_FLAG: u8 = 8;
|
||||||
pub const CASTLING_BQ_MASK: u64 = 1008806316530991104; // B8 C8 D8
|
pub const CASTLING_BQ_MASK: u64 = 1008806316530991104; // B8 C8 D8
|
||||||
|
pub const CASTLING_BQ_K_POS_MASK: u64 = 1152921504606846976; // E8
|
||||||
|
pub const CASTLING_BQ_R_POS_MASK: u64 = 72057594037927936; // A8
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
|
|
@ -51,13 +58,15 @@ pub const PIECE_TYPES: [PieceType; 6] = [
|
||||||
PieceType::Bishop,
|
PieceType::Bishop,
|
||||||
PieceType::Rook,
|
PieceType::Rook,
|
||||||
PieceType::Queen,
|
PieceType::Queen,
|
||||||
PieceType::King];
|
PieceType::King,
|
||||||
|
];
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub struct Board {
|
pub struct Board {
|
||||||
pub side_to_move: Color,
|
pub side_to_move: Color,
|
||||||
|
|
||||||
pub pieces: [[u64; 2]; 6],
|
pub pieces: [[u64; 2]; 6],
|
||||||
|
pub pieces_on_squares: [Option<PieceType>; 64], // <-- ADDED
|
||||||
|
|
||||||
pub occupied: [u64; 2],
|
pub occupied: [u64; 2],
|
||||||
pub all_occupied: u64,
|
pub all_occupied: u64,
|
||||||
|
|
@ -76,9 +85,10 @@ impl Board {
|
||||||
pub fn from_fen(fen: &str) -> Self {
|
pub fn from_fen(fen: &str) -> Self {
|
||||||
let mut parts = fen.split_whitespace();
|
let mut parts = fen.split_whitespace();
|
||||||
|
|
||||||
// Initialisiere das 2D-Array
|
// Initialisiere die Arrays
|
||||||
let mut pieces = [[0u64; 2]; 6];
|
let mut pieces = [[0u64; 2]; 6];
|
||||||
let mut occupied = [0u64; 2];
|
let mut occupied = [0u64; 2];
|
||||||
|
let mut pieces_on_squares = [None; 64]; // <-- ADDED
|
||||||
|
|
||||||
// Part 1: Piece placement
|
// Part 1: Piece placement
|
||||||
let placement = parts.next().unwrap_or("");
|
let placement = parts.next().unwrap_or("");
|
||||||
|
|
@ -99,24 +109,60 @@ impl Board {
|
||||||
let color_idx = Color::White as usize;
|
let color_idx = Color::White as usize;
|
||||||
occupied[color_idx] |= mask;
|
occupied[color_idx] |= mask;
|
||||||
match c {
|
match c {
|
||||||
'P' => pieces[PieceType::Pawn as usize][color_idx] |= mask,
|
'P' => {
|
||||||
'N' => pieces[PieceType::Knight as usize][color_idx] |= mask,
|
pieces[PieceType::Pawn as usize][color_idx] |= mask;
|
||||||
'B' => pieces[PieceType::Bishop as usize][color_idx] |= mask,
|
pieces_on_squares[sq as usize] = Some(PieceType::Pawn); // <-- ADDED
|
||||||
'R' => pieces[PieceType::Rook as usize][color_idx] |= mask,
|
}
|
||||||
'Q' => pieces[PieceType::Queen as usize][color_idx] |= mask,
|
'N' => {
|
||||||
'K' => pieces[PieceType::King as usize][color_idx] |= mask,
|
pieces[PieceType::Knight as usize][color_idx] |= mask;
|
||||||
|
pieces_on_squares[sq as usize] = Some(PieceType::Knight); // <-- ADDED
|
||||||
|
}
|
||||||
|
'B' => {
|
||||||
|
pieces[PieceType::Bishop as usize][color_idx] |= mask;
|
||||||
|
pieces_on_squares[sq as usize] = Some(PieceType::Bishop); // <-- ADDED
|
||||||
|
}
|
||||||
|
'R' => {
|
||||||
|
pieces[PieceType::Rook as usize][color_idx] |= mask;
|
||||||
|
pieces_on_squares[sq as usize] = Some(PieceType::Rook); // <-- ADDED
|
||||||
|
}
|
||||||
|
'Q' => {
|
||||||
|
pieces[PieceType::Queen as usize][color_idx] |= mask;
|
||||||
|
pieces_on_squares[sq as usize] = Some(PieceType::Queen); // <-- ADDED
|
||||||
|
}
|
||||||
|
'K' => {
|
||||||
|
pieces[PieceType::King as usize][color_idx] |= mask;
|
||||||
|
pieces_on_squares[sq as usize] = Some(PieceType::King); // <-- ADDED
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let color_idx = Color::Black as usize;
|
let color_idx = Color::Black as usize;
|
||||||
occupied[color_idx] |= mask;
|
occupied[color_idx] |= mask;
|
||||||
match c {
|
match c {
|
||||||
'p' => pieces[PieceType::Pawn as usize][color_idx] |= mask,
|
'p' => {
|
||||||
'n' => pieces[PieceType::Knight as usize][color_idx] |= mask,
|
pieces[PieceType::Pawn as usize][color_idx] |= mask;
|
||||||
'b' => pieces[PieceType::Bishop as usize][color_idx] |= mask,
|
pieces_on_squares[sq as usize] = Some(PieceType::Pawn); // <-- ADDED
|
||||||
'r' => pieces[PieceType::Rook as usize][color_idx] |= mask,
|
}
|
||||||
'q' => pieces[PieceType::Queen as usize][color_idx] |= mask,
|
'n' => {
|
||||||
'k' => pieces[PieceType::King as usize][color_idx] |= mask,
|
pieces[PieceType::Knight as usize][color_idx] |= mask;
|
||||||
|
pieces_on_squares[sq as usize] = Some(PieceType::Knight); // <-- ADDED
|
||||||
|
}
|
||||||
|
'b' => {
|
||||||
|
pieces[PieceType::Bishop as usize][color_idx] |= mask;
|
||||||
|
pieces_on_squares[sq as usize] = Some(PieceType::Bishop); // <-- ADDED
|
||||||
|
}
|
||||||
|
'r' => {
|
||||||
|
pieces[PieceType::Rook as usize][color_idx] |= mask;
|
||||||
|
pieces_on_squares[sq as usize] = Some(PieceType::Rook); // <-- ADDED
|
||||||
|
}
|
||||||
|
'q' => {
|
||||||
|
pieces[PieceType::Queen as usize][color_idx] |= mask;
|
||||||
|
pieces_on_squares[sq as usize] = Some(PieceType::Queen); // <-- ADDED
|
||||||
|
}
|
||||||
|
'k' => {
|
||||||
|
pieces[PieceType::King as usize][color_idx] |= mask;
|
||||||
|
pieces_on_squares[sq as usize] = Some(PieceType::King); // <-- ADDED
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -133,10 +179,18 @@ impl Board {
|
||||||
// Part 3: Castling rights
|
// Part 3: Castling rights
|
||||||
let mut castling_rights = 0u8;
|
let mut castling_rights = 0u8;
|
||||||
if let Some(castle_str) = parts.next() {
|
if let Some(castle_str) = parts.next() {
|
||||||
if castle_str.contains('K') { castling_rights |= CASTLING_WK; }
|
if castle_str.contains('K') {
|
||||||
if castle_str.contains('Q') { castling_rights |= CASTLING_WQ; }
|
castling_rights |= CASTLING_WK_FLAG;
|
||||||
if castle_str.contains('k') { castling_rights |= CASTLING_BK; }
|
}
|
||||||
if castle_str.contains('q') { castling_rights |= CASTLING_BQ; }
|
if castle_str.contains('Q') {
|
||||||
|
castling_rights |= CASTLING_WQ_FLAG;
|
||||||
|
}
|
||||||
|
if castle_str.contains('k') {
|
||||||
|
castling_rights |= CASTLING_BK_FLAG;
|
||||||
|
}
|
||||||
|
if castle_str.contains('q') {
|
||||||
|
castling_rights |= CASTLING_BQ_FLAG;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Part 4: En passant target
|
// Part 4: En passant target
|
||||||
|
|
@ -163,7 +217,8 @@ impl Board {
|
||||||
|
|
||||||
Board {
|
Board {
|
||||||
side_to_move,
|
side_to_move,
|
||||||
pieces, // Geändertes Feld
|
pieces,
|
||||||
|
pieces_on_squares, // <-- ADDED
|
||||||
occupied,
|
occupied,
|
||||||
all_occupied,
|
all_occupied,
|
||||||
empty_squares,
|
empty_squares,
|
||||||
|
|
@ -206,15 +261,27 @@ impl Board {
|
||||||
|
|
||||||
// Part 2: Active color
|
// Part 2: Active color
|
||||||
fen.push(' ');
|
fen.push(' ');
|
||||||
fen.push(if self.side_to_move == Color::White { 'w' } else { 'b' });
|
fen.push(if self.side_to_move == Color::White {
|
||||||
|
'w'
|
||||||
|
} else {
|
||||||
|
'b'
|
||||||
|
});
|
||||||
|
|
||||||
// Part 3: Castling rights
|
// Part 3: Castling rights
|
||||||
fen.push(' ');
|
fen.push(' ');
|
||||||
let mut castle_str = String::new();
|
let mut castle_str = String::new();
|
||||||
if (self.castling_rights & CASTLING_WK) != 0 { castle_str.push('K'); }
|
if (self.castling_rights & CASTLING_WK_FLAG) != 0 {
|
||||||
if (self.castling_rights & CASTLING_WQ) != 0 { castle_str.push('Q'); }
|
castle_str.push('K');
|
||||||
if (self.castling_rights & CASTLING_BK) != 0 { castle_str.push('k'); }
|
}
|
||||||
if (self.castling_rights & CASTLING_BQ) != 0 { castle_str.push('q'); }
|
if (self.castling_rights & CASTLING_WQ_FLAG) != 0 {
|
||||||
|
castle_str.push('Q');
|
||||||
|
}
|
||||||
|
if (self.castling_rights & CASTLING_BK_FLAG) != 0 {
|
||||||
|
castle_str.push('k');
|
||||||
|
}
|
||||||
|
if (self.castling_rights & CASTLING_BQ_FLAG) != 0 {
|
||||||
|
castle_str.push('q');
|
||||||
|
}
|
||||||
|
|
||||||
if castle_str.is_empty() {
|
if castle_str.is_empty() {
|
||||||
fen.push('-');
|
fen.push('-');
|
||||||
|
|
@ -250,18 +317,42 @@ impl Board {
|
||||||
let white = Color::White as usize;
|
let white = Color::White as usize;
|
||||||
let black = Color::Black as usize;
|
let black = Color::Black as usize;
|
||||||
|
|
||||||
if (self.pieces[PieceType::Pawn as usize][white] & sq_mask) != 0 { return Some('P'); }
|
if (self.pieces[PieceType::Pawn as usize][white] & sq_mask) != 0 {
|
||||||
if (self.pieces[PieceType::Pawn as usize][black] & sq_mask) != 0 { return Some('p'); }
|
return Some('P');
|
||||||
if (self.pieces[PieceType::Knight as usize][white] & sq_mask) != 0 { return Some('N'); }
|
}
|
||||||
if (self.pieces[PieceType::Knight as usize][black] & sq_mask) != 0 { return Some('n'); }
|
if (self.pieces[PieceType::Pawn as usize][black] & sq_mask) != 0 {
|
||||||
if (self.pieces[PieceType::Bishop as usize][white] & sq_mask) != 0 { return Some('B'); }
|
return Some('p');
|
||||||
if (self.pieces[PieceType::Bishop as usize][black] & sq_mask) != 0 { return Some('b'); }
|
}
|
||||||
if (self.pieces[PieceType::Rook as usize][white] & sq_mask) != 0 { return Some('R'); }
|
if (self.pieces[PieceType::Knight as usize][white] & sq_mask) != 0 {
|
||||||
if (self.pieces[PieceType::Rook as usize][black] & sq_mask) != 0 { return Some('r'); }
|
return Some('N');
|
||||||
if (self.pieces[PieceType::Queen as usize][white] & sq_mask) != 0 { return Some('Q'); }
|
}
|
||||||
if (self.pieces[PieceType::Queen as usize][black] & sq_mask) != 0 { return Some('q'); }
|
if (self.pieces[PieceType::Knight as usize][black] & sq_mask) != 0 {
|
||||||
if (self.pieces[PieceType::King as usize][white] & sq_mask) != 0 { return Some('K'); }
|
return Some('n');
|
||||||
if (self.pieces[PieceType::King as usize][black] & sq_mask) != 0 { return Some('k'); }
|
}
|
||||||
|
if (self.pieces[PieceType::Bishop as usize][white] & sq_mask) != 0 {
|
||||||
|
return Some('B');
|
||||||
|
}
|
||||||
|
if (self.pieces[PieceType::Bishop as usize][black] & sq_mask) != 0 {
|
||||||
|
return Some('b');
|
||||||
|
}
|
||||||
|
if (self.pieces[PieceType::Rook as usize][white] & sq_mask) != 0 {
|
||||||
|
return Some('R');
|
||||||
|
}
|
||||||
|
if (self.pieces[PieceType::Rook as usize][black] & sq_mask) != 0 {
|
||||||
|
return Some('r');
|
||||||
|
}
|
||||||
|
if (self.pieces[PieceType::Queen as usize][white] & sq_mask) != 0 {
|
||||||
|
return Some('Q');
|
||||||
|
}
|
||||||
|
if (self.pieces[PieceType::Queen as usize][black] & sq_mask) != 0 {
|
||||||
|
return Some('q');
|
||||||
|
}
|
||||||
|
if (self.pieces[PieceType::King as usize][white] & sq_mask) != 0 {
|
||||||
|
return Some('K');
|
||||||
|
}
|
||||||
|
if (self.pieces[PieceType::King as usize][black] & sq_mask) != 0 {
|
||||||
|
return Some('k');
|
||||||
|
}
|
||||||
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
@ -286,7 +377,6 @@ impl Board {
|
||||||
println!(" a b c d e f g h\n");
|
println!(" a b c d e f g h\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Prints a single bitboard (u64) as an 8x8 grid for debugging.
|
/// Prints a single bitboard (u64) as an 8x8 grid for debugging.
|
||||||
fn print_bitboard(&self, name: &str, bitboard: u64) {
|
fn print_bitboard(&self, name: &str, bitboard: u64) {
|
||||||
println!("--- {} ---", name);
|
println!("--- {} ---", name);
|
||||||
|
|
@ -319,17 +409,35 @@ impl Board {
|
||||||
self.print_bitboard("White Pawns", self.pieces[PieceType::Pawn as usize][white]);
|
self.print_bitboard("White Pawns", self.pieces[PieceType::Pawn as usize][white]);
|
||||||
self.print_bitboard("Black Pawns", self.pieces[PieceType::Pawn as usize][black]);
|
self.print_bitboard("Black Pawns", self.pieces[PieceType::Pawn as usize][black]);
|
||||||
|
|
||||||
self.print_bitboard("White Knights", self.pieces[PieceType::Knight as usize][white]);
|
self.print_bitboard(
|
||||||
self.print_bitboard("Black Knights", self.pieces[PieceType::Knight as usize][black]);
|
"White Knights",
|
||||||
|
self.pieces[PieceType::Knight as usize][white],
|
||||||
|
);
|
||||||
|
self.print_bitboard(
|
||||||
|
"Black Knights",
|
||||||
|
self.pieces[PieceType::Knight as usize][black],
|
||||||
|
);
|
||||||
|
|
||||||
self.print_bitboard("White Bishops", self.pieces[PieceType::Bishop as usize][white]);
|
self.print_bitboard(
|
||||||
self.print_bitboard("Black Bishops", self.pieces[PieceType::Bishop as usize][black]);
|
"White Bishops",
|
||||||
|
self.pieces[PieceType::Bishop as usize][white],
|
||||||
|
);
|
||||||
|
self.print_bitboard(
|
||||||
|
"Black Bishops",
|
||||||
|
self.pieces[PieceType::Bishop as usize][black],
|
||||||
|
);
|
||||||
|
|
||||||
self.print_bitboard("White Rooks", self.pieces[PieceType::Rook as usize][white]);
|
self.print_bitboard("White Rooks", self.pieces[PieceType::Rook as usize][white]);
|
||||||
self.print_bitboard("Black Rooks", self.pieces[PieceType::Rook as usize][black]);
|
self.print_bitboard("Black Rooks", self.pieces[PieceType::Rook as usize][black]);
|
||||||
|
|
||||||
self.print_bitboard("White Queens", self.pieces[PieceType::Queen as usize][white]);
|
self.print_bitboard(
|
||||||
self.print_bitboard("Black Queens", self.pieces[PieceType::Queen as usize][black]);
|
"White Queens",
|
||||||
|
self.pieces[PieceType::Queen as usize][white],
|
||||||
|
);
|
||||||
|
self.print_bitboard(
|
||||||
|
"Black Queens",
|
||||||
|
self.pieces[PieceType::Queen as usize][black],
|
||||||
|
);
|
||||||
|
|
||||||
self.print_bitboard("White King", self.pieces[PieceType::King as usize][white]);
|
self.print_bitboard("White King", self.pieces[PieceType::King as usize][white]);
|
||||||
self.print_bitboard("Black King", self.pieces[PieceType::King as usize][black]);
|
self.print_bitboard("Black King", self.pieces[PieceType::King as usize][black]);
|
||||||
|
|
@ -343,63 +451,196 @@ impl Board {
|
||||||
println!("============================================\n");
|
println!("============================================\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn capture_black_piece(&mut self, target_square_bitboard: u64) -> PieceType {
|
fn clear_square(&mut self, target_square: Square, color: Color) -> PieceType {
|
||||||
|
let target_square_bitboard = target_square.to_bitboard();
|
||||||
|
|
||||||
|
// update occupancy helper bitboards
|
||||||
|
self.occupied[color as usize] ^= target_square_bitboard;
|
||||||
|
self.all_occupied ^= target_square_bitboard;
|
||||||
|
self.empty_squares |= target_square_bitboard;
|
||||||
|
|
||||||
|
self.pieces_on_squares[target_square as usize] = None; // <-- ADDED
|
||||||
|
|
||||||
for piece_type in PIECE_TYPES {
|
for piece_type in PIECE_TYPES {
|
||||||
if self.pieces[piece_type as usize][Color::Black as usize] & target_square_bitboard > 0 {
|
if self.pieces[piece_type as usize][color as usize] & target_square_bitboard > 0 {
|
||||||
self.pieces[piece_type as usize][Color::Black as usize] ^= target_square_bitboard;
|
self.pieces[piece_type as usize][color as usize] ^= target_square_bitboard;
|
||||||
return piece_type;
|
return piece_type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
panic!("fn 'capture_black_piece' failed: no piece found");
|
panic!("fn 'clear_square' failed: no piece found");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn capture_white_piece(&mut self, target_square_bitboard: u64) -> PieceType {
|
fn remove_specific_piece(
|
||||||
for piece_type in PIECE_TYPES {
|
&mut self,
|
||||||
if self.pieces[piece_type as usize][Color::White as usize] & target_square_bitboard > 0 {
|
target_square: Square,
|
||||||
self.pieces[piece_type as usize][Color::White as usize] ^= target_square_bitboard;
|
color: Color,
|
||||||
return piece_type;
|
piece_type: PieceType,
|
||||||
}
|
) {
|
||||||
}
|
let target_square_bitboard = target_square.to_bitboard();
|
||||||
panic!("fn 'capture_white_piece' failed: no piece found");
|
self.pieces[piece_type as usize][color as usize] ^= target_square_bitboard;
|
||||||
|
|
||||||
|
self.pieces_on_squares[target_square as usize] = None; // <-- ADDED
|
||||||
|
|
||||||
|
// update occupancy helper bitboards
|
||||||
|
self.occupied[color as usize] ^= target_square_bitboard;
|
||||||
|
self.all_occupied ^= target_square_bitboard;
|
||||||
|
self.empty_squares |= target_square_bitboard;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn put_white_piece(&mut self, target_square_bitboard: u64, piece_type: PieceType) {
|
fn put_piece(&mut self, target_square: Square, color: Color, piece_type: PieceType) {
|
||||||
self.pieces[piece_type as usize][Color::White as usize] |= target_square_bitboard;
|
let target_square_bitboard = target_square.to_bitboard();
|
||||||
}
|
self.pieces[piece_type as usize][color as usize] |= target_square_bitboard;
|
||||||
|
|
||||||
fn put_black_piece(&mut self, target_square_bitboard: u64, piece_type: PieceType) {
|
self.pieces_on_squares[target_square as usize] = Some(piece_type); // <-- ADDED
|
||||||
self.pieces[piece_type as usize][Color::Black as usize] |= target_square_bitboard;
|
|
||||||
|
// update occupancy helper bitboards
|
||||||
|
self.occupied[color as usize] |= target_square_bitboard;
|
||||||
|
self.all_occupied |= target_square_bitboard;
|
||||||
|
self.empty_squares ^= target_square_bitboard;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn make_move(&mut self, mv: Move) -> UndoMove {
|
pub fn make_move(&mut self, mv: Move) -> UndoMove {
|
||||||
// TODO implement .get_from, .get_to, .get_flag
|
let from = mv.get_from();
|
||||||
let from = mv.value()& MOVE_FROM_MASK;
|
let to = mv.get_to();
|
||||||
let to = (mv.value() & MOVE_TO_MASK) >> 6;
|
let flags = mv.get_flags();
|
||||||
let flag = mv.value() & MOVE_FLAG_MASK;
|
|
||||||
|
|
||||||
// TODO castle, en passant, promotion
|
let old_en_passant_target: Option<Square> = self.en_passant_target;
|
||||||
if self.side_to_move == Color::White {
|
let old_castling_rights: u8 = self.castling_rights;
|
||||||
return if flag & MOVE_FLAG_CAPTURE > 0 { // Capture
|
let old_halfmove_clock: u8 = self.halfmove_clock;
|
||||||
let piece_type_from = self.capture_white_piece(1_u64 << from);
|
|
||||||
let piece_type_capture = self.capture_black_piece(1_u64 << to);
|
// needed for half move tracking
|
||||||
self.put_white_piece(1_u64 << to, piece_type_from);
|
let old_friendly_pawns = self.pieces[PieceType::Pawn as usize][self.side_to_move as usize];
|
||||||
UndoMove::new(mv,
|
let old_total_pieces = self.all_occupied.count_ones();
|
||||||
Some(piece_type_capture),
|
|
||||||
self.en_passant_target,
|
let mut opt_captured_piece: Option<PieceType> = None;
|
||||||
self.castling_rights,
|
let mut opt_en_passant_target: Option<Square> = None;
|
||||||
self.halfmove_clock)
|
|
||||||
} else { // No capture
|
match flags {
|
||||||
let piece_type_from = self.capture_white_piece(1_u64 << from);
|
MOVE_FLAG_QUIET => {
|
||||||
self.put_white_piece(1_u64 << to, piece_type_from);
|
let piece_type_from = self.clear_square(from, self.side_to_move);
|
||||||
UndoMove::new(mv,
|
self.put_piece(to, self.side_to_move, piece_type_from);
|
||||||
None,
|
}
|
||||||
self.en_passant_target,
|
MOVE_FLAG_CAPTURE => {
|
||||||
self.castling_rights,
|
let piece_type_from = self.clear_square(from, self.side_to_move);
|
||||||
self.halfmove_clock)
|
opt_captured_piece = Some(self.clear_square(to, !self.side_to_move));
|
||||||
|
self.put_piece(to, self.side_to_move, piece_type_from);
|
||||||
|
}
|
||||||
|
MOVE_FLAG_DOUBLE_PAWN => {
|
||||||
|
let piece_type_from = self.clear_square(from, self.side_to_move);
|
||||||
|
self.put_piece(to, self.side_to_move, piece_type_from);
|
||||||
|
opt_en_passant_target = Some(to + (self.side_to_move as i8 * 16 - 8));
|
||||||
|
}
|
||||||
|
MOVE_FLAG_PROMO_Q => {
|
||||||
|
self.remove_specific_piece(from, self.side_to_move, PieceType::Pawn);
|
||||||
|
self.put_piece(to, self.side_to_move, PieceType::Queen);
|
||||||
|
}
|
||||||
|
MOVE_FLAG_PROMO_N => {
|
||||||
|
self.remove_specific_piece(from, self.side_to_move, PieceType::Pawn);
|
||||||
|
self.put_piece(to, self.side_to_move, PieceType::Knight);
|
||||||
|
}
|
||||||
|
MOVE_FLAG_PROMO_B => {
|
||||||
|
self.remove_specific_piece(from, self.side_to_move, PieceType::Pawn);
|
||||||
|
self.put_piece(to, self.side_to_move, PieceType::Bishop);
|
||||||
|
}
|
||||||
|
MOVE_FLAG_PROMO_R => {
|
||||||
|
self.remove_specific_piece(from, self.side_to_move, PieceType::Pawn);
|
||||||
|
self.put_piece(to, self.side_to_move, PieceType::Rook);
|
||||||
|
}
|
||||||
|
MOVE_FLAG_PROMO_Q_CAP => {
|
||||||
|
self.remove_specific_piece(from, self.side_to_move, PieceType::Pawn);
|
||||||
|
opt_captured_piece = Some(self.clear_square(to, !self.side_to_move));
|
||||||
|
self.put_piece(to, self.side_to_move, PieceType::Queen);
|
||||||
|
}
|
||||||
|
MOVE_FLAG_PROMO_N_CAP => {
|
||||||
|
self.remove_specific_piece(from, self.side_to_move, PieceType::Pawn);
|
||||||
|
opt_captured_piece = Some(self.clear_square(to, !self.side_to_move));
|
||||||
|
self.put_piece(to, self.side_to_move, PieceType::Knight);
|
||||||
|
}
|
||||||
|
MOVE_FLAG_PROMO_B_CAP => {
|
||||||
|
self.remove_specific_piece(from, self.side_to_move, PieceType::Pawn);
|
||||||
|
opt_captured_piece = Some(self.clear_square(to, !self.side_to_move));
|
||||||
|
self.put_piece(to, self.side_to_move, PieceType::Bishop);
|
||||||
|
}
|
||||||
|
MOVE_FLAG_PROMO_R_CAP => {
|
||||||
|
self.remove_specific_piece(from, self.side_to_move, PieceType::Pawn);
|
||||||
|
opt_captured_piece = Some(self.clear_square(to, !self.side_to_move));
|
||||||
|
self.put_piece(to, self.side_to_move, PieceType::Rook);
|
||||||
|
}
|
||||||
|
MOVE_FLAG_WK_CASTLE => {
|
||||||
|
self.remove_specific_piece(Square::E1, Color::White, PieceType::King);
|
||||||
|
self.remove_specific_piece(Square::H1, Color::White, PieceType::Rook);
|
||||||
|
self.put_piece(Square::G1, Color::White, PieceType::King);
|
||||||
|
self.put_piece(Square::F1, Color::White, PieceType::Rook);
|
||||||
|
}
|
||||||
|
MOVE_FLAG_BK_CASTLE => {
|
||||||
|
self.remove_specific_piece(Square::E8, Color::Black, PieceType::King);
|
||||||
|
self.remove_specific_piece(Square::H8, Color::Black, PieceType::Rook);
|
||||||
|
self.put_piece(Square::G8, Color::Black, PieceType::King);
|
||||||
|
self.put_piece(Square::F8, Color::Black, PieceType::Rook);
|
||||||
|
}
|
||||||
|
MOVE_FLAG_WQ_CASTLE => {
|
||||||
|
self.remove_specific_piece(Square::E1, Color::White, PieceType::King);
|
||||||
|
self.remove_specific_piece(Square::A1, Color::White, PieceType::Rook);
|
||||||
|
self.put_piece(Square::C1, Color::White, PieceType::King);
|
||||||
|
self.put_piece(Square::D1, Color::White, PieceType::Rook);
|
||||||
|
}
|
||||||
|
MOVE_FLAG_BQ_CASTLE => {
|
||||||
|
self.remove_specific_piece(Square::E8, Color::Black, PieceType::King);
|
||||||
|
self.remove_specific_piece(Square::A8, Color::Black, PieceType::Rook);
|
||||||
|
self.put_piece(Square::C8, Color::Black, PieceType::King);
|
||||||
|
self.put_piece(Square::D8, Color::Black, PieceType::Rook);
|
||||||
|
}
|
||||||
|
MOVE_FLAG_EN_PASSANT => {
|
||||||
|
self.remove_specific_piece(from, self.side_to_move, PieceType::Pawn);
|
||||||
|
if self.side_to_move == Color::White {
|
||||||
|
self.remove_specific_piece(to - 8_u8, !self.side_to_move, PieceType::Pawn);
|
||||||
|
} else {
|
||||||
|
self.remove_specific_piece(to + 8_u8, !self.side_to_move, PieceType::Pawn);
|
||||||
|
}
|
||||||
|
opt_captured_piece = Some(PieceType::Pawn);
|
||||||
|
self.put_piece(to, self.side_to_move, PieceType::Pawn);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
panic!("unable to make_move: invalid flags: {}", flags);
|
||||||
}
|
}
|
||||||
} else { // Black
|
|
||||||
|
|
||||||
}
|
}
|
||||||
panic!("not yet implemented");
|
|
||||||
|
// set castle rights
|
||||||
|
let wk = self.pieces[PieceType::King as usize][Color::White as usize];
|
||||||
|
let wr = self.pieces[PieceType::Rook as usize][Color::White as usize];
|
||||||
|
let bk = self.pieces[PieceType::King as usize][Color::Black as usize];
|
||||||
|
let br = self.pieces[PieceType::Rook as usize][Color::Black as usize];
|
||||||
|
let castling_right_wk = ((wk & CASTLING_WK_K_POS_MASK) > 0 && (wr & CASTLING_WK_R_POS_MASK) > 0) as u8;
|
||||||
|
let castling_right_wq = (((wk & CASTLING_WQ_K_POS_MASK) > 0 && (wr & CASTLING_WQ_R_POS_MASK) > 0) as u8) << 1;
|
||||||
|
let castling_right_bk = (((bk & CASTLING_BK_K_POS_MASK) > 0 && (br & CASTLING_BK_R_POS_MASK) > 0) as u8) << 2;
|
||||||
|
let castling_right_bq = (((bk & CASTLING_BQ_K_POS_MASK) > 0 && (br & CASTLING_BQ_R_POS_MASK) > 0) as u8) << 3;
|
||||||
|
let new_castling_rights =
|
||||||
|
castling_right_wk | castling_right_wq | castling_right_bk | castling_right_bq;
|
||||||
|
self.castling_rights = self.castling_rights & new_castling_rights; // & operator makes sure castling rights cant be gained back
|
||||||
|
|
||||||
|
// set new en passant target
|
||||||
|
self.en_passant_target = opt_en_passant_target;
|
||||||
|
|
||||||
|
// increase halfmove clock by 1 if no pawn was pushed and now piece captured
|
||||||
|
let new_friendly_pawns = self.pieces[PieceType::Pawn as usize][self.side_to_move as usize];
|
||||||
|
let new_total_pieces = self.all_occupied.count_ones();
|
||||||
|
let pawns_changed = old_friendly_pawns ^ new_friendly_pawns;
|
||||||
|
let piece_captured = (old_total_pieces - new_total_pieces) as u64;
|
||||||
|
let increase_halfmove_clock = ((pawns_changed + piece_captured) == 0) as u8;
|
||||||
|
self.halfmove_clock = increase_halfmove_clock * (self.halfmove_clock + 1);
|
||||||
|
|
||||||
|
// increase full move number by 1 when black made a move
|
||||||
|
self.fullmove_number += self.side_to_move as u16;
|
||||||
|
|
||||||
|
// flip the side to move
|
||||||
|
self.side_to_move = !self.side_to_move;
|
||||||
|
|
||||||
|
UndoMove::new(
|
||||||
|
mv,
|
||||||
|
opt_captured_piece,
|
||||||
|
old_en_passant_target,
|
||||||
|
old_castling_rights,
|
||||||
|
old_halfmove_clock,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -10,11 +10,10 @@ fn main() {
|
||||||
generate_pseudo_legal_moves(&board, &mut move_list);
|
generate_pseudo_legal_moves(&board, &mut move_list);
|
||||||
|
|
||||||
for mv in move_list.iter() {
|
for mv in move_list.iter() {
|
||||||
board.pretty_print_ascii();
|
board = Board::from_fen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
|
||||||
println!("--> making move: {}", mv.to_algebraic());
|
println!("--> making move: {}", mv.to_algebraic());
|
||||||
let mut board_clone = board.clone();
|
board.make_move(*mv);
|
||||||
board_clone.make_move(*mv);
|
board.pretty_print_ascii();
|
||||||
board_clone.pretty_print_ascii();
|
|
||||||
println!("---------------------");
|
println!("---------------------");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
48
src/move.rs
48
src/move.rs
|
|
@ -2,6 +2,7 @@ use std::slice;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use crate::square::Square;
|
use crate::square::Square;
|
||||||
use crate::board::PieceType;
|
use crate::board::PieceType;
|
||||||
|
use crate::square::SQUARES;
|
||||||
|
|
||||||
// BIT 0 - 5: FROM SQUARE (0-63)
|
// BIT 0 - 5: FROM SQUARE (0-63)
|
||||||
pub const MOVE_FROM_MASK: u16 = 0b0000_0000_0011_1111;
|
pub const MOVE_FROM_MASK: u16 = 0b0000_0000_0011_1111;
|
||||||
|
|
@ -14,6 +15,7 @@ pub const MOVE_FLAG_MASK: u16 = 0b1111_0000_0000_0000;
|
||||||
|
|
||||||
pub const MOVE_FLAG_QUIET: u16 = 0b0000_0000_0000_0000;
|
pub const MOVE_FLAG_QUIET: u16 = 0b0000_0000_0000_0000;
|
||||||
pub const MOVE_FLAG_CAPTURE: u16 = 0b0001_0000_0000_0000;
|
pub const MOVE_FLAG_CAPTURE: u16 = 0b0001_0000_0000_0000;
|
||||||
|
pub const MOVE_FLAG_DOUBLE_PAWN: u16 = 0b0010_0000_0000_0000;
|
||||||
pub const MOVE_FLAG_EN_PASSANT: u16 = 0b0011_0000_0000_0000;
|
pub const MOVE_FLAG_EN_PASSANT: u16 = 0b0011_0000_0000_0000;
|
||||||
|
|
||||||
// Castle flags
|
// Castle flags
|
||||||
|
|
@ -27,6 +29,7 @@ pub const MOVE_FLAG_BQ_CASTLE: u16 = 0b0111_0000_0000_0000;
|
||||||
|
|
||||||
// Promotion flags (use the 1xxx bits)
|
// Promotion flags (use the 1xxx bits)
|
||||||
// We combine capture flag with promotion type
|
// We combine capture flag with promotion type
|
||||||
|
pub const MOVE_MASK_PROMO: u16 = 0b1000_0000_0000_0000;
|
||||||
pub const MOVE_FLAG_PROMO: u16 = 0b1000_0000_0000_0000;
|
pub const MOVE_FLAG_PROMO: u16 = 0b1000_0000_0000_0000;
|
||||||
|
|
||||||
pub const MOVE_FLAG_PROMO_N: u16 = 0b1000_0000_0000_0000;
|
pub const MOVE_FLAG_PROMO_N: u16 = 0b1000_0000_0000_0000;
|
||||||
|
|
@ -47,16 +50,25 @@ impl Move {
|
||||||
((to as u16) << 6 ) |
|
((to as u16) << 6 ) |
|
||||||
from as u16)
|
from as u16)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn value(&self) -> u16 {
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn get_flags(&self) -> u16 {
|
pub fn get_flags(&self) -> u16 {
|
||||||
self.0 & MOVE_FLAG_MASK
|
self.0 & MOVE_FLAG_MASK
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn get_from(&self) -> Square {
|
||||||
|
SQUARES[(self.0 & MOVE_FROM_MASK) as usize]
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn get_to(&self) -> Square {
|
||||||
|
// --- KORREKTUR HIER ---
|
||||||
|
// Die Klammern um (self.0 & MOVE_TO_MASK) sind entscheidend
|
||||||
|
SQUARES[((self.0 & MOVE_TO_MASK) >> 6) as usize]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Converts a square index (0-63) to algebraic notation (e.g., 0 -> "a1", 63 -> "h8").
|
/// Converts a square index (0-63) to algebraic notation (e.g., 0 -> "a1", 63 -> "h8").
|
||||||
fn square_val_to_alg(val: u16) -> String {
|
fn square_val_to_alg(val: u16) -> String {
|
||||||
|
|
@ -68,7 +80,7 @@ impl Move {
|
||||||
/// Converts the move to coordinate notation (e.g., "e2e4", "e7e8q", "e1g1").
|
/// Converts the move to coordinate notation (e.g., "e2e4", "e7e8q", "e1g1").
|
||||||
pub fn to_algebraic(&self) -> String {
|
pub fn to_algebraic(&self) -> String {
|
||||||
let flags = self.get_flags();
|
let flags = self.get_flags();
|
||||||
|
|
||||||
// Handle castling first. In this new format, the "to" square is
|
// Handle castling first. In this new format, the "to" square is
|
||||||
// the *king's* destination square (g1/c1 or g8/c8).
|
// the *king's* destination square (g1/c1 or g8/c8).
|
||||||
// Your old implementation reading the file is still fine.
|
// Your old implementation reading the file is still fine.
|
||||||
|
|
@ -158,17 +170,17 @@ pub struct UndoMove {
|
||||||
|
|
||||||
impl UndoMove {
|
impl UndoMove {
|
||||||
pub fn new(mv: Move,
|
pub fn new(mv: Move,
|
||||||
captured_piece: Option<PieceType>,
|
captured_piece: Option<PieceType>,
|
||||||
old_en_passant_square: Option<Square>,
|
old_en_passant_square: Option<Square>,
|
||||||
old_castling_rights: u8,
|
old_castling_rights: u8,
|
||||||
old_halfmove_clock: u8) -> Self {
|
old_halfmove_clock: u8) -> Self {
|
||||||
Self {
|
Self {
|
||||||
mv,
|
mv,
|
||||||
captured_piece,
|
captured_piece,
|
||||||
old_en_passant_square,
|
old_en_passant_square,
|
||||||
old_castling_rights,
|
old_castling_rights,
|
||||||
old_halfmove_clock
|
old_halfmove_clock
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -30,6 +30,7 @@ pub fn generate_knight_moves(board: &Board, list: &mut MoveList) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_king_moves(board: &Board, list: &mut MoveList) {
|
pub fn generate_king_moves(board: &Board, list: &mut MoveList) {
|
||||||
|
// TODO no castle when square or piece under attack
|
||||||
let enemy_occupied = board.occupied[!board.side_to_move as usize];
|
let enemy_occupied = board.occupied[!board.side_to_move as usize];
|
||||||
let friendly_king = board.pieces[PieceType::King as usize][board.side_to_move as usize];
|
let friendly_king = board.pieces[PieceType::King as usize][board.side_to_move as usize];
|
||||||
|
|
||||||
|
|
@ -59,26 +60,26 @@ pub fn generate_king_moves(board: &Board, list: &mut MoveList) {
|
||||||
// 2. Generate castling king moves
|
// 2. Generate castling king moves
|
||||||
if board.side_to_move == Color::White {
|
if board.side_to_move == Color::White {
|
||||||
// Kingside (OO)
|
// Kingside (OO)
|
||||||
if (board.castling_rights & CASTLING_WK) != 0 {
|
if (board.castling_rights & CASTLING_WK_FLAG) != 0 {
|
||||||
if (board.all_occupied & CASTLING_WK_MASK) == 0 {
|
if (board.all_occupied & CASTLING_WK_MASK) == 0 {
|
||||||
list.push(Move::new(Square::E1, Square::G1, MOVE_FLAG_WK_CASTLE));
|
list.push(Move::new(Square::E1, Square::G1, MOVE_FLAG_WK_CASTLE));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Queenside (OOO)
|
// Queenside (OOO)
|
||||||
if (board.castling_rights & CASTLING_WQ) != 0 {
|
if (board.castling_rights & CASTLING_WQ_FLAG) != 0 {
|
||||||
if (board.all_occupied & CASTLING_WQ_MASK) == 0 {
|
if (board.all_occupied & CASTLING_WQ_MASK) == 0 {
|
||||||
list.push(Move::new(Square::E1, Square::C1, MOVE_FLAG_WQ_CASTLE));
|
list.push(Move::new(Square::E1, Square::C1, MOVE_FLAG_WQ_CASTLE));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else { // Black
|
} else { // Black
|
||||||
// Kingside (OO)
|
// Kingside (OO)
|
||||||
if (board.castling_rights & CASTLING_BK) != 0 {
|
if (board.castling_rights & CASTLING_BK_FLAG) != 0 {
|
||||||
if (board.all_occupied & CASTLING_BK_MASK) == 0 {
|
if (board.all_occupied & CASTLING_BK_MASK) == 0 {
|
||||||
list.push(Move::new(Square::E8, Square::G8, MOVE_FLAG_BK_CASTLE));
|
list.push(Move::new(Square::E8, Square::G8, MOVE_FLAG_BK_CASTLE));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Queenside (OOO)
|
// Queenside (OOO)
|
||||||
if (board.castling_rights & CASTLING_BQ) != 0 {
|
if (board.castling_rights & CASTLING_BQ_FLAG) != 0 {
|
||||||
if (board.all_occupied & CASTLING_BQ_MASK) == 0 {
|
if (board.all_occupied & CASTLING_BQ_MASK) == 0 {
|
||||||
list.push(Move::new(Square::E8, Square::C8, MOVE_FLAG_BQ_CASTLE));
|
list.push(Move::new(Square::E8, Square::C8, MOVE_FLAG_BQ_CASTLE));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ pub fn generate_pawn_moves(board: &Board, list: &mut MoveList) {
|
||||||
while double_push_targets > 0 {
|
while double_push_targets > 0 {
|
||||||
let to = SQUARES[double_push_targets.trailing_zeros() as usize];
|
let to = SQUARES[double_push_targets.trailing_zeros() as usize];
|
||||||
let from = to - 16;
|
let from = to - 16;
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_QUIET));
|
list.push(Move::new(from, to, MOVE_FLAG_DOUBLE_PAWN));
|
||||||
double_push_targets &= double_push_targets - 1;
|
double_push_targets &= double_push_targets - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -149,7 +149,7 @@ pub fn generate_pawn_moves(board: &Board, list: &mut MoveList) {
|
||||||
|
|
||||||
while single_push_targets > 0 {
|
while single_push_targets > 0 {
|
||||||
let to = SQUARES[single_push_targets.trailing_zeros() as usize];
|
let to = SQUARES[single_push_targets.trailing_zeros() as usize];
|
||||||
let from = to + 8;
|
let from = to + 8_u8;
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_QUIET));
|
list.push(Move::new(from, to, MOVE_FLAG_QUIET));
|
||||||
single_push_targets &= single_push_targets - 1;
|
single_push_targets &= single_push_targets - 1;
|
||||||
}
|
}
|
||||||
|
|
@ -161,8 +161,8 @@ pub fn generate_pawn_moves(board: &Board, list: &mut MoveList) {
|
||||||
|
|
||||||
while double_push_targets > 0 {
|
while double_push_targets > 0 {
|
||||||
let to = SQUARES[double_push_targets.trailing_zeros() as usize];
|
let to = SQUARES[double_push_targets.trailing_zeros() as usize];
|
||||||
let from = to + 16;
|
let from = to + 16_u8;
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_QUIET));
|
list.push(Move::new(from, to, MOVE_FLAG_DOUBLE_PAWN));
|
||||||
double_push_targets &= double_push_targets - 1;
|
double_push_targets &= double_push_targets - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -172,7 +172,7 @@ pub fn generate_pawn_moves(board: &Board, list: &mut MoveList) {
|
||||||
|
|
||||||
while a_side_capture_targets > 0 {
|
while a_side_capture_targets > 0 {
|
||||||
let to = SQUARES[a_side_capture_targets.trailing_zeros() as usize];
|
let to = SQUARES[a_side_capture_targets.trailing_zeros() as usize];
|
||||||
let from = to + 9;
|
let from = to + 9_u8;
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_CAPTURE));
|
list.push(Move::new(from, to, MOVE_FLAG_CAPTURE));
|
||||||
a_side_capture_targets &= a_side_capture_targets - 1;
|
a_side_capture_targets &= a_side_capture_targets - 1;
|
||||||
}
|
}
|
||||||
|
|
@ -182,7 +182,7 @@ pub fn generate_pawn_moves(board: &Board, list: &mut MoveList) {
|
||||||
|
|
||||||
while h_side_capture_targets > 0 {
|
while h_side_capture_targets > 0 {
|
||||||
let to = SQUARES[h_side_capture_targets.trailing_zeros() as usize];
|
let to = SQUARES[h_side_capture_targets.trailing_zeros() as usize];
|
||||||
let from = to + 7;
|
let from = to + 7_u8;
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_CAPTURE));
|
list.push(Move::new(from, to, MOVE_FLAG_CAPTURE));
|
||||||
h_side_capture_targets &= h_side_capture_targets - 1;
|
h_side_capture_targets &= h_side_capture_targets - 1;
|
||||||
}
|
}
|
||||||
|
|
@ -193,7 +193,7 @@ pub fn generate_pawn_moves(board: &Board, list: &mut MoveList) {
|
||||||
|
|
||||||
while promotion_targets > 0 {
|
while promotion_targets > 0 {
|
||||||
let to = SQUARES[promotion_targets.trailing_zeros() as usize];
|
let to = SQUARES[promotion_targets.trailing_zeros() as usize];
|
||||||
let from = to + 8;
|
let from = to + 8_u8;
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_PROMO_Q));
|
list.push(Move::new(from, to, MOVE_FLAG_PROMO_Q));
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_PROMO_R));
|
list.push(Move::new(from, to, MOVE_FLAG_PROMO_R));
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_PROMO_B));
|
list.push(Move::new(from, to, MOVE_FLAG_PROMO_B));
|
||||||
|
|
@ -206,7 +206,7 @@ pub fn generate_pawn_moves(board: &Board, list: &mut MoveList) {
|
||||||
let mut promotion_targets_a_side_capture = ((friendly_pawns & PAWN_A_SIDE_CAPTURE_PROMOTION_MASK_BLACK) >> 9) & opponent_occupied;
|
let mut promotion_targets_a_side_capture = ((friendly_pawns & PAWN_A_SIDE_CAPTURE_PROMOTION_MASK_BLACK) >> 9) & opponent_occupied;
|
||||||
while promotion_targets_a_side_capture > 0 {
|
while promotion_targets_a_side_capture > 0 {
|
||||||
let to = SQUARES[promotion_targets_a_side_capture.trailing_zeros() as usize];
|
let to = SQUARES[promotion_targets_a_side_capture.trailing_zeros() as usize];
|
||||||
let from = to + 9;
|
let from = to + 9_u8;
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_PROMO_N_CAP));
|
list.push(Move::new(from, to, MOVE_FLAG_PROMO_N_CAP));
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_PROMO_B_CAP));
|
list.push(Move::new(from, to, MOVE_FLAG_PROMO_B_CAP));
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_PROMO_R_CAP));
|
list.push(Move::new(from, to, MOVE_FLAG_PROMO_R_CAP));
|
||||||
|
|
@ -218,7 +218,7 @@ pub fn generate_pawn_moves(board: &Board, list: &mut MoveList) {
|
||||||
let mut promotion_targets_h_side_capture = ((friendly_pawns & PAWN_H_SIDE_CAPTURE_PROMOTION_MASK_BLACK) >> 7) & opponent_occupied;
|
let mut promotion_targets_h_side_capture = ((friendly_pawns & PAWN_H_SIDE_CAPTURE_PROMOTION_MASK_BLACK) >> 7) & opponent_occupied;
|
||||||
while promotion_targets_h_side_capture > 0 {
|
while promotion_targets_h_side_capture > 0 {
|
||||||
let to = SQUARES[promotion_targets_h_side_capture.trailing_zeros() as usize];
|
let to = SQUARES[promotion_targets_h_side_capture.trailing_zeros() as usize];
|
||||||
let from = to + 7;
|
let from = to + 7_u8;
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_PROMO_N_CAP));
|
list.push(Move::new(from, to, MOVE_FLAG_PROMO_N_CAP));
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_PROMO_B_CAP));
|
list.push(Move::new(from, to, MOVE_FLAG_PROMO_B_CAP));
|
||||||
list.push(Move::new(from, to, MOVE_FLAG_PROMO_R_CAP));
|
list.push(Move::new(from, to, MOVE_FLAG_PROMO_R_CAP));
|
||||||
|
|
@ -235,14 +235,14 @@ pub fn generate_pawn_moves(board: &Board, list: &mut MoveList) {
|
||||||
// 1. Check A-Side capture (>> 9, e.g., B4 -> A3)
|
// 1. Check A-Side capture (>> 9, e.g., B4 -> A3)
|
||||||
let attacker_mask_a_side = (en_passant_target_bb << 9) & PAWN_A_SIDE_CAPTURE_MASK_BLACK;
|
let attacker_mask_a_side = (en_passant_target_bb << 9) & PAWN_A_SIDE_CAPTURE_MASK_BLACK;
|
||||||
if (attacker_mask_a_side & friendly_pawns) > 0 {
|
if (attacker_mask_a_side & friendly_pawns) > 0 {
|
||||||
let from = en_passant_target_square + 9;
|
let from = en_passant_target_square + 9_u8;
|
||||||
list.push(Move::new(from, en_passant_target_square, MOVE_FLAG_EN_PASSANT));
|
list.push(Move::new(from, en_passant_target_square, MOVE_FLAG_EN_PASSANT));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Check H-Side capture (>> 7, e.g., G4 -> H3)
|
// 2. Check H-Side capture (>> 7, e.g., G4 -> H3)
|
||||||
let attacker_mask_h_side = (en_passant_target_bb << 7) & PAWN_H_SIDE_CAPTURE_MASK_BLACK;
|
let attacker_mask_h_side = (en_passant_target_bb << 7) & PAWN_H_SIDE_CAPTURE_MASK_BLACK;
|
||||||
if (attacker_mask_h_side & friendly_pawns) > 0 {
|
if (attacker_mask_h_side & friendly_pawns) > 0 {
|
||||||
let from = en_passant_target_square + 7;
|
let from = en_passant_target_square + 7_u8;
|
||||||
list.push(Move::new(from, en_passant_target_square, MOVE_FLAG_EN_PASSANT));
|
list.push(Move::new(from, en_passant_target_square, MOVE_FLAG_EN_PASSANT));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,12 @@ pub const SQUARES: [Square; 64] = [
|
||||||
Square::A8, Square::B8, Square::C8, Square::D8, Square::E8, Square::F8, Square::G8, Square::H8,
|
Square::A8, Square::B8, Square::C8, Square::D8, Square::E8, Square::F8, Square::G8, Square::H8,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
impl Square {
|
||||||
|
pub fn to_bitboard(&self) -> u64 {
|
||||||
|
1_u64 << (*self as u8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl TryFrom<u8> for Square {
|
impl TryFrom<u8> for Square {
|
||||||
type Error = &'static str;
|
type Error = &'static str;
|
||||||
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
||||||
|
|
@ -101,6 +107,16 @@ impl Add<u8> for Square {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Add<i8> for Square {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn add(self, rhs: i8) -> Self::Output {
|
||||||
|
let new_val = ((self as i8) + rhs) as u8;
|
||||||
|
new_val.try_into().expect("Square addition resulted in an invalid square")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
impl Sub<u8> for Square {
|
impl Sub<u8> for Square {
|
||||||
type Output = Self;
|
type Output = Self;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue