1
0
Fork 0
mirror of https://github.com/sockspls/badfish synced 2025-05-03 10:09:35 +00:00

Merge branch 'master' into clusterMergeMaster3

This commit is contained in:
Joost VandeVondele 2019-01-09 21:52:30 +01:00
commit 21819b7bf8
22 changed files with 181 additions and 165 deletions

View file

@ -63,7 +63,7 @@ script:
# #
# Valgrind # Valgrind
# #
- export CXXFLAGS=-O1 - export CXXFLAGS="-O1 -fno-inline"
- if [ -x "$(command -v valgrind )" ]; then make clean && make -j2 ARCH=x86-64 debug=yes optimize=no build > /dev/null && ../tests/instrumented.sh --valgrind; fi - if [ -x "$(command -v valgrind )" ]; then make clean && make -j2 ARCH=x86-64 debug=yes optimize=no build > /dev/null && ../tests/instrumented.sh --valgrind; fi
- if [ -x "$(command -v valgrind )" ]; then ../tests/instrumented.sh --valgrind-thread; fi - if [ -x "$(command -v valgrind )" ]; then ../tests/instrumented.sh --valgrind-thread; fi
# #

View file

@ -86,7 +86,9 @@ Currently, Stockfish has the following UCI options:
Example: `C:\tablebases\wdl345;C:\tablebases\wdl6;D:\tablebases\dtz345;D:\tablebases\dtz6` Example: `C:\tablebases\wdl345;C:\tablebases\wdl6;D:\tablebases\dtz345;D:\tablebases\dtz6`
It is recommended to store .rtbw files on an SSD. There is no loss in storing It is recommended to store .rtbw files on an SSD. There is no loss in storing
the .rtbz files on a regular HD. the .rtbz files on a regular HD. It is recommended to verify all md5 checksums
of the downloaded tablebase files (`md5sum -c checksum.md5`) as corruption will
lead to engine crashes.
* #### SyzygyProbeDepth * #### SyzygyProbeDepth
Minimum remaining search depth for which a position is probed. Set this option Minimum remaining search depth for which a position is probed. Set this option

View file

