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
>= 2 && numpawns
>= 2)
225 if(numpieces
>= 1 && numpawns
>= 3)
230 void Engine::restore_thinking()
232 for(int i
=0; i
<current_ply
; i
++)
234 if(stack
[i
].curr_move
== -2)
236 else if(stack
[i
].curr_move
== -1)
237 board
.do_null_move();
239 board
.do_move(stack
[i
].moves
[stack
[i
].curr_move
]);
242 /* regenerate pinning info and under_check var, just to be sure :) */
244 board
.find_moves(mvs
);
248 Engine::moves_heuristic(Move
*mv
, int num_mv
, int ply
, int orig_depth
,
249 Move best_mv_hash
, bool quiesce
, Move
* prev
)
253 for(int i
=0;i
<num_mv
;i
++)
258 /* give a high bonus to the move stored in the hash, if any.
259 mark only which is, don't continue, because some extensions
260 may be triggered ad added later (ie pawn strike, etc) */
261 if(mv
[i
].as_int
== best_mv_hash
.as_int
)
266 if(PIECE_OF(board
.data
[mv
[i
].from
]) != PAWN
&&
267 (mv
[i
].from
== escape_from_1
[ply
-1] || mv
[i
].from
== escape_from_2
[ply
-1]) )
269 int x
= board
.move_see_val(mv
[i
]);
273 mv
[i
].val
+= 29000 + x
; /* escape */
280 /* process strong pawn moves */
281 if(PIECE_OF(board
.data
[mv
[i
].from
])==PAWN
) /* pawn strike */
283 if( ROW_OF(mv
[i
].to
) == board
.seventh_rank
[IS_WHITE(board
.color_to_move
)] )
285 int x
= board
.move_see_val(mv
[i
]);
289 mv
[i
].val
+= 29599; /* 7th push */
290 mv
[i
].extend
= PLY
; /* extend search */
295 if( mv
[i
].flags
== PROMOTEQUEEN
)
297 int x
= board
.move_see_val(mv
[i
]);
301 mv
[i
].val
+= 29600; /* promote! */
302 mv
[i
].extend
= PLY
; /* extend search */
308 if(orig_depth
>= 2*PLY
)
311 uint8_t up_right
= Board::up_dir
[IS_WHITE(board
.color_to_move
)] + RIGHT
;
312 uint8_t up_left
= Board::up_dir
[IS_WHITE(board
.color_to_move
)] + LEFT
;
313 uint8_t p1
= mv
[i
].to
+ up_right
;
314 uint8_t p2
= mv
[i
].to
+ up_left
;
315 uint8_t a
= OUT_OF_BOARD(p1
) ? 0 : board
.data
[p1
];
316 uint8_t b
= OUT_OF_BOARD(p2
) ? 0 : board
.data
[p2
];
317 if( (COLOR_OF(a
)==board
.other_color
&& PIECE_OF(a
)!=PAWN
)
318 || (COLOR_OF(b
)==board
.other_color
&& PIECE_OF(b
)!=PAWN
) )
320 int x
= board
.move_see_val(mv
[i
]);
324 mv
[i
].val
= 27000; /* pawn strike! */
325 //mv[i].extend = PLY; /* extend search */
335 int x
= board
.move_see_val(mv
[i
]);
337 if(prev
&& prev
->capture
&&
338 (mv
[i
].to
== prev
->to
) && (x
>= Board::simple_values
[PIECE_OF(prev
->capture
)]) )
341 if( (x
== Board::simple_values
[PIECE_OF(prev
->capture
)]) )
342 mv
[i
].extend
= /*(x==1) ? (PLY/2) :*/ PLY
;
343 // else if(prev->capture && ABS(x - Board::simple_values[PIECE_OF(prev->capture)]) == 1)
344 // mv[i].extend = PLY/2;
350 if(orig_depth
>-7*PLY
&& board
.move_is_check(mv
[i
]) )
356 else if(x
>=0 && orig_depth
>-7*PLY
&& board
.move_is_check(mv
[i
]) )
358 /* = capture but check */
363 else /* add a bonus for checks (but not too deep, or quiescence will get mad) */
364 if(orig_depth
>-3*PLY
&& board
.move_is_check(mv
[i
]) )
366 if(board
.move_see_val(mv
[i
])>=0)
373 /* null-move threat */
374 if(null_threat
[ply
-1] == mv
[i
])
380 mv
[i
].val
+= history_hit
[HISTORY_INDEX(mv
[i
])] * 1024 / (history_tot
[HISTORY_INDEX(mv
[i
])] + 4);
383 static int bof
[128] = {
384 0,0,1,2,2,1,0,0,ENDL
,
385 0,1,2,3,3,2,1,0,ENDL
,
386 0,2,4,5,5,4,2,0,ENDL
,
387 1,2,5,6,6,5,2,1,ENDL
,
388 1,2,5,6,6,5,2,1,ENDL
,
389 0,2,4,5,5,4,2,0,ENDL
,
390 0,1,2,3,3,2,1,0,ENDL
,
394 /* add a bonus for moves towards the center */
395 mv
[i
].val
+= (bof
[mv
[i
].to
] - bof
[mv
[i
].from
]);
396 #endif //CENTER_HEURISTIC
400 mv
[hash_move
].val
= 30000;
405 Engine::moves_quiescence_heuristic(Move
*mv
, int num_mv
, const Move
& best_mv_hash
,
406 int static_eval
, int alpha
, int beta
, int orig_depth
, Move
* prev
)
408 for(int i
=0;i
<num_mv
;i
++)
413 /* give a high bonus to the move stored in the hash, if any.
414 mark only which is, don't continue, because some extensions
415 may be triggered ad added later (ie pawn strike, etc) */
416 if(mv
[i
].as_int
== best_mv_hash
.as_int
)
423 /* process strong pawn moves */
424 if(PIECE_OF(board
.data
[mv
[i
].from
])==PAWN
) /* pawn strike */
426 if( ROW_OF(mv
[i
].to
) == board
.seventh_rank
[IS_WHITE(board
.color_to_move
)] )
428 int x
= board
.move_see_val(mv
[i
]);
436 mv
[i
].val
+= 29499; /* 7th push */
437 mv
[i
].extend
= PLY
; /* extend search */
441 if( mv
[i
].flags
== PROMOTEQUEEN
)
443 int x
= board
.move_see_val(mv
[i
]);
451 mv
[i
].val
+= 29500; /* promote! */
452 mv
[i
].extend
= PLY
; /* extend search */
458 uint8_t p1
= mv
[i
].to
+ up_right
;
459 uint8_t p2
= mv
[i
].to
+ up_left
;
460 uint8_t a
= OUT_OF_BOARD(p1
) ? 0 : board
.data
[p1
];
461 uint8_t b
= OUT_OF_BOARD(p2
) ? 0 : board
.data
[p2
];
462 if( (COLOR_OF(a
)==board
.other_color
&& PIECE_OF(a
)!=PAWN
)
463 || (COLOR_OF(b
)==board
.other_color
&& PIECE_OF(b
)!=PAWN
) )
465 int x
= board
.move_see_val(mv
[i
]);
472 mv
[i
].val
+= 27000; /* pawn strike! */
473 mv
[i
].extend
= PLY
; /* extend search */
481 int x
= board
.move_see_val(mv
[i
]);
483 if(prev
&& prev
->capture
&&
484 (mv
[i
].to
== prev
->to
) && (x
>= Board::simple_values
[PIECE_OF(prev
->capture
)]) )
487 if( (x
== Board::simple_values
[PIECE_OF(prev
->capture
)]) )
488 mv
[i
].extend
= /*(x==1) ? (PLY/2) :*/ PLY
;
489 // else if(prev->capture && ABS(x - Board::simple_values[PIECE_OF(prev->capture)]) == 1)
490 // mv[i].extend = PLY/2;
496 if(orig_depth
>-5*PLY
&& board
.move_is_check(mv
[i
]) )
502 else if(x
>=0 && orig_depth
>-5*PLY
&& board
.move_is_check(mv
[i
]) )
504 /* = capture but check */
509 else /* add a bonus for checks (but not too deep, or quiescence will get mad) */
510 if(orig_depth
>-3*PLY
&& board
.move_is_check(mv
[i
]) )
512 if(board
.move_see_val(mv
[i
])>=0)
522 /*******************************************************************************
523 The main alpha-beta recursive search function.
524 It handles both normal search (with or without null move)
525 and quiescence search, because i have having 2 almost identical
527 *******************************************************************************/
528 int16_t Engine::search(int ply
, int depth
, bool pv
, int16_t alpha
, int16_t beta
)
530 SearchStack
*s
= &stack
[ply
];
532 uint16_t cbest_mv_hash
= 0; /* the compressed move from the hash */
533 Move best_mv_hash
= Move::FromInt(0); /* the move from the hash */
534 int best_mv_found
= -1; /* the index of the best move AFTER searching */
536 bool extended
= false;
537 int16_t position_val
;
542 s
->base_depth
= depth
;
548 s
->threat
= Move::FromInt(0);
550 null_threat
[ply
] = Move::FromInt(0);
551 null_threat_dangerous
[ply
] = false;
552 //escape_from_1[ply] = escape_from_2[ply] = INVALID;
554 /* check if time is running out */
558 /* check for a draw for repetition or 50mvs. Of course the draw for
559 repetition must be checked BEFORE probing the hash :)*/
561 return (board
.color_to_move
== st_computer_color
) ? -35 :
562 ((board
.other_color
== st_computer_color
) ? 35 : 0); /* be aggressive! */
564 /*******************************************************************************
566 If the probe is succesful the hashtable will return us value
567 that can be exact, a lower bound or an upper bound, and if the
568 depth of the hashed search is >= the current depth this value
569 will be used to improve alpha and beta and possibly return immediatly.
570 The hastable will also give us a "best" move that will be searched
572 This is the move that caused the "final" cutoff when this position
573 was searched previously. This best move is actually the index of the best
574 move in the array of generated moves (it is supposed to be deterministic :)
575 *******************************************************************************/
577 HashEntry
*h
= probe_hash( board
.hash
);
579 if(h
&& (h
->depth
>= s
->base_depth
))// || ABS(h->value)>INF-1000) )
581 int16_t l
= h
->lower();
582 int16_t u
= h
->upper();
589 alpha
= MAX(alpha
, l
);
593 cbest_mv_hash
= h
->best_mv
;
595 /*******************************************************************************
596 Test if we are under check, and if so extend search
597 *******************************************************************************/
599 s
->under_check
= board
.under_attack(board
.king_pos
[IS_WHITE(board
.color_to_move
)],
602 /*******************************************************************************
603 If it is time to quiesce, evaluate and test if we can exit
604 immediately with a beta cut-off (try first a rough eval - delta)
605 *******************************************************************************/
606 quiesce
= ((!s
->under_check
) && (depth
<=0)) || (depth
<-60*PLY
);
609 if(quiesce
&& depth
>=-PLY
)
612 Move
*mv
= mv_stack
+ mv_stack_top
;
613 board
.do_null_move();
614 num_mv
= board
.find_moves(mv
);
615 uint8_t pup
= INVALID
;
617 for(int i
=0;i
<num_mv
;i
++)
619 if(!mv
[i
].capture
|| PIECE_OF(mv
[i
].capture
)==PAWN
)
621 if(mv
[i
].to
!= pup
&& board
.move_see_val(mv
[i
])>0)
631 board
.undo_null_move();
638 best
= board
.evaluate(st_computer_color
, alpha
, beta
);
640 alpha
= MAX(alpha
, best
);
643 stat_evaluate_cutoff
++;
652 /*******************************************************************************
654 *******************************************************************************/
655 if(!s
->under_check
&& (stack
[ply
-1].curr_move
!= -1) && depth
>= 2*PLY
&& beta
<WORST_MATE
&& null_move_ok())
658 int sdepth
= (depth
>= 5*PLY
) ? (depth
-4*PLY
) : depth
-3*PLY
;
663 board
.do_null_move();
664 val
= -search( ply
+1, sdepth
, true, -beta
, -beta
+1);
665 board
.undo_null_move();
675 if(val
< -WORST_MATE
)
676 null_threat_dangerous
[ply
] = true;
678 if(val
<alpha
-100 && /* we are facing a threat*/
679 stack
[ply
+1].best_move
!= -1) /* be sure we aren't reading random memory */
681 /* ok, officially the array stack[ply+1].moves has already
682 been deallocated, but who cares :) */
683 s
->threat
= stack
[ply
+1].moves
[stack
[ply
+1].best_move
];
686 /* Botvinnik-Markoff extension!!! */
687 if(!extended
&& ply
>=3 && (s
->threat
== stack
[ply
-2].threat
) )
700 /*******************************************************************************
701 Now generate the legal moves and look for a check/stalemate
702 *******************************************************************************/
704 /* generate all the legal moves */
705 s
->moves
= &mv_stack
[mv_stack_top
];
706 s
->num_moves
= board
.find_moves(s
->moves
);
707 mv_stack_top
+= s
->num_moves
;
708 s
->under_check
= board
.under_check
;
710 if(s
->under_check
==2) /* double check */
715 else if(s
->under_check
) /* simple check */
718 if(stack
[ply
-1].curr_move
>=0 &&
719 !board
.pins
[stack
[ply
-1].moves
[ /* last moved piece is not attacking the king */
720 stack
[ply
-1].curr_move
].to
]) /* so this is a discover check */
727 /* return now if the positon is terminal */
732 /* while mating, sacrify as much as possible :) */
733 best
= -INF
+ ply
;//*50 + board.material[IS_WHITE(eng_color)]/50;
740 /* single-reply extension */
741 if(s
->num_moves
== 1 && !extended
)
746 else if(s
->num_moves
<= 3 && !extended
)
752 /*******************************************************************************
754 First comes the move from the hashtable, if avalable.
755 The remaining moves are sorted with a heuristic that keeps in account
756 the history heuristic (ie the moves that previously caused an alpha
757 cutoff), a MVV/LVA bonus value and a small bonus for moves that go
759 *******************************************************************************/
761 /* convert the move we got from the hash to the move structure */
764 best_mv_hash
= board
.uncompress_move(cbest_mv_hash
);
765 /* if it happened that the move we got from the hashtable
766 is not valid, simply no move will get the high
767 heuristic bonus value */
769 #if INTERNAL_ITERATIVE_DEEPENING
770 else if(s
->base_depth
>3*PLY
&& pv
) /* don't do it only on the pv, or it will be useless :) */
774 int val
= search(ply
+1, s
->base_depth
-2*PLY
, true, alpha
, beta
);
777 HashEntry
*h2
= probe_hash( board
.hash
);
778 if(h2
&& h2
->best_mv
)
780 cbest_mv_hash
= h2
->best_mv
;
781 best_mv_hash
= board
.uncompress_move(cbest_mv_hash
);
784 #endif //INTERNAL_ITERATIVE_DEEPENING
786 /* for each move calculate the heuristic goodness value */
788 Move
*prev
= (stack
[ply
-1].curr_move
>=0) ? &stack
[ply
-1].moves
[stack
[ply
-1].curr_move
] : NULL
;
790 moves_quiescence_heuristic( s
->moves
, s
->num_moves
, best_mv_hash
,
791 best
, alpha
, beta
, s
->base_depth
, prev
);
793 moves_heuristic( s
->moves
, s
->num_moves
, ply
, s
->base_depth
,
794 best_mv_hash
, quiesce
, prev
);
797 /* if quiesce rip-off the "non-critical" moves */
801 for(int i
=0;i
<s
->num_moves
;i
++)
802 if(s
->moves
[i
].val
>0)
803 s
->moves
[n
++] = s
->moves
[i
];
804 mv_stack_top
-= s
->num_moves
-n
;
808 /* Don't do it now, do it incrementally */
809 //sort_moves( s->moves, s->num_moves );
812 #if EARLY_TRANSP_CUTOFF
813 /*******************************************************************************
814 Try to get an early beta cutoff using the hash table values
815 of the following moves, and improve alpha too.
816 Try on the first 6 value of the ordered moves (argh, looking into the
817 hashtable is very expensive because of the cache!!!!!!!!)
818 *******************************************************************************/
822 HashKey hk
= board
.move_hash(s
->moves
[0]);
823 for(int i
=1;i
<s
->num_moves
;i
++)
826 HashKey newhk
= board
.move_hash(s
->moves
[i
]);
827 HashEntry
*h2
= probe_hash( hk
);
830 if(h2
&& h2
->depth
>= depth
-PLY
)
837 alpha
= MAX(alpha
, (int16_t)-h2
->up
);
841 HashEntry
*h2
= probe_hash( hk
);
842 if(h2
&& h2
->depth
>= depth
-PLY
)
849 alpha
= MAX(alpha
, (int16_t)-h2
->up
);
852 #endif //EARLY_TRANSP_CUTOFF
854 /* set the current best move index (as will be saved in the hash) */
857 /*******************************************************************************
858 It is now time to loop all the successor moves and search recursively.
859 *******************************************************************************/
862 /* calcluate the evaluation (required by fitility pruning) */
863 position_val
= quiesce
? best
: board
.evaluate( st_computer_color
, -INF
, INF
);
866 for(int i
=0;i
<s
->num_moves
;i
++)
869 int sdepth
= depth
-100;
871 /* sort moves incrementally, in the hope of a beta cut */
872 incremental_sort_moves(s
->moves
+i
, s
->num_moves
-i
);
874 if(depth
< s
->base_depth
+100)
875 sdepth
+= s
->moves
[i
].extend
; /* extensions calculated during the heuristic sort */
878 /* futility pruning, it is done only if we are no under check
879 and the move is not a "critical" move */
880 if(depth
>0 && depth
<3*PLY
&& !s
->under_check
&& s
->moves
[i
].val
< 28000)
882 static const int mavala
[] = { 0, 490, 315, 980, 315, 100, 0 };
884 int16_t fmargin
= (depth
<= PLY
? 420 : 950);
885 int16_t fval
= position_val
+ mavala
[PIECE_OF(s
->moves
[i
].capture
)];
886 if(fval
< alpha
-fmargin
)
891 /* collect history statistics */
892 if(s
->moves
[i
].val
<28000)
894 int ix
= HISTORY_INDEX(s
->moves
[i
]);
895 if(history_tot
[ix
] > 1024)
897 history_tot
[ix
] = history_tot
[ix
]*7/8;
898 history_hit
[ix
] = history_hit
[ix
]*7/8;
904 if(!quiesce
&& PIECE_OF(board
.data
[s
->moves
[i
].from
]) == PAWN
&& s
->moves
[i
].val
== 27000) //FIXME, UGLY
906 escape_from_1
[ply
] = s
->moves
[i
].to
+ Board::up_dir
[IS_WHITE(board
.color_to_move
)] + RIGHT
;
907 escape_from_2
[ply
] = s
->moves
[i
].to
+ Board::up_dir
[IS_WHITE(board
.color_to_move
)] + LEFT
;
911 escape_from_1
[ply
] = escape_from_2
[ply
] = 0;
917 board
.do_move(s
->moves
[i
]);
921 if(s
->base_depth
> 0 && sdepth
<= 0)
923 STAT(quiesce_called
);
924 q
= stat_quiesce_nodes
;
927 #if NEGA_SCOUT /* use negascout, (null window search for nodes that are not in the pv) */
928 if(i
== 0) // || depth<200)
929 val
= -search( ply
+1, sdepth
, pv
, -beta
, -alpha
);
932 #if LATE_MOVE_REDUCTION
933 /* history pruning, if this is not a "critical" move and the failhigh
934 stats are too low, try a reduced depth search (if it returns >alpha,
935 re-do the full depth search) */
936 // if((sdepth>0) && !s->under_check && depth<=3*PLY && s->moves[i].val<28000 &&
937 // (history_hit[HISTORY_INDEX(s->moves[i])]+1)*3
938 // < (history_tot[HISTORY_INDEX(s->moves[i])]+1))
939 if((sdepth
>0) && !s
->under_check
&& s
->moves
[i
].val
<28000 && i
>=7 )
941 val
= -search( ply
+1, sdepth
- 60, false, -alpha
-1, -alpha
);
943 goto skip_search
; /* reduced search was effective */
946 val
= -search( ply
+1, sdepth
, false, -alpha
-1, -alpha
);
947 if((val
>alpha
) && pv
)
948 val
= -search( ply
+1, sdepth
, true, -beta
, -alpha
);
951 /* normal full width alpha-beta */
952 val
= -search( ply
+1, sdepth
, pv
, -beta
, -alpha
);
955 if(s
->base_depth
> 0 && sdepth
<= 0)
957 q
= stat_quiesce_nodes
-q
;
958 if(q
> stat_max_quiesce_nodes
)
960 stat_max_quiesce_nodes
= q
;
961 max_quiesce_board
= board
;
966 board
.undo_move(s
->moves
[i
]);
969 /* update the current best value and check for and alpha cut */
970 best
= MAX(best
, val
);
985 /* update a few stats */
996 if(ply
==0 && depth
>100)
1005 stat_search_moves0
++;
1009 /* collect statistics for the history */
1011 !s
->moves
[best_mv_found
].capture
&&
1012 !(s
->moves
[best_mv_found
].flags
>=PROMOTE_FIRST
))
1014 history_hit
[HISTORY_INDEX(s
->moves
[best_mv_found
])]++;
1015 history_tot
[HISTORY_INDEX(s
->moves
[best_mv_found
])]++;
1019 mv_stack_top
-= s
->num_moves
; /* free the moves we allocated */
1021 /* this is a null move, save what the threat is */
1022 if(stack
[ply
-1].curr_move
== -1 && best_mv_found
>= 0)
1023 null_threat
[ply
-1] = s
->moves
[best_mv_found
];
1025 /* if we found a best move searching, that move will be saved.
1026 if we did no search (ie quiescence), save the old hash value,
1027 or -1 if no hash entry had been found */
1028 int bestmv
= cbest_mv_hash
;
1029 if(best_mv_found
>= 0)
1030 bestmv
= board
.compress_move(s
->moves
[best_mv_found
]);
1032 /* write the value in the hash, with the index of the best move */
1033 write_hash( best
> s
->alpha
? MIN(best
, beta
) : -INF
,
1034 best
< beta
? MAX(best
, s
->alpha
) : +INF
,
1035 MAX(s
->base_depth
,-500), bestmv
);
1041 Move
Engine::find_best_move()
1043 int num_mate_hits
= 0;
1044 SearchStack
*s
= &stack
[0];
1050 /* initialize the root node */
1052 s
->base_depth
= 100;
1057 s
->threat
= Move::FromInt(0);
1060 s
->moves
= mv_stack
;
1061 s
->num_moves
= mv_stack_top
= board
.find_moves(s
->moves
);
1063 /* calculate how much time we will think*/
1064 start_think_time
= current_time();
1065 if( analysis_limit
== TIME_LIMIT
)
1067 if(board
.color_to_move
== st_computer_color
)
1069 else /* pondering? analysing? */
1070 time_best_csec
= 99999999;
1071 max_think_time
= start_think_time
+ time_best_csec
- 2;
1074 /* to print the analysis */
1076 output("\tply\tscore\ttime\tnodes\tpv\n");
1078 /* return immediatly if the move is forced. */
1082 /* probe the play lines */
1083 if( eng_status
== PLAYING
1084 && st_computer_color
== board
.color_to_move
1085 && probe_lines( board
.hash
, &retv
))
1091 /* probe the book */
1092 if(probe_book( board
.hash
, &retv
)) {
1093 for(int i
=0;i
<s
->num_moves
++;i
++)
1094 if(retv
.as_int
== s
->moves
[i
].as_int
)
1099 output("Error!!! invalid move in the book!!!\n");
1104 prof_find_moves
= 0;
1105 prof_find_captures
= 0;
1107 prof_sort_moves
= 0;
1108 prof_move_is_check
= 0;
1109 prof_move_see_val
= 0;
1113 stat_early_transp
= 0;
1118 stat_best_first
= 0;
1120 stat_search_moves
= 0;
1121 stat_best_first0
= 0;
1123 stat_search_moves0
= 0;
1125 stat_evaluate_cutoff
= 0;
1128 stat_hash_write
= 0;
1133 //analysis_color = board.color_to_move;
1134 processed_nodes
= 0;
1135 int16_t best_guess
= 0;
1139 /* set the back jump for the quick thinking exit */
1143 /* start with a guess of 0 */
1144 s
->moves
[0].val
= 0;
1147 /* do the iterative deepening thing. */
1150 int16_t alpha
= -INF
;
1153 memset( history_tot
, 0, HISTORY_SIZE
*sizeof(uint16_t));
1154 memset( history_hit
, 0, HISTORY_SIZE
*sizeof(uint16_t));
1156 /* save the result of the previous search */
1157 result
[s
->base_depth
/PLY
-1] = s
->moves
[0];
1159 /* for each move call the alpha-beta search function */
1161 for(i
=0;i
<s
->num_moves
;i
++)
1165 board
.do_move(s
->moves
[i
]);
1169 s
->moves
[i
].val
= -search( 1, s
->base_depth
-PLY
, true, -INF
, -alpha
);
1173 s
->moves
[i
].val
= -search( 1, s
->base_depth
-PLY
, false, -alpha
-1, -alpha
);
1174 if(s
->moves
[i
].val
> alpha
)
1175 s
->moves
[i
].val
= -search( 1, s
->base_depth
-PLY
, true, -INF
, -alpha
);
1178 s
->moves
[i
].val
= -search( 1, s
->base_depth
-100, true, -INF
, -alpha
);
1180 board
.undo_move(s
->moves
[i
]);
1185 if(s
->moves
[i
].val
> alpha
)
1187 alpha
= s
->moves
[i
].val
;
1192 /* this move caused an alpha cut, so print the new line */
1193 if( post
/*&& processed_nodes>100000*/)
1195 output("\t%d\t%d\t%d\t%llu\t", s
->base_depth
/100,
1196 s
->moves
[i
].val
, current_time() - start_think_time
, processed_nodes
);
1197 print_moves(&s
->moves
[i
], 1, true);
1204 /* the search is done, sort the moves so that best is searched first */
1207 s
->moves
[best_mv
].val
++;
1208 sort_moves(s
->moves
, i
); /* sort i moves (those that we where able to search) */
1212 /* print the result of the analysis at this depth */
1213 if( post
/*&& processed_nodes>100000*/)
1215 output("\t%d\t%d\t%d\t%llu\t", s
->base_depth
/100,
1216 s
->moves
[0].val
, current_time() - start_think_time
, processed_nodes
);
1217 print_moves(&s
->moves
[0], 1, true);
1221 if( s
->base_depth
>= 40*PLY
)
1224 /* return in case of fixed depth search */
1225 if( eng_status
== PLAYING
&& st_computer_color
== board
.color_to_move
&&
1226 analysis_limit
== DEPTH_LIMIT
&& s
->base_depth
== st_depth
*PLY
)
1229 /* return if 3/5 of time is gone (we can't search another ply anyway) */
1230 if( eng_status
== PLAYING
&& st_computer_color
== board
.color_to_move
&&
1231 analysis_limit
== TIME_LIMIT
&&
1232 (current_time()-start_think_time
) >= (time_best_csec
*3/5) )
1235 /* if a checkmate was detected return immediately */
1236 if( ABS(alpha
) > WORST_MATE
)
1239 if(num_mate_hits
>= 5)
1243 s
->base_depth
+= PLY
;
1251 prof_tot
= rdtsc() - prof_tot
;
1252 #define SHOW_PROF(a) output("@"#a": %llu (%llu%%)\n", \
1253 prof_##a, prof_##a*100/prof_tot);
1257 SHOW_PROF(find_moves
);
1258 SHOW_PROF(find_captures
);
1259 SHOW_PROF(heuristic
);
1260 SHOW_PROF(move_is_check
);
1261 SHOW_PROF(move_see_val
);
1262 SHOW_PROF(sort_moves
);
1264 output("#nodes: %llu (~%llu nps)\n", processed_nodes
, (processed_nodes
*100)/
1265 MAX(current_time()-start_think_time
,1) );
1266 output("# %d times all the moves were seached (non-leaf non-quiesce node)\n",
1268 output("# of which %d times first move caused a cutoff\n", stat_best_cut
);
1269 output("# of the remaining %d times first move was really best (%02d%%)\n",
1270 stat_best_first
, (stat_best_first
*100)/MAX(stat_search_moves
-stat_best_cut
, 1));
1271 output("# evaluate was called %d times (quiescence node)\n", stat_evaluate
);
1272 output("# of which %d times caused an early cutoff (leaf node)\n",
1273 stat_evaluate_cutoff
);
1274 output("#hash: %d writes, %d probes (%d succesful, =%d, >%d, <%d)\n",
1275 stat_hash_write
, stat_hash_tot
, stat_hash_ex
+stat_hash_low
+stat_hash_upp
,
1276 stat_hash_ex
, stat_hash_low
, stat_hash_upp
);
1277 output("#etc: %d\n", stat_early_transp
);
1278 output("#null move: %d (%d succesful)\n", stat_null_move
, stat_null_cut
);
1282 max_quiesce_board
.write_board(buf
);
1283 output("#max quiesce board: %s [%d %d]\n", buf
, max_quiesce_alpha
, max_quiesce_beta
);