Compare commits
1 commit
main
...
experiment
Author | SHA1 | Date | |
---|---|---|---|
0d8653894a |
19 changed files with 499 additions and 320 deletions
|
@ -1,7 +1,7 @@
|
|||
// Eryn Wells <eryn@erynwells.me>
|
||||
|
||||
use super::library::{library, FILES, RANKS};
|
||||
use super::{LeadingBitScanner, TrailingBitScanner};
|
||||
use super::LeadingBitScanner;
|
||||
use crate::{square::Direction, Square};
|
||||
use std::fmt;
|
||||
use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, Not};
|
||||
|
|
9
board/src/display.rs
Normal file
9
board/src/display.rs
Normal file
|
@ -0,0 +1,9 @@
|
|||
// Eryn Wells <eryn@erynwells.me>
|
||||
|
||||
pub trait ASCIIDisplay {
|
||||
fn fmt(&self, &mut f: fmt::Formatter) -> fmt::Result;
|
||||
}
|
||||
|
||||
pub trait UnicodeDisplay {
|
||||
fn fmt(&self, &mut f: fmt::Formatter) -> fmt::Result;
|
||||
}
|
|
@ -1,13 +1,15 @@
|
|||
// Eryn Wells <eryn@erynwells.me>
|
||||
|
||||
mod bitboard;
|
||||
mod moves;
|
||||
//mod moves;
|
||||
#[macro_use]
|
||||
pub mod piece;
|
||||
#[macro_use]
|
||||
pub mod position;
|
||||
mod square;
|
||||
|
||||
pub use moves::Move;
|
||||
pub(crate) use bitboard::BitBoard;
|
||||
//pub use moves::Move;
|
||||
pub use piece::Color;
|
||||
pub use position::Position;
|
||||
pub use square::{File, Rank, Square};
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
// Eryn Wells <eryn@erynwells.me>
|
||||
|
||||
use super::{move_generator_declaration, MoveGeneratorInternal, MoveSet};
|
||||
use super::{classical, move_generator_declaration, MoveGeneratorInternal, MoveSet, PieceSight};
|
||||
use crate::{
|
||||
bitboard::BitBoard,
|
||||
piece::{Color, Piece, PlacedPiece},
|
||||
square::Direction,
|
||||
Move, Position,
|
||||
};
|
||||
|
||||
|
@ -20,35 +18,14 @@ impl<'pos> MoveGeneratorInternal for ClassicalMoveGenerator<'pos> {
|
|||
let color = piece.color();
|
||||
let square = placed_piece.square();
|
||||
|
||||
let blockers = position.occupied_squares();
|
||||
let empty_squares = !blockers;
|
||||
let empty_squares = position.empty_squares();
|
||||
let friendly_pieces = position.bitboard_for_color(color);
|
||||
let opposing_pieces = position.bitboard_for_color(color.other());
|
||||
|
||||
let mut all_moves = BitBoard::empty();
|
||||
let sight = classical::BishopSight.sight(square, position);
|
||||
|
||||
macro_rules! update_moves_with_ray {
|
||||
($direction:ident, $occupied_squares:tt) => {
|
||||
let ray = BitBoard::ray(square, Direction::$direction);
|
||||
if let Some(first_occupied_square) =
|
||||
BitBoard::$occupied_squares(&(ray & blockers)).next()
|
||||
{
|
||||
let remainder = BitBoard::ray(first_occupied_square, Direction::$direction);
|
||||
let attack_ray = ray & !remainder;
|
||||
all_moves |= attack_ray;
|
||||
} else {
|
||||
all_moves |= ray;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
update_moves_with_ray!(NorthEast, occupied_squares_trailing);
|
||||
update_moves_with_ray!(NorthWest, occupied_squares_trailing);
|
||||
update_moves_with_ray!(SouthEast, occupied_squares);
|
||||
update_moves_with_ray!(SouthWest, occupied_squares);
|
||||
|
||||
let quiet_moves_bb = all_moves & (empty_squares | !friendly_pieces);
|
||||
let capture_moves_bb = all_moves & opposing_pieces;
|
||||
let quiet_moves_bb = sight & (empty_squares | !friendly_pieces);
|
||||
let capture_moves_bb = sight & opposing_pieces;
|
||||
|
||||
let map_to_move = |sq| Move::new(piece, square, sq);
|
||||
let quiet_moves = quiet_moves_bb.occupied_squares().map(map_to_move);
|
||||
|
|
1
board/src/moves/classical.rs
Normal file
1
board/src/moves/classical.rs
Normal file
|
@ -0,0 +1 @@
|
|||
// Eryn Wells <eryn@erynwells.me>
|
|
@ -3,7 +3,7 @@
|
|||
//! Declares the KingMoveGenerator type. This struct is responsible for
|
||||
//! generating the possible moves for the king in the given position.
|
||||
|
||||
use super::{move_generator_declaration, MoveGeneratorInternal, MoveSet};
|
||||
use super::{classical, move_generator_declaration, MoveGeneratorInternal, MoveSet, PieceSight};
|
||||
use crate::{
|
||||
bitboard::BitBoard,
|
||||
piece::{Color, Piece, PlacedPiece},
|
||||
|
@ -50,7 +50,7 @@ impl<'pos> MoveGeneratorInternal for KingMoveGenerator<'pos> {
|
|||
let empty_squares = position.empty_squares();
|
||||
let opposing_pieces = position.bitboard_for_color(color.other());
|
||||
|
||||
let all_moves = BitBoard::king_moves(square);
|
||||
let all_moves = classical::KingSight.sight(square, position);
|
||||
let quiet_moves_bb = all_moves & empty_squares;
|
||||
let capture_moves_bb = all_moves & opposing_pieces;
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// Eryn Wells <eryn@erynwells.me>
|
||||
|
||||
mod bishop;
|
||||
mod classical;
|
||||
mod king;
|
||||
mod knight;
|
||||
mod r#move;
|
||||
|
@ -9,6 +10,7 @@ mod move_set;
|
|||
mod pawn;
|
||||
mod queen;
|
||||
mod rook;
|
||||
pub(crate) mod sight;
|
||||
|
||||
pub use move_generator::Moves;
|
||||
pub use r#move::Move;
|
||||
|
@ -16,7 +18,6 @@ pub use r#move::Move;
|
|||
pub(self) use move_set::MoveSet;
|
||||
|
||||
use crate::{
|
||||
bitboard::BitBoard,
|
||||
piece::{Color, Piece, PlacedPiece},
|
||||
Position, Square,
|
||||
};
|
||||
|
@ -35,6 +36,7 @@ macro_rules! move_generator_declaration {
|
|||
move_generator_declaration!($name, getters);
|
||||
};
|
||||
($name:ident, struct) => {
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub(super) struct $name<'pos> {
|
||||
position: &'pos crate::Position,
|
||||
color: crate::piece::Color,
|
||||
|
|
|
@ -1,41 +1,86 @@
|
|||
// Eryn Wells <eryn@erynwells.me>
|
||||
|
||||
use crate::{
|
||||
piece::{Piece, PlacedPiece, Shape},
|
||||
position::BoardSide,
|
||||
Square,
|
||||
};
|
||||
use crate::{piece::*, position::BoardSide, Square};
|
||||
|
||||
#[derive(Debug, Clone, Eq, Hash, PartialEq)]
|
||||
pub struct Move {
|
||||
piece: Piece,
|
||||
from: Square,
|
||||
to: Square,
|
||||
capturing: Option<PlacedPiece>,
|
||||
promoting_to: Option<Shape>,
|
||||
/// A move that transfers a piece from one square to another.
|
||||
trait Move<C: Color, S: Shape>: Sized {
|
||||
fn piece(&self) -> Piece<C, S>;
|
||||
fn from_square(&self) -> Square;
|
||||
fn to_square(&self) -> Square;
|
||||
}
|
||||
|
||||
impl Move {
|
||||
pub fn new(piece: Piece, from: Square, to: Square) -> Move {
|
||||
Move {
|
||||
/// A move that captures an opposing piece.
|
||||
trait Capturing<C: Color, S: Shape, CapturedS: Shape>: Move<C, S> {
|
||||
type CaptureMove;
|
||||
|
||||
fn capturing(self, capturing: CapturedS) -> Self::CaptureMove;
|
||||
fn captured_piece(&self) -> Piece<C::Other, CapturedS>;
|
||||
}
|
||||
|
||||
/// A move that promotes a pawn to another piece.
|
||||
trait Promoting<C: Color, S: Shape, PromotingS: Shape>: Move<C, Pawn> {
|
||||
type PromotionMove;
|
||||
|
||||
fn promoting_to(self, shape: PromotingS) -> Self::PromotionMove;
|
||||
fn promoting_piece(&self) -> Piece<C, S>;
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, Hash, PartialEq)]
|
||||
pub struct SimpleMove<C, S> {
|
||||
piece: Piece<C, S>,
|
||||
from_square: Square,
|
||||
to_square: Square,
|
||||
}
|
||||
|
||||
impl<C: Color, S: Shape> SimpleMove<C, S> {
|
||||
fn new(piece: Piece<C, S>, from_square: Square, to_square: Square) -> Self {
|
||||
SimpleMove {
|
||||
piece,
|
||||
from,
|
||||
to,
|
||||
capturing: None,
|
||||
promoting_to: None,
|
||||
from_square,
|
||||
to_square,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn capturing(mut self, piece: PlacedPiece) -> Move {
|
||||
self.capturing = Some(piece);
|
||||
self
|
||||
fn capturing<CapturedS: Shape>(
|
||||
self,
|
||||
captured_piece: Piece<C::Other, CapturedS>,
|
||||
) -> Capture<C, S, CapturedS> {
|
||||
Capture {
|
||||
r#move: self,
|
||||
captured_piece,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<C, S> Move<C, S> for Piece<C, S> {
|
||||
fn piece(&self) -> Piece<C, S> {
|
||||
self.piece
|
||||
}
|
||||
|
||||
pub fn promoting_to(mut self, shape: Shape) -> Move {
|
||||
self.promoting_to = Some(shape);
|
||||
self
|
||||
fn from_square(&self) -> Square {
|
||||
self.from_square
|
||||
}
|
||||
|
||||
fn to_square(&self) -> Square {
|
||||
self.to_square
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Capture<C: Color, S: Shape, CapturedS: Shape> {
|
||||
r#move: dyn Move<C, S>,
|
||||
captured_piece: Piece<C::Other, CapturedS>,
|
||||
}
|
||||
|
||||
pub struct Promotion<C: Color, PromS: Shape> {
|
||||
r#move: dyn Move<C, Pawn>,
|
||||
promoting_to_shape: PromS,
|
||||
}
|
||||
|
||||
pub struct CapturingMove<C: Color, S: Shape, CapturingShape: Shape> {
|
||||
capturing: PlacedPiece<C::Other, CapturingShape>,
|
||||
}
|
||||
|
||||
impl<C: Color, S: Shape> Move<C, S> {
|
||||
pub fn is_castle(&self) -> bool {
|
||||
let color = self.piece.color();
|
||||
self.piece.shape() == Shape::King
|
||||
|
|
|
@ -9,6 +9,7 @@ use super::{
|
|||
use crate::piece::Color;
|
||||
use crate::Position;
|
||||
|
||||
#[derive(Clone, Eq, PartialEq)]
|
||||
pub struct Moves<'pos> {
|
||||
pawn_moves: PawnMoveGenerator<'pos>,
|
||||
knight_moves: KnightMoveGenerator<'pos>,
|
||||
|
|
|
@ -1,16 +1,19 @@
|
|||
use crate::{bitboard::BitBoard, piece::PlacedPiece, Move};
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
struct BitBoardSet {
|
||||
quiet: BitBoard,
|
||||
captures: BitBoard,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
struct MoveListSet {
|
||||
quiet: Vec<Move>,
|
||||
captures: Vec<Move>,
|
||||
}
|
||||
|
||||
/// A set of moves for a piece on the board.
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub(super) struct MoveSet {
|
||||
piece: PlacedPiece,
|
||||
bitboards: BitBoardSet,
|
||||
|
|
|
@ -12,7 +12,7 @@ enum MoveList {
|
|||
Captures = 2,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
struct MoveIterator(usize, usize);
|
||||
|
||||
struct MoveGenerationParameters {
|
||||
|
@ -23,6 +23,7 @@ struct MoveGenerationParameters {
|
|||
right_capture_shift: fn(BitBoard) -> BitBoard,
|
||||
}
|
||||
|
||||
#[derive(Clone, Eq, PartialEq)]
|
||||
pub(super) struct PawnMoveGenerator<'pos> {
|
||||
color: Color,
|
||||
position: &'pos Position,
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
// Eryn Wells <eryn@erynwells.me>
|
||||
|
||||
use super::{move_generator_declaration, MoveGeneratorInternal, MoveSet};
|
||||
use super::{classical, move_generator_declaration, MoveGeneratorInternal, MoveSet, PieceSight};
|
||||
use crate::{
|
||||
bitboard::BitBoard,
|
||||
piece::{Color, Piece, PlacedPiece},
|
||||
square::Direction,
|
||||
Move, Position,
|
||||
};
|
||||
|
||||
|
@ -25,31 +23,7 @@ impl<'pos> MoveGeneratorInternal for ClassicalMoveGenerator<'pos> {
|
|||
let friendly_pieces = position.bitboard_for_color(color);
|
||||
let opposing_pieces = position.bitboard_for_color(color.other());
|
||||
|
||||
let mut all_moves = BitBoard::empty();
|
||||
|
||||
macro_rules! update_moves_with_ray {
|
||||
($direction:ident, $occupied_squares:tt) => {
|
||||
let ray = BitBoard::ray(square, Direction::$direction);
|
||||
if let Some(first_occupied_square) =
|
||||
BitBoard::$occupied_squares(&(ray & blockers)).next()
|
||||
{
|
||||
let remainder = BitBoard::ray(first_occupied_square, Direction::$direction);
|
||||
let attack_ray = ray & !remainder;
|
||||
all_moves |= attack_ray;
|
||||
} else {
|
||||
all_moves |= ray;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
update_moves_with_ray!(NorthWest, occupied_squares_trailing);
|
||||
update_moves_with_ray!(North, occupied_squares_trailing);
|
||||
update_moves_with_ray!(NorthEast, occupied_squares_trailing);
|
||||
update_moves_with_ray!(East, occupied_squares_trailing);
|
||||
update_moves_with_ray!(SouthEast, occupied_squares);
|
||||
update_moves_with_ray!(South, occupied_squares);
|
||||
update_moves_with_ray!(SouthWest, occupied_squares);
|
||||
update_moves_with_ray!(West, occupied_squares);
|
||||
let mut all_moves = classical::QueenSight.sight(square, position);
|
||||
|
||||
let quiet_moves_bb = all_moves & (empty_squares | !friendly_pieces);
|
||||
let capture_moves_bb = all_moves & opposing_pieces;
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
// Eryn Wells <eryn@erynwells.me>
|
||||
|
||||
use super::{move_generator_declaration, MoveGeneratorInternal, MoveSet};
|
||||
use super::{classical, move_generator_declaration, MoveGeneratorInternal, MoveSet, PieceSight};
|
||||
use crate::{
|
||||
bitboard::BitBoard,
|
||||
piece::{Color, Piece, PlacedPiece},
|
||||
square::Direction,
|
||||
Move, Position,
|
||||
};
|
||||
|
||||
|
@ -25,27 +23,7 @@ impl<'pos> MoveGeneratorInternal for ClassicalMoveGenerator<'pos> {
|
|||
let friendly_pieces = position.bitboard_for_color(color);
|
||||
let opposing_pieces = position.bitboard_for_color(color.other());
|
||||
|
||||
let mut all_moves = BitBoard::empty();
|
||||
|
||||
macro_rules! update_moves_with_ray {
|
||||
($direction:ident, $occupied_squares:tt) => {
|
||||
let ray = BitBoard::ray(square, Direction::$direction);
|
||||
if let Some(first_occupied_square) =
|
||||
BitBoard::$occupied_squares(&(ray & blockers)).next()
|
||||
{
|
||||
let remainder = BitBoard::ray(first_occupied_square, Direction::$direction);
|
||||
let attack_ray = ray & !remainder;
|
||||
all_moves |= attack_ray;
|
||||
} else {
|
||||
all_moves |= ray;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
update_moves_with_ray!(North, occupied_squares_trailing);
|
||||
update_moves_with_ray!(East, occupied_squares_trailing);
|
||||
update_moves_with_ray!(South, occupied_squares);
|
||||
update_moves_with_ray!(West, occupied_squares);
|
||||
let all_moves = classical::RookSight.sight(square, position);
|
||||
|
||||
let quiet_moves_bb = all_moves & (empty_squares | !friendly_pieces);
|
||||
let capture_moves_bb = all_moves & opposing_pieces;
|
||||
|
|
165
board/src/moves/sight.rs
Normal file
165
board/src/moves/sight.rs
Normal file
|
@ -0,0 +1,165 @@
|
|||
// Eryn Wells <eryn@erynwells.me>
|
||||
|
||||
use crate::{piece::*, square::Direction, BitBoard, Position, Square};
|
||||
|
||||
pub(crate) trait Sight {
|
||||
fn sight_on_empty_board(self, square: Square) -> BitBoard;
|
||||
fn sight<PosC>(self, square: Square, position: &Position<PosC>) -> BitBoard;
|
||||
}
|
||||
|
||||
impl Sight for Piece<White, Pawn> {
|
||||
fn sight_on_empty_board(self, square: Square) -> BitBoard {
|
||||
let pawn: BitBoard = square.into();
|
||||
pawn.shift_north_west_one() | pawn.shift_north_east_one()
|
||||
}
|
||||
|
||||
fn sight<PosC>(self, square: Square, position: &Position<PosC>) -> BitBoard {
|
||||
let mut possible_squares = position.empty_squares() | position.opposing_pieces();
|
||||
if let Some(en_passant) = position.en_passant_square() {
|
||||
possible_squares |= en_passant.into();
|
||||
}
|
||||
|
||||
self.sight_on_empty_board(square) & possible_squares
|
||||
}
|
||||
}
|
||||
|
||||
impl Sight for Piece<Black, Pawn> {
|
||||
fn sight_on_empty_board(self, square: Square) -> BitBoard {
|
||||
let pawn: BitBoard = square.into();
|
||||
pawn.shift_south_west_one() | pawn.shift_south_east_one()
|
||||
}
|
||||
|
||||
fn sight<PosC>(self, square: Square, position: &Position<PosC>) -> BitBoard {
|
||||
let mut possible_squares = position.empty_squares() | position.opposing_pieces();
|
||||
if let Some(en_passant) = position.en_passant_square() {
|
||||
possible_squares |= en_passant.into();
|
||||
}
|
||||
|
||||
self.sight_on_empty_board(square) & possible_squares
|
||||
}
|
||||
}
|
||||
|
||||
impl<C> Sight for Piece<C, Knight> {
|
||||
fn sight_on_empty_board(self, square: Square) -> BitBoard {
|
||||
BitBoard::knight_moves(square)
|
||||
}
|
||||
|
||||
fn sight<PosC>(self, square: Square, position: &Position<PosC>) -> BitBoard {
|
||||
self.sight_on_empty_board(square) & !position.friendly_pieces()
|
||||
}
|
||||
}
|
||||
|
||||
impl<C> Sight for Piece<C, Bishop> {
|
||||
fn sight_on_empty_board(self, square: Square) -> BitBoard {
|
||||
BitBoard::bishop_moves(square)
|
||||
}
|
||||
|
||||
fn sight<PosC>(self, square: Square, position: &Position<PosC>) -> BitBoard {
|
||||
let mut sight = BitBoard::empty();
|
||||
|
||||
let blockers = position.occupied_squares();
|
||||
macro_rules! update_moves_with_ray {
|
||||
($direction:ident, $occupied_squares:tt) => {
|
||||
let ray = BitBoard::ray(square, Direction::$direction);
|
||||
if let Some(first_occupied_square) =
|
||||
BitBoard::$occupied_squares(&(ray & blockers)).next()
|
||||
{
|
||||
let remainder = BitBoard::ray(first_occupied_square, Direction::$direction);
|
||||
let attack_ray = ray & !remainder;
|
||||
sight |= attack_ray;
|
||||
} else {
|
||||
sight |= ray;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
update_moves_with_ray!(NorthEast, occupied_squares_trailing);
|
||||
update_moves_with_ray!(NorthWest, occupied_squares_trailing);
|
||||
update_moves_with_ray!(SouthEast, occupied_squares);
|
||||
update_moves_with_ray!(SouthWest, occupied_squares);
|
||||
|
||||
sight
|
||||
}
|
||||
}
|
||||
|
||||
impl<C> Sight for Piece<C, Rook> {
|
||||
fn sight_on_empty_board(self, square: Square) -> BitBoard {
|
||||
BitBoard::rook_moves(square)
|
||||
}
|
||||
|
||||
fn sight<PosC>(self, square: Square, position: &Position<PosC>) -> BitBoard {
|
||||
let mut sight = BitBoard::empty();
|
||||
|
||||
let blockers = position.occupied_squares();
|
||||
|
||||
macro_rules! update_moves_with_ray {
|
||||
($direction:ident, $occupied_squares:tt) => {
|
||||
let ray = BitBoard::ray(square, Direction::$direction);
|
||||
if let Some(first_occupied_square) =
|
||||
BitBoard::$occupied_squares(&(ray & blockers)).next()
|
||||
{
|
||||
let remainder = BitBoard::ray(first_occupied_square, Direction::$direction);
|
||||
let attack_ray = ray & !remainder;
|
||||
sight |= attack_ray;
|
||||
} else {
|
||||
sight |= ray;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
update_moves_with_ray!(North, occupied_squares_trailing);
|
||||
update_moves_with_ray!(East, occupied_squares_trailing);
|
||||
update_moves_with_ray!(South, occupied_squares);
|
||||
update_moves_with_ray!(West, occupied_squares);
|
||||
|
||||
sight
|
||||
}
|
||||
}
|
||||
|
||||
impl<C> Sight for Piece<C, Queen> {
|
||||
fn sight_on_empty_board(self, square: Square) -> BitBoard {
|
||||
BitBoard::queen_moves(square)
|
||||
}
|
||||
|
||||
fn sight<PosC>(self, square: Square, position: &Position<PosC>) -> BitBoard {
|
||||
let mut sight = BitBoard::empty();
|
||||
|
||||
let blockers = position.occupied_squares();
|
||||
|
||||
macro_rules! update_moves_with_ray {
|
||||
($direction:ident, $occupied_squares:tt) => {
|
||||
let ray = BitBoard::ray(square, Direction::$direction);
|
||||
if let Some(first_occupied_square) =
|
||||
BitBoard::$occupied_squares(&(ray & blockers)).next()
|
||||
{
|
||||
let remainder = BitBoard::ray(first_occupied_square, Direction::$direction);
|
||||
let attack_ray = ray & !remainder;
|
||||
sight |= attack_ray;
|
||||
} else {
|
||||
sight |= ray;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
update_moves_with_ray!(NorthWest, occupied_squares_trailing);
|
||||
update_moves_with_ray!(North, occupied_squares_trailing);
|
||||
update_moves_with_ray!(NorthEast, occupied_squares_trailing);
|
||||
update_moves_with_ray!(East, occupied_squares_trailing);
|
||||
update_moves_with_ray!(SouthEast, occupied_squares);
|
||||
update_moves_with_ray!(South, occupied_squares);
|
||||
update_moves_with_ray!(SouthWest, occupied_squares);
|
||||
update_moves_with_ray!(West, occupied_squares);
|
||||
|
||||
sight
|
||||
}
|
||||
}
|
||||
|
||||
impl<C> Sight for Piece<C, King> {
|
||||
fn sight_on_empty_board(self, square: Square) -> BitBoard {
|
||||
BitBoard::king_moves(square)
|
||||
}
|
||||
|
||||
fn sight<PosC>(self, square: Square, position: &Position<PosC>) -> BitBoard {
|
||||
self.sight_on_empty_board(square) & !position.friendly_pieces()
|
||||
}
|
||||
}
|
|
@ -2,117 +2,80 @@
|
|||
|
||||
use crate::{bitboard::BitBoard, Square};
|
||||
use std::fmt;
|
||||
use std::slice::Iter;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub enum Color {
|
||||
White = 0,
|
||||
Black = 1,
|
||||
pub trait Color: Sized {
|
||||
type Other: Color;
|
||||
}
|
||||
|
||||
impl Color {
|
||||
pub fn iter() -> impl Iterator<Item = Color> {
|
||||
[Color::White, Color::Black].into_iter()
|
||||
}
|
||||
|
||||
pub fn other(&self) -> Color {
|
||||
match self {
|
||||
Color::White => Color::Black,
|
||||
Color::Black => Color::White,
|
||||
macro_rules! into_int_type {
|
||||
($name:ident, $int_type:ident, $value:expr) => {
|
||||
impl Into<$int_type> for $name {
|
||||
fn into(self) -> $int_type {
|
||||
$value
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub enum Shape {
|
||||
Pawn = 0,
|
||||
Knight = 1,
|
||||
Bishop = 2,
|
||||
Rook = 3,
|
||||
Queen = 4,
|
||||
King = 5,
|
||||
}
|
||||
macro_rules! color_struct {
|
||||
($name:ident, $index:expr, $other_color:ident) => {
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub struct $name;
|
||||
|
||||
impl Shape {
|
||||
pub fn iter() -> Iter<'static, Shape> {
|
||||
const ALL_SHAPES: [Shape; 6] = [
|
||||
Shape::Pawn,
|
||||
Shape::Knight,
|
||||
Shape::Bishop,
|
||||
Shape::Rook,
|
||||
Shape::Queen,
|
||||
Shape::King,
|
||||
];
|
||||
|
||||
ALL_SHAPES.iter()
|
||||
}
|
||||
|
||||
pub fn promotable() -> Iter<'static, Shape> {
|
||||
const PROMOTABLE_SHAPES: [Shape; 4] =
|
||||
[Shape::Queen, Shape::Rook, Shape::Bishop, Shape::Knight];
|
||||
|
||||
PROMOTABLE_SHAPES.iter()
|
||||
}
|
||||
|
||||
fn _ascii_representation(&self) -> char {
|
||||
match self {
|
||||
Shape::Pawn => 'p',
|
||||
Shape::Knight => 'N',
|
||||
Shape::Bishop => 'B',
|
||||
Shape::Rook => 'R',
|
||||
Shape::Queen => 'Q',
|
||||
Shape::King => 'K',
|
||||
impl Color for $name {
|
||||
type Other = $other_color;
|
||||
}
|
||||
}
|
||||
|
||||
into_int_type!($name, u8, $index);
|
||||
into_int_type!($name, usize, $index);
|
||||
};
|
||||
}
|
||||
|
||||
color_struct!(White, 0, Black);
|
||||
color_struct!(Black, 1, White);
|
||||
|
||||
macro_rules! shape_struct {
|
||||
($name:ident, $index:expr, $char:expr, $white_char:expr, $black_char:expr) => {
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub struct $name;
|
||||
|
||||
impl Shape for $name {}
|
||||
|
||||
into_int_type!($name, u8, $index);
|
||||
into_int_type!($name, usize, $index);
|
||||
|
||||
impl Into<char> for $name {
|
||||
fn into(self) -> char {
|
||||
$char
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Piece<$name, White> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", $white_char)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Piece<$name, Black> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", $black_char)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub trait Shape: Sized {}
|
||||
|
||||
shape_struct!(Pawn, 0, 'P', '♙', '♟');
|
||||
shape_struct!(Knight, 1, 'N', '♘', '♞');
|
||||
shape_struct!(Bishop, 2, 'B', '♗', '♝');
|
||||
shape_struct!(Rook, 3, 'R', '♖', '♜');
|
||||
shape_struct!(Queen, 4, 'Q', '♕', '♛');
|
||||
shape_struct!(King, 5, 'K', '♔', '♚');
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub struct TryFromError;
|
||||
|
||||
impl TryFrom<char> for Shape {
|
||||
type Error = TryFromError;
|
||||
|
||||
fn try_from(value: char) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
'p' => Ok(Shape::Pawn),
|
||||
'N' => Ok(Shape::Knight),
|
||||
'B' => Ok(Shape::Bishop),
|
||||
'R' => Ok(Shape::Rook),
|
||||
'Q' => Ok(Shape::Queen),
|
||||
'K' => Ok(Shape::King),
|
||||
_ => Err(TryFromError),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&str> for Shape {
|
||||
type Error = TryFromError;
|
||||
|
||||
fn try_from(value: &str) -> Result<Self, Self::Error> {
|
||||
let first_char = value.chars().nth(0).ok_or(TryFromError)?;
|
||||
Shape::try_from(first_char)
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<char> for &Shape {
|
||||
fn into(self) -> char {
|
||||
self._ascii_representation()
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<char> for Shape {
|
||||
fn into(self) -> char {
|
||||
self._ascii_representation()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Shape {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let self_char: char = self.into();
|
||||
write!(f, "{}", self_char)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub enum PiecePlacementError {
|
||||
ExistsOnSquare,
|
||||
|
@ -129,24 +92,28 @@ macro_rules! piece {
|
|||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub struct Piece {
|
||||
color: Color,
|
||||
shape: Shape,
|
||||
pub struct Piece<C: Color, S: Shape> {
|
||||
color: C,
|
||||
shape: S,
|
||||
}
|
||||
|
||||
macro_rules! piece_constructor {
|
||||
($func_name:ident, $type:tt) => {
|
||||
pub fn $func_name(color: Color) -> Piece {
|
||||
($func_name:ident, $shape:tt) => {
|
||||
pub fn $func_name(color: C) -> Piece<C, S> {
|
||||
Piece {
|
||||
color,
|
||||
shape: Shape::$type,
|
||||
shape: $shape,
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl Piece {
|
||||
pub fn new(color: Color, shape: Shape) -> Piece {
|
||||
impl<C, S> Piece<C, S>
|
||||
where
|
||||
C: Color,
|
||||
S: Shape,
|
||||
{
|
||||
pub fn new(color: C, shape: S) -> Piece<C, S> {
|
||||
Piece { color, shape }
|
||||
}
|
||||
|
||||
|
@ -157,49 +124,28 @@ impl Piece {
|
|||
piece_constructor!(queen, Queen);
|
||||
piece_constructor!(king, King);
|
||||
|
||||
pub fn color(&self) -> Color {
|
||||
pub fn color(&self) -> C {
|
||||
self.color
|
||||
}
|
||||
|
||||
pub fn shape(&self) -> Shape {
|
||||
pub fn shape(&self) -> S {
|
||||
self.shape
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Piece {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let char = match (self.color, self.shape) {
|
||||
(Color::White, Shape::Pawn) => '♟',
|
||||
(Color::White, Shape::Knight) => '♞',
|
||||
(Color::White, Shape::Bishop) => '♝',
|
||||
(Color::White, Shape::Rook) => '♜',
|
||||
(Color::White, Shape::Queen) => '♛',
|
||||
(Color::White, Shape::King) => '♚',
|
||||
(Color::Black, Shape::Pawn) => '♙',
|
||||
(Color::Black, Shape::Knight) => '♘',
|
||||
(Color::Black, Shape::Bishop) => '♗',
|
||||
(Color::Black, Shape::Rook) => '♖',
|
||||
(Color::Black, Shape::Queen) => '♕',
|
||||
(Color::Black, Shape::King) => '♔',
|
||||
};
|
||||
|
||||
write!(f, "{}", char)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub struct PlacedPiece {
|
||||
piece: Piece,
|
||||
pub struct PlacedPiece<C, S> {
|
||||
piece: Piece<C, S>,
|
||||
square: Square,
|
||||
}
|
||||
|
||||
impl PlacedPiece {
|
||||
pub const fn new(piece: Piece, square: Square) -> PlacedPiece {
|
||||
impl<C, S> PlacedPiece<C, S> {
|
||||
pub const fn new(piece: Piece<C, S>, square: Square) -> PlacedPiece<C, S> {
|
||||
PlacedPiece { piece, square }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn piece(&self) -> Piece {
|
||||
pub fn piece(&self) -> Piece<C, S> {
|
||||
self.piece
|
||||
}
|
||||
|
||||
|
|
|
@ -3,15 +3,15 @@
|
|||
use crate::{File, Position, Rank, Square};
|
||||
use std::{fmt, fmt::Write};
|
||||
|
||||
pub struct DiagramFormatter<'a>(&'a Position);
|
||||
pub struct DiagramFormatter<'a, PosC>(&'a Position<PosC>);
|
||||
|
||||
impl<'a> DiagramFormatter<'a> {
|
||||
pub fn new(position: &'a Position) -> DiagramFormatter {
|
||||
impl<'a, PosC> DiagramFormatter<'a, PosC> {
|
||||
pub fn new(position: &'a Position<PosC>) -> DiagramFormatter<PosC> {
|
||||
DiagramFormatter(position)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> fmt::Display for DiagramFormatter<'a> {
|
||||
impl<'a, PosC> fmt::Display for DiagramFormatter<'a, PosC> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let mut output = String::new();
|
||||
|
||||
|
|
|
@ -8,19 +8,32 @@ pub(super) struct Flags(u8);
|
|||
|
||||
impl Flags {
|
||||
#[inline]
|
||||
pub(super) fn player_has_right_to_castle_flag_offset(color: Color, side: BoardSide) -> u8 {
|
||||
pub(super) fn player_has_right_to_castle_flag_offset<C: Color>(
|
||||
color: C,
|
||||
side: BoardSide,
|
||||
) -> u8 {
|
||||
((color as u8) << 1) + side as u8
|
||||
}
|
||||
|
||||
pub(super) fn player_has_right_to_castle(&self, color: Color, side: BoardSide) -> bool {
|
||||
pub(super) fn player_has_right_to_castle<C: Color>(&self, color: C, side: BoardSide) -> bool {
|
||||
(self.0 & (1 << Self::player_has_right_to_castle_flag_offset(color, side))) != 0
|
||||
}
|
||||
|
||||
pub(super) fn set_player_has_right_to_castle_flag(&mut self, color: Color, side: BoardSide) {
|
||||
#[cfg(test)]
|
||||
pub(super) fn set_player_has_right_to_castle_flag<C: Color>(
|
||||
&mut self,
|
||||
color: C,
|
||||
side: BoardSide,
|
||||
) {
|
||||
self.0 |= 1 << Self::player_has_right_to_castle_flag_offset(color, side);
|
||||
}
|
||||
|
||||
pub(super) fn clear_player_has_right_to_castle_flag(&mut self, color: Color, side: BoardSide) {
|
||||
#[cfg(test)]
|
||||
pub(super) fn clear_player_has_right_to_castle_flag<C: Color>(
|
||||
&mut self,
|
||||
color: C,
|
||||
side: BoardSide,
|
||||
) {
|
||||
self.0 &= !(1 << Self::player_has_right_to_castle_flag_offset(color, side));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,33 +2,37 @@
|
|||
|
||||
use super::Position;
|
||||
use crate::bitboard::BitBoard;
|
||||
use crate::piece::{Color, Piece, PlacedPiece, Shape};
|
||||
use crate::piece::*;
|
||||
use crate::Square;
|
||||
|
||||
pub struct Pieces<'a> {
|
||||
color: Color,
|
||||
position: &'a Position,
|
||||
pub struct Pieces<'a, PosC, C: Color> {
|
||||
color: C,
|
||||
position: &'a Position<PosC>,
|
||||
|
||||
current_shape: Option<Shape>,
|
||||
current_shape: Option<dyn Shape>,
|
||||
|
||||
shape_iterator: Box<dyn Iterator<Item = &'static Shape>>,
|
||||
shape_iterator: std::array::IntoIter<dyn Shape, 6>,
|
||||
square_iterator: Option<Box<dyn Iterator<Item = Square>>>,
|
||||
}
|
||||
|
||||
impl<'a> Pieces<'a> {
|
||||
pub(crate) fn new(position: &Position, color: Color) -> Pieces {
|
||||
impl<'a, PosC, C> Pieces<'a, PosC, C> {
|
||||
pub(crate) fn new(position: &Position<PosC>, color: C) -> Pieces<PosC, C> {
|
||||
Pieces {
|
||||
color,
|
||||
position,
|
||||
current_shape: None,
|
||||
shape_iterator: Box::new(Shape::iter()),
|
||||
shape_iterator: [Pawn, Knight, Bishop, Rook, Queen, King].into_iter(),
|
||||
square_iterator: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for Pieces<'a> {
|
||||
type Item = PlacedPiece;
|
||||
impl<'a, PosC, C, S> Iterator for Pieces<'a, PosC, C>
|
||||
where
|
||||
C: Color,
|
||||
S: Shape,
|
||||
{
|
||||
type Item = PlacedPiece<C, S>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if let Some(square_iterator) = &mut self.square_iterator {
|
||||
|
@ -80,7 +84,11 @@ mod tests {
|
|||
use crate::Square;
|
||||
use std::collections::HashSet;
|
||||
|
||||
fn place_piece_in_position(pos: &mut Position, piece: Piece, sq: Square) {
|
||||
fn place_piece_in_position<PosC, C, S>(
|
||||
pos: &mut Position<PosC>,
|
||||
piece: Piece<C, S>,
|
||||
sq: Square,
|
||||
) {
|
||||
pos.place_piece(piece, sq)
|
||||
.expect("Unable to place {piece:?} queen on {sq}");
|
||||
}
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
use super::{flags::Flags, Pieces};
|
||||
use crate::{
|
||||
bitboard::BitBoard,
|
||||
moves::Moves,
|
||||
//moves::Moves,
|
||||
piece::{Color, Piece, PiecePlacementError, PlacedPiece, Shape},
|
||||
BitBoard,
|
||||
Square,
|
||||
};
|
||||
use std::fmt;
|
||||
|
@ -28,16 +28,9 @@ macro_rules! position {
|
|||
}
|
||||
|
||||
#[derive(Clone, Eq, Hash, PartialEq)]
|
||||
pub struct Position {
|
||||
color_to_move: Color,
|
||||
pub struct Position<ColorToMove> {
|
||||
color_to_move: ColorToMove,
|
||||
|
||||
/// Position flags indicating various bits of game state. The flags are as
|
||||
/// follows:
|
||||
///
|
||||
/// 0. white can castle king-side
|
||||
/// 1. white can castle queen-side
|
||||
/// 2. black can castle king-side
|
||||
/// 3. black can castle queen-side
|
||||
flags: Flags,
|
||||
|
||||
/// Composite bitboards for all the pieces of a particular color.
|
||||
|
@ -45,12 +38,14 @@ pub struct Position {
|
|||
|
||||
/// Bitboards representing positions of particular piece types per color.
|
||||
pieces_per_type: [[BitBoard; 6]; 2],
|
||||
|
||||
en_passant_square: Option<Square>,
|
||||
}
|
||||
|
||||
impl Position {
|
||||
pub fn empty() -> Position {
|
||||
impl<ColorToMove> Position<ColorToMove> {
|
||||
pub fn empty() -> Position<ColorToMove> {
|
||||
Position {
|
||||
color_to_move: Color::White,
|
||||
color_to_move: crate::piece::White,
|
||||
flags: Default::default(),
|
||||
pieces_per_color: [BitBoard::empty(); 2],
|
||||
pieces_per_type: [
|
||||
|
@ -71,11 +66,12 @@ impl Position {
|
|||
BitBoard::empty(),
|
||||
],
|
||||
],
|
||||
en_passant_square: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return a starting position.
|
||||
pub fn starting() -> Position {
|
||||
pub fn starting() -> Position<ColorToMove> {
|
||||
let white_pieces = [
|
||||
BitBoard::new(0x00FF000000000000),
|
||||
BitBoard::new(0x4200000000000000),
|
||||
|
@ -95,13 +91,14 @@ impl Position {
|
|||
];
|
||||
|
||||
Position {
|
||||
color_to_move: Color::White,
|
||||
color_to_move: crate::piece::White,
|
||||
flags: Default::default(),
|
||||
pieces_per_color: [
|
||||
white_pieces.iter().fold(BitBoard::empty(), |a, b| a | *b),
|
||||
black_pieces.iter().fold(BitBoard::empty(), |a, b| a | *b),
|
||||
],
|
||||
pieces_per_type: [white_pieces, black_pieces],
|
||||
en_passant_square: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -118,20 +115,15 @@ impl Position {
|
|||
/// 2. The king must not be in check
|
||||
/// 3. In the course of castling on that side, the king must not pass
|
||||
/// through a square that an enemy piece can see
|
||||
pub(crate) fn player_has_right_to_castle(&self, color: Color, side: BoardSide) -> bool {
|
||||
pub(crate) fn player_has_right_to_castle<C>(&self, color: C, side: BoardSide) -> bool {
|
||||
self.flags.player_has_right_to_castle(color, side)
|
||||
}
|
||||
|
||||
fn set_player_has_right_to_castle_flag(&mut self, color: Color, side: BoardSide) {
|
||||
self.flags.set_player_has_right_to_castle_flag(color, side);
|
||||
}
|
||||
|
||||
fn clear_player_has_right_to_castle_flag(&mut self, color: Color, side: BoardSide) {
|
||||
self.flags
|
||||
.clear_player_has_right_to_castle_flag(color, side);
|
||||
}
|
||||
|
||||
pub fn place_piece(&mut self, piece: Piece, square: Square) -> Result<(), PiecePlacementError> {
|
||||
pub fn place_piece<C, S>(
|
||||
&mut self,
|
||||
piece: Piece<C, S>,
|
||||
square: Square,
|
||||
) -> Result<(), PiecePlacementError> {
|
||||
let type_bb = self.bitboard_for_piece_mut(piece);
|
||||
|
||||
if type_bb.has_piece_at(square) {
|
||||
|
@ -146,40 +138,27 @@ impl Position {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn move_generator(&self, color: Color) -> Moves {
|
||||
Moves::new(self, color)
|
||||
}
|
||||
// pub fn move_generator<C>(&self, color: C) -> Moves {
|
||||
// Moves::new(self, color)
|
||||
// }
|
||||
|
||||
/// Return a BitBoard representing the set of squares containing a piece.
|
||||
#[inline]
|
||||
pub(crate) fn occupied_squares(&self) -> BitBoard {
|
||||
self.pieces_per_color[Color::White as usize] | self.pieces_per_color[Color::Black as usize]
|
||||
}
|
||||
|
||||
/// Return a BitBoard representing the set of squares containing a piece.
|
||||
/// This set is the inverse of `occupied_squares`.
|
||||
#[inline]
|
||||
pub(crate) fn empty_squares(&self) -> BitBoard {
|
||||
!self.occupied_squares()
|
||||
}
|
||||
|
||||
pub(crate) fn bitboard_for_piece(&self, piece: Piece) -> BitBoard {
|
||||
pub(crate) fn bitboard_for_piece<C, S>(&self, piece: Piece<C, S>) -> BitBoard {
|
||||
self.pieces_per_type[piece.color() as usize][piece.shape() as usize]
|
||||
}
|
||||
|
||||
fn bitboard_for_piece_mut(&mut self, piece: Piece) -> &mut BitBoard {
|
||||
fn bitboard_for_piece_mut<C, S>(&mut self, piece: Piece<C, S>) -> &mut BitBoard {
|
||||
&mut self.pieces_per_type[piece.color() as usize][piece.shape() as usize]
|
||||
}
|
||||
|
||||
pub(crate) fn bitboard_for_color(&self, color: Color) -> BitBoard {
|
||||
pub(crate) fn bitboard_for_color<C>(&self, color: C) -> BitBoard {
|
||||
self.pieces_per_color[color as usize]
|
||||
}
|
||||
|
||||
fn bitboard_for_color_mut(&mut self, color: Color) -> &mut BitBoard {
|
||||
fn bitboard_for_color_mut<C>(&mut self, color: C) -> &mut BitBoard {
|
||||
&mut self.pieces_per_color[color as usize]
|
||||
}
|
||||
|
||||
pub fn piece_on_square(&self, sq: Square) -> Option<PlacedPiece> {
|
||||
pub fn piece_on_square<C, S>(&self, sq: Square) -> Option<PlacedPiece<C, S>> {
|
||||
for color in Color::iter() {
|
||||
for shape in Shape::iter() {
|
||||
let piece = Piece::new(color, *shape);
|
||||
|
@ -193,19 +172,76 @@ impl Position {
|
|||
None
|
||||
}
|
||||
|
||||
pub fn pieces(&self, color: Color) -> Pieces {
|
||||
pub fn pieces<C>(&self, color: C) -> Pieces<ColorToMove, C> {
|
||||
Pieces::new(&self, color)
|
||||
}
|
||||
|
||||
pub fn king<C>(&self, color: C) -> PlacedPiece<C, crate::piece::King> {
|
||||
let king = Piece::king(color);
|
||||
let bitboard = self.bitboard_for_piece(king);
|
||||
let square = bitboard.occupied_squares().next().unwrap();
|
||||
PlacedPiece::new(king, square)
|
||||
}
|
||||
|
||||
pub fn is_king_in_check(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Position {
|
||||
impl<ColorToMove> Position<ColorToMove> {
|
||||
/// Return a BitBoard representing the set of squares containing a piece.
|
||||
#[inline]
|
||||
pub(crate) fn occupied_squares(&self) -> BitBoard {
|
||||
self.pieces_per_color[Color::White as usize] | self.pieces_per_color[Color::Black as usize]
|
||||
}
|
||||
|
||||
/// A BitBoard representing the set of empty squares. This set is the
|
||||
/// inverse of `occupied_squares`.
|
||||
#[inline]
|
||||
pub(crate) fn empty_squares(&self) -> BitBoard {
|
||||
!self.occupied_squares()
|
||||
}
|
||||
|
||||
/// A BitBoard representing squares occupied by the current player's pieces.
|
||||
pub(crate) fn friendly_pieces(&self) -> BitBoard {
|
||||
self.bitboard_for_color(self.color_to_move)
|
||||
}
|
||||
|
||||
/// A BitBoard representing squares occupied by the opposing player's pieces.
|
||||
pub(crate) fn opposing_pieces(&self) -> BitBoard {
|
||||
self.bitboard_for_color(self.color_to_move.other())
|
||||
}
|
||||
|
||||
/// If the previous move create an en passant elibile square, return `Some`.
|
||||
/// Otherwise, return `None`.
|
||||
pub(crate) fn en_passant_square(&self) -> Option<Square> {
|
||||
self.en_passant_square
|
||||
}
|
||||
}
|
||||
|
||||
impl<ColorToMove> Position<ColorToMove> {
|
||||
fn sight_of_pieces_of_color<C>(&self, color: C) -> BitBoard {
|
||||
self.pieces(color)
|
||||
.map(|placed_piece| {
|
||||
self.sight_of_piece(placed_piece)
|
||||
.sight(placed_piece.square(), self)
|
||||
})
|
||||
.fold(BitBoard::empty(), std::ops::BitOr::bitor)
|
||||
}
|
||||
|
||||
fn sight_of_piece<C, S>(&self, placed_piece: PlacedPiece<C, S>) -> BitBoard {
|
||||
placed_piece.piece().sight()
|
||||
}
|
||||
}
|
||||
|
||||
impl<ColorToMove> Default for Position<ColorToMove> {
|
||||
fn default() -> Self {
|
||||
Self::empty()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromIterator<PlacedPiece> for Position {
|
||||
fn from_iter<T: IntoIterator<Item = PlacedPiece>>(iter: T) -> Self {
|
||||
impl<ColorToMove, C, S> FromIterator<PlacedPiece<C, S>> for Position<ColorToMove> {
|
||||
fn from_iter<T: IntoIterator<Item = PlacedPiece<C, S>>>(iter: T) -> Self {
|
||||
let mut position = Position::empty();
|
||||
for placed_piece in iter {
|
||||
_ = position.place_piece(placed_piece.piece(), placed_piece.square());
|
||||
|
@ -215,7 +251,7 @@ impl FromIterator<PlacedPiece> for Position {
|
|||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Position {
|
||||
impl<ColorToMove> fmt::Debug for Position<ColorToMove> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let mut output = String::new();
|
||||
|
||||
|
@ -245,7 +281,7 @@ impl fmt::Debug for Position {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::piece::Shape;
|
||||
use crate::{piece::Shape, position::DiagramFormatter};
|
||||
|
||||
#[test]
|
||||
fn place_piece() {
|
||||
|
@ -273,6 +309,24 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn king_is_not_in_check() {
|
||||
let position = position![
|
||||
White King on E4,
|
||||
Black Rook on D8,
|
||||
];
|
||||
println!("{}", DiagramFormatter::new(&position));
|
||||
|
||||
assert!(!position.is_king_in_check());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn king_is_in_check() {
|
||||
let position = position![
|
||||
White King on E4,
|
||||
Black Rook on E8,
|
||||
];
|
||||
println!("{}", DiagramFormatter::new(&position));
|
||||
|
||||
assert!(position.is_king_in_check());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue