2024-01-15 16:03:06 -08:00
|
|
|
// Eryn Wells <eryn@erynwells.me>
|
|
|
|
|
|
2024-03-08 08:04:21 -08:00
|
|
|
//! Defines routines for computing sight of a piece. Sight is the set of squares
|
|
|
|
|
//! that a piece can see. In other words, it's the set of squares attacked or
|
|
|
|
|
//! controled by a piece.
|
2025-05-18 08:08:47 -07:00
|
|
|
//!
|
|
|
|
|
//! These functions use some common terms to describe arguments.
|
|
|
|
|
//!
|
|
|
|
|
//! occupancy
|
|
|
|
|
//! : The set of occupied squares on the board.
|
|
|
|
|
//!
|
|
|
|
|
//! vacancy
|
|
|
|
|
//! : The set of empty squares on the board, `!occpuancy`.
|
|
|
|
|
//!
|
|
|
|
|
//! blockers
|
|
|
|
|
//! : The set of squares occupied by friendly pieces that block moves to that
|
|
|
|
|
//! square and beyond.
|
2024-03-08 08:04:21 -08:00
|
|
|
|
2025-05-21 10:08:59 -07:00
|
|
|
use crate::Board;
|
|
|
|
|
use chessfriend_bitboard::{BitBoard, IterationDirection};
|
2025-05-18 08:08:47 -07:00
|
|
|
use chessfriend_core::{Color, Direction, Piece, Shape, Square};
|
2025-05-21 10:08:59 -07:00
|
|
|
use std::ops::BitOr;
|
|
|
|
|
|
|
|
|
|
impl Board {
|
|
|
|
|
/// Compute sight of the piece on the given square.
|
|
|
|
|
pub fn sight(&self, square: Square) -> BitBoard {
|
|
|
|
|
if let Some(piece) = self.get_piece(square) {
|
|
|
|
|
piece.sight(square, self)
|
|
|
|
|
} else {
|
|
|
|
|
BitBoard::empty()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn active_sight(&self) -> BitBoard {
|
|
|
|
|
self.friendly_sight(self.active_color)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// A [`BitBoard`] of all squares the given color can see.
|
|
|
|
|
pub fn friendly_sight(&self, color: Color) -> BitBoard {
|
|
|
|
|
// TODO: Probably want to implement a caching layer here.
|
|
|
|
|
self.friendly_occupancy(color)
|
|
|
|
|
.occupied_squares(&IterationDirection::default())
|
|
|
|
|
.map(|square| self.sight(square))
|
|
|
|
|
.fold(BitBoard::empty(), BitOr::bitor)
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-23 09:56:47 -07:00
|
|
|
pub fn active_color_opposing_sight(&self) -> BitBoard {
|
|
|
|
|
self.opposing_sight(self.active_color)
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-21 10:08:59 -07:00
|
|
|
/// A [`BitBoard`] of all squares visible by colors that oppose the given color.
|
2025-05-23 09:56:47 -07:00
|
|
|
pub fn opposing_sight(&self, color: Color) -> BitBoard {
|
2025-05-21 10:08:59 -07:00
|
|
|
// TODO: Probably want to implement a caching layer here.
|
|
|
|
|
Color::ALL
|
|
|
|
|
.into_iter()
|
|
|
|
|
.filter_map(|c| {
|
2025-05-23 09:56:47 -07:00
|
|
|
if c == color {
|
2025-05-21 10:08:59 -07:00
|
|
|
None
|
|
|
|
|
} else {
|
|
|
|
|
Some(self.friendly_sight(c))
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.fold(BitBoard::empty(), BitOr::bitor)
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-05-18 08:08:47 -07:00
|
|
|
|
|
|
|
|
pub trait Sight {
|
|
|
|
|
fn sight(&self, square: Square, board: &Board) -> BitBoard;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Sight for Piece {
|
|
|
|
|
fn sight(&self, square: Square, board: &Board) -> BitBoard {
|
|
|
|
|
let occupancy = board.occupancy();
|
|
|
|
|
let info = SightInfo {
|
|
|
|
|
square,
|
|
|
|
|
occupancy,
|
|
|
|
|
friendly_occupancy: board.friendly_occupancy(self.color),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
match self.shape {
|
|
|
|
|
Shape::Pawn => {
|
|
|
|
|
let en_passant_square: BitBoard = board.en_passant_target.into();
|
|
|
|
|
match self.color {
|
|
|
|
|
Color::White => white_pawn_sight(&info, en_passant_square),
|
|
|
|
|
Color::Black => black_pawn_sight(&info, en_passant_square),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Shape::Knight => knight_sight(&info),
|
|
|
|
|
Shape::Bishop => bishop_sight(&info),
|
|
|
|
|
Shape::Rook => rook_sight(&info),
|
|
|
|
|
Shape::Queen => queen_sight(&info),
|
|
|
|
|
Shape::King => king_sight(&info),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
[bitboard, board, core, moves] Implement SliderMoveGenerator
This generator produces moves for slider pieces: bishops, rooks, and queens. All
of these pieces behave identically, though with different sets of rays that
emanate from the origin square. Claude helped me significantly with the
implementation and unit testing. All the unit tests that took advantage of Claude
for implementation are marked as such with an _ai_claude suffix to the test name.
One unique aspect of this move generator that Claude suggested to me was to use
loop { } instead of a recursive call to next() when the internal iterators expire.
I may try to port this to the other move generators in the future.
To support this move generator, implement a Slider enum in core that represents
one of the three slider pieces.
Add Board::bishops(), Board::rooks() and Board::queens() to return BitBoards of
those pieces. These are analogous to the pawns() and knights() methods that return
their corresponding pieces.
Also in the board create, replace the separate sight method implementations with
a macro. These are all the same, but with a different sight method called under
the hood.
Finally, derive Clone and Debug for the bit_scanner types.
2025-05-26 17:41:43 -07:00
|
|
|
macro_rules! sight_method {
|
|
|
|
|
($name:ident) => {
|
|
|
|
|
pub fn $name(&self, square: Square, color: Option<Color>) -> BitBoard {
|
|
|
|
|
let color = self.unwrap_color(color);
|
|
|
|
|
|
|
|
|
|
let info = SightInfo {
|
|
|
|
|
square,
|
|
|
|
|
occupancy: self.occupancy(),
|
|
|
|
|
friendly_occupancy: self.friendly_occupancy(color),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
$name(&info)
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Board {
|
|
|
|
|
sight_method!(bishop_sight);
|
|
|
|
|
sight_method!(rook_sight);
|
|
|
|
|
sight_method!(queen_sight);
|
[board, moves, position] Implement KingMoveGenerator
Implement a move generator that emits moves for the king(s) of a particular color.
There will, of course, only ever be one king per side in any valid board, but
this iterator can (in theory) handle multiple kings on the board. This iterator
is almost entirely copypasta of the SliderMoveGenerator. The major difference is
castling.
Castle moves are emitted by a helper CastleIterator type. This struct collects
information about whether the given color can castle on each side of the board
and then emits moves for each side, if indicated.
Do some light refactoring of the castle-related methods on Board to accommodate
this move generator. Remove the dependency on internal state and rename the
"can_castle" method to color_can_castle.
In order to facilitate creating castling moves without relying on Board, remove
the origin and target squares from the encoded castling move. Code that makes
a castling move already looks up castling parameters to move the king and rook to
the right squares, so encoding those squares was redundant. This change
necessitated some updates to position.
Lastly, bring in a handful of unit tests courtesy of Claude. Apparently, it's my
new best coding friend. 🙃
2025-05-26 23:37:33 -07:00
|
|
|
sight_method!(king_sight);
|
[bitboard, board, core, moves] Implement SliderMoveGenerator
This generator produces moves for slider pieces: bishops, rooks, and queens. All
of these pieces behave identically, though with different sets of rays that
emanate from the origin square. Claude helped me significantly with the
implementation and unit testing. All the unit tests that took advantage of Claude
for implementation are marked as such with an _ai_claude suffix to the test name.
One unique aspect of this move generator that Claude suggested to me was to use
loop { } instead of a recursive call to next() when the internal iterators expire.
I may try to port this to the other move generators in the future.
To support this move generator, implement a Slider enum in core that represents
one of the three slider pieces.
Add Board::bishops(), Board::rooks() and Board::queens() to return BitBoards of
those pieces. These are analogous to the pawns() and knights() methods that return
their corresponding pieces.
Also in the board create, replace the separate sight method implementations with
a macro. These are all the same, but with a different sight method called under
the hood.
Finally, derive Clone and Debug for the bit_scanner types.
2025-05-26 17:41:43 -07:00
|
|
|
}
|
|
|
|
|
|
2025-05-18 08:08:47 -07:00
|
|
|
struct SightInfo {
|
|
|
|
|
square: Square,
|
|
|
|
|
occupancy: BitBoard,
|
|
|
|
|
friendly_occupancy: BitBoard,
|
|
|
|
|
}
|
2024-01-15 16:03:06 -08:00
|
|
|
|
2024-02-01 08:43:03 -08:00
|
|
|
macro_rules! ray_in_direction {
|
2025-05-08 17:37:51 -07:00
|
|
|
($square:expr, $blockers:expr, $direction:ident, $first_occupied_square:tt) => {{
|
2024-02-01 08:43:03 -08:00
|
|
|
let ray = BitBoard::ray($square, Direction::$direction);
|
2025-05-08 17:37:51 -07:00
|
|
|
let ray_blockers = ray & $blockers;
|
|
|
|
|
if let Some(first_occupied_square) = ray_blockers.$first_occupied_square() {
|
2024-02-01 08:43:03 -08:00
|
|
|
let remainder = BitBoard::ray(first_occupied_square, Direction::$direction);
|
|
|
|
|
let attack_ray = ray & !remainder;
|
|
|
|
|
attack_ray
|
|
|
|
|
} else {
|
2025-05-08 17:37:51 -07:00
|
|
|
ray
|
2024-02-01 08:43:03 -08:00
|
|
|
}
|
|
|
|
|
}};
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-08 08:04:21 -08:00
|
|
|
/// Compute sight of a white pawn.
|
2025-05-18 08:08:47 -07:00
|
|
|
fn white_pawn_sight(info: &SightInfo, en_passant_square: BitBoard) -> BitBoard {
|
|
|
|
|
let possible_squares = !info.friendly_occupancy | en_passant_square;
|
|
|
|
|
|
|
|
|
|
let pawn: BitBoard = info.square.into();
|
2024-03-08 08:04:21 -08:00
|
|
|
let pawn = pawn.shift_north_west_one() | pawn.shift_north_east_one();
|
2025-05-18 08:08:47 -07:00
|
|
|
|
2024-03-08 08:04:21 -08:00
|
|
|
pawn & possible_squares
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-18 08:08:47 -07:00
|
|
|
fn black_pawn_sight(info: &SightInfo, en_passant_square: BitBoard) -> BitBoard {
|
|
|
|
|
let possible_squares = !info.friendly_occupancy | en_passant_square;
|
|
|
|
|
|
|
|
|
|
let pawn: BitBoard = info.square.into();
|
2024-03-08 08:04:21 -08:00
|
|
|
let pawn = pawn.shift_south_west_one() | pawn.shift_south_east_one();
|
2025-05-18 08:08:47 -07:00
|
|
|
|
2024-03-08 08:04:21 -08:00
|
|
|
pawn & possible_squares
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-18 08:08:47 -07:00
|
|
|
fn knight_sight(info: &SightInfo) -> BitBoard {
|
|
|
|
|
BitBoard::knight_moves(info.square)
|
2024-03-08 08:04:21 -08:00
|
|
|
}
|
|
|
|
|
|
2025-05-18 08:08:47 -07:00
|
|
|
fn bishop_sight(info: &SightInfo) -> BitBoard {
|
|
|
|
|
let bishop = info.square;
|
|
|
|
|
let occupancy = info.occupancy;
|
2024-03-08 08:04:21 -08:00
|
|
|
|
|
|
|
|
#[rustfmt::skip]
|
2025-05-18 08:08:47 -07:00
|
|
|
let sight = ray_in_direction!(bishop, occupancy, NorthEast, first_occupied_square_trailing)
|
|
|
|
|
| ray_in_direction!(bishop, occupancy, SouthEast, first_occupied_square_leading)
|
|
|
|
|
| ray_in_direction!(bishop, occupancy, SouthWest, first_occupied_square_leading)
|
|
|
|
|
| ray_in_direction!(bishop, occupancy, NorthWest, first_occupied_square_trailing);
|
2024-03-08 08:04:21 -08:00
|
|
|
|
|
|
|
|
sight
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-18 08:08:47 -07:00
|
|
|
fn rook_sight(info: &SightInfo) -> BitBoard {
|
|
|
|
|
let rook = info.square;
|
|
|
|
|
let occupancy = info.occupancy;
|
|
|
|
|
|
2024-03-08 08:04:21 -08:00
|
|
|
#[rustfmt::skip]
|
2025-05-18 08:08:47 -07:00
|
|
|
let sight = ray_in_direction!(rook, occupancy, North, first_occupied_square_trailing)
|
|
|
|
|
| ray_in_direction!(rook, occupancy, East, first_occupied_square_trailing)
|
|
|
|
|
| ray_in_direction!(rook, occupancy, South, first_occupied_square_leading)
|
|
|
|
|
| ray_in_direction!(rook, occupancy, West, first_occupied_square_leading);
|
2024-03-08 08:04:21 -08:00
|
|
|
|
|
|
|
|
sight
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-18 08:08:47 -07:00
|
|
|
fn queen_sight(info: &SightInfo) -> BitBoard {
|
|
|
|
|
let queen = info.square;
|
|
|
|
|
let occupancy = info.occupancy;
|
2024-02-01 08:42:19 -08:00
|
|
|
|
2025-05-18 08:08:47 -07:00
|
|
|
#[rustfmt::skip]
|
|
|
|
|
let sight = ray_in_direction!(queen, occupancy, NorthWest, first_occupied_square_trailing)
|
|
|
|
|
| ray_in_direction!(queen, occupancy, North, first_occupied_square_trailing)
|
|
|
|
|
| ray_in_direction!(queen, occupancy, NorthEast, first_occupied_square_trailing)
|
|
|
|
|
| ray_in_direction!(queen, occupancy, East, first_occupied_square_trailing)
|
|
|
|
|
| ray_in_direction!(queen, occupancy, SouthEast, first_occupied_square_leading)
|
|
|
|
|
| ray_in_direction!(queen, occupancy, South, first_occupied_square_leading)
|
|
|
|
|
| ray_in_direction!(queen, occupancy, SouthWest, first_occupied_square_leading)
|
|
|
|
|
| ray_in_direction!(queen, occupancy, West, first_occupied_square_leading);
|
2024-03-08 08:04:21 -08:00
|
|
|
|
2025-05-18 08:08:47 -07:00
|
|
|
sight
|
2024-03-08 08:04:21 -08:00
|
|
|
}
|
|
|
|
|
|
2025-05-18 08:08:47 -07:00
|
|
|
fn king_sight(info: &SightInfo) -> BitBoard {
|
|
|
|
|
BitBoard::king_moves(info.square)
|
2024-03-08 08:04:21 -08:00
|
|
|
}
|
|
|
|
|
|
2024-01-17 08:44:27 -08:00
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests {
|
2025-05-21 10:08:59 -07:00
|
|
|
use crate::test_board;
|
2024-02-01 08:42:19 -08:00
|
|
|
use chessfriend_bitboard::bitboard;
|
2025-05-18 08:08:47 -07:00
|
|
|
use chessfriend_core::piece;
|
2024-02-01 08:42:19 -08:00
|
|
|
|
2024-01-17 08:44:27 -08:00
|
|
|
macro_rules! sight_test {
|
2025-05-18 08:08:47 -07:00
|
|
|
($test_name:ident, $position:expr, $piece:expr, $square:expr, $bitboard:expr) => {
|
2024-01-17 08:44:27 -08:00
|
|
|
#[test]
|
|
|
|
|
fn $test_name() {
|
2025-05-18 08:08:47 -07:00
|
|
|
use chessfriend_core::Square;
|
|
|
|
|
use $crate::sight::Sight;
|
|
|
|
|
|
2024-01-17 08:44:27 -08:00
|
|
|
let pos = $position;
|
2024-01-28 00:25:53 -08:00
|
|
|
let piece = $piece;
|
2025-05-21 10:08:59 -07:00
|
|
|
let sight = piece.sight($square, &pos);
|
2024-01-17 08:44:27 -08:00
|
|
|
|
|
|
|
|
assert_eq!(sight, $bitboard);
|
|
|
|
|
}
|
|
|
|
|
};
|
2025-05-18 08:08:47 -07:00
|
|
|
($test_name:ident, $piece:expr, $square:expr, $bitboard:expr) => {
|
2025-05-21 10:08:59 -07:00
|
|
|
sight_test! {$test_name, $crate::Board::empty(), $piece, $square, $bitboard}
|
2024-01-17 08:44:27 -08:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-21 10:08:59 -07:00
|
|
|
#[test]
|
|
|
|
|
fn friendly_sight() {
|
|
|
|
|
let pos = test_board!(
|
|
|
|
|
White King on E4,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
let sight = pos.active_sight();
|
|
|
|
|
assert_eq!(sight, bitboard![E5 F5 F4 F3 E3 D3 D4 D5]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn opposing_sight() {
|
|
|
|
|
let pos = test_board!(
|
|
|
|
|
White King on E4,
|
|
|
|
|
Black Rook on E7,
|
|
|
|
|
);
|
|
|
|
|
|
2025-05-23 09:56:47 -07:00
|
|
|
let sight = pos.active_color_opposing_sight();
|
2025-05-21 10:08:59 -07:00
|
|
|
assert_eq!(sight, bitboard![A7 B7 C7 D7 F7 G7 H7 E8 E6 E5 E4]);
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-18 08:08:47 -07:00
|
|
|
// #[test]
|
|
|
|
|
// fn pawns_and_knights_cannot_make_rays() {
|
|
|
|
|
// assert_eq!(Shape::Pawn.ray_to_square(Square::F7, Square::E8), None);
|
|
|
|
|
// assert_eq!(Shape::Knight.ray_to_square(Square::F6, Square::E8), None);
|
|
|
|
|
// }
|
2024-02-01 08:42:19 -08:00
|
|
|
|
2024-01-17 08:44:27 -08:00
|
|
|
mod pawn {
|
2025-05-21 10:08:59 -07:00
|
|
|
use crate::{sight::Sight, test_board};
|
2024-01-24 09:18:12 -08:00
|
|
|
use chessfriend_bitboard::{bitboard, BitBoard};
|
2025-05-18 08:08:47 -07:00
|
|
|
use chessfriend_core::{piece, Square};
|
2024-01-17 08:44:27 -08:00
|
|
|
|
2025-05-18 08:08:47 -07:00
|
|
|
sight_test!(e4_pawn, piece!(White Pawn), Square::E4, bitboard![D5 F5]);
|
2024-01-17 08:44:27 -08:00
|
|
|
|
|
|
|
|
sight_test!(
|
|
|
|
|
e4_pawn_one_blocker,
|
2025-05-21 10:08:59 -07:00
|
|
|
test_board![
|
2024-01-17 08:44:27 -08:00
|
|
|
White Bishop on D5,
|
|
|
|
|
White Pawn on E4,
|
|
|
|
|
],
|
2025-05-18 08:08:47 -07:00
|
|
|
piece!(White Pawn),
|
|
|
|
|
Square::E4,
|
2024-01-17 08:44:27 -08:00
|
|
|
bitboard!(F5)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn e4_pawn_two_blocker() {
|
2025-05-21 10:08:59 -07:00
|
|
|
let pos = test_board!(
|
2024-01-17 08:44:27 -08:00
|
|
|
White Bishop on D5,
|
|
|
|
|
White Queen on F5,
|
|
|
|
|
White Pawn on E4,
|
|
|
|
|
);
|
2024-01-21 13:06:44 -08:00
|
|
|
|
2025-05-18 08:08:47 -07:00
|
|
|
let piece = piece!(White Pawn);
|
2025-05-21 10:08:59 -07:00
|
|
|
let sight = piece.sight(Square::E4, &pos);
|
2024-01-17 08:44:27 -08:00
|
|
|
|
|
|
|
|
assert_eq!(sight, BitBoard::empty());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn e4_pawn_capturable() {
|
2025-05-21 10:08:59 -07:00
|
|
|
let pos = test_board!(
|
2024-01-17 08:44:27 -08:00
|
|
|
Black Bishop on D5,
|
|
|
|
|
White Queen on F5,
|
|
|
|
|
White Pawn on E4,
|
|
|
|
|
);
|
2024-01-21 13:06:44 -08:00
|
|
|
|
2025-05-18 08:08:47 -07:00
|
|
|
let piece = piece!(White Pawn);
|
2025-05-21 10:08:59 -07:00
|
|
|
let sight = piece.sight(Square::E4, &pos);
|
2024-01-17 08:44:27 -08:00
|
|
|
|
2025-05-18 08:08:47 -07:00
|
|
|
assert_eq!(sight, bitboard![D5]);
|
2024-01-17 08:44:27 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn e5_en_passant() {
|
2025-05-21 10:08:59 -07:00
|
|
|
let pos = test_board!(White, [
|
2024-01-17 08:44:27 -08:00
|
|
|
White Pawn on E5,
|
|
|
|
|
Black Pawn on D5,
|
2025-05-08 17:37:51 -07:00
|
|
|
], D6);
|
2025-05-18 08:08:47 -07:00
|
|
|
let piece = piece!(White Pawn);
|
2025-05-21 10:08:59 -07:00
|
|
|
let sight = piece.sight(Square::E5, &pos);
|
2024-01-17 08:44:27 -08:00
|
|
|
|
2025-05-08 17:37:51 -07:00
|
|
|
assert_eq!(sight, bitboard!(D6 F6));
|
2024-01-17 08:44:27 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[macro_use]
|
|
|
|
|
mod knight {
|
2024-01-24 09:18:12 -08:00
|
|
|
use chessfriend_bitboard::bitboard;
|
2024-01-24 17:08:27 -08:00
|
|
|
use chessfriend_core::piece;
|
2024-01-17 08:44:27 -08:00
|
|
|
|
|
|
|
|
sight_test!(
|
|
|
|
|
f6_knight,
|
2025-05-18 08:08:47 -07:00
|
|
|
piece!(Black Knight),
|
|
|
|
|
Square::F6,
|
2025-05-08 17:37:51 -07:00
|
|
|
bitboard![H7 G8 E8 D7 D5 E4 G4 H5]
|
2024-01-17 08:44:27 -08:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mod bishop {
|
2024-02-01 08:42:19 -08:00
|
|
|
use super::*;
|
2024-01-17 08:44:27 -08:00
|
|
|
|
|
|
|
|
sight_test!(
|
|
|
|
|
c2_bishop,
|
2025-05-18 08:08:47 -07:00
|
|
|
piece!(Black Bishop),
|
|
|
|
|
Square::C2,
|
2025-05-08 17:37:51 -07:00
|
|
|
bitboard![D1 B3 A4 B1 D3 E4 F5 G6 H7]
|
2024-01-17 08:44:27 -08:00
|
|
|
);
|
2024-02-01 08:42:19 -08:00
|
|
|
|
2025-05-18 08:08:47 -07:00
|
|
|
// #[test]
|
|
|
|
|
// fn ray_to_square() {
|
|
|
|
|
// let generated_ray = Shape::Bishop.ray_to_square(Square::C5, Square::E7);
|
|
|
|
|
// let expected_ray = bitboard![D6 E7];
|
|
|
|
|
// assert_eq!(generated_ray, Some(expected_ray));
|
|
|
|
|
// }
|
2024-01-17 08:44:27 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mod rook {
|
2024-02-01 08:42:19 -08:00
|
|
|
use super::*;
|
2025-05-21 10:08:59 -07:00
|
|
|
use crate::test_board;
|
2024-01-17 08:44:27 -08:00
|
|
|
|
|
|
|
|
sight_test!(
|
|
|
|
|
g3_rook,
|
2025-05-18 08:08:47 -07:00
|
|
|
piece!(White Rook),
|
|
|
|
|
Square::G3,
|
2025-05-08 17:37:51 -07:00
|
|
|
bitboard![G1 G2 G4 G5 G6 G7 G8 A3 B3 C3 D3 E3 F3 H3]
|
2024-01-17 08:44:27 -08:00
|
|
|
);
|
2024-01-28 00:25:53 -08:00
|
|
|
|
|
|
|
|
sight_test!(
|
|
|
|
|
e4_rook_with_e1_white_king_e7_black_king,
|
2025-05-21 10:08:59 -07:00
|
|
|
test_board![
|
2024-01-28 00:25:53 -08:00
|
|
|
White Rook on E4,
|
2025-05-18 08:08:47 -07:00
|
|
|
White King on E2,
|
2024-01-28 00:25:53 -08:00
|
|
|
Black King on E7,
|
|
|
|
|
],
|
2025-05-18 08:08:47 -07:00
|
|
|
piece!(White Rook),
|
|
|
|
|
Square::E4,
|
|
|
|
|
bitboard![A4 B4 C4 D4 F4 G4 H4 E2 E3 E5 E6 E7]
|
2024-01-28 00:25:53 -08:00
|
|
|
);
|
2024-02-01 08:42:19 -08:00
|
|
|
|
2025-05-18 08:08:47 -07:00
|
|
|
// #[test]
|
|
|
|
|
// fn ray_to_square() {
|
|
|
|
|
// let generated_ray = Shape::Rook.ray_to_square(Square::C2, Square::C6);
|
|
|
|
|
// let expected_ray = bitboard![C3 C4 C5 C6];
|
|
|
|
|
// assert_eq!(generated_ray, Some(expected_ray));
|
|
|
|
|
|
|
|
|
|
// let generated_ray = Shape::Rook.ray_to_square(Square::D2, Square::H2);
|
|
|
|
|
// let expected_ray = bitboard![E2 F2 G2 H2];
|
|
|
|
|
// assert_eq!(generated_ray, Some(expected_ray));
|
|
|
|
|
|
|
|
|
|
// let generated_ray = Shape::Rook.ray_to_square(Square::G6, Square::B6);
|
|
|
|
|
// let expected_ray = bitboard![B6 C6 D6 E6 F6];
|
|
|
|
|
// assert_eq!(generated_ray, Some(expected_ray));
|
|
|
|
|
|
|
|
|
|
// let generated_ray = Shape::Rook.ray_to_square(Square::A6, Square::A3);
|
|
|
|
|
// let expected_ray = bitboard![A5 A4 A3];
|
|
|
|
|
// assert_eq!(generated_ray, Some(expected_ray));
|
|
|
|
|
// }
|
2024-01-28 00:25:53 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mod king {
|
|
|
|
|
use chessfriend_bitboard::bitboard;
|
|
|
|
|
use chessfriend_core::piece;
|
|
|
|
|
|
2025-05-18 08:08:47 -07:00
|
|
|
sight_test!(
|
|
|
|
|
e1_king,
|
|
|
|
|
piece!(White King),
|
|
|
|
|
Square::E1,
|
|
|
|
|
bitboard![D1 D2 E2 F2 F1]
|
|
|
|
|
);
|
2024-01-17 08:44:27 -08:00
|
|
|
}
|
|
|
|
|
}
|