diff options
author | eug-vs <eugene@eug-vs.xyz> | 2023-02-21 05:22:54 +0300 |
---|---|---|
committer | eug-vs <eugene@eug-vs.xyz> | 2023-02-21 05:28:45 +0300 |
commit | 46e9fcdcce5730827355db9449c41dc0a0e42b1f (patch) | |
tree | 7b9903446bd7884df6a22ddd2c6a2b8a6dcc3d44 | |
parent | 02ebad55af6c76ac9e36832f9be041f547f63b7c (diff) | |
download | chessnost-46e9fcdcce5730827355db9449c41dc0a0e42b1f.tar.gz |
refactor: use bitboard trait
-rw-r--r-- | src/attacks.rs | 48 | ||||
-rw-r--r-- | src/bitboard.rs | 163 | ||||
-rw-r--r-- | src/board/engine.rs | 14 | ||||
-rw-r--r-- | src/board/mod.rs | 131 | ||||
-rw-r--r-- | src/moves.rs | 4 |
5 files changed, 188 insertions, 172 deletions
diff --git a/src/attacks.rs b/src/attacks.rs index eafaf01..d32ac64 100644 --- a/src/attacks.rs +++ b/src/attacks.rs @@ -307,7 +307,7 @@ impl Attacks { #[cfg(test)] mod tests { - use crate::{bitboard::{pop_count, print}, square::Square}; + use crate::{bitboard::BitboardFns, square::Square}; use super::*; @@ -323,15 +323,15 @@ mod tests { let square = Square::E4 as usize; let white_attacks = attacks[Color::White as usize][square]; - print(white_attacks, "Pawn e4"); + white_attacks.print("Pawn e4"); assert_eq!(white_attacks, Square::D5.to_bitboard() | Square::F5.to_bitboard()); 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); + assert_eq!(attacks[Color::White as usize][Square::E8 as usize].pop_count(), 0); + assert_eq!(attacks[Color::Black as usize][Square::E1 as usize].pop_count(), 0); } #[test] @@ -353,7 +353,7 @@ mod tests { let attacks = Attacks::precompute_knight_attacks(); let e4_attacks = attacks[Square::E4 as usize]; - print(e4_attacks, "Knight e4"); + e4_attacks.print("Knight e4"); assert_ne!(e4_attacks & Square::G5.to_bitboard(), 0); assert_ne!(e4_attacks & Square::G3.to_bitboard(), 0); @@ -368,27 +368,27 @@ mod tests { 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); + assert_eq!(attacks[Square::G1 as usize].pop_count(), 3); + assert_eq!(attacks[Square::H8 as usize].pop_count(), 2); } #[test] fn king_attacks() { let attacks = Attacks::precompute_king_attacks(); - print(attacks[Square::E4 as usize], "King e4"); + attacks[Square::E4 as usize].print("King e4"); - assert_eq!(pop_count(attacks[Square::E4 as usize]), 8); + assert_eq!(attacks[Square::E4 as usize].pop_count(), 8); - assert_eq!(pop_count(attacks[Square::A1 as usize]), 3); - assert_eq!(pop_count(attacks[Square::A8 as usize]), 3); - assert_eq!(pop_count(attacks[Square::H1 as usize]), 3); - assert_eq!(pop_count(attacks[Square::H8 as usize]), 3); + assert_eq!(attacks[Square::A1 as usize].pop_count(), 3); + assert_eq!(attacks[Square::A8 as usize].pop_count(), 3); + assert_eq!(attacks[Square::H1 as usize].pop_count(), 3); + assert_eq!(attacks[Square::H8 as usize].pop_count(), 3); - assert_eq!(pop_count(attacks[Square::E1 as usize]), 5); - assert_eq!(pop_count(attacks[Square::E8 as usize]), 5); - assert_eq!(pop_count(attacks[Square::A4 as usize]), 5); - assert_eq!(pop_count(attacks[Square::H4 as usize]), 5); + assert_eq!(attacks[Square::E1 as usize].pop_count(), 5); + assert_eq!(attacks[Square::E8 as usize].pop_count(), 5); + assert_eq!(attacks[Square::A4 as usize].pop_count(), 5); + assert_eq!(attacks[Square::H4 as usize].pop_count(), 5); } #[test] @@ -421,7 +421,7 @@ mod tests { attacks[5][square] | attacks[6][square] | attacks[7][square]; - print(bitboard, "Rays from e4"); + bitboard.print("Rays from e4"); } #[test] @@ -430,8 +430,8 @@ mod tests { let square = Square::E4; let bb = attacks.bishop(DEFAULT_OCCUPANCY, square); - print(DEFAULT_OCCUPANCY, "Occupancy"); - print(bb, "Bishop e4"); + DEFAULT_OCCUPANCY.print("Occupancy"); + bb.print("Bishop e4"); assert_ne!(bb & Square::C2.to_bitboard(), 0); assert_eq!(bb & Square::B1.to_bitboard(), 0); @@ -454,8 +454,8 @@ mod tests { Square::F3.to_bitboard(); let bb = attacks.rook(occupancy, square); - print(occupancy, "Occupancy"); - print(bb, "Rook e4"); + occupancy.print("Occupancy"); + bb.print("Rook e4"); assert_ne!(bb & Square::E8.to_bitboard(), 0); assert_ne!(bb & Square::E7.to_bitboard(), 0); @@ -474,7 +474,7 @@ mod tests { let attacks = Attacks::new(); let square = Square::E4; let bb = attacks.queen(DEFAULT_OCCUPANCY, square); - print(DEFAULT_OCCUPANCY, "Occupancy"); - print(bb, "Queen e4"); + DEFAULT_OCCUPANCY.print("Occupancy"); + bb.print("Queen e4"); } } diff --git a/src/bitboard.rs b/src/bitboard.rs index ed7ec1b..ad21664 100644 --- a/src/bitboard.rs +++ b/src/bitboard.rs @@ -3,40 +3,32 @@ use crate::square::Square; /// Finite set of up to 64 bits representing chess board squares pub type Bitboard = u64; -/// Print bitboard on screen in the same way squares appear in memory -/// (i.e the board is actually flipped along X) -#[allow(dead_code)] -pub fn print(bb: Bitboard, title: &str) { - println!("\n {}", title); - for rank in (0..8).rev() { - print!("{}|", rank + 1); - for file in 0..8 { - let index = rank * 8 + file; - print!("{}", if bb >> index & 1 == 1 { "⚫" } else { ". " }); - if file == 7 { - println!(); - } - } - } - return println!(" a b c d e f g h"); -} +pub trait BitboardFns { + /// Print bitboard on the screen + fn print(self, title: &str) -> (); -/// Return bitboard cardinality, aka number of elements in the set -pub fn pop_count(mut bb: Bitboard) -> u8 { - let mut count = 0; - while bb > 0 { - count += 1; - bb &= bb - 1; - } - return count; -} + /// Return bitboard cardinality, aka number of elements in the set + fn pop_count(self) -> u8; -/// Return Bitboard with only Least Single Bit -pub fn ls1b(bb: Bitboard) -> Bitboard { - if bb == 0 { - return 0 - } - bb & !(bb - 1) + /// Return Bitboard with only Least Single Bit + fn ls1b(self) -> Self; + + /// Return the square corresponding to Least Single Bit + /// using De Brujin method. For single Bitboards it works + /// like a mapper from Bitboards to Squares. + /// + /// ```rust + /// # use chessnost::{bitboard::BitboardFns, square::Square}; + /// assert_eq!(5.bitscan(), Square::from(0)); + /// assert_eq!(4.bitscan(), Square::C1); + /// ``` + fn bitscan(self) -> Square; + + /// Perform bitscan and reset the *ls1b* + fn bitscan_and_reset(&mut self) -> Square; + + /// Convert bitboard into the list of squares + fn serialize(self) -> Vec<Square>; } const DE_BRUJIN_SEQUENCE: [u8; 64] = [ @@ -50,38 +42,62 @@ const DE_BRUJIN_SEQUENCE: [u8; 64] = [ 25, 14, 19, 9, 13, 8, 7, 6 ]; -/// Return the square corresponding to Least Single Bit -/// using De Brujin method. For single Bitboards it works -/// like a mapper from Bitboards to Squares. -/// -/// ```rust -/// # use chessnost::{bitboard::bitscan, square::Square}; -/// assert_eq!(bitscan(5), Square::from(0)); -/// assert_eq!(bitscan(4), Square::C1); -/// ``` -pub fn bitscan(bb: Bitboard) -> Square { - // TODO: generate private De Brujin routine - debug_assert!(bb != 0, "Can not bitscan empty bitboard"); - let magic: u64 = 0x03f79d71b4cb0a89; - let ls1b = ls1b(bb); - let index = DE_BRUJIN_SEQUENCE[(((ls1b as u128 * magic as u128) as u64) >> 58) as usize]; - Square::from(index) -} +impl BitboardFns for Bitboard { + fn print(self, title: &str) -> () { + println!("\n {}", title); + for rank in (0..8).rev() { + print!("{}|", rank + 1); + for file in 0..8 { + let index = rank * 8 + file; + print!("{}", if self >> index & 1 == 1 { "⚫" } else { ". " }); + if file == 7 { + println!(); + } + } + } + return println!(" a b c d e f g h"); + } -/// Perform bitscan and reset the *ls1b* -pub fn bitscan_and_reset(bb: &mut Bitboard) -> Square { - let square = bitscan(*bb); - *bb &= *bb - 1; // Reset ls1b - square -} + fn pop_count(mut self) -> u8 { + let mut count = 0; + while self > 0 { + count += 1; + self &= self - 1; + } + return count; + } + + + fn ls1b(self) -> Self { + if self == 0 { + return 0 + } + self & !(self - 1) + } -/// Convert bitboard into the list of squares -pub fn serialize_bitboard(mut bb: Bitboard) -> Vec<Square> { - let mut serialized = Vec::with_capacity(64); - while bb > 0 { - serialized.push(bitscan_and_reset(&mut bb)); + + fn bitscan(self) -> Square { + // TODO: generate private De Brujin routine + debug_assert!(self != 0, "Can not bitscan empty bitboard"); + let magic: u64 = 0x03f79d71b4cb0a89; + let ls1b = self.ls1b(); + let index = DE_BRUJIN_SEQUENCE[(((ls1b as u128 * magic as u128) as u64) >> 58) as usize]; + Square::from(index) + } + + fn bitscan_and_reset(&mut self) -> Square { + let square = self.bitscan(); + *self &= *self - 1; // Reset ls1b + square + } + + fn serialize(mut self) -> Vec<Square> { + let mut serialized = Vec::with_capacity(64); + while self > 0 { + serialized.push(self.bitscan_and_reset()); + } + serialized } - serialized } #[cfg(test)] @@ -90,38 +106,37 @@ mod tests { #[test] fn test_pop_count() { - assert_eq!(pop_count(127), 7); + assert_eq!(127.pop_count(), 7); } #[test] fn test_ls1b() { - assert_eq!(ls1b(38), 2); - assert_eq!(ls1b(16), 16); - assert_eq!(ls1b(20), 4); + assert_eq!(38.ls1b(), 2); + assert_eq!(16.ls1b(), 16); + assert_eq!(20.ls1b(), 4); } #[test] fn test_bitscan() { - 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)); + assert_eq!(4.bitscan(), Square::from(2)); + assert_eq!(16.bitscan(), Square::from(4)); + assert_eq!(64.bitscan(), Square::from(6)); + assert_eq!(128.bitscan(), Square::from(7)); } #[test] fn test_bitscan_with_non_single_bb() { - assert_eq!(bitscan(5), Square::from(0)); - assert_eq!(bitscan(6), Square::from(1)); - assert_eq!(bitscan(7), Square::from(0)); + assert_eq!(5.bitscan(), Square::from(0)); + assert_eq!(6.bitscan(), Square::from(1)); + assert_eq!(7.bitscan(), Square::from(0)); } #[test] fn test_serialize_bitboard() { let bb = 1 << 4 | 1 << 15 | 1 << 60; - let serialized = serialize_bitboard(bb); + let serialized = bb.serialize(); 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/engine.rs b/src/board/engine.rs index ad2b3b2..5168350 100644 --- a/src/board/engine.rs +++ b/src/board/engine.rs @@ -1,5 +1,5 @@ use std::{time::{Instant, Duration}, f32::INFINITY, cmp::Ordering}; -use crate::{bitboard::pop_count, board::*}; +use crate::board::*; use super::ttable::{NodeType, TranspositionTableItem}; @@ -171,7 +171,7 @@ impl Board { _ => panic!("Unreachable") }; - material += serialize_bitboard(*bitboard).iter().fold(0., |acc, square| { + material += bitboard.serialize().iter().fold(0., |acc, square| { acc + piece_type.static_eval() + bonus_table[ match color { Color::White => square.mirror() as usize, @@ -195,7 +195,7 @@ impl Board { for file in 0..8 { let file_mask = A_FILE << file; - let pawns_on_file = pop_count(pawns & file_mask) as f32; + let pawns_on_file = (pawns & file_mask).pop_count() as f32; // Doubled pawns (-1 because one pawn on a file is ok) result += (pawns_on_file - 1.).max(0.0); @@ -214,7 +214,7 @@ impl Board { Color::White => self.occupancy >> 8, Color::Black => self.occupancy << 8, }; - result += pop_count(pawns & blocked_mask) as f32; + result += (pawns & blocked_mask).pop_count() as f32; result } @@ -224,14 +224,14 @@ impl Board { pub fn king_tropism(&self, color: Color) -> f32 { let mut result = 0.0; - let king_square = bitscan(match color { + let king_square = match color { Color::White => self.pieces[PieceType::King as usize], Color::Black => self.pieces[PieceType::KingBlack as usize], - }); + }.bitscan(); for (piece_type, bitboard) in self.pieces_by_color(color.flip()).iter().enumerate() { if piece_type != PieceType::King as usize && piece_type != PieceType::Pawn as usize { - for square in serialize_bitboard(*bitboard) { + for square in bitboard.serialize() { let distance = (king_square.rank() as f32 - square.rank() as f32).abs() + (king_square.file() as f32 - square.file() as f32).abs(); diff --git a/src/board/mod.rs b/src/board/mod.rs index a1166d6..1533ea2 100644 --- a/src/board/mod.rs +++ b/src/board/mod.rs @@ -1,7 +1,7 @@ use std::io::{stdin, stdout, Write}; use rand::{rngs::StdRng,SeedableRng,Rng}; -use crate::{bitboard::{Bitboard, serialize_bitboard, bitscan, pop_count}, moves::{Move, MoveKind}, attacks::Attacks, square::Square}; +use crate::{bitboard::{Bitboard, BitboardFns}, moves::{Move, MoveKind}, attacks::Attacks, square::Square}; use self::ttable::{TranspositionTable, TTABLE_SIZE}; mod engine; @@ -210,7 +210,7 @@ impl Board { } for (piece_id, bitboard) in self.pieces.iter().enumerate() { - for square in serialize_bitboard(*bitboard) { + for square in bitboard.serialize() { self.hash ^= self.zobrist_seed[piece_id * 64 + square as usize]; } } @@ -267,7 +267,7 @@ impl Board { for (piece_id, piece) in player_pieces.iter().enumerate() { match PieceType::from(piece_id) { PieceType::Pawn => { - for source in serialize_bitboard(*piece) { + for source in piece.serialize() { let ep_bitboard = match self.ep_target { Some(square) => { let rank = square.rank(); @@ -279,7 +279,7 @@ impl Board { } None => 0, }; - for target in serialize_bitboard(self.attacks.pawn[color as usize][source as usize] & capture_targets) { + for target in (self.attacks.pawn[color as usize][source as usize] & capture_targets).serialize() { moves.push(Move { source, target, kind: MoveKind::Capture }); if target.rank() == 7 { for promo_type in [PieceType::Bishop, PieceType::Knight, PieceType::Rook, PieceType::Queen] { @@ -291,10 +291,10 @@ impl Board { } } }; - for target in serialize_bitboard(self.attacks.pawn[color as usize][source as usize] & ep_bitboard) { + for target in (self.attacks.pawn[color as usize][source as usize] & ep_bitboard).serialize() { moves.push(Move { source, target, kind: MoveKind::EnPassant }); } - for target in serialize_bitboard(self.attacks.pawn_pushes[color as usize][source as usize] & empty) { + for target in (self.attacks.pawn_pushes[color as usize][source as usize] & empty).serialize() { moves.push(Move { source, target, kind: MoveKind::Quiet }); if target.rank() == 7 { for promo_type in [PieceType::Bishop, PieceType::Knight, PieceType::Rook, PieceType::Queen] { @@ -314,18 +314,18 @@ impl Board { Color::White => empty >> 8, Color::Black => empty << 8, }; - for source in serialize_bitboard(*piece & able_to_double_push_mask) { - for target in serialize_bitboard(self.attacks.pawn_double_pushes[color as usize][source as usize] & empty) { + for source in (*piece & able_to_double_push_mask).serialize() { + for target in (self.attacks.pawn_double_pushes[color as usize][source as usize] & empty).serialize() { moves.push(Move { source, target, kind: MoveKind::DoublePush }); }; } } PieceType::King => { - for source in serialize_bitboard(*piece) { - for target in serialize_bitboard(self.attacks.king[source as usize] & empty) { + for source in piece.serialize() { + for target in (self.attacks.king[source as usize] & empty).serialize() { moves.push(Move { source, target, kind: MoveKind::Quiet }); }; - for target in serialize_bitboard(self.attacks.king[source as usize] & capture_targets) { + for target in (self.attacks.king[source as usize] & capture_targets).serialize() { moves.push(Move { source, target, kind: MoveKind::Capture }); }; @@ -335,7 +335,7 @@ impl Board { Color::Black => Square::E8, }; if *piece == king_home_position.to_bitboard() { - for rook_square in serialize_bitboard(player_pieces[PieceType::Rook as usize]) + for rook_square in (player_pieces[PieceType::Rook as usize]).serialize() .iter() .filter(|rook_square| rook_square.rank() == king_home_position.rank()) { @@ -390,43 +390,43 @@ impl Board { } } PieceType::Knight => { - for source in serialize_bitboard(*piece) { - for target in serialize_bitboard(self.attacks.knight[source as usize] & empty) { + for source in piece.serialize() { + for target in (self.attacks.knight[source as usize] & empty).serialize() { moves.push(Move { source, target, kind: MoveKind::Quiet }); }; - for target in serialize_bitboard(self.attacks.knight[source as usize] & capture_targets) { + for target in (self.attacks.knight[source as usize] & capture_targets).serialize() { moves.push(Move { source, target, kind: MoveKind::Capture }); }; } } PieceType::Bishop => { - for source in serialize_bitboard(*piece) { - for target in serialize_bitboard(self.attacks.bishop(self.occupancy, source) & empty) { + for source in piece.serialize() { + for target in (self.attacks.bishop(self.occupancy, source) & empty).serialize() { moves.push(Move { source, target, kind: MoveKind::Quiet }); }; - for target in serialize_bitboard(self.attacks.bishop(self.occupancy, source) & capture_targets) { + for target in (self.attacks.bishop(self.occupancy, source) & capture_targets).serialize() { moves.push(Move { source, target, kind: MoveKind::Capture }); }; } } PieceType::Rook => { - for source in serialize_bitboard(*piece) { - for target in serialize_bitboard(self.attacks.rook(self.occupancy, source) & empty) { + for source in piece.serialize() { + for target in (self.attacks.rook(self.occupancy, source) & empty).serialize() { moves.push(Move { source, target, kind: MoveKind::Quiet }); }; } - for source in serialize_bitboard(*piece) { - for target in serialize_bitboard(self.attacks.rook(self.occupancy, source) & capture_targets) { + for source in piece.serialize() { + for target in (self.attacks.rook(self.occupancy, source) & capture_targets).serialize() { moves.push(Move { source, target, kind: MoveKind::Capture }); }; } } PieceType::Queen => { - for source in serialize_bitboard(*piece) { - for target in serialize_bitboard(self.attacks.queen(self.occupancy, source) & empty) { + for source in piece.serialize() { + for target in (self.attacks.queen(self.occupancy, source) & empty).serialize() { moves.push(Move { source, target, kind: MoveKind::Quiet }); }; - for target in serialize_bitboard(self.attacks.queen(self.occupancy, source) & capture_targets) { + for target in (self.attacks.queen(self.occupancy, source) & capture_targets).serialize() { moves.push(Move { source, target, kind: MoveKind::Capture }); }; } @@ -449,7 +449,7 @@ impl Board { Color::White => self.pieces[PieceType::PawnBlack as usize], }; - let pawn_attacked_squares = serialize_bitboard(opponent_pawns).iter().fold(0u64, |acc, square| { + let pawn_attacked_squares = opponent_pawns.serialize().iter().fold(0u64, |acc, square| { acc | self.attacks.pawn[color.flip() as usize][*square as usize] }); @@ -459,7 +459,7 @@ impl Board { for (piece_type, piece) in player_pieces.iter().enumerate() { match PieceType::from(piece_type) { PieceType::Pawn => { - for source in serialize_bitboard(*piece) { + for source in piece.serialize() { let ep_bitboard = match self.ep_target { Some(square) => { let rank = square.rank(); @@ -471,20 +471,20 @@ impl Board { } None => 0, }; - mobility += pop_count(self.attacks.pawn[color as usize][source as usize] & (opponent_occupancy | ep_bitboard)) as f32; - mobility += pop_count(self.attacks.pawn_pushes[color as usize][source as usize] & empty) as f32; + mobility += (self.attacks.pawn[color as usize][source as usize] & (opponent_occupancy | ep_bitboard)).pop_count() as f32; + mobility += (self.attacks.pawn_pushes[color as usize][source as usize] & empty).pop_count() as f32; } let able_to_double_push_mask = match color { Color::White => empty >> 8, Color::Black => empty << 8, }; - for source in serialize_bitboard(*piece & able_to_double_push_mask) { - mobility += pop_count(self.attacks.pawn_double_pushes[color as usize][source as usize] & empty) as f32; + for source in (*piece & able_to_double_push_mask).serialize() { + mobility += (self.attacks.pawn_double_pushes[color as usize][source as usize] & empty).pop_count() as f32; } } PieceType::King => { - for source in serialize_bitboard(*piece) { - mobility += pop_count(self.attacks.king[source as usize] & (empty | opponent_occupancy)) as f32; + for source in piece.serialize() { + mobility += (self.attacks.king[source as usize] & (empty | opponent_occupancy)).pop_count() as f32; // Castling let king_home_position = match color { @@ -492,7 +492,8 @@ impl Board { Color::Black => Square::E8, }; if *piece == king_home_position.to_bitboard() { - for rook_square in serialize_bitboard(player_pieces[PieceType::Rook as usize]) + for rook_square in player_pieces[PieceType::Rook as usize] + .serialize() .iter() .filter(|rook_square| rook_square.rank() == king_home_position.rank()) { @@ -530,18 +531,18 @@ impl Board { } } PieceType::Knight => { - for source in serialize_bitboard(*piece) { - mobility += pop_count(self.attacks.knight[source as usize] & (empty | opponent_occupancy)) as f32; + for source in piece.serialize() { + mobility += (self.attacks.knight[source as usize] & (empty | opponent_occupancy)).pop_count() as f32; } } PieceType::Bishop => { - for source in serialize_bitboard(*piece) { - mobility += pop_count(self.attacks.bishop(self.occupancy, source) & (empty | opponent_occupancy)) as f32; + for source in piece.serialize() { + mobility += (self.attacks.bishop(self.occupancy, source) & (empty | opponent_occupancy)).pop_count() as f32; } } PieceType::Rook => { - for source in serialize_bitboard(*piece) { - mobility += pop_count(self.attacks.rook(self.occupancy, source) & (empty | opponent_occupancy)) as f32; + for source in piece.serialize() { + mobility += (self.attacks.rook(self.occupancy, source) & (empty | opponent_occupancy)).pop_count() as f32; } } PieceType::Queen => { @@ -836,7 +837,7 @@ impl Board { Color::White => self.pieces[PieceType::King as usize], Color::Black => self.pieces[PieceType::KingBlack as usize], }; - let square = bitscan(king_bb); + let square = king_bb.bitscan(); self.is_square_attacked(square, color.flip()) } } @@ -868,7 +869,7 @@ impl Color { #[cfg(test)] mod tests { use super::*; - use crate::{bitboard::{pop_count, bitscan, print}, square::Square}; + use crate::{bitboard::BitboardFns, square::Square}; #[test] fn square_enum() { @@ -882,29 +883,29 @@ mod tests { let board = Board::new(); board.print(); - print(board.empty(), "Empty squares"); - - assert_eq!(pop_count(board.pieces[PieceType::Pawn as usize]), 8); - assert_eq!(pop_count(board.pieces[PieceType::Knight as usize]), 2); - assert_eq!(pop_count(board.pieces[PieceType::Bishop as usize]), 2); - assert_eq!(pop_count(board.pieces[PieceType::Rook as usize]), 2); - assert_eq!(pop_count(board.pieces[PieceType::Queen as usize]), 1); - assert_eq!(pop_count(board.pieces[PieceType::King as usize]), 1); - - assert_eq!(pop_count(board.pieces[PieceType::PawnBlack as usize]), 8); - assert_eq!(pop_count(board.pieces[PieceType::KnightBlack as usize]), 2); - assert_eq!(pop_count(board.pieces[PieceType::BishopBlack as usize]), 2); - assert_eq!(pop_count(board.pieces[PieceType::RookBlack as usize]), 2); - 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); - 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); - assert_eq!(pop_count(board.color_occupancy(Color::White)), 16); - assert_eq!(pop_count(board.color_occupancy(Color::Black)), 16); + board.empty().print("Empty squares"); + + assert_eq!(board.pieces[PieceType::Pawn as usize].pop_count(), 8); + assert_eq!(board.pieces[PieceType::Knight as usize].pop_count(), 2); + assert_eq!(board.pieces[PieceType::Bishop as usize].pop_count(), 2); + assert_eq!(board.pieces[PieceType::Rook as usize].pop_count(), 2); + assert_eq!(board.pieces[PieceType::Queen as usize].pop_count(), 1); + assert_eq!(board.pieces[PieceType::King as usize].pop_count(), 1); + + assert_eq!(board.pieces[PieceType::PawnBlack as usize].pop_count(), 8); + assert_eq!(board.pieces[PieceType::KnightBlack as usize].pop_count(), 2); + assert_eq!(board.pieces[PieceType::BishopBlack as usize].pop_count(), 2); + assert_eq!(board.pieces[PieceType::RookBlack as usize].pop_count(), 2); + assert_eq!(board.pieces[PieceType::QueenBlack as usize].pop_count(), 1); + assert_eq!(board.pieces[PieceType::KingBlack as usize].pop_count(), 1); + + assert_eq!(board.pieces[PieceType::King as usize].bitscan(), Square::E1); + assert_eq!(board.pieces[PieceType::QueenBlack as usize].bitscan(), Square::D8); + + assert_eq!(board.occupancy.pop_count(), 32); + assert_eq!(board.empty().pop_count(), 32); + assert_eq!(board.color_occupancy(Color::White).pop_count(), 16); + assert_eq!(board.color_occupancy(Color::Black).pop_count(), 16); } #[test] diff --git a/src/moves.rs b/src/moves.rs index 57103d0..58fb979 100644 --- a/src/moves.rs +++ b/src/moves.rs @@ -1,4 +1,4 @@ -use crate::{square::Square, bitboard::print, board::PieceType}; +use crate::{square::Square, bitboard::BitboardFns, board::PieceType}; #[derive(Debug, Clone, PartialEq, Eq, Copy)] pub enum MoveKind { @@ -20,7 +20,7 @@ pub struct Move { impl Move { pub fn print(&self) { let bb = self.source.to_bitboard() | self.target.to_bitboard(); - print(bb, format!("{:?}", self).as_str()); + bb.print(format!("{:?}", self).as_str()); } /// Tactical move is a move that changes material score |