use crate::types::{Color, File, PieceType, Rank, Square};
use super::Bitboard;
pub static FILE_BB: [Bitboard; File::NUM] = init_file_bb();
pub static RANK_BB: [Bitboard; Rank::NUM] = init_rank_bb();
pub static SQUARE_BB: [Bitboard; Square::NUM] = init_square_bb();
pub static PAWN_EFFECT: [[Bitboard; Square::NUM]; Color::NUM] = init_pawn_effect();
pub static KNIGHT_EFFECT: [[Bitboard; Square::NUM]; Color::NUM] = init_knight_effect();
pub static SILVER_EFFECT: [[Bitboard; Square::NUM]; Color::NUM] = init_silver_effect();
pub static GOLD_EFFECT: [[Bitboard; Square::NUM]; Color::NUM] = init_gold_effect();
pub static KING_EFFECT: [Bitboard; Square::NUM] = init_king_effect();
const fn init_file_bb() -> [Bitboard; File::NUM] {
let mut result = [Bitboard::EMPTY; File::NUM];
let mut file = 0u8;
while file < 9 {
let base = file as usize * 9;
if file < 7 {
let mut bits = 0u64;
let mut rank = 0;
while rank < 9 {
bits |= 1u64 << (base + rank);
rank += 1;
}
result[file as usize] = Bitboard::new(bits, 0);
} else {
let mut bits = 0u64;
let mut rank = 0;
while rank < 9 {
bits |= 1u64 << (base - 63 + rank);
rank += 1;
}
result[file as usize] = Bitboard::new(0, bits);
}
file += 1;
}
result
}
const fn init_rank_bb() -> [Bitboard; Rank::NUM] {
let mut result = [Bitboard::EMPTY; Rank::NUM];
let mut rank = 0u8;
while rank < 9 {
let mut p0 = 0u64;
let mut p1 = 0u64;
let mut file = 0u8;
while file < 9 {
let idx = file as usize * 9 + rank as usize;
if idx < 63 {
p0 |= 1u64 << idx;
} else {
p1 |= 1u64 << (idx - 63);
}
file += 1;
}
result[rank as usize] = Bitboard::new(p0, p1);
rank += 1;
}
result
}
const fn init_square_bb() -> [Bitboard; Square::NUM] {
let mut result = [Bitboard::EMPTY; Square::NUM];
let mut i = 0;
while i < 81 {
if i < 63 {
result[i] = Bitboard::new(1u64 << i, 0);
} else {
result[i] = Bitboard::new(0, 1u64 << (i - 63));
}
i += 1;
}
result
}
const fn init_pawn_effect() -> [[Bitboard; Square::NUM]; Color::NUM] {
let mut result = [[Bitboard::EMPTY; Square::NUM]; Color::NUM];
let mut sq = 0;
while sq < 81 {
let file = sq / 9;
let rank = sq % 9;
if rank > 0 {
let to = file * 9 + (rank - 1);
result[0][sq] = square_bb_const(to);
}
if rank < 8 {
let to = file * 9 + (rank + 1);
result[1][sq] = square_bb_const(to);
}
sq += 1;
}
result
}
const fn init_knight_effect() -> [[Bitboard; Square::NUM]; Color::NUM] {
let mut result = [[Bitboard::EMPTY; Square::NUM]; Color::NUM];
let mut sq = 0;
while sq < 81 {
let file = sq / 9;
let rank = sq % 9;
if rank >= 2 {
let to_rank = rank - 2;
if file < 8 {
let to = (file + 1) * 9 + to_rank;
result[0][sq] = bb_or_const(result[0][sq], square_bb_const(to));
}
if file > 0 {
let to = (file - 1) * 9 + to_rank;
result[0][sq] = bb_or_const(result[0][sq], square_bb_const(to));
}
}
if rank <= 6 {
let to_rank = rank + 2;
if file < 8 {
let to = (file + 1) * 9 + to_rank;
result[1][sq] = bb_or_const(result[1][sq], square_bb_const(to));
}
if file > 0 {
let to = (file - 1) * 9 + to_rank;
result[1][sq] = bb_or_const(result[1][sq], square_bb_const(to));
}
}
sq += 1;
}
result
}
const fn init_silver_effect() -> [[Bitboard; Square::NUM]; Color::NUM] {
let mut result = [[Bitboard::EMPTY; Square::NUM]; Color::NUM];
let mut sq = 0;
while sq < 81 {
let file = sq / 9;
let rank = sq % 9;
let mut bb_black = Bitboard::EMPTY;
if rank > 0 {
bb_black = bb_or_const(bb_black, square_bb_const(file * 9 + (rank - 1)));
}
if file < 8 && rank > 0 {
bb_black = bb_or_const(bb_black, square_bb_const((file + 1) * 9 + (rank - 1)));
}
if file > 0 && rank > 0 {
bb_black = bb_or_const(bb_black, square_bb_const((file - 1) * 9 + (rank - 1)));
}
if file < 8 && rank < 8 {
bb_black = bb_or_const(bb_black, square_bb_const((file + 1) * 9 + (rank + 1)));
}
if file > 0 && rank < 8 {
bb_black = bb_or_const(bb_black, square_bb_const((file - 1) * 9 + (rank + 1)));
}
result[0][sq] = bb_black;
let mut bb_white = Bitboard::EMPTY;
if rank < 8 {
bb_white = bb_or_const(bb_white, square_bb_const(file * 9 + (rank + 1)));
}
if file < 8 && rank < 8 {
bb_white = bb_or_const(bb_white, square_bb_const((file + 1) * 9 + (rank + 1)));
}
if file > 0 && rank < 8 {
bb_white = bb_or_const(bb_white, square_bb_const((file - 1) * 9 + (rank + 1)));
}
if file < 8 && rank > 0 {
bb_white = bb_or_const(bb_white, square_bb_const((file + 1) * 9 + (rank - 1)));
}
if file > 0 && rank > 0 {
bb_white = bb_or_const(bb_white, square_bb_const((file - 1) * 9 + (rank - 1)));
}
result[1][sq] = bb_white;
sq += 1;
}
result
}
const fn init_gold_effect() -> [[Bitboard; Square::NUM]; Color::NUM] {
let mut result = [[Bitboard::EMPTY; Square::NUM]; Color::NUM];
let mut sq = 0;
while sq < 81 {
let file = sq / 9;
let rank = sq % 9;
let mut bb_black = Bitboard::EMPTY;
if rank > 0 {
bb_black = bb_or_const(bb_black, square_bb_const(file * 9 + (rank - 1)));
}
if file < 8 && rank > 0 {
bb_black = bb_or_const(bb_black, square_bb_const((file + 1) * 9 + (rank - 1)));
}
if file > 0 && rank > 0 {
bb_black = bb_or_const(bb_black, square_bb_const((file - 1) * 9 + (rank - 1)));
}
if file < 8 {
bb_black = bb_or_const(bb_black, square_bb_const((file + 1) * 9 + rank));
}
if file > 0 {
bb_black = bb_or_const(bb_black, square_bb_const((file - 1) * 9 + rank));
}
if rank < 8 {
bb_black = bb_or_const(bb_black, square_bb_const(file * 9 + (rank + 1)));
}
result[0][sq] = bb_black;
let mut bb_white = Bitboard::EMPTY;
if rank < 8 {
bb_white = bb_or_const(bb_white, square_bb_const(file * 9 + (rank + 1)));
}
if file < 8 && rank < 8 {
bb_white = bb_or_const(bb_white, square_bb_const((file + 1) * 9 + (rank + 1)));
}
if file > 0 && rank < 8 {
bb_white = bb_or_const(bb_white, square_bb_const((file - 1) * 9 + (rank + 1)));
}
if file < 8 {
bb_white = bb_or_const(bb_white, square_bb_const((file + 1) * 9 + rank));
}
if file > 0 {
bb_white = bb_or_const(bb_white, square_bb_const((file - 1) * 9 + rank));
}
if rank > 0 {
bb_white = bb_or_const(bb_white, square_bb_const(file * 9 + (rank - 1)));
}
result[1][sq] = bb_white;
sq += 1;
}
result
}
const fn init_king_effect() -> [Bitboard; Square::NUM] {
let mut result = [Bitboard::EMPTY; Square::NUM];
let mut sq = 0;
while sq < 81 {
let file = sq / 9;
let rank = sq % 9;
let mut bb = Bitboard::EMPTY;
if rank > 0 {
bb = bb_or_const(bb, square_bb_const(file * 9 + (rank - 1)));
}
if rank < 8 {
bb = bb_or_const(bb, square_bb_const(file * 9 + (rank + 1)));
}
if file < 8 {
bb = bb_or_const(bb, square_bb_const((file + 1) * 9 + rank));
}
if file > 0 {
bb = bb_or_const(bb, square_bb_const((file - 1) * 9 + rank));
}
if file < 8 && rank > 0 {
bb = bb_or_const(bb, square_bb_const((file + 1) * 9 + (rank - 1)));
}
if file > 0 && rank > 0 {
bb = bb_or_const(bb, square_bb_const((file - 1) * 9 + (rank - 1)));
}
if file < 8 && rank < 8 {
bb = bb_or_const(bb, square_bb_const((file + 1) * 9 + (rank + 1)));
}
if file > 0 && rank < 8 {
bb = bb_or_const(bb, square_bb_const((file - 1) * 9 + (rank + 1)));
}
result[sq] = bb;
sq += 1;
}
result
}
const fn square_bb_const(sq: usize) -> Bitboard {
if sq < 63 {
Bitboard::new(1u64 << sq, 0)
} else {
Bitboard::new(0, 1u64 << (sq - 63))
}
}
const fn bb_or_const(a: Bitboard, b: Bitboard) -> Bitboard {
Bitboard::new(a.p0() | b.p0(), a.p1() | b.p1())
}
#[inline]
pub fn pawn_effect(color: Color, sq: Square) -> Bitboard {
PAWN_EFFECT[color.index()][sq.index()]
}
#[inline]
pub fn knight_effect(color: Color, sq: Square) -> Bitboard {
KNIGHT_EFFECT[color.index()][sq.index()]
}
#[inline]
pub fn silver_effect(color: Color, sq: Square) -> Bitboard {
SILVER_EFFECT[color.index()][sq.index()]
}
#[inline]
pub fn gold_effect(color: Color, sq: Square) -> Bitboard {
GOLD_EFFECT[color.index()][sq.index()]
}
#[inline]
pub fn king_effect(sq: Square) -> Bitboard {
KING_EFFECT[sq.index()]
}
#[inline]
pub fn piece_effect(pt: PieceType, color: Color, sq: Square) -> Bitboard {
match pt {
PieceType::Pawn => pawn_effect(color, sq),
PieceType::Knight => knight_effect(color, sq),
PieceType::Silver => silver_effect(color, sq),
PieceType::Gold
| PieceType::ProPawn
| PieceType::ProLance
| PieceType::ProKnight
| PieceType::ProSilver => gold_effect(color, sq),
PieceType::King => king_effect(sq),
_ => Bitboard::EMPTY,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_file_bb() {
let file1 = FILE_BB[0];
assert_eq!(file1.count(), 9);
for rank in 0..9 {
let sq = Square::new(File::File1, Rank::from_u8(rank).unwrap());
assert!(file1.contains(sq));
}
let sq21 = Square::new(File::File2, Rank::Rank1);
assert!(!file1.contains(sq21));
}
#[test]
fn test_rank_bb() {
let rank1 = RANK_BB[0];
assert_eq!(rank1.count(), 9);
for file in 0..9 {
let sq = Square::new(File::from_u8(file).unwrap(), Rank::Rank1);
assert!(rank1.contains(sq));
}
let sq12 = Square::new(File::File1, Rank::Rank2);
assert!(!rank1.contains(sq12));
}
#[test]
fn test_pawn_effect() {
let sq55 = Square::new(File::File5, Rank::Rank5);
let sq54 = Square::new(File::File5, Rank::Rank4);
let bb = pawn_effect(Color::Black, sq55);
assert_eq!(bb.count(), 1);
assert!(bb.contains(sq54));
let sq56 = Square::new(File::File5, Rank::Rank6);
let bb = pawn_effect(Color::White, sq55);
assert_eq!(bb.count(), 1);
assert!(bb.contains(sq56));
let sq11 = Square::new(File::File1, Rank::Rank1);
let bb = pawn_effect(Color::Black, sq11);
assert!(bb.is_empty());
}
#[test]
fn test_knight_effect() {
let sq55 = Square::new(File::File5, Rank::Rank5);
let sq43 = Square::new(File::File4, Rank::Rank3);
let sq63 = Square::new(File::File6, Rank::Rank3);
let bb = knight_effect(Color::Black, sq55);
assert_eq!(bb.count(), 2);
assert!(bb.contains(sq43));
assert!(bb.contains(sq63));
let sq47 = Square::new(File::File4, Rank::Rank7);
let sq67 = Square::new(File::File6, Rank::Rank7);
let bb = knight_effect(Color::White, sq55);
assert_eq!(bb.count(), 2);
assert!(bb.contains(sq47));
assert!(bb.contains(sq67));
}
#[test]
fn test_silver_effect() {
let sq55 = Square::new(File::File5, Rank::Rank5);
let bb = silver_effect(Color::Black, sq55);
assert_eq!(bb.count(), 5);
assert!(bb.contains(Square::new(File::File5, Rank::Rank4))); assert!(bb.contains(Square::new(File::File4, Rank::Rank4))); assert!(bb.contains(Square::new(File::File6, Rank::Rank4))); assert!(bb.contains(Square::new(File::File4, Rank::Rank6))); assert!(bb.contains(Square::new(File::File6, Rank::Rank6))); }
#[test]
fn test_gold_effect() {
let sq55 = Square::new(File::File5, Rank::Rank5);
let bb = gold_effect(Color::Black, sq55);
assert_eq!(bb.count(), 6);
assert!(bb.contains(Square::new(File::File5, Rank::Rank4))); assert!(bb.contains(Square::new(File::File4, Rank::Rank4))); assert!(bb.contains(Square::new(File::File6, Rank::Rank4))); assert!(bb.contains(Square::new(File::File4, Rank::Rank5))); assert!(bb.contains(Square::new(File::File6, Rank::Rank5))); assert!(bb.contains(Square::new(File::File5, Rank::Rank6))); }
#[test]
fn test_king_effect() {
let sq55 = Square::new(File::File5, Rank::Rank5);
let bb = king_effect(sq55);
assert_eq!(bb.count(), 8);
let sq11 = Square::new(File::File1, Rank::Rank1);
let bb = king_effect(sq11);
assert_eq!(bb.count(), 3);
let sq15 = Square::new(File::File1, Rank::Rank5);
let bb = king_effect(sq15);
assert_eq!(bb.count(), 5);
}
}