<commit_before>//! Generates look-up tables and implements look-up methods.

use rand::{Rng, thread_rng};
use basetypes::*;
use position::bitsets::*;


/// Look-up tables and look-up methods for move generation.
pub struct BoardGeometry {
    grid: [u8; 120],
    piece_grid_deltas: [[i8; 8]; 5],
    piece_longrange: [bool; 5],

    /// Contains attack bitboards for each piece on each possible
    /// square.
    /// 
    /// # Examples
    ///
    /// ```text
    /// g.attacks[QUEEN][D4]        g.attacks[KNIGHT][D4] 
    /// . . . 1 . . . 1             . . . . . . . .       
    /// 1 . . 1 . . 1 .             . . . . . . . .       
    /// . 1 . 1 . 1 . .             . . 1 . 1 . . .       
    /// . . 1 1 1 . . .             . 1 . . . 1 . .       
    /// 1 1 1 Q 1 1 1 1             . . . N . . . .       
    /// . . 1 1 1 . . .             . 1 . . . 1 . .       
    /// . 1 . 1 . 1 . .             . . 1 . 1 . . .       
    /// 1 . . 1 . . 1 .             . . . . . . . .       
    /// ```
    attacks: [[Bitboard; 64]; 5],

    /// Contains "blockers and beyond" bitboards for each piece on
    /// each possible square.
    ///
    /// # Examples:
    ///
    /// ```text
    /// g.blockers_and_beyond[KNIGHT][D4]  g.blockers_and_beyond[QUEEN][D4]
    /// . . . . . . . .                    . . . . . . . .
    /// . . . . . . . .                    . . . 1 . . 1 .
    /// . . . . . . . .                    . 1 . 1 . 1 . .
    /// . . . . . . . .                    . . 1 1 1 . . .
    /// . . . N . . . .                    . 1 1 Q 1 1 1 .
    /// . . . . . . . .                    . . 1 1 1 . . .
    /// . . . . . . . .                    . 1 . 1 . 1 . .
    /// . . . . . . . .                    . . . . . . . .
    /// ```
    blockers_and_beyond: [[Bitboard; 64]; 5],

    /// Contains bitboards with all squares lying at the line
    /// determined by two squares.
    ///
    /// # Examples
    ///
    /// ```text
    /// g.squares_at_line[B2][F6]
    /// . . . . . . . 1
    /// . . . . . . 1 .
    /// . . . . . 1 . .
    /// . . . . 1 . . .
    /// . . . 1 . . . .
    /// . . 1 . . . . .
    /// . 1 . . . . . .
    /// 1 . . . . . . .
    /// ```
    pub squares_at_line: [[Bitboard; 64]; 64],

    /// Contains bitboards with all squares lying between two squares
    /// including the two squares themselves.
    ///
    /// # Examples
    ///
    /// ```text
    /// g.squares_between_including[B2][F6]
    /// . . . . . . . .
    /// . . . . . . . .
    /// . . . . . 1 . .
    /// . . . . 1 . . .
    /// . . . 1 . . . .
    /// . . 1 . . . . .
    /// . 1 . . . . . .
    /// . . . . . . . .
    /// ```
    pub squares_between_including: [[Bitboard; 64]; 64],

    /// Contains bitboards with all squares hidden behind a blocker
    /// from the attacker's position.
    ///
    /// # Examples:
    /// 
    /// ```text
    /// g.squares_behind_blocker[B2][F6]
    /// . . . . . . . 1
    /// . . . . . . 1 .
    /// . . . . . B . .
    /// . . . . . . . .
    /// . . . . . . . .
    /// . . . . . . . .
    /// . A . . . . . .
    /// . . . . . . . .
    /// ```
    pub squares_behind_blocker: [[Bitboard; 64]; 64],
}


