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