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>
|
// Eryn Wells <eryn@erynwells.me>
|
||||||
|
|
||||||
use super::library::{library, FILES, RANKS};
|
use super::library::{library, FILES, RANKS};
|
||||||
use super::{LeadingBitScanner, TrailingBitScanner};
|
use super::LeadingBitScanner;
|
||||||
use crate::{square::Direction, Square};
|
use crate::{square::Direction, Square};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, Not};
|
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>
|
// Eryn Wells <eryn@erynwells.me>
|
||||||
|
|
||||||
mod bitboard;
|
mod bitboard;
|
||||||
mod moves;
|
//mod moves;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod piece;
|
pub mod piece;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod position;
|
pub mod position;
|
||||||
mod square;
|
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 position::Position;
|
||||||
pub use square::{File, Rank, Square};
|
pub use square::{File, Rank, Square};
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
// Eryn Wells <eryn@erynwells.me>
|
// Eryn Wells <eryn@erynwells.me>
|
||||||
|
|
||||||
use super::{move_generator_declaration, MoveGeneratorInternal, MoveSet};
|
use super::{classical, move_generator_declaration, MoveGeneratorInternal, MoveSet, PieceSight};
|
||||||
use crate::{
|
use crate::{
|
||||||
bitboard::BitBoard,
|
|
||||||
piece::{Color, Piece, PlacedPiece},
|
piece::{Color, Piece, PlacedPiece},
|
||||||
square::Direction,
|
|
||||||
Move, Position,
|
Move, Position,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -20,35 +18,14 @@ impl<'pos> MoveGeneratorInternal for ClassicalMoveGenerator<'pos> {
|
||||||
let color = piece.color();
|
let color = piece.color();
|
||||||
let square = placed_piece.square();
|
let square = placed_piece.square();
|
||||||
|
|
||||||
let blockers = position.occupied_squares();
|
let empty_squares = position.empty_squares();
|
||||||
let empty_squares = !blockers;
|
|
||||||
let friendly_pieces = position.bitboard_for_color(color);
|
let friendly_pieces = position.bitboard_for_color(color);
|
||||||
let opposing_pieces = position.bitboard_for_color(color.other());
|
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 {
|
let quiet_moves_bb = sight & (empty_squares | !friendly_pieces);
|
||||||
($direction:ident, $occupied_squares:tt) => {
|
let capture_moves_bb = sight & opposing_pieces;
|
||||||
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 map_to_move = |sq| Move::new(piece, square, sq);
|
let map_to_move = |sq| Move::new(piece, square, sq);
|
||||||
let quiet_moves = quiet_moves_bb.occupied_squares().map(map_to_move);
|
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
|
//! Declares the KingMoveGenerator type. This struct is responsible for
|
||||||
//! generating the possible moves for the king in the given position.
|
//! 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::{
|
use crate::{
|
||||||
bitboard::BitBoard,
|
bitboard::BitBoard,
|
||||||
piece::{Color, Piece, PlacedPiece},
|
piece::{Color, Piece, PlacedPiece},
|
||||||
|
@ -50,7 +50,7 @@ impl<'pos> MoveGeneratorInternal for KingMoveGenerator<'pos> {
|
||||||
let empty_squares = position.empty_squares();
|
let empty_squares = position.empty_squares();
|
||||||
let opposing_pieces = position.bitboard_for_color(color.other());
|
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 quiet_moves_bb = all_moves & empty_squares;
|
||||||
let capture_moves_bb = all_moves & opposing_pieces;
|
let capture_moves_bb = all_moves & opposing_pieces;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
// Eryn Wells <eryn@erynwells.me>
|
// Eryn Wells <eryn@erynwells.me>
|
||||||
|
|
||||||
mod bishop;
|
mod bishop;
|
||||||
|
mod classical;
|
||||||
mod king;
|
mod king;
|
||||||
mod knight;
|
mod knight;
|
||||||
mod r#move;
|
mod r#move;
|
||||||
|
@ -9,6 +10,7 @@ mod move_set;
|
||||||
mod pawn;
|
mod pawn;
|
||||||
mod queen;
|
mod queen;
|
||||||
mod rook;
|
mod rook;
|
||||||
|
pub(crate) mod sight;
|
||||||
|
|
||||||
pub use move_generator::Moves;
|
pub use move_generator::Moves;
|
||||||
pub use r#move::Move;
|
pub use r#move::Move;
|
||||||
|
@ -16,7 +18,6 @@ pub use r#move::Move;
|
||||||
pub(self) use move_set::MoveSet;
|
pub(self) use move_set::MoveSet;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
bitboard::BitBoard,
|
|
||||||
piece::{Color, Piece, PlacedPiece},
|
piece::{Color, Piece, PlacedPiece},
|
||||||
Position, Square,
|
Position, Square,
|
||||||
};
|
};
|
||||||
|
@ -35,6 +36,7 @@ macro_rules! move_generator_declaration {
|
||||||
move_generator_declaration!($name, getters);
|
move_generator_declaration!($name, getters);
|
||||||
};
|
};
|
||||||
($name:ident, struct) => {
|
($name:ident, struct) => {
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub(super) struct $name<'pos> {
|
pub(super) struct $name<'pos> {
|
||||||
position: &'pos crate::Position,
|
position: &'pos crate::Position,
|
||||||
color: crate::piece::Color,
|
color: crate::piece::Color,
|
||||||
|
|
|
@ -1,41 +1,86 @@
|
||||||
// Eryn Wells <eryn@erynwells.me>
|
// Eryn Wells <eryn@erynwells.me>
|
||||||
|
|
||||||
use crate::{
|
use crate::{piece::*, position::BoardSide, Square};
|
||||||
piece::{Piece, PlacedPiece, Shape},
|
|
||||||
position::BoardSide,
|
|
||||||
Square,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, Hash, PartialEq)]
|
/// A move that transfers a piece from one square to another.
|
||||||
pub struct Move {
|
trait Move<C: Color, S: Shape>: Sized {
|
||||||
piece: Piece,
|
fn piece(&self) -> Piece<C, S>;
|
||||||
from: Square,
|
fn from_square(&self) -> Square;
|
||||||
to: Square,
|
fn to_square(&self) -> Square;
|
||||||
capturing: Option<PlacedPiece>,
|
|
||||||
promoting_to: Option<Shape>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Move {
|
/// A move that captures an opposing piece.
|
||||||
pub fn new(piece: Piece, from: Square, to: Square) -> Move {
|
trait Capturing<C: Color, S: Shape, CapturedS: Shape>: Move<C, S> {
|
||||||
Move {
|
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,
|
piece,
|
||||||
from,
|
from_square,
|
||||||
to,
|
to_square,
|
||||||
capturing: None,
|
|
||||||
promoting_to: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn capturing(mut self, piece: PlacedPiece) -> Move {
|
fn capturing<CapturedS: Shape>(
|
||||||
self.capturing = Some(piece);
|
self,
|
||||||
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 {
|
fn from_square(&self) -> Square {
|
||||||
self.promoting_to = Some(shape);
|
self.from_square
|
||||||
self
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
pub fn is_castle(&self) -> bool {
|
||||||
let color = self.piece.color();
|
let color = self.piece.color();
|
||||||
self.piece.shape() == Shape::King
|
self.piece.shape() == Shape::King
|
||||||
|
|
|
@ -9,6 +9,7 @@ use super::{
|
||||||
use crate::piece::Color;
|
use crate::piece::Color;
|
||||||
use crate::Position;
|
use crate::Position;
|
||||||
|
|
||||||
|
#[derive(Clone, Eq, PartialEq)]
|
||||||
pub struct Moves<'pos> {
|
pub struct Moves<'pos> {
|
||||||
pawn_moves: PawnMoveGenerator<'pos>,
|
pawn_moves: PawnMoveGenerator<'pos>,
|
||||||
knight_moves: KnightMoveGenerator<'pos>,
|
knight_moves: KnightMoveGenerator<'pos>,
|
||||||
|
|
|
@ -1,16 +1,19 @@
|
||||||
use crate::{bitboard::BitBoard, piece::PlacedPiece, Move};
|
use crate::{bitboard::BitBoard, piece::PlacedPiece, Move};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
struct BitBoardSet {
|
struct BitBoardSet {
|
||||||
quiet: BitBoard,
|
quiet: BitBoard,
|
||||||
captures: BitBoard,
|
captures: BitBoard,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
struct MoveListSet {
|
struct MoveListSet {
|
||||||
quiet: Vec<Move>,
|
quiet: Vec<Move>,
|
||||||
captures: Vec<Move>,
|
captures: Vec<Move>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A set of moves for a piece on the board.
|
/// A set of moves for a piece on the board.
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub(super) struct MoveSet {
|
pub(super) struct MoveSet {
|
||||||
piece: PlacedPiece,
|
piece: PlacedPiece,
|
||||||
bitboards: BitBoardSet,
|
bitboards: BitBoardSet,
|
||||||
|
|
|
@ -12,7 +12,7 @@ enum MoveList {
|
||||||
Captures = 2,
|
Captures = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
struct MoveIterator(usize, usize);
|
struct MoveIterator(usize, usize);
|
||||||
|
|
||||||
struct MoveGenerationParameters {
|
struct MoveGenerationParameters {
|
||||||
|
@ -23,6 +23,7 @@ struct MoveGenerationParameters {
|
||||||
right_capture_shift: fn(BitBoard) -> BitBoard,
|
right_capture_shift: fn(BitBoard) -> BitBoard,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Eq, PartialEq)]
|
||||||
pub(super) struct PawnMoveGenerator<'pos> {
|
pub(super) struct PawnMoveGenerator<'pos> {
|
||||||
color: Color,
|
color: Color,
|
||||||
position: &'pos Position,
|
position: &'pos Position,
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
// Eryn Wells <eryn@erynwells.me>
|
// Eryn Wells <eryn@erynwells.me>
|
||||||
|
|
||||||
use super::{move_generator_declaration, MoveGeneratorInternal, MoveSet};
|
use super::{classical, move_generator_declaration, MoveGeneratorInternal, MoveSet, PieceSight};
|
||||||
use crate::{
|
use crate::{
|
||||||
bitboard::BitBoard,
|
|
||||||
piece::{Color, Piece, PlacedPiece},
|
piece::{Color, Piece, PlacedPiece},
|
||||||
square::Direction,
|
|
||||||
Move, Position,
|
Move, Position,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -25,31 +23,7 @@ impl<'pos> MoveGeneratorInternal for ClassicalMoveGenerator<'pos> {
|
||||||
let friendly_pieces = position.bitboard_for_color(color);
|
let friendly_pieces = position.bitboard_for_color(color);
|
||||||
let opposing_pieces = position.bitboard_for_color(color.other());
|
let opposing_pieces = position.bitboard_for_color(color.other());
|
||||||
|
|
||||||
let mut all_moves = BitBoard::empty();
|
let mut all_moves = classical::QueenSight.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!(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 quiet_moves_bb = all_moves & (empty_squares | !friendly_pieces);
|
let quiet_moves_bb = all_moves & (empty_squares | !friendly_pieces);
|
||||||
let capture_moves_bb = all_moves & opposing_pieces;
|
let capture_moves_bb = all_moves & opposing_pieces;
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
// Eryn Wells <eryn@erynwells.me>
|
// Eryn Wells <eryn@erynwells.me>
|
||||||
|
|
||||||
use super::{move_generator_declaration, MoveGeneratorInternal, MoveSet};
|
use super::{classical, move_generator_declaration, MoveGeneratorInternal, MoveSet, PieceSight};
|
||||||
use crate::{
|
use crate::{
|
||||||
bitboard::BitBoard,
|
|
||||||
piece::{Color, Piece, PlacedPiece},
|
piece::{Color, Piece, PlacedPiece},
|
||||||
square::Direction,
|
|
||||||
Move, Position,
|
Move, Position,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -25,27 +23,7 @@ impl<'pos> MoveGeneratorInternal for ClassicalMoveGenerator<'pos> {
|
||||||
let friendly_pieces = position.bitboard_for_color(color);
|
let friendly_pieces = position.bitboard_for_color(color);
|
||||||
let opposing_pieces = position.bitboard_for_color(color.other());
|
let opposing_pieces = position.bitboard_for_color(color.other());
|
||||||
|
|
||||||
let mut all_moves = BitBoard::empty();
|
let all_moves = classical::RookSight.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!(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 quiet_moves_bb = all_moves & (empty_squares | !friendly_pieces);
|
let quiet_moves_bb = all_moves & (empty_squares | !friendly_pieces);
|
||||||
let capture_moves_bb = all_moves & opposing_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 crate::{bitboard::BitBoard, Square};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::slice::Iter;
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
pub trait Color: Sized {
|
||||||
pub enum Color {
|
type Other: Color;
|
||||||
White = 0,
|
|
||||||
Black = 1,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Color {
|
macro_rules! into_int_type {
|
||||||
pub fn iter() -> impl Iterator<Item = Color> {
|
($name:ident, $int_type:ident, $value:expr) => {
|
||||||
[Color::White, Color::Black].into_iter()
|
impl Into<$int_type> for $name {
|
||||||
}
|
fn into(self) -> $int_type {
|
||||||
|
$value
|
||||||
pub fn other(&self) -> Color {
|
|
||||||
match self {
|
|
||||||
Color::White => Color::Black,
|
|
||||||
Color::Black => Color::White,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
macro_rules! color_struct {
|
||||||
pub enum Shape {
|
($name:ident, $index:expr, $other_color:ident) => {
|
||||||
Pawn = 0,
|
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||||
Knight = 1,
|
pub struct $name;
|
||||||
Bishop = 2,
|
|
||||||
Rook = 3,
|
impl Color for $name {
|
||||||
Queen = 4,
|
type Other = $other_color;
|
||||||
King = 5,
|
}
|
||||||
|
|
||||||
|
into_int_type!($name, u8, $index);
|
||||||
|
into_int_type!($name, usize, $index);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Shape {
|
color_struct!(White, 0, Black);
|
||||||
pub fn iter() -> Iter<'static, Shape> {
|
color_struct!(Black, 1, White);
|
||||||
const ALL_SHAPES: [Shape; 6] = [
|
|
||||||
Shape::Pawn,
|
|
||||||
Shape::Knight,
|
|
||||||
Shape::Bishop,
|
|
||||||
Shape::Rook,
|
|
||||||
Shape::Queen,
|
|
||||||
Shape::King,
|
|
||||||
];
|
|
||||||
|
|
||||||
ALL_SHAPES.iter()
|
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;
|
||||||
|
|
||||||
pub fn promotable() -> Iter<'static, Shape> {
|
impl Shape for $name {}
|
||||||
const PROMOTABLE_SHAPES: [Shape; 4] =
|
|
||||||
[Shape::Queen, Shape::Rook, Shape::Bishop, Shape::Knight];
|
|
||||||
|
|
||||||
PROMOTABLE_SHAPES.iter()
|
into_int_type!($name, u8, $index);
|
||||||
}
|
into_int_type!($name, usize, $index);
|
||||||
|
|
||||||
fn _ascii_representation(&self) -> char {
|
impl Into<char> for $name {
|
||||||
match self {
|
fn into(self) -> char {
|
||||||
Shape::Pawn => 'p',
|
$char
|
||||||
Shape::Knight => 'N',
|
|
||||||
Shape::Bishop => 'B',
|
|
||||||
Shape::Rook => 'R',
|
|
||||||
Shape::Queen => 'Q',
|
|
||||||
Shape::King => 'K',
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)]
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
pub struct TryFromError;
|
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)]
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
pub enum PiecePlacementError {
|
pub enum PiecePlacementError {
|
||||||
ExistsOnSquare,
|
ExistsOnSquare,
|
||||||
|
@ -129,24 +92,28 @@ macro_rules! piece {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||||
pub struct Piece {
|
pub struct Piece<C: Color, S: Shape> {
|
||||||
color: Color,
|
color: C,
|
||||||
shape: Shape,
|
shape: S,
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! piece_constructor {
|
macro_rules! piece_constructor {
|
||||||
($func_name:ident, $type:tt) => {
|
($func_name:ident, $shape:tt) => {
|
||||||
pub fn $func_name(color: Color) -> Piece {
|
pub fn $func_name(color: C) -> Piece<C, S> {
|
||||||
Piece {
|
Piece {
|
||||||
color,
|
color,
|
||||||
shape: Shape::$type,
|
shape: $shape,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Piece {
|
impl<C, S> Piece<C, S>
|
||||||
pub fn new(color: Color, shape: Shape) -> Piece {
|
where
|
||||||
|
C: Color,
|
||||||
|
S: Shape,
|
||||||
|
{
|
||||||
|
pub fn new(color: C, shape: S) -> Piece<C, S> {
|
||||||
Piece { color, shape }
|
Piece { color, shape }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,49 +124,28 @@ impl Piece {
|
||||||
piece_constructor!(queen, Queen);
|
piece_constructor!(queen, Queen);
|
||||||
piece_constructor!(king, King);
|
piece_constructor!(king, King);
|
||||||
|
|
||||||
pub fn color(&self) -> Color {
|
pub fn color(&self) -> C {
|
||||||
self.color
|
self.color
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn shape(&self) -> Shape {
|
pub fn shape(&self) -> S {
|
||||||
self.shape
|
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)]
|
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||||
pub struct PlacedPiece {
|
pub struct PlacedPiece<C, S> {
|
||||||
piece: Piece,
|
piece: Piece<C, S>,
|
||||||
square: Square,
|
square: Square,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PlacedPiece {
|
impl<C, S> PlacedPiece<C, S> {
|
||||||
pub const fn new(piece: Piece, square: Square) -> PlacedPiece {
|
pub const fn new(piece: Piece<C, S>, square: Square) -> PlacedPiece<C, S> {
|
||||||
PlacedPiece { piece, square }
|
PlacedPiece { piece, square }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn piece(&self) -> Piece {
|
pub fn piece(&self) -> Piece<C, S> {
|
||||||
self.piece
|
self.piece
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,15 +3,15 @@
|
||||||
use crate::{File, Position, Rank, Square};
|
use crate::{File, Position, Rank, Square};
|
||||||
use std::{fmt, fmt::Write};
|
use std::{fmt, fmt::Write};
|
||||||
|
|
||||||
pub struct DiagramFormatter<'a>(&'a Position);
|
pub struct DiagramFormatter<'a, PosC>(&'a Position<PosC>);
|
||||||
|
|
||||||
impl<'a> DiagramFormatter<'a> {
|
impl<'a, PosC> DiagramFormatter<'a, PosC> {
|
||||||
pub fn new(position: &'a Position) -> DiagramFormatter {
|
pub fn new(position: &'a Position<PosC>) -> DiagramFormatter<PosC> {
|
||||||
DiagramFormatter(position)
|
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 {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
let mut output = String::new();
|
let mut output = String::new();
|
||||||
|
|
||||||
|
|
|
@ -8,19 +8,32 @@ pub(super) struct Flags(u8);
|
||||||
|
|
||||||
impl Flags {
|
impl Flags {
|
||||||
#[inline]
|
#[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
|
((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
|
(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);
|
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));
|
self.0 &= !(1 << Self::player_has_right_to_castle_flag_offset(color, side));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,33 +2,37 @@
|
||||||
|
|
||||||
use super::Position;
|
use super::Position;
|
||||||
use crate::bitboard::BitBoard;
|
use crate::bitboard::BitBoard;
|
||||||
use crate::piece::{Color, Piece, PlacedPiece, Shape};
|
use crate::piece::*;
|
||||||
use crate::Square;
|
use crate::Square;
|
||||||
|
|
||||||
pub struct Pieces<'a> {
|
pub struct Pieces<'a, PosC, C: Color> {
|
||||||
color: Color,
|
color: C,
|
||||||
position: &'a Position,
|
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>>>,
|
square_iterator: Option<Box<dyn Iterator<Item = Square>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Pieces<'a> {
|
impl<'a, PosC, C> Pieces<'a, PosC, C> {
|
||||||
pub(crate) fn new(position: &Position, color: Color) -> Pieces {
|
pub(crate) fn new(position: &Position<PosC>, color: C) -> Pieces<PosC, C> {
|
||||||
Pieces {
|
Pieces {
|
||||||
color,
|
color,
|
||||||
position,
|
position,
|
||||||
current_shape: None,
|
current_shape: None,
|
||||||
shape_iterator: Box::new(Shape::iter()),
|
shape_iterator: [Pawn, Knight, Bishop, Rook, Queen, King].into_iter(),
|
||||||
square_iterator: None,
|
square_iterator: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Iterator for Pieces<'a> {
|
impl<'a, PosC, C, S> Iterator for Pieces<'a, PosC, C>
|
||||||
type Item = PlacedPiece;
|
where
|
||||||
|
C: Color,
|
||||||
|
S: Shape,
|
||||||
|
{
|
||||||
|
type Item = PlacedPiece<C, S>;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
if let Some(square_iterator) = &mut self.square_iterator {
|
if let Some(square_iterator) = &mut self.square_iterator {
|
||||||
|
@ -80,7 +84,11 @@ mod tests {
|
||||||
use crate::Square;
|
use crate::Square;
|
||||||
use std::collections::HashSet;
|
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)
|
pos.place_piece(piece, sq)
|
||||||
.expect("Unable to place {piece:?} queen on {sq}");
|
.expect("Unable to place {piece:?} queen on {sq}");
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,9 @@
|
||||||
|
|
||||||
use super::{flags::Flags, Pieces};
|
use super::{flags::Flags, Pieces};
|
||||||
use crate::{
|
use crate::{
|
||||||
bitboard::BitBoard,
|
//moves::Moves,
|
||||||
moves::Moves,
|
|
||||||
piece::{Color, Piece, PiecePlacementError, PlacedPiece, Shape},
|
piece::{Color, Piece, PiecePlacementError, PlacedPiece, Shape},
|
||||||
|
BitBoard,
|
||||||
Square,
|
Square,
|
||||||
};
|
};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
@ -28,16 +28,9 @@ macro_rules! position {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Eq, Hash, PartialEq)]
|
#[derive(Clone, Eq, Hash, PartialEq)]
|
||||||
pub struct Position {
|
pub struct Position<ColorToMove> {
|
||||||
color_to_move: Color,
|
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,
|
flags: Flags,
|
||||||
|
|
||||||
/// Composite bitboards for all the pieces of a particular color.
|
/// 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.
|
/// Bitboards representing positions of particular piece types per color.
|
||||||
pieces_per_type: [[BitBoard; 6]; 2],
|
pieces_per_type: [[BitBoard; 6]; 2],
|
||||||
|
|
||||||
|
en_passant_square: Option<Square>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Position {
|
impl<ColorToMove> Position<ColorToMove> {
|
||||||
pub fn empty() -> Position {
|
pub fn empty() -> Position<ColorToMove> {
|
||||||
Position {
|
Position {
|
||||||
color_to_move: Color::White,
|
color_to_move: crate::piece::White,
|
||||||
flags: Default::default(),
|
flags: Default::default(),
|
||||||
pieces_per_color: [BitBoard::empty(); 2],
|
pieces_per_color: [BitBoard::empty(); 2],
|
||||||
pieces_per_type: [
|
pieces_per_type: [
|
||||||
|
@ -71,11 +66,12 @@ impl Position {
|
||||||
BitBoard::empty(),
|
BitBoard::empty(),
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
en_passant_square: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a starting position.
|
/// Return a starting position.
|
||||||
pub fn starting() -> Position {
|
pub fn starting() -> Position<ColorToMove> {
|
||||||
let white_pieces = [
|
let white_pieces = [
|
||||||
BitBoard::new(0x00FF000000000000),
|
BitBoard::new(0x00FF000000000000),
|
||||||
BitBoard::new(0x4200000000000000),
|
BitBoard::new(0x4200000000000000),
|
||||||
|
@ -95,13 +91,14 @@ impl Position {
|
||||||
];
|
];
|
||||||
|
|
||||||
Position {
|
Position {
|
||||||
color_to_move: Color::White,
|
color_to_move: crate::piece::White,
|
||||||
flags: Default::default(),
|
flags: Default::default(),
|
||||||
pieces_per_color: [
|
pieces_per_color: [
|
||||||
white_pieces.iter().fold(BitBoard::empty(), |a, b| a | *b),
|
white_pieces.iter().fold(BitBoard::empty(), |a, b| a | *b),
|
||||||
black_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],
|
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
|
/// 2. The king must not be in check
|
||||||
/// 3. In the course of castling on that side, the king must not pass
|
/// 3. In the course of castling on that side, the king must not pass
|
||||||
/// through a square that an enemy piece can see
|
/// 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)
|
self.flags.player_has_right_to_castle(color, side)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_player_has_right_to_castle_flag(&mut self, color: Color, side: BoardSide) {
|
pub fn place_piece<C, S>(
|
||||||
self.flags.set_player_has_right_to_castle_flag(color, side);
|
&mut self,
|
||||||
}
|
piece: Piece<C, S>,
|
||||||
|
square: Square,
|
||||||
fn clear_player_has_right_to_castle_flag(&mut self, color: Color, side: BoardSide) {
|
) -> Result<(), PiecePlacementError> {
|
||||||
self.flags
|
|
||||||
.clear_player_has_right_to_castle_flag(color, side);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn place_piece(&mut self, piece: Piece, square: Square) -> Result<(), PiecePlacementError> {
|
|
||||||
let type_bb = self.bitboard_for_piece_mut(piece);
|
let type_bb = self.bitboard_for_piece_mut(piece);
|
||||||
|
|
||||||
if type_bb.has_piece_at(square) {
|
if type_bb.has_piece_at(square) {
|
||||||
|
@ -146,40 +138,27 @@ impl Position {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn move_generator(&self, color: Color) -> Moves {
|
// pub fn move_generator<C>(&self, color: C) -> Moves {
|
||||||
Moves::new(self, color)
|
// Moves::new(self, color)
|
||||||
}
|
// }
|
||||||
|
|
||||||
/// Return a BitBoard representing the set of squares containing a piece.
|
pub(crate) fn bitboard_for_piece<C, S>(&self, piece: Piece<C, S>) -> BitBoard {
|
||||||
#[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 {
|
|
||||||
self.pieces_per_type[piece.color() as usize][piece.shape() as usize]
|
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]
|
&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]
|
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]
|
&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 color in Color::iter() {
|
||||||
for shape in Shape::iter() {
|
for shape in Shape::iter() {
|
||||||
let piece = Piece::new(color, *shape);
|
let piece = Piece::new(color, *shape);
|
||||||
|
@ -193,19 +172,76 @@ impl Position {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pieces(&self, color: Color) -> Pieces {
|
pub fn pieces<C>(&self, color: C) -> Pieces<ColorToMove, C> {
|
||||||
Pieces::new(&self, color)
|
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 {
|
fn default() -> Self {
|
||||||
Self::empty()
|
Self::empty()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromIterator<PlacedPiece> for Position {
|
impl<ColorToMove, C, S> FromIterator<PlacedPiece<C, S>> for Position<ColorToMove> {
|
||||||
fn from_iter<T: IntoIterator<Item = PlacedPiece>>(iter: T) -> Self {
|
fn from_iter<T: IntoIterator<Item = PlacedPiece<C, S>>>(iter: T) -> Self {
|
||||||
let mut position = Position::empty();
|
let mut position = Position::empty();
|
||||||
for placed_piece in iter {
|
for placed_piece in iter {
|
||||||
_ = position.place_piece(placed_piece.piece(), placed_piece.square());
|
_ = 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 {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
let mut output = String::new();
|
let mut output = String::new();
|
||||||
|
|
||||||
|
@ -245,7 +281,7 @@ impl fmt::Debug for Position {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::piece::Shape;
|
use crate::{piece::Shape, position::DiagramFormatter};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn place_piece() {
|
fn place_piece() {
|
||||||
|
@ -273,6 +309,24 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[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