mirror of
https://github.com/peterosterlund2/droidfish.git
synced 2024-11-27 06:10:28 +01:00
DroidFish: Update to stockfish 9.
This commit is contained in:
parent
e75d83de94
commit
1404bdf264
|
@ -2,7 +2,7 @@
|
|||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
||||
Copyright (C) 2015-2017 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
|
||||
Stockfish is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
||||
Copyright (C) 2015-2017 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
|
||||
Stockfish is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -111,7 +111,7 @@ namespace {
|
|||
ksq[WHITE] = Square((idx >> 0) & 0x3F);
|
||||
ksq[BLACK] = Square((idx >> 6) & 0x3F);
|
||||
us = Color ((idx >> 12) & 0x01);
|
||||
psq = make_square(File((idx >> 13) & 0x3), RANK_7 - Rank((idx >> 15) & 0x7));
|
||||
psq = make_square(File((idx >> 13) & 0x3), Rank(RANK_7 - ((idx >> 15) & 0x7)));
|
||||
|
||||
// Check if two pieces are on the same square or if a king can be captured
|
||||
if ( distance(ksq[WHITE], ksq[BLACK]) <= 1
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
||||
Copyright (C) 2015-2017 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
|
||||
Stockfish is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -54,7 +54,7 @@ namespace {
|
|||
Bitboard RookTable[0x19000]; // To store rook attacks
|
||||
Bitboard BishopTable[0x1480]; // To store bishop attacks
|
||||
|
||||
void init_magics(Bitboard table[], Magic magics[], Square deltas[]);
|
||||
void init_magics(Bitboard table[], Magic magics[], Direction directions[]);
|
||||
|
||||
// bsf_index() returns the index into BSFTable[] to look up the bitscan. Uses
|
||||
// Matt Taylor's folding for 32 bit case, extended to 64 bit by Kim Walisch.
|
||||
|
@ -188,7 +188,7 @@ void Bitboards::init() {
|
|||
for (Square s = SQ_A1; s <= SQ_H8; ++s)
|
||||
for (int i = 0; steps[pt][i]; ++i)
|
||||
{
|
||||
Square to = s + Square(c == WHITE ? steps[pt][i] : -steps[pt][i]);
|
||||
Square to = s + Direction(c == WHITE ? steps[pt][i] : -steps[pt][i]);
|
||||
|
||||
if (is_ok(to) && distance(s, to) < 3)
|
||||
{
|
||||
|
@ -199,11 +199,11 @@ void Bitboards::init() {
|
|||
}
|
||||
}
|
||||
|
||||
Square RookDeltas[] = { NORTH, EAST, SOUTH, WEST };
|
||||
Square BishopDeltas[] = { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST };
|
||||
Direction RookDirections[] = { NORTH, EAST, SOUTH, WEST };
|
||||
Direction BishopDirections[] = { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST };
|
||||
|
||||
init_magics(RookTable, RookMagics, RookDeltas);
|
||||
init_magics(BishopTable, BishopMagics, BishopDeltas);
|
||||
init_magics(RookTable, RookMagics, RookDirections);
|
||||
init_magics(BishopTable, BishopMagics, BishopDirections);
|
||||
|
||||
for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1)
|
||||
{
|
||||
|
@ -225,14 +225,14 @@ void Bitboards::init() {
|
|||
|
||||
namespace {
|
||||
|
||||
Bitboard sliding_attack(Square deltas[], Square sq, Bitboard occupied) {
|
||||
Bitboard sliding_attack(Direction directions[], Square sq, Bitboard occupied) {
|
||||
|
||||
Bitboard attack = 0;
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
for (Square s = sq + deltas[i];
|
||||
is_ok(s) && distance(s, s - deltas[i]) == 1;
|
||||
s += deltas[i])
|
||||
for (Square s = sq + directions[i];
|
||||
is_ok(s) && distance(s, s - directions[i]) == 1;
|
||||
s += directions[i])
|
||||
{
|
||||
attack |= s;
|
||||
|
||||
|
@ -249,7 +249,7 @@ namespace {
|
|||
// chessprogramming.wikispaces.com/Magic+Bitboards. In particular, here we
|
||||
// use the so called "fancy" approach.
|
||||
|
||||
void init_magics(Bitboard table[], Magic magics[], Square deltas[]) {
|
||||
void init_magics(Bitboard table[], Magic magics[], Direction directions[]) {
|
||||
|
||||
// Optimal PRNG seeds to pick the correct magics in the shortest time
|
||||
int seeds[][RANK_NB] = { { 8977, 44560, 54343, 38998, 5731, 95205, 104912, 17020 },
|
||||
|
@ -269,7 +269,7 @@ namespace {
|
|||
// the number of 1s of the mask. Hence we deduce the size of the shift to
|
||||
// apply to the 64 or 32 bits word to get the index.
|
||||
Magic& m = magics[s];
|
||||
m.mask = sliding_attack(deltas, s, 0) & ~edges;
|
||||
m.mask = sliding_attack(directions, s, 0) & ~edges;
|
||||
m.shift = (Is64Bit ? 64 : 32) - popcount(m.mask);
|
||||
|
||||
// Set the offset for the attacks table of the square. We have individual
|
||||
|
@ -281,7 +281,7 @@ namespace {
|
|||
b = size = 0;
|
||||
do {
|
||||
occupancy[size] = b;
|
||||
reference[size] = sliding_attack(deltas, s, b);
|
||||
reference[size] = sliding_attack(directions, s, b);
|
||||
|
||||
if (HasPext)
|
||||
m.attacks[pext(b, m.mask)] = reference[size];
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
||||
Copyright (C) 2015-2017 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
|
||||
Stockfish is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -126,11 +126,10 @@ inline Bitboard& operator^=(Bitboard& b, Square s) {
|
|||
return b ^= SquareBB[s];
|
||||
}
|
||||
|
||||
inline bool more_than_one(Bitboard b) {
|
||||
constexpr bool more_than_one(Bitboard b) {
|
||||
return b & (b - 1);
|
||||
}
|
||||
|
||||
|
||||
/// rank_bb() and file_bb() return a bitboard representing all the squares on
|
||||
/// the given file or rank.
|
||||
|
||||
|
@ -153,8 +152,8 @@ inline Bitboard file_bb(Square s) {
|
|||
|
||||
/// shift() moves a bitboard one step along direction D. Mainly for pawns
|
||||
|
||||
template<Square D>
|
||||
inline Bitboard shift(Bitboard b) {
|
||||
template<Direction D>
|
||||
constexpr Bitboard shift(Bitboard b) {
|
||||
return D == NORTH ? b << 8 : D == SOUTH ? b >> 8
|
||||
: D == NORTH_EAST ? (b & ~FileHBB) << 9 : D == SOUTH_EAST ? (b & ~FileHBB) >> 7
|
||||
: D == NORTH_WEST ? (b & ~FileABB) << 7 : D == SOUTH_WEST ? (b & ~FileABB) >> 9
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
||||
Copyright (C) 2015-2017 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
|
||||
Stockfish is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -524,7 +524,7 @@ ScaleFactor Endgame<KRPKB>::operator()(const Position& pos) const {
|
|||
Square bsq = pos.square<BISHOP>(weakSide);
|
||||
Square psq = pos.square<PAWN>(strongSide);
|
||||
Rank rk = relative_rank(strongSide, psq);
|
||||
Square push = pawn_push(strongSide);
|
||||
Direction push = pawn_push(strongSide);
|
||||
|
||||
// If the pawn is on the 5th rank and the pawn (currently) is on
|
||||
// the same color square as the bishop then there is a chance of
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
||||
Copyright (C) 2015-2017 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
|
||||
Stockfish is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
||||
Copyright (C) 2015-2017 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
|
||||
Stockfish is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -31,12 +31,21 @@
|
|||
|
||||
namespace {
|
||||
|
||||
const Bitboard Center = (FileDBB | FileEBB) & (Rank4BB | Rank5BB);
|
||||
const Bitboard QueenSide = FileABB | FileBBB | FileCBB | FileDBB;
|
||||
const Bitboard CenterFiles = FileCBB | FileDBB | FileEBB | FileFBB;
|
||||
const Bitboard KingSide = FileEBB | FileFBB | FileGBB | FileHBB;
|
||||
|
||||
const Bitboard KingFlank[FILE_NB] = {
|
||||
QueenSide, QueenSide, QueenSide, CenterFiles, CenterFiles, KingSide, KingSide, KingSide
|
||||
};
|
||||
|
||||
namespace Trace {
|
||||
|
||||
enum Tracing {NO_TRACE, TRACE};
|
||||
|
||||
enum Term { // The first 8 entries are for PieceType
|
||||
MATERIAL = 8, IMBALANCE, MOBILITY, THREAT, PASSED, SPACE, TOTAL, TERM_NB
|
||||
MATERIAL = 8, IMBALANCE, MOBILITY, THREAT, PASSED, SPACE, INITIATIVE, TOTAL, TERM_NB
|
||||
};
|
||||
|
||||
double scores[TERM_NB][COLOR_NB][PHASE_NB];
|
||||
|
@ -54,7 +63,7 @@ namespace {
|
|||
|
||||
std::ostream& operator<<(std::ostream& os, Term t) {
|
||||
|
||||
if (t == MATERIAL || t == IMBALANCE || t == Term(PAWN) || t == TOTAL)
|
||||
if (t == MATERIAL || t == IMBALANCE || t == Term(PAWN) || t == INITIATIVE || t == TOTAL)
|
||||
os << " --- --- | --- --- | ";
|
||||
else
|
||||
os << std::setw(5) << scores[t][WHITE][MG] << " "
|
||||
|
@ -88,6 +97,7 @@ namespace {
|
|||
template<Color Us> void initialize();
|
||||
template<Color Us> Score evaluate_king();
|
||||
template<Color Us> Score evaluate_threats();
|
||||
int king_distance(Color c, Square s);
|
||||
template<Color Us> Score evaluate_passed_pawns();
|
||||
template<Color Us> Score evaluate_space();
|
||||
template<Color Us, PieceType Pt> Score evaluate_pieces();
|
||||
|
@ -102,7 +112,8 @@ namespace {
|
|||
Score mobility[COLOR_NB] = { SCORE_ZERO, SCORE_ZERO };
|
||||
|
||||
// attackedBy[color][piece type] is a bitboard representing all squares
|
||||
// attacked by a given color and piece type (can be also ALL_PIECES).
|
||||
// attacked by a given color and piece type. Special "piece types" which are
|
||||
// also calculated are QUEEN_DIAGONAL and ALL_PIECES.
|
||||
Bitboard attackedBy[COLOR_NB][PIECE_TYPE_NB];
|
||||
|
||||
// attackedBy2[color] are the squares attacked by 2 pieces of a given color,
|
||||
|
@ -162,8 +173,8 @@ namespace {
|
|||
// supported by a pawn. If the minor piece occupies an outpost square
|
||||
// then score is doubled.
|
||||
const Score Outpost[][2] = {
|
||||
{ S(22, 6), S(33, 9) }, // Knight
|
||||
{ S( 9, 2), S(14, 4) } // Bishop
|
||||
{ S(22, 6), S(36,12) }, // Knight
|
||||
{ S( 9, 2), S(15, 5) } // Bishop
|
||||
};
|
||||
|
||||
// RookOnFile[semiopen/open] contains bonuses for each rook when there is no
|
||||
|
@ -188,8 +199,8 @@ namespace {
|
|||
// Passed[mg/eg][Rank] contains midgame and endgame bonuses for passed pawns.
|
||||
// We don't use a Score because we process the two components independently.
|
||||
const Value Passed[][RANK_NB] = {
|
||||
{ V(5), V( 5), V(31), V(73), V(166), V(252) },
|
||||
{ V(7), V(14), V(38), V(73), V(166), V(252) }
|
||||
{ V(0), V(5), V( 5), V(31), V(73), V(166), V(252) },
|
||||
{ V(0), V(7), V(14), V(38), V(73), V(166), V(252) }
|
||||
};
|
||||
|
||||
// PassedFile[File] contains a bonus according to the file of a passed pawn
|
||||
|
@ -198,25 +209,29 @@ namespace {
|
|||
S(-20,-12), S( 1, -8), S( 2, 10), S( 9, 10)
|
||||
};
|
||||
|
||||
// Rank factor applied on some bonus for passed pawn on rank 4 or beyond
|
||||
const int RankFactor[RANK_NB] = {0, 0, 0, 2, 6, 11, 16};
|
||||
|
||||
// KingProtector[PieceType-2] contains a bonus according to distance from king
|
||||
const Score KingProtector[] = { S(-3, -5), S(-4, -3), S(-3, 0), S(-1, 1) };
|
||||
|
||||
// Assorted bonuses and penalties used by evaluation
|
||||
const Score MinorBehindPawn = S( 16, 0);
|
||||
const Score BishopPawns = S( 8, 12);
|
||||
const Score RookOnPawn = S( 8, 24);
|
||||
const Score TrappedRook = S( 92, 0);
|
||||
const Score WeakQueen = S( 50, 10);
|
||||
const Score OtherCheck = S( 10, 10);
|
||||
const Score CloseEnemies = S( 7, 0);
|
||||
const Score PawnlessFlank = S( 20, 80);
|
||||
const Score ThreatByHangingPawn = S( 71, 61);
|
||||
const Score ThreatBySafePawn = S(182,175);
|
||||
const Score ThreatByRank = S( 16, 3);
|
||||
const Score Hanging = S( 48, 27);
|
||||
const Score ThreatByPawnPush = S( 38, 22);
|
||||
const Score HinderPassedPawn = S( 7, 0);
|
||||
const Score TrappedBishopA1H1 = S( 50, 50);
|
||||
const Score MinorBehindPawn = S( 16, 0);
|
||||
const Score BishopPawns = S( 8, 12);
|
||||
const Score LongRangedBishop = S( 22, 0);
|
||||
const Score RookOnPawn = S( 8, 24);
|
||||
const Score TrappedRook = S( 92, 0);
|
||||
const Score WeakQueen = S( 50, 10);
|
||||
const Score CloseEnemies = S( 7, 0);
|
||||
const Score PawnlessFlank = S( 20, 80);
|
||||
const Score ThreatBySafePawn = S(192,175);
|
||||
const Score ThreatByRank = S( 16, 3);
|
||||
const Score Hanging = S( 48, 27);
|
||||
const Score WeakUnopposedPawn = S( 5, 25);
|
||||
const Score ThreatByPawnPush = S( 38, 22);
|
||||
const Score ThreatByAttackOnQueen = S( 38, 22);
|
||||
const Score HinderPassedPawn = S( 7, 0);
|
||||
const Score TrappedBishopA1H1 = S( 50, 50);
|
||||
|
||||
#undef S
|
||||
#undef V
|
||||
|
@ -225,10 +240,10 @@ namespace {
|
|||
const int KingAttackWeights[PIECE_TYPE_NB] = { 0, 0, 78, 56, 45, 11 };
|
||||
|
||||
// Penalties for enemy's safe checks
|
||||
const int QueenCheck = 780;
|
||||
const int RookCheck = 880;
|
||||
const int BishopCheck = 435;
|
||||
const int KnightCheck = 790;
|
||||
const int QueenSafeCheck = 780;
|
||||
const int RookSafeCheck = 880;
|
||||
const int BishopSafeCheck = 435;
|
||||
const int KnightSafeCheck = 790;
|
||||
|
||||
// Threshold for lazy and space evaluation
|
||||
const Value LazyThreshold = Value(1500);
|
||||
|
@ -241,9 +256,9 @@ namespace {
|
|||
template<Tracing T> template<Color Us>
|
||||
void Evaluation<T>::initialize() {
|
||||
|
||||
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
||||
const Square Up = (Us == WHITE ? NORTH : SOUTH);
|
||||
const Square Down = (Us == WHITE ? SOUTH : NORTH);
|
||||
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
||||
const Direction Up = (Us == WHITE ? NORTH : SOUTH);
|
||||
const Direction Down = (Us == WHITE ? SOUTH : NORTH);
|
||||
const Bitboard LowRanks = (Us == WHITE ? Rank2BB | Rank3BB: Rank7BB | Rank6BB);
|
||||
|
||||
// Find our pawns on the first two ranks, and those which are blocked
|
||||
|
@ -292,11 +307,14 @@ namespace {
|
|||
|
||||
attackedBy[Us][Pt] = 0;
|
||||
|
||||
if (Pt == QUEEN)
|
||||
attackedBy[Us][QUEEN_DIAGONAL] = 0;
|
||||
|
||||
while ((s = *pl++) != SQ_NONE)
|
||||
{
|
||||
// Find attacked squares, including x-ray attacks for bishops and rooks
|
||||
b = Pt == BISHOP ? attacks_bb<BISHOP>(s, pos.pieces() ^ pos.pieces(Us, QUEEN))
|
||||
: Pt == ROOK ? attacks_bb< ROOK>(s, pos.pieces() ^ pos.pieces(Us, ROOK, QUEEN))
|
||||
b = Pt == BISHOP ? attacks_bb<BISHOP>(s, pos.pieces() ^ pos.pieces(QUEEN))
|
||||
: Pt == ROOK ? attacks_bb< ROOK>(s, pos.pieces() ^ pos.pieces(QUEEN) ^ pos.pieces(Us, ROOK))
|
||||
: pos.attacks_from<Pt>(s);
|
||||
|
||||
if (pos.pinned_pieces(Us) & s)
|
||||
|
@ -305,6 +323,9 @@ namespace {
|
|||
attackedBy2[Us] |= attackedBy[Us][ALL_PIECES] & b;
|
||||
attackedBy[Us][ALL_PIECES] |= attackedBy[Us][Pt] |= b;
|
||||
|
||||
if (Pt == QUEEN)
|
||||
attackedBy[Us][QUEEN_DIAGONAL] |= b & PseudoAttacks[BISHOP][s];
|
||||
|
||||
if (b & kingRing[Them])
|
||||
{
|
||||
kingAttackersCount[Us]++;
|
||||
|
@ -324,12 +345,12 @@ namespace {
|
|||
// Bonus for outpost squares
|
||||
bb = OutpostRanks & ~pe->pawn_attacks_span(Them);
|
||||
if (bb & s)
|
||||
score += Outpost[Pt == BISHOP][!!(attackedBy[Us][PAWN] & s)] * 2;
|
||||
score += Outpost[Pt == BISHOP][bool(attackedBy[Us][PAWN] & s)] * 2;
|
||||
else
|
||||
{
|
||||
bb &= b & ~pos.pieces(Us);
|
||||
if (bb)
|
||||
score += Outpost[Pt == BISHOP][!!(attackedBy[Us][PAWN] & bb)];
|
||||
score += Outpost[Pt == BISHOP][bool(attackedBy[Us][PAWN] & bb)];
|
||||
}
|
||||
|
||||
// Bonus when behind a pawn
|
||||
|
@ -337,10 +358,16 @@ namespace {
|
|||
&& (pos.pieces(PAWN) & (s + pawn_push(Us))))
|
||||
score += MinorBehindPawn;
|
||||
|
||||
// Penalty for pawns on the same color square as the bishop
|
||||
if (Pt == BISHOP)
|
||||
{
|
||||
// Penalty for pawns on the same color square as the bishop
|
||||
score -= BishopPawns * pe->pawns_on_same_color_squares(Us, s);
|
||||
|
||||
// Bonus for bishop on a long diagonal which can "see" both center squares
|
||||
if (more_than_one(Center & (attacks_bb<BISHOP>(s, pos.pieces(PAWN)) | s)))
|
||||
score += LongRangedBishop;
|
||||
}
|
||||
|
||||
// An important Chess960 pattern: A cornered bishop blocked by a friendly
|
||||
// pawn diagonally in front of it is a very serious problem, especially
|
||||
// when that pawn is also blocked.
|
||||
|
@ -348,7 +375,7 @@ namespace {
|
|||
&& pos.is_chess960()
|
||||
&& (s == relative_square(Us, SQ_A1) || s == relative_square(Us, SQ_H1)))
|
||||
{
|
||||
Square d = pawn_push(Us) + (file_of(s) == FILE_A ? EAST : WEST);
|
||||
Direction d = pawn_push(Us) + (file_of(s) == FILE_A ? EAST : WEST);
|
||||
if (pos.piece_on(s + d) == make_piece(Us, PAWN))
|
||||
score -= !pos.empty(s + d + pawn_push(Us)) ? TrappedBishopA1H1 * 4
|
||||
: pos.piece_on(s + d + d) == make_piece(Us, PAWN) ? TrappedBishopA1H1 * 2
|
||||
|
@ -364,7 +391,7 @@ namespace {
|
|||
|
||||
// Bonus when on an open or semi-open file
|
||||
if (pe->semiopen_file(Us, file_of(s)))
|
||||
score += RookOnFile[!!pe->semiopen_file(Them, file_of(s))];
|
||||
score += RookOnFile[bool(pe->semiopen_file(Them, file_of(s)))];
|
||||
|
||||
// Penalty when trapped by the king, even more if the king cannot castle
|
||||
else if (mob <= 3)
|
||||
|
@ -395,25 +422,15 @@ namespace {
|
|||
|
||||
// evaluate_king() assigns bonuses and penalties to a king of a given color
|
||||
|
||||
const Bitboard QueenSide = FileABB | FileBBB | FileCBB | FileDBB;
|
||||
const Bitboard CenterFiles = FileCBB | FileDBB | FileEBB | FileFBB;
|
||||
const Bitboard KingSide = FileEBB | FileFBB | FileGBB | FileHBB;
|
||||
|
||||
const Bitboard KingFlank[FILE_NB] = {
|
||||
QueenSide, QueenSide, QueenSide, CenterFiles, CenterFiles, KingSide, KingSide, KingSide
|
||||
};
|
||||
|
||||
template<Tracing T> template<Color Us>
|
||||
Score Evaluation<T>::evaluate_king() {
|
||||
|
||||
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
||||
const Square Up = (Us == WHITE ? NORTH : SOUTH);
|
||||
const Bitboard Camp = (Us == WHITE ? AllSquares ^ Rank6BB ^ Rank7BB ^ Rank8BB
|
||||
: AllSquares ^ Rank1BB ^ Rank2BB ^ Rank3BB);
|
||||
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
||||
const Bitboard Camp = (Us == WHITE ? AllSquares ^ Rank6BB ^ Rank7BB ^ Rank8BB
|
||||
: AllSquares ^ Rank1BB ^ Rank2BB ^ Rank3BB);
|
||||
|
||||
const Square ksq = pos.square<KING>(Us);
|
||||
Bitboard kingOnlyDefended, undefended, b, b1, b2, safe, other;
|
||||
int kingDanger;
|
||||
Bitboard weak, b, b1, b2, safe, unsafeChecks;
|
||||
|
||||
// King shelter and enemy pawns storm
|
||||
Score score = pe->king_safety<Us>(pos, ksq);
|
||||
|
@ -421,78 +438,65 @@ namespace {
|
|||
// Main king safety evaluation
|
||||
if (kingAttackersCount[Them] > (1 - pos.count<QUEEN>(Them)))
|
||||
{
|
||||
// Find the attacked squares which are defended only by our king...
|
||||
kingOnlyDefended = attackedBy[Them][ALL_PIECES]
|
||||
& attackedBy[Us][KING]
|
||||
& ~attackedBy2[Us];
|
||||
// Attacked squares defended at most once by our queen or king
|
||||
weak = attackedBy[Them][ALL_PIECES]
|
||||
& ~attackedBy2[Us]
|
||||
& (attackedBy[Us][KING] | attackedBy[Us][QUEEN] | ~attackedBy[Us][ALL_PIECES]);
|
||||
|
||||
// ... and those which are not defended at all in the larger king ring
|
||||
undefended = attackedBy[Them][ALL_PIECES]
|
||||
& ~attackedBy[Us][ALL_PIECES]
|
||||
& kingRing[Us]
|
||||
& ~pos.pieces(Them);
|
||||
|
||||
// Initialize the 'kingDanger' variable, which will be transformed
|
||||
// later into a king danger score. The initial value is based on the
|
||||
// number and types of the enemy's attacking pieces, the number of
|
||||
// attacked and weak squares around our king, the absence of queen and
|
||||
// the quality of the pawn shelter (current 'score' value).
|
||||
kingDanger = kingAttackersCount[Them] * kingAttackersWeight[Them]
|
||||
+ 102 * kingAdjacentZoneAttacksCount[Them]
|
||||
+ 191 * popcount(kingOnlyDefended | undefended)
|
||||
+ 143 * !!pos.pinned_pieces(Us)
|
||||
- 848 * !pos.count<QUEEN>(Them)
|
||||
- 9 * mg_value(score) / 8
|
||||
+ 40;
|
||||
int kingDanger = unsafeChecks = 0;
|
||||
|
||||
// Analyse the safe enemy's checks which are possible on next move
|
||||
safe = ~pos.pieces(Them);
|
||||
safe &= ~attackedBy[Us][ALL_PIECES] | (kingOnlyDefended & attackedBy2[Them]);
|
||||
safe &= ~attackedBy[Us][ALL_PIECES] | (weak & attackedBy2[Them]);
|
||||
|
||||
b1 = pos.attacks_from< ROOK>(ksq);
|
||||
b2 = pos.attacks_from<BISHOP>(ksq);
|
||||
b1 = attacks_bb<ROOK >(ksq, pos.pieces() ^ pos.pieces(Us, QUEEN));
|
||||
b2 = attacks_bb<BISHOP>(ksq, pos.pieces() ^ pos.pieces(Us, QUEEN));
|
||||
|
||||
// Enemy queen safe checks
|
||||
if ((b1 | b2) & attackedBy[Them][QUEEN] & safe)
|
||||
kingDanger += QueenCheck;
|
||||
if ((b1 | b2) & attackedBy[Them][QUEEN] & safe & ~attackedBy[Us][QUEEN])
|
||||
kingDanger += QueenSafeCheck;
|
||||
|
||||
// For minors and rooks, also consider the square safe if attacked twice,
|
||||
// and only defended by our queen.
|
||||
safe |= attackedBy2[Them]
|
||||
& ~(attackedBy2[Us] | pos.pieces(Them))
|
||||
& attackedBy[Us][QUEEN];
|
||||
b1 &= attackedBy[Them][ROOK];
|
||||
b2 &= attackedBy[Them][BISHOP];
|
||||
|
||||
// Some other potential checks are also analysed, even from squares
|
||||
// currently occupied by the opponent own pieces, as long as the square
|
||||
// is not attacked by our pawns, and is not occupied by a blocked pawn.
|
||||
other = ~( attackedBy[Us][PAWN]
|
||||
| (pos.pieces(Them, PAWN) & shift<Up>(pos.pieces(PAWN))));
|
||||
// Enemy rooks checks
|
||||
if (b1 & safe)
|
||||
kingDanger += RookSafeCheck;
|
||||
else
|
||||
unsafeChecks |= b1;
|
||||
|
||||
// Enemy rooks safe and other checks
|
||||
if (b1 & attackedBy[Them][ROOK] & safe)
|
||||
kingDanger += RookCheck;
|
||||
// Enemy bishops checks
|
||||
if (b2 & safe)
|
||||
kingDanger += BishopSafeCheck;
|
||||
else
|
||||
unsafeChecks |= b2;
|
||||
|
||||
else if (b1 & attackedBy[Them][ROOK] & other)
|
||||
score -= OtherCheck;
|
||||
|
||||
// Enemy bishops safe and other checks
|
||||
if (b2 & attackedBy[Them][BISHOP] & safe)
|
||||
kingDanger += BishopCheck;
|
||||
|
||||
else if (b2 & attackedBy[Them][BISHOP] & other)
|
||||
score -= OtherCheck;
|
||||
|
||||
// Enemy knights safe and other checks
|
||||
// Enemy knights checks
|
||||
b = pos.attacks_from<KNIGHT>(ksq) & attackedBy[Them][KNIGHT];
|
||||
if (b & safe)
|
||||
kingDanger += KnightCheck;
|
||||
kingDanger += KnightSafeCheck;
|
||||
else
|
||||
unsafeChecks |= b;
|
||||
|
||||
else if (b & other)
|
||||
score -= OtherCheck;
|
||||
// Unsafe or occupied checking squares will also be considered, as long as
|
||||
// the square is in the attacker's mobility area.
|
||||
unsafeChecks &= mobilityArea[Them];
|
||||
|
||||
// Transform the kingDanger units into a Score, and substract it from the evaluation
|
||||
kingDanger += kingAttackersCount[Them] * kingAttackersWeight[Them]
|
||||
+ 102 * kingAdjacentZoneAttacksCount[Them]
|
||||
+ 191 * popcount(kingRing[Us] & weak)
|
||||
+ 143 * popcount(pos.pinned_pieces(Us) | unsafeChecks)
|
||||
- 848 * !pos.count<QUEEN>(Them)
|
||||
- 9 * mg_value(score) / 8
|
||||
+ 40;
|
||||
|
||||
// Transform the kingDanger units into a Score, and subtract it from the evaluation
|
||||
if (kingDanger > 0)
|
||||
{
|
||||
int mobilityDanger = mg_value(mobility[Them] - mobility[Us]);
|
||||
kingDanger = std::max(0, kingDanger + mobilityDanger);
|
||||
score -= make_score(kingDanger * kingDanger / 4096, kingDanger / 16);
|
||||
}
|
||||
}
|
||||
|
||||
// King tropism: firstly, find squares that opponent attacks in our king flank
|
||||
|
@ -526,11 +530,11 @@ namespace {
|
|||
template<Tracing T> template<Color Us>
|
||||
Score Evaluation<T>::evaluate_threats() {
|
||||
|
||||
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
||||
const Square Up = (Us == WHITE ? NORTH : SOUTH);
|
||||
const Square Left = (Us == WHITE ? NORTH_WEST : SOUTH_EAST);
|
||||
const Square Right = (Us == WHITE ? NORTH_EAST : SOUTH_WEST);
|
||||
const Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB);
|
||||
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
||||
const Direction Up = (Us == WHITE ? NORTH : SOUTH);
|
||||
const Direction Left = (Us == WHITE ? NORTH_WEST : SOUTH_EAST);
|
||||
const Direction Right = (Us == WHITE ? NORTH_EAST : SOUTH_WEST);
|
||||
const Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB);
|
||||
|
||||
Bitboard b, weak, defended, stronglyProtected, safeThreats;
|
||||
Score score = SCORE_ZERO;
|
||||
|
@ -546,9 +550,6 @@ namespace {
|
|||
safeThreats = (shift<Right>(b) | shift<Left>(b)) & weak;
|
||||
|
||||
score += ThreatBySafePawn * popcount(safeThreats);
|
||||
|
||||
if (weak ^ safeThreats)
|
||||
score += ThreatByHangingPawn;
|
||||
}
|
||||
|
||||
// Squares strongly protected by the opponent, either because they attack the
|
||||
|
@ -593,6 +594,10 @@ namespace {
|
|||
score += ThreatByKing[more_than_one(b)];
|
||||
}
|
||||
|
||||
// Bonus for opponent unopposed weak pawns
|
||||
if (pos.pieces(Us, ROOK, QUEEN))
|
||||
score += WeakUnopposedPawn * pe->weak_unopposed(Them);
|
||||
|
||||
// Find squares where our pawns can push on the next move
|
||||
b = shift<Up>(pos.pieces(Us, PAWN)) & ~pos.pieces();
|
||||
b |= shift<Up>(b & TRank3BB) & ~pos.pieces();
|
||||
|
@ -608,12 +613,24 @@ namespace {
|
|||
|
||||
score += ThreatByPawnPush * popcount(b);
|
||||
|
||||
// Add a bonus for safe slider attack threats on opponent queen
|
||||
safeThreats = ~pos.pieces(Us) & ~attackedBy2[Them] & attackedBy2[Us];
|
||||
b = (attackedBy[Us][BISHOP] & attackedBy[Them][QUEEN_DIAGONAL])
|
||||
| (attackedBy[Us][ROOK ] & attackedBy[Them][QUEEN] & ~attackedBy[Them][QUEEN_DIAGONAL]);
|
||||
|
||||
score += ThreatByAttackOnQueen * popcount(b & safeThreats);
|
||||
|
||||
if (T)
|
||||
Trace::add(THREAT, Us, score);
|
||||
|
||||
return score;
|
||||
}
|
||||
|
||||
// helper used by evaluate_passed_pawns to cap the distance
|
||||
template<Tracing T>
|
||||
int Evaluation<T>::king_distance(Color c, Square s) {
|
||||
return std::min(distance(pos.square<KING>(c), s), 5);
|
||||
}
|
||||
|
||||
// evaluate_passed_pawns() evaluates the passed pawns and candidate passed
|
||||
// pawns of the given color.
|
||||
|
@ -621,8 +638,8 @@ namespace {
|
|||
template<Tracing T> template<Color Us>
|
||||
Score Evaluation<T>::evaluate_passed_pawns() {
|
||||
|
||||
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
||||
const Square Up = (Us == WHITE ? NORTH : SOUTH);
|
||||
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
||||
const Direction Up = (Us == WHITE ? NORTH : SOUTH);
|
||||
|
||||
Bitboard b, bb, squaresToQueen, defendedSquares, unsafeSquares;
|
||||
Score score = SCORE_ZERO;
|
||||
|
@ -638,8 +655,8 @@ namespace {
|
|||
bb = forward_file_bb(Us, s) & (attackedBy[Them][ALL_PIECES] | pos.pieces(Them));
|
||||
score -= HinderPassedPawn * popcount(bb);
|
||||
|
||||
int r = relative_rank(Us, s) - RANK_2;
|
||||
int rr = r * (r - 1);
|
||||
int r = relative_rank(Us, s);
|
||||
int rr = RankFactor[r];
|
||||
|
||||
Value mbonus = Passed[MG][r], ebonus = Passed[EG][r];
|
||||
|
||||
|
@ -648,12 +665,11 @@ namespace {
|
|||
Square blockSq = s + Up;
|
||||
|
||||
// Adjust bonus based on the king's proximity
|
||||
ebonus += distance(pos.square<KING>(Them), blockSq) * 5 * rr
|
||||
- distance(pos.square<KING>( Us), blockSq) * 2 * rr;
|
||||
ebonus += (king_distance(Them, blockSq) * 5 - king_distance(Us, blockSq) * 2) * rr;
|
||||
|
||||
// If blockSq is not the queening square then consider also a second push
|
||||
if (relative_rank(Us, blockSq) != RANK_8)
|
||||
ebonus -= distance(pos.square<KING>(Us), blockSq + Up) * rr;
|
||||
if (r != RANK_7)
|
||||
ebonus -= king_distance(Us, blockSq + Up) * rr;
|
||||
|
||||
// If the pawn is free to advance, then increase the bonus
|
||||
if (pos.empty(blockSq))
|
||||
|
@ -762,6 +778,9 @@ namespace {
|
|||
// that the endgame score will never change sign after the bonus.
|
||||
int v = ((eg > 0) - (eg < 0)) * std::max(initiative, -abs(eg));
|
||||
|
||||
if (T)
|
||||
Trace::add(INITIATIVE, make_score(0, v));
|
||||
|
||||
return make_score(0, v);
|
||||
}
|
||||
|
||||
|
@ -822,7 +841,7 @@ namespace {
|
|||
// Initialize score by reading the incrementally updated scores included in
|
||||
// the position object (material + piece square tables) and the material
|
||||
// imbalance. Score is computed internally from the white point of view.
|
||||
Score score = pos.psq_score() + me->imbalance();
|
||||
Score score = pos.psq_score() + me->imbalance() + Eval::Contempt;
|
||||
|
||||
// Probe the pawn hash table
|
||||
pe = Pawns::probe(pos);
|
||||
|
@ -880,18 +899,19 @@ namespace {
|
|||
Trace::add(TOTAL, score);
|
||||
}
|
||||
|
||||
return (pos.side_to_move() == WHITE ? v : -v) + Eval::Tempo; // Side to move point of view
|
||||
return pos.side_to_move() == WHITE ? v : -v; // Side to move point of view
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Score Eval::Contempt = SCORE_ZERO;
|
||||
|
||||
/// evaluate() is the evaluator for the outer world. It returns a static evaluation
|
||||
/// of the position from the point of view of the side to move.
|
||||
|
||||
Value Eval::evaluate(const Position& pos)
|
||||
{
|
||||
return Evaluation<>(pos).value();
|
||||
return Evaluation<>(pos).value() + Eval::Tempo;
|
||||
}
|
||||
|
||||
/// trace() is like evaluate(), but instead of returning a value, it returns
|
||||
|
@ -902,7 +922,7 @@ std::string Eval::trace(const Position& pos) {
|
|||
|
||||
std::memset(scores, 0, sizeof(scores));
|
||||
|
||||
Value v = Evaluation<TRACE>(pos).value();
|
||||
Value v = Evaluation<TRACE>(pos).value() + Eval::Tempo;
|
||||
v = pos.side_to_move() == WHITE ? v : -v; // White's point of view
|
||||
|
||||
std::stringstream ss;
|
||||
|
@ -922,6 +942,7 @@ std::string Eval::trace(const Position& pos) {
|
|||
<< " Threats | " << Term(THREAT)
|
||||
<< " Passed pawns | " << Term(PASSED)
|
||||
<< " Space | " << Term(SPACE)
|
||||
<< " Initiative | " << Term(INITIATIVE)
|
||||
<< "----------------+-------------+-------------+-------------\n"
|
||||
<< " Total | " << Term(TOTAL);
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
||||
Copyright (C) 2015-2017 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
|
||||
Stockfish is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -31,6 +31,8 @@ namespace Eval {
|
|||
|
||||
const Value Tempo = Value(20); // Must be visible to search
|
||||
|
||||
extern Score Contempt;
|
||||
|
||||
std::string trace(const Position& pos);
|
||||
|
||||
Value evaluate(const Position& pos);
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
||||
Copyright (C) 2015-2017 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
|
||||
Stockfish is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -45,11 +45,11 @@ int main(int argc, char* argv[]) {
|
|||
Pawns::init();
|
||||
Tablebases::init(Options["SyzygyPath"]);
|
||||
TT.resize(Options["Hash"]);
|
||||
Threads.init(Options["Threads"]);
|
||||
Threads.set(Options["Threads"]);
|
||||
Search::clear(); // After threads are up
|
||||
|
||||
UCI::loop(argc, argv);
|
||||
|
||||
Threads.exit();
|
||||
Threads.set(0);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
||||
Copyright (C) 2015-2017 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
|
||||
Stockfish is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -39,7 +39,7 @@ namespace {
|
|||
{ 32, 255, -3 }, // Knight OUR PIECES
|
||||
{ 0, 104, 4, 0 }, // Bishop
|
||||
{ -26, -2, 47, 105, -149 }, // Rook
|
||||
{-185, 24, 122, 137, -134, 0 } // Queen
|
||||
{-189, 24, 117, 133, -134, -10 } // Queen
|
||||
};
|
||||
|
||||
const int QuadraticTheirs[][PIECE_TYPE_NB] = {
|
||||
|
@ -50,18 +50,7 @@ namespace {
|
|||
{ 9, 63, 0 }, // Knight OUR PIECES
|
||||
{ 59, 65, 42, 0 }, // Bishop
|
||||
{ 46, 39, 24, -24, 0 }, // Rook
|
||||
{ 101, 100, -37, 141, 268, 0 } // Queen
|
||||
};
|
||||
|
||||
// PawnSet[pawn count] contains a bonus/malus indexed by number of pawns
|
||||
const int PawnSet[] = {
|
||||
24, -32, 107, -51, 117, -9, -126, -21, 31
|
||||
};
|
||||
|
||||
// QueenMinorsImbalance[opp_minor_count] is applied when only one side has a queen.
|
||||
// It contains a bonus/malus for the side with the queen.
|
||||
const int QueenMinorsImbalance[13] = {
|
||||
31, -8, -15, -25, -5
|
||||
{ 97, 100, -42, 137, 268, 0 } // Queen
|
||||
};
|
||||
|
||||
// Endgame evaluation and scaling functions are accessed directly and not through
|
||||
|
@ -100,9 +89,9 @@ namespace {
|
|||
|
||||
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
||||
|
||||
int bonus = PawnSet[pieceCount[Us][PAWN]];
|
||||
int bonus = 0;
|
||||
|
||||
// Second-degree polynomial material imbalance by Tord Romstad
|
||||
// Second-degree polynomial material imbalance, by Tord Romstad
|
||||
for (int pt1 = NO_PIECE_TYPE; pt1 <= QUEEN; ++pt1)
|
||||
{
|
||||
if (!pieceCount[Us][pt1])
|
||||
|
@ -117,10 +106,6 @@ namespace {
|
|||
bonus += pieceCount[Us][pt1] * v;
|
||||
}
|
||||
|
||||
// Special handling of Queen vs. Minors
|
||||
if (pieceCount[Us][QUEEN] == 1 && pieceCount[Them][QUEEN] == 0)
|
||||
bonus += QueenMinorsImbalance[pieceCount[Them][KNIGHT] + pieceCount[Them][BISHOP]];
|
||||
|
||||
return bonus;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
||||
Copyright (C) 2015-2017 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
|
||||
Stockfish is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
||||
Copyright (C) 2015-2017 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
|
||||
Stockfish is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -51,7 +51,7 @@ namespace {
|
|||
|
||||
/// Version number. If Version is left empty, then compile date in the format
|
||||
/// DD-MM-YY and show in engine_info.
|
||||
const string Version = "2017-09-06";
|
||||
const string Version = "9";
|
||||
|
||||
/// Our fancy logging facility. The trick here is to replace cin.rdbuf() and
|
||||
/// cout.rdbuf() with two Tie objects that tie cin and cout to a file stream. We
|
||||
|
@ -293,14 +293,6 @@ int get_group(size_t idx) {
|
|||
|
||||
void bindThisThread(size_t idx) {
|
||||
|
||||
// If OS already scheduled us on a different group than 0 then don't overwrite
|
||||
// the choice, eventually we are one of many one-threaded processes running on
|
||||
// some Windows NUMA hardware, for instance in fishtest. To make it simple,
|
||||
// just check if running threads are below a threshold, in this case all this
|
||||
// NUMA machinery is not needed.
|
||||
if (Threads.size() < 8)
|
||||
return;
|
||||
|
||||
// Use only local variables to be thread-safe
|
||||
int group = get_group(idx);
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
||||
Copyright (C) 2015-2017 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
|
||||
Stockfish is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
||||
Copyright (C) 2015-2017 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
|
||||
Stockfish is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -42,8 +42,8 @@ namespace {
|
|||
|
||||
assert(!pos.checkers());
|
||||
|
||||
const Square K = Chess960 ? kto > kfrom ? WEST : EAST
|
||||
: KingSide ? WEST : EAST;
|
||||
const Direction K = Chess960 ? kto > kfrom ? WEST : EAST
|
||||
: KingSide ? WEST : EAST;
|
||||
|
||||
for (Square s = kto; s != kfrom; s += K)
|
||||
if (pos.attackers_to(s) & enemies)
|
||||
|
@ -65,7 +65,7 @@ namespace {
|
|||
}
|
||||
|
||||
|
||||
template<GenType Type, Square D>
|
||||
template<GenType Type, Direction D>
|
||||
ExtMove* make_promotions(ExtMove* moveList, Square to, Square ksq) {
|
||||
|
||||
if (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS)
|
||||
|
@ -94,13 +94,13 @@ namespace {
|
|||
|
||||
// Compute our parametrized parameters at compile time, named according to
|
||||
// the point of view of white side.
|
||||
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
||||
const Bitboard TRank8BB = (Us == WHITE ? Rank8BB : Rank1BB);
|
||||
const Bitboard TRank7BB = (Us == WHITE ? Rank7BB : Rank2BB);
|
||||
const Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB);
|
||||
const Square Up = (Us == WHITE ? NORTH : SOUTH);
|
||||
const Square Right = (Us == WHITE ? NORTH_EAST : SOUTH_WEST);
|
||||
const Square Left = (Us == WHITE ? NORTH_WEST : SOUTH_EAST);
|
||||
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
||||
const Bitboard TRank8BB = (Us == WHITE ? Rank8BB : Rank1BB);
|
||||
const Bitboard TRank7BB = (Us == WHITE ? Rank7BB : Rank2BB);
|
||||
const Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB);
|
||||
const Direction Up = (Us == WHITE ? NORTH : SOUTH);
|
||||
const Direction Right = (Us == WHITE ? NORTH_EAST : SOUTH_WEST);
|
||||
const Direction Left = (Us == WHITE ? NORTH_WEST : SOUTH_EAST);
|
||||
|
||||
Bitboard emptySquares;
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
||||
Copyright (C) 2015-2017 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
|
||||
Stockfish is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -45,7 +45,7 @@ struct ExtMove {
|
|||
|
||||
// Inhibit unwanted implicit conversions to Move
|
||||
// with an ambiguity that yields to a compile error.
|
||||
operator float() const;
|
||||
operator float() const = delete;
|
||||
};
|
||||
|
||||
inline bool operator<(const ExtMove& f, const ExtMove& s) {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
||||
Copyright (C) 2015-2017 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
|
||||
Stockfish is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -68,8 +68,8 @@ namespace {
|
|||
|
||||
/// MovePicker constructor for the main search
|
||||
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh,
|
||||
const PieceToHistory** ch, Move cm, Move* killers_p)
|
||||
: pos(p), mainHistory(mh), contHistory(ch), countermove(cm),
|
||||
const CapturePieceToHistory* cph, const PieceToHistory** ch, Move cm, Move* killers_p)
|
||||
: pos(p), mainHistory(mh), captureHistory(cph), contHistory(ch), countermove(cm),
|
||||
killers{killers_p[0], killers_p[1]}, depth(d){
|
||||
|
||||
assert(d > DEPTH_ZERO);
|
||||
|
@ -80,8 +80,8 @@ MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHist
|
|||
}
|
||||
|
||||
/// MovePicker constructor for quiescence search
|
||||
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh, Square s)
|
||||
: pos(p), mainHistory(mh) {
|
||||
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh, const CapturePieceToHistory* cph, Square s)
|
||||
: pos(p), mainHistory(mh), captureHistory(cph) {
|
||||
|
||||
assert(d <= DEPTH_ZERO);
|
||||
|
||||
|
@ -107,8 +107,8 @@ MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHist
|
|||
|
||||
/// MovePicker constructor for ProbCut: we generate captures with SEE higher
|
||||
/// than or equal to the given threshold.
|
||||
MovePicker::MovePicker(const Position& p, Move ttm, Value th)
|
||||
: pos(p), threshold(th) {
|
||||
MovePicker::MovePicker(const Position& p, Move ttm, Value th, const CapturePieceToHistory* cph)
|
||||
: pos(p), captureHistory(cph), threshold(th) {
|
||||
|
||||
assert(!pos.checkers());
|
||||
|
||||
|
@ -123,7 +123,7 @@ MovePicker::MovePicker(const Position& p, Move ttm, Value th)
|
|||
|
||||
/// score() assigns a numerical value to each move in a list, used for sorting.
|
||||
/// Captures are ordered by Most Valuable Victim (MVV), preferring captures
|
||||
/// near our home rank. Quiets are ordered using the histories.
|
||||
/// with a good history. Quiets are ordered using the histories.
|
||||
template<GenType Type>
|
||||
void MovePicker::score() {
|
||||
|
||||
|
@ -132,7 +132,7 @@ void MovePicker::score() {
|
|||
for (auto& m : *this)
|
||||
if (Type == CAPTURES)
|
||||
m.value = PieceValue[MG][pos.piece_on(to_sq(m))]
|
||||
- Value(200 * relative_rank(pos.side_to_move(), to_sq(m)));
|
||||
+ Value((*captureHistory)[pos.moved_piece(m)][to_sq(m)][type_of(pos.piece_on(to_sq(m)))]);
|
||||
|
||||
else if (Type == QUIETS)
|
||||
m.value = (*mainHistory)[pos.side_to_move()][from_to(m)]
|
||||
|
@ -179,7 +179,7 @@ Move MovePicker::next_move(bool skipQuiets) {
|
|||
move = pick_best(cur++, endMoves);
|
||||
if (move != ttMove)
|
||||
{
|
||||
if (pos.see_ge(move))
|
||||
if (pos.see_ge(move, Value(-55 * (cur-1)->value / 1024)))
|
||||
return move;
|
||||
|
||||
// Losing capture, move it to the beginning of the array
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
||||
Copyright (C) 2015-2017 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
|
||||
Stockfish is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -22,6 +22,7 @@
|
|||
#define MOVEPICK_H_INCLUDED
|
||||
|
||||
#include <array>
|
||||
#include <limits>
|
||||
|
||||
#include "movegen.h"
|
||||
#include "position.h"
|
||||
|
@ -39,7 +40,7 @@ struct StatBoards : public std::array<std::array<T, Size2>, Size1> {
|
|||
void update(T& entry, int bonus, const int D) {
|
||||
|
||||
assert(abs(bonus) <= D); // Ensure range is [-32 * D, 32 * D]
|
||||
assert(abs(32 * D) < INT16_MAX); // Ensure we don't overflow
|
||||
assert(abs(32 * D) < (std::numeric_limits<T>::max)()); // Ensure we don't overflow
|
||||
|
||||
entry += bonus * 32 - entry * abs(bonus) / D;
|
||||
|
||||
|
@ -47,6 +48,26 @@ struct StatBoards : public std::array<std::array<T, Size2>, Size1> {
|
|||
}
|
||||
};
|
||||
|
||||
/// StatCubes is a generic 3-dimensional array used to store various statistics
|
||||
template<int Size1, int Size2, int Size3, typename T = int16_t>
|
||||
struct StatCubes : public std::array<std::array<std::array<T, Size3>, Size2>, Size1> {
|
||||
|
||||
void fill(const T& v) {
|
||||
T* p = &(*this)[0][0][0];
|
||||
std::fill(p, p + sizeof(*this) / sizeof(*p), v);
|
||||
}
|
||||
|
||||
void update(T& entry, int bonus, const int D, const int W) {
|
||||
|
||||
assert(abs(bonus) <= D); // Ensure range is [-W * D, W * D]
|
||||
assert(abs(W * D) < (std::numeric_limits<T>::max)()); // Ensure we don't overflow
|
||||
|
||||
entry += bonus * W - entry * abs(bonus) / D;
|
||||
|
||||
assert(abs(entry) <= W * D);
|
||||
}
|
||||
};
|
||||
|
||||
/// ButterflyBoards are 2 tables (one for each color) indexed by the move's from
|
||||
/// and to squares, see chessprogramming.wikispaces.com/Butterfly+Boards
|
||||
typedef StatBoards<COLOR_NB, int(SQUARE_NB) * int(SQUARE_NB)> ButterflyBoards;
|
||||
|
@ -54,6 +75,9 @@ typedef StatBoards<COLOR_NB, int(SQUARE_NB) * int(SQUARE_NB)> ButterflyBoards;
|
|||
/// PieceToBoards are addressed by a move's [piece][to] information
|
||||
typedef StatBoards<PIECE_NB, SQUARE_NB> PieceToBoards;
|
||||
|
||||
/// CapturePieceToBoards are addressed by a move's [piece][to][captured piece type] information
|
||||
typedef StatCubes<PIECE_NB, SQUARE_NB, PIECE_TYPE_NB> CapturePieceToBoards;
|
||||
|
||||
/// ButterflyHistory records how often quiet moves have been successful or
|
||||
/// unsuccessful during the current search, and is used for reduction and move
|
||||
/// ordering decisions. It uses ButterflyBoards as backing store.
|
||||
|
@ -72,6 +96,14 @@ struct PieceToHistory : public PieceToBoards {
|
|||
}
|
||||
};
|
||||
|
||||
/// CapturePieceToHistory is like PieceToHistory, but is based on CapturePieceToBoards
|
||||
struct CapturePieceToHistory : public CapturePieceToBoards {
|
||||
|
||||
void update(Piece pc, Square to, PieceType captured, int bonus) {
|
||||
StatCubes::update((*this)[pc][to][captured], bonus, 324, 2);
|
||||
}
|
||||
};
|
||||
|
||||
/// CounterMoveHistory stores counter moves indexed by [piece][to] of the previous
|
||||
/// move, see chessprogramming.wikispaces.com/Countermove+Heuristic
|
||||
typedef StatBoards<PIECE_NB, SQUARE_NB, Move> CounterMoveHistory;
|
||||
|
@ -93,9 +125,9 @@ class MovePicker {
|
|||
public:
|
||||
MovePicker(const MovePicker&) = delete;
|
||||
MovePicker& operator=(const MovePicker&) = delete;
|
||||
MovePicker(const Position&, Move, Value);
|
||||
MovePicker(const Position&, Move, Depth, const ButterflyHistory*, Square);
|
||||
MovePicker(const Position&, Move, Depth, const ButterflyHistory*, const PieceToHistory**, Move, Move*);
|
||||
MovePicker(const Position&, Move, Value, const CapturePieceToHistory*);
|
||||
MovePicker(const Position&, Move, Depth, const ButterflyHistory*, const CapturePieceToHistory*, Square);
|
||||
MovePicker(const Position&, Move, Depth, const ButterflyHistory*, const CapturePieceToHistory*, const PieceToHistory**, Move, Move*);
|
||||
Move next_move(bool skipQuiets = false);
|
||||
|
||||
private:
|
||||
|
@ -105,6 +137,7 @@ private:
|
|||
|
||||
const Position& pos;
|
||||
const ButterflyHistory* mainHistory;
|
||||
const CapturePieceToHistory* captureHistory;
|
||||
const PieceToHistory** contHistory;
|
||||
Move ttMove, countermove, killers[2];
|
||||
ExtMove *cur, *endMoves, *endBadCaptures;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
||||
Copyright (C) 2015-2017 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
|
||||
Stockfish is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -31,11 +31,11 @@ namespace {
|
|||
#define V Value
|
||||
#define S(mg, eg) make_score(mg, eg)
|
||||
|
||||
// Isolated pawn penalty by opposed flag
|
||||
const Score Isolated[] = { S(27, 30), S(13, 18) };
|
||||
// Isolated pawn penalty
|
||||
const Score Isolated = S(13, 18);
|
||||
|
||||
// Backward pawn penalty by opposed flag
|
||||
const Score Backward[] = { S(40, 26), S(24, 12) };
|
||||
// Backward pawn penalty
|
||||
const Score Backward = S(24, 12);
|
||||
|
||||
// Connected pawn bonus by opposed, phalanx, #support and rank
|
||||
Score Connected[2][2][3][RANK_NB];
|
||||
|
@ -43,12 +43,6 @@ namespace {
|
|||
// Doubled pawn penalty
|
||||
const Score Doubled = S(18, 38);
|
||||
|
||||
// Lever bonus by rank
|
||||
const Score Lever[RANK_NB] = {
|
||||
S( 0, 0), S( 0, 0), S(0, 0), S(0, 0),
|
||||
S(17, 16), S(33, 32), S(0, 0), S(0, 0)
|
||||
};
|
||||
|
||||
// Weakness of our pawn shelter in front of the king by [isKingFile][distance from edge][rank].
|
||||
// RANK_1 = 0 is used for files where we have no pawns or our pawn is behind our king.
|
||||
const Value ShelterWeakness[][int(FILE_NB) / 2][RANK_NB] = {
|
||||
|
@ -94,10 +88,10 @@ namespace {
|
|||
template<Color Us>
|
||||
Score evaluate(const Position& pos, Pawns::Entry* e) {
|
||||
|
||||
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
||||
const Square Up = (Us == WHITE ? NORTH : SOUTH);
|
||||
const Square Right = (Us == WHITE ? NORTH_EAST : SOUTH_WEST);
|
||||
const Square Left = (Us == WHITE ? NORTH_WEST : SOUTH_EAST);
|
||||
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
||||
const Direction Up = (Us == WHITE ? NORTH : SOUTH);
|
||||
const Direction Right = (Us == WHITE ? NORTH_EAST : SOUTH_WEST);
|
||||
const Direction Left = (Us == WHITE ? NORTH_WEST : SOUTH_EAST);
|
||||
|
||||
Bitboard b, neighbours, stoppers, doubled, supported, phalanx;
|
||||
Bitboard lever, leverPush;
|
||||
|
@ -109,7 +103,7 @@ namespace {
|
|||
Bitboard ourPawns = pos.pieces( Us, PAWN);
|
||||
Bitboard theirPawns = pos.pieces(Them, PAWN);
|
||||
|
||||
e->passedPawns[Us] = e->pawnAttacksSpan[Us] = 0;
|
||||
e->passedPawns[Us] = e->pawnAttacksSpan[Us] = e->weakUnopposed[Us] = 0;
|
||||
e->semiopenFiles[Us] = 0xFF;
|
||||
e->kingSquares[Us] = SQ_NONE;
|
||||
e->pawnAttacks[Us] = shift<Right>(ourPawns) | shift<Left>(ourPawns);
|
||||
|
@ -174,19 +168,16 @@ namespace {
|
|||
|
||||
// Score this pawn
|
||||
if (supported | phalanx)
|
||||
score += Connected[opposed][!!phalanx][popcount(supported)][relative_rank(Us, s)];
|
||||
score += Connected[opposed][bool(phalanx)][popcount(supported)][relative_rank(Us, s)];
|
||||
|
||||
else if (!neighbours)
|
||||
score -= Isolated[opposed];
|
||||
score -= Isolated, e->weakUnopposed[Us] += !opposed;
|
||||
|
||||
else if (backward)
|
||||
score -= Backward[opposed];
|
||||
score -= Backward, e->weakUnopposed[Us] += !opposed;
|
||||
|
||||
if (doubled && !supported)
|
||||
score -= Doubled;
|
||||
|
||||
if (lever)
|
||||
score += Lever[relative_rank(Us, s)];
|
||||
}
|
||||
|
||||
return score;
|
||||
|
@ -254,7 +245,7 @@ Value Entry::shelter_storm(const Position& pos, Square ksq) {
|
|||
Value safety = MaxSafetyBonus;
|
||||
File center = std::max(FILE_B, std::min(FILE_G, file_of(ksq)));
|
||||
|
||||
for (File f = center - File(1); f <= center + File(1); ++f)
|
||||
for (File f = File(center - 1); f <= File(center + 1); ++f)
|
||||
{
|
||||
b = ourPawns & file_bb(f);
|
||||
Rank rkUs = b ? relative_rank(Us, backmost_sq(Us, b)) : RANK_1;
|
||||
|
@ -262,7 +253,7 @@ Value Entry::shelter_storm(const Position& pos, Square ksq) {
|
|||
b = theirPawns & file_bb(f);
|
||||
Rank rkThem = b ? relative_rank(Us, frontmost_sq(Them, b)) : RANK_1;
|
||||
|
||||
int d = std::min(f, FILE_H - f);
|
||||
int d = std::min(f, ~f);
|
||||
safety -= ShelterWeakness[f == file_of(ksq)][d][rkUs]
|
||||
+ StormDanger
|
||||
[f == file_of(ksq) && rkThem == relative_rank(Us, ksq) + 1 ? BlockedByKing :
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
||||
Copyright (C) 2015-2017 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
|
||||
Stockfish is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -37,6 +37,7 @@ struct Entry {
|
|||
Bitboard pawn_attacks(Color c) const { return pawnAttacks[c]; }
|
||||
Bitboard passed_pawns(Color c) const { return passedPawns[c]; }
|
||||
Bitboard pawn_attacks_span(Color c) const { return pawnAttacksSpan[c]; }
|
||||
int weak_unopposed(Color c) const { return weakUnopposed[c]; }
|
||||
int pawn_asymmetry() const { return asymmetry; }
|
||||
int open_files() const { return openFiles; }
|
||||
|
||||
|
@ -49,7 +50,7 @@ struct Entry {
|
|||
}
|
||||
|
||||
int pawns_on_same_color_squares(Color c, Square s) const {
|
||||
return pawnsOnSquares[c][!!(DarkSquares & s)];
|
||||
return pawnsOnSquares[c][bool(DarkSquares & s)];
|
||||
}
|
||||
|
||||
template<Color Us>
|
||||
|
@ -71,6 +72,7 @@ struct Entry {
|
|||
Bitboard pawnAttacksSpan[COLOR_NB];
|
||||
Square kingSquares[COLOR_NB];
|
||||
Score kingSafety[COLOR_NB];
|
||||
int weakUnopposed[COLOR_NB];
|
||||
int castlingRights[COLOR_NB];
|
||||
int semiopenFiles[COLOR_NB];
|
||||
int pawnsOnSquares[COLOR_NB][COLOR_NB]; // [color][light/dark squares]
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
||||
Copyright (C) 2015-2017 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
|
||||
Stockfish is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -211,10 +211,10 @@ Position& Position::set(const string& fenStr, bool isChess960, StateInfo* si, Th
|
|||
while ((ss >> token) && !isspace(token))
|
||||
{
|
||||
if (isdigit(token))
|
||||
sq += Square(token - '0'); // Advance the given number of files
|
||||
sq += (token - '0') * EAST; // Advance the given number of files
|
||||
|
||||
else if (token == '/')
|
||||
sq -= Square(16);
|
||||
sq += 2 * SOUTH;
|
||||
|
||||
else if ((idx = PieceToChar.find(token)) != string::npos)
|
||||
{
|
||||
|
@ -272,7 +272,7 @@ Position& Position::set(const string& fenStr, bool isChess960, StateInfo* si, Th
|
|||
// 5-6. Halfmove clock and fullmove number
|
||||
ss >> std::skipws >> st->rule50 >> gamePly;
|
||||
|
||||
// Convert from fullmove starting from 1 to ply starting from 0,
|
||||
// Convert from fullmove starting from 1 to gamePly starting from 0,
|
||||
// handle also common incorrect FEN with fullmove = 0.
|
||||
gamePly = std::max(2 * (gamePly - 1), 0) + (sideToMove == BLACK);
|
||||
|
||||
|
@ -787,7 +787,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
|
|||
if ( (int(to) ^ int(from)) == 16
|
||||
&& (attacks_from<PAWN>(to - pawn_push(us), us) & pieces(them, PAWN)))
|
||||
{
|
||||
st->epSquare = (from + to) / 2;
|
||||
st->epSquare = to - pawn_push(us);
|
||||
k ^= Zobrist::enpassant[file_of(st->epSquare)];
|
||||
}
|
||||
|
||||
|
@ -1003,17 +1003,21 @@ bool Position::see_ge(Move m, Value threshold) const {
|
|||
Value balance; // Values of the pieces taken by us minus opponent's ones
|
||||
Bitboard occupied, stmAttackers;
|
||||
|
||||
balance = PieceValue[MG][piece_on(to)];
|
||||
// The opponent may be able to recapture so this is the best result
|
||||
// we can hope for.
|
||||
balance = PieceValue[MG][piece_on(to)] - threshold;
|
||||
|
||||
if (balance < threshold)
|
||||
if (balance < VALUE_ZERO)
|
||||
return false;
|
||||
|
||||
// Now assume the worst possible result: that the opponent can
|
||||
// capture our piece for free.
|
||||
balance -= PieceValue[MG][nextVictim];
|
||||
|
||||
if (balance >= threshold) // Always true if nextVictim == KING
|
||||
if (balance >= VALUE_ZERO) // Always true if nextVictim == KING
|
||||
return true;
|
||||
|
||||
bool relativeStm = true; // True if the opponent is to move
|
||||
bool opponentToMove = true;
|
||||
occupied = pieces() ^ from ^ to;
|
||||
|
||||
// Find all attackers to the destination square, with the moving piece removed,
|
||||
|
@ -1022,6 +1026,12 @@ bool Position::see_ge(Move m, Value threshold) const {
|
|||
|
||||
while (true)
|
||||
{
|
||||
// The balance is negative only because we assumed we could win
|
||||
// the last piece for free. We are truly winning only if we can
|
||||
// win the last piece _cheaply enough_. Test if we can actually
|
||||
// do this otherwise "give up".
|
||||
assert(balance < VALUE_ZERO);
|
||||
|
||||
stmAttackers = attackers & pieces(stm);
|
||||
|
||||
// Don't allow pinned pieces to attack pieces except the king as long all
|
||||
|
@ -1029,25 +1039,40 @@ bool Position::see_ge(Move m, Value threshold) const {
|
|||
if (!(st->pinnersForKing[stm] & ~occupied))
|
||||
stmAttackers &= ~st->blockersForKing[stm];
|
||||
|
||||
// If we have no more attackers we must give up
|
||||
if (!stmAttackers)
|
||||
return relativeStm;
|
||||
break;
|
||||
|
||||
// Locate and remove the next least valuable attacker
|
||||
nextVictim = min_attacker<PAWN>(byTypeBB, to, stmAttackers, occupied, attackers);
|
||||
|
||||
if (nextVictim == KING)
|
||||
return relativeStm == bool(attackers & pieces(~stm));
|
||||
{
|
||||
// Our only attacker is the king. If the opponent still has
|
||||
// attackers we must give up. Otherwise we make the move and
|
||||
// (having no more attackers) the opponent must give up.
|
||||
if (!(attackers & pieces(~stm)))
|
||||
opponentToMove = !opponentToMove;
|
||||
break;
|
||||
}
|
||||
|
||||
balance += relativeStm ? PieceValue[MG][nextVictim]
|
||||
: -PieceValue[MG][nextVictim];
|
||||
// Assume the opponent can win the next piece for free and switch sides
|
||||
balance += PieceValue[MG][nextVictim];
|
||||
opponentToMove = !opponentToMove;
|
||||
|
||||
relativeStm = !relativeStm;
|
||||
|
||||
if (relativeStm == (balance >= threshold))
|
||||
return relativeStm;
|
||||
// If balance is negative after receiving a free piece then give up
|
||||
if (balance < VALUE_ZERO)
|
||||
break;
|
||||
|
||||
// Complete the process of switching sides. The first line swaps
|
||||
// all negative numbers with non-negative numbers. The compiler
|
||||
// probably knows that it is just the bitwise negation ~balance.
|
||||
balance = -balance-1;
|
||||
stm = ~stm;
|
||||
}
|
||||
|
||||
// If the opponent gave up we win, otherwise we lose.
|
||||
return opponentToMove;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1071,11 +1096,10 @@ bool Position::is_draw(int ply) const {
|
|||
{
|
||||
stp = stp->previous->previous;
|
||||
|
||||
// At root position ply is 1, so return a draw score if a position
|
||||
// repeats once earlier but strictly after the root, or repeats twice
|
||||
// before or at the root.
|
||||
// Return a draw score if a position repeats once earlier but strictly
|
||||
// after the root, or repeats twice before or at the root.
|
||||
if ( stp->key == st->key
|
||||
&& ++cnt + (ply - 1 > i) == 2)
|
||||
&& ++cnt + (ply > i) == 2)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
||||
Copyright (C) 2015-2017 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
|
||||
Stockfish is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
||||
Copyright (C) 2015-2017 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
|
||||
Stockfish is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -116,7 +116,7 @@ void init() {
|
|||
|
||||
for (Square s = SQ_A1; s <= SQ_H8; ++s)
|
||||
{
|
||||
File f = std::min(file_of(s), FILE_H - file_of(s));
|
||||
File f = std::min(file_of(s), ~file_of(s));
|
||||
psq[ pc][ s] = v + Bonus[pc][rank_of(s)][f];
|
||||
psq[~pc][~s] = -psq[pc][s];
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
||||
Copyright (C) 2015-2017 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
|
||||
Stockfish is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -67,8 +67,7 @@ namespace {
|
|||
const int skipPhase[] = { 0, 1, 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 6, 7 };
|
||||
|
||||
// Razoring and futility margin based on depth
|
||||
// razor_margin[0] is unused as long as depth >= ONE_PLY in search
|
||||
const int razor_margin[] = { 0, 570, 603, 554 };
|
||||
const int razor_margin = 600;
|
||||
Value futility_margin(Depth d) { return Value(150 * d / ONE_PLY); }
|
||||
|
||||
// Futility and reductions lookup tables, initialized at startup
|
||||
|
@ -87,58 +86,15 @@ namespace {
|
|||
|
||||
// Skill structure is used to implement strength limit
|
||||
struct Skill {
|
||||
Skill(int l) : level(l) {}
|
||||
explicit Skill(int l) : level(l) {}
|
||||
bool enabled() const { return level < 20; }
|
||||
bool time_to_pick(Depth depth) const { return depth / ONE_PLY == 1 + level; }
|
||||
Move best_move(size_t multiPV) { return best ? best : pick_best(multiPV); }
|
||||
Move pick_best(size_t multiPV);
|
||||
|
||||
int level;
|
||||
Move best = MOVE_NONE;
|
||||
};
|
||||
|
||||
// EasyMoveManager structure is used to detect an 'easy move'. When the PV is stable
|
||||
// across multiple search iterations, we can quickly return the best move.
|
||||
struct EasyMoveManager {
|
||||
|
||||
void clear() {
|
||||
stableCnt = 0;
|
||||
expectedPosKey = 0;
|
||||
pv[0] = pv[1] = pv[2] = MOVE_NONE;
|
||||
}
|
||||
|
||||
Move get(Key key) const {
|
||||
return expectedPosKey == key ? pv[2] : MOVE_NONE;
|
||||
}
|
||||
|
||||
void update(Position& pos, const std::vector<Move>& newPv) {
|
||||
|
||||
assert(newPv.size() >= 3);
|
||||
|
||||
// Keep track of how many times in a row the 3rd ply remains stable
|
||||
stableCnt = (newPv[2] == pv[2]) ? stableCnt + 1 : 0;
|
||||
|
||||
if (!std::equal(newPv.begin(), newPv.begin() + 3, pv))
|
||||
{
|
||||
std::copy(newPv.begin(), newPv.begin() + 3, pv);
|
||||
|
||||
StateInfo st[2];
|
||||
pos.do_move(newPv[0], st[0]);
|
||||
pos.do_move(newPv[1], st[1]);
|
||||
expectedPosKey = pos.key();
|
||||
pos.undo_move(newPv[1]);
|
||||
pos.undo_move(newPv[0]);
|
||||
}
|
||||
}
|
||||
|
||||
Key expectedPosKey;
|
||||
int stableCnt;
|
||||
Move pv[3];
|
||||
};
|
||||
|
||||
EasyMoveManager EasyMove;
|
||||
Value DrawValue[COLOR_NB];
|
||||
|
||||
template <NodeType NT>
|
||||
Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, bool cutNode, bool skipEarlyPruning);
|
||||
|
||||
|
@ -150,6 +106,8 @@ namespace {
|
|||
void update_pv(Move* pv, Move move, Move* childPv);
|
||||
void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus);
|
||||
void update_stats(const Position& pos, Stack* ss, Move move, Move* quiets, int quietsCnt, int bonus);
|
||||
void update_capture_stats(const Position& pos, Move move, Move* captures, int captureCnt, int bonus);
|
||||
bool pv_is_draw(Position& pos);
|
||||
|
||||
// perft() is our utility to verify move generation. All the leaf nodes up
|
||||
// to the given depth are generated and counted, and the sum is returned.
|
||||
|
@ -190,7 +148,7 @@ void Search::init() {
|
|||
{
|
||||
double r = log(d) * log(mc) / 1.95;
|
||||
|
||||
Reductions[NonPV][imp][d][mc] = int(round(r));
|
||||
Reductions[NonPV][imp][d][mc] = int(std::round(r));
|
||||
Reductions[PV][imp][d][mc] = std::max(Reductions[NonPV][imp][d][mc] - 1, 0);
|
||||
|
||||
// Increase reduction for non-PV nodes when eval is not improving
|
||||
|
@ -214,12 +172,7 @@ void Search::clear() {
|
|||
|
||||
Time.availableNodes = 0;
|
||||
TT.clear();
|
||||
|
||||
for (Thread* th : Threads)
|
||||
th->clear();
|
||||
|
||||
Threads.main()->callsCnt = 0;
|
||||
Threads.main()->previousScore = VALUE_INFINITE;
|
||||
Threads.clear();
|
||||
}
|
||||
|
||||
|
||||
|
@ -240,8 +193,9 @@ void MainThread::search() {
|
|||
TT.new_search();
|
||||
|
||||
int contempt = Options["Contempt"] * PawnValueEg / 100; // From centipawns
|
||||
DrawValue[ us] = VALUE_DRAW - Value(contempt);
|
||||
DrawValue[~us] = VALUE_DRAW + Value(contempt);
|
||||
|
||||
Eval::Contempt = (us == WHITE ? make_score(contempt, contempt / 2)
|
||||
: -make_score(contempt, contempt / 2));
|
||||
|
||||
if (rootMoves.empty())
|
||||
{
|
||||
|
@ -259,11 +213,6 @@ void MainThread::search() {
|
|||
Thread::search(); // Let's start searching!
|
||||
}
|
||||
|
||||
// When playing in 'nodes as time' mode, subtract the searched nodes from
|
||||
// the available ones before exiting.
|
||||
if (Limits.npmsec)
|
||||
Time.availableNodes += Limits.inc[us] - Threads.nodes_searched();
|
||||
|
||||
// When we reach the maximum depth, we can arrive here without a raise of
|
||||
// Threads.stop. However, if we are pondering or in an infinite search,
|
||||
// the UCI protocol states that we shouldn't print the best move before the
|
||||
|
@ -283,10 +232,14 @@ void MainThread::search() {
|
|||
if (th != this)
|
||||
th->wait_for_search_finished();
|
||||
|
||||
// When playing in 'nodes as time' mode, subtract the searched nodes from
|
||||
// the available ones before exiting.
|
||||
if (Limits.npmsec)
|
||||
Time.availableNodes += Limits.inc[us] - Threads.nodes_searched();
|
||||
|
||||
// Check if there are threads with a better score than main thread
|
||||
Thread* bestThread = this;
|
||||
if ( !this->easyMovePlayed
|
||||
&& Options["MultiPV"] == 1
|
||||
if ( Options["MultiPV"] == 1
|
||||
&& !Limits.depth
|
||||
&& !Skill(Options["Skill Level"]).enabled()
|
||||
&& rootMoves[0].pv[0] != MOVE_NONE)
|
||||
|
@ -324,10 +277,12 @@ void MainThread::search() {
|
|||
|
||||
void Thread::search() {
|
||||
|
||||
Stack stack[MAX_PLY+7], *ss = stack+4; // To allow referencing (ss-4) and (ss+2)
|
||||
Stack stack[MAX_PLY+7], *ss = stack+4; // To reference from (ss-4) to (ss+2)
|
||||
Value bestValue, alpha, beta, delta;
|
||||
Move easyMove = MOVE_NONE;
|
||||
Move lastBestMove = MOVE_NONE;
|
||||
Depth lastBestMoveDepth = DEPTH_ZERO;
|
||||
MainThread* mainThread = (this == Threads.main() ? Threads.main() : nullptr);
|
||||
double timeReduction = 1.0;
|
||||
|
||||
std::memset(ss-4, 0, 7 * sizeof(Stack));
|
||||
for (int i = 4; i > 0; i--)
|
||||
|
@ -338,9 +293,7 @@ void Thread::search() {
|
|||
|
||||
if (mainThread)
|
||||
{
|
||||
easyMove = EasyMove.get(rootPos.key());
|
||||
EasyMove.clear();
|
||||
mainThread->easyMovePlayed = mainThread->failedLow = false;
|
||||
mainThread->failedLow = false;
|
||||
mainThread->bestMoveChanges = 0;
|
||||
}
|
||||
|
||||
|
@ -453,6 +406,11 @@ void Thread::search() {
|
|||
if (!Threads.stop)
|
||||
completedDepth = rootDepth;
|
||||
|
||||
if (rootMoves[0].pv[0] != lastBestMove) {
|
||||
lastBestMove = rootMoves[0].pv[0];
|
||||
lastBestMoveDepth = rootDepth;
|
||||
}
|
||||
|
||||
// Have we found a "mate in x"?
|
||||
if ( Limits.mate
|
||||
&& bestValue >= VALUE_MATE_IN_MAX_PLY
|
||||
|
@ -472,21 +430,29 @@ void Thread::search() {
|
|||
if (!Threads.stop && !Threads.stopOnPonderhit)
|
||||
{
|
||||
// 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.
|
||||
// of the available time has been used
|
||||
const int F[] = { mainThread->failedLow,
|
||||
bestValue - mainThread->previousScore };
|
||||
|
||||
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() * 5 / 44;
|
||||
Color us = rootPos.side_to_move();
|
||||
bool thinkHard = bestValue == VALUE_DRAW
|
||||
&& Limits.time[us] - Time.elapsed() > Limits.time[~us]
|
||||
&& ::pv_is_draw(rootPos);
|
||||
|
||||
double unstablePvFactor = 1 + mainThread->bestMoveChanges + thinkHard;
|
||||
|
||||
// if the bestMove is stable over several iterations, reduce time for this move,
|
||||
// the longer the move has been stable, the more.
|
||||
// Use part of the gained time from a previous stable move for the current move.
|
||||
timeReduction = 1;
|
||||
for (int i : {3, 4, 5})
|
||||
if (lastBestMoveDepth * i < completedDepth && !thinkHard)
|
||||
timeReduction *= 1.3;
|
||||
unstablePvFactor *= std::pow(mainThread->previousTimeReduction, 0.51) / timeReduction;
|
||||
|
||||
if ( rootMoves.size() == 1
|
||||
|| Time.elapsed() > Time.optimum() * unstablePvFactor * improvingFactor / 628
|
||||
|| (mainThread->easyMovePlayed = doEasyMove, doEasyMove))
|
||||
|| Time.elapsed() > Time.optimum() * unstablePvFactor * improvingFactor / 628)
|
||||
{
|
||||
// If we are allowed to ponder do not stop the search now but
|
||||
// keep pondering until the GUI sends "ponderhit" or "stop".
|
||||
|
@ -496,26 +462,18 @@ void Thread::search() {
|
|||
Threads.stop = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (rootMoves[0].pv.size() >= 3)
|
||||
EasyMove.update(rootPos, rootMoves[0].pv);
|
||||
else
|
||||
EasyMove.clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (!mainThread)
|
||||
return;
|
||||
|
||||
// Clear any candidate easy move that wasn't stable for the last search
|
||||
// iterations; the second condition prevents consecutive fast moves.
|
||||
if (EasyMove.stableCnt < 6 || mainThread->easyMovePlayed)
|
||||
EasyMove.clear();
|
||||
mainThread->previousTimeReduction = timeReduction;
|
||||
|
||||
// If skill level is enabled, swap best PV line with the sub-optimal one
|
||||
if (skill.enabled())
|
||||
std::swap(rootMoves[0], *std::find(rootMoves.begin(),
|
||||
rootMoves.end(), skill.best_move(multiPV)));
|
||||
std::swap(rootMoves[0], *std::find(rootMoves.begin(), rootMoves.end(),
|
||||
skill.best ? skill.best : skill.pick_best(multiPV)));
|
||||
}
|
||||
|
||||
|
||||
|
@ -527,7 +485,7 @@ namespace {
|
|||
Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, bool cutNode, bool skipEarlyPruning) {
|
||||
|
||||
const bool PvNode = NT == PV;
|
||||
const bool rootNode = PvNode && (ss-1)->ply == 0;
|
||||
const bool rootNode = PvNode && ss->ply == 0;
|
||||
|
||||
assert(-VALUE_INFINITE <= alpha && alpha < beta && beta <= VALUE_INFINITE);
|
||||
assert(PvNode || (alpha == beta - 1));
|
||||
|
@ -535,7 +493,7 @@ namespace {
|
|||
assert(!(PvNode && cutNode));
|
||||
assert(depth / ONE_PLY * ONE_PLY == depth);
|
||||
|
||||
Move pv[MAX_PLY+1], quietsSearched[64];
|
||||
Move pv[MAX_PLY+1], capturesSearched[32], quietsSearched[64];
|
||||
StateInfo st;
|
||||
TTEntry* tte;
|
||||
Key posKey;
|
||||
|
@ -543,33 +501,31 @@ namespace {
|
|||
Depth extension, newDepth;
|
||||
Value bestValue, value, ttValue, eval, maxValue;
|
||||
bool ttHit, inCheck, givesCheck, singularExtensionNode, improving;
|
||||
bool captureOrPromotion, doFullDepthSearch, moveCountPruning, skipQuiets, ttCapture;
|
||||
bool captureOrPromotion, doFullDepthSearch, moveCountPruning, skipQuiets, ttCapture, pvExact;
|
||||
Piece movedPiece;
|
||||
int moveCount, quietCount;
|
||||
int moveCount, captureCount, quietCount;
|
||||
|
||||
// Step 1. Initialize node
|
||||
Thread* thisThread = pos.this_thread();
|
||||
inCheck = pos.checkers();
|
||||
moveCount = quietCount = ss->moveCount = 0;
|
||||
moveCount = captureCount = quietCount = ss->moveCount = 0;
|
||||
ss->statScore = 0;
|
||||
bestValue = -VALUE_INFINITE;
|
||||
maxValue = VALUE_INFINITE;
|
||||
ss->ply = (ss-1)->ply + 1;
|
||||
|
||||
// Check for the available remaining time
|
||||
if (thisThread == Threads.main())
|
||||
static_cast<MainThread*>(thisThread)->check_time();
|
||||
|
||||
// Used to send selDepth info to GUI
|
||||
if (PvNode && thisThread->selDepth < ss->ply)
|
||||
thisThread->selDepth = ss->ply;
|
||||
// Used to send selDepth info to GUI (selDepth counts from 1, ply from 0)
|
||||
if (PvNode && thisThread->selDepth < ss->ply + 1)
|
||||
thisThread->selDepth = ss->ply + 1;
|
||||
|
||||
if (!rootNode)
|
||||
{
|
||||
// Step 2. Check for aborted search and immediate draw
|
||||
if (Threads.stop.load(std::memory_order_relaxed) || pos.is_draw(ss->ply) || ss->ply >= MAX_PLY)
|
||||
return ss->ply >= MAX_PLY && !inCheck ? evaluate(pos)
|
||||
: DrawValue[pos.side_to_move()];
|
||||
return ss->ply >= MAX_PLY && !inCheck ? evaluate(pos) : VALUE_DRAW;
|
||||
|
||||
// Step 3. Mate distance pruning. Even if we mate at the next move our score
|
||||
// would be at best mate_in(ss->ply+1), but if alpha is already bigger because
|
||||
|
@ -585,6 +541,7 @@ namespace {
|
|||
|
||||
assert(0 <= ss->ply && ss->ply < MAX_PLY);
|
||||
|
||||
(ss+1)->ply = ss->ply + 1;
|
||||
ss->currentMove = (ss+1)->excludedMove = bestMove = MOVE_NONE;
|
||||
ss->contHistory = &thisThread->contHistory[NO_PIECE][0];
|
||||
(ss+2)->killers[0] = (ss+2)->killers[1] = MOVE_NONE;
|
||||
|
@ -594,7 +551,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);
|
||||
posKey = pos.key() ^ Key(excludedMove << 16); // isn't a very good hash
|
||||
tte = TT.probe(posKey, ttHit);
|
||||
ttValue = ttHit ? value_from_tt(tte->value(), ss->ply) : VALUE_NONE;
|
||||
ttMove = rootNode ? thisThread->rootMoves[thisThread->PVIdx].pv[0]
|
||||
|
@ -650,8 +607,8 @@ namespace {
|
|||
|
||||
int drawScore = TB::UseRule50 ? 1 : 0;
|
||||
|
||||
value = wdl < -drawScore ? -VALUE_MATE + MAX_PLY + ss->ply
|
||||
: wdl > drawScore ? VALUE_MATE - MAX_PLY - ss->ply
|
||||
value = wdl < -drawScore ? -VALUE_MATE + MAX_PLY + ss->ply + 1
|
||||
: wdl > drawScore ? VALUE_MATE - MAX_PLY - ss->ply - 1
|
||||
: VALUE_DRAW + 2 * wdl * drawScore;
|
||||
|
||||
Bound b = wdl < -drawScore ? BOUND_UPPER
|
||||
|
@ -706,18 +663,18 @@ namespace {
|
|||
ss->staticEval, TT.generation());
|
||||
}
|
||||
|
||||
if (skipEarlyPruning)
|
||||
if (skipEarlyPruning || !pos.non_pawn_material(pos.side_to_move()))
|
||||
goto moves_loop;
|
||||
|
||||
// Step 6. Razoring (skipped when in check)
|
||||
if ( !PvNode
|
||||
&& depth < 4 * ONE_PLY
|
||||
&& eval + razor_margin[depth / ONE_PLY] <= alpha)
|
||||
&& eval + razor_margin <= alpha)
|
||||
{
|
||||
if (depth <= ONE_PLY)
|
||||
return qsearch<NonPV, false>(pos, ss, alpha, alpha+1);
|
||||
|
||||
Value ralpha = alpha - razor_margin[depth / ONE_PLY];
|
||||
Value ralpha = alpha - razor_margin;
|
||||
Value v = qsearch<NonPV, false>(pos, ss, ralpha, ralpha+1);
|
||||
if (v <= ralpha)
|
||||
return v;
|
||||
|
@ -727,15 +684,14 @@ namespace {
|
|||
if ( !rootNode
|
||||
&& depth < 7 * ONE_PLY
|
||||
&& eval - futility_margin(depth) >= beta
|
||||
&& eval < VALUE_KNOWN_WIN // Do not return unproven wins
|
||||
&& pos.non_pawn_material(pos.side_to_move()))
|
||||
&& eval < VALUE_KNOWN_WIN) // Do not return unproven wins
|
||||
return eval;
|
||||
|
||||
// Step 8. Null move search with verification search (is omitted in PV nodes)
|
||||
if ( !PvNode
|
||||
&& eval >= beta
|
||||
&& (ss->staticEval >= beta - 35 * (depth / ONE_PLY - 6) || depth >= 13 * ONE_PLY)
|
||||
&& pos.non_pawn_material(pos.side_to_move()))
|
||||
&& ss->staticEval >= beta - 36 * depth / ONE_PLY + 225
|
||||
&& (ss->ply >= thisThread->nmp_ply || ss->ply % 2 != thisThread->nmp_odd))
|
||||
{
|
||||
|
||||
assert(eval - beta >= 0);
|
||||
|
@ -757,13 +713,19 @@ namespace {
|
|||
if (nullValue >= VALUE_MATE_IN_MAX_PLY)
|
||||
nullValue = beta;
|
||||
|
||||
if (depth < 12 * ONE_PLY && abs(beta) < VALUE_KNOWN_WIN)
|
||||
if (abs(beta) < VALUE_KNOWN_WIN && (depth < 12 * ONE_PLY || thisThread->nmp_ply))
|
||||
return nullValue;
|
||||
|
||||
// Do verification search at high depths
|
||||
// disable null move pruning for side to move for the first part of the remaining search tree
|
||||
thisThread->nmp_ply = ss->ply + 3 * (depth-R) / 4;
|
||||
thisThread->nmp_odd = ss->ply % 2;
|
||||
|
||||
Value v = depth-R < ONE_PLY ? qsearch<NonPV, false>(pos, ss, beta-1, beta)
|
||||
: search<NonPV>(pos, ss, beta-1, beta, depth-R, false, true);
|
||||
|
||||
thisThread->nmp_odd = thisThread->nmp_ply = 0;
|
||||
|
||||
if (v >= beta)
|
||||
return nullValue;
|
||||
}
|
||||
|
@ -780,7 +742,7 @@ namespace {
|
|||
|
||||
assert(is_ok((ss-1)->currentMove));
|
||||
|
||||
MovePicker mp(pos, ttMove, rbeta - ss->staticEval);
|
||||
MovePicker mp(pos, ttMove, rbeta - ss->staticEval, &thisThread->captureHistory);
|
||||
|
||||
while ((move = mp.next_move()) != MOVE_NONE)
|
||||
if (pos.legal(move))
|
||||
|
@ -814,7 +776,7 @@ moves_loop: // When in check search starts from here
|
|||
const PieceToHistory* contHist[] = { (ss-1)->contHistory, (ss-2)->contHistory, nullptr, (ss-4)->contHistory };
|
||||
Move countermove = thisThread->counterMoves[pos.piece_on(prevSq)][prevSq];
|
||||
|
||||
MovePicker mp(pos, ttMove, depth, &thisThread->mainHistory, contHist, countermove, ss->killers);
|
||||
MovePicker mp(pos, ttMove, depth, &thisThread->mainHistory, &thisThread->captureHistory, contHist, countermove, ss->killers);
|
||||
value = bestValue; // Workaround a bogus 'uninitialized' warning under gcc
|
||||
improving = ss->staticEval >= (ss-2)->staticEval
|
||||
/* || ss->staticEval == VALUE_NONE Already implicit in the previous condition */
|
||||
|
@ -829,6 +791,7 @@ moves_loop: // When in check search starts from here
|
|||
&& tte->depth() >= depth - 3 * ONE_PLY;
|
||||
skipQuiets = false;
|
||||
ttCapture = false;
|
||||
pvExact = PvNode && ttHit && tte->bound() == BOUND_EXACT;
|
||||
|
||||
// Step 11. Loop through moves
|
||||
// Loop through all pseudo-legal moves until no moves remain or a beta cutoff occurs
|
||||
|
@ -861,7 +824,7 @@ moves_loop: // When in check search starts from here
|
|||
movedPiece = pos.moved_piece(move);
|
||||
|
||||
givesCheck = type_of(move) == NORMAL && !pos.discovered_check_candidates()
|
||||
? pos.check_squares(type_of(pos.piece_on(from_sq(move)))) & to_sq(move)
|
||||
? pos.check_squares(type_of(movedPiece)) & to_sq(move)
|
||||
: pos.gives_check(move);
|
||||
|
||||
moveCountPruning = depth < 16 * ONE_PLY
|
||||
|
@ -973,6 +936,10 @@ moves_loop: // When in check search starts from here
|
|||
if ((ss-1)->moveCount > 15)
|
||||
r -= ONE_PLY;
|
||||
|
||||
// Decrease reduction for exact PV nodes
|
||||
if (pvExact)
|
||||
r -= ONE_PLY;
|
||||
|
||||
// Increase reduction if ttMove is a capture
|
||||
if (ttCapture)
|
||||
r += ONE_PLY;
|
||||
|
@ -995,10 +962,10 @@ moves_loop: // When in check search starts from here
|
|||
- 4000;
|
||||
|
||||
// Decrease/increase reduction by comparing opponent's stat score
|
||||
if (ss->statScore > 0 && (ss-1)->statScore < 0)
|
||||
if (ss->statScore >= 0 && (ss-1)->statScore < 0)
|
||||
r -= ONE_PLY;
|
||||
|
||||
else if (ss->statScore < 0 && (ss-1)->statScore > 0)
|
||||
else if ((ss-1)->statScore >= 0 && ss->statScore < 0)
|
||||
r += ONE_PLY;
|
||||
|
||||
// Decrease/increase reduction for moves with a good/bad history
|
||||
|
@ -1100,6 +1067,8 @@ moves_loop: // When in check search starts from here
|
|||
|
||||
if (!captureOrPromotion && move != bestMove && quietCount < 64)
|
||||
quietsSearched[quietCount++] = move;
|
||||
else if (captureOrPromotion && move != bestMove && captureCount < 32)
|
||||
capturesSearched[captureCount++] = move;
|
||||
}
|
||||
|
||||
// The following condition would detect a stop only after move loop has been
|
||||
|
@ -1119,12 +1088,14 @@ moves_loop: // When in check search starts from here
|
|||
|
||||
if (!moveCount)
|
||||
bestValue = excludedMove ? alpha
|
||||
: inCheck ? mated_in(ss->ply) : DrawValue[pos.side_to_move()];
|
||||
: inCheck ? mated_in(ss->ply) : VALUE_DRAW;
|
||||
else if (bestMove)
|
||||
{
|
||||
// Quiet best move: update move sorting heuristics
|
||||
if (!pos.capture_or_promotion(bestMove))
|
||||
update_stats(pos, ss, bestMove, quietsSearched, quietCount, stat_bonus(depth));
|
||||
else
|
||||
update_capture_stats(pos, bestMove, capturesSearched, captureCount, stat_bonus(depth));
|
||||
|
||||
// Extra penalty for a quiet TT move in previous ply when it gets refuted
|
||||
if ((ss-1)->moveCount == 1 && !pos.captured_piece())
|
||||
|
@ -1159,7 +1130,7 @@ moves_loop: // When in check search starts from here
|
|||
|
||||
const bool PvNode = NT == PV;
|
||||
|
||||
assert(InCheck == !!pos.checkers());
|
||||
assert(InCheck == bool(pos.checkers()));
|
||||
assert(alpha >= -VALUE_INFINITE && alpha < beta && beta <= VALUE_INFINITE);
|
||||
assert(PvNode || (alpha == beta - 1));
|
||||
assert(depth <= DEPTH_ZERO);
|
||||
|
@ -1183,13 +1154,12 @@ moves_loop: // When in check search starts from here
|
|||
}
|
||||
|
||||
ss->currentMove = bestMove = MOVE_NONE;
|
||||
ss->ply = (ss-1)->ply + 1;
|
||||
(ss+1)->ply = ss->ply + 1;
|
||||
moveCount = 0;
|
||||
|
||||
// Check for an instant draw or if the maximum ply has been reached
|
||||
if (pos.is_draw(ss->ply) || ss->ply >= MAX_PLY)
|
||||
return ss->ply >= MAX_PLY && !InCheck ? evaluate(pos)
|
||||
: DrawValue[pos.side_to_move()];
|
||||
return ss->ply >= MAX_PLY && !InCheck ? evaluate(pos) : VALUE_DRAW;
|
||||
|
||||
assert(0 <= ss->ply && ss->ply < MAX_PLY);
|
||||
|
||||
|
@ -1198,7 +1168,6 @@ moves_loop: // When in check search starts from here
|
|||
// only two types of depth in TT: DEPTH_QS_CHECKS or DEPTH_QS_NO_CHECKS.
|
||||
ttDepth = InCheck || depth >= DEPTH_QS_CHECKS ? DEPTH_QS_CHECKS
|
||||
: DEPTH_QS_NO_CHECKS;
|
||||
|
||||
// Transposition table lookup
|
||||
posKey = pos.key();
|
||||
tte = TT.probe(posKey, ttHit);
|
||||
|
@ -1241,7 +1210,7 @@ moves_loop: // When in check search starts from here
|
|||
if (bestValue >= beta)
|
||||
{
|
||||
if (!ttHit)
|
||||
tte->save(pos.key(), value_to_tt(bestValue, ss->ply), BOUND_LOWER,
|
||||
tte->save(posKey, value_to_tt(bestValue, ss->ply), BOUND_LOWER,
|
||||
DEPTH_NONE, MOVE_NONE, ss->staticEval, TT.generation());
|
||||
|
||||
return bestValue;
|
||||
|
@ -1257,7 +1226,7 @@ moves_loop: // When in check search starts from here
|
|||
// 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.
|
||||
MovePicker mp(pos, ttMove, depth, &pos.this_thread()->mainHistory, to_sq((ss-1)->currentMove));
|
||||
MovePicker mp(pos, ttMove, depth, &pos.this_thread()->mainHistory, &pos.this_thread()->captureHistory, to_sq((ss-1)->currentMove));
|
||||
|
||||
// Loop through the moves until no moves remain or a beta cutoff occurs
|
||||
while ((move = mp.next_move()) != MOVE_NONE)
|
||||
|
@ -1265,7 +1234,7 @@ moves_loop: // When in check search starts from here
|
|||
assert(is_ok(move));
|
||||
|
||||
givesCheck = type_of(move) == NORMAL && !pos.discovered_check_candidates()
|
||||
? pos.check_squares(type_of(pos.piece_on(from_sq(move)))) & to_sq(move)
|
||||
? pos.check_squares(type_of(pos.moved_piece(move))) & to_sq(move)
|
||||
: pos.gives_check(move);
|
||||
|
||||
moveCount++;
|
||||
|
@ -1301,7 +1270,6 @@ moves_loop: // When in check search starts from here
|
|||
|
||||
// Don't search moves with negative SEE values
|
||||
if ( (!InCheck || evasionPrunable)
|
||||
&& type_of(move) != PROMOTION
|
||||
&& !pos.see_ge(move))
|
||||
continue;
|
||||
|
||||
|
@ -1412,6 +1380,26 @@ moves_loop: // When in check search starts from here
|
|||
}
|
||||
|
||||
|
||||
// update_capture_stats() updates move sorting heuristics when a new capture best move is found
|
||||
|
||||
void update_capture_stats(const Position& pos, Move move,
|
||||
Move* captures, int captureCnt, int bonus) {
|
||||
|
||||
CapturePieceToHistory& captureHistory = pos.this_thread()->captureHistory;
|
||||
Piece moved_piece = pos.moved_piece(move);
|
||||
PieceType captured = type_of(pos.piece_on(to_sq(move)));
|
||||
captureHistory.update(moved_piece, to_sq(move), captured, bonus);
|
||||
|
||||
// Decrease all the other played capture moves
|
||||
for (int i = 0; i < captureCnt; ++i)
|
||||
{
|
||||
moved_piece = pos.moved_piece(captures[i]);
|
||||
captured = type_of(pos.piece_on(to_sq(captures[i])));
|
||||
captureHistory.update(moved_piece, to_sq(captures[i]), captured, -bonus);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// update_stats() updates move sorting heuristics when a new quiet best move is found
|
||||
|
||||
void update_stats(const Position& pos, Stack* ss, Move move,
|
||||
|
@ -1443,6 +1431,24 @@ moves_loop: // When in check search starts from here
|
|||
}
|
||||
|
||||
|
||||
// Is the PV leading to a draw position? Assumes all pv moves are legal
|
||||
bool pv_is_draw(Position& pos) {
|
||||
|
||||
StateInfo st[MAX_PLY];
|
||||
auto& pv = pos.this_thread()->rootMoves[0].pv;
|
||||
|
||||
for (size_t i = 0; i < pv.size(); ++i)
|
||||
pos.do_move(pv[i], st[i]);
|
||||
|
||||
bool isDraw = pos.is_draw(pv.size());
|
||||
|
||||
for (size_t i = pv.size(); i > 0; --i)
|
||||
pos.undo_move(pv[i-1]);
|
||||
|
||||
return isDraw;
|
||||
}
|
||||
|
||||
|
||||
// When playing with strength handicap, choose best move among a set of RootMoves
|
||||
// using a statistical rule dependent on 'level'. Idea by Heinz van Saanen.
|
||||
|
||||
|
@ -1466,7 +1472,7 @@ moves_loop: // When in check search starts from here
|
|||
int push = ( weakness * int(topScore - rootMoves[i].score)
|
||||
+ delta * (rng.rand<unsigned>() % weakness)) / 128;
|
||||
|
||||
if (rootMoves[i].score + push > maxScore)
|
||||
if (rootMoves[i].score + push >= maxScore)
|
||||
{
|
||||
maxScore = rootMoves[i].score + push;
|
||||
best = rootMoves[i].pv[0];
|
||||
|
@ -1505,7 +1511,7 @@ moves_loop: // When in check search starts from here
|
|||
if (Threads.ponder)
|
||||
return;
|
||||
|
||||
if ( (Limits.use_time_management() && elapsed > Time.maximum())
|
||||
if ( (Limits.use_time_management() && elapsed > Time.maximum() - 10)
|
||||
|| (Limits.movetime && elapsed >= Limits.movetime)
|
||||
|| (Limits.nodes && Threads.nodes_searched() >= (uint64_t)Limits.nodes))
|
||||
Threads.stop = true;
|
||||
|
@ -1614,6 +1620,10 @@ void Tablebases::filter_root_moves(Position& pos, Search::RootMoves& rootMoves)
|
|||
if (Cardinality < popcount(pos.pieces()) || pos.can_castle(ANY_CASTLING))
|
||||
return;
|
||||
|
||||
// Don't filter any moves if the user requested analysis on multiple
|
||||
if (Options["MultiPV"] != 1)
|
||||
return;
|
||||
|
||||
// If the current root position is in the tablebases, then RootMoves
|
||||
// contains only moves that preserve the draw or the win.
|
||||
RootInTB = root_probe(pos, rootMoves, TB::Score);
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
||||
Copyright (C) 2015-2017 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
|
||||
Stockfish is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||
Copyright (c) 2013 Ronald de Man
|
||||
Copyright (C) 2016-2017 Marco Costalba, Lucas Braesch
|
||||
Copyright (C) 2016-2018 Marco Costalba, Lucas Braesch
|
||||
|
||||
Stockfish is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -133,16 +133,16 @@ struct Atomic {
|
|||
std::atomic_bool ready;
|
||||
};
|
||||
|
||||
// We define types for the different parts of the WLDEntry and DTZEntry with
|
||||
// We define types for the different parts of the WDLEntry and DTZEntry with
|
||||
// corresponding specializations for pieces or pawns.
|
||||
|
||||
struct WLDEntryPiece {
|
||||
struct WDLEntryPiece {
|
||||
PairsData* precomp;
|
||||
};
|
||||
|
||||
struct WDLEntryPawn {
|
||||
uint8_t pawnCount[2]; // [Lead color / other color]
|
||||
WLDEntryPiece file[2][4]; // [wtm / btm][FILE_A..FILE_D]
|
||||
WDLEntryPiece file[2][4]; // [wtm / btm][FILE_A..FILE_D]
|
||||
};
|
||||
|
||||
struct DTZEntryPiece {
|
||||
|
@ -172,7 +172,7 @@ struct WDLEntry : public TBEntry {
|
|||
WDLEntry(const std::string& code);
|
||||
~WDLEntry();
|
||||
union {
|
||||
WLDEntryPiece pieceTable[2]; // [wtm / btm]
|
||||
WDLEntryPiece pieceTable[2]; // [wtm / btm]
|
||||
WDLEntryPawn pawnTable;
|
||||
};
|
||||
};
|
||||
|
@ -1379,9 +1379,8 @@ void Tablebases::init(const std::string& paths) {
|
|||
for (PieceType p3 = PAWN; p3 <= p2; ++p3) {
|
||||
EntryTable.insert({KING, p1, p2, p3, KING});
|
||||
|
||||
if (sizeof(char*) >= 8)
|
||||
for (PieceType p4 = PAWN; p4 <= p3; ++p4)
|
||||
EntryTable.insert({KING, p1, p2, p3, p4, KING});
|
||||
for (PieceType p4 = PAWN; p4 <= p3; ++p4)
|
||||
EntryTable.insert({KING, p1, p2, p3, p4, KING});
|
||||
|
||||
for (PieceType p4 = PAWN; p4 < KING; ++p4)
|
||||
EntryTable.insert({KING, p1, p2, p3, KING, p4});
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||
Copyright (c) 2013 Ronald de Man
|
||||
Copyright (C) 2016-2017 Marco Costalba, Lucas Braesch
|
||||
Copyright (C) 2016-2018 Marco Costalba, Lucas Braesch
|
||||
|
||||
Stockfish is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
||||
Copyright (C) 2015-2017 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
|
||||
Stockfish is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -24,6 +24,7 @@
|
|||
#include "movegen.h"
|
||||
#include "search.h"
|
||||
#include "thread.h"
|
||||
#include "uci.h"
|
||||
#include "syzygy/tbprobe.h"
|
||||
|
||||
ThreadPool Threads; // Global object
|
||||
|
@ -35,7 +36,6 @@ ThreadPool Threads; // Global object
|
|||
Thread::Thread(size_t n) : idx(n), stdThread(&Thread::idle_loop, this) {
|
||||
|
||||
wait_for_search_finished();
|
||||
clear(); // Zero-init histories (based on std::array)
|
||||
}
|
||||
|
||||
|
||||
|
@ -58,6 +58,7 @@ void Thread::clear() {
|
|||
|
||||
counterMoves.fill(MOVE_NONE);
|
||||
mainHistory.fill(0);
|
||||
captureHistory.fill(0);
|
||||
|
||||
for (auto& to : contHistory)
|
||||
for (auto& h : to)
|
||||
|
@ -91,7 +92,13 @@ void Thread::wait_for_search_finished() {
|
|||
|
||||
void Thread::idle_loop() {
|
||||
|
||||
WinProcGroup::bindThisThread(idx);
|
||||
// If OS already scheduled us on a different group than 0 then don't overwrite
|
||||
// the choice, eventually we are one of many one-threaded processes running on
|
||||
// some Windows NUMA hardware, for instance in fishtest. To make it simple,
|
||||
// just check if running threads are below a threshold, in this case all this
|
||||
// NUMA machinery is not needed.
|
||||
if (Options["Threads"] >= 8)
|
||||
WinProcGroup::bindThisThread(idx);
|
||||
|
||||
while (true)
|
||||
{
|
||||
|
@ -109,41 +116,39 @@ void Thread::idle_loop() {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/// ThreadPool::init() creates and launches the threads that will go
|
||||
/// immediately to sleep in idle_loop. We cannot use the c'tor because
|
||||
/// Threads is a static object and we need a fully initialized engine at
|
||||
/// this point due to allocation of Endgames in the Thread constructor.
|
||||
|
||||
void ThreadPool::init(size_t requested) {
|
||||
|
||||
push_back(new MainThread(0));
|
||||
set(requested);
|
||||
}
|
||||
|
||||
|
||||
/// ThreadPool::exit() terminates threads before the program exits. Cannot be
|
||||
/// done in the destructor because threads must be terminated before deleting
|
||||
/// any static object, so before main() returns.
|
||||
|
||||
void ThreadPool::exit() {
|
||||
|
||||
main()->wait_for_search_finished();
|
||||
set(0);
|
||||
}
|
||||
|
||||
|
||||
/// ThreadPool::set() creates/destroys threads to match the requested number
|
||||
/// ThreadPool::set() creates/destroys threads to match the requested number.
|
||||
/// Created and launced threads wil go immediately to sleep in idle_loop.
|
||||
/// Upon resizing, threads are recreated to allow for binding if necessary.
|
||||
|
||||
void ThreadPool::set(size_t requested) {
|
||||
|
||||
while (size() < requested)
|
||||
push_back(new Thread(size()));
|
||||
if (size() > 0) { // destroy any existing thread(s)
|
||||
main()->wait_for_search_finished();
|
||||
|
||||
while (size() > requested)
|
||||
delete back(), pop_back();
|
||||
while (size() > 0)
|
||||
delete back(), pop_back();
|
||||
}
|
||||
|
||||
if (requested > 0) { // create new thread(s)
|
||||
push_back(new MainThread(0));
|
||||
|
||||
while (size() < requested)
|
||||
push_back(new Thread(size()));
|
||||
clear();
|
||||
}
|
||||
}
|
||||
|
||||
/// ThreadPool::clear() sets threadPool data to initial values.
|
||||
|
||||
void ThreadPool::clear() {
|
||||
|
||||
for (Thread* th : *this)
|
||||
th->clear();
|
||||
|
||||
main()->callsCnt = 0;
|
||||
main()->previousScore = VALUE_INFINITE;
|
||||
main()->previousTimeReduction = 1;
|
||||
}
|
||||
|
||||
/// ThreadPool::start_thinking() wakes up main thread waiting in idle_loop() and
|
||||
/// returns immediately. Main thread will wake up other threads and start the search.
|
||||
|
@ -180,9 +185,9 @@ void ThreadPool::start_thinking(Position& pos, StateListPtr& states,
|
|||
// is shared by threads but is accessed in read-only mode.
|
||||
StateInfo tmp = setupStates->back();
|
||||
|
||||
for (Thread* th : Threads)
|
||||
for (Thread* th : *this)
|
||||
{
|
||||
th->nodes = th->tbHits = 0;
|
||||
th->nodes = th->tbHits = th->nmp_ply = th->nmp_odd = 0;
|
||||
th->rootDepth = th->completedDepth = DEPTH_ZERO;
|
||||
th->rootMoves = rootMoves;
|
||||
th->rootPos.set(pos.fen(), pos.is_chess960(), &setupStates->back(), th);
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
||||
Copyright (C) 2015-2017 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
|
||||
Stockfish is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -61,7 +61,7 @@ public:
|
|||
Material::Table materialTable;
|
||||
Endgames endgames;
|
||||
size_t PVIdx;
|
||||
int selDepth;
|
||||
int selDepth, nmp_ply, nmp_odd;
|
||||
std::atomic<uint64_t> nodes, tbHits;
|
||||
|
||||
Position rootPos;
|
||||
|
@ -69,6 +69,7 @@ public:
|
|||
Depth rootDepth, completedDepth;
|
||||
CounterMoveHistory counterMoves;
|
||||
ButterflyHistory mainHistory;
|
||||
CapturePieceToHistory captureHistory;
|
||||
ContinuationHistory contHistory;
|
||||
};
|
||||
|
||||
|
@ -82,8 +83,8 @@ struct MainThread : public Thread {
|
|||
void search() override;
|
||||
void check_time();
|
||||
|
||||
bool easyMovePlayed, failedLow;
|
||||
double bestMoveChanges;
|
||||
bool failedLow;
|
||||
double bestMoveChanges, previousTimeReduction;
|
||||
Value previousScore;
|
||||
int callsCnt;
|
||||
};
|
||||
|
@ -95,9 +96,8 @@ struct MainThread : public Thread {
|
|||
|
||||
struct ThreadPool : public std::vector<Thread*> {
|
||||
|
||||
void init(size_t); // No constructor and destructor, threads rely on globals that should
|
||||
void exit(); // be initialized and valid during the whole thread lifetime.
|
||||
void start_thinking(Position&, StateListPtr&, const Search::LimitsType&, bool = false);
|
||||
void clear();
|
||||
void set(size_t);
|
||||
|
||||
MainThread* main() const { return static_cast<MainThread*>(front()); }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
||||
Copyright (C) 2015-2017 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
|
||||
Stockfish is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
||||
Copyright (C) 2015-2017 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
|
||||
Stockfish is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -19,6 +19,8 @@
|
|||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <cfloat>
|
||||
#include <cmath>
|
||||
|
||||
#include "search.h"
|
||||
#include "timeman.h"
|
||||
|
@ -30,43 +32,41 @@ namespace {
|
|||
|
||||
enum TimeType { OptimumTime, MaxTime };
|
||||
|
||||
int remaining(int myTime, int myInc, int moveOverhead, int movesToGo,
|
||||
int moveNum, bool ponder, TimeType type) {
|
||||
const int MoveHorizon = 50; // Plan time management at most this many moves ahead
|
||||
const double MaxRatio = 7.09; // When in trouble, we can step over reserved time with this ratio
|
||||
const double StealRatio = 0.35; // However we must not steal time from remaining moves over this ratio
|
||||
|
||||
if (myTime <= 0)
|
||||
return 0;
|
||||
|
||||
double ratio; // Which ratio of myTime we are going to use
|
||||
// move_importance() is a skew-logistic function based on naive statistical
|
||||
// analysis of "how many games are still undecided after n half-moves". Game
|
||||
// is considered "undecided" as long as neither side has >275cp advantage.
|
||||
// Data was extracted from the CCRL game database with some simple filtering criteria.
|
||||
|
||||
// Usage of increment follows quadratic distribution with the maximum at move 25
|
||||
double inc = myInc * std::max(55.0, 120 - 0.12 * (moveNum - 25) * (moveNum - 25));
|
||||
double move_importance(int ply) {
|
||||
|
||||
// In moves-to-go we distribute time according to a quadratic function with
|
||||
// the maximum around move 20 for 40 moves in y time case.
|
||||
if (movesToGo)
|
||||
{
|
||||
ratio = (type == OptimumTime ? 1.0 : 6.0) / std::min(50, movesToGo);
|
||||
const double XScale = 7.64;
|
||||
const double XShift = 58.4;
|
||||
const double Skew = 0.183;
|
||||
|
||||
if (moveNum <= 40)
|
||||
ratio *= 1.1 - 0.001 * (moveNum - 20) * (moveNum - 20);
|
||||
else
|
||||
ratio *= 1.5;
|
||||
return pow((1 + exp((ply - XShift) / XScale)), -Skew) + DBL_MIN; // Ensure non-zero
|
||||
}
|
||||
|
||||
ratio *= 1 + inc / (myTime * 8.5);
|
||||
}
|
||||
// Otherwise we increase usage of remaining time as the game goes on
|
||||
else
|
||||
{
|
||||
double k = 1 + 20 * moveNum / (500.0 + moveNum);
|
||||
ratio = (type == OptimumTime ? 0.017 : 0.07) * (k + inc / myTime);
|
||||
}
|
||||
template<TimeType T>
|
||||
int remaining(int myTime, int movesToGo, int ply, int slowMover) {
|
||||
|
||||
int time = int(std::min(1.0, ratio) * std::max(0, myTime - moveOverhead));
|
||||
const double TMaxRatio = (T == OptimumTime ? 1 : MaxRatio);
|
||||
const double TStealRatio = (T == OptimumTime ? 0 : StealRatio);
|
||||
|
||||
if (type == OptimumTime && ponder)
|
||||
time = 5 * time / 4;
|
||||
double moveImportance = (move_importance(ply) * slowMover) / 100;
|
||||
double otherMovesImportance = 0;
|
||||
|
||||
return time;
|
||||
for (int i = 1; i < movesToGo; ++i)
|
||||
otherMovesImportance += move_importance(ply + 2 * i);
|
||||
|
||||
double ratio1 = (TMaxRatio * moveImportance) / (TMaxRatio * moveImportance + otherMovesImportance);
|
||||
double ratio2 = (moveImportance + TStealRatio * otherMovesImportance) / (moveImportance + otherMovesImportance);
|
||||
|
||||
return int(myTime * std::min(ratio1, ratio2)); // Intel C++ asks for an explicit cast
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -81,11 +81,12 @@ namespace {
|
|||
/// inc > 0 && movestogo == 0 means: x basetime + z increment
|
||||
/// inc > 0 && movestogo != 0 means: x moves in y minutes + z increment
|
||||
|
||||
void TimeManagement::init(Search::LimitsType& limits, Color us, int ply)
|
||||
{
|
||||
int moveOverhead = Options["Move Overhead"];
|
||||
int npmsec = Options["nodestime"];
|
||||
bool ponder = Options["Ponder"];
|
||||
void TimeManagement::init(Search::LimitsType& limits, Color us, int ply) {
|
||||
|
||||
int minThinkingTime = Options["Minimum Thinking Time"];
|
||||
int moveOverhead = Options["Move Overhead"];
|
||||
int slowMover = Options["Slow Mover"];
|
||||
int npmsec = Options["nodestime"];
|
||||
|
||||
// If we have to play in 'nodes as time' mode, then convert from time
|
||||
// to nodes, and use resulting values in time management formulas.
|
||||
|
@ -102,11 +103,30 @@ void TimeManagement::init(Search::LimitsType& limits, Color us, int ply)
|
|||
limits.npmsec = npmsec;
|
||||
}
|
||||
|
||||
int moveNum = (ply + 1) / 2;
|
||||
|
||||
startTime = limits.startTime;
|
||||
optimumTime = remaining(limits.time[us], limits.inc[us], moveOverhead,
|
||||
limits.movestogo, moveNum, ponder, OptimumTime);
|
||||
maximumTime = remaining(limits.time[us], limits.inc[us], moveOverhead,
|
||||
limits.movestogo, moveNum, ponder, MaxTime);
|
||||
optimumTime = maximumTime = std::max(limits.time[us], minThinkingTime);
|
||||
|
||||
const int MaxMTG = limits.movestogo ? std::min(limits.movestogo, MoveHorizon) : MoveHorizon;
|
||||
|
||||
// We calculate optimum time usage for different hypothetical "moves to go"-values
|
||||
// and choose the minimum of calculated search time values. Usually the greatest
|
||||
// hypMTG gives the minimum values.
|
||||
for (int hypMTG = 1; hypMTG <= MaxMTG; ++hypMTG)
|
||||
{
|
||||
// Calculate thinking time for hypothetical "moves to go"-value
|
||||
int hypMyTime = limits.time[us]
|
||||
+ limits.inc[us] * (hypMTG - 1)
|
||||
- moveOverhead * (2 + std::min(hypMTG, 40));
|
||||
|
||||
hypMyTime = std::max(hypMyTime, 0);
|
||||
|
||||
int t1 = minThinkingTime + remaining<OptimumTime>(hypMyTime, hypMTG, ply, slowMover);
|
||||
int t2 = minThinkingTime + remaining<MaxTime >(hypMyTime, hypMTG, ply, slowMover);
|
||||
|
||||
optimumTime = std::min(t1, optimumTime);
|
||||
maximumTime = std::min(t2, maximumTime);
|
||||
}
|
||||
|
||||
if (Options["Ponder"])
|
||||
optimumTime += optimumTime / 4;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
||||
Copyright (C) 2015-2017 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
|
||||
Stockfish is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
||||
Copyright (C) 2015-2017 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
|
||||
Stockfish is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -33,7 +33,7 @@ TranspositionTable TT; // Our global transposition table
|
|||
|
||||
void TranspositionTable::resize(size_t mbSize) {
|
||||
|
||||
size_t newClusterCount = size_t(1) << msb((mbSize * 1024 * 1024) / sizeof(Cluster));
|
||||
size_t newClusterCount = mbSize * 1024 * 1024 / sizeof(Cluster);
|
||||
|
||||
if (newClusterCount == clusterCount)
|
||||
return;
|
||||
|
@ -41,7 +41,7 @@ void TranspositionTable::resize(size_t mbSize) {
|
|||
clusterCount = newClusterCount;
|
||||
|
||||
free(mem);
|
||||
mem = calloc(clusterCount * sizeof(Cluster) + CacheLineSize - 1, 1);
|
||||
mem = malloc(clusterCount * sizeof(Cluster) + CacheLineSize - 1);
|
||||
|
||||
if (!mem)
|
||||
{
|
||||
|
@ -51,6 +51,7 @@ void TranspositionTable::resize(size_t mbSize) {
|
|||
}
|
||||
|
||||
table = (Cluster*)((uintptr_t(mem) + CacheLineSize - 1) & ~(CacheLineSize - 1));
|
||||
clear();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
||||
Copyright (C) 2015-2017 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
|
||||
Stockfish is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -104,9 +104,9 @@ public:
|
|||
void resize(size_t mbSize);
|
||||
void clear();
|
||||
|
||||
// The lowest order bits of the key are used to get the index of the cluster
|
||||
// The 32 lowest order bits of the key are used to get the index of the cluster
|
||||
TTEntry* first_entry(const Key key) const {
|
||||
return &table[(size_t)key & (clusterCount - 1)].entry[0];
|
||||
return &table[(uint32_t(key) * uint64_t(clusterCount)) >> 32].entry[0];
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
||||
Copyright (C) 2015-2017 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
|
||||
Stockfish is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -146,7 +146,7 @@ enum CastlingRight {
|
|||
};
|
||||
|
||||
template<Color C, CastlingSide S> struct MakeCastling {
|
||||
static const CastlingRight
|
||||
static constexpr CastlingRight
|
||||
right = C == WHITE ? S == QUEEN_SIDE ? WHITE_OOO : WHITE_OO
|
||||
: S == QUEEN_SIDE ? BLACK_OOO : BLACK_OO;
|
||||
};
|
||||
|
@ -195,6 +195,7 @@ enum Value : int {
|
|||
enum PieceType {
|
||||
NO_PIECE_TYPE, PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING,
|
||||
ALL_PIECES = 0,
|
||||
QUEEN_DIAGONAL = 7,
|
||||
PIECE_TYPE_NB = 8
|
||||
};
|
||||
|
||||
|
@ -222,7 +223,7 @@ enum Depth : int {
|
|||
|
||||
static_assert(!(ONE_PLY & (ONE_PLY - 1)), "ONE_PLY is not a power of 2");
|
||||
|
||||
enum Square {
|
||||
enum Square : int {
|
||||
SQ_A1, SQ_B1, SQ_C1, SQ_D1, SQ_E1, SQ_F1, SQ_G1, SQ_H1,
|
||||
SQ_A2, SQ_B2, SQ_C2, SQ_D2, SQ_E2, SQ_F2, SQ_G2, SQ_H2,
|
||||
SQ_A3, SQ_B3, SQ_C3, SQ_D3, SQ_E3, SQ_F3, SQ_G3, SQ_H3,
|
||||
|
@ -233,8 +234,10 @@ enum Square {
|
|||
SQ_A8, SQ_B8, SQ_C8, SQ_D8, SQ_E8, SQ_F8, SQ_G8, SQ_H8,
|
||||
SQ_NONE,
|
||||
|
||||
SQUARE_NB = 64,
|
||||
SQUARE_NB = 64
|
||||
};
|
||||
|
||||
enum Direction : int {
|
||||
NORTH = 8,
|
||||
EAST = 1,
|
||||
SOUTH = -NORTH,
|
||||
|
@ -261,7 +264,7 @@ enum Rank : int {
|
|||
/// care to avoid left-shifting a signed int to avoid undefined behavior.
|
||||
enum Score : int { SCORE_ZERO };
|
||||
|
||||
inline Score make_score(int mg, int eg) {
|
||||
constexpr Score make_score(int mg, int eg) {
|
||||
return Score((int)((unsigned int)eg << 16) + mg);
|
||||
}
|
||||
|
||||
|
@ -269,58 +272,68 @@ inline Score make_score(int mg, int eg) {
|
|||
/// according to the standard a simple cast to short is implementation defined
|
||||
/// and so is a right shift of a signed integer.
|
||||
inline Value eg_value(Score s) {
|
||||
|
||||
union { uint16_t u; int16_t s; } eg = { uint16_t(unsigned(s + 0x8000) >> 16) };
|
||||
return Value(eg.s);
|
||||
}
|
||||
|
||||
inline Value mg_value(Score s) {
|
||||
|
||||
union { uint16_t u; int16_t s; } mg = { uint16_t(unsigned(s)) };
|
||||
return Value(mg.s);
|
||||
}
|
||||
|
||||
#define ENABLE_BASE_OPERATORS_ON(T) \
|
||||
inline T operator+(T d1, T d2) { return T(int(d1) + int(d2)); } \
|
||||
inline T operator-(T d1, T d2) { return T(int(d1) - int(d2)); } \
|
||||
inline T operator-(T d) { return T(-int(d)); } \
|
||||
inline T& operator+=(T& d1, T d2) { return d1 = d1 + d2; } \
|
||||
inline T& operator-=(T& d1, T d2) { return d1 = d1 - d2; } \
|
||||
#define ENABLE_BASE_OPERATORS_ON(T) \
|
||||
constexpr T operator+(T d1, T d2) { return T(int(d1) + int(d2)); } \
|
||||
constexpr T operator-(T d1, T d2) { return T(int(d1) - int(d2)); } \
|
||||
constexpr T operator-(T d) { return T(-int(d)); } \
|
||||
inline T& operator+=(T& d1, T d2) { return d1 = d1 + d2; } \
|
||||
inline T& operator-=(T& d1, T d2) { return d1 = d1 - d2; }
|
||||
|
||||
#define ENABLE_FULL_OPERATORS_ON(T) \
|
||||
ENABLE_BASE_OPERATORS_ON(T) \
|
||||
inline T operator*(int i, T d) { return T(i * int(d)); } \
|
||||
inline T operator*(T d, int i) { return T(int(d) * i); } \
|
||||
inline T& operator++(T& d) { return d = T(int(d) + 1); } \
|
||||
inline T& operator--(T& d) { return d = T(int(d) - 1); } \
|
||||
inline T operator/(T d, int i) { return T(int(d) / i); } \
|
||||
inline int operator/(T d1, T d2) { return int(d1) / int(d2); } \
|
||||
inline T& operator*=(T& d, int i) { return d = T(int(d) * i); } \
|
||||
#define ENABLE_INCR_OPERATORS_ON(T) \
|
||||
inline T& operator++(T& d) { return d = T(int(d) + 1); } \
|
||||
inline T& operator--(T& d) { return d = T(int(d) - 1); }
|
||||
|
||||
#define ENABLE_FULL_OPERATORS_ON(T) \
|
||||
ENABLE_BASE_OPERATORS_ON(T) \
|
||||
ENABLE_INCR_OPERATORS_ON(T) \
|
||||
constexpr T operator*(int i, T d) { return T(i * int(d)); } \
|
||||
constexpr T operator*(T d, int i) { return T(int(d) * i); } \
|
||||
constexpr T operator/(T d, int i) { return T(int(d) / i); } \
|
||||
constexpr int operator/(T d1, T d2) { return int(d1) / int(d2); } \
|
||||
inline T& operator*=(T& d, int i) { return d = T(int(d) * i); } \
|
||||
inline T& operator/=(T& d, int i) { return d = T(int(d) / i); }
|
||||
|
||||
ENABLE_FULL_OPERATORS_ON(Value)
|
||||
ENABLE_FULL_OPERATORS_ON(PieceType)
|
||||
ENABLE_FULL_OPERATORS_ON(Piece)
|
||||
ENABLE_FULL_OPERATORS_ON(Color)
|
||||
ENABLE_FULL_OPERATORS_ON(Depth)
|
||||
ENABLE_FULL_OPERATORS_ON(Square)
|
||||
ENABLE_FULL_OPERATORS_ON(File)
|
||||
ENABLE_FULL_OPERATORS_ON(Rank)
|
||||
ENABLE_FULL_OPERATORS_ON(Direction)
|
||||
|
||||
ENABLE_INCR_OPERATORS_ON(PieceType)
|
||||
ENABLE_INCR_OPERATORS_ON(Piece)
|
||||
ENABLE_INCR_OPERATORS_ON(Color)
|
||||
ENABLE_INCR_OPERATORS_ON(Square)
|
||||
ENABLE_INCR_OPERATORS_ON(File)
|
||||
ENABLE_INCR_OPERATORS_ON(Rank)
|
||||
|
||||
ENABLE_BASE_OPERATORS_ON(Score)
|
||||
|
||||
#undef ENABLE_FULL_OPERATORS_ON
|
||||
#undef ENABLE_INCR_OPERATORS_ON
|
||||
#undef ENABLE_BASE_OPERATORS_ON
|
||||
|
||||
/// Additional operators to add integers to a Value
|
||||
inline Value operator+(Value v, int i) { return Value(int(v) + i); }
|
||||
inline Value operator-(Value v, int i) { return Value(int(v) - i); }
|
||||
constexpr Value operator+(Value v, int i) { return Value(int(v) + i); }
|
||||
constexpr Value operator-(Value v, int i) { return Value(int(v) - i); }
|
||||
inline Value& operator+=(Value& v, int i) { return v = v + i; }
|
||||
inline Value& operator-=(Value& v, int i) { return v = v - i; }
|
||||
|
||||
/// Additional operators to add a Direction to a Square
|
||||
inline Square operator+(Square s, Direction d) { return Square(int(s) + int(d)); }
|
||||
inline Square operator-(Square s, Direction d) { return Square(int(s) - int(d)); }
|
||||
inline Square& operator+=(Square &s, Direction d) { return s = s + d; }
|
||||
inline Square& operator-=(Square &s, Direction d) { return s = s - d; }
|
||||
|
||||
/// Only declared but not defined. We don't want to multiply two scores due to
|
||||
/// a very high risk of overflow. So user should explicitly convert to integer.
|
||||
inline Score operator*(Score s1, Score s2);
|
||||
Score operator*(Score, Score) = delete;
|
||||
|
||||
/// Division of a Score must be handled separately for each term
|
||||
inline Score operator/(Score s, int i) {
|
||||
|
@ -339,39 +352,43 @@ inline Score operator*(Score s, int i) {
|
|||
return result;
|
||||
}
|
||||
|
||||
inline Color operator~(Color c) {
|
||||
constexpr Color operator~(Color c) {
|
||||
return Color(c ^ BLACK); // Toggle color
|
||||
}
|
||||
|
||||
inline Square operator~(Square s) {
|
||||
constexpr Square operator~(Square s) {
|
||||
return Square(s ^ SQ_A8); // Vertical flip SQ_A1 -> SQ_A8
|
||||
}
|
||||
|
||||
inline Piece operator~(Piece pc) {
|
||||
constexpr File operator~(File f) {
|
||||
return File(f ^ FILE_H); // Horizontal flip FILE_A -> FILE_H
|
||||
}
|
||||
|
||||
constexpr Piece operator~(Piece pc) {
|
||||
return Piece(pc ^ 8); // Swap color of piece B_KNIGHT -> W_KNIGHT
|
||||
}
|
||||
|
||||
inline CastlingRight operator|(Color c, CastlingSide s) {
|
||||
constexpr CastlingRight operator|(Color c, CastlingSide s) {
|
||||
return CastlingRight(WHITE_OO << ((s == QUEEN_SIDE) + 2 * c));
|
||||
}
|
||||
|
||||
inline Value mate_in(int ply) {
|
||||
constexpr Value mate_in(int ply) {
|
||||
return VALUE_MATE - ply;
|
||||
}
|
||||
|
||||
inline Value mated_in(int ply) {
|
||||
constexpr Value mated_in(int ply) {
|
||||
return -VALUE_MATE + ply;
|
||||
}
|
||||
|
||||
inline Square make_square(File f, Rank r) {
|
||||
constexpr Square make_square(File f, Rank r) {
|
||||
return Square((r << 3) + f);
|
||||
}
|
||||
|
||||
inline Piece make_piece(Color c, PieceType pt) {
|
||||
constexpr Piece make_piece(Color c, PieceType pt) {
|
||||
return Piece((c << 3) + pt);
|
||||
}
|
||||
|
||||
inline PieceType type_of(Piece pc) {
|
||||
constexpr PieceType type_of(Piece pc) {
|
||||
return PieceType(pc & 7);
|
||||
}
|
||||
|
||||
|
@ -380,27 +397,27 @@ inline Color color_of(Piece pc) {
|
|||
return Color(pc >> 3);
|
||||
}
|
||||
|
||||
inline bool is_ok(Square s) {
|
||||
constexpr bool is_ok(Square s) {
|
||||
return s >= SQ_A1 && s <= SQ_H8;
|
||||
}
|
||||
|
||||
inline File file_of(Square s) {
|
||||
constexpr File file_of(Square s) {
|
||||
return File(s & 7);
|
||||
}
|
||||
|
||||
inline Rank rank_of(Square s) {
|
||||
constexpr Rank rank_of(Square s) {
|
||||
return Rank(s >> 3);
|
||||
}
|
||||
|
||||
inline Square relative_square(Color c, Square s) {
|
||||
constexpr Square relative_square(Color c, Square s) {
|
||||
return Square(s ^ (c * 56));
|
||||
}
|
||||
|
||||
inline Rank relative_rank(Color c, Rank r) {
|
||||
constexpr Rank relative_rank(Color c, Rank r) {
|
||||
return Rank(r ^ (c * 7));
|
||||
}
|
||||
|
||||
inline Rank relative_rank(Color c, Square s) {
|
||||
constexpr Rank relative_rank(Color c, Square s) {
|
||||
return relative_rank(c, rank_of(s));
|
||||
}
|
||||
|
||||
|
@ -409,27 +426,27 @@ inline bool opposite_colors(Square s1, Square s2) {
|
|||
return ((s >> 3) ^ s) & 1;
|
||||
}
|
||||
|
||||
inline Square pawn_push(Color c) {
|
||||
constexpr Direction pawn_push(Color c) {
|
||||
return c == WHITE ? NORTH : SOUTH;
|
||||
}
|
||||
|
||||
inline Square from_sq(Move m) {
|
||||
constexpr Square from_sq(Move m) {
|
||||
return Square((m >> 6) & 0x3F);
|
||||
}
|
||||
|
||||
inline Square to_sq(Move m) {
|
||||
constexpr Square to_sq(Move m) {
|
||||
return Square(m & 0x3F);
|
||||
}
|
||||
|
||||
inline int from_to(Move m) {
|
||||
constexpr int from_to(Move m) {
|
||||
return m & 0xFFF;
|
||||
}
|
||||
|
||||
inline MoveType type_of(Move m) {
|
||||
constexpr MoveType type_of(Move m) {
|
||||
return MoveType(m & (3 << 14));
|
||||
}
|
||||
|
||||
inline PieceType promotion_type(Move m) {
|
||||
constexpr PieceType promotion_type(Move m) {
|
||||
return PieceType(((m >> 12) & 3) + KNIGHT);
|
||||
}
|
||||
|
||||
|
@ -438,11 +455,11 @@ inline Move make_move(Square from, Square to) {
|
|||
}
|
||||
|
||||
template<MoveType T>
|
||||
inline Move make(Square from, Square to, PieceType pt = KNIGHT) {
|
||||
constexpr Move make(Square from, Square to, PieceType pt = KNIGHT) {
|
||||
return Move(T + ((pt - KNIGHT) << 12) + (from << 6) + to);
|
||||
}
|
||||
|
||||
inline bool is_ok(Move m) {
|
||||
constexpr bool is_ok(Move m) {
|
||||
return from_sq(m) != to_sq(m); // Catch MOVE_NULL and MOVE_NONE
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
||||
Copyright (C) 2015-2017 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
|
||||
Stockfish is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
||||
Copyright (C) 2015-2017 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
|
||||
Stockfish is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
||||
Copyright (C) 2015-2017 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
||||
|
||||
Stockfish is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -55,17 +55,20 @@ bool CaseInsensitiveLess::operator() (const string& s1, const string& s2) const
|
|||
|
||||
void init(OptionsMap& o) {
|
||||
|
||||
const int MaxHashMB = Is64Bit ? 1024 * 1024 : 2048;
|
||||
// at most 2^32 clusters.
|
||||
const int MaxHashMB = Is64Bit ? 131072 : 2048;
|
||||
|
||||
o["Debug Log File"] << Option("", on_logger);
|
||||
o["Contempt"] << Option(0, -100, 100);
|
||||
o["Contempt"] << Option(20, -100, 100);
|
||||
o["Threads"] << Option(1, 1, 512, on_threads);
|
||||
o["Hash"] << Option(16, 1, MaxHashMB, on_hash_size);
|
||||
o["Clear Hash"] << Option(on_clear_hash);
|
||||
o["Ponder"] << Option(false);
|
||||
o["MultiPV"] << Option(1, 1, 500);
|
||||
o["Skill Level"] << Option(20, 0, 20);
|
||||
o["Move Overhead"] << Option(60, 0, 5000);
|
||||
o["Move Overhead"] << Option(30, 0, 5000);
|
||||
o["Minimum Thinking Time"] << Option(20, 0, 5000);
|
||||
o["Slow Mover"] << Option(89, 10, 1000);
|
||||
o["nodestime"] << Option(0, 0, 10000);
|
||||
o["UCI_Chess960"] << Option(false);
|
||||
o["SyzygyPath"] << Option("<empty>", on_tb_path);
|
||||
|
|
Loading…
Reference in New Issue
Block a user