impl BoardGeometry {
    /// Creates and initializes a new instance.
    pub fn new() -> BoardGeometry {
        unsafe {
            init_magics();
        }

        // We use 10x12 grid (8x8 with guarding markers, 2 at top and
        // bottom, 1 at the sides), so that we can detect out-of-board
        // movements. Each cell in the grid contains the corresponding
        // square number (from 0 to 63) or 0xff (the guarding marker).
        let mut grid = [0xffu8; 120];
        for i in 0..64 {
            grid[BoardGeometry::grid_index(i)] = i as u8;
        }

        // "piece_deltas" represent the change in the grid-index when
        // sliding a particular piece by one square in a particular
        // direction. We are not concerned with pawns here.
        let mut piece_grid_deltas = [[0i8; 8]; 5];
        piece_grid_deltas[QUEEN] = [-11, -10, -9, -1, 1, 9, 10, 11];
        piece_grid_deltas[ROOK] = [0, -10, 0, -1, 1, 0, 10, 0];
        piece_grid_deltas[BISHOP] = [-11, 0, -9, 0, 0, 9, 0, 11];
        piece_grid_deltas[KNIGHT] = [-21, -19, -12, -8, 8, 12, 19, 21];
        piece_grid_deltas[KING] = [-11, -10, -9, -1, 1, 9, 10, 11];

        // All pieces except knights and kings are long-range (They
        // can slide by more than one square). We are not concerned
        // with pawns here.
        let mut piece_longrange = [true; 5];
        piece_longrange[KNIGHT] = false;
        piece_longrange[KING] = false;

        let mut bg = BoardGeometry {
            grid: grid,
            piece_grid_deltas: piece_grid_deltas,
            piece_longrange: piece_longrange,
            attacks: [[0; 64]; 5],
            blockers_and_beyond: [[0; 64]; 5],
            squares_at_line: [[0; 64]; 64],
            squares_between_including: [[0; 64]; 64],
            squares_behind_blocker: [[0; 64]; 64],
        };

        bg.fill_attack_and_blockers_and_beyond_arrays();
        bg.fill_squares_between_including_and_squares_behind_blocker_arrays();
        bg.fill_squares_at_line_array();
        bg
    }

    /// Returns a reference to an initialized `BoardGeometry` object.
    ///
    /// The object is created only during the first call. All next
    /// calls will return a reference to the same object. This is done
    /// in a thread-safe manner.
    pub fn get() -> &'static BoardGeometry {
        use std::sync::{Once, ONCE_INIT};
        static INIT_GEOMETRY: Once = ONCE_INIT;
        static mut geometry: Option<BoardGeometry> = None;
        unsafe {
            INIT_GEOMETRY.call_once(|| {
                geometry = Some(BoardGeometry::new());
            });
            geometry.as_ref().unwrap()
        }
    }

    /// Returns the set of squares that are attacked by a piece (not a
    /// pawn).
    ///
    /// This function returns the set of squares that are attacked by
    /// a piece of type `piece` from the square `from_square`, on a
    /// board which is occupied with other pieces according to the
    /// `occupied` bitboard.
    ///
    /// # Safety
    ///
    /// This method is unsafe because it is extremely
    /// performace-critical, and so it does unchecked array
    /// accesses. Users of this method should make sure that:
    ///
    /// * `piece < PAWN`.
    /// * `from_square <= 63`.
    #[cfg(target_pointer_width = "64")]
    #[inline]
    pub unsafe fn piece_attacks_from(&self,
                                     occupied: Bitboard,
                                     piece: PieceType,
                                     from_square: Square)
                                     -> Bitboard {
        assert!(piece < PAWN);
        assert!(from_square <= 63);
        match piece {
            KING => king_attacks(from_square),
            QUEEN => queen_attacks(from_square, occupied),
            ROOK => rook_attacks(from_square, occupied),
            BISHOP => bishop_attacks(from_square, occupied),
            _ => knight_attacks(from_square),
        }
    }

    /// Returns the set of squares that are attacked by a piece (not a
    /// pawn).
    ///
    /// This function returns the set of squares that are attacked by
    /// a piece of type `piece` from the square `from_square`, on a
    /// board which is occupied with other pieces according to the
    /// `occupied` bitboard.
    ///
    /// # Safety
    ///
    /// This method is unsafe because it is extremely
    /// performace-critical, and so it does unchecked array
    /// accesses. Users of this method should make sure that:
    ///
    /// * `piece < PAWN`.
    /// * `from_square <= 63`.
    #[cfg(target_pointer_width = "32")]
    #[inline]
    pub unsafe fn piece_attacks_from(&self,
                                     occupied: Bitboard,
                                     piece: PieceType,
                                     from_square: Square)
                                     -> Bitboard {
        assert!(piece < PAWN);
        assert!(from_square <= 63);
        let behind: &[Bitboard; 64] = self.squares_behind_blocker.get_unchecked(from_square);
        let mut attacks = *self.attacks.get_unchecked(piece).get_unchecked(from_square);
        let mut blockers = occupied &
                           *self.blockers_and_beyond
                                .get_unchecked(piece)
                                .get_unchecked(from_square);
        while blockers != BB_EMPTY_SET {
            attacks &= !*behind.get_unchecked(bitscan_forward_and_reset(&mut blockers));
        }
        attacks
    }

    fn grid_index(i: Square) -> usize {
        ((i / 8) * 10 + (i % 8) + 21)
    }

    fn fill_attack_and_blockers_and_beyond_arrays(&mut self) {
        for piece in 0..5 {
            for square in 0..64 {
                let mut attack = 0u64;
                let mut blockers = 0u64;
                for move_direction in 0..8 {
                    let delta = self.piece_grid_deltas[piece][move_direction];
                    if delta != 0 {
                        let mut last_mask = 0u64;
                        let mut curr_grid_index = BoardGeometry::grid_index(square);
                        loop {
                            curr_grid_index = (curr_grid_index as i8 + delta) as usize;
                            let curr_square = self.grid[curr_grid_index] as Square;
                            if curr_square != 0xff {
                                last_mask = 1 << curr_square;
                                attack |= last_mask;
                                blockers |= last_mask;
                                if self.piece_longrange[piece] {
                                    continue;
                                }
                            }
                            blockers &= !last_mask;
                            break;
                        }
                    }
                }
                self.attacks[piece][square] = attack;
                self.blockers_and_beyond[piece][square] = blockers;
            }
        }
    }

    fn fill_squares_between_including_and_squares_behind_blocker_arrays(&mut self) {
        for attacker in 0..64 {
            for blocker in 0..64 {
                // Try to find a grid-index increment (delta) that
                // will generate all squares at the line. If the
                // attacker and the blocker happens not to lie at a
                // straight line, then and we simply proceed to the
                // next attacker/blocker pair.
                let rank_diff = rank(blocker) as i8 - rank(attacker) as i8;
                let file_diff = file(blocker) as i8 - file(attacker) as i8;
                let delta = match (rank_diff, file_diff) {
                    (0, 0) => continue,
                    (0, f) => f.signum(),
                    (r, 0) => 10 * r.signum(),
                    (r, f) if r == f => 10 * r.signum() + r.signum(),
                    (r, f) if r == -f => 10 * r.signum() - r.signum(),
                    _ => continue,
                };

                // Starting from the attacker's square update
                // "squares_between_including" until the blocker's
                // square is encountered, then switch to updating
                // "squares_behind_blocker" until the end of the board
                // is reached.
                let mut squares_between_including = 0u64;
                let mut squares_behind_blocker = 0u64;
                let mut curr_grid_index = BoardGeometry::grid_index(attacker);
                let mut blocker_encountered = false;
                loop {
                    let curr_square = self.grid[curr_grid_index] as Square;
                    match curr_square {
                        0xff => {
                            break;
                        }
                        x if x == blocker => {
                            squares_between_including |= 1 << curr_square;
                            blocker_encountered = true;
                        }
                        _ => {
                            if blocker_encountered {
                                squares_behind_blocker |= 1 << curr_square;
                            } else {
                                squares_between_including |= 1 << curr_square;
                            }
                        }
                    }
                    curr_grid_index = (curr_grid_index as i8 + delta) as usize;
                }
                assert!(blocker_encountered);
                self.squares_between_including[attacker][blocker] = squares_between_including;
                self.squares_behind_blocker[attacker][blocker] = squares_behind_blocker;
            }
        }
    }

    fn fill_squares_at_line_array(&mut self) {
        for a in 0..64 {
            for b in 0..64 {
                self.squares_at_line[a][b] = self.squares_between_including[a][b] |
                                             self.squares_behind_blocker[a][b] |
                                             self.squares_behind_blocker[b][a];
            }
        }
    }
}


