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
+1 -3
View File
@@ -207,7 +207,6 @@ namespace {
// Bonuses for enemy's safe checks // Bonuses for enemy's safe checks
const int QueenContactCheckBonus = 3; const int QueenContactCheckBonus = 3;
const int DiscoveredCheckBonus = 3;
const int QueenCheckBonus = 2; const int QueenCheckBonus = 2;
const int RookCheckBonus = 1; const int RookCheckBonus = 1;
const int BishopCheckBonus = 1; const int BishopCheckBonus = 1;
@@ -862,8 +861,7 @@ namespace {
// value if the other side has a rook or queen. // value if the other side has a rook or queen.
if (square_file(s) == FILE_A || square_file(s) == FILE_H) if (square_file(s) == FILE_A || square_file(s) == FILE_H)
{ {
if ( pos.non_pawn_material(Them) <= KnightValueMidgame if (pos.non_pawn_material(Them) <= KnightValueMidgame)
&& pos.piece_count(Them, KNIGHT) <= 1)
ebonus += ebonus / 4; ebonus += ebonus / 4;
else if (pos.pieces(ROOK, QUEEN, Them)) else if (pos.pieces(ROOK, QUEEN, Them))
ebonus -= ebonus / 4; ebonus -= ebonus / 4;
+1 -1
View File
@@ -58,7 +58,7 @@ using namespace std;
/// Version number. If this is left empty, the current date (in the format /// Version number. If this is left empty, the current date (in the format
/// YYMMDD) is used as a version number. /// 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 AppName = "Stockfish";
static const string AppTag = ""; static const string AppTag = "";
+3 -3
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 // of direct checks and ordinary discovered check, the only case we
// need to handle is the unusual case of a discovered check through the // need to handle is the unusual case of a discovered check through
// captured pawn. // the captured pawn.
if (move_is_ep(m)) if (move_is_ep(m))
{ {
Square capsq = make_square(square_file(to), square_rank(from)); Square capsq = make_square(square_file(to), square_rank(from));
+1 -1
View File
@@ -68,7 +68,7 @@ const int MaxGameLength = 220;
struct CheckInfo { struct CheckInfo {
CheckInfo(const Position&); explicit CheckInfo(const Position&);
Bitboard dcCandidates; Bitboard dcCandidates;
Bitboard checkSq[8]; Bitboard checkSq[8];
+38 -34
View File
@@ -47,7 +47,7 @@ namespace {
AMBIGUITY_BOTH 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); Ambiguity move_ambiguity(const Position& pos, Move m);
const string time_string(int milliseconds); const string time_string(int milliseconds);
@@ -68,28 +68,25 @@ const string move_to_san(Position& pos, Move m) {
assert(pos.is_ok()); assert(pos.is_ok());
assert(move_is_ok(m)); assert(move_is_ok(m));
Square from, to; string san;
PieceType pt; Square from = move_from(m);
Square to = move_to(m);
from = move_from(m); PieceType pt = type_of_piece(pos.piece_on(move_from(m)));
to = move_to(m);
pt = type_of_piece(pos.piece_on(move_from(m)));
string san = "";
if (m == MOVE_NONE) if (m == MOVE_NONE)
return "(none)"; return "(none)";
else if (m == MOVE_NULL) else if (m == MOVE_NULL)
return "(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"; 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"; san = "O-O";
else else
{ {
if (pt != PAWN) if (pt != PAWN)
{ {
san += piece_type_to_char(pt, true); san += piece_type_to_char(pt, true);
switch (move_ambiguity(pos, m)) { switch (move_ambiguity(pos, m)) {
case AMBIGUITY_NONE: case AMBIGUITY_NONE:
break; break;
@@ -115,13 +112,13 @@ const string move_to_san(Position& pos, Move m) {
san += square_to_string(move_to(m)); san += square_to_string(move_to(m));
if (move_is_promotion(m)) if (move_is_promotion(m))
{ {
san += '='; san += "=";
san += piece_type_to_char(move_promotion_piece(m), true); 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, // The move gives check ? We don't use pos.move_is_check() here
// promotions and en passant captures). // because we need to test for mate after the move is done.
StateInfo st; StateInfo st;
pos.do_move(m, st); pos.do_move(m, st);
if (pos.is_check()) 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; size_t maxLength = 80 - startColumn;
Position p(pos, pos.thread()); 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; length += moveStr.length() + 1;
if (breakLines && length > maxLength) if (breakLines && length > maxLength)
{ {
s << '\n' << std::setw(startColumn) << ' '; s << "\n" << std::setw(startColumn) << " ";
length = moveStr.length() + 1; length = moveStr.length() + 1;
} }
s << moveStr << ' '; s << moveStr << ' ';
if (line[i] == MOVE_NULL) if (*m == MOVE_NULL)
p.do_null_move(st); p.do_null_move(st);
else else
p.do_move(line[i], st); p.do_move(*m, st);
} }
return s.str(); 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 /// It is used to write search information to the log file (which is created
/// when the UCI parameter "Use Search Log" is "true"). /// when the UCI parameter "Use Search Log" is "true").
const string pretty_pv(const Position& pos, int time, int depth, const string pretty_pv(const Position& pos, int time, int depth, uint64_t nodes,
uint64_t nodes, Value score, ValueType type, Move pv[]) { Value score, ValueType type, Move pv[]) {
const uint64_t K = 1000;
const uint64_t M = 1000000;
std::stringstream s; std::stringstream s;
// Depth // Depth
s << std::setw(2) << depth << " "; s << std::setw(2) << depth << " ";
// Score // Score
s << ((type == VALUE_TYPE_LOWER)? ">" : ((type == VALUE_TYPE_UPPER)? "<" : " ")); s << (type == VALUE_TYPE_LOWER ? ">" : type == VALUE_TYPE_UPPER ? "<" : " ")
s << std::setw(7) << score_string(score); << std::setw(7) << score_string(score);
// Time // Time
s << std::setw(8) << time_string(time) << " "; s << std::setw(8) << time_string(time) << " ";
// Nodes // Nodes
if (nodes < 1000000ULL) if (nodes < M)
s << std::setw(8) << nodes << " "; s << std::setw(8) << nodes / 1 << " ";
else if (nodes < 1000000000ULL) else if (nodes < K * M)
s << std::setw(7) << nodes/1000ULL << 'k' << " "; s << std::setw(7) << nodes / K << "K ";
else else
s << std::setw(7) << nodes/1000000ULL << 'M' << " "; s << std::setw(7) << nodes / M << "M ";
// PV // PV
s << line_to_san(pos, pv, 30, true); 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; std::stringstream s;
s << std::setfill('0'); s << std::setfill('0');
int hours = milliseconds / (1000*60*60); int hours = millisecs / MSecHour;
int minutes = (milliseconds - hours*1000*60*60) / (1000*60); int minutes = (millisecs - hours * MSecHour) / MSecMinute;
int seconds = (milliseconds - hours*1000*60*60 - minutes*1000*60) / 1000; int seconds = (millisecs - hours * MSecHour - minutes * MSecMinute) / 1000;
if (hours) if (hours)
s << hours << ':'; s << hours << ':';
@@ -421,7 +425,7 @@ namespace {
if (v >= VALUE_MATE - 200) if (v >= VALUE_MATE - 200)
s << "#" << (VALUE_MATE - v + 1) / 2; s << "#" << (VALUE_MATE - v + 1) / 2;
else if(v <= -VALUE_MATE + 200) else if (v <= -VALUE_MATE + 200)
s << "-#" << (VALUE_MATE + v) / 2; s << "-#" << (VALUE_MATE + v) / 2;
else else
{ {
+64 -107
View File
@@ -282,7 +282,7 @@ namespace {
/// Local functions /// Local functions
Value id_loop(const Position& pos, Move searchMoves[]); 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> template <NodeType PvNode>
Value search(Position& pos, SearchStack* ss, Value alpha, Value beta, Depth depth, int ply); Value search(Position& pos, SearchStack* ss, Value alpha, Value beta, Depth depth, int ply);
@@ -296,8 +296,6 @@ namespace {
template <NodeType PvNode> template <NodeType PvNode>
Depth extension(const Position& pos, Move m, bool captureOrPromotion, bool moveIsCheck, bool singleEvasion, bool mateThreat, bool* dangerous); 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 connected_moves(const Position& pos, Move m1, Move m2);
bool value_is_mate(Value value); bool value_is_mate(Value value);
bool move_is_killer(Move m, SearchStack* ss); bool move_is_killer(Move m, SearchStack* ss);
@@ -314,7 +312,7 @@ namespace {
void ponderhit(); void ponderhit();
void wait_for_stop_or_ponderhit(); void wait_for_stop_or_ponderhit();
void init_ss_array(SearchStack* ss, int size); 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) #if !defined(_MSC_VER)
void *init_thread(void *threadID); void *init_thread(void *threadID);
@@ -364,16 +362,16 @@ void init_search() {
} }
// SearchStack::init() initializes a search stack. Used at the beginning of a // SearchStack::init() initializes a search stack entry.
// new search from the root. // Called at the beginning of search() when starting to examine a new node.
void SearchStack::init() { void SearchStack::init() {
pv[0] = pv[1] = MOVE_NONE; currentMove = threatMove = bestMove = MOVE_NONE;
currentMove = threatMove = MOVE_NONE;
reduction = Depth(0); reduction = Depth(0);
eval = VALUE_NONE; eval = VALUE_NONE;
} }
// SearchStack::initKillers() initializes killers for a search stack entry
void SearchStack::initKillers() { void SearchStack::initKillers() {
mateKiller = MOVE_NONE; mateKiller = MOVE_NONE;
@@ -605,6 +603,7 @@ namespace {
Position p(pos, pos.thread()); Position p(pos, pos.thread());
SearchStack ss[PLY_MAX_PLUS_2]; SearchStack ss[PLY_MAX_PLUS_2];
Move pv[PLY_MAX_PLUS_2];
Move EasyMove = MOVE_NONE; Move EasyMove = MOVE_NONE;
Value value, alpha = -VALUE_INFINITE, beta = VALUE_INFINITE; Value value, alpha = -VALUE_INFINITE, beta = VALUE_INFINITE;
@@ -634,6 +633,7 @@ namespace {
TT.new_search(); TT.new_search();
H.clear(); H.clear();
init_ss_array(ss, PLY_MAX_PLUS_2); init_ss_array(ss, PLY_MAX_PLUS_2);
pv[0] = pv[1] = MOVE_NONE;
ValueByIteration[1] = rml.get_move_score(0); ValueByIteration[1] = rml.get_move_score(0);
Iteration = 1; Iteration = 1;
@@ -665,11 +665,11 @@ namespace {
} }
// Search to the current depth, rml is updated and sorted, alpha and beta could change // 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 // Write PV to transposition table, in case the relevant entries have
// been overwritten during the search. // been overwritten during the search.
TT.insert_pv(p, ss->pv); TT.insert_pv(p, pv);
if (AbortSearch) if (AbortSearch)
break; // Value cannot be trusted. Break out immediately! break; // Value cannot be trusted. Break out immediately!
@@ -678,7 +678,7 @@ namespace {
ValueByIteration[Iteration] = value; ValueByIteration[Iteration] = value;
// Drop the easy move if differs from the new best move // Drop the easy move if differs from the new best move
if (ss->pv[0] != EasyMove) if (pv[0] != EasyMove)
EasyMove = MOVE_NONE; EasyMove = MOVE_NONE;
if (UseTimeManagement) if (UseTimeManagement)
@@ -700,7 +700,7 @@ namespace {
// Stop search early if one move seems to be much better than the others // Stop search early if one move seems to be much better than the others
int64_t nodes = TM.nodes_searched(); int64_t nodes = TM.nodes_searched();
if ( Iteration >= 8 if ( Iteration >= 8
&& EasyMove == ss->pv[0] && EasyMove == pv[0]
&& ( ( rml.get_move_cumulative_nodes(0) > (nodes * 85) / 100 && ( ( rml.get_move_cumulative_nodes(0) > (nodes * 85) / 100
&& current_search_time() > MaxSearchTime / 16) && current_search_time() > MaxSearchTime / 16)
||( rml.get_move_cumulative_nodes(0) > (nodes * 98) / 100 ||( rml.get_move_cumulative_nodes(0) > (nodes * 98) / 100
@@ -743,18 +743,18 @@ namespace {
<< " hashfull " << TT.full() << endl; << " hashfull " << TT.full() << endl;
// Print the best move and the ponder move to the standard output // 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); pv[0] = rml.get_move(0);
ss->pv[1] = MOVE_NONE; 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) if (pv[1] != MOVE_NONE)
cout << " ponder " << ss->pv[1]; cout << " ponder " << pv[1];
cout << endl; cout << endl;
@@ -768,12 +768,12 @@ namespace {
LogFile << "\nNodes: " << TM.nodes_searched() LogFile << "\nNodes: " << TM.nodes_searched()
<< "\nNodes/second: " << nps() << "\nNodes/second: " << nps()
<< "\nBest move: " << move_to_san(p, ss->pv[0]); << "\nBest move: " << move_to_san(p, pv[0]);
StateInfo st; StateInfo st;
p.do_move(ss->pv[0], st); p.do_move(pv[0], st);
LogFile << "\nPonder move: " 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; << endl;
} }
return rml.get_move_score(0); return rml.get_move_score(0);
@@ -785,7 +785,7 @@ namespace {
// scheme, prints some information to the standard output and handles // scheme, prints some information to the standard output and handles
// the fail low/high loops. // 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; EvalInfo ei;
StateInfo st; StateInfo st;
@@ -935,12 +935,12 @@ namespace {
// We are failing high and going to do a research. It's important to update // 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. // the score before research in case we run out of time while researching.
rml.set_move_score(i, value); rml.set_move_score(i, value);
update_pv(ss); ss->bestMove = move;
TT.extract_pv(pos, ss->pv, PLY_MAX); TT.extract_pv(pos, move, pv, PLY_MAX);
rml.set_move_pv(i, ss->pv); rml.set_move_pv(i, pv);
// Print information to the standard output // 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 // Prepare for a research after a fail high, each time with a wider window
*betaPtr = beta = Min(beta + AspirationDelta * (1 << researchCountFH), VALUE_INFINITE); *betaPtr = beta = Min(beta + AspirationDelta * (1 << researchCountFH), VALUE_INFINITE);
@@ -975,9 +975,9 @@ namespace {
// Update PV // Update PV
rml.set_move_score(i, value); rml.set_move_score(i, value);
update_pv(ss); ss->bestMove = move;
TT.extract_pv(pos, ss->pv, PLY_MAX); TT.extract_pv(pos, move, pv, PLY_MAX);
rml.set_move_pv(i, ss->pv); rml.set_move_pv(i, pv);
if (MultiPV == 1) if (MultiPV == 1)
{ {
@@ -988,7 +988,7 @@ namespace {
BestMoveChangesByIteration[Iteration]++; BestMoveChangesByIteration[Iteration]++;
// Print information to the standard output // 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 // Raise alpha to setup proper non-pv search upper bound
if (value > alpha) if (value > alpha)
@@ -1061,7 +1061,7 @@ namespace {
Depth ext, newDepth; Depth ext, newDepth;
Value bestValue, value, oldAlpha; Value bestValue, value, oldAlpha;
Value refinedValue, nullValue, futilityValueScaled; // Non-PV specific Value refinedValue, nullValue, futilityValueScaled; // Non-PV specific
bool isCheck, singleEvasion, moveIsCheck, captureOrPromotion, dangerous; bool isCheck, singleEvasion, singularExtensionNode, moveIsCheck, captureOrPromotion, dangerous;
bool mateThreat = false; bool mateThreat = false;
int moveCount = 0; int moveCount = 0;
int threadID = pos.thread(); int threadID = pos.thread();
@@ -1246,7 +1246,7 @@ namespace {
search<PvNode>(pos, ss, alpha, beta, d, ply); search<PvNode>(pos, ss, alpha, beta, d, ply);
ss->skipNullMove = false; ss->skipNullMove = false;
ttMove = ss->pv[0]; ttMove = ss->bestMove;
tte = TT.retrieve(posKey); tte = TT.retrieve(posKey);
} }
@@ -1257,11 +1257,12 @@ namespace {
// Initialize a MovePicker object for the current position // Initialize a MovePicker object for the current position
MovePicker mp = MovePicker(pos, ttMove, depth, H, ss, (PvNode ? -VALUE_INFINITE : beta)); MovePicker mp = MovePicker(pos, ttMove, depth, H, ss, (PvNode ? -VALUE_INFINITE : beta));
CheckInfo ci(pos); CheckInfo ci(pos);
bool singularExtensionNode = depth >= SingularExtensionDepth[PvNode] singleEvasion = isCheck && mp.number_of_evasions() == 1;
&& tte && tte->move() singularExtensionNode = depth >= SingularExtensionDepth[PvNode]
&& !excludedMove // Do not allow recursive singular extension search && tte && tte->move()
&& is_lower_bound(tte->type()) && !excludedMove // Do not allow recursive singular extension search
&& tte->depth() >= depth - 3 * OnePly; && is_lower_bound(tte->type())
&& tte->depth() >= depth - 3 * OnePly;
// Step 10. Loop through moves // Step 10. Loop through moves
// Loop through all legal moves until no moves remain or a beta cutoff occurs // Loop through all legal moves until no moves remain or a beta cutoff occurs
@@ -1274,7 +1275,6 @@ namespace {
if (move == excludedMove) if (move == excludedMove)
continue; continue;
singleEvasion = (isCheck && mp.number_of_evasions() == 1);
moveIsCheck = pos.move_is_check(move, ci); moveIsCheck = pos.move_is_check(move, ci);
captureOrPromotion = pos.move_is_capture_or_promotion(move); captureOrPromotion = pos.move_is_capture_or_promotion(move);
@@ -1410,10 +1410,10 @@ namespace {
if (PvNode && value < beta) // This guarantees that always: alpha < beta if (PvNode && value < beta) // This guarantees that always: alpha < beta
alpha = value; alpha = value;
update_pv(ss);
if (value == value_mate_in(ply + 1)) if (value == value_mate_in(ply + 1))
ss->mateKiller = move; ss->mateKiller = move;
ss->bestMove = move;
} }
} }
@@ -1442,22 +1442,20 @@ namespace {
if (AbortSearch || TM.thread_should_stop(threadID)) if (AbortSearch || TM.thread_should_stop(threadID))
return bestValue; return bestValue;
if (bestValue <= oldAlpha) ValueType f = (bestValue <= oldAlpha ? VALUE_TYPE_UPPER : bestValue >= beta ? VALUE_TYPE_LOWER : VALUE_TYPE_EXACT);
TT.store(posKey, value_to_tt(bestValue, ply), VALUE_TYPE_UPPER, depth, MOVE_NONE, ss->eval, ei.kingDanger[pos.side_to_move()]); 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); 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)) if (!pos.move_is_capture_or_promotion(move))
{ {
update_history(pos, move, depth, movesSearched, moveCount); update_history(pos, move, depth, movesSearched, moveCount);
update_killers(move, ss); 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); assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE);
@@ -1488,7 +1486,7 @@ namespace {
Value oldAlpha = alpha; Value oldAlpha = alpha;
TM.incrementNodeCounter(pos.thread()); TM.incrementNodeCounter(pos.thread());
ss->pv[0] = ss->pv[1] = ss->currentMove = MOVE_NONE; ss->bestMove = ss->currentMove = MOVE_NONE;
ss->eval = VALUE_NONE; ss->eval = VALUE_NONE;
// Check for an instant draw or maximum ply reached // Check for an instant draw or maximum ply reached
@@ -1615,7 +1613,7 @@ namespace {
if (value > alpha) if (value > alpha)
{ {
alpha = value; alpha = value;
update_pv(ss); ss->bestMove = move;
} }
} }
} }
@@ -1627,19 +1625,13 @@ namespace {
// Update transposition table // Update transposition table
Depth d = (depth == Depth(0) ? Depth(0) : Depth(-1)); Depth d = (depth == Depth(0) ? Depth(0) : Depth(-1));
if (bestValue <= oldAlpha) 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), VALUE_TYPE_UPPER, d, MOVE_NONE, ss->eval, ei.kingDanger[pos.side_to_move()]); TT.store(pos.get_key(), value_to_tt(bestValue, ply), f, d, ss->bestMove, 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()]);
// Update killers only for good checking moves // Update killers only for checking moves that fails high
if (!pos.move_is_capture_or_promotion(move)) if ( bestValue >= beta
update_killers(move, ss); && !pos.move_is_capture_or_promotion(ss->bestMove))
} update_killers(ss->bestMove, 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()]);
assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE); 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 if (PvNode && value < sp->beta) // This guarantees that always: sp->alpha < sp->beta
sp->alpha = value; sp->alpha = value;
sp_update_pv(sp->parentSstack, ss); sp->parentSstack->bestMove = ss->bestMove = move;
} }
} }
} }
@@ -1814,40 +1806,6 @@ namespace {
lock_release(&(sp->lock)); 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 // connected_moves() tests whether two moves are 'connected' in the sense
// that the first move somehow made the second move possible (for instance // that the first move somehow made the second move possible (for instance
@@ -1948,7 +1906,7 @@ namespace {
if (*dangerous) if (*dangerous)
{ {
if (moveIsCheck && pos.see_sign(m)>= 0) if (moveIsCheck && pos.see_sign(m) >= 0)
result += CheckExtension[PvNode]; result += CheckExtension[PvNode];
if (singleEvasion) if (singleEvasion)
@@ -2287,29 +2245,28 @@ namespace {
// print_pv_info() prints to standard output and eventually to log file information on // 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. // 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 cout << "info depth " << Iteration
<< " score " << value_to_string(value) << " score " << value_to_string(value)
<< ((value >= beta) ? " lowerbound" : << (value >= beta ? " lowerbound" : value <= alpha ? " upperbound" : "")
((value <= alpha)? " upperbound" : ""))
<< " time " << current_search_time() << " time " << current_search_time()
<< " nodes " << TM.nodes_searched() << " nodes " << TM.nodes_searched()
<< " nps " << nps() << " nps " << nps()
<< " pv "; << " pv ";
for (int j = 0; ss->pv[j] != MOVE_NONE && j < PLY_MAX; j++) for (Move* m = pv; *m != MOVE_NONE; m++)
cout << ss->pv[j] << " "; cout << *m << " ";
cout << endl; cout << endl;
if (UseLogFile) if (UseLogFile)
{ {
ValueType type = (value >= beta ? VALUE_TYPE_LOWER ValueType t = value >= beta ? VALUE_TYPE_LOWER :
: (value <= alpha ? VALUE_TYPE_UPPER : VALUE_TYPE_EXACT)); value <= alpha ? VALUE_TYPE_UPPER : VALUE_TYPE_EXACT;
LogFile << pretty_pv(pos, current_search_time(), Iteration, LogFile << pretty_pv(pos, current_search_time(), Iteration,
TM.nodes_searched(), value, type, ss->pv) << endl; TM.nodes_searched(), value, t, pv) << endl;
} }
} }
+1 -1
View File
@@ -50,11 +50,11 @@ const int KILLER_MAX = 2;
struct EvalInfo; struct EvalInfo;
struct SearchStack { struct SearchStack {
Move pv[PLY_MAX_PLUS_2];
Move currentMove; Move currentMove;
Move mateKiller; Move mateKiller;
Move threatMove; Move threatMove;
Move excludedMove; Move excludedMove;
Move bestMove;
Move killers[KILLER_MAX]; Move killers[KILLER_MAX];
Depth reduction; Depth reduction;
Value eval; Value eval;
+19 -14
View File
@@ -38,7 +38,7 @@ TranspositionTable TT;
TranspositionTable::TranspositionTable() { TranspositionTable::TranspositionTable() {
size = writes = 0; size = overwrites = 0;
entries = 0; entries = 0;
generation = 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) { 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; TTEntry *tte, *replace;
uint32_t posKey32 = posKey >> 32; // Use the high 32 bits as key 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); tte->save(posKey32, v, t, d, m, generation, statV, kingD);
return; 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; continue;
int c1 = (replace->generation() == generation ? 2 : 0); c1 = (replace->generation() == generation ? 2 : 0);
int c2 = (tte->generation() == generation ? -2 : 0); c2 = (tte->generation() == generation ? -2 : 0);
int c3 = (tte->depth() < replace->depth() ? 1 : 0); c3 = (tte->depth() < replace->depth() ? 1 : 0);
if (c1 + c2 + c3 > 0) if (c1 + c2 + c3 > 0)
replace = tte; replace = tte;
} }
replace->save(posKey32, v, t, d, m, generation, statV, kingD); 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() { void TranspositionTable::new_search() {
generation++; 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, /// 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. /// 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; const TTEntry* tte;
StateInfo st; StateInfo st;
Position p(pos, pos.thread()); Position p(pos, pos.thread());
int ply = 0; int ply = 0;
// Update position to the end of current PV assert(bestMove != MOVE_NONE);
while (pv[ply] != MOVE_NONE)
p.do_move(pv[ply++], st);
// 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 while ( (tte = retrieve(p.get_key())) != NULL
&& tte->move() != MOVE_NONE && tte->move() != MOVE_NONE
&& (tte->type() == VALUE_TYPE_EXACT || ply < 2)
&& move_is_legal(p, tte->move()) && move_is_legal(p, tte->move())
&& (!p.is_draw() || ply < 2) && (!p.is_draw() || ply < 2)
&& ply < PLY_MAX) && 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 /// 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. /// It is used to display the "info hashfull ..." information in UCI.
int TranspositionTable::full() const { int TranspositionTable::full() const {
double N = double(size) * ClusterSize; 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))));
} }
+3 -3
View File
@@ -110,15 +110,15 @@ public:
TTEntry* retrieve(const Key posKey) const; TTEntry* retrieve(const Key posKey) const;
void new_search(); void new_search();
void insert_pv(const Position& pos, Move pv[]); 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; int full() const;
TTEntry* first_entry(const Key posKey) const; TTEntry* first_entry(const Key posKey) const;
private: 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. // from read only variables.
unsigned char pad_before[64 - sizeof(unsigned)]; 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]; unsigned char pad_after[64];
size_t size; size_t size;