@@ -18,7 +18,6 @@ pub struct Engine {
18
18
pub my_past_positions : Vec < u64 > ,
19
19
pub nodes : u64 ,
20
20
pub searching_depth : i32 ,
21
- pv : [ [ Option < Move > ; 100 ] ; 100 ] ,
22
21
movegen : MoveGen ,
23
22
tt : TT
24
23
}
@@ -31,7 +30,6 @@ impl Engine {
31
30
my_past_positions : Vec :: with_capacity ( 64 ) ,
32
31
searching_depth : 0 ,
33
32
nodes : 0 ,
34
- pv : [ [ None ; 100 ] ; 100 ] ,
35
33
movegen : MoveGen :: new ( ) ,
36
34
tt : TT :: new ( )
37
35
}
@@ -67,9 +65,6 @@ impl Engine {
67
65
68
66
let board = & mut self . board . clone ( ) ;
69
67
70
- //set up pv table
71
- self . pv = [ [ None ; 100 ] ; 100 ] ;
72
-
73
68
//set up multithread for search abort
74
69
let search_abort = Arc :: new ( AtomicBool :: new ( false ) ) ;
75
70
let counter_abort = search_abort. clone ( ) ;
@@ -80,7 +75,7 @@ impl Engine {
80
75
81
76
let mut past_positions = self . my_past_positions . clone ( ) ;
82
77
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) ;
84
79
85
80
if result != None {
86
81
let ( best_mv, eval) = result. unwrap ( ) ;
@@ -96,33 +91,6 @@ impl Engine {
96
91
nps = ( ( self . nodes as f32 * 1000_f32 ) / elapsed) as u64 ;
97
92
}
98
93
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
-
126
94
let mut score_str = if eval. mate {
127
95
let mut mate_score = if eval. score > 0 {
128
96
( ( ( Score :: CHECKMATE_BASE - eval. score + 1 ) / 2 ) as f32 ) . ceil ( )
@@ -135,7 +103,7 @@ impl Engine {
135
103
format ! ( "cp {}" , eval. score)
136
104
} ;
137
105
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 ) ) ;
139
107
} else {
140
108
break ;
141
109
}
@@ -147,6 +115,28 @@ impl Engine {
147
115
_960_to_regular_ ( best_move, & self . board )
148
116
}
149
117
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
+
150
140
fn is_repetition ( & self , board : & Board , past_positions : & mut Vec < u64 > ) -> bool {
151
141
if past_positions. len ( ) > 0 {
152
142
for i in 0 ..past_positions. len ( ) - 1 {
@@ -158,39 +148,30 @@ impl Engine {
158
148
return false ;
159
149
}
160
150
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 ) > {
173
152
//abort?
174
153
if self . searching_depth > 1 && ( abort. load ( Ordering :: Relaxed ) || stop_abort. load ( Ordering :: Relaxed ) ) {
175
154
return None ;
176
155
}
177
156
178
- let ply = self . searching_depth - depth;
179
-
180
- self . nodes += 1 ;
157
+ let in_check = !board. checkers ( ) . is_empty ( ) ;
181
158
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 ;
184
163
}
185
164
165
+ self . nodes += 1 ;
166
+
186
167
match board. status ( ) {
187
168
GameStatus :: Won => return Some ( ( None , Eval :: new ( -Score :: CHECKMATE_BASE + ply, true ) ) ) ,
188
169
GameStatus :: Drawn => return Some ( ( None , Eval :: new ( Score :: DRAW , false ) ) ) ,
189
170
GameStatus :: Ongoing => { }
190
171
}
191
172
192
173
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
194
175
}
195
176
196
177
//check for three move repetition
@@ -244,7 +225,7 @@ impl Engine {
244
225
// THEN prune
245
226
*/
246
227
247
- if depth <= Self :: MAX_DEPTH_RFP && board . checkers ( ) == BitBoard :: EMPTY {
228
+ if depth <= Self :: MAX_DEPTH_RFP && !in_check {
248
229
if static_eval - ( Self :: MULTIPLIER_RFP * depth) >= beta {
249
230
return Some ( ( None , Eval :: new ( static_eval, false ) ) ) ;
250
231
}
@@ -261,15 +242,15 @@ impl Engine {
261
242
262
243
let our_pieces = board. colors ( board. side_to_move ( ) ) ;
263
244
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 {
265
246
let r = if depth > 6 {
266
247
3
267
248
} else {
268
249
2
269
250
} ;
270
251
271
252
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
273
254
274
255
null_score. score *= -1 ;
275
256
@@ -291,7 +272,7 @@ impl Engine {
291
272
let mut value: Eval ;
292
273
293
274
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) ?;
295
276
child_eval. score *= -1 ;
296
277
297
278
value = child_eval;
@@ -301,7 +282,7 @@ impl Engine {
301
282
//IF the first X searched are searched
302
283
//IF this move is QUIET
303
284
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) ?;
305
286
child_eval. score *= -1 ;
306
287
307
288
value = child_eval;
@@ -312,7 +293,7 @@ impl Engine {
312
293
313
294
//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
314
295
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) ?;
316
297
child_eval. score *= -1 ;
317
298
318
299
value = child_eval;
@@ -325,7 +306,6 @@ impl Engine {
325
306
eval = value;
326
307
best_move = Some ( mv) ;
327
308
if eval. score > alpha {
328
- self . update_pv ( best_move, ply as usize ) ;
329
309
alpha = eval. score ;
330
310
if alpha >= beta {
331
311
self . tt . insert ( best_move, eval. score , board. hash ( ) , ply, depth, NodeKind :: LowerBound ) ;
@@ -354,12 +334,6 @@ impl Engine {
354
334
355
335
self . nodes += 1 ;
356
336
357
- if ply < 100 {
358
- self . pv [ ply as usize ] = [ None ; 100 ] ;
359
- }
360
-
361
- ply += 1 ;
362
-
363
337
match board. status ( ) {
364
338
GameStatus :: Won => return Some ( ( None , Eval :: new ( -Score :: CHECKMATE_BASE + ply, true ) ) ) ,
365
339
GameStatus :: Drawn => return Some ( ( None , Eval :: new ( Score :: DRAW , false ) ) ) ,
@@ -400,7 +374,7 @@ impl Engine {
400
374
401
375
past_positions. push ( board_cache. hash ( ) ) ;
402
376
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) ?;
404
378
405
379
past_positions. pop ( ) ;
406
380
@@ -410,7 +384,6 @@ impl Engine {
410
384
eval = child_eval;
411
385
best_move = Some ( mv) ;
412
386
if eval. score > alpha {
413
- self . update_pv ( best_move, ply as usize ) ;
414
387
alpha = eval. score ;
415
388
if alpha >= beta {
416
389
return Some ( ( None , Eval :: new ( beta, false ) ) ) ;
0 commit comments