/// Loop-up tables for calculating Zobrist hashes.
///
/// Zobrist Hashing is a technique to transform a board position of
/// arbitrary size into a number of a set length, with an equal
/// distribution over all possible numbers, invented by Albert
/// Zobrist.  The main purpose of Zobrist hash codes in chess
/// programming is to get an almost unique index number for any chess
/// position, with a very important requirement that two similar
/// positions generate entirely different indices. These index numbers
/// are used for faster and more space efficient hash tables or
/// databases, e.g. transposition tables and opening books.
pub struct ZobristArrays {
    /// The constant with which the hash value should be XOR-ed when
    /// the side to move changes.
    pub to_move: u64,

    /// Constants with which the hash value should be XOR-ed when a
    /// piece of given color on a given square appears/disappears.
    pub pieces: [[[u64; 64]; 6]; 2],

    /// Constants with which the hash value should be XOR-ed, for the
    /// old and the new castling rights on each move.
    pub castling: [u64; 16],

    /// Constants with which the hash value should be XOR-ed, for the
    /// old and the new en-passant file on each move.  Only the first
    /// 8 indexes are used -- the rest exist for memory safety
    /// reasons, and are set to `0`.
    pub en_passant: [u64; 16],

    /// Derived from the `pieces` field. Contains the constants with
    /// which the Zobrist hash value should be XOR-ed to reflect the
    /// movement of the rook during castling.
    pub castling_rook_move: [[u64; 2]; 2],
}


