[explorer, moves, position] Remove unused MoveBuilder
This thing isn't used by any of the "modern" code I've written. It was difficult to write, but kinda neat architecturally. It made a lot of invalid configurations of moves into build-time errors. Anyway… Remove several of the tests that relied on it, but that hadn't been updated to use the newer code either.
This commit is contained in:
parent
035a83723d
commit
651544fdd9
7 changed files with 4 additions and 589 deletions
|
@ -6,7 +6,7 @@ use chessfriend_board::ZobristState;
|
|||
use chessfriend_board::{fen::FromFenStr, Board};
|
||||
use chessfriend_core::random::RandomNumberGenerator;
|
||||
use chessfriend_core::{Color, Piece, Shape, Square};
|
||||
use chessfriend_moves::{Builder as MoveBuilder, GeneratedMove, ValidateMove};
|
||||
use chessfriend_moves::GeneratedMove;
|
||||
use chessfriend_position::{fen::ToFenStr, PlacePieceStrategy, Position};
|
||||
use clap::{Arg, Command};
|
||||
use rustyline::error::ReadlineError;
|
||||
|
@ -128,22 +128,8 @@ fn respond(line: &str, state: &mut State) -> anyhow::Result<CommandResult> {
|
|||
println!("{}", state.position.to_fen_str()?);
|
||||
result.should_print_position = false;
|
||||
}
|
||||
Some(("make", matches)) => {
|
||||
let from_square = Square::from_algebraic_str(
|
||||
matches
|
||||
.get_one::<String>("from")
|
||||
.ok_or(CommandHandlingError::MissingArgument("from"))?,
|
||||
)?;
|
||||
|
||||
let to_square = Square::from_algebraic_str(
|
||||
matches
|
||||
.get_one::<String>("to")
|
||||
.ok_or(CommandHandlingError::MissingArgument("to"))?,
|
||||
)?;
|
||||
|
||||
let ply = MoveBuilder::new().from(from_square).to(to_square).build()?;
|
||||
|
||||
state.position.make_move(ply, ValidateMove::Yes)?;
|
||||
Some(("make", _matches)) => {
|
||||
unimplemented!()
|
||||
}
|
||||
Some(("place", matches)) => {
|
||||
let color = matches
|
||||
|
|
|
@ -1,428 +0,0 @@
|
|||
// Eryn Wells <eryn@erynwells.me>
|
||||
|
||||
use crate::{defs::Kind, Move, PromotionShape};
|
||||
use chessfriend_board::{en_passant::EnPassant, CastleParameters};
|
||||
use chessfriend_core::{Color, File, PlacedPiece, Rank, Square, Wing};
|
||||
use std::result::Result as StdResult;
|
||||
use thiserror::Error;
|
||||
|
||||
pub type Result = std::result::Result<Move, Error>;
|
||||
type EncodedMoveResult = std::result::Result<u16, Error>;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Error, Eq, PartialEq)]
|
||||
pub enum Error {
|
||||
#[error("no origin square")]
|
||||
MissingOriginSquare,
|
||||
#[error("no target square")]
|
||||
MissingTargetSquare,
|
||||
#[error("no capture square")]
|
||||
MissingCaptureSquare,
|
||||
#[error("invalid en passant square")]
|
||||
InvalidEnPassantSquare,
|
||||
}
|
||||
|
||||
const MASK: u16 = 0b111_111;
|
||||
|
||||
fn build_move_bits(origin_square: Square, target_square: Square) -> u16 {
|
||||
(origin_square as u16 & MASK) << 4 | (target_square as u16 & MASK) << 10
|
||||
}
|
||||
|
||||
pub trait Style {
|
||||
fn origin_square(&self) -> Option<Square> {
|
||||
None
|
||||
}
|
||||
|
||||
fn target_square(&self) -> Option<Square> {
|
||||
None
|
||||
}
|
||||
|
||||
fn move_bits(&self) -> EncodedMoveResult {
|
||||
let origin_square = self.origin_square().ok_or(Error::MissingOriginSquare)?;
|
||||
let target_square = self.target_square().ok_or(Error::MissingTargetSquare)?;
|
||||
|
||||
Ok(build_move_bits(origin_square, target_square))
|
||||
}
|
||||
|
||||
unsafe fn move_bits_unchecked(&self) -> u16 {
|
||||
let origin_square = self.origin_square().unwrap();
|
||||
let target_square = self.target_square().unwrap();
|
||||
|
||||
build_move_bits(origin_square, target_square)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct Builder<S: Style> {
|
||||
style: S,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct Null;
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct Push {
|
||||
from: Option<Square>,
|
||||
to: Option<Square>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct DoublePush {
|
||||
from: Square,
|
||||
to: Square,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct Capture {
|
||||
push: Push,
|
||||
capture: Option<Square>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct EnPassantCapture {
|
||||
push: Push,
|
||||
capture: Option<EnPassant>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct Promotion<S> {
|
||||
style: S,
|
||||
promotion: PromotionShape,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct Castle {
|
||||
color: Color,
|
||||
wing: Wing,
|
||||
}
|
||||
|
||||
impl Style for Null {}
|
||||
|
||||
impl Style for Push {
|
||||
fn origin_square(&self) -> Option<Square> {
|
||||
self.from
|
||||
}
|
||||
|
||||
fn target_square(&self) -> Option<Square> {
|
||||
self.to
|
||||
}
|
||||
}
|
||||
|
||||
impl Style for Capture {
|
||||
fn origin_square(&self) -> Option<Square> {
|
||||
self.push.from
|
||||
}
|
||||
|
||||
fn target_square(&self) -> Option<Square> {
|
||||
self.push.to
|
||||
}
|
||||
}
|
||||
|
||||
impl Style for Castle {
|
||||
fn origin_square(&self) -> Option<Square> {
|
||||
let parameters = CastleParameters::get(self.color, self.wing);
|
||||
Some(parameters.origin.king)
|
||||
}
|
||||
|
||||
fn target_square(&self) -> Option<Square> {
|
||||
let parameters = CastleParameters::get(self.color, self.wing);
|
||||
Some(parameters.target.king)
|
||||
}
|
||||
}
|
||||
|
||||
impl Style for DoublePush {
|
||||
fn origin_square(&self) -> Option<Square> {
|
||||
Some(self.from)
|
||||
}
|
||||
|
||||
fn target_square(&self) -> Option<Square> {
|
||||
Some(self.to)
|
||||
}
|
||||
|
||||
fn move_bits(&self) -> StdResult<u16, Error> {
|
||||
Ok(
|
||||
Kind::DoublePush as u16
|
||||
| (self.from as u16 & MASK) << 4
|
||||
| (self.to as u16 & MASK) << 10,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Style for EnPassantCapture {
|
||||
fn origin_square(&self) -> Option<Square> {
|
||||
self.push.from
|
||||
}
|
||||
|
||||
fn target_square(&self) -> Option<Square> {
|
||||
self.push.to
|
||||
}
|
||||
|
||||
fn move_bits(&self) -> EncodedMoveResult {
|
||||
let origin_square = self.origin_square().ok_or(Error::MissingOriginSquare)?;
|
||||
let target_square = self.target_square().ok_or(Error::MissingTargetSquare)?;
|
||||
|
||||
Ok(build_move_bits(origin_square, target_square))
|
||||
}
|
||||
}
|
||||
|
||||
impl Style for Promotion<Push> {
|
||||
fn origin_square(&self) -> Option<Square> {
|
||||
self.style.from
|
||||
}
|
||||
|
||||
fn target_square(&self) -> Option<Square> {
|
||||
self.style.to
|
||||
}
|
||||
}
|
||||
|
||||
impl Style for Promotion<Capture> {
|
||||
fn origin_square(&self) -> Option<Square> {
|
||||
self.style.push.from
|
||||
}
|
||||
|
||||
fn target_square(&self) -> Option<Square> {
|
||||
self.style.push.to
|
||||
}
|
||||
}
|
||||
|
||||
impl Promotion<Push> {
|
||||
fn move_bits(&self) -> StdResult<u16, Error> {
|
||||
let origin_square = self
|
||||
.style
|
||||
.origin_square()
|
||||
.ok_or(Error::MissingOriginSquare)? as u16;
|
||||
let target_square = self
|
||||
.style
|
||||
.target_square()
|
||||
.ok_or(Error::MissingTargetSquare)? as u16;
|
||||
|
||||
Ok(Kind::Promotion as u16
|
||||
| self.promotion as u16
|
||||
| (origin_square & MASK << 4)
|
||||
| (target_square & MASK << 10))
|
||||
}
|
||||
}
|
||||
|
||||
impl Promotion<Capture> {
|
||||
fn move_bits(&self) -> StdResult<u16, Error> {
|
||||
let origin_square = self
|
||||
.style
|
||||
.origin_square()
|
||||
.ok_or(Error::MissingOriginSquare)? as u16;
|
||||
let target_square = self
|
||||
.style
|
||||
.target_square()
|
||||
.ok_or(Error::MissingTargetSquare)? as u16;
|
||||
|
||||
Ok(Kind::CapturePromotion as u16
|
||||
| self.promotion as u16
|
||||
| (origin_square & MASK) << 4
|
||||
| (target_square & MASK) << 10)
|
||||
}
|
||||
}
|
||||
|
||||
impl Builder<Null> {
|
||||
#[must_use]
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn push(piece: &PlacedPiece) -> Builder<Push> {
|
||||
Builder {
|
||||
style: Push {
|
||||
from: Some(piece.square),
|
||||
to: None,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn double_push(file: File, color: Color) -> Builder<DoublePush> {
|
||||
let (from, to) = match color {
|
||||
Color::White => (
|
||||
Square::from_file_rank(file, Rank::TWO),
|
||||
Square::from_file_rank(file, Rank::FOUR),
|
||||
),
|
||||
Color::Black => (
|
||||
Square::from_file_rank(file, Rank::SEVEN),
|
||||
Square::from_file_rank(file, Rank::FIVE),
|
||||
),
|
||||
};
|
||||
|
||||
Builder {
|
||||
style: DoublePush { from, to },
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn castling(color: Color, wing: Wing) -> Builder<Castle> {
|
||||
Builder {
|
||||
style: Castle { color, wing },
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn capturing_piece(piece: &PlacedPiece, capturing: &PlacedPiece) -> Builder<Capture> {
|
||||
Self::push(piece).capturing_piece(capturing)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn from(&self, square: Square) -> Builder<Push> {
|
||||
Builder {
|
||||
style: Push {
|
||||
from: Some(square),
|
||||
to: None,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn build(&self) -> Move {
|
||||
Move(0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Builder<Null> {
|
||||
fn default() -> Self {
|
||||
Self { style: Null }
|
||||
}
|
||||
}
|
||||
|
||||
impl Builder<Push> {
|
||||
pub fn from(&mut self, square: Square) -> &mut Self {
|
||||
self.style.from = Some(square);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn to(&mut self, square: Square) -> &mut Self {
|
||||
self.style.to = Some(square);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn capturing_on(&self, square: Square) -> Builder<Capture> {
|
||||
let mut style = self.style.clone();
|
||||
style.to = Some(square);
|
||||
|
||||
Builder {
|
||||
style: Capture {
|
||||
push: style,
|
||||
capture: Some(square),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn capturing_en_passant_on(&self, target_square: Square) -> Builder<EnPassantCapture> {
|
||||
match EnPassant::from_target_square(target_square) {
|
||||
Some(en_passant) => {
|
||||
let mut style = self.style.clone();
|
||||
style.to = Some(en_passant.target_square());
|
||||
|
||||
Builder {
|
||||
style: EnPassantCapture {
|
||||
push: style,
|
||||
capture: Some(en_passant),
|
||||
},
|
||||
}
|
||||
}
|
||||
None => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn capturing_piece(&self, piece: &PlacedPiece) -> Builder<Capture> {
|
||||
Builder {
|
||||
style: Capture {
|
||||
push: self.style.clone(),
|
||||
capture: Some(piece.square),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn promoting_to(&self, shape: PromotionShape) -> Builder<Promotion<Push>> {
|
||||
Builder {
|
||||
style: Promotion {
|
||||
style: self.style.clone(),
|
||||
promotion: shape,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build(&self) -> Result {
|
||||
Ok(Move(Kind::Quiet as u16 | self.style.move_bits()?))
|
||||
}
|
||||
}
|
||||
|
||||
impl Builder<Castle> {
|
||||
fn bits(&self) -> u16 {
|
||||
let bits = match self.style.wing {
|
||||
Wing::KingSide => Kind::KingSideCastle,
|
||||
Wing::QueenSide => Kind::QueenSideCastle,
|
||||
};
|
||||
|
||||
bits as u16
|
||||
}
|
||||
|
||||
pub fn build(&self) -> Result {
|
||||
Ok(Move(self.bits() | self.style.move_bits()?))
|
||||
}
|
||||
}
|
||||
|
||||
impl Builder<Capture> {
|
||||
#[must_use]
|
||||
pub fn promoting_to(self, shape: PromotionShape) -> Builder<Promotion<Capture>> {
|
||||
Builder {
|
||||
style: Promotion {
|
||||
style: self.style,
|
||||
promotion: shape,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build(&self) -> Result {
|
||||
Ok(Move(Kind::Capture as u16 | self.style.move_bits()?))
|
||||
}
|
||||
}
|
||||
|
||||
impl Builder<DoublePush> {
|
||||
pub fn build(&self) -> Result {
|
||||
Ok(Move(Kind::DoublePush as u16 | self.style.move_bits()?))
|
||||
}
|
||||
}
|
||||
|
||||
impl Builder<EnPassantCapture> {
|
||||
/// Builds an en passant move.
|
||||
///
|
||||
/// ## Safety
|
||||
///
|
||||
/// This method builds without doing error checking.
|
||||
#[must_use]
|
||||
pub unsafe fn build_unchecked(&self) -> Move {
|
||||
Move(Kind::EnPassantCapture as u16 | self.style.move_bits_unchecked())
|
||||
}
|
||||
|
||||
/// Build an en passant move.
|
||||
///
|
||||
/// ## Errors
|
||||
///
|
||||
/// Returns an error if the target or origin squares are invalid.
|
||||
pub fn build(&self) -> Result {
|
||||
Ok(Move(
|
||||
Kind::EnPassantCapture as u16 | self.style.move_bits()?,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl Builder<Promotion<Push>> {
|
||||
pub fn build(&self) -> Result {
|
||||
Ok(Move(self.style.move_bits()?))
|
||||
}
|
||||
}
|
||||
|
||||
impl Builder<Promotion<Capture>> {
|
||||
pub fn build(&self) -> Result {
|
||||
Ok(Move(self.style.move_bits()?))
|
||||
}
|
||||
}
|
|
@ -3,7 +3,6 @@
|
|||
pub mod generators;
|
||||
pub mod testing;
|
||||
|
||||
mod builder;
|
||||
mod defs;
|
||||
mod macros;
|
||||
mod make_move;
|
||||
|
@ -11,7 +10,6 @@ mod moves;
|
|||
mod record;
|
||||
mod unmake_move;
|
||||
|
||||
pub use builder::{Builder, Error as BuildMoveError, Result as BuildMoveResult};
|
||||
pub use defs::{Kind, PromotionShape};
|
||||
pub use generators::GeneratedMove;
|
||||
pub use make_move::{MakeMove, MakeMoveError, MakeMoveResult, ValidateMove};
|
||||
|
|
|
@ -1,17 +1,8 @@
|
|||
// Eryn Wells <eryn@erynwells.me>
|
||||
|
||||
use crate::BuildMoveError;
|
||||
|
||||
pub type TestResult = Result<(), TestError>;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub enum TestError {
|
||||
BuildMove(BuildMoveError),
|
||||
NoLegalMoves,
|
||||
}
|
||||
|
||||
impl From<BuildMoveError> for TestError {
|
||||
fn from(value: BuildMoveError) -> Self {
|
||||
TestError::BuildMove(value)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,108 +0,0 @@
|
|||
// Eryn Wells <eryn@erynwells.me>
|
||||
|
||||
use chessfriend_core::{piece, Color, File, Shape, Square, Wing};
|
||||
use chessfriend_moves::{testing::*, Builder, PromotionShape};
|
||||
|
||||
macro_rules! assert_flag {
|
||||
($move:expr, $left:expr, $right:expr, $desc:expr) => {
|
||||
assert_eq!($left, $right, "{:?} -> {}", $move, stringify!($desc))
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! assert_flags {
|
||||
($move:expr, $quiet:expr, $double_push:expr, $en_passant:expr, $capture:expr, $castle:expr, $promotion:expr) => {
|
||||
assert_flag!($move, $move.is_quiet(), $quiet, "is_quiet");
|
||||
assert_flag!(
|
||||
$move,
|
||||
$move.is_double_push(),
|
||||
$double_push,
|
||||
"is_double_push"
|
||||
);
|
||||
assert_flag!($move, $move.is_en_passant(), $en_passant, "is_en_passant");
|
||||
assert_flag!($move, $move.is_capture(), $capture, "is_capture");
|
||||
assert_flag!($move, $move.is_castle(), $castle, "is_castle");
|
||||
assert_flag!($move, $move.is_promotion(), $promotion, "is_promotion");
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn move_flags_quiet() -> TestResult {
|
||||
let mv = Builder::push(&piece!(White Pawn on A4))
|
||||
.to(Square::A5)
|
||||
.build()?;
|
||||
assert_flags!(mv, true, false, false, false, false, false);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn move_flags_double_push() -> TestResult {
|
||||
let mv = Builder::double_push(File::C, Color::White).build()?;
|
||||
assert_flags!(mv, false, true, false, false, false, false);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn move_flags_capture() -> TestResult {
|
||||
let mv = Builder::new()
|
||||
.from(Square::A4)
|
||||
.capturing_on(Square::B5)
|
||||
.build()?;
|
||||
|
||||
assert_flags!(mv, false, false, false, true, false, false);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn move_flags_en_passant_capture() -> TestResult {
|
||||
let ply = Builder::new()
|
||||
.from(Square::A4)
|
||||
.capturing_en_passant_on(Square::B3)
|
||||
.build()?;
|
||||
|
||||
assert!(ply.is_en_passant());
|
||||
assert_eq!(ply.origin_square(), Square::A4);
|
||||
assert_eq!(ply.target_square(), Square::B3);
|
||||
assert_eq!(ply.capture_square(), Some(Square::B4));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn move_flags_promotion() -> TestResult {
|
||||
let ply = Builder::push(&piece!(White Pawn on H7))
|
||||
.to(Square::H8)
|
||||
.promoting_to(PromotionShape::Queen)
|
||||
.build()?;
|
||||
|
||||
assert!(ply.is_promotion());
|
||||
assert_eq!(ply.promotion_shape(), Some(Shape::Queen));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn move_flags_capture_promotion() -> TestResult {
|
||||
let ply = Builder::push(&piece!(White Pawn on H7))
|
||||
.to(Square::H8)
|
||||
.capturing_piece(&piece!(Black Knight on G8))
|
||||
.promoting_to(PromotionShape::Queen)
|
||||
.build()?;
|
||||
|
||||
assert!(ply.is_capture());
|
||||
assert!(ply.is_promotion());
|
||||
assert_eq!(ply.promotion_shape(), Some(Shape::Queen));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn move_flags_castle() -> TestResult {
|
||||
let mv = Builder::castling(Color::White, Wing::KingSide).build()?;
|
||||
|
||||
assert_flags!(mv, false, false, false, false, true, false);
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
// Eryn Wells <eryn@erynwells.me>
|
||||
|
||||
use chessfriend_core::{piece, Square};
|
||||
use chessfriend_moves::{testing::*, Builder};
|
||||
|
||||
#[test]
|
||||
fn pawn_push() -> TestResult {
|
||||
let mv = Builder::push(&piece!(White Pawn on A3))
|
||||
.to(Square::A4)
|
||||
.build()?;
|
||||
|
||||
assert!(mv.is_quiet());
|
||||
assert_eq!(mv.origin_square(), Square::A3);
|
||||
assert_eq!(mv.target_square(), Square::A4);
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
// Eryn Wells <eryn@erynwells.me>
|
||||
|
||||
use chessfriend_moves::{BuildMoveError, MakeMoveError};
|
||||
use chessfriend_moves::MakeMoveError;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! assert_eq_bitboards {
|
||||
|
@ -19,17 +19,10 @@ pub type TestResult = Result<(), TestError>;
|
|||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub enum TestError {
|
||||
BuildMove(BuildMoveError),
|
||||
MakeMove(MakeMoveError),
|
||||
NoLegalMoves,
|
||||
}
|
||||
|
||||
impl From<BuildMoveError> for TestError {
|
||||
fn from(value: BuildMoveError) -> Self {
|
||||
TestError::BuildMove(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MakeMoveError> for TestError {
|
||||
fn from(value: MakeMoveError) -> Self {
|
||||
TestError::MakeMove(value)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue