Reinitialize repository and add working move generation for all pieces

This commit is contained in:
Moritz Eigenauer 2025-11-12 17:01:12 +01:00
commit 951a8bbec6
28 changed files with 3373 additions and 0 deletions

328
src/board.rs Normal file
View 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
View file

@ -0,0 +1,4 @@
pub mod board;
pub mod r#move;
pub mod square;
pub mod movegen;

13
src/main.rs Normal file
View 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
View 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
View 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);
}

View 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
View 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
View 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
View 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
View 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))
}
}