impl ZobristArrays {
    /// Creates and initializes a new instance.
    pub fn new() -> ZobristArrays {
        use rand::{Rng, SeedableRng};
        use rand::isaac::Isaac64Rng;

        let seed: &[_] = &[1, 2, 3, 4];
        let mut rng: Isaac64Rng = SeedableRng::from_seed(seed);

        let to_move = rng.gen();
        let mut pieces = [[[0; 64]; 6]; 2];
        let mut castling = [0; 16];
        let mut en_passant = [0; 16];
        let mut castling_rook_move = [[0; 2]; 2];

        for color in 0..2 {
            for piece in 0..6 {
                for square in 0..64 {
                    pieces[color][piece][square] = rng.gen();
                }
            }
        }

        for value in 0..16 {
            castling[value] = rng.gen();
        }

        for file in 0..8 {
            en_passant[file] = rng.gen();
        }

        castling_rook_move[WHITE][QUEENSIDE] = pieces[WHITE][ROOK][A1] ^ pieces[WHITE][ROOK][D1];
        castling_rook_move[WHITE][KINGSIDE] = pieces[WHITE][ROOK][H1] ^ pieces[WHITE][ROOK][F1];
        castling_rook_move[BLACK][QUEENSIDE] = pieces[BLACK][ROOK][A8] ^ pieces[BLACK][ROOK][D8];
        castling_rook_move[BLACK][KINGSIDE] = pieces[BLACK][ROOK][H8] ^ pieces[BLACK][ROOK][F8];

        ZobristArrays {
            to_move: to_move,
            pieces: pieces,
            castling: castling,
            en_passant: en_passant,
            castling_rook_move: castling_rook_move,
        }
    }

    /// Returns a reference to an initialized `ZobristArrays` object.
    ///
    /// The object is created only during the first call. All next
    /// calls will return a reference to the same object. This is done
    /// in a thread-safe manner.
    pub fn get() -> &'static ZobristArrays {
        use std::sync::{Once, ONCE_INIT};
        static INIT_ARRAYS: Once = ONCE_INIT;
        static mut arrays: Option<ZobristArrays> = None;
        unsafe {
            INIT_ARRAYS.call_once(|| {
                arrays = Some(ZobristArrays::new());
            });
            arrays.as_ref().unwrap()
        }
    }
}


/// Reverse the bits in a 64 bit number using a recursive algorithm
/// which swaps the order of sub-elements, starting with even and odd bits
pub fn reverse(mut v: u64) -> u64 {
    v = ((v >> 1) & 0x5555555555555555) | ((v & 0x5555555555555555) << 1);
    v = ((v >> 2) & 0x3333333333333333) | ((v & 0x3333333333333333) << 2);
    v = ((v >> 4) & 0x0F0F0F0F0F0F0F0F) | ((v & 0x0F0F0F0F0F0F0F0F) << 4);
    v = ((v >> 8) & 0x00FF00FF00FF00FF) | ((v & 0x00FF00FF00FF00FF) << 8);
    v = ((v >> 16) & 0x0000FFFF0000FFFF) | ((v & 0x0000FFFF0000FFFF) << 16);
    ((v >> 32) & 0x00000000FFFFFFFF) | ((v & 0x00000000FFFFFFFF) << 32)
}

/// Calculate sliding piece moves for a given occupancy and mask
fn get_line_attacks(piece: Bitboard, occupied: Bitboard, line: Bitboard) -> Bitboard {
    let potential_blockers = occupied & line;
    let forward = potential_blockers.wrapping_sub(piece.wrapping_mul(2));
    let rev = reverse(reverse(potential_blockers).wrapping_sub(reverse(piece).wrapping_mul(2)));
    (forward ^ rev) & line
}

fn get_rook_attacks(piece: Bitboard, from_square: Square, occupied: Bitboard) -> Bitboard {
    get_line_attacks(piece, occupied, bb_file(from_square)) |
    get_line_attacks(piece, occupied, bb_rank(from_square))
}

fn get_bishop_attacks(piece: Bitboard, from_square: Square, occupied: Bitboard) -> Bitboard {
    get_line_attacks(piece, occupied, bb_diag(from_square)) |
    get_line_attacks(piece, occupied, bb_anti_diag(from_square))
}

// Helper functions for `piece_attacks_from`.
#[inline(always)]
unsafe fn knight_attacks(from_square: Square) -> Bitboard {
    *KNIGHT_MAP.get_unchecked(from_square)
}

#[inline(always)]
unsafe fn king_attacks(from_square: Square) -> Bitboard {
    *KING_MAP.get_unchecked(from_square)
}

#[inline(always)]
unsafe fn bishop_attacks(from_square: Square, occupied: Bitboard) -> Bitboard {
    BISHOP_MAP.get_unchecked(from_square).att(occupied)
}

#[inline(always)]
unsafe fn rook_attacks(from_square: Square, occupied: Bitboard) -> Bitboard {
    ROOK_MAP.get_unchecked(from_square).att(occupied)
}<commit_msg>style<commit_after>//! Generates look-up tables and implements look-up methods.

use rand::{Rng, thread_rng};
use basetypes::*;
use position::bitsets::*;


