DroidFish: Updated stockfish engine to version 8.

This commit is contained in:
Peter Osterlund 2016-11-01 19:40:58 +01:00
parent 503390c19f
commit 3d227b6bee
20 changed files with 282 additions and 273 deletions

View File

@ -76,7 +76,14 @@ const vector<string> Defaults = {
"8/8/3P3k/8/1p6/8/1P6/1K3n2 b - - 0 1", // Nd2 - draw
// 7-man positions
"8/R7/2q5/8/6k1/8/1P5p/K6R w - - 0 124" // Draw
"8/R7/2q5/8/6k1/8/1P5p/K6R w - - 0 124", // Draw
// Mate and stalemate positions
"8/8/8/8/8/6k1/6p1/6K1 w - -",
"5k2/5P2/5K2/8/8/8/8/8 b - -",
"8/8/8/8/8/4k3/4p3/4K3 w - -",
"8/8/8/8/8/5K2/8/3Q1k2 b - -",
"7k/7P/6K1/8/3B4/8/8/8 b - -"
};
} // namespace

View File

@ -123,9 +123,9 @@ namespace {
// Immediate win if a pawn can be promoted without getting captured
else if ( us == WHITE
&& rank_of(psq) == RANK_7
&& ksq[us] != psq + DELTA_N
&& ( distance(ksq[~us], psq + DELTA_N) > 1
|| (StepAttacksBB[KING][ksq[us]] & (psq + DELTA_N))))
&& ksq[us] != psq + NORTH
&& ( distance(ksq[~us], psq + NORTH) > 1
|| (StepAttacksBB[KING][ksq[us]] & (psq + NORTH))))
result = WIN;
// Immediate draw if it is a stalemate or a king captures undefended pawn
@ -166,12 +166,12 @@ namespace {
if (Us == WHITE)
{
if (rank_of(psq) < RANK_7) // Single push
r |= db[index(Them, ksq[Them], ksq[Us], psq + DELTA_N)];
r |= db[index(Them, ksq[Them], ksq[Us], psq + NORTH)];
if ( rank_of(psq) == RANK_2 // Double push
&& psq + DELTA_N != ksq[Us]
&& psq + DELTA_N != ksq[Them])
r |= db[index(Them, ksq[Them], ksq[Us], psq + DELTA_N + DELTA_N)];
&& psq + NORTH != ksq[Us]
&& psq + NORTH != ksq[Them])
r |= db[index(Them, ksq[Them], ksq[Us], psq + NORTH + NORTH)];
}
return result = r & Good ? Good : r & UNKNOWN ? UNKNOWN : Bad;

View File

@ -205,8 +205,8 @@ void Bitboards::init() {
StepAttacksBB[make_piece(c, pt)][s] |= to;
}
Square RookDeltas[] = { DELTA_N, DELTA_E, DELTA_S, DELTA_W };
Square BishopDeltas[] = { DELTA_NE, DELTA_SE, DELTA_SW, DELTA_NW };
Square RookDeltas[] = { NORTH, EAST, SOUTH, WEST };
Square BishopDeltas[] = { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST };
init_magics(RookTable, RookAttacks, RookMagics, RookMasks, RookShifts, RookDeltas, magic_index<ROOK>);
init_magics(BishopTable, BishopAttacks, BishopMagics, BishopMasks, BishopShifts, BishopDeltas, magic_index<BISHOP>);

View File

