Removed killer, just use history. small cleanup.
[rattatechess.git] / search.cpp
blob0d2eed6fb3a7ea19db6592993ed0a96538a4d226
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 Move null_threat[MAX_PV];
27 bool null_threat_dangerous[MAX_PV];
29 #define HISTORY_SIZE (64*64)
30 uint16_t history_tot[HISTORY_SIZE];
31 uint16_t history_hit[HISTORY_SIZE];
33 #define HISTORY_INDEX(m) (SQUARE_TO_64(m.from)*64 + SQUARE_TO_64(m.to))
34 #define PROF(f,n) {uint64_t tmp = rdtsc(); f; prof_##n += rdtsc()-tmp; }
36 /*uint64_t prof_eval;
37 uint64_t prof_find_moves;
38 uint64_t prof_find_captures;
39 uint64_t prof_heuristic;
40 uint64_t prof_sort_moves;
41 uint64_t prof_do_move;
42 uint64_t prof_move_is_check;
43 uint64_t prof_move_see_val;
44 uint64_t prof_tot;*/
46 int stat_early_transp;
47 int stat_hash_write;
48 int stat_hash_tot;
49 int stat_hash_ex;
50 int stat_hash_low;
51 int stat_hash_upp;
52 int stat_best_cut;
53 int stat_best_first;
54 int stat_search_moves;
55 int stat_best_cut0;
56 int stat_best_first0;
57 int stat_search_moves0;
58 int stat_evaluate;
59 int stat_evaluate_cutoff;
60 int stat_null_move;
61 int stat_null_cut;
63 class QNode
65 public:
66 int num_children;
67 QNode* children;
68 Move move;
69 int depth;
70 int weight;
71 int16_t alpha;
72 int16_t beta;
73 int16_t value;
74 int type;
76 void del_children();
77 void print(int depth = 0);
78 void print_root(int depth = 0);
81 void QNode::del_children()
83 for(int i=0;i<num_children;i++)
84 children[i].del_children();
85 free(children);
88 void QNode::print_root(int depth)
90 for(int i=0;i<num_children;i++)
91 children[i].print(depth);
94 void QNode::print(int depth)
97 static const char* types[] = { "zero??", "DRAW", "HASH_LOW", "HASH_HIGH", "EVAL", "MATE", "SEARCH", };
98 char buf[256];
99 Engine::eng()->move_to_alg(buf, &move);
100 //printf("%d ", depth);
101 for(int i=0;i<depth;i++)printf("| ");
102 printf("|%s (weight=%d guess=%d value=%d depth=%d window=[%d %d] type=%s)\n", buf, weight,
103 move.val, value, this->depth, alpha, beta, types[type]);
105 Engine::eng()->board.do_move(move);
106 print_root(depth+1);
107 Engine::eng()->board.undo_move(move);
110 #if 0
111 #define STAT(x)
112 #else
114 #define S_ALL \
115 S(max_quiesce_nodes); \
116 S(quiesce_nodes); \
117 S(quiesce_hash); \
118 S(quiesce_called); \
119 S(quiesce_best_can_be_first); \
120 S(quiesce_best_was_first); \
121 S(quiesce_cutoff); \
122 S(quiesce_cutoff_first); \
123 S(search_nodes); \
124 S(search_hash); \
125 S(search_best_can_be_first); \
126 S(search_best_was_first); \
127 S(search_cutoff); \
128 S(search_cutoff_first); \
129 S(null_tried); \
130 S(null_successful);
132 #define STAT(x) stat_##x++;
134 #define S(x) uint64_t stat_##x;
135 S_ALL
136 Board max_quiesce_board;
137 int16_t max_quiesce_alpha;
138 int16_t max_quiesce_beta;
139 #undef S
141 void reset_stats()
143 #define S(x) stat_##x = 0;
144 S_ALL
145 #undef S
148 void print_stats()
150 #define S(x) printf("# " #x " = %llu\n", (unsigned long long)stat_##x);
151 S_ALL
152 #undef S
155 #endif
157 #define NEW_HEURISTIC 1
159 #define NEW_QUIESCENCE 0
161 /* enable the quiescence search */
162 #define QUIESCENCE 1
164 /* enable the nega-scout pv-search */
165 #define NEGA_SCOUT 1
167 /* enable the null move */
168 #define NULL_MOVE 1
170 /* enable hashing the positions */
171 #define HASH_TABLE 1
173 /* use the hastable to detect tranpositions */
174 #define TRANSP_TABLE 1
176 /* SEEMS TO BE QUITE BAD:
177 trust the values from a search at lower depth stored in the hashtable
178 to produce a cutoff, taking the value with a margin of uncertainity */
179 #define APPROX_TRANSP_CUTOFF 0
181 /* before doing the alpha beta search check if any of the following positions
182 can give use an early cutoff thanks to the hashtable */
183 #define EARLY_TRANSP_CUTOFF 1
185 /* SEEMS TO BE A BIT BAD:
186 when the we find that the values stored in the hash (the result of a
187 lighter search) were wrong by a big factor, this means that the node is
188 unstable, so re-search it */
189 #define CONSISTENCY_EXTENSION 0
191 /* SEEMS TO BE A BIT BAD:
192 Extend when there is only one decent move */
193 #define SINGULAR_EXTENSION 0
195 /* DANGEROUS:
196 reduce nodes for moves that are not check/captures that are considered
197 bad from the heuristic */
198 #define HISTORY_PRUNING 1
200 /* futility pruning: */
201 #define FUTILITY 0
203 /* sort the moves to improve alpha-beta cutoff */
204 #define SORT_MOVES 1
206 /* use the candidate move stored in the hashtable */
207 #define HASH_HEURISTIC 1
209 /* when the hashtable provides no "best" move, do a depth-2 search */
210 #define INTERNAL_ITERATIVE_DEEPENING 0
212 /* use the history sorting heuristic */
213 #define HISTORY_HEURISTIC 0
215 /* use the Max Value Victim/Least Value Attacker sorting heuristic */
216 #define MVV_LVA_HEURISTIC 1
218 /* improve the sorting heuristic for pawn strikes */
219 #define PAWNSTRIKE_HEURISTIC 1
221 /* improve the sorting heuristic for moves to the center */
222 #define CENTER_HEURISTIC 0
224 /* search 2 times per ply, to compare our move sorting to the perfect move sorting */
225 #define RE_SEARCH 0
228 class SearchStack
230 public:
231 int base_depth; /* depth of the search at this ply */
232 int extensions; /* global extensions at this node */
233 Move *moves; /* all generated moves */
234 int num_moves; /* num of moves */
235 int curr_move; /* the move being currently analyzed */
236 int16_t alpha; /* alpha ans beta when the search started (not improved) */
237 int16_t beta;
238 bool under_check;
239 Move threat;
240 int best_move;
243 Move mv_stack[200*MAX_PV];
244 int mv_stack_top = 0;
245 SearchStack stack[MAX_PV];
246 int current_ply = 0;
248 void Engine::print_stat()
250 if(eng_status != ANALYZING)
252 printf("Thinking: ");
253 for(int i=0; i<current_ply; i++)
255 if(stack[i].curr_move == -2)
257 continue;
258 } //Internal iterative deepening
259 else if(stack[i].curr_move == -1)
261 printf("<NULL>");
262 board.do_null_move();
264 else
266 char buf[32];
267 printf("%s", move_to_alg(buf, &(stack[i].moves[stack[i].curr_move]) ) );
268 board.do_move(stack[i].moves[stack[i].curr_move]);
270 printf((i != current_ply-1) ? " " : "\n");
272 rewind_thinking();
273 return;
276 if(thinking)
278 char buf[32];
279 output("stat01: %d %llu %d %d %d %s\n",
280 current_time() - start_think_time,
281 (unsigned long long)processed_nodes,
282 stack[0].base_depth/100,
283 stack[0].num_moves-1-stack[0].curr_move,
284 stack[0].num_moves,
285 move_to_alg(buf, &(stack[0].moves[stack[0].curr_move]) ) );
287 else
288 output("stat01: 0 0 0 0 0\n");
291 void Engine::rewind_thinking()
293 for(int i=current_ply-1; i>=0; i--)
295 if(stack[i].curr_move == -2)
297 else if(stack[i].curr_move == -1)
298 board.undo_null_move();
299 else
300 board.undo_move(stack[i].moves[stack[i].curr_move]);
304 void Engine::restore_thinking()
306 for(int i=0; i<current_ply; i++)
308 if(stack[i].curr_move == -2)
310 else if(stack[i].curr_move == -1)
311 board.do_null_move();
312 else
313 board.do_move(stack[i].moves[stack[i].curr_move]);
316 /* regenerate pinning info and under_check var, just to be sure :) */
317 Move mvs[250];
318 board.find_moves(mvs);
321 void
322 Engine::moves_heuristic(Move *mv, int num_mv, int ply, int orig_depth,
323 Move best_mv_hash, bool quiesce, Move* prev)
325 /*uint8_t up_right = Board::up_dir[IS_WHITE(board.color_to_move)] + RIGHT;
326 uint8_t up_left = Board::up_dir[IS_WHITE(board.color_to_move)] + LEFT;*/
327 int hash_move = -1;
329 for(int i=0;i<num_mv;i++)
331 mv[i].val = 0;
332 mv[i].extend = 0;
334 #if HASH_TABLE && HASH_HEURISTIC
335 /* give a high bonus to the move stored in the hash, if any.
336 mark only which is, don't continue, because some extensions
337 may be triggered ad added later (ie pawn strike, etc) */
338 if(mv[i].as_int == best_mv_hash.as_int)
339 hash_move = i;
340 #endif //HASH_HEURISTIC
342 #if 0
343 /* process strong pawn moves */
344 if(PIECE_OF(board.data[mv[i].from])==PAWN) /* pawn strike */
346 if( ROW_OF(mv[i].to) == board.seventh_rank[IS_WHITE(board.color_to_move)] )
348 int x = board.move_see_val(mv[i]);
350 if(x<0)
352 mv[i].val += -15000;
353 continue;
356 mv[i].val += 29499; /* 7th push */
357 mv[i].extend = 1; /* extend search */
358 continue;
361 if( mv[i].flags == PROMOTEQUEEN )
363 int x = board.move_see_val(mv[i]);
365 if(x<0)
367 mv[i].val += -15000;
368 continue;
371 mv[i].val += 29500; /* promote! */
372 mv[i].extend = 1; /* extend search */
373 continue;
376 #if 0
377 /* pawn strike */
378 uint8_t p1 = mv[i].to + up_right;
379 uint8_t p2 = mv[i].to + up_left;
380 uint8_t a = OUT_OF_BOARD(p1) ? 0 : board.data[p1];
381 uint8_t b = OUT_OF_BOARD(p2) ? 0 : board.data[p2];
382 if( (COLOR_OF(a)==board.other_color && PIECE_OF(a)!=PAWN)
383 || (COLOR_OF(b)==board.other_color && PIECE_OF(b)!=PAWN) )
385 int x = board.move_see_val(mv[i]);
386 if(x<0)
388 mv[i].val += -15000;
389 continue;
392 mv[i].val += 27000; /* pawn strike! */
393 mv[i].extend = 1; /* extend search */
394 continue;
396 #endif
398 #endif
399 if(mv[i].capture)
401 int x = board.move_see_val(mv[i]);
403 if(prev)
405 static const int vallapiglia[] = { 0, 5, 3, 9, 3, 1, 0 };
407 if(mv[i].to == prev->to)
408 if(x >= vallapiglia[PIECE_OF(prev->capture)])
410 mv[i].val = 29500;
411 continue;
415 if(x>0)
417 if(orig_depth>-7*PLY && board.move_is_check(mv[i]) )
418 mv[i].val = 29800+x;
419 else
420 mv[i].val = 29000+x;
421 continue;
423 else if(x>=0 && orig_depth>-7*PLY && board.move_is_check(mv[i]) )
425 /* = capture but check */
426 mv[i].val = 29800;
427 continue;
430 else /* add a bonus for checks (but not too deep, or quiescence will get mad) */
431 if(orig_depth>-3*PLY && board.move_is_check(mv[i]) )
433 if(board.move_see_val(mv[i])>=0)
435 mv[i].val = 28799;
436 continue;
440 if(null_threat[ply-1] == mv[i])
442 mv[i].val += 28500;
443 continue;
446 mv[i].val += history_hit[HISTORY_INDEX(mv[i])] * 512 / (history_tot[HISTORY_INDEX(mv[i])] + 4);
448 #if CENTER_HEURISTIC
449 static int bof[128] = {
450 0,0,1,2,2,1,0,0,ENDL,
451 0,1,2,3,3,2,1,0,ENDL,
452 0,2,4,5,5,4,2,0,ENDL,
453 1,2,5,6,6,5,2,1,ENDL,
454 1,2,5,6,6,5,2,1,ENDL,
455 0,2,4,5,5,4,2,0,ENDL,
456 0,1,2,3,3,2,1,0,ENDL,
457 0,0,1,2,2,1,0,0,ENDL
460 /* add a bonus for moves towards the center */
461 mv[i].val += (bof[mv[i].to] - bof[mv[i].from]);
462 #endif //CENTER_HEURISTIC
465 if(hash_move!=-1)
466 mv[hash_move].val = 30000;
469 #if 1
471 void
472 Engine::moves_quiescence_heuristic(Move *mv, int num_mv, const Move& best_mv_hash,
473 int static_eval, int alpha, int beta, int orig_depth, Move* prev)
475 for(int i=0;i<num_mv;i++)
477 mv[i].val = -10000;
478 mv[i].extend = 0;
480 #if HASH_TABLE && HASH_HEURISTIC
481 /* give a high bonus to the move stored in the hash, if any.
482 mark only which is, don't continue, because some extensions
483 may be triggered ad added later (ie pawn strike, etc) */
484 if(mv[i].as_int == best_mv_hash.as_int)
486 mv[i].val = 30000;
487 continue;
489 #endif //HASH_HEURISTIC
491 #if 0
492 /* process strong pawn moves */
493 if(PIECE_OF(board.data[mv[i].from])==PAWN) /* pawn strike */
495 if( ROW_OF(mv[i].to) == board.seventh_rank[IS_WHITE(board.color_to_move)] )
497 int x = board.move_see_val(mv[i]);
499 if(x<0)
501 mv[i].val += -15000;
502 continue;
505 mv[i].val += 29499; /* 7th push */
506 mv[i].extend = 1; /* extend search */
507 continue;
510 if( mv[i].flags == PROMOTEQUEEN )
512 int x = board.move_see_val(mv[i]);
514 if(x<0)
516 mv[i].val += -15000;
517 continue;
520 mv[i].val += 29500; /* promote! */
521 mv[i].extend = 1; /* extend search */
522 continue;
525 #if 0
526 /* pawn strike */
527 uint8_t p1 = mv[i].to + up_right;
528 uint8_t p2 = mv[i].to + up_left;
529 uint8_t a = OUT_OF_BOARD(p1) ? 0 : board.data[p1];
530 uint8_t b = OUT_OF_BOARD(p2) ? 0 : board.data[p2];
531 if( (COLOR_OF(a)==board.other_color && PIECE_OF(a)!=PAWN)
532 || (COLOR_OF(b)==board.other_color && PIECE_OF(b)!=PAWN) )
534 int x = board.move_see_val(mv[i]);
535 if(x<0)
537 mv[i].val += -15000;
538 continue;
541 mv[i].val += 27000; /* pawn strike! */
542 mv[i].extend = 1; /* extend search */
543 continue;
545 #endif
547 #endif
548 if(mv[i].capture)
550 int x = board.move_see_val(mv[i]);
552 if(prev)
554 static const int vallapiglia[] = { 0, 5, 3, 9, 3, 1, 0 };
556 if(mv[i].to == prev->to)
557 if(x >= vallapiglia[PIECE_OF(prev->capture)])
559 mv[i].val = 29500;
560 continue;
564 if(x>0)
566 if(orig_depth>-5*PLY && board.move_is_check(mv[i]) )
567 mv[i].val = 18000+x;
568 else
569 mv[i].val = 10000+x;
570 continue;
572 else if(x>=0 && orig_depth>-5*PLY && board.move_is_check(mv[i]) )
574 /* = capture but check */
575 mv[i].val = 18000;
576 continue;
579 else /* add a bonus for checks (but not too deep, or quiescence will get mad) */
580 if(orig_depth>-3*PLY && board.move_is_check(mv[i]) )
582 if(board.move_see_val(mv[i])>=0)
584 mv[i].val = 7990;
585 continue;
591 #else
593 void
594 Engine::moves_quiescence_heuristic(Move *mv, int num_mv, const Move& best_mv_hash,
595 int static_eval, int alpha, int beta, int depth, Move* prev)
597 for(int i=0;i<num_mv;i++)
599 mv[i].val = -30000;
600 mv[i].cost = 0;
602 /* give a high bonus to the move stored in the hash, if any. */
603 if(mv[i].as_int == best_mv_hash.as_int)
605 mv[i].val = 30000;
606 continue;
608 #if 0
609 if( mv[i].flags == PROMOTEQUEEN )
611 mv[i].val = 20000;
612 continue;
614 #endif
615 if(mv[i].capture)
617 int x = board.move_see_val(mv[i]);
619 if( (static_eval == -INF && x>0)
620 || (static_eval + x*100 + 100 > alpha) )
622 if( board.move_is_check(mv[i]) )
623 mv[i].val = 15000 + x*64;
624 else
625 mv[i].val = 10000 + x*64;
626 continue;
628 else
630 if( (depth >= -7*PLY) && board.move_is_check(mv[i]))
631 mv[i].val = 5000 + x*64;
632 else if( (depth >= -2*PLY) && (x >= 0) )
633 mv[i].val = 1000 + x*64;
634 continue;
638 if( (depth >= -3*PLY) && board.move_is_check(mv[i]) )
640 #if TRACK_ATTACKS
641 A88 atk = IS_WHITE(board.other_color) ? board.w_attacks : board.b_attacks;
642 A88 def = IS_WHITE(board.color_to_move) ? board.w_attacks : board.b_attacks;
644 if(atk[mv[i].to] && !def[mv[i].to])
646 mv[i].val = -5000;
647 mv[i].cost = 50;
649 else
651 mv[i].val = -2000;
652 mv[i].cost = 30;
654 #else
655 mv[i].val = 500;
656 #endif
657 continue;
662 #endif
664 QNode* quiescence_node = NULL;
666 //r1b3k1/2p2rpp/p1P5/1p2N3/6nq/N1P5/PP1P1bPP/R1BQR1K1 w - - 0 1
667 void
668 Engine::test_quiescence(int16_t alpha, int16_t beta)
670 QNode qroot;
671 quiescence_node = &qroot;
672 reset_stats();
674 quiesce(0, 100, alpha, beta);
675 qroot.print_root();
676 qroot.del_children();
677 print_stats();
678 quiescence_node = NULL;
681 int16_t
682 Engine::quiesce(int ply, int depth, int16_t alpha, int16_t beta)
684 SearchStack *s = &stack[ply];
685 int16_t static_eval = -INF;
686 int16_t best = -INF;
687 int16_t best_guessed = alpha;
688 uint16_t cbest_mv_hash = 0; /* the compressed move from the hash */
689 Move best_mv_hash = Move::FromInt(0); /* the move from the hash */
690 int best_mv_found = -1; /* the index of the best move AFTER searching */
691 bool dangerous_position = false;
693 QNode *info_node = quiescence_node;
694 if(info_node)info_node->children = 0;
695 if(info_node)info_node->num_children = 0;
696 if(info_node)info_node->type = 0;
697 if(info_node)info_node->depth = depth;
698 if(info_node)info_node->alpha = alpha;
699 if(info_node)info_node->beta = beta;
701 STAT(quiesce_nodes);
702 if(ply > 75)
704 rewind_thinking();
705 print_stat();
706 ASSERT(0);
707 exit(1);
710 s->base_depth = 0;
711 s->extensions = 0;
712 s->num_moves = 0;
713 s->curr_move = -3;
714 s->alpha = alpha;
715 s->beta = beta;
716 s->threat = Move::FromInt(0);
717 s->best_move = -1;
719 prefetch_hash( board.hash );
721 /* check if time is running out */
722 if(check_time())
723 return 0;
725 /* check for a draw for repetition or 50mvs. Of course the draw for
726 repetition must be checked BEFORE probing the hash :)*/
727 if(check_draw())
729 int16_t draw = (board.color_to_move == st_computer_color) ? v_eval_draw :
730 ((board.other_color == st_computer_color) ? -v_eval_draw : 0); /* be aggressive! */
731 if(info_node)info_node->value = draw;
732 if(info_node)info_node->type = 1;
733 return draw;
737 /*******************************************************************************
738 Probe the hashtable.
739 If the probe is succesful the hashtable will return us value
740 that can be exact, a lower bound or an upper bound, and if the
741 depth of the hashed search is >= the current depth this value
742 will be used to improve alpha and beta and possibly return immediatly.
743 The hastable will also give us a "best" move that will be searched
744 first.
745 This is the move that caused the "final" cutoff when this position
746 was searched previously. This best move is actually the index of the best
747 move in the array of generated moves (it is supposed to be deterministic :)
748 *******************************************************************************/
750 HashEntry *h = probe_hash( board.hash );
752 if(h)
754 int16_t l = h->lower();
755 int16_t u = h->upper();
757 if(l>=beta || u==l)
759 STAT(quiesce_hash);
760 if(info_node)info_node->value = l;
761 if(info_node)info_node->type = 2;
762 return l;
764 if(u<=alpha)
766 STAT(quiesce_hash);
767 if(info_node)info_node->value = u;
768 if(info_node)info_node->type = 3;
769 return u;
772 beta = MIN(beta, u);
773 alpha = MAX(alpha, l);
775 cbest_mv_hash = h->best_mv;
776 best_guessed = MAX(best_guessed, h->lower());
780 /*******************************************************************************
781 Test if we are under check, and if so extend search
782 *******************************************************************************/
784 s->under_check = board.under_attack(board.king_pos[IS_WHITE(board.color_to_move)],
785 board.other_color);
787 if(s->under_check)
788 dangerous_position = true;
789 // else
790 // {
791 // int d = 0;
792 // int num_mv;
793 // Move *mv = mv_stack + mv_stack_top;
794 // board.do_null_move();
795 // num_mv = board.find_moves(mv);
797 // for(int i=0;i<num_mv;i++)
798 // {
799 // if(!mv[i].capture)
800 // continue;
801 // if(board.move_see_val(mv[i])>0)
802 // d++;
803 // }
805 // board.undo_null_move();
806 // if(d >= 2)
807 // dangerous_position = true;
808 // }
810 if(ply > 50)
811 dangerous_position = false;
813 if(!dangerous_position)
815 best = static_eval = board.evaluate(st_computer_color, alpha, beta);
817 alpha = MAX(alpha, best);
818 if(best >= beta)
820 if(info_node)info_node->value = best;
821 if(info_node)info_node->type = 4;
822 goto qsearch_done;
825 if(ply>50)
826 goto qsearch_done;
830 /*******************************************************************************
831 Now generate the legal moves and look for a check/stalemate
832 *******************************************************************************/
834 /* generate all the legal moves */
835 s->moves = &mv_stack[mv_stack_top];
836 s->num_moves = board.find_moves(s->moves);
837 mv_stack_top += s->num_moves;
838 s->under_check = board.under_check;
840 /* return now if the positon is terminal */
841 if(!s->num_moves)
843 if(s->under_check)
844 /* while mating, sacrify as much as possible :) */
845 best = -INF + ply;//*50 + board.material[IS_WHITE(eng_color)]/50;
846 else
847 best = 0;
848 if(info_node)info_node->value = best;
849 if(info_node)info_node->type = 5;
850 goto qsearch_done;
854 /*******************************************************************************
855 Sort the moves.
856 First comes the move from the hashtable, if avalable.
857 The remaining moves are sorted with a heuristic that keeps in account
858 the history heuristic (ie the moves that previously caused an alpha
859 cutoff), a MVV/LVA bonus value and a small bonus for moves that go
860 toward the center.
861 *******************************************************************************/
863 /* convert the move we got from the hash to the move structure */
864 if(cbest_mv_hash)
866 best_mv_hash = board.uncompress_move(cbest_mv_hash);
867 /* if it happened that the move we got from the hashtable
868 is not valid, simply no move will get the high
869 heuristic bonus value */
872 /* for each move calculate the heuristic goodness value */
873 moves_quiescence_heuristic(s->moves, s->num_moves, best_mv_hash, static_eval, alpha, beta, depth, NULL);
875 /* if quiesce rip-off bad moves */
876 if(!dangerous_position)
878 int n = 0;
879 for(int i=0;i<s->num_moves;i++)
880 if(s->moves[i].val>=0)
881 s->moves[n++] = s->moves[i];
882 mv_stack_top -= s->num_moves-n;
883 s->num_moves = n;
886 /* sort the moves using the heuristic values */
887 if(s->num_moves > 1)
888 sort_moves( s->moves, s->num_moves );
890 /* set the current best move index (as will be saved in the hash) */
891 best_mv_found = 0;
893 /*******************************************************************************
894 It is now time to loop all the successor moves and search recursively.
895 *******************************************************************************/
897 if(info_node)info_node->children = (QNode*)malloc(sizeof(QNode)*s->num_moves);
899 for(int i=0;i<s->num_moves;i++)
901 int16_t val;
903 /* sort moves incrementally, in the hope of a beta cut */
904 //incremental_sort_moves(s->moves+i, s->num_moves-i);
906 uint64_t w = stat_quiesce_nodes;
907 if(info_node)info_node->num_children++;
908 if(info_node)quiescence_node = &info_node->children[i];
909 if(info_node)quiescence_node->move = s->moves[i];
911 s->curr_move = i;
912 current_ply++;
913 board.do_move(s->moves[i]);
914 val = -quiesce( ply+1, depth - 100, -beta, -alpha);
915 board.undo_move(s->moves[i]);
916 current_ply--;
918 if(info_node)info_node->children[i].weight = stat_quiesce_nodes-w;
920 /* update the current best value and check for and alpha cut */
921 best = MAX(best, val);
922 if(best > alpha)
924 best_mv_found = i;
925 s->best_move = i;
927 /* alpha cut! */
928 alpha = best;
931 /* beta cut! */
932 if(best >= beta)
934 STAT(quiesce_cutoff);
935 if(i==0)
936 STAT(quiesce_cutoff_first);
937 break;
941 if(info_node)info_node->value = best;
942 if(info_node)info_node->type = 6;
944 qsearch_done:
945 mv_stack_top -= s->num_moves; /* free the moves we allocated */
947 /* if we found a best move searching, that move will be saved.
948 if we did no search (ie quiescence), save the old hash value,
949 or -1 if no hash entry had been found */
950 int bestmv = cbest_mv_hash;
951 if(best_mv_found >= 0)
953 bestmv = board.compress_move(s->moves[best_mv_found]);
954 STAT(quiesce_best_can_be_first);
955 if(best_mv_found == 0)
956 STAT(quiesce_best_was_first);
959 /* write the value in the hash, with the index of the best move */
960 write_hash( best > s->alpha ? best : -INF,
961 best < beta ? best : +INF, 0, bestmv);
963 return best;
967 /*******************************************************************************
968 The main alpha-beta recursive search function.
969 It handles both normal search (with or without null move)
970 and quiescence search, because i have having 2 almost identical
971 function around.
972 *******************************************************************************/
973 int16_t Engine::search(int ply, int depth, bool pv, int16_t alpha, int16_t beta)
975 SearchStack *s = &stack[ply];
976 int16_t best = -INF;
977 uint16_t cbest_mv_hash = 0; /* the compressed move from the hash */
978 Move best_mv_hash = Move::FromInt(0); /* the move from the hash */
979 int best_mv_found = -1; /* the index of the best move AFTER searching */
980 bool quiesce;
981 bool extended = false;
982 int16_t position_val;
983 #if CONSISTENCY_EXTENSION
984 int old_hash_lower = -INF;
985 int old_hash_upper = INF;
986 int old_hash_depth = 0;
987 #endif //CONSISTENCY_EXTENSION
989 if(depth <= 0)
990 STAT(quiesce_nodes)
992 s->base_depth = depth;
993 s->extensions = 0;
994 s->num_moves = 0;
995 s->curr_move = -1;
996 s->alpha = alpha;
997 s->beta = beta;
998 s->threat = Move::FromInt(0);
999 s->best_move = -1;
1000 null_threat[ply] = Move::FromInt(0);
1001 null_threat_dangerous[ply] = false;
1003 /* check if time is running out */
1004 if(check_time())
1005 return 0;
1007 /* check for a draw for repetition or 50mvs. Of course the draw for
1008 repetition must be checked BEFORE probing the hash :)*/
1009 if(check_draw())
1010 return (board.color_to_move == st_computer_color) ? -35 :
1011 ((board.other_color == st_computer_color) ? 35 : 0); /* be aggressive! */
1013 #if HASH_TABLE
1014 /*******************************************************************************
1015 Probe the hashtable.
1016 If the probe is succesful the hashtable will return us value
1017 that can be exact, a lower bound or an upper bound, and if the
1018 depth of the hashed search is >= the current depth this value
1019 will be used to improve alpha and beta and possibly return immediatly.
1020 The hastable will also give us a "best" move that will be searched
1021 first.
1022 This is the move that caused the "final" cutoff when this position
1023 was searched previously. This best move is actually the index of the best
1024 move in the array of generated moves (it is supposed to be deterministic :)
1025 *******************************************************************************/
1026 stat_hash_tot++;
1027 HashEntry *h = probe_hash( board.hash );
1029 #if TRANSP_TABLE
1030 if(h && (h->depth >= s->base_depth))// || ABS(h->value)>INF-1000) )
1032 int16_t l = h->lower();
1033 int16_t u = h->upper();
1034 if(l>=beta || u==l)
1035 return l;
1036 if(u<=alpha)
1037 return u;
1039 beta = MIN(beta, u);
1040 alpha = MAX(alpha, l);
1043 #if APPROX_TRANSP_CUTOFF
1044 /* risky, we are assuming that the result of a search at lower
1045 depth will not be very different from the true result */
1046 if(h && depth<=300 && (h->depth >= depth-100))
1048 if(h->upper()+350<=alpha)
1049 return alpha;
1050 if(h->lower()-350>=beta)
1051 return beta;
1053 #endif //APPROX_TRANSP_CUTOFF
1054 #endif //TRANSP_TABLE
1056 #if HASH_HEURISTIC
1057 if(h)
1058 cbest_mv_hash = h->best_mv;
1059 #endif //HASH_HEURISTIC
1061 #if CONSISTENCY_EXTENSION
1062 /* save the bounds stored in the hash, so we can re-search unstable nodes */
1063 if(h)
1065 old_hash_lower = h->lo;
1066 old_hash_upper = h->up;
1067 old_hash_depth = h->depth;
1069 #endif //CONSISTENCY_EXTENSION
1071 #endif //HASH_TABLE
1074 /*******************************************************************************
1075 Test if we are under check, and if so extend search
1076 *******************************************************************************/
1078 s->under_check = board.under_attack(board.king_pos[IS_WHITE(board.color_to_move)],
1079 board.other_color);
1080 #if 0
1081 if(s->under_check)
1083 depth += PLY;
1084 extended = true;
1086 #endif
1088 /*******************************************************************************
1089 If it is time to quiesce, evaluate and test if we can exit
1090 immediately with a beta cut-off (try first a rough eval - delta)
1091 *******************************************************************************/
1092 #if NEW_QUIESCENCE
1093 quiesce = false;
1094 #else
1095 quiesce = ((!s->under_check) && (depth<=0)) || (depth<-60*PLY);
1096 #endif
1098 #if 0
1099 if(quiesce && depth>=-100)
1101 int num_mv;
1102 Move *mv = mv_stack + mv_stack_top;
1103 board.do_null_move();
1104 num_mv = board.find_moves(mv);
1106 for(int i=0;i<num_mv;i++)
1108 if(!mv[i].capture)
1109 continue;
1110 if(board.move_see_val(mv[i])>0)
1112 quiesce = false;
1113 break;
1117 board.undo_null_move();
1119 #endif
1121 if(quiesce)
1123 stat_evaluate++;
1124 best = board.evaluate(st_computer_color, alpha, beta);
1126 alpha = MAX(alpha, best);
1127 if(best >= beta)
1129 stat_evaluate_cutoff++;
1130 goto search_done;
1133 //best =0;
1134 #if QUIESCENCE
1135 if(ply>60)
1136 #endif //QUIESCENCE
1137 goto search_done;
1141 #if NULL_MOVE
1142 /*******************************************************************************
1143 Try the null move.
1144 *******************************************************************************/
1145 if(!s->under_check && (stack[ply-1].curr_move != -1) && depth >= 2*PLY && beta<INF-1000)
1147 int16_t val;
1148 int sdepth = depth-3*PLY;
1150 stat_null_move++;
1151 s->curr_move = -1;
1152 current_ply++;
1153 board.do_null_move();
1154 val = -search( ply+1, sdepth, true, -beta, -beta+1);
1155 board.undo_null_move();
1156 current_ply--;
1158 /* null move cut! */
1159 if(val >= beta)
1161 stat_null_cut++;
1162 return val;
1165 if(val < -INF+1000)
1166 null_threat_dangerous[ply] = true;
1167 #if 0
1168 if(val<alpha-100 && /* we are facing a threat*/
1169 stack[ply+1].best_move != -1) /* be sure we aren't reading random memory */
1171 /* ok, officially the array stack[ply+1].moves has already
1172 been deallocated, but who cares :) */
1173 s->threat = stack[ply+1].moves[stack[ply+1].best_move];
1175 #if 0
1176 /* Botvinnik-Markoff extension!!! */
1177 if(!extended && ply>=3 && (s->threat == stack[ply-2].threat) )
1179 depth += 80;
1180 extended = true;
1182 #endif
1184 #endif
1186 #endif
1190 /*******************************************************************************
1191 Now generate the legal moves and look for a check/stalemate
1192 *******************************************************************************/
1194 /* generate all the legal moves */
1195 s->moves = &mv_stack[mv_stack_top];
1196 s->num_moves = board.find_moves(s->moves);
1197 mv_stack_top += s->num_moves;
1198 s->under_check = board.under_check;
1200 if(s->under_check==2) /* double check */
1202 depth += 200;
1203 extended = true;
1205 else if(s->under_check) /* simple check */
1207 depth += 100;
1208 if(stack[ply-1].curr_move>=0 &&
1209 !board.pins[stack[ply-1].moves[ /* last moved piece is not attacking the king */
1210 stack[ply-1].curr_move].to]) /* so this is a discover check */
1212 depth += 50;
1214 extended = true;
1217 /* return now if the positon is terminal */
1218 if(!s->num_moves)
1220 if(s->under_check)
1222 /* while mating, sacrify as much as possible :) */
1223 best = -INF + ply;//*50 + board.material[IS_WHITE(eng_color)]/50;
1225 else
1226 best = 0;
1227 goto search_done;
1230 /* single-reply extension */
1231 if(s->num_moves == 1 && !extended)
1233 depth += 100;
1234 extended = true;
1236 else if(s->num_moves <= 3 && !extended)
1238 depth += 50;
1239 extended = true;
1242 /*******************************************************************************
1243 Sort the moves.
1244 First comes the move from the hashtable, if avalable.
1245 The remaining moves are sorted with a heuristic that keeps in account
1246 the history heuristic (ie the moves that previously caused an alpha
1247 cutoff), a MVV/LVA bonus value and a small bonus for moves that go
1248 toward the center.
1249 *******************************************************************************/
1250 #if SORT_MOVES
1252 #if HASH_HEURISTIC
1254 /* convert the move we got from the hash to the move structure */
1255 if(cbest_mv_hash)
1257 best_mv_hash = board.uncompress_move(cbest_mv_hash);
1258 /* if it happened that the move we got from the hashtable
1259 is not valid, simply no move will get the high
1260 heuristic bonus value */
1262 #if INTERNAL_ITERATIVE_DEEPENING
1263 else if(s->base_depth>3*PLY && pv) /* don't do it only on the pv, or it will be useless :) */
1265 s->curr_move = -2;
1266 current_ply++;
1267 int val = search(ply+1, s->base_depth-2*PLY, true, alpha, beta);
1268 current_ply--;
1270 HashEntry *h2 = probe_hash( board.hash );
1271 if(h2 && h2->best_mv)
1273 cbest_mv_hash = h2->best_mv;
1274 best_mv_hash = board.uncompress_move(cbest_mv_hash);
1277 #endif //INTERNAL_ITERATIVE_DEEPENING
1278 #endif //HASH_HEURISTIC
1280 /* for each move calculate the heuristic goodness value */
1282 Move *prev = (stack[ply-1].curr_move>=0) ? &stack[ply-1].moves[stack[ply-1].curr_move] : NULL;
1283 #if NEW_HEURISTIC
1284 if(quiesce)
1285 moves_quiescence_heuristic( s->moves, s->num_moves, best_mv_hash,
1286 best, alpha, beta, s->base_depth, prev);
1287 else
1288 #endif
1289 moves_heuristic( s->moves, s->num_moves, ply, s->base_depth,
1290 best_mv_hash, quiesce, prev );
1293 /* if quiesce rip-off the "non-critical" moves */
1294 if(quiesce)
1296 int n = 0;
1297 for(int i=0;i<s->num_moves;i++)
1298 if(s->moves[i].val>0)
1299 s->moves[n++] = s->moves[i];
1300 mv_stack_top -= s->num_moves-n;
1301 s->num_moves = n;
1304 //sort_moves( s->moves, s->num_moves );
1305 #endif //SORT_MOVES
1309 #if EARLY_TRANSP_CUTOFF && HASH_TABLE
1310 /*******************************************************************************
1311 Try to get an early beta cutoff using the hash table values
1312 of the following moves, and improve alpha too.
1313 Try on the first 6 value of the ordered moves (argh, looking into the
1314 hashtable is very expensive because of the cache!!!!!!!!)
1315 *******************************************************************************/
1316 if(depth>=2*PLY)
1317 for(int i=MIN(s->num_moves-1,10);i>0;i--)
1319 HashKey hk = board.move_hash(s->moves[i]);
1320 HashEntry *h2 = probe_hash( hk );
1321 stat_hash_tot++;
1323 if(h2 && h2->depth >= depth-100)
1325 int16_t u = h2->upper();
1326 if(-u >= beta)
1328 /* increase the node count to simulate calling
1329 the search function for this move */
1330 stat_early_transp++;
1331 processed_nodes++;
1333 best = -u;
1334 goto search_done;
1338 #endif //EARLY_TRANSP_CUTOFF && HASH_TABLE
1341 /* set the current best move index (as will be saved in the hash) */
1342 best_mv_found = 0;
1344 /*******************************************************************************
1345 It is now time to loop all the successor moves and search recursively.
1346 *******************************************************************************/
1348 /* calcluate the evaluation (required by fitility pruning) */
1349 position_val = quiesce ? best : board.evaluate( st_computer_color, -INF, INF);
1351 for(int i=0;i<s->num_moves;i++)
1353 int16_t val;
1354 int sdepth = depth-100;
1356 #if SORT_MOVES
1357 /* sort moves incrementally, in the hope of a beta cut */
1358 incremental_sort_moves(s->moves+i, s->num_moves-i);
1359 #endif
1361 if(s->moves[i].extend) /* extensions calculated during the heuristic sort */
1362 sdepth += PLY;
1364 #if 1
1365 /* recapture extension */
1366 static const int vallapiglia[] = { 0, 5, 3, 9, 3, 1, 0 };
1367 if(s->moves[i].capture && stack[ply-1].curr_move>=0)
1369 Move& prev = stack[ply-1].moves[stack[ply-1].curr_move];
1371 if(s->moves[i].to == prev.to)
1373 if(vallapiglia[PIECE_OF(board.data[s->moves[i].to])]
1374 == vallapiglia[PIECE_OF(prev.capture)]
1375 && board.move_see_val(s->moves[i]) == vallapiglia[PIECE_OF(prev.capture)] )
1376 sdepth += PIECE_OF(s->moves[i].capture) == PAWN ? 50 : 100;
1379 #endif
1381 #if FUTILITY
1382 /* futility pruning, it is done only if we are no under check
1383 and the move is not a "critical" move */
1384 if(depth>0 && depth<3*PLY && !s->under_check && s->moves[i].val < 28000)
1386 static const int mavala[] = { 0, 490, 315, 980, 315, 100, 0 };
1388 int16_t fmargin = (depth <= PLY ? 420 : 950);
1389 int16_t fval = position_val + mavala[PIECE_OF(s->moves[i].capture)];
1390 if(fval < alpha-fmargin)
1391 continue;
1393 #endif
1395 if((!s->moves[i].capture || PIECE_OF(s->moves[i].capture)==PAWN) && !(s->moves[i].flags>=PROMOTE_FIRST))
1397 int ix = HISTORY_INDEX(s->moves[i]);
1398 if(history_tot[ix] > 1024)
1400 history_tot[ix] >>= 1;
1401 history_hit[ix] >>= 1;
1403 history_tot[ix]++;
1406 s->curr_move = i;
1407 current_ply++;
1408 board.do_move(s->moves[i]);
1410 #if NEW_QUIESCENCE
1411 if(sdepth <= 0)
1413 uint64_t q = stat_quiesce_nodes;
1414 STAT(quiesce_called);
1415 val = -this->quiesce( ply+1, 0, -beta, -alpha);
1416 q = stat_quiesce_nodes-q;
1417 if(q > stat_max_quiesce_nodes)
1419 stat_max_quiesce_nodes = q;
1420 max_quiesce_board = board;
1421 max_quiesce_alpha = -beta;
1422 max_quiesce_beta = -alpha;
1425 else
1426 #endif
1428 uint64_t q;
1429 if(s->base_depth > 0 && sdepth <= 0)
1431 STAT(quiesce_called);
1432 q = stat_quiesce_nodes;
1435 #if NEGA_SCOUT /* use negascout, (null window search for nodes that are not in the pv) */
1436 if(quiesce || i == 0) // || depth<200)
1437 val = -search( ply+1, sdepth, pv, -beta, -alpha);
1438 else
1440 #if HISTORY_PRUNING
1441 /* history pruning, if this is not a "critical" move and the failhigh
1442 stats are too low, try a reduced depth search (if it returns >alpha,
1443 re-do the full depth search) */
1444 if( !quiesce && !s->under_check && depth<=3*PLY && s->moves[i].val<28000 &&
1445 (history_hit[HISTORY_INDEX(s->moves[i])]+1)*3
1446 < (history_tot[HISTORY_INDEX(s->moves[i])]+1) )
1448 val = -search( ply+1, sdepth - 100, false, -alpha-1, -alpha );
1449 if(val <= alpha)
1450 goto skip_search; /* reduced search was effective */
1452 #endif
1453 val = -search( ply+1, sdepth, false, -alpha-1, -alpha );
1454 if((val>alpha) && pv)
1455 val = -search( ply+1, sdepth, true, -beta, -alpha );
1457 #else
1458 /* normal full width alpha-beta */
1459 val = -search( ply+1, sdepth, pv, -beta, -alpha );
1460 #endif
1462 if(s->base_depth > 0 && sdepth <= 0)
1464 q = stat_quiesce_nodes-q;
1465 if(q > stat_max_quiesce_nodes)
1467 stat_max_quiesce_nodes = q;
1468 max_quiesce_board = board;
1472 skip_search:
1473 board.undo_move(s->moves[i]);
1474 current_ply--;
1476 /* update the current best value and check for and alpha cut */
1477 best = MAX(best, val);
1478 if(best > alpha)
1480 best_mv_found = i;
1481 s->best_move = i;
1483 /* alpha cut! */
1484 alpha = best;
1486 /* beta cut! */
1487 if(best >= beta)
1488 break;
1491 /* update a few stats */
1492 if(!quiesce)
1494 if(best_mv_found==0)
1496 if(best >= beta)
1497 stat_best_cut++;
1498 else
1499 stat_best_first++;
1501 stat_search_moves++;
1502 if(ply==0 && depth>100)
1504 if(best_mv_found==0)
1506 if(best >= beta)
1507 stat_best_cut0++;
1508 else
1509 stat_best_first0++;
1511 stat_search_moves0++;
1515 if(best >= beta &&
1516 !s->moves[best_mv_found].capture &&
1517 !(s->moves[best_mv_found].flags>=PROMOTE_FIRST))
1519 history_hit[HISTORY_INDEX(s->moves[best_mv_found])]++;
1520 history_tot[HISTORY_INDEX(s->moves[best_mv_found])]++;
1523 search_done:
1524 mv_stack_top -= s->num_moves; /* free the moves we allocated */
1525 /*if(best_mv_found>=0 && skip_null)
1526 strong_reply[ply] = mv[best_mv_found];
1527 else
1528 strong_reply[ply] = Move::FromInt(0);*/
1530 if(stack[ply-1].curr_move == -1 && best_mv_found >= 0)
1531 null_threat[ply-1] = s->moves[best_mv_found];
1533 #if HASH_TABLE
1534 /* if we found a best move searching, that move will be saved.
1535 if we did no search (ie quiescence), save the old hash value,
1536 or -1 if no hash entry had been found */
1537 int bestmv = cbest_mv_hash;
1538 if(best_mv_found >= 0)
1539 bestmv = board.compress_move(s->moves[best_mv_found]);
1541 /* write the value in the hash, with the index of the best move */
1542 write_hash( best > s->alpha ? best : -INF,
1543 best < beta ? best : +INF,
1544 MAX(s->base_depth,-500), bestmv);
1545 #endif //HASH_TABLE
1547 #if CONSISTENCY_EXTENSION
1548 /* instability re-search, ie search deeper the nodes whose value
1549 change a lot since last evaluation */
1550 //if(!skip_inst)
1551 if(s->base_depth < stack[ply-1].base_depth)
1553 if( ((best < old_hash_lower-150) ||
1554 (best > old_hash_upper+150) )
1555 && old_hash_depth>=s->base_depth-100
1556 && s->base_depth<=400 && s->base_depth>0)// && !skip_null )
1557 return search(ply, s->base_depth+100, pv, alpha, beta );
1559 #endif //CONSISTENCY_EXTENSION
1561 return best;
1564 //r1b3k1/2p2rpp/p1P5/1p2N3/6nq/N1P5/PP1P1bPP/R1BQR1K1 w - - 0 14
1565 Move Engine::find_best_move()
1567 SearchStack *s = &stack[0];
1568 Move retv;
1569 Move result[80];
1570 #if RE_SEARCH
1571 bool research = true;
1572 #endif //RE_SEARCH
1574 ASSERT(!thinking);
1576 /* initialize the root node */
1577 current_ply = 0;
1578 s->base_depth = 100;
1579 s->extensions = 0;
1580 s->curr_move = -1;
1581 s->alpha = -INF;
1582 s->beta = INF;
1583 s->threat = Move::FromInt(0);
1584 s->best_move = -1;
1586 s->moves = mv_stack;
1587 s->num_moves = mv_stack_top = board.find_moves(s->moves);
1589 /* to print the analysis */
1590 if(post)
1591 output("\tply\tscore\ttime\tnodes\tpv\n");
1593 /* return immediatly if the move is forced. */
1594 if(s->num_moves==1)
1595 return s->moves[0];
1597 /* probe the play lines */
1598 if( eng_status == PLAYING
1599 && st_computer_color == board.color_to_move
1600 && probe_lines( board.hash, &retv))
1602 retv.val = 0;
1603 return retv;
1606 /* probe the book */
1607 if(probe_book( board.hash, &retv)) {
1608 for(int i=0;i<s->num_moves++;i++)
1609 if(retv.as_int == s->moves[i].as_int)
1611 retv.val = 0;
1612 return retv;
1614 output("Error!!! invalid move in the book!!!\n");
1617 #if 0
1618 prof_eval = 0;
1619 prof_find_moves = 0;
1620 prof_find_captures = 0;
1621 prof_heuristic = 0;
1622 prof_sort_moves = 0;
1623 prof_move_is_check = 0;
1624 prof_move_see_val = 0;
1625 prof_tot = rdtsc();
1626 #endif
1628 stat_early_transp = 0;
1629 stat_hash_tot = 0;
1630 stat_hash_ex = 0;
1631 stat_hash_low = 0;
1632 stat_hash_upp = 0;
1633 stat_best_first = 0;
1634 stat_best_cut = 0;
1635 stat_search_moves = 0;
1636 stat_best_first0 = 0;
1637 stat_best_cut0 = 0;
1638 stat_search_moves0 = 0;
1639 stat_evaluate = 0;
1640 stat_evaluate_cutoff = 0;
1641 stat_null_move = 0;
1642 stat_null_cut = 0;
1643 stat_hash_write = 0;
1645 reset_stats();
1646 //reset_hash();
1648 /* calculate how much time we will think*/
1649 start_think_time = current_time();
1650 if( analysis_limit == TIME_LIMIT )
1652 if(board.color_to_move == st_computer_color)
1653 calc_best_time();
1654 else /* pondering? analysing? */
1655 time_best_csec = 99999999;
1656 max_think_time = start_think_time + time_best_csec - 2;
1659 //analysis_color = board.color_to_move;
1660 processed_nodes = 0;
1661 int16_t best_guess = 0;
1662 thinking = true;
1663 make_old_hash();
1665 /* set the back jump for the quick thinking exit */
1666 if(setjmp(back))
1667 goto exit_thinking;
1669 /* start with a guess of 0 */
1670 s->moves[0].val = 0;
1671 retv = s->moves[0];
1673 /* do the iterative deepening thing. */
1674 while(1)
1676 int16_t alpha = -INF;
1677 int i=0;
1679 memset( history_tot, 0, HISTORY_SIZE*sizeof(uint16_t));
1680 memset( history_hit, 0, HISTORY_SIZE*sizeof(uint16_t));
1682 /* save the result of the previous search */
1683 result[s->base_depth/PLY-1] = s->moves[0];
1685 /* for each move call the alpha-beta search function */
1686 int best_mv = 0;
1687 for(i=0;i<s->num_moves;i++)
1689 s->curr_move = i;
1690 current_ply++;
1691 board.do_move(s->moves[i]);
1692 #if NEGA_SCOUT
1693 if(i == 0)
1695 s->moves[i].val = -search( 1, s->base_depth-PLY, true, -INF, -alpha );
1697 else
1699 s->moves[i].val = -search( 1, s->base_depth-PLY, false, -alpha-1, -alpha );
1700 if(s->moves[i].val > alpha)
1701 s->moves[i].val = -search( 1, s->base_depth-PLY, true, -INF, -alpha );
1703 #else
1704 s->moves[i].val = -search( 1, s->base_depth-100, true, -INF, -alpha );
1705 #endif
1706 board.undo_move(s->moves[i]);
1707 current_ply--;
1710 /* cut alpha */
1711 if(s->moves[i].val > alpha)
1713 alpha = s->moves[i].val;
1714 retv = s->moves[i];
1715 best_mv = i;
1716 s->best_move = i;
1718 /* this move caused an alpha cut, so print the new line */
1719 if( post /*&& processed_nodes>100000*/)
1721 output("\t%d\t%d\t%d\t%llu\t", s->base_depth/100,
1722 s->moves[i].val, current_time() - start_think_time, processed_nodes);
1723 print_moves(&s->moves[i], 1, true);
1728 best_guess = alpha;
1730 /* the search is done, sort the moves so that best is searched first */
1731 if(i>1)
1733 s->moves[best_mv].val++;
1734 sort_moves(s->moves, i); /* sort i moves (those that we where able to search) */
1735 s->moves[0].val--;
1738 /* print the result of the analysis at this depth */
1739 if( post /*&& processed_nodes>100000*/)
1741 output("\t%d\t%d\t%d\t%llu\t", s->base_depth/100,
1742 s->moves[0].val, current_time() - start_think_time, processed_nodes);
1743 print_moves(&s->moves[0], 1, true);
1746 /* max depth */
1747 if( s->base_depth >= 40*PLY )
1748 break;
1750 /* return in case of fixed depth search */
1751 if( eng_status == PLAYING && st_computer_color == board.color_to_move &&
1752 analysis_limit == DEPTH_LIMIT && s->base_depth == st_depth*PLY)
1753 break;
1755 /* return if 3/5 of time is gone (we can't search another ply anyway) */
1756 if( eng_status == PLAYING && st_computer_color == board.color_to_move &&
1757 analysis_limit == TIME_LIMIT &&
1758 (current_time()-start_think_time) >= (time_best_csec*3/5) )
1759 break;
1761 /* if a checkmate was detected return immediately */
1762 if( ABS(alpha) > INF-1000)
1763 break;
1765 #if RE_SEARCH
1766 if(!research)
1767 s->base_depth += PLY;
1768 else
1770 for(int i=0;i<(1<<21);i++)
1772 HashEntry* h = &hash_table[i];
1773 h->depth -= PLY;
1775 output(" -> (Hash purged)\n");
1777 research = !research;
1778 #else
1779 s->base_depth += PLY;
1780 #endif
1783 exit_thinking:
1785 if(post)
1787 #if 0
1788 prof_tot = rdtsc() - prof_tot;
1789 #define SHOW_PROF(a) output("@"#a": %llu (%llu%%)\n", \
1790 prof_##a, prof_##a*100/prof_tot);
1791 SHOW_PROF(tot);
1792 SHOW_PROF(eval);
1793 SHOW_PROF(do_move);
1794 SHOW_PROF(find_moves);
1795 SHOW_PROF(find_captures);
1796 SHOW_PROF(heuristic);
1797 SHOW_PROF(move_is_check);
1798 SHOW_PROF(move_see_val);
1799 SHOW_PROF(sort_moves);
1800 #endif
1801 output("#nodes: %llu (~%llu nps)\n", processed_nodes, (processed_nodes*100)/
1802 MAX(current_time()-start_think_time,1) );
1803 output("# %d times all the moves were seached (non-leaf non-quiesce node)\n",
1804 stat_search_moves);
1805 output("# of which %d times first move caused a cutoff\n", stat_best_cut);
1806 output("# of the remaining %d times first move was really best (%02d%%)\n",
1807 stat_best_first, (stat_best_first*100)/MAX(stat_search_moves-stat_best_cut, 1));
1808 output("# evaluate was called %d times (quiescence node)\n", stat_evaluate);
1809 output("# of which %d times caused an early cutoff (leaf node)\n",
1810 stat_evaluate_cutoff);
1811 output("#hash: %d writes, %d probes (%d succesful, =%d, >%d, <%d)\n",
1812 stat_hash_write, stat_hash_tot, stat_hash_ex+stat_hash_low+stat_hash_upp,
1813 stat_hash_ex, stat_hash_low, stat_hash_upp);
1814 output("#etc: %d\n", stat_early_transp);
1815 output("#null move: %d (%d succesful)\n", stat_null_move, stat_null_cut);
1817 print_stats();
1818 char buf[256];
1819 max_quiesce_board.write_board(buf);
1820 output("#max quiesce board: %s [%d %d]\n", buf, max_quiesce_alpha, max_quiesce_beta);
1823 thinking = false;
1824 return retv;