1
0
Fork 0
mirror of https://github.com/sockspls/badfish synced 2025-04-30 08:43:09 +00:00

Merge pull request #45 from joergoster/sf-nnue-update

Sf nnue update
This commit is contained in:
nodchip 2020-07-11 19:17:38 +09:00 committed by GitHub
commit ae4db5ebfd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 177 additions and 134 deletions

View file

@ -75,9 +75,6 @@ Currently, Stockfish has the following UCI options:
Assume a time delay of x ms due to network and GUI overheads. This is useful to
avoid losses on time in those cases.
* #### Minimum Thinking Time
Search for at least x ms per move.
* #### Slow Mover
Lower values will make Stockfish take less time in games, higher values will
make it think longer.

View file

@ -88,7 +88,7 @@ const vector<string> Defaults = {
// Chess 960
"setoption name UCI_Chess960 value true",
"bbqnnrkr/pppppppp/8/8/8/8/PPPPPPPP/BBQNNRKR w KQkq - 0 1 moves g2g3 d7d5 d2d4 c8h3 c1g5 e8d6 g5e7 f7f6",
"bbqnnrkr/pppppppp/8/8/8/8/PPPPPPPP/BBQNNRKR w HFhf - 0 1 moves g2g3 d7d5 d2d4 c8h3 c1g5 e8d6 g5e7 f7f6",
"setoption name UCI_Chess960 value false"
};

View file

