Compare commits

..

15 Commits

Author SHA1 Message Date
Marco Costalba
21de03fad7 Revert "Another PSQT tuning round"
At longer TC of 1'+0" patch fails:
Orig - Mod: 841 - 819 (-6 elo!)

Just before the release ;-)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-02 06:55:03 +01:00
Marco Costalba
2d635f7b74 Stockfish 1.8
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-02 06:23:15 +01:00
Marco Costalba
b50dc1647f Mark CheckInfo c'tor as explicit
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-01 22:21:09 +01:00
Marco Costalba
971c591be7 Move singleEvasion assignment out of move's loop
We don't need to recheck after every move.

Spotted by Ralph Stoesser.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-01 22:18:53 +01:00
Joona Kiiski
b24a2dfc72 Another PSQT tuning round
This time with a new algorithm by Joona.

It works basically like this:

repeat
{
   1) pick 8000 random positions from qsearch
   2) "go depth 8" to get the true evaluation.
   3) "eval" to get the stand pat score
   4) Adjusting parameters one by one to minimize deltasum between
true evaluation and stand  pat scores.
}

* Good news: method seems to converge
* Bad news: Point where it converges is not optimum.

So it's more or less trial and error... sometimes works, sometimes
doesn't. It can give you the right direction, but if you let it run
too long, it fails. Far from scientific ;)

After 14800 games with 5s/game
Orig - Mod: 3318 - 3570 - 7626 (+6 elo)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-29 18:52:51 +01:00
Marco Costalba
4d170725ab Remove a redundant check in passed pawn eval
When first condition is met then second one is
always true.

Spotted by Ralph Stoesser.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-29 18:35:54 +01:00
Marco Costalba
aad8c82cf6 Code style triviality in san.cpp
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-29 18:33:43 +01:00
Marco Costalba
6c0a37bbf2 Rename TranspositionTable 'writes' in 'overwrites'
Better documents what that variable means.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-29 18:23:45 +01:00
Marco Costalba
5c3ebd1fbf Extract only exact scores to get the PV
This should allow to skip overwritten nodes because
only in PV we store in TT with VALUE_TYPE_EXACT flag.

Test result for the whole series is:

After 3627 games at 5"
Mod vs Orig +1037 =1605 -985 +5 ELO

After 1311 games at 1'+0"
Mod vs Orig +234 =850 -227 +2 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-29 18:23:28 +01:00
Marco Costalba
62c68c2d21 Retire update_pv() and sp_update_pv()
Expand inline instead.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-26 15:43:54 +01:00
Marco Costalba
adb43cc0cc Retire pv[] from SearchStack
Extract PV info from TT instead of using
a set of arrays. This is almost equivalent
except for cases when TT is full and the PV entry
is overwritten, but this is very rare.

(Almost) No functional change

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-26 15:13:39 +01:00
Marco Costalba
0a687b2cf0 Introduce bestMove to store PV move
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-26 14:42:44 +01:00
Marco Costalba
eb48c54687 Cleanup code that stores score in TT
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-26 11:01:43 +01:00
Joona Kiiski
3c3b129e7b Fix some wrong documentation
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-26 10:23:31 +01:00
Joona Kiiski
918533dc06 Remove unused constant
Fixes warning on ICC

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-26 10:22:26 +01:00
9 changed files with 131 additions and 167 deletions

View File

@@ -207,7 +207,6 @@ namespace {
// Bonuses for enemy's safe checks
const int QueenContactCheckBonus = 3;
const int DiscoveredCheckBonus = 3;
const int QueenCheckBonus = 2;
const int RookCheckBonus = 1;
const int BishopCheckBonus = 1;
@@ -862,8 +861,7 @@ namespace {
// value if the other side has a rook or queen.
if (square_file(s) == FILE_A || square_file(s) == FILE_H)
{
if ( pos.non_pawn_material(Them) <= KnightValueMidgame
&& pos.piece_count(Them, KNIGHT) <= 1)
if (pos.non_pawn_material(Them) <= KnightValueMidgame)
ebonus += ebonus / 4;
else if (pos.pieces(ROOK, QUEEN, Them))
ebonus -= ebonus / 4;

View File

@@ -58,7 +58,7 @@ using namespace std;
/// Version number. If this is left empty, the current date (in the format
/// YYMMDD) is used as a version number.
static const string EngineVersion = "1.8 beta 2";
static const string EngineVersion = "1.8";
static const string AppName = "Stockfish";
static const string AppTag = "";

View File

@@ -641,10 +641,10 @@ bool Position::move_is_check(Move m, const CheckInfo& ci) const {
}
}
// En passant capture with check? We have already handled the case
// En passant capture with check ? We have already handled the case
// of direct checks and ordinary discovered check, the only case we
// need to handle is the unusual case of a discovered check through the
// captured pawn.
// need to handle is the unusual case of a discovered check through
// the captured pawn.
if (move_is_ep(m))
{
Square capsq = make_square(square_file(to), square_rank(from));

View File

@@ -68,7 +68,7 @@ const int MaxGameLength = 220;
struct CheckInfo {
CheckInfo(const Position&);
explicit CheckInfo(const Position&);
Bitboard dcCandidates;
Bitboard checkSq[8];

View File

@@ -47,7 +47,7 @@ namespace {
AMBIGUITY_BOTH
};
const History H; // used as dummy argument for MovePicker c'tor
const History H; // Used as dummy argument for MovePicker c'tor
Ambiguity move_ambiguity(const Position& pos, Move m);
const string time_string(int milliseconds);
@@ -68,28 +68,25 @@ const string move_to_san(Position& pos, Move m) {
assert(pos.is_ok());
assert(move_is_ok(m));
Square from, to;
PieceType pt;
from = move_from(m);
to = move_to(m);
pt = type_of_piece(pos.piece_on(move_from(m)));
string san = "";
string san;
Square from = move_from(m);
Square to = move_to(m);
PieceType pt = type_of_piece(pos.piece_on(move_from(m)));
if (m == MOVE_NONE)
return "(none)";
else if (m == MOVE_NULL)
return "(null)";
else if (move_is_long_castle(m) || (int(to - from) == -2 && pt == KING))
else if (move_is_long_castle(m) || (int(to - from) == -2 && pt == KING))
san = "O-O-O";
else if (move_is_short_castle(m) || (int(to - from) == 2 && pt == KING))
else if (move_is_short_castle(m) || (int(to - from) == 2 && pt == KING))
san = "O-O";
else
{
if (pt != PAWN)
{
san += piece_type_to_char(pt, true);
switch (move_ambiguity(pos, m)) {
case AMBIGUITY_NONE:
break;
@@ -115,13 +112,13 @@ const string move_to_san(Position& pos, Move m) {
san += square_to_string(move_to(m));
if (move_is_promotion(m))
{
san += '=';
san += "=";
san += piece_type_to_char(move_promotion_piece(m), true);
}
}
// Is the move check? We don't use pos.move_is_check(m) here, because
// Position::move_is_check doesn't detect all checks (not castling moves,
// promotions and en passant captures).
// The move gives check ? We don't use pos.move_is_check() here
// because we need to test for mate after the move is done.
StateInfo st;
pos.do_move(m, st);
if (pos.is_check())
@@ -301,21 +298,21 @@ const string line_to_san(const Position& pos, Move line[], int startColumn, bool
size_t maxLength = 80 - startColumn;
Position p(pos, pos.thread());
for (int i = 0; line[i] != MOVE_NONE; i++)
for (Move* m = line; *m != MOVE_NONE; m++)
{
moveStr = move_to_san(p, line[i]);
moveStr = move_to_san(p, *m);
length += moveStr.length() + 1;
if (breakLines && length > maxLength)
{
s << '\n' << std::setw(startColumn) << ' ';
s << "\n" << std::setw(startColumn) << " ";
length = moveStr.length() + 1;
}
s << moveStr << ' ';
if (line[i] == MOVE_NULL)
if (*m == MOVE_NULL)
p.do_null_move(st);
else
p.do_move(line[i], st);
p.do_move(*m, st);
}
return s.str();
}
@@ -325,27 +322,31 @@ const string line_to_san(const Position& pos, Move line[], int startColumn, bool
/// It is used to write search information to the log file (which is created
/// when the UCI parameter "Use Search Log" is "true").
const string pretty_pv(const Position& pos, int time, int depth,
uint64_t nodes, Value score, ValueType type, Move pv[]) {
const string pretty_pv(const Position& pos, int time, int depth, uint64_t nodes,
Value score, ValueType type, Move pv[]) {
const uint64_t K = 1000;
const uint64_t M = 1000000;
std::stringstream s;
// Depth
s << std::setw(2) << depth << " ";
// Score
s << ((type == VALUE_TYPE_LOWER)? ">" : ((type == VALUE_TYPE_UPPER)? "<" : " "));
s << std::setw(7) << score_string(score);
s << (type == VALUE_TYPE_LOWER ? ">" : type == VALUE_TYPE_UPPER ? "<" : " ")
<< std::setw(7) << score_string(score);
// Time
s << std::setw(8) << time_string(time) << " ";
// Nodes
if (nodes < 1000000ULL)
s << std::setw(8) << nodes << " ";
else if (nodes < 1000000000ULL)
s << std::setw(7) << nodes/1000ULL << 'k' << " ";
if (nodes < M)
s << std::setw(8) << nodes / 1 << " ";
else if (nodes < K * M)
s << std::setw(7) << nodes / K << "K ";
else
s << std::setw(7) << nodes/1000000ULL << 'M' << " ";
s << std::setw(7) << nodes / M << "M ";
// PV
s << line_to_san(pos, pv, 30, true);
@@ -398,14 +399,17 @@ namespace {
}
const string time_string(int milliseconds) {
const string time_string(int millisecs) {
const int MSecMinute = 1000 * 60;
const int MSecHour = 1000 * 60 * 60;
std::stringstream s;
s << std::setfill('0');
int hours = milliseconds / (1000*60*60);
int minutes = (milliseconds - hours*1000*60*60) / (1000*60);
int seconds = (milliseconds - hours*1000*60*60 - minutes*1000*60) / 1000;
int hours = millisecs / MSecHour;
int minutes = (millisecs - hours * MSecHour) / MSecMinute;
int seconds = (millisecs - hours * MSecHour - minutes * MSecMinute) / 1000;
if (hours)
s << hours << ':';
@@ -421,7 +425,7 @@ namespace {
if (v >= VALUE_MATE - 200)
s << "#" << (VALUE_MATE - v + 1) / 2;
else if(v <= -VALUE_MATE + 200)
else if (v <= -VALUE_MATE + 200)
s << "-#" << (VALUE_MATE + v) / 2;
else
{

View File

@@ -282,7 +282,7 @@ namespace {
/// Local functions
Value id_loop(const Position& pos, Move searchMoves[]);
Value root_search(Position& pos, SearchStack* ss, RootMoveList& rml, Value* alphaPtr, Value* betaPtr);
Value root_search(Position& pos, SearchStack* ss, Move* pv, RootMoveList& rml, Value* alphaPtr, Value* betaPtr);
template <NodeType PvNode>
Value search(Position& pos, SearchStack* ss, Value alpha, Value beta, Depth depth, int ply);
@@ -296,8 +296,6 @@ namespace {
template <NodeType PvNode>
Depth extension(const Position& pos, Move m, bool captureOrPromotion, bool moveIsCheck, bool singleEvasion, bool mateThreat, bool* dangerous);
void update_pv(SearchStack* ss);
void sp_update_pv(SearchStack* pss, SearchStack* ss);
bool connected_moves(const Position& pos, Move m1, Move m2);
bool value_is_mate(Value value);
bool move_is_killer(Move m, SearchStack* ss);
@@ -314,7 +312,7 @@ namespace {
void ponderhit();
void wait_for_stop_or_ponderhit();
void init_ss_array(SearchStack* ss, int size);
void print_pv_info(const Position& pos, SearchStack* ss, Value alpha, Value beta, Value value);
void print_pv_info(const Position& pos, Move pv[], Value alpha, Value beta, Value value);
#if !defined(_MSC_VER)
void *init_thread(void *threadID);
@@ -364,16 +362,16 @@ void init_search() {
}
// SearchStack::init() initializes a search stack. Used at the beginning of a
// new search from the root.
// SearchStack::init() initializes a search stack entry.
// Called at the beginning of search() when starting to examine a new node.
void SearchStack::init() {
pv[0] = pv[1] = MOVE_NONE;
currentMove = threatMove = MOVE_NONE;
currentMove = threatMove = bestMove = MOVE_NONE;
reduction = Depth(0);
eval = VALUE_NONE;
}
// SearchStack::initKillers() initializes killers for a search stack entry
void SearchStack::initKillers() {
mateKiller = MOVE_NONE;
@@ -605,6 +603,7 @@ namespace {
Position p(pos, pos.thread());
SearchStack ss[PLY_MAX_PLUS_2];
Move pv[PLY_MAX_PLUS_2];
Move EasyMove = MOVE_NONE;
Value value, alpha = -VALUE_INFINITE, beta = VALUE_INFINITE;
@@ -634,6 +633,7 @@ namespace {
TT.new_search();
H.clear();
init_ss_array(ss, PLY_MAX_PLUS_2);
pv[0] = pv[1] = MOVE_NONE;
ValueByIteration[1] = rml.get_move_score(0);
Iteration = 1;
@@ -665,11 +665,11 @@ namespace {
}
// Search to the current depth, rml is updated and sorted, alpha and beta could change
value = root_search(p, ss, rml, &alpha, &beta);
value = root_search(p, ss, pv, rml, &alpha, &beta);
// Write PV to transposition table, in case the relevant entries have
// been overwritten during the search.
TT.insert_pv(p, ss->pv);
TT.insert_pv(p, pv);
if (AbortSearch)
break; // Value cannot be trusted. Break out immediately!
@@ -678,7 +678,7 @@ namespace {
ValueByIteration[Iteration] = value;
// Drop the easy move if differs from the new best move
if (ss->pv[0] != EasyMove)
if (pv[0] != EasyMove)
EasyMove = MOVE_NONE;
if (UseTimeManagement)
@@ -700,7 +700,7 @@ namespace {
// Stop search early if one move seems to be much better than the others
int64_t nodes = TM.nodes_searched();
if ( Iteration >= 8
&& EasyMove == ss->pv[0]
&& EasyMove == pv[0]
&& ( ( rml.get_move_cumulative_nodes(0) > (nodes * 85) / 100
&& current_search_time() > MaxSearchTime / 16)
||( rml.get_move_cumulative_nodes(0) > (nodes * 98) / 100
@@ -743,18 +743,18 @@ namespace {
<< " hashfull " << TT.full() << endl;
// Print the best move and the ponder move to the standard output
if (ss->pv[0] == MOVE_NONE)
if (pv[0] == MOVE_NONE)
{
ss->pv[0] = rml.get_move(0);
ss->pv[1] = MOVE_NONE;
pv[0] = rml.get_move(0);
pv[1] = MOVE_NONE;
}
assert(ss->pv[0] != MOVE_NONE);
assert(pv[0] != MOVE_NONE);
cout << "bestmove " << ss->pv[0];
cout << "bestmove " << pv[0];
if (ss->pv[1] != MOVE_NONE)
cout << " ponder " << ss->pv[1];
if (pv[1] != MOVE_NONE)
cout << " ponder " << pv[1];
cout << endl;
@@ -768,12 +768,12 @@ namespace {
LogFile << "\nNodes: " << TM.nodes_searched()
<< "\nNodes/second: " << nps()
<< "\nBest move: " << move_to_san(p, ss->pv[0]);
<< "\nBest move: " << move_to_san(p, pv[0]);
StateInfo st;
p.do_move(ss->pv[0], st);
p.do_move(pv[0], st);
LogFile << "\nPonder move: "
<< move_to_san(p, ss->pv[1]) // Works also with MOVE_NONE
<< move_to_san(p, pv[1]) // Works also with MOVE_NONE
<< endl;
}
return rml.get_move_score(0);
@@ -785,7 +785,7 @@ namespace {
// scheme, prints some information to the standard output and handles
// the fail low/high loops.
Value root_search(Position& pos, SearchStack* ss, RootMoveList& rml, Value* alphaPtr, Value* betaPtr) {
Value root_search(Position& pos, SearchStack* ss, Move* pv, RootMoveList& rml, Value* alphaPtr, Value* betaPtr) {
EvalInfo ei;
StateInfo st;
@@ -935,12 +935,12 @@ namespace {
// We are failing high and going to do a research. It's important to update
// the score before research in case we run out of time while researching.
rml.set_move_score(i, value);
update_pv(ss);
TT.extract_pv(pos, ss->pv, PLY_MAX);
rml.set_move_pv(i, ss->pv);
ss->bestMove = move;
TT.extract_pv(pos, move, pv, PLY_MAX);
rml.set_move_pv(i, pv);
// Print information to the standard output
print_pv_info(pos, ss, alpha, beta, value);
print_pv_info(pos, pv, alpha, beta, value);
// Prepare for a research after a fail high, each time with a wider window
*betaPtr = beta = Min(beta + AspirationDelta * (1 << researchCountFH), VALUE_INFINITE);
@@ -975,9 +975,9 @@ namespace {
// Update PV
rml.set_move_score(i, value);
update_pv(ss);
TT.extract_pv(pos, ss->pv, PLY_MAX);
rml.set_move_pv(i, ss->pv);
ss->bestMove = move;
TT.extract_pv(pos, move, pv, PLY_MAX);
rml.set_move_pv(i, pv);
if (MultiPV == 1)
{
@@ -988,7 +988,7 @@ namespace {
BestMoveChangesByIteration[Iteration]++;
// Print information to the standard output
print_pv_info(pos, ss, alpha, beta, value);
print_pv_info(pos, pv, alpha, beta, value);
// Raise alpha to setup proper non-pv search upper bound
if (value > alpha)
@@ -1061,7 +1061,7 @@ namespace {
Depth ext, newDepth;
Value bestValue, value, oldAlpha;
Value refinedValue, nullValue, futilityValueScaled; // Non-PV specific
bool isCheck, singleEvasion, moveIsCheck, captureOrPromotion, dangerous;
bool isCheck, singleEvasion, singularExtensionNode, moveIsCheck, captureOrPromotion, dangerous;
bool mateThreat = false;
int moveCount = 0;
int threadID = pos.thread();
@@ -1246,7 +1246,7 @@ namespace {
search<PvNode>(pos, ss, alpha, beta, d, ply);
ss->skipNullMove = false;
ttMove = ss->pv[0];
ttMove = ss->bestMove;
tte = TT.retrieve(posKey);
}
@@ -1257,11 +1257,12 @@ namespace {
// Initialize a MovePicker object for the current position
MovePicker mp = MovePicker(pos, ttMove, depth, H, ss, (PvNode ? -VALUE_INFINITE : beta));
CheckInfo ci(pos);
bool singularExtensionNode = depth >= SingularExtensionDepth[PvNode]
&& tte && tte->move()
&& !excludedMove // Do not allow recursive singular extension search
&& is_lower_bound(tte->type())
&& tte->depth() >= depth - 3 * OnePly;
singleEvasion = isCheck && mp.number_of_evasions() == 1;
singularExtensionNode = depth >= SingularExtensionDepth[PvNode]
&& tte && tte->move()
&& !excludedMove // Do not allow recursive singular extension search
&& is_lower_bound(tte->type())
&& tte->depth() >= depth - 3 * OnePly;
// Step 10. Loop through moves
// Loop through all legal moves until no moves remain or a beta cutoff occurs
@@ -1274,7 +1275,6 @@ namespace {
if (move == excludedMove)
continue;
singleEvasion = (isCheck && mp.number_of_evasions() == 1);
moveIsCheck = pos.move_is_check(move, ci);
captureOrPromotion = pos.move_is_capture_or_promotion(move);
@@ -1410,10 +1410,10 @@ namespace {
if (PvNode && value < beta) // This guarantees that always: alpha < beta
alpha = value;
update_pv(ss);
if (value == value_mate_in(ply + 1))
ss->mateKiller = move;
ss->bestMove = move;
}
}
@@ -1442,22 +1442,20 @@ namespace {
if (AbortSearch || TM.thread_should_stop(threadID))
return bestValue;
if (bestValue <= oldAlpha)
TT.store(posKey, value_to_tt(bestValue, ply), VALUE_TYPE_UPPER, depth, MOVE_NONE, ss->eval, ei.kingDanger[pos.side_to_move()]);
ValueType f = (bestValue <= oldAlpha ? VALUE_TYPE_UPPER : bestValue >= beta ? VALUE_TYPE_LOWER : VALUE_TYPE_EXACT);
move = (bestValue <= oldAlpha ? MOVE_NONE : ss->bestMove);
TT.store(posKey, value_to_tt(bestValue, ply), f, depth, move, ss->eval, ei.kingDanger[pos.side_to_move()]);
else if (bestValue >= beta)
// Update killers and history only for non capture moves that fails high
if (bestValue >= beta)
{
TM.incrementBetaCounter(pos.side_to_move(), depth, threadID);
move = ss->pv[0];
TT.store(posKey, value_to_tt(bestValue, ply), VALUE_TYPE_LOWER, depth, move, ss->eval, ei.kingDanger[pos.side_to_move()]);
if (!pos.move_is_capture_or_promotion(move))
{
update_history(pos, move, depth, movesSearched, moveCount);
update_killers(move, ss);
}
}
else
TT.store(posKey, value_to_tt(bestValue, ply), VALUE_TYPE_EXACT, depth, ss->pv[0], ss->eval, ei.kingDanger[pos.side_to_move()]);
assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE);
@@ -1488,7 +1486,7 @@ namespace {
Value oldAlpha = alpha;
TM.incrementNodeCounter(pos.thread());
ss->pv[0] = ss->pv[1] = ss->currentMove = MOVE_NONE;
ss->bestMove = ss->currentMove = MOVE_NONE;
ss->eval = VALUE_NONE;
// Check for an instant draw or maximum ply reached
@@ -1615,7 +1613,7 @@ namespace {
if (value > alpha)
{
alpha = value;
update_pv(ss);
ss->bestMove = move;
}
}
}
@@ -1627,19 +1625,13 @@ namespace {
// Update transposition table
Depth d = (depth == Depth(0) ? Depth(0) : Depth(-1));
if (bestValue <= oldAlpha)
TT.store(pos.get_key(), value_to_tt(bestValue, ply), VALUE_TYPE_UPPER, d, MOVE_NONE, ss->eval, ei.kingDanger[pos.side_to_move()]);
else if (bestValue >= beta)
{
move = ss->pv[0];
TT.store(pos.get_key(), value_to_tt(bestValue, ply), VALUE_TYPE_LOWER, d, move, ss->eval, ei.kingDanger[pos.side_to_move()]);
ValueType f = (bestValue <= oldAlpha ? VALUE_TYPE_UPPER : bestValue >= beta ? VALUE_TYPE_LOWER : VALUE_TYPE_EXACT);
TT.store(pos.get_key(), value_to_tt(bestValue, ply), f, d, ss->bestMove, ss->eval, ei.kingDanger[pos.side_to_move()]);
// Update killers only for good checking moves
if (!pos.move_is_capture_or_promotion(move))
update_killers(move, ss);
}
else
TT.store(pos.get_key(), value_to_tt(bestValue, ply), VALUE_TYPE_EXACT, d, ss->pv[0], ss->eval, ei.kingDanger[pos.side_to_move()]);
// Update killers only for checking moves that fails high
if ( bestValue >= beta
&& !pos.move_is_capture_or_promotion(ss->bestMove))
update_killers(ss->bestMove, ss);
assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE);
@@ -1802,7 +1794,7 @@ namespace {
if (PvNode && value < sp->beta) // This guarantees that always: sp->alpha < sp->beta
sp->alpha = value;
sp_update_pv(sp->parentSstack, ss);
sp->parentSstack->bestMove = ss->bestMove = move;
}
}
}
@@ -1814,40 +1806,6 @@ namespace {
lock_release(&(sp->lock));
}
// update_pv() is called whenever a search returns a value > alpha.
// It updates the PV in the SearchStack object corresponding to the
// current node.
void update_pv(SearchStack* ss) {
Move* src = (ss+1)->pv;
Move* dst = ss->pv;
*dst = ss->currentMove;
do
*++dst = *src;
while (*src++ != MOVE_NONE);
}
// sp_update_pv() is a variant of update_pv for use at split points. The
// difference between the two functions is that sp_update_pv also updates
// the PV at the parent node.
void sp_update_pv(SearchStack* pss, SearchStack* ss) {
Move* src = (ss+1)->pv;
Move* dst = ss->pv;
Move* pdst = pss->pv;
*dst = *pdst = ss->currentMove;
do
*++dst = *++pdst = *src;
while (*src++ != MOVE_NONE);
}
// connected_moves() tests whether two moves are 'connected' in the sense
// that the first move somehow made the second move possible (for instance
@@ -1948,7 +1906,7 @@ namespace {
if (*dangerous)
{
if (moveIsCheck && pos.see_sign(m)>= 0)
if (moveIsCheck && pos.see_sign(m) >= 0)
result += CheckExtension[PvNode];
if (singleEvasion)
@@ -2287,29 +2245,28 @@ namespace {
// print_pv_info() prints to standard output and eventually to log file information on
// the current PV line. It is called at each iteration or after a new pv is found.
void print_pv_info(const Position& pos, SearchStack* ss, Value alpha, Value beta, Value value) {
void print_pv_info(const Position& pos, Move pv[], Value alpha, Value beta, Value value) {
cout << "info depth " << Iteration
<< " score " << value_to_string(value)
<< ((value >= beta) ? " lowerbound" :
((value <= alpha)? " upperbound" : ""))
<< " score " << value_to_string(value)
<< (value >= beta ? " lowerbound" : value <= alpha ? " upperbound" : "")
<< " time " << current_search_time()
<< " nodes " << TM.nodes_searched()
<< " nps " << nps()
<< " pv ";
for (int j = 0; ss->pv[j] != MOVE_NONE && j < PLY_MAX; j++)
cout << ss->pv[j] << " ";
for (Move* m = pv; *m != MOVE_NONE; m++)
cout << *m << " ";
cout << endl;
if (UseLogFile)
{
ValueType type = (value >= beta ? VALUE_TYPE_LOWER
: (value <= alpha ? VALUE_TYPE_UPPER : VALUE_TYPE_EXACT));
ValueType t = value >= beta ? VALUE_TYPE_LOWER :
value <= alpha ? VALUE_TYPE_UPPER : VALUE_TYPE_EXACT;
LogFile << pretty_pv(pos, current_search_time(), Iteration,
TM.nodes_searched(), value, type, ss->pv) << endl;
TM.nodes_searched(), value, t, pv) << endl;
}
}

View File

@@ -50,11 +50,11 @@ const int KILLER_MAX = 2;
struct EvalInfo;
struct SearchStack {
Move pv[PLY_MAX_PLUS_2];
Move currentMove;
Move mateKiller;
Move threatMove;
Move excludedMove;
Move bestMove;
Move killers[KILLER_MAX];
Depth reduction;
Value eval;

View File

@@ -38,7 +38,7 @@ TranspositionTable TT;
TranspositionTable::TranspositionTable() {
size = writes = 0;
size = overwrites = 0;
entries = 0;
generation = 0;
}
@@ -100,6 +100,7 @@ void TranspositionTable::clear() {
void TranspositionTable::store(const Key posKey, Value v, ValueType t, Depth d, Move m, Value statV, Value kingD) {
int c1, c2, c3;
TTEntry *tte, *replace;
uint32_t posKey32 = posKey >> 32; // Use the high 32 bits as key
@@ -115,18 +116,19 @@ void TranspositionTable::store(const Key posKey, Value v, ValueType t, Depth d,
tte->save(posKey32, v, t, d, m, generation, statV, kingD);
return;
}
else if (i == 0) // replace would be a no-op in this common case
if (i == 0) // replace would be a no-op in this common case
continue;
int c1 = (replace->generation() == generation ? 2 : 0);
int c2 = (tte->generation() == generation ? -2 : 0);
int c3 = (tte->depth() < replace->depth() ? 1 : 0);
c1 = (replace->generation() == generation ? 2 : 0);
c2 = (tte->generation() == generation ? -2 : 0);
c3 = (tte->depth() < replace->depth() ? 1 : 0);
if (c1 + c2 + c3 > 0)
replace = tte;
}
replace->save(posKey32, v, t, d, m, generation, statV, kingD);
writes++;
overwrites++;
}
@@ -155,7 +157,7 @@ TTEntry* TranspositionTable::retrieve(const Key posKey) const {
void TranspositionTable::new_search() {
generation++;
writes = 0;
overwrites = 0;
}
@@ -185,20 +187,23 @@ void TranspositionTable::insert_pv(const Position& pos, Move pv[]) {
/// will often get single-move PVs when the search stops while failing high,
/// and a single-move PV means that we don't have a ponder move.
void TranspositionTable::extract_pv(const Position& pos, Move pv[], const int PLY_MAX) {
void TranspositionTable::extract_pv(const Position& pos, Move bestMove, Move pv[], const int PLY_MAX) {
const TTEntry* tte;
StateInfo st;
Position p(pos, pos.thread());
int ply = 0;
// Update position to the end of current PV
while (pv[ply] != MOVE_NONE)
p.do_move(pv[ply++], st);
assert(bestMove != MOVE_NONE);
// Try to add moves from TT while possible
pv[ply] = bestMove;
p.do_move(pv[ply++], st);
// Extract moves from TT when possible. We try hard to always
// get a ponder move, that's the reason of ply < 2 conditions.
while ( (tte = retrieve(p.get_key())) != NULL
&& tte->move() != MOVE_NONE
&& (tte->type() == VALUE_TYPE_EXACT || ply < 2)
&& move_is_legal(p, tte->move())
&& (!p.is_draw() || ply < 2)
&& ply < PLY_MAX)
@@ -211,11 +216,11 @@ void TranspositionTable::extract_pv(const Position& pos, Move pv[], const int PL
/// TranspositionTable::full() returns the permill of all transposition table
/// entries which have received at least one write during the current search.
/// entries which have received at least one overwrite during the current search.
/// It is used to display the "info hashfull ..." information in UCI.
int TranspositionTable::full() const {
double N = double(size) * ClusterSize;
return int(1000 * (1 - exp(writes * log(1.0 - 1.0/N))));
return int(1000 * (1 - exp(overwrites * log(1.0 - 1.0/N))));
}

View File

@@ -110,15 +110,15 @@ public:
TTEntry* retrieve(const Key posKey) const;
void new_search();
void insert_pv(const Position& pos, Move pv[]);
void extract_pv(const Position& pos, Move pv[], const int PLY_MAX);
void extract_pv(const Position& pos, Move bestMove, Move pv[], const int PLY_MAX);
int full() const;
TTEntry* first_entry(const Key posKey) const;
private:
// Be sure 'writes' is at least one cache line away
// Be sure 'overwrites' is at least one cache line away
// from read only variables.
unsigned char pad_before[64 - sizeof(unsigned)];
unsigned writes; // heavy SMP read/write access here
unsigned overwrites; // heavy SMP read/write access here
unsigned char pad_after[64];
size_t size;