#[macro_use]
mod macros;
pub mod bit_twiddles;
pub mod piece_move;
pub mod masks;
pub mod mono_traits;
pub mod sq;
pub mod bitboard;
pub mod move_list;
pub mod score;
use self::bit_twiddles::*;
use self::masks::*;
use self::sq::SQ;
use self::bitboard::BitBoard;
use std::fmt;
use std::mem;
use std::ops::Not;
pub const ALL_PIECE_TYPES: [PieceType; PIECE_TYPE_CNT - 2] =
[PieceType::P, PieceType::N, PieceType::B, PieceType::R, PieceType::Q, PieceType::K];
pub const ALL_PLAYERS: [Player; 2] = [Player::White, Player::Black];
pub static ALL_FILES: [File; FILE_CNT] = [
File::A,
File::B,
File::C,
File::D,
File::E,
File::F,
File::G,
File::H,
];
pub static ALL_RANKS: [Rank; RANK_CNT] = [
Rank::R1,
Rank::R2,
Rank::R3,
Rank::R4,
Rank::R5,
Rank::R6,
Rank::R7,
Rank::R8,
];
#[derive(Copy, Clone, Debug, PartialEq)]
#[repr(u8)]
pub enum Player {
White = 0,
Black = 1,
}
impl Player {
#[inline(always)]
pub fn other_player(self) -> Player {
!(self)
}
#[inline(always)]
pub fn relative_square(self, sq: SQ) -> SQ {
assert!(sq.is_okay());
sq ^ SQ((self) as u8 * 56)
}
#[inline(always)]
pub fn pawn_push(self) -> i8 {
match self {
Player::White => NORTH,
Player::Black => SOUTH,
}
}
#[inline(always)]
pub fn relative_rank_of_sq(self, sq: SQ) -> Rank {
self.relative_rank(sq.rank())
}
#[inline]
pub fn relative_rank(self, rank: Rank) -> Rank {
let r = (rank as u8) ^ (self as u8 * 7);
debug_assert!(r < 8);
unsafe {
mem::transmute::<u8,Rank>(r)
}
}
}
impl Not for Player {
type Output = Player;
fn not(self) -> Self::Output {
let other: u8 = (self as u8) ^ 0b0000_0001;
unsafe {
mem::transmute(other)
}
}
}
impl fmt::Display for Player {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{}",
if self == &Player::White {
"White"
} else {
"Black"
}
)
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum GenTypes {
All,
Captures,
Quiets,
QuietChecks,
Evasions,
NonEvasions
}
#[repr(u8)]
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum PieceType {
None = 0,
P = 1,
N = 2,
B = 3,
R = 4,
Q = 5,
K = 6,
All = 7
}
impl PieceType {
#[inline]
pub fn value(self) -> i8 {
match self {
PieceType::P => 1,
PieceType::N | PieceType::B => 3,
PieceType::R => 5,
PieceType::Q => 8,
_ => 0,
}
}
#[inline(always)]
pub fn is_none(self) -> bool {
self == PieceType::None
}
#[inline(always)]
pub fn is_some(self) -> bool {
!self.is_none()
}
#[inline(always)]
pub fn is_real(self) -> bool {
self != PieceType::None && self != PieceType::All
}
#[inline]
pub fn char_lower(self) -> char {
match self {
PieceType::P => 'p',
PieceType::N => 'n',
PieceType::B => 'b',
PieceType::R => 'r',
PieceType::Q => 'q',
PieceType::K => 'k',
_ => panic!(),
}
}
#[inline]
pub fn char_upper(self) -> char {
match self {
PieceType::P => 'P',
PieceType::N => 'N',
PieceType::B => 'B',
PieceType::R => 'R',
PieceType::Q => 'Q',
PieceType::K => 'K',
_ => panic!(),
}
}
}
impl fmt::Display for PieceType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let s = match *self {
PieceType::P => "Pawn",
PieceType::N => "Knight",
PieceType::B => "Bishop",
PieceType::R => "Rook",
PieceType::Q => "Queen",
PieceType::K => "King",
PieceType::All => "All",
PieceType::None => "",
};
f.pad(s)
}
}
#[repr(u8)]
#[derive(Copy, Clone, PartialEq)]
pub enum Piece {
None = 0b0000,
WhitePawn = 0b0001,
WhiteKnight = 0b0010,
WhiteBishop = 0b0011,
WhiteRook = 0b0100,
WhiteQueen = 0b0101,
WhiteKing = 0b0110,
BlackPawn = 0b1001,
BlackKnight = 0b1010,
BlackBishop = 0b1011,
BlackRook = 0b1100,
BlackQueen = 0b1101,
BlackKing = 0b1110
}
impl Piece {
#[inline(always)]
pub fn player(self) -> Option<Player> {
if self as u8 & 0b0111 == 0 {
None
} else {
Some(self.player_lossy())
}
}
#[inline(always)]
pub fn player_lossy(self) -> Player {
unsafe {
mem::transmute((self as u8 >> 3) & 0b1)
}
}
#[inline(always)]
pub fn type_of(self) -> PieceType {
unsafe {
mem::transmute(self as u8 & 0b111)
}
}
#[inline(always)]
pub fn player_piece(self) -> Option<(Player, PieceType)> {
if self == Piece::None {
None
} else {
Some(self.player_piece_lossy())
}
}
#[inline(always)]
pub fn player_piece_lossy(self) -> (Player, PieceType) {
(self.player_lossy(), self.type_of())
}
#[inline(always)]
pub fn make(player: Player, piece_type: PieceType) -> Option<Piece> {
match piece_type {
PieceType::None => Some(Piece::None),
PieceType::All => None,
_ => Some(Piece::make_lossy(player, piece_type))
}
}
#[inline(always)]
pub fn make_lossy(player: Player, piece_type: PieceType) -> Piece {
unsafe {
let bits: u8 = (player as u8) << 3 | piece_type as u8;
mem::transmute(bits)
}
}
#[inline]
pub fn character(self) -> Option<char> {
if self == Piece::None {
None
} else {
Some(self.character_lossy())
}
}
pub fn character_lossy(self) -> char {
match self {
Piece::None => panic!(),
Piece::WhitePawn => 'P',
Piece::WhiteKnight => 'N',
Piece::WhiteBishop => 'B',
Piece::WhiteRook => 'R',
Piece::WhiteQueen => 'Q',
Piece::WhiteKing => 'K',
Piece::BlackPawn => 'p',
Piece::BlackKnight => 'n',
Piece::BlackBishop => 'b',
Piece::BlackRook => 'r',
Piece::BlackQueen => 'q',
Piece::BlackKing => 'k'
}
}
}
impl fmt::Display for Piece {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if *self != Piece::None {
write!(f, "{}", self.character_lossy())
} else {
write!(f, "X")
}
}
}
impl fmt::Debug for Piece {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let s = match *self {
Piece::None => "None",
Piece::WhitePawn => "WhitePawn",
Piece::WhiteKnight => "WhiteKnight",
Piece::WhiteBishop => "WhiteBishop",
Piece::WhiteRook => "WhiteRook",
Piece::WhiteQueen => "WhiteQueen",
Piece::WhiteKing => "WhiteKing",
Piece::BlackPawn => "BlackPawn",
Piece::BlackKnight => "BlackKnight",
Piece::BlackBishop => "BlackBishop",
Piece::BlackRook => "BlackRook",
Piece::BlackQueen => "BlackQueen",
Piece::BlackKing => "BlackKing",
};
write!(f, "{}", s)
}
}
#[repr(u8)]
#[derive(Copy, Clone, PartialEq, Debug, Ord, PartialOrd, Eq)]
pub enum File {
A = 0, B = 1,
C = 2,
D = 3,
E = 4,
F = 5,
G = 6,
H = 7,
}
impl File {
#[inline]
pub const fn left_side_mask(self) -> u8 {
(1 << self as u8) - 1
}
#[inline]
pub const fn right_side_mask(self) -> u8 {
!((1 << (self as u16 + 1)) - 1) as u8
}
#[inline]
pub fn min(self, other: File) -> File {
if (self as u8) < (other as u8) {
self
} else {
other
}
}
#[inline]
pub fn max(self, other: File) -> File {
if (self as u8) > (other as u8) {
self
} else {
other
}
}
pub fn distance(self, other: File) -> u8 {
if self > other {
self as u8 - other as u8
} else {
other as u8 - self as u8
}
}
pub fn bb(self) -> BitBoard {
BitBoard(file_bb(self as u8))
}
}
impl Not for File {
type Output = File;
fn not(self) -> File {
unsafe {
let f = self as u8 ^ File::H as u8;
mem::transmute::<u8,File>(0b111 & f)
}
}
}
#[repr(u8)]
#[derive(Copy, Clone, PartialEq, Debug, Eq, Ord, PartialOrd)]
pub enum Rank { R1 = 0,
R2 = 1,
R3 = 2,
R4 = 3,
R5 = 4,
R6 = 5,
R7 = 6,
R8 = 7,
}
impl Rank {
pub fn distance(self, other: Rank) -> u8 {
if self > other {
self as u8 - other as u8
} else {
other as u8 - self as u8
}
}
pub fn bb(self) -> BitBoard {
BitBoard(rank_bb(self as u8))
}
}
#[derive(Copy, Clone, PartialEq, Debug)]
#[repr(u8)]
pub enum CastleType {
KingSide = 0,
QueenSide = 1,
}
#[doc(hidden)]
#[derive(Copy, Clone, PartialEq, Debug)]
#[repr(u8)]
pub enum Phase {
MG = 0,
EG = 1
}
#[inline(always)]
pub fn rank_bb(s: u8) -> u64 {
RANK_BB[rank_idx_of_sq(s) as usize]
}
#[inline(always)]
pub fn rank_of_sq(s: u8) -> Rank {
unsafe {
mem::transmute::<u8,Rank>((s >> 3) & 0b0000_0111)
}
}
#[inline(always)]
pub fn rank_idx_of_sq(s: u8) -> u8 {
(s >> 3) as u8
}
#[inline(always)]
pub fn file_bb(s: u8) -> u64 {
FILE_BB[file_of_sq(s) as usize]
}
#[inline(always)]
pub fn file_of_sq(s: u8) -> File {
unsafe {
mem::transmute::<u8,File>(s & 0b0000_0111)
}
}
#[inline(always)]
pub fn file_idx_of_sq(s: u8) -> u8 {
(s & 0b0000_0111) as u8
}
#[inline]
pub fn u64_to_u8(b: u64) -> u8 {
debug_assert_eq!(popcount64(b), 1);
bit_scan_forward(b)
}
#[inline]
pub fn u8_to_u64(s: u8) -> u64 {
debug_assert!(s < 64);
(1 as u64).wrapping_shl(s as u32)
}