@ -124,12 +124,19 @@ 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, Bitboard b) { return b ^ s; }
inline Bitboard operator|(Square s, Square s2) { return square_bb(s) | s2; }
inline Bitboard operator|(Square s1, Square s2) { return square_bb(s1) | s2; }
constexpr bool more_than_one(Bitboard b) {
return b & (b - 1);
}
/// Counts the occupation of the bitboard depending on the occupation of SQ_A1
/// as in `b & (1ULL << SQ_A1) ? more_than_two(b) : more_than_one(b)`
constexpr bool conditional_more_than_two(Bitboard b) {
return b & (b - 1) & (b - 2);
}
constexpr bool opposite_colors(Square s1, Square s2) {
return (s1 + rank_of(s1) + s2 + rank_of(s2)) & 1;
}
@ -138,19 +145,19 @@ constexpr bool opposite_colors(Square s1, Square s2) {
/// rank_bb() and file_bb() return a bitboard representing all the squares on
/// the given file or rank.
inline Bitboard rank_bb(Rank r) {
constexpr Bitboard rank_bb(Rank r) {
return Rank1BB << (8 * r);
}
inline Bitboard rank_bb(Square s) {
constexpr Bitboard rank_bb(Square s) {
return rank_bb(rank_of(s));
}
inline Bitboard file_bb(File f) {
constexpr Bitboard file_bb(File f) {
return FileABB << f;
}
inline Bitboard file_bb(Square s) {
constexpr Bitboard file_bb(Square s) {
return file_bb(file_of(s));
}
@ -195,16 +202,16 @@ constexpr Bitboard pawn_double_attacks_bb(Bitboard b) {
/// adjacent_files_bb() returns a bitboard representing all the squares on the
/// adjacent files of the given one.
/// adjacent files of a given square.
inline Bitboard adjacent_files_bb(Square s) {
constexpr Bitboard adjacent_files_bb(Square s) {
return shift<EAST>(file_bb(s)) | shift<WEST>(file_bb(s));
}
/// line_bb(Square, Square) returns a bitboard representing an entire line,
/// from board edge to board edge, that intersects the given squares. If the
/// given squares are not on a same file/rank/diagonal, returns 0. For instance,
/// line_bb() returns a bitboard representing an entire line (from board edge
/// to board edge) that intersects the two given squares. If the given squares
/// are not on a same file/rank/diagonal, the function returns 0. For instance,
/// line_bb(SQ_C4, SQ_F7) will return a bitboard with the A2-G8 diagonal.
inline Bitboard line_bb(Square s1, Square s2) {
@ -215,8 +222,8 @@ inline Bitboard line_bb(Square s1, Square s2) {
/// between_bb() returns a bitboard representing squares that are linearly
/// between the given squares (excluding the given squares). If the given
/// squares are not on a same file/rank/diagonal, return 0. For instance,
/// between the two given squares (excluding the given squares). If the given
/// squares are not on a same file/rank/diagonal, we return 0. For instance,
/// between_bb(SQ_C4, SQ_F7) will return a bitboard with squares D5 and E6.
inline Bitboard between_bb(Square s1, Square s2) {
@ -229,7 +236,7 @@ inline Bitboard between_bb(Square s1, Square s2) {
/// in front of the given one, from the point of view of the given color. For instance,
/// 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) {
constexpr Bitboard forward_ranks_bb(Color c, Square s) {
return c == WHITE ? ~Rank1BB << 8 * relative_rank(WHITE, s)
: ~Rank8BB >> 8 * relative_rank(BLACK, s);
}
@ -238,7 +245,7 @@ inline Bitboard forward_ranks_bb(Color c, Square s) {
/// forward_file_bb() returns a bitboard representing all the squares along the
/// line in front of the given one, from the point of view of the given color.
inline Bitboard forward_file_bb(Color c, Square s) {
constexpr Bitboard forward_file_bb(Color c, Square s) {
return forward_ranks_bb(c, s) & file_bb(s);
}
@ -247,7 +254,7 @@ inline Bitboard forward_file_bb(Color c, Square s) {
/// be attacked by a pawn of the given color when it moves along its file, starting
/// from the given square.
inline Bitboard pawn_attack_span(Color c, Square s) {
constexpr Bitboard pawn_attack_span(Color c, Square s) {
return forward_ranks_bb(c, s) & adjacent_files_bb(s);
}
@ -255,7 +262,7 @@ inline Bitboard pawn_attack_span(Color c, Square s) {
/// passed_pawn_span() returns a bitboard which can be used to test if a pawn of
/// the given color and on the given square is a passed pawn.
inline Bitboard passed_pawn_span(Color c, Square s) {
constexpr Bitboard passed_pawn_span(Color c, Square s) {
return pawn_attack_span(c, s) | forward_file_bb(c, s);
}

View file

@ -181,15 +181,15 @@ Value Endgame<KRKP>::operator()(const Position& pos) const {
assert(verify_material(pos, strongSide, RookValueMg, 0));
assert(verify_material(pos, weakSide, VALUE_ZERO, 1));
Square strongKing = relative_square(strongSide, pos.square<KING>(strongSide));
Square weakKing = relative_square(strongSide, pos.square<KING>(weakSide));
Square strongRook = relative_square(strongSide, pos.square<ROOK>(strongSide));
Square weakPawn = relative_square(strongSide, pos.square<PAWN>(weakSide));
Square queeningSquare = make_square(file_of(weakPawn), RANK_1);
Square strongKing = pos.square<KING>(strongSide);
Square weakKing = pos.square<KING>(weakSide);
Square strongRook = pos.square<ROOK>(strongSide);
Square weakPawn = pos.square<PAWN>(weakSide);
Square queeningSquare = make_square(file_of(weakPawn), relative_rank(weakSide, RANK_8));
Value result;
// If the stronger side's king is in front of the pawn, it's a win
if (forward_file_bb(WHITE, strongKing) & weakPawn)
if (forward_file_bb(strongSide, strongKing) & weakPawn)
result = RookValueEg - distance(strongKing, weakPawn);
// If the weaker side's king is too far from the pawn and the rook,
@ -200,15 +200,15 @@ Value Endgame<KRKP>::operator()(const Position& pos) const {
// If the pawn is far advanced and supported by the defending king,
// the position is drawish
else if ( rank_of(weakKing) <= RANK_3
else if ( relative_rank(strongSide, weakKing) <= RANK_3
&& distance(weakKing, weakPawn) == 1
&& rank_of(strongKing) >= RANK_4
&& relative_rank(strongSide, strongKing) >= RANK_4
&& distance(strongKing, weakPawn) > 2 + (pos.side_to_move() == strongSide))
result = Value(80) - 8 * distance(strongKing, weakPawn);
else
result = Value(200) - 8 * ( distance(strongKing, weakPawn + SOUTH)
- distance(weakKing, weakPawn + SOUTH)
result = Value(200) - 8 * ( distance(strongKing, weakPawn + pawn_push(weakSide))
- distance(weakKing, weakPawn + pawn_push(weakSide))
- distance(weakPawn, queeningSquare));
return strongSide == pos.side_to_move() ? result : -result;

View file

@ -82,11 +82,11 @@ namespace {
// KingAttackWeights[PieceType] contains king attack weights by piece type
constexpr int KingAttackWeights[PIECE_TYPE_NB] = { 0, 0, 81, 52, 44, 10 };
// Penalties for enemy's safe checks
constexpr int QueenSafeCheck = 772;
constexpr int RookSafeCheck = 1084;
constexpr int BishopSafeCheck = 645;
constexpr int KnightSafeCheck = 792;
// SafeCheck[PieceType][single/multiple] contains safe check bonus by piece type,
// higher if multiple safe checks are possible for that piece type.
constexpr int SafeCheck[][2] = {
{}, {}, {792, 1283}, {645, 967}, {1084, 1897}, {772, 1119}
};
#define S(mg, eg) make_score(mg, eg)
@ -108,6 +108,18 @@ namespace {
S(110,182), S(114,182), S(114,192), S(116,219) }
};
// KingProtector[knight/bishop] contains penalty for each distance unit to own king
constexpr Score KingProtector[] = { S(8, 9), S(6, 9) };
// Outpost[knight/bishop] contains bonuses for each knight or bishop occupying a
// pawn protected square on rank 4 to 6 which is also safe from a pawn attack.
constexpr Score Outpost[] = { S(56, 36), S(30, 23) };
// PassedRank[Rank] contains a bonus according to the rank of a passed pawn
constexpr Score PassedRank[RANK_NB] = {
S(0, 0), S(10, 28), S(17, 33), S(15, 41), S(62, 72), S(168, 177), S(276, 260)
};
// RookOnFile[semiopen/open] contains bonuses for each rook when there is
// no (friendly) pawn on the rook file.
constexpr Score RookOnFile[] = { S(19, 7), S(48, 29) };
@ -123,23 +135,15 @@ namespace {
S(0, 0), S(3, 46), S(37, 68), S(42, 60), S(0, 38), S(58, 41)
};
// PassedRank[Rank] contains a bonus according to the rank of a passed pawn
constexpr Score PassedRank[RANK_NB] = {
S(0, 0), S(10, 28), S(17, 33), S(15, 41), S(62, 72), S(168, 177), S(276, 260)
};
// Assorted bonuses and penalties
constexpr Score BishopKingProtector = S( 6, 9);
constexpr Score BadOutpost = S( -7, 36);
constexpr Score BishopOnKingRing = S( 24, 0);
constexpr Score BishopOutpost = S( 30, 23);
constexpr Score BishopPawns = S( 3, 7);
constexpr Score BishopXRayPawns = S( 4, 5);
constexpr Score CorneredBishop = S( 50, 50);
constexpr Score FlankAttacks = S( 8, 0);
constexpr Score Hanging = S( 69, 36);
constexpr Score KnightKingProtector = S( 8, 9);
constexpr Score KnightOnQueen = S( 16, 11);
constexpr Score KnightOutpost = S( 56, 36);
constexpr Score LongDiagonalBishop = S( 45, 0);
constexpr Score MinorBehindPawn = S( 18, 3);
constexpr Score PassedFile = S( 11, 8);
@ -309,8 +313,14 @@ namespace {
{
// Bonus if piece is on an outpost square or can reach one
bb = OutpostRanks & attackedBy[Us][PAWN] & ~pe->pawn_attacks_span(Them);
if (bb & s)
score += (Pt == KNIGHT) ? KnightOutpost : BishopOutpost;
if ( Pt == KNIGHT
&& bb & s & ~CenterFiles
&& !(b & pos.pieces(Them) & ~pos.pieces(PAWN))
&& !conditional_more_than_two(
pos.pieces(Them) & ~pos.pieces(PAWN) & (s & QueenSide ? QueenSide : KingSide)))
score += BadOutpost;
else if (bb & s)
score += Outpost[Pt == BISHOP];
else if (Pt == KNIGHT && bb & b & ~pos.pieces(Us))
score += ReachableOutpost;
@ -319,8 +329,7 @@ namespace {
score += MinorBehindPawn;
// Penalty if the piece is far from the king
score -= (Pt == KNIGHT ? KnightKingProtector
: BishopKingProtector) * distance(pos.square<KING>(Us), s);
score -= KingProtector[Pt == BISHOP] * distance(pos.square<KING>(Us), s);
if (Pt == BISHOP)
{
@ -422,41 +431,33 @@ namespace {
b2 = attacks_bb<BISHOP>(ksq, pos.pieces() ^ pos.pieces(Us, QUEEN));
// Enemy rooks checks
rookChecks = b1 & safe & attackedBy[Them][ROOK];
rookChecks = b1 & attackedBy[Them][ROOK] & safe;
if (rookChecks)
kingDanger += more_than_one(rookChecks) ? RookSafeCheck * 175/100
: RookSafeCheck;
kingDanger += SafeCheck[ROOK][more_than_one(rookChecks)];
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;
// Enemy queen safe checks: count them only if the checks are from squares from
// which opponent cannot give a rook check, because rook checks are more valuable.
queenChecks = (b1 | b2) & attackedBy[Them][QUEEN] & safe
& ~(attackedBy[Us][QUEEN] | rookChecks);
if (queenChecks)
kingDanger += more_than_one(queenChecks) ? QueenSafeCheck * 145/100
: QueenSafeCheck;
kingDanger += SafeCheck[QUEEN][more_than_one(queenChecks)];
// 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
// Enemy bishops checks: count them only if they are from squares from which
// opponent cannot give a queen check, because queen checks are more valuable.
bishopChecks = b2 & attackedBy[Them][BISHOP] & safe
& ~queenChecks;
if (bishopChecks)
kingDanger += more_than_one(bishopChecks) ? BishopSafeCheck * 3/2
: BishopSafeCheck;
kingDanger += SafeCheck[BISHOP][more_than_one(bishopChecks)];
else
unsafeChecks |= b2 & attackedBy[Them][BISHOP];
// Enemy knights checks
knightChecks = attacks_bb<KNIGHT>(ksq) & attackedBy[Them][KNIGHT];
if (knightChecks & safe)
kingDanger += more_than_one(knightChecks & safe) ? KnightSafeCheck * 162/100
: KnightSafeCheck;
kingDanger += SafeCheck[KNIGHT][more_than_one(knightChecks & safe)];
else
unsafeChecks |= knightChecks;
@ -466,7 +467,7 @@ namespace {
b2 = b1 & attackedBy2[Them];
b3 = attackedBy[Us][ALL_PIECES] & KingFlank[file_of(ksq)] & Camp;
int kingFlankAttack = popcount(b1) + popcount(b2);
int kingFlankAttack = popcount(b1) + popcount(b2);
int kingFlankDefense = popcount(b3);
kingDanger += kingAttackersCount[Them] * kingAttackersWeight[Them]
@ -727,9 +728,9 @@ namespace {
}
// Evaluation::winnable() adjusts the mg and eg score components based on the
// known attacking/defending status of the players. A single value is derived
// by interpolation from the mg and eg values and returned.
// Evaluation::winnable() adjusts the midgame and endgame score components, based on
// the known attacking/defending status of the players. The final value is derived
// by interpolation from the midgame and endgame values.
template<Tracing T>
Value Evaluation<T>::winnable(Score score) const {
@ -743,8 +744,8 @@ namespace {
bool almostUnwinnable = outflanking < 0
&& !pawnsOnBothFlanks;
bool infiltration = rank_of(pos.square<KING>(WHITE)) > RANK_4
|| rank_of(pos.square<KING>(BLACK)) < RANK_5;
bool infiltration = rank_of(pos.square<KING>(WHITE)) > RANK_4
|| rank_of(pos.square<KING>(BLACK)) < RANK_5;
// Compute the initiative bonus for the attacking side
int complexity = 9 * pe->passed_count()
@ -769,11 +770,10 @@ namespace {
eg += v;
// Compute the scale factor for the winning side
Color strongSide = eg > VALUE_DRAW ? WHITE : BLACK;
int sf = me->scale_factor(pos, strongSide);
// If scale is not already specific, scale down the endgame via general heuristics
// If scale factor is not already specific, scale down via general heuristics
if (sf == SCALE_FACTOR_NORMAL)
{
if (pos.opposite_bishops())
@ -784,6 +784,15 @@ namespace {
else
sf = 22 + 3 * pos.count<ALL_PIECES>(strongSide);
}
else if ( pos.non_pawn_material(WHITE) == RookValueMg
&& pos.non_pawn_material(BLACK) == RookValueMg
&& pos.count<PAWN>(strongSide) - pos.count<PAWN>(~strongSide) <= 1
&& bool(KingSide & pos.pieces(strongSide, PAWN)) != bool(QueenSide & pos.pieces(strongSide, PAWN))
&& (attackedBy[~strongSide][KING] & pos.pieces(~strongSide, PAWN)))
sf = 36;
else if (pos.count<QUEEN>() == 1)
sf = 37 + 3 * (pos.count<QUEEN>(WHITE) == 1 ? pos.count<BISHOP>(BLACK) + pos.count<KNIGHT>(BLACK)
: pos.count<BISHOP>(WHITE) + pos.count<KNIGHT>(WHITE));
else
sf = std::min(sf, 36 + 7 * pos.count<PAWN>(strongSide));
}

View file

@ -29,22 +29,20 @@ namespace {
ExtMove* make_promotions(ExtMove* moveList, Square to, Square ksq) {
if (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS)
{
*moveList++ = make<PROMOTION>(to - D, to, QUEEN);
if (attacks_bb<KNIGHT>(to) & ksq)
*moveList++ = make<PROMOTION>(to - D, to, KNIGHT);
}
if (Type == QUIETS || Type == EVASIONS || Type == NON_EVASIONS)
{
*moveList++ = make<PROMOTION>(to - D, to, ROOK);
*moveList++ = make<PROMOTION>(to - D, to, BISHOP);
*moveList++ = make<PROMOTION>(to - D, to, KNIGHT);
if (!(attacks_bb<KNIGHT>(to) & ksq))
*moveList++ = make<PROMOTION>(to - D, to, KNIGHT);
}
// Knight promotion is the only promotion that can give a direct check
// that's not already included in the queen promotion.
if (Type == QUIET_CHECKS && (attacks_bb<KNIGHT>(to) & ksq))
*moveList++ = make<PROMOTION>(to - D, to, KNIGHT);
else
(void)ksq; // Silence a warning under MSVC
return moveList;
}
@ -263,8 +261,8 @@ namespace {
} // namespace
/// <CAPTURES> Generates all pseudo-legal captures and queen promotions
/// <QUIETS> Generates all pseudo-legal non-captures and underpromotions
/// <CAPTURES> Generates all pseudo-legal captures plus queen and checking knight promotions
/// <QUIETS> Generates all pseudo-legal non-captures and underpromotions(except checking knight)
/// <NON_EVASIONS> Generates all pseudo-legal captures and non-captures
///
/// Returns a pointer to the end of the move list.
@ -287,8 +285,8 @@ template ExtMove* generate<QUIETS>(const Position&, ExtMove*);
template ExtMove* generate<NON_EVASIONS>(const Position&, ExtMove*);
/// generate<QUIET_CHECKS> generates all pseudo-legal non-captures and knight
/// underpromotions that give check. Returns a pointer to the end of the move list.
/// generate<QUIET_CHECKS> generates all pseudo-legal non-captures.
/// Returns a pointer to the end of the move list.
template<>
ExtMove* generate<QUIET_CHECKS>(const Position& pos, ExtMove* moveList) {

View file

@ -38,7 +38,12 @@ namespace {
constexpr Score WeakLever = S( 0, 56);
constexpr Score WeakUnopposed = S(13, 27);
constexpr Score BlockedStorm[RANK_NB] = {S( 0, 0), S( 0, 0), S( 76, 78), S(-10, 15), S(-7, 10), S(-4, 6), S(-1, 2)};
// Bonus for blocked pawns at 5th or 6th rank
constexpr Score BlockedPawn[2] = { S(-11, -4), S(-3, 4) };
constexpr Score BlockedStorm[RANK_NB] = {
S(0, 0), S(0, 0), S(76, 78), S(-10, 15), S(-7, 10), S(-4, 6), S(-1, 2)
};
// Connected pawn bonus
constexpr int Connected[RANK_NB] = { 0, 7, 8, 12, 29, 48, 86 };
@ -143,7 +148,7 @@ namespace {
// Score this pawn
if (support | phalanx)
{
int v = Connected[r] * (4 + 2 * bool(phalanx) - 2 * bool(opposed) - bool(blocked)) / 2
int v = Connected[r] * (2 + bool(phalanx) - bool(opposed))
+ 21 * popcount(support);
score += make_score(v, v * (r - 2) / 4);
@ -167,6 +172,9 @@ namespace {
if (!support)
score -= Doubled * doubled
+ WeakLever * more_than_one(lever);
if (blocked && r > RANK_4)
score += BlockedPawn[r-4];
}
return score;

View file

@ -119,15 +119,7 @@ void Position::init() {
Zobrist::enpassant[f] = rng.rand<Key>();
for (int cr = NO_CASTLING; cr <= ANY_CASTLING; ++cr)
{
Zobrist::castling[cr] = 0;
Bitboard b = cr;
while (b)
{
Key k = Zobrist::castling[1ULL << pop_lsb(&b)];
Zobrist::castling[cr] ^= k ? k : rng.rand<Key>();
}
}
Zobrist::castling[cr] = rng.rand<Key>();
Zobrist::side = rng.rand<Key>();
Zobrist::noPawns = rng.rand<Key>();
@ -186,9 +178,9 @@ Position& Position::set(const string& fenStr, bool isChess960, StateInfo* si, Th
4) En passant target square (in algebraic notation). If there's no en passant
target square, this is "-". If a pawn has just made a 2-square move, this
is the position "behind" the pawn. This is recorded only if there is a pawn
in position to make an en passant capture, and if there really is a pawn
that might have advanced two squares.
is the position "behind" the pawn. Following X-FEN standard, this is recorded only
if there is a pawn in position to make an en passant capture, and if there really
is a pawn that might have advanced two squares.
5) Halfmove clock. This is the number of halfmoves since the last pawn advance
or capture. This is used to determine if a draw can be claimed under the
@ -278,17 +270,25 @@ Position& Position::set(const string& fenStr, bool isChess960, StateInfo* si, Th
set_castling_right(c, rsq);
}
// 4. En passant square. Ignore if no pawn capture is possible
// 4. En passant square.
// Ignore if square is invalid or not on side to move relative rank 6.
bool enpassant = false;
if ( ((ss >> col) && (col >= 'a' && col <= 'h'))
&& ((ss >> row) && (row == '3' || row == '6')))
&& ((ss >> row) && (row == (sideToMove == WHITE ? '6' : '3'))))
{
st->epSquare = make_square(File(col - 'a'), Rank(row - '1'));
if ( !(attackers_to(st->epSquare) & pieces(sideToMove, PAWN))
|| !(pieces(~sideToMove, PAWN) & (st->epSquare + pawn_push(~sideToMove))))
st->epSquare = SQ_NONE;
// En passant square will be considered only if
// a) side to move have a pawn threatening epSquare
// b) there is an enemy pawn in front of epSquare
// c) there is no piece on epSquare or behind epSquare
enpassant = pawn_attacks_bb(~sideToMove, st->epSquare) & pieces(sideToMove, PAWN)
&& (pieces(~sideToMove, PAWN) & (st->epSquare + pawn_push(~sideToMove)))
&& !(pieces() & (st->epSquare | (st->epSquare + pawn_push(sideToMove))));
}
else
if (!enpassant)
st->epSquare = SQ_NONE;
// 5-6. Halfmove clock and fullmove number
@ -851,9 +851,9 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
// Update castling rights if needed
if (st->castlingRights && (castlingRightsMask[from] | castlingRightsMask[to]))
{
int cr = castlingRightsMask[from] | castlingRightsMask[to];
k ^= Zobrist::castling[st->castlingRights & cr];
st->castlingRights &= ~cr;
k ^= Zobrist::castling[st->castlingRights];
st->castlingRights &= ~(castlingRightsMask[from] | castlingRightsMask[to]);
k ^= Zobrist::castling[st->castlingRights];
}
// Move the piece. The tricky Chess960 castling is handled earlier

View file

@ -92,7 +92,7 @@ constexpr Score PBonus[RANK_NB][FILE_NB] =
{ S( 3,-10), S( 3, -6), S( 10, 10), S( 19, 0), S( 16, 14), S( 19, 7), S( 7, -5), S( -5,-19) },
{ S( -9,-10), S(-15,-10), S( 11,-10), S( 15, 4), S( 32, 4), S( 22, 3), S( 5, -6), S(-22, -4) },
{ S( -4, 6), S(-23, -2), S( 6, -8), S( 20, -4), S( 40,-13), S( 17,-12), S( 4,-10), S( -8, -9) },
{ S( 13, 9), S( 0, 4), S(-13, 3), S( 1,-12), S( 11,-12), S( -2, -6), S(-13, 13), S( 5, 8) },
{ S( 13, 10), S( 0, 5), S(-13, 4), S( 1, -5), S( 11, -5), S( -2, -5), S(-13, 14), S( 5, 9) },
{ S( 5, 28), S(-12, 20), S( -7, 21), S( 22, 28), S( -8, 30), S( -5, 7), S(-15, 6), S( -8, 13) },
{ S( -7, 0), S( 7,-11), S( -3, 12), S(-13, 21), S( 5, 25), S(-16, 19), S( 10, 4), S( -8, 7) }
};

View file

@ -263,10 +263,10 @@ void MainThread::search() {
Thread* bestThread = this;
if (int(Options["MultiPV"]) == 1 &&
!Limits.depth &&
!(Skill(Options["Skill Level"]).enabled() || int(Options["UCI_LimitStrength"])) &&
rootMoves[0].pv[0] != MOVE_NONE)
if ( int(Options["MultiPV"]) == 1
&& !Limits.depth
&& !(Skill(Options["Skill Level"]).enabled() || int(Options["UCI_LimitStrength"]))
&& rootMoves[0].pv[0] != MOVE_NONE)
bestThread = Threads.get_best_thread();
bestPreviousScore = bestThread->rootMoves[0].score;
@ -596,7 +596,7 @@ namespace {
Key posKey;
Move ttMove, move, excludedMove, bestMove;
Depth extension, newDepth;
Value bestValue, value, ttValue, eval, maxValue;
Value bestValue, value, ttValue, eval, maxValue, probcutBeta;
bool ttHit, ttPv, formerPv, givesCheck, improving, didLMR, priorCapture;
bool captureOrPromotion, doFullDepthSearch, moveCountPruning,
ttCapture, singularQuietLMR;
@ -662,7 +662,7 @@ namespace {
// search to overwrite a previous full search TT value, so we use a different
// position key in case of an excluded move.
excludedMove = ss->excludedMove;
posKey = pos.key() ^ (Key(excludedMove) << 48); // Isn't a very good hash
posKey = excludedMove == MOVE_NONE ? pos.key() : pos.key() ^ make_key(excludedMove);
tte = TT.probe(posKey, ttHit);
ttValue = ttHit ? value_from_tt(tte->value(), ss->ply, pos.rule50_count()) : VALUE_NONE;
ttMove = rootNode ? thisThread->rootMoves[thisThread->pvIdx].pv[0]
@ -670,7 +670,11 @@ namespace {
ttPv = PvNode || (ttHit && tte->is_pv());
formerPv = ttPv && !PvNode;
if (ttPv && depth > 12 && ss->ply - 1 < MAX_LPH && !priorCapture && is_ok((ss-1)->currentMove))
if ( ttPv
&& depth > 12
&& ss->ply - 1 < MAX_LPH
&& !priorCapture
&& is_ok((ss-1)->currentMove))
thisThread->lowPlyHistory[ss->ply - 1][from_to((ss-1)->currentMove)] << stat_bonus(depth - 5);
// thisThread->ttHitAverage can be used to approximate the running average of ttHit
@ -867,23 +871,33 @@ namespace {
}
}
probcutBeta = beta + 176 - 49 * improving;
// Step 10. ProbCut (~10 Elo)
// If we have a good enough capture and a reduced search returns a value
// much above beta, we can (almost) safely prune the previous move.
if ( !PvNode
&& depth > 4
&& abs(beta) < VALUE_TB_WIN_IN_MAX_PLY)
&& abs(beta) < VALUE_TB_WIN_IN_MAX_PLY
&& !( ttHit
&& tte->depth() >= depth - 3
&& ttValue != VALUE_NONE
&& ttValue < probcutBeta))
{
Value raisedBeta = beta + 176 - 49 * improving;
assert(raisedBeta < VALUE_INFINITE);
MovePicker mp(pos, ttMove, raisedBeta - ss->staticEval, &captureHistory);
if ( ttHit
&& tte->depth() >= depth - 3
&& ttValue != VALUE_NONE
&& ttValue >= probcutBeta
&& ttMove
&& pos.capture_or_promotion(ttMove))
return probcutBeta;
assert(probcutBeta < VALUE_INFINITE);
MovePicker mp(pos, ttMove, probcutBeta - ss->staticEval, &captureHistory);
int probCutCount = 0;
while ( (move = mp.next_move()) != MOVE_NONE
&& probCutCount < 2 + 2 * cutNode
&& !( move == ttMove
&& tte->depth() >= depth - 4
&& ttValue < raisedBeta))
&& probCutCount < 2 + 2 * cutNode)
if (move != excludedMove && pos.legal(move))
{
assert(pos.capture_or_promotion(move));
@ -901,16 +915,21 @@ namespace {
pos.do_move(move, st);
// Perform a preliminary qsearch to verify that the move holds
value = -qsearch<NonPV>(pos, ss+1, -raisedBeta, -raisedBeta+1);
value = -qsearch<NonPV>(pos, ss+1, -probcutBeta, -probcutBeta+1);
// If the qsearch held, perform the regular search
if (value >= raisedBeta)
value = -search<NonPV>(pos, ss+1, -raisedBeta, -raisedBeta+1, depth - 4, !cutNode);
if (value >= probcutBeta)
value = -search<NonPV>(pos, ss+1, -probcutBeta, -probcutBeta+1, depth - 4, !cutNode);
pos.undo_move(move);
if (value >= raisedBeta)
if (value >= probcutBeta)
{
tte->save(posKey, value_to_tt(value, ss->ply), ttPv,
BOUND_LOWER,
depth - 3, move, ss->staticEval);
return value;
}
}
}
@ -1486,8 +1505,8 @@ moves_loop: // When in check, search starts from here
// Initialize a MovePicker object for the current position, and prepare
// to search the moves. Because the depth is <= 0 here, only captures,
// queen promotions and checks (only if depth >= DEPTH_QS_CHECKS) will
// be generated.
// queen and checking knight promotions, and other checks(only if depth >= DEPTH_QS_CHECKS)
// will be generated.
MovePicker mp(pos, ttMove, depth, &thisThread->mainHistory,
&thisThread->captureHistory,
contHist,

View file

@ -501,6 +501,11 @@ inline PieceNumber& operator--(PieceNumber& d) { return d = PieceNumber(int8_t(d
constexpr bool is_ok(PieceNumber pn) { return pn < PIECE_NUMBER_NB; }
#endif // defined(EVAL_NNUE) || defined(EVAL_LEARN)
/// Based on a congruential pseudo random number generator
constexpr Key make_key(uint64_t seed) {
return seed * 6364136223846793005ULL + 1442695040888963407ULL;
}
#endif // #ifndef TYPES_H_INCLUDED
#include "tune.h" // Global visibility to tuning setup