aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/attacks.rs52
-rw-r--r--src/bitboard.rs8
-rw-r--r--src/board/io.rs2
-rw-r--r--src/board/mod.rs59
-rw-r--r--src/board/zobrist.rs25
-rw-r--r--src/grossmeister/mod.rs2
-rw-r--r--src/grossmeister/move_generation.rs23
-rw-r--r--src/grossmeister/search.rs73
-rw-r--r--src/main.rs6
-rw-r--r--src/moves.rs6
10 files changed, 123 insertions, 133 deletions
diff --git a/src/attacks.rs b/src/attacks.rs
index d0f2ddd..f666bae 100644
--- a/src/attacks.rs
+++ b/src/attacks.rs
@@ -49,6 +49,12 @@ pub struct Attacks {
pub ray_attacks: [AttackTable; 8],
}
+impl Default for Attacks {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
#[allow(unused)]
impl Attacks {
pub fn new() -> Self {
@@ -97,34 +103,36 @@ impl Attacks {
fn precompute_knight_attacks() -> AttackTable {
let mut attacks = [0; 64];
- for index in 0..64 {
- let square = 1u64 << index;
- attacks[index] =
- ((square & NOT_A_FILE & NOT_B_FILE) << 6) |
- ((square & NOT_G_FILE & NOT_H_FILE) << 10) |
- ((square & NOT_A_FILE) << 15) |
- ((square & NOT_H_FILE) << 17) |
- ((square & NOT_G_FILE & NOT_H_FILE) >> 6) |
- ((square & NOT_A_FILE & NOT_B_FILE) >> 10) |
- ((square & NOT_H_FILE) >> 15) |
- ((square & NOT_A_FILE) >> 17);
+
+ for (index, bitboard) in attacks.iter_mut().enumerate() {
+ let square_bb = Square::from(index as u8).to_bitboard();
+ *bitboard =
+ ((square_bb & NOT_A_FILE & NOT_B_FILE) << 6) |
+ ((square_bb & NOT_G_FILE & NOT_H_FILE) << 10) |
+ ((square_bb & NOT_A_FILE) << 15) |
+ ((square_bb & NOT_H_FILE) << 17) |
+ ((square_bb & NOT_G_FILE & NOT_H_FILE) >> 6) |
+ ((square_bb & NOT_A_FILE & NOT_B_FILE) >> 10) |
+ ((square_bb & NOT_H_FILE) >> 15) |
+ ((square_bb & NOT_A_FILE) >> 17);
}
attacks
}
fn precompute_king_attacks() -> AttackTable {
let mut attacks = [0; 64];
- for index in 0..64 {
- let square = 1u64 << index;
- attacks[index] =
- ((square & NOT_A_FILE) >> 1) |
- ((square & NOT_A_FILE) << 7) |
- ((square & NOT_A_FILE) >> 9) |
- ((square & NOT_H_FILE) << 1) |
- ((square & NOT_H_FILE) >> 7) |
- ((square & NOT_H_FILE) << 9) |
- (square << 8) |
- (square >> 8);
+
+ for (index, bitboard) in attacks.iter_mut().enumerate() {
+ let square_bb = Square::from(index as u8).to_bitboard();
+ *bitboard =
+ ((square_bb & NOT_A_FILE) >> 1) |
+ ((square_bb & NOT_A_FILE) << 7) |
+ ((square_bb & NOT_A_FILE) >> 9) |
+ ((square_bb & NOT_H_FILE) << 1) |
+ ((square_bb & NOT_H_FILE) >> 7) |
+ ((square_bb & NOT_H_FILE) << 9) |
+ (square_bb << 8) |
+ (square_bb >> 8);
}
attacks
}
diff --git a/src/bitboard.rs b/src/bitboard.rs
index ad21664..4fb5b30 100644
--- a/src/bitboard.rs
+++ b/src/bitboard.rs
@@ -5,7 +5,7 @@ pub type Bitboard = u64;
pub trait BitboardFns {
/// Print bitboard on the screen
- fn print(self, title: &str) -> ();
+ fn print(self, title: &str);
/// Return bitboard cardinality, aka number of elements in the set
fn pop_count(self) -> u8;
@@ -43,7 +43,7 @@ const DE_BRUJIN_SEQUENCE: [u8; 64] = [
];
impl BitboardFns for Bitboard {
- fn print(self, title: &str) -> () {
+ fn print(self, title: &str) {
println!("\n {}", title);
for rank in (0..8).rev() {
print!("{}|", rank + 1);
@@ -55,7 +55,7 @@ impl BitboardFns for Bitboard {
}
}
}
- return println!(" a b c d e f g h");
+ println!(" a b c d e f g h");
}
fn pop_count(mut self) -> u8 {
@@ -64,7 +64,7 @@ impl BitboardFns for Bitboard {
count += 1;
self &= self - 1;
}
- return count;
+ count
}
diff --git a/src/board/io.rs b/src/board/io.rs
index ca75c8c..67aa096 100644
--- a/src/board/io.rs
+++ b/src/board/io.rs
@@ -8,7 +8,7 @@ const PIECE_CHARS: [&str; 12] = [
/// Input/Output operations with Board
pub trait IO {
- fn print(&self) -> ();
+ fn print(&self);
#[allow(non_snake_case)]
fn from_FEN(fen: String) -> Self;
diff --git a/src/board/mod.rs b/src/board/mod.rs
index 579488b..aab3136 100644
--- a/src/board/mod.rs
+++ b/src/board/mod.rs
@@ -32,6 +32,13 @@ pub struct Board {
attacks: Attacks,
}
+impl Default for Board {
+ fn default() -> Self {
+ Board::new()
+ }
+
+}
+
impl Board {
pub fn new() -> Self {
let default_fen = String::from("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
@@ -68,7 +75,7 @@ impl Board {
.iter()
.enumerate()
.find(|(_, bitboard)| *bitboard & square_bb > 0)
- .and_then(|(pt, _)| Some(Piece::from(pt)))
+ .map(|(pt, _)| Piece::from(pt))
}
pub fn ep_bitboard(&self) -> Bitboard {
@@ -143,7 +150,7 @@ impl Board {
self.zobrist_toggle_piece(source_piece, mov.target);
}
}
- Piece::from(source_piece)
+ source_piece
},
None => {
self.print();
@@ -290,22 +297,19 @@ impl Board {
}
// Return captured piece to target square
- match captured_piece {
- Some(target_piece) => {
- match mov.kind {
- // Return pawn captured by En Passant pawn if needed
- MoveKind::EnPassant => {
- let original_dead_pawn_bb = Square::from_coords(mov.source.rank(), mov.target.file()).to_bitboard();
- self.piece_sets[target_piece as usize] |= original_dead_pawn_bb;
- self.occupancy |= original_dead_pawn_bb;
- },
- _ => {
- self.piece_sets[target_piece as usize] |= move_target_bb;
- self.occupancy |= move_target_bb;
- },
- }
- },
- None => {}
+ if let Some(target_piece) = captured_piece {
+ match mov.kind {
+ // Return pawn captured by En Passant pawn if needed
+ MoveKind::EnPassant => {
+ let original_dead_pawn_bb = Square::from_coords(mov.source.rank(), mov.target.file()).to_bitboard();
+ self.piece_sets[target_piece as usize] |= original_dead_pawn_bb;
+ self.occupancy |= original_dead_pawn_bb;
+ },
+ _ => {
+ self.piece_sets[target_piece as usize] |= move_target_bb;
+ self.occupancy |= move_target_bb;
+ },
+ }
}
@@ -381,16 +385,15 @@ mod tests {
fn make_move() {
let fen = String::from("q1b2k2/5p1p/4p1pb/pPPp4/3N4/3nPB2/P2QKnR1/1R6 w - - 0 25");
let mut board = Board::from_FEN(fen);
- let initial_board = board.clone();
+ let initial_board = board;
board.print();
let black_move = Move { source: Square::F7, target: Square::F5, kind: MoveKind::Quiet };
println!("\n{:?}", black_move);
- match board.make_move(black_move) {
- Some(..) => panic!("No piece should be captured"),
- None => {},
- };
+ if let Some(..) = board.make_move(black_move) {
+ panic!("No piece should be captured");
+ }
board.print();
@@ -423,7 +426,7 @@ mod tests {
fn unmake_move() {
let fen = String::from("q1b2k2/5p1p/4p1pb/pPPp4/3N4/3nPB2/P2QKnR1/1R6 w - - 0 25");
let mut board = Board::from_FEN(fen);
- let initial_board = board.clone();
+ let initial_board = board;
let mov = Move { source: Square::D2, target: Square::A5, kind: MoveKind::Capture };
@@ -442,9 +445,9 @@ mod tests {
fn is_square_attacked() {
let board = Board::new();
- assert_eq!(board.is_square_attacked(Square::E2, Color::White), true);
- assert_eq!(board.is_square_attacked(Square::E2, Color::Black), false);
- assert_eq!(board.is_square_attacked(Square::E4, Color::White), false);
- assert_eq!(board.is_square_attacked(Square::B6, Color::Black), true);
+ assert!(board.is_square_attacked(Square::E2, Color::White));
+ assert!(!board.is_square_attacked(Square::E2, Color::Black));
+ assert!(!board.is_square_attacked(Square::E4, Color::White));
+ assert!(board.is_square_attacked(Square::B6, Color::Black));
}
}
diff --git a/src/board/zobrist.rs b/src/board/zobrist.rs
index 5286a73..88a2fb7 100644
--- a/src/board/zobrist.rs
+++ b/src/board/zobrist.rs
@@ -18,12 +18,12 @@ pub trait Zobrist {
/// Compute store zobrist hash of the current position
/// https://www.chessprogramming.org/Zobrist_Hashing
- fn compute_hash(&mut self) -> ();
+ fn compute_hash(&mut self);
- fn zobrist_toggle_piece(&mut self, piece_type: Piece, square: Square) -> ();
- fn zobrist_toggle_castling_right(&mut self, color: Color, side: CastlingSide) -> ();
- fn zobrist_toggle_ep_square(&mut self, ep_square: Square) -> ();
- fn zobrist_toggle_color(&mut self) -> ();
+ fn zobrist_toggle_piece(&mut self, piece_type: Piece, square: Square);
+ fn zobrist_toggle_castling_right(&mut self, color: Color, side: CastlingSide);
+ fn zobrist_toggle_ep_square(&mut self, ep_square: Square);
+ fn zobrist_toggle_color(&mut self);
}
impl Zobrist for Board {
@@ -32,7 +32,7 @@ impl Zobrist for Board {
[(); ZOBRIST_SEED_SIZE].map(|_| rng.gen())
}
- fn compute_hash(&mut self) -> () {
+ fn compute_hash(&mut self) {
self.hash = 0;
for piece_id in 0..self.piece_sets.len() {
@@ -48,9 +48,8 @@ impl Zobrist for Board {
}
}
- match self.ep_target {
- Some(square) => self.zobrist_toggle_ep_square(square),
- None => {},
+ if let Some(square) = self.ep_target {
+ self.zobrist_toggle_ep_square(square);
}
if self.color() == Color::Black {
@@ -58,19 +57,19 @@ impl Zobrist for Board {
}
}
- fn zobrist_toggle_piece(&mut self, piece_type: Piece, square: Square) -> () {
+ fn zobrist_toggle_piece(&mut self, piece_type: Piece, square: Square) {
self.hash ^= self.zobrist_seed[piece_type as usize * TOTAL_SQUARES + square as usize];
}
- fn zobrist_toggle_castling_right(&mut self, color: Color, side: CastlingSide) -> () {
+ fn zobrist_toggle_castling_right(&mut self, color: Color, side: CastlingSide) {
self.hash ^= self.zobrist_seed[(TOTAL_PIECES * TOTAL_SQUARES) + color as usize * 2 + side as usize];
}
- fn zobrist_toggle_ep_square(&mut self, ep_square: Square) -> () {
+ fn zobrist_toggle_ep_square(&mut self, ep_square: Square) {
self.hash ^= self.zobrist_seed[(TOTAL_PIECES * TOTAL_SQUARES + TOTAL_CASTLING_RIGHTS) + ep_square.file() as usize];
}
- fn zobrist_toggle_color(&mut self) -> () {
+ fn zobrist_toggle_color(&mut self) {
self.hash ^= self.zobrist_seed[ZOBRIST_SEED_SIZE - 1];
}
}
diff --git a/src/grossmeister/mod.rs b/src/grossmeister/mod.rs
index b7c134d..6ed5f17 100644
--- a/src/grossmeister/mod.rs
+++ b/src/grossmeister/mod.rs
@@ -26,7 +26,7 @@ pub struct Grossmeister {
impl Grossmeister {
pub fn new(board: Board) -> Self {
- return Self {
+ Self {
board,
attacks: Attacks::new(),
transposition_table: vec![None; TTABLE_SIZE as usize],
diff --git a/src/grossmeister/move_generation.rs b/src/grossmeister/move_generation.rs
index 25d92c7..c3acc91 100644
--- a/src/grossmeister/move_generation.rs
+++ b/src/grossmeister/move_generation.rs
@@ -153,7 +153,7 @@ impl Grossmeister {
}
}
}
- return moves
+ moves
}
/// Evaluate move for move ordering, prioritizing efficient captures
@@ -195,25 +195,20 @@ impl Grossmeister {
let mut ordered_moves: Vec<Move> = moves_with_eval.iter().map(|(m, _)| *m).collect();
// Insert killer moves after winning captures
- let equal_capture_index = match moves_with_eval.iter().position(|(m, eval)| m.is_tactical() && *eval == 0.0) {
- Some(x) => x,
- None => 0,
- };
+ let equal_capture_index = moves_with_eval
+ .iter()
+ .position(|(m, eval)| m.is_tactical() && *eval == 0.0)
+ .unwrap_or(0);
for killer in killer_moves {
- match ordered_moves.iter().position(|m| *m == killer) {
- Some(index) => {
+ if let Some(index) = ordered_moves.iter().position(|m| *m == killer) {
let mov = ordered_moves.remove(index);
ordered_moves.insert(equal_capture_index, mov);
- }
- None => {}
- };
-
+ }
}
- match self.transposition() {
- Some(transposition) => ordered_moves.insert(0, transposition.mov),
- None => {},
+ if let Some(transposition) = self.transposition() {
+ ordered_moves.insert(0, transposition.mov);
}
ordered_moves
diff --git a/src/grossmeister/search.rs b/src/grossmeister/search.rs
index 57ce672..3efa9f8 100644
--- a/src/grossmeister/search.rs
+++ b/src/grossmeister/search.rs
@@ -21,30 +21,27 @@ impl Grossmeister {
let mut killer_moves = Vec::new();
let color = self.board.color();
- match self.transposition() {
- Some(transposition) => {
- if transposition.depth == depth_left {
- match transposition.node_type {
- NodeType::PV => { // PV-nodes have exact score
+ if let Some(transposition) = self.transposition() {
+ if transposition.depth == depth_left {
+ match transposition.node_type {
+ NodeType::PV => { // PV-nodes have exact score
+ principal_variation.push(transposition.mov);
+ return (transposition.score, principal_variation);
+ }
+ NodeType::Cut => {
+ if transposition.score >= beta {
principal_variation.push(transposition.mov);
- return (transposition.score, principal_variation);
- }
- NodeType::Cut => {
- if transposition.score >= beta {
- principal_variation.push(transposition.mov);
- return (beta, principal_variation);
- }
+ return (beta, principal_variation);
}
- NodeType::All => {
- if transposition.score <= alpha {
- principal_variation.push(transposition.mov);
- return (alpha, principal_variation);
- }
+ }
+ NodeType::All => {
+ if transposition.score <= alpha {
+ principal_variation.push(transposition.mov);
+ return (alpha, principal_variation);
}
}
}
}
- None => {},
}
if depth_left == 0 {
@@ -57,9 +54,9 @@ impl Grossmeister {
let mut should_pv_search = true;
let mut legal_move_found = false;
for mov in moves {
- let ep_target_before = self.board.ep_target.clone();
- let castling_rights_before = self.board.castling_rights.clone();
- let hash_before = self.board.hash.clone();
+ let ep_target_before = self.board.ep_target;
+ let castling_rights_before = self.board.castling_rights;
+ let hash_before = self.board.hash;
let captured_piece = self.board.make_move(mov);
if !self.board.is_king_in_check(color) {
@@ -135,10 +132,8 @@ impl Grossmeister {
}
}
- if !legal_move_found {
- if self.board.is_king_in_check(color) {
- return (-VALUE_WIN, principal_variation);
- }
+ if !legal_move_found && self.board.is_king_in_check(color) {
+ return (-VALUE_WIN, principal_variation);
}
(alpha, principal_variation)
@@ -161,18 +156,14 @@ impl Grossmeister {
}
// If we are not in check, we can only search tactical moves
- moves = moves
- .iter()
- .filter(|m| m.is_tactical())
- .map(|m| *m)
- .collect()
+ moves.retain(|m| m.is_tactical())
}
let mut legal_move_found = false;
for mov in moves {
- let ep_target_before = self.board.ep_target.clone();
- let castling_rights_before = self.board.castling_rights.clone();
- let hash_before = self.board.hash.clone();
+ let ep_target_before = self.board.ep_target;
+ let castling_rights_before = self.board.castling_rights;
+ let hash_before = self.board.hash;
let captured_piece = self.board.make_move(mov);
if !self.board.is_king_in_check(color) {
@@ -191,10 +182,8 @@ impl Grossmeister {
}
}
- if !legal_move_found {
- if self.board.is_king_in_check(color) {
- return -VALUE_WIN
- }
+ if !legal_move_found && self.board.is_king_in_check(color) {
+ return -VALUE_WIN
}
alpha
@@ -252,7 +241,7 @@ impl Grossmeister {
continue;
}
- if search_result.1.len() > 0 {
+ if !search_result.1.is_empty() {
depth += 1;
gradual_widening_counter = 0;
alpha = search_result.0 - window_size;
@@ -265,7 +254,7 @@ impl Grossmeister {
}
match result {
- Some(r) => return r,
+ Some(r) => r,
None => panic!("Could not find a move in time"),
}
}
@@ -287,9 +276,9 @@ impl Grossmeister {
}
for mov in moves {
- let ep_target_before = self.board.ep_target.clone();
- let castling_rights_before = self.board.castling_rights.clone();
- let hash_before = self.board.hash.clone();
+ let ep_target_before = self.board.ep_target;
+ let castling_rights_before = self.board.castling_rights;
+ let hash_before = self.board.hash;
let captured_piece = self.board.make_move(mov);
// King can not be in check after our own move
if !self.board.is_king_in_check(color) {
diff --git a/src/main.rs b/src/main.rs
index bb244ca..e7633bc 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -43,9 +43,9 @@ fn computer_move(gm: &mut Grossmeister, time_left: &mut Duration) {
// Ponder for some time
println!("Pondering, assume opponent move from PV: {:?}", pv[1]);
- let ep_target_before = gm.board.ep_target.clone();
- let castling_rights_before = gm.board.castling_rights.clone();
- let hash_before = gm.board.hash.clone();
+ let ep_target_before = gm.board.ep_target;
+ let castling_rights_before = gm.board.castling_rights;
+ let hash_before = gm.board.hash;
let captured_piece = gm.board.make_move(pv[1]);
gm.iterative_deepening(max_depth, Duration::from_secs(3), false);
gm.board.unmake_move(pv[1], captured_piece, ep_target_before, castling_rights_before, hash_before);
diff --git a/src/moves.rs b/src/moves.rs
index 858fe43..e27d74c 100644
--- a/src/moves.rs
+++ b/src/moves.rs
@@ -25,10 +25,6 @@ impl Move {
/// Tactical move is a move that changes material score
pub fn is_tactical(&self) -> bool {
- match self.kind {
- MoveKind::Capture => true,
- MoveKind::EnPassant => true,
- _ => false,
- }
+ matches!(self.kind, MoveKind::Capture | MoveKind::EnPassant)
}
}