use std::fmt;
use utils::parse_fen;
pub type Color = usize;
pub const WHITE: Color = 0;
pub const BLACK: Color = 1;
pub type PieceType = usize;
pub const KING: PieceType = 0;
pub const QUEEN: PieceType = 1;
pub const ROOK: PieceType = 2;
pub const BISHOP: PieceType = 3;
pub const KNIGHT: PieceType = 4;
pub const PAWN: PieceType = 5;
pub const PIECE_NONE: PieceType = 6;
pub type Square = usize;
pub type Bitboard = u64;
#[derive(Clone, Debug)]
pub struct PiecesPlacement {
pub piece_type: [Bitboard; 6],
pub color: [Bitboard; 2],
}
impl fmt::Display for PiecesPlacement {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut s = String::new();
for rank in (0..8).rev() {
s.push('\n');
for file in 0..8 {
let square = Board::square(file, rank);
let bb = 1 << square;
let piece = match bb {
x if x & self.piece_type[KING] != 0 => 'k',
x if x & self.piece_type[QUEEN] != 0 => 'q',
x if x & self.piece_type[ROOK] != 0 => 'r',
x if x & self.piece_type[BISHOP] != 0 => 'b',
x if x & self.piece_type[KNIGHT] != 0 => 'n',
x if x & self.piece_type[PAWN] != 0 => 'p',
_ => '.',
};
if bb & self.color[WHITE] != 0 {
s.push(piece.to_uppercase().next().unwrap());
} else {
s.push(piece);
}
}
}
writeln!(f, "{}", s)
}
}
pub type CastlingSide = usize;
pub const QUEENSIDE: CastlingSide = 0;
pub const KINGSIDE: CastlingSide = 1;
#[derive(Clone, Copy, Debug)]
pub struct CastlingRights(usize);
impl CastlingRights {
#[inline]
pub fn new(value: usize) -> CastlingRights {
CastlingRights(value & 0b1111)
}
#[inline]
pub fn value(&self) -> usize {
self.0
}
pub fn grant(&mut self, player: Color, side: CastlingSide) -> bool {
assert!(player <= 1);
assert!(side <= 1);
let rights_before = self.0;
let granted = 1 << (player << 1) << side;
self.0 |= granted;
granted & !rights_before != 0
}
#[inline]
pub fn update(&mut self, orig_square: Square, dest_square: Square) {
debug_assert!(orig_square <= 63);
debug_assert!(dest_square <= 63);
const WQ: usize = (1 << (WHITE << 1) << QUEENSIDE);
const WK: usize = (1 << (WHITE << 1) << KINGSIDE);
const W: usize = WQ | WK;
const BQ: usize = (1 << (BLACK << 1) << QUEENSIDE);
const BK: usize = (1 << (BLACK << 1) << KINGSIDE);
const B: usize = BQ | BK;
const CASTLING_RELATION: [usize; 64] = [
!WQ, !0, !0, !0, !W, !0, !0, !WK,
!0, !0, !0, !0, !0, !0, !0, !0,
!0, !0, !0, !0, !0, !0, !0, !0,
!0, !0, !0, !0, !0, !0, !0, !0,
!0, !0, !0, !0, !0, !0, !0, !0,
!0, !0, !0, !0, !0, !0, !0, !0,
!0, !0, !0, !0, !0, !0, !0, !0,
!BQ, !0, !0, !0, !B, !0, !0, !BK
];
self.0 &= CASTLING_RELATION[orig_square] & CASTLING_RELATION[dest_square];
}
#[inline]
pub fn can_castle(&self, player: Color, side: CastlingSide) -> bool {
debug_assert!(player <= 1);
debug_assert!(side <= 1);
(1 << (player << 1) << side) & self.0 != 0
}
}
impl fmt::Display for CastlingRights {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut value = self.value();
for s in ["Q", "K", "q", "k"].iter() {
if value & 1 == 1 {
try!(f.write_str(s));
}
value >>= 1;
}
Ok(())
}
}
pub struct IllegalBoard;
#[derive(Clone, Debug)]
pub struct Board {
pub pieces: PiecesPlacement,
pub to_move: Color,
pub castling_rights: CastlingRights,
pub enpassant_file: usize,
pub occupied: Bitboard,
}
impl Board {
pub fn from_fen(fen: &str) -> Result<Board, IllegalBoard> {
parse_fen(fen).map(|x| x.0)
}
#[inline]
pub fn square(file: usize, rank: usize) -> Square {
debug_assert!(file < 8);
debug_assert!(rank < 8);
(rank << 3) + file
}
#[inline]
pub fn file(square: Square) -> usize {
debug_assert!(square <= 63);
square % 8
}
#[inline]
pub fn rank(square: Square) -> usize {
debug_assert!(square <= 63);
square >> 3
}
}
#[cfg(test)]
mod tests {
use super::*;
use squares::*;
#[test]
fn castling_rights() {
let mut c = CastlingRights::new(0b1110);
assert_eq!(c.can_castle(WHITE, QUEENSIDE), false);
assert_eq!(c.can_castle(WHITE, KINGSIDE), true);
assert_eq!(c.can_castle(BLACK, QUEENSIDE), true);
assert_eq!(c.can_castle(BLACK, KINGSIDE), true);
c.update(H8, H7);
assert_eq!(c.can_castle(WHITE, QUEENSIDE), false);
assert_eq!(c.can_castle(WHITE, KINGSIDE), true);
assert_eq!(c.can_castle(BLACK, QUEENSIDE), true);
assert_eq!(c.can_castle(BLACK, KINGSIDE), false);
assert_eq!(c.value(), 0b0110);
assert_eq!(c.grant(BLACK, KINGSIDE), true);
assert_eq!(c.grant(BLACK, KINGSIDE), false);
assert_eq!(c.value(), 0b1110);
}
}