Struct cozy_chess::Board

source ·
pub struct Board { /* private fields */ }
Expand description

A chessboard.

This keeps about as much state as a FEN string, and does not keep track of history.

Implementations§

source§

impl Board

source

pub fn generate_moves(&self, listener: impl FnMut(PieceMoves) -> bool) -> bool

Generate all legal moves given a position in no particular order. To retrieve the moves, a listener callback must be passed that receives compact PieceMoves. This does not guarantee that each PieceMoves value has a unique from square. However, each PieceMoves value will have at least one move. The listener will be called a maximum of 18 times. The listener can abort the movegen early by returning true. In this case, this function also returns true.

§Examples
let board = Board::default();
let mut total_moves = 0;
board.generate_moves(|moves| {
    // Done this way for demonstration.
    // Actual counting is best done in bulk with moves.len().
    for _mv in moves {
        total_moves += 1;
    }
    false
});
assert_eq!(total_moves, 20);
source

pub fn generate_moves_for( &self, mask: BitBoard, listener: impl FnMut(PieceMoves) -> bool ) -> bool

Version of Board::generate_moves moves that generates moves for only a subset of pieces.

§Examples
let board = Board::default();
let knights = board.pieces(Piece::Knight);
let mut knight_moves = 0;
board.generate_moves_for(knights, |moves| {
    // Done this way for demonstration.
    // Actual counting is best done in bulk with moves.len().
    for _mv in moves {
        knight_moves += 1;
    }
    false
});
assert_eq!(knight_moves, 4);

See if a move is legal.

§Examples
let mut board = Board::default();
assert!(board.is_legal("e2e4".parse().unwrap()));
assert!(!board.is_legal("e1e8".parse().unwrap()));
source§

impl Board

source

pub fn from_fen(fen: &str, shredder: bool) -> Result<Self, FenParseError>

Parse a FEN string. If shredder is true, it parses Shredder FEN instead. You can also parse the board with FromStr, which parses both FEN types.

§Examples
§FEN
const STARTPOS: &str = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
let board = Board::from_fen(STARTPOS, false).unwrap();
assert_eq!(format!("{}", board), STARTPOS);
§Shredder FEN
const STARTPOS: &str = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w HAha - 0 1";
let board = Board::from_fen(STARTPOS, true).unwrap();
assert_eq!(format!("{:#}", board), STARTPOS);
source§

impl Board

source

pub fn startpos() -> Self

Get a board with the default start position.

§Examples
let startpos = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1".parse().unwrap();
let board = Board::default();
assert_eq!(board, startpos);
source

pub fn chess960_startpos(scharnagl_number: u32) -> Self

Get a board with a chess960 start position. Converts a Scharnagl number to its corresponding position.

§Panics

Panic if the Scharnagl number is invalid (not within the range 0..960).

§Examples
let startpos = Board::default();
// 518 is the Scharnagl number for the default start position.
let board = Board::chess960_startpos(518);
assert_eq!(board, startpos);
source

pub fn double_chess960_startpos( white_scharnagl_number: u32, black_scharnagl_number: u32 ) -> Self

Get a board with a double chess960 start position. Uses two Scharnagl numbers for the initial setup for white and the initial setup for black.

§Panics

Panic if either Scharnagl number is invalid (not within the range 0..960).

§Examples
let startpos = Board::default();
// 518 is the Scharnagl number for the default start position.
let board = Board::double_chess960_startpos(518, 518);
assert_eq!(board, startpos);
source

pub fn pieces(&self, piece: Piece) -> BitBoard

Get a BitBoard of all the pieces of a certain type.

§Examples
let board = Board::default();
let pawns = board.pieces(Piece::Pawn);
assert_eq!(pawns, bitboard! {
    . . . . . . . .
    X X X X X X X X
    . . . . . . . .
    . . . . . . . .
    . . . . . . . .
    . . . . . . . .
    X X X X X X X X
    . . . . . . . .
});
source

pub fn colors(&self, color: Color) -> BitBoard

Get a BitBoard of all the pieces of a certain color.

§Examples
let board = Board::default();
let white_pieces = board.colors(Color::White);
assert_eq!(white_pieces, bitboard! {
    . . . . . . . .
    . . . . . . . .
    . . . . . . . .
    . . . . . . . .
    . . . . . . . .
    . . . . . . . .
    X X X X X X X X
    X X X X X X X X
});
source

pub fn colored_pieces(&self, color: Color, piece: Piece) -> BitBoard

Get a BitBoard of all the pieces of a certain color and type. Shorthand for board.colors(color) & board.pieces(piece).

