Reinitialize repository and add working move generation for all pieces
This commit is contained in:
commit
951a8bbec6
28 changed files with 3373 additions and 0 deletions
328
src/board.rs
Normal file
328
src/board.rs
Normal file
|
|
@ -0,0 +1,328 @@
|
|||
use crate::square::Square;
|
||||
use std::mem;
|
||||
use crate::r#move::*;
|
||||
use std::ops::Not;
|
||||
|
||||
pub const CASTLING_WK: u8 = 1;
|
||||
pub const CASTLING_WK_MASK: u64 = 96; // F1 G1
|
||||
|
||||
pub const CASTLING_WQ: u8 = 2;
|
||||
pub const CASTLING_WQ_MASK: u64 = 14; // B1 C1 D1
|
||||
|
||||
pub const CASTLING_BK: u8 = 4;
|
||||
pub const CASTLING_BK_MASK: u64 = 6917529027641081856; // F8 G8
|
||||
|
||||
pub const CASTLING_BQ: u8 = 8;
|
||||
pub const CASTLING_BQ_MASK: u64 = 1008806316530991104; // B8 C8 D8
|
||||
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[repr(u8)]
|
||||
pub enum Color {
|
||||
White = 0,
|
||||
Black = 1,
|
||||
}
|
||||
|
||||
impl Not for Color {
|
||||
type Output = Self;
|
||||
|
||||
fn not(self) -> Self::Output {
|
||||
match self {
|
||||
Color::White => Color::Black,
|
||||
Color::Black => Color::White,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[repr(u8)]
|
||||
pub enum PieceType {
|
||||
Pawn = 0,
|
||||
Knight = 1,
|
||||
Bishop = 2,
|
||||
Rook = 3,
|
||||
Queen = 4,
|
||||
King = 5,
|
||||
}
|
||||
|
||||
pub struct Board {
|
||||
pub side_to_move: Color,
|
||||
|
||||
pub pieces: [[u64; 2]; 6],
|
||||
|
||||
pub occupied: [u64; 2],
|
||||
pub all_occupied: u64,
|
||||
pub empty_squares: u64,
|
||||
|
||||
pub castling_rights: u8,
|
||||
pub en_passant_target: Option<Square>,
|
||||
|
||||
pub halfmove_clock: u8,
|
||||
pub fullmove_number: u16,
|
||||
}
|
||||
|
||||
impl Board {
|
||||
/// Creates a new Board instance from a FEN string.
|
||||
/// Assumes the FEN string is valid.
|
||||
pub fn from_fen(fen: &str) -> Self {
|
||||
let mut parts = fen.split_whitespace();
|
||||
|
||||
// Initialisiere das 2D-Array
|
||||
let mut pieces = [[0u64; 2]; 6];
|
||||
let mut occupied = [0u64; 2];
|
||||
|
||||
// Part 1: Piece placement
|
||||
let placement = parts.next().unwrap_or("");
|
||||
let mut rank = 7;
|
||||
let mut file = 0;
|
||||
|
||||
for c in placement.chars() {
|
||||
if c.is_digit(10) {
|
||||
file += c.to_digit(10).unwrap_or(0) as usize;
|
||||
} else if c == '/' {
|
||||
rank -= 1;
|
||||
file = 0;
|
||||
} else if c.is_alphabetic() {
|
||||
let sq = (rank * 8 + file) as u8;
|
||||
let mask = 1u64 << sq;
|
||||
|
||||
if c.is_uppercase() {
|
||||
let color_idx = Color::White as usize;
|
||||
occupied[color_idx] |= mask;
|
||||
match c {
|
||||
'P' => pieces[PieceType::Pawn as usize][color_idx] |= mask,
|
||||
'N' => pieces[PieceType::Knight as usize][color_idx] |= mask,
|
||||
'B' => pieces[PieceType::Bishop as usize][color_idx] |= mask,
|
||||
'R' => pieces[PieceType::Rook as usize][color_idx] |= mask,
|
||||
'Q' => pieces[PieceType::Queen as usize][color_idx] |= mask,
|
||||
'K' => pieces[PieceType::King as usize][color_idx] |= mask,
|
||||
_ => {}
|
||||
}
|
||||
} else {
|
||||
let color_idx = Color::Black as usize;
|
||||
occupied[color_idx] |= mask;
|
||||
match c {
|
||||
'p' => pieces[PieceType::Pawn as usize][color_idx] |= mask,
|
||||
'n' => pieces[PieceType::Knight as usize][color_idx] |= mask,
|
||||
'b' => pieces[PieceType::Bishop as usize][color_idx] |= mask,
|
||||
'r' => pieces[PieceType::Rook as usize][color_idx] |= mask,
|
||||
'q' => pieces[PieceType::Queen as usize][color_idx] |= mask,
|
||||
'k' => pieces[PieceType::King as usize][color_idx] |= mask,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
file += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Part 2: Active color
|
||||
let side_to_move = match parts.next().unwrap_or("w") {
|
||||
"b" => Color::Black,
|
||||
_ => Color::White,
|
||||
};
|
||||
|
||||
// Part 3: Castling rights
|
||||
let mut castling_rights = 0u8;
|
||||
if let Some(castle_str) = parts.next() {
|
||||
if castle_str.contains('K') { castling_rights |= CASTLING_WK; }
|
||||
if castle_str.contains('Q') { castling_rights |= CASTLING_WQ; }
|
||||
if castle_str.contains('k') { castling_rights |= CASTLING_BK; }
|
||||
if castle_str.contains('q') { castling_rights |= CASTLING_BQ; }
|
||||
}
|
||||
|
||||
// Part 4: En passant target
|
||||
let en_passant_target = match parts.next().unwrap_or("-") {
|
||||
"-" => None,
|
||||
sq_str => {
|
||||
let chars: Vec<char> = sq_str.chars().collect();
|
||||
let file = (chars[0] as u8 - b'a') as u8;
|
||||
let rank = (chars[1] as u8 - b'1') as u8;
|
||||
let sq_index = rank * 8 + file;
|
||||
// This is unsafe, but assumes the FEN is valid
|
||||
Some(unsafe { mem::transmute::<u8, Square>(sq_index) })
|
||||
}
|
||||
};
|
||||
|
||||
// Part 5: Halfmove clock
|
||||
let halfmove_clock = parts.next().unwrap_or("0").parse::<u8>().unwrap_or(0);
|
||||
|
||||
// Part 6: Fullmove number
|
||||
let fullmove_number = parts.next().unwrap_or("1").parse::<u16>().unwrap_or(1);
|
||||
|
||||
let all_occupied = occupied[Color::White as usize] | occupied[Color::Black as usize];
|
||||
let empty_squares = !all_occupied;
|
||||
|
||||
Board {
|
||||
side_to_move,
|
||||
pieces, // Geändertes Feld
|
||||
occupied,
|
||||
all_occupied,
|
||||
empty_squares,
|
||||
castling_rights,
|
||||
en_passant_target,
|
||||
halfmove_clock,
|
||||
fullmove_number,
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts the current board state into a FEN string.
|
||||
pub fn to_fen(&self) -> String {
|
||||
let mut fen = String::with_capacity(90);
|
||||
|
||||
// Part 1: Piece placement
|
||||
let mut empty_count = 0;
|
||||
for rank in (0..=7).rev() {
|
||||
for file in 0..=7 {
|
||||
let sq = (rank * 8 + file) as u8;
|
||||
let mask = 1u64 << sq;
|
||||
|
||||
if let Some(piece) = self.get_piece_at(mask) {
|
||||
if empty_count > 0 {
|
||||
fen.push((b'0' + empty_count) as char);
|
||||
empty_count = 0;
|
||||
}
|
||||
fen.push(piece);
|
||||
} else {
|
||||
empty_count += 1;
|
||||
}
|
||||
}
|
||||
if empty_count > 0 {
|
||||
fen.push((b'0' + empty_count) as char);
|
||||
empty_count = 0;
|
||||
}
|
||||
if rank > 0 {
|
||||
fen.push('/');
|
||||
}
|
||||
}
|
||||
|
||||
// Part 2: Active color
|
||||
fen.push(' ');
|
||||
fen.push(if self.side_to_move == Color::White { 'w' } else { 'b' });
|
||||
|
||||
// Part 3: Castling rights
|
||||
fen.push(' ');
|
||||
let mut castle_str = String::new();
|
||||
if (self.castling_rights & CASTLING_WK) != 0 { castle_str.push('K'); }
|
||||
if (self.castling_rights & CASTLING_WQ) != 0 { castle_str.push('Q'); }
|
||||
if (self.castling_rights & CASTLING_BK) != 0 { castle_str.push('k'); }
|
||||
if (self.castling_rights & CASTLING_BQ) != 0 { castle_str.push('q'); }
|
||||
|
||||
if castle_str.is_empty() {
|
||||
fen.push('-');
|
||||
} else {
|
||||
fen.push_str(&castle_str);
|
||||
}
|
||||
|
||||
// Part 4: En passant target
|
||||
fen.push(' ');
|
||||
if let Some(sq) = self.en_passant_target {
|
||||
let sq_index = sq as u8;
|
||||
let file = (sq_index % 8) as u8;
|
||||
let rank = (sq_index / 8) as u8;
|
||||
fen.push((b'a' + file) as char);
|
||||
fen.push((b'1' + rank) as char);
|
||||
} else {
|
||||
fen.push('-');
|
||||
}
|
||||
|
||||
// Part 5: Halfmove clock
|
||||
fen.push(' ');
|
||||
fen.push_str(&self.halfmove_clock.to_string());
|
||||
|
||||
// Part 6: Fullmove number
|
||||
fen.push(' ');
|
||||
fen.push_str(&self.fullmove_number.to_string());
|
||||
|
||||
fen
|
||||
}
|
||||
|
||||
/// Helper function to find which piece (as a char) is on a given square mask.
|
||||
fn get_piece_at(&self, sq_mask: u64) -> Option<char> {
|
||||
let white = Color::White 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][black] & sq_mask) != 0 { 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::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
|
||||
}
|
||||
|
||||
/// Prints a single bitboard (u64) as an 8x8 grid for debugging.
|
||||
fn print_bitboard(&self, name: &str, bitboard: u64) {
|
||||
println!("--- {} ---", name);
|
||||
println!(" a b c d e f g h");
|
||||
for rank in (0..=7).rev() {
|
||||
print!("{} ", rank + 1);
|
||||
for file in 0..=7 {
|
||||
let sq_index = rank * 8 + file;
|
||||
let mask = 1u64 << sq_index;
|
||||
|
||||
if (bitboard & mask) != 0 {
|
||||
print!("1 ");
|
||||
} else {
|
||||
print!(". ");
|
||||
}
|
||||
}
|
||||
println!();
|
||||
}
|
||||
println!("RAW VALUE: {}", bitboard);
|
||||
println!();
|
||||
}
|
||||
|
||||
/// Prints all internal bitboards for debugging purposes.
|
||||
pub fn pretty_print_internals(&self) {
|
||||
println!("\n========= BOARD INTERNAL BITBOARDS =========");
|
||||
|
||||
let white = Color::White as usize;
|
||||
let black = Color::Black as usize;
|
||||
|
||||
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("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("Black Bishops", self.pieces[PieceType::Bishop as usize][black]);
|
||||
|
||||
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("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("Black King", self.pieces[PieceType::King as usize][black]);
|
||||
|
||||
println!("--- Aggregate Bitboards ---");
|
||||
self.print_bitboard("All White Pieces", self.occupied[white]);
|
||||
self.print_bitboard("All Black Pieces", self.occupied[black]);
|
||||
self.print_bitboard("All Occupied", self.all_occupied);
|
||||
self.print_bitboard("Empty Squares", self.empty_squares);
|
||||
|
||||
println!("============================================\n");
|
||||
}
|
||||
|
||||
pub fn make_move(&mut self, mv: Move) {
|
||||
let from = mv.value()& MOVE_FROM_MASK;
|
||||
let to = mv.value() & MOVE_TO_MASK;
|
||||
let flag = mv.value() & MOVE_FLAG_MASK;
|
||||
|
||||
// promo must come first because of double usage of the flag bits
|
||||
if flag == MOVE_FLAG_NO_PROMO {
|
||||
|
||||
} else { //
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
4
src/lib.rs
Normal file
4
src/lib.rs
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
pub mod board;
|
||||
pub mod r#move;
|
||||
pub mod square;
|
||||
pub mod movegen;
|
||||
13
src/main.rs
Normal file
13
src/main.rs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
use chess_engine::board::Board;
|
||||
use chess_engine::movegen::generate_pseudo_legal_moves;
|
||||
use chess_engine::r#move::*;
|
||||
|
||||
|
||||
fn main() {
|
||||
let board = Board::from_fen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR b KQkq - 1 2");
|
||||
let mut move_list = MoveList::new();
|
||||
|
||||
generate_pseudo_legal_moves(&board, &mut move_list);
|
||||
|
||||
println!("Counted {} pseudo legal moves.", move_list.len());
|
||||
}
|
||||
174
src/move.rs
Normal file
174
src/move.rs
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
use std::slice;
|
||||
use std::fmt;
|
||||
use crate::square::Square;
|
||||
use crate::board::PieceType;
|
||||
|
||||
// BIT 0 - 5: FROM SQUARE (0-63)
|
||||
pub const MOVE_FROM_MASK: u16 = 0b0000_0000_0011_1111;
|
||||
|
||||
// BIT 6 - 11: TO SQUARE (0-63)
|
||||
pub const MOVE_TO_MASK: u16 = 0b0000_1111_1100_0000;
|
||||
|
||||
// BIT 12 - 15: FLAGS (4 bits)
|
||||
// 1. 0 no capture, 1 capture
|
||||
pub const MOVE_FLAG_MASK: u16 = 0b1111_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_EN_PASSANT: u16 = 0b0010_0000_0000_0000;
|
||||
|
||||
pub const MOVE_FLAG_WK_CASTLE: u16 = 0b0011_0000_0000_0000;
|
||||
pub const MOVE_FLAG_WQ_CASTLE: u16 = 0b0100_0000_0000_0000;
|
||||
pub const MOVE_FLAG_BK_CASTLE: u16 = 0b0101_0000_0000_0000;
|
||||
pub const MOVE_FLAG_BQ_CASTLE: u16 = 0b0110_0000_0000_0000;
|
||||
// 0111 is free
|
||||
|
||||
// Promotion flags (use the 1xxx bits)
|
||||
// We combine capture flag with promotion type
|
||||
pub const MOVE_FLAG_PROMO: u16 = 0b1000_0000_0000_0000;
|
||||
pub const MOVE_FLAG_NO_PROMO: u16 = 0b0000_0000_0000_0000;
|
||||
|
||||
pub const MOVE_FLAG_PROMO_N: u16 = 0b1000_0000_0000_0000;
|
||||
pub const MOVE_FLAG_PROMO_B: u16 = 0b1001_0000_0000_0000;
|
||||
pub const MOVE_FLAG_PROMO_R: u16 = 0b1010_0000_0000_0000;
|
||||
pub const MOVE_FLAG_PROMO_Q: u16 = 0b1011_0000_0000_0000;
|
||||
pub const MOVE_FLAG_PROMO_CAP_N: u16 = 0b1100_0000_0000_0000;
|
||||
pub const MOVE_FLAG_PROMO_CAP_B: u16 = 0b1101_0000_0000_0000;
|
||||
pub const MOVE_FLAG_PROMO_CAP_R: u16 = 0b1110_0000_0000_0000;
|
||||
pub const MOVE_FLAG_PROMO_CAP_Q: u16 = 0b1111_0000_0000_0000;
|
||||
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub struct Move(u16);
|
||||
|
||||
impl Move {
|
||||
pub fn new(from: Square, to: Square, flags: u16) -> Move {
|
||||
Move(flags |
|
||||
((to as u16) << 6 ) |
|
||||
from as u16)
|
||||
}
|
||||
|
||||
pub fn value(&self) -> u16 {
|
||||
self.0
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn get_flags(&self) -> u16 {
|
||||
self.0 & MOVE_FLAG_MASK
|
||||
}
|
||||
|
||||
|
||||
/// Converts a square index (0-63) to algebraic notation (e.g., 0 -> "a1", 63 -> "h8").
|
||||
fn square_val_to_alg(val: u16) -> String {
|
||||
let file = (b'a' + (val % 8) as u8) as char;
|
||||
let rank = (b'1' + (val / 8) as u8) as char;
|
||||
format!("{}{}", file, rank)
|
||||
}
|
||||
|
||||
/// Converts the move to coordinate notation (e.g., "e2e4", "e7e8q", "e1g1").
|
||||
pub fn to_algebraic(&self) -> String {
|
||||
let flags = self.get_flags();
|
||||
|
||||
// Handle castling first. In this new format, the "to" square is
|
||||
// the *king's* destination square (g1/c1 or g8/c8).
|
||||
// Your old implementation reading the file is still fine.
|
||||
if (flags == MOVE_FLAG_WK_CASTLE) || (flags == MOVE_FLAG_BK_CASTLE) {
|
||||
return "O-O".to_string();
|
||||
}
|
||||
if (flags == MOVE_FLAG_WQ_CASTLE) || (flags == MOVE_FLAG_BQ_CASTLE) {
|
||||
return "O-O-O".to_string();
|
||||
}
|
||||
|
||||
let from_val = self.0 & MOVE_FROM_MASK;
|
||||
let to_val = (self.0 & MOVE_TO_MASK) >> 6;
|
||||
|
||||
let from_str = Self::square_val_to_alg(from_val);
|
||||
let to_str = Self::square_val_to_alg(to_val);
|
||||
|
||||
// Check if it's any promotion type (1xxx)
|
||||
if (flags & 0b1000_0000_0000_0000) != 0 {
|
||||
let promo_char = match flags {
|
||||
MOVE_FLAG_PROMO_N | MOVE_FLAG_PROMO_CAP_N => 'n',
|
||||
MOVE_FLAG_PROMO_B | MOVE_FLAG_PROMO_CAP_B => 'b',
|
||||
MOVE_FLAG_PROMO_R | MOVE_FLAG_PROMO_CAP_R => 'r',
|
||||
MOVE_FLAG_PROMO_Q | MOVE_FLAG_PROMO_CAP_Q => 'q',
|
||||
_ => '?', // Should not happen
|
||||
};
|
||||
format!("{}{}{}", from_str, to_str, promo_char)
|
||||
} else {
|
||||
// This covers Quiet, DoublePawn, Capture, EnPassant
|
||||
format!("{}{}", from_str, to_str)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ... Rest des MoveList-Codes bleibt exakt gleich ...
|
||||
// (MoveList, new, push, len, is_empty, iter, impl fmt::Display)
|
||||
pub struct MoveList {
|
||||
moves: [Move; 256],
|
||||
count: usize,
|
||||
}
|
||||
|
||||
impl MoveList {
|
||||
pub fn new() -> Self {
|
||||
MoveList {
|
||||
moves: [unsafe { std::mem::zeroed() }; 256],
|
||||
count: 0,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn push(&mut self, mv: Move) {
|
||||
debug_assert!(self.count < 256, "Move list overflow!");
|
||||
|
||||
self.moves[self.count] = mv;
|
||||
self.count += 1;
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn len(&self) -> usize {
|
||||
self.count
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.count == 0
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn iter(&self) -> slice::Iter<'_, Move> {
|
||||
self.moves[..self.count].iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for MoveList {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", &self.iter().map(|mv| mv.to_algebraic()).collect::<Vec<String>>().join(" "))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub struct UndoMove {
|
||||
mv: Move,
|
||||
captured_piece: Option<PieceType>,
|
||||
old_en_passant_square: Option<Square>,
|
||||
old_castling_rights: u8,
|
||||
old_halfmove_clock: u8,
|
||||
}
|
||||
|
||||
impl UndoMove {
|
||||
pub fn new(mv: Move,
|
||||
captured_piece: Option<PieceType>,
|
||||
old_en_passant_square: Option<Square>,
|
||||
old_castling_rights: u8,
|
||||
old_halfmove_clock: u8) -> Self {
|
||||
Self {
|
||||
mv,
|
||||
captured_piece,
|
||||
old_en_passant_square,
|
||||
old_castling_rights,
|
||||
old_halfmove_clock
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
19
src/movegen/mod.rs
Normal file
19
src/movegen/mod.rs
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
pub mod non_sliders;
|
||||
pub mod sliders;
|
||||
pub mod pawns;
|
||||
pub mod tables;
|
||||
|
||||
use crate::board::Board;
|
||||
use crate::r#move::*;
|
||||
use non_sliders::*;
|
||||
use sliders::*;
|
||||
use pawns::*;
|
||||
|
||||
pub fn generate_pseudo_legal_moves(board: &Board, list: &mut MoveList) {
|
||||
generate_pawn_moves(board, list);
|
||||
generate_knight_moves(board, list);
|
||||
generate_bishop_moves(board, list);
|
||||
generate_rook_moves(board, list);
|
||||
generate_queen_moves(board, list);
|
||||
generate_king_moves(board, list);
|
||||
}
|
||||
87
src/movegen/non_sliders.rs
Normal file
87
src/movegen/non_sliders.rs
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
use crate::board::*;
|
||||
use crate::r#move::*;
|
||||
use crate::square::*;
|
||||
use super::tables::{KING_ATTACKS, KNIGHT_ATTACKS};
|
||||
|
||||
pub fn generate_knight_moves(board: &Board, list: &mut MoveList) {
|
||||
let enemy_occupied = board.occupied[!board.side_to_move as usize];
|
||||
let mut friendly_knights = board.pieces[PieceType::Knight as usize][board.side_to_move as usize];
|
||||
|
||||
while friendly_knights != 0 {
|
||||
let square = SQUARES[friendly_knights.trailing_zeros() as usize];
|
||||
let mut attacks = KNIGHT_ATTACKS[square as usize] & !board.occupied[board.side_to_move as usize];
|
||||
|
||||
while attacks != 0 {
|
||||
let attack = SQUARES[attacks.trailing_zeros() as usize];
|
||||
let attack_bb = 1u64 << attack as u64;
|
||||
|
||||
let flags = if (enemy_occupied & attack_bb) != 0 {
|
||||
MOVE_FLAG_CAPTURE
|
||||
} else {
|
||||
MOVE_FLAG_QUIET
|
||||
};
|
||||
|
||||
let mv = Move::new(square, attack, flags);
|
||||
list.push(mv);
|
||||
attacks &= attacks - 1;
|
||||
}
|
||||
friendly_knights &= friendly_knights - 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate_king_moves(board: &Board, list: &mut MoveList) {
|
||||
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];
|
||||
|
||||
if friendly_king == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
let square = SQUARES[friendly_king.trailing_zeros() as usize];
|
||||
|
||||
// 1. Generate standard king moves
|
||||
let mut attacks = KING_ATTACKS[square as usize] & !board.occupied[board.side_to_move as usize];
|
||||
while attacks != 0 {
|
||||
let attack = SQUARES[attacks.trailing_zeros() as usize];
|
||||
let attack_bb = 1u64 << attack as u64;
|
||||
|
||||
let flags = if (enemy_occupied & attack_bb) != 0 {
|
||||
MOVE_FLAG_CAPTURE
|
||||
} else {
|
||||
MOVE_FLAG_QUIET
|
||||
};
|
||||
|
||||
let mv = Move::new(square, attack, flags);
|
||||
list.push(mv);
|
||||
attacks &= attacks - 1;
|
||||
}
|
||||
|
||||
// 2. Generate castling king moves
|
||||
if board.side_to_move == Color::White {
|
||||
// Kingside (OO)
|
||||
if (board.castling_rights & CASTLING_WK) != 0 {
|
||||
if (board.all_occupied & CASTLING_WK_MASK) == 0 {
|
||||
list.push(Move::new(Square::E1, Square::G1, MOVE_FLAG_WK_CASTLE));
|
||||
}
|
||||
}
|
||||
// Queenside (OOO)
|
||||
if (board.castling_rights & CASTLING_WQ) != 0 {
|
||||
if (board.all_occupied & CASTLING_WQ_MASK) == 0 {
|
||||
list.push(Move::new(Square::E1, Square::C1, MOVE_FLAG_WQ_CASTLE));
|
||||
}
|
||||
}
|
||||
} else { // Black
|
||||
// Kingside (OO)
|
||||
if (board.castling_rights & CASTLING_BK) != 0 {
|
||||
if (board.all_occupied & CASTLING_BK_MASK) == 0 {
|
||||
list.push(Move::new(Square::E8, Square::G8, MOVE_FLAG_BK_CASTLE));
|
||||
}
|
||||
}
|
||||
// Queenside (OOO)
|
||||
if (board.castling_rights & CASTLING_BQ) != 0 {
|
||||
if (board.all_occupied & CASTLING_BQ_MASK) == 0 {
|
||||
list.push(Move::new(Square::E8, Square::C8, MOVE_FLAG_BQ_CASTLE));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
251
src/movegen/pawns.rs
Normal file
251
src/movegen/pawns.rs
Normal file
|
|
@ -0,0 +1,251 @@
|
|||
use crate::board::*;
|
||||
use crate::r#move::*;
|
||||
use crate::square::*;
|
||||
|
||||
pub const RANK1_MASK: u64 = 255; // A1 - H1
|
||||
pub const RANK2_MASK: u64 = 65280; // A2 - H2
|
||||
pub const RANK3_MASK: u64 = 16711680; // A3 - H3
|
||||
pub const RANK4_MASK: u64 = 4278190080; // A4 - H4
|
||||
pub const RANK5_MASK: u64 = 1095216660480; // A5 - H5
|
||||
pub const RANK6_MASK: u64 = 280375465082880; // A6 - H6
|
||||
pub const RANK7_MASK: u64 = 71776119061217280; // A7 - H7
|
||||
pub const RANK8_MASK: u64 = 18374686479671623680; // A8 - H8
|
||||
|
||||
|
||||
pub const PAWN_A_SIDE_CAPTURE_MASK_WITHE: u64 = 280371153272574; // B1 - H6 (omitted promotions)
|
||||
pub const PAWN_H_SIDE_CAPTURE_MASK_WITHE: u64 = 140185576636287; // A1- G6 (omitted promotions)
|
||||
|
||||
pub const PAWN_A_SIDE_CAPTURE_MASK_BLACK: u64 = 18374403900871409664; // B3 - H8 (omitted promotions)
|
||||
pub const PAWN_H_SIDE_CAPTURE_MASK_BLACK: u64 = 9187201950435704832; // A3- G8 (omitted promotions)
|
||||
|
||||
|
||||
pub const PAWN_A_SIDE_CAPTURE_PROMOTION_MASK_WITHE: u64 = 71494644084506624; // B7 - H7
|
||||
pub const PAWN_H_SIDE_CAPTURE_PROMOTION_MASK_WITHE: u64 = 35747322042253312; // A7- G7
|
||||
|
||||
pub const PAWN_A_SIDE_CAPTURE_PROMOTION_MASK_BLACK: u64 = 65024; // B2 - H2
|
||||
pub const PAWN_H_SIDE_CAPTURE_PROMOTION_MASK_BLACK: u64 = 32512; // A2 - G2
|
||||
|
||||
|
||||
|
||||
pub fn generate_pawn_moves(board: &Board, list: &mut MoveList) {
|
||||
|
||||
// 1. Withe
|
||||
if board.side_to_move == Color::White {
|
||||
let friendly_pawns = board.pieces[PieceType::Pawn as usize][0];
|
||||
let opponent_occupied = board.occupied[1];
|
||||
|
||||
// 1.1 Single Push
|
||||
let mut single_push_targets = ((friendly_pawns & !(RANK8_MASK | RANK7_MASK)) << 8) & board.empty_squares;
|
||||
|
||||
while single_push_targets > 0 {
|
||||
let to = SQUARES[single_push_targets.trailing_zeros() as usize];
|
||||
let from = to - 8;
|
||||
list.push(Move::new(from, to, MOVE_FLAG_QUIET));
|
||||
single_push_targets &= single_push_targets - 1;
|
||||
}
|
||||
|
||||
// 1.2 Double Push
|
||||
let base_rank_pawns = friendly_pawns & RANK2_MASK;
|
||||
let rank3_unblocked = (base_rank_pawns << 8) & board.empty_squares;
|
||||
let mut double_push_targets = (rank3_unblocked << 8) & board.empty_squares;
|
||||
|
||||
while double_push_targets > 0 {
|
||||
let to = SQUARES[double_push_targets.trailing_zeros() as usize];
|
||||
let from = to - 16;
|
||||
list.push(Move::new(from, to, MOVE_FLAG_QUIET));
|
||||
double_push_targets &= double_push_targets - 1;
|
||||
}
|
||||
|
||||
// 1.3 Captures
|
||||
// 1.3.1 A-Side Capture (omitted promotion captures)
|
||||
let mut a_side_capture_targets = (friendly_pawns & PAWN_H_SIDE_CAPTURE_MASK_WITHE) << 7 & opponent_occupied;
|
||||
|
||||
while a_side_capture_targets > 0 {
|
||||
let to = SQUARES[a_side_capture_targets.trailing_zeros() as usize];
|
||||
let from = to - 7;
|
||||
list.push(Move::new(from, to, MOVE_FLAG_CAPTURE));
|
||||
a_side_capture_targets &= a_side_capture_targets - 1;
|
||||
}
|
||||
|
||||
// 1.3.2 H-Side Capture (omitted promotion captures)
|
||||
let mut h_side_capture_targets = (friendly_pawns & PAWN_A_SIDE_CAPTURE_MASK_WITHE) << 9 & opponent_occupied;
|
||||
|
||||
while h_side_capture_targets > 0 {
|
||||
let to = SQUARES[h_side_capture_targets.trailing_zeros() as usize];
|
||||
let from = to - 9;
|
||||
list.push(Move::new(from, to, MOVE_FLAG_CAPTURE));
|
||||
h_side_capture_targets &= h_side_capture_targets - 1;
|
||||
}
|
||||
|
||||
// 1.4 Promotion
|
||||
// 1.4.1 Pushing promotion
|
||||
let mut promotion_targets = ((friendly_pawns & RANK7_MASK) << 8) & board.empty_squares;
|
||||
|
||||
while promotion_targets > 0 {
|
||||
let to = SQUARES[promotion_targets.trailing_zeros() as usize];
|
||||
let from = to - 8;
|
||||
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_B));
|
||||
list.push(Move::new(from, to, MOVE_FLAG_PROMO_N));
|
||||
promotion_targets &= promotion_targets - 1;
|
||||
}
|
||||
|
||||
// 1.4.2 Capturing Promotion
|
||||
// 1.4.2.1 A-side capturing promotion
|
||||
// CORRECTED: Use PAWN_A_SIDE_CAPTURE_PROMOTION_MASK_WITHE (excludes A-file)
|
||||
let mut promotion_targets_a_side_capture = ((friendly_pawns & PAWN_A_SIDE_CAPTURE_PROMOTION_MASK_WITHE) << 7) & board.occupied[1];
|
||||
while promotion_targets_a_side_capture > 0 {
|
||||
let to = SQUARES[promotion_targets_a_side_capture.trailing_zeros() as usize];
|
||||
let from = to - 7;
|
||||
list.push(Move::new(from, to, MOVE_FLAG_PROMO_CAP_Q));
|
||||
list.push(Move::new(from, to, MOVE_FLAG_PROMO_CAP_R));
|
||||
list.push(Move::new(from, to, MOVE_FLAG_PROMO_CAP_B));
|
||||
list.push(Move::new(from, to, MOVE_FLAG_PROMO_CAP_N));
|
||||
promotion_targets_a_side_capture &= promotion_targets_a_side_capture - 1;
|
||||
}
|
||||
|
||||
// 1.4.2.2 H-side capturing promotion
|
||||
// CORRECTED: Use PAWN_H_SIDE_CAPTURE_PROMOTION_MASK_WITHE (excludes H-file)
|
||||
let mut promotion_targets_h_side_capture = ((friendly_pawns & PAWN_H_SIDE_CAPTURE_PROMOTION_MASK_WITHE) << 9) & board.occupied[1];
|
||||
while promotion_targets_h_side_capture > 0 {
|
||||
let to = SQUARES[promotion_targets_h_side_capture.trailing_zeros() as usize];
|
||||
let from = to - 9;
|
||||
list.push(Move::new(from, to, MOVE_FLAG_PROMO_CAP_Q));
|
||||
list.push(Move::new(from, to, MOVE_FLAG_PROMO_CAP_R));
|
||||
list.push(Move::new(from, to, MOVE_FLAG_PROMO_CAP_B));
|
||||
list.push(Move::new(from, to, MOVE_FLAG_PROMO_CAP_N));
|
||||
promotion_targets_h_side_capture &= promotion_targets_h_side_capture - 1;
|
||||
}
|
||||
|
||||
// 1.5 En Passant
|
||||
if let Some(en_passant_target_square) = board.en_passant_target {
|
||||
// Check if the target square is on the 6th rank (A6=40 to H6=47)
|
||||
if (en_passant_target_square >= Square::A6) && (en_passant_target_square <= Square::H6) {
|
||||
let en_passant_target_bb: u64 = 1_u64 << (en_passant_target_square as u64);
|
||||
|
||||
// 1. Check A-Side capture (<< 7, e.g., D5 -> C6)
|
||||
let attacker_mask_a_side = (en_passant_target_bb >> 7) & PAWN_H_SIDE_CAPTURE_MASK_WITHE;
|
||||
if (attacker_mask_a_side & friendly_pawns) > 0 {
|
||||
let from = en_passant_target_square - 7;
|
||||
list.push(Move::new(from, en_passant_target_square, MOVE_FLAG_EN_PASSANT));
|
||||
}
|
||||
|
||||
// 2. Check H-Side capture (<< 9, e.g., B5 -> C6)
|
||||
let attacker_mask_h_side = (en_passant_target_bb >> 9) & PAWN_A_SIDE_CAPTURE_MASK_WITHE;
|
||||
if (attacker_mask_h_side & friendly_pawns) > 0 {
|
||||
let from = en_passant_target_square - 9;
|
||||
list.push(Move::new(from, en_passant_target_square, MOVE_FLAG_EN_PASSANT));
|
||||
}
|
||||
}
|
||||
}
|
||||
// 2. Black
|
||||
} else {
|
||||
let friendly_pawns = board.pieces[PieceType::Pawn as usize][1];
|
||||
let opponent_occupied = board.occupied[0];
|
||||
|
||||
// 2.1 Single Push
|
||||
let mut single_push_targets = ((friendly_pawns & !(RANK1_MASK | RANK2_MASK)) >> 8) & board.empty_squares;
|
||||
|
||||
while single_push_targets > 0 {
|
||||
let to = SQUARES[single_push_targets.trailing_zeros() as usize];
|
||||
let from = to + 8;
|
||||
list.push(Move::new(from, to, MOVE_FLAG_QUIET));
|
||||
single_push_targets &= single_push_targets - 1;
|
||||
}
|
||||
|
||||
// 2.2 Double Push
|
||||
let base_rank_pawns = friendly_pawns & RANK7_MASK;
|
||||
let rank6_unblocked = (base_rank_pawns >> 8) & board.empty_squares;
|
||||
let mut double_push_targets = (rank6_unblocked >> 8) & board.empty_squares;
|
||||
|
||||
while double_push_targets > 0 {
|
||||
let to = SQUARES[double_push_targets.trailing_zeros() as usize];
|
||||
let from = to + 16;
|
||||
list.push(Move::new(from, to, MOVE_FLAG_QUIET));
|
||||
double_push_targets &= double_push_targets - 1;
|
||||
}
|
||||
|
||||
// 2.3 Captures
|
||||
// 2.3.1 A-Side Capture (>> 9)
|
||||
let mut a_side_capture_targets = (friendly_pawns & PAWN_A_SIDE_CAPTURE_MASK_BLACK) >> 9 & opponent_occupied;
|
||||
|
||||
while a_side_capture_targets > 0 {
|
||||
let to = SQUARES[a_side_capture_targets.trailing_zeros() as usize];
|
||||
let from = to + 9;
|
||||
list.push(Move::new(from, to, MOVE_FLAG_CAPTURE));
|
||||
a_side_capture_targets &= a_side_capture_targets - 1;
|
||||
}
|
||||
|
||||
// 2.3.2 H-Side Capture (>> 7)
|
||||
let mut h_side_capture_targets = (friendly_pawns & PAWN_H_SIDE_CAPTURE_MASK_BLACK) >> 7 & opponent_occupied;
|
||||
|
||||
while h_side_capture_targets > 0 {
|
||||
let to = SQUARES[h_side_capture_targets.trailing_zeros() as usize];
|
||||
let from = to + 7;
|
||||
list.push(Move::new(from, to, MOVE_FLAG_CAPTURE));
|
||||
h_side_capture_targets &= h_side_capture_targets - 1;
|
||||
}
|
||||
|
||||
// 2.4 Promotion
|
||||
// 2.4.1 Pushing promotion
|
||||
let mut promotion_targets = ((friendly_pawns & RANK2_MASK) >> 8) & board.empty_squares;
|
||||
|
||||
while promotion_targets > 0 {
|
||||
let to = SQUARES[promotion_targets.trailing_zeros() as usize];
|
||||
let from = to + 8;
|
||||
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_B));
|
||||
list.push(Move::new(from, to, MOVE_FLAG_PROMO_N));
|
||||
promotion_targets &= promotion_targets - 1;
|
||||
}
|
||||
|
||||
// 2.4.2 Capturing Promotion
|
||||
// 2.4.2.1 A-side capturing promotion (>> 9)
|
||||
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 {
|
||||
let to = SQUARES[promotion_targets_a_side_capture.trailing_zeros() as usize];
|
||||
let from = to + 9;
|
||||
list.push(Move::new(from, to, MOVE_FLAG_PROMO_CAP_Q));
|
||||
list.push(Move::new(from, to, MOVE_FLAG_PROMO_CAP_R));
|
||||
list.push(Move::new(from, to, MOVE_FLAG_PROMO_CAP_B));
|
||||
list.push(Move::new(from, to, MOVE_FLAG_PROMO_CAP_N));
|
||||
promotion_targets_a_side_capture &= promotion_targets_a_side_capture - 1;
|
||||
}
|
||||
|
||||
// 2.4.2.2 H-side capturing promotion (>> 7)
|
||||
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 {
|
||||
let to = SQUARES[promotion_targets_h_side_capture.trailing_zeros() as usize];
|
||||
let from = to + 7;
|
||||
list.push(Move::new(from, to, MOVE_FLAG_PROMO_CAP_Q));
|
||||
list.push(Move::new(from, to, MOVE_FLAG_PROMO_CAP_R));
|
||||
list.push(Move::new(from, to, MOVE_FLAG_PROMO_CAP_B));
|
||||
list.push(Move::new(from, to, MOVE_FLAG_PROMO_CAP_N));
|
||||
promotion_targets_h_side_capture &= promotion_targets_h_side_capture - 1;
|
||||
}
|
||||
|
||||
// 2.5 En Passant
|
||||
if let Some(en_passant_target_square) = board.en_passant_target {
|
||||
// Check if the target square is on the 3rd rank (A3=16 to H3=23)
|
||||
if (en_passant_target_square >= Square::A3) && (en_passant_target_square <= Square::H3) {
|
||||
let en_passant_target_bb: u64 = 1_u64 << (en_passant_target_square as u64);
|
||||
|
||||
// 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;
|
||||
if (attacker_mask_a_side & friendly_pawns) > 0 {
|
||||
let from = en_passant_target_square + 9;
|
||||
list.push(Move::new(from, en_passant_target_square, MOVE_FLAG_EN_PASSANT));
|
||||
}
|
||||
|
||||
// 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;
|
||||
if (attacker_mask_h_side & friendly_pawns) > 0 {
|
||||
let from = en_passant_target_square + 7;
|
||||
list.push(Move::new(from, en_passant_target_square, MOVE_FLAG_EN_PASSANT));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
132
src/movegen/sliders.rs
Normal file
132
src/movegen/sliders.rs
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
use crate::board::*;
|
||||
use crate::r#move::{Move, MoveList, MOVE_FLAG_CAPTURE, MOVE_FLAG_QUIET};
|
||||
use crate::square::SQUARES;
|
||||
use super::tables::*;
|
||||
|
||||
pub fn generate_rook_moves(board: &Board, list: &mut MoveList) {
|
||||
let mut friendly_rooks = board.pieces[PieceType::Rook as usize][board.side_to_move as usize];
|
||||
while friendly_rooks > 0 {
|
||||
let square_index = friendly_rooks.trailing_zeros() as usize;
|
||||
|
||||
let premask = PREMASKS_ROOK[square_index];
|
||||
let magic = MAGICS_ROOK[square_index];
|
||||
let relevant_bits = RELEVANT_BITS_ROOK[square_index];
|
||||
let shift = 64 - relevant_bits;
|
||||
let blockers = board.all_occupied & premask;
|
||||
let attack_table = get_rook_attacks();
|
||||
|
||||
let magic_index = (blockers.wrapping_mul(magic)) >> shift;
|
||||
|
||||
let movable_squares = attack_table[square_index][magic_index as usize];
|
||||
|
||||
// 1. Normal moves
|
||||
let mut quiet_moves = movable_squares & !board.all_occupied;
|
||||
while quiet_moves > 0 {
|
||||
let from = SQUARES[square_index];
|
||||
let to = SQUARES[quiet_moves.trailing_zeros() as usize];
|
||||
list.push(Move::new(from, to, MOVE_FLAG_QUIET));
|
||||
quiet_moves &= quiet_moves - 1;
|
||||
}
|
||||
|
||||
// 2. Captures
|
||||
let mut capture_moves = movable_squares & board.occupied[!board.side_to_move as usize];
|
||||
while capture_moves > 0 {
|
||||
let from = SQUARES[square_index];
|
||||
let to = SQUARES[capture_moves.trailing_zeros() as usize];
|
||||
list.push(Move::new(from, to, MOVE_FLAG_CAPTURE));
|
||||
capture_moves &= capture_moves - 1;
|
||||
}
|
||||
|
||||
friendly_rooks &= friendly_rooks - 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate_bishop_moves(board: &Board, list: &mut MoveList) {
|
||||
let mut friendly_bishops = board.pieces[PieceType::Bishop as usize][board.side_to_move as usize];
|
||||
while friendly_bishops > 0 {
|
||||
let square_index = friendly_bishops.trailing_zeros() as usize;
|
||||
|
||||
let premask = PREMASKS_BISHOP[square_index];
|
||||
let magic = MAGICS_BISHOP[square_index];
|
||||
let relevant_bits = RELEVANT_BITS_BISHOP[square_index];
|
||||
let shift = 64 - relevant_bits;
|
||||
let blockers = board.all_occupied & premask;
|
||||
let attack_table = get_bishop_attacks();
|
||||
|
||||
let magic_index = (blockers.wrapping_mul(magic)) >> shift;
|
||||
|
||||
let movable_squares = attack_table[square_index][magic_index as usize];
|
||||
|
||||
// 1. Normal moves
|
||||
let mut quiet_moves = movable_squares & !board.all_occupied;
|
||||
while quiet_moves > 0 {
|
||||
let from = SQUARES[square_index];
|
||||
let to = SQUARES[quiet_moves.trailing_zeros() as usize];
|
||||
list.push(Move::new(from, to, MOVE_FLAG_QUIET));
|
||||
quiet_moves &= quiet_moves - 1;
|
||||
}
|
||||
|
||||
// 2. Captures
|
||||
let mut capture_moves = movable_squares & board.occupied[!board.side_to_move as usize];
|
||||
while capture_moves > 0 {
|
||||
let from = SQUARES[square_index];
|
||||
let to = SQUARES[capture_moves.trailing_zeros() as usize];
|
||||
list.push(Move::new(from, to, MOVE_FLAG_CAPTURE));
|
||||
capture_moves &= capture_moves - 1;
|
||||
}
|
||||
|
||||
friendly_bishops &= friendly_bishops - 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate_queen_moves(board: &Board, list: &mut MoveList) {
|
||||
let mut friendly_queens = board.pieces[PieceType::Queen as usize][board.side_to_move as usize];
|
||||
while friendly_queens > 0 {
|
||||
let square_index = friendly_queens.trailing_zeros() as usize;
|
||||
|
||||
// --- 1. Get Rook Attacks ---
|
||||
let rook_premask = PREMASKS_ROOK[square_index];
|
||||
let rook_magic = MAGICS_ROOK[square_index];
|
||||
let rook_relevant_bits = RELEVANT_BITS_ROOK[square_index];
|
||||
let rook_shift = 64 - rook_relevant_bits;
|
||||
let rook_blockers = board.all_occupied & rook_premask;
|
||||
let rook_attack_table = get_rook_attacks();
|
||||
let rook_magic_index = (rook_blockers.wrapping_mul(rook_magic)) >> rook_shift;
|
||||
let rook_moves = rook_attack_table[square_index][rook_magic_index as usize];
|
||||
|
||||
// --- 2. Get Bishop Attacks ---
|
||||
let bishop_premask = PREMASKS_BISHOP[square_index];
|
||||
let bishop_magic = MAGICS_BISHOP[square_index];
|
||||
let bishop_relevant_bits = RELEVANT_BITS_BISHOP[square_index];
|
||||
let bishop_shift = 64 - bishop_relevant_bits;
|
||||
let bishop_blockers = board.all_occupied & bishop_premask;
|
||||
let bishop_attack_table = get_bishop_attacks();
|
||||
let bishop_magic_index = (bishop_blockers.wrapping_mul(bishop_magic)) >> bishop_shift;
|
||||
let bishop_moves = bishop_attack_table[square_index][bishop_magic_index as usize];
|
||||
|
||||
// --- 3. Combine Attacks ---
|
||||
let movable_squares = rook_moves | bishop_moves;
|
||||
|
||||
// --- 4. Generate Moves (Identical to Rook/Bishop) ---
|
||||
|
||||
// 4a. Normal moves
|
||||
let mut quiet_moves = movable_squares & !board.all_occupied;
|
||||
while quiet_moves > 0 {
|
||||
let from = SQUARES[square_index];
|
||||
let to = SQUARES[quiet_moves.trailing_zeros() as usize];
|
||||
list.push(Move::new(from, to, MOVE_FLAG_QUIET));
|
||||
quiet_moves &= quiet_moves - 1;
|
||||
}
|
||||
|
||||
// 4b. Captures
|
||||
let mut capture_moves = movable_squares & board.occupied[!board.side_to_move as usize];
|
||||
while capture_moves > 0 {
|
||||
let from = SQUARES[square_index];
|
||||
let to = SQUARES[capture_moves.trailing_zeros() as usize];
|
||||
list.push(Move::new(from, to, MOVE_FLAG_CAPTURE));
|
||||
capture_moves &= capture_moves - 1;
|
||||
}
|
||||
|
||||
friendly_queens &= friendly_queens - 1;
|
||||
}
|
||||
}
|
||||
647
src/movegen/tables.rs
Normal file
647
src/movegen/tables.rs
Normal file
|
|
@ -0,0 +1,647 @@
|
|||
use std::sync::OnceLock;
|
||||
|
||||
|
||||
pub const KNIGHT_ATTACKS: [u64; 64] = [
|
||||
0b00000000_00000000_00000000_00000000_00000000_00000010_00000100_00000000, // Square 0 (A1)
|
||||
0b00000000_00000000_00000000_00000000_00000000_00000101_00001000_00000000, // Square 1 (B1)
|
||||
0b00000000_00000000_00000000_00000000_00000000_00001010_00010001_00000000, // Square 2 (C1)
|
||||
0b00000000_00000000_00000000_00000000_00000000_00010100_00100010_00000000, // Square 3 (D1)
|
||||
0b00000000_00000000_00000000_00000000_00000000_00101000_01000100_00000000, // Square 4 (E1)
|
||||
0b00000000_00000000_00000000_00000000_00000000_01010000_10001000_00000000, // Square 5 (F1)
|
||||
0b00000000_00000000_00000000_00000000_00000000_10100000_00010000_00000000, // Square 6 (G1)
|
||||
0b00000000_00000000_00000000_00000000_00000000_01000000_00100000_00000000, // Square 7 (H1)
|
||||
0b00000000_00000000_00000000_00000000_00000010_00000100_00000000_00000100, // Square 8 (A2)
|
||||
0b00000000_00000000_00000000_00000000_00000101_00001000_00000000_00001000, // Square 9 (B2)
|
||||
0b00000000_00000000_00000000_00000000_00001010_00010001_00000000_00010001, // Square 10 (C2)
|
||||
0b00000000_00000000_00000000_00000000_00010100_00100010_00000000_00100010, // Square 11 (D2)
|
||||
0b00000000_00000000_00000000_00000000_00101000_01000100_00000000_01000100, // Square 12 (E2)
|
||||
0b00000000_00000000_00000000_00000000_01010000_10001000_00000000_10001000, // Square 13 (F2)
|
||||
0b00000000_00000000_00000000_00000000_10100000_00010000_00000000_00010000, // Square 14 (G2)
|
||||
0b00000000_00000000_00000000_00000000_01000000_00100000_00000000_00100000, // Square 15 (H2)
|
||||
0b00000000_00000000_00000000_00000010_00000100_00000000_00000100_00000010, // Square 16 (A3)
|
||||
0b00000000_00000000_00000000_00000101_00001000_00000000_00001000_00000101, // Square 17 (B3)
|
||||
0b00000000_00000000_00000000_00001010_00010001_00000000_00010001_00001010, // Square 18 (C3)
|
||||
0b00000000_00000000_00000000_00010100_00100010_00000000_00100010_00010100, // Square 19 (D3)
|
||||
0b00000000_00000000_00000000_00101000_01000100_00000000_01000100_00101000, // Square 20 (E3)
|
||||
0b00000000_00000000_00000000_01010000_10001000_00000000_10001000_01010000, // Square 21 (F3)
|
||||
0b00000000_00000000_00000000_10100000_00010000_00000000_00010000_10100000, // Square 22 (G3)
|
||||
0b00000000_00000000_00000000_01000000_00100000_00000000_00100000_01000000, // Square 23 (H3)
|
||||
0b00000000_00000000_00000010_00000100_00000000_00000100_00000010_00000000, // Square 24 (A4)
|
||||
0b00000000_00000000_00000101_00001000_00000000_00001000_00000101_00000000, // Square 25 (B4)
|
||||
0b00000000_00000000_00001010_00010001_00000000_00010001_00001010_00000000, // Square 26 (C4)
|
||||
0b00000000_00000000_00010100_00100010_00000000_00100010_00010100_00000000, // Square 27 (D4)
|
||||
0b00000000_00000000_00101000_01000100_00000000_01000100_00101000_00000000, // Square 28 (E4)
|
||||
0b00000000_00000000_01010000_10001000_00000000_10001000_01010000_00000000, // Square 29 (F4)
|
||||
0b00000000_00000000_10100000_00010000_00000000_00010000_10100000_00000000, // Square 30 (G4)
|
||||
0b00000000_00000000_01000000_00100000_00000000_00100000_01000000_00000000, // Square 31 (H4)
|
||||
0b00000000_00000010_00000100_00000000_00000100_00000010_00000000_00000000, // Square 32 (A5)
|
||||
0b00000000_00000101_00001000_00000000_00001000_00000101_00000000_00000000, // Square 33 (B5)
|
||||
0b00000000_00001010_00010001_00000000_00010001_00001010_00000000_00000000, // Square 34 (C5)
|
||||
0b00000000_00010100_00100010_00000000_00100010_00010100_00000000_00000000, // Square 35 (D5)
|
||||
0b00000000_00101000_01000100_00000000_01000100_00101000_00000000_00000000, // Square 36 (E5)
|
||||
0b00000000_01010000_10001000_00000000_10001000_01010000_00000000_00000000, // Square 37 (F5)
|
||||
0b00000000_10100000_00010000_00000000_00010000_10100000_00000000_00000000, // Square 38 (G5)
|
||||
0b00000000_01000000_00100000_00000000_00100000_01000000_00000000_00000000, // Square 39 (H5)
|
||||
0b00000010_00000100_00000000_00000100_00000010_00000000_00000000_00000000, // Square 40 (A6)
|
||||
0b00000101_00001000_00000000_00001000_00000101_00000000_00000000_00000000, // Square 41 (B6)
|
||||
0b00001010_00010001_00000000_00010001_00001010_00000000_00000000_00000000, // Square 42 (C6)
|
||||
0b00010100_00100010_00000000_00100010_00010100_00000000_00000000_00000000, // Square 43 (D6)
|
||||
0b00101000_01000100_00000000_01000100_00101000_00000000_00000000_00000000, // Square 44 (E6)
|
||||
0b01010000_10001000_00000000_10001000_01010000_00000000_00000000_00000000, // Square 45 (F6)
|
||||
0b10100000_00010000_00000000_00010000_10100000_00000000_00000000_00000000, // Square 46 (G6)
|
||||
0b01000000_00100000_00000000_00100000_01000000_00000000_00000000_00000000, // Square 47 (H6)
|
||||
0b00000100_00000000_00000100_00000010_00000000_00000000_00000000_00000000, // Square 48 (A7)
|
||||
0b00001000_00000000_00001000_00000101_00000000_00000000_00000000_00000000, // Square 49 (B7)
|
||||
0b00010001_00000000_00010001_00001010_00000000_00000000_00000000_00000000, // Square 50 (C7)
|
||||
0b00100010_00000000_00100010_00010100_00000000_00000000_00000000_00000000, // Square 51 (D7)
|
||||
0b01000100_00000000_01000100_00101000_00000000_00000000_00000000_00000000, // Square 52 (E7)
|
||||
0b10001000_00000000_10001000_01010000_00000000_00000000_00000000_00000000, // Square 53 (F7)
|
||||
0b00010000_00000000_00010000_10100000_00000000_00000000_00000000_00000000, // Square 54 (G7)
|
||||
0b00100000_00000000_00100000_01000000_00000000_00000000_00000000_00000000, // Square 55 (H7)
|
||||
0b00000000_00000100_00000010_00000000_00000000_00000000_00000000_00000000, // Square 56 (A8)
|
||||
0b00000000_00001000_00000101_00000000_00000000_00000000_00000000_00000000, // Square 57 (B8)
|
||||
0b00000000_00010001_00001010_00000000_00000000_00000000_00000000_00000000, // Square 58 (C8)
|
||||
0b00000000_00100010_00010100_00000000_00000000_00000000_00000000_00000000, // Square 59 (D8)
|
||||
0b00000000_01000100_00101000_00000000_00000000_00000000_00000000_00000000, // Square 60 (E8)
|
||||
0b00000000_10001000_01010000_00000000_00000000_00000000_00000000_00000000, // Square 61 (F8)
|
||||
0b00000000_00010000_10100000_00000000_00000000_00000000_00000000_00000000, // Square 62 (G8)
|
||||
0b00000000_00100000_01000000_00000000_00000000_00000000_00000000_00000000, // Square 63 (H8)
|
||||
];
|
||||
|
||||
pub const PREMASKS_ROOK: [u64; 64] = [
|
||||
0b00000000_00000001_00000001_00000001_00000001_00000001_00000001_01111110, // Square 0 (A1)
|
||||
0b00000000_00000010_00000010_00000010_00000010_00000010_00000010_01111100, // Square 1 (B1)
|
||||
0b00000000_00000100_00000100_00000100_00000100_00000100_00000100_01111010, // Square 2 (C1)
|
||||
0b00000000_00001000_00001000_00001000_00001000_00001000_00001000_01110110, // Square 3 (D1)
|
||||
0b00000000_00010000_00010000_00010000_00010000_00010000_00010000_01101110, // Square 4 (E1)
|
||||
0b00000000_00100000_00100000_00100000_00100000_00100000_00100000_01011110, // Square 5 (F1)
|
||||
0b00000000_01000000_01000000_01000000_01000000_01000000_01000000_00111110, // Square 6 (G1)
|
||||
0b00000000_10000000_10000000_10000000_10000000_10000000_10000000_01111110, // Square 7 (H1)
|
||||
0b00000000_00000001_00000001_00000001_00000001_00000001_01111110_00000000, // Square 8 (A2)
|
||||
0b00000000_00000010_00000010_00000010_00000010_00000010_01111100_00000000, // Square 9 (B2)
|
||||
0b00000000_00000100_00000100_00000100_00000100_00000100_01111010_00000000, // Square 10 (C2)
|
||||
0b00000000_00001000_00001000_00001000_00001000_00001000_01110110_00000000, // Square 11 (D2)
|
||||
0b00000000_00010000_00010000_00010000_00010000_00010000_01101110_00000000, // Square 12 (E2)
|
||||
0b00000000_00100000_00100000_00100000_00100000_00100000_01011110_00000000, // Square 13 (F2)
|
||||
0b00000000_01000000_01000000_01000000_01000000_01000000_00111110_00000000, // Square 14 (G2)
|
||||
0b00000000_10000000_10000000_10000000_10000000_10000000_01111110_00000000, // Square 15 (H2)
|
||||
0b00000000_00000001_00000001_00000001_00000001_01111110_00000001_00000000, // Square 16 (A3)
|
||||
0b00000000_00000010_00000010_00000010_00000010_01111100_00000010_00000000, // Square 17 (B3)
|
||||
0b00000000_00000100_00000100_00000100_00000100_01111010_00000100_00000000, // Square 18 (C3)
|
||||
0b00000000_00001000_00001000_00001000_00001000_01110110_00001000_00000000, // Square 19 (D3)
|
||||
0b00000000_00010000_00010000_00010000_00010000_01101110_00010000_00000000, // Square 20 (E3)
|
||||
0b00000000_00100000_00100000_00100000_00100000_01011110_00100000_00000000, // Square 21 (F3)
|
||||
0b00000000_01000000_01000000_01000000_01000000_00111110_01000000_00000000, // Square 22 (G3)
|
||||
0b00000000_10000000_10000000_10000000_10000000_01111110_10000000_00000000, // Square 23 (H3)
|
||||
0b00000000_00000001_00000001_00000001_01111110_00000001_00000001_00000000, // Square 24 (A4)
|
||||
0b00000000_00000010_00000010_00000010_01111100_00000010_00000010_00000000, // Square 25 (B4)
|
||||
0b00000000_00000100_00000100_00000100_01111010_00000100_00000100_00000000, // Square 26 (C4)
|
||||
0b00000000_00001000_00001000_00001000_01110110_00001000_00001000_00000000, // Square 27 (D4)
|
||||
0b00000000_00010000_00010000_00010000_01101110_00010000_00010000_00000000, // Square 28 (E4)
|
||||
0b00000000_00100000_00100000_00100000_01011110_00100000_00100000_00000000, // Square 29 (F4)
|
||||
0b00000000_01000000_01000000_01000000_00111110_01000000_01000000_00000000, // Square 30 (G4)
|
||||
0b00000000_10000000_10000000_10000000_01111110_10000000_10000000_00000000, // Square 31 (H4)
|
||||
0b00000000_00000001_00000001_01111110_00000001_00000001_00000001_00000000, // Square 32 (A5)
|
||||
0b00000000_00000010_00000010_01111100_00000010_00000010_00000010_00000000, // Square 33 (B5)
|
||||
0b00000000_00000100_00000100_01111010_00000100_00000100_00000100_00000000, // Square 34 (C5)
|
||||
0b00000000_00001000_00001000_01110110_00001000_00001000_00001000_00000000, // Square 35 (D5)
|
||||
0b00000000_00010000_00010000_01101110_00010000_00010000_00010000_00000000, // Square 36 (E5)
|
||||
0b00000000_00100000_00100000_01011110_00100000_00100000_00100000_00000000, // Square 37 (F5)
|
||||
0b00000000_01000000_01000000_00111110_01000000_01000000_01000000_00000000, // Square 38 (G5)
|
||||
0b00000000_10000000_10000000_01111110_10000000_10000000_10000000_00000000, // Square 39 (H5)
|
||||
0b00000000_00000001_01111110_00000001_00000001_00000001_00000001_00000000, // Square 40 (A6)
|
||||
0b00000000_00000010_01111100_00000010_00000010_00000010_00000010_00000000, // Square 41 (B6)
|
||||
0b00000000_00000100_01111010_00000100_00000100_00000100_00000100_00000000, // Square 42 (C6)
|
||||
0b00000000_00001000_01110110_00001000_00001000_00001000_00001000_00000000, // Square 43 (D6)
|
||||
0b00000000_00010000_01101110_00010000_00010000_00010000_00010000_00000000, // Square 44 (E6)
|
||||
0b00000000_00100000_01011110_00100000_00100000_00100000_00100000_00000000, // Square 45 (F6)
|
||||
0b00000000_01000000_00111110_01000000_01000000_01000000_01000000_00000000, // Square 46 (G6)
|
||||
0b00000000_10000000_01111110_10000000_10000000_10000000_10000000_00000000, // Square 47 (H6)
|
||||
0b00000000_01111110_00000001_00000001_00000001_00000001_00000001_00000000, // Square 48 (A7)
|
||||
0b00000000_01111100_00000010_00000010_00000010_00000010_00000010_00000000, // Square 49 (B7)
|
||||
0b00000000_01111010_00000100_00000100_00000100_00000100_00000100_00000000, // Square 50 (C7)
|
||||
0b00000000_01110110_00001000_00001000_00001000_00001000_00001000_00000000, // Square 51 (D7)
|
||||
0b00000000_01101110_00010000_00010000_00010000_00010000_00010000_00000000, // Square 52 (E7)
|
||||
0b00000000_01011110_00100000_00100000_00100000_00100000_00100000_00000000, // Square 53 (F7)
|
||||
0b00000000_00111110_01000000_01000000_01000000_01000000_01000000_00000000, // Square 54 (G7)
|
||||
0b00000000_01111110_10000000_10000000_10000000_10000000_10000000_00000000, // Square 55 (H7)
|
||||
0b01111110_00000001_00000001_00000001_00000001_00000001_00000001_00000000, // Square 56 (A8)
|
||||
0b01111100_00000010_00000010_00000010_00000010_00000010_00000010_00000000, // Square 57 (B8)
|
||||
0b01111010_00000100_00000100_00000100_00000100_00000100_00000100_00000000, // Square 58 (C8)
|
||||
0b01110110_00001000_00001000_00001000_00001000_00001000_00001000_00000000, // Square 59 (D8)
|
||||
0b01101110_00010000_00010000_00010000_00010000_00010000_00010000_00000000, // Square 60 (E8)
|
||||
0b01011110_00100000_00100000_00100000_00100000_00100000_00100000_00000000, // Square 61 (F8)
|
||||
0b00111110_01000000_01000000_01000000_01000000_01000000_01000000_00000000, // Square 62 (G8)
|
||||
0b01111110_10000000_10000000_10000000_10000000_10000000_10000000_00000000, // Square 63 (H8)
|
||||
];
|
||||
|
||||
pub const PREMASKS_BISHOP: [u64; 64] = [
|
||||
0b00000000_01000000_00100000_00010000_00001000_00000100_00000010_00000000, // Square 0 (A1)
|
||||
0b00000000_00000000_01000000_00100000_00010000_00001000_00000100_00000000, // Square 1 (B1)
|
||||
0b00000000_00000000_00000000_01000000_00100000_00010000_00001010_00000000, // Square 2 (C1)
|
||||
0b00000000_00000000_00000000_00000000_01000000_00100010_00010100_00000000, // Square 3 (D1)
|
||||
0b00000000_00000000_00000000_00000000_00000010_01000100_00101000_00000000, // Square 4 (E1)
|
||||
0b00000000_00000000_00000000_00000010_00000100_00001000_01010000_00000000, // Square 5 (F1)
|
||||
0b00000000_00000000_00000010_00000100_00001000_00010000_00100000_00000000, // Square 6 (G1)
|
||||
0b00000000_00000010_00000100_00001000_00010000_00100000_01000000_00000000, // Square 7 (H1)
|
||||
0b00000000_00100000_00010000_00001000_00000100_00000010_00000000_00000000, // Square 8 (A2)
|
||||
0b00000000_01000000_00100000_00010000_00001000_00000100_00000000_00000000, // Square 9 (B2)
|
||||
0b00000000_00000000_01000000_00100000_00010000_00001010_00000000_00000000, // Square 10 (C2)
|
||||
0b00000000_00000000_00000000_01000000_00100010_00010100_00000000_00000000, // Square 11 (D2)
|
||||
0b00000000_00000000_00000000_00000010_01000100_00101000_00000000_00000000, // Square 12 (E2)
|
||||
0b00000000_00000000_00000010_00000100_00001000_01010000_00000000_00000000, // Square 13 (F2)
|
||||
0b00000000_00000010_00000100_00001000_00010000_00100000_00000000_00000000, // Square 14 (G2)
|
||||
0b00000000_00000100_00001000_00010000_00100000_01000000_00000000_00000000, // Square 15 (H2)
|
||||
0b00000000_00010000_00001000_00000100_00000010_00000000_00000010_00000000, // Square 16 (A3)
|
||||
0b00000000_00100000_00010000_00001000_00000100_00000000_00000100_00000000, // Square 17 (B3)
|
||||
0b00000000_01000000_00100000_00010000_00001010_00000000_00001010_00000000, // Square 18 (C3)
|
||||
0b00000000_00000000_01000000_00100010_00010100_00000000_00010100_00000000, // Square 19 (D3)
|
||||
0b00000000_00000000_00000010_01000100_00101000_00000000_00101000_00000000, // Square 20 (E3)
|
||||
0b00000000_00000010_00000100_00001000_01010000_00000000_01010000_00000000, // Square 21 (F3)
|
||||
0b00000000_00000100_00001000_00010000_00100000_00000000_00100000_00000000, // Square 22 (G3)
|
||||
0b00000000_00001000_00010000_00100000_01000000_00000000_01000000_00000000, // Square 23 (H3)
|
||||
0b00000000_00001000_00000100_00000010_00000000_00000010_00000100_00000000, // Square 24 (A4)
|
||||
0b00000000_00010000_00001000_00000100_00000000_00000100_00001000_00000000, // Square 25 (B4)
|
||||
0b00000000_00100000_00010000_00001010_00000000_00001010_00010000_00000000, // Square 26 (C4)
|
||||
0b00000000_01000000_00100010_00010100_00000000_00010100_00100010_00000000, // Square 27 (D4)
|
||||
0b00000000_00000010_01000100_00101000_00000000_00101000_01000100_00000000, // Square 28 (E4)
|
||||
0b00000000_00000100_00001000_01010000_00000000_01010000_00001000_00000000, // Square 29 (F4)
|
||||
0b00000000_00001000_00010000_00100000_00000000_00100000_00010000_00000000, // Square 30 (G4)
|
||||
0b00000000_00010000_00100000_01000000_00000000_01000000_00100000_00000000, // Square 31 (H4)
|
||||
0b00000000_00000100_00000010_00000000_00000010_00000100_00001000_00000000, // Square 32 (A5)
|
||||
0b00000000_00001000_00000100_00000000_00000100_00001000_00010000_00000000, // Square 33 (B5)
|
||||
0b00000000_00010000_00001010_00000000_00001010_00010000_00100000_00000000, // Square 34 (C5)
|
||||
0b00000000_00100010_00010100_00000000_00010100_00100010_01000000_00000000, // Square 35 (D5)
|
||||
0b00000000_01000100_00101000_00000000_00101000_01000100_00000010_00000000, // Square 36 (E5)
|
||||
0b00000000_00001000_01010000_00000000_01010000_00001000_00000100_00000000, // Square 37 (F5)
|
||||
0b00000000_00010000_00100000_00000000_00100000_00010000_00001000_00000000, // Square 38 (G5)
|
||||
0b00000000_00100000_01000000_00000000_01000000_00100000_00010000_00000000, // Square 39 (H5)
|
||||
0b00000000_00000010_00000000_00000010_00000100_00001000_00010000_00000000, // Square 40 (A6)
|
||||
0b00000000_00000100_00000000_00000100_00001000_00010000_00100000_00000000, // Square 41 (B6)
|
||||
0b00000000_00001010_00000000_00001010_00010000_00100000_01000000_00000000, // Square 42 (C6)
|
||||
0b00000000_00010100_00000000_00010100_00100010_01000000_00000000_00000000, // Square 43 (D6)
|
||||
0b00000000_00101000_00000000_00101000_01000100_00000010_00000000_00000000, // Square 44 (E6)
|
||||
0b00000000_01010000_00000000_01010000_00001000_00000100_00000010_00000000, // Square 45 (F6)
|
||||
0b00000000_00100000_00000000_00100000_00010000_00001000_00000100_00000000, // Square 46 (G6)
|
||||
0b00000000_01000000_00000000_01000000_00100000_00010000_00001000_00000000, // Square 47 (H6)
|
||||
0b00000000_00000000_00000010_00000100_00001000_00010000_00100000_00000000, // Square 48 (A7)
|
||||
0b00000000_00000000_00000100_00001000_00010000_00100000_01000000_00000000, // Square 49 (B7)
|
||||
0b00000000_00000000_00001010_00010000_00100000_01000000_00000000_00000000, // Square 50 (C7)
|
||||
0b00000000_00000000_00010100_00100010_01000000_00000000_00000000_00000000, // Square 51 (D7)
|
||||
0b00000000_00000000_00101000_01000100_00000010_00000000_00000000_00000000, // Square 52 (E7)
|
||||
0b00000000_00000000_01010000_00001000_00000100_00000010_00000000_00000000, // Square 53 (F7)
|
||||
0b00000000_00000000_00100000_00010000_00001000_00000100_00000010_00000000, // Square 54 (G7)
|
||||
0b00000000_00000000_01000000_00100000_00010000_00001000_00000100_00000000, // Square 55 (H7)
|
||||
0b00000000_00000010_00000100_00001000_00010000_00100000_01000000_00000000, // Square 56 (A8)
|
||||
0b00000000_00000100_00001000_00010000_00100000_01000000_00000000_00000000, // Square 57 (B8)
|
||||
0b00000000_00001010_00010000_00100000_01000000_00000000_00000000_00000000, // Square 58 (C8)
|
||||
0b00000000_00010100_00100010_01000000_00000000_00000000_00000000_00000000, // Square 59 (D8)
|
||||
0b00000000_00101000_01000100_00000010_00000000_00000000_00000000_00000000, // Square 60 (E8)
|
||||
0b00000000_01010000_00001000_00000100_00000010_00000000_00000000_00000000, // Square 61 (F8)
|
||||
0b00000000_00100000_00010000_00001000_00000100_00000010_00000000_00000000, // Square 62 (G8)
|
||||
0b00000000_01000000_00100000_00010000_00001000_00000100_00000010_00000000, // Square 63 (H8)
|
||||
];
|
||||
|
||||
pub const KING_ATTACKS: [u64; 64] = [
|
||||
0b00000000_00000000_00000000_00000000_00000000_00000000_00000011_00000010, // Square 0 (A1)
|
||||
0b00000000_00000000_00000000_00000000_00000000_00000000_00000111_00000101, // Square 1 (B1)
|
||||
0b00000000_00000000_00000000_00000000_00000000_00000000_00001110_00001010, // Square 2 (C1)
|
||||
0b00000000_00000000_00000000_00000000_00000000_00000000_00011100_00010100, // Square 3 (D1)
|
||||
0b00000000_00000000_00000000_00000000_00000000_00000000_00111000_00101000, // Square 4 (E1)
|
||||
0b00000000_00000000_00000000_00000000_00000000_00000000_01110000_01010000, // Square 5 (F1)
|
||||
0b00000000_00000000_00000000_00000000_00000000_00000000_11100000_10100000, // Square 6 (G1)
|
||||
0b00000000_00000000_00000000_00000000_00000000_00000000_11000000_01000000, // Square 7 (H1)
|
||||
0b00000000_00000000_00000000_00000000_00000000_00000011_00000010_00000011, // Square 8 (A2)
|
||||
0b00000000_00000000_00000000_00000000_00000000_00000111_00000101_00000111, // Square 9 (B2)
|
||||
0b00000000_00000000_00000000_00000000_00000000_00001110_00001010_00001110, // Square 10 (C2)
|
||||
0b00000000_00000000_00000000_00000000_00000000_00011100_00010100_00011100, // Square 11 (D2)
|
||||
0b00000000_00000000_00000000_00000000_00000000_00111000_00101000_00111000, // Square 12 (E2)
|
||||
0b00000000_00000000_00000000_00000000_00000000_01110000_01010000_01110000, // Square 13 (F2)
|
||||
0b00000000_00000000_00000000_00000000_00000000_11100000_10100000_11100000, // Square 14 (G2)
|
||||
0b00000000_00000000_00000000_00000000_00000000_11000000_01000000_11000000, // Square 15 (H2)
|
||||
0b00000000_00000000_00000000_00000000_00000011_00000010_00000011_00000000, // Square 16 (A3)
|
||||
0b00000000_00000000_00000000_00000000_00000111_00000101_00000111_00000000, // Square 17 (B3)
|
||||
0b00000000_00000000_00000000_00000000_00001110_00001010_00001110_00000000, // Square 18 (C3)
|
||||
0b00000000_00000000_00000000_00000000_00011100_00010100_00011100_00000000, // Square 19 (D3)
|
||||
0b00000000_00000000_00000000_00000000_00111000_00101000_00111000_00000000, // Square 20 (E3)
|
||||
0b00000000_00000000_00000000_00000000_01110000_01010000_01110000_00000000, // Square 21 (F3)
|
||||
0b00000000_00000000_00000000_00000000_11100000_10100000_11100000_00000000, // Square 22 (G3)
|
||||
0b00000000_00000000_00000000_00000000_11000000_01000000_11000000_00000000, // Square 23 (H3)
|
||||
0b00000000_00000000_00000000_00000011_00000010_00000011_00000000_00000000, // Square 24 (A4)
|
||||
0b00000000_00000000_00000000_00000111_00000101_00000111_00000000_00000000, // Square 25 (B4)
|
||||
0b00000000_00000000_00000000_00001110_00001010_00001110_00000000_00000000, // Square 26 (C4)
|
||||
0b00000000_00000000_00000000_00011100_00010100_00011100_00000000_00000000, // Square 27 (D4)
|
||||
0b00000000_00000000_00000000_00111000_00101000_00111000_00000000_00000000, // Square 28 (E4)
|
||||
0b00000000_00000000_00000000_01110000_01010000_01110000_00000000_00000000, // Square 29 (F4)
|
||||
0b00000000_00000000_00000000_11100000_10100000_11100000_00000000_00000000, // Square 30 (G4)
|
||||
0b00000000_00000000_00000000_11000000_01000000_11000000_00000000_00000000, // Square 31 (H4)
|
||||
0b00000000_00000000_00000011_00000010_00000011_00000000_00000000_00000000, // Square 32 (A5)
|
||||
0b00000000_00000000_00000111_00000101_00000111_00000000_00000000_00000000, // Square 33 (B5)
|
||||
0b00000000_00000000_00001110_00001010_00001110_00000000_00000000_00000000, // Square 34 (C5)
|
||||
0b00000000_00000000_00011100_00010100_00011100_00000000_00000000_00000000, // Square 35 (D5)
|
||||
0b00000000_00000000_00111000_00101000_00111000_00000000_00000000_00000000, // Square 36 (E5)
|
||||
0b00000000_00000000_01110000_01010000_01110000_00000000_00000000_00000000, // Square 37 (F5)
|
||||
0b00000000_00000000_11100000_10100000_11100000_00000000_00000000_00000000, // Square 38 (G5)
|
||||
0b00000000_00000000_11000000_01000000_11000000_00000000_00000000_00000000, // Square 39 (H5)
|
||||
0b00000000_00000011_00000010_00000011_00000000_00000000_00000000_00000000, // Square 40 (A6)
|
||||
0b00000000_00000111_00000101_00000111_00000000_00000000_00000000_00000000, // Square 41 (B6)
|
||||
0b00000000_00001110_00001010_00001110_00000000_00000000_00000000_00000000, // Square 42 (C6)
|
||||
0b00000000_00011100_00010100_00011100_00000000_00000000_00000000_00000000, // Square 43 (D6)
|
||||
0b00000000_00111000_00101000_00111000_00000000_00000000_00000000_00000000, // Square 44 (E6)
|
||||
0b00000000_01110000_01010000_01110000_00000000_00000000_00000000_00000000, // Square 45 (F6)
|
||||
0b00000000_11100000_10100000_11100000_00000000_00000000_00000000_00000000, // Square 46 (G6)
|
||||
0b00000000_11000000_01000000_11000000_00000000_00000000_00000000_00000000, // Square 47 (H6)
|
||||
0b00000011_00000010_00000011_00000000_00000000_00000000_00000000_00000000, // Square 48 (A7)
|
||||
0b00000111_00000101_00000111_00000000_00000000_00000000_00000000_00000000, // Square 49 (B7)
|
||||
0b00001110_00001010_00001110_00000000_00000000_00000000_00000000_00000000, // Square 50 (C7)
|
||||
0b00011100_00010100_00011100_00000000_00000000_00000000_00000000_00000000, // Square 51 (D7)
|
||||
0b00111000_00101000_00111000_00000000_00000000_00000000_00000000_00000000, // Square 52 (E7)
|
||||
0b01110000_01010000_01110000_00000000_00000000_00000000_00000000_00000000, // Square 53 (F7)
|
||||
0b11100000_10100000_11100000_00000000_00000000_00000000_00000000_00000000, // Square 54 (G7)
|
||||
0b11000000_01000000_11000000_00000000_00000000_00000000_00000000_00000000, // Square 55 (H7)
|
||||
0b00000010_00000011_00000000_00000000_00000000_00000000_00000000_00000000, // Square 56 (A8)
|
||||
0b00000101_00000111_00000000_00000000_00000000_00000000_00000000_00000000, // Square 57 (B8)
|
||||
0b00001010_00001110_00000000_00000000_00000000_00000000_00000000_00000000, // Square 58 (C8)
|
||||
0b00010100_00011100_00000000_00000000_00000000_00000000_00000000_00000000, // Square 59 (D8)
|
||||
0b00101000_00111000_00000000_00000000_00000000_00000000_00000000_00000000, // Square 60 (E8)
|
||||
0b01010000_01110000_00000000_00000000_00000000_00000000_00000000_00000000, // Square 61 (F8)
|
||||
0b10100000_11100000_00000000_00000000_00000000_00000000_00000000_00000000, // Square 62 (G8)
|
||||
0b01000000_11000000_00000000_00000000_00000000_00000000_00000000_00000000, // Square 63 (H8)
|
||||
];
|
||||
|
||||
pub const MAGICS_ROOK: [u64; 64] = [
|
||||
0b10001010_10000000_00010000_01000000_00000000_10000000_00000000_00100000, // Square 0 (A1)
|
||||
0b00000001_01000000_00000000_00100000_00000000_00010000_00000000_01000000, // Square 1 (B1)
|
||||
0b00000010_10000000_00011000_10000000_10100000_00000001_01110000_00000001, // Square 2 (C1)
|
||||
0b00000001_00000000_00001000_00010000_00000001_00000000_00000100_00100000, // Square 3 (D1)
|
||||
0b00000010_00000000_00000010_00000000_00010000_00001000_00000100_00100000, // Square 4 (E1)
|
||||
0b00000011_00000000_00011100_00000000_00000010_00000001_00000000_00001000, // Square 5 (F1)
|
||||
0b10000100_10000000_00000000_10000000_00000010_00000000_00000001_00000000, // Square 6 (G1)
|
||||
0b00100000_10000000_00001000_10000000_00000100_01000000_00101001_00000000, // Square 7 (H1)
|
||||
0b00000000_00000000_10000000_00000000_10011000_00100000_01000000_00000000, // Square 8 (A2)
|
||||
0b00100000_00100100_01000000_00010000_00000000_00100000_00000000_01000000, // Square 9 (B2)
|
||||
0b00000001_00000000_10000000_00100000_00000000_10000000_00010000_00000000, // Square 10 (C2)
|
||||
0b00000001_00100000_10000000_00001000_00000000_10000000_00010000_00000000, // Square 11 (D2)
|
||||
0b00000010_00001000_10000000_10000000_10001000_00000000_00000100_00000000, // Square 12 (E2)
|
||||
0b00000000_00000010_10000000_00100010_00000000_10000000_00000100_00000000, // Square 13 (F2)
|
||||
0b00100010_00000000_10000000_00000001_00000000_00000010_00000000_10000000, // Square 14 (G2)
|
||||
0b00001000_00000001_00000000_00000000_01100000_10000010_00010001_00000000, // Square 15 (H2)
|
||||
0b00000000_10000000_00000100_01000000_00000110_01000010_00100000_00000000, // Square 16 (A3)
|
||||
0b00000001_00000000_10000000_10000000_00100000_00000000_01000000_00000000, // Square 17 (B3)
|
||||
0b00010010_00010000_10001010_00000000_00010000_00100000_01000010_00000000, // Square 18 (C3)
|
||||
0b00000001_01000000_10000100_10000000_00010000_00000000_00001000_00000010, // Square 19 (D3)
|
||||
0b00000100_10000001_10000010_10000000_00010100_00000000_00101000_00000000, // Square 20 (E3)
|
||||
0b10000000_10010100_00000000_01000000_00000010_00000000_01000001_00000000, // Square 21 (F3)
|
||||
0b01000000_00010000_00000100_00000000_00010000_00000001_00001000_00000010, // Square 22 (G3)
|
||||
0b00000000_00000000_00000010_00000000_00001000_10000000_01100001_00000100, // Square 23 (H3)
|
||||
0b00000001_00000000_01000000_00000000_10000000_00100000_10000000_00000000, // Square 24 (A4)
|
||||
0b00100000_01000000_00000000_00100001_00100000_00001000_00010000_00000000, // Square 25 (B4)
|
||||
0b00000000_00100001_00100000_00000110_10000000_00010000_00000000_10000001, // Square 26 (C4)
|
||||
0b00000000_00100000_00010000_00000000_10000000_00001000_00000000_10000000, // Square 27 (D4)
|
||||
0b00000000_00000010_00000000_00001010_00000000_00100000_00000100_00010000, // Square 28 (E4)
|
||||
0b00000000_00000000_00000010_00000000_10000000_10000000_00000100_00000000, // Square 29 (F4)
|
||||
0b00000000_10000000_00001000_10000100_00000000_00010000_00000001_00000010, // Square 30 (G4)
|
||||
0b00000000_10000000_00000000_01000110_00000000_00000100_00101000_10000001, // Square 31 (H4)
|
||||
0b01000000_01000000_00000000_10000000_01000000_10000000_00000000_00100000, // Square 32 (A5)
|
||||
0b00000100_01000000_00000000_00110000_00000000_00100000_00001000_00000001, // Square 33 (B5)
|
||||
0b00000000_00000100_00100000_00000000_00010001_00000000_01000101_00000000, // Square 34 (C5)
|
||||
0b00000001_10001000_00000010_00000000_00010000_00010000_00000001_00000000, // Square 35 (D5)
|
||||
0b00000000_00010100_10000000_00000100_00000001_10000000_00101000_00000000, // Square 36 (E5)
|
||||
0b00100000_10000000_00000100_00000000_10000000_10000000_00000010_00000000, // Square 37 (F5)
|
||||
0b00000001_00100100_00001000_00000010_00000100_00000000_00010000_00000001, // Square 38 (G5)
|
||||
0b00000010_00000000_00000100_01100101_00000010_00000000_00000100_10000100, // Square 39 (H5)
|
||||
0b00000100_10000000_01000000_00000000_10000000_00001000_10000000_00100000, // Square 40 (A6)
|
||||
0b00010000_00000000_01000010_00100000_00010000_00000011_01000000_00000000, // Square 41 (B6)
|
||||
0b00000000_00110000_00100000_00000001_00000000_00010001_00000000_01000000, // Square 42 (C6)
|
||||
0b00000000_00000000_00010000_00000000_00100001_00000001_00000000_00001001, // Square 43 (D6)
|
||||
0b00100000_00000010_00001000_00000001_00000000_00010001_00000000_00000100, // Square 44 (E6)
|
||||
0b00000010_00000010_00000000_10000000_00000100_00000000_10000000_00000010, // Square 45 (F6)
|
||||
0b00000000_00100000_00000010_00000000_00000100_00000001_00000001_00000000, // Square 46 (G6)
|
||||
0b00100000_01001000_01000100_00000000_01000000_10000010_00000000_00000001, // Square 47 (H6)
|
||||
0b00000001_00000001_00000000_00100010_00000000_01000000_10000010_00000000, // Square 48 (A7)
|
||||
0b00000000_01000000_10000000_00100000_00000000_01000000_00010000_10000000, // Square 49 (B7)
|
||||
0b01000000_00001000_00010100_00100000_00000100_01000001_00000001_00000000, // Square 50 (C7)
|
||||
0b00000010_00000110_00001000_00100000_11000000_00010010_00000010_00000000, // Square 51 (D7)
|
||||
0b00000000_00000001_00000000_00010000_00000100_00001000_00000001_00000000, // Square 52 (E7)
|
||||
0b00000010_00001100_00000010_00000000_10000000_00000100_00000000_10000000, // Square 53 (F7)
|
||||
0b00101001_00110101_01100001_00001000_00110000_00000010_00100100_00000000, // Square 54 (G7)
|
||||
0b00000000_01000100_01000100_00000000_01000001_00000000_10010010_00000000, // Square 55 (H7)
|
||||
0b00000010_10000000_00000000_00010000_01000000_10000000_00100001_00000001, // Square 56 (A8)
|
||||
0b00100001_00000000_00011001_00000000_01000000_00000000_00100000_10000101, // Square 57 (B8)
|
||||
0b10000000_11000000_00001000_01000001_00000000_00010000_00100000_00000001, // Square 58 (C8)
|
||||
0b01000000_00100100_00001000_00010000_00000001_00000000_00000100_00100001, // Square 59 (D8)
|
||||
0b00000000_00000010_00000000_00110000_10100000_00100100_01001000_01110010, // Square 60 (E8)
|
||||
0b00000000_00010010_00000000_00010000_00001000_01000001_01000100_00000010, // Square 61 (F8)
|
||||
0b00000010_00000000_01100001_00000100_10010000_00001010_00001000_00000100, // Square 62 (G8)
|
||||
0b00000000_00000001_00000000_01000000_10000001_00000000_00100100_00000010, // Square 63 (H8)
|
||||
];
|
||||
|
||||
pub const MAGICS_BISHOP: [u64; 64] = [
|
||||
0b00000000_01000000_00000100_00001000_01000100_01000000_01000000_10000100, // Square 0 (A1)
|
||||
0b00000000_00100000_00000100_00100000_10001010_00000000_01000010_00001000, // Square 1 (B1)
|
||||
0b00000000_00010000_00011001_00000000_01000001_00001000_00000010_00000010, // Square 2 (C1)
|
||||
0b00000001_00001000_00000110_00001000_01000101_00000100_00100000_00010000, // Square 3 (D1)
|
||||
0b00000101_10000001_00010000_01000001_10000000_10000000_00000010_00010000, // Square 4 (E1)
|
||||
0b00100001_00010010_00001000_00000100_01000110_00100000_00000000_00010000, // Square 5 (F1)
|
||||
0b00010000_10000000_10000010_00001000_00100000_00000110_00000010_00010000, // Square 6 (G1)
|
||||
0b00000011_11000000_10000000_10000100_00010000_00100010_00000010_00000000, // Square 7 (H1)
|
||||
0b00000000_00000100_00000101_00000100_00000100_01000100_00000100_00000100, // Square 8 (A2)
|
||||
0b00000000_00000000_00000010_00010000_00000001_01000010_00000000_10001000, // Square 9 (B2)
|
||||
0b00100100_11010000_00001000_00001000_00000001_00001000_00100001_00000010, // Square 10 (C2)
|
||||
0b00000000_00000001_00000010_00001010_00001010_00000010_00000100_00000000, // Square 11 (D2)
|
||||
0b00000000_00000000_00000100_00000011_00001000_00100000_00000100_00000010, // Square 12 (E2)
|
||||
0b00000000_00000100_00000001_00010000_00000010_00010000_00001000_00000000, // Square 13 (F2)
|
||||
0b00000100_00000001_01001000_01000001_00000100_00010000_01000000_00000101, // Square 14 (G2)
|
||||
0b00001000_00000001_00000001_00000100_00000010_00000010_00000010_00000000, // Square 15 (H2)
|
||||
0b00000000_01000000_00000010_00010000_11000011_10001000_00000001_00000000, // Square 16 (A3)
|
||||
0b00000100_00000100_00000010_00100000_00100100_00010000_10000010_00000000, // Square 17 (B3)
|
||||
0b00001000_00010000_00000001_10000010_00000000_00100000_01000001_00000010, // Square 18 (C3)
|
||||
0b00000000_00000100_00000000_00101000_00000001_10100000_00100000_00000011, // Square 19 (D3)
|
||||
0b00000000_10000101_00000100_00001000_00100000_00001000_00000100_00000000, // Square 20 (E3)
|
||||
0b10000001_00000001_00000010_11001000_00001000_10001000_00000100_00000000, // Square 21 (F3)
|
||||
0b00000000_00001110_10010000_00000100_00010000_10001000_01001000_00000000, // Square 22 (G3)
|
||||
0b10000000_00000010_00000010_00000100_10000000_10000100_00000001_00000010, // Square 23 (H3)
|
||||
0b00000010_00100000_00100000_00001000_01100101_00001001_00000010_00000001, // Square 24 (A4)
|
||||
0b00100000_00010000_00010000_00001010_00000010_00000010_00010010_00000010, // Square 25 (B4)
|
||||
0b00000001_01010010_00000100_10000100_00001000_00000010_00100100_00000001, // Square 26 (C4)
|
||||
0b00000000_00100000_00001000_00000000_00000010_00001000_00010001_00010000, // Square 27 (D4)
|
||||
0b01000000_00000001_00000000_00010000_00100001_00000000_01000000_00000000, // Square 28 (E4)
|
||||
0b10000000_00000000_01000000_01000000_00001010_00000001_00010000_00000010, // Square 29 (F4)
|
||||
0b00000000_11100100_00000000_01000000_10000001_00000001_00010000_00000010, // Square 30 (G4)
|
||||
0b00000000_00011100_00000000_01000000_00000001_00000001_00100000_10000000, // Square 31 (H4)
|
||||
0b10000000_00000100_00100000_00001001_01100010_10100000_00000010_00100000, // Square 32 (A5)
|
||||
0b10000100_00100010_00010000_00000010_00001000_01010000_00000010_00000010, // Square 33 (B5)
|
||||
0b00100000_00000000_01000000_00100010_00000000_00110000_00001100_00001000, // Square 34 (C5)
|
||||
0b10000110_01000110_00000010_00000000_10000000_00001000_00000000_10000000, // Square 35 (D5)
|
||||
0b10000000_00000010_00001010_00000010_00000000_00010000_00001000_00001000, // Square 36 (E5)
|
||||
0b00100000_00010000_00000000_01001000_10000000_00010001_00010000_00000000, // Square 37 (F5)
|
||||
0b01100010_00110000_00000000_10100000_10000000_00000001_00010100_00000000, // Square 38 (G5)
|
||||
0b01000010_00000000_10001100_00000011_01000000_00100000_10010010_00000010, // Square 39 (H5)
|
||||
0b00000010_00001001_00011000_10000010_01000000_00000000_00010000_00000000, // Square 40 (A6)
|
||||
0b01000000_00000100_00001000_10101000_10000100_00000000_00011000_00000000, // Square 41 (B6)
|
||||
0b00000000_00010001_00000100_00000000_10100110_00001000_00000100_00000000, // Square 42 (C6)
|
||||
0b00011000_01000000_00000110_00001010_01000100_00000010_00001000_00000000, // Square 43 (D6)
|
||||
0b00000000_10010000_00001000_00000001_00000100_00000000_00000000_01000001, // Square 44 (E6)
|
||||
0b00000010_00000001_00000001_00010000_00000000_10000000_10000001_00000001, // Square 45 (F6)
|
||||
0b00011010_00100010_00001000_00001000_00000101_00000100_11110000_10000000, // Square 46 (G6)
|
||||
0b10000000_00010010_00000010_00000110_00000000_00100001_00010010_00010010, // Square 47 (H6)
|
||||
0b00000101_00000000_10000110_00010000_00010001_00100100_00000000_00000000, // Square 48 (A7)
|
||||
0b00000001_10000000_10000000_01100001_00001000_00100000_00001000_00000000, // Square 49 (B7)
|
||||
0b01000000_00000000_00000010_00001110_00000001_00000100_00000000_01000100, // Square 50 (C7)
|
||||
0b00110000_00000000_00000000_00100110_00010000_01000100_00000000_00001010, // Square 51 (D7)
|
||||
0b00001000_00000010_00100100_00010001_00000010_00000010_00000000_00000010, // Square 52 (E7)
|
||||
0b00000000_00100000_10010000_01100000_01100001_00100001_00000000_00000001, // Square 53 (F7)
|
||||
0b01011010_10000100_10000100_00010000_00000100_00000001_00000011_00010000, // Square 54 (G7)
|
||||
0b00000000_00000100_00000001_00001000_00000001_00000001_00011100_00000100, // Square 55 (H7)
|
||||
0b00000000_00001010_00000001_00000001_00001001_01010000_00100010_00000000, // Square 56 (A8)
|
||||
0b00000000_00000000_00000000_01001010_00000010_00000001_00100000_00000000, // Square 57 (B8)
|
||||
0b01010000_00000010_00000001_00000001_00000000_10011000_10110000_00101000, // Square 58 (C8)
|
||||
0b10000000_01000000_00000000_00101000_00010001_00000100_00001001_00000000, // Square 59 (D8)
|
||||
0b00000000_00101000_00000000_00000000_00010000_00000010_00000010_00000100, // Square 60 (E8)
|
||||
0b00000110_00000000_00000000_00100000_00100000_00101101_00000010_01000000, // Square 61 (F8)
|
||||
0b10001001_00011000_10000100_01001000_01000010_00001000_00100010_00000000, // Square 62 (G8)
|
||||
0b01000000_00010000_00000001_00010000_00101001_00000010_00000000_00100000, // Square 63 (H8)
|
||||
];
|
||||
|
||||
pub const RELEVANT_BITS_ROOK: [u8; 64] = [
|
||||
12, 11, 11, 11, 11, 11, 11, 12,
|
||||
11, 10, 10, 10, 10, 10, 10, 11,
|
||||
11, 10, 10, 10, 10, 10, 10, 11,
|
||||
11, 10, 10, 10, 10, 10, 10, 11,
|
||||
11, 10, 10, 10, 10, 10, 10, 11,
|
||||
11, 10, 10, 10, 10, 10, 10, 11,
|
||||
11, 10, 10, 10, 10, 10, 10, 11,
|
||||
12, 11, 11, 11, 11, 11, 11, 12,
|
||||
];
|
||||
pub const RELEVANT_BITS_BISHOP: [u8; 64] = [
|
||||
6, 5, 5, 5, 5, 5, 5, 6,
|
||||
5, 5, 5, 5, 5, 5, 5, 5,
|
||||
5, 5, 7, 7, 7, 7, 5, 5,
|
||||
5, 5, 7, 9, 9, 7, 5, 5,
|
||||
5, 5, 7, 9, 9, 7, 5, 5,
|
||||
5, 5, 7, 7, 7, 7, 5, 5,
|
||||
5, 5, 5, 5, 5, 5, 5, 5,
|
||||
6, 5, 5, 5, 5, 5, 5, 6,
|
||||
];
|
||||
|
||||
|
||||
static ROOK_ATTACKS: OnceLock<Box<[[u64; 4096]; 64]>> = OnceLock::new();
|
||||
static BISHOP_ATTACKS: OnceLock<Box<[[u64; 512]; 64]>> = OnceLock::new();
|
||||
|
||||
|
||||
// HILFSFUNKTION: Berechnet Turmzüge "langsam"
|
||||
// Diese Funktion wird nur beim "Backen" der Tabellen verwendet.
|
||||
fn calculate_rook_attacks_slowly(square: usize, blockers: u64) -> u64 {
|
||||
let mut attacks = 0_u64;
|
||||
let rank = square / 8;
|
||||
let file = square % 8;
|
||||
|
||||
// 1. Nach Norden (rank +)
|
||||
for r in (rank + 1)..=7 {
|
||||
let target_sq = r * 8 + file;
|
||||
attacks |= 1_u64 << target_sq;
|
||||
if (blockers >> target_sq) & 1 == 1 {
|
||||
break; // Wir treffen einen Blocker, stopp
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Nach Süden (rank -)
|
||||
for r in (0..rank).rev() {
|
||||
let target_sq = r * 8 + file;
|
||||
attacks |= 1_u64 << target_sq;
|
||||
if (blockers >> target_sq) & 1 == 1 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Nach Osten (file +)
|
||||
for f in (file + 1)..=7 {
|
||||
let target_sq = rank * 8 + f;
|
||||
attacks |= 1_u64 << target_sq;
|
||||
if (blockers >> target_sq) & 1 == 1 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Nach Westen (file -)
|
||||
for f in (0..file).rev() {
|
||||
let target_sq = rank * 8 + f;
|
||||
attacks |= 1_u64 << target_sq;
|
||||
if (blockers >> target_sq) & 1 == 1 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
attacks
|
||||
}
|
||||
|
||||
fn generate_final_rook_attacks() -> Box<[[u64; 4096]; 64]> {
|
||||
// Heap-Allokation (Dein Code war hier korrekt)
|
||||
let mut v: Vec<[u64; 4096]> = Vec::with_capacity(64);
|
||||
for _ in 0..64 {
|
||||
v.push([0_u64; 4096]);
|
||||
}
|
||||
let mut final_rook_attacks: Box<[[u64; 4096]; 64]> = v.try_into().unwrap_or_else(|_| {
|
||||
panic!("Vec to Box conversion failed.");
|
||||
});
|
||||
|
||||
// Haupt-Back-Schleife
|
||||
for square_index in 0_usize..=63_usize {
|
||||
let premask = PREMASKS_ROOK[square_index]; // [deine Quelle]
|
||||
let magic = MAGICS_ROOK[square_index]; // [deine Quelle]
|
||||
// ACHTUNG: Hier war ein Fehler in deinem Code, du hattest BISHOP statt ROOK
|
||||
let relevant_bits = RELEVANT_BITS_ROOK[square_index]; // [deine Quelle]
|
||||
let shift = 64 - relevant_bits;
|
||||
|
||||
// Schleife durch alle 2^n Blocker-Kombinationen
|
||||
let mut blocker_combination = 0_u64;
|
||||
loop {
|
||||
// ---- HIER IST DIE KORREKTE LOGIK ----
|
||||
|
||||
// 1. Berechne die "echten" Züge für diese Blocker-Kombination (der langsame Weg)
|
||||
let attack_squares = calculate_rook_attacks_slowly(square_index, blocker_combination);
|
||||
|
||||
// 2. Berechne den "magischen" Speicherort
|
||||
let magic_index = (blocker_combination.wrapping_mul(magic)) >> shift;
|
||||
let magic_index_as_usize = magic_index as usize;
|
||||
|
||||
// 3. Speichere die echten Züge an diesem magischen Ort
|
||||
final_rook_attacks[square_index][magic_index_as_usize] = attack_squares;
|
||||
|
||||
// ---- ENDE DER LOGIK ----
|
||||
|
||||
// Gehe zur nächsten Blocker-Kombination (Dein Code war hier korrekt)
|
||||
if blocker_combination == premask {
|
||||
break;
|
||||
}
|
||||
blocker_combination = blocker_combination.wrapping_sub(premask) & premask;
|
||||
}
|
||||
}
|
||||
|
||||
final_rook_attacks
|
||||
}
|
||||
|
||||
pub fn get_rook_attacks() -> &'static Box<[[u64; 4096]; 64]> {
|
||||
// get_or_init stellt sicher, dass generate_final_rook_attacks()
|
||||
// nur beim allerersten Aufruf ausgeführt wird.
|
||||
// Alle anderen Aufrufe geben sofort die fertige Tabelle zurück.
|
||||
ROOK_ATTACKS.get_or_init(generate_final_rook_attacks)
|
||||
}
|
||||
|
||||
// HILFSFUNKTION: Berechnet Läuferzüge "langsam"
|
||||
// Diese Funktion wird nur beim "Backen" der Tabellen verwendet.
|
||||
fn calculate_bishop_attacks_slowly(square: usize, blockers: u64) -> u64 {
|
||||
let mut attacks = 0_u64;
|
||||
let rank = square / 8;
|
||||
let file = square % 8;
|
||||
|
||||
// Temporäre Rank/File-Iteratoren
|
||||
let (mut r, mut f);
|
||||
|
||||
// 1. Nach Nord-Osten (rank+, file+)
|
||||
r = rank + 1;
|
||||
f = file + 1;
|
||||
while r <= 7 && f <= 7 {
|
||||
let target_sq = r * 8 + f;
|
||||
attacks |= 1_u64 << target_sq;
|
||||
if (blockers >> target_sq) & 1 == 1 {
|
||||
break; // Wir treffen einen Blocker, stopp
|
||||
}
|
||||
r += 1;
|
||||
f += 1;
|
||||
}
|
||||
|
||||
// 2. Nach Süd-Osten (rank-, file+)
|
||||
r = rank; // Start bei rank, da 0..rank fehlschlägt wenn rank = 0
|
||||
f = file + 1;
|
||||
while r > 0 && f <= 7 { // r > 0 (da r = rank-1 in der 1. Iteration)
|
||||
r -= 1;
|
||||
let target_sq = r * 8 + f;
|
||||
attacks |= 1_u64 << target_sq;
|
||||
if (blockers >> target_sq) & 1 == 1 {
|
||||
break;
|
||||
}
|
||||
f += 1;
|
||||
}
|
||||
|
||||
// 3. Nach Süd-Westen (rank-, file-)
|
||||
r = rank;
|
||||
f = file;
|
||||
while r > 0 && f > 0 { // r > 0 und f > 0
|
||||
r -= 1;
|
||||
f -= 1;
|
||||
let target_sq = r * 8 + f;
|
||||
attacks |= 1_u64 << target_sq;
|
||||
if (blockers >> target_sq) & 1 == 1 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Nach Nord-Westen (rank+, file-)
|
||||
r = rank + 1;
|
||||
f = file;
|
||||
while r <= 7 && f > 0 { // f > 0
|
||||
f -= 1;
|
||||
let target_sq = r * 8 + f;
|
||||
attacks |= 1_u64 << target_sq;
|
||||
if (blockers >> target_sq) & 1 == 1 {
|
||||
break;
|
||||
}
|
||||
r += 1;
|
||||
}
|
||||
|
||||
attacks
|
||||
}
|
||||
|
||||
fn generate_final_bishop_attacks() -> Box<[[u64; 512]; 64]> {
|
||||
// Heap-Allokation
|
||||
// (Array ist kleiner: 512 statt 4096. Stack Overflow wäre hier unwahrscheinlich,
|
||||
// aber wir bleiben konsistent mit der Turm-Logik.)
|
||||
let mut v: Vec<[u64; 512]> = Vec::with_capacity(64);
|
||||
for _ in 0..64 {
|
||||
v.push([0_u64; 512]);
|
||||
}
|
||||
let mut final_bishop_attacks: Box<[[u64; 512]; 64]> = v.try_into().unwrap_or_else(|_| {
|
||||
panic!("Vec to Box conversion failed for bishops.");
|
||||
});
|
||||
|
||||
// Haupt-Back-Schleife
|
||||
for square_index in 0_usize..=63_usize {
|
||||
// Verwende die BISHOP-Konstanten aus deiner tables.rs
|
||||
let premask = PREMASKS_BISHOP[square_index];
|
||||
let magic = MAGICS_BISHOP[square_index];
|
||||
let relevant_bits = RELEVANT_BITS_BISHOP[square_index];
|
||||
let shift = 64 - relevant_bits;
|
||||
|
||||
// Schleife durch alle 2^n Blocker-Kombinationen
|
||||
let mut blocker_combination = 0_u64;
|
||||
loop {
|
||||
// 1. Berechne die "echten" Züge für diese Blocker-Kombination (der langsame Weg)
|
||||
let attack_squares = calculate_bishop_attacks_slowly(square_index, blocker_combination);
|
||||
|
||||
// 2. Berechne den "magischen" Speicherort
|
||||
let magic_index = (blocker_combination.wrapping_mul(magic)) >> shift;
|
||||
let magic_index_as_usize = magic_index as usize;
|
||||
|
||||
// 3. Speichere die echten Züge an diesem magischen Ort
|
||||
// (Stelle sicher, dass magic_index_as_usize < 512 ist,
|
||||
// was durch korrekte Magics garantiert wird)
|
||||
final_bishop_attacks[square_index][magic_index_as_usize] = attack_squares;
|
||||
|
||||
// Gehe zur nächsten Blocker-Kombination
|
||||
if blocker_combination == premask {
|
||||
break;
|
||||
}
|
||||
blocker_combination = blocker_combination.wrapping_sub(premask) & premask;
|
||||
}
|
||||
}
|
||||
|
||||
final_bishop_attacks
|
||||
}
|
||||
|
||||
pub fn get_bishop_attacks() -> &'static Box<[[u64; 512]; 64]> {
|
||||
// get_or_init stellt sicher, dass generate_final_bishop_attacks()
|
||||
// nur beim allerersten Aufruf ausgeführt wird.
|
||||
// Alle anderen Aufrufe geben sofort die fertige Tabelle zurück.
|
||||
BISHOP_ATTACKS.get_or_init(generate_final_bishop_attacks)
|
||||
}
|
||||
141
src/square.rs
Normal file
141
src/square.rs
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
use std::ops::{Sub, Add};
|
||||
use std::cmp::Ordering;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[repr(u8)]
|
||||
pub enum Square {
|
||||
A1 = 0,
|
||||
B1 = 1,
|
||||
C1 = 2,
|
||||
D1 = 3,
|
||||
E1 = 4,
|
||||
F1 = 5,
|
||||
G1 = 6,
|
||||
H1 = 7,
|
||||
A2 = 8,
|
||||
B2 = 9,
|
||||
C2 = 10,
|
||||
D2 = 11,
|
||||
E2 = 12,
|
||||
F2 = 13,
|
||||
G2 = 14,
|
||||
H2 = 15,
|
||||
A3 = 16,
|
||||
B3 = 17,
|
||||
C3 = 18,
|
||||
D3 = 19,
|
||||
E3 = 20,
|
||||
F3 = 21,
|
||||
G3 = 22,
|
||||
H3 = 23,
|
||||
A4 = 24,
|
||||
B4 = 25,
|
||||
C4 = 26,
|
||||
D4 = 27,
|
||||
E4 = 28,
|
||||
F4 = 29,
|
||||
G4 = 30,
|
||||
H4 = 31,
|
||||
A5 = 32,
|
||||
B5 = 33,
|
||||
C5 = 34,
|
||||
D5 = 35,
|
||||
E5 = 36,
|
||||
F5 = 37,
|
||||
G5 = 38,
|
||||
H5 = 39,
|
||||
A6 = 40,
|
||||
B6 = 41,
|
||||
C6 = 42,
|
||||
D6 = 43,
|
||||
E6 = 44,
|
||||
F6 = 45,
|
||||
G6 = 46,
|
||||
H6 = 47,
|
||||
A7 = 48,
|
||||
B7 = 49,
|
||||
C7 = 50,
|
||||
D7 = 51,
|
||||
E7 = 52,
|
||||
F7 = 53,
|
||||
G7 = 54,
|
||||
H7 = 55,
|
||||
A8 = 56,
|
||||
B8 = 57,
|
||||
C8 = 58,
|
||||
D8 = 59,
|
||||
E8 = 60,
|
||||
F8 = 61,
|
||||
G8 = 62,
|
||||
H8 = 63,
|
||||
}
|
||||
|
||||
pub const SQUARES: [Square; 64] = [
|
||||
Square::A1, Square::B1, Square::C1, Square::D1, Square::E1, Square::F1, Square::G1, Square::H1,
|
||||
Square::A2, Square::B2, Square::C2, Square::D2, Square::E2, Square::F2, Square::G2, Square::H2,
|
||||
Square::A3, Square::B3, Square::C3, Square::D3, Square::E3, Square::F3, Square::G3, Square::H3,
|
||||
Square::A4, Square::B4, Square::C4, Square::D4, Square::E4, Square::F4, Square::G4, Square::H4,
|
||||
Square::A5, Square::B5, Square::C5, Square::D5, Square::E5, Square::F5, Square::G5, Square::H5,
|
||||
Square::A6, Square::B6, Square::C6, Square::D6, Square::E6, Square::F6, Square::G6, Square::H6,
|
||||
Square::A7, Square::B7, Square::C7, Square::D7, Square::E7, Square::F7, Square::G7, Square::H7,
|
||||
Square::A8, Square::B8, Square::C8, Square::D8, Square::E8, Square::F8, Square::G8, Square::H8,
|
||||
];
|
||||
|
||||
impl TryFrom<u8> for Square {
|
||||
type Error = &'static str;
|
||||
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
||||
if value <= 63 {
|
||||
Ok(unsafe { std::mem::transmute(value) })
|
||||
} else {
|
||||
Err("Square index out of bounds")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<u8> for Square {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: u8) -> Self::Output {
|
||||
let new_val = (self as u8) + rhs;
|
||||
new_val.try_into().expect("Square addition resulted in an invalid square")
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub<u8> for Square {
|
||||
type Output = Self;
|
||||
|
||||
fn sub(self, rhs: u8) -> Self::Output {
|
||||
let new_val = (self as u8).checked_sub(rhs)
|
||||
.expect("Square subtraction resulted in an underflow");
|
||||
|
||||
new_val.try_into().expect("Square subtraction resulted in an invalid square")
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Square {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
|
||||
fn lt(&self, other: &Self) -> bool {
|
||||
(*self as u8) < (*other as u8)
|
||||
}
|
||||
|
||||
fn le(&self, other: &Self) -> bool {
|
||||
(*self as u8) <= (*other as u8)
|
||||
}
|
||||
|
||||
fn gt(&self, other: &Self) -> bool {
|
||||
(*self as u8) > (*other as u8)
|
||||
}
|
||||
|
||||
fn ge(&self, other: &Self) -> bool {
|
||||
(*self as u8) >= (*other as u8)
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Square {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
(*self as u8).cmp(&(*other as u8))
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue