use crate::prelude::*;
use crate::bitboard::magic::Magic;
macro_rules! cached {
( $name:literal ) => {{
cached!($name, "", "")
}};
( $name:literal, $tag:literal ) => {{
cached!($name, "-", $tag)
}};
( $name:literal, $sep:literal, $tag:literal ) => {{
#[allow(unsafe_code)]
unsafe { std::mem::transmute(*include_bytes!(cached_filename!($name, $sep, $tag))) }
}};
}
#[cfg(all(target_pointer_width = "64", target_endian = "little"))]
macro_rules! cached_filename {
( $name:literal, $sep:literal, $tag:literal ) => {
concat!("../../share/cached/", $name, ".le64", $sep, $tag, ".bin")
};
}
#[cfg(all(target_pointer_width = "64", target_endian = "big"))]
macro_rules! cached_filename {
( $name:literal, $sep:literal, $tag:literal ) => {
concat!("../../share/cached/", $name, ".be64", $sep, $tag, ".bin")
}
}
#[cfg(all(target_pointer_width = "32", target_endian = "little"))]
macro_rules! cached_filename {
( $name:literal, $sep:literal, $tag:literal ) => {
concat!("../../share/cached/", $name, ".le32", $sep, $tag, ".bin")
}
}
#[cfg(all(target_pointer_width = "32", target_endian = "big"))]
macro_rules! cached_filename {
( $name:literal, $sep:literal, $tag:literal ) => {
concat!("../../share/cached/", $name, ".be32", $sep, $tag, ".bin")
}
}
const SQUARE_DISTANCE: [[u8; Square::COUNT]; Square::COUNT] = cached!("square_distance");
const LINE: [[Bitboard; Square::COUNT]; Square::COUNT] = cached!("line");
const BETWEEN: [[Bitboard; Square::COUNT]; Square::COUNT] = cached!("between");
const PSEUDO_ATTACKS: [[Bitboard; Square::COUNT]; Token::COUNT] = cached!("pseudo_attacks");
const PAWN_ATTACKS: [[Bitboard; Square::COUNT]; Color::COUNT] = cached!("pawn_attacks");
const BISHOP_MAGICS: Magic<0x1480> = Magic {
magics: cached!("bishop_magic_numbers", "pext_off"),
attacks: cached!("bishop_magic_attacks", "pext_off"),
};
const ROOK_MAGICS: Magic<0x19000> = Magic {
magics: cached!("rook_magic_numbers", "pext_off"),
attacks: cached!("rook_magic_attacks", "pext_off"),
};
#[inline]
#[must_use]
pub const fn square_distance(s1: Square, s2: Square) -> u8 {
SQUARE_DISTANCE[s1][s2]
}
#[inline]
pub const fn line(s1: Square, s2: Square) -> Bitboard {
LINE[s1][s2]
}
pub const fn between(s1: Square, s2: Square) -> Bitboard {
BETWEEN[s1][s2]
}
#[inline]
pub const fn attacks(color: Color, token: Token, square: Square, occupied: Bitboard) -> Bitboard {
debug_assert!((occupied & square).is_empty(),
"occupancy bitboard must not contain the attacking token");
match token {
Token::Pawn => PAWN_ATTACKS[color][square],
Token::Bishop => BISHOP_MAGICS.attacks(square, occupied),
Token::Rook => ROOK_MAGICS .attacks(square, occupied),
Token::Queen => BISHOP_MAGICS.attacks(square, occupied) |
ROOK_MAGICS .attacks(square, occupied),
_ => PSEUDO_ATTACKS[token][square]
}
}
#[cfg(test)]
mod tests {
use crate::prelude::*;
use super::super::{cached, computed};
#[test]
fn square_distance() {
for s1 in Square::iter() {
for s2 in Square::iter() {
assert_eq!(
computed::square_distance(s1, s2),
cached ::square_distance(s1, s2),
);
}
}
}
#[test]
fn line() {
for s1 in Square::iter() {
for s2 in Square::iter() {
assert_eq!(
computed::line(s1, s2),
cached ::line(s1, s2),
);
}
}
}
#[test]
fn between() {
for s1 in Square::iter() {
for s2 in Square::iter() {
assert_eq!(
computed::between(s1, s2),
cached ::between(s1, s2),
);
}
}
}
#[test]
fn attacks() {
let occupied =
Square::A1 | Square::B1 | Square::D1 | Square::F1 |
Square::E2 | Square::G2 |
Square::C3 | Square::D3 |
Square::H5 |
Square::A6 | Square::C6 |
Square::A7 | Square::H7 |
Square::B8 | Square::D8 | Square::F8 | Square::G8 | Square::H8;
for color in Color::iter() {
for token in Token::iter() {
for square in Square::iter() {
assert_eq!(
computed::attacks(color, token, square, occupied & !square),
cached ::attacks(color, token, square, occupied & !square),
);
}
}
}
}
#[test]
#[should_panic(expected = "must not contain the attacking token")]
fn attacks_includes_origin_square() {
let _ = cached::attacks(Color::White, Token::King, Square::C7, Square::C7.into());
}
}