Deleted log file from repository
[rattatechess.git] / search.cpp
blob8e4ee2e3cce1b6ddba9c595e4a7b3b413913044d
1 /***************************************************************************
2 search.cpp - description
3 -------------------
4 begin : Wed Mar 13 2002
5 copyright : (C) 2002-2005 by Monge Maurizio
6 email : monge@linuz.sns.it
7 ***************************************************************************/
9 /***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
18 #include "engine.h"
19 #include "utils.h"
20 #include <string.h>
21 #include <stdlib.h>
23 #define MAX_PV 80
24 #define PLY 100
26 uint64_t history_tot[64*64];
27 uint64_t history_hit[64*64];
28 uint16_t killers[MAX_PV][64*64];
30 #define HISTORY_INDEX(m) (SQUARE_TO_64(m.from)*64 + \
31 SQUARE_TO_64(m.to))
32 #define PROF(f,n) {uint64_t tmp = rdtsc(); f; prof_##n += rdtsc()-tmp; }
34 /*uint64_t prof_eval;
35 uint64_t prof_find_moves;
36 uint64_t prof_find_captures;
37 uint64_t prof_heuristic;
38 uint64_t prof_sort_moves;
39 uint64_t prof_do_move;
40 uint64_t prof_move_is_check;
41 uint64_t prof_move_see_val;
42 uint64_t prof_tot;*/
44 int stat_early_transp;
45 int stat_hash_write;
46 int stat_hash_tot;
47 int stat_hash_ex;
48 int stat_hash_low;
49 int stat_hash_upp;
50 int stat_best_cut;
51 int stat_best_first;
52 int stat_search_moves;
53 int stat_best_cut0;
54 int stat_best_first0;
55 int stat_search_moves0;
56 int stat_evaluate;
57 int stat_evaluate_cutoff;
58 int stat_null_move;
59 int stat_null_cut;
61 //int stat_
62 /* enable the quiescence search */
63 #define QUIESCENCE 1
65 /* enable the nega-scout pv-search */
66 #define NEGA_SCOUT 1
68 /* enable the null move */
69 #define NULL_MOVE 1
71 /* enable hashing the positions */
72 #define HASH_TABLE 1
74 /* use the hastable to detect tranpositions */
75 #define TRANSP_TABLE 1
77 /* SEEMS TO BE QUITE BAD:
78 trust the values from a search at lower depth stored in the hashtable
79 to produce a cutoff, taking the value with a margin of uncertainity */
80 #define APPROX_TRANSP_CUTOFF 0
82 /* before doing the alpha beta search check if any of the following positions
83 can give use an early cutoff thanks to the hashtable */
84 #define EARLY_TRANSP_CUTOFF 1
86 /* SEEMS TO BE A BIT BAD:
87 when the we find that the values stored in the hash (the result of a
88 lighter search) were wrong by a big factor, this means that the node is
89 unstable, so re-search it */
90 #define CONSISTENCY_EXTENSION 0
92 /* SEEMS TO BE A BIT BAD:
93 Extend when there is only one decent move */
94 #define SINGULAR_EXTENSION 0
96 /* DANGEROUS:
97 reduce nodes for moves that are not check/captures that are considered
98 bad from the heuristic */
99 #define HISTORY_PRUNING 1
101 /* futility pruning: */
102 #define FUTILITY 1
104 /* sort the moves to improve alpha-beta cutoff */
105 #define SORT_MOVES 1
107 /* use the candidate move stored in the hashtable */
108 #define HASH_HEURISTIC 1
110 /* when the hashtable provides no "best" move, do a depth-2 search */
111 #define INTERNAL_ITERATIVE_DEEPENING 0
113 /* use the history sorting heuristic */
114 #define HISTORY_HEURISTIC 1
116 /* use the Max Value Victim/Least Value Attacker sorting heuristic */
117 #define MVV_LVA_HEURISTIC 1
119 /* improve the sorting heuristic for pawn strikes */
120 #define PAWNSTRIKE_HEURISTIC 1
122 /* improve the sorting heuristic for moves to the center */
123 #define CENTER_HEURISTIC 0
125 /* search 2 times per ply, to compare our move sorting to the perfect move sorting */
126 #define RE_SEARCH 0
129 class SearchStack
131 public:
132 int base_depth; /* depth of the search at this ply */
133 int extensions; /* global extensions at this node */
134 Move *moves; /* all generated moves */
135 int num_moves; /* num of moves */
136 int curr_move; /* the move being currently analyzed */
137 int16_t alpha; /* alpha ans beta when the search started (not improved) */
138 int16_t beta;
139 bool under_check;
140 Move threat;
141 int best_move;
144 Move mv_stack[200*MAX_PV];
145 int mv_stack_top = 0;
146 SearchStack stack[MAX_PV];
147 int current_ply = 0;
149 void Engine::print_stat()
151 if(eng_status != ANALYZING)
153 output("You cannot use this command now!\n");
154 return;
157 if(thinking)
159 char buf[32];
160 output("stat01: %d %llu %d %d %d %s\n",
161 current_time() - start_think_time,
162 (unsigned long long)processed_nodes,
163 stack[0].base_depth/100,
164 stack[0].num_moves-1-stack[0].curr_move,
165 stack[0].num_moves,
166 move_to_alg(buf, &(stack[0].moves[stack[0].curr_move]) ) );
168 else
169 output("stat01: 0 0 0 0 0\n");
172 void Engine::rewind_thinking()
174 for(int i=current_ply-1; i>=0; i--)
176 if(stack[i].curr_move == -1)
177 board.undo_null_move();
178 else
179 board.undo_move(stack[i].moves[stack[i].curr_move]);
183 void Engine::restore_thinking()
185 for(int i=0; i<current_ply; i++)
187 if(stack[i].curr_move == -1)
188 board.do_null_move();
189 else
190 board.do_move(stack[i].moves[stack[i].curr_move]);
193 /* regenerate pinning info and under_check var, just to be sure :) */
194 Move mvs[250];
195 board.find_moves(mvs);
198 void
199 Engine::moves_heuristic(Move *mv, int num_mv, int ply, int orig_depth,
200 Move best_mv_hash, bool quiesce)
202 /*uint8_t up_right = Board::up_dir[IS_WHITE(board.color_to_move)] + RIGHT;
203 uint8_t up_left = Board::up_dir[IS_WHITE(board.color_to_move)] + LEFT;*/
204 int hash_move = -1;
206 for(int i=0;i<num_mv;i++)
208 mv[i].val = 0;
209 mv[i].extend = 0;
211 #if HASH_TABLE && HASH_HEURISTIC
212 /* give a high bonus to the move stored in the hash, if any.
213 mark only which is, don't continue, because some extensions
214 may be triggered ad added later (ie pawn strike, etc) */
215 if(mv[i].as_int == best_mv_hash.as_int)
216 hash_move = i;
217 #endif //HASH_HEURISTIC
219 /* process strong pawn moves */
220 if(PIECE_OF(board.data[mv[i].from])==PAWN) /* pawn strike */
222 if( ROW_OF(mv[i].to) == board.seventh_rank[IS_WHITE(board.color_to_move)] )
224 int x = board.move_see_val(mv[i]);
226 if(x<0)
228 mv[i].val += -15000;
229 continue;
232 mv[i].val += 29499; /* 7th push */
233 mv[i].extend = 1; /* extend search */
234 continue;
237 if( mv[i].flags == PROMOTEQUEEN )
239 int x = board.move_see_val(mv[i]);
241 if(x<0)
243 mv[i].val += -15000;
244 continue;
247 mv[i].val += 29500; /* promote! */
248 mv[i].extend = 1; /* extend search */
249 continue;
252 #if 0
253 /* pawn strike */
254 uint8_t p1 = mv[i].to + up_right;
255 uint8_t p2 = mv[i].to + up_left;
256 uint8_t a = OUT_OF_BOARD(p1) ? 0 : board.data[p1];
257 uint8_t b = OUT_OF_BOARD(p2) ? 0 : board.data[p2];
258 if( (COLOR_OF(a)==board.other_color && PIECE_OF(a)!=PAWN)
259 || (COLOR_OF(b)==board.other_color && PIECE_OF(b)!=PAWN) )
261 int x = board.move_see_val(mv[i]);
262 if(x<0)
264 mv[i].val += -15000;
265 continue;
268 mv[i].val += 27000; /* pawn strike! */
269 mv[i].extend = 1; /* extend search */
270 continue;
272 #endif
275 if(mv[i].capture)
277 int x = board.move_see_val(mv[i]);
279 if(x>0)
281 if(orig_depth>-7*PLY && board.move_is_check(mv[i]) )
283 mv[i].val += 29800+x;
284 //mv[i].extend = 1;
286 else
287 mv[i].val += 29000+x;
288 continue;
290 else if(x<0)
292 mv[i].val += -15000+x;
293 continue;
295 else if(orig_depth>-7*PLY && board.move_is_check(mv[i]) )
297 /* = capture but check */
298 mv[i].val += 29800;
299 continue;
302 else /* add a bonus for checks (but not too deep, or quiescence will get mad) */
303 if(orig_depth>-3*PLY && board.move_is_check(mv[i]) )
305 if(board.move_see_val(mv[i])>=0)
307 mv[i].val += 28799;
308 continue;
312 if(quiesce)
313 continue;
315 #if HISTORY_HEURISTIC
316 /* add the value depending on the heuristic */
317 mv[i].val += killers[ply][HISTORY_INDEX(mv[i])];
318 if(ply>=2)
319 mv[i].val += killers[ply-2][HISTORY_INDEX(mv[i])];
320 #endif //HISTORY_HEURISTIC
322 #if CENTER_HEURISTIC
323 static int bof[128] = {
324 0,0,1,2,2,1,0,0,ENDL,
325 0,1,2,3,3,2,1,0,ENDL,
326 0,2,4,5,5,4,2,0,ENDL,
327 1,2,5,6,6,5,2,1,ENDL,
328 1,2,5,6,6,5,2,1,ENDL,
329 0,2,4,5,5,4,2,0,ENDL,
330 0,1,2,3,3,2,1,0,ENDL,
331 0,0,1,2,2,1,0,0,ENDL
334 /* add a bonus for moves towards the center */
335 mv[i].val += (bof[mv[i].to] - bof[mv[i].from]);
336 #endif //CENTER_HEURISTIC
339 if(hash_move!=-1)
340 mv[hash_move].val = 30000;
344 /*******************************************************************************
345 The main alpha-beta recursive search function.
346 It handles both normal search (with or without null move)
347 and quiescence search, because i have having 2 almost identical
348 function around.
349 *******************************************************************************/
350 int16_t Engine::search(int ply, int depth, bool pv, int16_t alpha, int16_t beta)
352 SearchStack *s = &stack[ply];
353 int16_t best = -INF;
354 uint16_t cbest_mv_hash = 0; /* the compressed move from the hash */
355 Move best_mv_hash = Move::FromInt(0); /* the move from the hash */
356 int best_mv_found = -1; /* the index of the best move AFTER searching */
357 bool quiesce;
358 bool extended = false;
359 int16_t position_val;
360 #if CONSISTENCY_EXTENSION
361 int old_hash_lower = -INF;
362 int old_hash_upper = INF;
363 int old_hash_depth = 0;
364 #endif //CONSISTENCY_EXTENSION
366 s->base_depth = depth;
367 s->extensions = 0;
368 s->num_moves = 0;
369 s->curr_move = -1;
370 s->alpha = alpha;
371 s->beta = beta;
372 s->threat = Move::FromInt(0);
373 s->best_move = -1;
375 /* check if time is running out */
376 if(check_time())
377 return 0;
379 /* check for a draw for repetition or 50mvs. Of course the draw for
380 repetition must be checked BEFORE probing the hash :)*/
381 if(check_draw())
382 return (board.color_to_move == st_computer_color) ? -35 :
383 ((board.other_color == st_computer_color) ? 35 : 0); /* be aggressive! */
385 #if HASH_TABLE
386 /*******************************************************************************
387 Probe the hashtable.
388 If the probe is succesful the hashtable will return us value
389 that can be exact, a lower bound or an upper bound, and if the
390 depth of the hashed search is >= the current depth this value
391 will be used to improve alpha and beta and possibly return immediatly.
392 The hastable will also give us a "best" move that will be searched
393 first.
394 This is the move that caused the "final" cutoff when this position
395 was searched previously. This best move is actually the index of the best
396 move in the array of generated moves (it is supposed to be deterministic :)
397 *******************************************************************************/
398 stat_hash_tot++;
399 HashEntry *h = probe_hash( board.hash );
401 #if TRANSP_TABLE
402 if(h && (h->depth >= s->base_depth))// || ABS(h->value)>INF-1000) )
404 int16_t l = h->lower();
405 int16_t u = h->upper();
406 if(l>=beta || u==l)
407 return l;
408 if(u<=alpha)
409 return u;
411 beta = MIN(beta, u);
412 alpha = MAX(alpha, l);
415 #if APPROX_TRANSP_CUTOFF
416 /* risky, we are assuming that the result of a search at lower
417 depth will not be very different from the true result */
418 if(h && depth<=300 && (h->depth >= depth-100))
420 if(h->upper()+350<=alpha)
421 return alpha;
422 if(h->lower()-350>=beta)
423 return beta;
425 #endif //APPROX_TRANSP_CUTOFF
426 #endif //TRANSP_TABLE
428 #if HASH_HEURISTIC
429 if(h)
430 cbest_mv_hash = h->best_mv;
431 #endif //HASH_HEURISTIC
433 #if CONSISTENCY_EXTENSION
434 /* save the bounds stored in the hash, so we can re-search unstable nodes */
435 if(h)
437 old_hash_lower = h->lo;
438 old_hash_upper = h->up;
439 old_hash_depth = h->depth;
441 #endif //CONSISTENCY_EXTENSION
443 #endif //HASH_TABLE
446 /*******************************************************************************
447 Test if we are under check, and if so extend search
448 *******************************************************************************/
450 s->under_check = board.under_attack(board.king_pos[IS_WHITE(board.color_to_move)],
451 board.other_color);
452 #if 0
453 if(s->under_check)
455 depth += PLY;
456 extended = true;
458 #endif
460 /*******************************************************************************
461 If it is time to quiesce, evaluate and test if we can exit
462 immediately with a beta cut-off (try first a rough eval - delta)
463 *******************************************************************************/
464 quiesce = ((!s->under_check) && (depth<=0)) || (depth<-60*PLY);
465 #if 0
466 if(quiesce && depth>=-100)
468 int num_mv;
469 Move *mv = mv_stack + mv_stack_top;
470 board.do_null_move();
471 num_mv = board.find_moves(mv);
473 for(int i=0;i<num_mv;i++)
475 if(!mv[i].capture)
476 continue;
477 if(board.move_see_val(mv[i])>0)
479 quiesce = false;
480 break;
484 board.undo_null_move();
486 #endif
488 if(quiesce)
490 stat_evaluate++;
491 best = board.evaluate(st_computer_color, alpha, beta);
493 alpha = MAX(alpha, best);
494 if(best >= beta)
496 stat_evaluate_cutoff++;
497 goto search_done;
500 //best =0;
501 #if QUIESCENCE
502 if(ply>60)
503 #endif //QUIESCENCE
504 goto search_done;
508 #if NULL_MOVE
509 /*******************************************************************************
510 Try the null move.
511 *******************************************************************************/
512 if(!s->under_check && (stack[ply-1].curr_move!=-1) && depth >= 2*PLY && beta<INF-1000)
514 int16_t val;
515 int sdepth = depth-3*PLY;
517 stat_null_move++;
518 s->curr_move = -1;
519 current_ply++;
520 board.do_null_move();
521 val = -search( ply+1, sdepth, true, -beta, -beta+1);
522 board.undo_null_move();
523 current_ply--;
525 /* null move cut! */
526 if(val >= beta)
528 stat_null_cut++;
529 return val;
532 if(val<alpha-100 && /* we are facing a threat*/
533 stack[ply+1].best_move != -1) /* be sure we aren't reading random memory */
535 /* ok, officially the array stack[ply+1].moves has already
536 been deallocated, but who cares :) */
537 s->threat = stack[ply+1].moves[stack[ply+1].best_move];
539 #if 0
540 /* Botvinnik-Markoff extension!!! */
541 if(!extended && ply>=3 && (s->threat == stack[ply-2].threat) )
543 depth += 80;
544 extended = true;
546 #endif
549 #endif
553 /*******************************************************************************
554 Now generate the legal moves and look for a check/stalemate
555 *******************************************************************************/
557 /* generate all the legal moves */
558 s->moves = &mv_stack[mv_stack_top];
559 s->num_moves = board.find_moves(s->moves);
560 mv_stack_top += s->num_moves;
561 s->under_check = board.under_check;
563 if(s->under_check==2) /* double check */
565 depth += 200;
566 extended = true;
568 else if(s->under_check) /* simple check */
570 depth += 100;
571 if(stack[ply-1].curr_move!=-1 &&
572 !board.pins[stack[ply-1].moves[ /* last moved piece is not attacking the king */
573 stack[ply-1].curr_move].to]) /* so this is a discover check */
575 depth += 50;
577 extended = true;
580 /* return now if the positon is terminal */
581 if(!s->num_moves)
583 if(s->under_check)
585 /* while mating, sacrify as much as possible :) */
586 best = -INF + ply;//*50 + board.material[IS_WHITE(eng_color)]/50;
588 else
589 best = 0;
590 goto search_done;
593 /* single-reply extension */
594 if(s->num_moves == 1 && !extended)
596 depth += 100;
597 extended = true;
599 else if(s->num_moves <= 3 && !extended)
601 depth += 50;
602 extended = true;
605 /*******************************************************************************
606 Sort the moves.
607 First comes the move from the hashtable, if avalable.
608 The remaining moves are sorted with a heuristic that keeps in account
609 the history heuristic (ie the moves that previously caused an alpha
610 cutoff), a MVV/LVA bonus value and a small bonus for moves that go
611 toward the center.
612 *******************************************************************************/
613 #if SORT_MOVES
615 #if HASH_HEURISTIC
617 /* convert the move we got from the hash to the move structure */
618 if(cbest_mv_hash)
620 best_mv_hash = board.uncompress_move(cbest_mv_hash);
621 /* if it happened that the move we got from the hashtable
622 is not valid, simply no move will get the high
623 heuristic bonus value */
625 #if INTERNAL_ITERATIVE_DEEPENING
626 else if(s->base_depth>300) /* don't do it only on the pv, or it will be useless :) */
628 int val = search( ply+1, s->base_depth-200, true, alpha, beta);
629 /*if (val >= beta)
630 val = search( ply+1, s->base_depth-200, true, alpha, INF, last_capture);*/
631 //if (val <= alpha)
632 // val = search( ply+1, s->base_depth-200, true, -INF, beta, last_capture);
634 /*HashEntry *h2 = probe_hash( board.hash );
635 if(h2 && h2->best_mv)
637 cbest_mv_hash = h2->best_mv;
638 best_mv_hash = board.uncompress_move(cbest_mv_hash);
641 #endif //INTERNAL_ITERATIVE_DEEPENING
642 #endif //HASH_HEURISTIC
644 /* for each move calculate the heuristic goodness value */
645 moves_heuristic( s->moves, s->num_moves, ply, s->base_depth,
646 best_mv_hash, quiesce );
648 /* if quiesce rip-off the "non-critical" moves */
649 if(quiesce)
651 int n = 0;
652 for(int i=0;i<s->num_moves;i++)
653 if(s->moves[i].val>=28000)
654 s->moves[n++] = s->moves[i];
655 mv_stack_top -= s->num_moves-n;
656 s->num_moves = n;
660 /* sort the moves using the heuristic values */
661 #if 0
662 sort_moves( s->moves, s->num_moves );
663 #endif
665 #if HISTORY_HEURISTIC
666 /* reset killer values for the 3-next search */
667 if(depth>=200)
669 memset( &killers[ply+3], 0, 64*64*sizeof(uint16_t));
670 /*memset( &history_hit[ply+3], 0, 64*64*sizeof(uint64_t));
671 memset( &history_tot[ply+3], 0, 64*64*sizeof(uint64_t));*/
673 #endif //HISTORY_HEURISTIC
674 #endif //SORT_MOVES
678 #if EARLY_TRANSP_CUTOFF && HASH_TABLE
679 /*******************************************************************************
680 Try to get an early beta cutoff using the hash table values
681 of the following moves, and improve alpha too.
682 Try on the first 6 value of the ordered moves (argh, looking into the
683 hashtable is very expensive because of the cache!!!!!!!!)
684 *******************************************************************************/
685 if(depth>=2*PLY)
686 for(int i=MIN(s->num_moves-1,10);i>0;i--)
688 HashKey hk = board.move_hash(s->moves[i]);
689 HashEntry *h2 = probe_hash( hk );
690 stat_hash_tot++;
692 if(h2 && h2->depth >= depth-100)
694 int16_t u = h2->upper();
695 if(-u >= beta)
697 /* increase the node count to simulate calling
698 the search function for this move */
699 stat_early_transp++;
700 processed_nodes++;
702 best = -u;
703 goto search_done;
707 #endif //EARLY_TRANSP_CUTOFF && HASH_TABLE
710 /* set the current best move index (as will be saved in the hash) */
711 best_mv_found = 0;
713 /*******************************************************************************
714 It is now time to loop all the successor moves and search recursively.
715 *******************************************************************************/
717 /* calcluate the evaluation (required by fitility pruning) */
718 position_val = quiesce ? best : board.evaluate( st_computer_color, -INF, INF);
720 /*for DEBUG*/
721 #ifdef DEBUG
722 {int w = IS_WHITE(board.color_to_move);
723 for(int i=0;i<s->num_moves;i++)
725 if(s->moves[i].from == board.king_pos[w] && DISTANCE(s->moves[i].to, board.king_pos[!w]) < 2)
726 ASSERT(!"Error!!!!");
728 #endif
730 for(int i=0;i<s->num_moves;i++)
732 int16_t val;
733 int sdepth = depth-100;
735 #if SORT_MOVES
736 /* sort moves incrementally, in the hope of a beta cut */
737 incremental_sort_moves(s->moves+i, s->num_moves-i);
738 #endif
740 /* calculate local search extensions */
741 #if 0
742 if(!extended)
744 //if(s->moves[i].extend) /* extensions calculated during the heuristic sort */
745 // sdepth += 100;
746 else if(s->moves[i].to == last_capture && board.move_see_val(s->moves[i])>=0)
747 sdepth += 100; /* recapture extension */
749 #endif
751 /* recapture extension */
752 static const int vallapiglia[] = { 0, 5, 3, 9, 3, 1, 0 };
753 if(stack[ply-1].curr_move!=-1)
755 Move& prev = stack[ply-1].moves[stack[ply-1].curr_move];
757 if(s->moves[i].to == prev.to)
759 if(vallapiglia[PIECE_OF(board.data[s->moves[i].to])]
760 == vallapiglia[PIECE_OF(prev.capture)])
761 depth += 50;
765 #if FUTILITY
766 /* futility pruning, it is done only if we are no under check
767 and the move is not a "critical" move */
768 if(depth<300 && !s->under_check && s->moves[i].val <28000)
770 static const int mavala[] = { 0, 490, 315, 980, 315, 100, 0 };
772 int16_t fmargin = quiesce ? 150 : (depth < 200 ? 320 : 850);
773 int16_t fval = position_val + mavala[PIECE_OF(s->moves[i].capture)];
774 if(fval < alpha-fmargin)
775 continue;
777 #endif
779 if(!s->moves[i].capture && !(s->moves[i].flags>=PROMOTE_FIRST))
780 history_tot[HISTORY_INDEX(s->moves[i])]++;
782 s->curr_move = i;
783 current_ply++;
784 board.do_move(s->moves[i]);
786 #if NEGA_SCOUT /* use negascout, (null window search for nodes that are not in the pv) */
787 if(i == 0) // || depth<200)
788 val = -search( ply+1, sdepth, pv, -beta, -alpha);
789 else
791 #if HISTORY_PRUNING
792 /* history pruning, if this is not a "critical" move and the failhigh
793 stats are too low, try a reduced depth search (if it returns >alpha,
794 re-do the full depth search) */
795 if( s->moves[i].val<28000 &&
796 (history_hit[HISTORY_INDEX(s->moves[i])]+1)
797 < (history_tot[HISTORY_INDEX(s->moves[i])]+1)/4)
799 val = -search( ply+1, sdepth - 100, false, -alpha-1, -alpha );
800 if(val <= alpha)
801 goto skip_search; /* reduced search was effective */
803 #endif
804 val = -search( ply+1, sdepth, false, -alpha-1, -alpha );
805 if((val>alpha) && pv)
806 val = -search( ply+1, sdepth, true, -beta, -alpha );
808 #else
809 /* normal full width alpha-beta */
810 val = -search( ply+1, sdepth, pv, -beta, -alpha );
811 #endif
812 skip_search:
813 board.undo_move(s->moves[i]);
814 current_ply--;
816 /* update the current best value and check for and alpha cut */
817 best = MAX(best, val);
818 if(best > alpha)
820 best_mv_found = i;
821 s->best_move = i;
823 /* alpha cut! */
824 alpha = best;
826 /* beta cut! */
827 if(best >= beta)
828 break;
831 /* update a few stats */
832 if(!quiesce)
834 if(best_mv_found==0)
836 if(best >= beta)
837 stat_best_cut++;
838 else
839 stat_best_first++;
841 stat_search_moves++;
842 if(ply==0 && depth>100)
844 if(best_mv_found==0)
846 if(best >= beta)
847 stat_best_cut0++;
848 else
849 stat_best_first0++;
851 stat_search_moves0++;
855 /* improve the heuristic value of the best move */
856 #if SORT_MOVES && HISTORY_HEURISTIC
857 for(int i=0;i<best_mv_found;i++)
859 uint16_t& val = killers[ply][HISTORY_INDEX(s->moves[i])];
860 val = MAX(val-2, 0);
861 //history_tot[HISTORY_INDEX(s->moves[i])]++;
863 killers[ply][HISTORY_INDEX(s->moves[best_mv_found])] += 3;
865 if(best >= beta &&
866 !s->moves[best_mv_found].capture &&
867 !(s->moves[best_mv_found].flags>=PROMOTE_FIRST))
868 history_hit[HISTORY_INDEX(s->moves[best_mv_found])]++;
869 //history_tot[HISTORY_INDEX(s->moves[best_mv_found])]++;
870 #endif //SORT_MOVES && HISTORY_HEURISTIC
872 search_done:
873 mv_stack_top -= s->num_moves; /* free the moves we allocated */
874 /*if(best_mv_found>=0 && skip_null)
875 strong_reply[ply] = mv[best_mv_found];
876 else
877 strong_reply[ply] = Move::FromInt(0);*/
879 #if HASH_TABLE
880 /* if we found a best move searching, that move will be saved.
881 if we did no search (ie quiescence), save the old hash value,
882 or -1 if no hash entry had been found */
883 int bestmv = cbest_mv_hash;
884 if(best_mv_found >= 0)
885 bestmv = board.compress_move(s->moves[best_mv_found]);
887 /* write the value in the hash, with the index of the best move */
888 write_hash( best > s->alpha ? best : -INF,
889 best < beta ? best : +INF,
890 MAX(s->base_depth,-500), bestmv);
891 #endif //HASH_TABLE
893 #if CONSISTENCY_EXTENSION
894 /* instability re-search, ie search deeper the nodes whose value
895 change a lot since last evaluation */
896 //if(!skip_inst)
897 if(s->base_depth < stack[ply-1].base_depth)
899 if( ((best < old_hash_lower-150) ||
900 (best > old_hash_upper+150) )
901 && old_hash_depth>=s->base_depth-100
902 && s->base_depth<=400 && s->base_depth>0)// && !skip_null )
903 return search(ply, s->base_depth+100, pv, alpha, beta );
905 #endif //CONSISTENCY_EXTENSION
907 return best;
911 Move Engine::find_best_move()
913 SearchStack *s = &stack[0];
914 Move retv;
915 Move result[80];
916 #if RE_SEARCH
917 bool research = true;
918 #endif //RE_SEARCH
920 ASSERT(!thinking);
922 /* initialize the root node */
923 current_ply = 0;
924 s->base_depth = 100;
925 s->extensions = 0;
926 s->curr_move = -1;
927 s->alpha = -INF;
928 s->beta = INF;
929 s->threat = Move::FromInt(0);
930 s->best_move = -1;
932 s->moves = mv_stack;
933 s->num_moves = mv_stack_top = board.find_moves(s->moves);
935 /* to print the analysis */
936 if(post)
937 output("\tply\tscore\ttime\tnodes\tpv\n");
939 /* return immediatly if the move is forced. */
940 if(s->num_moves==1)
941 return s->moves[0];
943 /* probe the play lines */
944 if( eng_status == PLAYING
945 && st_computer_color == board.color_to_move
946 && probe_lines( board.hash, &retv))
948 retv.val = 0;
949 return retv;
952 /* probe the book */
953 if(probe_book( board.hash, &retv)) {
954 for(int i=0;i<s->num_moves++;i++)
955 if(retv.as_int == s->moves[i].as_int)
957 retv.val = 0;
958 return retv;
960 output("Error!!! invalid move in the book!!!\n");
963 #if 0
964 prof_eval = 0;
965 prof_find_moves = 0;
966 prof_find_captures = 0;
967 prof_heuristic = 0;
968 prof_sort_moves = 0;
969 prof_move_is_check = 0;
970 prof_move_see_val = 0;
971 prof_tot = rdtsc();
972 #endif
974 stat_early_transp = 0;
975 stat_hash_tot = 0;
976 stat_hash_ex = 0;
977 stat_hash_low = 0;
978 stat_hash_upp = 0;
979 stat_best_first = 0;
980 stat_best_cut = 0;
981 stat_search_moves = 0;
982 stat_best_first0 = 0;
983 stat_best_cut0 = 0;
984 stat_search_moves0 = 0;
985 stat_evaluate = 0;
986 stat_evaluate_cutoff = 0;
987 stat_null_move = 0;
988 stat_null_cut = 0;
989 stat_hash_write = 0;
990 //reset_hash();
992 /* calculate how much time we will think*/
993 start_think_time = current_time();
994 if( analysis_limit == TIME_LIMIT )
996 if(board.color_to_move == st_computer_color)
997 calc_best_time();
998 else /* pondering? analysing? */
999 time_best_csec = 99999999;
1000 max_think_time = start_think_time + time_best_csec - 2;
1003 //analysis_color = board.color_to_move;
1004 processed_nodes = 0;
1005 thinking = true;
1006 make_old_hash();
1008 /* set the back jump for the quick thinking exit */
1009 if(setjmp(back))
1010 goto exit_thinking;
1012 /* start with a guess of 0 */
1013 s->moves[0].val = 0;
1014 retv = s->moves[0];
1016 /* do the iterative deepening thing. */
1017 while(1)
1019 int16_t alpha = -INF;
1020 int i=0;
1022 #if SORT_MOVES && HISTORY_HEURISTIC
1023 /* reset killer values for the next search */
1024 for(int i=0;i<40;i++)
1025 memset( &killers[i], 0, 64*64*sizeof(uint16_t));
1026 #endif
1027 memset( history_tot, 0, 64*64*sizeof(uint64_t));
1028 memset( history_hit, 0, 64*64*sizeof(uint64_t));
1030 /* save the result of the previous search */
1031 result[s->base_depth/PLY-1] = s->moves[0];
1033 /* for each move call the alpha-beta search function */
1034 int best_mv = 0;
1035 for(i=0;i<s->num_moves;i++)
1037 s->curr_move = i;
1038 current_ply++;
1039 board.do_move(s->moves[i]);
1040 #if NEGA_SCOUT
1041 if(i == 0)
1043 s->moves[i].val = -search( 1, s->base_depth-100, true,
1044 -INF, -alpha );
1046 else
1048 s->moves[i].val = -search( 1, s->base_depth-100, false,
1049 -alpha-1, -alpha );
1050 if(s->moves[i].val > alpha)
1051 s->moves[i].val = -search( 1, s->base_depth-100, true,
1052 -INF, -alpha );
1054 #else
1055 s->moves[i].val = -search( 1, s->base_depth-100, true,
1056 -INF, -alpha );
1057 #endif
1058 board.undo_move(s->moves[i]);
1059 current_ply--;
1062 /* cut alpha */
1063 if(s->moves[i].val > alpha)
1065 alpha = s->moves[i].val;
1066 retv = s->moves[i];
1067 best_mv = i;
1068 s->best_move = i;
1070 /* this move caused an alpha cut, so print the new line */
1071 if( post /*&& processed_nodes>100000*/)
1073 output("\t%d\t%d\t%d\t%llu\t", s->base_depth/100,
1074 s->moves[i].val, current_time() - start_think_time, processed_nodes);
1075 print_moves(&s->moves[i], 1, true);
1080 /* the search is done, sort the moves so that best is searched first */
1081 if(i>1)
1083 s->moves[best_mv].val++;
1084 sort_moves(s->moves, i); /* sort i moves (those that we where able to search) */
1085 s->moves[0].val--;
1088 /* print the result of the analysis at this depth */
1089 if( post /*&& processed_nodes>100000*/)
1091 output("\t%d\t%d\t%d\t%llu\t", s->base_depth/100,
1092 s->moves[0].val, current_time() - start_think_time, processed_nodes);
1093 print_moves(&s->moves[0], 1, true);
1096 /* max depth */
1097 if( s->base_depth >= 40*PLY )
1098 break;
1100 /* return in case of fixed depth search */
1101 if( eng_status == PLAYING && st_computer_color == board.color_to_move &&
1102 analysis_limit == DEPTH_LIMIT && s->base_depth == st_depth*PLY)
1103 break;
1105 /* return if 3/5 of time is gone (we can't search another ply anyway) */
1106 if( eng_status == PLAYING && st_computer_color == board.color_to_move &&
1107 analysis_limit == TIME_LIMIT &&
1108 (current_time()-start_think_time) >= (time_best_csec*3/5) )
1109 break;
1111 /* if a checkmate was detected return immediately */
1112 if( ABS(alpha) > INF-1000)
1113 break;
1115 #if RE_SEARCH
1116 if(!research)
1117 s->base_depth += PLY;
1118 else
1120 for(int i=0;i<(1<<21);i++)
1122 HashEntry* h = &hash_table[i];
1123 h->depth -= PLY;
1125 output(" -> (Hash purged)\n");
1127 research = !research;
1128 #else
1129 s->base_depth += PLY;
1130 #endif
1133 exit_thinking:
1135 if(post)
1137 #if 0
1138 prof_tot = rdtsc() - prof_tot;
1139 #define SHOW_PROF(a) output("@"#a": %llu (%llu%%)\n", \
1140 prof_##a, prof_##a*100/prof_tot);
1141 SHOW_PROF(tot);
1142 SHOW_PROF(eval);
1143 SHOW_PROF(do_move);
1144 SHOW_PROF(find_moves);
1145 SHOW_PROF(find_captures);
1146 SHOW_PROF(heuristic);
1147 SHOW_PROF(move_is_check);
1148 SHOW_PROF(move_see_val);
1149 SHOW_PROF(sort_moves);
1150 #endif
1151 output("#nodes: %llu (~%llu nps)\n", processed_nodes, (processed_nodes*100)/
1152 MAX(current_time()-start_think_time,1) );
1153 output("# %d times all the moves were seached (non-leaf non-quiesce node)\n",
1154 stat_search_moves);
1155 output("# of which %d times first move caused a cutoff\n", stat_best_cut);
1156 output("# of the remaining %d times first move was really best (%02d%%)\n",
1157 stat_best_first, (stat_best_first*100)/MAX(stat_search_moves-stat_best_cut, 1));
1158 output("# evaluate was called %d times (quiescence node)\n", stat_evaluate);
1159 output("# of which %d times caused an early cutoff (leaf node)\n",
1160 stat_evaluate_cutoff);
1161 output("#hash: %d writes, %d probes (%d succesful, =%d, >%d, <%d)\n",
1162 stat_hash_write, stat_hash_tot, stat_hash_ex+stat_hash_low+stat_hash_upp,
1163 stat_hash_ex, stat_hash_low, stat_hash_upp );
1164 output("#etc: %d\n", stat_early_transp);
1165 output("#null move: %d (%d succesful)\n", stat_null_move, stat_null_cut);
1168 thinking = false;
1169 return retv;