use core::{fmt, ops, str};
use prelude::*;
#[cfg(feature = "serde")]
use serde::*;
use iter;
const ALL_BITS: u8 = 0b1111;
const MAX_LEN: usize = 1 + ALL_BITS as usize;
impl_rand!(u8 => Rights, Right);
#[derive(PartialEq, Eq, Clone, Copy, Hash, FromUnchecked)]
pub struct Rights(u8);
impl From<u8> for Rights {
#[inline]
fn from(inner: u8) -> Rights {
Self::FULL & Rights(inner)
}
}
impl From<Color> for Rights {
#[inline]
fn from(color: Color) -> Rights {
match color {
Color::White => Self::WHITE_KING | Self::WHITE_QUEEN,
Color::Black => Self::BLACK_KING | Self::BLACK_QUEEN,
}
}
}
impl Default for Rights {
#[inline]
fn default() -> Rights { Rights::FULL }
}
impl fmt::Debug for Rights {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.is_empty() {
fmt::Display::fmt("(empty)", f)
} else {
self.map_str(|s| fmt::Display::fmt(s, f))
}
}
}
impl fmt::Display for Rights {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.map_str(|s| s.fmt(f))
}
}
define_from_str_error! { Rights;
"failed to parse a string as castling rights"
}
#[cfg(feature = "serde")]
impl Serialize for Rights {
fn serialize<S: Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
self.map_str(|s| ser.serialize_str(s))
}
}
impl str::FromStr for Rights {
type Err = FromStrError;
fn from_str(s: &str) -> Result<Rights, FromStrError> {
let bytes = s.as_bytes();
let mut result = Rights::EMPTY;
if bytes.len() == 1 && bytes[0] == b'-' {
Ok(result)
} else {
for &byte in bytes {
result |= match byte {
b'K' => Rights::WHITE_KING,
b'k' => Rights::BLACK_KING,
b'Q' => Rights::WHITE_QUEEN,
b'q' => Rights::BLACK_QUEEN,
_ => return Err(FromStrError(())),
};
}
Ok(result)
}
}
}
impl<T> ::misc::Extract<[T; MAX_LEN]> for Rights {
type Output = T;
#[inline]
fn extract<'a>(self, array: &'a [T; MAX_LEN]) -> &'a T {
unsafe { array.get_unchecked(self.0 as usize) }
}
#[inline]
fn extract_mut<'a>(self, array: &'a mut [T; MAX_LEN]) -> &'a mut T {
unsafe { array.get_unchecked_mut(self.0 as usize) }
}
}
impl Rights {
pub const WHITE: Rights = Rights(0b0011);
pub const BLACK: Rights = Rights(0b1100);
pub const WHITE_KING: Rights = Rights(0b0001);
pub const WHITE_QUEEN: Rights = Rights(0b0010);
pub const BLACK_KING: Rights = Rights(0b0100);
pub const BLACK_QUEEN: Rights = Rights(0b1000);
#[inline]
pub fn map_str<T, F: FnOnce(&mut str) -> T>(&self, f: F) -> T {
let mut buf = [0u8; 4];
let slice: &mut [u8] = if self.is_empty() {
buf[0] = b'-';
&mut buf[..1]
} else {
let mut idx = 0;
for right in *self {
unsafe {
*buf.get_unchecked_mut(idx) = char::from(right) as u8;
}
idx += 1;
}
unsafe { buf.get_unchecked_mut(..idx) }
};
unsafe { f(str::from_utf8_unchecked_mut(slice)) }
}
}
impl_bit_set! { Rights ALL_BITS => Right }
impl_composition_ops! { Rights => Right }
impl From<Right> for Rights {
#[inline]
fn from(right: Right) -> Self {
Rights(1 << right as usize)
}
}
#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash, FromUnchecked)]
#[uncon(impl_from, other(u16, u32, u64, usize))]
#[repr(u8)]
pub enum Right {
WhiteKing,
WhiteQueen,
BlackKing,
BlackQueen,
}
impl ops::Not for Side {
type Output = Side;
#[inline]
fn not(self) -> Side {
(1 - self as u8).into()
}
}
impl From<Right> for char {
#[inline]
fn from(right: Right) -> char {
b"KQkq"[right as usize] as char
}
}
impl From<Right> for Piece {
#[inline]
fn from(right: Right) -> Piece {
match right {
Right::WhiteKing => Piece::WhiteKing,
Right::WhiteQueen => Piece::WhiteQueen,
Right::BlackKing => Piece::BlackKing,
Right::BlackQueen => Piece::BlackQueen,
}
}
}
impl Right {
#[inline]
pub fn new(color: Color, side: Side) -> Right {
(((color as u8) << 1) | side as u8).into()
}
#[inline]
pub fn from_char(ch: char) -> Option<Right> {
match ch {
'K' => Some(Right::WhiteKing),
'Q' => Some(Right::WhiteQueen),
'k' => Some(Right::BlackKing),
'q' => Some(Right::BlackQueen),
_ => None,
}
}
#[inline]
pub fn path(self) -> Bitboard {
path::ALL[self as usize]
}
#[inline]
pub fn path_iter(self) -> iter::Range<Square> {
static ITERS: [iter::Range<Square>; 4] = [
iter::Range { iter: 05..07 },
iter::Range { iter: 01..04 },
iter::Range { iter: 61..63 },
iter::Range { iter: 57..60 },
];
ITERS[self as usize].clone()
}
#[inline]
pub fn color(self) -> Color {
((self as u8) >> 1).into()
}
#[inline]
pub fn side(self) -> Side {
(1 & self as u8).into()
}
}
pub mod path {
use super::*;
pub const WHITE_KING: Bitboard = Bitboard(0x60);
pub const BLACK_KING: Bitboard = Bitboard(WHITE_KING.0 << 56);
pub const WHITE_QUEEN: Bitboard = Bitboard(0x0E);
pub const BLACK_QUEEN: Bitboard = Bitboard(WHITE_QUEEN.0 << 56);
pub static ALL: [Bitboard; 4] = [
WHITE_KING,
WHITE_QUEEN,
BLACK_KING,
BLACK_QUEEN,
];
}
#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash, FromUnchecked)]
#[uncon(impl_from, other(u16, u32, u64, usize))]
#[repr(u8)]
pub enum Side {
King,
Queen,
}
impl From<Side> for Role {
#[inline]
fn from(side: Side) -> Role {
match side {
Side::King => Role::King,
Side::Queen => Role::Queen,
}
}
}
#[cfg(any(test, feature = "rand"))]
impl ::rand::Rand for Side {
#[inline]
fn rand<R: ::rand::Rng>(rng: &mut R) -> Self {
if bool::rand(rng) {
Side::King
} else {
Side::Queen
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn castle_right_new() {
for &side in &[Side::King, Side::Queen] {
for &color in &[Color::White, Color::Black] {
let right = Right::new(color, side);
assert_eq!(right.side(), side);
assert_eq!(right.color(), color);
}
}
}
#[test]
fn castle_right_char() {
for right in Rights::FULL {
let ch = char::from(right);
assert_eq!(Some(right), Right::from_char(ch));
}
}
#[test]
fn castle_right_path() {
fn path(right: Right) -> Bitboard {
use self::Right::*;
match right {
WhiteKing => path::WHITE_KING,
BlackKing => path::BLACK_KING,
WhiteQueen => path::WHITE_QUEEN,
BlackQueen => path::BLACK_QUEEN,
}
}
for right in Rights::FULL {
assert_eq!(right.path(), path(right));
}
}
#[test]
fn castle_rights_string() {
use self::Right::*;
let pairs = [
(Rights::FULL, "KQkq"),
(Rights::EMPTY, "-"),
(BlackKing.into(), "k"),
(BlackKing | WhiteQueen, "Qk"),
];
for &(rights, exp) in &pairs {
rights.map_str(|s| {
assert_eq!(s, exp);
assert_eq!(rights, s.parse().unwrap());
});
}
}
}