Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ license = "MIT"
documentation = "https://jordanbray.github.io/chess/chess/index.html"

[dependencies]
arrayvec = "0.5.1"
nodrop = "0.1.14"
failure = "0.1.6"
arrayvec = { version = "0.7.2", default-features = false }
nodrop = { version = "0.1.14", default_features = false }
failure = { version = "0.1.6", optional = true }

[profile.release]
opt-level = 3
Expand All @@ -32,3 +32,16 @@ opt-level = 3
[build-dependencies]
rand = { version = "0.7.2", default_features = false, features = ["small_rng"] }
failure = "0.1.6"

[features]
default = ["std"]
std = [ "dep:failure" ]

# always optimize build script, because it takes a long time to run unoptimized
[profile.dev.build-override]
opt-level = 3
[profile.release.build-override]
opt-level = 3
[profile.test.build-override]
opt-level = 3

9 changes: 4 additions & 5 deletions src/bitboard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,18 +254,17 @@ impl Not for &BitBoard {
impl fmt::Display for BitBoard {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut s: String = "".to_owned();
for x in 0..64 {
if self.0 & (1u64 << x) == (1u64 << x) {
s.push_str("X ");
write!(f, "X ")?;
} else {
s.push_str(". ");
write!(f, ". ")?;
}
if x % 8 == 7 {
s.push_str("\n");
write!(f, "\n")?;
}
}
write!(f, "{}", s)
Ok(())
}
}