/// Look-up tables and look-up methods for move generation.
pub struct BoardGeometry {
    grid: [u8; 120],
    piece_grid_deltas: [[i8; 8]; 5],
    piece_longrange: [bool; 5],

    /// Contains attack bitboards for each piece on each possible
    /// square.
    /// 
    /// # Examples
    ///
    /// ```text
    /// g.attacks[QUEEN][D4]        g.attacks[KNIGHT][D4] 
    /// . . . 1 . . . 1             . . . . . . . .       
    /// 1 . . 1 . . 1 .             . . . . . . . .       
    /// . 1 . 1 . 1 . .             . . 1 . 1 . . .       
    /// . . 1 1 1 . . .             . 1 . . . 1 . .       
    /// 1 1 1 Q 1 1 1 1             . . . N . . . .       
    /// . . 1 1 1 . . .             . 1 . . . 1 . .       
    /// . 1 . 1 . 1 . .             . . 1 . 1 . . .       
    /// 1 . . 1 . . 1 .             . . . . . . . .       
    /// ```
    attacks: [[Bitboard; 64]; 5],

    /// Contains "blockers and beyond" bitboards for each piece on
    /// each possible square.
    ///
    /// # Examples:
    ///
    /// ```text
    /// g.blockers_and_beyond[KNIGHT][D4]  g.blockers_and_beyond[QUEEN][D4]
    /// . . . . . . . .                    . . . . . . . .
    /// . . . . . . . .                    . . . 1 . . 1 .
    /// . . . . . . . .                    . 1 . 1 . 1 . .
    /// . . . . . . . .                    . . 1 1 1 . . .
    /// . . . N . . . .                    . 1 1 Q 1 1 1 .
    /// . . . . . . . .                    . . 1 1 1 . . .
    /// . . . . . . . .                    . 1 . 1 . 1 . .
    /// . . . . . . . .                    . . . . . . . .
    /// ```
    blockers_and_beyond: [[Bitboard; 64]; 5],

    /// Contains bitboards with all squares lying at the line
    /// determined by two squares.
    ///
    /// # Examples
    ///
    /// ```text
    /// g.squares_at_line[B2][F6]
    /// . . . . . . . 1
    /// . . . . . . 1 .
    /// . . . . . 1 . .
    /// . . . . 1 . . .
    /// . . . 1 . . . .
    /// . . 1 . . . . .
    /// . 1 . . . . . .
    /// 1 . . . . . . .
    /// ```
    pub squares_at_line: [[Bitboard; 64]; 64],

    /// Contains bitboards with all squares lying between two squares
    /// including the two squares themselves.
    ///
    /// # Examples
    ///
    /// ```text
    /// g.squares_between_including[B2][F6]
    /// . . . . . . . .
    /// . . . . . . . .
    /// . . . . . 1 . .
    /// . . . . 1 . . .
    /// . . . 1 . . . .
    /// . . 1 . . . . .
    /// . 1 . . . . . .
    /// . . . . . . . .
    /// ```
    pub squares_between_including: [[Bitboard; 64]; 64],

    /// Contains bitboards with all squares hidden behind a blocker
    /// from the attacker's position.
    ///
    /// # Examples:
    /// 
    /// ```text
    /// g.squares_behind_blocker[B2][F6]
    /// . . . . . . . 1
    /// . . . . . . 1 .
    /// . . . . . B . .
    /// . . . . . . . .
    /// . . . . . . . .
    /// . . . . . . . .
    /// . A . . . . . .
    /// . . . . . . . .
    /// ```
    pub squares_behind_blocker: [[Bitboard; 64]; 64],
}


impl BoardGeometry {
    /// Creates and initializes a new instance.
    pub fn new() -> BoardGeometry {
        unsafe {
            init_magics();
        }

        // We use 10x12 grid (8x8 with guarding markers, 2 at top and
        // bottom, 1 at the sides), so that we can detect out-of-board
        // movements. Each cell in the grid contains the corresponding
        // square number (from 0 to 63) or 0xff (the guarding marker).
        let mut grid = [0xffu8; 120];
        for i in 0..64 {
            grid[BoardGeometry::grid_index(i)] = i as u8;
        }

        // "piece_deltas" represent the change in the grid-index when
        // sliding a particular piece by one square in a particular
        // direction. We are not concerned with pawns here.
        let mut piece_grid_deltas = [[0i8; 8]; 5];
        piece_grid_deltas[QUEEN] = [-11, -10, -9, -1, 1, 9, 10, 11];
        piece_grid_deltas[ROOK] = [0, -10, 0, -1, 1, 0, 10, 0];
        piece_grid_deltas[BISHOP] = [-11, 0, -9, 0, 0, 9, 0, 11];
        piece_grid_deltas[KNIGHT] = [-21, -19, -12, -8, 8, 12, 19, 21];
        piece_grid_deltas[KING] = [-11, -10, -9, -1, 1, 9, 10, 11];

        // All pieces except knights and kings are long-range (They
        // can slide by more than one square). We are not concerned
        // with pawns here.
        let mut piece_longrange = [true; 5];
        piece_longrange[KNIGHT] = false;
        piece_longrange[KING] = false;

        let mut bg = BoardGeometry {
            grid: grid,
            piece_grid_deltas: piece_grid_deltas,
            piece_longrange: piece_longrange,
            attacks: [[0; 64]; 5],
            blockers_and_beyond: [[0; 64]; 5],
            squares_at_line: [[0; 64]; 64],
            squares_between_including: [[0; 64]; 64],
            squares_behind_blocker: [[0; 64]; 64],
        };

        bg.fill_attack_and_blockers_and_beyond_arrays();
        bg.fill_squares_between_including_and_squares_behind_blocker_arrays();
        bg.fill_squares_at_line_array();
        bg
    }

