1 /***************************************************************************
2 search.cpp - description
4 begin : Wed Mar 13 2002
5 copyright : (C) 2002-2005 by Monge Maurizio
6 email : monge@linuz.sns.it
7 ***************************************************************************/
9 /***************************************************************************
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. *
16 ***************************************************************************/
28 // uint16_t killers[MAX_PV][64*64];
30 // #define HISTORY_INDEX(m) (SQUARE_TO_64(m.from)*64 + SQUARE_TO_64(m.to))
34 /* enable the nega-scout pv-search */
37 /* enable the null move */
40 /* before doing the alpha beta search check if any of the following positions
41 can give use an early cutoff thanks to the hashtable */
42 #define EARLY_TRANSP_CUTOFF 0
44 /* when the hashtable provides no "best" move, do a depth-2 search */
45 #define INTERNAL_ITERATIVE_DEEPENING 0
47 /* use the history sorting heuristic */
48 #define HISTORY_HEURISTIC 1
50 /* improve the sorting heuristic for moves to the center */
51 #define CENTER_HEURISTIC 0
56 int base_depth; /* depth of the search at this ply */
57 int extensions; /* global extensions at this node */
58 Move *moves; /* all generated moves */
59 int num_moves; /* num of moves */
60 int curr_move; /* the move being currently analyzed */
61 int16_t alpha; /* alpha ans beta when the search started (not improved) */
68 Move mv_stack[200*MAX_PV];
70 SearchStack stack[MAX_PV];
76 #define STAT(x) stat_##x++;
78 #define S(x) uint64_t stat_##x;
82 S(quiesce_best_can_be_first);
83 S(quiesce_best_was_first);
85 S(quiesce_cutoff_first);
88 S(search_best_can_be_first);
89 S(search_best_was_first);
91 S(search_cutoff_first);
98 #define S(x) stat_##x = 0;
102 S(quiesce_best_can_be_first);
103 S(quiesce_best_was_first);
105 S(quiesce_cutoff_first);
108 S(search_best_can_be_first);
109 S(search_best_was_first);
111 S(search_cutoff_first);
119 #define S(x) printf("# " #x " = "U64F"\n", stat_##x);
123 S(quiesce_best_can_be_first);
124 S(quiesce_best_was_first);
126 S(quiesce_cutoff_first);
129 S(search_best_can_be_first);
130 S(search_best_was_first);
132 S(search_cutoff_first);
140 void Engine::print_stat()
142 if(eng_status != ANALYZING)
144 printf("Thinking: ");
145 for(int i=0; i<current_ply; i++)
147 if(stack[i].curr_move == -2)
150 } //Internal iterative deepening
151 else if(stack[i].curr_move == -1)
154 board.do_null_move();
159 printf("%s", move_to_alg(buf, &(stack[i].moves[stack[i].curr_move]) ) );
160 board.do_move(stack[i].moves[stack[i].curr_move]);
162 printf((i != current_ply-1) ? " " : "\n");
171 output("stat01: %d "U64F" %d %d %d %s\n",
172 current_time() - start_think_time,
174 stack[0].base_depth/100,
175 stack[0].num_moves-1-stack[0].curr_move,
177 move_to_alg(buf, &(stack[0].moves[stack[0].curr_move]) ) );
180 output("stat01: 0 0 0 0 0\n");
183 void Engine::rewind_thinking()
185 for(int i=current_ply-1; i>=0; i--)
187 if(stack[i].curr_move == -2)
188 { } //Internal iterative deepening
189 else if(stack[i].curr_move == -1)
190 board.undo_null_move();
192 board.undo_move(stack[i].moves[stack[i].curr_move]);
196 void Engine::restore_thinking()
198 for(int i=0; i<current_ply; i++)
200 if(stack[i].curr_move == -2)
201 { } //Internal iterative deepening
202 else if(stack[i].curr_move == -1)
203 board.do_null_move();
205 board.do_move(stack[i].moves[stack[i].curr_move]);
208 /* regenerate pinning info and under_check var, just to be sure :) */
210 board.find_moves(mvs);
215 Engine::moves_heuristic(Move *mv, int num_mv, int ply, int orig_depth,
216 Move best_mv_hash, bool quiesce)
218 /*uint8_t up_right = Board::up_dir[IS_WHITE(board.color_to_move)] + RIGHT;
219 uint8_t up_left = Board::up_dir[IS_WHITE(board.color_to_move)] + LEFT;*/
222 for(int i=0;i<num_mv;i++)
227 /* give a high bonus to the move stored in the hash, if any.
228 mark only which is, don't continue, because some extensions
229 may be triggered ad added later (ie pawn strike, etc) */
230 if(mv[i].as_int == best_mv_hash.as_int)
233 if(board.move_is_check(mv[i]) )
235 int see = board.move_see_val(mv[i]);
236 if(orig_depth>-5*PLY && see >= 0)
237 mv[i].val = 25000 + see*64;
241 else if(mv[i].capture)
243 int see = board.move_see_val(mv[i]);
244 if(see > 0 || (orig_depth>-5*PLY && see==0) )
245 mv[i].val = 20000 + see*64;
252 mv[hash_move].val = 30000;
256 Engine::moves_heuristic(Move *mv, int num_mv, int ply, int orig_depth,
257 Move best_mv_hash, bool quiesce)
259 /*uint8_t up_right = Board::up_dir[IS_WHITE(board.color_to_move)] + RIGHT;
260 uint8_t up_left = Board::up_dir[IS_WHITE(board.color_to_move)] + LEFT;*/
263 for(int i=0;i<num_mv;i++)
268 /* give a high bonus to the move stored in the hash, if any.
269 mark only which is, don't continue, because some extensions
270 may be triggered ad added later (ie pawn strike, etc) */
271 if(mv[i].as_int == best_mv_hash.as_int)
274 /* process strong pawn moves */
275 if(PIECE_OF(board.data[mv[i].from])==PAWN) /* pawn strike */
277 if( ROW_OF(mv[i].to) == board.seventh_rank[IS_WHITE(board.color_to_move)] )
279 int x = board.move_see_val(mv[i]);
287 mv[i].val += 29499; /* 7th push */
288 mv[i].extend = 1; /* extend search */
292 if( mv[i].flags == PROMOTEQUEEN )
294 int x = board.move_see_val(mv[i]);
302 mv[i].val += 29500; /* promote! */
303 mv[i].extend = 1; /* extend search */
309 uint8_t p1 = mv[i].to + up_right;
310 uint8_t p2 = mv[i].to + up_left;
311 uint8_t a = OUT_OF_BOARD(p1) ? 0 : board.data[p1];
312 uint8_t b = OUT_OF_BOARD(p2) ? 0 : board.data[p2];
313 if( (COLOR_OF(a)==board.other_color && PIECE_OF(a)!=PAWN)
314 || (COLOR_OF(b)==board.other_color && PIECE_OF(b)!=PAWN) )
316 int x = board.move_see_val(mv[i]);
323 mv[i].val += 27000; /* pawn strike! */
324 mv[i].extend = 1; /* extend search */
332 int x = board.move_see_val(mv[i]);
336 if(orig_depth>-7*PLY && board.move_is_check(mv[i]) )
338 mv[i].val += 29800+x;
342 mv[i].val += 29000+x;
347 mv[i].val += -15000+x;
350 else if(orig_depth>-7*PLY && board.move_is_check(mv[i]) )
352 /* = capture but check */
357 else /* add a bonus for checks (but not too deep, or quiescence will get mad) */
358 if(0 && orig_depth>-3*PLY && board.move_is_check(mv[i]) )
360 if(board.move_see_val(mv[i])>=0)
370 #if HISTORY_HEURISTIC
371 /* add the value depending on the heuristic */
372 // mv[i].val += killers[ply][HISTORY_INDEX(mv[i])];
374 // mv[i].val += killers[ply-2][HISTORY_INDEX(mv[i])];
375 #endif //HISTORY_HEURISTIC
378 static int bof[128] = {
379 0,0,1,2,2,1,0,0,ENDL,
380 0,1,2,3,3,2,1,0,ENDL,
381 0,2,4,5,5,4,2,0,ENDL,
382 1,2,5,6,6,5,2,1,ENDL,
383 1,2,5,6,6,5,2,1,ENDL,
384 0,2,4,5,5,4,2,0,ENDL,
385 0,1,2,3,3,2,1,0,ENDL,
389 /* add a bonus for moves towards the center */
390 mv[i].val += (bof[mv[i].to] - bof[mv[i].from]);
391 #endif //CENTER_HEURISTIC
395 mv[hash_move].val = 30000;
401 Engine::moves_quiescence_heuristic(Move *mv, int num_mv, const Move& best_mv_hash, int static_eval, int alpha, int beta)
403 for(int i=0;i<num_mv;i++)
408 /* give a high bonus to the move stored in the hash, if any. */
409 if(mv[i].as_int == best_mv_hash.as_int)
415 if( mv[i].flags == PROMOTEQUEEN )
423 int x = board.move_see_val(mv[i]);
425 if((static_eval == -INF && x>0)
426 || (static_eval + x*100 + 100 > alpha))
428 if( board.move_is_check(mv[i]) )
429 mv[i].val = 15000 + x*64;
431 mv[i].val = 10000 + x*64;
436 if(board.move_is_check(mv[i]))
438 mv[i].val = 5000 + x*64;
439 mv[i].cost = 20 + MAX(0, -x*8);
444 mv[i].cost = 40 + MAX(0, -x*12);
450 if( board.move_is_check(mv[i]) )
452 A88 atk = IS_WHITE(board.other_color) ? board.w_attacks : board.b_attacks;
453 A88 def = IS_WHITE(board.color_to_move) ? board.w_attacks : board.b_attacks;
455 if(atk[mv[i].to] && !def[mv[i].to])
472 Engine::quiesce(int ply, int depth, int16_t alpha, int16_t beta)
474 SearchStack *s = &stack[ply];
475 int16_t static_eval = -INF;
477 int16_t best_guessed = alpha;
478 uint16_t cbest_mv_hash = 0; /* the compressed move from the hash */
479 Move best_mv_hash = Move::FromInt(0); /* the move from the hash */
480 int best_mv_found = -1; /* the index of the best move AFTER searching */
481 bool dangerous_position = false;
491 s->threat = Move::FromInt(0);
494 prefetch_hash( board.hash );
496 /* check if time is running out */
500 /* check for a draw for repetition or 50mvs. Of course the draw for
501 repetition must be checked BEFORE probing the hash :)*/
503 return (board.color_to_move == st_computer_color) ? v_eval_draw :
504 ((board.other_color == st_computer_color) ? -v_eval_draw : 0); /* be aggressive! */
507 /*******************************************************************************
509 If the probe is succesful the hashtable will return us value
510 that can be exact, a lower bound or an upper bound, and if the
511 depth of the hashed search is >= the current depth this value
512 will be used to improve alpha and beta and possibly return immediatly.
513 The hastable will also give us a "best" move that will be searched
515 This is the move that caused the "final" cutoff when this position
516 was searched previously. This best move is actually the index of the best
517 move in the array of generated moves (it is supposed to be deterministic :)
518 *******************************************************************************/
520 HashEntry *h = probe_hash( board.hash );
524 int16_t l = h->lower();
525 int16_t u = h->upper();
539 alpha = MAX(alpha, l);
541 cbest_mv_hash = h->best_mv;
542 best_guessed = MAX(best_guessed, h->lower());
546 /*******************************************************************************
547 Test if we are under check, and if so extend search
548 *******************************************************************************/
550 s->under_check = board.under_attack(board.king_pos[IS_WHITE(board.color_to_move)],
554 dangerous_position = true;
559 // Move *mv = mv_stack + mv_stack_top;
560 // board.do_null_move();
561 // num_mv = board.find_moves(mv);
563 // for(int i=0;i<num_mv;i++)
565 // if(!mv[i].capture)
567 // if(board.move_see_val(mv[i])>0)
571 // board.undo_null_move();
573 // dangerous_position = true;
577 dangerous_position = false;
579 if(!dangerous_position)
581 best = static_eval = board.evaluate(st_computer_color, alpha, beta);
583 alpha = MAX(alpha, best);
592 /*******************************************************************************
593 Now generate the legal moves and look for a check/stalemate
594 *******************************************************************************/
596 /* generate all the legal moves */
597 s->moves = &mv_stack[mv_stack_top];
598 s->num_moves = board.find_moves(s->moves);
599 mv_stack_top += s->num_moves;
600 s->under_check = board.under_check;
602 /* return now if the positon is terminal */
606 /* while mating, sacrify as much as possible :) */
607 best = -INF + ply;//*50 + board.material[IS_WHITE(eng_color)]/50;
614 /*******************************************************************************
616 First comes the move from the hashtable, if avalable.
617 The remaining moves are sorted with a heuristic that keeps in account
618 the history heuristic (ie the moves that previously caused an alpha
619 cutoff), a MVV/LVA bonus value and a small bonus for moves that go
621 *******************************************************************************/
623 /* convert the move we got from the hash to the move structure */
626 best_mv_hash = board.uncompress_move(cbest_mv_hash);
627 /* if it happened that the move we got from the hashtable
628 is not valid, simply no move will get the high
629 heuristic bonus value */
632 /* for each move calculate the heuristic goodness value */
633 moves_quiescence_heuristic(s->moves, s->num_moves, best_mv_hash, static_eval, alpha, beta);
635 /* if quiesce rip-off bad moves */
636 if(!dangerous_position)
639 for(int i=0;i<s->num_moves;i++)
640 if(s->moves[i].val>=10000 ||
641 (s->moves[i].val>=-10000 && depth>s->moves[i].cost) )
642 s->moves[n++] = s->moves[i];
643 mv_stack_top -= s->num_moves-n;
647 /* sort the moves using the heuristic values */
648 sort_moves( s->moves, s->num_moves );
650 /* set the current best move index (as will be saved in the hash) */
653 /*******************************************************************************
654 It is now time to loop all the successor moves and search recursively.
655 *******************************************************************************/
657 for(int i=0;i<s->num_moves;i++)
661 /* sort moves incrementally, in the hope of a beta cut */
662 //incremental_sort_moves(s->moves+i, s->num_moves-i);
666 board.do_move(s->moves[i]);
667 val = -quiesce( ply+1, depth - s->moves[i].cost, -beta, -alpha);
668 board.undo_move(s->moves[i]);
671 /* update the current best value and check for and alpha cut */
672 best = MAX(best, val);
685 STAT(quiesce_cutoff);
687 STAT(quiesce_cutoff_first);
694 mv_stack_top -= s->num_moves; /* free the moves we allocated */
696 /* if we found a best move searching, that move will be saved.
697 if we did no search (ie quiescence), save the old hash value,
698 or -1 if no hash entry had been found */
699 int bestmv = cbest_mv_hash;
700 if(best_mv_found >= 0)
702 bestmv = board.compress_move(s->moves[best_mv_found]);
703 STAT(quiesce_best_can_be_first);
704 if(best_mv_found == 0)
705 STAT(quiesce_best_was_first);
708 /* write the value in the hash, with the index of the best move */
709 write_hash( best > s->alpha ? best : -INF,
710 best < beta ? best : +INF, 0, bestmv);
716 /*******************************************************************************
717 The main alpha-beta recursive search function.
718 It handles both normal search (with or without null move)
719 and quiescence search, because i have having 2 almost identical
721 *******************************************************************************/
724 Engine::search(int ply, int depth, bool pv, int16_t alpha, int16_t beta, bool inner)
726 SearchStack *s = &stack[ply];
727 int null_value = INF;
729 int16_t best_guessed = alpha;
730 uint16_t cbest_mv_hash = 0; /* the compressed move from the hash */
731 Move best_mv_hash = Move::FromInt(0); /* the move from the hash */
732 int best_mv_found = -1; /* the index of the best move AFTER searching */
733 bool extended = false;
737 s->base_depth = depth;
743 s->threat = Move::FromInt(0);
746 prefetch_hash( board.hash );
748 /* check if time is running out */
752 /* check for a draw for repetition or 50mvs. Of course the draw for
753 repetition must be checked BEFORE probing the hash :)*/
755 return (board.color_to_move == st_computer_color) ? v_eval_draw :
756 ((board.other_color == st_computer_color) ? -v_eval_draw : 0); /* be aggressive! */
758 /*******************************************************************************
760 If the probe is succesful the hashtable will return us value
761 that can be exact, a lower bound or an upper bound, and if the
762 depth of the hashed search is >= the current depth this value
763 will be used to improve alpha and beta and possibly return immediatly.
764 The hastable will also give us a "best" move that will be searched
766 This is the move that caused the "final" cutoff when this position
767 was searched previously. This best move is actually the index of the best
768 move in the array of generated moves (it is supposed to be deterministic :)
769 *******************************************************************************/
770 HashEntry *h = probe_hash( board.hash );
772 if(h && (h->depth >= s->base_depth))// || ABS(h->value)>INF-1000) )
774 int16_t l = h->lower();
775 int16_t u = h->upper();
790 alpha = MAX(alpha, l);
794 cbest_mv_hash = h->best_mv;
795 best_guessed = MAX(best_guessed, h->lower());
799 /*******************************************************************************
800 Test if we are under check, and if so extend search
801 *******************************************************************************/
803 s->under_check = board.under_attack(board.king_pos[IS_WHITE(board.color_to_move)],
806 /*******************************************************************************
807 If it is time to quiesce, evaluate and test if we can exit
808 immediately with a beta cut-off (try first a rough eval - delta)
809 *******************************************************************************/
810 //s quiesce = (!s->under_check) && (depth<=0);
812 if(quiesce && depth>=-100)
815 Move *mv = mv_stack + mv_stack_top;
816 board.do_null_move();
817 num_mv = board.find_moves(mv);
819 for(int i=0;i<num_mv;i++)
823 if(board.move_see_val(mv[i])>0)
830 board.undo_null_move();
836 /*******************************************************************************
838 *******************************************************************************/
839 if(!s->under_check && (stack[ply-1].curr_move!=-1) && depth >= 2*PLY && beta<INF-1000)
843 board.do_null_move();
844 null_value = -search( ply+1, depth-v_search_null_reduction, true, -beta, -beta+1);
845 //null_value = -search( ply+1, depth-v_search_null_reduction, true, -beta, -INF);
846 board.undo_null_move();
852 if(null_value >= beta)
854 STAT(null_successful);
858 // if(val<alpha-100 && /* we are facing a threat*/
859 // stack[ply+1].best_move != -1) /* be sure we aren't reading random memory */
861 // /* ok, officially the array stack[ply+1].moves has already
862 // been deallocated, but who cares :) */
863 // s->threat = stack[ply+1].moves[stack[ply+1].best_move];
866 // /* Botvinnik-Markoff extension!!! */
867 // if(!extended && ply>=3 && (s->threat == stack[ply-2].threat) )
879 /*******************************************************************************
880 Now generate the legal moves and look for a check/stalemate
881 *******************************************************************************/
883 /* generate all the legal moves */
884 s->moves = &mv_stack[mv_stack_top];
885 s->num_moves = board.find_moves(s->moves);
886 mv_stack_top += s->num_moves;
887 s->under_check = board.under_check;
889 if(s->under_check==2) /* double check */
894 else if(s->under_check) /* simple check */
897 if(stack[ply-1].curr_move!=-1 &&
898 !board.pins[stack[ply-1].moves[ /* last moved piece is not attacking the king */
899 stack[ply-1].curr_move].to]) /* so this is a discover check */
906 /* return now if the positon is terminal */
910 /* while mating, sacrify as much as possible :) */
911 best = -INF + ply;//*50 + board.material[IS_WHITE(eng_color)]/50;
917 /* single-reply extension */
918 if(s->num_moves == 1 && !extended)
923 else if(s->num_moves <= 3 && !extended)
931 /*******************************************************************************
932 Try to get an early beta cutoff using the hash table values
933 of the following moves, and improve alpha too.
934 Try only the first 6 value of the ordered moves (argh, looking into the
935 hashtable is very expensive because of the cache!!!!!!!!)
936 *******************************************************************************/
937 #if EARLY_TRANSP_CUTOFF
940 HashKey hk = board.move_hash(s->moves[0]);
941 for(int i=1;i<s->num_moves;i++)
944 HashKey newhk = board.move_hash(s->moves[i]);
945 HashEntry *h2 = probe_hash( hk );
948 if(h2 && h2->depth >= depth-100)
955 alpha = MAX(alpha, (int16_t)-h2->up);
959 HashEntry *h2 = probe_hash( hk );
960 if(h2 && h2->depth >= depth-100)
967 alpha = MAX(alpha, (int16_t)-h2->up);
970 #endif //EARLY_TRANSP_CUTOFF
973 /*******************************************************************************
975 First comes the move from the hashtable, if avalable.
976 The remaining moves are sorted with a heuristic that keeps in account
977 the history heuristic (ie the moves that previously caused an alpha
978 cutoff), a MVV/LVA bonus value and a small bonus for moves that go
980 *******************************************************************************/
982 /* convert the move we got from the hash to the move structure */
985 best_mv_hash = board.uncompress_move(cbest_mv_hash);
986 /* if it happened that the move we got from the hashtable
987 is not valid, simply no move will get the high
988 heuristic bonus value */
990 #if INTERNAL_ITERATIVE_DEEPENING
991 else if(s->base_depth>=3*PLY && pv) /* don't do it only on the pv, or it will be useless :) */
995 int val = search(ply+1, s->base_depth-2*PLY, true, alpha, beta);
998 HashEntry *h2 = probe_hash( board.hash );
999 if(h2 && h2->best_mv)
1001 cbest_mv_hash = h2->best_mv;
1002 best_mv_hash = board.uncompress_move(cbest_mv_hash);
1004 best_guessed = MAX(best_guessed, h2->lower());
1007 #endif //INTERNAL_ITERATIVE_DEEPENING
1010 /* for each move calculate the heuristic goodness value */
1011 moves_heuristic( s->moves, s->num_moves, ply, s->base_depth,
1012 best_mv_hash, false );
1014 /* sort the moves using the heuristic values */
1015 sort_moves( s->moves, s->num_moves );
1017 /* mh threat extension, unluckily does not seam to work well */
1018 // if(!extended && ply<7 && (null_value < best_guessed-v_search_threat_threshold))
1021 // depth += v_search_threat_extension;
1025 /* set the current best move index (as will be saved in the hash) */
1028 /*******************************************************************************
1029 It is now time to loop all the successor moves and search recursively.
1030 *******************************************************************************/
1032 for(int i=0;i<s->num_moves;i++)
1035 int sdepth = depth-100;
1037 /* sort moves incrementally, in the hope of a beta cut */
1038 //incremental_sort_moves(s->moves+i, s->num_moves-i);
1042 board.do_move(s->moves[i]);
1048 val = -search( ply+1, sdepth, pv, -beta, -alpha);
1051 val = -search( ply+1, sdepth, false, -alpha-1, -alpha );
1052 if((val>alpha) && pv)
1053 val = -search( ply+1, sdepth, true, -beta, -alpha );
1056 val = -search( ply+1, sdepth, pv, -beta, -alpha);
1061 val = -quiesce( ply+1, 100, -beta, -alpha);
1062 STAT(quiesce_called);
1065 board.undo_move(s->moves[i]);
1068 /* update the current best value and check for and alpha cut */
1069 best = MAX(best, val);
1082 STAT(search_cutoff);
1084 STAT(search_cutoff_first);
1090 // for(int i=0;i<best_mv_found;i++)
1092 // uint16_t& val = killers[0][HISTORY_INDEX(s->moves[i])];
1093 // val = MAX(val-1, 0);
1095 // {uint16_t& kval = killers[0][HISTORY_INDEX(s->moves[best_mv_found])];
1096 // kval = MIN(kval+16, 29000);}
1100 mv_stack_top -= s->num_moves; /* free the moves we allocated */
1102 /* if we found a best move searching, that move will be saved.
1103 if we did no search (ie quiescence), save the old hash value,
1104 or -1 if no hash entry had been found */
1105 int bestmv = cbest_mv_hash;
1106 if(best_mv_found >= 0)
1108 bestmv = board.compress_move(s->moves[best_mv_found]);
1109 STAT(search_best_can_be_first);
1110 if(best_mv_found == 0)
1111 STAT(search_best_was_first);
1114 /* write the value in the hash, with the index of the best move */
1115 write_hash( best > s->alpha ? best : -INF,
1116 best < beta ? best : +INF,
1117 s->base_depth, bestmv);
1124 Engine::find_best_move()
1126 SearchStack *s = &stack[0];
1133 /* initialize the root node */
1135 s->base_depth = 2*PLY;
1140 s->threat = Move::FromInt(0);
1143 s->moves = mv_stack;
1144 s->num_moves = mv_stack_top = board.find_moves(s->moves);
1146 /* to print the analysis */
1148 output("\tply\tscore\ttime\tnodes\tpv\n");
1150 /* return immediatly if the move is forced. */
1154 /* probe the play lines */
1155 if( eng_status == PLAYING
1156 && st_computer_color == board.color_to_move
1157 && probe_lines( board.hash, &retv))
1163 /* probe the book */
1164 if(probe_book( board.hash, &retv) ) {
1165 for(int i=0;i<s->num_moves++;i++)
1166 if(retv.as_int == s->moves[i].as_int)
1171 output("ERROR! Got an invalid move from the book!\n");
1174 /* calculate how much time we will think*/
1175 start_think_time = current_time();
1176 if( analysis_limit == TIME_LIMIT )
1178 if(board.color_to_move == st_computer_color)
1180 else /* pondering? analysing? */
1181 time_best_csec = 99999999;
1182 max_think_time = start_think_time + time_best_csec - 2;
1185 processed_nodes = 0;
1189 /* set the back jump for the quick thinking exit */
1193 /* start with a guess of 0 */
1194 s->moves[0].val = 0;
1197 /* do the iterative deepening thing. */
1200 int16_t alpha = -INF;
1203 // for(int i=0;i<40;i++)
1204 // memset( &killers[i], 0, 64*64*sizeof(uint16_t));
1206 /* for each move call the alpha-beta search function */
1209 for(i=0;i<s->num_moves;i++)
1213 board.do_move(s->moves[i]);
1217 s->moves[i].val = -search( 1, s->base_depth-100, true,
1222 s->moves[i].val = -search( 1, s->base_depth-100, false,
1224 if(s->moves[i].val > alpha)
1225 s->moves[i].val = -search( 1, s->base_depth-100, true,
1229 s->moves[i].val = -search( 1, s->base_depth-100, true, -INF, -alpha);
1231 board.undo_move(s->moves[i]);
1235 if(s->moves[i].val > alpha)
1237 alpha = s->moves[i].val;
1242 /* this move caused an alpha cut, so print the new line */
1243 if( post /*&& processed_nodes>100000*/)
1245 output("\t%d\t%d\t%d\t"U64F"\t", s->base_depth/100,
1246 s->moves[i].val, current_time() - start_think_time, processed_nodes);
1247 print_moves(&s->moves[i], 1, true);
1252 /* the search is done, sort the moves so that best is searched first */
1255 s->moves[best_mv].val++;
1256 sort_moves(s->moves, i); /* sort i moves (those that we where able to search) */
1260 /* print the result of the analysis at this depth */
1261 if( post /*&& processed_nodes>100000*/)
1263 output("\t%d\t%d\t%d\t"U64F"\t", s->base_depth/100,
1264 s->moves[0].val, current_time() - start_think_time, processed_nodes);
1265 print_moves(&s->moves[0], 1, true);
1269 if( s->base_depth >= 40*PLY )
1272 /* return in case of fixed depth search */
1273 if( eng_status == PLAYING && st_computer_color == board.color_to_move &&
1274 analysis_limit == DEPTH_LIMIT && s->base_depth == st_depth*PLY)
1277 /* return if 3/5 of time is gone (we can't search another ply anyway) */
1278 if( eng_status == PLAYING && st_computer_color == board.color_to_move &&
1279 analysis_limit == TIME_LIMIT &&
1280 (current_time()-start_think_time) >= (time_best_csec*3/5) )
1283 /* if a checkmate was detected return immediately */
1284 if( ABS(alpha) > INF-1000)
1287 s->base_depth += PLY;
1294 output("#nodes: "U64F" (~"U64F" nps)\n", processed_nodes, (processed_nodes*100)/
1295 MAX(current_time()-start_think_time,1) );