From: Fabian Fichter Date: Sun, 17 Nov 2019 15:09:04 +0000 (+0100) Subject: Merge official-stockfish/master X-Git-Url: http://winboard.nl/cgi-bin?a=commitdiff_plain;h=6775c7e44cd7d3f80a3c7928e388b215eeb56da7;p=fairystockfish.git Merge official-stockfish/master bench: 4756806 --- 6775c7e44cd7d3f80a3c7928e388b215eeb56da7 diff --cc src/evaluate.cpp index 2315c70,2b7ab39..d993d2b --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@@ -458,14 -377,11 +458,14 @@@ namespace Score Evaluation::king() const { constexpr Color Them = (Us == WHITE ? BLACK : WHITE); - constexpr Bitboard Camp = (Us == WHITE ? AllSquares ^ Rank6BB ^ Rank7BB ^ Rank8BB - : AllSquares ^ Rank1BB ^ Rank2BB ^ Rank3BB); + Rank r = relative_rank(Us, std::min(Rank((pos.max_rank() - 1) / 2 + 1), pos.max_rank()), pos.max_rank()); + Bitboard Camp = AllSquares ^ forward_ranks_bb(Us, r); + + if (!pos.count(Us) || !pos.checking_permitted()) + return SCORE_ZERO; - Bitboard weak, b1, b2, safe, unsafeChecks = 0; + Bitboard weak, b1, b2, b3, safe, unsafeChecks = 0; - Bitboard rookChecks, queenChecks, bishopChecks, knightChecks; + Bitboard queenChecks, knightChecks, pawnChecks, otherChecks; int kingDanger = 0; const Square ksq = pos.square(Us); @@@ -484,81 -400,63 +484,84 @@@ b1 = attacks_bb(ksq, pos.pieces() ^ pos.pieces(Us, QUEEN)); b2 = attacks_bb(ksq, pos.pieces() ^ pos.pieces(Us, QUEEN)); - // Enemy rooks checks - rookChecks = b1 & safe & attackedBy[Them][ROOK]; + std::function get_attacks = [this](Color c, PieceType pt) { + return attackedBy[c][pt] | (pos.captures_to_hand() && pos.count_in_hand(c, pt) ? ~pos.pieces() : Bitboard(0)); + }; + for (PieceType pt : pos.piece_types()) + { + switch (pt) + { + case QUEEN: + // Enemy queen safe checks: we count them only if they are from squares from + // which we can't give a rook check, because rook checks are more valuable. + queenChecks = (b1 | b2) + & get_attacks(Them, QUEEN) + & safe + & ~attackedBy[Us][QUEEN] + & ~(b1 & attackedBy[Them][ROOK]); + + if (queenChecks) + kingDanger += QueenSafeCheck; + break; + case ROOK: + case BISHOP: + case KNIGHT: + knightChecks = attacks_bb(Us, pt, ksq, pos.pieces() ^ pos.pieces(Us, QUEEN)) & get_attacks(Them, pt) & pos.board_bb(); + if (knightChecks & safe) + kingDanger += pt == ROOK ? RookSafeCheck + : pt == BISHOP ? BishopSafeCheck + : KnightSafeCheck; + else + unsafeChecks |= knightChecks; + break; + case PAWN: + if (pos.captures_to_hand() && pos.count_in_hand(Them, pt)) + { + pawnChecks = attacks_bb(Us, pt, ksq, pos.pieces()) & ~pos.pieces() & pos.board_bb(); + if (pawnChecks & safe) + kingDanger += OtherSafeCheck; + else + unsafeChecks |= pawnChecks; + } + break; + case SHOGI_PAWN: + case KING: + break; + default: + otherChecks = attacks_bb(Us, pt, ksq, pos.pieces()) & get_attacks(Them, pt) & pos.board_bb(); + if (otherChecks & safe) + kingDanger += OtherSafeCheck; + else + unsafeChecks |= otherChecks; + } + } - if (rookChecks) - kingDanger += RookSafeCheck; - else - unsafeChecks |= b1 & attackedBy[Them][ROOK]; - - // Enemy queen safe checks: we count them only if they are from squares from - // which we can't give a rook check, because rook checks are more valuable. - queenChecks = (b1 | b2) - & attackedBy[Them][QUEEN] - & safe - & ~attackedBy[Us][QUEEN] - & ~rookChecks; - - if (queenChecks) - kingDanger += QueenSafeCheck; - - // Enemy bishops checks: we count them only if they are from squares from - // which we can't give a queen check, because queen checks are more valuable. - bishopChecks = b2 - & attackedBy[Them][BISHOP] - & safe - & ~queenChecks; - - if (bishopChecks) - kingDanger += BishopSafeCheck; - else - unsafeChecks |= b2 & attackedBy[Them][BISHOP]; + if (pos.check_counting()) + kingDanger *= 2; - // Enemy knights checks - knightChecks = pos.attacks_from(ksq) & attackedBy[Them][KNIGHT]; - - if (knightChecks & safe) - kingDanger += KnightSafeCheck; - else - unsafeChecks |= knightChecks; + Square s = file_of(ksq) == FILE_A ? ksq + EAST : file_of(ksq) == pos.max_file() ? ksq + WEST : ksq; + Bitboard kingFlank = pos.max_file() == FILE_H ? KingFlank[file_of(ksq)] : file_bb(s) | adjacent_files_bb(s); - // Find the squares that opponent attacks in our king flank, and the squares - // which are attacked twice in that flank. + // Find the squares that opponent attacks in our king flank, the squares + // which they attack twice in that flank, and the squares that we defend. - b1 = attackedBy[Them][ALL_PIECES] & KingFlank[file_of(ksq)] & Camp; + b1 = attackedBy[Them][ALL_PIECES] & kingFlank & Camp; b2 = b1 & attackedBy2[Them]; - b3 = attackedBy[Us][ALL_PIECES] & KingFlank[file_of(ksq)] & Camp; ++ b3 = attackedBy[Us][ALL_PIECES] & kingFlank & Camp; - int kingFlankAttacks = popcount(b1) + popcount(b2); + int kingFlankAttack = popcount(b1) + popcount(b2); + int kingFlankDefense = popcount(b3); kingDanger += kingAttackersCount[Them] * kingAttackersWeight[Them] - + 185 * popcount(kingRing[Us] & weak) + + kingAttackersCountInHand[Them] * kingAttackersWeight[Them] + + kingAttackersCount[Them] * kingAttackersWeightInHand[Them] + + 185 * popcount(kingRing[Us] & weak) * (1 + pos.captures_to_hand() + pos.check_counting()) + 148 * popcount(unsafeChecks) + 98 * popcount(pos.blockers_for_king(Us)) - + 69 * kingAttacksCount[Them] + + 69 * kingAttacksCount[Them] * (2 + 8 * pos.check_counting() + pos.captures_to_hand()) / 2 - + 3 * kingFlankAttacks * kingFlankAttacks / 8 + + 4 * (kingFlankAttack - kingFlankDefense) + + 3 * kingFlankAttack * kingFlankAttack / 8 + mg_value(mobility[Them] - mobility[Us]) - - 873 * !pos.count(Them) + - 873 * !(pos.major_pieces(Them) || pos.captures_to_hand() || pos.xiangqi_general()) / (1 + pos.check_counting()) - 100 * bool(attackedBy[Us][KNIGHT] & attackedBy[Us][KING]) - 35 * bool(attackedBy[Us][BISHOP] & attackedBy[Us][KING]) - 6 * mg_value(score) / 8 @@@ -566,21 -464,14 +569,21 @@@ // Transform the kingDanger units into a Score, and subtract it from the evaluation if (kingDanger > 100) - score -= make_score(kingDanger * kingDanger / 4096, kingDanger / 16); + score -= make_score(std::min(kingDanger * kingDanger / 4096, 3000), kingDanger / 16); // Penalty when our king is on a pawnless flank - if (!(pos.pieces(PAWN) & KingFlank[file_of(ksq)])) + if (!(pos.pieces(PAWN) & kingFlank)) score -= PawnlessFlank; - // King tropism bonus, to anticipate slow motion attacks on our king - score -= FlankAttacks * kingFlankAttacks * (1 + 5 * pos.captures_to_hand() + pos.check_counting()); + // Penalty if king flank is under attack, potentially moving toward the king - score -= FlankAttacks * kingFlankAttack; ++ score -= FlankAttacks * kingFlankAttack * (1 + 5 * pos.captures_to_hand() + pos.check_counting()); + + if (pos.check_counting()) + score += make_score(0, mg_value(score) / 2); + + // For drop games, king danger is independent of game phase + if (pos.captures_to_hand()) + score = make_score(mg_value(score), mg_value(score)) * 2 / (2 + 3 * !pos.shogi_doubled_pawn()); if (T) Trace::add(KING, Us, score); diff --cc src/search.cpp index f3248ae,e75db24..1e8fc72 --- a/src/search.cpp +++ b/src/search.cpp @@@ -991,7 -955,45 +991,51 @@@ moves_loop: // When in check, search st movedPiece = pos.moved_piece(move); givesCheck = pos.gives_check(move); - // Step 13. Extensions (~70 Elo) + // Calculate new depth for this move + newDepth = depth - 1; + + // Step 13. Pruning at shallow depth (~170 Elo) + if ( !rootNode - && pos.non_pawn_material(us) ++ && (pos.non_pawn_material(us) || !(pos.pieces(us) ^ pos.pieces(us, PAWN))) + && bestValue > VALUE_MATED_IN_MAX_PLY) + { + // Skip quiet moves if movecount exceeds our FutilityMoveCount threshold - moveCountPruning = moveCount >= futility_move_count(improving, depth); ++ moveCountPruning = moveCount >= futility_move_count(improving, depth) ++ || (pos.must_capture() && (moveCountPruning || (pos.capture(move) && pos.legal(move)))); + + if ( !captureOrPromotion + && !givesCheck - && (!PvNode || !pos.advanced_pawn_push(move) || pos.non_pawn_material(~us) > BishopValueMg)) ++ && (!pos.must_capture() || !pos.attackers_to(to_sq(move), ~us)) ++ && (!PvNode || !pos.advanced_pawn_push(move) || pos.non_pawn_material(~us) > BishopValueMg || pos.count(us) == pos.count(us))) + { + // Reduced depth of the next LMR search + int lmrDepth = std::max(newDepth - reduction(improving, depth, moveCount), 0); + + // Countermoves based pruning (~20 Elo) + if ( lmrDepth < 4 + ((ss-1)->statScore > 0 || (ss-1)->moveCount == 1) - && (*contHist[0])[movedPiece][to_sq(move)] < CounterMovePruneThreshold - && (*contHist[1])[movedPiece][to_sq(move)] < CounterMovePruneThreshold) ++ && (*contHist[0])[history_slot(movedPiece)][to_sq(move)] < CounterMovePruneThreshold ++ && (*contHist[1])[history_slot(movedPiece)][to_sq(move)] < CounterMovePruneThreshold) + continue; + + // Futility pruning: parent node (~2 Elo) + if ( lmrDepth < 6 + && !inCheck ++ && !( pos.extinction_value() == -VALUE_MATE ++ && pos.extinction_piece_types().find(ALL_PIECES) == pos.extinction_piece_types().end()) + && ss->staticEval + 250 + 211 * lmrDepth <= alpha) + continue; + + // Prune moves with negative SEE (~10 Elo) - if (!pos.see_ge(move, Value(-(31 - std::min(lmrDepth, 18)) * lmrDepth * lmrDepth))) ++ if (!pos.must_capture() && !pos.see_ge(move, Value(-(31 - std::min(lmrDepth, 18)) * lmrDepth * lmrDepth))) + continue; + } - else if (!pos.see_ge(move, Value(-199) * depth)) // (~20 Elo) ++ else if ( !(givesCheck && extension) ++ && !pos.must_capture() ++ && !pos.see_ge(move, Value(-199 - 120 * pos.captures_to_hand()) * depth)) // (~20 Elo) + continue; + } + + // Step 14. Extensions (~70 Elo) // Singular extension search (~60 Elo). If all moves but one fail low on a // search of (alpha-s, beta-s), and just one fails high on (alpha, beta), @@@ -1045,55 -1047,8 +1089,14 @@@ if (type_of(move) == CASTLING) extension = 1; + // Losing chess capture extension + else if ( pos.must_capture() + && pos.capture(move) + && MoveList(pos).size() == 1) + extension = 1; + - // Calculate new depth for this move - newDepth = depth - 1 + extension; - - // Step 14. Pruning at shallow depth (~170 Elo) - if ( !rootNode - && (pos.non_pawn_material(us) || !(pos.pieces(us) ^ pos.pieces(us, PAWN))) - && bestValue > VALUE_MATED_IN_MAX_PLY) - { - // Skip quiet moves if movecount exceeds our FutilityMoveCount threshold - moveCountPruning = moveCount >= futility_move_count(improving, depth) - || (pos.must_capture() && (moveCountPruning || (pos.capture(move) && pos.legal(move)))); - - if ( !captureOrPromotion - && !givesCheck - && (!pos.must_capture() || !pos.attackers_to(to_sq(move), ~us)) - && (!PvNode || !pos.advanced_pawn_push(move) || pos.non_pawn_material(~us) > BishopValueMg || pos.count(us) == pos.count(us))) - { - // Reduced depth of the next LMR search - int lmrDepth = std::max(newDepth - reduction(improving, depth, moveCount), 0); - - // Countermoves based pruning (~20 Elo) - if ( lmrDepth < 4 + ((ss-1)->statScore > 0 || (ss-1)->moveCount == 1) - && (*contHist[0])[history_slot(movedPiece)][to_sq(move)] < CounterMovePruneThreshold - && (*contHist[1])[history_slot(movedPiece)][to_sq(move)] < CounterMovePruneThreshold) - continue; - - // Futility pruning: parent node (~2 Elo) - if ( lmrDepth < 6 - && !inCheck - && !( pos.extinction_value() == -VALUE_MATE - && pos.extinction_piece_types().find(ALL_PIECES) == pos.extinction_piece_types().end()) - && ss->staticEval + 250 + 211 * lmrDepth <= alpha) - continue; - - // Prune moves with negative SEE (~10 Elo) - if (!pos.must_capture() && !pos.see_ge(move, Value(-(31 - std::min(lmrDepth, 18)) * lmrDepth * lmrDepth))) - continue; - } - else if ( !(givesCheck && extension) - && !pos.must_capture() - && !pos.see_ge(move, Value(-199 - 120 * pos.captures_to_hand()) * depth)) // (~20 Elo) - continue; - } + // Add extension to new depth + newDepth += extension; // Speculative prefetch as early as possible prefetch(TT.first_entry(pos.key_after(move)));