§Examples
let board = Board::default();
let white_pawns = board.colored_pieces(Color::White, Piece::Pawn);
assert_eq!(white_pawns, bitboard! {
    . . . . . . . .
    . . . . . . . .
    . . . . . . . .
    . . . . . . . .
    . . . . . . . .
    . . . . . . . .
    X X X X X X X X
    . . . . . . . .
});
source

pub fn occupied(&self) -> BitBoard

Get a BitBoard of all the pieces on the board.

§Examples
let board = Board::default();
assert_eq!(board.occupied(), bitboard! {
    X X X X X X X X
    X X X X X X X X
    . . . . . . . .
    . . . . . . . .
    . . . . . . . .
    . . . . . . . .
    X X X X X X X X
    X X X X X X X X
});
source

pub fn side_to_move(&self) -> Color

Get the current side to move.

§Examples
let mut board = Board::default();
assert_eq!(board.side_to_move(), Color::White);
board.play("e2e4".parse().unwrap());
assert_eq!(board.side_to_move(), Color::Black);
source

pub fn castle_rights(&self, color: Color) -> &CastleRights

Get the CastleRights for some side.

§Examples
let mut board = Board::default();
let rights = board.castle_rights(Color::White);
assert_eq!(rights.short, Some(File::H));
assert_eq!(rights.long, Some(File::A));
board.play("e2e4".parse().unwrap());
board.play("e7e5".parse().unwrap());
board.play("e1e2".parse().unwrap());
let rights = board.castle_rights(Color::White);
assert_eq!(rights.short, None);
assert_eq!(rights.long, None);
source

pub fn en_passant(&self) -> Option<File>

Get the en passant file, if it exists.

§Examples
let mut board: Board = "1k2r3/2p5/p4p2/Pb6/1p1b1P1R/1P6/2P3PP/5K2 w - - 1 36"
    .parse().unwrap();
assert_eq!(board.en_passant(), None);
board.play("c2c4".parse().unwrap());
assert_eq!(board.en_passant(), Some(File::C));
board.play("b4c3".parse().unwrap());
assert_eq!(board.en_passant(), None);
source

pub fn hash(&self) -> u64

Get the incrementally updated position hash. Does not include the halfmove clock or fullmove number.

§Examples
let mut board = Board::default();
board.play("e2e4".parse().unwrap());
board.play("e7e5".parse().unwrap());
board.play("e1e2".parse().unwrap());
board.play("e8e7".parse().unwrap());
let expected: Board = "rnbq1bnr/ppppkppp/8/4p3/4P3/8/PPPPKPPP/RNBQ1BNR w - - 2 3"
   .parse().unwrap();
assert_eq!(expected.hash(), board.hash());
source

pub fn hash_without_ep(&self) -> u64

Get the incrementally updated position hash without en passant information. Does not include the halfmove clock or fullmove number. This may be used for equivalence checks if en passant is not relevant.

§Examples
let has_ep: Board = "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1"
   .parse().unwrap();
let no_ep: Board = "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq - 4 3"
   .parse().unwrap();
assert_ne!(has_ep.hash(), no_ep.hash());
assert_eq!(has_ep.hash_without_ep(), no_ep.hash());
source

pub fn pinned(&self) -> BitBoard

Get the pinned pieces for the side to move. Note that this counts pieces regardless of color. This counts any piece preventing check on our king.

§Examples
let board: Board = "8/8/1q4k1/5p2/1n6/3B4/1KP3r1/8 w - - 0 1".parse().unwrap();
assert_eq!(board.pinned(), bitboard! {
    . . . . . . . .
    . . . . . . . .
    . . . . . . . .
    . . . . . . . .
    . X . . . . . .
    . . . . . . . .
    . . X . . . . .
    . . . . . . . .
});
source

pub fn checkers(&self) -> BitBoard

Get the pieces currently giving check.

§Examples
let mut board: Board = "1r4r1/pbpknp1p/1b3P2/8/8/B1PB1q2/P4PPP/3R2K1 w - - 0 22"
    .parse().unwrap();
assert_eq!(board.checkers(), BitBoard::EMPTY);
board.play("d3f5".parse().unwrap());
assert_eq!(board.checkers(), bitboard! {
    . . . . . . . .
    . . . . . . . .
    . . . . . . . .
    . . . . . X . .
    . . . . . . . .
    . . . . . . . .
    . . . . . . . .
    . . . X . . . .
});
source

pub fn halfmove_clock(&self) -> u8

Get the halfmove clock.

§Examples
let mut board = Board::default();
assert_eq!(board.halfmove_clock(), 0);
board.play("e2e4".parse().unwrap());
board.play("e7e5".parse().unwrap());
// Remains at zero for pawn moves
assert_eq!(board.halfmove_clock(), 0);
board.play("e1e2".parse().unwrap());
// Non-pawn move
assert_eq!(board.halfmove_clock(), 1);
source

