Merge branch 'main' into rename-board-crate
# Conflicts: # explorer/src/main.rs
This commit is contained in:
commit
569693bda9
8 changed files with 138 additions and 34 deletions
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
use crate::library::{library, FILES, RANKS};
|
use crate::library::{library, FILES, RANKS};
|
||||||
use crate::LeadingBitScanner;
|
use crate::LeadingBitScanner;
|
||||||
use chessfriend_core::{Direction, Square};
|
use chessfriend_core::{Color, Direction, Square};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::ops::Not;
|
use std::ops::Not;
|
||||||
|
|
||||||
|
|
|
@ -28,4 +28,18 @@ macro_rules! test_position {
|
||||||
pos
|
pos
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
(empty) => {
|
||||||
|
{
|
||||||
|
let pos = Position::empty();
|
||||||
|
println!("{pos}");
|
||||||
|
pos
|
||||||
|
}
|
||||||
|
};
|
||||||
|
(starting) => {
|
||||||
|
{
|
||||||
|
let pos = Position::starting();
|
||||||
|
println!("{pos}");
|
||||||
|
pos
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,7 +74,7 @@ impl MoveGeneratorInternal for KingMoveGenerator {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::position;
|
use crate::{position, r#move::AlgebraicMoveFormatter, PositionBuilder};
|
||||||
use chessfriend_bitboard::bitboard;
|
use chessfriend_bitboard::bitboard;
|
||||||
use chessfriend_core::{piece, Square};
|
use chessfriend_core::{piece, Square};
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
@ -154,4 +154,40 @@ mod tests {
|
||||||
generated_moves
|
generated_moves
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn black_king_in_check_by_rook() {
|
||||||
|
let pos = PositionBuilder::new()
|
||||||
|
.place_piece(piece!(White King on E1))
|
||||||
|
.place_piece(piece!(White Rook on E4))
|
||||||
|
.place_piece(piece!(Black King on E7))
|
||||||
|
.to_move(Color::Black)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
assert!(pos.is_king_in_check());
|
||||||
|
|
||||||
|
let generator = KingMoveGenerator::new(&pos, Color::Black);
|
||||||
|
let generated_moves: HashSet<Move> = generator.iter().cloned().collect();
|
||||||
|
|
||||||
|
let king = piece!(Black King);
|
||||||
|
let from_square = Square::E7;
|
||||||
|
let expected_moves = HashSet::from_iter([
|
||||||
|
MoveBuilder::new(king, from_square, Square::D6).build(),
|
||||||
|
MoveBuilder::new(king, from_square, Square::D7).build(),
|
||||||
|
MoveBuilder::new(king, from_square, Square::D8).build(),
|
||||||
|
MoveBuilder::new(king, from_square, Square::F6).build(),
|
||||||
|
MoveBuilder::new(king, from_square, Square::F7).build(),
|
||||||
|
MoveBuilder::new(king, from_square, Square::F8).build(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
generated_moves,
|
||||||
|
expected_moves,
|
||||||
|
"Difference: {:?}",
|
||||||
|
generated_moves
|
||||||
|
.symmetric_difference(&expected_moves)
|
||||||
|
.map(|mv| format!("{}", AlgebraicMoveFormatter::new(mv, &pos)))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,6 @@ impl<'a> fmt::Display for DiagramFormatter<'a> {
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{position, Position};
|
use crate::{position, Position};
|
||||||
use chessfriend_core::piece;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore]
|
#[ignore]
|
||||||
|
|
|
@ -333,8 +333,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn piece_in_starting_position() {
|
fn piece_in_starting_position() {
|
||||||
let pos = Position::starting();
|
let pos = test_position!(starting);
|
||||||
println!("{pos}");
|
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
pos.piece_on_square(Square::H1),
|
pos.piece_on_square(Square::H1),
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
// Eryn Wells <eryn@erynwells.me>
|
// Eryn Wells <eryn@erynwells.me>
|
||||||
|
|
||||||
use crate::position::piece_sets::PieceBitBoards;
|
use crate::position::piece_sets::PieceBitBoards;
|
||||||
use crate::Position;
|
|
||||||
use chessfriend_bitboard::BitBoard;
|
use chessfriend_bitboard::BitBoard;
|
||||||
use chessfriend_core::{Color, Direction, Piece, PlacedPiece, Shape, Square};
|
use chessfriend_core::{Color, Direction, PlacedPiece, Shape, Square};
|
||||||
|
|
||||||
pub(crate) trait SightExt {
|
pub(crate) trait SightExt {
|
||||||
fn sight(&self, pieces: &PieceBitBoards, en_passant_square: Option<Square>) -> BitBoard;
|
fn sight(&self, pieces: &PieceBitBoards, en_passant_square: Option<Square>) -> BitBoard;
|
||||||
|
@ -13,11 +12,13 @@ pub(crate) trait SightExt {
|
||||||
pieces: &PieceBitBoards,
|
pieces: &PieceBitBoards,
|
||||||
en_passant_square: Option<Square>,
|
en_passant_square: Option<Square>,
|
||||||
) -> BitBoard;
|
) -> BitBoard;
|
||||||
|
|
||||||
fn black_pawn_sight(
|
fn black_pawn_sight(
|
||||||
&self,
|
&self,
|
||||||
pieces: &PieceBitBoards,
|
pieces: &PieceBitBoards,
|
||||||
en_passant_square: Option<Square>,
|
en_passant_square: Option<Square>,
|
||||||
) -> BitBoard;
|
) -> BitBoard;
|
||||||
|
|
||||||
fn knight_sight(&self, pieces: &PieceBitBoards) -> BitBoard;
|
fn knight_sight(&self, pieces: &PieceBitBoards) -> BitBoard;
|
||||||
fn bishop_sight(&self, pieces: &PieceBitBoards) -> BitBoard;
|
fn bishop_sight(&self, pieces: &PieceBitBoards) -> BitBoard;
|
||||||
fn rook_sight(&self, pieces: &PieceBitBoards) -> BitBoard;
|
fn rook_sight(&self, pieces: &PieceBitBoards) -> BitBoard;
|
||||||
|
|
|
@ -7,7 +7,7 @@ edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
chessfriend_core = { path = "../core" }
|
chessfriend_core = { path = "../core" }
|
||||||
chessfriend_position = { path = "../position" }
|
chessfriend_position = { path = "../board" }
|
||||||
clap = { version = "4.4.12", features = ["derive"] }
|
clap = { version = "4.4.12", features = ["derive"] }
|
||||||
rustyline = "13.0.0"
|
rustyline = "13.0.0"
|
||||||
shlex = "1.2.0"
|
shlex = "1.2.0"
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use chessfriend_core::Square;
|
use chessfriend_core::{Color, Piece, PlacedPiece, Shape, Square};
|
||||||
use chessfriend_position::{fen::ToFen, MakeMoveBuilder, MoveBuilder, Position, PositionBuilder};
|
use chessfriend_position::{fen::ToFen, MakeMoveBuilder, MoveBuilder, Position, PositionBuilder};
|
||||||
use clap::{Arg, Command};
|
use clap::{Arg, Command};
|
||||||
use rustyline::error::ReadlineError;
|
use rustyline::error::ReadlineError;
|
||||||
|
@ -29,28 +29,31 @@ fn command_line() -> Command {
|
||||||
{all-args}
|
{all-args}
|
||||||
";
|
";
|
||||||
|
|
||||||
// strip out name/version
|
|
||||||
const APPLET_TEMPLATE: &str = "\
|
|
||||||
{about-with-newline}\n\
|
|
||||||
{usage-heading}\n {usage}\n\
|
|
||||||
\n\
|
|
||||||
{all-args}{after-help}\
|
|
||||||
";
|
|
||||||
|
|
||||||
Command::new("explorer")
|
Command::new("explorer")
|
||||||
.multicall(true)
|
.multicall(true)
|
||||||
.arg_required_else_help(true)
|
.arg_required_else_help(true)
|
||||||
.subcommand_required(true)
|
.subcommand_required(true)
|
||||||
.subcommand_value_name("APPLET")
|
.subcommand_value_name("CMD")
|
||||||
.subcommand_help_heading("APPLETS")
|
.subcommand_help_heading("COMMANDS")
|
||||||
.help_template(PARSER_TEMPLATE)
|
.help_template(PARSER_TEMPLATE)
|
||||||
.subcommand(Command::new("print").about("Print the board"))
|
.subcommand(Command::new("fen").about("Print the current position as a FEN string"))
|
||||||
|
.subcommand(
|
||||||
|
Command::new("make")
|
||||||
|
.arg(Arg::new("piece").required(true))
|
||||||
|
.arg(Arg::new("from").required(true))
|
||||||
|
.arg(Arg::new("to").required(true))
|
||||||
|
.about("Make a move"),
|
||||||
|
)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
Command::new("place")
|
Command::new("place")
|
||||||
|
.arg(Arg::new("color").required(true))
|
||||||
.arg(Arg::new("piece").required(true))
|
.arg(Arg::new("piece").required(true))
|
||||||
.arg(Arg::new("square").required(true)),
|
.arg(Arg::new("square").required(true))
|
||||||
|
.about("Place a piece on the board"),
|
||||||
)
|
)
|
||||||
.subcommand(Command::new("quit").about("Quit the program"))
|
.subcommand(Command::new("print").about("Print the board"))
|
||||||
|
.subcommand(Command::new("quit").alias("exit").about("Quit the program"))
|
||||||
|
.subcommand(Command::new("starting").about("Reset the board to the starting position"))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn respond(line: &str, state: &mut State) -> Result<CommandResult, String> {
|
fn respond(line: &str, state: &mut State) -> Result<CommandResult, String> {
|
||||||
|
@ -67,20 +70,72 @@ fn respond(line: &str, state: &mut State) -> Result<CommandResult, String> {
|
||||||
result.should_continue = false;
|
result.should_continue = false;
|
||||||
result.should_print_position = false;
|
result.should_print_position = false;
|
||||||
}
|
}
|
||||||
Some(("place", _matches)) => {
|
Some(("fen", _matches)) => {
|
||||||
let piece_arg = _matches.get_one::<String>("piece").unwrap();
|
println!(
|
||||||
let shape = match piece_arg.chars().nth(0) {
|
"{}",
|
||||||
Some(c) => Shape::try_from(c).map_err(|_| ()),
|
state
|
||||||
None => Err(()),
|
.position
|
||||||
}
|
.to_fen()
|
||||||
.map_err(|_| "Error: invalid piece specifier")?;
|
.map_err(|_| "error: Unable to generate FEN for current position")?
|
||||||
|
);
|
||||||
|
|
||||||
let square_arg = _matches.get_one::<String>("square").unwrap();
|
result.should_print_position = false;
|
||||||
let square = Square::from_algebraic_str(square_arg)
|
}
|
||||||
|
Some(("make", matches)) => {
|
||||||
|
let shape = matches
|
||||||
|
.get_one::<String>("piece")
|
||||||
|
.ok_or("Missing piece descriptor")?;
|
||||||
|
let shape = Shape::try_from(shape).map_err(|_| "Invalid piece descriptor")?;
|
||||||
|
|
||||||
|
let from_square = Square::from_algebraic_str(
|
||||||
|
matches.get_one::<String>("from").ok_or("Missing square")?,
|
||||||
|
)
|
||||||
|
.map_err(|_| "Error: invalid square specifier")?;
|
||||||
|
|
||||||
|
let to_square = Square::from_algebraic_str(
|
||||||
|
matches.get_one::<String>("to").ok_or("Missing square")?,
|
||||||
|
)
|
||||||
|
.map_err(|_| "Error: invalid square specifier")?;
|
||||||
|
|
||||||
|
let mv = MoveBuilder::new(
|
||||||
|
Piece::new(state.position.player_to_move(), shape),
|
||||||
|
from_square,
|
||||||
|
to_square,
|
||||||
|
)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
state.position = MakeMoveBuilder::new(&state.position)
|
||||||
|
.make(&mv)
|
||||||
|
.map_err(|err| format!("error: Cannot make move: {:?}", err))?
|
||||||
|
.build();
|
||||||
|
state.builder = PositionBuilder::from_position(&state.position);
|
||||||
|
}
|
||||||
|
Some(("place", matches)) => {
|
||||||
|
let color = matches
|
||||||
|
.get_one::<String>("color")
|
||||||
|
.ok_or("Missing color descriptor")?;
|
||||||
|
let color = Color::try_from(color).map_err(|_| "Invalid color descriptor")?;
|
||||||
|
|
||||||
|
let shape = matches
|
||||||
|
.get_one::<String>("piece")
|
||||||
|
.ok_or("Missing piece descriptor")?;
|
||||||
|
let shape = Shape::try_from(shape).map_err(|_| "Invalid piece descriptor")?;
|
||||||
|
|
||||||
|
let square = matches
|
||||||
|
.get_one::<String>("square")
|
||||||
|
.ok_or("Missing square")?;
|
||||||
|
let square = Square::from_algebraic_str(square)
|
||||||
.map_err(|_| "Error: invalid square specifier")?;
|
.map_err(|_| "Error: invalid square specifier")?;
|
||||||
|
|
||||||
pos.place_piece(&Piece::new(Color::White, shape), &square)
|
let piece = PlacedPiece::new(Piece::new(color, shape), square);
|
||||||
.map_err(|_| "Error: Unable to place piece")?;
|
|
||||||
|
state.builder.place_piece(piece);
|
||||||
|
state.position = state.builder.build();
|
||||||
|
}
|
||||||
|
Some(("starting", _matches)) => {
|
||||||
|
let starting_position = Position::starting();
|
||||||
|
state.builder = PositionBuilder::from_position(&starting_position);
|
||||||
|
state.position = starting_position;
|
||||||
}
|
}
|
||||||
Some((name, _matches)) => unimplemented!("{name}"),
|
Some((name, _matches)) => unimplemented!("{name}"),
|
||||||
None => unreachable!("Subcommand required"),
|
None => unreachable!("Subcommand required"),
|
||||||
|
@ -107,7 +162,7 @@ fn main() -> Result<(), String> {
|
||||||
println!("{} to move.", state.position.player_to_move());
|
println!("{} to move.", state.position.player_to_move());
|
||||||
}
|
}
|
||||||
|
|
||||||
let readline = editor.readline("? ");
|
let readline = editor.readline("\n? ");
|
||||||
match readline {
|
match readline {
|
||||||
Ok(line) => {
|
Ok(line) => {
|
||||||
let line = line.trim();
|
let line = line.trim();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue