use crate::bitboard::*;
use crate::board::*;
pub(crate) const BISHOP_SHR: u8 = 55;
pub(crate) const ROOK_SHR: u8 = 52;
#[inline]
pub const fn hash(shr: u8, factor: u64, x: Bitboard) -> usize {
(x.0.wrapping_mul(factor) >> shr) as usize
}
macro_rules! by_square {
($sq:ident, $init:expr, $e:expr) => {{
let mut res = [$init; 64];
let mut $sq: u8 = 0;
while $sq < 64 {
res[$sq as usize] = {
let $sq = Square::new($sq).unwrap();
$e
};
$sq += 1;
}
BySquare(res)
}};
}
macro_rules! loop_bishop_directions {
($d:ident, $e:expr) => {{
{
let $d = Direction::NorthEast;
$e
}
{
let $d = Direction::NorthWest;
$e
}
{
let $d = Direction::SouthWest;
$e
}
{
let $d = Direction::SouthEast;
$e
}
}};
}
macro_rules! loop_rook_directions {
($d:ident, $e:expr) => {{
{
let $d = Direction::East;
$e
}
{
let $d = Direction::North;
$e
}
{
let $d = Direction::West;
$e
}
{
let $d = Direction::South;
$e
}
}};
}
macro_rules! loop_all_directions {
($d:ident, $e:expr) => {{
loop_bishop_directions!($d, $e);
loop_rook_directions!($d, $e);
}};
}
macro_rules! by_direction {
($d:ident, $e:expr) => {{
let mut res = [Bitboard(0); 8];
let mut $d: u8 = 0;
while $d < 8 {
res[$d as usize] = {
let $d = Direction::new($d).unwrap();
$e
};
$d += 1;
}
ByDirection(res)
}};
}
#[inline]
pub(crate) const fn ray(square: Square, direction: Direction) -> Bitboard {
static DATA: BySquare<ByDirection<Bitboard>> = by_square!(
square,
ByDirection([Bitboard(0); 8]),
by_direction!(direction, {
let mut square = square;
let mut res = 0;
while let Some(x) = square.trans(direction) {
square = x;
res |= square.bitboard().0;
}
Bitboard(res)
})
);
*DATA.get(square).get(direction)
}
#[inline]
pub(crate) const fn line(a: Square, b: Square) -> Bitboard {
static DATA: BySquare<BySquare<Bitboard>> = by_square!(a, BySquare([Bitboard(0); 64]), {
by_square!(b, Bitboard(0), {
let mut res = Bitboard(0);
loop_all_directions!(d, {
let r = ray(a, d);
if r.contains(b) {
res = r;
}
});
res
})
});
*DATA.get(a).get(b)
}
#[inline]
pub(crate) const fn segment(a: Square, b: Square) -> Bitboard {
static DATA: BySquare<BySquare<Bitboard>> = by_square!(a, BySquare([Bitboard(0); 64]), {
by_square!(b, Bitboard(0), {
let mut res = 0;
loop_all_directions!(d, {
let r = ray(a, d);
if r.contains(b) {
res = r.0 & !ray(b, d).0;
}
});
Bitboard(res | b.bitboard().0)
})
});
*DATA.get(a).get(b)
}
#[inline]
pub(crate) const fn bishop_lines(square: Square) -> Bitboard {
static DATA: BySquare<Bitboard> = by_square!(sq, Bitboard(0), {
let mut res = 0;
loop_bishop_directions!(d, {
res |= ray(sq, d).0;
});
Bitboard(res)
});
*DATA.get(square)
}
#[inline]
pub(crate) const fn rook_lines(square: Square) -> Bitboard {
static DATA: BySquare<Bitboard> = by_square!(sq, Bitboard(0), {
let mut res = 0;
loop_rook_directions!(d, {
res |= ray(sq, d).0;
});
Bitboard(res)
});
*DATA.get(square)
}
#[inline]
pub(crate) const fn king(square: Square) -> Bitboard {
static DATA: BySquare<Bitboard> = by_square!(sq, Bitboard(0), {
let mut res = 0;
loop_all_directions!(d, {
if let Some(x) = sq.trans(d) {
res |= x.bitboard().0;
}
});
Bitboard(res)
});
*DATA.get(square)
}
#[inline]
pub(crate) const fn knight(square: Square) -> Bitboard {
static DATA: BySquare<Bitboard> = by_square!(s, Bitboard(0), {
let mut res = Bitboard(0);
if let Some(s) = s.trans(Direction::North) {
if let Some(s) = s.trans(Direction::NorthEast) {
res.insert(s);
}
if let Some(s) = s.trans(Direction::NorthWest) {
res.insert(s)
};
}
if let Some(s) = s.trans(Direction::West) {
if let Some(s) = s.trans(Direction::NorthWest) {
res.insert(s)
};
if let Some(s) = s.trans(Direction::SouthWest) {
res.insert(s)
};
}
if let Some(s) = s.trans(Direction::South) {
if let Some(s) = s.trans(Direction::SouthWest) {
res.insert(s)
};
if let Some(s) = s.trans(Direction::SouthEast) {
res.insert(s)
};
}
if let Some(s) = s.trans(Direction::East) {
if let Some(s) = s.trans(Direction::SouthEast) {
res.insert(s)
};
if let Some(s) = s.trans(Direction::NorthEast) {
res.insert(s)
};
}
res
});
*DATA.get(square)
}
#[inline]
pub(crate) fn pawn_attack(color: Color, square: Square) -> Bitboard {
let m = square.bitboard().trans(color.forward());
m.trans(Direction::East) | m.trans(Direction::West)
}