# shakmaty
A Rust library for chess move generation
[![Build Status](https://travis-ci.org/niklasf/shakmaty.svg?branch=master)](https://travis-ci.org/niklasf/shakmaty)
[![crates.io](https://img.shields.io/crates/v/shakmaty.svg)](https://crates.io/crates/shakmaty)
[![docs.rs](https://docs.rs/shakmaty/badge.svg)](https://docs.rs/shakmaty)
## Features
- Generate legal moves:
```rust
use shakmaty::{Chess, Position};
let pos = Chess::default();
let legals = pos.legal_moves();
assert_eq!(legals.len(), 20);
```
- Play moves:
```rust
use shakmaty::{Square, Move, Role};
let pos = pos.play(&Move::Normal {
role: Role::Pawn,
from: Square::E2,
to: Square::E4,
capture: None,
promotion: None,
})?;
```
- Detect game end conditions: `pos.is_checkmate()`, `pos.is_stalemate()`,
`pos.is_insufficient_material()`, `pos.outcome()`.
- Read and write FENs, SANs and UCIs.
- Supports all Lichess variants: Standard chess, Chess960, Antichess, Atomic,
King of the Hill, Three-Check, Crazyhouse, Racing Kings and Horde. Provides
vocabulary to implement other variants.
- Bitboards and compact fixed shift magic attack tables.
- Probe Syzygy tablebases with [shakmaty-syzygy](https://crates.io/crates/shakmaty-syzygy).
## Documentation
[Read the documentation](https://docs.rs/shakmaty)
## Benchmarks
Simple [perft](https://www.chessprogramming.org/Perft) of the initial
position. No hashtables. i7-6850K CPU @ 3.60GHz.
| shakmaty 0.16.0 | 1.0 ms | 24.1 ms |
| [jordanbray/chess](https://crates.io/crates/chess) 3.1.1 | 0.8 ms | 18.6 ms |
| Stockfish 8 (x86-64-bmi2) | 4 ms | 33 ms |
It should be noted that Stockfish is not optimized for perft speed and also
maintains additional data structures for evaluation. Newer versions of
Stockfish put even less emphasis on this.
## Changelog
- 0.20.0
- Removed tracking of promoted pieces from `Board` and added
`Setup::promoted()` instead. This is used only by Crazyhouse. All other
variants will return `Bitboard(0)`. Removed `FenOpts::promoted()`
accordingly. Moved `fen::board_fen()` as a method to `Board`.
- Implemented Zobrist hashing.
- Fixed (or rather implemented) insufficient material detection for `Horde`.
- Added new feature `step` that implements the nightly `Step` trait for
`File`, `Rank` and `Square`.
- Let `Bitboard` respect `Display` formatting options.
- Fixed return type of `File::offset()`.
- Implemented `Eq` and `Hash` for `Chess` and `Pieces`.
- 0.19.0
- Update `arrayvec` to 0.7.x. `MoveList` is now using const generics.
- Derive `Hash` for `Move`, `Outcome`, and `Fen`.
- Eliminate unsafe usage where no longer required for performance. Justify
remaining cases.
- 0.18.0
- Remove `f32`, `f64`, `u128`, and `i128` conversions.
- Use `std::num::TryFromIntError`.
- Functions now return `MoveList` instead of using it as an out parameter.
Return value optimization by hand is no longer required.
- Introduce `ByColor`, used as `Material` and `ByColor<RemainingChecks>`.
- Introduce `PlayError`.
- Renamed `variants` module to `variant`. Now gated behind a non-default
feature `variant`.
- 0.17.2
- Parse `Uci::to_move()` where king captures unmoved rook.
- 0.17.1
- Also reject checker aligned with king and en passant square with
`PositionErrorKinds::IMPOSSIBLE_CHECK`.
- 0.17.0
- Introduce `CastlingMode`, now required for
`FromSetup::from_setup(..., mode)`, the `VariantPosition` analogon,
`Fen::position(mode)`, and exposed by `Castles::mode()`.
- `Uci::from_move()` now takes the mode as context instead of the position.
Give `pos.castles().mode()` for the old behavior.
- Add `Uci::from_standard()`.
- Rework `PositionError`. The original error kinds are available as
`PositionError::kinds()`. There are now methods to safely ignore particular
errors.
- Reject setups with impossible (i.e., too much) material with the new
`PositionErrorKinds::IMPOSSIBLE_MATERIAL`. Can be ignored using
`PositionError::ignore_impossible_material()` for the previous behavior.
- Reject setups with multiple aligned sliding checkers with the new
`PositionErrorKinds::IMPOSSIBLE_CHECK`.
- Rename `BAD_CASTLING_RIGHTS` to `INVALID_CASTLING_RIGHTS`.
- Remove `IllegalMoveError`. In the context of UCI validation, replace with
`IllegalUciError`. `Position::play()` instead returns the original position
as the error.
- Change `fullmoves` from `u32` to `NonZeroU32` everywhere.
- Remove public `Castles::from_setup()`.
- Remove `Square::with_rank_of()`.
- Remove `Giveaway` in favor of `Antichess` (where players start without
castling rights).
- Fix `swap_turn()` if en passant square exists. Would always fail, now
discards the en passant square.
- Add `Move::to_uci()` convenience method.
- Add `CastlingSide::{king,rook}_to_file()`.
- Add `Variant::distinguishes_promoted()`.
- Add `Variant::uci()` and `Variant::from_uci()`.
- Future proof error types (remove some implemented traits and available
constructors).
- 0.16.4
- Fix insufficient material detection with same-color bishops on both sides.
- Document limitations of `Position::is_irreversible()`. Moves that cede
en passant are now considered irreversible.
- 0.16.3
- Implement `From<Role>` for nonzero integer types.
- Performance: Remove internal `BB_BETWEEN` table and compute it from rays at
runtime, to improve cache efficiency.
- Support Miri.
- 0.16.2
- Fix Racing Kings game end detection: Black cannot catch up if their own
pieces block the goal.
- Pawn drops in Crazyhouse are now considered zeroing.
- 0.16.1
- Fix (impossible) Crazyhouse insufficient material.
- Fix (impossible) castling rights of exploded king in Atomic chess.
- 0.16.0
- Update `arrayvec` to 0.5.x, which comes with significant performance
improvements.
- The default `Giveaway` position now has castling rights.
- 0.15.3
- Follow FICS rules in Atomic castling edge cases.
- Use `#[repr(align)] enum` and `reverse_bits()` stabilized in Rust 1.37.
- 0.15.2
- In Horde chess, allow double pawn moves from the first rank.
- Added `{Square,Bitboard}::{flip_anti_diagonal,rotate_90,rotate_180,rotate_270}()`.
- 0.15.1
- FEN parser was expecting `~` before promoted pieces, but it should be
after.
- 0.15.0
- Moved `Position::from_setup()` to a seperate new trait `FromSetup`.
- Square and file/rank index calculations are now performed with `u32` and
`i32`, which is more performant than using the narrower types `u8` and
`i8`. The types are still `#[repr(u8)]`.
- Renamed `Square::combine()` to `Square::with_rank_of()`.
- Added `Fen::from_setup()`.
- Added `FenOpts::scid()` for Scid/Lichess compatible FEN formatting.
Of course the parser also accepts these formats.
- Added `variant::Variant` and `VariantPosition` for runtime selected
chess variants. Limited to the built in variants.
- Added `{Material,MaterialSide}::is_empty()`.
- 0.14.1
- `TryFrom` now available on stable.
- 0.14.0
- `SanPlus::from_move()` no longer requires the move to be legal, which
was an undocumented requirement. The new
`SanPlus::from_move_and_play_unchecked()` is closest to the previous
behavior.
- Added `San::disambiguate()` and `SanSuffix::from_position()`.
- Implement `TryFrom` for various types on nightly.
- Implement `Add`, `AddAssign`, `Sub`, `SubAssign` for `Material` and
`MaterialSide`.
- Added `CastlingSide::from_{king|queen}_side()`.
- Use `u32` for `depth` argument of `perft()`.
- 0.13.1
- Performance improvements on nightly (aligned `Move` enum).
- 0.13.0
- Replaced `SanPlus::check` and `SanPlus::checkmate` with `san::Suffix` enum.
- Renamed `{Rank,File}::rotate()` to `flip_diagonal()`.
- Renamed `Bitboard::flip()` to `toggle()`.
- Added `Square::coords()`.
- Added `Bitboard::flip_{vertical,horizontal,diagonal}()`.
- Added `Position::promotion_moves()`.
- Derive `Hash` on `Board`, `FenOpts`, `San`, `SanPlus`, `Suffix`, `Color`,
`Role`, `Piece`, `RemainingChecks`, `CastlingSide`, and `Uci`.
- Minimum Rust version 1.31.0.
- 0.12.0
- `Setup::halfmove_clock()` is now `Setup::halfmoves()`.
- New conversions: `f32::from(file)`, `f64::from(rank)`.
- Replace `Pockets` and `Pocket` by more general `Material` and
`MaterialSide`. Note that their `Display` and `FromStr` implementations
differ.
- Unify naming of error types.
- 0.11.2
- Fix Atomic insufficient material: KQN can mate.
- 0.11.1
- Fix Chess960 should not allow a-side castling over a blocking h-side rook.
- 0.11.0
- `Outcome` is now `Copy`.
- `Position::castling_uncovers_rank_attack()` is no longer public.
- 0.10.0
- Add `File`, `Rank`. These are now returned by `Square::{file, rank}`.
`Square::from_coords(file, rank)` takes the new types and is no longer
fallible.
- `Bitboard` is now `IntoIterator` instead of `Iterator` itself.
Methods `Bitboard::{first, last, count, is_empty}` remain.
- `Bitboard::{add, flip, discard, with, without}` are now generic over
`Into<Bitboard>`. Alternative methods `*_all` have been removed.
- `Bitboard::relative_shift(color, shift: u8)` now takes `u32`.
- `shakmaty::CarryRippler` is now `shakmaty::bitboard::CarryRippler`.
- Add new methods:
`Bitboard::{pop_front, pop_back, is_disjoint, is_subset, is_superset}`.
- Add `Position::has_insufficient_material(color)`.
- 0.9.0
- Remove `uci`, `chess960_uci`, `san` and `san_plus` that were deprecated
in 0.8.1.
- Rename `*::from_bytes()` to `*::from_ascii()`.
- Take small copy types by value: `Piece::char()`, `CastlingSide::*`.
- Add `Castles::has(color, side)`.
- `fen::{board_fen, epd, fen}` are now shortcuts for formatting with
default options.
- Minimum rust version 1.27.0 (i128 conversions again, fused iterators again,
`Option::filter()`, `dyn Trait`).
- Eliminate many uses of unsafe, including `TrustedLen` impls, at minor cost.
- 0.8.1
- Make `Role` discriminants public.
- Put `San`, `SanPlus` and `Uci` constructors on `San`, `SanPlus` and `Uci`
respectively.
- 0.8.0
- Revert fused iterators and u128. Minimum Rust version back to 1.23.0.
- Change `Role` discriminants. Now starting with `Pawn = 1`.
- Performance improvements (~12% faster perft).
- Switch benchmarks to `criterion.rs`.
- 0.7.2
- Add `Outcome.winner()`.
- 0.7.1
- Minimum Rust version 1.26.0 (fused iterators, u128 conversions).
- 0.7.0
- Reintroduce the remaining Lichess variants: `Crazyhouse`, `KingOfTheHill`,
`ThreeCheck`, `Horde`, `RacingKings`.
- Expose `Position.castles()` and replace `Position.is_chess960()` with
`Position.castles().is_chess960()`.
- Fix insufficient material: KNvK was not given as drawn due to a typo.
- Fix insufficient material in `Atomic`: Two knights of different colors
are not safe.
- Let `Pockets.count()` and `Pocket.count()` return `usize`.
- 0.6.7
- Giveaway starting position should have no castling rights.
- 0.6.6
- Fix missing king promotions in Giveaway.
- 0.6.5
- Validate color of missing king in atomic chess.
- Clear move buffers before generating variant moves.
- 0.6.4
- Reintroduce `Giveaway` and `Atomic` chess variants.
- 0.6.3
- New method `Move.is_zeroing()`.
- 0.6.2
- Make unit error types (`InvalidSquareName`, `InvalidUci`, `InvalidSan`)
completely public.
- Documentation, coding style and debugging tweaks.
- 0.6.1
- Expose `attacks::bishop_mask` and `attacks::rook_mask`.
- Eliminate almost all unchecked indexing.
- 0.6.0
- Split `impl From<Move> for Uci` into `uci()` and `chess960_uci()`.
- Fix display of pawn drops.
- Move generating methods clear the move buffer (and therefor no longer panic on too full buffers).
- Added `Position.is_chess960()`, `Bitboard.without_all()`, `Role.upper_char()`, `Board.stepper()`.
- 0.5.1
- Fix `Uci::to_move()` for en passant moves. Thanks zxqfl.
- 0.5.0
- Use `u64` instead of `usize` for `perft()`.
- Export error type `InvalidSquareName`.
- New methods: `CastlingSide.is_{queen|king}_side()`, `San.matches()`, `Move.is_capture()`, `Move.is_promotion()`, `Move.castling_side()`, `Position.is_check()`.
- Derive `Ord` and `PartialOrd` for `Role`.
- Support running benchmarks on stable.
- 0.4.2
- Fix build error on beta due to the new nightly `option_filter` feature.
- Fix unterminated code block in documentation.
- 0.4.1
- Fix build error due to the new nightly
[`option_filter`](https://github.com/rust-lang/rust/issues/45860) feature.
- 0.4.0
- Rename `Color::from_bool()` to `Color::from_white()`,
add `Color::from_black()`.
- Add `Move::role()`, `Move::is_en_passant()` and `Move::is_castle()`.
- Add `Position::en_passant_moves()` and `Position::capture_moves()`.
- Implement `BitXor<bool>` for `Color`.
- Implement `FusedIterator` and `TrustedLen` on `Bitboard`.
- 0.3.0
- Switch to `#[repr(i8)]` for `Square`. Implement all lossless integer
conversions `From<Square>`.
- Add `Square::flip_horizontal()`, `flip_vertical()` and `flip_diagonal()`.
- Efficiently implement `CarryRippler::last()` by @nvzqz.
- Eliminate some unchecked indexing by @nvzqz.
- Faster ASCII case conversions and tests by @nvzqz.
- 0.2.0
- `Square` is now a `#[repr(u8)]` enum.
- Use `bitflags` for `PositionError`.
- Rename `RemainingChecks::subtract()` to `decrement()`.
- Add `Position::swap_turn()`.
- 0.1.0
- First release with support for stable Rust.
## License
Shakmaty is licensed under the GPL-3.0 (or any later version at your option).
See the COPYING file for the full license text.