Expand Down
1 change: 1 addition & 0 deletions src/board.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ impl Board {
/// ```
#[deprecated(since = "3.1.0", note = "please use `Board::from_str(fen)?` instead")]
#[inline]
#[cfg(feature="std")]
pub fn from_fen(fen: String) -> Option<Board> {
Board::from_str(&fen).ok()
}
Expand Down
39 changes: 19 additions & 20 deletions src/board_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ use crate::error::Error;
use crate::file::{File, ALL_FILES};
use crate::piece::Piece;
use crate::rank::{Rank, ALL_RANKS};
use crate::square::{Square, ALL_SQUARES};
use crate::square::{Square, ALL_SQUARES, NUM_SQUARES};
use arrayvec::ArrayVec;

use std::fmt;
use std::ops::{Index, IndexMut};
Expand Down Expand Up @@ -288,7 +289,7 @@ impl fmt::Display for BoardBuilder {
}

if let Some((piece, color)) = self.pieces[square] {
write!(f, "{}", piece.to_string(color))?;
write!(f, "{}", piece.with_color(color))?;
} else {
count += 1;
}
Expand All @@ -315,12 +316,12 @@ impl fmt::Display for BoardBuilder {
write!(
f,
"{}",
self.castle_rights[Color::White.to_index()].to_string(Color::White)
self.castle_rights[Color::White.to_index()].with_color(Color::White)
)?;
write!(
f,
"{}",
self.castle_rights[Color::Black.to_index()].to_string(Color::Black)
self.castle_rights[Color::Black.to_index()].with_color(Color::Black)
)?;
if self.castle_rights[0] == CastleRights::NoRights
&& self.castle_rights[1] == CastleRights::NoRights
Expand Down Expand Up @@ -353,17 +354,19 @@ impl FromStr for BoardBuilder {
let mut cur_file = File::A;
let mut fen = &mut BoardBuilder::new();

let tokens: Vec<&str> = value.split(' ').collect();
if tokens.len() < 4 {
return Err(Error::InvalidFen {
#[cfg(feature="std")]
let invalid = || Error::InvalidFen {
fen: value.to_string(),
});
}
};
#[cfg(not(feature="std"))]
let invalid = || Error::InvalidFen;

let mut tokens = value.split(' ');

let pieces = tokens[0];
let side = tokens[1];
let castles = tokens[2];
let ep = tokens[3];
let pieces = tokens.next().ok_or(invalid())?;
let side = tokens.next().ok_or(invalid())?;
let castles = tokens.next().ok_or(invalid())?;
let ep = tokens.next().ok_or(invalid())?;

for x in pieces.chars() {
match x {
Expand Down Expand Up @@ -436,19 +439,15 @@ impl FromStr for BoardBuilder {
cur_file = cur_file.right();
}
_ => {
return Err(Error::InvalidFen {
fen: value.to_string(),
});
return Err(invalid());
}
}
}
match side {
"w" | "W" => fen = fen.side_to_move(Color::White),
"b" | "B" => fen = fen.side_to_move(Color::Black),
_ => {
return Err(Error::InvalidFen {
fen: value.to_string(),
})
return Err(invalid())
}
}

Expand Down Expand Up @@ -482,7 +481,7 @@ impl FromStr for BoardBuilder {

impl From<&Board> for BoardBuilder {
fn from(board: &Board) -> Self {
let mut pieces = vec![];
let mut pieces = ArrayVec::<_, NUM_SQUARES>::new();
for sq in ALL_SQUARES.iter() {
if let Some(piece) = board.piece_on(*sq) {
let color = board.color_on(*sq).unwrap();
Expand Down
42 changes: 36 additions & 6 deletions src/castle_rights.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::hint::unreachable_unchecked;
use std::fmt;

use crate::bitboard::{BitBoard, EMPTY};
use crate::color::Color;
Expand Down Expand Up @@ -118,6 +119,15 @@ impl CastleRights {
}
}

fn to_str(&self) -> &'static str {
match *self {
CastleRights::NoRights => "",
CastleRights::KingSide => "k",
CastleRights::QueenSide => "q",
CastleRights::Both => "kq",
}
}

/// Convert the castle rights to an FEN compatible string.
///
/// ```
Expand All @@ -128,13 +138,9 @@ impl CastleRights {
/// assert_eq!(CastleRights::KingSide.to_string(Color::White), "K");
/// assert_eq!(CastleRights::QueenSide.to_string(Color::Black), "q");
/// ```
#[cfg(feature="std")]
pub fn to_string(&self, color: Color) -> String {
let result = match *self {
CastleRights::NoRights => "",
CastleRights::KingSide => "k",
CastleRights::QueenSide => "q",
CastleRights::Both => "kq",
};
let result = self.to_str();

if color == Color::White {
result.to_uppercase()
Expand All @@ -152,4 +158,28 @@ impl CastleRights {
_ => unsafe { unreachable_unchecked() },
}
}

pub fn with_color(&self, color: Color) -> CastleRightsWithColor {
CastleRightsWithColor { castle_rights: *self, color }
}
}

pub struct CastleRightsWithColor {
castle_rights: CastleRights,
color: Color,
}

impl fmt::Display for CastleRightsWithColor {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let s = self.castle_rights.to_str();

if self.color == Color::White {
for c in s.chars() {
write!(f, "{}", c.to_uppercase())?
}
Ok(())
} else {
write!(f, "{}", s)
}
}
}
14 changes: 14 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
#[cfg(feature="std")]
use failure::Fail;

/// Sometimes, bad stuff happens.
#[derive(Clone, Debug, Fail)]
#[cfg(feature="std")]
pub enum Error {
/// The FEN string is invalid
#[fail(display = "Invalid FEN string: {}", fen)]
Expand Down Expand Up @@ -33,3 +35,15 @@ pub enum Error {
#[fail(display = "The string specified does not contain a valid file")]
InvalidFile,
}

#[derive(Clone, Debug)]
#[cfg(not(feature="std"))]
pub enum Error {
InvalidFen,
InvalidBoard,
InvalidSquare,
InvalidSanMove,
InvalidUciMove,
InvalidRank,
InvalidFile,
}
8 changes: 8 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#![doc(html_root_url = "https://jordanbray.github.io/chess/")]
#![cfg_attr(not(feature="std"), no_std)]
//! # Rust Chess Library
//! This is a chess move generation library for rust. It is designed to be fast, so that it can be
//! used in a chess engine or UI without performance issues.
Expand All @@ -18,13 +19,18 @@
//! ```
//!

#[cfg(not(feature="std"))]
extern crate core as std;

mod board;
pub use crate::board::*;

mod bitboard;
pub use crate::bitboard::{BitBoard, EMPTY};

#[cfg(feature="std")]
mod cache_table;
#[cfg(feature="std")]
pub use crate::cache_table::*;

mod castle_rights;
Expand Down Expand Up @@ -66,7 +72,9 @@ pub use crate::movegen::MoveGen;

mod zobrist;

#[cfg(feature="std")]
mod game;
#[cfg(feature="std")]
pub use crate::game::{Action, Game, GameResult};

mod board_builder;
Expand Down
4 changes: 2 additions & 2 deletions src/movegen/movegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ impl SquareAndBitBoard {
}
}

pub type MoveList = NoDrop<ArrayVec<[SquareAndBitBoard; 18]>>;
pub type MoveList = NoDrop<ArrayVec<SquareAndBitBoard, 18>>;

/// An incremental move generator
///
Expand Down Expand Up @@ -95,7 +95,7 @@ impl MoveGen {
fn enumerate_moves(board: &Board) -> MoveList {
let checkers = *board.checkers();
let mask = !board.color_combined(board.side_to_move());
let mut movelist = NoDrop::new(ArrayVec::<[SquareAndBitBoard; 18]>::new());
let mut movelist = NoDrop::new(ArrayVec::<SquareAndBitBoard, 18>::new());

if checkers == EMPTY {
PawnType::legals::<NotInCheckType>(&mut movelist, &board, mask);
Expand Down
45 changes: 33 additions & 12 deletions src/piece.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,17 @@ impl Piece {
*self as usize
}

fn piece_char(&self) -> char {
match *self {
Piece::Pawn => 'p',
Piece::Knight => 'n',
Piece::Bishop => 'b',
Piece::Rook => 'r',
Piece::Queen => 'q',
Piece::King => 'k',
}
}

/// Convert a piece with a color to a string. White pieces are uppercase, black pieces are
/// lowercase.
///
Expand All @@ -48,6 +59,7 @@ impl Piece {
/// assert_eq!(Piece::Knight.to_string(Color::Black), "n");
/// ```
#[inline]
#[cfg(feature="std")]
pub fn to_string(&self, color: Color) -> String {
let piece = format!("{}", self);
if color == Color::White {
Expand All @@ -56,21 +68,30 @@ impl Piece {
piece
}
}

#[inline]
pub fn with_color(&self, color: Color) -> PieceWithColor {
PieceWithColor { piece: *self, color }
}
}

impl fmt::Display for Piece {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{}",
match *self {
Piece::Pawn => "p",
Piece::Knight => "n",
Piece::Bishop => "b",
Piece::Rook => "r",
Piece::Queen => "q",
Piece::King => "k",
}
)
write!(f, "{}", self.piece_char())
}
}

pub struct PieceWithColor {
piece: Piece,
color: Color,
}

impl fmt::Display for PieceWithColor {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.color == Color::White {
write!(f, "{}", self.piece.piece_char().to_uppercase())
} else {
write!(f, "{}", self.piece.piece_char())
}
}
}
Loading