use core::board::{MultiBoard, PieceMap};
use core::misc::Contained;
use core::mv::{self, MoveVec};
use prelude::*;
mod state;
pub use self::state::*;
mod mv_gen;
pub use self::mv_gen::*;
#[cfg(all(test, nightly))]
mod benches;
#[derive(Clone)]
pub struct Position {
state: State,
pieces: PieceMap,
board: MultiBoard,
player: Color,
}
impl PartialEq for Position {
fn eq(&self, other: &Position) -> bool {
self.pieces == other.pieces &&
self.player == other.player &&
self.state == other.state
}
}
impl Eq for Position {}
impl Default for Position {
#[inline]
fn default() -> Position {
const STANDARD: Position = Position {
state: State::STANDARD,
pieces: PieceMap::STANDARD,
board: MultiBoard::STANDARD,
player: Color::White,
};
STANDARD
}
}
impl Position {
#[inline]
pub fn pieces(&self) -> &PieceMap {
&self.pieces
}
#[inline]
pub fn board(&self) -> &MultiBoard {
&self.board
}
#[inline]
pub fn gen<'a, 'b>(&'a self, moves: &'b mut MoveVec) -> MoveGen<'a, 'b> {
MoveGen { pos: self, buf: moves }
}
pub fn is_legal(&self, mv: Move) -> bool {
use self::mv::Matches;
let src = mv.src();
let dst = mv.dst();
let player = self.player();
let king = self.king_square(player);
let board = self.board();
let checked = board.is_attacked(king, player);
match mv.matches() {
Matches::Castle(mv) => {
if checked {
return false;
}
let right = mv.right();
if player != right.color() || !self.rights().contains(right) {
return false;
}
for sq in right.path_iter() {
if board.is_attacked(sq, player) {
return false;
}
}
true
},
_ => unimplemented!(),
}
}
#[inline]
pub fn contains<'a, T: Contained<&'a Self>>(&'a self, value: T) -> bool {
value.contained_in(self)
}
#[inline]
pub fn player(&self) -> Color {
self.player
}
#[inline]
pub fn player_bitboard(&self) -> Bitboard {
self.board().bitboard(self.player())
}
#[inline]
pub fn opponent(&self) -> Color {
!self.player()
}
#[inline]
pub fn opponent_bitboard(&self) -> Bitboard {
self.board().bitboard(self.opponent())
}
#[inline]
pub fn en_passant(&self) -> Option<Square> {
self.state.en_passant()
}
#[inline]
pub fn rights(&self) -> Rights {
self.state.rights()
}
#[inline]
pub fn king_square(&self, color: Color) -> Square {
let piece = Piece::new(Role::King, color);
let board = self.board().bitboard(piece);
debug_assert!(!board.is_empty(), "{:?} not found", piece);
unsafe { board.lsb_unchecked() }
}
}
impl<'a> Contained<&'a Position> for Square {
#[inline]
fn contained_in(self, pos: &Position) -> bool {
pos.pieces().contains(self)
}
}
macro_rules! impl_contained {
($($t:ty),+) => {
$(impl<'a> Contained<&'a Position> for $t {
#[inline]
fn contained_in(self, pos: &Position) -> bool {
!pos.board().bitboard(self).is_empty()
}
})+
}
}
impl_contained! { Piece, Role, Color }
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn initial_pieces() {
let pos = Position::default();
let all = pos.board().all_bits();
for square in Square::ALL {
if let Some(&piece) = pos.pieces().get(square) {
assert!(all.contains(square));
let board = pos.board();
assert!(board.contains(square, piece));
assert!(board.contains(square, piece.role()));
assert!(board.contains(square, piece.color()));
} else {
let (a, b) = pos.board.split();
for &slice in &[&a[..], &b[..]] {
for &bitboard in slice {
assert!(!bitboard.contains(square));
}
}
}
}
}
}