use crate::bitboard::{BitBoard, EMPTY};
use crate::file::File;
use crate::gen_tables::rays::get_rays;
use crate::piece::Piece;
use crate::rank::Rank;
use crate::square::{Square, ALL_SQUARES};
use rand::Rng;
const ROOK_BITS: usize = 12;
const BISHOP_BITS: usize = 9;
pub const NUM_MOVES: usize = 64 * (1<<ROOK_BITS) +
64 * (1<<BISHOP_BITS) ;
fn rook_directions() -> Vec<fn(Square) -> Option<Square>> {
fn left(sq: Square) -> Option<Square> {
sq.left()
}
fn right(sq: Square) -> Option<Square> {
sq.right()
}
fn up(sq: Square) -> Option<Square> {
sq.up()
}
fn down(sq: Square) -> Option<Square> {
sq.down()
}
vec![left, right, up, down]
}
fn bishop_directions() -> Vec<fn(Square) -> Option<Square>> {
fn nw(sq: Square) -> Option<Square> {
sq.left().and_then(|s| s.up())
}
fn ne(sq: Square) -> Option<Square> {
sq.right().and_then(|s| s.up())
}
fn sw(sq: Square) -> Option<Square> {
sq.left().and_then(|s| s.down())
}
fn se(sq: Square) -> Option<Square> {
sq.right().and_then(|s| s.down())
}
vec![nw, ne, sw, se]
}
pub fn random_bitboard<R: Rng>(rng: &mut R) -> BitBoard {
BitBoard::new(rng.gen::<u64>() & rng.gen::<u64>() & rng.gen::<u64>())
}
pub fn magic_mask(sq: Square, piece: Piece) -> BitBoard {
get_rays(sq, piece)
& if piece == Piece::Bishop {
!gen_edges()
} else {
!ALL_SQUARES
.iter()
.filter(|edge| {
(sq.get_rank() == edge.get_rank()
&& (edge.get_file() == File::A || edge.get_file() == File::H))
|| (sq.get_file() == edge.get_file()
&& (edge.get_rank() == Rank::First || edge.get_rank() == Rank::Eighth))
})
.fold(EMPTY, |b, s| b | BitBoard::from_square(*s))
}
}
fn rays_to_questions(mask: BitBoard) -> Vec<BitBoard> {
let mut result = vec![];
let squares = mask.collect::<Vec<_>>();
for i in 0..(1u64 << mask.popcnt()) {
let mut current = EMPTY;
for j in 0..mask.popcnt() {
if (i & (1u64 << j)) == (1u64 << j) {
current |= BitBoard::from_square(squares[j as usize]);
}
}
result.push(current);
}
result
}
pub fn questions_and_answers(sq: Square, piece: Piece) -> (Vec<BitBoard>, Vec<BitBoard>) {
let mask = magic_mask(sq, piece);
let questions = rays_to_questions(mask);
let mut answers = vec![];
let movement = if piece == Piece::Bishop {
bishop_directions()
} else {
rook_directions()
};
for question in questions.iter() {
let mut answer = EMPTY;
for m in movement.iter() {
let mut next = m(sq);
while next != None {
answer ^= BitBoard::from_square(next.unwrap());
if (BitBoard::from_square(next.unwrap()) & *question) != EMPTY {
break;
}
next = m(next.unwrap());
}
}
answers.push(answer);
}
(questions, answers)
}
fn gen_edges() -> BitBoard {
ALL_SQUARES
.iter()
.filter(|sq| {
sq.get_rank() == Rank::First
|| sq.get_rank() == Rank::Eighth
|| sq.get_file() == File::A
|| sq.get_file() == File::H
})
.fold(EMPTY, |b, s| b | BitBoard::from_square(*s))
}