X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fsearch.cpp;h=c323de5d48f35a62d00e56552449c1255f946f4e;hp=ec4272a9e0f9bcb7ebf601515621e34be4e632ba;hb=53c2bf069752d9d15d1678d79b0490b33ef240b4;hpb=51c3af9dd01951cf23f17c5f7c6cb9f7c32dccdc diff --git a/src/search.cpp b/src/search.cpp index ec4272a9..c323de5d 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -288,7 +288,6 @@ namespace { 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); @@ -327,6 +326,37 @@ namespace { //// 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 @@ -448,7 +478,7 @@ bool think(const Position& pos, bool infinite, bool ponder, int side_to_move, if (movesToGo == 1) { MaxSearchTime = myTime / 2; - AbsoluteMaxSearchTime = + AbsoluteMaxSearchTime = (myTime > 3000)? (myTime - 500) : ((myTime * 3) / 4); } else { MaxSearchTime = myTime / Min(movesToGo, 20); @@ -868,9 +898,9 @@ namespace { << " 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 @@ -897,8 +927,7 @@ namespace { if ( newDepth >= 3*OnePly && i >= MultiPV + LMRPVMoves && !dangerous - && !moveIsCapture - && !move_is_promotion(move) + && !captureOrPromotion && !move_is_castle(move)) { ss[0].reduction = OnePly; @@ -978,7 +1007,7 @@ namespace { 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) @@ -1093,13 +1122,13 @@ namespace { 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 @@ -1115,8 +1144,7 @@ namespace { if ( depth >= 3*OnePly && moveCount >= LMRPVMoves && !dangerous - && !moveIsCapture - && !move_is_promotion(move) + && !captureOrPromotion && !move_is_castle(move) && !move_is_killer(move, ss[ply])) { @@ -1200,7 +1228,7 @@ namespace { { 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]); @@ -1354,20 +1382,19 @@ namespace { 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) @@ -1400,8 +1427,7 @@ namespace { if ( depth >= 3*OnePly && moveCount >= LMRNonPVMoves && !dangerous - && !moveIsCapture - && !move_is_promotion(move) + && !captureOrPromotion && !move_is_castle(move) && !move_is_killer(move, ss[ply])) { @@ -1460,7 +1486,7 @@ namespace { { 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]); @@ -1596,6 +1622,7 @@ namespace { // Don't search captures and checks with negative SEE values if ( !isCheck + && move != ttMove && !move_is_promotion(move) && pos.see_sign(move) < 0) continue; @@ -1622,7 +1649,7 @@ namespace { // 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); @@ -1643,7 +1670,7 @@ namespace { } // 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; @@ -1678,7 +1705,7 @@ namespace { 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; @@ -1688,14 +1715,13 @@ namespace { // 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) @@ -1735,8 +1761,7 @@ namespace { // 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])) { @@ -1818,7 +1843,7 @@ namespace { && (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)); @@ -1830,7 +1855,7 @@ namespace { // 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. @@ -1841,8 +1866,7 @@ namespace { // 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])) { @@ -2267,8 +2291,8 @@ namespace { // 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); @@ -2302,7 +2326,7 @@ namespace { } } - 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)) @@ -2314,7 +2338,7 @@ namespace { } if ( pvNode - && capture + && captureOrPromotion && pos.type_of_piece_on(move_to(m)) != PAWN && pos.see_sign(m) >= 0) { @@ -2348,9 +2372,8 @@ namespace { 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); @@ -2412,15 +2435,6 @@ namespace { } - // 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. @@ -2432,7 +2446,7 @@ namespace { 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])); } }