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 ***************************************************************************/
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 #define WORST_MATE (INF-2500)
39 int stat_early_transp
;
47 int stat_search_moves
;
50 int stat_search_moves0
;
52 int stat_evaluate_cutoff
;
62 S(max_quiesce_nodes); \
66 S(quiesce_best_can_be_first); \
67 S(quiesce_best_was_first); \
69 S(quiesce_cutoff_first); \
72 S(search_best_can_be_first); \
73 S(search_best_was_first); \
75 S(search_cutoff_first); \
79 #define STAT(x) stat_##x++;
81 #define S(x) uint64_t stat_##x;
83 Board max_quiesce_board
;
84 int16_t max_quiesce_alpha
;
85 int16_t max_quiesce_beta
;
90 #define S(x) stat_##x = 0;
97 #define S(x) printf("# " #x " = %llu\n", (unsigned long long)stat_##x);
104 /* enable the quiescence search */
107 /* enable the nega-scout pv-search */
110 /* enable the null move */
113 /* before doing the alpha beta search check if any of the following positions
114 can give use an early cutoff thanks to the hashtable */
115 #define EARLY_TRANSP_CUTOFF 1
117 /* SEEMS TO BE A BIT BAD:
118 Extend when there is only one decent move */
119 #define SINGULAR_EXTENSION 0
121 /* reduce nodes for moves that are not check/captures that are considered
122 bad from the heuristic */
123 #define LATE_MOVE_REDUCTION 1
125 /* futility pruning: */
128 /* when the hashtable provides no "best" move, do a depth-2 search */
129 #define INTERNAL_ITERATIVE_DEEPENING 0
131 /* use the history sorting heuristic */
132 #define HISTORY_HEURISTIC 1
134 /* improve the sorting heuristic for pawn strikes */
135 #define PAWNSTRIKE_HEURISTIC 1
137 /* improve the sorting heuristic for moves to the center */
138 #define CENTER_HEURISTIC 0
144 int base_depth
; /* depth of the search at this ply */
145 int extensions
; /* global extensions at this node */
146 Move
*moves
; /* all generated moves */
147 int num_moves
; /* num of moves */
148 int curr_move
; /* the move being currently analyzed */
149 int16_t alpha
; /* alpha ans beta when the search started (not improved) */
156 Move mv_stack
[200*MAX_PV
];
157 int mv_stack_top
= 0;
158 SearchStack stack
[MAX_PV
];
161 void Engine::print_stat()
163 if(eng_status
!= ANALYZING
)
165 printf("Thinking: ");
166 for(int i
=0; i
<current_ply
; i
++)
168 if(stack
[i
].curr_move
== -2)
169 continue; //Internal iterative deepening
170 else if(stack
[i
].curr_move
== -1)
173 board
.do_null_move();
178 printf("%s", move_to_alg(buf
, &(stack
[i
].moves
[stack
[i
].curr_move
]) ) );
179 board
.do_move(stack
[i
].moves
[stack
[i
].curr_move
]);
181 printf((i
!= current_ply
-1) ? " " : "\n");
190 output("stat01: %d %llu %d %d %d %s\n",
191 current_time() - start_think_time
,
192 (unsigned long long)processed_nodes
,
193 stack
[0].base_depth
/100,
194 stack
[0].num_moves
-1-stack
[0].curr_move
,
196 move_to_alg(buf
, &(stack
[0].moves
[stack
[0].curr_move
]) ) );
199 output("stat01: 0 0 0 0 0\n");
202 void Engine::rewind_thinking()
204 for(int i
=current_ply
-1; i
>=0; i
--)
206 if(stack
[i
].curr_move
== -2)
208 else if(stack
[i
].curr_move
== -1)
209 board
.undo_null_move();
211 board
.undo_move(stack
[i
].moves
[stack
[i
].curr_move
]);
215 bool Engine::null_move_ok()
217 int c
= IS_WHITE(board
.color_to_move
) ? 5 : -1;
218 int numpawns
= board
.mat_tracking
[c
+PAWN
].count
;
219 int numpieces
= board
.mat_tracking
[c
+KNIGHT
].count
+ board
.mat_tracking
[c
+BISHOP
].count
220 + board
.mat_tracking
[c
+ROOK
].count
+ board
.mat_tracking
[c
+QUEEN
].count
;
223 if(numpieces
>= 1 && numpawns
>= 2)
228 void Engine::restore_thinking()
230 for(int i
=0; i
<current_ply
; i
++)
232 if(stack
[i
].curr_move
== -2)
234 else if(stack
[i
].curr_move
== -1)
235 board
.do_null_move();
237 board
.do_move(stack
[i
].moves
[stack
[i
].curr_move
]);
240 /* regenerate pinning info and under_check var, just to be sure :) */
242 board
.find_moves(mvs
);
246 Engine::moves_heuristic(Move
*mv
, int num_mv
, int ply
, int orig_depth
,
247 Move best_mv_hash
, bool quiesce
, Move
* prev
)
251 for(int i
=0;i
<num_mv
;i
++)
256 /* give a high bonus to the move stored in the hash, if any.
257 mark only which is, don't continue, because some extensions
258 may be triggered ad added later (ie pawn strike, etc) */
259 if(mv
[i
].as_int
== best_mv_hash
.as_int
)
264 if(PIECE_OF(board
.data
[mv
[i
].from
]) != PAWN
&&
265 (mv
[i
].from
== escape_from_1
[ply
-1] || mv
[i
].from
== escape_from_2
[ply
-1]) )
267 int x
= board
.move_see_val(mv
[i
]);
271 mv
[i
].val
+= 29000 + x
; /* escape */
278 /* process strong pawn moves */
279 if(PIECE_OF(board
.data
[mv
[i
].from
])==PAWN
) /* pawn strike */
281 if( ROW_OF(mv
[i
].to
) == board
.seventh_rank
[IS_WHITE(board
.color_to_move
)] )
283 int x
= board
.move_see_val(mv
[i
]);
287 mv
[i
].val
+= 29599; /* 7th push */
288 mv
[i
].extend
= PLY
; /* extend search */
293 if( mv
[i
].flags
== PROMOTEQUEEN
)
295 int x
= board
.move_see_val(mv
[i
]);
299 mv
[i
].val
+= 29600; /* promote! */
300 mv
[i
].extend
= PLY
; /* extend search */
306 if(orig_depth
>= 2*PLY
)
309 uint8_t up_right
= Board::up_dir
[IS_WHITE(board
.color_to_move
)] + RIGHT
;
310 uint8_t up_left
= Board::up_dir
[IS_WHITE(board
.color_to_move
)] + LEFT
;
311 uint8_t p1
= mv
[i
].to
+ up_right
;
312 uint8_t p2
= mv
[i
].to
+ up_left
;
313 uint8_t a
= OUT_OF_BOARD(p1
) ? 0 : board
.data
[p1
];
314 uint8_t b
= OUT_OF_BOARD(p2
) ? 0 : board
.data
[p2
];
315 if( (COLOR_OF(a
)==board
.other_color
&& PIECE_OF(a
)!=PAWN
)
316 || (COLOR_OF(b
)==board
.other_color
&& PIECE_OF(b
)!=PAWN
) )
318 int x
= board
.move_see_val(mv
[i
]);
322 mv
[i
].val
= 27000; /* pawn strike! */
323 //mv[i].extend = PLY; /* extend search */
333 int x
= board
.move_see_val(mv
[i
]);
335 if(prev
&& prev
->capture
&&
336 (mv
[i
].to
== prev
->to
) && (x
>= Board::simple_values
[PIECE_OF(prev
->capture
)]) )
339 if( (x
== Board::simple_values
[PIECE_OF(prev
->capture
)]) )
340 mv
[i
].extend
= /*(x==1) ? (PLY/2) :*/ PLY
;
341 // else if(prev->capture && ABS(x - Board::simple_values[PIECE_OF(prev->capture)]) == 1)
342 // mv[i].extend = PLY/2;
348 if(orig_depth
>-7*PLY
&& board
.move_is_check(mv
[i
]) )
354 else if(x
>=0 && orig_depth
>-7*PLY
&& board
.move_is_check(mv
[i
]) )
356 /* = capture but check */
361 else /* add a bonus for checks (but not too deep, or quiescence will get mad) */
362 if(orig_depth
>-3*PLY
&& board
.move_is_check(mv
[i
]) )
364 if(board
.move_see_val(mv
[i
])>=0)
371 /* null-move threat */
372 if(null_threat
[ply
-1] == mv
[i
])
378 mv
[i
].val
+= history_hit
[HISTORY_INDEX(mv
[i
])] * 1024 / (history_tot
[HISTORY_INDEX(mv
[i
])] + 4);
381 static int bof
[128] = {
382 0,0,1,2,2,1,0,0,ENDL
,
383 0,1,2,3,3,2,1,0,ENDL
,
384 0,2,4,5,5,4,2,0,ENDL
,
385 1,2,5,6,6,5,2,1,ENDL
,
386 1,2,5,6,6,5,2,1,ENDL
,
387 0,2,4,5,5,4,2,0,ENDL
,
388 0,1,2,3,3,2,1,0,ENDL
,
392 /* add a bonus for moves towards the center */
393 mv
[i
].val
+= (bof
[mv
[i
].to
] - bof
[mv
[i
].from
]);
394 #endif //CENTER_HEURISTIC
398 mv
[hash_move
].val
= 30000;
403 Engine::moves_quiescence_heuristic(Move
*mv
, int num_mv
, const Move
& best_mv_hash
,
404 int static_eval
, int alpha
, int beta
, int orig_depth
, Move
* prev
)
406 for(int i
=0;i
<num_mv
;i
++)
411 /* give a high bonus to the move stored in the hash, if any.
412 mark only which is, don't continue, because some extensions
413 may be triggered ad added later (ie pawn strike, etc) */
414 if(mv
[i
].as_int
== best_mv_hash
.as_int
)
421 /* process strong pawn moves */
422 if(PIECE_OF(board
.data
[mv
[i
].from
])==PAWN
) /* pawn strike */
424 if( ROW_OF(mv
[i
].to
) == board
.seventh_rank
[IS_WHITE(board
.color_to_move
)] )
426 int x
= board
.move_see_val(mv
[i
]);
434 mv
[i
].val
+= 29499; /* 7th push */
435 mv
[i
].extend
= PLY
; /* extend search */
439 if( mv
[i
].flags
== PROMOTEQUEEN
)
441 int x
= board
.move_see_val(mv
[i
]);
449 mv
[i
].val
+= 29500; /* promote! */
450 mv
[i
].extend
= PLY
; /* extend search */
456 uint8_t p1
= mv
[i
].to
+ up_right
;
457 uint8_t p2
= mv
[i
].to
+ up_left
;
458 uint8_t a
= OUT_OF_BOARD(p1
) ? 0 : board
.data
[p1
];
459 uint8_t b
= OUT_OF_BOARD(p2
) ? 0 : board
.data
[p2
];
460 if( (COLOR_OF(a
)==board
.other_color
&& PIECE_OF(a
)!=PAWN
)
461 || (COLOR_OF(b
)==board
.other_color
&& PIECE_OF(b
)!=PAWN
) )
463 int x
= board
.move_see_val(mv
[i
]);
470 mv
[i
].val
+= 27000; /* pawn strike! */
471 mv
[i
].extend
= PLY
; /* extend search */
479 int x
= board
.move_see_val(mv
[i
]);
481 if(prev
&& prev
->capture
&&
482 (mv
[i
].to
== prev
->to
) && (x
>= Board::simple_values
[PIECE_OF(prev
->capture
)]) )
485 if( (x
== Board::simple_values
[PIECE_OF(prev
->capture
)]) )
486 mv
[i
].extend
= /*(x==1) ? (PLY/2) :*/ PLY
;
487 // else if(prev->capture && ABS(x - Board::simple_values[PIECE_OF(prev->capture)]) == 1)
488 // mv[i].extend = PLY/2;
494 if(orig_depth
>-5*PLY
&& board
.move_is_check(mv
[i
]) )
500 else if(x
>=0 && orig_depth
>-5*PLY
&& board
.move_is_check(mv
[i
]) )
502 /* = capture but check */
507 else /* add a bonus for checks (but not too deep, or quiescence will get mad) */
508 if(orig_depth
>-3*PLY
&& board
.move_is_check(mv
[i
]) )
510 if(board
.move_see_val(mv
[i
])>=0)
520 /*******************************************************************************
521 The main alpha-beta recursive search function.
522 It handles both normal search (with or without null move)
523 and quiescence search, because i have having 2 almost identical
525 *******************************************************************************/
526 int16_t Engine::search(int ply
, int depth
, bool pv
, int16_t alpha
, int16_t beta
)
528 SearchStack
*s
= &stack
[ply
];
530 uint16_t cbest_mv_hash
= 0; /* the compressed move from the hash */
531 Move best_mv_hash
= Move::FromInt(0); /* the move from the hash */
532 int best_mv_found
= -1; /* the index of the best move AFTER searching */
534 bool extended
= false;
535 int16_t position_val
;
540 s
->base_depth
= depth
;
546 s
->threat
= Move::FromInt(0);
548 null_threat
[ply
] = Move::FromInt(0);
549 null_threat_dangerous
[ply
] = false;
550 //escape_from_1[ply] = escape_from_2[ply] = INVALID;
552 /* check if time is running out */
556 /* check for a draw for repetition or 50mvs. Of course the draw for
557 repetition must be checked BEFORE probing the hash :)*/
559 return (board
.color_to_move
== st_computer_color
) ? -35 :
560 ((board
.other_color
== st_computer_color
) ? 35 : 0); /* be aggressive! */
562 /*******************************************************************************
564 If the probe is succesful the hashtable will return us value
565 that can be exact, a lower bound or an upper bound, and if the
566 depth of the hashed search is >= the current depth this value
567 will be used to improve alpha and beta and possibly return immediatly.
568 The hastable will also give us a "best" move that will be searched
570 This is the move that caused the "final" cutoff when this position
571 was searched previously. This best move is actually the index of the best
572 move in the array of generated moves (it is supposed to be deterministic :)
573 *******************************************************************************/
575 HashEntry
*h
= probe_hash( board
.hash
);
577 if(h
&& (h
->depth
>= s
->base_depth
))// || ABS(h->value)>INF-1000) )
579 int16_t l
= h
->lower();
580 int16_t u
= h
->upper();
587 alpha
= MAX(alpha
, l
);
591 cbest_mv_hash
= h
->best_mv
;
593 /*******************************************************************************
594 Test if we are under check, and if so extend search
595 *******************************************************************************/
597 s
->under_check
= board
.under_attack(board
.king_pos
[IS_WHITE(board
.color_to_move
)],
600 /*******************************************************************************
601 If it is time to quiesce, evaluate and test if we can exit
602 immediately with a beta cut-off (try first a rough eval - delta)
603 *******************************************************************************/
604 quiesce
= ((!s
->under_check
) && (depth
<=0)) || (depth
<-60*PLY
);
607 if(quiesce
&& depth
>=-PLY
)
610 Move
*mv
= mv_stack
+ mv_stack_top
;
611 board
.do_null_move();
612 num_mv
= board
.find_moves(mv
);
613 uint8_t pup
= INVALID
;
615 for(int i
=0;i
<num_mv
;i
++)
617 if(!mv
[i
].capture
|| PIECE_OF(mv
[i
].capture
)==PAWN
)
619 if(mv
[i
].to
!= pup
&& board
.move_see_val(mv
[i
])>0)
629 board
.undo_null_move();
636 best
= board
.evaluate(st_computer_color
, alpha
, beta
);
638 alpha
= MAX(alpha
, best
);
641 stat_evaluate_cutoff
++;
650 /*******************************************************************************
652 *******************************************************************************/
653 if(!s
->under_check
&& (stack
[ply
-1].curr_move
!= -1) && depth
>= 2*PLY
&& beta
<WORST_MATE
&& null_move_ok())
656 int sdepth
= (depth
>= 5*PLY
) ? (depth
-4*PLY
) : depth
-3*PLY
;
661 board
.do_null_move();
662 val
= -search( ply
+1, sdepth
, true, -beta
, -beta
+1);
663 board
.undo_null_move();
673 if(val
< -WORST_MATE
)
674 null_threat_dangerous
[ply
] = true;
676 if(val
<alpha
-100 && /* we are facing a threat*/
677 stack
[ply
+1].best_move
!= -1) /* be sure we aren't reading random memory */
679 /* ok, officially the array stack[ply+1].moves has already
680 been deallocated, but who cares :) */
681 s
->threat
= stack
[ply
+1].moves
[stack
[ply
+1].best_move
];
684 /* Botvinnik-Markoff extension!!! */
685 if(!extended
&& ply
>=3 && (s
->threat
== stack
[ply
-2].threat
) )
698 /*******************************************************************************
699 Now generate the legal moves and look for a check/stalemate
700 *******************************************************************************/
702 /* generate all the legal moves */
703 s
->moves
= &mv_stack
[mv_stack_top
];
704 s
->num_moves
= board
.find_moves(s
->moves
);
705 mv_stack_top
+= s
->num_moves
;
706 s
->under_check
= board
.under_check
;
708 if(s
->under_check
==2) /* double check */
713 else if(s
->under_check
) /* simple check */
716 if(stack
[ply
-1].curr_move
>=0 &&
717 !board
.pins
[stack
[ply
-1].moves
[ /* last moved piece is not attacking the king */
718 stack
[ply
-1].curr_move
].to
]) /* so this is a discover check */
725 /* return now if the positon is terminal */
730 /* while mating, sacrify as much as possible :) */
731 best
= -INF
+ ply
;//*50 + board.material[IS_WHITE(eng_color)]/50;
738 /* single-reply extension */
739 if(s
->num_moves
== 1 && !extended
)
744 else if(s
->num_moves
<= 3 && !extended
)
750 /*******************************************************************************
752 First comes the move from the hashtable, if avalable.
753 The remaining moves are sorted with a heuristic that keeps in account
754 the history heuristic (ie the moves that previously caused an alpha
755 cutoff), a MVV/LVA bonus value and a small bonus for moves that go
757 *******************************************************************************/
759 /* convert the move we got from the hash to the move structure */
762 best_mv_hash
= board
.uncompress_move(cbest_mv_hash
);
763 /* if it happened that the move we got from the hashtable
764 is not valid, simply no move will get the high
765 heuristic bonus value */
767 #if INTERNAL_ITERATIVE_DEEPENING
768 else if(s
->base_depth
>3*PLY
&& pv
) /* don't do it only on the pv, or it will be useless :) */
772 int val
= search(ply
+1, s
->base_depth
-2*PLY
, true, alpha
, beta
);
775 HashEntry
*h2
= probe_hash( board
.hash
);
776 if(h2
&& h2
->best_mv
)
778 cbest_mv_hash
= h2
->best_mv
;
779 best_mv_hash
= board
.uncompress_move(cbest_mv_hash
);
782 #endif //INTERNAL_ITERATIVE_DEEPENING
784 /* for each move calculate the heuristic goodness value */
786 Move
*prev
= (stack
[ply
-1].curr_move
>=0) ? &stack
[ply
-1].moves
[stack
[ply
-1].curr_move
] : NULL
;
788 moves_quiescence_heuristic( s
->moves
, s
->num_moves
, best_mv_hash
,
789 best
, alpha
, beta
, s
->base_depth
, prev
);
791 moves_heuristic( s
->moves
, s
->num_moves
, ply
, s
->base_depth
,
792 best_mv_hash
, quiesce
, prev
);
795 /* if quiesce rip-off the "non-critical" moves */
799 for(int i
=0;i
<s
->num_moves
;i
++)
800 if(s
->moves
[i
].val
>0)
801 s
->moves
[n
++] = s
->moves
[i
];
802 mv_stack_top
-= s
->num_moves
-n
;
806 /* Don't do it now, do it incrementally */
807 //sort_moves( s->moves, s->num_moves );
810 #if EARLY_TRANSP_CUTOFF
811 /*******************************************************************************
812 Try to get an early beta cutoff using the hash table values
813 of the following moves, and improve alpha too.
814 Try on the first 6 value of the ordered moves (argh, looking into the
815 hashtable is very expensive because of the cache!!!!!!!!)
816 *******************************************************************************/
820 HashKey hk
= board
.move_hash(s
->moves
[0]);
821 for(int i
=1;i
<s
->num_moves
;i
++)
824 HashKey newhk
= board
.move_hash(s
->moves
[i
]);
825 HashEntry
*h2
= probe_hash( hk
);
828 if(h2
&& h2
->depth
>= depth
-PLY
)
835 alpha
= MAX(alpha
, (int16_t)-h2
->up
);
839 HashEntry
*h2
= probe_hash( hk
);
840 if(h2
&& h2
->depth
>= depth
-PLY
)
847 alpha
= MAX(alpha
, (int16_t)-h2
->up
);
850 #endif //EARLY_TRANSP_CUTOFF
852 /* set the current best move index (as will be saved in the hash) */
855 /*******************************************************************************
856 It is now time to loop all the successor moves and search recursively.
857 *******************************************************************************/
860 /* calcluate the evaluation (required by fitility pruning) */
861 position_val
= quiesce
? best
: board
.evaluate( st_computer_color
, -INF
, INF
);
864 for(int i
=0;i
<s
->num_moves
;i
++)
867 int sdepth
= depth
-100;
869 /* sort moves incrementally, in the hope of a beta cut */
870 incremental_sort_moves(s
->moves
+i
, s
->num_moves
-i
);
872 if(depth
< s
->base_depth
+100)
873 sdepth
+= s
->moves
[i
].extend
; /* extensions calculated during the heuristic sort */
876 /* futility pruning, it is done only if we are no under check
877 and the move is not a "critical" move */
878 if(depth
>0 && depth
<3*PLY
&& !s
->under_check
&& s
->moves
[i
].val
< 28000)
880 static const int mavala
[] = { 0, 490, 315, 980, 315, 100, 0 };
882 int16_t fmargin
= (depth
<= PLY
? 420 : 950);
883 int16_t fval
= position_val
+ mavala
[PIECE_OF(s
->moves
[i
].capture
)];
884 if(fval
< alpha
-fmargin
)
889 /* collect history statistics */
890 if(s
->moves
[i
].val
<28000)
892 int ix
= HISTORY_INDEX(s
->moves
[i
]);
893 if(history_tot
[ix
] > 1024)
895 history_tot
[ix
] = history_tot
[ix
]*7/8;
896 history_hit
[ix
] = history_hit
[ix
]*7/8;
902 if(!quiesce
&& PIECE_OF(board
.data
[s
->moves
[i
].from
]) == PAWN
&& s
->moves
[i
].val
== 27000) //FIXME, UGLY
904 escape_from_1
[ply
] = s
->moves
[i
].to
+ Board::up_dir
[IS_WHITE(board
.color_to_move
)] + RIGHT
;
905 escape_from_2
[ply
] = s
->moves
[i
].to
+ Board::up_dir
[IS_WHITE(board
.color_to_move
)] + LEFT
;
909 escape_from_1
[ply
] = escape_from_2
[ply
] = 0;
915 board
.do_move(s
->moves
[i
]);
919 if(s
->base_depth
> 0 && sdepth
<= 0)
921 STAT(quiesce_called
);
922 q
= stat_quiesce_nodes
;
925 #if NEGA_SCOUT /* use negascout, (null window search for nodes that are not in the pv) */
926 if(i
== 0) // || depth<200)
927 val
= -search( ply
+1, sdepth
, pv
, -beta
, -alpha
);
930 #if LATE_MOVE_REDUCTION
931 /* history pruning, if this is not a "critical" move and the failhigh
932 stats are too low, try a reduced depth search (if it returns >alpha,
933 re-do the full depth search) */
934 // if((sdepth>0) && !s->under_check && depth<=3*PLY && s->moves[i].val<28000 &&
935 // (history_hit[HISTORY_INDEX(s->moves[i])]+1)*3
936 // < (history_tot[HISTORY_INDEX(s->moves[i])]+1))
937 if((sdepth
>0) && !s
->under_check
&& s
->moves
[i
].val
<28000 && (i
>=7 || (i
>=5 && s
->moves
[i
].val
<350) ) )
939 val
= -search( ply
+1, sdepth
- PLY
, false, -alpha
-1, -alpha
);
941 goto skip_search
; /* reduced search was effective */
944 val
= -search( ply
+1, sdepth
, false, -alpha
-1, -alpha
);
945 if((val
>alpha
) && pv
)
946 val
= -search( ply
+1, sdepth
, true, -beta
, -alpha
);
949 /* normal full width alpha-beta */
950 val
= -search( ply
+1, sdepth
, pv
, -beta
, -alpha
);
953 if(s
->base_depth
> 0 && sdepth
<= 0)
955 q
= stat_quiesce_nodes
-q
;
956 if(q
> stat_max_quiesce_nodes
)
958 stat_max_quiesce_nodes
= q
;
959 max_quiesce_board
= board
;
964 board
.undo_move(s
->moves
[i
]);
967 /* update the current best value and check for and alpha cut */
968 best
= MAX(best
, val
);
983 /* update a few stats */
994 if(ply
==0 && depth
>100)
1003 stat_search_moves0
++;
1007 /* collect statistics for the history */
1009 !s
->moves
[best_mv_found
].capture
&&
1010 !(s
->moves
[best_mv_found
].flags
>=PROMOTE_FIRST
))
1012 history_hit
[HISTORY_INDEX(s
->moves
[best_mv_found
])]++;
1013 history_tot
[HISTORY_INDEX(s
->moves
[best_mv_found
])]++;
1017 mv_stack_top
-= s
->num_moves
; /* free the moves we allocated */
1019 /* this is a null move, save what the threat is */
1020 if(stack
[ply
-1].curr_move
== -1 && best_mv_found
>= 0)
1021 null_threat
[ply
-1] = s
->moves
[best_mv_found
];
1023 /* if we found a best move searching, that move will be saved.
1024 if we did no search (ie quiescence), save the old hash value,
1025 or -1 if no hash entry had been found */
1026 int bestmv
= cbest_mv_hash
;
1027 if(best_mv_found
>= 0)
1028 bestmv
= board
.compress_move(s
->moves
[best_mv_found
]);
1030 /* write the value in the hash, with the index of the best move */
1031 write_hash( best
> s
->alpha
? best
: -INF
,
1032 best
< beta
? MAX(best
, s
->alpha
) : +INF
,
1033 MAX(s
->base_depth
,-500), bestmv
);
1039 Move
Engine::find_best_move()
1041 int num_mate_hits
= 0;
1042 SearchStack
*s
= &stack
[0];
1048 /* initialize the root node */
1050 s
->base_depth
= 100;
1055 s
->threat
= Move::FromInt(0);
1058 s
->moves
= mv_stack
;
1059 s
->num_moves
= mv_stack_top
= board
.find_moves(s
->moves
);
1061 /* calculate how much time we will think*/
1062 start_think_time
= current_time();
1063 if( analysis_limit
== TIME_LIMIT
)
1065 if(board
.color_to_move
== st_computer_color
)
1067 else /* pondering? analysing? */
1068 time_best_csec
= 99999999;
1069 max_think_time
= start_think_time
+ time_best_csec
- 2;
1072 /* to print the analysis */
1074 output("\tply\tscore\ttime\tnodes\tpv\n");
1076 /* return immediatly if the move is forced. */
1080 /* probe the play lines */
1081 if( eng_status
== PLAYING
1082 && st_computer_color
== board
.color_to_move
1083 && probe_lines( board
.hash
, &retv
))
1089 /* probe the book */
1090 if(probe_book( board
.hash
, &retv
)) {
1091 for(int i
=0;i
<s
->num_moves
++;i
++)
1092 if(retv
.as_int
== s
->moves
[i
].as_int
)
1097 output("Error!!! invalid move in the book!!!\n");
1102 prof_find_moves
= 0;
1103 prof_find_captures
= 0;
1105 prof_sort_moves
= 0;
1106 prof_move_is_check
= 0;
1107 prof_move_see_val
= 0;
1111 stat_early_transp
= 0;
1116 stat_best_first
= 0;
1118 stat_search_moves
= 0;
1119 stat_best_first0
= 0;
1121 stat_search_moves0
= 0;
1123 stat_evaluate_cutoff
= 0;
1126 stat_hash_write
= 0;
1131 //analysis_color = board.color_to_move;
1132 processed_nodes
= 0;
1133 int16_t best_guess
= 0;
1137 /* set the back jump for the quick thinking exit */
1141 /* start with a guess of 0 */
1142 s
->moves
[0].val
= 0;
1145 /* do the iterative deepening thing. */
1148 int16_t alpha
= -INF
;
1151 memset( history_tot
, 0, HISTORY_SIZE
*sizeof(uint16_t));
1152 memset( history_hit
, 0, HISTORY_SIZE
*sizeof(uint16_t));
1154 /* save the result of the previous search */
1155 result
[s
->base_depth
/PLY
-1] = s
->moves
[0];
1157 /* for each move call the alpha-beta search function */
1159 for(i
=0;i
<s
->num_moves
;i
++)
1163 board
.do_move(s
->moves
[i
]);
1167 s
->moves
[i
].val
= -search( 1, s
->base_depth
-PLY
, true, -INF
, -alpha
);
1171 s
->moves
[i
].val
= -search( 1, s
->base_depth
-PLY
, false, -alpha
-1, -alpha
);
1172 if(s
->moves
[i
].val
> alpha
)
1173 s
->moves
[i
].val
= -search( 1, s
->base_depth
-PLY
, true, -INF
, -alpha
);
1176 s
->moves
[i
].val
= -search( 1, s
->base_depth
-100, true, -INF
, -alpha
);
1178 board
.undo_move(s
->moves
[i
]);
1183 if(s
->moves
[i
].val
> alpha
)
1185 alpha
= s
->moves
[i
].val
;
1190 /* this move caused an alpha cut, so print the new line */
1191 if( post
/*&& processed_nodes>100000*/)
1193 output("\t%d\t%d\t%d\t%llu\t", s
->base_depth
/100,
1194 s
->moves
[i
].val
, current_time() - start_think_time
, processed_nodes
);
1195 print_moves(&s
->moves
[i
], 1, true);
1202 /* the search is done, sort the moves so that best is searched first */
1205 s
->moves
[best_mv
].val
++;
1206 sort_moves(s
->moves
, i
); /* sort i moves (those that we where able to search) */
1210 /* print the result of the analysis at this depth */
1211 if( post
/*&& processed_nodes>100000*/)
1213 output("\t%d\t%d\t%d\t%llu\t", s
->base_depth
/100,
1214 s
->moves
[0].val
, current_time() - start_think_time
, processed_nodes
);
1215 print_moves(&s
->moves
[0], 1, true);
1219 if( s
->base_depth
>= 40*PLY
)
1222 /* return in case of fixed depth search */
1223 if( eng_status
== PLAYING
&& st_computer_color
== board
.color_to_move
&&
1224 analysis_limit
== DEPTH_LIMIT
&& s
->base_depth
== st_depth
*PLY
)
1227 /* return if 3/5 of time is gone (we can't search another ply anyway) */
1228 if( eng_status
== PLAYING
&& st_computer_color
== board
.color_to_move
&&
1229 analysis_limit
== TIME_LIMIT
&&
1230 (current_time()-start_think_time
) >= (time_best_csec
*3/5) )
1233 /* if a checkmate was detected return immediately */
1234 if( ABS(alpha
) > WORST_MATE
)
1237 if(num_mate_hits
>= 5)
1241 s
->base_depth
+= PLY
;
1249 prof_tot
= rdtsc() - prof_tot
;
1250 #define SHOW_PROF(a) output("@"#a": %llu (%llu%%)\n", \
1251 prof_##a, prof_##a*100/prof_tot);
1255 SHOW_PROF(find_moves
);
1256 SHOW_PROF(find_captures
);
1257 SHOW_PROF(heuristic
);
1258 SHOW_PROF(move_is_check
);
1259 SHOW_PROF(move_see_val
);
1260 SHOW_PROF(sort_moves
);
1262 output("#nodes: %llu (~%llu nps)\n", processed_nodes
, (processed_nodes
*100)/
1263 MAX(current_time()-start_think_time
,1) );
1264 output("# %d times all the moves were seached (non-leaf non-quiesce node)\n",
1266 output("# of which %d times first move caused a cutoff\n", stat_best_cut
);
1267 output("# of the remaining %d times first move was really best (%02d%%)\n",
1268 stat_best_first
, (stat_best_first
*100)/MAX(stat_search_moves
-stat_best_cut
, 1));
1269 output("# evaluate was called %d times (quiescence node)\n", stat_evaluate
);
1270 output("# of which %d times caused an early cutoff (leaf node)\n",
1271 stat_evaluate_cutoff
);
1272 output("#hash: %d writes, %d probes (%d succesful, =%d, >%d, <%d)\n",
1273 stat_hash_write
, stat_hash_tot
, stat_hash_ex
+stat_hash_low
+stat_hash_upp
,
1274 stat_hash_ex
, stat_hash_low
, stat_hash_upp
);
1275 output("#etc: %d\n", stat_early_transp
);
1276 output("#null move: %d (%d succesful)\n", stat_null_move
, stat_null_cut
);
1280 max_quiesce_board
.write_board(buf
);
1281 output("#max quiesce board: %s [%d %d]\n", buf
, max_quiesce_alpha
, max_quiesce_beta
);