@ -184,8 +184,8 @@ namespace {
// init_magics() computes all rook and bishop attacks at startup. Magic // init_magics() computes all rook and bishop attacks at startup. Magic
// bitboards are used to look up attacks of sliding pieces. As a reference see // bitboards are used to look up attacks of sliding pieces. As a reference see
// chessprogramming.wikispaces.com/Magic+Bitboards. In particular, here we // www.chessprogramming.org/Magic_Bitboards. In particular, here we use the so
// use the so called "fancy" approach. // called "fancy" approach.
void init_magics(Bitboard table[], Magic magics[], Direction directions[]) { void init_magics(Bitboard table[], Magic magics[], Direction directions[]) {

View file

@ -239,9 +239,9 @@ void signals_poll() {
} }
void save(Thread* thread, TTEntry* tte, void save(Thread* thread, TTEntry* tte,
Key k, Value v, Bound b, Depth d, Move m, Value ev) { Key k, Value v, bool PvHit, Bound b, Depth d, Move m, Value ev) {
tte->save(k, v, b, d, m, ev); tte->save(k, v, PvHit, b, d, m, ev);
if (d > 3 * ONE_PLY) if (d > 3 * ONE_PLY)
{ {
@ -291,7 +291,7 @@ void save(Thread* thread, TTEntry* tte,
bool found; bool found;
TTEntry* replace_tte; TTEntry* replace_tte;
replace_tte = TT.probe(e.first, found); replace_tte = TT.probe(e.first, found);
replace_tte->save(e.first, e.second.value(), e.second.bound(), e.second.depth(), replace_tte->save(e.first, e.second.value(), e.second.pv_hit(), e.second.bound(), e.second.depth(),
e.second.move(), e.second.eval()); e.second.move(), e.second.eval());
} }
} }

View file

@ -73,7 +73,7 @@ bool getline(std::istream& input, std::string& str);
int size(); int size();
int rank(); int rank();
inline bool is_root() { return rank() == 0; } inline bool is_root() { return rank() == 0; }
void save(Thread* thread, TTEntry* tte, Key k, Value v, Bound b, Depth d, Move m, Value ev); void save(Thread* thread, TTEntry* tte, Key k, Value v, bool PvHit, Bound b, Depth d, Move m, Value ev);
void pick_moves(MoveInfo& mi, std::string& PVLine); void pick_moves(MoveInfo& mi, std::string& PVLine);
void ttRecvBuff_resize(size_t nThreads); void ttRecvBuff_resize(size_t nThreads);
uint64_t nodes_searched(); uint64_t nodes_searched();
@ -90,7 +90,7 @@ inline bool getline(std::istream& input, std::string& str) { return static_cast<
constexpr int size() { return 1; } constexpr int size() { return 1; }
constexpr int rank() { return 0; } constexpr int rank() { return 0; }
constexpr bool is_root() { return true; } constexpr bool is_root() { return true; }
inline void save(Thread*, TTEntry* tte, Key k, Value v, Bound b, Depth d, Move m, Value ev) { tte->save(k, v, b, d, m, ev); } inline void save(Thread*, TTEntry* tte, Key k, Value v, bool PvHit, Bound b, Depth d, Move m, Value ev) { tte->save(k, v, PvHit, b, d, m, ev); }
inline void pick_moves(MoveInfo&, std::string&) { } inline void pick_moves(MoveInfo&, std::string&) { }
inline void ttRecvBuff_resize(size_t) { } inline void ttRecvBuff_resize(size_t) { }
uint64_t nodes_searched(); uint64_t nodes_searched();

View file

@ -724,6 +724,9 @@ ScaleFactor Endgame<KNPK>::operator()(const Position& pos) const {
template<> template<>
ScaleFactor Endgame<KNPKB>::operator()(const Position& pos) const { ScaleFactor Endgame<KNPKB>::operator()(const Position& pos) const {
assert(verify_material(pos, strongSide, KnightValueMg, 1));
assert(verify_material(pos, weakSide, BishopValueMg, 0));
Square pawnSq = pos.square<PAWN>(strongSide); Square pawnSq = pos.square<PAWN>(strongSide);
Square bishopSq = pos.square<BISHOP>(weakSide); Square bishopSq = pos.square<BISHOP>(weakSide);
Square weakKingSq = pos.square<KING>(weakSide); Square weakKingSq = pos.square<KING>(weakSide);

View file

@ -213,7 +213,7 @@ namespace {
// kingRing[color] are the squares adjacent to the king, plus (only for a // kingRing[color] are the squares adjacent to the king, plus (only for a
// king on its first rank) the squares two ranks in front. For instance, // king on its first rank) the squares two ranks in front. For instance,
// if black's king is on g8, kingRing[BLACK] is f8, h8, f7, g7, h7, f6, g6 // if black's king is on g8, kingRing[BLACK] is f8, h8, f7, g7, h7, f6, g6
// and h6. It is set to 0 when king safety evaluation is skipped. // and h6.
Bitboard kingRing[COLOR_NB]; Bitboard kingRing[COLOR_NB];
// kingAttackersCount[color] is the number of pieces of the given color // kingAttackersCount[color] is the number of pieces of the given color
@ -505,7 +505,7 @@ namespace {
Score score = SCORE_ZERO; Score score = SCORE_ZERO;
// Non-pawn enemies // Non-pawn enemies
nonPawnEnemies = pos.pieces(Them) & ~pos.pieces(Them, PAWN); nonPawnEnemies = pos.pieces(Them) & ~pos.pieces(PAWN);
// Squares strongly protected by the enemy, either because they defend the // Squares strongly protected by the enemy, either because they defend the
// square with a pawn, or because they defend the square twice and we don't. // square with a pawn, or because they defend the square twice and we don't.
@ -717,7 +717,8 @@ namespace {
behind |= (Us == WHITE ? behind >> 16 : behind << 16); behind |= (Us == WHITE ? behind >> 16 : behind << 16);
int bonus = popcount(safe) + popcount(behind & safe); int bonus = popcount(safe) + popcount(behind & safe);
int weight = pos.count<ALL_PIECES>(Us) - 2 * pe->open_files(); int weight = pos.count<ALL_PIECES>(Us)
- 2 * popcount(pe->semiopenFiles[WHITE] & pe->semiopenFiles[BLACK]);
Score score = make_score(bonus * weight * weight / 16, 0); Score score = make_score(bonus * weight * weight / 16, 0);

View file

@ -25,47 +25,6 @@
namespace { namespace {
template<Color Us, CastlingSide Cs, bool Checks, bool Chess960>
ExtMove* generate_castling(const Position& pos, ExtMove* moveList) {
constexpr CastlingRight Cr = Us | Cs;
constexpr bool KingSide = (Cs == KING_SIDE);
if (pos.castling_impeded(Cr) || !pos.can_castle(Cr))
return moveList;
// After castling, the rook and king final positions are the same in Chess960
// as they would be in standard chess.
Square kfrom = pos.square<KING>(Us);
Square rfrom = pos.castling_rook_square(Cr);
Square kto = relative_square(Us, KingSide ? SQ_G1 : SQ_C1);
Bitboard enemies = pos.pieces(~Us);
assert(!pos.checkers());
const Direction step = Chess960 ? kto > kfrom ? WEST : EAST
: KingSide ? WEST : EAST;
for (Square s = kto; s != kfrom; s += step)
if (pos.attackers_to(s) & enemies)
return moveList;
// Because we generate only legal castling moves we need to verify that
// when moving the castling rook we do not discover some hidden checker.
// For instance an enemy queen in SQ_A1 when castling rook is in SQ_B1.
if (Chess960 && (attacks_bb<ROOK>(kto, pos.pieces() ^ rfrom) & pos.pieces(~Us, ROOK, QUEEN)))
return moveList;
Move m = make<CASTLING>(kfrom, rfrom);
if (Checks && !pos.gives_check(m))
return moveList;
*moveList++ = m;
return moveList;
}
template<GenType Type, Direction D> template<GenType Type, Direction D>
ExtMove* make_promotions(ExtMove* moveList, Square to, Square ksq) { ExtMove* make_promotions(ExtMove* moveList, Square to, Square ksq) {
@ -93,10 +52,8 @@ namespace {
template<Color Us, GenType Type> template<Color Us, GenType Type>
ExtMove* generate_pawn_moves(const Position& pos, ExtMove* moveList, Bitboard target) { ExtMove* generate_pawn_moves(const Position& pos, ExtMove* moveList, Bitboard target) {
// Compute our parametrized parameters at compile time, named according to // Compute some compile time parameters relative to the white side
// the point of view of white side.
constexpr Color Them = (Us == WHITE ? BLACK : WHITE); constexpr Color Them = (Us == WHITE ? BLACK : WHITE);
constexpr Bitboard TRank8BB = (Us == WHITE ? Rank8BB : Rank1BB);
constexpr Bitboard TRank7BB = (Us == WHITE ? Rank7BB : Rank2BB); constexpr Bitboard TRank7BB = (Us == WHITE ? Rank7BB : Rank2BB);
constexpr Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB); constexpr Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB);
constexpr Direction Up = (Us == WHITE ? NORTH : SOUTH); constexpr Direction Up = (Us == WHITE ? NORTH : SOUTH);
@ -161,7 +118,7 @@ namespace {
} }
// Promotions and underpromotions // Promotions and underpromotions
if (pawnsOn7 && (Type != EVASIONS || (target & TRank8BB))) if (pawnsOn7)
{ {
if (Type == CAPTURES) if (Type == CAPTURES)
emptySquares = ~pos.pieces(); emptySquares = ~pos.pieces();
@ -262,7 +219,9 @@ namespace {
template<Color Us, GenType Type> template<Color Us, GenType Type>
ExtMove* generate_all(const Position& pos, ExtMove* moveList, Bitboard target) { ExtMove* generate_all(const Position& pos, ExtMove* moveList, Bitboard target) {
constexpr bool Checks = Type == QUIET_CHECKS; constexpr CastlingRight OO = Us | KING_SIDE;
constexpr CastlingRight OOO = Us | QUEEN_SIDE;
constexpr bool Checks = Type == QUIET_CHECKS; // Reduce template instantations
moveList = generate_pawn_moves<Us, Type>(pos, moveList, target); moveList = generate_pawn_moves<Us, Type>(pos, moveList, target);
moveList = generate_moves<KNIGHT, Checks>(pos, moveList, Us, target); moveList = generate_moves<KNIGHT, Checks>(pos, moveList, Us, target);
@ -276,19 +235,14 @@ namespace {
Bitboard b = pos.attacks_from<KING>(ksq) & target; Bitboard b = pos.attacks_from<KING>(ksq) & target;
while (b) while (b)
*moveList++ = make_move(ksq, pop_lsb(&b)); *moveList++ = make_move(ksq, pop_lsb(&b));
}
if (Type != CAPTURES && Type != EVASIONS && pos.castling_rights(Us)) if (Type != CAPTURES && pos.can_castle(CastlingRight(OO | OOO)))
{
if (pos.is_chess960())
{ {
moveList = generate_castling<Us, KING_SIDE, Checks, true>(pos, moveList); if (!pos.castling_impeded(OO) && pos.can_castle(OO))
moveList = generate_castling<Us, QUEEN_SIDE, Checks, true>(pos, moveList); *moveList++ = make<CASTLING>(ksq, pos.castling_rook_square(OO));
}
else if (!pos.castling_impeded(OOO) && pos.can_castle(OOO))
{ *moveList++ = make<CASTLING>(ksq, pos.castling_rook_square(OOO));
moveList = generate_castling<Us, KING_SIDE, Checks, false>(pos, moveList);
moveList = generate_castling<Us, QUEEN_SIDE, Checks, false>(pos, moveList);
} }
} }

View file

@ -31,9 +31,6 @@ namespace {
QSEARCH_TT, QCAPTURE_INIT, QCAPTURE, QCHECK_INIT, QCHECK QSEARCH_TT, QCAPTURE_INIT, QCAPTURE, QCHECK_INIT, QCHECK
}; };
// Helper filter used with select()
const auto Any = [](){ return true; };
// partial_insertion_sort() sorts moves in descending order up to and including // partial_insertion_sort() sorts moves in descending order up to and including
// a given limit. The order of moves smaller than the limit is left unspecified. // a given limit. The order of moves smaller than the limit is left unspecified.
void partial_insertion_sort(ExtMove* begin, ExtMove* end, int limit) { void partial_insertion_sort(ExtMove* begin, ExtMove* end, int limit) {
@ -225,7 +222,7 @@ top:
/* fallthrough */ /* fallthrough */
case BAD_CAPTURE: case BAD_CAPTURE:
return select<Next>(Any); return select<Next>([](){ return true; });
case EVASION_INIT: case EVASION_INIT:
cur = moves; cur = moves;
@ -236,7 +233,7 @@ top:
/* fallthrough */ /* fallthrough */
case EVASION: case EVASION:
return select<Best>(Any); return select<Best>([](){ return true; });
case PROBCUT: case PROBCUT:
return select<Best>([&](){ return pos.see_ge(move, threshold); }); return select<Best>([&](){ return pos.see_ge(move, threshold); });
@ -261,7 +258,7 @@ top:
/* fallthrough */ /* fallthrough */
case QCHECK: case QCHECK:
return select<Next>(Any); return select<Next>([](){ return true; });
} }
assert(false); assert(false);

View file

@ -85,11 +85,11 @@ enum StatsParams { NOT_USED = 0 };
/// 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 2 tables (one for each color) indexed by /// ordering decisions. It uses 2 tables (one for each color) indexed by
/// the move's from and to squares, see chessprogramming.wikispaces.com/Butterfly+Boards /// the move's from and to squares, see www.chessprogramming.org/Butterfly_Boards
typedef Stats<int16_t, 10692, COLOR_NB, int(SQUARE_NB) * int(SQUARE_NB)> ButterflyHistory; typedef Stats<int16_t, 10692, COLOR_NB, int(SQUARE_NB) * int(SQUARE_NB)> ButterflyHistory;
/// 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 www.chessprogramming.org/Countermove_Heuristic
typedef Stats<Move, NOT_USED, PIECE_NB, SQUARE_NB> CounterMoveHistory; typedef Stats<Move, NOT_USED, PIECE_NB, SQUARE_NB> CounterMoveHistory;
/// CapturePieceToHistory is addressed by a move's [piece][to][captured piece type] /// CapturePieceToHistory is addressed by a move's [piece][to][captured piece type]

View file

@ -115,7 +115,7 @@ namespace {
// not attacked more times than defended. // not attacked more times than defended.
if ( !(stoppers ^ lever ^ leverPush) if ( !(stoppers ^ lever ^ leverPush)
&& popcount(support) >= popcount(lever) - 1 && popcount(support) >= popcount(lever) - 1
&& popcount(phalanx) >= popcount(leverPush)) && popcount(phalanx) >= popcount(leverPush))
e->passedPawns[Us] |= s; e->passedPawns[Us] |= s;
else if ( stoppers == SquareBB[s + Up] else if ( stoppers == SquareBB[s + Up]
@ -185,7 +185,6 @@ Entry* probe(const Position& pos) {
e->key = key; e->key = key;
e->scores[WHITE] = evaluate<WHITE>(pos, e); e->scores[WHITE] = evaluate<WHITE>(pos, e);
e->scores[BLACK] = evaluate<BLACK>(pos, e); e->scores[BLACK] = evaluate<BLACK>(pos, e);
e->openFiles = popcount(e->semiopenFiles[WHITE] & e->semiopenFiles[BLACK]);
e->asymmetry = popcount( (e->passedPawns[WHITE] | e->passedPawns[BLACK]) e->asymmetry = popcount( (e->passedPawns[WHITE] | e->passedPawns[BLACK])
| (e->semiopenFiles[WHITE] ^ e->semiopenFiles[BLACK])); | (e->semiopenFiles[WHITE] ^ e->semiopenFiles[BLACK]));

View file

@ -39,7 +39,6 @@ struct Entry {
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 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 semiopen_file(Color c, File f) const { int semiopen_file(Color c, File f) const {
return semiopenFiles[c] & (1 << f); return semiopenFiles[c] & (1 << f);
@ -73,7 +72,6 @@ struct Entry {
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]
int asymmetry; int asymmetry;
int openFiles;
}; };
typedef HashTable<Entry, 16384> Table; typedef HashTable<Entry, 16384> Table;

View file

@ -183,7 +183,7 @@ void Position::init() {
{ {
std::swap(cuckoo[i], key); std::swap(cuckoo[i], key);
std::swap(cuckooMove[i], move); std::swap(cuckooMove[i], move);
if (move == 0) // Arrived at empty slot ? if (move == MOVE_NONE) // Arrived at empty slot?
break; break;
i = (i == H1(key)) ? H2(key) : H1(key); // Push victim to alternative slot i = (i == H1(key)) ? H2(key) : H1(key); // Push victim to alternative slot
} }
@ -465,16 +465,16 @@ const string Position::fen() const {
ss << (sideToMove == WHITE ? " w " : " b "); ss << (sideToMove == WHITE ? " w " : " b ");
if (can_castle(WHITE_OO)) if (can_castle(WHITE_OO))
ss << (chess960 ? char('A' + file_of(castling_rook_square(WHITE | KING_SIDE))) : 'K'); ss << (chess960 ? char('A' + file_of(castling_rook_square(WHITE_OO ))) : 'K');
if (can_castle(WHITE_OOO)) if (can_castle(WHITE_OOO))
ss << (chess960 ? char('A' + file_of(castling_rook_square(WHITE | QUEEN_SIDE))) : 'Q'); ss << (chess960 ? char('A' + file_of(castling_rook_square(WHITE_OOO))) : 'Q');
if (can_castle(BLACK_OO)) if (can_castle(BLACK_OO))
ss << (chess960 ? char('a' + file_of(castling_rook_square(BLACK | KING_SIDE))) : 'k'); ss << (chess960 ? char('a' + file_of(castling_rook_square(BLACK_OO ))) : 'k');
if (can_castle(BLACK_OOO)) if (can_castle(BLACK_OOO))
ss << (chess960 ? char('a' + file_of(castling_rook_square(BLACK | QUEEN_SIDE))) : 'q'); ss << (chess960 ? char('a' + file_of(castling_rook_square(BLACK_OOO))) : 'q');
if (!can_castle(ANY_CASTLING)) if (!can_castle(ANY_CASTLING))
ss << '-'; ss << '-';
@ -540,6 +540,7 @@ bool Position::legal(Move m) const {
Color us = sideToMove; Color us = sideToMove;
Square from = from_sq(m); Square from = from_sq(m);
Square to = to_sq(m);
assert(color_of(moved_piece(m)) == us); assert(color_of(moved_piece(m)) == us);
assert(piece_on(square<KING>(us)) == make_piece(us, KING)); assert(piece_on(square<KING>(us)) == make_piece(us, KING));
@ -550,7 +551,6 @@ bool Position::legal(Move m) const {
if (type_of(m) == ENPASSANT) if (type_of(m) == ENPASSANT)
{ {
Square ksq = square<KING>(us); Square ksq = square<KING>(us);
Square to = to_sq(m);
Square capsq = to - pawn_push(us); Square capsq = to - pawn_push(us);
Bitboard occupied = (pieces() ^ from ^ capsq) | to; Bitboard occupied = (pieces() ^ from ^ capsq) | to;
@ -563,16 +563,35 @@ bool Position::legal(Move m) const {
&& !(attacks_bb<BISHOP>(ksq, occupied) & pieces(~us, QUEEN, BISHOP)); && !(attacks_bb<BISHOP>(ksq, occupied) & pieces(~us, QUEEN, BISHOP));
} }
// If the moving piece is a king, check whether the destination // Castling moves generation does not check if the castling path is clear of
// square is attacked by the opponent. Castling moves are checked // enemy attacks, it is delayed at a later time: now!
// for legality during move generation. if (type_of(m) == CASTLING)
{
// After castling, the rook and king final positions are the same in
// Chess960 as they would be in standard chess.
to = relative_square(us, to > from ? SQ_G1 : SQ_C1);
Direction step = to > from ? WEST : EAST;
for (Square s = to; s != from; s += step)
if (attackers_to(s) & pieces(~us))
return false;
// In case of Chess960, verify that when moving the castling rook we do
// not discover some hidden checker.
// For instance an enemy queen in SQ_A1 when castling rook is in SQ_B1.
return !chess960
|| !(attacks_bb<ROOK>(to, pieces() ^ to_sq(m)) & pieces(~us, ROOK, QUEEN));
}
// If the moving piece is a king, check whether the destination square is
// attacked by the opponent.
if (type_of(piece_on(from)) == KING) if (type_of(piece_on(from)) == KING)
return type_of(m) == CASTLING || !(attackers_to(to_sq(m)) & pieces(~us)); return !(attackers_to(to) & pieces(~us));
// A non-king move is legal if and only if it is not pinned or it // A non-king move is legal if and only if it is not pinned or it
// is moving along the ray towards or away from the king. // is moving along the ray towards or away from the king.
return !(blockers_for_king(us) & from) return !(blockers_for_king(us) & from)
|| aligned(from, to_sq(m), square<KING>(us)); || aligned(from, to, square<KING>(us));
} }

View file

@ -265,7 +265,7 @@ inline bool Position::can_castle(CastlingRight cr) const {
} }
inline int Position::castling_rights(Color c) const { inline int Position::castling_rights(Color c) const {
return st->castlingRights & ((WHITE_OO | WHITE_OOO) << (2 * c)); return st->castlingRights & (c == WHITE ? WHITE_CASTLING : BLACK_CASTLING);
} }
inline bool Position::castling_impeded(CastlingRight cr) const { inline bool Position::castling_impeded(CastlingRight cr) const {

View file

@ -91,14 +91,14 @@ constexpr Score Bonus[][RANK_NB][int(FILE_NB) / 2] = {
}; };
constexpr Score PBonus[RANK_NB][FILE_NB] = constexpr Score PBonus[RANK_NB][FILE_NB] =
{ // Pawn { // Pawn (asymmetric distribution)
{ S( 0, 0), S( 0, 0), S( 0, 0), S( 0, 0), S( 0, 0), S( 0, 0), S( 0, 0), S( 0, 0) }, { },
{ S( 0,-11), S( -3, -4), S( 13, -1), S( 19, -4), S( 16, 17), S( 13, 7), S( 4, 4), S( -4,-13) }, { S( 0,-11), S( -3,-4), S(13, -1), S( 19, -4), S(16, 17), S(13, 7), S( 4, 4), S( -4,-13) },
{ S(-16, -8), S(-12, -6), S( 20, -3), S( 21, 0), S( 25,-11), S( 29, 3), S( 0, 0), S(-27, -1) }, { S(-16, -8), S(-12,-6), S(20, -3), S( 21, 0), S(25,-11), S(29, 3), S( 0, 0), S(-27, -1) },
{ S(-11, 3), S(-17, 6), S( 11,-10), S( 21, 1), S( 32, -6), S( 19,-11), S( -5, 0), S(-14, -2) }, { S(-11, 3), S(-17, 6), S(11,-10), S( 21, 1), S(32, -6), S(19,-11), S( -5, 0), S(-14, -2) },
{ S( 4, 13), S( 6, 7), S( -8, 3), S( 3, -5), S( 8,-15), S( -2, -1), S(-19, 9), S( -5, 13) }, { S( 4, 13), S( 6, 7), S(-8, 3), S( 3, -5), S( 8,-15), S(-2, -1), S(-19, 9), S( -5, 13) },
{ S( -5, 25), S(-19, 20), S( 7, 16), S( 8, 12), S( -7, 21), S( -2, 3), S(-10, -4), S(-16, 15) }, { S( -5, 25), S(-19,20), S( 7, 16), S( 8, 12), S(-7, 21), S(-2, 3), S(-10, -4), S(-16, 15) },
{ S(-10, 6), S( 9, -5), S( -7, 16), S(-12, 27), S( -7, 15), S( -8, 11), S( 16, -7), S( -8, 4) } { S(-10, 6), S( 9,-5), S(-7, 16), S(-12, 27), S(-7, 15), S(-8, 11), S( 16, -7), S( -8, 4) }
}; };
#undef S #undef S

View file

@ -114,8 +114,8 @@ namespace {
Value value_from_tt(Value v, int ply); Value value_from_tt(Value v, int ply);
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_quiet_stats(const Position& pos, Stack* ss, Move move, Move* quiets, int quietsCnt, int bonus); void update_quiet_stats(const Position& pos, Stack* ss, Move move, Move* quiets, int quietCount, int bonus);
void update_capture_stats(const Position& pos, Move move, Move* captures, int captureCnt, int bonus); void update_capture_stats(const Position& pos, Move move, Move* captures, int captureCount, int bonus);
inline bool gives_check(const Position& pos, Move move) { inline bool gives_check(const Position& pos, Move move) {
Color us = pos.side_to_move(); Color us = pos.side_to_move();
@ -529,32 +529,32 @@ void Thread::search() {
if ( Limits.use_time_management() if ( Limits.use_time_management()
&& !Threads.stop && !Threads.stop
&& !Threads.stopOnPonderhit) && !Threads.stopOnPonderhit)
{
double fallingEval = (306 + 119 * failedLow + 6 * (mainThread->previousScore - bestValue)) / 581.0;
fallingEval = std::max(0.5, std::min(1.5, fallingEval));
// If the bestMove is stable over several iterations, reduce time accordingly
timeReduction = 1.0;
for (int i : {3, 4, 5})
if (lastBestMoveDepth * i < completedDepth)
timeReduction *= 1.25;
// Use part of the gained time from a previous stable move for the current move
double bestMoveInstability = 1.0 + mainThread->bestMoveChanges;
bestMoveInstability *= std::pow(mainThread->previousTimeReduction, 0.528) / timeReduction;
// Stop the search if we have only one legal move, or if available time elapsed
if ( rootMoves.size() == 1
|| Time.elapsed() > Time.optimum() * bestMoveInstability * fallingEval)
{ {
double fallingEval = (306 + 119 * failedLow + 6 * (mainThread->previousScore - bestValue)) / 581.0; // If we are allowed to ponder do not stop the search now but
fallingEval = std::max(0.5, std::min(1.5, fallingEval)); // keep pondering until the GUI sends "ponderhit" or "stop".
if (Threads.ponder)
// If the bestMove is stable over several iterations, reduce time accordingly Threads.stopOnPonderhit = true;
timeReduction = 1.0; else
for (int i : {3, 4, 5}) Threads.stop = true;
if (lastBestMoveDepth * i < completedDepth)
timeReduction *= 1.25;
// Use part of the gained time from a previous stable move for the current move
double bestMoveInstability = 1.0 + mainThread->bestMoveChanges;
bestMoveInstability *= std::pow(mainThread->previousTimeReduction, 0.528) / timeReduction;
// Stop the search if we have only one legal move, or if available time elapsed
if ( rootMoves.size() == 1
|| Time.elapsed() > Time.optimum() * bestMoveInstability * fallingEval)
{
// If we are allowed to ponder do not stop the search now but
// keep pondering until the GUI sends "ponderhit" or "stop".
if (Threads.ponder)
Threads.stopOnPonderhit = true;
else
Threads.stop = true;
}
} }
}
} }
if (!mainThread) if (!mainThread)
@ -608,7 +608,7 @@ namespace {
Move ttMove, move, excludedMove, bestMove; Move ttMove, move, excludedMove, bestMove;
Depth extension, newDepth; Depth extension, newDepth;
Value bestValue, value, ttValue, eval, maxValue, pureStaticEval; Value bestValue, value, ttValue, eval, maxValue, pureStaticEval;
bool ttHit, inCheck, givesCheck, improving; bool ttHit, pvHit, inCheck, givesCheck, improving;
bool captureOrPromotion, doFullDepthSearch, moveCountPruning, skipQuiets, ttCapture, pvExact; bool captureOrPromotion, doFullDepthSearch, moveCountPruning, skipQuiets, ttCapture, pvExact;
Piece movedPiece; Piece movedPiece;
int moveCount, captureCount, quietCount; int moveCount, captureCount, quietCount;
@ -674,6 +674,7 @@ namespace {
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]
: ttHit ? tte->move() : MOVE_NONE; : ttHit ? tte->move() : MOVE_NONE;
pvHit = ttHit ? tte->pv_hit() : false;
// At non-PV nodes we check for an early TT cutoff // At non-PV nodes we check for an early TT cutoff
if ( !PvNode if ( !PvNode
@ -707,6 +708,11 @@ namespace {
return ttValue; return ttValue;
} }
if ( depth > 6 * ONE_PLY
&& !excludedMove
&& PvNode)
pvHit = true;
// Step 5. Tablebases probe // Step 5. Tablebases probe
if (!rootNode && TB::Cardinality) if (!rootNode && TB::Cardinality)
{ {
@ -741,7 +747,7 @@ namespace {
|| (b == BOUND_LOWER ? value >= beta : value <= alpha)) || (b == BOUND_LOWER ? value >= beta : value <= alpha))
{ {
Cluster::save(thisThread, tte, Cluster::save(thisThread, tte,
posKey, value_to_tt(value, ss->ply), b, posKey, value_to_tt(value, ss->ply), pvHit, b,
std::min(DEPTH_MAX - ONE_PLY, depth + 6 * ONE_PLY), std::min(DEPTH_MAX - ONE_PLY, depth + 6 * ONE_PLY),
MOVE_NONE, VALUE_NONE); MOVE_NONE, VALUE_NONE);
@ -793,7 +799,7 @@ namespace {
ss->staticEval = eval = pureStaticEval = -(ss-1)->staticEval + 2 * Eval::Tempo; ss->staticEval = eval = pureStaticEval = -(ss-1)->staticEval + 2 * Eval::Tempo;
Cluster::save(thisThread, tte, Cluster::save(thisThread, tte,
posKey, VALUE_NONE, BOUND_NONE, DEPTH_NONE, MOVE_NONE, posKey, VALUE_NONE, pvHit, BOUND_NONE, DEPTH_NONE, MOVE_NONE,
pureStaticEval); pureStaticEval);
} }
@ -909,6 +915,7 @@ namespace {
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 = ttHit ? tte->move() : MOVE_NONE; ttMove = ttHit ? tte->move() : MOVE_NONE;
pvHit = ttHit ? tte->pv_hit() : false;
} }
moves_loop: // When in check, search starts from here moves_loop: // When in check, search starts from here
@ -977,13 +984,21 @@ moves_loop: // When in check, search starts from here
&& tte->depth() >= depth - 3 * ONE_PLY && tte->depth() >= depth - 3 * ONE_PLY
&& pos.legal(move)) && pos.legal(move))
{ {
Value reducedBeta = std::max(ttValue - 2 * depth / ONE_PLY, -VALUE_MATE); Value singularBeta = std::max(ttValue - 2 * depth / ONE_PLY, -VALUE_MATE);
ss->excludedMove = move; ss->excludedMove = move;
value = search<NonPV>(pos, ss, reducedBeta - 1, reducedBeta, depth / 2, cutNode); value = search<NonPV>(pos, ss, singularBeta - 1, singularBeta, depth / 2, cutNode);
ss->excludedMove = MOVE_NONE; ss->excludedMove = MOVE_NONE;
if (value < reducedBeta) if (value < singularBeta)
extension = ONE_PLY; extension = ONE_PLY;
// Multi-cut pruning
// Our ttMove is assumed to fail high, and now we failed high also on a reduced
// search without the ttMove. So we assume this expected Cut-node is not singular,
// that is multiple moves fail high, and we can prune the whole subtree by returning
// the hard beta bound.
else if (cutNode && singularBeta > beta)
return beta;
} }
else if ( givesCheck // Check extension (~2 Elo) else if ( givesCheck // Check extension (~2 Elo)
&& pos.see_ge(move)) && pos.see_ge(move))
@ -1061,6 +1076,10 @@ moves_loop: // When in check, search starts from here
{ {
Depth r = reduction<PvNode>(improving, depth, moveCount); Depth r = reduction<PvNode>(improving, depth, moveCount);
// Decrease reduction if position is or has been on the PV
if (pvHit && !PvNode)
r -= ONE_PLY;
// Decrease reduction if opponent's move count is high (~10 Elo) // Decrease reduction if opponent's move count is high (~10 Elo)
if ((ss-1)->moveCount > 15) if ((ss-1)->moveCount > 15)
r -= ONE_PLY; r -= ONE_PLY;
@ -1244,7 +1263,7 @@ moves_loop: // When in check, search starts from here
if (!excludedMove) if (!excludedMove)
Cluster::save(thisThread, tte, Cluster::save(thisThread, tte,
posKey, value_to_tt(bestValue, ss->ply), posKey, value_to_tt(bestValue, ss->ply), pvHit,
bestValue >= beta ? BOUND_LOWER : bestValue >= beta ? BOUND_LOWER :
PvNode && bestMove ? BOUND_EXACT : BOUND_UPPER, PvNode && bestMove ? BOUND_EXACT : BOUND_UPPER,
depth, bestMove, pureStaticEval); depth, bestMove, pureStaticEval);
@ -1274,7 +1293,7 @@ moves_loop: // When in check, search starts from here
Move ttMove, move, bestMove; Move ttMove, move, bestMove;
Depth ttDepth; Depth ttDepth;
Value bestValue, value, ttValue, futilityValue, futilityBase, oldAlpha; Value bestValue, value, ttValue, futilityValue, futilityBase, oldAlpha;
bool ttHit, inCheck, givesCheck, evasionPrunable; bool ttHit, pvHit, inCheck, givesCheck, evasionPrunable;
int moveCount; int moveCount;
if (PvNode) if (PvNode)
@ -1308,6 +1327,7 @@ moves_loop: // When in check, search starts from here
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 = ttHit ? tte->move() : MOVE_NONE; ttMove = ttHit ? tte->move() : MOVE_NONE;
pvHit = ttHit ? tte->pv_hit() : false;
if ( !PvNode if ( !PvNode
&& ttHit && ttHit
@ -1346,7 +1366,7 @@ moves_loop: // When in check, search starts from here
{ {
if (!ttHit) if (!ttHit)
Cluster::save(thisThread, tte, Cluster::save(thisThread, tte,
posKey, value_to_tt(bestValue, ss->ply), BOUND_LOWER, posKey, value_to_tt(bestValue, ss->ply), pvHit, BOUND_LOWER,
DEPTH_NONE, MOVE_NONE, ss->staticEval); DEPTH_NONE, MOVE_NONE, ss->staticEval);
return bestValue; return bestValue;
@ -1458,7 +1478,7 @@ moves_loop: // When in check, search starts from here
return mated_in(ss->ply); // Plies to mate from the root return mated_in(ss->ply); // Plies to mate from the root
Cluster::save(thisThread, tte, Cluster::save(thisThread, tte,
posKey, value_to_tt(bestValue, ss->ply), posKey, value_to_tt(bestValue, ss->ply), pvHit,
bestValue >= beta ? BOUND_LOWER : bestValue >= beta ? BOUND_LOWER :
PvNode && bestValue > oldAlpha ? BOUND_EXACT : BOUND_UPPER, PvNode && bestValue > oldAlpha ? BOUND_EXACT : BOUND_UPPER,
ttDepth, bestMove, ss->staticEval); ttDepth, bestMove, ss->staticEval);
@ -1518,7 +1538,7 @@ moves_loop: // When in check, search starts from here
// update_capture_stats() updates move sorting heuristics when a new capture best move is found // update_capture_stats() updates move sorting heuristics when a new capture best move is found
void update_capture_stats(const Position& pos, Move move, void update_capture_stats(const Position& pos, Move move,
Move* captures, int captureCnt, int bonus) { Move* captures, int captureCount, int bonus) {
CapturePieceToHistory& captureHistory = pos.this_thread()->captureHistory; CapturePieceToHistory& captureHistory = pos.this_thread()->captureHistory;
Piece moved_piece = pos.moved_piece(move); Piece moved_piece = pos.moved_piece(move);
@ -1528,7 +1548,7 @@ moves_loop: // When in check, search starts from here
captureHistory[moved_piece][to_sq(move)][captured] << bonus; captureHistory[moved_piece][to_sq(move)][captured] << bonus;
// Decrease all the other played capture moves // Decrease all the other played capture moves
for (int i = 0; i < captureCnt; ++i) for (int i = 0; i < captureCount; ++i)
{ {
moved_piece = pos.moved_piece(captures[i]); moved_piece = pos.moved_piece(captures[i]);
captured = type_of(pos.piece_on(to_sq(captures[i]))); captured = type_of(pos.piece_on(to_sq(captures[i])));
@ -1540,7 +1560,7 @@ moves_loop: // When in check, search starts from here
// update_quiet_stats() updates move sorting heuristics when a new quiet best move is found // update_quiet_stats() updates move sorting heuristics when a new quiet best move is found
void update_quiet_stats(const Position& pos, Stack* ss, Move move, void update_quiet_stats(const Position& pos, Stack* ss, Move move,
Move* quiets, int quietsCnt, int bonus) { Move* quiets, int quietCount, int bonus) {
if (ss->killers[0] != move) if (ss->killers[0] != move)
{ {
@ -1560,7 +1580,7 @@ moves_loop: // When in check, search starts from here
} }
// Decrease all the other played quiet moves // Decrease all the other played quiet moves
for (int i = 0; i < quietsCnt; ++i) for (int i = 0; i < quietCount; ++i)
{ {
thisThread->mainHistory[us][from_to(quiets[i])] << -bonus; thisThread->mainHistory[us][from_to(quiets[i])] << -bonus;
update_continuation_histories(ss, pos.moved_piece(quiets[i]), to_sq(quiets[i]), -bonus); update_continuation_histories(ss, pos.moved_piece(quiets[i]), to_sq(quiets[i]), -bonus);
@ -1706,7 +1726,7 @@ bool RootMove::extract_ponder_from_tt(Position& pos) {
assert(pv.size() == 1); assert(pv.size() == 1);
if (!pv[0]) if (pv[0] == MOVE_NONE)
return false; return false;
pos.do_move(pv[0], st); pos.do_move(pv[0], st);

View file

@ -215,14 +215,22 @@ public:
return *baseAddress = nullptr, nullptr; return *baseAddress = nullptr, nullptr;
fstat(fd, &statbuf); fstat(fd, &statbuf);
if (statbuf.st_size % 64 != 16)
{
std::cerr << "Corrupt tablebase file " << fname << std::endl;
exit(EXIT_FAILURE);
}
*mapping = statbuf.st_size; *mapping = statbuf.st_size;
*baseAddress = mmap(nullptr, statbuf.st_size, PROT_READ, MAP_SHARED, fd, 0); *baseAddress = mmap(nullptr, statbuf.st_size, PROT_READ, MAP_SHARED, fd, 0);
madvise(*baseAddress, statbuf.st_size, MADV_RANDOM); madvise(*baseAddress, statbuf.st_size, MADV_RANDOM);
::close(fd); ::close(fd);
if (*baseAddress == MAP_FAILED) { if (*baseAddress == MAP_FAILED)
{
std::cerr << "Could not mmap() " << fname << std::endl; std::cerr << "Could not mmap() " << fname << std::endl;
exit(1); exit(EXIT_FAILURE);
} }
#else #else
// Note FILE_FLAG_RANDOM_ACCESS is only a hint to Windows and as such may get ignored. // Note FILE_FLAG_RANDOM_ACCESS is only a hint to Windows and as such may get ignored.
@ -234,21 +242,30 @@ public:
DWORD size_high; DWORD size_high;
DWORD size_low = GetFileSize(fd, &size_high); DWORD size_low = GetFileSize(fd, &size_high);
if (size_low % 64 != 16)
{
std::cerr << "Corrupt tablebase file " << fname << std::endl;
exit(EXIT_FAILURE);
}
HANDLE mmap = CreateFileMapping(fd, nullptr, PAGE_READONLY, size_high, size_low, nullptr); HANDLE mmap = CreateFileMapping(fd, nullptr, PAGE_READONLY, size_high, size_low, nullptr);
CloseHandle(fd); CloseHandle(fd);
if (!mmap) { if (!mmap)
{
std::cerr << "CreateFileMapping() failed" << std::endl; std::cerr << "CreateFileMapping() failed" << std::endl;
exit(1); exit(EXIT_FAILURE);
} }
*mapping = (uint64_t)mmap; *mapping = (uint64_t)mmap;
*baseAddress = MapViewOfFile(mmap, FILE_MAP_READ, 0, 0, 0); *baseAddress = MapViewOfFile(mmap, FILE_MAP_READ, 0, 0, 0);
if (!*baseAddress) { if (!*baseAddress)
{
std::cerr << "MapViewOfFile() failed, name = " << fname std::cerr << "MapViewOfFile() failed, name = " << fname
<< ", error = " << GetLastError() << std::endl; << ", error = " << GetLastError() << std::endl;
exit(1); exit(EXIT_FAILURE);
} }
#endif #endif
uint8_t* data = (uint8_t*)*baseAddress; uint8_t* data = (uint8_t*)*baseAddress;
@ -256,7 +273,8 @@ public:
constexpr uint8_t Magics[][4] = { { 0xD7, 0x66, 0x0C, 0xA5 }, constexpr uint8_t Magics[][4] = { { 0xD7, 0x66, 0x0C, 0xA5 },
{ 0x71, 0xE8, 0x23, 0x5D } }; { 0x71, 0xE8, 0x23, 0x5D } };
if (memcmp(data, Magics[type == WDL], 4)) { if (memcmp(data, Magics[type == WDL], 4))
{
std::cerr << "Corrupted table in file " << fname << std::endl; std::cerr << "Corrupted table in file " << fname << std::endl;
unmap(*baseAddress, *mapping); unmap(*baseAddress, *mapping);
return *baseAddress = nullptr, nullptr; return *baseAddress = nullptr, nullptr;
@ -417,7 +435,7 @@ class TBTables {
} }
} }
std::cerr << "TB hash table size too low!" << std::endl; std::cerr << "TB hash table size too low!" << std::endl;
exit(1); exit(EXIT_FAILURE);
} }
public: public:

View file

@ -31,7 +31,7 @@
TranspositionTable TT; // Our global transposition table TranspositionTable TT; // Our global transposition table
/// TTEntry::save saves a TTEntry /// TTEntry::save saves a TTEntry
void TTEntry::save(Key k, Value v, Bound b, Depth d, Move m, Value ev) { void TTEntry::save(Key k, Value v, bool PvNode, Bound b, Depth d, Move m, Value ev) {
assert(d / ONE_PLY * ONE_PLY == d); assert(d / ONE_PLY * ONE_PLY == d);
@ -47,7 +47,7 @@ void TTEntry::save(Key k, Value v, Bound b, Depth d, Move m, Value ev) {
key16 = (uint16_t)(k >> 48); key16 = (uint16_t)(k >> 48);
value16 = (int16_t)v; value16 = (int16_t)v;
eval16 = (int16_t)ev; eval16 = (int16_t)ev;
genBound8 = (uint8_t)(TT.generation8 | b); genBound8 = (uint8_t)(TT.generation8 | PvNode << 2 | b);
depth8 = (int8_t)(d / ONE_PLY); depth8 = (int8_t)(d / ONE_PLY);
} }
} }
@ -122,7 +122,7 @@ TTEntry* TranspositionTable::probe(const Key key, bool& found) const {
for (int i = 0; i < ClusterSize; ++i) for (int i = 0; i < ClusterSize; ++i)
if (!tte[i].key16 || tte[i].key16 == key16) if (!tte[i].key16 || tte[i].key16 == key16)
{ {
tte[i].genBound8 = uint8_t(generation8 | tte[i].bound()); // Refresh tte[i].genBound8 = uint8_t(generation8 | tte[i].pv_hit() << 2 | tte[i].bound()); // Refresh
return found = (bool)tte[i].key16, &tte[i]; return found = (bool)tte[i].key16, &tte[i];
} }
@ -131,11 +131,11 @@ TTEntry* TranspositionTable::probe(const Key key, bool& found) const {
TTEntry* replace = tte; TTEntry* replace = tte;
for (int i = 1; i < ClusterSize; ++i) for (int i = 1; i < ClusterSize; ++i)
// Due to our packed storage format for generation and its cyclic // Due to our packed storage format for generation and its cyclic
// nature we add 259 (256 is the modulus plus 3 to keep the lowest // nature we add 263 (263 is the modulus plus 7 to keep the lowest
// two bound bits from affecting the result) to calculate the entry // two bound bits from affecting the result) to calculate the entry
// age correctly even after generation8 overflows into the next cycle. // age correctly even after generation8 overflows into the next cycle.
if ( replace->depth8 - ((259 + generation8 - replace->genBound8) & 0xFC) * 2 if ( replace->depth8 - ((263 + generation8 - replace->genBound8) & 0xF8)
> tte[i].depth8 - ((259 + generation8 - tte[i].genBound8) & 0xFC) * 2) > tte[i].depth8 - ((263 + generation8 - tte[i].genBound8) & 0xF8))
replace = &tte[i]; replace = &tte[i];
return found = false, replace; return found = false, replace;

View file

@ -35,7 +35,8 @@ namespace Cluster {
/// move 16 bit /// move 16 bit
/// value 16 bit /// value 16 bit
/// eval value 16 bit /// eval value 16 bit
/// generation 6 bit /// generation 5 bit
/// PvNode 1 bit
/// bound type 2 bit /// bound type 2 bit
/// depth 8 bit /// depth 8 bit
@ -45,8 +46,9 @@ struct TTEntry {
Value value() const { return (Value)value16; } Value value() const { return (Value)value16; }
Value eval() const { return (Value)eval16; } Value eval() const { return (Value)eval16; }
Depth depth() const { return (Depth)(depth8 * int(ONE_PLY)); } Depth depth() const { return (Depth)(depth8 * int(ONE_PLY)); }
bool pv_hit() const { return (bool)(genBound8 & 0x4); }
Bound bound() const { return (Bound)(genBound8 & 0x3); } Bound bound() const { return (Bound)(genBound8 & 0x3); }
void save(Key k, Value v, Bound b, Depth d, Move m, Value ev); void save(Key k, Value v, bool PvNode, Bound b, Depth d, Move m, Value ev);
private: private:
friend class TranspositionTable; friend class TranspositionTable;
@ -84,7 +86,7 @@ class TranspositionTable {
public: public:
~TranspositionTable() { free(mem); } ~TranspositionTable() { free(mem); }
void new_search() { generation8 += 4; } // Lower 2 bits are used by Bound void new_search() { generation8 += 8; } // Lower 3 bits are used by PV flag and Bound
TTEntry* probe(const Key key, bool& found) const; TTEntry* probe(const Key key, bool& found) const;
int hashfull() const; int hashfull() const;
void resize(size_t mbSize); void resize(size_t mbSize);

View file

@ -141,7 +141,9 @@ enum CastlingRight {
WHITE_OOO = WHITE_OO << 1, WHITE_OOO = WHITE_OO << 1,
BLACK_OO = WHITE_OO << 2, BLACK_OO = WHITE_OO << 2,
BLACK_OOO = WHITE_OO << 3, BLACK_OOO = WHITE_OO << 3,
ANY_CASTLING = WHITE_OO | WHITE_OOO | BLACK_OO | BLACK_OOO, WHITE_CASTLING = WHITE_OO | WHITE_OOO,
BLACK_CASTLING = BLACK_OO | BLACK_OOO,
ANY_CASTLING = WHITE_CASTLING | BLACK_CASTLING,
CASTLING_RIGHT_NB = 16 CASTLING_RIGHT_NB = 16
}; };

View file

@ -28,14 +28,14 @@ case $1 in
echo "sanitizer-undefined testing started" echo "sanitizer-undefined testing started"
prefix='!' prefix='!'
exeprefix='' exeprefix=''
postfix='2>&1 | grep "runtime error:"' postfix='2>&1 | grep -A50 "runtime error:"'
threads="1" threads="1"
;; ;;
--sanitizer-thread) --sanitizer-thread)
echo "sanitizer-thread testing started" echo "sanitizer-thread testing started"
prefix='!' prefix='!'
exeprefix='' exeprefix=''
postfix='2>&1 | grep "WARNING: ThreadSanitizer:"' postfix='2>&1 | grep -A50 "WARNING: ThreadSanitizer:"'
threads="2" threads="2"
cat << EOF > tsan.supp cat << EOF > tsan.supp
@ -45,6 +45,7 @@ race:TTEntry::bound
race:TTEntry::save race:TTEntry::save
race:TTEntry::value race:TTEntry::value
race:TTEntry::eval race:TTEntry::eval
race:TTEntry::pv_hit
race:TranspositionTable::probe race:TranspositionTable::probe
race:TranspositionTable::hashfull race:TranspositionTable::hashfull

View file

@ -1,5 +1,5 @@
#!/bin/bash #!/bin/bash
# verify perft numbers (positions from https://chessprogramming.wikispaces.com/Perft+Results) # verify perft numbers (positions from www.chessprogramming.org/Perft_Results)
error() error()
{ {