pub fn set_halfmove_clock(&mut self, n: u8)

Set the halfmove clock.

§Panics

This method panics if the argument is larger than 100.

§Examples
let mut board: Board = "rnbqkb1r/pppppppp/5n2/8/8/5N2/PPPPPPPP/RNBQKB1R w KQkq - 2 2"
    .parse().unwrap();
assert_eq!(board.halfmove_clock(), 2);
board.set_halfmove_clock(0);
assert_eq!(board.halfmove_clock(), 0);
source

pub fn fullmove_number(&self) -> u16

Get the fullmove number.

§Examples
let mut board = Board::default();
// The fullmove number starts at one.
assert_eq!(board.fullmove_number(), 1);
board.play("e2e4".parse().unwrap());
board.play("e7e5".parse().unwrap());
board.play("e1e2".parse().unwrap());
// 3 plies is 1.5 moves, which rounds down
assert_eq!(board.fullmove_number(), 2);
source

pub fn set_fullmove_number(&mut self, n: u16)

Set the fullmove number.

§Panics

This method panics if the argument is zero.

§Examples
let mut board = Board::default();
// The fullmove number starts at one.
assert_eq!(board.fullmove_number(), 1);
board.set_fullmove_number(2);
assert_eq!(board.fullmove_number(), 2);
source

pub fn piece_on(&self, square: Square) -> Option<Piece>

Get the Piece on square, if there is one.

§Examples
let board = Board::default();
assert_eq!(board.piece_on(Square::E1), Some(Piece::King));
source

pub fn color_on(&self, square: Square) -> Option<Color>

Get the Color of the piece on square, if there is one.

§Examples
let board = Board::default();
assert_eq!(board.color_on(Square::E1), Some(Color::White));
source

pub fn king(&self, color: Color) -> Square

Get the king square of some side.

§Examples
let board = Board::default();
assert_eq!(board.king(Color::White), Square::E1);
source

pub fn status(&self) -> GameStatus

Get the status of the game. Note that this game may still be drawn from threefold repetition. The game may also be drawn from insufficient material cases such as bare kings; This method does not detect such cases. If the game is won, the loser is the current side to move.

§Examples
§Checkmate
let mut board = Board::default();
const MOVES: &[&str] = &[
    "e2e4", "e7e5", "g1f3", "b8c6", "d2d4", "e5d4",
    "f3d4", "f8c5", "c2c3", "d8f6", "d4c6", "f6f2"
];
for mv in MOVES {
    assert_eq!(board.status(), GameStatus::Ongoing);
    board.play(mv.parse().unwrap());
}
assert_eq!(board.status(), GameStatus::Won);
let winner = !board.side_to_move();
assert_eq!(winner, Color::Black);
§Stalemate
let mut board = Board::default();
const MOVES: &[&str] = &[
    "c2c4", "h7h5", "h2h4", "a7a5", "d1a4",
    "a8a6", "a4a5", "a6h6", "a5c7", "f7f6",
    "c7d7", "e8f7", "d7b7", "d8d3", "b7b8",
    "d3h7", "b8c8", "f7g6", "c8e6"
];
for mv in MOVES {
    assert_eq!(board.status(), GameStatus::Ongoing);
    board.play(mv.parse().unwrap());
}
assert_eq!(board.status(), GameStatus::Drawn);
§50 move rule
let mut board = Board::default();
board.play("e2e4".parse().unwrap());
board.play("e7e5".parse().unwrap());
const MOVES: &[&str] = &["e1e2", "e8e7", "e2e1", "e7e8"];
for mv in MOVES.iter().cycle().take(50 * 2) {
    assert_eq!(board.status(), GameStatus::Ongoing);
    board.play(mv.parse().unwrap());
}
assert_eq!(board.status(), GameStatus::Drawn);
source

pub fn same_position(&self, other: &Self) -> bool

Check if two positions are equivalent based on the FIDE definition. This differs from the Eq implementation in that:

  • It does not check the halfmove clock or fullmove number
  • It ignores the state of the en passant square if it does not apply (capture would not be legal) This method can be used as a strict check for threefold repetition.
§Examples
let board_a = "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1"
    .parse::<Board>().unwrap();
let board_b = "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq - 4 3"
    .parse::<Board>().unwrap();
assert!(board_a != board_b); // Differing EP and halfmove clock
assert!(board_a.same_position(&board_b)); // Identical by FIDE rules
 
let board_c = "rnbqkb1r/ppp1pppp/5n2/3pP3/8/8/PPPP1PPP/RNBQKBNR w KQkq d6 0 3"
    .parse::<Board>().unwrap();