@ -124,13 +124,13 @@ inline Bitboard file_bb(Square s) {
}
/// shift_bb() moves a bitboard one step along direction Delta. Mainly for pawns
/// shift() moves a bitboard one step along direction D. Mainly for pawns
template<Square Delta>
inline Bitboard shift_bb(Bitboard b) {
return Delta == DELTA_N ? b << 8 : Delta == DELTA_S ? b >> 8
: Delta == DELTA_NE ? (b & ~FileHBB) << 9 : Delta == DELTA_SE ? (b & ~FileHBB) >> 7
: Delta == DELTA_NW ? (b & ~FileABB) << 7 : Delta == DELTA_SW ? (b & ~FileABB) >> 9
template<Square D>
inline Bitboard shift(Bitboard b) {
return D == NORTH ? b << 8 : D == SOUTH ? b >> 8
: D == NORTH_EAST ? (b & ~FileHBB) << 9 : D == SOUTH_EAST ? (b & ~FileHBB) >> 7
: D == NORTH_WEST ? (b & ~FileABB) << 7 : D == SOUTH_WEST ? (b & ~FileABB) >> 9
: 0;
}

View File

@ -259,8 +259,8 @@ Value Endgame<KRKP>::operator()(const Position& pos) const {
result = Value(80) - 8 * distance(wksq, psq);
else
result = Value(200) - 8 * ( distance(wksq, psq + DELTA_S)
- distance(bksq, psq + DELTA_S)
result = Value(200) - 8 * ( distance(wksq, psq + SOUTH)
- distance(bksq, psq + SOUTH)
- distance(psq, queeningSq));
return strongSide == pos.side_to_move() ? result : -result;
@ -496,7 +496,7 @@ ScaleFactor Endgame<KRPKR>::operator()(const Position& pos) const {
// If the defending king blocks the pawn and the attacking king is too far
// away, it's a draw.
if ( r <= RANK_5
&& bksq == wpsq + DELTA_N
&& bksq == wpsq + NORTH
&& distance(wksq, wpsq) - tempo >= 2
&& distance(wksq, brsq) - tempo >= 2)
return SCALE_FACTOR_DRAW;
@ -517,10 +517,10 @@ ScaleFactor Endgame<KRPKR>::operator()(const Position& pos) const {
&& file_of(wrsq) == f
&& wrsq < wpsq
&& (distance(wksq, queeningSq) < distance(bksq, queeningSq) - 2 + tempo)
&& (distance(wksq, wpsq + DELTA_N) < distance(bksq, wpsq + DELTA_N) - 2 + tempo)
&& (distance(wksq, wpsq + NORTH) < distance(bksq, wpsq + NORTH) - 2 + tempo)
&& ( distance(bksq, wrsq) + tempo >= 3
|| ( distance(wksq, queeningSq) < distance(bksq, wrsq) + tempo
&& (distance(wksq, wpsq + DELTA_N) < distance(bksq, wrsq) + tempo))))
&& (distance(wksq, wpsq + NORTH) < distance(bksq, wrsq) + tempo))))
return ScaleFactor( SCALE_FACTOR_MAX
- 8 * distance(wpsq, queeningSq)
- 2 * distance(wksq, queeningSq));

View File

@ -156,7 +156,8 @@ namespace {
// ThreatBySafePawn[PieceType] contains bonuses according to which piece
// type is attacked by a pawn which is protected or is not attacked.
const Score ThreatBySafePawn[PIECE_TYPE_NB] = {
S(0, 0), S(0, 0), S(176, 139), S(131, 127), S(217, 218), S(203, 215) };
S(0, 0), S(0, 0), S(176, 139), S(131, 127), S(217, 218), S(203, 215)
};
// Threat[by minor/by rook][attacked PieceType] contains
// bonuses according to which piece type attacks which one.
@ -197,6 +198,8 @@ namespace {
const Score Hanging = S(48, 27);
const Score ThreatByPawnPush = S(38, 22);
const Score Unstoppable = S( 0, 20);
const Score PawnlessFlank = S(20, 80);
const Score HinderPassedPawn = S( 7, 0);
// Penalty for a bishop on a1/h1 (a8/h8 for black) which is trapped by
// a friendly pawn on b2/g2 (b7/g7 for black). This can obviously only
@ -223,8 +226,8 @@ namespace {
template<Color Us>
void eval_init(const Position& pos, EvalInfo& ei) {
const Color Them = (Us == WHITE ? BLACK : WHITE);
const Square Down = (Us == WHITE ? DELTA_S : DELTA_N);
const Color Them = (Us == WHITE ? BLACK : WHITE);
const Square Down = (Us == WHITE ? SOUTH : NORTH);
ei.pinnedPieces[Us] = pos.pinned_pieces(Us);
Bitboard b = ei.attackedBy[Them][KING];
@ -235,7 +238,7 @@ namespace {
// Init king safety tables only if we are going to use them
if (pos.non_pawn_material(Us) >= QueenValueMg)
{
ei.kingRing[Them] = b | shift_bb<Down>(b);
ei.kingRing[Them] = b | shift<Down>(b);
b &= ei.attackedBy[Us][PAWN];
ei.kingAttackersCount[Us] = popcount(b);
ei.kingAdjacentZoneAttacksCount[Us] = ei.kingAttackersWeight[Us] = 0;
@ -321,7 +324,7 @@ namespace {
&& pos.is_chess960()
&& (s == relative_square(Us, SQ_A1) || s == relative_square(Us, SQ_H1)))
{
Square d = pawn_push(Us) + (file_of(s) == FILE_A ? DELTA_E : DELTA_W);
Square d = pawn_push(Us) + (file_of(s) == FILE_A ? EAST : WEST);
if (pos.piece_on(s + d) == make_piece(Us, PAWN))
score -= !pos.empty(s + d + pawn_push(Us)) ? TrappedBishopA1H1 * 4
: pos.piece_on(s + d + d) == make_piece(Us, PAWN) ? TrappedBishopA1H1 * 2
@ -391,8 +394,8 @@ namespace {
template<Color Us, bool DoTrace>
Score evaluate_king(const Position& pos, const EvalInfo& ei) {
const Color Them = (Us == WHITE ? BLACK : WHITE);
const Square Up = (Us == WHITE ? DELTA_N : DELTA_S);
const Color Them = (Us == WHITE ? BLACK : WHITE);
const Square Up = (Us == WHITE ? NORTH : SOUTH);
Bitboard undefended, b, b1, b2, safe, other;
int kingDanger;
@ -438,7 +441,7 @@ namespace {
// ... and some other potential checks, only requiring the square to be
// safe from pawn-attacks, and not being occupied by a blocked pawn.
other = ~( ei.attackedBy[Us][PAWN]
| (pos.pieces(Them, PAWN) & shift_bb<Up>(pos.pieces(PAWN))));
| (pos.pieces(Them, PAWN) & shift<Up>(pos.pieces(PAWN))));
b1 = pos.attacks_from<ROOK >(ksq);
b2 = pos.attacks_from<BISHOP>(ksq);
@ -481,7 +484,8 @@ namespace {
}
// King tropism: firstly, find squares that opponent attacks in our king flank
b = ei.attackedBy[Them][ALL_PIECES] & KingFlank[Us][file_of(ksq)];
File kf = file_of(ksq);
b = ei.attackedBy[Them][ALL_PIECES] & KingFlank[Us][kf];
assert(((Us == WHITE ? b << 4 : b >> 4) & b) == 0);
assert(popcount(Us == WHITE ? b << 4 : b >> 4) == popcount(b));
@ -493,6 +497,10 @@ namespace {
score -= CloseEnemies * popcount(b);
// Penalty when our king is on a pawnless flank
if (!(pos.pieces(PAWN) & (KingFlank[WHITE][kf] | KingFlank[BLACK][kf])))
score -= PawnlessFlank;
if (DoTrace)
Trace::add(KING, Us, score);
@ -506,12 +514,12 @@ namespace {
template<Color Us, bool DoTrace>
Score evaluate_threats(const Position& pos, const EvalInfo& ei) {
const Color Them = (Us == WHITE ? BLACK : WHITE);
const Square Up = (Us == WHITE ? DELTA_N : DELTA_S);
const Square Left = (Us == WHITE ? DELTA_NW : DELTA_SE);
const Square Right = (Us == WHITE ? DELTA_NE : DELTA_SW);
const Bitboard TRank2BB = (Us == WHITE ? Rank2BB : Rank7BB);
const Bitboard TRank7BB = (Us == WHITE ? Rank7BB : Rank2BB);
const Color Them = (Us == WHITE ? BLACK : WHITE);
const Square Up = (Us == WHITE ? NORTH : SOUTH);
const Square Left = (Us == WHITE ? NORTH_WEST : SOUTH_EAST);
const Square Right = (Us == WHITE ? NORTH_EAST : SOUTH_WEST);
const Bitboard TRank2BB = (Us == WHITE ? Rank2BB : Rank7BB);
const Bitboard TRank7BB = (Us == WHITE ? Rank7BB : Rank2BB);
enum { Minor, Rook };
@ -531,7 +539,7 @@ namespace {
b = pos.pieces(Us, PAWN) & ( ~ei.attackedBy[Them][ALL_PIECES]
| ei.attackedBy[Us][ALL_PIECES]);
safeThreats = (shift_bb<Right>(b) | shift_bb<Left>(b)) & weak;
safeThreats = (shift<Right>(b) | shift<Left>(b)) & weak;
if (weak ^ safeThreats)
score += ThreatByHangingPawn;
@ -568,13 +576,13 @@ namespace {
// Bonus if some pawns can safely push and attack an enemy piece
b = pos.pieces(Us, PAWN) & ~TRank7BB;
b = shift_bb<Up>(b | (shift_bb<Up>(b & TRank2BB) & ~pos.pieces()));
b = shift<Up>(b | (shift<Up>(b & TRank2BB) & ~pos.pieces()));
b &= ~pos.pieces()
& ~ei.attackedBy[Them][PAWN]
& (ei.attackedBy[Us][ALL_PIECES] | ~ei.attackedBy[Them][ALL_PIECES]);
b = (shift_bb<Left>(b) | shift_bb<Right>(b))
b = (shift<Left>(b) | shift<Right>(b))
& pos.pieces(Them)
& ~ei.attackedBy[Us][PAWN];
@ -594,7 +602,7 @@ namespace {
const Color Them = (Us == WHITE ? BLACK : WHITE);
Bitboard b, squaresToQueen, defendedSquares, unsafeSquares;
Bitboard b, bb, squaresToQueen, defendedSquares, unsafeSquares;
Score score = SCORE_ZERO;
b = ei.pi->passed_pawns(Us);
@ -606,6 +614,9 @@ namespace {
assert(pos.pawn_passed(Us, s));
assert(!(pos.pieces(PAWN) & forward_bb(Us, s)));
bb = forward_bb(Us, s) & (ei.attackedBy[Them][ALL_PIECES] | pos.pieces(Them));
score -= HinderPassedPawn * popcount(bb);
int r = relative_rank(Us, s) - RANK_2;
int rr = r * (r - 1);
@ -631,7 +642,7 @@ namespace {
// in the pawn's path attacked or occupied by the enemy.
defendedSquares = unsafeSquares = squaresToQueen = forward_bb(Us, s);
Bitboard bb = forward_bb(Them, s) & pos.pieces(ROOK, QUEEN) & pos.attacks_from<ROOK>(s);
bb = forward_bb(Them, s) & pos.pieces(ROOK, QUEEN) & pos.attacks_from<ROOK>(s);
if (!(pos.pieces(Us) & bb))
defendedSquares &= ei.attackedBy[Us][ALL_PIECES];
@ -803,8 +814,8 @@ Value Eval::evaluate(const Position& pos) {
// Pawns blocked or on ranks 2 and 3 will be excluded from the mobility area
Bitboard blockedPawns[] = {
pos.pieces(WHITE, PAWN) & (shift_bb<DELTA_S>(pos.pieces()) | Rank2BB | Rank3BB),
pos.pieces(BLACK, PAWN) & (shift_bb<DELTA_N>(pos.pieces()) | Rank7BB | Rank6BB)
pos.pieces(WHITE, PAWN) & (shift<SOUTH>(pos.pieces()) | Rank2BB | Rank3BB),
pos.pieces(BLACK, PAWN) & (shift<NORTH>(pos.pieces()) | Rank7BB | Rank6BB)
};
// Do not include in mobility area squares protected by enemy pawns, or occupied

View File

@ -32,7 +32,7 @@ namespace {
/// Version number. If Version is left empty, then compile date in the format
/// DD-MM-YY and show in engine_info.
const string Version = "2016-09-17";
const string Version = "8";
/// 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

View File

@ -42,8 +42,8 @@ namespace {
assert(!pos.checkers());
const Square K = Chess960 ? kto > kfrom ? DELTA_W : DELTA_E
: KingSide ? DELTA_W : DELTA_E;
const Square K = Chess960 ? kto > kfrom ? WEST : EAST
: KingSide ? WEST : EAST;
for (Square s = kto; s != kfrom; s += K)
if (pos.attackers_to(s) & enemies)
@ -65,23 +65,23 @@ namespace {
}
template<GenType Type, Square Delta>
template<GenType Type, Square D>
ExtMove* make_promotions(ExtMove* moveList, Square to, Square ksq) {
if (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS)
*moveList++ = make<PROMOTION>(to - Delta, to, QUEEN);
*moveList++ = make<PROMOTION>(to - D, to, QUEEN);
if (Type == QUIETS || Type == EVASIONS || Type == NON_EVASIONS)
{
*moveList++ = make<PROMOTION>(to - Delta, to, ROOK);
*moveList++ = make<PROMOTION>(to - Delta, to, BISHOP);
*moveList++ = make<PROMOTION>(to - Delta, to, KNIGHT);
*moveList++ = make<PROMOTION>(to - D, to, ROOK);
*moveList++ = make<PROMOTION>(to - D, to, BISHOP);
*moveList++ = make<PROMOTION>(to - D, to, KNIGHT);
}
// Knight promotion is the only promotion that can give a direct check
// that's not already included in the queen promotion.
if (Type == QUIET_CHECKS && (StepAttacksBB[W_KNIGHT][to] & ksq))
*moveList++ = make<PROMOTION>(to - Delta, to, KNIGHT);
*moveList++ = make<PROMOTION>(to - D, to, KNIGHT);
else
(void)ksq; // Silence a warning under MSVC
@ -94,13 +94,13 @@ namespace {
// Compute our parametrized parameters at compile time, named according to
// the point of view of white side.
const Color Them = (Us == WHITE ? BLACK : WHITE);
const Bitboard TRank8BB = (Us == WHITE ? Rank8BB : Rank1BB);
const Bitboard TRank7BB = (Us == WHITE ? Rank7BB : Rank2BB);
const Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB);
const Square Up = (Us == WHITE ? DELTA_N : DELTA_S);
const Square Right = (Us == WHITE ? DELTA_NE : DELTA_SW);
const Square Left = (Us == WHITE ? DELTA_NW : DELTA_SE);
const Color Them = (Us == WHITE ? BLACK : WHITE);
const Bitboard TRank8BB = (Us == WHITE ? Rank8BB : Rank1BB);
const Bitboard TRank7BB = (Us == WHITE ? Rank7BB : Rank2BB);
const Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB);
const Square Up = (Us == WHITE ? NORTH : SOUTH);
const Square Right = (Us == WHITE ? NORTH_EAST : SOUTH_WEST);
const Square Left = (Us == WHITE ? NORTH_WEST : SOUTH_EAST);
Bitboard emptySquares;
@ -115,8 +115,8 @@ namespace {
{
emptySquares = (Type == QUIETS || Type == QUIET_CHECKS ? target : ~pos.pieces());
Bitboard b1 = shift_bb<Up>(pawnsNotOn7) & emptySquares;
Bitboard b2 = shift_bb<Up>(b1 & TRank3BB) & emptySquares;
Bitboard b1 = shift<Up>(pawnsNotOn7) & emptySquares;
Bitboard b2 = shift<Up>(b1 & TRank3BB) & emptySquares;
if (Type == EVASIONS) // Consider only blocking squares
{
@ -138,8 +138,8 @@ namespace {
Bitboard dcCandidates = pos.discovered_check_candidates();
if (pawnsNotOn7 & dcCandidates)
{
Bitboard dc1 = shift_bb<Up>(pawnsNotOn7 & dcCandidates) & emptySquares & ~file_bb(ksq);
Bitboard dc2 = shift_bb<Up>(dc1 & TRank3BB) & emptySquares;
Bitboard dc1 = shift<Up>(pawnsNotOn7 & dcCandidates) & emptySquares & ~file_bb(ksq);
Bitboard dc2 = shift<Up>(dc1 & TRank3BB) & emptySquares;
b1 |= dc1;
b2 |= dc2;
@ -168,9 +168,9 @@ namespace {
if (Type == EVASIONS)
emptySquares &= target;
Bitboard b1 = shift_bb<Right>(pawnsOn7) & enemies;
Bitboard b2 = shift_bb<Left >(pawnsOn7) & enemies;
Bitboard b3 = shift_bb<Up >(pawnsOn7) & emptySquares;
Bitboard b1 = shift<Right>(pawnsOn7) & enemies;
Bitboard b2 = shift<Left >(pawnsOn7) & enemies;
Bitboard b3 = shift<Up >(pawnsOn7) & emptySquares;
Square ksq = pos.square<KING>(Them);
@ -187,8 +187,8 @@ namespace {
// Standard and en-passant captures
if (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS)
{
Bitboard b1 = shift_bb<Right>(pawnsNotOn7) & enemies;
Bitboard b2 = shift_bb<Left >(pawnsNotOn7) & enemies;
Bitboard b1 = shift<Right>(pawnsNotOn7) & enemies;
Bitboard b2 = shift<Left >(pawnsNotOn7) & enemies;
while (b1)
{

View File

@ -115,7 +115,7 @@ MovePicker::MovePicker(const Position& p, Move ttm, Value th)
ttMove = ttm
&& pos.pseudo_legal(ttm)
&& pos.capture(ttm)
&& pos.see(ttm) > threshold ? ttm : MOVE_NONE;
&& pos.see_ge(ttm, threshold + 1)? ttm : MOVE_NONE;
stage += (ttMove == MOVE_NONE);
}
@ -159,19 +159,13 @@ void MovePicker::score<QUIETS>() {
template<>
void MovePicker::score<EVASIONS>() {
// Try winning and equal captures ordered by MVV/LVA, then non-captures ordered
// by history value, then bad captures and quiet moves with a negative SEE ordered
// by SEE value.
// Try captures ordered by MVV/LVA, then non-captures ordered by history value
const HistoryStats& history = pos.this_thread()->history;
const FromToStats& fromTo = pos.this_thread()->fromTo;
Color c = pos.side_to_move();
Value see;
for (auto& m : *this)
if ((see = pos.see_sign(m)) < VALUE_ZERO)
m.value = see - HistoryStats::Max; // At the bottom
else if (pos.capture(m))
if (pos.capture(m))
m.value = PieceValue[MG][pos.piece_on(to_sq(m))]
- Value(type_of(pos.moved_piece(m))) + HistoryStats::Max;
else
@ -207,7 +201,7 @@ Move MovePicker::next_move() {
move = pick_best(cur++, endMoves);
if (move != ttMove)
{
if (pos.see_sign(move) >= VALUE_ZERO)
if (pos.see_ge(move, VALUE_ZERO))
return move;
// Losing capture, move it to the beginning of the array
@ -277,8 +271,7 @@ Move MovePicker::next_move() {
case EVASIONS_INIT:
cur = moves;
endMoves = generate<EVASIONS>(pos, cur);
if (endMoves - cur - (ttMove != MOVE_NONE) > 1)
score<EVASIONS>();
score<EVASIONS>();
++stage;
case ALL_EVASIONS:
@ -301,7 +294,7 @@ Move MovePicker::next_move() {
{
move = pick_best(cur++, endMoves);
if ( move != ttMove
&& pos.see(move) > threshold)
&& pos.see_ge(move, threshold + 1))
return move;
}
break;

View File

@ -37,9 +37,8 @@ namespace {
// Backward pawn penalty by opposed flag
const Score Backward[2] = { S(56, 33), S(41, 19) };
// Unsupported pawn penalty for pawns which are neither isolated or backward,
// by number of pawns it supports [less than 2 / exactly 2].
const Score Unsupported[2] = { S(17, 8), S(21, 12) };
// Unsupported pawn penalty for pawns which are neither isolated or backward
const Score Unsupported = S(17, 8);
// Connected pawn bonus by opposed, phalanx, twice supported and rank
Score Connected[2][2][2][RANK_NB];
@ -50,14 +49,16 @@ namespace {
// 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) };
S(17, 16), S(33, 32), S(0, 0), S(0, 0)
};
// Weakness of our pawn shelter in front of the king by [distance from edge][rank]
const Value ShelterWeakness[][RANK_NB] = {
{ V( 97), V(21), V(26), V(51), V(87), V( 89), V( 99) },
{ V(120), V( 0), V(28), V(76), V(88), V(103), V(104) },
{ V(101), V( 7), V(54), V(78), V(77), V( 92), V(101) },
{ V( 80), V(11), V(44), V(68), V(87), V( 90), V(119) } };
{ V( 80), V(11), V(44), V(68), V(87), V( 90), V(119) }
};
// Danger of enemy pawns moving toward our king by [type][distance from edge][rank]
const Value StormDanger[][4][RANK_NB] = {
@ -76,7 +77,8 @@ namespace {
{ { V( 0), V(-283), V(-281), V(57), V(31) },
{ V( 0), V( 58), V( 141), V(39), V(18) },
{ V( 0), V( 65), V( 142), V(48), V(32) },
{ V( 0), V( 60), V( 126), V(51), V(19) } } };
{ V( 0), V( 60), V( 126), V(51), V(19) } }
};
// Max bonus for king safety. Corresponds to start position with all the pawns
// in front of the king and no enemy pawn on the horizon.
@ -88,10 +90,10 @@ namespace {
template<Color Us>
Score evaluate(const Position& pos, Pawns::Entry* e) {
const Color Them = (Us == WHITE ? BLACK : WHITE);
const Square Up = (Us == WHITE ? DELTA_N : DELTA_S);
const Square Right = (Us == WHITE ? DELTA_NE : DELTA_SW);
const Square Left = (Us == WHITE ? DELTA_NW : DELTA_SE);
const Color Them = (Us == WHITE ? BLACK : WHITE);
const Square Up = (Us == WHITE ? NORTH : SOUTH);
const Square Right = (Us == WHITE ? NORTH_EAST : SOUTH_WEST);
const Square Left = (Us == WHITE ? NORTH_WEST : SOUTH_EAST);
Bitboard b, neighbours, stoppers, doubled, supported, phalanx;
Square s;
@ -103,10 +105,10 @@ namespace {
Bitboard ourPawns = pos.pieces(Us , PAWN);
Bitboard theirPawns = pos.pieces(Them, PAWN);
e->passedPawns[Us] = e->pawnAttacksSpan[Us] = 0;
e->kingSquares[Us] = SQ_NONE;
e->passedPawns[Us] = e->pawnAttacksSpan[Us] = 0;
e->semiopenFiles[Us] = 0xFF;
e->pawnAttacks[Us] = shift_bb<Right>(ourPawns) | shift_bb<Left>(ourPawns);
e->kingSquares[Us] = SQ_NONE;
e->pawnAttacks[Us] = shift<Right>(ourPawns) | shift<Left>(ourPawns);
e->pawnsOnSquares[Us][BLACK] = popcount(ourPawns & DarkSquares);
e->pawnsOnSquares[Us][WHITE] = pos.count<PAWN>(Us) - e->pawnsOnSquares[Us][BLACK];
@ -117,7 +119,7 @@ namespace {
File f = file_of(s);
e->semiopenFiles[Us] &= ~(1 << f);
e->semiopenFiles[Us] &= ~(1 << f);
e->pawnAttacksSpan[Us] |= pawn_attack_span(Us, s);
// Flag the pawn
@ -142,7 +144,7 @@ namespace {
// The pawn is backward when it cannot safely progress to that rank:
// either there is a stopper in the way on this rank, or there is a
// stopper on adjacent file which controls the way to that rank.
backward = (b | shift_bb<Up>(b & adjacent_files_bb(f))) & stoppers;
backward = (b | shift<Up>(b & adjacent_files_bb(f))) & stoppers;
assert(!backward || !(pawn_attack_span(Them, s + Up) & neighbours));
}
@ -160,7 +162,7 @@ namespace {
score -= Backward[opposed];
else if (!supported)
score -= Unsupported[more_than_one(neighbours & pawnAttacksBB[s])];
score -= Unsupported;
if (connected)
score += Connected[opposed][!!phalanx][more_than_one(supported)][relative_rank(Us, s)];
@ -183,8 +185,8 @@ namespace Pawns {
/// hard-coded tables, when makes sense, we prefer to calculate them with a formula
/// to reduce independent parameters and to allow easier tuning and better insight.
void init()
{
void init() {
static const int Seed[RANK_NB] = { 0, 8, 19, 13, 71, 94, 169, 324 };
for (int opposed = 0; opposed <= 1; ++opposed)

View File

@ -425,23 +425,28 @@ Phase Position::game_phase() const {
/// slider if removing that piece from the board would result in a position where
/// square 's' is attacked. For example, a king-attack blocking piece can be either
/// a pinned or a discovered check piece, according if its color is the opposite
/// or the same of the color of the slider. The pinners bitboard get filled with
/// real and potential pinners.
/// or the same of the color of the slider.
Bitboard Position::slider_blockers(Bitboard sliders, Square s, Bitboard& pinners) const {
Bitboard b, p, result = 0;
Bitboard result = 0;
pinners = 0;
// Pinners are sliders that attack 's' when a pinned piece is removed
pinners = p = ( (PseudoAttacks[ROOK ][s] & pieces(QUEEN, ROOK))
| (PseudoAttacks[BISHOP][s] & pieces(QUEEN, BISHOP))) & sliders;
// Snipers are sliders that attack 's' when a piece is removed
Bitboard snipers = ( (PseudoAttacks[ROOK ][s] & pieces(QUEEN, ROOK))
| (PseudoAttacks[BISHOP][s] & pieces(QUEEN, BISHOP))) & sliders;
while (p)
while (snipers)
{
b = between_bb(s, pop_lsb(&p)) & pieces();
Square sniperSq = pop_lsb(&snipers);
Bitboard b = between_bb(s, sniperSq) & pieces();
if (!more_than_one(b))
result |= b;
if (!more_than_one(b))
{
result |= b;
if (b & pieces(color_of(piece_on(s))))
pinners |= sniperSq;
}
}
return result;
}
@ -950,102 +955,83 @@ Key Position::key_after(Move m) const {
}
/// Position::see() is a static exchange evaluator: It tries to estimate the
/// material gain or loss resulting from a move.
/// Position::see_ge (Static Exchange Evaluation Greater or Equal) tests if the
/// SEE value of move is greater or equal to the given value. We'll use an
/// algorithm similar to alpha-beta pruning with a null window.
Value Position::see_sign(Move m) const {
bool Position::see_ge(Move m, Value v) const {
assert(is_ok(m));
// Early return if SEE cannot be negative because captured piece value
// is not less then capturing one. Note that king moves always return
// here because king midgame value is set to 0.
if (PieceValue[MG][moved_piece(m)] <= PieceValue[MG][piece_on(to_sq(m))])
return VALUE_KNOWN_WIN;
return see(m);
}
Value Position::see(Move m) const {
Square from, to;
Bitboard occupied, attackers, stmAttackers;
Value swapList[32];
int slIndex = 1;
PieceType captured;
Color stm;
assert(is_ok(m));
from = from_sq(m);
to = to_sq(m);
swapList[0] = PieceValue[MG][piece_on(to)];
stm = color_of(piece_on(from));
occupied = pieces() ^ from;
// Castling moves are implemented as king capturing the rook so cannot
// be handled correctly. Simply return VALUE_ZERO that is always correct
// unless in the rare case the rook ends up under attack.
// Castling moves are implemented as king capturing the rook so cannot be
// handled correctly. Simply assume the SEE value is VALUE_ZERO that is always
// correct unless in the rare case the rook ends up under attack.
if (type_of(m) == CASTLING)
return VALUE_ZERO;
return VALUE_ZERO >= v;
Square from = from_sq(m), to = to_sq(m);
PieceType nextVictim = type_of(piece_on(from));
Color stm = ~color_of(piece_on(from)); // First consider opponent's move
Value balance; // Values of the pieces taken by us minus opponent's ones
Bitboard occupied, stmAttackers;
if (type_of(m) == ENPASSANT)
{
occupied ^= to - pawn_push(stm); // Remove the captured pawn
swapList[0] = PieceValue[MG][PAWN];
occupied = SquareBB[to - pawn_push(~stm)]; // Remove the captured pawn
balance = PieceValue[MG][PAWN];
}
else
{
balance = PieceValue[MG][piece_on(to)];
occupied = 0;
}
// Find all attackers to the destination square, with the moving piece
// removed, but possibly an X-ray attacker added behind it.
attackers = attackers_to(to, occupied) & occupied;
if (balance < v)
return false;
// If the opponent has no attackers we are finished
stm = ~stm;
stmAttackers = attackers & pieces(stm);
occupied ^= to; // For the case when captured piece is a pinner
if (nextVictim == KING)
return true;
// Don't allow pinned pieces to attack as long all pinners (this includes also
// potential ones) are on their original square. When a pinner moves to the
// exchange-square or get captured on it, we fall back to standard SEE behaviour.
if ( (stmAttackers & pinned_pieces(stm))
&& (st->pinnersForKing[stm] & occupied) == st->pinnersForKing[stm])
stmAttackers &= ~pinned_pieces(stm);
balance -= PieceValue[MG][nextVictim];
if (!stmAttackers)
return swapList[0];
if (balance >= v)
return true;
// The destination square is defended, which makes things rather more
// difficult to compute. We proceed by building up a "swap list" containing
// the material gain or loss at each stop in a sequence of captures to the
// destination square, where the sides alternately capture, and always
// capture with the least valuable piece. After each capture, we look for
// new X-ray attacks from behind the capturing piece.
captured = type_of(piece_on(from));
bool relativeStm = true; // True if the opponent is to move
occupied ^= pieces() ^ from ^ to;
do {
assert(slIndex < 32);
// Find all attackers to the destination square, with the moving piece removed,
// but possibly an X-ray attacker added behind it.
Bitboard attackers = attackers_to(to, occupied) & occupied;
// Add the new entry to the swap list
swapList[slIndex] = -swapList[slIndex - 1] + PieceValue[MG][captured];
while (true)
{
stmAttackers = attackers & pieces(stm);
// Don't allow pinned pieces to attack pieces except the king as long all
// pinners are on their original square.
if (!(st->pinnersForKing[stm] & ~occupied))
stmAttackers &= ~st->blockersForKing[stm];
if (!stmAttackers)
return relativeStm;
// Locate and remove the next least valuable attacker
captured = min_attacker<PAWN>(byTypeBB, to, stmAttackers, occupied, attackers);
nextVictim = min_attacker<PAWN>(byTypeBB, to, stmAttackers, occupied, attackers);
if (nextVictim == KING)
return relativeStm == bool(attackers & pieces(~stm));
balance += relativeStm ? PieceValue[MG][nextVictim]
: -PieceValue[MG][nextVictim];
relativeStm = !relativeStm;
if (relativeStm == (balance >= v))
return relativeStm;
stm = ~stm;
stmAttackers = attackers & pieces(stm);
if ( (stmAttackers & pinned_pieces(stm))
&& (st->pinnersForKing[stm] & occupied) == st->pinnersForKing[stm])
stmAttackers &= ~pinned_pieces(stm);
++slIndex;
} while (stmAttackers && (captured != KING || (--slIndex, false))); // Stop before a king capture
// Having built the swap list, we negamax through it to find the best
// achievable score from the point of view of the side to move.
while (--slIndex)
swapList[slIndex - 1] = std::min(-swapList[slIndex], swapList[slIndex - 1]);
return swapList[0];
}
}

View File

@ -133,8 +133,7 @@ public:
void undo_null_move();
// Static Exchange Evaluation
Value see(Move m) const;
Value see_sign(Move m) const;
bool see_ge(Move m, Value value) const;
// Accessing hash keys
Key key() const;
@ -149,7 +148,6 @@ public:
bool is_chess960() const;
Thread* this_thread() const;
uint64_t nodes_searched() const;
void set_nodes_searched(uint64_t n);
bool is_draw() const;
int rule50_count() const;
Score psq_score() const;
@ -342,10 +340,6 @@ inline uint64_t Position::nodes_searched() const {
return nodes;
}
inline void Position::set_nodes_searched(uint64_t n) {
nodes = n;
}
inline bool Position::opposite_bishops() const {
return pieceCount[W_BISHOP] == 1
&& pieceCount[B_BISHOP] == 1

View File

@ -23,8 +23,9 @@
#include "types.h"
Value PieceValue[PHASE_NB][PIECE_NB] = {
{ VALUE_ZERO, PawnValueMg, KnightValueMg, BishopValueMg, RookValueMg, QueenValueMg },
{ VALUE_ZERO, PawnValueEg, KnightValueEg, BishopValueEg, RookValueEg, QueenValueEg } };
{ VALUE_ZERO, PawnValueMg, KnightValueMg, BishopValueMg, RookValueMg, QueenValueMg },
{ VALUE_ZERO, PawnValueEg, KnightValueEg, BishopValueEg, RookValueEg, QueenValueEg }
};
namespace PSQT {

View File

@ -46,7 +46,6 @@ namespace Search {
namespace Tablebases {
int Cardinality;
uint64_t Hits;
bool RootInTB;
bool UseRule50;
Depth ProbeDepth;
@ -462,11 +461,7 @@ void Thread::search() {
if (!mainThread)
continue;
if (Signals.stop)
sync_cout << "info nodes " << Threads.nodes_searched()
<< " time " << Time.elapsed() << sync_endl;
else if (PVIdx + 1 == multiPV || Time.elapsed() > 3000)
if (Signals.stop || PVIdx + 1 == multiPV || Time.elapsed() > 3000)
sync_cout << UCI::pv(rootPos, rootDepth, alpha, beta) << sync_endl;
}
@ -571,6 +566,7 @@ namespace {
Thread* thisThread = pos.this_thread();
inCheck = pos.checkers();
moveCount = quietCount = ss->moveCount = 0;
ss->history = VALUE_ZERO;
bestValue = -VALUE_INFINITE;
ss->ply = (ss-1)->ply + 1;
@ -636,8 +632,6 @@ namespace {
&& (ttValue >= beta ? (tte->bound() & BOUND_LOWER)
: (tte->bound() & BOUND_UPPER)))
{
ss->currentMove = ttMove; // Can be MOVE_NONE
// If ttMove is quiet, update killers, history, counter move on TT hit
if (ttValue >= beta && ttMove)
{
@ -674,7 +668,7 @@ namespace {
if (found)
{
TB::Hits++;
thisThread->tbHits++;
int drawScore = TB::UseRule50 ? 1 : 0;
@ -728,8 +722,7 @@ namespace {
&& ttMove == MOVE_NONE
&& eval + razor_margin[depth / ONE_PLY] <= alpha)
{
if ( depth <= ONE_PLY
&& eval + razor_margin[3 * ONE_PLY] <= alpha)
if (depth <= ONE_PLY)
return qsearch<NonPV, false>(pos, ss, alpha, beta, DEPTH_ZERO);
Value ralpha = alpha - razor_margin[depth / ONE_PLY];
@ -744,7 +737,7 @@ namespace {
&& eval - futility_margin(depth) >= beta
&& eval < VALUE_KNOWN_WIN // Do not return unproven wins
&& pos.non_pawn_material(pos.side_to_move()))
return eval - futility_margin(depth);
return eval;
// Step 8. Null move search with verification search (is omitted in PV nodes)
if ( !PvNode
@ -845,8 +838,7 @@ moves_loop: // When in check search starts from here
singularExtensionNode = !rootNode
&& depth >= 8 * ONE_PLY
&& ttMove != MOVE_NONE
/* && ttValue != VALUE_NONE Already implicit in the next condition */
&& abs(ttValue) < VALUE_KNOWN_WIN
&& ttValue != VALUE_NONE
&& !excludedMove // Recursive singular search is not allowed
&& (tte->bound() & BOUND_LOWER)
&& tte->depth() >= depth - 3 * ONE_PLY;
@ -891,7 +883,7 @@ moves_loop: // When in check search starts from here
// Step 12. Extend checks
if ( givesCheck
&& !moveCountPruning
&& pos.see_sign(move) >= VALUE_ZERO)
&& pos.see_ge(move, VALUE_ZERO))
extension = ONE_PLY;
// Singular extension search. If all moves but one fail low on a search of
@ -904,7 +896,7 @@ moves_loop: // When in check search starts from here
&& !extension
&& pos.legal(move))
{
Value rBeta = ttValue - 2 * depth / ONE_PLY;
Value rBeta = std::max(ttValue - 2 * depth / ONE_PLY, -VALUE_MATE);
Depth d = (depth / (2 * ONE_PLY)) * ONE_PLY;
ss->excludedMove = move;
ss->skipEarlyPruning = true;
@ -921,8 +913,7 @@ moves_loop: // When in check search starts from here
// Step 13. Pruning at shallow depth
if ( !rootNode
&& !inCheck
&& bestValue > VALUE_MATED_IN_MAX_PLY)
&& bestValue > VALUE_MATED_IN_MAX_PLY)
{
if ( !captureOrPromotion
&& !givesCheck
@ -944,16 +935,18 @@ moves_loop: // When in check search starts from here
// Futility pruning: parent node
if ( lmrDepth < 7
&& !inCheck
&& ss->staticEval + 256 + 200 * lmrDepth <= alpha)
continue;
// Prune moves with negative SEE
if ( lmrDepth < 8
&& pos.see_sign(move) < Value(-35 * lmrDepth * lmrDepth))
&& !pos.see_ge(move, Value(-35 * lmrDepth * lmrDepth)))
continue;
}
else if ( depth < 7 * ONE_PLY
&& pos.see_sign(move) < Value(-35 * depth / ONE_PLY * depth / ONE_PLY))
&& !extension
&& !pos.see_ge(move, Value(-35 * depth / ONE_PLY * depth / ONE_PLY)))
continue;
}
@ -995,17 +988,25 @@ moves_loop: // When in check search starts from here
// because the destination square is empty.
else if ( type_of(move) == NORMAL
&& type_of(pos.piece_on(to_sq(move))) != PAWN
&& pos.see(make_move(to_sq(move), from_sq(move))) < VALUE_ZERO)
&& !pos.see_ge(make_move(to_sq(move), from_sq(move)), VALUE_ZERO))
r -= 2 * ONE_PLY;
ss->history = thisThread->history[moved_piece][to_sq(move)]
+ (cmh ? (*cmh )[moved_piece][to_sq(move)] : VALUE_ZERO)
+ (fmh ? (*fmh )[moved_piece][to_sq(move)] : VALUE_ZERO)
+ (fmh2 ? (*fmh2)[moved_piece][to_sq(move)] : VALUE_ZERO)
+ thisThread->fromTo.get(~pos.side_to_move(), move)
- 8000; // Correction factor
// Decrease/increase reduction by comparing opponent's stat score
if (ss->history > VALUE_ZERO && (ss-1)->history < VALUE_ZERO)
r -= ONE_PLY;
else if (ss->history < VALUE_ZERO && (ss-1)->history > VALUE_ZERO)
r += ONE_PLY;
// Decrease/increase reduction for moves with a good/bad history
Value val = thisThread->history[moved_piece][to_sq(move)]
+ (cmh ? (*cmh )[moved_piece][to_sq(move)] : VALUE_ZERO)
+ (fmh ? (*fmh )[moved_piece][to_sq(move)] : VALUE_ZERO)
+ (fmh2 ? (*fmh2)[moved_piece][to_sq(move)] : VALUE_ZERO)
+ thisThread->fromTo.get(~pos.side_to_move(), move);
int rHist = (val - 8000) / 20000;
r = std::max(DEPTH_ZERO, (r / ONE_PLY - rHist) * ONE_PLY);
r = std::max(DEPTH_ZERO, (r / ONE_PLY - ss->history / 20000) * ONE_PLY);
}
Depth d = std::max(newDepth - r, ONE_PLY);
@ -1123,6 +1124,9 @@ moves_loop: // When in check search starts from here
// All legal moves have been searched and if there are no legal moves, it
// must be a mate or a stalemate. If we are in a singular extension search then
// return a fail low score.
assert(moveCount || !inCheck || excludedMove || !MoveList<LEGAL>(pos).size());
if (!moveCount)
bestValue = excludedMove ? alpha
: inCheck ? mated_in(ss->ply) : DrawValue[pos.side_to_move()];
@ -1226,10 +1230,7 @@ moves_loop: // When in check search starts from here
&& ttValue != VALUE_NONE // Only in case of TT access race
&& (ttValue >= beta ? (tte->bound() & BOUND_LOWER)
: (tte->bound() & BOUND_UPPER)))
{
ss->currentMove = ttMove; // Can be MOVE_NONE
return ttValue;
}
// Evaluate the position statically
if (InCheck)
@ -1302,7 +1303,7 @@ moves_loop: // When in check search starts from here
continue;
}
if (futilityBase <= alpha && pos.see(move) <= VALUE_ZERO)
if (futilityBase <= alpha && !pos.see_ge(move, VALUE_ZERO + 1))
{
bestValue = std::max(bestValue, futilityBase);
continue;
@ -1317,7 +1318,7 @@ moves_loop: // When in check search starts from here
// Don't search moves with negative SEE values
if ( (!InCheck || evasionPrunable)
&& type_of(move) != PROMOTION
&& pos.see_sign(move) < VALUE_ZERO)
&& !pos.see_ge(move, VALUE_ZERO))
continue;
// Speculative prefetch as early as possible
@ -1522,7 +1523,7 @@ moves_loop: // When in check search starts from here
if ( (Limits.use_time_management() && elapsed > Time.maximum() - 10)
|| (Limits.movetime && elapsed >= Limits.movetime)
|| (Limits.nodes && Threads.nodes_searched() >= Limits.nodes))
|| (Limits.nodes && Threads.nodes_searched() >= (uint64_t)Limits.nodes))
Signals.stop = true;
}
@ -1539,7 +1540,8 @@ string UCI::pv(const Position& pos, Depth depth, Value alpha, Value beta) {
const RootMoves& rootMoves = pos.this_thread()->rootMoves;
size_t PVIdx = pos.this_thread()->PVIdx;
size_t multiPV = std::min((size_t)Options["MultiPV"], rootMoves.size());
uint64_t nodes_searched = Threads.nodes_searched();
uint64_t nodesSearched = Threads.nodes_searched();
uint64_t tbHits = Threads.tb_hits() + (TB::RootInTB ? rootMoves.size() : 0);
for (size_t i = 0; i < multiPV; ++i)
{
@ -1566,13 +1568,13 @@ string UCI::pv(const Position& pos, Depth depth, Value alpha, Value beta) {
if (!tb && i == PVIdx)
ss << (v >= beta ? " lowerbound" : v <= alpha ? " upperbound" : "");
ss << " nodes " << nodes_searched
<< " nps " << nodes_searched * 1000 / elapsed;
ss << " nodes " << nodesSearched
<< " nps " << nodesSearched * 1000 / elapsed;
if (elapsed > 1000) // Earlier makes little sense
ss << " hashfull " << TT.hashfull();
ss << " tbhits " << TB::Hits
ss << " tbhits " << tbHits
<< " time " << elapsed
<< " pv";
@ -1589,13 +1591,16 @@ string UCI::pv(const Position& pos, Depth depth, Value alpha, Value beta) {
/// fail high at root. We try hard to have a ponder move to return to the GUI,
/// otherwise in case of 'ponder on' we have nothing to think on.
bool RootMove::extract_ponder_from_tt(Position& pos)
{
bool RootMove::extract_ponder_from_tt(Position& pos) {
StateInfo st;
bool ttHit;
assert(pv.size() == 1);
if (!pv[0])
return false;
pos.do_move(pv[0], st, pos.gives_check(pv[0]));
TTEntry* tte = TT.probe(pos.key(), ttHit);
@ -1612,7 +1617,6 @@ bool RootMove::extract_ponder_from_tt(Position& pos)
void Tablebases::filter_root_moves(Position& pos, Search::RootMoves& rootMoves) {
Hits = 0;
RootInTB = false;
UseRule50 = Options["Syzygy50MoveRule"];
ProbeDepth = Options["SyzygyProbeDepth"] * ONE_PLY;
@ -1645,13 +1649,8 @@ void Tablebases::filter_root_moves(Position& pos, Search::RootMoves& rootMoves)
Cardinality = 0;
}
if (RootInTB)
{
Hits = rootMoves.size();
if (!UseRule50)
TB::Score = TB::Score > VALUE_DRAW ? VALUE_MATE - MAX_PLY - 1
: TB::Score < VALUE_DRAW ? -VALUE_MATE + MAX_PLY + 1
: VALUE_DRAW;
}
if (RootInTB && !UseRule50)
TB::Score = TB::Score > VALUE_DRAW ? VALUE_MATE - MAX_PLY - 1
: TB::Score < VALUE_DRAW ? -VALUE_MATE + MAX_PLY + 1
: VALUE_DRAW;
}

View File

@ -43,6 +43,7 @@ struct Stack {
Move excludedMove;
Move killers[2];
Value staticEval;
Value history;
bool skipEarlyPruning;
int moveCount;
CounterMoveStats* counterMoves;

View File

@ -36,6 +36,7 @@ Thread::Thread() {
resetCalls = exit = false;
maxPly = callsCnt = 0;
tbHits = 0;
history.clear();
counterMoves.clear();
idx = Threads.size(); // Start from 0
@ -158,15 +159,26 @@ void ThreadPool::read_uci_options() {
/// ThreadPool::nodes_searched() returns the number of nodes searched
int64_t ThreadPool::nodes_searched() {
uint64_t ThreadPool::nodes_searched() const {
int64_t nodes = 0;
uint64_t nodes = 0;
for (Thread* th : *this)
nodes += th->rootPos.nodes_searched();
return nodes;
}
/// ThreadPool::tb_hits() returns the number of TB hits
uint64_t ThreadPool::tb_hits() const {
uint64_t hits = 0;
for (Thread* th : *this)
hits += th->tbHits;
return hits;
}
/// ThreadPool::start_thinking() wakes up the main thread sleeping in idle_loop()
/// and starts a new search, then returns immediately.
@ -184,7 +196,8 @@ void ThreadPool::start_thinking(Position& pos, StateListPtr& states,
|| std::count(limits.searchmoves.begin(), limits.searchmoves.end(), m))
rootMoves.push_back(Search::RootMove(m));
Tablebases::filter_root_moves(pos, rootMoves);
if (!rootMoves.empty())
Tablebases::filter_root_moves(pos, rootMoves);
// After ownership transfer 'states' becomes empty, so if we stop the search
// and call 'go' again without setting a new position states.get() == NULL.
@ -198,6 +211,7 @@ void ThreadPool::start_thinking(Position& pos, StateListPtr& states,
for (Thread* th : Threads)
{
th->maxPly = 0;
th->tbHits = 0;
th->rootDepth = DEPTH_ZERO;
th->rootMoves = rootMoves;
th->rootPos.set(pos.fen(), pos.is_chess960(), &setupStates->back(), th);

View File

@ -62,6 +62,7 @@ public:
Endgames endgames;
size_t idx, PVIdx;
int maxPly, callsCnt;
uint64_t tbHits;
Position rootPos;
Search::RootMoves rootMoves;
@ -98,7 +99,8 @@ struct ThreadPool : public std::vector<Thread*> {
MainThread* main() { return static_cast<MainThread*>(at(0)); }
void start_thinking(Position&, StateListPtr&, const Search::LimitsType&);
void read_uci_options();
int64_t nodes_searched();
uint64_t nodes_searched() const;
uint64_t tb_hits() const;
private:
StateListPtr setupStates;

View File

@ -52,8 +52,8 @@ namespace {
}
template<TimeType T>
int remaining(int myTime, int movesToGo, int ply, int slowMover)
{
int remaining(int myTime, int movesToGo, int ply, int slowMover) {
const double TMaxRatio = (T == OptimumTime ? 1 : MaxRatio);
const double TStealRatio = (T == OptimumTime ? 0 : StealRatio);
@ -81,8 +81,8 @@ namespace {
/// inc > 0 && movestogo == 0 means: x basetime + z increment
/// inc > 0 && movestogo != 0 means: x moves in y minutes + z increment
void TimeManagement::init(Search::LimitsType& limits, Color us, int ply)
{
void TimeManagement::init(Search::LimitsType& limits, Color us, int ply) {
int minThinkingTime = Options["Minimum Thinking Time"];
int moveOverhead = Options["Move Overhead"];
int slowMover = Options["Slow Mover"];

View File

@ -100,11 +100,11 @@ TTEntry* TranspositionTable::probe(const Key key, bool& found) const {
}
/// Returns an approximation of the hashtable occupation during a search. The
/// hash is x permill full, as per UCI protocol.
/// TranspositionTable::hashfull() returns an approximation of the hashtable
/// occupation during a search. The hash is x permill full, as per UCI protocol.
int TranspositionTable::hashfull() const {
int TranspositionTable::hashfull() const
{
int cnt = 0;
for (int i = 0; i < 1000 / ClusterSize; i++)
{

View File

@ -115,7 +115,7 @@ const int MAX_PLY = 128;
/// any normal move destination square is always different from origin square
/// while MOVE_NONE and MOVE_NULL have the same origin and destination square.
enum Move {
enum Move : int {
MOVE_NONE,
MOVE_NULL = 65
};
@ -237,35 +237,34 @@ enum Square {
SQUARE_NB = 64,
DELTA_N = 8,
DELTA_E = 1,
DELTA_S = -8,
DELTA_W = -1,
NORTH = 8,
EAST = 1,
SOUTH = -8,
WEST = -1,
DELTA_NN = DELTA_N + DELTA_N,
DELTA_NE = DELTA_N + DELTA_E,
DELTA_SE = DELTA_S + DELTA_E,
DELTA_SS = DELTA_S + DELTA_S,
DELTA_SW = DELTA_S + DELTA_W,
DELTA_NW = DELTA_N + DELTA_W
NORTH_EAST = NORTH + EAST,
SOUTH_EAST = SOUTH + EAST,
SOUTH_WEST = SOUTH + WEST,
NORTH_WEST = NORTH + WEST
};
enum File {
enum File : int {
FILE_A, FILE_B, FILE_C, FILE_D, FILE_E, FILE_F, FILE_G, FILE_H, FILE_NB
};
enum Rank {
enum Rank : int {
RANK_1, RANK_2, RANK_3, RANK_4, RANK_5, RANK_6, RANK_7, RANK_8, RANK_NB
};
/// Score enum stores a middlegame and an endgame value in a single integer
/// (enum). The least significant 16 bits are used to store the endgame value
/// and the upper 16 bits are used to store the middlegame value.
/// and the upper 16 bits are used to store the middlegame value. Take some
/// care to avoid left-shifting a signed int to avoid undefined behavior.
enum Score : int { SCORE_ZERO };
inline Score make_score(int mg, int eg) {
return Score((eg << 16) + mg);
return Score((int)((unsigned int)eg << 16) + mg);
}
/// Extracting the signed lower and upper 16 bits is not so trivial because
@ -401,7 +400,7 @@ inline bool opposite_colors(Square s1, Square s2) {
}
inline Square pawn_push(Color c) {
return c == WHITE ? DELTA_N : DELTA_S;
return c == WHITE ? NORTH : SOUTH;
}
inline Square from_sq(Move m) {