1 /****************************
2 * evaluate() function decides if given position is terminal (checkmate,
3 * stalemate, ...) , if not, seeks it in the hash table, if not
4 * present, calls dynamic (search()) or static (static_eval()) evaluation.
5 * This also handles extensions.
6 ******************/
7
8 #include "phalanx.h"
9
10 #define EXTENSION_BASE 80
11
12 #define NULL_MOVE_PRUNING
13
14 #define RECAPTURE_EXTENSIONS
15 #define PEE_EXTENSIONS /* entering kings+pawns endgame extends */
16 #define CHECK_EXTENSIONS
17 #define PAWNPUSH_EXTENSIONS
18
19 #define minmv (P_VALUE)
20
21 /* 12 moves to draw: the static evaluation goes to zero */
22 #define RULE_50_CLOSE 24
23
24 /**
25 *** Phalanx uses very simple implementation of static-eval cache.
26 *** It eats 512 kB and makes it about 10% faster on a 486.
27 **/
28 #undef CACHE
29 #ifdef CACHE
30 unsigned * C; /* 64k entries of 4 bytes: 256kB */
31 #endif
32
33
34
initcache(void)35 void initcache(void)
36 {
37 #ifdef CACHE
38 C = malloc(0x10000*sizeof(unsigned)); /* 64k entries of 8 bytes: 512kB */
39 if( C==NULL ) { puts("cannot alloc static eval cache!"); exit(0); }
40 #endif
41 }
42
43
44 tsearchnode S[MAXPLY];
45
approx_eval(void)46 static inline int approx_eval(void)
47 {
48 S[Ply].psnl = - S[Ply-1].psnl;
49
50 S[Ply].devi = S[Ply-1].devi*2/3 + abs(S[Ply].psnl)/8;
51 if( G[Counter-1].m.in2 ) S[Ply].devi += 60; else S[Ply].devi += 40;
52
53 /* pawn promotions should mostly trigger full static eval in the child node,
54 * and avoid the lazy one, otherwise the engine delays promotions due to
55 * the high bonus for the pawn on the 7th row. */
56 if(
57 ( G[Counter-1].m.in1 == WP && G[Counter-1].m.to >= A7 )
58 ||
59 ( G[Counter-1].m.in1 == BP && G[Counter-1].m.to <= H2 )
60 )
61 S[Ply].devi += 3*P_VALUE;
62
63 return G[Counter].mtrl - G[Counter].xmtrl + S[Ply].psnl;
64 }
65
66
67
static_eval(void)68 int static_eval(void)
69 {
70
71 int positional;
72 int r50 = 100 - G[Counter].rule50;
73 int material = G[Counter].mtrl-G[Counter].xmtrl;
74
75 #ifdef CACHE
76 if( ( ( C[ 0x0000FFFF & G[Counter].hashboard ] ^ G[Counter].hashboard )
77 & 0xFFFF0000 ) == 0 )
78 {
79 unsigned * cc = C + ( 0x0000FFFF & G[Counter].hashboard );
80 Wknow.prune = (((*cc)&0x00004FFF)!=0);
81 Bknow.prune = (((*cc)&0x00008FFF)!=0);
82 return ( (*cc) & 0x00003FFF ) ;
83 }
84 #endif
85
86 positional = score_position();
87
88 if( r50 < RULE_50_CLOSE )
89 { positional = positional * r50 / RULE_50_CLOSE;
90 material = material * r50 / RULE_50_CLOSE;
91 }
92
93 #undef RAISE
94 #ifdef RAISE
95 /* Inbalanced material: take positional bonus seriously */
96 if( abs(material) > 200 )
97 {
98 int m = abs(material) - 200;
99 if( m > 1000 ) m=1000;
100 #ifdef SCORING
101 if( Scoring )
102 printf(
103 " ( ) inbalanced material, positional raised: %i -> %i\n",
104 positional, positional + positional*m/500 );
105 #endif
106 positional = positional + positional*m/500;
107 }
108 #endif
109
110 #ifdef CACHE
111 {
112 unsigned * cc = C + ( 0x0000FFFF & G[Counter].hashboard );
113 *cc = ( 0xFFFF0000 & G[Counter].hashboard ) | ( material+positional );
114 if( Wknow.prune ) *cc |= 0x00004000; else *cc &= (0xFFFFFFFF-0x00004000);
115 if( Bknow.prune ) *cc |= 0x00008000; else *cc &= (0xFFFFFFFF-0x00008000);
116 }
117 #endif
118
119 S[Ply].psnl = positional;
120 S[Ply].devi = 0;
121
122 #undef debug
123 #ifdef debug
124 if(abs(positional)>600)
125 { Scoring = 1; score_position(); Scoring = 0;
126 printboard(); printf("[%i,%i,%i]",material,positional,score_position());
127 getchar();
128 }
129 #endif
130
131 return material+positional;
132
133 }
134
135
136
repetition(int n)137 inline int repetition( int n )
138 {
139 int i;
140 int r=0;
141 unsigned board = G[Counter].hashboard;
142 for( i=Counter-2; i>=0; i-=2 )
143 {
144 if( G[i].hashboard == board ) if( ++r == n ) return 1;
145 if( G[i].rule50 <= 1 ) break;
146 }
147 return 0;
148 }
149
150
151
material_draw(void)152 int material_draw( void )
153 {
154 int i, n=2;
155
156 for( i=L[WKP].next; i!=0; i=L[i].next )
157 switch( B[i] )
158 { case WQ: case WR: case WP: return 0;
159 default: n--; if( n==0 ) return 0;
160 }
161
162 for( i=L[BKP].next; i!=0; i=L[i].next )
163 switch( B[i] )
164 { case BQ: case BR: case BP: return 0;
165 default: n--; if( n==0 ) return 0;
166 }
167
168 return 1;
169 }
170
171
172
173 /*****************************************************************/
174
evaluate(int Alpha,int Beta)175 int evaluate( int Alpha, int Beta )
176 {
177
178 static int timeslice = 2000;
179 static int polslice = 4000;
180 int result;
181 tmove m[256]; int n; /* moves and number of moves */
182 thashentry *t;
183 int check;
184 int lastiter;
185 int totmat = Totmat = G[Counter].mtrl+G[Counter].xmtrl;
186
187 if(Ply%2) lastiter = -LastIter; else lastiter = LastIter;
188
189 Nodes++;
190
191 if( Flag.level == fixedtime || Flag.level == timecontrol )
192 if( ( Nodes % timeslice ) == 0 && !Flag.analyze )
193 {
194 extern long T1;
195 int t = Flag.centiseconds - ptime() + T1;
196
197 if( t < 0 ) { if( Flag.ponder >= 2 ) Flag.ponder = 3; else Abort = 2; }
198 else
199 if( t != Flag.centiseconds )
200 timeslice =
201 Nodes * t / ( Flag.centiseconds - t ) * 2 / 3;
202
203 if( timeslice > 5*Flag.centiseconds ) timeslice = 5*Flag.centiseconds;
204 if( timeslice < 50 ) timeslice=50;
205 }
206
207 {
208 static int64 lnodes = 0;
209 if( lnodes + polslice < Nodes || Nodes == 1 )
210 {
211 static long lptime = 0;
212 long nptime = ptime();
213
214 if( nptime == lptime ) nptime++;
215
216 if( nptime - lptime < 100 ) polslice = polslice*11/10;
217 else { polslice = polslice*10/11; }
218
219 lptime = nptime;
220
221 if( Flag.post && !Flag.xboard ) verboseline();
222
223 if(Flag.polling)
224 {
225
226 #if defined(__GNUC__) && !defined(__MINGW32__)
227 static fd_set readfds;
228 static struct timeval tv;
229 int data;
230
231 FD_ZERO (&readfds);
232 FD_SET (fileno(stdin), &readfds);
233 tv.tv_sec=0;
234 tv.tv_usec=0;
235 select(16, &readfds, 0, 0, &tv);
236 data=FD_ISSET(fileno(stdin), &readfds);
237 if(data)
238 {
239 if(polslice<8000 || Flag.analyze) polslice=4000; else polslice/=2;
240 interrupt(0);
241 }
242
243 #else
244
245 /* Credit here goes to Dr Oliver Brausch for the code from his
246 * program Olithink. Some rewriting has been done by CMF, but not much
247 * as I have absolutely no idea whatsoever what this does.
248 * I think the original code is from Crafty by Prof. Robert Hyatt. [JA] */
249
250 static int init = 0, pipe;
251 static HANDLE inh;
252 DWORD dw;
253
254 /* If we're running under XBoard then we can't use _kbhit() as the input commands
255 * are sent to us directly over the internal pipe */
256 if (Flag.xboard>0) {
257 #if defined(FILE_CNT)
258 if (stdin->_cnt > 0) return stdin->_cnt;
259 #endif
260 if (!init) {
261 init = 1;
262 inh = GetStdHandle(STD_INPUT_HANDLE);
263 pipe = !GetConsoleMode(inh, &dw);
264 if (!pipe) {
265 SetConsoleMode(inh, dw & ~(ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT));
266 FlushConsoleInputBuffer(inh);
267 }
268 }
269 if (pipe) {
270 if (!PeekNamedPipe(inh, NULL, 0, NULL, &dw, NULL)) return 1;
271 return dw;
272 }
273 else {
274 GetNumberOfConsoleInputEvents(inh, &dw);
275 return dw <= 1 ? 0 : dw;
276 }
277 }
278 else return _kbhit();
279
280 #endif
281
282 }
283
284 /*
285 if( Flag.analyze )
286 printf("stat01: %d %d %d %d %d\n",0,Nodes,A_d,A_i,A_n);
287 */
288
289 lnodes = Nodes;
290 }
291 }
292
293 if( Ply >= MAXPLY-2 )
294 { PV[Ply][Ply].from=0; return G[Counter].mtrl-G[Counter].xmtrl; }
295
296 if( G[Counter].rule50 >= 100 ) /* 50 moves draw */
297 { PV[Ply][Ply].from=0; return DRAW; }
298
299 /* insufficient material draw */
300 if( G[Counter].mtrl<400 && G[Counter].mtrl<400 )
301 if( material_draw() )
302 { PV[Ply][Ply].from=0; return DRAW; }
303
304 if( G[Counter].rule50 >= 3 )
305 if( repetition(1) ) /* third rep. draw */
306 {
307 int j;
308 int ext=0;
309 PV[Ply][Ply].from=0;
310
311 for( j=Counter-1; j>Counter-Ply; j-=2 )
312 { ext += G[j-1].m.dch - G[j].m.dch; }
313
314 if( ext > 0 )
315 {
316 if( ext > 500 ) ext=500;
317 ext += Ply*20;
318 }
319 else if( ext < 0 )
320 {
321 if( ext < -500 ) ext=-500;
322 ext -= Ply*20;
323 }
324
325 /* Speculative drawscore
326 * Human players sometimes play a wild sacrifice leading to unclear
327 * lines, making sure they could achieve a repetition draw at least.
328 * This is the same speculative heuristics:
329 * Repetition draw is scored as a slight advantage to the side that
330 * forced the repetition, ie. that had less extensions in the path,
331 * that's why we count the cumulative extension above. The deeper
332 * in the tree this happens, the higher speculative bonus we give,
333 * that is the Ply*20 above. However, if the remaining Depth is large,
334 * we pull the score back closer to the DRAW score, because with
335 * the larger Depth we should be able to find something better
336 * than draw.
337 */
338 return DRAW + ext/(15+max(-5,Depth/10));
339 }
340
341 /********************************************************************
342 * Now it is time to look into the hashtable.
343 ********************************************************************/
344 if( SizeHT == 0 || Depth<0 ) t = NULL;
345 else
346 if( (t=seekHT()) != NULL )
347 if( Age == t->age || Beta-Alpha == 1 )
348 if( t->depth >= Depth || ( Depth<300 && abs(t->value)>CHECKMATE-1000 ) )
349 {
350 int val = t->value;
351 if( val > CHECKMATE-1000 ) val -= Ply;
352 else if( val < -CHECKMATE+1000 ) val += Ply;
353
354 switch( t->result )
355 {
356 case no_cut: /* `true value', good_score */
357 PV[Ply][Ply].from=0; return val;
358 break;
359 case alpha_cut: /* `this or less', failed_low */
360 if( val <= Alpha ) { PV[Ply][Ply].from=0; return Alpha; }
361 break;
362 case beta_cut: /* `this or more', failed_high */
363 if( val >= Beta ) { PV[Ply][Ply].from=0; return Beta; }
364 break;
365 }
366 }
367 /***** End of hashtable stuff *****/
368
369 #undef nodef
370 #ifdef nodef
371 {
372 static int64 int good=0, all=0;
373 if( t!=NULL && t->move!=0 ) good++;
374 all++;
375 if( all%100000 == 0 && all!=0 )
376 printf("hit percentage = %lld.%02lld%%\n",good*100/all,good*10000/all%100);
377 }
378 #endif
379
380 if( Ply<2 ) /* called from rootsearch() */
381 S[Ply].check = check = checktest(Color);
382 else /* called from search() and the checktest() has been run */
383 check = S[Ply].check;
384
385 if( Depth>0 || check )
386 {
387
388 if(Depth<=0) result = approx_eval();
389 else result = static_eval();
390
391 #define FORWARD_PRUNING
392 #ifdef FORWARD_PRUNING
393 /*
394 * A simple forward pruning:
395 * The Depth is low and the static evaluation is over [Alpha plus margin]
396 * Our king is safe (khung<limit) and we don't have much hung material.
397 * Let's lift Alpha and prune if it gets >= Beta.
398 * This works quite fine for larger Depths than 200 (2 plies) as well,
399 * tested with limit 600 on a set of positions and it's still finding
400 * everything and in a shorter time, but I'm keeping the depth limit
401 * conservative for now.
402 * This is similar to what the old Phalanx XXII had, except now
403 * we use the margin.
404 */
405 if( !check
406 && Depth < 200
407 && ( Color==WHITE
408 ?
409 ( Wknow.hung<14 && Wknow.khung<6 )
410 :
411 ( Bknow.hung<14 && Bknow.khung<6 )
412 )
413 )
414 {
415 int r = result - (P_VALUE+Depth)/10;
416 if( r>=Beta ) { PV[Ply][Ply].from=0; return Beta; }
417 if( r>Alpha ) Alpha=r;
418 }
419 #endif /* FORWARD_PRUNING */
420
421
422 /*
423 if( Depth<1500 && Depth>0
424 && Beta-Alpha==1 && !check
425 && result < Beta-P_VALUE-Depth )
426 {
427 generate_legal_checks(m,&n);
428 if( n==0 ) { result=Alpha; goto end; }
429 }
430 else
431 */
432 generate_legal_moves(m,&n,check);
433
434 /** Return, if there is no legal move - checkmate or stalemate **/
435 if(n==0)
436 {
437 PV[Ply][Ply].from=0;
438 if(check) return Ply-CHECKMATE;
439 else return DRAW;
440 }
441
442 #ifdef NULL_MOVE_PRUNING
443 if(
444 Depth > 100
445 && ( result >= Beta || Depth > 350 )
446 && ! FollowPV
447 && ! check
448 && n>4
449 && ( (Color==WHITE) ? (Wknow.q||Wknow.r||Wknow.b||Wknow.n>1)
450 : (Bknow.q||Bknow.r||Bknow.b||Bknow.n>1) )
451 && G[Counter-1].m.special != NULL_MOVE /* prev. node not nm */
452 && ( t==NULL || t->depth <= Depth-350
453 || t->result==beta_cut || t->value >= Beta )
454 )
455 {
456 int value;
457 int olddepth = Depth;
458
459 G[Counter].m.in1 = 0; /* disable en passant */
460 G[Counter].m.special = NULL_MOVE;
461 G[Counter].m.to = 2;
462 Counter ++; Ply ++;
463 G[Counter].castling = G[Counter-1].castling;
464 G[Counter].rule50 = G[Counter-1].rule50 + 1;
465 G[Counter].hashboard =
466 HASH_COLOR ^ G[Counter-1].hashboard;
467 G[Counter].mtrl = G[Counter-1].xmtrl;
468 G[Counter].xmtrl = G[Counter-1].mtrl;
469 Color = enemy(Color);
470 S[Ply].check=0;
471
472 /* reduction depends on number of moves generated */
473 /* n=20 ... R=2, n=40 ... R=3, n=50 ... R=3.5 */
474 Depth -= 200 + n*5;
475
476 if(Depth<0) Depth=0; else Depth -= Depth/4;
477 value = -evaluate(-Beta, -Beta+1);
478
479 Color = enemy(Color);
480 Counter --; Ply --;
481 Depth = olddepth;
482 Totmat = totmat;
483
484 if( value >= Beta ) { result = Beta; goto end; }
485 }
486 #endif
487
488 #define PROBCUT
489 #ifdef PROBCUT
490 #define MRGN 190
491 /*
492 * If we have a capture that can get us above Beta+MRGN, we try to
493 * search the capturing move at a reduced depth and with raised Beta.
494 * If we then get a fail high, the previous opponent move was likely
495 * a blunder and we can prune this node.
496 * This is complementary to null move pruning. Null move can prune many
497 * weak moves, but not those that create a threat, e.g. unprotected rook
498 * attacks queen - null move allows capturing the queen and thus cannot
499 * prune the silly attack, whereas in ProbCut queen captures the rook,
500 * confirms with the reduced search that the previous opponent move
501 * was a blunder and prunes.
502 */
503
504 if( Depth>350 && Beta-Alpha==1 && !check )
505 {
506 int i;
507 int r = Alpha;
508 int olddepth = Depth;
509
510 Depth-= 350;
511
512 for( i=0; i!=n; i++ )
513 if( m[i].in2 && result+Values[m[i].in2>>4] >= Beta+MRGN )
514 {
515 do_move(m+i); S[Ply].check=checktest(Color);
516 r = - evaluate( -Beta-MRGN, -Beta-MRGN+1 );
517 undo_move(m+i);
518 if( r>=Beta+MRGN ) break;
519 }
520 Depth = olddepth;
521
522 if( r>= Beta+MRGN ) { result = Beta; goto end; }
523 }
524
525 #endif /* PROBCUT */
526
527 #ifdef CHECK_EXTENSIONS
528 if( check && Depth>0 )
529 {
530 int newdch, i;
531
532 /* We compute the extension from the depth remaining (Depth)
533 * and number of legal moves available (n) */
534 newdch =
535 EXTENSION_BASE - 20
536 - 3000/(Depth+100) /* 30..0 */
537 - 200/(n*(n+1)); /* 1~100,2~33,3~16,..0 */
538
539 if( result<=lastiter-50 || result <= -250 ) /* losing anyway */
540 newdch = (newdch+100)/2; /* smaller extension, 50% */
541
542 for( i=0; i!=n; i++ )
543 if( m[i].in2 ) m[i].dch = (newdch+100)/2; /* capture */
544 else m[i].dch = newdch;
545 }
546 #endif
547
548 #ifdef PAWNPUSH_EXTENSIONS
549 if( Totmat < 4000 )
550 if(result<lastiter+50 && result<250) /* winning anyway: dont extend */
551 {
552 int i;
553 for( i=0; i!=n; i++ )
554 if( piece(m[i].in2a) == PAWN
555 && m[i].special == 0
556 && ( ( Color==WHITE && m[i].to >= A6 )
557 || ( Color==BLACK && m[i].to <= H3 ) ) )
558 {
559 int j;
560 int support=0;
561 int newdch=EXTENSION_BASE;
562
563 if( Color == WHITE )
564 {
565
566 for( j=m[i].to+10; j<=H7; j+=10 )
567 if( B[j-1]==BP
568 || B[j]==BP
569 || B[j+1]==BP )
570 goto no_push_extension;
571
572 for( j=m[i].to; j<=H8; j+=10 )
573 {
574 if( B[j] ) support--;
575 if( see(B,m[i].from,j) < 0 )
576 support--;
577 else support++;
578 }
579 }
580 else
581 {
582 for( j=m[i].to-10; j>=A2; j-=10 )
583 if( B[j-1]==WP
584 || B[j]==WP
585 || B[j+1]==WP )
586 goto no_push_extension;
587
588 for( j=m[i].to; j>=A1; j-=10 )
589 {
590 if( B[j] ) support--;
591 if( see(B,m[i].from,j) < 0 )
592 support--;
593 else support++;
594 }
595 }
596
597 newdch += Depth/20 + Totmat/100 - 30*support;
598
599 switch( m[i].to/10 )
600 { case 8: case 3:
601 if(support>0) newdch -= 20*support+10; break; }
602
603 if( newdch < m[i].dch )
604 { m[i].dch = newdch; }
605
606 no_push_extension:;
607 }
608 }
609 #endif
610
611 #ifdef RECAPTURE_EXTENSIONS
612 if( Depth>0 && G[Counter-1].m.in2 )
613 if( result<lastiter+50 && result<250 ) /* winning anyway: dont */
614 {
615 int i, t=G[Counter-1].m.to;
616 int v1 = Values[ G[Counter-1].m.in1 >> 4 ];
617 int v2 = Values[ G[Counter-1].m.in2 >> 4 ];
618 int newdch;
619
620 if( Depth <= 200 )
621 newdch = EXTENSION_BASE-30;
622 else
623 newdch = EXTENSION_BASE-20;
624
625 if( min(v1,v2) > 400 || G[Counter].mtrl < Q_VALUE )
626 newdch -= 70;
627 else
628 if( min(v1,v2) > 200 || G[Counter].mtrl < (Q_VALUE+N_VALUE) )
629 newdch -= 45;
630
631 /* recaptures depth bonus */
632 for( i=0; i!=n; i++ )
633 if( m[i].to == t )
634 if( m[i].dch > newdch )
635 /* if( Depth<=100 || see(B,m[i].from,m[i].to) >= v1 ) */
636 m[i].dch = newdch;
637 }
638 #endif
639
640 #ifdef PEE_EXTENSIONS
641 if( Depth > 200
642 && G[Counter].mtrl <= (8*P_VALUE)
643 && G[Counter].xmtrl <= (8*P_VALUE+Q_VALUE)
644 && G[Counter-1].m.in2 > KNIGHT )
645 {
646 int i;
647 int target=0;
648 int cdch;
649
650 for( i=L[L[Color].next].next; i!=0; i=L[i].next )
651 if( B[i] >= KNIGHT ) goto nopee;
652
653 for( i=L[L[enemy(Color)].next].next; i!=0; i=L[i].next )
654 if( B[i] >= KNIGHT )
655 { if( target ) goto nopee; else target=i; }
656
657 if( ! target ) goto nopee;
658
659 if( G[Counter-1].m.in2 >= QUEEN ) cdch = min(Depth,450);
660 else cdch = min(Depth*2/3,350);
661
662 for( i=0; i!=n; i++ )
663 if( m[i].to == target )
664 { m[i].dch -= cdch;
665 /* printboard(NULL); printm(m[i],NULL); getchar(); */ }
666
667 nopee:;
668 }
669 #endif
670
671 #ifdef ETTC
672 if( Depth > 200 && SizeHT != 0 )
673 {
674 extern void do_hash(tmove *), undo_hash(tmove *);
675
676 int i;
677 for( i=0; i!=n; i++ )
678 {
679 thashentry *t;
680 do_hash(m+i);
681
682 if( (t=seekHT()) != NULL )
683 if( t->depth >= Depth )
684 if( t->result != beta_cut )
685 {
686 int val = -t->value;
687 if( val > CHECKMATE-100 ) val -= Ply;
688 else if( val < -CHECKMATE+100 ) val += Ply;
689
690 if( val > Alpha )
691 {
692 if( val >= Beta )
693 {
694 undo_hash(m+i);
695 G[Counter].m = m[i];
696 PV[Ply][Ply] = m[i];
697 PV[Ply][Ply+1].from = 0;
698 result = Beta; goto end;
699 }
700 Alpha=val;
701 }
702 }
703 undo_hash(m+i);
704 }
705 }
706 #endif
707
708 }
709 else
710 { /*** Quiescence search ***/
711
712 result = approx_eval();
713
714 if( ( result < Beta+S[Ply].devi && result > Alpha-S[Ply].devi )
715 || Totmat<=(B_VALUE+P_VALUE) || Ply<2 )
716 result = static_eval();
717
718 if( result >= Beta ) return result;
719
720 if( result <= Alpha-(Q_VALUE+minmv) && Depth <= -100 )
721 { return Alpha; }
722
723 #ifdef QCAPSONLY
724 generate_legal_captures(m,&n,Alpha-result-minmv);
725 #else
726 /* What to generate? Only captures or also safe checks? */
727 if( G[Counter].mtrl-G[Counter].xmtrl < 400
728 && Depth > -100
729 )
730 generate_legal_checks(m,&n);
731 else
732 generate_legal_captures(m,&n,Alpha-result-minmv);
733 #endif
734 }
735
736 /*** Compute heuristic values of moves ***/
737 add_killer( m, n, t );
738
739 PV[Ply][Ply].from = 0;
740
741 if( Flag.nps )
742 {
743 if( Flag.easy )
744 { if( n>10 && Flag.easy<=100 ) blunder(m,&n); }
745
746 /* timecontrol fix */
747 if( polslice > Flag.easy+200 ) polslice=Flag.easy+200;
748
749 /* Now limit the NPS, lowest value is 100.
750 * For higher values of nps levels like 50000 nps, there's no need
751 * to check for the limit and call ptime() at every node,
752 * hence the condition below */
753 if( Nodes%(1+Flag.nps/500)==0 )
754 {
755 int nps_actual = Nodes*100/max(ptime()-T1,1);
756 if( nps_actual > Flag.nps && !Abort ) usleep(100000);
757 }
758 }
759
760 /*** Full-width search ***/
761 if( Depth>0 || check )
762 {
763 result = search(m,n,Alpha,Beta);
764 }
765 else /*** Quiescence ***/
766 {
767 if( result > Alpha )
768 result = search(m,n,result,Beta);
769 else
770 result = search(m,n,Alpha,Beta);
771 }
772
773 end:
774
775 if( result>=Beta && Depth>0 )
776 write_killer( G[Counter].m.from, G[Counter].m.to );
777
778 if( SizeHT != 0 && Depth >= 0 && Abort == 0 ) writeHT( result, Alpha, Beta );
779
780 /**
781 *** Check learning file.
782 *** This should be done before search. It is here only for
783 *** timing heuristics stability problem that needs better
784 *** solution.
785 **/
786 if( Depth > 300 && Flag.learn )
787 if( Depth > 400 || Ply<3 )
788 {
789 int lresult = rlearn();
790 if( lresult != NOVALUE )
791 { PV[Ply][Ply].from=0;
792 if( lresult > CHECKMATE-1000 ) lresult -= Ply;
793 if( lresult < -CHECKMATE+1000 ) lresult += Ply;
794 result = lresult;
795 }
796 }
797
798 return result;
799
800 }
801
802
803