    /// Returns a reference to an initialized `BoardGeometry` object.
    ///
    /// The object is created only during the first call. All next
    /// calls will return a reference to the same object. This is done
    /// in a thread-safe manner.
    pub fn get() -> &'static BoardGeometry {
        use std::sync::{Once, ONCE_INIT};
        static INIT_GEOMETRY: Once = ONCE_INIT;
        static mut geometry: Option<BoardGeometry> = None;
        unsafe {
            INIT_GEOMETRY.call_once(|| {
                geometry = Some(BoardGeometry::new());
            });
            geometry.as_ref().unwrap()
        }
    }

    /// Returns the set of squares that are attacked by a piece (not a
    /// pawn).
    ///
    /// This function returns the set of squares that are attacked by
    /// a piece of type `piece` from the square `from_square`, on a
    /// board which is occupied with other pieces according to the
    /// `occupied` bitboard.
    ///
    /// # Safety
    ///
    /// This method is unsafe because it is extremely
    /// performace-critical, and so it does unchecked array
    /// accesses. Users of this method should make sure that:
    ///
    /// * `piece < PAWN`.
    /// * `from_square <= 63`.
    #[cfg(target_pointer_width = "64")]
    #[inline]
    pub unsafe fn piece_attacks_from(&self,
                                     occupied: Bitboard,
                                     piece: PieceType,
                                     from_square: Square)
                                     -> Bitboard {
        assert!(piece < PAWN);
        assert!(from_square <= 63);
        match piece {
            KING => king_attacks(from_square),
            QUEEN => queen_attacks(from_square, occupied),
            ROOK => rook_attacks(from_square, occupied),
            BISHOP => bishop_attacks(from_square, occupied),
            _ => knight_attacks(from_square),
        }
    }

    /// Returns the set of squares that are attacked by a piece (not a
    /// pawn).
    ///
    /// This function returns the set of squares that are attacked by
    /// a piece of type `piece` from the square `from_square`, on a
    /// board which is occupied with other pieces according to the
    /// `occupied` bitboard.
    ///
    /// # Safety
    ///
    /// This method is unsafe because it is extremely
    /// performace-critical, and so it does unchecked array
    /// accesses. Users of this method should make sure that:
    ///
    /// * `piece < PAWN`.
    /// * `from_square <= 63`.
    #[cfg(target_pointer_width = "32")]
    #[inline]
    pub unsafe fn piece_attacks_from(&self,
                                     occupied: Bitboard,
                                     piece: PieceType,
                                     from_square: Square)
                                     -> Bitboard {
        assert!(piece < PAWN);
        assert!(from_square <= 63);
        let behind: &[Bitboard; 64] = self.squares_behind_blocker.get_unchecked(from_square);
        let mut attacks = *self.attacks.get_unchecked(piece).get_unchecked(from_square);
        let mut blockers = occupied &
                           *self.blockers_and_beyond
                                .get_unchecked(piece)
                                .get_unchecked(from_square);
        while blockers != BB_EMPTY_SET {
            attacks &= !*behind.get_unchecked(bitscan_forward_and_reset(&mut blockers));
        }
        attacks
    }

    fn grid_index(i: Square) -> usize {
        ((i / 8) * 10 + (i % 8) + 21)
    }

    fn fill_attack_and_blockers_and_beyond_arrays(&mut self) {
        for piece in 0..5 {
            for square in 0..64 {
                let mut attack = 0u64;
                let mut blockers = 0u64;
                for move_direction in 0..8 {
                    let delta = self.piece_grid_deltas[piece][move_direction];
                    if delta != 0 {
                        let mut last_mask = 0u64;
                        let mut curr_grid_index = BoardGeometry::grid_index(square);
                        loop {
                            curr_grid_index = (curr_grid_index as i8 + delta) as usize;
                            let curr_square = self.grid[curr_grid_index] as Square;
                            if curr_square != 0xff {
                                last_mask = 1 << curr_square;
                                attack |= last_mask;
                                blockers |= last_mask;
                                if self.piece_longrange[piece] {
                                    continue;
                                }
                            }
                            blockers &= !last_mask;
                            break;
                        }
                    }
                }
                self.attacks[piece][square] = attack;
                self.blockers_and_beyond[piece][square] = blockers;
            }
        }
    }

    fn fill_squares_between_including_and_squares_behind_blocker_arrays(&mut self) {
        for attacker in 0..64 {
            for blocker in 0..64 {
                // Try to find a grid-index increment (delta) that
                // will generate all squares at the line. If the
                // attacker and the blocker happens not to lie at a
                // straight line, then and we simply proceed to the
                // next attacker/blocker pair.
                let rank_diff = rank(blocker) as i8 - rank(attacker) as i8;
                let file_diff = file(blocker) as i8 - file(attacker) as i8;
                let delta = match (rank_diff, file_diff) {
                    (0, 0) => continue,
                    (0, f) => f.signum(),
                    (r, 0) => 10 * r.signum(),
                    (r, f) if r == f => 10 * r.signum() + r.signum(),
                    (r, f) if r == -f => 10 * r.signum() - r.signum(),
                    _ => continue,
                };

                // Starting from the attacker's square update
                // "squares_between_including" until the blocker's
                // square is encountered, then switch to updating
                // "squares_behind_blocker" until the end of the board
                // is reached.
                let mut squares_between_including = 0u64;
                let mut squares_behind_blocker = 0u64;
                let mut curr_grid_index = BoardGeometry::grid_index(attacker);
                let mut blocker_encountered = false;
                loop {
                    let curr_square = self.grid[curr_grid_index] as Square;
                    match curr_square {
                        0xff => {
                            break;
                        }
                        x if x == blocker => {
                            squares_between_including |= 1 << curr_square;
                            blocker_encountered = true;
                        }
                        _ => {
                            if blocker_encountered {
                                squares_behind_blocker |= 1 << curr_square;
                            } else {
                                squares_between_including |= 1 << curr_square;
                            }
                        }
                    }
                    curr_grid_index = (curr_grid_index as i8 + delta) as usize;
                }
                assert!(blocker_encountered);
                self.squares_between_including[attacker][blocker] = squares_between_including;
                self.squares_behind_blocker[attacker][blocker] = squares_behind_blocker;
            }
        }
    }

    fn fill_squares_at_line_array(&mut self) {
        for a in 0..64 {
            for b in 0..64 {
                self.squares_at_line[a][b] = self.squares_between_including[a][b] |
                                             self.squares_behind_blocker[a][b] |
                                             self.squares_behind_blocker[b][a];
            }
        }
    }
}


/// Loop-up tables for calculating Zobrist hashes.
///
/// Zobrist Hashing is a technique to transform a board position of
/// arbitrary size into a number of a set length, with an equal
/// distribution over all possible numbers, invented by Albert
/// Zobrist.  The main purpose of Zobrist hash codes in chess
/// programming is to get an almost unique index number for any chess
/// position, with a very important requirement that two similar
/// positions generate entirely different indices. These index numbers
/// are used for faster and more space efficient hash tables or
/// databases, e.g. transposition tables and opening books.
pub struct ZobristArrays {
    /// The constant with which the hash value should be XOR-ed when
    /// the side to move changes.
    pub to_move: u64,

    /// Constants with which the hash value should be XOR-ed when a
    /// piece of given color on a given square appears/disappears.
    pub pieces: [[[u64; 64]; 6]; 2],

    /// Constants with which the hash value should be XOR-ed, for the
    /// old and the new castling rights on each move.
    pub castling: [u64; 16],

    /// Constants with which the hash value should be XOR-ed, for the
    /// old and the new en-passant file on each move.  Only the first
    /// 8 indexes are used -- the rest exist for memory safety
    /// reasons, and are set to `0`.
    pub en_passant: [u64; 16],

    /// Derived from the `pieces` field. Contains the constants with
    /// which the Zobrist hash value should be XOR-ed to reflect the
    /// movement of the rook during castling.
    pub castling_rook_move: [[u64; 2]; 2],
}


