mirror of
https://github.com/sockspls/badfish
synced 2025-04-30 08:43:09 +00:00
Merge branch 'master' into sf-nnue-update
This commit is contained in:
commit
db0615eed9
11 changed files with 177 additions and 134 deletions
|
@ -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.
|
||||
|
|
|
@ -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"
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
103
src/evaluate.cpp
103
src/evaluate.cpp
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) }
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue