mirror of
https://github.com/peterosterlund2/droidfish.git
synced 2025-12-17 19:22:18 +01:00
DroidFish: Update to stockfish 9.
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
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
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
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
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
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
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
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[WHITE] = Square((idx >> 0) & 0x3F);
|
||||||
ksq[BLACK] = Square((idx >> 6) & 0x3F);
|
ksq[BLACK] = Square((idx >> 6) & 0x3F);
|
||||||
us = Color ((idx >> 12) & 0x01);
|
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
|
// Check if two pieces are on the same square or if a king can be captured
|
||||||
if ( distance(ksq[WHITE], ksq[BLACK]) <= 1
|
if ( distance(ksq[WHITE], ksq[BLACK]) <= 1
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
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
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
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 RookTable[0x19000]; // To store rook attacks
|
||||||
Bitboard BishopTable[0x1480]; // To store bishop 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
|
// 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.
|
// 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 (Square s = SQ_A1; s <= SQ_H8; ++s)
|
||||||
for (int i = 0; steps[pt][i]; ++i)
|
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)
|
if (is_ok(to) && distance(s, to) < 3)
|
||||||
{
|
{
|
||||||
@@ -199,11 +199,11 @@ void Bitboards::init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Square RookDeltas[] = { NORTH, EAST, SOUTH, WEST };
|
Direction RookDirections[] = { NORTH, EAST, SOUTH, WEST };
|
||||||
Square BishopDeltas[] = { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST };
|
Direction BishopDirections[] = { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST };
|
||||||
|
|
||||||
init_magics(RookTable, RookMagics, RookDeltas);
|
init_magics(RookTable, RookMagics, RookDirections);
|
||||||
init_magics(BishopTable, BishopMagics, BishopDeltas);
|
init_magics(BishopTable, BishopMagics, BishopDirections);
|
||||||
|
|
||||||
for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1)
|
for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1)
|
||||||
{
|
{
|
||||||
@@ -225,14 +225,14 @@ void Bitboards::init() {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
Bitboard sliding_attack(Square deltas[], Square sq, Bitboard occupied) {
|
Bitboard sliding_attack(Direction directions[], Square sq, Bitboard occupied) {
|
||||||
|
|
||||||
Bitboard attack = 0;
|
Bitboard attack = 0;
|
||||||
|
|
||||||
for (int i = 0; i < 4; ++i)
|
for (int i = 0; i < 4; ++i)
|
||||||
for (Square s = sq + deltas[i];
|
for (Square s = sq + directions[i];
|
||||||
is_ok(s) && distance(s, s - deltas[i]) == 1;
|
is_ok(s) && distance(s, s - directions[i]) == 1;
|
||||||
s += deltas[i])
|
s += directions[i])
|
||||||
{
|
{
|
||||||
attack |= s;
|
attack |= s;
|
||||||
|
|
||||||
@@ -249,7 +249,7 @@ namespace {
|
|||||||
// chessprogramming.wikispaces.com/Magic+Bitboards. In particular, here we
|
// chessprogramming.wikispaces.com/Magic+Bitboards. In particular, here we
|
||||||
// use the so called "fancy" approach.
|
// 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
|
// Optimal PRNG seeds to pick the correct magics in the shortest time
|
||||||
int seeds[][RANK_NB] = { { 8977, 44560, 54343, 38998, 5731, 95205, 104912, 17020 },
|
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
|
// 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.
|
// apply to the 64 or 32 bits word to get the index.
|
||||||
Magic& m = magics[s];
|
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);
|
m.shift = (Is64Bit ? 64 : 32) - popcount(m.mask);
|
||||||
|
|
||||||
// Set the offset for the attacks table of the square. We have individual
|
// Set the offset for the attacks table of the square. We have individual
|
||||||
@@ -281,7 +281,7 @@ namespace {
|
|||||||
b = size = 0;
|
b = size = 0;
|
||||||
do {
|
do {
|
||||||
occupancy[size] = b;
|
occupancy[size] = b;
|
||||||
reference[size] = sliding_attack(deltas, s, b);
|
reference[size] = sliding_attack(directions, s, b);
|
||||||
|
|
||||||
if (HasPext)
|
if (HasPext)
|
||||||
m.attacks[pext(b, m.mask)] = reference[size];
|
m.attacks[pext(b, m.mask)] = reference[size];
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
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
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
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];
|
return b ^= SquareBB[s];
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool more_than_one(Bitboard b) {
|
constexpr bool more_than_one(Bitboard b) {
|
||||||
return b & (b - 1);
|
return b & (b - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// rank_bb() and file_bb() return a bitboard representing all the squares on
|
/// rank_bb() and file_bb() return a bitboard representing all the squares on
|
||||||
/// the given file or rank.
|
/// 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
|
/// shift() moves a bitboard one step along direction D. Mainly for pawns
|
||||||
|
|
||||||
template<Square D>
|
template<Direction D>
|
||||||
inline Bitboard shift(Bitboard b) {
|
constexpr Bitboard shift(Bitboard b) {
|
||||||
return D == NORTH ? b << 8 : D == SOUTH ? b >> 8
|
return D == NORTH ? b << 8 : D == SOUTH ? b >> 8
|
||||||
: D == NORTH_EAST ? (b & ~FileHBB) << 9 : D == SOUTH_EAST ? (b & ~FileHBB) >> 7
|
: D == NORTH_EAST ? (b & ~FileHBB) << 9 : D == SOUTH_EAST ? (b & ~FileHBB) >> 7
|
||||||
: D == NORTH_WEST ? (b & ~FileABB) << 7 : D == SOUTH_WEST ? (b & ~FileABB) >> 9
|
: 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
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
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
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
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 bsq = pos.square<BISHOP>(weakSide);
|
||||||
Square psq = pos.square<PAWN>(strongSide);
|
Square psq = pos.square<PAWN>(strongSide);
|
||||||
Rank rk = relative_rank(strongSide, psq);
|
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
|
// 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
|
// 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
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
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
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
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
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
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
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -31,12 +31,21 @@
|
|||||||
|
|
||||||
namespace {
|
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 {
|
namespace Trace {
|
||||||
|
|
||||||
enum Tracing {NO_TRACE, TRACE};
|
enum Tracing {NO_TRACE, TRACE};
|
||||||
|
|
||||||
enum Term { // The first 8 entries are for PieceType
|
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];
|
double scores[TERM_NB][COLOR_NB][PHASE_NB];
|
||||||
@@ -54,7 +63,7 @@ namespace {
|
|||||||
|
|
||||||
std::ostream& operator<<(std::ostream& os, Term t) {
|
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 << " --- --- | --- --- | ";
|
os << " --- --- | --- --- | ";
|
||||||
else
|
else
|
||||||
os << std::setw(5) << scores[t][WHITE][MG] << " "
|
os << std::setw(5) << scores[t][WHITE][MG] << " "
|
||||||
@@ -88,6 +97,7 @@ namespace {
|
|||||||
template<Color Us> void initialize();
|
template<Color Us> void initialize();
|
||||||
template<Color Us> Score evaluate_king();
|
template<Color Us> Score evaluate_king();
|
||||||
template<Color Us> Score evaluate_threats();
|
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_passed_pawns();
|
||||||
template<Color Us> Score evaluate_space();
|
template<Color Us> Score evaluate_space();
|
||||||
template<Color Us, PieceType Pt> Score evaluate_pieces();
|
template<Color Us, PieceType Pt> Score evaluate_pieces();
|
||||||
@@ -102,7 +112,8 @@ namespace {
|
|||||||
Score mobility[COLOR_NB] = { SCORE_ZERO, SCORE_ZERO };
|
Score mobility[COLOR_NB] = { SCORE_ZERO, SCORE_ZERO };
|
||||||
|
|
||||||
// attackedBy[color][piece type] is a bitboard representing all squares
|
// 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];
|
Bitboard attackedBy[COLOR_NB][PIECE_TYPE_NB];
|
||||||
|
|
||||||
// attackedBy2[color] are the squares attacked by 2 pieces of a given color,
|
// 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
|
// supported by a pawn. If the minor piece occupies an outpost square
|
||||||
// then score is doubled.
|
// then score is doubled.
|
||||||
const Score Outpost[][2] = {
|
const Score Outpost[][2] = {
|
||||||
{ S(22, 6), S(33, 9) }, // Knight
|
{ S(22, 6), S(36,12) }, // Knight
|
||||||
{ S( 9, 2), S(14, 4) } // Bishop
|
{ S( 9, 2), S(15, 5) } // Bishop
|
||||||
};
|
};
|
||||||
|
|
||||||
// RookOnFile[semiopen/open] contains bonuses for each rook when there is no
|
// 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.
|
// 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.
|
// We don't use a Score because we process the two components independently.
|
||||||
const Value Passed[][RANK_NB] = {
|
const Value Passed[][RANK_NB] = {
|
||||||
{ V(5), V( 5), V(31), V(73), V(166), V(252) },
|
{ V(0), 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(7), V(14), V(38), V(73), V(166), V(252) }
|
||||||
};
|
};
|
||||||
|
|
||||||
// PassedFile[File] contains a bonus according to the file of a passed pawn
|
// 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)
|
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
|
// 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) };
|
const Score KingProtector[] = { S(-3, -5), S(-4, -3), S(-3, 0), S(-1, 1) };
|
||||||
|
|
||||||
// Assorted bonuses and penalties used by evaluation
|
// Assorted bonuses and penalties used by evaluation
|
||||||
const Score MinorBehindPawn = S( 16, 0);
|
const Score MinorBehindPawn = S( 16, 0);
|
||||||
const Score BishopPawns = S( 8, 12);
|
const Score BishopPawns = S( 8, 12);
|
||||||
const Score RookOnPawn = S( 8, 24);
|
const Score LongRangedBishop = S( 22, 0);
|
||||||
const Score TrappedRook = S( 92, 0);
|
const Score RookOnPawn = S( 8, 24);
|
||||||
const Score WeakQueen = S( 50, 10);
|
const Score TrappedRook = S( 92, 0);
|
||||||
const Score OtherCheck = S( 10, 10);
|
const Score WeakQueen = S( 50, 10);
|
||||||
const Score CloseEnemies = S( 7, 0);
|
const Score CloseEnemies = S( 7, 0);
|
||||||
const Score PawnlessFlank = S( 20, 80);
|
const Score PawnlessFlank = S( 20, 80);
|
||||||
const Score ThreatByHangingPawn = S( 71, 61);
|
const Score ThreatBySafePawn = S(192,175);
|
||||||
const Score ThreatBySafePawn = S(182,175);
|
const Score ThreatByRank = S( 16, 3);
|
||||||
const Score ThreatByRank = S( 16, 3);
|
const Score Hanging = S( 48, 27);
|
||||||
const Score Hanging = S( 48, 27);
|
const Score WeakUnopposedPawn = S( 5, 25);
|
||||||
const Score ThreatByPawnPush = S( 38, 22);
|
const Score ThreatByPawnPush = S( 38, 22);
|
||||||
const Score HinderPassedPawn = S( 7, 0);
|
const Score ThreatByAttackOnQueen = S( 38, 22);
|
||||||
const Score TrappedBishopA1H1 = S( 50, 50);
|
const Score HinderPassedPawn = S( 7, 0);
|
||||||
|
const Score TrappedBishopA1H1 = S( 50, 50);
|
||||||
|
|
||||||
#undef S
|
#undef S
|
||||||
#undef V
|
#undef V
|
||||||
@@ -225,10 +240,10 @@ namespace {
|
|||||||
const int KingAttackWeights[PIECE_TYPE_NB] = { 0, 0, 78, 56, 45, 11 };
|
const int KingAttackWeights[PIECE_TYPE_NB] = { 0, 0, 78, 56, 45, 11 };
|
||||||
|
|
||||||
// Penalties for enemy's safe checks
|
// Penalties for enemy's safe checks
|
||||||
const int QueenCheck = 780;
|
const int QueenSafeCheck = 780;
|
||||||
const int RookCheck = 880;
|
const int RookSafeCheck = 880;
|
||||||
const int BishopCheck = 435;
|
const int BishopSafeCheck = 435;
|
||||||
const int KnightCheck = 790;
|
const int KnightSafeCheck = 790;
|
||||||
|
|
||||||
// Threshold for lazy and space evaluation
|
// Threshold for lazy and space evaluation
|
||||||
const Value LazyThreshold = Value(1500);
|
const Value LazyThreshold = Value(1500);
|
||||||
@@ -241,9 +256,9 @@ namespace {
|
|||||||
template<Tracing T> template<Color Us>
|
template<Tracing T> template<Color Us>
|
||||||
void Evaluation<T>::initialize() {
|
void Evaluation<T>::initialize() {
|
||||||
|
|
||||||
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
||||||
const Square Up = (Us == WHITE ? NORTH : SOUTH);
|
const Direction Up = (Us == WHITE ? NORTH : SOUTH);
|
||||||
const Square Down = (Us == WHITE ? SOUTH : NORTH);
|
const Direction Down = (Us == WHITE ? SOUTH : NORTH);
|
||||||
const Bitboard LowRanks = (Us == WHITE ? Rank2BB | Rank3BB: Rank7BB | Rank6BB);
|
const Bitboard LowRanks = (Us == WHITE ? Rank2BB | Rank3BB: Rank7BB | Rank6BB);
|
||||||
|
|
||||||
// Find our pawns on the first two ranks, and those which are blocked
|
// Find our pawns on the first two ranks, and those which are blocked
|
||||||
@@ -292,11 +307,14 @@ namespace {
|
|||||||
|
|
||||||
attackedBy[Us][Pt] = 0;
|
attackedBy[Us][Pt] = 0;
|
||||||
|
|
||||||
|
if (Pt == QUEEN)
|
||||||
|
attackedBy[Us][QUEEN_DIAGONAL] = 0;
|
||||||
|
|
||||||
while ((s = *pl++) != SQ_NONE)
|
while ((s = *pl++) != SQ_NONE)
|
||||||
{
|
{
|
||||||
// Find attacked squares, including x-ray attacks for bishops and rooks
|
// Find attacked squares, including x-ray attacks for bishops and rooks
|
||||||
b = Pt == BISHOP ? attacks_bb<BISHOP>(s, pos.pieces() ^ pos.pieces(Us, QUEEN))
|
b = Pt == BISHOP ? attacks_bb<BISHOP>(s, pos.pieces() ^ pos.pieces(QUEEN))
|
||||||
: Pt == ROOK ? attacks_bb< ROOK>(s, pos.pieces() ^ pos.pieces(Us, ROOK, QUEEN))
|
: Pt == ROOK ? attacks_bb< ROOK>(s, pos.pieces() ^ pos.pieces(QUEEN) ^ pos.pieces(Us, ROOK))
|
||||||
: pos.attacks_from<Pt>(s);
|
: pos.attacks_from<Pt>(s);
|
||||||
|
|
||||||
if (pos.pinned_pieces(Us) & s)
|
if (pos.pinned_pieces(Us) & s)
|
||||||
@@ -305,6 +323,9 @@ namespace {
|
|||||||
attackedBy2[Us] |= attackedBy[Us][ALL_PIECES] & b;
|
attackedBy2[Us] |= attackedBy[Us][ALL_PIECES] & b;
|
||||||
attackedBy[Us][ALL_PIECES] |= attackedBy[Us][Pt] |= b;
|
attackedBy[Us][ALL_PIECES] |= attackedBy[Us][Pt] |= b;
|
||||||
|
|
||||||
|
if (Pt == QUEEN)
|
||||||
|
attackedBy[Us][QUEEN_DIAGONAL] |= b & PseudoAttacks[BISHOP][s];
|
||||||
|
|
||||||
if (b & kingRing[Them])
|
if (b & kingRing[Them])
|
||||||
{
|
{
|
||||||
kingAttackersCount[Us]++;
|
kingAttackersCount[Us]++;
|
||||||
@@ -324,12 +345,12 @@ namespace {
|
|||||||
// Bonus for outpost squares
|
// Bonus for outpost squares
|
||||||
bb = OutpostRanks & ~pe->pawn_attacks_span(Them);
|
bb = OutpostRanks & ~pe->pawn_attacks_span(Them);
|
||||||
if (bb & s)
|
if (bb & s)
|
||||||
score += Outpost[Pt == BISHOP][!!(attackedBy[Us][PAWN] & s)] * 2;
|
score += Outpost[Pt == BISHOP][bool(attackedBy[Us][PAWN] & s)] * 2;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
bb &= b & ~pos.pieces(Us);
|
bb &= b & ~pos.pieces(Us);
|
||||||
if (bb)
|
if (bb)
|
||||||
score += Outpost[Pt == BISHOP][!!(attackedBy[Us][PAWN] & bb)];
|
score += Outpost[Pt == BISHOP][bool(attackedBy[Us][PAWN] & bb)];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bonus when behind a pawn
|
// Bonus when behind a pawn
|
||||||
@@ -337,10 +358,16 @@ namespace {
|
|||||||
&& (pos.pieces(PAWN) & (s + pawn_push(Us))))
|
&& (pos.pieces(PAWN) & (s + pawn_push(Us))))
|
||||||
score += MinorBehindPawn;
|
score += MinorBehindPawn;
|
||||||
|
|
||||||
// Penalty for pawns on the same color square as the bishop
|
|
||||||
if (Pt == 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);
|
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
|
// An important Chess960 pattern: A cornered bishop blocked by a friendly
|
||||||
// pawn diagonally in front of it is a very serious problem, especially
|
// pawn diagonally in front of it is a very serious problem, especially
|
||||||
// when that pawn is also blocked.
|
// when that pawn is also blocked.
|
||||||
@@ -348,7 +375,7 @@ namespace {
|
|||||||
&& pos.is_chess960()
|
&& pos.is_chess960()
|
||||||
&& (s == relative_square(Us, SQ_A1) || s == relative_square(Us, SQ_H1)))
|
&& (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))
|
if (pos.piece_on(s + d) == make_piece(Us, PAWN))
|
||||||
score -= !pos.empty(s + d + pawn_push(Us)) ? TrappedBishopA1H1 * 4
|
score -= !pos.empty(s + d + pawn_push(Us)) ? TrappedBishopA1H1 * 4
|
||||||
: pos.piece_on(s + d + d) == make_piece(Us, PAWN) ? TrappedBishopA1H1 * 2
|
: 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
|
// Bonus when on an open or semi-open file
|
||||||
if (pe->semiopen_file(Us, file_of(s)))
|
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
|
// Penalty when trapped by the king, even more if the king cannot castle
|
||||||
else if (mob <= 3)
|
else if (mob <= 3)
|
||||||
@@ -395,25 +422,15 @@ namespace {
|
|||||||
|
|
||||||
// evaluate_king() assigns bonuses and penalties to a king of a given color
|
// 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>
|
template<Tracing T> template<Color Us>
|
||||||
Score Evaluation<T>::evaluate_king() {
|
Score Evaluation<T>::evaluate_king() {
|
||||||
|
|
||||||
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
||||||
const Square Up = (Us == WHITE ? NORTH : SOUTH);
|
const Bitboard Camp = (Us == WHITE ? AllSquares ^ Rank6BB ^ Rank7BB ^ Rank8BB
|
||||||
const Bitboard Camp = (Us == WHITE ? AllSquares ^ Rank6BB ^ Rank7BB ^ Rank8BB
|
: AllSquares ^ Rank1BB ^ Rank2BB ^ Rank3BB);
|
||||||
: AllSquares ^ Rank1BB ^ Rank2BB ^ Rank3BB);
|
|
||||||
|
|
||||||
const Square ksq = pos.square<KING>(Us);
|
const Square ksq = pos.square<KING>(Us);
|
||||||
Bitboard kingOnlyDefended, undefended, b, b1, b2, safe, other;
|
Bitboard weak, b, b1, b2, safe, unsafeChecks;
|
||||||
int kingDanger;
|
|
||||||
|
|
||||||
// King shelter and enemy pawns storm
|
// King shelter and enemy pawns storm
|
||||||
Score score = pe->king_safety<Us>(pos, ksq);
|
Score score = pe->king_safety<Us>(pos, ksq);
|
||||||
@@ -421,78 +438,65 @@ namespace {
|
|||||||
// Main king safety evaluation
|
// Main king safety evaluation
|
||||||
if (kingAttackersCount[Them] > (1 - pos.count<QUEEN>(Them)))
|
if (kingAttackersCount[Them] > (1 - pos.count<QUEEN>(Them)))
|
||||||
{
|
{
|
||||||
// Find the attacked squares which are defended only by our king...
|
// Attacked squares defended at most once by our queen or king
|
||||||
kingOnlyDefended = attackedBy[Them][ALL_PIECES]
|
weak = attackedBy[Them][ALL_PIECES]
|
||||||
& attackedBy[Us][KING]
|
& ~attackedBy2[Us]
|
||||||
& ~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
|
int kingDanger = unsafeChecks = 0;
|
||||||
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;
|
|
||||||
|
|
||||||
// Analyse the safe enemy's checks which are possible on next move
|
// Analyse the safe enemy's checks which are possible on next move
|
||||||
safe = ~pos.pieces(Them);
|
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);
|
b1 = attacks_bb<ROOK >(ksq, pos.pieces() ^ pos.pieces(Us, QUEEN));
|
||||||
b2 = pos.attacks_from<BISHOP>(ksq);
|
b2 = attacks_bb<BISHOP>(ksq, pos.pieces() ^ pos.pieces(Us, QUEEN));
|
||||||
|
|
||||||
// Enemy queen safe checks
|
// Enemy queen safe checks
|
||||||
if ((b1 | b2) & attackedBy[Them][QUEEN] & safe)
|
if ((b1 | b2) & attackedBy[Them][QUEEN] & safe & ~attackedBy[Us][QUEEN])
|
||||||
kingDanger += QueenCheck;
|
kingDanger += QueenSafeCheck;
|
||||||
|
|
||||||
// For minors and rooks, also consider the square safe if attacked twice,
|
b1 &= attackedBy[Them][ROOK];
|
||||||
// and only defended by our queen.
|
b2 &= attackedBy[Them][BISHOP];
|
||||||
safe |= attackedBy2[Them]
|
|
||||||
& ~(attackedBy2[Us] | pos.pieces(Them))
|
|
||||||
& attackedBy[Us][QUEEN];
|
|
||||||
|
|
||||||
// Some other potential checks are also analysed, even from squares
|
// Enemy rooks checks
|
||||||
// currently occupied by the opponent own pieces, as long as the square
|
if (b1 & safe)
|
||||||
// is not attacked by our pawns, and is not occupied by a blocked pawn.
|
kingDanger += RookSafeCheck;
|
||||||
other = ~( attackedBy[Us][PAWN]
|
else
|
||||||
| (pos.pieces(Them, PAWN) & shift<Up>(pos.pieces(PAWN))));
|
unsafeChecks |= b1;
|
||||||
|
|
||||||
// Enemy rooks safe and other checks
|
// Enemy bishops checks
|
||||||
if (b1 & attackedBy[Them][ROOK] & safe)
|
if (b2 & safe)
|
||||||
kingDanger += RookCheck;
|
kingDanger += BishopSafeCheck;
|
||||||
|
else
|
||||||
|
unsafeChecks |= b2;
|
||||||
|
|
||||||
else if (b1 & attackedBy[Them][ROOK] & other)
|
// Enemy knights checks
|
||||||
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
|
|
||||||
b = pos.attacks_from<KNIGHT>(ksq) & attackedBy[Them][KNIGHT];
|
b = pos.attacks_from<KNIGHT>(ksq) & attackedBy[Them][KNIGHT];
|
||||||
if (b & safe)
|
if (b & safe)
|
||||||
kingDanger += KnightCheck;
|
kingDanger += KnightSafeCheck;
|
||||||
|
else
|
||||||
|
unsafeChecks |= b;
|
||||||
|
|
||||||
else if (b & other)
|
// Unsafe or occupied checking squares will also be considered, as long as
|
||||||
score -= OtherCheck;
|
// 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)
|
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);
|
score -= make_score(kingDanger * kingDanger / 4096, kingDanger / 16);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// King tropism: firstly, find squares that opponent attacks in our king flank
|
// King tropism: firstly, find squares that opponent attacks in our king flank
|
||||||
@@ -526,11 +530,11 @@ namespace {
|
|||||||
template<Tracing T> template<Color Us>
|
template<Tracing T> template<Color Us>
|
||||||
Score Evaluation<T>::evaluate_threats() {
|
Score Evaluation<T>::evaluate_threats() {
|
||||||
|
|
||||||
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
||||||
const Square Up = (Us == WHITE ? NORTH : SOUTH);
|
const Direction Up = (Us == WHITE ? NORTH : SOUTH);
|
||||||
const Square Left = (Us == WHITE ? NORTH_WEST : SOUTH_EAST);
|
const Direction Left = (Us == WHITE ? NORTH_WEST : SOUTH_EAST);
|
||||||
const Square Right = (Us == WHITE ? NORTH_EAST : SOUTH_WEST);
|
const Direction Right = (Us == WHITE ? NORTH_EAST : SOUTH_WEST);
|
||||||
const Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB);
|
const Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB);
|
||||||
|
|
||||||
Bitboard b, weak, defended, stronglyProtected, safeThreats;
|
Bitboard b, weak, defended, stronglyProtected, safeThreats;
|
||||||
Score score = SCORE_ZERO;
|
Score score = SCORE_ZERO;
|
||||||
@@ -546,9 +550,6 @@ namespace {
|
|||||||
safeThreats = (shift<Right>(b) | shift<Left>(b)) & weak;
|
safeThreats = (shift<Right>(b) | shift<Left>(b)) & weak;
|
||||||
|
|
||||||
score += ThreatBySafePawn * popcount(safeThreats);
|
score += ThreatBySafePawn * popcount(safeThreats);
|
||||||
|
|
||||||
if (weak ^ safeThreats)
|
|
||||||
score += ThreatByHangingPawn;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Squares strongly protected by the opponent, either because they attack the
|
// Squares strongly protected by the opponent, either because they attack the
|
||||||
@@ -593,6 +594,10 @@ namespace {
|
|||||||
score += ThreatByKing[more_than_one(b)];
|
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
|
// Find squares where our pawns can push on the next move
|
||||||
b = shift<Up>(pos.pieces(Us, PAWN)) & ~pos.pieces();
|
b = shift<Up>(pos.pieces(Us, PAWN)) & ~pos.pieces();
|
||||||
b |= shift<Up>(b & TRank3BB) & ~pos.pieces();
|
b |= shift<Up>(b & TRank3BB) & ~pos.pieces();
|
||||||
@@ -608,12 +613,24 @@ namespace {
|
|||||||
|
|
||||||
score += ThreatByPawnPush * popcount(b);
|
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)
|
if (T)
|
||||||
Trace::add(THREAT, Us, score);
|
Trace::add(THREAT, Us, score);
|
||||||
|
|
||||||
return 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
|
// evaluate_passed_pawns() evaluates the passed pawns and candidate passed
|
||||||
// pawns of the given color.
|
// pawns of the given color.
|
||||||
@@ -621,8 +638,8 @@ namespace {
|
|||||||
template<Tracing T> template<Color Us>
|
template<Tracing T> template<Color Us>
|
||||||
Score Evaluation<T>::evaluate_passed_pawns() {
|
Score Evaluation<T>::evaluate_passed_pawns() {
|
||||||
|
|
||||||
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
||||||
const Square Up = (Us == WHITE ? NORTH : SOUTH);
|
const Direction Up = (Us == WHITE ? NORTH : SOUTH);
|
||||||
|
|
||||||
Bitboard b, bb, squaresToQueen, defendedSquares, unsafeSquares;
|
Bitboard b, bb, squaresToQueen, defendedSquares, unsafeSquares;
|
||||||
Score score = SCORE_ZERO;
|
Score score = SCORE_ZERO;
|
||||||
@@ -638,8 +655,8 @@ namespace {
|
|||||||
bb = forward_file_bb(Us, s) & (attackedBy[Them][ALL_PIECES] | pos.pieces(Them));
|
bb = forward_file_bb(Us, s) & (attackedBy[Them][ALL_PIECES] | pos.pieces(Them));
|
||||||
score -= HinderPassedPawn * popcount(bb);
|
score -= HinderPassedPawn * popcount(bb);
|
||||||
|
|
||||||
int r = relative_rank(Us, s) - RANK_2;
|
int r = relative_rank(Us, s);
|
||||||
int rr = r * (r - 1);
|
int rr = RankFactor[r];
|
||||||
|
|
||||||
Value mbonus = Passed[MG][r], ebonus = Passed[EG][r];
|
Value mbonus = Passed[MG][r], ebonus = Passed[EG][r];
|
||||||
|
|
||||||
@@ -648,12 +665,11 @@ namespace {
|
|||||||
Square blockSq = s + Up;
|
Square blockSq = s + Up;
|
||||||
|
|
||||||
// Adjust bonus based on the king's proximity
|
// Adjust bonus based on the king's proximity
|
||||||
ebonus += distance(pos.square<KING>(Them), blockSq) * 5 * rr
|
ebonus += (king_distance(Them, blockSq) * 5 - king_distance(Us, blockSq) * 2) * rr;
|
||||||
- distance(pos.square<KING>( Us), blockSq) * 2 * rr;
|
|
||||||
|
|
||||||
// If blockSq is not the queening square then consider also a second push
|
// If blockSq is not the queening square then consider also a second push
|
||||||
if (relative_rank(Us, blockSq) != RANK_8)
|
if (r != RANK_7)
|
||||||
ebonus -= distance(pos.square<KING>(Us), blockSq + Up) * rr;
|
ebonus -= king_distance(Us, blockSq + Up) * rr;
|
||||||
|
|
||||||
// If the pawn is free to advance, then increase the bonus
|
// If the pawn is free to advance, then increase the bonus
|
||||||
if (pos.empty(blockSq))
|
if (pos.empty(blockSq))
|
||||||
@@ -762,6 +778,9 @@ namespace {
|
|||||||
// that the endgame score will never change sign after the bonus.
|
// that the endgame score will never change sign after the bonus.
|
||||||
int v = ((eg > 0) - (eg < 0)) * std::max(initiative, -abs(eg));
|
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);
|
return make_score(0, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -822,7 +841,7 @@ namespace {
|
|||||||
// Initialize score by reading the incrementally updated scores included in
|
// Initialize score by reading the incrementally updated scores included in
|
||||||
// the position object (material + piece square tables) and the material
|
// the position object (material + piece square tables) and the material
|
||||||
// imbalance. Score is computed internally from the white point of view.
|
// 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
|
// Probe the pawn hash table
|
||||||
pe = Pawns::probe(pos);
|
pe = Pawns::probe(pos);
|
||||||
@@ -880,18 +899,19 @@ namespace {
|
|||||||
Trace::add(TOTAL, score);
|
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
|
} // namespace
|
||||||
|
|
||||||
|
Score Eval::Contempt = SCORE_ZERO;
|
||||||
|
|
||||||
/// evaluate() is the evaluator for the outer world. It returns a static evaluation
|
/// 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.
|
/// of the position from the point of view of the side to move.
|
||||||
|
|
||||||
Value Eval::evaluate(const Position& pos)
|
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
|
/// 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));
|
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
|
v = pos.side_to_move() == WHITE ? v : -v; // White's point of view
|
||||||
|
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
@@ -922,6 +942,7 @@ std::string Eval::trace(const Position& pos) {
|
|||||||
<< " Threats | " << Term(THREAT)
|
<< " Threats | " << Term(THREAT)
|
||||||
<< " Passed pawns | " << Term(PASSED)
|
<< " Passed pawns | " << Term(PASSED)
|
||||||
<< " Space | " << Term(SPACE)
|
<< " Space | " << Term(SPACE)
|
||||||
|
<< " Initiative | " << Term(INITIATIVE)
|
||||||
<< "----------------+-------------+-------------+-------------\n"
|
<< "----------------+-------------+-------------+-------------\n"
|
||||||
<< " Total | " << Term(TOTAL);
|
<< " Total | " << Term(TOTAL);
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
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
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
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
|
const Value Tempo = Value(20); // Must be visible to search
|
||||||
|
|
||||||
|
extern Score Contempt;
|
||||||
|
|
||||||
std::string trace(const Position& pos);
|
std::string trace(const Position& pos);
|
||||||
|
|
||||||
Value evaluate(const Position& pos);
|
Value evaluate(const Position& pos);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
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
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
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();
|
Pawns::init();
|
||||||
Tablebases::init(Options["SyzygyPath"]);
|
Tablebases::init(Options["SyzygyPath"]);
|
||||||
TT.resize(Options["Hash"]);
|
TT.resize(Options["Hash"]);
|
||||||
Threads.init(Options["Threads"]);
|
Threads.set(Options["Threads"]);
|
||||||
Search::clear(); // After threads are up
|
Search::clear(); // After threads are up
|
||||||
|
|
||||||
UCI::loop(argc, argv);
|
UCI::loop(argc, argv);
|
||||||
|
|
||||||
Threads.exit();
|
Threads.set(0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
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
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -39,7 +39,7 @@ namespace {
|
|||||||
{ 32, 255, -3 }, // Knight OUR PIECES
|
{ 32, 255, -3 }, // Knight OUR PIECES
|
||||||
{ 0, 104, 4, 0 }, // Bishop
|
{ 0, 104, 4, 0 }, // Bishop
|
||||||
{ -26, -2, 47, 105, -149 }, // Rook
|
{ -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] = {
|
const int QuadraticTheirs[][PIECE_TYPE_NB] = {
|
||||||
@@ -50,18 +50,7 @@ namespace {
|
|||||||
{ 9, 63, 0 }, // Knight OUR PIECES
|
{ 9, 63, 0 }, // Knight OUR PIECES
|
||||||
{ 59, 65, 42, 0 }, // Bishop
|
{ 59, 65, 42, 0 }, // Bishop
|
||||||
{ 46, 39, 24, -24, 0 }, // Rook
|
{ 46, 39, 24, -24, 0 }, // Rook
|
||||||
{ 101, 100, -37, 141, 268, 0 } // Queen
|
{ 97, 100, -42, 137, 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
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Endgame evaluation and scaling functions are accessed directly and not through
|
// Endgame evaluation and scaling functions are accessed directly and not through
|
||||||
@@ -100,9 +89,9 @@ namespace {
|
|||||||
|
|
||||||
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
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)
|
for (int pt1 = NO_PIECE_TYPE; pt1 <= QUEEN; ++pt1)
|
||||||
{
|
{
|
||||||
if (!pieceCount[Us][pt1])
|
if (!pieceCount[Us][pt1])
|
||||||
@@ -117,10 +106,6 @@ namespace {
|
|||||||
bonus += pieceCount[Us][pt1] * v;
|
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;
|
return bonus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
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
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
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
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
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
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
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
|
/// Version number. If Version is left empty, then compile date in the format
|
||||||
/// DD-MM-YY and show in engine_info.
|
/// 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
|
/// 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
|
/// 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) {
|
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
|
// Use only local variables to be thread-safe
|
||||||
int group = get_group(idx);
|
int group = get_group(idx);
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
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
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
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
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
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
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -42,8 +42,8 @@ namespace {
|
|||||||
|
|
||||||
assert(!pos.checkers());
|
assert(!pos.checkers());
|
||||||
|
|
||||||
const Square K = Chess960 ? kto > kfrom ? WEST : EAST
|
const Direction K = Chess960 ? kto > kfrom ? WEST : EAST
|
||||||
: KingSide ? WEST : EAST;
|
: KingSide ? WEST : EAST;
|
||||||
|
|
||||||
for (Square s = kto; s != kfrom; s += K)
|
for (Square s = kto; s != kfrom; s += K)
|
||||||
if (pos.attackers_to(s) & enemies)
|
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) {
|
ExtMove* make_promotions(ExtMove* moveList, Square to, Square ksq) {
|
||||||
|
|
||||||
if (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS)
|
if (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS)
|
||||||
@@ -94,13 +94,13 @@ namespace {
|
|||||||
|
|
||||||
// Compute our parametrized parameters at compile time, named according to
|
// Compute our parametrized parameters at compile time, named according to
|
||||||
// the point of view of white side.
|
// the point of view of white side.
|
||||||
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
||||||
const Bitboard TRank8BB = (Us == WHITE ? Rank8BB : Rank1BB);
|
const Bitboard TRank8BB = (Us == WHITE ? Rank8BB : Rank1BB);
|
||||||
const Bitboard TRank7BB = (Us == WHITE ? Rank7BB : Rank2BB);
|
const Bitboard TRank7BB = (Us == WHITE ? Rank7BB : Rank2BB);
|
||||||
const Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB);
|
const Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB);
|
||||||
const Square Up = (Us == WHITE ? NORTH : SOUTH);
|
const Direction Up = (Us == WHITE ? NORTH : SOUTH);
|
||||||
const Square Right = (Us == WHITE ? NORTH_EAST : SOUTH_WEST);
|
const Direction Right = (Us == WHITE ? NORTH_EAST : SOUTH_WEST);
|
||||||
const Square Left = (Us == WHITE ? NORTH_WEST : SOUTH_EAST);
|
const Direction Left = (Us == WHITE ? NORTH_WEST : SOUTH_EAST);
|
||||||
|
|
||||||
Bitboard emptySquares;
|
Bitboard emptySquares;
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
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
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
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
|
// Inhibit unwanted implicit conversions to Move
|
||||||
// with an ambiguity that yields to a compile error.
|
// 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) {
|
inline bool operator<(const ExtMove& f, const ExtMove& s) {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
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
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
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 constructor for the main search
|
||||||
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh,
|
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh,
|
||||||
const PieceToHistory** ch, Move cm, Move* killers_p)
|
const CapturePieceToHistory* cph, const PieceToHistory** ch, Move cm, Move* killers_p)
|
||||||
: pos(p), mainHistory(mh), contHistory(ch), countermove(cm),
|
: pos(p), mainHistory(mh), captureHistory(cph), contHistory(ch), countermove(cm),
|
||||||
killers{killers_p[0], killers_p[1]}, depth(d){
|
killers{killers_p[0], killers_p[1]}, depth(d){
|
||||||
|
|
||||||
assert(d > DEPTH_ZERO);
|
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 constructor for quiescence search
|
||||||
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh, Square s)
|
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh, const CapturePieceToHistory* cph, Square s)
|
||||||
: pos(p), mainHistory(mh) {
|
: pos(p), mainHistory(mh), captureHistory(cph) {
|
||||||
|
|
||||||
assert(d <= DEPTH_ZERO);
|
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
|
/// MovePicker constructor for ProbCut: we generate captures with SEE higher
|
||||||
/// than or equal to the given threshold.
|
/// than or equal to the given threshold.
|
||||||
MovePicker::MovePicker(const Position& p, Move ttm, Value th)
|
MovePicker::MovePicker(const Position& p, Move ttm, Value th, const CapturePieceToHistory* cph)
|
||||||
: pos(p), threshold(th) {
|
: pos(p), captureHistory(cph), threshold(th) {
|
||||||
|
|
||||||
assert(!pos.checkers());
|
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.
|
/// score() assigns a numerical value to each move in a list, used for sorting.
|
||||||
/// Captures are ordered by Most Valuable Victim (MVV), preferring captures
|
/// 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>
|
template<GenType Type>
|
||||||
void MovePicker::score() {
|
void MovePicker::score() {
|
||||||
|
|
||||||
@@ -132,7 +132,7 @@ void MovePicker::score() {
|
|||||||
for (auto& m : *this)
|
for (auto& m : *this)
|
||||||
if (Type == CAPTURES)
|
if (Type == CAPTURES)
|
||||||
m.value = PieceValue[MG][pos.piece_on(to_sq(m))]
|
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)
|
else if (Type == QUIETS)
|
||||||
m.value = (*mainHistory)[pos.side_to_move()][from_to(m)]
|
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);
|
move = pick_best(cur++, endMoves);
|
||||||
if (move != ttMove)
|
if (move != ttMove)
|
||||||
{
|
{
|
||||||
if (pos.see_ge(move))
|
if (pos.see_ge(move, Value(-55 * (cur-1)->value / 1024)))
|
||||||
return move;
|
return move;
|
||||||
|
|
||||||
// Losing capture, move it to the beginning of the array
|
// 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
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
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
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -22,6 +22,7 @@
|
|||||||
#define MOVEPICK_H_INCLUDED
|
#define MOVEPICK_H_INCLUDED
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
#include "movegen.h"
|
#include "movegen.h"
|
||||||
#include "position.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) {
|
void update(T& entry, int bonus, const int D) {
|
||||||
|
|
||||||
assert(abs(bonus) <= D); // Ensure range is [-32 * D, 32 * 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;
|
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
|
/// ButterflyBoards are 2 tables (one for each color) indexed by the move's from
|
||||||
/// and to squares, see chessprogramming.wikispaces.com/Butterfly+Boards
|
/// and to squares, see chessprogramming.wikispaces.com/Butterfly+Boards
|
||||||
typedef StatBoards<COLOR_NB, int(SQUARE_NB) * int(SQUARE_NB)> ButterflyBoards;
|
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
|
/// PieceToBoards are addressed by a move's [piece][to] information
|
||||||
typedef StatBoards<PIECE_NB, SQUARE_NB> PieceToBoards;
|
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
|
/// ButterflyHistory records how often quiet moves have been successful or
|
||||||
/// unsuccessful during the current search, and is used for reduction and move
|
/// unsuccessful during the current search, and is used for reduction and move
|
||||||
/// ordering decisions. It uses ButterflyBoards as backing store.
|
/// 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
|
/// CounterMoveHistory stores counter moves indexed by [piece][to] of the previous
|
||||||
/// move, see chessprogramming.wikispaces.com/Countermove+Heuristic
|
/// move, see chessprogramming.wikispaces.com/Countermove+Heuristic
|
||||||
typedef StatBoards<PIECE_NB, SQUARE_NB, Move> CounterMoveHistory;
|
typedef StatBoards<PIECE_NB, SQUARE_NB, Move> CounterMoveHistory;
|
||||||
@@ -93,9 +125,9 @@ class MovePicker {
|
|||||||
public:
|
public:
|
||||||
MovePicker(const MovePicker&) = delete;
|
MovePicker(const MovePicker&) = delete;
|
||||||
MovePicker& operator=(const MovePicker&) = delete;
|
MovePicker& operator=(const MovePicker&) = delete;
|
||||||
MovePicker(const Position&, Move, Value);
|
MovePicker(const Position&, Move, Value, const CapturePieceToHistory*);
|
||||||
MovePicker(const Position&, Move, Depth, const ButterflyHistory*, Square);
|
MovePicker(const Position&, Move, Depth, const ButterflyHistory*, const CapturePieceToHistory*, Square);
|
||||||
MovePicker(const Position&, Move, Depth, const ButterflyHistory*, const PieceToHistory**, Move, Move*);
|
MovePicker(const Position&, Move, Depth, const ButterflyHistory*, const CapturePieceToHistory*, const PieceToHistory**, Move, Move*);
|
||||||
Move next_move(bool skipQuiets = false);
|
Move next_move(bool skipQuiets = false);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -105,6 +137,7 @@ private:
|
|||||||
|
|
||||||
const Position& pos;
|
const Position& pos;
|
||||||
const ButterflyHistory* mainHistory;
|
const ButterflyHistory* mainHistory;
|
||||||
|
const CapturePieceToHistory* captureHistory;
|
||||||
const PieceToHistory** contHistory;
|
const PieceToHistory** contHistory;
|
||||||
Move ttMove, countermove, killers[2];
|
Move ttMove, countermove, killers[2];
|
||||||
ExtMove *cur, *endMoves, *endBadCaptures;
|
ExtMove *cur, *endMoves, *endBadCaptures;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
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
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -31,11 +31,11 @@ namespace {
|
|||||||
#define V Value
|
#define V Value
|
||||||
#define S(mg, eg) make_score(mg, eg)
|
#define S(mg, eg) make_score(mg, eg)
|
||||||
|
|
||||||
// Isolated pawn penalty by opposed flag
|
// Isolated pawn penalty
|
||||||
const Score Isolated[] = { S(27, 30), S(13, 18) };
|
const Score Isolated = S(13, 18);
|
||||||
|
|
||||||
// Backward pawn penalty by opposed flag
|
// Backward pawn penalty
|
||||||
const Score Backward[] = { S(40, 26), S(24, 12) };
|
const Score Backward = S(24, 12);
|
||||||
|
|
||||||
// Connected pawn bonus by opposed, phalanx, #support and rank
|
// Connected pawn bonus by opposed, phalanx, #support and rank
|
||||||
Score Connected[2][2][3][RANK_NB];
|
Score Connected[2][2][3][RANK_NB];
|
||||||
@@ -43,12 +43,6 @@ namespace {
|
|||||||
// Doubled pawn penalty
|
// Doubled pawn penalty
|
||||||
const Score Doubled = S(18, 38);
|
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].
|
// 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.
|
// 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] = {
|
const Value ShelterWeakness[][int(FILE_NB) / 2][RANK_NB] = {
|
||||||
@@ -94,10 +88,10 @@ namespace {
|
|||||||
template<Color Us>
|
template<Color Us>
|
||||||
Score evaluate(const Position& pos, Pawns::Entry* e) {
|
Score evaluate(const Position& pos, Pawns::Entry* e) {
|
||||||
|
|
||||||
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
||||||
const Square Up = (Us == WHITE ? NORTH : SOUTH);
|
const Direction Up = (Us == WHITE ? NORTH : SOUTH);
|
||||||
const Square Right = (Us == WHITE ? NORTH_EAST : SOUTH_WEST);
|
const Direction Right = (Us == WHITE ? NORTH_EAST : SOUTH_WEST);
|
||||||
const Square Left = (Us == WHITE ? NORTH_WEST : SOUTH_EAST);
|
const Direction Left = (Us == WHITE ? NORTH_WEST : SOUTH_EAST);
|
||||||
|
|
||||||
Bitboard b, neighbours, stoppers, doubled, supported, phalanx;
|
Bitboard b, neighbours, stoppers, doubled, supported, phalanx;
|
||||||
Bitboard lever, leverPush;
|
Bitboard lever, leverPush;
|
||||||
@@ -109,7 +103,7 @@ namespace {
|
|||||||
Bitboard ourPawns = pos.pieces( Us, PAWN);
|
Bitboard ourPawns = pos.pieces( Us, PAWN);
|
||||||
Bitboard theirPawns = pos.pieces(Them, 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->semiopenFiles[Us] = 0xFF;
|
||||||
e->kingSquares[Us] = SQ_NONE;
|
e->kingSquares[Us] = SQ_NONE;
|
||||||
e->pawnAttacks[Us] = shift<Right>(ourPawns) | shift<Left>(ourPawns);
|
e->pawnAttacks[Us] = shift<Right>(ourPawns) | shift<Left>(ourPawns);
|
||||||
@@ -174,19 +168,16 @@ namespace {
|
|||||||
|
|
||||||
// Score this pawn
|
// Score this pawn
|
||||||
if (supported | phalanx)
|
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)
|
else if (!neighbours)
|
||||||
score -= Isolated[opposed];
|
score -= Isolated, e->weakUnopposed[Us] += !opposed;
|
||||||
|
|
||||||
else if (backward)
|
else if (backward)
|
||||||
score -= Backward[opposed];
|
score -= Backward, e->weakUnopposed[Us] += !opposed;
|
||||||
|
|
||||||
if (doubled && !supported)
|
if (doubled && !supported)
|
||||||
score -= Doubled;
|
score -= Doubled;
|
||||||
|
|
||||||
if (lever)
|
|
||||||
score += Lever[relative_rank(Us, s)];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return score;
|
return score;
|
||||||
@@ -254,7 +245,7 @@ Value Entry::shelter_storm(const Position& pos, Square ksq) {
|
|||||||
Value safety = MaxSafetyBonus;
|
Value safety = MaxSafetyBonus;
|
||||||
File center = std::max(FILE_B, std::min(FILE_G, file_of(ksq)));
|
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);
|
b = ourPawns & file_bb(f);
|
||||||
Rank rkUs = b ? relative_rank(Us, backmost_sq(Us, b)) : RANK_1;
|
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);
|
b = theirPawns & file_bb(f);
|
||||||
Rank rkThem = b ? relative_rank(Us, frontmost_sq(Them, b)) : RANK_1;
|
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]
|
safety -= ShelterWeakness[f == file_of(ksq)][d][rkUs]
|
||||||
+ StormDanger
|
+ StormDanger
|
||||||
[f == file_of(ksq) && rkThem == relative_rank(Us, ksq) + 1 ? BlockedByKing :
|
[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
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
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
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
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 pawn_attacks(Color c) const { return pawnAttacks[c]; }
|
||||||
Bitboard passed_pawns(Color c) const { return passedPawns[c]; }
|
Bitboard passed_pawns(Color c) const { return passedPawns[c]; }
|
||||||
Bitboard pawn_attacks_span(Color c) const { return pawnAttacksSpan[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 pawn_asymmetry() const { return asymmetry; }
|
||||||
int open_files() const { return openFiles; }
|
int open_files() const { return openFiles; }
|
||||||
|
|
||||||
@@ -49,7 +50,7 @@ struct Entry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int pawns_on_same_color_squares(Color c, Square s) const {
|
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>
|
template<Color Us>
|
||||||
@@ -71,6 +72,7 @@ struct Entry {
|
|||||||
Bitboard pawnAttacksSpan[COLOR_NB];
|
Bitboard pawnAttacksSpan[COLOR_NB];
|
||||||
Square kingSquares[COLOR_NB];
|
Square kingSquares[COLOR_NB];
|
||||||
Score kingSafety[COLOR_NB];
|
Score kingSafety[COLOR_NB];
|
||||||
|
int weakUnopposed[COLOR_NB];
|
||||||
int castlingRights[COLOR_NB];
|
int castlingRights[COLOR_NB];
|
||||||
int semiopenFiles[COLOR_NB];
|
int semiopenFiles[COLOR_NB];
|
||||||
int pawnsOnSquares[COLOR_NB][COLOR_NB]; // [color][light/dark squares]
|
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
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
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
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
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))
|
while ((ss >> token) && !isspace(token))
|
||||||
{
|
{
|
||||||
if (isdigit(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 == '/')
|
else if (token == '/')
|
||||||
sq -= Square(16);
|
sq += 2 * SOUTH;
|
||||||
|
|
||||||
else if ((idx = PieceToChar.find(token)) != string::npos)
|
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
|
// 5-6. Halfmove clock and fullmove number
|
||||||
ss >> std::skipws >> st->rule50 >> gamePly;
|
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.
|
// handle also common incorrect FEN with fullmove = 0.
|
||||||
gamePly = std::max(2 * (gamePly - 1), 0) + (sideToMove == BLACK);
|
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
|
if ( (int(to) ^ int(from)) == 16
|
||||||
&& (attacks_from<PAWN>(to - pawn_push(us), us) & pieces(them, PAWN)))
|
&& (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)];
|
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
|
Value balance; // Values of the pieces taken by us minus opponent's ones
|
||||||
Bitboard occupied, stmAttackers;
|
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;
|
return false;
|
||||||
|
|
||||||
|
// Now assume the worst possible result: that the opponent can
|
||||||
|
// capture our piece for free.
|
||||||
balance -= PieceValue[MG][nextVictim];
|
balance -= PieceValue[MG][nextVictim];
|
||||||
|
|
||||||
if (balance >= threshold) // Always true if nextVictim == KING
|
if (balance >= VALUE_ZERO) // Always true if nextVictim == KING
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
bool relativeStm = true; // True if the opponent is to move
|
bool opponentToMove = true;
|
||||||
occupied = pieces() ^ from ^ to;
|
occupied = pieces() ^ from ^ to;
|
||||||
|
|
||||||
// Find all attackers to the destination square, with the moving piece removed,
|
// 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)
|
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);
|
stmAttackers = attackers & pieces(stm);
|
||||||
|
|
||||||
// Don't allow pinned pieces to attack pieces except the king as long all
|
// 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))
|
if (!(st->pinnersForKing[stm] & ~occupied))
|
||||||
stmAttackers &= ~st->blockersForKing[stm];
|
stmAttackers &= ~st->blockersForKing[stm];
|
||||||
|
|
||||||
|
// If we have no more attackers we must give up
|
||||||
if (!stmAttackers)
|
if (!stmAttackers)
|
||||||
return relativeStm;
|
break;
|
||||||
|
|
||||||
// Locate and remove the next least valuable attacker
|
// Locate and remove the next least valuable attacker
|
||||||
nextVictim = min_attacker<PAWN>(byTypeBB, to, stmAttackers, occupied, attackers);
|
nextVictim = min_attacker<PAWN>(byTypeBB, to, stmAttackers, occupied, attackers);
|
||||||
|
|
||||||
if (nextVictim == KING)
|
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]
|
// Assume the opponent can win the next piece for free and switch sides
|
||||||
: -PieceValue[MG][nextVictim];
|
balance += PieceValue[MG][nextVictim];
|
||||||
|
opponentToMove = !opponentToMove;
|
||||||
|
|
||||||
relativeStm = !relativeStm;
|
// If balance is negative after receiving a free piece then give up
|
||||||
|
if (balance < VALUE_ZERO)
|
||||||
if (relativeStm == (balance >= threshold))
|
break;
|
||||||
return relativeStm;
|
|
||||||
|
|
||||||
|
// 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;
|
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;
|
stp = stp->previous->previous;
|
||||||
|
|
||||||
// At root position ply is 1, so return a draw score if a position
|
// Return a draw score if a position repeats once earlier but strictly
|
||||||
// repeats once earlier but strictly after the root, or repeats twice
|
// after the root, or repeats twice before or at the root.
|
||||||
// before or at the root.
|
|
||||||
if ( stp->key == st->key
|
if ( stp->key == st->key
|
||||||
&& ++cnt + (ply - 1 > i) == 2)
|
&& ++cnt + (ply > i) == 2)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
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
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
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
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
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
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
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)
|
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] = v + Bonus[pc][rank_of(s)][f];
|
||||||
psq[~pc][~s] = -psq[pc][s];
|
psq[~pc][~s] = -psq[pc][s];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
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
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
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 };
|
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
|
// Razoring and futility margin based on depth
|
||||||
// razor_margin[0] is unused as long as depth >= ONE_PLY in search
|
const int razor_margin = 600;
|
||||||
const int razor_margin[] = { 0, 570, 603, 554 };
|
|
||||||
Value futility_margin(Depth d) { return Value(150 * d / ONE_PLY); }
|
Value futility_margin(Depth d) { return Value(150 * d / ONE_PLY); }
|
||||||
|
|
||||||
// Futility and reductions lookup tables, initialized at startup
|
// Futility and reductions lookup tables, initialized at startup
|
||||||
@@ -87,58 +86,15 @@ namespace {
|
|||||||
|
|
||||||
// Skill structure is used to implement strength limit
|
// Skill structure is used to implement strength limit
|
||||||
struct Skill {
|
struct Skill {
|
||||||
Skill(int l) : level(l) {}
|
explicit Skill(int l) : level(l) {}
|
||||||
bool enabled() const { return level < 20; }
|
bool enabled() const { return level < 20; }
|
||||||
bool time_to_pick(Depth depth) const { return depth / ONE_PLY == 1 + level; }
|
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);
|
Move pick_best(size_t multiPV);
|
||||||
|
|
||||||
int level;
|
int level;
|
||||||
Move best = MOVE_NONE;
|
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>
|
template <NodeType NT>
|
||||||
Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, bool cutNode, bool skipEarlyPruning);
|
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_pv(Move* pv, Move move, Move* childPv);
|
||||||
void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus);
|
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_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
|
// 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.
|
// 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;
|
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);
|
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
|
// Increase reduction for non-PV nodes when eval is not improving
|
||||||
@@ -214,12 +172,7 @@ void Search::clear() {
|
|||||||
|
|
||||||
Time.availableNodes = 0;
|
Time.availableNodes = 0;
|
||||||
TT.clear();
|
TT.clear();
|
||||||
|
Threads.clear();
|
||||||
for (Thread* th : Threads)
|
|
||||||
th->clear();
|
|
||||||
|
|
||||||
Threads.main()->callsCnt = 0;
|
|
||||||
Threads.main()->previousScore = VALUE_INFINITE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -240,8 +193,9 @@ void MainThread::search() {
|
|||||||
TT.new_search();
|
TT.new_search();
|
||||||
|
|
||||||
int contempt = Options["Contempt"] * PawnValueEg / 100; // From centipawns
|
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())
|
if (rootMoves.empty())
|
||||||
{
|
{
|
||||||
@@ -259,11 +213,6 @@ void MainThread::search() {
|
|||||||
Thread::search(); // Let's start searching!
|
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
|
// 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,
|
// 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
|
// the UCI protocol states that we shouldn't print the best move before the
|
||||||
@@ -283,10 +232,14 @@ void MainThread::search() {
|
|||||||
if (th != this)
|
if (th != this)
|
||||||
th->wait_for_search_finished();
|
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
|
// Check if there are threads with a better score than main thread
|
||||||
Thread* bestThread = this;
|
Thread* bestThread = this;
|
||||||
if ( !this->easyMovePlayed
|
if ( Options["MultiPV"] == 1
|
||||||
&& Options["MultiPV"] == 1
|
|
||||||
&& !Limits.depth
|
&& !Limits.depth
|
||||||
&& !Skill(Options["Skill Level"]).enabled()
|
&& !Skill(Options["Skill Level"]).enabled()
|
||||||
&& rootMoves[0].pv[0] != MOVE_NONE)
|
&& rootMoves[0].pv[0] != MOVE_NONE)
|
||||||
@@ -324,10 +277,12 @@ void MainThread::search() {
|
|||||||
|
|
||||||
void Thread::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;
|
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);
|
MainThread* mainThread = (this == Threads.main() ? Threads.main() : nullptr);
|
||||||
|
double timeReduction = 1.0;
|
||||||
|
|
||||||
std::memset(ss-4, 0, 7 * sizeof(Stack));
|
std::memset(ss-4, 0, 7 * sizeof(Stack));
|
||||||
for (int i = 4; i > 0; i--)
|
for (int i = 4; i > 0; i--)
|
||||||
@@ -338,9 +293,7 @@ void Thread::search() {
|
|||||||
|
|
||||||
if (mainThread)
|
if (mainThread)
|
||||||
{
|
{
|
||||||
easyMove = EasyMove.get(rootPos.key());
|
mainThread->failedLow = false;
|
||||||
EasyMove.clear();
|
|
||||||
mainThread->easyMovePlayed = mainThread->failedLow = false;
|
|
||||||
mainThread->bestMoveChanges = 0;
|
mainThread->bestMoveChanges = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -453,6 +406,11 @@ void Thread::search() {
|
|||||||
if (!Threads.stop)
|
if (!Threads.stop)
|
||||||
completedDepth = rootDepth;
|
completedDepth = rootDepth;
|
||||||
|
|
||||||
|
if (rootMoves[0].pv[0] != lastBestMove) {
|
||||||
|
lastBestMove = rootMoves[0].pv[0];
|
||||||
|
lastBestMoveDepth = rootDepth;
|
||||||
|
}
|
||||||
|
|
||||||
// Have we found a "mate in x"?
|
// Have we found a "mate in x"?
|
||||||
if ( Limits.mate
|
if ( Limits.mate
|
||||||
&& bestValue >= VALUE_MATE_IN_MAX_PLY
|
&& bestValue >= VALUE_MATE_IN_MAX_PLY
|
||||||
@@ -472,21 +430,29 @@ void Thread::search() {
|
|||||||
if (!Threads.stop && !Threads.stopOnPonderhit)
|
if (!Threads.stop && !Threads.stopOnPonderhit)
|
||||||
{
|
{
|
||||||
// Stop the search if only one legal move is available, or if all
|
// 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
|
// of the available time has been used
|
||||||
// from the previous search and just did a fast verification.
|
|
||||||
const int F[] = { mainThread->failedLow,
|
const int F[] = { mainThread->failedLow,
|
||||||
bestValue - mainThread->previousScore };
|
bestValue - mainThread->previousScore };
|
||||||
|
|
||||||
int improvingFactor = std::max(229, std::min(715, 357 + 119 * F[0] - 6 * F[1]));
|
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
|
Color us = rootPos.side_to_move();
|
||||||
&& mainThread->bestMoveChanges < 0.03
|
bool thinkHard = bestValue == VALUE_DRAW
|
||||||
&& Time.elapsed() > Time.optimum() * 5 / 44;
|
&& 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
|
if ( rootMoves.size() == 1
|
||||||
|| Time.elapsed() > Time.optimum() * unstablePvFactor * improvingFactor / 628
|
|| Time.elapsed() > Time.optimum() * unstablePvFactor * improvingFactor / 628)
|
||||||
|| (mainThread->easyMovePlayed = doEasyMove, doEasyMove))
|
|
||||||
{
|
{
|
||||||
// If we are allowed to ponder do not stop the search now but
|
// If we are allowed to ponder do not stop the search now but
|
||||||
// keep pondering until the GUI sends "ponderhit" or "stop".
|
// keep pondering until the GUI sends "ponderhit" or "stop".
|
||||||
@@ -496,26 +462,18 @@ void Thread::search() {
|
|||||||
Threads.stop = true;
|
Threads.stop = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rootMoves[0].pv.size() >= 3)
|
|
||||||
EasyMove.update(rootPos, rootMoves[0].pv);
|
|
||||||
else
|
|
||||||
EasyMove.clear();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mainThread)
|
if (!mainThread)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Clear any candidate easy move that wasn't stable for the last search
|
mainThread->previousTimeReduction = timeReduction;
|
||||||
// iterations; the second condition prevents consecutive fast moves.
|
|
||||||
if (EasyMove.stableCnt < 6 || mainThread->easyMovePlayed)
|
|
||||||
EasyMove.clear();
|
|
||||||
|
|
||||||
// If skill level is enabled, swap best PV line with the sub-optimal one
|
// If skill level is enabled, swap best PV line with the sub-optimal one
|
||||||
if (skill.enabled())
|
if (skill.enabled())
|
||||||
std::swap(rootMoves[0], *std::find(rootMoves.begin(),
|
std::swap(rootMoves[0], *std::find(rootMoves.begin(), rootMoves.end(),
|
||||||
rootMoves.end(), skill.best_move(multiPV)));
|
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) {
|
Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, bool cutNode, bool skipEarlyPruning) {
|
||||||
|
|
||||||
const bool PvNode = NT == PV;
|
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(-VALUE_INFINITE <= alpha && alpha < beta && beta <= VALUE_INFINITE);
|
||||||
assert(PvNode || (alpha == beta - 1));
|
assert(PvNode || (alpha == beta - 1));
|
||||||
@@ -535,7 +493,7 @@ namespace {
|
|||||||
assert(!(PvNode && cutNode));
|
assert(!(PvNode && cutNode));
|
||||||
assert(depth / ONE_PLY * ONE_PLY == depth);
|
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;
|
StateInfo st;
|
||||||
TTEntry* tte;
|
TTEntry* tte;
|
||||||
Key posKey;
|
Key posKey;
|
||||||
@@ -543,33 +501,31 @@ namespace {
|
|||||||
Depth extension, newDepth;
|
Depth extension, newDepth;
|
||||||
Value bestValue, value, ttValue, eval, maxValue;
|
Value bestValue, value, ttValue, eval, maxValue;
|
||||||
bool ttHit, inCheck, givesCheck, singularExtensionNode, improving;
|
bool ttHit, inCheck, givesCheck, singularExtensionNode, improving;
|
||||||
bool captureOrPromotion, doFullDepthSearch, moveCountPruning, skipQuiets, ttCapture;
|
bool captureOrPromotion, doFullDepthSearch, moveCountPruning, skipQuiets, ttCapture, pvExact;
|
||||||
Piece movedPiece;
|
Piece movedPiece;
|
||||||
int moveCount, quietCount;
|
int moveCount, captureCount, quietCount;
|
||||||
|
|
||||||
// Step 1. Initialize node
|
// Step 1. Initialize node
|
||||||
Thread* thisThread = pos.this_thread();
|
Thread* thisThread = pos.this_thread();
|
||||||
inCheck = pos.checkers();
|
inCheck = pos.checkers();
|
||||||
moveCount = quietCount = ss->moveCount = 0;
|
moveCount = captureCount = quietCount = ss->moveCount = 0;
|
||||||
ss->statScore = 0;
|
ss->statScore = 0;
|
||||||
bestValue = -VALUE_INFINITE;
|
bestValue = -VALUE_INFINITE;
|
||||||
maxValue = VALUE_INFINITE;
|
maxValue = VALUE_INFINITE;
|
||||||
ss->ply = (ss-1)->ply + 1;
|
|
||||||
|
|
||||||
// Check for the available remaining time
|
// Check for the available remaining time
|
||||||
if (thisThread == Threads.main())
|
if (thisThread == Threads.main())
|
||||||
static_cast<MainThread*>(thisThread)->check_time();
|
static_cast<MainThread*>(thisThread)->check_time();
|
||||||
|
|
||||||
// Used to send selDepth info to GUI
|
// Used to send selDepth info to GUI (selDepth counts from 1, ply from 0)
|
||||||
if (PvNode && thisThread->selDepth < ss->ply)
|
if (PvNode && thisThread->selDepth < ss->ply + 1)
|
||||||
thisThread->selDepth = ss->ply;
|
thisThread->selDepth = ss->ply + 1;
|
||||||
|
|
||||||
if (!rootNode)
|
if (!rootNode)
|
||||||
{
|
{
|
||||||
// Step 2. Check for aborted search and immediate draw
|
// 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)
|
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)
|
return ss->ply >= MAX_PLY && !inCheck ? evaluate(pos) : VALUE_DRAW;
|
||||||
: DrawValue[pos.side_to_move()];
|
|
||||||
|
|
||||||
// Step 3. Mate distance pruning. Even if we mate at the next move our score
|
// 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
|
// 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);
|
assert(0 <= ss->ply && ss->ply < MAX_PLY);
|
||||||
|
|
||||||
|
(ss+1)->ply = ss->ply + 1;
|
||||||
ss->currentMove = (ss+1)->excludedMove = bestMove = MOVE_NONE;
|
ss->currentMove = (ss+1)->excludedMove = bestMove = MOVE_NONE;
|
||||||
ss->contHistory = &thisThread->contHistory[NO_PIECE][0];
|
ss->contHistory = &thisThread->contHistory[NO_PIECE][0];
|
||||||
(ss+2)->killers[0] = (ss+2)->killers[1] = MOVE_NONE;
|
(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
|
// search to overwrite a previous full search TT value, so we use a different
|
||||||
// position key in case of an excluded move.
|
// position key in case of an excluded move.
|
||||||
excludedMove = ss->excludedMove;
|
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);
|
tte = TT.probe(posKey, ttHit);
|
||||||
ttValue = ttHit ? value_from_tt(tte->value(), ss->ply) : VALUE_NONE;
|
ttValue = ttHit ? value_from_tt(tte->value(), ss->ply) : VALUE_NONE;
|
||||||
ttMove = rootNode ? thisThread->rootMoves[thisThread->PVIdx].pv[0]
|
ttMove = rootNode ? thisThread->rootMoves[thisThread->PVIdx].pv[0]
|
||||||
@@ -650,8 +607,8 @@ namespace {
|
|||||||
|
|
||||||
int drawScore = TB::UseRule50 ? 1 : 0;
|
int drawScore = TB::UseRule50 ? 1 : 0;
|
||||||
|
|
||||||
value = 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
|
: wdl > drawScore ? VALUE_MATE - MAX_PLY - ss->ply - 1
|
||||||
: VALUE_DRAW + 2 * wdl * drawScore;
|
: VALUE_DRAW + 2 * wdl * drawScore;
|
||||||
|
|
||||||
Bound b = wdl < -drawScore ? BOUND_UPPER
|
Bound b = wdl < -drawScore ? BOUND_UPPER
|
||||||
@@ -706,18 +663,18 @@ namespace {
|
|||||||
ss->staticEval, TT.generation());
|
ss->staticEval, TT.generation());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (skipEarlyPruning)
|
if (skipEarlyPruning || !pos.non_pawn_material(pos.side_to_move()))
|
||||||
goto moves_loop;
|
goto moves_loop;
|
||||||
|
|
||||||
// Step 6. Razoring (skipped when in check)
|
// Step 6. Razoring (skipped when in check)
|
||||||
if ( !PvNode
|
if ( !PvNode
|
||||||
&& depth < 4 * ONE_PLY
|
&& depth < 4 * ONE_PLY
|
||||||
&& eval + razor_margin[depth / ONE_PLY] <= alpha)
|
&& eval + razor_margin <= alpha)
|
||||||
{
|
{
|
||||||
if (depth <= ONE_PLY)
|
if (depth <= ONE_PLY)
|
||||||
return qsearch<NonPV, false>(pos, ss, alpha, alpha+1);
|
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);
|
Value v = qsearch<NonPV, false>(pos, ss, ralpha, ralpha+1);
|
||||||
if (v <= ralpha)
|
if (v <= ralpha)
|
||||||
return v;
|
return v;
|
||||||
@@ -727,15 +684,14 @@ namespace {
|
|||||||
if ( !rootNode
|
if ( !rootNode
|
||||||
&& depth < 7 * ONE_PLY
|
&& depth < 7 * ONE_PLY
|
||||||
&& eval - futility_margin(depth) >= beta
|
&& eval - futility_margin(depth) >= beta
|
||||||
&& eval < VALUE_KNOWN_WIN // Do not return unproven wins
|
&& eval < VALUE_KNOWN_WIN) // Do not return unproven wins
|
||||||
&& pos.non_pawn_material(pos.side_to_move()))
|
|
||||||
return eval;
|
return eval;
|
||||||
|
|
||||||
// Step 8. Null move search with verification search (is omitted in PV nodes)
|
// Step 8. Null move search with verification search (is omitted in PV nodes)
|
||||||
if ( !PvNode
|
if ( !PvNode
|
||||||
&& eval >= beta
|
&& eval >= beta
|
||||||
&& (ss->staticEval >= beta - 35 * (depth / ONE_PLY - 6) || depth >= 13 * ONE_PLY)
|
&& ss->staticEval >= beta - 36 * depth / ONE_PLY + 225
|
||||||
&& pos.non_pawn_material(pos.side_to_move()))
|
&& (ss->ply >= thisThread->nmp_ply || ss->ply % 2 != thisThread->nmp_odd))
|
||||||
{
|
{
|
||||||
|
|
||||||
assert(eval - beta >= 0);
|
assert(eval - beta >= 0);
|
||||||
@@ -757,13 +713,19 @@ namespace {
|
|||||||
if (nullValue >= VALUE_MATE_IN_MAX_PLY)
|
if (nullValue >= VALUE_MATE_IN_MAX_PLY)
|
||||||
nullValue = beta;
|
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;
|
return nullValue;
|
||||||
|
|
||||||
// Do verification search at high depths
|
// 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)
|
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);
|
: search<NonPV>(pos, ss, beta-1, beta, depth-R, false, true);
|
||||||
|
|
||||||
|
thisThread->nmp_odd = thisThread->nmp_ply = 0;
|
||||||
|
|
||||||
if (v >= beta)
|
if (v >= beta)
|
||||||
return nullValue;
|
return nullValue;
|
||||||
}
|
}
|
||||||
@@ -780,7 +742,7 @@ namespace {
|
|||||||
|
|
||||||
assert(is_ok((ss-1)->currentMove));
|
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)
|
while ((move = mp.next_move()) != MOVE_NONE)
|
||||||
if (pos.legal(move))
|
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 };
|
const PieceToHistory* contHist[] = { (ss-1)->contHistory, (ss-2)->contHistory, nullptr, (ss-4)->contHistory };
|
||||||
Move countermove = thisThread->counterMoves[pos.piece_on(prevSq)][prevSq];
|
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
|
value = bestValue; // Workaround a bogus 'uninitialized' warning under gcc
|
||||||
improving = ss->staticEval >= (ss-2)->staticEval
|
improving = ss->staticEval >= (ss-2)->staticEval
|
||||||
/* || ss->staticEval == VALUE_NONE Already implicit in the previous condition */
|
/* || 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;
|
&& tte->depth() >= depth - 3 * ONE_PLY;
|
||||||
skipQuiets = false;
|
skipQuiets = false;
|
||||||
ttCapture = false;
|
ttCapture = false;
|
||||||
|
pvExact = PvNode && ttHit && tte->bound() == BOUND_EXACT;
|
||||||
|
|
||||||
// Step 11. Loop through moves
|
// Step 11. Loop through moves
|
||||||
// Loop through all pseudo-legal moves until no moves remain or a beta cutoff occurs
|
// 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);
|
movedPiece = pos.moved_piece(move);
|
||||||
|
|
||||||
givesCheck = type_of(move) == NORMAL && !pos.discovered_check_candidates()
|
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);
|
: pos.gives_check(move);
|
||||||
|
|
||||||
moveCountPruning = depth < 16 * ONE_PLY
|
moveCountPruning = depth < 16 * ONE_PLY
|
||||||
@@ -973,6 +936,10 @@ moves_loop: // When in check search starts from here
|
|||||||
if ((ss-1)->moveCount > 15)
|
if ((ss-1)->moveCount > 15)
|
||||||
r -= ONE_PLY;
|
r -= ONE_PLY;
|
||||||
|
|
||||||
|
// Decrease reduction for exact PV nodes
|
||||||
|
if (pvExact)
|
||||||
|
r -= ONE_PLY;
|
||||||
|
|
||||||
// Increase reduction if ttMove is a capture
|
// Increase reduction if ttMove is a capture
|
||||||
if (ttCapture)
|
if (ttCapture)
|
||||||
r += ONE_PLY;
|
r += ONE_PLY;
|
||||||
@@ -995,10 +962,10 @@ moves_loop: // When in check search starts from here
|
|||||||
- 4000;
|
- 4000;
|
||||||
|
|
||||||
// Decrease/increase reduction by comparing opponent's stat score
|
// 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;
|
r -= ONE_PLY;
|
||||||
|
|
||||||
else if (ss->statScore < 0 && (ss-1)->statScore > 0)
|
else if ((ss-1)->statScore >= 0 && ss->statScore < 0)
|
||||||
r += ONE_PLY;
|
r += ONE_PLY;
|
||||||
|
|
||||||
// Decrease/increase reduction for moves with a good/bad history
|
// 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)
|
if (!captureOrPromotion && move != bestMove && quietCount < 64)
|
||||||
quietsSearched[quietCount++] = move;
|
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
|
// 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)
|
if (!moveCount)
|
||||||
bestValue = excludedMove ? alpha
|
bestValue = excludedMove ? alpha
|
||||||
: inCheck ? mated_in(ss->ply) : DrawValue[pos.side_to_move()];
|
: inCheck ? mated_in(ss->ply) : VALUE_DRAW;
|
||||||
else if (bestMove)
|
else if (bestMove)
|
||||||
{
|
{
|
||||||
// Quiet best move: update move sorting heuristics
|
// Quiet best move: update move sorting heuristics
|
||||||
if (!pos.capture_or_promotion(bestMove))
|
if (!pos.capture_or_promotion(bestMove))
|
||||||
update_stats(pos, ss, bestMove, quietsSearched, quietCount, stat_bonus(depth));
|
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
|
// Extra penalty for a quiet TT move in previous ply when it gets refuted
|
||||||
if ((ss-1)->moveCount == 1 && !pos.captured_piece())
|
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;
|
const bool PvNode = NT == PV;
|
||||||
|
|
||||||
assert(InCheck == !!pos.checkers());
|
assert(InCheck == bool(pos.checkers()));
|
||||||
assert(alpha >= -VALUE_INFINITE && alpha < beta && beta <= VALUE_INFINITE);
|
assert(alpha >= -VALUE_INFINITE && alpha < beta && beta <= VALUE_INFINITE);
|
||||||
assert(PvNode || (alpha == beta - 1));
|
assert(PvNode || (alpha == beta - 1));
|
||||||
assert(depth <= DEPTH_ZERO);
|
assert(depth <= DEPTH_ZERO);
|
||||||
@@ -1183,13 +1154,12 @@ moves_loop: // When in check search starts from here
|
|||||||
}
|
}
|
||||||
|
|
||||||
ss->currentMove = bestMove = MOVE_NONE;
|
ss->currentMove = bestMove = MOVE_NONE;
|
||||||
ss->ply = (ss-1)->ply + 1;
|
(ss+1)->ply = ss->ply + 1;
|
||||||
moveCount = 0;
|
moveCount = 0;
|
||||||
|
|
||||||
// Check for an instant draw or if the maximum ply has been reached
|
// Check for an instant draw or if the maximum ply has been reached
|
||||||
if (pos.is_draw(ss->ply) || ss->ply >= MAX_PLY)
|
if (pos.is_draw(ss->ply) || ss->ply >= MAX_PLY)
|
||||||
return ss->ply >= MAX_PLY && !InCheck ? evaluate(pos)
|
return ss->ply >= MAX_PLY && !InCheck ? evaluate(pos) : VALUE_DRAW;
|
||||||
: DrawValue[pos.side_to_move()];
|
|
||||||
|
|
||||||
assert(0 <= ss->ply && ss->ply < MAX_PLY);
|
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.
|
// only two types of depth in TT: DEPTH_QS_CHECKS or DEPTH_QS_NO_CHECKS.
|
||||||
ttDepth = InCheck || depth >= DEPTH_QS_CHECKS ? DEPTH_QS_CHECKS
|
ttDepth = InCheck || depth >= DEPTH_QS_CHECKS ? DEPTH_QS_CHECKS
|
||||||
: DEPTH_QS_NO_CHECKS;
|
: DEPTH_QS_NO_CHECKS;
|
||||||
|
|
||||||
// Transposition table lookup
|
// Transposition table lookup
|
||||||
posKey = pos.key();
|
posKey = pos.key();
|
||||||
tte = TT.probe(posKey, ttHit);
|
tte = TT.probe(posKey, ttHit);
|
||||||
@@ -1241,7 +1210,7 @@ moves_loop: // When in check search starts from here
|
|||||||
if (bestValue >= beta)
|
if (bestValue >= beta)
|
||||||
{
|
{
|
||||||
if (!ttHit)
|
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());
|
DEPTH_NONE, MOVE_NONE, ss->staticEval, TT.generation());
|
||||||
|
|
||||||
return bestValue;
|
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,
|
// to search the moves. Because the depth is <= 0 here, only captures,
|
||||||
// queen promotions and checks (only if depth >= DEPTH_QS_CHECKS) will
|
// queen promotions and checks (only if depth >= DEPTH_QS_CHECKS) will
|
||||||
// be generated.
|
// 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
|
// Loop through the moves until no moves remain or a beta cutoff occurs
|
||||||
while ((move = mp.next_move()) != MOVE_NONE)
|
while ((move = mp.next_move()) != MOVE_NONE)
|
||||||
@@ -1265,7 +1234,7 @@ moves_loop: // When in check search starts from here
|
|||||||
assert(is_ok(move));
|
assert(is_ok(move));
|
||||||
|
|
||||||
givesCheck = type_of(move) == NORMAL && !pos.discovered_check_candidates()
|
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);
|
: pos.gives_check(move);
|
||||||
|
|
||||||
moveCount++;
|
moveCount++;
|
||||||
@@ -1301,7 +1270,6 @@ moves_loop: // When in check search starts from here
|
|||||||
|
|
||||||
// Don't search moves with negative SEE values
|
// Don't search moves with negative SEE values
|
||||||
if ( (!InCheck || evasionPrunable)
|
if ( (!InCheck || evasionPrunable)
|
||||||
&& type_of(move) != PROMOTION
|
|
||||||
&& !pos.see_ge(move))
|
&& !pos.see_ge(move))
|
||||||
continue;
|
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
|
// update_stats() updates move sorting heuristics when a new quiet best move is found
|
||||||
|
|
||||||
void update_stats(const Position& pos, Stack* ss, Move move,
|
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
|
// 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.
|
// 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)
|
int push = ( weakness * int(topScore - rootMoves[i].score)
|
||||||
+ delta * (rng.rand<unsigned>() % weakness)) / 128;
|
+ delta * (rng.rand<unsigned>() % weakness)) / 128;
|
||||||
|
|
||||||
if (rootMoves[i].score + push > maxScore)
|
if (rootMoves[i].score + push >= maxScore)
|
||||||
{
|
{
|
||||||
maxScore = rootMoves[i].score + push;
|
maxScore = rootMoves[i].score + push;
|
||||||
best = rootMoves[i].pv[0];
|
best = rootMoves[i].pv[0];
|
||||||
@@ -1505,7 +1511,7 @@ moves_loop: // When in check search starts from here
|
|||||||
if (Threads.ponder)
|
if (Threads.ponder)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if ( (Limits.use_time_management() && elapsed > Time.maximum())
|
if ( (Limits.use_time_management() && elapsed > Time.maximum() - 10)
|
||||||
|| (Limits.movetime && elapsed >= Limits.movetime)
|
|| (Limits.movetime && elapsed >= Limits.movetime)
|
||||||
|| (Limits.nodes && Threads.nodes_searched() >= (uint64_t)Limits.nodes))
|
|| (Limits.nodes && Threads.nodes_searched() >= (uint64_t)Limits.nodes))
|
||||||
Threads.stop = true;
|
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))
|
if (Cardinality < popcount(pos.pieces()) || pos.can_castle(ANY_CASTLING))
|
||||||
return;
|
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
|
// If the current root position is in the tablebases, then RootMoves
|
||||||
// contains only moves that preserve the draw or the win.
|
// contains only moves that preserve the draw or the win.
|
||||||
RootInTB = root_probe(pos, rootMoves, TB::Score);
|
RootInTB = root_probe(pos, rootMoves, TB::Score);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
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
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
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
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (c) 2013 Ronald de Man
|
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
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -133,16 +133,16 @@ struct Atomic {
|
|||||||
std::atomic_bool ready;
|
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.
|
// corresponding specializations for pieces or pawns.
|
||||||
|
|
||||||
struct WLDEntryPiece {
|
struct WDLEntryPiece {
|
||||||
PairsData* precomp;
|
PairsData* precomp;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct WDLEntryPawn {
|
struct WDLEntryPawn {
|
||||||
uint8_t pawnCount[2]; // [Lead color / other color]
|
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 {
|
struct DTZEntryPiece {
|
||||||
@@ -172,7 +172,7 @@ struct WDLEntry : public TBEntry {
|
|||||||
WDLEntry(const std::string& code);
|
WDLEntry(const std::string& code);
|
||||||
~WDLEntry();
|
~WDLEntry();
|
||||||
union {
|
union {
|
||||||
WLDEntryPiece pieceTable[2]; // [wtm / btm]
|
WDLEntryPiece pieceTable[2]; // [wtm / btm]
|
||||||
WDLEntryPawn pawnTable;
|
WDLEntryPawn pawnTable;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -1379,9 +1379,8 @@ void Tablebases::init(const std::string& paths) {
|
|||||||
for (PieceType p3 = PAWN; p3 <= p2; ++p3) {
|
for (PieceType p3 = PAWN; p3 <= p2; ++p3) {
|
||||||
EntryTable.insert({KING, p1, p2, p3, KING});
|
EntryTable.insert({KING, p1, p2, p3, KING});
|
||||||
|
|
||||||
if (sizeof(char*) >= 8)
|
for (PieceType p4 = PAWN; p4 <= p3; ++p4)
|
||||||
for (PieceType p4 = PAWN; p4 <= p3; ++p4)
|
EntryTable.insert({KING, p1, p2, p3, p4, KING});
|
||||||
EntryTable.insert({KING, p1, p2, p3, p4, KING});
|
|
||||||
|
|
||||||
for (PieceType p4 = PAWN; p4 < KING; ++p4)
|
for (PieceType p4 = PAWN; p4 < KING; ++p4)
|
||||||
EntryTable.insert({KING, p1, p2, p3, 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
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (c) 2013 Ronald de Man
|
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
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
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
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
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
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -24,6 +24,7 @@
|
|||||||
#include "movegen.h"
|
#include "movegen.h"
|
||||||
#include "search.h"
|
#include "search.h"
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
|
#include "uci.h"
|
||||||
#include "syzygy/tbprobe.h"
|
#include "syzygy/tbprobe.h"
|
||||||
|
|
||||||
ThreadPool Threads; // Global object
|
ThreadPool Threads; // Global object
|
||||||
@@ -35,7 +36,6 @@ ThreadPool Threads; // Global object
|
|||||||
Thread::Thread(size_t n) : idx(n), stdThread(&Thread::idle_loop, this) {
|
Thread::Thread(size_t n) : idx(n), stdThread(&Thread::idle_loop, this) {
|
||||||
|
|
||||||
wait_for_search_finished();
|
wait_for_search_finished();
|
||||||
clear(); // Zero-init histories (based on std::array)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -58,6 +58,7 @@ void Thread::clear() {
|
|||||||
|
|
||||||
counterMoves.fill(MOVE_NONE);
|
counterMoves.fill(MOVE_NONE);
|
||||||
mainHistory.fill(0);
|
mainHistory.fill(0);
|
||||||
|
captureHistory.fill(0);
|
||||||
|
|
||||||
for (auto& to : contHistory)
|
for (auto& to : contHistory)
|
||||||
for (auto& h : to)
|
for (auto& h : to)
|
||||||
@@ -91,7 +92,13 @@ void Thread::wait_for_search_finished() {
|
|||||||
|
|
||||||
void Thread::idle_loop() {
|
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)
|
while (true)
|
||||||
{
|
{
|
||||||
@@ -109,41 +116,39 @@ void Thread::idle_loop() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// ThreadPool::set() creates/destroys threads to match the requested number.
|
||||||
/// ThreadPool::init() creates and launches the threads that will go
|
/// Created and launced threads wil go immediately to sleep in idle_loop.
|
||||||
/// immediately to sleep in idle_loop. We cannot use the c'tor because
|
/// Upon resizing, threads are recreated to allow for binding if necessary.
|
||||||
/// 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
|
|
||||||
|
|
||||||
void ThreadPool::set(size_t requested) {
|
void ThreadPool::set(size_t requested) {
|
||||||
|
|
||||||
while (size() < requested)
|
if (size() > 0) { // destroy any existing thread(s)
|
||||||
push_back(new Thread(size()));
|
main()->wait_for_search_finished();
|
||||||
|
|
||||||
while (size() > requested)
|
while (size() > 0)
|
||||||
delete back(), pop_back();
|
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
|
/// 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.
|
/// 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.
|
// is shared by threads but is accessed in read-only mode.
|
||||||
StateInfo tmp = setupStates->back();
|
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->rootDepth = th->completedDepth = DEPTH_ZERO;
|
||||||
th->rootMoves = rootMoves;
|
th->rootMoves = rootMoves;
|
||||||
th->rootPos.set(pos.fen(), pos.is_chess960(), &setupStates->back(), th);
|
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
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
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
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -61,7 +61,7 @@ public:
|
|||||||
Material::Table materialTable;
|
Material::Table materialTable;
|
||||||
Endgames endgames;
|
Endgames endgames;
|
||||||
size_t PVIdx;
|
size_t PVIdx;
|
||||||
int selDepth;
|
int selDepth, nmp_ply, nmp_odd;
|
||||||
std::atomic<uint64_t> nodes, tbHits;
|
std::atomic<uint64_t> nodes, tbHits;
|
||||||
|
|
||||||
Position rootPos;
|
Position rootPos;
|
||||||
@@ -69,6 +69,7 @@ public:
|
|||||||
Depth rootDepth, completedDepth;
|
Depth rootDepth, completedDepth;
|
||||||
CounterMoveHistory counterMoves;
|
CounterMoveHistory counterMoves;
|
||||||
ButterflyHistory mainHistory;
|
ButterflyHistory mainHistory;
|
||||||
|
CapturePieceToHistory captureHistory;
|
||||||
ContinuationHistory contHistory;
|
ContinuationHistory contHistory;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -82,8 +83,8 @@ struct MainThread : public Thread {
|
|||||||
void search() override;
|
void search() override;
|
||||||
void check_time();
|
void check_time();
|
||||||
|
|
||||||
bool easyMovePlayed, failedLow;
|
bool failedLow;
|
||||||
double bestMoveChanges;
|
double bestMoveChanges, previousTimeReduction;
|
||||||
Value previousScore;
|
Value previousScore;
|
||||||
int callsCnt;
|
int callsCnt;
|
||||||
};
|
};
|
||||||
@@ -95,9 +96,8 @@ struct MainThread : public Thread {
|
|||||||
|
|
||||||
struct ThreadPool : public std::vector<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 start_thinking(Position&, StateListPtr&, const Search::LimitsType&, bool = false);
|
||||||
|
void clear();
|
||||||
void set(size_t);
|
void set(size_t);
|
||||||
|
|
||||||
MainThread* main() const { return static_cast<MainThread*>(front()); }
|
MainThread* main() const { return static_cast<MainThread*>(front()); }
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
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
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
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
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
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
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -19,6 +19,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <cfloat>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
#include "search.h"
|
#include "search.h"
|
||||||
#include "timeman.h"
|
#include "timeman.h"
|
||||||
@@ -30,43 +32,41 @@ namespace {
|
|||||||
|
|
||||||
enum TimeType { OptimumTime, MaxTime };
|
enum TimeType { OptimumTime, MaxTime };
|
||||||
|
|
||||||
int remaining(int myTime, int myInc, int moveOverhead, int movesToGo,
|
const int MoveHorizon = 50; // Plan time management at most this many moves ahead
|
||||||
int moveNum, bool ponder, TimeType type) {
|
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 move_importance(int ply) {
|
||||||
double inc = myInc * std::max(55.0, 120 - 0.12 * (moveNum - 25) * (moveNum - 25));
|
|
||||||
|
|
||||||
// In moves-to-go we distribute time according to a quadratic function with
|
const double XScale = 7.64;
|
||||||
// the maximum around move 20 for 40 moves in y time case.
|
const double XShift = 58.4;
|
||||||
if (movesToGo)
|
const double Skew = 0.183;
|
||||||
{
|
|
||||||
ratio = (type == OptimumTime ? 1.0 : 6.0) / std::min(50, movesToGo);
|
|
||||||
|
|
||||||
if (moveNum <= 40)
|
return pow((1 + exp((ply - XShift) / XScale)), -Skew) + DBL_MIN; // Ensure non-zero
|
||||||
ratio *= 1.1 - 0.001 * (moveNum - 20) * (moveNum - 20);
|
}
|
||||||
else
|
|
||||||
ratio *= 1.5;
|
|
||||||
|
|
||||||
ratio *= 1 + inc / (myTime * 8.5);
|
template<TimeType T>
|
||||||
}
|
int remaining(int myTime, int movesToGo, int ply, int slowMover) {
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
double moveImportance = (move_importance(ply) * slowMover) / 100;
|
||||||
time = 5 * time / 4;
|
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
|
} // namespace
|
||||||
@@ -81,11 +81,12 @@ namespace {
|
|||||||
/// inc > 0 && movestogo == 0 means: x basetime + z increment
|
/// inc > 0 && movestogo == 0 means: x basetime + z increment
|
||||||
/// inc > 0 && movestogo != 0 means: x moves in y minutes + z increment
|
/// inc > 0 && movestogo != 0 means: x moves in y minutes + z increment
|
||||||
|
|
||||||
void TimeManagement::init(Search::LimitsType& limits, Color us, int ply)
|
void TimeManagement::init(Search::LimitsType& limits, Color us, int ply) {
|
||||||
{
|
|
||||||
int moveOverhead = Options["Move Overhead"];
|
int minThinkingTime = Options["Minimum Thinking Time"];
|
||||||
int npmsec = Options["nodestime"];
|
int moveOverhead = Options["Move Overhead"];
|
||||||
bool ponder = Options["Ponder"];
|
int slowMover = Options["Slow Mover"];
|
||||||
|
int npmsec = Options["nodestime"];
|
||||||
|
|
||||||
// If we have to play in 'nodes as time' mode, then convert from time
|
// If we have to play in 'nodes as time' mode, then convert from time
|
||||||
// to nodes, and use resulting values in time management formulas.
|
// 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;
|
limits.npmsec = npmsec;
|
||||||
}
|
}
|
||||||
|
|
||||||
int moveNum = (ply + 1) / 2;
|
|
||||||
|
|
||||||
startTime = limits.startTime;
|
startTime = limits.startTime;
|
||||||
optimumTime = remaining(limits.time[us], limits.inc[us], moveOverhead,
|
optimumTime = maximumTime = std::max(limits.time[us], minThinkingTime);
|
||||||
limits.movestogo, moveNum, ponder, OptimumTime);
|
|
||||||
maximumTime = remaining(limits.time[us], limits.inc[us], moveOverhead,
|
const int MaxMTG = limits.movestogo ? std::min(limits.movestogo, MoveHorizon) : MoveHorizon;
|
||||||
limits.movestogo, moveNum, ponder, MaxTime);
|
|
||||||
|
// 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
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
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
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
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
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
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
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
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) {
|
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)
|
if (newClusterCount == clusterCount)
|
||||||
return;
|
return;
|
||||||
@@ -41,7 +41,7 @@ void TranspositionTable::resize(size_t mbSize) {
|
|||||||
clusterCount = newClusterCount;
|
clusterCount = newClusterCount;
|
||||||
|
|
||||||
free(mem);
|
free(mem);
|
||||||
mem = calloc(clusterCount * sizeof(Cluster) + CacheLineSize - 1, 1);
|
mem = malloc(clusterCount * sizeof(Cluster) + CacheLineSize - 1);
|
||||||
|
|
||||||
if (!mem)
|
if (!mem)
|
||||||
{
|
{
|
||||||
@@ -51,6 +51,7 @@ void TranspositionTable::resize(size_t mbSize) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
table = (Cluster*)((uintptr_t(mem) + CacheLineSize - 1) & ~(CacheLineSize - 1));
|
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
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
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
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -104,9 +104,9 @@ public:
|
|||||||
void resize(size_t mbSize);
|
void resize(size_t mbSize);
|
||||||
void clear();
|
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 {
|
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:
|
private:
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
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
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
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 {
|
template<Color C, CastlingSide S> struct MakeCastling {
|
||||||
static const CastlingRight
|
static constexpr CastlingRight
|
||||||
right = C == WHITE ? S == QUEEN_SIDE ? WHITE_OOO : WHITE_OO
|
right = C == WHITE ? S == QUEEN_SIDE ? WHITE_OOO : WHITE_OO
|
||||||
: S == QUEEN_SIDE ? BLACK_OOO : BLACK_OO;
|
: S == QUEEN_SIDE ? BLACK_OOO : BLACK_OO;
|
||||||
};
|
};
|
||||||
@@ -195,6 +195,7 @@ enum Value : int {
|
|||||||
enum PieceType {
|
enum PieceType {
|
||||||
NO_PIECE_TYPE, PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING,
|
NO_PIECE_TYPE, PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING,
|
||||||
ALL_PIECES = 0,
|
ALL_PIECES = 0,
|
||||||
|
QUEEN_DIAGONAL = 7,
|
||||||
PIECE_TYPE_NB = 8
|
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");
|
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_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_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,
|
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_A8, SQ_B8, SQ_C8, SQ_D8, SQ_E8, SQ_F8, SQ_G8, SQ_H8,
|
||||||
SQ_NONE,
|
SQ_NONE,
|
||||||
|
|
||||||
SQUARE_NB = 64,
|
SQUARE_NB = 64
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Direction : int {
|
||||||
NORTH = 8,
|
NORTH = 8,
|
||||||
EAST = 1,
|
EAST = 1,
|
||||||
SOUTH = -NORTH,
|
SOUTH = -NORTH,
|
||||||
@@ -261,7 +264,7 @@ enum Rank : int {
|
|||||||
/// care to avoid left-shifting a signed int to avoid undefined behavior.
|
/// care to avoid left-shifting a signed int to avoid undefined behavior.
|
||||||
enum Score : int { SCORE_ZERO };
|
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);
|
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
|
/// according to the standard a simple cast to short is implementation defined
|
||||||
/// and so is a right shift of a signed integer.
|
/// and so is a right shift of a signed integer.
|
||||||
inline Value eg_value(Score s) {
|
inline Value eg_value(Score s) {
|
||||||
|
|
||||||
union { uint16_t u; int16_t s; } eg = { uint16_t(unsigned(s + 0x8000) >> 16) };
|
union { uint16_t u; int16_t s; } eg = { uint16_t(unsigned(s + 0x8000) >> 16) };
|
||||||
return Value(eg.s);
|
return Value(eg.s);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Value mg_value(Score s) {
|
inline Value mg_value(Score s) {
|
||||||
|
|
||||||
union { uint16_t u; int16_t s; } mg = { uint16_t(unsigned(s)) };
|
union { uint16_t u; int16_t s; } mg = { uint16_t(unsigned(s)) };
|
||||||
return Value(mg.s);
|
return Value(mg.s);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define ENABLE_BASE_OPERATORS_ON(T) \
|
#define ENABLE_BASE_OPERATORS_ON(T) \
|
||||||
inline 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)); } \
|
||||||
inline 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)); } \
|
||||||
inline T operator-(T d) { return T(-int(d)); } \
|
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; } \
|
||||||
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) \
|
#define ENABLE_INCR_OPERATORS_ON(T) \
|
||||||
ENABLE_BASE_OPERATORS_ON(T) \
|
inline T& operator++(T& d) { return d = T(int(d) + 1); } \
|
||||||
inline T operator*(int i, T d) { return T(i * int(d)); } \
|
inline T& operator--(T& d) { return d = T(int(d) - 1); }
|
||||||
inline T operator*(T d, int i) { return T(int(d) * i); } \
|
|
||||||
inline T& operator++(T& d) { return d = T(int(d) + 1); } \
|
#define ENABLE_FULL_OPERATORS_ON(T) \
|
||||||
inline T& operator--(T& d) { return d = T(int(d) - 1); } \
|
ENABLE_BASE_OPERATORS_ON(T) \
|
||||||
inline T operator/(T d, int i) { return T(int(d) / i); } \
|
ENABLE_INCR_OPERATORS_ON(T) \
|
||||||
inline int operator/(T d1, T d2) { return int(d1) / int(d2); } \
|
constexpr T operator*(int i, T d) { return T(i * int(d)); } \
|
||||||
inline T& operator*=(T& d, int i) { return d = T(int(d) * i); } \
|
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); }
|
inline T& operator/=(T& d, int i) { return d = T(int(d) / i); }
|
||||||
|
|
||||||
ENABLE_FULL_OPERATORS_ON(Value)
|
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(Depth)
|
||||||
ENABLE_FULL_OPERATORS_ON(Square)
|
ENABLE_FULL_OPERATORS_ON(Direction)
|
||||||
ENABLE_FULL_OPERATORS_ON(File)
|
|
||||||
ENABLE_FULL_OPERATORS_ON(Rank)
|
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)
|
ENABLE_BASE_OPERATORS_ON(Score)
|
||||||
|
|
||||||
#undef ENABLE_FULL_OPERATORS_ON
|
#undef ENABLE_FULL_OPERATORS_ON
|
||||||
|
#undef ENABLE_INCR_OPERATORS_ON
|
||||||
#undef ENABLE_BASE_OPERATORS_ON
|
#undef ENABLE_BASE_OPERATORS_ON
|
||||||
|
|
||||||
/// Additional operators to add integers to a Value
|
/// Additional operators to add integers to a Value
|
||||||
inline 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 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; }
|
||||||
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
|
/// 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.
|
/// 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
|
/// Division of a Score must be handled separately for each term
|
||||||
inline Score operator/(Score s, int i) {
|
inline Score operator/(Score s, int i) {
|
||||||
@@ -339,39 +352,43 @@ inline Score operator*(Score s, int i) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Color operator~(Color c) {
|
constexpr Color operator~(Color c) {
|
||||||
return Color(c ^ BLACK); // Toggle color
|
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
|
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
|
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));
|
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;
|
return VALUE_MATE - ply;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Value mated_in(int ply) {
|
constexpr Value mated_in(int ply) {
|
||||||
return -VALUE_MATE + 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);
|
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);
|
return Piece((c << 3) + pt);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline PieceType type_of(Piece pc) {
|
constexpr PieceType type_of(Piece pc) {
|
||||||
return PieceType(pc & 7);
|
return PieceType(pc & 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -380,27 +397,27 @@ inline Color color_of(Piece pc) {
|
|||||||
return Color(pc >> 3);
|
return Color(pc >> 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool is_ok(Square s) {
|
constexpr bool is_ok(Square s) {
|
||||||
return s >= SQ_A1 && s <= SQ_H8;
|
return s >= SQ_A1 && s <= SQ_H8;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline File file_of(Square s) {
|
constexpr File file_of(Square s) {
|
||||||
return File(s & 7);
|
return File(s & 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Rank rank_of(Square s) {
|
constexpr Rank rank_of(Square s) {
|
||||||
return Rank(s >> 3);
|
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));
|
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));
|
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));
|
return relative_rank(c, rank_of(s));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -409,27 +426,27 @@ inline bool opposite_colors(Square s1, Square s2) {
|
|||||||
return ((s >> 3) ^ s) & 1;
|
return ((s >> 3) ^ s) & 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Square pawn_push(Color c) {
|
constexpr Direction pawn_push(Color c) {
|
||||||
return c == WHITE ? NORTH : SOUTH;
|
return c == WHITE ? NORTH : SOUTH;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Square from_sq(Move m) {
|
constexpr Square from_sq(Move m) {
|
||||||
return Square((m >> 6) & 0x3F);
|
return Square((m >> 6) & 0x3F);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Square to_sq(Move m) {
|
constexpr Square to_sq(Move m) {
|
||||||
return Square(m & 0x3F);
|
return Square(m & 0x3F);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int from_to(Move m) {
|
constexpr int from_to(Move m) {
|
||||||
return m & 0xFFF;
|
return m & 0xFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline MoveType type_of(Move m) {
|
constexpr MoveType type_of(Move m) {
|
||||||
return MoveType(m & (3 << 14));
|
return MoveType(m & (3 << 14));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline PieceType promotion_type(Move m) {
|
constexpr PieceType promotion_type(Move m) {
|
||||||
return PieceType(((m >> 12) & 3) + KNIGHT);
|
return PieceType(((m >> 12) & 3) + KNIGHT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -438,11 +455,11 @@ inline Move make_move(Square from, Square to) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<MoveType T>
|
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);
|
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
|
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
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
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
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
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
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
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
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
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
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
||||||
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
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
|
Stockfish is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
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) {
|
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["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["Threads"] << Option(1, 1, 512, on_threads);
|
||||||
o["Hash"] << Option(16, 1, MaxHashMB, on_hash_size);
|
o["Hash"] << Option(16, 1, MaxHashMB, on_hash_size);
|
||||||
o["Clear Hash"] << Option(on_clear_hash);
|
o["Clear Hash"] << Option(on_clear_hash);
|
||||||
o["Ponder"] << Option(false);
|
o["Ponder"] << Option(false);
|
||||||
o["MultiPV"] << Option(1, 1, 500);
|
o["MultiPV"] << Option(1, 1, 500);
|
||||||
o["Skill Level"] << Option(20, 0, 20);
|
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["nodestime"] << Option(0, 0, 10000);
|
||||||
o["UCI_Chess960"] << Option(false);
|
o["UCI_Chess960"] << Option(false);
|
||||||
o["SyzygyPath"] << Option("<empty>", on_tb_path);
|
o["SyzygyPath"] << Option("<empty>", on_tb_path);
|
||||||
|
|||||||
Reference in New Issue
Block a user