1
0
Fork 0

update docs

This commit is contained in:
Paul-Nicolas Madelaine 2025-11-18 06:49:33 +01:00
parent 671ff331d3
commit b45952b6b7
5 changed files with 47 additions and 43 deletions

View file

@ -123,6 +123,9 @@ impl File {
} }
} }
/// ## Safety
///
/// The caller must ensure that `index < 8`.
#[inline] #[inline]
pub const unsafe fn new_unchecked(index: u8) -> Self { pub const unsafe fn new_unchecked(index: u8) -> Self {
debug_assert!(index < 8); debug_assert!(index < 8);
@ -135,9 +138,9 @@ impl File {
} }
#[inline] #[inline]
pub const fn from_ascii(c: u8) -> Option<Self> { pub const fn from_ascii(file: u8) -> Option<Self> {
if c <= b'h' { if file <= b'h' {
match c.checked_sub(b'a') { match file.checked_sub(b'a') {
Some(i) => Some(unsafe { Self::new_unchecked(i) }), Some(i) => Some(unsafe { Self::new_unchecked(i) }),
None => None, None => None,
} }
@ -213,6 +216,9 @@ impl Rank {
} }
} }
/// ## Safety
///
/// The caller must ensure that `index < 8`.
#[inline] #[inline]
pub const unsafe fn new_unchecked(index: u8) -> Self { pub const unsafe fn new_unchecked(index: u8) -> Self {
debug_assert!(index < 8); debug_assert!(index < 8);
@ -225,9 +231,9 @@ impl Rank {
} }
#[inline] #[inline]
pub const fn from_ascii(c: u8) -> Option<Self> { pub const fn from_ascii(rank: u8) -> Option<Self> {
if c <= b'8' { if rank <= b'8' {
match c.checked_sub(b'1') { match rank.checked_sub(b'1') {
Some(i) => Some(unsafe { Self::new_unchecked(i) }), Some(i) => Some(unsafe { Self::new_unchecked(i) }),
None => None, None => None,
} }

View file

@ -5,19 +5,18 @@
//! //!
//! ## Overview //! ## Overview
//! //!
//! The most important type in eschac is [`Position`](position::Position), it represents a chess //! In eschac, a chess position is represented with the [`Position`](position::Position) type.
//! position from which legal moves are generated. [`Position::new`](position::Position::new) //! [`Position::new`](position::Position::new) returns the starting position of a chess game, and
//! returns the starting position of a chess game, and arbitrary positions can be built using the //! arbitrary positions can be built using the [`Setup`](setup::Setup) type. This type must be
//! [`Setup`](setup::Setup) type, but they must be validated and converted to a //! validated and converted to a [`Position`](position::Position) to generate moves as eschac does
//! [`Position`](position::Position) to generate moves as eschac does not handle certain illegal -- //! not handle certain unreachable positions (see
//! as in unreachable in a normal game -- positions (see //! [`Setup::into_position`](setup::Setup::into_position) to know more). Legal moves are generated
//! [`IllegalPositionReason`](setup::IllegalPositionReason) to know more). Legal moves are then //! using the [`Position::legal_moves`](position::Position::legal_moves) method or obtained from
//! generated using the [`Position::legal_moves`](position::Position::legal_moves) method or //! chess notation like [`UciMove`](uci::UciMove) or [`San`](san::San). Moves are represented with
//! obtained from chess notation like [`UciMove`](uci::UciMove) or [`San`](san::San). Moves are //! the [`Move<'l>`](moves::Move) type, which holds a reference to the origin position (this
//! represented with the [`Move<'l>`](moves::Move) type, which holds a reference to the origin //! ensures the move is played on the correct position). Finally, moves are played with
//! position (hence the lifetime), this ensures the move is played on the correct position. //! [`Move::make`](moves::Move::make) which returns a new [`Position`](position::Position), and on
//! Finally, moves are played using the [`Move::make`](moves::Move::make) method which returns a new //! it goes.
//! [`Position`](position::Position), and on it goes.
//! //!
//! ## Example //! ## Example
//! //!

View file

@ -205,6 +205,8 @@ impl<'l> Move<'l> {
/// [composition](https://lichess.org/editor/R6R/3Q4/1Q4Q1/4Q3/2Q4Q/Q4Q2/pp1Q4/kBNN1KB1_w_-_-_0_1) /// [composition](https://lichess.org/editor/R6R/3Q4/1Q4Q1/4Q3/2Q4Q/Q4Q2/pp1Q4/kBNN1KB1_w_-_-_0_1)
/// with 218 legal moves. 60 years later, this was proven to be optimal by /// with 218 legal moves. 60 years later, this was proven to be optimal by
/// [Tobs40](https://lichess.org/@/Tobs40/blog/why-a-reachable-position-can-have-at-most-218-playable-moves/a5xdxeqs). /// [Tobs40](https://lichess.org/@/Tobs40/blog/why-a-reachable-position-can-have-at-most-218-playable-moves/a5xdxeqs).
/// Even though the [`Position`] type can represent more positions than just reachable positions,
/// the proof still holds, as its definition of a position is even less restrictive.
#[must_use] #[must_use]
pub struct Moves<'l> { pub struct Moves<'l> {
position: &'l Position, position: &'l Position,

View file

@ -31,16 +31,16 @@ use core::ops::ControlFlow;
/// be applied unambiguously or when doing so enables some code optimisation. See /// be applied unambiguously or when doing so enables some code optimisation. See
/// [`IllegalPositionReason`] for details about rejected positions. /// [`IllegalPositionReason`] for details about rejected positions.
/// ///
/// ## Move generation & play /// ## Move generation & Play
/// ///
/// The [`legal_moves`](Position::legal_moves) method generates the list of all legal moves on the /// The [`legal_moves`](Position::legal_moves) method generates the list of all legal moves on the
/// position. [`UciMove::to_move`] and [`San::to_move`] can also be used to convert chess notation /// position. [`UciMove::to_move`] and [`San::to_move`] can also be used to convert chess notation
/// to playable moves. /// to playable moves.
/// ///
/// Playing a move is done through a copy-make interface. [`legal_moves`](Position::legal_moves) /// Playing a move is done through a copy-make interface. [`legal_moves`](Position::legal_moves)
/// returns a sequence of [`Move`] objects. Moves hold a reference to the position from where they /// returns a sequence of [`Move<'l>`](Move) objects. Moves hold a reference to the position
/// were computed. They can be played without further checks and without potential panics using /// from where they were computed. They can be played without further checks and without potential
/// [`Move::make`]. /// panics using [`Move::make`].
/// ///
/// ## En passant & Equality /// ## En passant & Equality
/// ///
@ -197,10 +197,9 @@ impl Position {
/// Discards the en passant target square. /// Discards the en passant target square.
/// ///
/// This function is useful to check for position equality, notably when implementing FIDE's /// This function will remove the en passant target square even if taking en passant is legal.
/// draw by repetition rules. Note that this function will remove the en passant target square /// If this is not desirable, it is the caller's responsibility to rule out the legality of en
/// even if taking en passant is legal. If this is not desirable, it is the caller's /// passant before calling this function.
/// responsibility to rule out the legality of en passant before calling this function.
#[inline] #[inline]
pub fn remove_en_passant_target_square(&mut self) { pub fn remove_en_passant_target_square(&mut self) {
self.0.en_passant = OptionSquare::None; self.0.en_passant = OptionSquare::None;

View file

@ -12,8 +12,8 @@ use alloc::string::String;
/// **A builder type for chess positions.** /// **A builder type for chess positions.**
/// ///
/// This type is useful to edit a position without having to ensure it stays legal at every step. /// This type is useful to edit a position without having to ensure it stays legal at every step.
/// It must be validated and converted to a [`Position`] using the [`Setup::into_position`] method /// It must be validated and converted to a [`Position`] using [`Setup::into_position`] before
/// before generating moves. /// generating moves.
/// ///
/// ## Text description /// ## Text description
/// ///
@ -21,8 +21,12 @@ use alloc::string::String;
/// uses a slightly different notation, which simply removes the last two fields of the FEN record /// uses a slightly different notation, which simply removes the last two fields of the FEN record
/// (i.e. the halfmove clock and the fullmove number) as the [`Position`] type does not keep /// (i.e. the halfmove clock and the fullmove number) as the [`Position`] type does not keep
/// track of those. For example, the starting position is recorded as /// track of those. For example, the starting position is recorded as
/// `rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq -`. [`Setup::from_text_record`] and /// `rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq -`.
/// [`Setup::to_text_record`] can be used to read and write these records. ///
/// [`Display`](core::fmt::Display) and [`FromStr`](alloc::str::FromStr) are purposely not
/// implemented on [`Setup`] as there does not exist a truely canonical format for writing chess
/// positions. The format described above is implemented in
/// [`from_text_record`](Setup::from_text_record) and [`to_text_record`](Setup::to_text_record).
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)] #[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Setup { pub struct Setup {
pub(crate) w: Bitboard, pub(crate) w: Bitboard,
@ -51,21 +55,14 @@ impl Setup {
} }
} }
/// Reads a position from a text record. /// Reads a position from a text record
/// /// (see [`from_ascii_record`](Setup::from_ascii_record)).
/// This is a shortcut for:
/// ```
/// # use eschac::setup::Setup;
/// # |record: &str| {
/// Setup::from_ascii_record(record.as_bytes())
/// # };
/// ```
#[inline] #[inline]
pub fn from_text_record(record: &str) -> Result<Self, ParseRecordError> { pub fn from_text_record(record: &str) -> Result<Self, ParseRecordError> {
Self::from_ascii_record(record.as_bytes()) Self::from_ascii_record(record.as_bytes())
} }
/// Reads a position from an ascii record. /// Reads a position from a text record.
pub fn from_ascii_record(record: &[u8]) -> Result<Self, ParseRecordError> { pub fn from_ascii_record(record: &[u8]) -> Result<Self, ParseRecordError> {
let mut s = record.iter().copied().peekable(); let mut s = record.iter().copied().peekable();
let mut setup = Setup::new(); let mut setup = Setup::new();
@ -146,7 +143,8 @@ impl Setup {
}) })
} }
/// Returns the text record of the position. /// Returns the text record of the position
/// (see [`write_text_record`](Setup::write_text_record)).
pub fn to_text_record(&self) -> String { pub fn to_text_record(&self) -> String {
let mut record = String::with_capacity(81); let mut record = String::with_capacity(81);
self.write_text_record(&mut record).unwrap(); self.write_text_record(&mut record).unwrap();
@ -614,7 +612,7 @@ impl Iterator for IllegalPositionReasons {
} }
} }
/// Reasons for illegal positions to be rejected by eschac. /// Reasons for an illegal position to be rejected by eschac.
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)] #[repr(u8)]
pub enum IllegalPositionReason { pub enum IllegalPositionReason {