for (unsigned i = 0; i < (1 << 16); ++i)
PopCnt16[i] = std::bitset<16>(i).count();
- for (Square s = SQ_A1; s <= SQ_H8; ++s)
- SquareBB[s] = (1ULL << s);
+ for (Square s = SQ_A1; s <= SQ_MAX; ++s)
+ SquareBB[s] = make_bitboard(s);
- for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1)
- for (Square s2 = SQ_A1; s2 <= SQ_H8; ++s2)
+ for (File f = FILE_A; f <= FILE_MAX; ++f)
+ for (Rank r = RANK_1; r <= RANK_MAX; ++r)
+ BoardSizeBB[f][r] = forward_file_bb(BLACK, make_square(f, r)) | SquareBB[make_square(f, r)] | (f > FILE_A ? BoardSizeBB[f - 1][r] : Bitboard(0));
+
+ for (Square s1 = SQ_A1; s1 <= SQ_MAX; ++s1)
+ for (Square s2 = SQ_A1; s2 <= SQ_MAX; ++s2)
SquareDistance[s1][s2] = std::max(distance<File>(s1, s2), distance<Rank>(s1, s2));
- int steps[][5] = { {}, { 7, 9 }, { 6, 10, 15, 17 }, {}, {}, {}, { 1, 7, 8, 9 } };
+ // Piece moves
+ std::vector<Direction> RookDirections = { NORTH, EAST, SOUTH, WEST };
+ std::vector<Direction> BishopDirections = { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST };
+
+#ifdef PRECOMPUTED_MAGICS
+ init_magics(RookTable, RookMagics, RookDirections, RookMagicInit);
+ init_magics(BishopTable, BishopMagics, BishopDirections, BishopMagicInit);
+#else
+ init_magics(RookTable, RookMagics, RookDirections);
+ init_magics(BishopTable, BishopMagics, BishopDirections);
+#endif
- for (Color c = WHITE; c <= BLACK; ++c)
+ for (Color c : { WHITE, BLACK })
- for (PieceType pt : { PAWN, KNIGHT, KING })
- for (Square s = SQ_A1; s <= SQ_H8; ++s)
- for (int i = 0; steps[pt][i]; ++i)
+ for (PieceType pt = PAWN; pt <= KING; ++pt)
+ {
+ const PieceInfo* pi = pieceMap.find(pt)->second;
+
+ for (Square s = SQ_A1; s <= SQ_MAX; ++s)
+ {
+ for (Direction d : pi->stepsCapture)
{
- Square to = s + Direction(c == WHITE ? steps[pt][i] : -steps[pt][i]);
+ Square to = s + Direction(c == WHITE ? d : -d);
- if (is_ok(to) && distance(s, to) < 3)
+ if (is_ok(to) && distance(s, to) < 4)
{
- if (pt == PAWN)
- PawnAttacks[c][s] |= to;
- else
- PseudoAttacks[pt][s] |= to;
+ PseudoAttacks[c][pt][s] |= to;
+ LeaperAttacks[c][pt][s] |= to;
}
}
+ for (Direction d : pi->stepsQuiet)
+ {
+ Square to = s + Direction(c == WHITE ? d : -d);
- Direction RookDirections[] = { NORTH, EAST, SOUTH, WEST };
- Direction BishopDirections[] = { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST };
-
- init_magics(RookTable, RookMagics, RookDirections);
- init_magics(BishopTable, BishopMagics, BishopDirections);
+ if (is_ok(to) && distance(s, to) < 4)
+ {
+ PseudoMoves[c][pt][s] |= to;
+ LeaperMoves[c][pt][s] |= to;
+ }
+ }
+ PseudoAttacks[c][pt][s] |= sliding_attack(pi->sliderCapture, s, 0, c);
+ PseudoMoves[c][pt][s] |= sliding_attack(pi->sliderQuiet, s, 0, c);
+ }
+ }
- for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1)
+ for (Square s1 = SQ_A1; s1 <= SQ_MAX; ++s1)
{
- PseudoAttacks[QUEEN][s1] = PseudoAttacks[BISHOP][s1] = attacks_bb<BISHOP>(s1, 0);
- PseudoAttacks[QUEEN][s1] |= PseudoAttacks[ ROOK][s1] = attacks_bb< ROOK>(s1, 0);
-
for (PieceType pt : { BISHOP, ROOK })
- for (Square s2 = SQ_A1; s2 <= SQ_H8; ++s2)
- if (PseudoAttacks[pt][s1] & s2)
- LineBB[s1][s2] = (attacks_bb(pt, s1, 0) & attacks_bb(pt, s2, 0)) | s1 | s2;
+ for (Square s2 = SQ_A1; s2 <= SQ_MAX; ++s2)
+ if (PseudoAttacks[WHITE][pt][s1] & s2)
+ LineBB[s1][s2] = (attacks_bb(WHITE, pt, s1, 0) & attacks_bb(WHITE, pt, s2, 0)) | s1 | s2;
}
}
// PassedRank[Rank] contains a bonus according to the rank of a passed pawn
constexpr Score PassedRank[RANK_NB] = {
- S(0, 0), S(5, 18), S(12, 23), S(10, 31), S(57, 62), S(163, 167), S(271, 250)
- };
-
- // PassedFile[File] contains a bonus according to the file of a passed pawn
- constexpr Score PassedFile[FILE_NB] = {
- S( -1, 7), S( 0, 9), S(-9, -8), S(-30,-14),
- S(-30,-14), S(-9, -8), S( 0, 9), S( -1, 7)
+ S(0, 0), S(10, 28), S(17, 33), S(15, 41), S(62, 72), S(168, 177), S(276, 260)
};
+ // KingProximity contains a penalty according to distance from king
+ constexpr Score KingProximity = S(1, 3);
+
// Assorted bonuses and penalties
- constexpr Score AttacksOnSpaceArea = S( 4, 0);
constexpr Score BishopPawns = S( 3, 7);
constexpr Score CorneredBishop = S( 50, 50);
constexpr Score FlankAttacks = S( 8, 0);
b &= ~attackedBy[Them][PAWN] & safe;
// Bonus for safe pawn threats on the next move
- b = (pawn_attacks_bb<Us>(b) | shift<Up>(shift<Up>(pos.pieces(Us, SHOGI_PAWN)))) & pos.pieces(Them);
- b = pawn_attacks_bb<Us>(b) & nonPawnEnemies;
++ b = (pawn_attacks_bb<Us>(b) | shift<Up>(shift<Up>(pos.pieces(Us, SHOGI_PAWN)))) & nonPawnEnemies;
score += ThreatByPawnPush * popcount(b);
// Our safe or protected pawns
constexpr Direction Up = (Us == WHITE ? NORTH : SOUTH);
auto king_proximity = [&](Color c, Square s) {
- return std::min(distance(pos.square<KING>(c), s), 5);
+ return pos.count<KING>(c) ? std::min(distance(pos.square<KING>(c), s), 5) : 5;
};
- Bitboard b, bb, squaresToQueen, defendedSquares, unsafeSquares;
+ Bitboard b, bb, squaresToQueen, unsafeSquares;
Score score = SCORE_ZERO;
b = pe->passed_pawns(Us);
assert(!(pos.pieces(Them, PAWN) & forward_file_bb(Us, s + Up)));
- int r = relative_rank(Us, s);
+ int r = std::max(RANK_8 - std::max(pos.promotion_rank() - relative_rank(Us, s, pos.max_rank()), 0), 0);
+ File f = file_of(s);
Score bonus = PassedRank[r];
if (r > RANK_3)
{
- int w = (r-2) * (r-2) + 2;
+ int w = 5 * r - 13;
Square blockSq = s + Up;
- // Adjust bonus based on the king's proximity
- bonus += make_score(0, ( king_proximity(Them, blockSq) * 5
- - king_proximity(Us, blockSq) * 2) * w);
+ // Skip bonus for antichess variants
+ if (pos.extinction_value() != VALUE_MATE)
+ {
+ // Adjust bonus based on the king's proximity
+ bonus += make_score(0, ( king_proximity(Them, blockSq) * 5
+ - king_proximity(Us, blockSq) * 2) * w);
- // If blockSq is not the queening square then consider also a second push
- if (r != RANK_7)
- bonus -= make_score(0, king_proximity(Us, blockSq + Up) * w);
+ // If blockSq is not the queening square then consider also a second push
+ if (r != RANK_7)
+ bonus -= make_score(0, king_proximity(Us, blockSq + Up) * w);
+ }
// If the pawn is free to advance, then increase the bonus
if (pos.empty(blockSq))
// Scale down bonus for candidate passers which need more than one
// pawn push to become passed, or have a pawn in front of them.
if ( !pos.pawn_passed(Us, s + Up)
- || (pos.pieces(PAWN) & forward_file_bb(Us, s)))
+ || (pos.pieces(PAWN) & (s + Up)))
bonus = bonus / 2;
- score += bonus + PassedFile[file_of(s)];
- score += bonus - PassedFile * std::min(f, ~f);
++ score += bonus - PassedFile * std::min(f, File(pos.max_file() - f));
+ }
+
+ // Scale by maximum promotion piece value
+ Value maxMg = VALUE_ZERO, maxEg = VALUE_ZERO;
+ for (PieceType pt : pos.promotion_piece_types())
+ {
+ maxMg = std::max(maxMg, PieceValue[MG][pt]);
+ maxEg = std::max(maxEg, PieceValue[EG][pt]);
+ }
+ score = make_score(mg_value(score) * int(maxMg - PawnValueMg) / (QueenValueMg - PawnValueMg),
+ eg_value(score) * int(maxEg - PawnValueEg) / (QueenValueEg - PawnValueEg));
+
+ // Score passed shogi pawns
+ const Square* pl = pos.squares(Us, SHOGI_PAWN);
+ Square s;
+
+ PieceType pt = pos.promoted_piece_type(SHOGI_PAWN);
+ if (pt != NO_PIECE_TYPE)
+ {
+ while ((s = *pl++) != SQ_NONE)
+ {
+ if ((pos.pieces(Them, SHOGI_PAWN) & forward_file_bb(Us, s)) || relative_rank(Us, s, pos.max_rank()) == pos.max_rank())
+ continue;
+
+ Square blockSq = s + Up;
+ int d = std::max(pos.promotion_rank() - relative_rank(Us, s, pos.max_rank()), 1);
+ d += !!(attackedBy[Them][ALL_PIECES] & ~attackedBy2[Us] & blockSq);
+ score += make_score(PieceValue[MG][pt], PieceValue[EG][pt]) / (4 * d * d);
+ }
}
if (T)
behind |= shift<Down>(behind);
behind |= shift<Down+Down>(behind);
+ if (pawnsOnly)
+ {
+ safe = behind & ~attackedBy[Them][ALL_PIECES];
+ behind = 0;
+ }
-
- int bonus = popcount(safe) + popcount(behind & safe);
+ int bonus = popcount(safe) + popcount(behind & safe & ~attackedBy[Them][ALL_PIECES]);
int weight = pos.count<ALL_PIECES>(Us) - 1;
Score score = make_score(bonus * weight * weight / 16, 0);
if ((e->evaluationFunction = Endgames::probe<Value>(key)) != nullptr)
return e;
- for (Color c = WHITE; c <= BLACK; ++c)
+ for (Color c : { WHITE, BLACK })
+ if (is_KFsPsK(pos, c))
+ {
+ e->evaluationFunction = &EvaluateKFsPsK[c];
+ return e;
+ }
+
- for (Color c = WHITE; c <= BLACK; ++c)
++ for (Color c : { WHITE, BLACK })
if (is_KXK(pos, c))
{
e->evaluationFunction = &EvaluateKXK[c];
// Flag the pawn
opposed = theirPawns & forward_file_bb(Us, s);
stoppers = theirPawns & passed_pawn_span(Us, s);
- lever = theirPawns & PawnAttacks[Us][s];
- leverPush = theirPawns & PawnAttacks[Us][s + Up];
- doubled = ourPawns & (s - Up);
+ lever = theirPawns & PseudoAttacks[Us][PAWN][s];
+ leverPush = relative_rank(Them, s, pos.max_rank()) > RANK_1 ? theirPawns & PseudoAttacks[Us][PAWN][s + Up] : Bitboard(0);
+ doubled = r > RANK_1 ? ourPawns & (s - Up) : Bitboard(0);
neighbours = ourPawns & adjacent_files_bb(s);
phalanx = neighbours & rank_bb(s);
- support = neighbours & rank_bb(s - Up);
+ support = r > RANK_1 ? neighbours & rank_bb(s - Up) : Bitboard(0);
- // A pawn is backward when it is behind all pawns of the same color
- // on the adjacent files and cannot be safely advanced.
- backward = relative_rank(Them, s, pos.max_rank()) > RANK_1
- && !(ourPawns & pawn_attack_span(Them, s + Up))
+ // A pawn is backward when it is behind all pawns of the same color on
+ // the adjacent files and cannot safely advance. Phalanx and isolated
+ // pawns will be excluded when the pawn is scored.
+ backward = !(neighbours & forward_ranks_bb(Them, s))
++ && is_ok(s + Up)
&& (stoppers & (leverPush | (s + Up)));
- // Passed pawns will be properly scored in evaluation because we need
- // full attack info to evaluate them. Include also not passed pawns
- // which could become passed after one or two pawn pushes when are
- // not attacked more times than defended.
- if ( !(stoppers ^ lever) ||
- (!(stoppers ^ leverPush) && popcount(phalanx) >= popcount(leverPush)))
+ // A pawn is passed if one of the three following conditions is true:
+ // (a) there is no stoppers except some levers
+ // (b) the only stoppers are the leverPush, but we outnumber them
+ // (c) there is only one front stopper which can be levered.
+ passed = !(stoppers ^ lever)
+ || ( !(stoppers ^ leverPush)
+ && popcount(phalanx) >= popcount(leverPush))
- || ( stoppers == square_bb(s + Up) && r >= RANK_5
++ || ( is_ok(s + Up) && stoppers == square_bb(s + Up) && r >= RANK_5
+ && (shift<Up>(support) & ~(theirPawns | doubleAttackThem)));
+
+ // Passed pawns will be properly scored later in evaluation when we have
+ // full attack info.
+ if (passed)
e->passedPawns[Us] |= s;
// Score this pawn
if (support | phalanx)
{
- int v = Connected[r] * (phalanx ? 3 : 2) / (opposed ? 2 : 1)
+ int v = Connected[r] * (phalanx ? 3 : 2) * (r == RANK_2 && pos.captures_to_hand() ? 3 : 1) / (opposed ? 2 : 1)
+ 17 * popcount(support);
-
+ if (r >= RANK_4 && pos.count<PAWN>(Us) > popcount(pos.board_bb()) / 4)
+ v = std::max(v, popcount(support | phalanx) * 50) / (opposed ? 2 : 1);
score += make_score(v, v * (r - 2) / 4);
}
+
else if (!neighbours)
- score -= Isolated + WeakUnopposed * int(!opposed);
+ score -= Isolated * (1 + 2 * pos.must_capture()) + WeakUnopposed * int(!opposed);
else if (backward)
score -= Backward + WeakUnopposed * int(!opposed);
score -= Doubled;
}
+ // Penalize the unsupported and non passed pawns attacked twice by the enemy
+ b = ourPawns
+ & doubleAttackThem
+ & ~(e->pawnAttacks[Us] | e->passedPawns[Us]);
+ score -= WeakLever * popcount(b);
+
+ // Double pawn evaluation if there are no non-pawn pieces
+ if (pos.count<ALL_PIECES>(Us) == pos.count<PAWN>(Us))
+ score = score * 2;
+
+ const Square* pl_shogi = pos.squares<SHOGI_PAWN>(Us);
+
+ ourPawns = pos.pieces(Us, SHOGI_PAWN);
+ theirPawns = pos.pieces(Them, SHOGI_PAWN);
+
+ // Loop through all shogi pawns of the current color and score each one
+ while ((s = *pl_shogi++) != SQ_NONE)
+ {
+ assert(pos.piece_on(s) == make_piece(Us, SHOGI_PAWN));
+
+ neighbours = ourPawns & adjacent_files_bb(s);
+
+ if (!neighbours)
+ score -= Isolated / 2;
+ }
+
return score;
}
template<Color Us>
void Entry::evaluate_shelter(const Position& pos, Square ksq, Score& shelter) {
- constexpr Color Them = (Us == WHITE ? BLACK : WHITE);
+ constexpr Color Them = (Us == WHITE ? BLACK : WHITE);
- Bitboard b = pos.pieces(PAWN) & ~forward_ranks_bb(Them, ksq);
+ Bitboard b = pos.pieces(PAWN, SHOGI_PAWN) & ~forward_ranks_bb(Them, ksq);
Bitboard ourPawns = b & pos.pieces(Us);
Bitboard theirPawns = b & pos.pieces(Them);
- Value bonus[] = { Value(5), Value(5) };
+ Score bonus = make_score(5, 5);
- File center = clamp(file_of(ksq), FILE_B, FILE_G);
+ File center = clamp(file_of(ksq), FILE_B, File(pos.max_file() - 1));
for (File f = File(center - 1); f <= File(center + 1); ++f)
{
b = ourPawns & file_bb(f);
- Rank ourRank = b ? relative_rank(Us, frontmost_sq(Them, b)) : RANK_1;
+ Rank ourRank = b ? relative_rank(Us, frontmost_sq(Them, b), pos.max_rank()) : RANK_1;
b = theirPawns & file_bb(f);
- Rank theirRank = b ? relative_rank(Us, frontmost_sq(Them, b)) : RANK_1;
+ Rank theirRank = b ? relative_rank(Us, frontmost_sq(Them, b), pos.max_rank()) : RANK_1;
- int d = std::min(f, ~f);
- bonus += make_score(ShelterStrength[d][ourRank], 0);
+ int d = std::min(std::min(f, File(pos.max_file() - f)), FILE_D);
- bonus[MG] += ShelterStrength[d][ourRank] * (1 + (pos.captures_to_hand() && ourRank <= RANK_2));
++ bonus += make_score(ShelterStrength[d][ourRank], 0) * (1 + (pos.captures_to_hand() && ourRank <= RANK_2));
if (ourRank && (ourRank == theirRank - 1))
- bonus[MG] -= 82 * (theirRank == RANK_3), bonus[EG] -= 82 * (theirRank == RANK_3);
+ bonus -= make_score(82 * (theirRank == RANK_3), 82 * (theirRank == RANK_3));
else
- bonus[MG] -= UnblockedStorm[d][theirRank];
+ bonus -= make_score(UnblockedStorm[d][theirRank], 0);
}
- if (bonus[MG] > mg_value(shelter))
- shelter = make_score(bonus[MG], bonus[EG]);
+ if (mg_value(bonus) > mg_value(shelter))
+ shelter = bonus;
}
PRNG rng(1070372);
- for (Color c = WHITE; c <= BLACK; ++c)
- for (Piece pc : Pieces)
- for (Square s = SQ_A1; s <= SQ_H8; ++s)
- Zobrist::psq[pc][s] = rng.rand<Key>();
++ for (Color c : {WHITE, BLACK})
+ for (PieceType pt = PAWN; pt <= KING; ++pt)
+ for (Square s = SQ_A1; s <= SQ_MAX; ++s)
+ Zobrist::psq[make_piece(c, pt)][s] = rng.rand<Key>();
- for (File f = FILE_A; f <= FILE_H; ++f)
+ for (File f = FILE_A; f <= FILE_MAX; ++f)
Zobrist::enpassant[f] = rng.rand<Key>();
for (int cr = NO_CASTLING; cr <= ANY_CASTLING; ++cr)
Zobrist::side = rng.rand<Key>();
Zobrist::noPawns = rng.rand<Key>();
- for (Color c = WHITE; c <= BLACK; ++c)
++ for (Color c : {WHITE, BLACK})
+ for (int n = 0; n < CHECKS_NB; ++n)
+ Zobrist::checks[c][n] = rng.rand<Key>();
+
- for (Color c = WHITE; c <= BLACK; ++c)
++ for (Color c : {WHITE, BLACK})
+ for (PieceType pt = PAWN; pt <= KING; ++pt)
+ for (int n = 0; n < SQUARE_NB; ++n)
+ Zobrist::inHand[make_piece(c, pt)][n] = rng.rand<Key>();
+
// Prepare the cuckoo tables
std::memset(cuckoo, 0, sizeof(cuckoo));
std::memset(cuckooMove, 0, sizeof(cuckooMove));
int count = 0;
- for (Color c = WHITE; c <= BLACK; ++c)
- for (Piece pc : Pieces)
- for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1)
- for (Square s2 = Square(s1 + 1); s2 <= SQ_H8; ++s2)
- if (PseudoAttacks[type_of(pc)][s1] & s2)
++ for (Color c : {WHITE, BLACK})
+ for (PieceType pt = KNIGHT; pt <= QUEEN || pt == KING; pt != QUEEN ? ++pt : pt = KING)
+ {
+ Piece pc = make_piece(c, pt);
+ for (Square s1 = SQ_A1; s1 <= SQ_MAX; ++s1)
+ for (Square s2 = Square(s1 + 1); s2 <= SQ_MAX; ++s2)
+ if (PseudoAttacks[WHITE][type_of(pc)][s1] & s2)
{
Move move = make_move(s1, s2);
Key key = Zobrist::psq[pc][s1] ^ Zobrist::psq[pc][s2] ^ Zobrist::side;
si->key ^= Zobrist::castling[si->castlingRights];
- for (Color c = WHITE; c <= BLACK; ++c)
- for (Piece pc : Pieces)
- for (int cnt = 0; cnt < pieceCount[pc]; ++cnt)
- si->materialKey ^= Zobrist::psq[pc][cnt];
++ for (Color c : {WHITE, BLACK})
+ for (PieceType pt = PAWN; pt <= KING; ++pt)
+ {
+ Piece pc = make_piece(c, pt);
+
+ for (int cnt = 0; cnt < pieceCount[pc]; ++cnt)
+ si->materialKey ^= Zobrist::psq[pc][cnt];
+
+ if (piece_drops())
+ si->key ^= Zobrist::inHand[pc][pieceCountInHand[c][pt]];
+ }
+
+ if (max_check_count())
- for (Color c = WHITE; c <= BLACK; ++c)
++ for (Color c : {WHITE, BLACK})
+ si->key ^= Zobrist::checks[c][si->checksGiven[c]];
}
ss << '/';
}
+ // pieces in hand
+ if (piece_drops())
+ {
+ ss << '[';
- for (Color c = WHITE; c <= BLACK; ++c)
++ for (Color c : {WHITE, BLACK})
+ for (PieceType pt = KING; pt >= PAWN; --pt)
+ ss << std::string(pieceCountInHand[c][pt], piece_to_char()[make_piece(c, pt)]);
+ ss << ']';
+ }
+
ss << (sideToMove == WHITE ? " w " : " b ");
if (can_castle(WHITE_OO))
if (std::memcmp(&si, st, sizeof(StateInfo)))
assert(0 && "pos_is_ok: State");
- for (Color c = WHITE; c <= BLACK; ++c)
- for (Piece pc : Pieces)
- {
- if ( pieceCount[pc] != popcount(pieces(color_of(pc), type_of(pc)))
- || pieceCount[pc] != std::count(board, board + SQUARE_NB, pc))
- assert(0 && "pos_is_ok: Pieces");
-
- for (int i = 0; i < pieceCount[pc]; ++i)
- if (board[pieceList[pc][i]] != pc || index[pieceList[pc][i]] != i)
- assert(0 && "pos_is_ok: Index");
- }
++ for (Color c : {WHITE, BLACK})
+ for (PieceType pt = PAWN; pt <= KING; ++pt)
+ {
+ Piece pc = make_piece(c, pt);
+ if ( pieceCount[pc] != popcount(pieces(c, pt))
+ || pieceCount[pc] != std::count(board, board + SQUARE_NB, pc))
+ assert(0 && "pos_is_ok: Pieces");
+
+ for (int i = 0; i < pieceCount[pc]; ++i)
+ if (board[pieceList[pc][i]] != pc || index[pieceList[pc][i]] != i)
+ assert(0 && "pos_is_ok: Index");
+ }
- for (Color c = WHITE; c <= BLACK; ++c)
- for (CastlingSide s = KING_SIDE; s <= QUEEN_SIDE; s = CastlingSide(s + 1))
+ for (Color c : { WHITE, BLACK })
+ for (CastlingSide s : {KING_SIDE, QUEEN_SIDE})
{
if (!can_castle(c | s))
continue;
return st->checkSquares[pt];
}
+ inline bool Position::is_discovery_check_on_king(Color c, Move m) const {
- return st->blockersForKing[c] & from_sq(m);
++ return is_ok(from_sq(m)) && st->blockersForKing[c] & from_sq(m);
+ }
+
inline bool Position::pawn_passed(Color c, Square s) const {
return !(pieces(~c, PAWN) & passed_pawn_span(c, s));
}
&& pos.pawn_passed(us, to_sq(move)))
extension = ONE_PLY;
++ // Losing chess capture extension
++ else if ( pos.must_capture()
++ && pos.capture(move)
++ && MoveList<CAPTURES>(pos).size() == 1)
++ extension = ONE_PLY;
++
// Calculate new depth for this move
newDepth = depth - ONE_PLY + extension;
if ( !captureOrPromotion
&& !givesCheck
- && (!pos.advanced_pawn_push(move) || pos.non_pawn_material(~us) > BishopValueMg))
+ && (!pos.must_capture() || !pos.attackers_to(to_sq(move), ~us))
+ && (!pos.advanced_pawn_push(move) || pos.non_pawn_material(~us) > BishopValueMg || pos.count<ALL_PIECES>(us) == pos.count<PAWN>(us)))
{
- // Move count based pruning (~30 Elo)
+ // Move count based pruning
if (moveCountPruning)
continue;
continue;
// Prune moves with negative SEE (~10 Elo)
- if (!pos.must_capture() && !pos.see_ge(move, Value(-29 * lmrDepth * lmrDepth)))
- 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 ((!givesCheck || !extension)
- && !pos.must_capture()
- && !pos.see_ge(move, -(PawnValueEg + 120 * pos.captures_to_hand()) * (depth / ONE_PLY))) // (~20 Elo)
+ else if ( (!givesCheck || !extension)
- && !pos.see_ge(move, -PawnValueEg * (depth / ONE_PLY))) // (~20 Elo)
++ && !pos.must_capture()
++ && !pos.see_ge(move, -(PawnValueEg + 120 * pos.captures_to_hand()) * (depth / ONE_PLY))) // (~20 Elo)
continue;
}
r -= 2 * ONE_PLY;
ss->statScore = thisThread->mainHistory[us][from_to(move)]
- + (*contHist[0])[movedPiece][to_sq(move)]
- + (*contHist[1])[movedPiece][to_sq(move)]
- + (*contHist[3])[movedPiece][to_sq(move)]
+ + (*contHist[0])[history_slot(movedPiece)][to_sq(move)]
+ + (*contHist[1])[history_slot(movedPiece)][to_sq(move)]
+ + (*contHist[3])[history_slot(movedPiece)][to_sq(move)]
- 4000;
+ // Reset statScore to zero if negative and most stats shows >= 0
+ if ( ss->statScore < 0
- && (*contHist[0])[movedPiece][to_sq(move)] >= 0
- && (*contHist[1])[movedPiece][to_sq(move)] >= 0
++ && (*contHist[0])[history_slot(movedPiece)][to_sq(move)] >= 0
++ && (*contHist[1])[history_slot(movedPiece)][to_sq(move)] >= 0
+ && thisThread->mainHistory[us][from_to(move)] >= 0)
+ ss->statScore = 0;
+
// Decrease/increase reduction by comparing opponent's stat score (~10 Elo)
if (ss->statScore >= 0 && (ss-1)->statScore < 0)
r -= ONE_PLY;
o["Slow Mover"] << Option(84, 10, 1000);
o["nodestime"] << Option(0, 0, 10000);
o["UCI_Chess960"] << Option(false);
+ o["UCI_Variant"] << Option("chess", variants.get_keys(), on_variant_change);
o["UCI_AnalyseMode"] << Option(false);
+ o["UCI_LimitStrength"] << Option(false);
+ o["UCI_Elo"] << Option(1350, 1350, 2850);
o["SyzygyPath"] << Option("<empty>", on_tb_path);
o["SyzygyProbeDepth"] << Option(1, 1, 100);
o["Syzygy50MoveRule"] << Option(true);