init_magics(RookTable, RookMagics, RookDirections);
init_magics(BishopTable, BishopMagics, BishopDirections);
- // Helper returning the target bitboard of a step from a square
- auto landing_square_bb = [&](Square s, int step)
- {
- Square to = Square(s + step);
- return is_ok(to) && distance(s, to) <= 2 ? square_bb(to) : Bitboard(0);
- };
-
for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1)
{
PawnAttacks[WHITE][s1] = pawn_attacks_bb<WHITE>(square_bb(s1));
PawnAttacks[BLACK][s1] = pawn_attacks_bb<BLACK>(square_bb(s1));
for (int step : {-9, -8, -7, -1, 1, 7, 8, 9} )
- PseudoAttacks[KING][s1] |= landing_square_bb(s1, step);
+ PseudoAttacks[KING][s1] |= safe_destination(s1, step);
for (int step : {-17, -15, -10, -6, 6, 10, 15, 17} )
- PseudoAttacks[KNIGHT][s1] |= landing_square_bb(s1, step);
+ PseudoAttacks[KNIGHT][s1] |= safe_destination(s1, step);
PseudoAttacks[QUEEN][s1] = PseudoAttacks[BISHOP][s1] = attacks_bb<BISHOP>(s1, 0);
PseudoAttacks[QUEEN][s1] |= PseudoAttacks[ ROOK][s1] = attacks_bb< ROOK>(s1, 0);
Bitboard sliding_attack(Direction directions[], Square sq, Bitboard occupied) {
- Bitboard attack = 0;
+ Bitboard attacks = 0;
for (int i = 0; i < 4; ++i)
- for (Square s = sq + directions[i];
- is_ok(s) && distance(s, s - directions[i]) == 1;
- s += directions[i])
- {
- attack |= s;
-
- if (occupied & s)
- break;
- }
+ {
+ Square s = sq;
+ while(safe_destination(s, directions[i]) && !(occupied & s))
+ attacks |= (s += directions[i]);
+ }
- return attack;
+ return attacks;
}
extern Magic BishopMagics[SQUARE_NB];
inline Bitboard square_bb(Square s) {
- assert(s >= SQ_A1 && s <= SQ_H8);
+ assert(is_ok(s));
return SquareBB[s];
}
inline Bitboard operator|(Square s, Bitboard b) { return b | s; }
inline Bitboard operator^(Square s, Bitboard b) { return b ^ s; }
-inline Bitboard operator|(Square s, Square s2) { return square_bb(s) | square_bb(s2); }
+inline Bitboard operator|(Square s, Square s2) { return square_bb(s) | s2; }
constexpr bool more_than_one(Bitboard b) {
return b & (b - 1);
/// forward_ranks_bb(BLACK, SQ_D3) will return the 16 squares on ranks 1 and 2.
inline Bitboard forward_ranks_bb(Color c, Square s) {
- return c == WHITE ? ~Rank1BB << 8 * (rank_of(s) - RANK_1)
- : ~Rank8BB >> 8 * (RANK_8 - rank_of(s));
+ return c == WHITE ? ~Rank1BB << 8 * relative_rank(WHITE, s)
+ : ~Rank8BB >> 8 * relative_rank(BLACK, s);
}
template<> inline int distance<Rank>(Square x, Square y) { return std::abs(rank_of(x) - rank_of(y)); }
template<> inline int distance<Square>(Square x, Square y) { return SquareDistance[x][y]; }
-inline File edge_distance(File f) { return std::min(f, File(FILE_H - f)); }
-inline Rank edge_distance(Rank r) { return std::min(r, Rank(RANK_8 - r)); }
+inline int edge_distance(File f) { return std::min(f, File(FILE_H - f)); }
+inline int edge_distance(Rank r) { return std::min(r, Rank(RANK_8 - r)); }
+
+/// Return the target square bitboard if we do not step off the board, empty otherwise
+
+inline Bitboard safe_destination(Square s, int step)
+{
+ Square to = Square(s + step);
+ return is_ok(to) && distance(s, to) <= 2 ? square_bb(to) : Bitboard(0);
+}
/// attacks_bb() returns a bitboard representing all the squares attacked by a
/// piece of type Pt (bishop or rook) placed on 's'.
{
if ( pos.opposite_bishops()
&& pos.non_pawn_material() == 2 * BishopValueMg)
- sf = 22 ;
+ sf = 22;
else
sf = std::min(sf, 36 + (pos.opposite_bishops() ? 2 : 7) * pos.count<PAWN>(strongSide));
assert(!pos.checkers());
Color us = pos.side_to_move();
- Bitboard dc = pos.blockers_for_king(~us) & pos.pieces(us);
+ Bitboard dc = pos.blockers_for_king(~us) & pos.pieces(us) & ~pos.pieces(PAWN);
while (dc)
{
Square from = pop_lsb(&dc);
PieceType pt = type_of(pos.piece_on(from));
- if (pt == PAWN)
- continue; // Will be generated together with direct checks
-
Bitboard b = pos.attacks_from(pt, from) & ~pos.pieces();
if (pt == KING)
// the king evasions in order to skip known illegal moves, which avoids any
// useless legality checks later on.
while (sliders)
- {
- Square checksq = pop_lsb(&sliders);
- sliderAttacks |= LineBB[ksq][checksq] ^ checksq;
- }
+ sliderAttacks |= LineBB[ksq][pop_lsb(&sliders)] & ~pos.checkers();
// Generate evasions for king, capture and non capture moves
Bitboard b = pos.attacks_from<KING>(ksq) & ~pos.pieces(us) & ~sliderAttacks;
b = theirPawns & file_bb(f);
int theirRank = b ? relative_rank(Us, frontmost_sq(Them, b)) : 0;
- File d = edge_distance(f);
+ File d = File(edge_distance(f));
bonus += make_score(ShelterStrength[d][ourRank], 0);
if (ourRank && (ourRank == theirRank - 1))
for (Square s = SQ_A1; s <= SQ_H8; ++s)
{
- File f = edge_distance(file_of(s));
+ File f = File(edge_distance(file_of(s)));
psq[ pc][ s] = score + (type_of(pc) == PAWN ? PBonus[rank_of(s)][file_of(s)]
: Bonus[pc][rank_of(s)][f]);
psq[~pc][flip_rank(s)] = -psq[pc][s];
}
}
- previousScore = bestThread->rootMoves[0].score;
+ bestPreviousScore = bestThread->rootMoves[0].score;
// Send again PV info if we have a new best thread
if (bestThread != this)
if (mainThread)
{
- if (mainThread->previousScore == VALUE_INFINITE)
+ if (mainThread->bestPreviousScore == VALUE_INFINITE)
for (int i=0; i<4; ++i)
mainThread->iterValue[i] = VALUE_ZERO;
else
for (int i=0; i<4; ++i)
- mainThread->iterValue[i] = mainThread->previousScore;
+ mainThread->iterValue[i] = mainThread->bestPreviousScore;
}
size_t multiPV = Options["MultiPV"];
// Reset aspiration window starting size
if (rootDepth >= 4)
{
- Value previousScore = rootMoves[pvIdx].previousScore;
+ Value prev = rootMoves[pvIdx].previousScore;
delta = Value(21);
- alpha = std::max(previousScore - delta,-VALUE_INFINITE);
- beta = std::min(previousScore + delta, VALUE_INFINITE);
+ alpha = std::max(prev - delta,-VALUE_INFINITE);
+ beta = std::min(prev + delta, VALUE_INFINITE);
// Adjust contempt based on root move's previousScore (dynamic contempt)
- int dct = ct + (102 - ct / 2) * previousScore / (abs(previousScore) + 157);
+ int dct = ct + (102 - ct / 2) * prev / (abs(prev) + 157);
contempt = (us == WHITE ? make_score(dct, dct / 2)
: -make_score(dct, dct / 2));
&& !Threads.stop
&& !mainThread->stopOnPonderhit)
{
- double fallingEval = (332 + 6 * (mainThread->previousScore - bestValue)
+ double fallingEval = (332 + 6 * (mainThread->bestPreviousScore - bestValue)
+ 6 * (mainThread->iterValue[iterIdx] - bestValue)) / 704.0;
fallingEval = Utility::clamp(fallingEval, 0.5, 1.5);
Move ttMove, move, excludedMove, bestMove;
Depth extension, newDepth;
Value bestValue, value, ttValue, eval, maxValue;
- bool ttHit, ttPv, inCheck, givesCheck, improving, didLMR, priorCapture;
+ bool ttHit, ttPv, formerPv, inCheck, givesCheck, improving, didLMR, priorCapture;
bool captureOrPromotion, doFullDepthSearch, moveCountPruning, ttCapture, singularLMR;
Piece movedPiece;
int moveCount, captureCount, quietCount;
ttMove = rootNode ? thisThread->rootMoves[thisThread->pvIdx].pv[0]
: ttHit ? tte->move() : MOVE_NONE;
ttPv = PvNode || (ttHit && tte->is_pv());
+ formerPv = ttPv && !PvNode;
if (ttPv && depth > 12 && ss->ply - 1 < MAX_LPH && !pos.captured_piece() && is_ok((ss-1)->currentMove))
thisThread->lowPlyHistory[ss->ply - 1][from_to((ss-1)->currentMove)] << stat_bonus(depth - 5);
&& depth >= 5
&& abs(beta) < VALUE_TB_WIN_IN_MAX_PLY)
{
- Value raisedBeta = std::min(beta + 189 - 45 * improving, VALUE_INFINITE);
+ Value raisedBeta = beta + 189 - 45 * improving;
+ assert(raisedBeta < VALUE_INFINITE);
MovePicker mp(pos, ttMove, raisedBeta - ss->staticEval, &captureHistory);
int probCutCount = 0;
value = bestValue;
singularLMR = moveCountPruning = false;
ttCapture = ttMove && pos.capture_or_promotion(ttMove);
- bool formerPv = ttPv && !PvNode;
// Mark this node as being searched
ThreadHolding th(thisThread, posKey, ss->ply);
}
else
{
+ // Capture history based pruning when the move doesn't give check
if ( !givesCheck
&& lmrDepth < 1
&& captureHistory[movedPiece][to_sq(move)][type_of(pos.piece_on(to_sq(move)))] < 0)
continue;
+ // See based pruning
if (!pos.see_ge(move, Value(-194) * depth)) // (~25 Elo)
continue;
}
std::swap(squares[0], *std::max_element(squares, squares + leadPawnsCnt, pawns_comp));
- tbFile = edge_distance(file_of(squares[0]));
+ tbFile = File(edge_distance(file_of(squares[0])));
}
// DTZ tables are one-sided, i.e. they store positions only for white to
th->clear();
main()->callsCnt = 0;
- main()->previousScore = VALUE_INFINITE;
+ main()->bestPreviousScore = VALUE_INFINITE;
main()->previousTimeReduction = 1.0;
}
void check_time();
double previousTimeReduction;
- Value previousScore;
+ Value bestPreviousScore;
Value iterValue[4];
int callsCnt;
bool stopOnPonderhit;
VALUE_NONE = 32002,
VALUE_TB_WIN_IN_MAX_PLY = VALUE_MATE - 2 * MAX_PLY,
- VALUE_TB_LOSS_IN_MAX_PLY = -VALUE_MATE + 2 * MAX_PLY,
+ VALUE_TB_LOSS_IN_MAX_PLY = -VALUE_TB_WIN_IN_MAX_PLY,
VALUE_MATE_IN_MAX_PLY = VALUE_MATE - MAX_PLY,
- VALUE_MATED_IN_MAX_PLY = -VALUE_MATE + MAX_PLY,
+ VALUE_MATED_IN_MAX_PLY = -VALUE_MATE_IN_MAX_PLY,
PawnValueMg = 128, PawnValueEg = 213,
KnightValueMg = 781, KnightValueEg = 854,
/// Multiplication of a Score by a boolean
inline Score operator*(Score s, bool b) {
- return Score(int(s) * int(b));
+ return b ? s : SCORE_ZERO;
}
constexpr Color operator~(Color c) {