impl ZobristArrays {
    /// Creates and initializes a new instance.
    pub fn new() -> ZobristArrays {
        use rand::{Rng, SeedableRng};
        use rand::isaac::Isaac64Rng;

        let seed: &[_] = &[1, 2, 3, 4];
        let mut rng: Isaac64Rng = SeedableRng::from_seed(seed);

        let to_move = rng.gen();
        let mut pieces = [[[0; 64]; 6]; 2];
        let mut castling = [0; 16];
        let mut en_passant = [0; 16];
        let mut castling_rook_move = [[0; 2]; 2];

        for color in 0..2 {
            for piece in 0..6 {
                for square in 0..64 {
                    pieces[color][piece][square] = rng.gen();
                }
            }
        }

        for value in 0..16 {
            castling[value] = rng.gen();
        }

        for file in 0..8 {
            en_passant[file] = rng.gen();
        }

        castling_rook_move[WHITE][QUEENSIDE] = pieces[WHITE][ROOK][A1] ^ pieces[WHITE][ROOK][D1];
        castling_rook_move[WHITE][KINGSIDE] = pieces[WHITE][ROOK][H1] ^ pieces[WHITE][ROOK][F1];
        castling_rook_move[BLACK][QUEENSIDE] = pieces[BLACK][ROOK][A8] ^ pieces[BLACK][ROOK][D8];
        castling_rook_move[BLACK][KINGSIDE] = pieces[BLACK][ROOK][H8] ^ pieces[BLACK][ROOK][F8];

        ZobristArrays {
            to_move: to_move,
            pieces: pieces,
            castling: castling,
            en_passant: en_passant,
            castling_rook_move: castling_rook_move,
        }
    }

    /// Returns a reference to an initialized `ZobristArrays` object.
    ///
    /// The object is created only during the first call. All next
    /// calls will return a reference to the same object. This is done
    /// in a thread-safe manner.
    pub fn get() -> &'static ZobristArrays {
        use std::sync::{Once, ONCE_INIT};
        static INIT_ARRAYS: Once = ONCE_INIT;
        static mut arrays: Option<ZobristArrays> = None;
        unsafe {
            INIT_ARRAYS.call_once(|| {
                arrays = Some(ZobristArrays::new());
            });
            arrays.as_ref().unwrap()
        }
    }
}


// Reverse the bits in a 64 bit number using a recursive algorithm
// which swaps the order of sub-elements, starting with even and odd
// bits
fn reverse(mut v: u64) -> u64 {
    v = ((v >> 1) & 0x5555555555555555) | ((v & 0x5555555555555555) << 1);
    v = ((v >> 2) & 0x3333333333333333) | ((v & 0x3333333333333333) << 2);
    v = ((v >> 4) & 0x0F0F0F0F0F0F0F0F) | ((v & 0x0F0F0F0F0F0F0F0F) << 4);
    v = ((v >> 8) & 0x00FF00FF00FF00FF) | ((v & 0x00FF00FF00FF00FF) << 8);
    v = ((v >> 16) & 0x0000FFFF0000FFFF) | ((v & 0x0000FFFF0000FFFF) << 16);
    ((v >> 32) & 0x00000000FFFFFFFF) | ((v & 0x00000000FFFFFFFF) << 32)
}


// Calculate sliding piece moves for a given occupancy and mask
fn get_line_attacks(piece: Bitboard, occupied: Bitboard, line: Bitboard) -> Bitboard {
    let potential_blockers = occupied & line;
    let forward = potential_blockers.wrapping_sub(piece.wrapping_mul(2));
    let rev = reverse(reverse(potential_blockers).wrapping_sub(reverse(piece).wrapping_mul(2)));
    (forward ^ rev) & line
}

fn get_rook_attacks(piece: Bitboard, from_square: Square, occupied: Bitboard) -> Bitboard {
    get_line_attacks(piece, occupied, bb_file(from_square)) |
    get_line_attacks(piece, occupied, bb_rank(from_square))
}

fn get_bishop_attacks(piece: Bitboard, from_square: Square, occupied: Bitboard) -> Bitboard {
    get_line_attacks(piece, occupied, bb_diag(from_square)) |
    get_line_attacks(piece, occupied, bb_anti_diag(from_square))
}


// Helper functions for `piece_attacks_from`.
#[inline(always)]
unsafe fn knight_attacks(from_square: Square) -> Bitboard {
    *KNIGHT_MAP.get_unchecked(from_square)
}

#[inline(always)]
unsafe fn king_attacks(from_square: Square) -> Bitboard {
    *KING_MAP.get_unchecked(from_square)
}

#[inline(always)]
unsafe fn bishop_attacks(from_square: Square, occupied: Bitboard) -> Bitboard {
    BISHOP_MAP.get_unchecked(from_square).att(occupied)
}

#[inline(always)]
unsafe fn rook_attacks(from_square: Square, occupied: Bitboard) -> Bitboard {
    ROOK_MAP.get_unchecked(from_square).att(occupied)
}
{'fraction_non_alphanumeric': 0.12864498502600746, 'fraction_numerical': 0.027163347869489835, 'mean_word_length': 1.4311534040107294, 'pattern_counts': {'":': 0, '<': 63, '<?xml version=': 0, '>': 89, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 16, 'word_list_counts': {'cursed_substrings.json': 60, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3477958', 'n_tokens_mistral': 12500, 'n_tokens_neox': 11330, 'n_words': 3101}