bool ok_to_do_nullmove(const Position& pos);
bool ok_to_prune(const Position& pos, Move m, Move threat, Depth d);
bool ok_to_use_TT(const TTEntry* tte, Depth depth, Value beta, int ply);
- bool ok_to_history(const Position& pos, Move m);
void update_history(const Position& pos, Move m, Depth depth, Move movesSearched[], int moveCount);
void update_killers(Move m, SearchStack& ss);
//// Functions
////
+
+/// perft() is our utility to verify move generation is bug free. All the
+/// legal moves up to given depth are generated and counted and the sum returned.
+
+int perft(Position& pos, Depth depth)
+{
+ Move move;
+ MovePicker mp = MovePicker(pos, MOVE_NONE, depth, H);
+ Bitboard dcCandidates = mp.discovered_check_candidates();
+ int sum = 0;
+
+ // If we are at the last ply we don't need to do and undo
+ // the moves, just to count them.
+ if (depth <= OnePly) // Replace with '<' to test also qsearch
+ {
+ while ((move = mp.get_next_move()) != MOVE_NONE) sum++;
+ return sum;
+ }
+
+ // Loop through all legal moves
+ while ((move = mp.get_next_move()) != MOVE_NONE)
+ {
+ StateInfo st;
+ pos.do_move(move, st, dcCandidates);
+ sum += perft(pos, depth - OnePly);
+ pos.undo_move(move);
+ }
+ return sum;
+}
+
+
/// think() is the external interface to Stockfish's search, and is called when
/// the program receives the UCI 'go' command. It initializes various
/// search-related global variables, and calls root_search(). It returns false
if (movesToGo == 1)
{
MaxSearchTime = myTime / 2;
- AbsoluteMaxSearchTime =
+ AbsoluteMaxSearchTime =
(myTime > 3000)? (myTime - 500) : ((myTime * 3) / 4);
} else {
MaxSearchTime = myTime / Min(movesToGo, 20);
<< " currmovenumber " << i + 1 << std::endl;
// Decide search depth for this move
- bool moveIsCapture = pos.move_is_capture(move);
+ bool captureOrPromotion = pos.move_is_capture_or_promotion(move);
bool dangerous;
- ext = extension(pos, move, true, moveIsCapture, pos.move_is_check(move), false, false, &dangerous);
+ ext = extension(pos, move, true, captureOrPromotion, pos.move_is_check(move), false, false, &dangerous);
newDepth = (Iteration - 2) * OnePly + ext + InitialDepth;
// Make the move, and search it
if ( newDepth >= 3*OnePly
&& i >= MultiPV + LMRPVMoves
&& !dangerous
- && !moveIsCapture
- && !move_is_promotion(move)
+ && !captureOrPromotion
&& !move_is_castle(move))
{
ss[0].reduction = OnePly;
std::cout << std::endl;
if (UseLogFile)
- LogFile << pretty_pv(pos, current_search_time(), Iteration, nodes_searched(), value,
+ LogFile << pretty_pv(pos, current_search_time(), Iteration, nodes_searched(), value,
((value >= beta)? VALUE_TYPE_LOWER
: ((value <= alpha)? VALUE_TYPE_UPPER : VALUE_TYPE_EXACT)),
ss[0].pv)
bool singleReply = (isCheck && mp.number_of_evasions() == 1);
bool moveIsCheck = pos.move_is_check(move, dcCandidates);
- bool moveIsCapture = pos.move_is_capture(move);
+ bool captureOrPromotion = pos.move_is_capture_or_promotion(move);
movesSearched[moveCount++] = ss[ply].currentMove = move;
// Decide the new search depth
bool dangerous;
- Depth ext = extension(pos, move, true, moveIsCapture, moveIsCheck, singleReply, mateThreat, &dangerous);
+ Depth ext = extension(pos, move, true, captureOrPromotion, moveIsCheck, singleReply, mateThreat, &dangerous);
Depth newDepth = depth - OnePly + ext;
// Make and search the move
if ( depth >= 3*OnePly
&& moveCount >= LMRPVMoves
&& !dangerous
- && !moveIsCapture
- && !move_is_promotion(move)
+ && !captureOrPromotion
&& !move_is_castle(move)
&& !move_is_killer(move, ss[ply]))
{
{
BetaCounter.add(pos.side_to_move(), depth, threadID);
Move m = ss[ply].pv[ply];
- if (ok_to_history(pos, m)) // Only non capture moves are considered
+ if (!pos.move_is_capture_or_promotion(m))
{
update_history(pos, m, depth, movesSearched, moveCount);
update_killers(m, ss[ply]);
bool singleReply = (isCheck && mp.number_of_evasions() == 1);
bool moveIsCheck = pos.move_is_check(move, dcCandidates);
- bool moveIsCapture = pos.move_is_capture(move);
+ bool captureOrPromotion = pos.move_is_capture_or_promotion(move);
movesSearched[moveCount++] = ss[ply].currentMove = move;
// Decide the new search depth
bool dangerous;
- Depth ext = extension(pos, move, false, moveIsCapture, moveIsCheck, singleReply, mateThreat, &dangerous);
+ Depth ext = extension(pos, move, false, captureOrPromotion, moveIsCheck, singleReply, mateThreat, &dangerous);
Depth newDepth = depth - OnePly + ext;
// Futility pruning
if ( useFutilityPruning
&& !dangerous
- && !moveIsCapture
- && !move_is_promotion(move))
+ && !captureOrPromotion)
{
// History pruning. See ok_to_prune() definition
if ( moveCount >= 2 + int(depth)
if ( depth >= 3*OnePly
&& moveCount >= LMRNonPVMoves
&& !dangerous
- && !moveIsCapture
- && !move_is_promotion(move)
+ && !captureOrPromotion
&& !move_is_castle(move)
&& !move_is_killer(move, ss[ply]))
{
{
BetaCounter.add(pos.side_to_move(), depth, threadID);
Move m = ss[ply].pv[ply];
- if (ok_to_history(pos, m)) // Only non capture moves are considered
+ if (!pos.move_is_capture_or_promotion(m))
{
update_history(pos, m, depth, movesSearched, moveCount);
update_killers(m, ss[ply]);
// Don't search captures and checks with negative SEE values
if ( !isCheck
+ && move != ttMove
&& !move_is_promotion(move)
&& pos.see_sign(move) < 0)
continue;
// All legal moves have been searched. A special case: If we're in check
// and no legal moves were found, it is checkmate.
- if (pos.is_check() && moveCount == 0) // Mate!
+ if (!moveCount && pos.is_check()) // Mate!
return value_mated_in(ply);
assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE);
}
// Update killers only for good check moves
- if (alpha >= beta && ok_to_history(pos, m)) // Only non capture moves are considered
+ if (alpha >= beta && !pos.move_is_capture_or_promotion(m))
update_killers(m, ss[ply]);
return bestValue;
assert(move_is_ok(move));
bool moveIsCheck = pos.move_is_check(move, sp->dcCandidates);
- bool moveIsCapture = pos.move_is_capture(move);
+ bool captureOrPromotion = pos.move_is_capture_or_promotion(move);
lock_grab(&(sp->lock));
int moveCount = ++sp->moves;
// Decide the new search depth.
bool dangerous;
- Depth ext = extension(pos, move, false, moveIsCapture, moveIsCheck, false, false, &dangerous);
+ Depth ext = extension(pos, move, false, captureOrPromotion, moveIsCheck, false, false, &dangerous);
Depth newDepth = sp->depth - OnePly + ext;
// Prune?
if ( useFutilityPruning
&& !dangerous
- && !moveIsCapture
- && !move_is_promotion(move))
+ && !captureOrPromotion)
{
// History pruning. See ok_to_prune() definition
if ( moveCount >= 2 + int(sp->depth)
// if the move fails high will be re-searched at full depth.
if ( !dangerous
&& moveCount >= LMRNonPVMoves
- && !moveIsCapture
- && !move_is_promotion(move)
+ && !captureOrPromotion
&& !move_is_castle(move)
&& !move_is_killer(move, ss[sp->ply]))
{
&& (move = sp->mp->get_next_move(sp->lock)) != MOVE_NONE)
{
bool moveIsCheck = pos.move_is_check(move, sp->dcCandidates);
- bool moveIsCapture = pos.move_is_capture(move);
+ bool captureOrPromotion = pos.move_is_capture_or_promotion(move);
assert(move_is_ok(move));
// Decide the new search depth.
bool dangerous;
- Depth ext = extension(pos, move, true, moveIsCapture, moveIsCheck, false, false, &dangerous);
+ Depth ext = extension(pos, move, true, captureOrPromotion, moveIsCheck, false, false, &dangerous);
Depth newDepth = sp->depth - OnePly + ext;
// Make and search the move.
// if the move fails high will be re-searched at full depth.
if ( !dangerous
&& moveCount >= LMRPVMoves
- && !moveIsCapture
- && !move_is_promotion(move)
+ && !captureOrPromotion
&& !move_is_castle(move)
&& !move_is_killer(move, ss[sp->ply]))
{
// extended, as example because the corresponding UCI option is set to zero,
// the move is marked as 'dangerous' so, at least, we avoid to prune it.
- Depth extension(const Position& pos, Move m, bool pvNode, bool capture, bool check,
- bool singleReply, bool mateThreat, bool* dangerous) {
+ Depth extension(const Position& pos, Move m, bool pvNode, bool captureOrPromotion,
+ bool check, bool singleReply, bool mateThreat, bool* dangerous) {
assert(m != MOVE_NONE);
}
}
- if ( capture
+ if ( captureOrPromotion
&& pos.type_of_piece_on(move_to(m)) != PAWN
&& ( pos.non_pawn_material(WHITE) + pos.non_pawn_material(BLACK)
- pos.midgame_value_of_piece_on(move_to(m)) == Value(0))
}
if ( pvNode
- && capture
+ && captureOrPromotion
&& pos.type_of_piece_on(move_to(m)) != PAWN
&& pos.see_sign(m) >= 0)
{
assert(move_is_ok(m));
assert(threat == MOVE_NONE || move_is_ok(threat));
- assert(!move_is_promotion(m));
assert(!pos.move_is_check(m));
- assert(!pos.move_is_capture(m));
+ assert(!pos.move_is_capture_or_promotion(m));
assert(!pos.move_is_passed_pawn_push(m));
assert(d >= OnePly);
}
- // ok_to_history() returns true if a move m can be stored
- // in history. Should be a non capturing move nor a promotion.
-
- bool ok_to_history(const Position& pos, Move m) {
-
- return !pos.move_is_capture(m) && !move_is_promotion(m);
- }
-
-
// update_history() registers a good move that produced a beta-cutoff
// in history and marks as failures all the other moves of that ply.
for (int i = 0; i < moveCount - 1; i++)
{
assert(m != movesSearched[i]);
- if (ok_to_history(pos, movesSearched[i]))
+ if (!pos.move_is_capture_or_promotion(movesSearched[i]))
H.failure(pos.piece_on(move_from(movesSearched[i])), move_to(movesSearched[i]));
}
}