use super::castle_rights::Castling;
use super::Board;
use core::*;
use core::piece_move::BitMove;
use core::sq::{SQ,NO_SQ};
use core::bitboard::BitBoard;
use core::masks::*;
use core::score::{Value,Score};
use tools::pleco_arc::Arc;
use helper::prelude::*;
#[derive(Clone)]
pub struct BoardState {
pub castling: Castling,
pub rule_50: i16,
pub ply: u16,
pub ep_square: SQ,
pub psq: Score,
pub zobrist: u64,
pub pawn_key: u64,
pub material_key: u64,
pub nonpawn_material: [Value; PLAYER_CNT],
pub captured_piece: PieceType,
pub checkers_bb: BitBoard,
pub blockers_king: [BitBoard; PLAYER_CNT],
pub pinners_king: [BitBoard; PLAYER_CNT],
pub check_sqs: [BitBoard; PIECE_TYPE_CNT],
pub prev_move: BitMove,
pub prev: Option<Arc<BoardState>>,
}
impl BoardState {
pub const fn blank() -> BoardState {
BoardState {
castling: Castling::empty_set(),
rule_50: 0,
ply: 0,
ep_square: NO_SQ,
psq: Score::ZERO,
zobrist: 0,
pawn_key: 0,
material_key: 0,
nonpawn_material: [0; PLAYER_CNT],
captured_piece: PieceType::None,
checkers_bb: BitBoard(0),
blockers_king: [BitBoard(0); PLAYER_CNT],
pinners_king: [BitBoard(0); PLAYER_CNT],
check_sqs: [BitBoard(0); PIECE_TYPE_CNT],
prev_move: BitMove::null(),
prev: None,
}
}
pub fn partial_clone(&self) -> BoardState {
BoardState {
castling: self.castling,
rule_50: self.rule_50,
ply: self.ply,
ep_square: self.ep_square,
psq: self.psq,
zobrist: self.zobrist,
pawn_key: self.pawn_key,
material_key: self.material_key,
nonpawn_material: self.nonpawn_material,
captured_piece: self.captured_piece,
checkers_bb: BitBoard(0),
blockers_king: [BitBoard(0); PLAYER_CNT],
pinners_king: [BitBoard(0); PLAYER_CNT],
check_sqs: [BitBoard(0); PIECE_TYPE_CNT],
prev_move: BitMove::null(),
prev: self.get_prev(),
}
}
pub(crate) fn set(&mut self, board: &Board) {
self.zobrist = 0;
self.material_key = 0;
self.pawn_key = z_no_pawns();
self.nonpawn_material = [0; 2];
let us = board.turn;
let them = !us;
let ksq = board.king_sq(us);
self.checkers_bb = board.attackers_to(ksq, board.occupied())
& board.bbs_player[them as usize];
self.set_check_info(board);
self.set_zob_hash(board);
self.set_material_key(board);
}
pub(crate) fn set_check_info(&mut self, board: &Board) {
let mut white_pinners: BitBoard = BitBoard(0);
self.blockers_king[Player::White as usize] = board.slider_blockers(
board.occupied_black(),
board.king_sq(Player::White),
&mut white_pinners);
self.pinners_king[Player::White as usize] = white_pinners;
let mut black_pinners: BitBoard = BitBoard(0);
self.blockers_king[Player::Black as usize] = board.slider_blockers(
board.occupied_white(),
board.king_sq(Player::Black),
&mut black_pinners);
self.pinners_king[Player::Black as usize] = black_pinners;
let ksq: SQ = board.king_sq(board.turn.other_player());
let occupied = board.occupied();
self.check_sqs[PieceType::P as usize] = pawn_attacks_from(ksq, board.turn.other_player());
self.check_sqs[PieceType::N as usize] = knight_moves(ksq);
self.check_sqs[PieceType::B as usize] = bishop_moves(occupied, ksq);
self.check_sqs[PieceType::R as usize] = rook_moves(occupied, ksq);
self.check_sqs[PieceType::Q as usize] = self.check_sqs[PieceType::B as usize]
| self.check_sqs[PieceType::R as usize];
self.check_sqs[PieceType::K as usize] = BitBoard(0);
}
fn set_zob_hash(&mut self, board: &Board) {
let mut b: BitBoard = board.occupied();
while let Some(sq) = b.pop_some_lsb() {
let piece = board.piece_locations.piece_at(sq);
self.psq += psq(piece,sq);
let key = z_square(sq, piece);
self.zobrist ^= key;
if piece.type_of() == PieceType::P {
self.pawn_key ^= key;
}
}
self.zobrist ^= z_castle(self.castling.bits());
let ep = self.ep_square;
if ep != NO_SQ {
self.zobrist ^= z_ep(ep);
}
match board.turn {
Player::Black => self.zobrist ^= z_side(),
Player::White => {}
};
}
fn set_material_key(&mut self, board: &Board) {
for player in &ALL_PLAYERS {
for piece in &ALL_PIECE_TYPES {
let count = board.piece_bb(*player, *piece).count_bits();
for n in 0..count {
self.material_key ^= z_square(SQ(n), Piece::make_lossy(*player, *piece));
}
if *piece != PieceType::P && *piece != PieceType::K {
self.nonpawn_material[*player as usize] +=
count as i32 * piecetype_value(*piece, false);
}
}
}
}
#[inline]
pub fn get_prev(&self) -> Option<Arc<BoardState>> {
self.prev.as_ref().cloned()
}
pub fn backtrace(&self) {
self.print_info();
if let Some(ref prev) = self.prev {
prev.backtrace();
}
}
pub fn print_info(&self) {
print!("ply: {}, move played: {} ",self.ply, self.prev_move);
if !self.checkers_bb.is_empty() {
print!("in check {}", self.checkers_bb.to_sq());
}
println!();
}
}
impl PartialEq for BoardState {
fn eq(&self, other: &BoardState) -> bool {
self.castling == other.castling &&
self.rule_50 == other.rule_50 &&
self.ep_square == other.ep_square &&
self.zobrist == other.zobrist &&
self.captured_piece == other.captured_piece &&
self.checkers_bb == other.checkers_bb &&
self.blockers_king == other.blockers_king &&
self.pinners_king == other.pinners_king &&
self.check_sqs == other.check_sqs
}
}