#![allow(dead_code)]
use crate::bitboard::Bitboard;
use crate::coretypes::{Castling, Color, Move, Square, SquareIndexable, NUM_SQUARES};
use crate::coretypes::{Color::*, PieceKind::*, Square::*};
use crate::movelist::MoveList;
pub const KNIGHT_PATTERN: [Bitboard; NUM_SQUARES] = generate_knight_patterns();
pub const KING_PATTERN: [Bitboard; NUM_SQUARES] = generate_king_patterns();
pub const ROOK_PATTERN: [Bitboard; NUM_SQUARES] = generate_rook_patterns();
pub const BISHOP_PATTERN: [Bitboard; NUM_SQUARES] = generate_bishop_patterns();
pub const QUEEN_PATTERN: [Bitboard; NUM_SQUARES] = generate_queen_patterns();
pub fn knight_pattern<I: SquareIndexable>(idx: I) -> Bitboard {
KNIGHT_PATTERN[idx.idx()]
}
pub fn king_pattern<I: SquareIndexable>(idx: I) -> Bitboard {
KING_PATTERN[idx.idx()]
}
pub fn rook_pattern<I: SquareIndexable>(idx: I) -> Bitboard {
ROOK_PATTERN[idx.idx()]
}
pub fn bishop_pattern<I: SquareIndexable>(idx: I) -> Bitboard {
BISHOP_PATTERN[idx.idx()]
}
pub fn queen_pattern<I: SquareIndexable>(idx: I) -> Bitboard {
ROOK_PATTERN[idx.idx()] | BISHOP_PATTERN[idx.idx()]
}
pub fn absolute_pins(
king: Square,
us: Bitboard,
them: Bitboard,
queens_rooks: Bitboard,
queens_bishops: Bitboard,
) -> (Bitboard, [Option<(Square, Bitboard)>; 8]) {
let mut pinned = Bitboard::EMPTY;
let mut pinned_between: [Option<(Square, Bitboard)>; 8] = [None; 8];
let mut index = 0;
let occupied = us | them;
for ortho_ray in [ray_attack_no, ray_attack_ea, ray_attack_so, ray_attack_we] {
let maybe_pinned = ortho_ray(king, occupied) & us; if !maybe_pinned.is_empty() {
let ray_without_pinned = ortho_ray(king, occupied ^ maybe_pinned);
let hits_queen_rook = ray_without_pinned & queens_rooks;
if !hits_queen_rook.is_empty() {
pinned |= maybe_pinned;
let pinned_square = maybe_pinned.get_lowest_square().unwrap();
let potential_moves_bb = ray_without_pinned ^ maybe_pinned;
pinned_between[index] = Some((pinned_square, potential_moves_bb));
index += 1;
}
}
}
for diag_ray in [
ray_attack_noea,
ray_attack_nowe,
ray_attack_soea,
ray_attack_sowe,
] {
let maybe_pinned = diag_ray(king, occupied) & us; if !maybe_pinned.is_empty() {
let ray_without_pinned = diag_ray(king, occupied ^ maybe_pinned);
let hits_queen_bishop = ray_without_pinned & queens_bishops;
if !hits_queen_bishop.is_empty() {
pinned |= maybe_pinned;
let pinned_square = maybe_pinned.get_lowest_square().unwrap();
let potential_moves_bb = ray_without_pinned ^ maybe_pinned;
pinned_between[index] = Some((pinned_square, potential_moves_bb));
index += 1;
}
}
}
debug_assert_eq!(pinned.count_squares() as usize, index);
(pinned, pinned_between)
}
pub fn legal_castling_moves(
moves: &mut MoveList,
player: Color,
castling: Castling,
occupied: Bitboard,
attacked: Bitboard,
) {
let (has_kingside, has_queenside, king_rank) = match player {
White => {
let kingside = castling.has(Castling::W_KING);
let queenside = castling.has(Castling::W_QUEEN);
let king_rank = Bitboard::RANK_1;
(kingside, queenside, king_rank)
}
Black => {
let kingside = castling.has(Castling::B_KING);
let queenside = castling.has(Castling::B_QUEEN);
let king_rank = Bitboard::RANK_8;
(kingside, queenside, king_rank)
}
};
if has_kingside {
let between = occupied & Bitboard::KINGSIDE_BETWEEN & king_rank;
let pass_attacked = attacked & Bitboard::KINGSIDE_PASS & king_rank;
if between.is_empty() && pass_attacked.is_empty() {
match player {
White => moves.push(Move::new(E1, G1, None)),
Black => moves.push(Move::new(E8, G8, None)),
}
}
}
if has_queenside {
let between = occupied & Bitboard::QUEENSIDE_BETWEEN & king_rank;
let pass_attacked = attacked & Bitboard::QUEENSIDE_PASS & king_rank;
if between.is_empty() && pass_attacked.is_empty() {
match player {
White => moves.push(Move::new(E1, C1, None)),
Black => moves.push(Move::new(E8, C8, None)),
}
}
}
}
pub fn pawn_pseudo_moves(
moves: &mut MoveList,
pawns: Bitboard,
color: Color,
occupied: Bitboard,
them: Bitboard,
en_passant: Option<Square>,
) {
let them_with_ep = match en_passant {
Some(ep_square) => them | Bitboard::from(ep_square),
None => them,
};
for from in pawns {
let pawn = Bitboard::from(from);
let single_push = pawn_single_pushes(pawn, color) & !occupied;
let double_push = pawn_double_pushes(pawn, color) & !occupied;
let valid_double_push = double_push & pawn_single_pushes(single_push, color);
let pushes = single_push | valid_double_push;
let attacks = pawn_attacks(pawn, color) & them_with_ep;
let tos = pushes.into_iter().chain(attacks.into_iter());
for to in tos {
if Bitboard::RANK_1.has_square(to) || Bitboard::RANK_8.has_square(to) {
moves.push(Move::new(from, to, Some(Queen)));
moves.push(Move::new(from, to, Some(Rook)));
moves.push(Move::new(from, to, Some(Bishop)));
moves.push(Move::new(from, to, Some(Knight)));
} else {
moves.push(Move::new(from, to, None));
}
}
}
}
pub fn knight_pseudo_moves(moves: &mut MoveList, knights: Bitboard, us: Bitboard) {
for from in knights {
let tos = knight_pattern(from) & !us;
for to in tos {
moves.push(Move::new(from, to, None));
}
}
}
pub fn queen_pseudo_moves(
moves: &mut MoveList,
queens: Bitboard,
occupied: Bitboard,
us: Bitboard,
) {
for from in queens {
let tos = solo_queen_attacks(from, occupied) & !us;
for to in tos {
moves.push(Move::new(from, to, None));
}
}
}
pub fn rook_pseudo_moves(moves: &mut MoveList, rooks: Bitboard, occupied: Bitboard, us: Bitboard) {
for from in rooks {
let tos = solo_rook_attacks(from, occupied) & !us;
for to in tos {
moves.push(Move::new(from, to, None));
}
}
}
pub fn bishop_pseudo_moves(
moves: &mut MoveList,
bishops: Bitboard,
occupied: Bitboard,
us: Bitboard,
) {
for from in bishops {
let tos = solo_bishop_attacks(from, occupied) & !us;
for to in tos {
moves.push(Move::new(from, to, None));
}
}
}
pub fn pawn_pushes(pawns: Bitboard, color: Color) -> Bitboard {
let single_push_bb = pawn_single_pushes(pawns, color);
let double_push_bb = pawn_double_pushes(pawns, color);
single_push_bb | double_push_bb
}
pub fn pawn_single_pushes(pawns: Bitboard, color: Color) -> Bitboard {
match color {
White => pawns.to_north(),
Black => pawns.to_south(),
}
}
pub fn pawn_double_pushes(pawns: Bitboard, color: Color) -> Bitboard {
match color {
White => (pawns & Bitboard::RANK_2).to_north().to_north(),
Black => (pawns & Bitboard::RANK_7).to_south().to_south(),
}
}
pub fn pawn_attacks(pawns: Bitboard, color: Color) -> Bitboard {
match color {
White => pawns.to_north().to_east() | pawns.to_north().to_west(),
Black => pawns.to_south().to_east() | pawns.to_south().to_west(),
}
}
pub fn pawn_double_attacks(pawns: Bitboard, color: Color) -> Bitboard {
match color {
White => pawns.to_north().to_east() & pawns.to_north().to_west(),
Black => pawns.to_south().to_east() & pawns.to_south().to_west(),
}
}
pub fn knight_attacks(knights: Bitboard) -> Bitboard {
let mut attacks = Bitboard::EMPTY;
attacks |= knights.to_north().to_north().to_east();
attacks |= knights.to_north().to_east().to_east();
attacks |= knights.to_south().to_east().to_east();
attacks |= knights.to_south().to_south().to_east();
attacks |= knights.to_south().to_south().to_west();
attacks |= knights.to_south().to_west().to_west();
attacks |= knights.to_north().to_west().to_west();
attacks |= knights.to_north().to_north().to_west();
attacks
}
pub fn king_attacks(king: Bitboard) -> Bitboard {
king_pattern(king.get_lowest_square().unwrap())
}
pub fn queen_attacks(queens: Bitboard, occupied: Bitboard) -> Bitboard {
queens
.into_iter()
.map(|square| solo_queen_attacks(square, occupied))
.fold(Bitboard::EMPTY, |acc, attacks| acc | attacks)
}
pub fn rook_attacks(rooks: Bitboard, occupied: Bitboard) -> Bitboard {
rooks
.into_iter()
.map(|square| solo_rook_attacks(square, occupied))
.fold(Bitboard::EMPTY, |acc, attacks| acc | attacks)
}
pub fn bishop_attacks(bishops: Bitboard, occupied: Bitboard) -> Bitboard {
bishops
.into_iter()
.map(|square| solo_bishop_attacks(square, occupied))
.fold(Bitboard::EMPTY, |acc, attacks| acc | attacks)
}
pub fn slide_attacks(
queens: Bitboard,
rooks: Bitboard,
bishops: Bitboard,
occupied: Bitboard,
) -> Bitboard {
let orthogonals = queens | rooks;
let diagonals = queens | bishops;
let orthogonal_attacks = orthogonals
.into_iter()
.map(|square| solo_rook_attacks(square, occupied))
.fold(Bitboard::EMPTY, |acc, attacks| acc | attacks);
let diagonal_attacks = diagonals
.into_iter()
.map(|square| solo_bishop_attacks(square, occupied))
.fold(Bitboard::EMPTY, |acc, attacks| acc | attacks);
orthogonal_attacks | diagonal_attacks
}
pub fn solo_queen_attacks(origin: Square, occupancy: Bitboard) -> Bitboard {
solo_rook_attacks(origin, occupancy) | solo_bishop_attacks(origin, occupancy)
}
pub fn solo_rook_attacks(origin: Square, occupancy: Bitboard) -> Bitboard {
ray_attack_no(origin, occupancy)
| ray_attack_ea(origin, occupancy)
| ray_attack_so(origin, occupancy)
| ray_attack_we(origin, occupancy)
}
pub fn solo_bishop_attacks(origin: Square, occupancy: Bitboard) -> Bitboard {
ray_attack_noea(origin, occupancy)
| ray_attack_soea(origin, occupancy)
| ray_attack_sowe(origin, occupancy)
| ray_attack_nowe(origin, occupancy)
}
pub fn pawn_attackers_to(target: Square, pawns: Bitboard, color: Color) -> Bitboard {
let mut attackers = Bitboard::EMPTY;
for pawn_square in pawns.into_iter() {
let pawn = Bitboard::from(pawn_square);
if pawn_attacks(pawn, color).has_square(target) {
attackers.set_square(pawn_square);
}
}
attackers
}
pub fn knight_attackers_to(target: Square, knights: Bitboard) -> Bitboard {
knights
.into_iter()
.filter(|square| knight_pattern(square).has_square(target))
.fold(Bitboard::EMPTY, |acc, square| acc | Bitboard::from(square))
}
pub fn king_attackers_to(target: Square, kings: Bitboard) -> Bitboard {
let mut attackers = Bitboard::EMPTY;
for king_square in kings.into_iter() {
if king_pattern(king_square).has_square(target) {
attackers.set_square(king_square);
}
}
attackers
}
pub fn queen_attackers_to(target: Square, queens: Bitboard, occupied: Bitboard) -> Bitboard {
let mut attackers = Bitboard::EMPTY;
for queen_square in queens.into_iter() {
if solo_queen_attacks(queen_square, occupied).has_square(target) {
attackers.set_square(queen_square);
}
}
attackers
}
pub fn rook_attackers_to(target: Square, rooks: Bitboard, occupied: Bitboard) -> Bitboard {
let mut attackers = Bitboard::EMPTY;
for rook_square in rooks.into_iter() {
if solo_rook_attacks(rook_square, occupied).has_square(target) {
attackers.set_square(rook_square);
}
}
attackers
}
pub fn bishop_attackers_to(target: Square, bishops: Bitboard, occupied: Bitboard) -> Bitboard {
let mut attackers = Bitboard::EMPTY;
for bishop_square in bishops.into_iter() {
if solo_bishop_attacks(bishop_square, occupied).has_square(target) {
attackers.set_square(bishop_square);
}
}
attackers
}
fn ray_attack_no(origin: Square, occupancy: Bitboard) -> Bitboard {
let mut ray = Bitboard::from(origin).to_north();
for _ in 0..6 {
if occupancy.has_any(&ray) {
return ray;
}
ray |= ray.to_north();
}
ray
}
fn ray_attack_ea(origin: Square, occupancy: Bitboard) -> Bitboard {
let mut ray = Bitboard::from(origin).to_east();
for _ in 0..6 {
if occupancy.has_any(&ray) {
return ray;
}
ray |= ray.to_east();
}
ray
}
fn ray_attack_so(origin: Square, occupancy: Bitboard) -> Bitboard {
let mut ray = Bitboard::from(origin).to_south();
for _ in 0..6 {
if occupancy.has_any(&ray) {
return ray;
}
ray |= ray.to_south();
}
ray
}
fn ray_attack_we(origin: Square, occupancy: Bitboard) -> Bitboard {
let mut ray = Bitboard::from(origin).to_west();
for _ in 0..6 {
if occupancy.has_any(&ray) {
return ray;
}
ray |= ray.to_west();
}
ray
}
fn ray_attack_noea(origin: Square, occupancy: Bitboard) -> Bitboard {
let mut ray = Bitboard::from(origin).to_north_east();
for _ in 0..6 {
if occupancy.has_any(&ray) {
return ray;
}
ray |= ray.to_north_east();
}
ray
}
fn ray_attack_soea(origin: Square, occupancy: Bitboard) -> Bitboard {
let mut ray = Bitboard::from(origin).to_south_east();
for _ in 0..6 {
if occupancy.has_any(&ray) {
return ray;
}
ray |= ray.to_south_east();
}
ray
}
fn ray_attack_sowe(origin: Square, occupancy: Bitboard) -> Bitboard {
let mut ray = Bitboard::from(origin).to_south_west();
for _ in 0..6 {
if occupancy.has_any(&ray) {
return ray;
}
ray |= ray.to_south_west();
}
ray
}
fn ray_attack_nowe(origin: Square, occupancy: Bitboard) -> Bitboard {
let mut ray = Bitboard::from(origin).to_north_west();
for _ in 0..6 {
if occupancy.has_any(&ray) {
return ray;
}
ray |= ray.to_north_west();
}
ray
}
macro_rules! repeat_for_each {
($array:ident, $func:ident, $($numbers:literal),+) => {
{
$($array[$numbers] = $func($numbers);)*
}
};
}
const fn generate_knight_patterns() -> [Bitboard; NUM_SQUARES] {
let mut pattern_arr = [Bitboard::EMPTY; NUM_SQUARES];
#[rustfmt::skip]
repeat_for_each!(
pattern_arr,
knight_pattern_index,
0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 58, 59, 60, 61, 62, 63
);
pattern_arr
}
const fn knight_pattern_index(index: usize) -> Bitboard {
let index_bb = Bitboard(1u64 << index);
let mut bb = Bitboard::EMPTY;
bb.0 |= index_bb.to_north().to_north().to_east().0;
bb.0 |= index_bb.to_north().to_east().to_east().0;
bb.0 |= index_bb.to_south().to_east().to_east().0;
bb.0 |= index_bb.to_south().to_south().to_east().0;
bb.0 |= index_bb.to_south().to_south().to_west().0;
bb.0 |= index_bb.to_south().to_west().to_west().0;
bb.0 |= index_bb.to_north().to_west().to_west().0;
bb.0 |= index_bb.to_north().to_north().to_west().0;
bb
}
const fn generate_king_patterns() -> [Bitboard; NUM_SQUARES] {
let mut pattern_arr = [Bitboard::EMPTY; NUM_SQUARES];
#[rustfmt::skip]
repeat_for_each!(
pattern_arr,
king_pattern_index,
0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 58, 59, 60, 61, 62, 63
);
pattern_arr
}
const fn king_pattern_index(index: usize) -> Bitboard {
let mut index_bb = Bitboard(1u64 << index);
let mut bb = Bitboard(index_bb.to_west().0 | index_bb.to_east().0);
index_bb.0 |= bb.0;
bb.0 |= index_bb.to_north().0;
bb.0 |= index_bb.to_south().0;
bb
}
const fn generate_rook_patterns() -> [Bitboard; NUM_SQUARES] {
let mut pattern_arr = [Bitboard::EMPTY; NUM_SQUARES];
#[rustfmt::skip]
repeat_for_each!(
pattern_arr,
rook_pattern_index,
0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 58, 59, 60, 61, 62, 63
);
pattern_arr
}
macro_rules! repeat_6_times {
($statement:stmt) => {
$statement
$statement
$statement
$statement
$statement
$statement
};
}
const fn rook_pattern_index(index: usize) -> Bitboard {
let index_bb = Bitboard(1u64 << index);
let mut north_bit_vec = index_bb.to_north();
repeat_6_times!(north_bit_vec.0 |= north_bit_vec.to_north().0);
let mut south_bit_vec = index_bb.to_south();
repeat_6_times!(south_bit_vec.0 |= south_bit_vec.to_south().0);
let mut east_bit_vec = index_bb.to_east();
repeat_6_times!(east_bit_vec.0 |= east_bit_vec.to_east().0);
let mut west_bit_vec = index_bb.to_west();
repeat_6_times!(west_bit_vec.0 |= west_bit_vec.to_west().0);
Bitboard(north_bit_vec.0 | south_bit_vec.0 | east_bit_vec.0 | west_bit_vec.0)
}
const fn generate_bishop_patterns() -> [Bitboard; NUM_SQUARES] {
let mut pattern_arr = [Bitboard::EMPTY; NUM_SQUARES];
#[rustfmt::skip]
repeat_for_each!(
pattern_arr,
bishop_pattern_index,
0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 58, 59, 60, 61, 62, 63
);
pattern_arr
}
const fn bishop_pattern_index(index: usize) -> Bitboard {
let index_bb = Bitboard(1u64 << index);
let mut no_ea_bit_vec = index_bb.to_north().to_east();
repeat_6_times!(no_ea_bit_vec.0 |= no_ea_bit_vec.to_north().to_east().0);
let mut so_ea_bit_vec = index_bb.to_south().to_east();
repeat_6_times!(so_ea_bit_vec.0 |= so_ea_bit_vec.to_south().to_east().0);
let mut so_we_bit_vec = index_bb.to_south().to_west();
repeat_6_times!(so_we_bit_vec.0 |= so_we_bit_vec.to_south().to_west().0);
let mut no_we_bit_vec = index_bb.to_north().to_west();
repeat_6_times!(no_we_bit_vec.0 |= no_we_bit_vec.to_north().to_west().0);
Bitboard(no_ea_bit_vec.0 | so_ea_bit_vec.0 | so_we_bit_vec.0 | no_we_bit_vec.0)
}
const fn generate_queen_patterns() -> [Bitboard; NUM_SQUARES] {
let mut pattern_arr = [Bitboard::EMPTY; NUM_SQUARES];
#[rustfmt::skip]
repeat_for_each!(
pattern_arr,
queen_pattern_index,
0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 58, 59, 60, 61, 62, 63
);
pattern_arr
}
const fn queen_pattern_index(index: usize) -> Bitboard {
Bitboard(ROOK_PATTERN[index].0 | BISHOP_PATTERN[index].0)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::coretypes::*;
#[test]
fn check_knight_patterns() {
let a1 = KNIGHT_PATTERN[A1.idx()];
println!("a1: {:?}", a1);
println!("a1 knight attack squares: {:?}", a1.squares());
assert_eq!(a1.count_squares(), 2);
assert!(a1.has_square(C2));
assert!(a1.has_square(B3));
let h1 = KNIGHT_PATTERN[H1.idx()];
assert_eq!(h1.count_squares(), 2);
assert!(h1.has_square(F2));
assert!(h1.has_square(G3));
let h8 = KNIGHT_PATTERN[H8.idx()];
assert_eq!(h8.count_squares(), 2);
assert!(h8.has_square(F7));
assert!(h8.has_square(G6));
let d4 = KNIGHT_PATTERN[D4.idx()];
assert_eq!(d4.count_squares(), 8);
for square in [E6, F5, F3, E2, C2, B3, B5, C6] {
assert!(d4.has_square(&square));
}
for square in Square::iter() {
assert!(!knight_pattern(square).has_square(square));
}
}
#[test]
fn check_king_patterns() {
{
let a1 = KING_PATTERN[A1.idx()];
assert_eq!(a1.count_squares(), 3);
assert!(a1.has_square(A2));
assert!(a1.has_square(B2));
assert!(a1.has_square(B1));
}
{
let a8 = KING_PATTERN[A8.idx()];
assert_eq!(a8.count_squares(), 3);
assert!(a8.has_square(A7));
assert!(a8.has_square(B7));
assert!(a8.has_square(B8));
}
{
let h1 = KING_PATTERN[H1.idx()];
assert_eq!(h1.count_squares(), 3);
assert!(h1.has_square(G1));
assert!(h1.has_square(G2));
assert!(h1.has_square(H2));
}
{
let h8 = KING_PATTERN[H8.idx()];
assert_eq!(h8.count_squares(), 3);
assert!(h8.has_square(G7));
assert!(h8.has_square(G8));
assert!(h8.has_square(H7));
}
{
let d6 = KING_PATTERN[D6.idx()];
assert_eq!(d6.count_squares(), 8);
for square in [C5, C6, C7, D5, D7, E5, E6, E7] {
assert!(d6.has_square(&square));
}
}
for square in Square::iter() {
assert!(!king_pattern(square).has_square(square));
}
}
#[test]
fn check_rook_patterns() {
{
let a1 = ROOK_PATTERN[A1.idx()];
assert_eq!(a1.count_squares(), 14);
for square in [A2, A3, A4, A5, A6, A7, A8, B1, C1, D1, E1, F1, G1, H1] {
assert!(a1.has_square(&square));
}
}
{
let h8 = ROOK_PATTERN[H8.idx()];
assert_eq!(h8.count_squares(), 14);
for square in [A8, B8, C8, D8, E8, F8, G8, H1, H2, H3, H4, H5, H6, H7] {
assert!(h8.has_square(&square));
}
}
{
let f3 = ROOK_PATTERN[F3.idx()];
assert_eq!(f3.count_squares(), 14);
for square in [A3, B3, C3, D3, E3, G3, H3, F1, F2, F4, F5, F6, F7, F8] {
assert!(f3.has_square(&square));
}
}
for square in Square::iter() {
assert!(!rook_pattern(square).has_square(square));
}
}
#[test]
fn check_bishop_patterns() {
{
let a1 = BISHOP_PATTERN[A1.idx()];
assert_eq!(a1.count_squares(), 7);
for square in [B2, C3, D4, E5, F6, G7, H8] {
assert!(a1.has_square(&square));
}
}
{
let h1 = BISHOP_PATTERN[H1.idx()];
assert_eq!(h1.count_squares(), 7);
for square in [A8, B7, C6, D5, E4, F3, G2] {
assert!(h1.has_square(&square));
}
}
{
let h8 = BISHOP_PATTERN[H8.idx()];
assert_eq!(h8.count_squares(), 7);
for square in [A1, B2, C3, D4, E5, F6, G7] {
assert!(h8.has_square(&square));
}
}
{
let c6 = BISHOP_PATTERN[C6.idx()];
assert_eq!(c6.count_squares(), 11);
for square in [A4, B5, D7, E8, A8, B7, D5, E4, F3, G2, H1] {
assert!(c6.has_square(&square));
}
}
for square in Square::iter() {
assert!(!bishop_pattern(square).has_square(square));
}
}
#[test]
fn check_queen_patterns() {
{
let a1 = QUEEN_PATTERN[A1.idx()];
assert_eq!(a1.count_squares(), 21);
for square in [B1, C1, D1, E1, F1, G1, H1, A2, A3, A4, A5, A6, A7, A8] {
assert!(a1.has_square(&square)); }
for square in [B2, C3, D4, E5, F6, G7, H8] {
assert!(a1.has_square(&square)); }
}
{
let h1 = QUEEN_PATTERN[H1.idx()];
assert_eq!(h1.count_squares(), 21);
for square in [A1, B1, C1, D1, E1, F1, G1, H2, H3, H4, H5, H6, H7, H8] {
assert!(h1.has_square(&square)); }
for square in [A8, B7, C6, D5, E4, F3, G2] {
assert!(h1.has_square(&square)); }
}
{
let c6 = QUEEN_PATTERN[C6.idx()];
assert_eq!(c6.count_squares(), 25);
for square in [C1, C2, C3, C4, C5, C7, C8, A6, B6, D6, E6, F6, G6, H6] {
assert!(c6.has_square(&square)); }
for square in [A4, B5, D7, E8, A8, B7, D5, E4, F3, G2, H1] {
assert!(c6.has_square(&square)); }
}
for square in Square::iter() {
assert!(!queen_pattern(square).has_square(square));
}
}
#[test]
fn check_pawn_pseudo_moves() {
{
let a1 = Bitboard::from(A1);
let a1_moves = pawn_pushes(a1, Color::Black);
assert_eq!(a1_moves.count_squares(), 0);
}
{
let a2 = Bitboard::from(A2);
let a2_moves = pawn_pushes(a2, Color::White);
assert_eq!(a2_moves.count_squares(), 2);
assert!(a2_moves.has_square(A3));
assert!(a2_moves.has_square(A4));
let a2_moves = pawn_pushes(a2, Color::Black);
assert_eq!(a2_moves.count_squares(), 1);
assert!(a2_moves.has_square(A1));
}
{
let f3 = Bitboard::from(F3);
let f3_moves = pawn_pushes(f3, Color::White);
assert_eq!(f3_moves.count_squares(), 1);
assert!(f3_moves.has_square(F4));
let f3_moves = pawn_pushes(f3, Color::Black);
assert_eq!(f3_moves.count_squares(), 1);
assert!(f3_moves.has_square(F2));
}
{
let h7 = Bitboard::from(H7);
let h7_moves = pawn_pushes(h7, Color::White);
assert_eq!(h7_moves.count_squares(), 1);
assert!(h7_moves.has_square(H8));
let h7_moves = pawn_pushes(h7, Color::Black);
assert_eq!(h7_moves.count_squares(), 2);
assert!(h7_moves.has_square(H6));
assert!(h7_moves.has_square(H5));
}
{
let pawns = Bitboard::from(vec![B2, C3, F7, H8].as_slice());
let w_pawn_moves = pawn_pushes(pawns, Color::White);
assert_eq!(w_pawn_moves.count_squares(), 4);
assert!(w_pawn_moves.has_square(B3));
assert!(w_pawn_moves.has_square(B4));
assert!(w_pawn_moves.has_square(C4));
assert!(w_pawn_moves.has_square(F8));
let b_pawn_moves = pawn_pushes(pawns, Color::Black);
assert_eq!(b_pawn_moves.count_squares(), 5);
assert!(b_pawn_moves.has_square(B1));
assert!(b_pawn_moves.has_square(C2));
assert!(b_pawn_moves.has_square(F6));
assert!(b_pawn_moves.has_square(F5));
assert!(b_pawn_moves.has_square(H7));
}
for square in Square::iter() {
let pawn = Bitboard::from(square);
assert!(!pawn_pushes(pawn, Color::Black).has_square(square));
assert!(!pawn_pushes(pawn, Color::White).has_square(square));
}
}
#[test]
fn check_pawn_attacks() {
{
let c2 = Bitboard::from(C2);
let c2_attacks = pawn_attacks(c2, Color::White);
assert_eq!(c2_attacks.count_squares(), 2);
assert!(c2_attacks.has_square(B3));
assert!(c2_attacks.has_square(D3));
let c2_attacks = pawn_attacks(c2, Color::Black);
assert_eq!(c2_attacks.count_squares(), 2);
assert!(c2_attacks.has_square(B1));
assert!(c2_attacks.has_square(D1));
}
{
let a1 = Bitboard::from(A1);
let a1_attacks = pawn_attacks(a1, Color::White);
assert_eq!(a1_attacks.count_squares(), 1);
assert!(a1_attacks.has_square(B2));
let a1_attacks = pawn_attacks(a1, Color::Black);
assert_eq!(a1_attacks.count_squares(), 0);
}
}
}