Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 75 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
name = "Mouse"
version = "0.1.0"
edition = "2024"
build = "build/build.rs"

[lib]
name = "mouse"
Expand All @@ -14,7 +15,7 @@ codegen-units = 1
lto = true

[dev-dependencies]
criterion = "0.7.0"
criterion = "0.8.2"
iai = { git = "https://github.com/sigaloid/iai", rev = "d56a597" }
perft_fixtures = { path = "perft_fixtures" }

Expand Down
99 changes: 99 additions & 0 deletions build/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
use std::fs;

mod gen_caches_non_sliders;
mod gen_caches_sliders;
mod gen_util;

const DIR_PATH: &str = "src/backend/";

fn main() {
println!("cargo:rerun-if-changed=build/build.rs");
println!("cargo:rerun-if-changed=build/gen_caches_non_sliders.rs");
println!("cargo:rerun-if-changed=build/gen_caches_sliders.rs");
println!("cargo:rerun-if-changed=build/gen_util.rs");
println!("cargo:rerun-if-changed=src/backend/caches.rs");

let mut king_moves = [0u64; 64];
for (square, king_moves_for_square) in king_moves.iter_mut().enumerate() {
*king_moves_for_square = gen_caches_non_sliders::gen_king_moves(square as i8);
}

let mut knight_moves = [0u64; 64];
for (square , knight_moves_for_square) in knight_moves.iter_mut().enumerate() {
*knight_moves_for_square = gen_caches_non_sliders::gen_knight_moves(square as i8);
}

let capture_pawn_moves = gen_caches_non_sliders::gen_pawn_captures();

let pext_data = gen_caches_sliders::gen_cache_sliders();
let rook_pext_mask = pext_data.rook_pext_mask;
let rook_pext_index = pext_data.rook_pext_index;
let bishop_pext_mask = pext_data.bishop_pext_mask;
let bishop_pext_index = pext_data.bishop_pext_index;
let pext_table = pext_data.pext_table;

let cache_strings = [
format!(
"pub const KING_MOVES: [BitBoard; SQUARES_AMOUNT] = unsafe{{std::mem::transmute({})}};",
array_to_string(&king_moves)
),
format!(
"pub const KNIGHT_MOVES: [BitBoard; SQUARES_AMOUNT] = unsafe{{std::mem::transmute({})}};",
array_to_string(&knight_moves)
),
format!(
"pub const PAWN_CAPTURE_MOVES: [[BitBoard; SQUARES_AMOUNT]; SIDES] = unsafe{{std::mem::transmute([{}, {}])}};",
array_to_string(&capture_pawn_moves[0]),
array_to_string(&capture_pawn_moves[1])
),
format!(
"pub const ROOK_PEXT_MASK: [BitBoard; SQUARES_AMOUNT] = unsafe{{std::mem::transmute({})}};",
array_to_string(&rook_pext_mask)
),
format!(
"pub const ROOK_PEXT_INDEX: [usize; SQUARES_AMOUNT] = {:?};",
rook_pext_index
),
format!(
"pub const BISHOP_PEXT_MASK: [BitBoard; SQUARES_AMOUNT] = unsafe{{std::mem::transmute({})}};",
array_to_string(&bishop_pext_mask)
),
format!(
"pub const BISHOP_PEXT_INDEX: [usize; SQUARES_AMOUNT] = {:?};",
bishop_pext_index
),
format!(
"pub static PEXT_TABLE: [BitBoard; {}] = unsafe{{std::mem::transmute({})}};",
gen_caches_sliders::PEXT_TABLE_SIZE,
array_to_string(&pext_table)
),
];

let mut file_content = String::from(
"// DO NOT EDIT THIS FILE.
// IT WAS AUTOGENERATED BY THE BUILD SCRIPT!

use crate::backend::state::board::bitboard::BitBoard;
use crate::backend::constants::SQUARES_AMOUNT;
use crate::backend::constants::SIDES;
",
);
for string in cache_strings {
file_content.push_str("#[rustfmt::skip]\n");
file_content.push_str(&string);
file_content.push_str("\n\n");
}

let full_path = format!("{}caches.rs", DIR_PATH);
fs::write(&full_path, file_content).unwrap();
}

fn array_to_string<const N: usize>(array: &[u64; N]) -> String {
let mut string = String::new();
string.push('[');
for bb in array {
string.push_str(&format!("{}u64,", bb));
}
string.push(']');
string
}
111 changes: 111 additions & 0 deletions build/gen_caches_non_sliders.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
use crate::gen_util::{
is_square_at_bottom_edge, is_square_at_left_edge, is_square_at_right_edge,
is_square_at_top_edge, is_square_valid, square_from_rank_and_file, square_to_bb,
square_to_file, square_to_rank,
};

/// Generates a `BitBoard` with all possible moves for a king piece from a given `Square`.
pub fn gen_king_moves(square: i8) -> u64 {
let mut bitboard = 0;

let rank = square_to_rank(square);
let file = square_to_file(square);

for file_offset in -1..=1 {
for rank_offset in -1..=1 {
// skip the current square
if file_offset == 0 && rank_offset == 0 {
continue;
}
// create the relevant square
let current_rank = rank + rank_offset;
let current_file = file + file_offset;

// and add it if it's valid
if is_square_valid(current_rank, current_file) {
let current_square = current_rank * 8 + current_file;
let bb = square_to_bb(current_square);
bitboard |= bb;
}
}
}
bitboard
}

/// Same as above but for the knight.
pub fn gen_knight_moves(square: i8) -> u64 {
let mut bitboard = 0;

let rank = square_to_rank(square);
let file = square_to_file(square);

// The offsets for the knight moves. Starting in the top left corner.
// `_ _ _ _ _ _ _ _`
// `_ _ 2 _ 3 _ _ _`
// `_ 1 _ _ _ 4 _ _`
// `_ _ _ K _ _ _ _`
// `_ 8 _ _ _ 5 _ _`
// `_ _ 7 _ 6 _ _ _`
// `_ _ _ _ _ _ _ _`
// `_ _ _ _ _ _ _ _`
let file_offset = [-2, -1, 1, 2, 2, 1, -1, -2];
let rank_offset = [1, 2, 2, 1, -1, -2, -2, -1];

for index in 0..8 {
// Calculate the current square.
let current_file = file + file_offset[index];
let current_rank = rank + rank_offset[index];

// If it is valid, add it to the bitboard.
if is_square_valid(current_rank, current_file) {
let current_square = square_from_rank_and_file(current_rank, current_file);
let bb = square_to_bb(current_square);
bitboard |= bb;
}
}

bitboard
}

pub fn gen_pawn_captures() -> [[u64; 64]; 2] {
let mut quiet_moves = [[0; 64]; 2];

for (side, quiet_moves_per_side) in quiet_moves.iter_mut().enumerate() {
// iterate over all squares
for square in 0..64 {
// and generate the moves for that square
quiet_moves_per_side[square as usize] = gen_pawn_captures_at_square(square, side == 0);
}
}

quiet_moves
}

fn gen_pawn_captures_at_square(square: i8, is_white: bool) -> u64 {
let mut bitboard: u64 = 0;
let mut current_square = square;

match is_white {
true => {
if is_square_at_top_edge(current_square) {
return bitboard;
}
current_square += 8;
}
false => {
if is_square_at_bottom_edge(current_square) {
return bitboard;
}
current_square -= 8;
}
}

if !is_square_at_right_edge(current_square) {
bitboard |= square_to_bb(current_square + 1);
}
if !is_square_at_left_edge(current_square) {
bitboard |= square_to_bb(current_square - 1);
}

bitboard
}
Loading
Loading