An attempt at making unit structs for Color and piece Shape
My idea was to implement traits on Piece that return sight lines, etc. This has turned out to be much more complex than I thought it would be. Ultimately, I don't think it's worth the effort.
This commit is contained in:
parent
953c2f1522
commit
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