From 7cb8cbb403160c8436385149cf1d6949665b4924 Mon Sep 17 00:00:00 2001 From: loco-loco Date: Tue, 17 May 2016 23:46:05 -0700 Subject: [PATCH 1/5] Assorted pruning tweaks LTC: LLR: 2.95 (-2.94,2.94) [0.00,5.00] Total: 38257 W: 5206 L: 4961 D: 28090 STC: LLR: 2.95 (-2.94,2.94) [0.00,5.00] Total: 16550 W: 3110 L: 2914 D: 10526 Bench: 8428997 --- src/search.cpp | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 2828ccda..3b384e86 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -609,6 +609,7 @@ namespace { Value bestValue, value, ttValue, eval, nullValue, futilityValue; bool ttHit, inCheck, givesCheck, singularExtensionNode, improving; bool captureOrPromotion, doFullDepthSearch; + Piece moved_piece; int moveCount, quietCount; // Step 1. Initialize node @@ -864,7 +865,9 @@ namespace { moves_loop: // When in check search starts from here Square prevSq = to_sq((ss-1)->currentMove); - const CounterMoveStats& cmh = CounterMoveHistory[pos.piece_on(prevSq)][prevSq]; + const CounterMoveStats* cmh = (ss-1)->counterMoves; + const CounterMoveStats* fmh = (ss-2)->counterMoves; + const CounterMoveStats* fmh2 = (ss-4)->counterMoves; MovePicker mp(pos, ttMove, depth, ss); CheckInfo ci(pos); @@ -910,6 +913,7 @@ moves_loop: // When in check search starts from here extension = DEPTH_ZERO; captureOrPromotion = pos.capture_or_promotion(move); + moved_piece = pos.moved_piece(move); givesCheck = type_of(move) == NORMAL && !ci.dcCandidates ? ci.checkSquares[type_of(pos.piece_on(from_sq(move)))] & to_sq(move) @@ -956,11 +960,12 @@ moves_loop: // When in check search starts from here && moveCount >= FutilityMoveCounts[improving][depth]) continue; - // History based pruning + // Countermoves based pruning if ( depth <= 4 * ONE_PLY && move != ss->killers[0] - && thisThread->history[pos.moved_piece(move)][to_sq(move)] < VALUE_ZERO - && cmh[pos.moved_piece(move)][to_sq(move)] < VALUE_ZERO) + && (!cmh || (*cmh )[moved_piece][to_sq(move)] < VALUE_ZERO) + && (!fmh || (*fmh )[moved_piece][to_sq(move)] < VALUE_ZERO) + && (!fmh2 || (*fmh2)[moved_piece][to_sq(move)] < VALUE_ZERO || (cmh && fmh))) continue; predictedDepth = std::max(newDepth - reduction(improving, depth, moveCount), DEPTH_ZERO); @@ -993,7 +998,7 @@ moves_loop: // When in check search starts from here } ss->currentMove = move; - ss->counterMoves = &CounterMoveHistory[pos.moved_piece(move)][to_sq(move)]; + ss->counterMoves = &CounterMoveHistory[moved_piece][to_sq(move)]; // Step 14. Make the move pos.do_move(move, st, givesCheck); @@ -1005,20 +1010,17 @@ moves_loop: // When in check search starts from here && !captureOrPromotion) { Depth r = reduction(improving, depth, moveCount); - Value hValue = thisThread->history[pos.piece_on(to_sq(move))][to_sq(move)]; - Value cmhValue = cmh[pos.piece_on(to_sq(move))][to_sq(move)]; - - const CounterMoveStats* fm = (ss - 2)->counterMoves; - const CounterMoveStats* fm2 = (ss - 4)->counterMoves; - Value fmValue = (fm ? (*fm)[pos.piece_on(to_sq(move))][to_sq(move)] : VALUE_ZERO); - Value fm2Value = (fm2 ? (*fm2)[pos.piece_on(to_sq(move))][to_sq(move)] : VALUE_ZERO); + Value val = thisThread->history[moved_piece][to_sq(move)] + + (cmh ? (*cmh )[moved_piece][to_sq(move)] : VALUE_ZERO) + + (fmh ? (*fmh )[moved_piece][to_sq(move)] : VALUE_ZERO) + + (fmh2 ? (*fmh2)[moved_piece][to_sq(move)] : VALUE_ZERO); // Increase reduction for cut nodes if (!PvNode && cutNode) r += ONE_PLY; // Decrease/increase reduction for moves with a good/bad history - int rHist = (hValue + cmhValue + fmValue + fm2Value - 10000) / 20000; + int rHist = (val - 10000) / 20000; r = std::max(DEPTH_ZERO, r - rHist * ONE_PLY); // Decrease reduction for moves that escape a capture. Filter out From 71bfbb22fce23f56b57d69b59a5cec1ff4b5aa03 Mon Sep 17 00:00:00 2001 From: Leonid Pechenik Date: Mon, 16 May 2016 16:30:57 -0400 Subject: [PATCH 2/5] More detailed dependence of time allocation on the magnitude of score change 10+0.1: LLR: 2.96 (-2.94,2.94) [0.00,5.00] Total: 5657 W: 1130 L: 979 D: 3548 60+0.6: LLR: 2.95 (-2.94,2.94) [0.00,5.00] Total: 36884 W: 5002 L: 4762 D: 27120 bench: 8428997 --- src/search.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 3b384e86..c6d63c7b 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -541,18 +541,18 @@ void Thread::search() { // Stop the search if only one legal move is available, or if all // of the available time has been used, or if we matched an easyMove // from the previous search and just did a fast verification. - const bool F[] = { !mainThread->failedLow, - bestValue >= mainThread->previousScore }; + const int F[] = { mainThread->failedLow, + bestValue - mainThread->previousScore }; - int improvingFactor = 640 - 160*F[0] - 126*F[1] - 124*F[0]*F[1]; + int improvingFactor = std::max(229, std::min(715, 357 + 119 * F[0] - 6 * F[1])); double unstablePvFactor = 1 + mainThread->bestMoveChanges; bool doEasyMove = rootMoves[0].pv[0] == easyMove && mainThread->bestMoveChanges < 0.03 - && Time.elapsed() > Time.optimum() * 25 / 204; + && Time.elapsed() > Time.optimum() * 5 / 42; if ( rootMoves.size() == 1 - || Time.elapsed() > Time.optimum() * unstablePvFactor * improvingFactor / 634 + || Time.elapsed() > Time.optimum() * unstablePvFactor * improvingFactor / 628 || (mainThread->easyMovePlayed = doEasyMove)) { // If we are allowed to ponder do not stop the search now but From ab0f4c03539b151f07d99a5336e47e8dbdc63c6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicolet?= Date: Tue, 24 May 2016 08:09:13 +0200 Subject: [PATCH 3/5] Simplify doubled pawn Only use doubled pawn malus when the doubled pawns are on consecutive squares. Passed STC: LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 7678 W: 1469 L: 1325 D: 4884 And LTC: LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 26739 W: 3562 L: 3449 D: 19728 Bench: 8211685 --- src/pawns.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pawns.cpp b/src/pawns.cpp index 74b3fd5e..1ccc0958 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -124,7 +124,7 @@ namespace { opposed = theirPawns & forward_bb(Us, s); stoppers = theirPawns & passed_pawn_mask(Us, s); lever = theirPawns & pawnAttacksBB[s]; - doubled = ourPawns & forward_bb(Us, s); + doubled = ourPawns & (s + Up); neighbours = ourPawns & adjacent_files_bb(f); phalanx = neighbours & rank_bb(s); supported = neighbours & rank_bb(s - Up); @@ -150,7 +150,7 @@ namespace { // Passed pawns will be properly scored in evaluation because we need // full attack info to evaluate them. Only the frontmost passed // pawn on each file is considered a true passed pawn. - if (!(stoppers | doubled)) + if (!(stoppers | doubled)) // FIXME this is just doubled by adjacent pawn e->passedPawns[Us] |= s; // Score this pawn @@ -167,7 +167,7 @@ namespace { score += Connected[opposed][!!phalanx][more_than_one(supported)][relative_rank(Us, s)]; if (doubled) - score -= Doubled / distance(s, frontmost_sq(Us, doubled)); + score -= Doubled; if (lever) score += Lever[relative_rank(Us, s)]; From abac509ccb1f197da1159ce02daaf4fa737c32e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicolet?= Date: Sat, 21 May 2016 10:05:19 +0200 Subject: [PATCH 4/5] Teach check_blockers to check also non-king pieces This is a prerequisite for next patch No functional change. --- src/position.cpp | 25 ++++++++++++------------- src/position.h | 6 +++--- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/position.cpp b/src/position.cpp index cd91b07f..6022518e 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -420,28 +420,27 @@ Phase Position::game_phase() const { } -/// Position::check_blockers() returns a bitboard of all the pieces with color -/// 'c' that are blocking check on the king with color 'kingColor'. A piece -/// blocks a check if removing that piece from the board would result in a -/// position where the king is in check. A check blocking piece can be either a -/// pinned or a discovered check piece, according if its color 'c' is the same -/// or the opposite of 'kingColor'. +/// Position::slider_blockers() returns a bitboard of all the pieces in 'target' that +/// are blocking attacks on the square 's' from 'sliders'. A piece blocks a slider +/// if removing that piece from the board would result in a position where square 's' +/// is attacked. For example, a king-attack blocking piece can be either a pinned or +/// a discovered check piece, according if its color is the opposite or the same of +/// the color of the slider. -Bitboard Position::check_blockers(Color c, Color kingColor) const { +Bitboard Position::slider_blockers(Bitboard target, Bitboard sliders, Square s) const { Bitboard b, pinners, result = 0; - Square ksq = square(kingColor); - // Pinners are sliders that give check when a pinned piece is removed - pinners = ( (pieces( ROOK, QUEEN) & PseudoAttacks[ROOK ][ksq]) - | (pieces(BISHOP, QUEEN) & PseudoAttacks[BISHOP][ksq])) & pieces(~kingColor); + // Pinners are sliders that attack 's' when a pinned piece is removed + pinners = ( (PseudoAttacks[ROOK ][s] & pieces(QUEEN, ROOK)) + | (PseudoAttacks[BISHOP][s] & pieces(QUEEN, BISHOP))) & sliders; while (pinners) { - b = between_bb(ksq, pop_lsb(&pinners)) & pieces(); + b = between_bb(s, pop_lsb(&pinners)) & pieces(); if (!more_than_one(b)) - result |= b & pieces(c); + result |= b & target; } return result; } diff --git a/src/position.h b/src/position.h index c3ba5ac8..b2538e96 100644 --- a/src/position.h +++ b/src/position.h @@ -131,6 +131,7 @@ public: Bitboard attacks_from(Piece pc, Square s) const; template Bitboard attacks_from(Square s) const; template Bitboard attacks_from(Square s, Color c) const; + Bitboard slider_blockers(Bitboard target, Bitboard sliders, Square s) const; // Properties of moves bool legal(Move m, Bitboard pinned) const; @@ -186,7 +187,6 @@ private: void set_state(StateInfo* si) const; // Other helpers - Bitboard check_blockers(Color c, Color kingColor) const; void put_piece(Color c, PieceType pt, Square s); void remove_piece(Color c, PieceType pt, Square s); void move_piece(Color c, PieceType pt, Square from, Square to); @@ -311,11 +311,11 @@ inline Bitboard Position::checkers() const { } inline Bitboard Position::discovered_check_candidates() const { - return check_blockers(sideToMove, ~sideToMove); + return slider_blockers(pieces(sideToMove), pieces(sideToMove), square(~sideToMove)); } inline Bitboard Position::pinned_pieces(Color c) const { - return check_blockers(c, c); + return slider_blockers(pieces(c), pieces(~c), square(c)); } inline bool Position::pawn_passed(Color c, Square s) const { From 07b247f9434f3633570aa124539ed5d2fc4f904f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicolet?= Date: Sat, 21 May 2016 10:05:19 +0200 Subject: [PATCH 5/5] Pins or discovered attacks on the opponent's queen Bonus for pins or discovered attacks on the opponent's queen STC: LLR: 2.96 (-2.94,2.94) [0.00,5.00] Total: 32020 W: 5914 L: 5652 D: 20454 LTC: LLR: 2.97 (-2.94,2.94) [0.00,5.00] Total: 10946 W: 1530 L: 1375 D: 8041 Bench: 7031649 --- src/evaluate.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 4a52e626..58058b1b 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -187,6 +187,7 @@ namespace { const Score OtherCheck = S(10, 10); const Score ThreatByHangingPawn = S(71, 61); const Score LooseEnemies = S( 0, 25); + const Score WeakQueen = S(35, 0); const Score Hanging = S(48, 27); const Score ThreatByPawnPush = S(38, 22); const Score Unstoppable = S( 0, 20); @@ -488,6 +489,13 @@ namespace { & ~(ei.attackedBy[Us][ALL_PIECES] | ei.attackedBy[Them][ALL_PIECES])) score += LooseEnemies; + // Bonus for pin or discovered attack on the opponent queen + if ( pos.count(Them) == 1 + && pos.slider_blockers(pos.pieces(), + pos.pieces(Us, ROOK, BISHOP), + pos.square(Them))) + score += WeakQueen; + // Non-pawn enemies attacked by a pawn weak = (pos.pieces(Them) ^ pos.pieces(Them, PAWN)) & ei.attackedBy[Us][PAWN];