chess-lib 0.1.3

A chess movement generator library.
Documentation
use crate::engine::common::{File, Rank, Square};

pub type Bitboard = u64;
pub type Direction = i8;

pub const EMPTY: Bitboard = 0;

pub const WHITE_PAWNS: Bitboard = 0b11111111 << 8;
pub const WHITE_ROOKS: Bitboard = 0b10000001;
pub const WHITE_KNIGHTS: Bitboard = 0b01000010;
pub const WHITE_BISHOPS: Bitboard = 0b00100100;
pub const WHITE_QUEENS: Bitboard = 0b00001000;
pub const WHITE_KING: Bitboard = 0b00010000;

pub const BLACK_PAWNS: Bitboard = 0b11111111 << (8 * 6);
pub const BLACK_ROOKS: Bitboard = 0b10000001 << (8 * 7);
pub const BLACK_KNIGHTS: Bitboard = 0b01000010 << (8 * 7);
pub const BLACK_BISHOPS: Bitboard = 0b00100100 << (8 * 7);
pub const BLACK_QUEENS: Bitboard = 0b00001000 << (8 * 7);
pub const BLACK_KING: Bitboard = 0b00010000 << (8 * 7);

pub const A_FILE: Bitboard = 0b0000000100000001000000010000000100000001000000010000000100000001;
pub const B_FILE: Bitboard = 0b0000001000000010000000100000001000000010000000100000001000000010;
pub const C_FILE: Bitboard = 0b0000010000000100000001000000010000000100000001000000010000000100;
pub const D_FILE: Bitboard = 0b0000100000001000000010000000100000001000000010000000100000001000;
pub const E_FILE: Bitboard = 0b0001000000010000000100000001000000010000000100000001000000010000;
pub const F_FILE: Bitboard = 0b0010000000100000001000000010000000100000001000000010000000100000;
pub const G_FILE: Bitboard = 0b0100000001000000010000000100000001000000010000000100000001000000;
pub const H_FILE: Bitboard = 0b1000000010000000100000001000000010000000100000001000000010000000;

pub const RANK_1: Bitboard = 0b11111111;
pub const RANK_2: Bitboard = 0b11111111 << 8;
pub const RANK_3: Bitboard = 0b11111111 << (8 * 2);
pub const RANK_4: Bitboard = 0b11111111 << (8 * 3);
pub const RANK_5: Bitboard = 0b11111111 << (8 * 4);
pub const RANK_6: Bitboard = 0b11111111 << (8 * 5);
pub const RANK_7: Bitboard = 0b11111111 << (8 * 6);
pub const RANK_8: Bitboard = 0b11111111 << (8 * 7);

pub const CASTLING_WHITE_KING_SQUARE: Bitboard = 0b01000000;
pub const CASTLING_WHITE_QUEEN_SQUARE: Bitboard = 0b00000100;
pub const CASTLING_BLACK_KING_SQUARE: Bitboard = 0b01000000 << (8 * 7);
pub const CASTLING_BLACK_QUEEN_SQUARE: Bitboard = 0b00000100 << (8 * 7);

pub const CASTLING_WHITE_KING_JUMP_SQUARES: Bitboard = 0b01100000;
pub const CASTLING_WHITE_QUEEN_JUMP_SQUARES: Bitboard = 0b00001100;
pub const CASTLING_BLACK_KING_JUMP_SQUARES: Bitboard = 0b01100000 << (8 * 7);
pub const CASTLING_BLACK_QUEEN_JUMP_SQUARES: Bitboard = 0b00001100 << (8 * 7);

pub const CASTLING_WHITE_KING_OCCUPIABLE_SQUARES: Bitboard = 0b01100000;
pub const CASTLING_WHITE_QUEEN_OCCUPIABLE_SQUARES: Bitboard = 0b00001110;
pub const CASTLING_BLACK_KING_OCCUPIABLE_SQUARES: Bitboard = 0b01100000 << (8 * 7);
pub const CASTLING_BLACK_QUEEN_OCCUPIABLE_SQUARES: Bitboard = 0b00001110 << (8 * 7);

pub const NORTH: Direction = 8;
pub const SOUTH: Direction = -8;
pub const EAST: Direction = 1;
pub const WEST: Direction = -1;
pub const NORTH_EAST: Direction = 9;
pub const NORTH_WEST: Direction = 7;
pub const SOUTH_EAST: Direction = -7;
pub const SOUTH_WEST: Direction = -9;

pub const DIRECTIONS: [Direction; 8] = [
    NORTH, SOUTH, EAST, WEST, NORTH_EAST, NORTH_WEST, SOUTH_EAST, SOUTH_WEST,
];

pub fn set_bit(bitboard: Bitboard, file: File, rank: Rank) -> Bitboard {
    bitboard | (0b1 << (rank.index() * 8 + file.index()))
}

pub fn get_single_piece_bitboard(bitboard: Bitboard, square: Square) -> Bitboard {
    let bit = 0b1 << (square.rank.index() * 8 + square.file.index());

    bitboard & bit
}

pub fn occupied_squares(bitboard: Bitboard) -> Vec<Square> {
    if bitboard == EMPTY {
        return Vec::with_capacity(0);
    }

    let mut squares = Vec::with_capacity(32);

    let mut bb = bitboard;
    let mut index = 0;

    while bb != 0 {
        if (bb & 1) != 0 {
            let rank = Rank::from_index(index / 8 + 1);
            let file = File::from_index(index % 8 + 1);
            squares.push(Square { file, rank });
        }

        bb >>= 1;
        index += 1;
    }

    squares
}

pub fn to_square(bitboard: Bitboard) -> Square {
    let rank = Rank::from_index((bitboard.trailing_zeros() / 8) as i8);
    let file = File::from_index((bitboard.trailing_zeros() % 8) as i8);

    Square { file, rank }
}

pub fn popcnt(bitboard: Bitboard) -> u32 {
    bitboard.count_ones()
}

pub fn is_empty(bitboard: Bitboard) -> bool {
    bitboard == EMPTY
}

pub fn is_occupied(bitboard: Bitboard, square: Square) -> bool {
    !is_empty(bitboard & square.bitboard())
}

pub fn is_diagonal(direction: Direction) -> bool {
    direction == NORTH_EAST
        || direction == NORTH_WEST
        || direction == SOUTH_EAST
        || direction == SOUTH_WEST
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_set_bit() {
        let bitboard = 0;
        let expected = 0b1 << (8 * 4 + 3);

        let result = set_bit(bitboard, File::D, Rank::Five);

        assert_eq!(result, expected);
    }
}