Try to simulate a human (to play abuser games on FICS)
[rattatechess.git] / search.cpp
blob70ea7e87dde1c11a86128f7915ff7ca393379d9b
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];
28 uint8_t escape_from_1[MAX_PV];
29 uint8_t escape_from_2[MAX_PV];
31 #define HISTORY_SIZE (64*64)
32 uint16_t history_tot[HISTORY_SIZE];
33 uint16_t history_hit[HISTORY_SIZE];
35 #define HISTORY_INDEX(m) (SQUARE_TO_64(m.from)*64 + SQUARE_TO_64(m.to))
37 int stat_early_transp;
38 int stat_hash_write;
39 int stat_hash_tot;
40 int stat_hash_ex;
41 int stat_hash_low;
42 int stat_hash_upp;
43 int stat_best_cut;
44 int stat_best_first;
45 int stat_search_moves;
46 int stat_best_cut0;
47 int stat_best_first0;
48 int stat_search_moves0;
49 int stat_evaluate;
50 int stat_evaluate_cutoff;
51 int stat_null_move;
52 int stat_null_cut;
55 #if 0
56 #define STAT(x)
57 #else
59 #define S_ALL \
60 S(max_quiesce_nodes); \
61 S(quiesce_nodes); \
62 S(quiesce_hash); \
63 S(quiesce_called); \
64 S(quiesce_best_can_be_first); \
65 S(quiesce_best_was_first); \
66 S(quiesce_cutoff); \
67 S(quiesce_cutoff_first); \
68 S(search_nodes); \
69 S(search_hash); \
70 S(search_best_can_be_first); \
71 S(search_best_was_first); \
72 S(search_cutoff); \
73 S(search_cutoff_first); \
74 S(null_tried); \
75 S(null_successful);
77 #define STAT(x) stat_##x++;
79 #define S(x) uint64_t stat_##x;
80 S_ALL
81 Board max_quiesce_board;
82 int16_t max_quiesce_alpha;
83 int16_t max_quiesce_beta;
84 #undef S
86 void reset_stats()
88 #define S(x) stat_##x = 0;
89 S_ALL
90 #undef S
93 void print_stats()
95 #define S(x) printf("# " #x " = %llu\n", (unsigned long long)stat_##x);
96 S_ALL
97 #undef S
100 #endif
102 /* enable the quiescence search */
103 #define QUIESCENCE 1
105 /* enable the nega-scout pv-search */
106 #define NEGA_SCOUT 1
108 /* enable the null move */
109 #define NULL_MOVE 1
111 /* before doing the alpha beta search check if any of the following positions
112 can give use an early cutoff thanks to the hashtable */
113 #define EARLY_TRANSP_CUTOFF 1
115 /* SEEMS TO BE A BIT BAD:
116 Extend when there is only one decent move */
117 #define SINGULAR_EXTENSION 0
119 /* DANGEROUS:
120 reduce nodes for moves that are not check/captures that are considered
121 bad from the heuristic */
122 #define HISTORY_PRUNING 1
124 /* futility pruning: */
125 #define FUTILITY 0
127 /* when the hashtable provides no "best" move, do a depth-2 search */
128 #define INTERNAL_ITERATIVE_DEEPENING 0
130 /* use the history sorting heuristic */
131 #define HISTORY_HEURISTIC 1
133 /* improve the sorting heuristic for pawn strikes */
134 #define PAWNSTRIKE_HEURISTIC 1
136 /* improve the sorting heuristic for moves to the center */
137 #define CENTER_HEURISTIC 0
140 class SearchStack
142 public:
143 int base_depth; /* depth of the search at this ply */
144 int extensions; /* global extensions at this node */
145 Move *moves; /* all generated moves */
146 int num_moves; /* num of moves */
147 int curr_move; /* the move being currently analyzed */
148 int16_t alpha; /* alpha ans beta when the search started (not improved) */
149 int16_t beta;
150 bool under_check;
151 Move threat;
152 int best_move;
155 Move mv_stack[200*MAX_PV];
156 int mv_stack_top = 0;
157 SearchStack stack[MAX_PV];
158 int current_ply = 0;
160 void Engine::print_stat()
162 if(eng_status != ANALYZING)
164 printf("Thinking: ");
165 for(int i=0; i<current_ply; i++)
167 if(stack[i].curr_move == -2)
168 continue; //Internal iterative deepening
169 else if(stack[i].curr_move == -1)
171 printf("<NULL>");
172 board.do_null_move();
174 else
176 char buf[32];
177 printf("%s", move_to_alg(buf, &(stack[i].moves[stack[i].curr_move]) ) );
178 board.do_move(stack[i].moves[stack[i].curr_move]);
180 printf((i != current_ply-1) ? " " : "\n");
182 rewind_thinking();
183 return;
186 if(thinking)
188 char buf[32];
189 output("stat01: %d %llu %d %d %d %s\n",
190 current_time() - start_think_time,
191 (unsigned long long)processed_nodes,
192 stack[0].base_depth/100,
193 stack[0].num_moves-1-stack[0].curr_move,
194 stack[0].num_moves,
195 move_to_alg(buf, &(stack[0].moves[stack[0].curr_move]) ) );
197 else
198 output("stat01: 0 0 0 0 0\n");
201 void Engine::rewind_thinking()
203 for(int i=current_ply-1; i>=0; i--)
205 if(stack[i].curr_move == -2)
207 else if(stack[i].curr_move == -1)
208 board.undo_null_move();
209 else
210 board.undo_move(stack[i].moves[stack[i].curr_move]);
214 void Engine::restore_thinking()
216 for(int i=0; i<current_ply; i++)
218 if(stack[i].curr_move == -2)
220 else if(stack[i].curr_move == -1)
221 board.do_null_move();
222 else
223 board.do_move(stack[i].moves[stack[i].curr_move]);
226 /* regenerate pinning info and under_check var, just to be sure :) */
227 Move mvs[250];
228 board.find_moves(mvs);
231 void
232 Engine::moves_heuristic(Move *mv, int num_mv, int ply, int orig_depth,
233 Move best_mv_hash, bool quiesce, Move* prev)
235 int hash_move = -1;
237 for(int i=0;i<num_mv;i++)
239 mv[i].val = 0;
240 mv[i].extend = 0;
242 /* give a high bonus to the move stored in the hash, if any.
243 mark only which is, don't continue, because some extensions
244 may be triggered ad added later (ie pawn strike, etc) */
245 if(mv[i].as_int == best_mv_hash.as_int)
246 hash_move = i;
248 #if 1
249 #if 0
250 if(PIECE_OF(board.data[mv[i].from]) != PAWN &&
251 (mv[i].from == escape_from_1[ply-1] || mv[i].from == escape_from_2[ply-1]) )
253 int x = board.move_see_val(mv[i]);
255 if(x >= 0)
257 mv[i].val += 29000 + x; /* escape */
258 mv[i].extend = PLY;
259 continue;
262 #endif
264 /* process strong pawn moves */
265 if(PIECE_OF(board.data[mv[i].from])==PAWN) /* pawn strike */
267 if( ROW_OF(mv[i].to) == board.seventh_rank[IS_WHITE(board.color_to_move)] )
269 int x = board.move_see_val(mv[i]);
271 if(x>=0)
273 mv[i].val += 29599; /* 7th push */
274 mv[i].extend = PLY; /* extend search */
275 continue;
279 if( mv[i].flags == PROMOTEQUEEN )
281 int x = board.move_see_val(mv[i]);
283 if(x>=0)
285 mv[i].val += 29600; /* promote! */
286 mv[i].extend = PLY; /* extend search */
287 continue;
291 #if 1
292 if(orig_depth >= 2*PLY)
294 /* pawn strike */
295 uint8_t up_right = Board::up_dir[IS_WHITE(board.color_to_move)] + RIGHT;
296 uint8_t up_left = Board::up_dir[IS_WHITE(board.color_to_move)] + LEFT;
297 uint8_t p1 = mv[i].to + up_right;
298 uint8_t p2 = mv[i].to + up_left;
299 uint8_t a = OUT_OF_BOARD(p1) ? 0 : board.data[p1];
300 uint8_t b = OUT_OF_BOARD(p2) ? 0 : board.data[p2];
301 if( (COLOR_OF(a)==board.other_color && PIECE_OF(a)!=PAWN)
302 || (COLOR_OF(b)==board.other_color && PIECE_OF(b)!=PAWN) )
304 int x = board.move_see_val(mv[i]);
306 if(x>=0)
308 mv[i].val = 27000; /* pawn strike! */
309 //mv[i].extend = PLY; /* extend search */
310 continue;
314 #endif
316 #endif
317 if(mv[i].capture)
319 int x = board.move_see_val(mv[i]);
321 if(prev && prev->capture)
323 static const int vallapiglia[] = { 0, 5, 3, 9, 3, 1, 0 };
325 if( (mv[i].to == prev->to) && (x >= vallapiglia[PIECE_OF(prev->capture)]) )
327 mv[i].val = 29900;
328 if( (x == vallapiglia[PIECE_OF(prev->capture)]) )
329 mv[i].extend = /*(x==1) ? (PLY/2) :*/ PLY;
330 // else if(prev->capture && ABS(x - vallapiglia[PIECE_OF(prev->capture)]) == 1)
331 // mv[i].extend = PLY/2;
332 continue;
336 if(x>0)
338 if(orig_depth>-7*PLY && board.move_is_check(mv[i]) )
339 mv[i].val = 29800+x;
340 else
341 mv[i].val = 29000+x;
342 continue;
344 else if(x>=0 && orig_depth>-7*PLY && board.move_is_check(mv[i]) )
346 /* = capture but check */
347 mv[i].val = 29800;
348 continue;
351 else /* add a bonus for checks (but not too deep, or quiescence will get mad) */
352 if(orig_depth>-3*PLY && board.move_is_check(mv[i]) )
354 if(board.move_see_val(mv[i])>=0)
356 mv[i].val = 28799;
357 continue;
361 /* null-move threat */
362 if(null_threat[ply-1] == mv[i])
364 mv[i].val = 28500;
365 continue;
368 mv[i].val += history_hit[HISTORY_INDEX(mv[i])] * 1024 / (history_tot[HISTORY_INDEX(mv[i])] + 4);
370 #if CENTER_HEURISTIC
371 static int bof[128] = {
372 0,0,1,2,2,1,0,0,ENDL,
373 0,1,2,3,3,2,1,0,ENDL,
374 0,2,4,5,5,4,2,0,ENDL,
375 1,2,5,6,6,5,2,1,ENDL,
376 1,2,5,6,6,5,2,1,ENDL,
377 0,2,4,5,5,4,2,0,ENDL,
378 0,1,2,3,3,2,1,0,ENDL,
379 0,0,1,2,2,1,0,0,ENDL
382 /* add a bonus for moves towards the center */
383 mv[i].val += (bof[mv[i].to] - bof[mv[i].from]);
384 #endif //CENTER_HEURISTIC
387 if(hash_move!=-1)
388 mv[hash_move].val = 30000;
392 void
393 Engine::moves_quiescence_heuristic(Move *mv, int num_mv, const Move& best_mv_hash,
394 int static_eval, int alpha, int beta, int orig_depth, Move* prev)
396 for(int i=0;i<num_mv;i++)
398 mv[i].val = -10000;
399 mv[i].extend = 0;
401 /* give a high bonus to the move stored in the hash, if any.
402 mark only which is, don't continue, because some extensions
403 may be triggered ad added later (ie pawn strike, etc) */
404 if(mv[i].as_int == best_mv_hash.as_int)
406 mv[i].val = 30000;
407 continue;
410 #if 0
411 /* process strong pawn moves */
412 if(PIECE_OF(board.data[mv[i].from])==PAWN) /* pawn strike */
414 if( ROW_OF(mv[i].to) == board.seventh_rank[IS_WHITE(board.color_to_move)] )
416 int x = board.move_see_val(mv[i]);
418 if(x<0)
420 mv[i].val += -15000;
421 continue;
424 mv[i].val += 29499; /* 7th push */
425 mv[i].extend = PLY; /* extend search */
426 continue;
429 if( mv[i].flags == PROMOTEQUEEN )
431 int x = board.move_see_val(mv[i]);
433 if(x<0)
435 mv[i].val += -15000;
436 continue;
439 mv[i].val += 29500; /* promote! */
440 mv[i].extend = PLY; /* extend search */
441 continue;
444 #if 0
445 /* pawn strike */
446 uint8_t p1 = mv[i].to + up_right;
447 uint8_t p2 = mv[i].to + up_left;
448 uint8_t a = OUT_OF_BOARD(p1) ? 0 : board.data[p1];
449 uint8_t b = OUT_OF_BOARD(p2) ? 0 : board.data[p2];
450 if( (COLOR_OF(a)==board.other_color && PIECE_OF(a)!=PAWN)
451 || (COLOR_OF(b)==board.other_color && PIECE_OF(b)!=PAWN) )
453 int x = board.move_see_val(mv[i]);
454 if(x<0)
456 mv[i].val += -15000;
457 continue;
460 mv[i].val += 27000; /* pawn strike! */
461 mv[i].extend = PLY; /* extend search */
462 continue;
464 #endif
466 #endif
467 if(mv[i].capture)
469 int x = board.move_see_val(mv[i]);
471 if(prev && prev->capture)
473 static const int vallapiglia[] = { 0, 5, 3, 9, 3, 1, 0 };
475 if( (mv[i].to == prev->to) && (x >= vallapiglia[PIECE_OF(prev->capture)]) )
477 mv[i].val = 29900;
478 if( (x == vallapiglia[PIECE_OF(prev->capture)]) )
479 mv[i].extend = /*(x==1) ? (PLY/2) :*/ PLY;
480 // else if(prev->capture && ABS(x - vallapiglia[PIECE_OF(prev->capture)]) == 1)
481 // mv[i].extend = PLY/2;
482 continue;
486 if(x>0)
488 if(orig_depth>-5*PLY && board.move_is_check(mv[i]) )
489 mv[i].val = 18000+x;
490 else
491 mv[i].val = 10000+x;
492 continue;
494 else if(x>=0 && orig_depth>-5*PLY && board.move_is_check(mv[i]) )
496 /* = capture but check */
497 mv[i].val = 18000;
498 continue;
501 else /* add a bonus for checks (but not too deep, or quiescence will get mad) */
502 if(orig_depth>-3*PLY && board.move_is_check(mv[i]) )
504 if(board.move_see_val(mv[i])>=0)
506 mv[i].val = 7990;
507 continue;
514 /*******************************************************************************
515 The main alpha-beta recursive search function.
516 It handles both normal search (with or without null move)
517 and quiescence search, because i have having 2 almost identical
518 function around.
519 *******************************************************************************/
520 int16_t Engine::search(int ply, int depth, bool pv, int16_t alpha, int16_t beta)
522 SearchStack *s = &stack[ply];
523 int16_t best = -INF;
524 uint16_t cbest_mv_hash = 0; /* the compressed move from the hash */
525 Move best_mv_hash = Move::FromInt(0); /* the move from the hash */
526 int best_mv_found = -1; /* the index of the best move AFTER searching */
527 bool quiesce;
528 bool extended = false;
529 int16_t position_val;
531 if(depth <= 0)
532 STAT(quiesce_nodes)
534 s->base_depth = depth;
535 s->extensions = 0;
536 s->num_moves = 0;
537 s->curr_move = -1;
538 s->alpha = alpha;
539 s->beta = beta;
540 s->threat = Move::FromInt(0);
541 s->best_move = -1;
542 null_threat[ply] = Move::FromInt(0);
543 null_threat_dangerous[ply] = false;
544 //escape_from_1[ply] = escape_from_2[ply] = INVALID;
546 /* check if time is running out */
547 if(check_time())
548 return 0;
550 /* check for a draw for repetition or 50mvs. Of course the draw for
551 repetition must be checked BEFORE probing the hash :)*/
552 if(check_draw())
553 return (board.color_to_move == st_computer_color) ? -35 :
554 ((board.other_color == st_computer_color) ? 35 : 0); /* be aggressive! */
556 /*******************************************************************************
557 Probe the hashtable.
558 If the probe is succesful the hashtable will return us value
559 that can be exact, a lower bound or an upper bound, and if the
560 depth of the hashed search is >= the current depth this value
561 will be used to improve alpha and beta and possibly return immediatly.
562 The hastable will also give us a "best" move that will be searched
563 first.
564 This is the move that caused the "final" cutoff when this position
565 was searched previously. This best move is actually the index of the best
566 move in the array of generated moves (it is supposed to be deterministic :)
567 *******************************************************************************/
568 stat_hash_tot++;
569 HashEntry *h = probe_hash( board.hash );
571 if(h && (h->depth >= s->base_depth))// || ABS(h->value)>INF-1000) )
573 int16_t l = h->lower();
574 int16_t u = h->upper();
575 if(l>=beta || u==l)
576 return l;
577 if(u<=alpha)
578 return u;
580 beta = MIN(beta, u);
581 alpha = MAX(alpha, l);
584 if(h)
585 cbest_mv_hash = h->best_mv;
587 /*******************************************************************************
588 Test if we are under check, and if so extend search
589 *******************************************************************************/
591 s->under_check = board.under_attack(board.king_pos[IS_WHITE(board.color_to_move)],
592 board.other_color);
594 /*******************************************************************************
595 If it is time to quiesce, evaluate and test if we can exit
596 immediately with a beta cut-off (try first a rough eval - delta)
597 *******************************************************************************/
598 quiesce = ((!s->under_check) && (depth<=0)) || (depth<-60*PLY);
600 #if 0 //PAPOPEPO
601 if(quiesce && depth>=-PLY)
603 int num_mv;
604 Move *mv = mv_stack + mv_stack_top;
605 board.do_null_move();
606 num_mv = board.find_moves(mv);
607 uint8_t pup = INVALID;
609 for(int i=0;i<num_mv;i++)
611 if(!mv[i].capture || PIECE_OF(mv[i].capture)==PAWN)
612 continue;
613 if(mv[i].to != pup && board.move_see_val(mv[i])>0)
614 if(pup == INVALID)
615 pup = mv[i].to;
616 else
618 quiesce = false;
619 break;
623 board.undo_null_move();
625 #endif
627 if(quiesce)
629 stat_evaluate++;
630 best = board.evaluate(st_computer_color, alpha, beta);
632 alpha = MAX(alpha, best);
633 if(best >= beta)
635 stat_evaluate_cutoff++;
636 goto search_done;
639 if(ply>60)
640 goto search_done;
643 #if NULL_MOVE
644 /*******************************************************************************
645 Try the null move.
646 *******************************************************************************/
647 if(!s->under_check && (stack[ply-1].curr_move != -1) && depth >= 2*PLY && beta<INF-1000)
649 int16_t val;
650 int sdepth = (depth >= 5*PLY) ? (depth-4*PLY) : depth-3*PLY;
652 stat_null_move++;
653 s->curr_move = -1;
654 current_ply++;
655 board.do_null_move();
656 val = -search( ply+1, sdepth, true, -beta, -beta+1);
657 board.undo_null_move();
658 current_ply--;
660 /* null move cut! */
661 if(val >= beta)
663 stat_null_cut++;
664 return val;
667 if(val < -INF+1000)
668 null_threat_dangerous[ply] = true;
669 #if 0
670 if(val<alpha-100 && /* we are facing a threat*/
671 stack[ply+1].best_move != -1) /* be sure we aren't reading random memory */
673 /* ok, officially the array stack[ply+1].moves has already
674 been deallocated, but who cares :) */
675 s->threat = stack[ply+1].moves[stack[ply+1].best_move];
677 #if 0
678 /* Botvinnik-Markoff extension!!! */
679 if(!extended && ply>=3 && (s->threat == stack[ply-2].threat) )
681 depth += 80;
682 extended = true;
684 #endif
686 #endif
688 #endif
692 /*******************************************************************************
693 Now generate the legal moves and look for a check/stalemate
694 *******************************************************************************/
696 /* generate all the legal moves */
697 s->moves = &mv_stack[mv_stack_top];
698 s->num_moves = board.find_moves(s->moves);
699 mv_stack_top += s->num_moves;
700 s->under_check = board.under_check;
702 if(s->under_check==2) /* double check */
704 depth += 2*PLY;
705 extended = true;
707 else if(s->under_check) /* simple check */
709 depth += PLY;
710 if(stack[ply-1].curr_move>=0 &&
711 !board.pins[stack[ply-1].moves[ /* last moved piece is not attacking the king */
712 stack[ply-1].curr_move].to]) /* so this is a discover check */
714 depth += PLY/2;
716 extended = true;
719 /* return now if the positon is terminal */
720 if(!s->num_moves)
722 if(s->under_check)
724 /* while mating, sacrify as much as possible :) */
725 best = -INF + ply;//*50 + board.material[IS_WHITE(eng_color)]/50;
727 else
728 best = 0;
729 goto search_done;
732 /* single-reply extension */
733 if(s->num_moves == 1 && !extended)
735 depth += PLY;
736 extended = true;
738 else if(s->num_moves <= 3 && !extended)
740 depth += PLY/2;
741 extended = true;
744 /*******************************************************************************
745 Sort the moves.
746 First comes the move from the hashtable, if avalable.
747 The remaining moves are sorted with a heuristic that keeps in account
748 the history heuristic (ie the moves that previously caused an alpha
749 cutoff), a MVV/LVA bonus value and a small bonus for moves that go
750 toward the center.
751 *******************************************************************************/
753 /* convert the move we got from the hash to the move structure */
754 if(cbest_mv_hash)
756 best_mv_hash = board.uncompress_move(cbest_mv_hash);
757 /* if it happened that the move we got from the hashtable
758 is not valid, simply no move will get the high
759 heuristic bonus value */
761 #if INTERNAL_ITERATIVE_DEEPENING
762 else if(s->base_depth>3*PLY && pv) /* don't do it only on the pv, or it will be useless :) */
764 s->curr_move = -2;
765 current_ply++;
766 int val = search(ply+1, s->base_depth-2*PLY, true, alpha, beta);
767 current_ply--;
769 HashEntry *h2 = probe_hash( board.hash );
770 if(h2 && h2->best_mv)
772 cbest_mv_hash = h2->best_mv;
773 best_mv_hash = board.uncompress_move(cbest_mv_hash);
776 #endif //INTERNAL_ITERATIVE_DEEPENING
778 /* for each move calculate the heuristic goodness value */
780 Move *prev = (stack[ply-1].curr_move>=0) ? &stack[ply-1].moves[stack[ply-1].curr_move] : NULL;
781 if(quiesce)
782 moves_quiescence_heuristic( s->moves, s->num_moves, best_mv_hash,
783 best, alpha, beta, s->base_depth, prev);
784 else
785 moves_heuristic( s->moves, s->num_moves, ply, s->base_depth,
786 best_mv_hash, quiesce, prev );
789 /* if quiesce rip-off the "non-critical" moves */
790 if(quiesce)
792 int n = 0;
793 for(int i=0;i<s->num_moves;i++)
794 if(s->moves[i].val>0)
795 s->moves[n++] = s->moves[i];
796 mv_stack_top -= s->num_moves-n;
797 s->num_moves = n;
800 /* Don't do it now, do it incrementally */
801 //sort_moves( s->moves, s->num_moves );
804 #if EARLY_TRANSP_CUTOFF
805 /*******************************************************************************
806 Try to get an early beta cutoff using the hash table values
807 of the following moves, and improve alpha too.
808 Try on the first 6 value of the ordered moves (argh, looking into the
809 hashtable is very expensive because of the cache!!!!!!!!)
810 *******************************************************************************/
812 if(depth >= 3*PLY)
814 HashKey hk = board.move_hash(s->moves[0]);
815 for(int i=1;i<s->num_moves;i++)
817 prefetch_hash(hk);
818 HashKey newhk = board.move_hash(s->moves[i]);
819 HashEntry *h2 = probe_hash( hk );
820 hk = newhk;
822 if(h2 && h2->depth >= depth-PLY)
824 if(-h2->up >= beta)
826 best = -h2->up;
827 goto search_done;
829 alpha = MAX(alpha, (int16_t)-h2->up);
833 HashEntry *h2 = probe_hash( hk );
834 if(h2 && h2->depth >= depth-PLY)
836 if(-h2->up >= beta)
838 best = -h2->up;
839 goto search_done;
841 alpha = MAX(alpha, (int16_t)-h2->up);
844 #endif //EARLY_TRANSP_CUTOFF
846 /* set the current best move index (as will be saved in the hash) */
847 best_mv_found = 0;
849 /*******************************************************************************
850 It is now time to loop all the successor moves and search recursively.
851 *******************************************************************************/
853 #if FUTILITY
854 /* calcluate the evaluation (required by fitility pruning) */
855 position_val = quiesce ? best : board.evaluate( st_computer_color, -INF, INF);
856 #endif
858 for(int i=0;i<s->num_moves;i++)
860 int16_t val;
861 int sdepth = depth-100;
863 /* sort moves incrementally, in the hope of a beta cut */
864 incremental_sort_moves(s->moves+i, s->num_moves-i);
866 if(depth < s->base_depth+100)
867 sdepth += s->moves[i].extend; /* extensions calculated during the heuristic sort */
869 #if FUTILITY
870 /* futility pruning, it is done only if we are no under check
871 and the move is not a "critical" move */
872 if(depth>0 && depth<3*PLY && !s->under_check && s->moves[i].val < 28000)
874 static const int mavala[] = { 0, 490, 315, 980, 315, 100, 0 };
876 int16_t fmargin = (depth <= PLY ? 420 : 950);
877 int16_t fval = position_val + mavala[PIECE_OF(s->moves[i].capture)];
878 if(fval < alpha-fmargin)
879 continue;
881 #endif
883 /* collect history statistics */
884 if(s->moves[i].val<28000)
886 int ix = HISTORY_INDEX(s->moves[i]);
887 if(history_tot[ix] > 1024)
889 history_tot[ix] = history_tot[ix]*7/8;
890 history_hit[ix] = history_hit[ix]*7/8;
892 history_tot[ix]++;
895 #if 0
896 if(!quiesce && PIECE_OF(board.data[s->moves[i].from]) == PAWN && s->moves[i].val == 27000) //FIXME, UGLY
898 escape_from_1[ply] = s->moves[i].to + Board::up_dir[IS_WHITE(board.color_to_move)] + RIGHT;
899 escape_from_2[ply] = s->moves[i].to + Board::up_dir[IS_WHITE(board.color_to_move)] + LEFT;
901 else
903 escape_from_1[ply] = escape_from_2[ply] = 0;
905 #endif
907 s->curr_move = i;
908 current_ply++;
909 board.do_move(s->moves[i]);
912 uint64_t q;
913 if(s->base_depth > 0 && sdepth <= 0)
915 STAT(quiesce_called);
916 q = stat_quiesce_nodes;
919 #if NEGA_SCOUT /* use negascout, (null window search for nodes that are not in the pv) */
920 if(i == 0) // || depth<200)
921 val = -search( ply+1, sdepth, pv, -beta, -alpha );
922 else
924 #if HISTORY_PRUNING
925 /* history pruning, if this is not a "critical" move and the failhigh
926 stats are too low, try a reduced depth search (if it returns >alpha,
927 re-do the full depth search) */
928 // if((sdepth>0) && !s->under_check && depth<=3*PLY && s->moves[i].val<28000 &&
929 // (history_hit[HISTORY_INDEX(s->moves[i])]+1)*3
930 // < (history_tot[HISTORY_INDEX(s->moves[i])]+1))
931 if((sdepth>0) && !s->under_check && s->moves[i].val<28000 && i>=7 )
933 val = -search( ply+1, sdepth - 100, false, -alpha-1, -alpha );
934 if(val <= alpha)
935 goto skip_search; /* reduced search was effective */
937 #endif
938 val = -search( ply+1, sdepth, false, -alpha-1, -alpha );
939 if((val>alpha) && pv)
940 val = -search( ply+1, sdepth, true, -beta, -alpha );
942 #else
943 /* normal full width alpha-beta */
944 val = -search( ply+1, sdepth, pv, -beta, -alpha );
945 #endif
947 if(s->base_depth > 0 && sdepth <= 0)
949 q = stat_quiesce_nodes-q;
950 if(q > stat_max_quiesce_nodes)
952 stat_max_quiesce_nodes = q;
953 max_quiesce_board = board;
957 skip_search:
958 board.undo_move(s->moves[i]);
959 current_ply--;
961 /* update the current best value and check for and alpha cut */
962 best = MAX(best, val);
963 if(best > alpha)
965 best_mv_found = i;
966 s->best_move = i;
968 /* alpha cut! */
969 alpha = best;
972 /* beta cut! */
973 if(best >= beta)
974 break;
977 /* update a few stats */
978 if(!quiesce)
980 if(best_mv_found==0)
982 if(best >= beta)
983 stat_best_cut++;
984 else
985 stat_best_first++;
987 stat_search_moves++;
988 if(ply==0 && depth>100)
990 if(best_mv_found==0)
992 if(best >= beta)
993 stat_best_cut0++;
994 else
995 stat_best_first0++;
997 stat_search_moves0++;
1001 /* collect statistics for the history */
1002 if(best >= beta &&
1003 !s->moves[best_mv_found].capture &&
1004 !(s->moves[best_mv_found].flags>=PROMOTE_FIRST))
1006 history_hit[HISTORY_INDEX(s->moves[best_mv_found])]++;
1007 history_tot[HISTORY_INDEX(s->moves[best_mv_found])]++;
1010 search_done:
1011 mv_stack_top -= s->num_moves; /* free the moves we allocated */
1013 /* this is a null move, save what the threat is */
1014 if(stack[ply-1].curr_move == -1 && best_mv_found >= 0)
1015 null_threat[ply-1] = s->moves[best_mv_found];
1017 /* if we found a best move searching, that move will be saved.
1018 if we did no search (ie quiescence), save the old hash value,
1019 or -1 if no hash entry had been found */
1020 int bestmv = cbest_mv_hash;
1021 if(best_mv_found >= 0)
1022 bestmv = board.compress_move(s->moves[best_mv_found]);
1024 /* write the value in the hash, with the index of the best move */
1025 write_hash( best > s->alpha ? best : -INF,
1026 best < beta ? best : +INF,
1027 MAX(s->base_depth,-500), bestmv);
1029 return best;
1033 Move Engine::find_best_move()
1035 SearchStack *s = &stack[0];
1036 Move retv;
1037 Move result[80];
1039 ASSERT(!thinking);
1041 /* initialize the root node */
1042 current_ply = 0;
1043 s->base_depth = 100;
1044 s->extensions = 0;
1045 s->curr_move = -1;
1046 s->alpha = -INF;
1047 s->beta = INF;
1048 s->threat = Move::FromInt(0);
1049 s->best_move = -1;
1051 s->moves = mv_stack;
1052 s->num_moves = mv_stack_top = board.find_moves(s->moves);
1054 /* calculate how much time we will think*/
1055 start_think_time = current_time();
1056 if( analysis_limit == TIME_LIMIT )
1058 if(board.color_to_move == st_computer_color)
1059 calc_best_time();
1060 else /* pondering? analysing? */
1061 time_best_csec = 99999999;
1062 max_think_time = start_think_time + time_best_csec - 2;
1065 /* to print the analysis */
1066 if(post)
1067 output("\tply\tscore\ttime\tnodes\tpv\n");
1069 /* return immediatly if the move is forced. */
1070 if(s->num_moves==1)
1071 return s->moves[0];
1073 /* probe the play lines */
1074 if( eng_status == PLAYING
1075 && st_computer_color == board.color_to_move
1076 && probe_lines( board.hash, &retv))
1078 retv.val = 0;
1079 return retv;
1082 /* probe the book */
1083 if(probe_book( board.hash, &retv)) {
1084 for(int i=0;i<s->num_moves++;i++)
1085 if(retv.as_int == s->moves[i].as_int)
1087 retv.val = 0;
1088 return retv;
1090 output("Error!!! invalid move in the book!!!\n");
1093 #if 0
1094 prof_eval = 0;
1095 prof_find_moves = 0;
1096 prof_find_captures = 0;
1097 prof_heuristic = 0;
1098 prof_sort_moves = 0;
1099 prof_move_is_check = 0;
1100 prof_move_see_val = 0;
1101 prof_tot = rdtsc();
1102 #endif
1104 stat_early_transp = 0;
1105 stat_hash_tot = 0;
1106 stat_hash_ex = 0;
1107 stat_hash_low = 0;
1108 stat_hash_upp = 0;
1109 stat_best_first = 0;
1110 stat_best_cut = 0;
1111 stat_search_moves = 0;
1112 stat_best_first0 = 0;
1113 stat_best_cut0 = 0;
1114 stat_search_moves0 = 0;
1115 stat_evaluate = 0;
1116 stat_evaluate_cutoff = 0;
1117 stat_null_move = 0;
1118 stat_null_cut = 0;
1119 stat_hash_write = 0;
1121 reset_stats();
1122 //reset_hash();
1124 //analysis_color = board.color_to_move;
1125 processed_nodes = 0;
1126 int16_t best_guess = 0;
1127 thinking = true;
1128 make_old_hash();
1130 /* set the back jump for the quick thinking exit */
1131 if(setjmp(back))
1132 goto exit_thinking;
1134 /* start with a guess of 0 */
1135 s->moves[0].val = 0;
1136 retv = s->moves[0];
1138 /* do the iterative deepening thing. */
1139 while(1)
1141 int16_t alpha = -INF;
1142 int i=0;
1144 memset( history_tot, 0, HISTORY_SIZE*sizeof(uint16_t));
1145 memset( history_hit, 0, HISTORY_SIZE*sizeof(uint16_t));
1147 /* save the result of the previous search */
1148 result[s->base_depth/PLY-1] = s->moves[0];
1150 /* for each move call the alpha-beta search function */
1151 int best_mv = 0;
1152 for(i=0;i<s->num_moves;i++)
1154 s->curr_move = i;
1155 current_ply++;
1156 board.do_move(s->moves[i]);
1157 #if NEGA_SCOUT
1158 if(i == 0)
1160 s->moves[i].val = -search( 1, s->base_depth-PLY, true, -INF, -alpha );
1162 else
1164 s->moves[i].val = -search( 1, s->base_depth-PLY, false, -alpha-1, -alpha );
1165 if(s->moves[i].val > alpha)
1166 s->moves[i].val = -search( 1, s->base_depth-PLY, true, -INF, -alpha );
1168 #else
1169 s->moves[i].val = -search( 1, s->base_depth-100, true, -INF, -alpha );
1170 #endif
1171 board.undo_move(s->moves[i]);
1172 current_ply--;
1175 /* cut alpha */
1176 if(s->moves[i].val > alpha)
1178 alpha = s->moves[i].val;
1179 retv = s->moves[i];
1180 best_mv = i;
1181 s->best_move = i;
1183 /* this move caused an alpha cut, so print the new line */
1184 if( post /*&& processed_nodes>100000*/)
1186 output("\t%d\t%d\t%d\t%llu\t", s->base_depth/100,
1187 s->moves[i].val, current_time() - start_think_time, processed_nodes);
1188 print_moves(&s->moves[i], 1, true);
1193 best_guess = alpha;
1195 /* the search is done, sort the moves so that best is searched first */
1196 if(i>1)
1198 s->moves[best_mv].val++;
1199 sort_moves(s->moves, i); /* sort i moves (those that we where able to search) */
1200 s->moves[0].val--;
1203 /* print the result of the analysis at this depth */
1204 if( post /*&& processed_nodes>100000*/)
1206 output("\t%d\t%d\t%d\t%llu\t", s->base_depth/100,
1207 s->moves[0].val, current_time() - start_think_time, processed_nodes);
1208 print_moves(&s->moves[0], 1, true);
1211 /* max depth */
1212 if( s->base_depth >= 40*PLY )
1213 break;
1215 /* return in case of fixed depth search */
1216 if( eng_status == PLAYING && st_computer_color == board.color_to_move &&
1217 analysis_limit == DEPTH_LIMIT && s->base_depth == st_depth*PLY)
1218 break;
1220 /* return if 3/5 of time is gone (we can't search another ply anyway) */
1221 if( eng_status == PLAYING && st_computer_color == board.color_to_move &&
1222 analysis_limit == TIME_LIMIT &&
1223 (current_time()-start_think_time) >= (time_best_csec*3/5) )
1224 break;
1226 /* if a checkmate was detected return immediately */
1227 if( ABS(alpha) > INF-1000)
1228 break;
1230 s->base_depth += PLY;
1233 exit_thinking:
1235 if(post)
1237 #if 0
1238 prof_tot = rdtsc() - prof_tot;
1239 #define SHOW_PROF(a) output("@"#a": %llu (%llu%%)\n", \
1240 prof_##a, prof_##a*100/prof_tot);
1241 SHOW_PROF(tot);
1242 SHOW_PROF(eval);
1243 SHOW_PROF(do_move);
1244 SHOW_PROF(find_moves);
1245 SHOW_PROF(find_captures);
1246 SHOW_PROF(heuristic);
1247 SHOW_PROF(move_is_check);
1248 SHOW_PROF(move_see_val);
1249 SHOW_PROF(sort_moves);
1250 #endif
1251 output("#nodes: %llu (~%llu nps)\n", processed_nodes, (processed_nodes*100)/
1252 MAX(current_time()-start_think_time,1) );
1253 output("# %d times all the moves were seached (non-leaf non-quiesce node)\n",
1254 stat_search_moves);
1255 output("# of which %d times first move caused a cutoff\n", stat_best_cut);
1256 output("# of the remaining %d times first move was really best (%02d%%)\n",
1257 stat_best_first, (stat_best_first*100)/MAX(stat_search_moves-stat_best_cut, 1));
1258 output("# evaluate was called %d times (quiescence node)\n", stat_evaluate);
1259 output("# of which %d times caused an early cutoff (leaf node)\n",
1260 stat_evaluate_cutoff);
1261 output("#hash: %d writes, %d probes (%d succesful, =%d, >%d, <%d)\n",
1262 stat_hash_write, stat_hash_tot, stat_hash_ex+stat_hash_low+stat_hash_upp,
1263 stat_hash_ex, stat_hash_low, stat_hash_upp);
1264 output("#etc: %d\n", stat_early_transp);
1265 output("#null move: %d (%d succesful)\n", stat_null_move, stat_null_cut);
1267 print_stats();
1268 char buf[256];
1269 max_quiesce_board.write_board(buf);
1270 output("#max quiesce board: %s [%d %d]\n", buf, max_quiesce_alpha, max_quiesce_beta);
1273 thinking = false;
1274 return retv;