|
4 | 4 | * Created Date: Thursday, November 21st 2024 |
5 | 5 | * Author: Paul Tsouchlos (DeveloperPaul123) ([email protected]) |
6 | 6 | * ----- |
7 | | - * Last Modified: Wed Dec 18 2024 |
| 7 | + * Last Modified: Tue Mar 25 2025 |
8 | 8 | * ----- |
9 | 9 | * Copyright (c) 2024 Paul Tsouchlos (DeveloperPaul123) |
10 | 10 | * GNU General Public License v3.0 or later |
@@ -33,6 +33,7 @@ use crate::{ |
33 | 33 | score::{LargeScoreType, Score, ScoreType}, |
34 | 34 | traits::Eval, |
35 | 35 | ttable::{self, TranspositionTableEntry}, |
| 36 | + tuneable::{MAX_RFP_DEPTH, RFP_MARGIN}, |
36 | 37 | }; |
37 | 38 | use ttable::TranspositionTable; |
38 | 39 |
|
@@ -345,6 +346,11 @@ impl<'a> Search<'a> { |
345 | 346 | } |
346 | 347 | } |
347 | 348 |
|
| 349 | + // can we prune the current node with something other than TT? |
| 350 | + if let Some(score) = self.pruned_score(board, depth, ply, alpha, beta) { |
| 351 | + return score; |
| 352 | + } |
| 353 | + |
348 | 354 | // get all legal moves |
349 | 355 | let mut move_list = MoveList::new(); |
350 | 356 | self.move_gen.generate_legal_moves(board, &mut move_list); |
@@ -462,6 +468,43 @@ impl<'a> Search<'a> { |
462 | 468 | best_score |
463 | 469 | } |
464 | 470 |
|
| 471 | + /// Checks to see if the current node can be pruned. If it can, returns the score. Otherwise returns None. |
| 472 | + /// |
| 473 | + /// # Arguments |
| 474 | + /// |
| 475 | + /// - `board` - The current board state. |
| 476 | + /// - `depth` - The current depth. |
| 477 | + /// - `beta` - The current beta value. |
| 478 | + /// |
| 479 | + /// # Returns |
| 480 | + /// |
| 481 | + /// The score of the position if it can be pruned, otherwise None. |
| 482 | + fn pruned_score( |
| 483 | + &self, |
| 484 | + board: &Board, |
| 485 | + depth: i16, |
| 486 | + ply: i16, |
| 487 | + alpha: Score, |
| 488 | + beta: Score, |
| 489 | + ) -> Option<Score> { |
| 490 | + let is_pv_node = ply == 0 || beta - alpha > Score::new(1); |
| 491 | + |
| 492 | + // no pruning if we are in check or if we are in a PV node |
| 493 | + if board.is_in_check(&self.move_gen) || is_pv_node { |
| 494 | + return None; |
| 495 | + } |
| 496 | + |
| 497 | + let static_eval = self.eval.eval(board); |
| 498 | + // Reverse futility pruning |
| 499 | + // https://cosmo.tardis.ac/files/2023-02-20-viri-wiki.html |
| 500 | + // https://www.chessprogramming.org/Reverse_Futility_Pruning |
| 501 | + // If the static evaluation is very high and beats beta by a depth-dependent margin, we can prune the move. |
| 502 | + if depth <= MAX_RFP_DEPTH && static_eval - RFP_MARGIN * depth > beta { |
| 503 | + return Some(static_eval); |
| 504 | + } |
| 505 | + None |
| 506 | + } |
| 507 | + |
465 | 508 | /// Implements [quiescence search](https://www.chessprogramming.org/Quiescence_Search). |
466 | 509 | /// We use this to avoid the horizon effect. The idea is to evaluate quiet moves where there are no tactical moves to make. |
467 | 510 | /// |
|
0 commit comments