diff options
author | eug-vs <eugene@eug-vs.xyz> | 2023-01-23 05:02:30 +0300 |
---|---|---|
committer | eug-vs <eugene@eug-vs.xyz> | 2023-01-23 05:10:48 +0300 |
commit | 9a41a379a8a1f33b6a9d28f1d5ff3c1d0826e1f5 (patch) | |
tree | 58a7ec5f6bdbc701436c011e82a5b6817483bb1c /src | |
parent | c61c22208de60465db7f9cf58cdfa5d204826daf (diff) | |
download | chessnost-9a41a379a8a1f33b6a9d28f1d5ff3c1d0826e1f5.tar.gz |
refactor: use Square as type everywhere
Diffstat (limited to 'src')
-rw-r--r-- | src/attacks.rs | 106 | ||||
-rw-r--r-- | src/bitboard.rs | 36 | ||||
-rw-r--r-- | src/board.rs | 56 | ||||
-rw-r--r-- | src/main.rs | 1 | ||||
-rw-r--r-- | src/moves.rs | 10 | ||||
-rw-r--r-- | src/square.rs | 24 |
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 + } +} + + |