Skip to content

Commit 279795e

Browse files
committed
Added Mate Extension + Fixed ply calculation
1 parent 990f2f5 commit 279795e

File tree

1 file changed

+40
-67
lines changed

1 file changed

+40
-67
lines changed

src/search/search_master.rs

+40-67
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ pub struct Engine {
1818
pub my_past_positions: Vec<u64>,
1919
pub nodes: u64,
2020
pub searching_depth: i32,
21-
pv: [[Option<Move>; 100]; 100],
2221
movegen: MoveGen,
2322
tt: TT
2423
}
@@ -31,7 +30,6 @@ impl Engine {
3130
my_past_positions: Vec::with_capacity(64),
3231
searching_depth: 0,
3332
nodes: 0,
34-
pv: [[None; 100]; 100],
3533
movegen: MoveGen::new(),
3634
tt: TT::new()
3735
}
@@ -67,9 +65,6 @@ impl Engine {
6765

6866
let board = &mut self.board.clone();
6967

70-
//set up pv table
71-
self.pv = [[None; 100]; 100];
72-
7368
//set up multithread for search abort
7469
let search_abort = Arc::new(AtomicBool::new(false));
7570
let counter_abort = search_abort.clone();
@@ -80,7 +75,7 @@ impl Engine {
8075

8176
let mut past_positions = self.my_past_positions.clone();
8277

83-
let result = self.search(&search_abort, &stop_abort, board, self.searching_depth, -i32::MAX, i32::MAX, &mut past_positions);
78+
let result = self.search(&search_abort, &stop_abort, board, self.searching_depth, 0, -i32::MAX, i32::MAX, &mut past_positions);
8479

8580
if result != None {
8681
let (best_mv, eval) = result.unwrap();
@@ -96,33 +91,6 @@ impl Engine {
9691
nps = ((self.nodes as f32 * 1000_f32) / elapsed) as u64;
9792
}
9893

99-
//get pv
100-
let mut pv = String::new();
101-
let pv_board = &mut self.board.clone();
102-
103-
for i in 0..self.pv[0].len() {
104-
if self.pv[0][i] != None {
105-
let pv_parsed = _960_to_regular_(self.pv[0][i], pv_board);
106-
107-
pv += &(pv_parsed.clone() + " ");
108-
109-
let mut uci_mv = String::new();
110-
let pv_mv = self.pv[0][i].unwrap();
111-
112-
let from = pv_mv.from.to_string();
113-
let to = pv_mv.to.to_string();
114-
115-
uci_mv += &from;
116-
uci_mv += &to;
117-
118-
if pv_mv.promotion != None {
119-
uci_mv += &pv_mv.promotion.unwrap().to_string();
120-
}
121-
122-
pv_board.play(uci_mv.parse().unwrap());
123-
}
124-
}
125-
12694
let mut score_str = if eval.mate {
12795
let mut mate_score = if eval.score > 0 {
12896
(((Score::CHECKMATE_BASE - eval.score + 1) / 2) as f32).ceil()
@@ -135,7 +103,7 @@ impl Engine {
135103
format!("cp {}", eval.score)
136104
};
137105

138-
println!("info depth {} time {} score {} nodes {} nps {} pv {}", self.searching_depth, elapsed as u64, score_str, self.nodes, nps, pv.trim());
106+
println!("info depth {} time {} score {} nodes {} nps {} pv {}", self.searching_depth, elapsed as u64, score_str, self.nodes, nps, self.get_pv(board, self.searching_depth, 0));
139107
} else {
140108
break;
141109
}
@@ -147,6 +115,28 @@ impl Engine {
147115
_960_to_regular_(best_move, &self.board)
148116
}
149117

118+
//fish PV from TT
119+
fn get_pv(&self, board: &mut Board, depth: i32, ply: i32) -> String {
120+
if depth == 0 {
121+
return String::new();
122+
}
123+
124+
//probe TT
125+
let table_find = self.tt.find(board.hash(), ply);
126+
if board.hash() == table_find.position {
127+
let mut pv = String::new();
128+
129+
if board.is_legal(table_find.best_move.unwrap()) {
130+
board.play_unchecked(table_find.best_move.unwrap());
131+
pv = format!("{} {}", table_find.best_move.unwrap(), self.get_pv(board, depth - 1, ply + 1));
132+
}
133+
134+
return pv;
135+
}
136+
137+
String::new()
138+
}
139+
150140
fn is_repetition(&self, board: &Board, past_positions: &mut Vec<u64>) -> bool {
151141
if past_positions.len() > 0 {
152142
for i in 0..past_positions.len() - 1 {
@@ -158,39 +148,30 @@ impl Engine {
158148
return false;
159149
}
160150

161-
fn update_pv(&mut self, mv: Option<Move>, ply: usize) {
162-
if ply < 99 {
163-
self.pv[ply][0] = mv;
164-
for i in 0..self.pv[ply + 1].len() {
165-
if i + 1 != self.pv[ply].len() {
166-
self.pv[ply][i + 1] = self.pv[ply + 1][i];
167-
}
168-
}
169-
}
170-
}
171-
172-
pub fn search(&mut self, abort: &AtomicBool, stop_abort: &AtomicBool, board: &Board, depth: i32, mut alpha: i32, beta: i32, past_positions: &mut Vec<u64>) -> Option<(Option<Move>, Eval)> {
151+
pub fn search(&mut self, abort: &AtomicBool, stop_abort: &AtomicBool, board: &Board, mut depth: i32, mut ply: i32, mut alpha: i32, beta: i32, past_positions: &mut Vec<u64>) -> Option<(Option<Move>, Eval)> {
173152
//abort?
174153
if self.searching_depth > 1 && (abort.load(Ordering::Relaxed) || stop_abort.load(Ordering::Relaxed)) {
175154
return None;
176155
}
177156

178-
let ply = self.searching_depth - depth;
179-
180-
self.nodes += 1;
157+
let in_check = !board.checkers().is_empty();
181158

182-
if ply < 100 {
183-
self.pv[ply as usize] = [None; 100];
159+
//search a little deeper if we are in check!
160+
if in_check {
161+
// https://www.chessprogramming.org/Check_Extensions
162+
depth += 1;
184163
}
185164

165+
self.nodes += 1;
166+
186167
match board.status() {
187168
GameStatus::Won => return Some((None, Eval::new(-Score::CHECKMATE_BASE + ply, true))),
188169
GameStatus::Drawn => return Some((None, Eval::new(Score::DRAW, false))),
189170
GameStatus::Ongoing => {}
190171
}
191172

192173
if depth <= 0 {
193-
return self.qsearch(&abort, &stop_abort, board, alpha, beta, self.searching_depth, past_positions); //proceed with qSearch to avoid horizon effect
174+
return self.qsearch(&abort, &stop_abort, board, alpha, beta, ply, past_positions); //proceed with qSearch to avoid horizon effect
194175
}
195176

196177
//check for three move repetition
@@ -244,7 +225,7 @@ impl Engine {
244225
// THEN prune
245226
*/
246227

247-
if depth <= Self::MAX_DEPTH_RFP && board.checkers() == BitBoard::EMPTY {
228+
if depth <= Self::MAX_DEPTH_RFP && !in_check {
248229
if static_eval - (Self::MULTIPLIER_RFP * depth) >= beta {
249230
return Some((None, Eval::new(static_eval, false)));
250231
}
@@ -261,15 +242,15 @@ impl Engine {
261242

262243
let our_pieces = board.colors(board.side_to_move());
263244
let sliding_pieces = board.pieces(Piece::Rook) | board.pieces(Piece::Bishop) | board.pieces(Piece::Queen);
264-
if ply > 0 && board.checkers() == BitBoard::EMPTY && !(our_pieces & sliding_pieces).is_empty() && static_eval >= beta {
245+
if ply > 0 && !in_check && !(our_pieces & sliding_pieces).is_empty() && static_eval >= beta {
265246
let r = if depth > 6 {
266247
3
267248
} else {
268249
2
269250
};
270251

271252
let nulled_board = board.clone().null_move().unwrap();
272-
let (_, mut null_score) = self.search(&abort, &stop_abort, &nulled_board, depth - r - 1, -beta, -beta + 1, past_positions)?; //perform a ZW search
253+
let (_, mut null_score) = self.search(&abort, &stop_abort, &nulled_board, depth - r - 1, ply + r + 1, -beta, -beta + 1, past_positions)?; //perform a ZW search
273254

274255
null_score.score *= -1;
275256

@@ -291,7 +272,7 @@ impl Engine {
291272
let mut value: Eval;
292273

293274
if moves_searched == 0 {
294-
let (_, mut child_eval) = self.search(&abort, &stop_abort, &board_cache, depth - 1, -beta, -alpha, past_positions)?;
275+
let (_, mut child_eval) = self.search(&abort, &stop_abort, &board_cache, depth - 1, ply + 1, -beta, -alpha, past_positions)?;
295276
child_eval.score *= -1;
296277

297278
value = child_eval;
@@ -301,7 +282,7 @@ impl Engine {
301282
//IF the first X searched are searched
302283
//IF this move is QUIET
303284
if depth >= Self::LMR_DEPTH_LIMIT && moves_searched >= Self::LMR_FULL_SEARCHED_MOVE_LIMIT && sm.movetype == MoveType::Quiet {
304-
let (_, mut child_eval) = self.search(&abort, &stop_abort, &board_cache, depth - 2, -alpha - 1, -alpha, past_positions)?;
285+
let (_, mut child_eval) = self.search(&abort, &stop_abort, &board_cache, depth - 2, ply + 2, -alpha - 1, -alpha, past_positions)?;
305286
child_eval.score *= -1;
306287

307288
value = child_eval;
@@ -312,7 +293,7 @@ impl Engine {
312293

313294
//if a value ever surprises us in the future with a score that ACTUALLY changes the lowerbound...we have to search at full depth, for this move may possibly be good
314295
if value.score > alpha {
315-
let (_, mut child_eval) = self.search(&abort, &stop_abort, &board_cache, depth - 1, -beta, -alpha, past_positions)?;
296+
let (_, mut child_eval) = self.search(&abort, &stop_abort, &board_cache, depth - 1, ply + 1, -beta, -alpha, past_positions)?;
316297
child_eval.score *= -1;
317298

318299
value = child_eval;
@@ -325,7 +306,6 @@ impl Engine {
325306
eval = value;
326307
best_move = Some(mv);
327308
if eval.score > alpha {
328-
self.update_pv(best_move, ply as usize);
329309
alpha = eval.score;
330310
if alpha >= beta {
331311
self.tt.insert(best_move, eval.score, board.hash(), ply, depth, NodeKind::LowerBound);
@@ -354,12 +334,6 @@ impl Engine {
354334

355335
self.nodes += 1;
356336

357-
if ply < 100 {
358-
self.pv[ply as usize] = [None; 100];
359-
}
360-
361-
ply += 1;
362-
363337
match board.status() {
364338
GameStatus::Won => return Some((None, Eval::new(-Score::CHECKMATE_BASE + ply, true))),
365339
GameStatus::Drawn => return Some((None, Eval::new(Score::DRAW, false))),
@@ -400,7 +374,7 @@ impl Engine {
400374

401375
past_positions.push(board_cache.hash());
402376

403-
let (_, mut child_eval) = self.qsearch(&abort, &stop_abort, &board_cache, -beta, -alpha, ply, past_positions)?;
377+
let (_, mut child_eval) = self.qsearch(&abort, &stop_abort, &board_cache, -beta, -alpha, ply + 1, past_positions)?;
404378

405379
past_positions.pop();
406380

@@ -410,7 +384,6 @@ impl Engine {
410384
eval = child_eval;
411385
best_move = Some(mv);
412386
if eval.score > alpha {
413-
self.update_pv(best_move, ply as usize);
414387
alpha = eval.score;
415388
if alpha >= beta {
416389
return Some((None, Eval::new(beta, false)));

0 commit comments

Comments
 (0)