let board_d = "rnbqkb1r/ppp1pppp/5n2/3pP3/8/8/PPPP1PPP/RNBQKBNR w KQkq - 4 5"
    .parse::<Board>().unwrap();
assert!(!board_c.same_position(&board_d)); // En passant is legal here
source

pub fn null_move(&self) -> Option<Board>

Attempt to play a null move, returning a new board if successful.

§Examples
let mut board = Board::default();
board.play("f2f4".parse().unwrap());
board.play("e7e5".parse().unwrap());
assert_eq!(board.side_to_move(), Color::White);
board = board.null_move().unwrap();
assert_eq!(board.side_to_move(), Color::Black);
board.play("d8h4".parse().unwrap());
// Can't leave the king in check
assert!(board.null_move().is_none());
source

pub fn play(&mut self, mv: Move)

Play a move while checking its legality. Note that this only supports Chess960 style castling. This method does not account for the 50 move rule, and checks only whether the move would be legal. The halfmove clock is capped at 100 and the fullmove number is capped at u16::MAX.

§Panics

This is guaranteed to panic if the move is illegal. See Board::try_play for a non-panicking variant. See Board::play_unchecked for a faster variant that’s not guaranteed to panic on illegal moves.

§Examples
let mut board = Board::default();
board.play("e2e4".parse().unwrap());
board.play("e7e5".parse().unwrap());
board.play("e1e2".parse().unwrap());
board.play("e8e7".parse().unwrap());
const EXPECTED: &str = "rnbq1bnr/ppppkppp/8/4p3/4P3/8/PPPPKPPP/RNBQ1BNR w - - 2 3";
assert_eq!(format!("{}", board), EXPECTED);
§Illegal moves
let mut board = Board::default();
board.play("e1e8".parse().unwrap());
source

pub fn try_play(&mut self, mv: Move) -> Result<(), IllegalMoveError>

Non-panicking version of Board::play. Tries to play a move, returning Ok(()) on success.

§Errors

Errors with IllegalMoveError if the move was illegal.

source

pub fn play_unchecked(&mut self, mv: Move)

Unchecked version of Board::play. Use this method with caution; Only legal moves should ever be passed to this method. Playing illegal moves may corrupt the board state, causing panics. However, it will not cause undefined behaviour.

§Panics

This may panic if the move is illegal. Additionally, playing illegal moves may corrupt the board state, which may cause further panics. See Board::play for a variant guaranteed to panic on illegal moves.

§Examples
let mut board = Board::default();
board.play_unchecked("e2e4".parse().unwrap());
board.play_unchecked("e7e5".parse().unwrap());
board.play_unchecked("e1e2".parse().unwrap());
board.play_unchecked("e8e7".parse().unwrap());
const EXPECTED: &str = "rnbq1bnr/ppppkppp/8/4p3/4P3/8/PPPPKPPP/RNBQ1BNR w - - 2 3";
assert_eq!(format!("{}", board), EXPECTED);

Trait Implementations§

source§

impl Clone for Board

source§

fn clone(&self) -> Board

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Debug for Board

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Default for Board

source§

fn default() -> Self

Returns the “default value” for a type. Read more
source§

impl Display for Board

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Display the board. You can use the alternate format mode for Shredder FEN.

§Examples
§FEN
const STARTPOS: &str = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
let board = Board::default();
assert_eq!(format!("{}", board), STARTPOS);
§Shredder FEN
const STARTPOS: &str = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w HAha - 0 1";
let board = Board::default();
assert_eq!(format!("{:#}", board), STARTPOS);
source§

impl FromStr for Board

source§

fn from_str(fen: &str) -> Result<Self, Self::Err>

Parse the board. This method will parse both regular FENs and Shredder FENs. See also: Board::from_fen.

§Examples
const STARTPOS: &str = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
let board: Board = STARTPOS.parse().unwrap();
assert_eq!(format!("{}", board), STARTPOS);
§

type Err = FenParseError

The associated error which can be returned from parsing.
source§

impl Hash for Board

source§

fn hash<__H: Hasher>(&self, state: &mut __H)

Feeds this value into the given Hasher. Read more
1.3.0 · source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where H: Hasher, Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
source§

impl PartialEq for Board

source§

fn eq(&self, other: &Board) -> bool

This method tests for self and other values to be equal, and is used by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
source§

impl Eq for Board

source§

impl StructuralPartialEq for Board

Auto Trait Implementations§

§

impl Freeze for Board

§

impl RefUnwindSafe for Board

§

impl Send for Board

§

impl Sync for Board

§

impl Unpin for Board

§

impl UnwindSafe for Board

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.