From 924689ec0285dd60f5525be8b6dbaaf19322eeaa Mon Sep 17 00:00:00 2001 From: Bruno BELANYI Date: Sun, 17 Jul 2022 23:06:50 +0200 Subject: [PATCH] Add 'Direction::move_board' Encapsulates the way to move a piece on a board, avoiding the need to mask and shift by hand. --- src/board/directions.rs | 524 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 524 insertions(+) diff --git a/src/board/directions.rs b/src/board/directions.rs index 7e10ab3..3345256 100644 --- a/src/board/directions.rs +++ b/src/board/directions.rs @@ -1,3 +1,5 @@ +use super::{Bitboard, Rank}; + /// A direction on the board. Either along the rook, bishop, or knight directions #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum Direction { @@ -20,3 +22,525 @@ pub enum Direction { NorthEastEast, NorthNorthEast, } + +impl Direction { + /// Move every piece on a board along the given direction. Do not wrap around the board. + #[inline(always)] + pub fn move_board(self, board: Bitboard) -> Bitboard { + // No need to filter for A/H ranks thanks to wrapping + match self { + Self::North => (board - Rank::Eighth.into_bitboard()) << 1, + Self::West => board >> 8, + Self::South => (board - Rank::First.into_bitboard()) >> 1, + Self::East => board << 8, + + Self::NorthWest => (board - Rank::Eighth.into_bitboard()) >> 7, + Self::SouthWest => (board - Rank::First.into_bitboard()) >> 9, + Self::SouthEast => (board - Rank::First.into_bitboard()) << 7, + Self::NorthEast => (board - Rank::Eighth.into_bitboard()) << 9, + + Self::NorthNorthWest => { + (board - Rank::Eighth.into_bitboard() - Rank::Seventh.into_bitboard()) >> 6 + } + Self::NorthWestWest => (board - Rank::Eighth.into_bitboard()) >> 15, + Self::SouthWestWest => (board - Rank::First.into_bitboard()) >> 17, + Self::SouthSouthWest => { + (board - Rank::First.into_bitboard() - Rank::Second.into_bitboard()) >> 10 + } + Self::SouthSouthEast => { + (board - Rank::First.into_bitboard() - Rank::Second.into_bitboard()) << 6 + } + Self::SouthEastEast => (board - Rank::First.into_bitboard()) << 15, + Self::NorthEastEast => (board - Rank::Eighth.into_bitboard()) << 17, + Self::NorthNorthEast => { + (board - Rank::Eighth.into_bitboard() - Rank::Seventh.into_bitboard()) << 10 + } + } + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::board::Square; + + #[test] + fn north() { + assert_eq!( + Direction::North.move_board(Square::A1.into_bitboard()), + Square::A2.into_bitboard() + ); + assert_eq!( + Direction::North.move_board(Square::A2.into_bitboard()), + Square::A3.into_bitboard() + ); + assert_eq!( + Direction::North.move_board(Square::A7.into_bitboard()), + Square::A8.into_bitboard() + ); + assert_eq!( + Direction::North.move_board(Square::A8.into_bitboard()), + Bitboard::EMPTY + ); + } + + #[test] + fn west() { + assert_eq!( + Direction::West.move_board(Square::A1.into_bitboard()), + Bitboard::EMPTY + ); + assert_eq!( + Direction::West.move_board(Square::B1.into_bitboard()), + Square::A1.into_bitboard() + ); + assert_eq!( + Direction::West.move_board(Square::G1.into_bitboard()), + Square::F1.into_bitboard() + ); + assert_eq!( + Direction::West.move_board(Square::H1.into_bitboard()), + Square::G1.into_bitboard() + ); + } + + #[test] + fn south() { + assert_eq!( + Direction::South.move_board(Square::A1.into_bitboard()), + Bitboard::EMPTY + ); + assert_eq!( + Direction::South.move_board(Square::A2.into_bitboard()), + Square::A1.into_bitboard() + ); + assert_eq!( + Direction::South.move_board(Square::A7.into_bitboard()), + Square::A6.into_bitboard() + ); + assert_eq!( + Direction::South.move_board(Square::A8.into_bitboard()), + Square::A7.into_bitboard() + ); + } + + #[test] + fn east() { + assert_eq!( + Direction::East.move_board(Square::A1.into_bitboard()), + Square::B1.into_bitboard() + ); + assert_eq!( + Direction::East.move_board(Square::B1.into_bitboard()), + Square::C1.into_bitboard() + ); + assert_eq!( + Direction::East.move_board(Square::G1.into_bitboard()), + Square::H1.into_bitboard() + ); + assert_eq!( + Direction::East.move_board(Square::H1.into_bitboard()), + Bitboard::EMPTY + ); + } + + #[test] + fn north_west() { + assert_eq!( + Direction::NorthWest.move_board(Square::A1.into_bitboard()), + Bitboard::EMPTY + ); + assert_eq!( + Direction::NorthWest.move_board(Square::B1.into_bitboard()), + Square::A2.into_bitboard() + ); + assert_eq!( + Direction::NorthWest.move_board(Square::H1.into_bitboard()), + Square::G2.into_bitboard() + ); + assert_eq!( + Direction::NorthWest.move_board(Square::A8.into_bitboard()), + Bitboard::EMPTY + ); + assert_eq!( + Direction::NorthWest.move_board(Square::B8.into_bitboard()), + Bitboard::EMPTY + ); + assert_eq!( + Direction::NorthWest.move_board(Square::H8.into_bitboard()), + Bitboard::EMPTY + ); + } + + #[test] + fn south_west() { + assert_eq!( + Direction::SouthWest.move_board(Square::A1.into_bitboard()), + Bitboard::EMPTY + ); + assert_eq!( + Direction::SouthWest.move_board(Square::B1.into_bitboard()), + Bitboard::EMPTY + ); + assert_eq!( + Direction::SouthWest.move_board(Square::H1.into_bitboard()), + Bitboard::EMPTY + ); + assert_eq!( + Direction::SouthWest.move_board(Square::A8.into_bitboard()), + Bitboard::EMPTY + ); + assert_eq!( + Direction::SouthWest.move_board(Square::B8.into_bitboard()), + Square::A7.into_bitboard() + ); + assert_eq!( + Direction::SouthWest.move_board(Square::H8.into_bitboard()), + Square::G7.into_bitboard() + ); + } + + #[test] + fn south_east() { + assert_eq!( + Direction::SouthEast.move_board(Square::A1.into_bitboard()), + Bitboard::EMPTY + ); + assert_eq!( + Direction::SouthEast.move_board(Square::B1.into_bitboard()), + Bitboard::EMPTY + ); + assert_eq!( + Direction::SouthEast.move_board(Square::H1.into_bitboard()), + Bitboard::EMPTY + ); + assert_eq!( + Direction::SouthEast.move_board(Square::A8.into_bitboard()), + Square::B7.into_bitboard() + ); + assert_eq!( + Direction::SouthEast.move_board(Square::B8.into_bitboard()), + Square::C7.into_bitboard() + ); + assert_eq!( + Direction::SouthEast.move_board(Square::H8.into_bitboard()), + Bitboard::EMPTY + ); + } + + #[test] + fn north_east() { + assert_eq!( + Direction::NorthEast.move_board(Square::A1.into_bitboard()), + Square::B2.into_bitboard() + ); + assert_eq!( + Direction::NorthEast.move_board(Square::B1.into_bitboard()), + Square::C2.into_bitboard() + ); + assert_eq!( + Direction::NorthEast.move_board(Square::H1.into_bitboard()), + Bitboard::EMPTY + ); + assert_eq!( + Direction::NorthEast.move_board(Square::A8.into_bitboard()), + Bitboard::EMPTY + ); + assert_eq!( + Direction::NorthEast.move_board(Square::B8.into_bitboard()), + Bitboard::EMPTY + ); + assert_eq!( + Direction::NorthEast.move_board(Square::H8.into_bitboard()), + Bitboard::EMPTY + ); + } + + #[test] + fn north_north_west() { + assert_eq!( + Direction::NorthNorthWest.move_board(Square::A1.into_bitboard()), + Bitboard::EMPTY, + ); + assert_eq!( + Direction::NorthNorthWest.move_board(Square::B2.into_bitboard()), + Square::A4.into_bitboard() + ); + assert_eq!( + Direction::NorthNorthWest.move_board(Square::H1.into_bitboard()), + Square::G3.into_bitboard() + ); + assert_eq!( + Direction::NorthNorthWest.move_board(Square::G2.into_bitboard()), + Square::F4.into_bitboard() + ); + assert_eq!( + Direction::NorthNorthWest.move_board(Square::A8.into_bitboard()), + Bitboard::EMPTY, + ); + assert_eq!( + Direction::NorthNorthWest.move_board(Square::B7.into_bitboard()), + Bitboard::EMPTY, + ); + assert_eq!( + Direction::NorthNorthWest.move_board(Square::H8.into_bitboard()), + Bitboard::EMPTY, + ); + assert_eq!( + Direction::NorthNorthWest.move_board(Square::G7.into_bitboard()), + Bitboard::EMPTY, + ); + } + + #[test] + fn north_west_west() { + assert_eq!( + Direction::NorthWestWest.move_board(Square::A1.into_bitboard()), + Bitboard::EMPTY, + ); + assert_eq!( + Direction::NorthWestWest.move_board(Square::B2.into_bitboard()), + Bitboard::EMPTY, + ); + assert_eq!( + Direction::NorthWestWest.move_board(Square::H1.into_bitboard()), + Square::F2.into_bitboard() + ); + assert_eq!( + Direction::NorthWestWest.move_board(Square::G2.into_bitboard()), + Square::E3.into_bitboard() + ); + assert_eq!( + Direction::NorthWestWest.move_board(Square::A8.into_bitboard()), + Bitboard::EMPTY, + ); + assert_eq!( + Direction::NorthWestWest.move_board(Square::B7.into_bitboard()), + Bitboard::EMPTY, + ); + assert_eq!( + Direction::NorthWestWest.move_board(Square::H8.into_bitboard()), + Bitboard::EMPTY, + ); + assert_eq!( + Direction::NorthWestWest.move_board(Square::G7.into_bitboard()), + Square::E8.into_bitboard() + ); + } + + #[test] + fn south_west_west() { + assert_eq!( + Direction::SouthWestWest.move_board(Square::A1.into_bitboard()), + Bitboard::EMPTY, + ); + assert_eq!( + Direction::SouthWestWest.move_board(Square::B2.into_bitboard()), + Bitboard::EMPTY, + ); + assert_eq!( + Direction::SouthWestWest.move_board(Square::H1.into_bitboard()), + Bitboard::EMPTY, + ); + assert_eq!( + Direction::SouthWestWest.move_board(Square::G2.into_bitboard()), + Square::E1.into_bitboard() + ); + assert_eq!( + Direction::SouthWestWest.move_board(Square::A8.into_bitboard()), + Bitboard::EMPTY, + ); + assert_eq!( + Direction::SouthWestWest.move_board(Square::B7.into_bitboard()), + Bitboard::EMPTY, + ); + assert_eq!( + Direction::SouthWestWest.move_board(Square::H8.into_bitboard()), + Square::F7.into_bitboard() + ); + assert_eq!( + Direction::SouthWestWest.move_board(Square::G7.into_bitboard()), + Square::E6.into_bitboard() + ); + } + + #[test] + fn south_south_west() { + assert_eq!( + Direction::SouthSouthWest.move_board(Square::A1.into_bitboard()), + Bitboard::EMPTY, + ); + assert_eq!( + Direction::SouthSouthWest.move_board(Square::B2.into_bitboard()), + Bitboard::EMPTY, + ); + assert_eq!( + Direction::SouthSouthWest.move_board(Square::H1.into_bitboard()), + Bitboard::EMPTY, + ); + assert_eq!( + Direction::SouthSouthWest.move_board(Square::G2.into_bitboard()), + Bitboard::EMPTY, + ); + assert_eq!( + Direction::SouthSouthWest.move_board(Square::A8.into_bitboard()), + Bitboard::EMPTY, + ); + assert_eq!( + Direction::SouthSouthWest.move_board(Square::B7.into_bitboard()), + Square::A5.into_bitboard() + ); + assert_eq!( + Direction::SouthSouthWest.move_board(Square::H8.into_bitboard()), + Square::G6.into_bitboard() + ); + assert_eq!( + Direction::SouthSouthWest.move_board(Square::G7.into_bitboard()), + Square::F5.into_bitboard() + ); + } + + #[test] + fn south_south_east() { + assert_eq!( + Direction::SouthSouthEast.move_board(Square::A1.into_bitboard()), + Bitboard::EMPTY, + ); + assert_eq!( + Direction::SouthSouthEast.move_board(Square::B2.into_bitboard()), + Bitboard::EMPTY, + ); + assert_eq!( + Direction::SouthSouthEast.move_board(Square::H1.into_bitboard()), + Bitboard::EMPTY, + ); + assert_eq!( + Direction::SouthSouthEast.move_board(Square::G2.into_bitboard()), + Bitboard::EMPTY, + ); + assert_eq!( + Direction::SouthSouthEast.move_board(Square::A8.into_bitboard()), + Square::B6.into_bitboard() + ); + assert_eq!( + Direction::SouthSouthEast.move_board(Square::B7.into_bitboard()), + Square::C5.into_bitboard() + ); + assert_eq!( + Direction::SouthSouthEast.move_board(Square::H8.into_bitboard()), + Bitboard::EMPTY, + ); + assert_eq!( + Direction::SouthSouthEast.move_board(Square::G7.into_bitboard()), + Square::H5.into_bitboard() + ); + } + + #[test] + fn south_east_east() { + assert_eq!( + Direction::SouthEastEast.move_board(Square::A1.into_bitboard()), + Bitboard::EMPTY, + ); + assert_eq!( + Direction::SouthEastEast.move_board(Square::B2.into_bitboard()), + Square::D1.into_bitboard() + ); + assert_eq!( + Direction::SouthEastEast.move_board(Square::H1.into_bitboard()), + Bitboard::EMPTY, + ); + assert_eq!( + Direction::SouthEastEast.move_board(Square::G2.into_bitboard()), + Bitboard::EMPTY, + ); + assert_eq!( + Direction::SouthEastEast.move_board(Square::A8.into_bitboard()), + Square::C7.into_bitboard() + ); + assert_eq!( + Direction::SouthEastEast.move_board(Square::B7.into_bitboard()), + Square::D6.into_bitboard() + ); + assert_eq!( + Direction::SouthEastEast.move_board(Square::H8.into_bitboard()), + Bitboard::EMPTY, + ); + assert_eq!( + Direction::SouthEastEast.move_board(Square::G7.into_bitboard()), + Bitboard::EMPTY, + ); + } + + #[test] + fn north_east_east() { + assert_eq!( + Direction::NorthEastEast.move_board(Square::A1.into_bitboard()), + Square::C2.into_bitboard() + ); + assert_eq!( + Direction::NorthEastEast.move_board(Square::B2.into_bitboard()), + Square::D3.into_bitboard() + ); + assert_eq!( + Direction::NorthEastEast.move_board(Square::H1.into_bitboard()), + Bitboard::EMPTY, + ); + assert_eq!( + Direction::NorthEastEast.move_board(Square::G2.into_bitboard()), + Bitboard::EMPTY, + ); + assert_eq!( + Direction::NorthEastEast.move_board(Square::A8.into_bitboard()), + Bitboard::EMPTY, + ); + assert_eq!( + Direction::NorthEastEast.move_board(Square::B7.into_bitboard()), + Square::D8.into_bitboard() + ); + assert_eq!( + Direction::NorthEastEast.move_board(Square::H8.into_bitboard()), + Bitboard::EMPTY, + ); + assert_eq!( + Direction::NorthEastEast.move_board(Square::G7.into_bitboard()), + Bitboard::EMPTY, + ); + } + + #[test] + fn north_north_east() { + assert_eq!( + Direction::NorthNorthEast.move_board(Square::A1.into_bitboard()), + Square::B3.into_bitboard() + ); + assert_eq!( + Direction::NorthNorthEast.move_board(Square::B2.into_bitboard()), + Square::C4.into_bitboard() + ); + assert_eq!( + Direction::NorthNorthEast.move_board(Square::H1.into_bitboard()), + Bitboard::EMPTY, + ); + assert_eq!( + Direction::NorthNorthEast.move_board(Square::G2.into_bitboard()), + Square::H4.into_bitboard() + ); + assert_eq!( + Direction::NorthNorthEast.move_board(Square::A8.into_bitboard()), + Bitboard::EMPTY, + ); + assert_eq!( + Direction::NorthNorthEast.move_board(Square::B7.into_bitboard()), + Bitboard::EMPTY, + ); + assert_eq!( + Direction::NorthNorthEast.move_board(Square::H8.into_bitboard()), + Bitboard::EMPTY, + ); + assert_eq!( + Direction::NorthNorthEast.move_board(Square::G7.into_bitboard()), + Bitboard::EMPTY, + ); + } +}