try from
This commit is contained in:
parent
8733993f1a
commit
d9e3879937
4 changed files with 47 additions and 40 deletions
|
|
@ -28,7 +28,7 @@
|
||||||
//!
|
//!
|
||||||
//! // read a position from a text record
|
//! // read a position from a text record
|
||||||
//! let setup = Setup::from_text_record("7k/4P1rp/5Q2/5p2/1Pp1bP2/8/r4K1P/6R1 w - -")?;
|
//! let setup = Setup::from_text_record("7k/4P1rp/5Q2/5p2/1Pp1bP2/8/r4K1P/6R1 w - -")?;
|
||||||
//! let position = setup.validate()?;
|
//! let position = setup.try_into()?;
|
||||||
//!
|
//!
|
||||||
//! // read a move in algebraic notation
|
//! // read a move in algebraic notation
|
||||||
//! let san = "Ke1".parse::<San>()?;
|
//! let san = "Ke1".parse::<San>()?;
|
||||||
|
|
|
||||||
|
|
@ -90,14 +90,14 @@ impl Position {
|
||||||
/// ```
|
/// ```
|
||||||
/// # use eschac::setup::Setup;
|
/// # use eschac::setup::Setup;
|
||||||
/// # |s: &str| -> Option<eschac::position::Position> {
|
/// # |s: &str| -> Option<eschac::position::Position> {
|
||||||
/// Setup::from_text_record(s).ok().and_then(|pos| pos.validate().ok())
|
/// Setup::from_text_record(s).ok().and_then(|setup| setup.try_into().ok())
|
||||||
/// # };
|
/// # };
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_text_record(s: &str) -> Option<Self> {
|
pub fn from_text_record(s: &str) -> Option<Self> {
|
||||||
Setup::from_text_record(s)
|
Setup::from_text_record(s)
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|pos| pos.validate().ok())
|
.and_then(|setup| setup.try_into().ok())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the text record of the position.
|
/// Returns the text record of the position.
|
||||||
|
|
|
||||||
77
src/setup.rs
77
src/setup.rs
|
|
@ -339,10 +339,44 @@ impl Setup {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the bitboard of each kind of piece.
|
||||||
|
#[inline]
|
||||||
|
pub fn pieces(&self) -> ByColor<ByRole<Bitboard>> {
|
||||||
|
let Self {
|
||||||
|
w,
|
||||||
|
p_b_q,
|
||||||
|
n_b_k,
|
||||||
|
r_q_k,
|
||||||
|
..
|
||||||
|
} = self.clone();
|
||||||
|
let k = n_b_k & r_q_k;
|
||||||
|
let q = p_b_q & r_q_k;
|
||||||
|
let b = p_b_q & n_b_k;
|
||||||
|
let n = n_b_k ^ b ^ k;
|
||||||
|
let r = r_q_k ^ q ^ k;
|
||||||
|
let p = p_b_q ^ b ^ q;
|
||||||
|
ByColor::new(|color| {
|
||||||
|
let mask = match color {
|
||||||
|
Color::White => w,
|
||||||
|
Color::Black => !w,
|
||||||
|
};
|
||||||
|
ByRole::new(|kind| {
|
||||||
|
mask & match kind {
|
||||||
|
Role::Pawn => p,
|
||||||
|
Role::Knight => n,
|
||||||
|
Role::Bishop => b,
|
||||||
|
Role::Rook => r,
|
||||||
|
Role::Queen => q,
|
||||||
|
Role::King => k,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Tries to validate the position, i.e. converting it to a [`Position`].
|
/// Tries to validate the position, i.e. converting it to a [`Position`].
|
||||||
///
|
///
|
||||||
/// See [`IllegalPositionReason`] for details.
|
/// See [`IllegalPositionReason`] for details.
|
||||||
pub fn validate(self) -> Result<Position, IllegalPosition> {
|
pub fn into_position(self) -> Result<Position, IllegalPosition> {
|
||||||
debug_assert!((self.w & !(self.p_b_q | self.n_b_k | self.r_q_k)).is_empty());
|
debug_assert!((self.w & !(self.p_b_q | self.n_b_k | self.r_q_k)).is_empty());
|
||||||
debug_assert!((self.p_b_q & self.n_b_k & self.r_q_k).is_empty());
|
debug_assert!((self.p_b_q & self.n_b_k & self.r_q_k).is_empty());
|
||||||
|
|
||||||
|
|
@ -467,40 +501,6 @@ impl Setup {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the bitboard of each kind of piece.
|
|
||||||
#[inline]
|
|
||||||
pub fn pieces(&self) -> ByColor<ByRole<Bitboard>> {
|
|
||||||
let Self {
|
|
||||||
w,
|
|
||||||
p_b_q,
|
|
||||||
n_b_k,
|
|
||||||
r_q_k,
|
|
||||||
..
|
|
||||||
} = self.clone();
|
|
||||||
let k = n_b_k & r_q_k;
|
|
||||||
let q = p_b_q & r_q_k;
|
|
||||||
let b = p_b_q & n_b_k;
|
|
||||||
let n = n_b_k ^ b ^ k;
|
|
||||||
let r = r_q_k ^ q ^ k;
|
|
||||||
let p = p_b_q ^ b ^ q;
|
|
||||||
ByColor::new(|color| {
|
|
||||||
let mask = match color {
|
|
||||||
Color::White => w,
|
|
||||||
Color::Black => !w,
|
|
||||||
};
|
|
||||||
ByRole::new(|kind| {
|
|
||||||
mask & match kind {
|
|
||||||
Role::Pawn => p,
|
|
||||||
Role::Knight => n,
|
|
||||||
Role::Bishop => b,
|
|
||||||
Role::Rook => r,
|
|
||||||
Role::Queen => q,
|
|
||||||
Role::King => k,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn get_role(&self, square: Square) -> Option<Role> {
|
pub(crate) fn get_role(&self, square: Square) -> Option<Role> {
|
||||||
let mask = square.bitboard();
|
let mask = square.bitboard();
|
||||||
|
|
@ -514,6 +514,13 @@ impl Setup {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TryFrom<Setup> for Position {
|
||||||
|
type Error = IllegalPosition;
|
||||||
|
fn try_from(setup: Setup) -> Result<Position, IllegalPosition> {
|
||||||
|
setup.into_position()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl std::fmt::Debug for Setup {
|
impl std::fmt::Debug for Setup {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||||
f.debug_tuple("Setup")
|
f.debug_tuple("Setup")
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ fn recursive_check_aux(position: Position, depth: usize) {
|
||||||
.en_passant_target_square()
|
.en_passant_target_square()
|
||||||
.map(|square| square.mirror()),
|
.map(|square| square.mirror()),
|
||||||
);
|
);
|
||||||
setup.validate().unwrap()
|
setup.into_position().unwrap()
|
||||||
};
|
};
|
||||||
let expected_mirror = position.mirror();
|
let expected_mirror = position.mirror();
|
||||||
assert_eq!(computed_mirror, expected_mirror);
|
assert_eq!(computed_mirror, expected_mirror);
|
||||||
|
|
@ -192,7 +192,7 @@ fn setup() {
|
||||||
assert!(
|
assert!(
|
||||||
Setup::from_text_record(record)
|
Setup::from_text_record(record)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.validate()
|
.into_position()
|
||||||
.is_err_and(|e| e.reasons().contains(reason)),
|
.is_err_and(|e| e.reasons().contains(reason)),
|
||||||
"{record} should be invalid because of {reason:?}",
|
"{record} should be invalid because of {reason:?}",
|
||||||
);
|
);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue