aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/attacks.rs106
-rw-r--r--src/bitboard.rs36
-rw-r--r--src/board.rs56
-rw-r--r--src/main.rs1
-rw-r--r--src/moves.rs10
-rw-r--r--src/square.rs24
6 files changed, 120 insertions, 113 deletions
diff --git a/src/attacks.rs b/src/attacks.rs
index 7fc6b7d..a9947bc 100644
--- a/src/attacks.rs
+++ b/src/attacks.rs
@@ -1,4 +1,4 @@
-use crate::{bitboard::Bitboard, board::Color};
+use crate::{bitboard::Bitboard, board::Color, square::Square};
static NOT_A_FILE: Bitboard = 0xFEFEFEFEFEFEFEFE;
static NOT_B_FILE: Bitboard = 0xFDFDFDFDFDFDFDFD;
@@ -248,8 +248,8 @@ impl Attacks {
///
/// Given a square and occupancy masked for rank, diagonal or anti-diagonal (note: not a file!)
/// return an attack bitboard that considers blocking pieces
- fn kindergarten_attacks_base(&self, occupancy: Bitboard, mask: Bitboard, square: u8) -> Bitboard {
- let file = square % 8;
+ fn kindergarten_attacks_base(&self, occupancy: Bitboard, mask: Bitboard, square: Square) -> Bitboard {
+ let file = square as u8 % 8;
let masked_occupancy = occupancy & mask;
let occupancy_rank = ((masked_occupancy as u128 * B_FILE as u128) >> 58 & 0b111111) << 1;
let rank_attacks = self.first_rank_attacks[occupancy_rank as usize][file as usize] as Bitboard;
@@ -262,9 +262,9 @@ impl Attacks {
}
/// https://www.chessprogramming.org/Kindergarten_Bitboards
- fn kindergarten_attacks_file(&self, occupancy: Bitboard, mask: Bitboard, square: u8) -> Bitboard {
- let file = square % 8;
- let rank = square / 8;
+ fn kindergarten_attacks_file(&self, occupancy: Bitboard, mask: Bitboard, square: Square) -> Bitboard {
+ let file = square as u8 % 8;
+ let rank = square as u8 / 8;
let masked_occupancy = (occupancy & mask) >> file; // Shift occupancy to A file
let occupancy_rank = ((masked_occupancy as u128 * DIAG_C2_H7 as u128) >> 58 & 0b111111) << 1;
@@ -274,7 +274,7 @@ impl Attacks {
((rank_attacks as u128 * DIAG_A1_H8 as u128) as Bitboard & H_FILE) >> (7 - file)
}
- pub fn bishop(&self, occupancy: Bitboard, square: u8) -> Bitboard {
+ pub fn bishop(&self, occupancy: Bitboard, square: Square) -> Bitboard {
let diagonal_mask =
self.ray_attacks[Direction::NoEa as usize][square as usize] |
self.ray_attacks[Direction::SoWe as usize][square as usize];
@@ -285,7 +285,7 @@ impl Attacks {
self.kindergarten_attacks_base(occupancy, diagonal_mask, square) | self.kindergarten_attacks_base(occupancy, anti_diagonal_mask, square)
}
- pub fn rook(&self, occupancy: Bitboard, square: u8) -> Bitboard {
+ pub fn rook(&self, occupancy: Bitboard, square: Square) -> Bitboard {
let vertical =
self.ray_attacks[Direction::Nort as usize][square as usize] |
self.ray_attacks[Direction::Sout as usize][square as usize];
@@ -296,14 +296,14 @@ impl Attacks {
self.kindergarten_attacks_file(occupancy, vertical, square) | self.kindergarten_attacks_base(occupancy, horizontal, square)
}
- pub fn queen(&self, occupancy: Bitboard, square: u8) -> Bitboard {
+ pub fn queen(&self, occupancy: Bitboard, square: Square) -> Bitboard {
self.rook(occupancy, square) | self.bishop(occupancy, square)
}
}
#[cfg(test)]
mod tests {
- use crate::{bitboard::{pop_count, print}, board::Square};
+ use crate::{bitboard::{pop_count, print}, square::Square};
use super::*;
@@ -321,10 +321,10 @@ mod tests {
print(white_attacks, "Pawn e4");
- assert_eq!(white_attacks, 1 << Square::D5 as usize | 1 << Square::F5 as usize);
+ assert_eq!(white_attacks, Square::D5.to_bitboard() | Square::F5.to_bitboard());
- assert_eq!(attacks[Color::White as usize][Square::H4 as usize], 1 << Square::G5 as usize);
- assert_eq!(attacks[Color::White as usize][Square::A4 as usize], 1 << Square::B5 as usize);
+ assert_eq!(attacks[Color::White as usize][Square::H4 as usize], Square::G5.to_bitboard());
+ assert_eq!(attacks[Color::White as usize][Square::A4 as usize], Square::B5.to_bitboard());
assert_eq!(pop_count(attacks[Color::White as usize][Square::E8 as usize]), 0);
assert_eq!(pop_count(attacks[Color::Black as usize][Square::E1 as usize]), 0);
@@ -333,10 +333,10 @@ mod tests {
#[test]
fn test_pawn_pushes() {
let pushes = Attacks::precompute_pawn_pushes();
- assert_eq!(pushes[Color::White as usize][Square::E4 as usize], 1 << Square::E5 as usize);
- assert_eq!(pushes[Color::White as usize][Square::A2 as usize], 1 << Square::A3 as usize | 1 << Square::A4 as usize);
- assert_eq!(pushes[Color::Black as usize][Square::E4 as usize], 1 << Square::E3 as usize);
- assert_eq!(pushes[Color::Black as usize][Square::H6 as usize], 1 << Square::H5 as usize | 1 << Square::H4 as usize);
+ assert_eq!(pushes[Color::White as usize][Square::E4 as usize], Square::E5.to_bitboard());
+ assert_eq!(pushes[Color::White as usize][Square::A2 as usize], Square::A3.to_bitboard() | Square::A4.to_bitboard());
+ assert_eq!(pushes[Color::Black as usize][Square::E4 as usize], Square::E3.to_bitboard());
+ assert_eq!(pushes[Color::Black as usize][Square::H6 as usize], Square::H5.to_bitboard() | Square::H4.to_bitboard());
}
#[test]
@@ -346,18 +346,18 @@ mod tests {
print(e4_attacks, "Knight e4");
- assert_ne!(e4_attacks & 1 << Square::G5 as usize, 0);
- assert_ne!(e4_attacks & 1 << Square::G3 as usize, 0);
- assert_ne!(e4_attacks & 1 << Square::C5 as usize, 0);
- assert_ne!(e4_attacks & 1 << Square::C3 as usize, 0);
- assert_ne!(e4_attacks & 1 << Square::D2 as usize, 0);
- assert_ne!(e4_attacks & 1 << Square::F2 as usize, 0);
- assert_ne!(e4_attacks & 1 << Square::D6 as usize, 0);
- assert_ne!(e4_attacks & 1 << Square::F6 as usize, 0);
+ assert_ne!(e4_attacks & Square::G5.to_bitboard(), 0);
+ assert_ne!(e4_attacks & Square::G3.to_bitboard(), 0);
+ assert_ne!(e4_attacks & Square::C5.to_bitboard(), 0);
+ assert_ne!(e4_attacks & Square::C3.to_bitboard(), 0);
+ assert_ne!(e4_attacks & Square::D2.to_bitboard(), 0);
+ assert_ne!(e4_attacks & Square::F2.to_bitboard(), 0);
+ assert_ne!(e4_attacks & Square::D6.to_bitboard(), 0);
+ assert_ne!(e4_attacks & Square::F6.to_bitboard(), 0);
- assert_eq!(e4_attacks & 1 << Square::E5 as usize, 0);
- assert_eq!(e4_attacks & 1 << Square::D4 as usize, 0);
- assert_eq!(e4_attacks & 1 << Square::A1 as usize, 0);
+ assert_eq!(e4_attacks & Square::E5.to_bitboard(), 0);
+ assert_eq!(e4_attacks & Square::D4.to_bitboard(), 0);
+ assert_eq!(e4_attacks & Square::A1.to_bitboard(), 0);
assert_eq!(pop_count(attacks[Square::G1 as usize]), 3);
assert_eq!(pop_count(attacks[Square::H8 as usize]), 2);
@@ -418,52 +418,52 @@ mod tests {
#[test]
fn test_bishop_attacks() {
let attacks = Attacks::new();
- let square = Square::E4 as u8;
+ let square = Square::E4;
let bb = attacks.bishop(DEFAULT_OCCUPANCY, square);
print(DEFAULT_OCCUPANCY, "Occupancy");
print(bb, "Bishop e4");
- assert_ne!(bb & 1 << Square::C2 as u8, 0);
- assert_eq!(bb & 1 << Square::B1 as u8, 0);
- assert_ne!(bb & 1 << Square::F3 as u8, 0);
- assert_eq!(bb & 1 << Square::G2 as u8, 0);
- assert_ne!(bb & 1 << Square::H7 as u8, 0);
- assert_ne!(bb & 1 << Square::B7 as u8, 0);
- assert_eq!(bb & 1 << Square::A8 as u8, 0);
+ assert_ne!(bb & Square::C2.to_bitboard(), 0);
+ assert_eq!(bb & Square::B1.to_bitboard(), 0);
+ assert_ne!(bb & Square::F3.to_bitboard(), 0);
+ assert_eq!(bb & Square::G2.to_bitboard(), 0);
+ assert_ne!(bb & Square::H7.to_bitboard(), 0);
+ assert_ne!(bb & Square::B7.to_bitboard(), 0);
+ assert_eq!(bb & Square::A8.to_bitboard(), 0);
}
#[test]
fn test_rook_attacks() {
let attacks = Attacks::new();
- let square = Square::E4 as u8;
+ let square = Square::E4;
let occupancy =
- 1 << Square::B7 as usize |
- 1 << Square::B1 as usize |
- 1 << Square::C2 as usize |
- 1 << Square::E3 as usize |
- 1 << Square::F3 as usize;
+ Square::B7.to_bitboard() |
+ Square::B1.to_bitboard() |
+ Square::C2.to_bitboard() |
+ Square::E3.to_bitboard() |
+ Square::F3.to_bitboard();
let bb = attacks.rook(occupancy, square);
print(occupancy, "Occupancy");
print(bb, "Rook e4");
- assert_ne!(bb & 1 << Square::E8 as u8, 0);
- assert_ne!(bb & 1 << Square::E7 as u8, 0);
- assert_ne!(bb & 1 << Square::E6 as u8, 0);
- assert_ne!(bb & 1 << Square::E5 as u8, 0);
- assert_ne!(bb & 1 << Square::E3 as u8, 0);
- assert_eq!(bb & 1 << Square::E2 as u8, 0);
- assert_eq!(bb & 1 << Square::E1 as u8, 0);
- assert_ne!(bb & 1 << Square::A4 as u8, 0);
- assert_ne!(bb & 1 << Square::H4 as u8, 0);
- assert_eq!(bb & 1 << Square::E4 as u8, 0);
+ assert_ne!(bb & Square::E8.to_bitboard(), 0);
+ assert_ne!(bb & Square::E7.to_bitboard(), 0);
+ assert_ne!(bb & Square::E6.to_bitboard(), 0);
+ assert_ne!(bb & Square::E5.to_bitboard(), 0);
+ assert_ne!(bb & Square::E3.to_bitboard(), 0);
+ assert_eq!(bb & Square::E2.to_bitboard(), 0);
+ assert_eq!(bb & Square::E1.to_bitboard(), 0);
+ assert_ne!(bb & Square::A4.to_bitboard(), 0);
+ assert_ne!(bb & Square::H4.to_bitboard(), 0);
+ assert_eq!(bb & Square::E4.to_bitboard(), 0);
}
#[test]
fn test_queen_attacks() {
let attacks = Attacks::new();
- let square = Square::E4 as u8;
+ let square = Square::E4;
let bb = attacks.queen(DEFAULT_OCCUPANCY, square);
print(DEFAULT_OCCUPANCY, "Occupancy");
print(bb, "Queen e4");
diff --git a/src/bitboard.rs b/src/bitboard.rs
index b05803c..d7a4fdb 100644
--- a/src/bitboard.rs
+++ b/src/bitboard.rs
@@ -1,3 +1,5 @@
+use crate::square::Square;
+
/// Finite set of up to 64 bits representing chess board squares
pub type Bitboard = u64;
@@ -28,7 +30,7 @@ pub fn pop_count(bb: Bitboard) -> u8 {
}
/// Return Bitboard with only Least Single Bit
-pub fn ls1b(bb: Bitboard) -> u64 {
+pub fn ls1b(bb: Bitboard) -> Bitboard {
if bb == 0 {
return 0
}
@@ -39,18 +41,20 @@ pub fn ls1b(bb: Bitboard) -> u64 {
///
/// WARNING: Only works for SINGLE Bitboards
/// Useful for calculating bit-index of LS1B
-pub fn bitscan(bb: Bitboard) -> u8 {
+pub fn bitscan(bb: Bitboard) -> Square {
debug_assert!(pop_count(bb) == 1, "Bitscan only works for SINGLE Bitboards!");
- pop_count(bb - 1)
+ Square::from(pop_count(bb - 1))
}
-pub fn bitscan_and_reset(bb: &mut Bitboard) -> u8 {
+/// Finds and removes ls1b in the bitboard, returning it's index
+pub fn bitscan_and_reset(bb: &mut Bitboard) -> Square {
let ls1b_bitboard = ls1b(*bb);
*bb ^= ls1b_bitboard;
bitscan(ls1b_bitboard)
}
-pub fn serialize_bitboard(bb: Bitboard) -> Vec<u8> {
+/// Convert bitboard into the list of squares
+pub fn serialize_bitboard(bb: Bitboard) -> Vec<Square> {
let mut serialized = Vec::with_capacity(64);
let mut bitboard = bb;
while bitboard > 0 {
@@ -77,10 +81,10 @@ mod tests {
#[test]
fn test_bitscan() {
- assert_eq!(bitscan(4), 2);
- assert_eq!(bitscan(16), 4);
- assert_eq!(bitscan(64), 6);
- assert_eq!(bitscan(128), 7);
+ assert_eq!(bitscan(4), Square::from(2));
+ assert_eq!(bitscan(16), Square::from(4));
+ assert_eq!(bitscan(64), Square::from(6));
+ assert_eq!(bitscan(128), Square::from(7));
}
#[test]
@@ -90,20 +94,12 @@ mod tests {
}
#[test]
- fn test_bitscan_and_reset() {
- assert_eq!(bitscan(4), 2);
- assert_eq!(bitscan(16), 4);
- assert_eq!(bitscan(64), 6);
- assert_eq!(bitscan(128), 7);
- }
-
- #[test]
fn test_serialize_bitboard() {
let bb = 1 << 4 | 1 << 15 | 1 << 60;
let serialized = serialize_bitboard(bb);
- assert_eq!(serialized[0], 4);
- assert_eq!(serialized[1], 15);
- assert_eq!(serialized[2], 60);
+ assert_eq!(serialized[0], Square::from(4));
+ assert_eq!(serialized[1], Square::from(15));
+ assert_eq!(serialized[2], Square::from(60));
}
}
diff --git a/src/board.rs b/src/board.rs
index 2047483..9df26fe 100644
--- a/src/board.rs
+++ b/src/board.rs
@@ -145,44 +145,44 @@ impl Board {
for (piece_type, piece) in self.pieces_by_color(color).iter().enumerate() {
match PieceType::from(piece_type) {
PieceType::Pawn => {
- for from in serialize_bitboard(*piece) {
- for to in serialize_bitboard(self.attacks.pawn_pushes[color as usize][from as usize] & available_targets) {
- moves.push(Move { from, to });
+ for source in serialize_bitboard(*piece) {
+ for target in serialize_bitboard(self.attacks.pawn_pushes[color as usize][source as usize] & available_targets) {
+ moves.push(Move { source, target });
};
}
}
PieceType::King => {
- for from in serialize_bitboard(*piece) {
- for to in serialize_bitboard(self.attacks.king[from as usize] & available_targets) {
- moves.push(Move { from, to });
+ for source in serialize_bitboard(*piece) {
+ for target in serialize_bitboard(self.attacks.king[source as usize] & available_targets) {
+ moves.push(Move { source, target });
};
}
}
PieceType::Knight => {
- for from in serialize_bitboard(*piece) {
- for to in serialize_bitboard(self.attacks.knight[from as usize] & available_targets) {
- moves.push(Move { from, to });
+ for source in serialize_bitboard(*piece) {
+ for target in serialize_bitboard(self.attacks.knight[source as usize] & available_targets) {
+ moves.push(Move { source, target });
};
}
}
PieceType::Bishop => {
- for from in serialize_bitboard(*piece) {
- for to in serialize_bitboard(self.attacks.bishop(self.occupancy, from) & available_targets) {
- moves.push(Move { from, to });
+ for source in serialize_bitboard(*piece) {
+ for target in serialize_bitboard(self.attacks.bishop(self.occupancy, source) & available_targets) {
+ moves.push(Move { source, target });
};
}
}
PieceType::Rook => {
- for from in serialize_bitboard(*piece) {
- for to in serialize_bitboard(self.attacks.rook(self.occupancy, from) & available_targets) {
- moves.push(Move { from, to });
+ for source in serialize_bitboard(*piece) {
+ for target in serialize_bitboard(self.attacks.rook(self.occupancy, source) & available_targets) {
+ moves.push(Move { source, target });
};
}
}
PieceType::Queen => {
- for from in serialize_bitboard(*piece) {
- for to in serialize_bitboard(self.attacks.queen(self.occupancy, from) & available_targets) {
- moves.push(Move { from, to });
+ for source in serialize_bitboard(*piece) {
+ for target in serialize_bitboard(self.attacks.queen(self.occupancy, source) & available_targets) {
+ moves.push(Move { source, target });
};
}
}
@@ -202,24 +202,10 @@ pub enum Color {
Black,
}
-/// Aliases to board square indexes
-#[allow(dead_code)]
-#[derive(Debug)]
-pub enum Square {
- A1, B1, C1, D1, E1, F1, G1, H1,
- A2, B2, C2, D2, E2, F2, G2, H2,
- A3, B3, C3, D3, E3, F3, G3, H3,
- A4, B4, C4, D4, E4, F4, G4, H4,
- A5, B5, C5, D5, E5, F5, G5, H5,
- A6, B6, C6, D6, E6, F6, G6, H6,
- A7, B7, C7, D7, E7, F7, G7, H7,
- A8, B8, C8, D8, E8, F8, G8, H8,
-}
-
#[cfg(test)]
mod tests {
use super::*;
- use crate::bitboard::{pop_count, bitscan, print};
+ use crate::{bitboard::{pop_count, bitscan, print}, square::Square};
const DEFAULT_FEN: &str = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
@@ -252,8 +238,8 @@ mod tests {
assert_eq!(pop_count(board.pieces[PieceType::QueenBlack as usize]), 1);
assert_eq!(pop_count(board.pieces[PieceType::KingBlack as usize]), 1);
- assert_eq!(bitscan(board.pieces[PieceType::King as usize]), Square::E1 as u8);
- assert_eq!(bitscan(board.pieces[PieceType::QueenBlack as usize]), Square::D8 as u8);
+ assert_eq!(bitscan(board.pieces[PieceType::King as usize]), Square::E1);
+ assert_eq!(bitscan(board.pieces[PieceType::QueenBlack as usize]), Square::D8);
assert_eq!(pop_count(board.occupancy), 32);
assert_eq!(pop_count(board.empty()), 32);
diff --git a/src/main.rs b/src/main.rs
index 3ffab60..9a38593 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,3 +1,4 @@
+mod square;
mod bitboard;
mod board;
mod attacks;
diff --git a/src/moves.rs b/src/moves.rs
index 97032e5..a43ed4b 100644
--- a/src/moves.rs
+++ b/src/moves.rs
@@ -1,14 +1,14 @@
-use crate::{board::Square, bitboard::print};
+use crate::{square::Square, bitboard::print};
#[derive(Debug)]
pub struct Move {
- pub from: u8,
- pub to: u8,
+ pub source: Square,
+ pub target: Square,
}
impl Move {
pub fn print(&self) {
- let bb = 1u64 << self.from | 1u64 << self.to;
+ let bb = self.source.to_bitboard() | self.target.to_bitboard();
print(bb, format!("{:?}", self).as_str());
}
}
@@ -21,7 +21,7 @@ mod tests {
#[test]
fn mock() {
- let mov = Move { from: Square::E2 as u8, to: Square::E4 as u8 };
+ let mov = Move { source: Square::E2, target: Square::E4 };
println!("{:?}", mov);
}
}
diff --git a/src/square.rs b/src/square.rs
new file mode 100644
index 0000000..ed2877c
--- /dev/null
+++ b/src/square.rs
@@ -0,0 +1,24 @@
+use crate::bitboard::Bitboard;
+
+/// Aliases to board square indexes
+#[allow(dead_code)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq, num_enum::FromPrimitive)]
+#[repr(u8)]
+pub enum Square {
+ #[default]
+ A1, B1, C1, D1, E1, F1, G1, H1,
+ A2, B2, C2, D2, E2, F2, G2, H2,
+ A3, B3, C3, D3, E3, F3, G3, H3,
+ A4, B4, C4, D4, E4, F4, G4, H4,
+ A5, B5, C5, D5, E5, F5, G5, H5,
+ A6, B6, C6, D6, E6, F6, G6, H6,
+ A7, B7, C7, D7, E7, F7, G7, H7,
+ A8, B8, C8, D8, E8, F8, G8, H8,
+}
+impl Square {
+ pub fn to_bitboard(&self) -> Bitboard {
+ 1u64 << *self as u8
+ }
+}
+
+