use crate::*;
pub const fn get_rook_relevant_blockers(square: Square) -> BitBoard {
let rank_moves =
square.rank().bitboard().0 & !(File::One.bitboard().0 | File::Nine.bitboard().0);
let file_moves = square.file().bitboard().0 & !(Rank::A.bitboard().0 | Rank::I.bitboard().0);
BitBoard::new((rank_moves ^ file_moves) & !square.bitboard().0)
}
pub const fn get_lance_relevant_blockers(square: Square, color: Color) -> BitBoard {
let mut ray = BitBoard::EMPTY.0;
let mut sq = square;
let dy = match color {
Color::White => 1,
Color::Black => -1,
};
while let Some(next_sq) = sq.try_offset(0, dy) {
ray |= next_sq.bitboard().0;
sq = next_sq;
}
BitBoard(ray & BitBoard::INNER.0)
}
pub const fn get_bishop_relevant_blockers(square: Square) -> BitBoard {
let mut rays = BitBoard::EMPTY.0;
let mut i = 0;
while i < Square::NUM {
let target = Square::index_const(i);
let rd = (square.rank() as i8 - target.rank() as i8).abs();
let fd = (square.file() as i8 - target.file() as i8).abs();
if rd == fd && rd != 0 {
rays |= 1 << i;
}
i += 1;
}
BitBoard(rays & BitBoard::INNER.0)
}
const fn get_slider_moves(square: Square, blockers: BitBoard, deltas: &[(i8, i8); 4]) -> BitBoard {
let blockers = blockers.rm(square);
let mut moves = BitBoard::EMPTY;
let mut i = 0;
while i < deltas.len() {
let (dx, dy) = deltas[i];
if dx == 0 && dy == 0 {
break;
}
let mut square = square;
while !blockers.has(square) {
if let Some(sq) = square.try_offset(dx, dy) {
square = sq;
moves.0 |= square.bitboard().0;
} else {
break;
}
}
i += 1;
}
moves
}
pub const fn get_rook_moves_slow(square: Square, blockers: BitBoard) -> BitBoard {
get_slider_moves(square, blockers, &[(1, 0), (0, -1), (-1, 0), (0, 1)])
}
pub const fn get_bishop_moves_slow(square: Square, blockers: BitBoard) -> BitBoard {
get_slider_moves(square, blockers, &[(1, 1), (1, -1), (-1, -1), (-1, 1)])
}
pub const fn get_lance_moves_slow(square: Square, blockers: BitBoard, color: Color) -> BitBoard {
let dy = match color {
Color::White => 1,
Color::Black => -1,
};
get_slider_moves(square, blockers, &[(0, dy), (0, 0), (0, 0), (0, 0)])
}
#[inline]
pub const fn rook_pseudo_attacks(square: Square) -> BitBoard {
const TABLE: [BitBoard; Square::NUM] = {
let mut table = [BitBoard::EMPTY; Square::NUM];
let mut index: usize = 0;
while index < Square::NUM {
let sq = Square::index_const(index);
let rank_moves = sq.rank().bitboard().0;
let file_moves = sq.file().bitboard().0;
table[index] = BitBoard(rank_moves ^ file_moves);
index += 1;
}
table
};
TABLE[square as usize]
}
#[inline]
pub const fn bishop_pseudo_attacks(square: Square) -> BitBoard {
const TABLE: [BitBoard; Square::NUM] = {
let mut table = [BitBoard::EMPTY; Square::NUM];
let mut index: usize = 0;
while index < Square::NUM {
let sq = Square::index_const(index);
table[index] = BitBoard(sq.up_diagonal().0 ^ sq.down_diagonal().0);
index += 1;
}
table
};
TABLE[square as usize]
}
#[inline]
pub const fn lance_pseudo_attacks(color: Color, square: Square) -> BitBoard {
const TABLE: [[BitBoard; Square::NUM]; Color::NUM] = {
let mut table = [[BitBoard::EMPTY; Square::NUM]; Color::NUM];
let white = Color::White as usize;
let black = Color::Black as usize;
let mut north_attacks: u128 = 0x0;
let mut south_attacks: u128 = 0x1FE;
let mut mask: u128 = 0xFF;
let mut index: usize = 0;
while index < Square::NUM {
if index % 9 == 0 {
mask = 0x1FF << index;
}
table[black][index] = BitBoard(north_attacks & mask);
table[white][index] = BitBoard(south_attacks & mask);
north_attacks = (north_attacks << 1) | 0x1;
south_attacks <<= 1;
index += 1;
}
table
};
TABLE[color as usize][square as usize]
}
#[inline(always)]
pub const fn get_lance_moves(color: Color, square: Square, occ: BitBoard) -> BitBoard {
let mut attacks = lance_pseudo_attacks(color, square).0;
let mut occ = occ.0;
let aok = attacks & occ;
if aok == 0 {
return BitBoard(attacks);
}
match color {
Color::White => BitBoard(((aok - 1) ^ occ) & attacks),
Color::Black => {
attacks = attacks.reverse_bits();
occ = occ.reverse_bits();
BitBoard(((((attacks & occ) - 1) ^ occ) & attacks).reverse_bits())
}
}
}
#[inline(always)]
pub const fn get_rook_file_moves(square: Square, occ: BitBoard) -> BitBoard {
let north = get_lance_moves(Color::Black, square, occ).0;
let south = get_lance_moves(Color::White, square, occ).0;
BitBoard(north | south)
}
const ROOK_RANK_MASKS: [(u128, u128); Square::NUM] = {
let mut masks = [(0u128, 0u128); Square::NUM];
let mut index = 0;
while index < Square::NUM {
let square = Square::index_const(index);
let file = square.file();
let rank = square.rank();
let rnk = rank.bitboard().0;
let west = rnk & file.west().0;
let east = rnk & file.east().0;
masks[index] = (west, east.reverse_bits());
index += 1;
}
masks
};
#[inline(always)]
pub const fn get_rook_rank_moves(square: Square, occ: BitBoard) -> BitBoard {
let (mut west_attacks, mut east_attacks) = ROOK_RANK_MASKS[square as usize];
let mut index = (west_attacks & occ.0).trailing_zeros();
if index < 127 {
west_attacks &= (1 << (index + 1)) - 1;
}
index = (east_attacks & occ.0.reverse_bits()).trailing_zeros();
if index < 127 {
east_attacks &= (1 << (index + 1)) - 1;
}
BitBoard::new(west_attacks | east_attacks.reverse_bits())
}
#[inline(always)]
pub const fn get_between_rays(from: Square, to: Square) -> BitBoard {
const fn get_between_rays(from: Square, to: Square) -> BitBoard {
let dx = to.file() as i8 - from.file() as i8; let dy = to.rank() as i8 - from.rank() as i8; let orthogonal = dx == 0 || dy == 0;
let diagonal = dx.abs() == dy.abs();
if !(orthogonal || diagonal) {
return BitBoard::EMPTY;
}
let dx = dx.signum(); let dy = dy.signum();
let mut square = from.offset(dx, dy);
let mut between = BitBoard::EMPTY;
while square as u8 != to as u8 {
between.0 |= square.bitboard().0;
square = square.offset(dx, dy);
}
between
}
#[allow(clippy::large_const_arrays)]
const TABLE: [[BitBoard; Square::NUM]; Square::NUM] = {
let mut table = [[BitBoard::EMPTY; Square::NUM]; Square::NUM];
let mut i = 0;
while i < table.len() {
let mut j = 0;
while j < table[i].len() {
table[i][j] = get_between_rays(Square::index_const(i), Square::index_const(j));
j += 1;
}
i += 1;
}
table
};
TABLE[from as usize][to as usize]
}
#[inline(always)]
pub const fn line_ray(from: Square, to: Square) -> BitBoard {
const fn get_line_rays(from: Square, to: Square) -> BitBoard {
let rays = bishop_pseudo_attacks(from);
if rays.has(to) {
return BitBoard(
(rays.0 | from.bitboard().0) & (bishop_pseudo_attacks(to).0 | to.bitboard().0),
);
}
let rays = rook_pseudo_attacks(from);
if rays.has(to) {
return BitBoard(
(rays.0 | from.bitboard().0) & (rook_pseudo_attacks(to).0 | to.bitboard().0),
);
}
BitBoard::EMPTY
}
#[allow(clippy::large_const_arrays)]
const TABLE: [[BitBoard; Square::NUM]; Square::NUM] = {
let mut table = [[BitBoard::EMPTY; Square::NUM]; Square::NUM];
let mut i = 0;
while i < table.len() {
let mut j = 0;
while j < table[i].len() {
table[i][j] = get_line_rays(Square::index_const(i), Square::index_const(j));
j += 1;
}
i += 1;
}
table
};
TABLE[from as usize][to as usize]
}