mod accessors;
mod attacks;
#[cfg(feature = "position-serialization")]
mod bit_io;
mod cache;
mod constructors;
#[cfg(feature = "position-serialization")]
mod huffman_coded_pos;
mod legality;
mod maintenance;
#[cfg(feature = "position-serialization")]
mod packed_sfen;
mod parser;
mod rules;
#[cfg(feature = "svg")]
mod svg;
mod types;
mod updates;
mod hash;
#[cfg(feature = "validation")]
mod validation;
use super::bitboard_set::BitboardSet;
use crate::board::state_info::StateIndex;
use crate::board::zobrist::ZobristKey;
use crate::types::{Color, EnteringKingRule, File, Hand, Piece, Rank, Square};
use std::fmt;
use crate::board::state_info::StateStack;
#[cfg(test)]
pub(super) use crate::types::Move32;
pub use super::parser::{MissingFieldKind, SfenError};
pub use crate::board::state_info::PartialKeys;
pub use cache::StateCacheView;
#[cfg(feature = "position-serialization")]
pub use huffman_coded_pos::{HuffmanCodedPos, HuffmanCodedPosError};
#[cfg(feature = "position-serialization")]
pub use packed_sfen::{PackedSfen, PackedSfenError, PackedSfenSink};
pub use types::{
BoardArray, CapturedPieceDelta, DeclarationDetail, DeclarationEvaluation, MoveApplyFacts,
MoveDelta32, MoveError, MoveStackSiteFacts, PackedPiece, Ply, ValidationError, ValidationIssue,
ValidationReport,
};
#[repr(C, align(64))]
#[derive(Clone)]
pub struct Position {
pub(super) board: BoardArray,
pub(super) bitboards: BitboardSet,
pub(super) hands: [Hand; Color::COUNT],
pub(super) zobrist: ZobristKey,
pub(super) board_key: ZobristKey,
pub(super) hand_key: ZobristKey,
pub(super) side_to_move: Color,
pub(super) entering_king_rule: EnteringKingRule,
pub(super) entering_king_point: [i32; Color::COUNT],
pub(super) ply: Ply,
pub(super) st_index: StateIndex,
pub(super) state_stack: StateStack,
pub(super) king_square: [Square; Color::COUNT],
}
impl Default for Position {
fn default() -> Self {
Self::empty()
}
}
impl fmt::Display for Position {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, " 9 8 7 6 5 4 3 2 1")?;
writeln!(f, "+-------------------+")?;
for rank_idx in 0..9 {
let rank_value = i8::try_from(rank_idx).expect("rank index within range");
let rank = Rank::new(rank_value);
write!(f, "|")?;
for file_idx in (0..9).rev() {
let file_value = i8::try_from(file_idx).expect("file index within range");
let sq = Square::from_file_rank(File::new(file_value), rank);
let piece = self.piece_on(sq);
if piece == Piece::NONE {
write!(f, " .")?;
} else {
write!(f, " *")?;
}
}
let rank_char =
char::from(b'a' + u8::try_from(rank_idx).expect("rank index fits in u8"));
writeln!(f, "|{rank_char}")?;
}
writeln!(f, "+-------------------+")?;
writeln!(f, "Side to move: {:?}", self.turn())?;
writeln!(f, "Ply: {}", self.ply)?;
Ok(())
}
}
#[derive(Clone, Copy)]
pub struct StateHistory<'a> {
stack: &'a StateStack,
current: StateIndex,
}
impl<'a> StateHistory<'a> {
#[must_use]
#[inline]
pub const fn len(&self) -> usize {
self.current + 1
}
#[must_use]
#[inline]
pub const fn is_empty(&self) -> bool {
false
}
pub fn iter(&self) -> impl Iterator<Item = StateHistoryEntry<'a>> {
let stack = self.stack;
let current = self.current;
(0..=current).map(move |idx| StateHistoryEntry { state: &stack[idx] })
}
}
#[derive(Clone, Copy)]
pub struct StateHistoryEntry<'a> {
state: &'a crate::board::state_info::StateInfo,
}
impl StateHistoryEntry<'_> {
#[must_use]
#[inline]
pub fn board_key(&self) -> ZobristKey {
self.state.board_key()
}
#[must_use]
#[inline]
pub fn hand(&self) -> Hand {
self.state.hand()
}
#[must_use]
#[inline]
pub fn plies_from_null(&self) -> Ply {
self.state.plies_from_null()
}
#[must_use]
#[inline]
pub fn repetition_times(&self) -> i32 {
self.state.repetition_times()
}
#[must_use]
#[inline]
pub fn repetition_type(&self) -> crate::types::RepetitionState {
self.state.repetition_type()
}
}
impl Position {
#[must_use]
#[inline]
pub(crate) fn state_stack(&self) -> &StateStack {
&self.state_stack
}
#[must_use]
#[inline]
pub fn state_history(&self) -> StateHistory<'_> {
StateHistory { stack: &self.state_stack, current: self.st_index }
}
#[must_use]
#[inline]
pub fn move32_from_usi(&self, usi: &str) -> Option<crate::types::Move32> {
crate::board::move_from_usi(self, usi)
}
#[cfg(test)]
#[must_use]
#[inline]
pub(crate) fn current_state(&self) -> &crate::board::state_info::StateInfo {
&self.state_stack[self.st_index]
}
#[must_use]
#[inline]
pub(crate) fn current_hot(&self) -> &crate::board::state_info::StateHot {
self.state_stack.hot(self.st_index)
}
#[must_use]
#[inline]
pub(crate) fn current_cold(&self) -> &crate::board::state_info::StateColdPayload {
self.state_stack.cold(self.st_index)
}
#[must_use]
pub const fn state_stack_depth(&self) -> usize {
self.st_index
}
pub fn prepare_search_state_capacity(
&mut self,
additional_states: usize,
) -> Result<(), MoveError> {
if self.state_stack.prepare_additional(additional_states) {
Ok(())
} else {
Err(MoveError::StateCapacityExceeded)
}
}
#[must_use]
#[inline(always)]
pub fn has_prepared_search_state(&self) -> bool {
self.state_stack.has_prepared_next()
}
pub(crate) fn state_stack_mut(&mut self) -> &mut StateStack {
&mut self.state_stack
}
}
#[cfg(test)]
mod tests;