use shogi_core::{Color, Square};
use crate::bitboard::{Bitboard, file_of, index_of, on_board, rank_of};
pub(crate) type LineKind = i8;
pub(crate) const RANK_LINE: LineKind = 0;
pub(crate) const DIAGONAL_UP_LINE: LineKind = 1;
pub(crate) const DIAGONAL_DOWN_LINE: LineKind = -1;
pub(crate) const fn walk_line(index: usize, occupied: u128, line: LineKind) -> u128 {
let mut bits = 0u128;
let mut direction = 0;
while direction < 2 {
let sign: i8 = if direction == 0 { 1 } else { -1 };
let (mut file, mut rank) = (file_of(index), rank_of(index));
loop {
file += sign;
rank += sign * line;
if !on_board(file, rank) {
break;
}
let to = index_of(file, rank);
bits |= 1 << to;
if occupied & (1 << to) != 0 {
break;
}
}
direction += 1;
}
bits
}
pub(crate) const fn relevant_mask(index: usize, line: LineKind) -> u128 {
let mut bits = 0u128;
let mut direction = 0;
while direction < 2 {
let sign: i8 = if direction == 0 { 1 } else { -1 };
let (mut file, mut rank) = (file_of(index), rank_of(index));
loop {
file += sign;
rank += sign * line;
if !on_board(file, rank) {
break;
}
if on_board(file + sign, rank + sign * line) {
bits |= 1 << index_of(file, rank);
}
}
direction += 1;
}
bits
}
#[cfg(all(feature = "slider-naive", feature = "slider-qugiy"))]
compile_error!("slider-naive and slider-qugiy select the same thing; enable at most one");
pub(crate) mod magic;
mod magics;
#[cfg(any(test, feature = "_bench-internals", feature = "slider-naive"))]
pub(crate) mod naive;
#[cfg(any(test, feature = "_bench-internals", feature = "slider-qugiy"))]
pub(crate) mod qugiy;
#[cfg(test)]
mod tests;
#[cfg(not(any(feature = "slider-naive", feature = "slider-qugiy")))]
pub(crate) use magic as active;
#[cfg(feature = "slider-naive")]
pub(crate) use naive as active;
#[cfg(all(feature = "slider-qugiy", not(feature = "slider-naive")))]
pub(crate) use qugiy as active;
static FILE_ATTACKS: [[u16; 128]; 9] = file_attacks_table();
static LANCE_ATTACKS: [[[u16; 128]; 9]; 2] = lance_attacks_table();
const fn walk_file(
rank_index: usize,
occupancy: u16,
toward_rank1: bool,
toward_rank9: bool,
) -> u16 {
let mut attacks = 0u16;
if toward_rank1 {
let mut rank = rank_index;
while rank > 0 {
rank -= 1;
attacks |= 1 << rank;
if occupancy & (1 << rank) != 0 {
break;
}
}
}
if toward_rank9 {
let mut rank = rank_index + 1;
while rank < 9 {
attacks |= 1 << rank;
if occupancy & (1 << rank) != 0 {
break;
}
rank += 1;
}
}
attacks
}
const fn file_attacks_table() -> [[u16; 128]; 9] {
let mut table = [[0u16; 128]; 9];
let mut rank = 0;
while rank < 9 {
let mut relevant = 0;
while relevant < 128 {
table[rank][relevant] = walk_file(rank, (relevant as u16) << 1, true, true);
relevant += 1;
}
rank += 1;
}
table
}
const fn lance_attacks_table() -> [[[u16; 128]; 9]; 2] {
let mut table = [[[0u16; 128]; 9]; 2];
let mut rank = 0;
while rank < 9 {
let mut relevant = 0;
while relevant < 128 {
let occupancy = (relevant as u16) << 1;
table[0][rank][relevant] = walk_file(rank, occupancy, true, false);
table[1][rank][relevant] = walk_file(rank, occupancy, false, true);
relevant += 1;
}
rank += 1;
}
table
}
#[inline(always)]
pub(crate) fn file_attacks(square: Square, occupied: Bitboard) -> Bitboard {
let index = square.array_index();
let (file_base, rank) = (index - index % 9, index % 9);
let relevant = ((occupied.bits() >> (file_base + 1)) & 0x7f) as usize;
Bitboard::from_bits((FILE_ATTACKS[rank][relevant] as u128) << file_base)
}
#[inline(always)]
pub(crate) fn lance_attacks(color: Color, square: Square, occupied: Bitboard) -> Bitboard {
let index = square.array_index();
let (file_base, rank) = (index - index % 9, index % 9);
let relevant = ((occupied.bits() >> (file_base + 1)) & 0x7f) as usize;
let pattern = LANCE_ATTACKS[color.array_index()][rank][relevant];
Bitboard::from_bits((pattern as u128) << file_base)
}