Compare commits

..

10 Commits

Author SHA1 Message Date
Marco Costalba
78e6b361c5 Stockfish 2.2.1
Hopefully fixed the "lose on time" issue.

stockfish bench signature is: 5457475

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2012-01-06 17:01:40 +01:00
Marco Costalba
aa392c366e Extra time management safety
Further increase safety against time losses. After this
change (tested on LittleBlitzer and cutechess) I had no
more time losses at 2" and 1"+0.02 TC both on Windows
and Linux on more than 10000 games.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2012-01-06 13:24:37 +01:00
Marco Costalba
f80c50bcdd Try hard not to lose on time
We try hard not to lose on time even under extreme
time pressure. We achieve this through 3 different but
coordinated steps:

    1) Increase max frequency of timer events

    2) Quickly return after a stop signal

    3) Take in account timer resolution

With these SF played under LittleBlitzer at 1"+0.02 and 3"+0
without losing on time even one game.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2012-01-06 01:41:45 +01:00
Marco Costalba
d282cf6964 Avoid a race at thread creation
Before creating main thread we set its do_sleep flag to true,
then thread is created and it will go to sleep in main_loop()
after resetting do_sleep.

But if after the setting of do_sleep and before its resetting
the UI thread calls start_thinking() it will not wait on:

  if (!asyncMode)
      while (!main.do_sleep)
          cond_wait(&sleepCond, &main.sleepLock);

as it should but will immediately return before the main thread has
started the search. This very rare race show itself during bench,
when the first position is erroneusly skipped so that bench node count
results of 5309038 instead of the correct 5457475.

The patch is somewhat tricky, but is simple and it works!

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2012-01-03 21:31:50 +01:00
Marco Costalba
b1fcfe4c5d Streamline generation of MV_NON_EVASION
Small speed-up of 3% in perft.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2012-01-03 19:18:38 +01:00
Marco Costalba
30418a3cfc Fix a warning under gcc
Locals left and right shadow two same named
variables in the std::ifstream base class.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2012-01-03 19:01:47 +01:00
Marco Costalba
cb1709ef5e Revert cond_signal() fix
It seems it yields to missing wake-up events with the
result of SF loosing on time as reported by many people.

So revert the patch and use a more robust approach: assume
there can be spurious wake ups events and make the code to
work also in those cases.

While debugging I found that WaitForSingleObject() had wrong
parameter 0 instead of INFINITE yielding to a crash while
exiting under Windows, strangely unnoticed til now.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2012-01-02 16:44:04 +01:00
Marco Costalba
67338e6f32 Big renaming of move's helpers
The aim is to have shorter names without losing
readibility but, if possible, increasing it.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2012-01-02 12:03:54 +01:00
Marco Costalba
8300ab149c Simplify Book APIs
Retire open(), close() and name() from public visibility
and greately simplify the code. It is amazing how much
can be squeezed out of an already mature code !

No functional change

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2012-01-01 14:46:18 +01:00
Marco Costalba
c00443b19e Restore development version
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-12-31 15:44:00 +01:00
13 changed files with 231 additions and 283 deletions

View File

@@ -17,13 +17,13 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
/* /*
The code in this file is based on the opening book code in PolyGlot The code in this file is based on the opening book code in PolyGlot
by Fabien Letouzey. PolyGlot is available under the GNU General by Fabien Letouzey. PolyGlot is available under the GNU General
Public License, and can be downloaded from http://wbec-ridderkerk.nl Public License, and can be downloaded from http://wbec-ridderkerk.nl
*/ */
#include <algorithm>
#include <cassert> #include <cassert>
#include <iostream> #include <iostream>
@@ -306,225 +306,182 @@ namespace {
const Key* ZobEnPassant = PolyGlotRandoms + 772; const Key* ZobEnPassant = PolyGlotRandoms + 772;
const Key* ZobTurn = PolyGlotRandoms + 780; const Key* ZobTurn = PolyGlotRandoms + 780;
// Piece offset is calculated as 64 * (PolyPiece ^ 1) where // PieceOffset is calculated as 64 * (PolyPiece ^ 1) where PolyPiece
// PolyPiece is: BP = 0, WP = 1, BN = 2, WN = 3 ... BK = 10, WK = 11 // is: BP = 0, WP = 1, BN = 2, WN = 3 ... BK = 10, WK = 11
const int PieceOfs[] = { 0, 64, 192, 320, 448, 576, 704, 0, const int PieceOffset[] = { 0, 64, 192, 320, 448, 576, 704, 0,
0, 0, 128, 256, 384, 512, 640 }; 0, 0, 128, 256, 384, 512, 640 };
// book_key() builds up a PolyGlot hash key out of a position // book_key() returns the PolyGlot hash key of the given position
uint64_t book_key(const Position& pos) { uint64_t book_key(const Position& pos) {
uint64_t result = 0; uint64_t key = 0;
Bitboard b = pos.occupied_squares(); Bitboard b = pos.occupied_squares();
while (b) while (b)
{ {
Square s = pop_1st_bit(&b); Square s = pop_1st_bit(&b);
result ^= ZobPiece[PieceOfs[pos.piece_on(s)] + s]; key ^= ZobPiece[PieceOffset[pos.piece_on(s)] + s];
} }
if (pos.can_castle(WHITE_OO)) b = (pos.can_castle(WHITE_OO) << 0) | (pos.can_castle(WHITE_OOO) << 1)
result ^= ZobCastle[0]; | (pos.can_castle(BLACK_OO) << 2) | (pos.can_castle(BLACK_OOO) << 3);
if (pos.can_castle(WHITE_OOO)) while (b)
result ^= ZobCastle[1]; key ^= ZobCastle[pop_1st_bit(&b)];
if (pos.can_castle(BLACK_OO))
result ^= ZobCastle[2];
if (pos.can_castle(BLACK_OOO))
result ^= ZobCastle[3];
if (pos.ep_square() != SQ_NONE) if (pos.ep_square() != SQ_NONE)
result ^= ZobEnPassant[file_of(pos.ep_square())]; key ^= ZobEnPassant[file_of(pos.ep_square())];
if (pos.side_to_move() == WHITE) if (pos.side_to_move() == WHITE)
result ^= ZobTurn[0]; key ^= ZobTurn[0];
return result; return key;
}
} }
} // namespace
/// Book c'tor. Make random number generation less deterministic, for book moves Book::Book() : size(0) {
Book::Book() : bookSize(0) {
for (int i = abs(system_time() % 10000); i > 0; i--) for (int i = abs(system_time() % 10000); i > 0; i--)
RKiss.rand<unsigned>(); RKiss.rand<unsigned>(); // Make random number generation less deterministic
}
Book::~Book() { if (is_open()) close(); }
/// Book::operator>>() reads sizeof(T) chars from the file's binary byte stream
/// and converts them in a number of type T. A Polyglot book stores numbers in
/// big-endian format.
template<typename T> Book& Book::operator>>(T& n) {
n = 0;
for (size_t i = 0; i < sizeof(T); i++)
n = T((n << 8) + ifstream::get());
return *this;
}
template<> Book& Book::operator>>(BookEntry& e) {
return *this >> e.key >> e.move >> e.count >> e.learn;
} }
/// Book destructor. Be sure file is closed before we leave. /// Book::open() tries to open a book file with the given name after closing
/// any exsisting one.
Book::~Book() { bool Book::open(const char* fName) {
close(); fileName = "";
}
if (is_open()) // Cannot close an already closed file
/// Book::close() closes the file only if it is open, otherwise the call fails
/// and the failbit internal state flag is set.
void Book::close() {
if (bookFile.is_open())
bookFile.close();
bookName = "";
bookSize = 0;
}
/// Book::open() opens a book file with a given name
void Book::open(const string& fileName) {
// Close old file before opening the new
close(); close();
bookFile.open(fileName.c_str(), ifstream::in | ifstream::binary |ios::ate); ifstream::open(fName, ifstream::in | ifstream::binary | ios::ate);
// Silently return when asked to open a non-exsistent file if (!is_open())
if (!bookFile.is_open()) return false; // Silently fail if the file is not found
return;
// Get the book size in number of entries, we are already at the file end // Get the book size in number of entries, we are already at the end of file
bookSize = long(bookFile.tellg()) / sizeof(BookEntry); size = tellg() / sizeof(BookEntry);
if (!bookFile.good()) if (!good())
{ {
cerr << "Failed to open book file " << fileName << endl; cerr << "Failed to open book file " << fName << endl;
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
// Set only if successful fileName = fName; // Set only if successful
bookName = fileName; return true;
} }
/// Book::probe() gets a book move for a given position. Returns MOVE_NONE /// Book::probe() tries to find a book move for the given position. If no move
/// if no book move is found. If findBest is true then returns always the /// is found returns MOVE_NONE. If pickBest is true returns always the highest
/// highest rated move otherwise chooses randomly based on the move score. /// rated move, otherwise randomly chooses one, based on the move score.
Move Book::probe(const Position& pos, bool findBest) { Move Book::probe(const Position& pos, const string& fName, bool pickBest) {
if (!bookSize || !bookFile.is_open()) BookEntry e;
uint16_t best = 0;
unsigned sum = 0;
Move move = MOVE_NONE;
uint64_t key = book_key(pos);
if (fileName != fName && !open(fName.c_str()))
return MOVE_NONE; return MOVE_NONE;
BookEntry entry; binary_search(key);
unsigned scoresSum = 0, bestScore = 0, bookMove = 0;
uint64_t key = book_key(pos);
int idx = first_entry(key) - 1;
// Choose a book move among the possible moves for the given position while (*this >> e, e.key == key && good())
while (++idx < bookSize && (entry = read_entry(idx), entry.key == key))
{ {
scoresSum += entry.count; best = max(best, e.count);
sum += e.count;
// Choose book move according to its score. If a move has a very // Choose book move according to its score. If a move has a very
// high score it has higher probability to be choosen than a move // high score it has higher probability to be choosen than a move
// with lower score. Note that first entry is always chosen. // with lower score. Note that first entry is always chosen.
if ( RKiss.rand<unsigned>() % scoresSum < entry.count if ( (RKiss.rand<unsigned>() % sum < e.count)
|| (findBest && entry.count > bestScore)) || (pickBest && e.count == best))
bookMove = entry.move; move = Move(e.move);
if (entry.count > bestScore)
bestScore = entry.count;
} }
if (!bookMove) if (!move)
return MOVE_NONE; return MOVE_NONE;
// A PolyGlot book move is encoded as follows: // A PolyGlot book move is encoded as follows:
// //
// bit 0- 5: destination square (from 0 to 63) // bit 0- 5: destination square (from 0 to 63)
// bit 6-11: origin square (from 0 to 63) // bit 6-11: origin square (from 0 to 63)
// bit 12-13-14: promotion piece (from KNIGHT == 1 to QUEEN == 4) // bit 12-14: promotion piece (from KNIGHT == 1 to QUEEN == 4)
// //
// Castling moves follow "king captures rook" representation. So in case // Castling moves follow "king captures rook" representation. So in case book
// book move is a promotion we have to convert to our representation, in // move is a promotion we have to convert to our representation, in all the
// all other cases we can directly compare with a Move after having // other cases we can directly compare with a Move after having masked out
// masked out special Move's flags that are not supported by PolyGlot. // the special Move's flags (bit 14-15) that are not supported by PolyGlot.
int promotion = (bookMove >> 12) & 7; int pt = (move >> 12) & 7;
if (pt)
move = make_promotion(from_sq(move), to_sq(move), PieceType(pt + 1));
if (promotion) // Add 'special move' flags and verify it is legal
bookMove = make_promotion_move(move_from(Move(bookMove)),
move_to(Move(bookMove)),
PieceType(promotion + 1));
// Verify the book move is legal
for (MoveList<MV_LEGAL> ml(pos); !ml.end(); ++ml) for (MoveList<MV_LEGAL> ml(pos); !ml.end(); ++ml)
if (unsigned(ml.move() & ~(3 << 14)) == bookMove) // Mask out special flags if (move == (ml.move() & 0x3FFF))
return ml.move(); return ml.move();
return MOVE_NONE; return MOVE_NONE;
} }
/// Book::first_entry() takes a book key as input, and does a binary search /// Book::binary_search() takes a book key as input, and does a binary search
/// through the book file for the given key. The index to the first (leftmost) /// through the book file for the given key. File stream current position is set
/// book entry with the same key as the input is returned. When the key is not /// to the leftmost book entry with the same key as the input.
/// found in the book file, bookSize is returned.
int Book::first_entry(uint64_t key) { void Book::binary_search(uint64_t key) {
int left, right, mid;
// Binary search (finds the leftmost entry with given key)
left = 0;
right = bookSize - 1;
assert(left <= right);
while (left < right)
{
mid = (left + right) / 2;
assert(mid >= left && mid < right);
if (key <= read_entry(mid).key)
right = mid;
else
left = mid + 1;
}
assert(left == right);
return read_entry(left).key == key ? left : bookSize;
}
/// Book::operator>>() reads sizeof(T) chars from the file's binary byte
/// stream and converts them in a number of type T.
template<typename T>
Book& Book::operator>>(T& n) {
n = 0;
for (size_t i = 0; i < sizeof(T); i++)
n = T((n << 8) + bookFile.get());
return *this;
}
/// Book::read_entry() takes an integer index, and returns the BookEntry
/// at the given index in the book file.
BookEntry Book::read_entry(int idx) {
assert(idx >= 0 && idx < bookSize);
assert(bookFile.is_open());
size_t low, high, mid;
BookEntry e; BookEntry e;
bookFile.seekg(idx * sizeof(BookEntry), ios_base::beg); low = 0;
high = size - 1;
*this >> e.key >> e.move >> e.count >> e.learn; assert(low <= high);
if (!bookFile.good()) while (low < high && good())
{ {
cerr << "Failed to read book entry at index " << idx << endl; mid = (low + high) / 2;
exit(EXIT_FAILURE);
assert(mid >= low && mid < high);
seekg(mid * sizeof(BookEntry), ios_base::beg);
*this >> e;
if (key <= e.key)
high = mid;
else
low = mid + 1;
} }
return e;
assert(low == high);
seekg(low * sizeof(BookEntry), ios_base::beg);
} }

View File

@@ -37,25 +37,22 @@ struct BookEntry {
uint32_t learn; uint32_t learn;
}; };
class Book {
class Book : private std::ifstream {
public: public:
Book(); Book();
~Book(); ~Book();
void open(const std::string& fileName); Move probe(const Position& pos, const std::string& fName, bool pickBest);
void close();
Move probe(const Position& pos, bool findBestMove);
const std::string name() const { return bookName; }
private: private:
template<typename T> Book& operator>>(T& n); template<typename T> Book& operator>>(T& n);
BookEntry read_entry(int idx); bool open(const char* fName);
int first_entry(uint64_t key); void binary_search(uint64_t key);
RKISS RKiss; RKISS RKiss;
std::ifstream bookFile; std::string fileName;
std::string bookName; size_t size;
int bookSize;
}; };
#endif // !defined(BOOK_H_INCLUDED) #endif // !defined(BOOK_H_INCLUDED)

View File

@@ -75,8 +75,8 @@ typedef HANDLE WaitCondition;
# define cond_init(x) { *x = CreateEvent(0, FALSE, FALSE, 0); } # define cond_init(x) { *x = CreateEvent(0, FALSE, FALSE, 0); }
# define cond_destroy(x) CloseHandle(*x) # define cond_destroy(x) CloseHandle(*x)
# define cond_signal(x) SetEvent(*x) # define cond_signal(x) SetEvent(*x)
# define cond_wait(x,y) { ResetEvent(*x); lock_release(y); WaitForSingleObject(*x, INFINITE); lock_grab(y); } # define cond_wait(x,y) { lock_release(y); WaitForSingleObject(*x, INFINITE); lock_grab(y); }
# define cond_timedwait(x,y,z) { ResetEvent(*x); lock_release(y); WaitForSingleObject(*x,z); lock_grab(y); } # define cond_timedwait(x,y,z) { lock_release(y); WaitForSingleObject(*x,z); lock_grab(y); }
#endif #endif

View File

@@ -55,7 +55,7 @@ using namespace std;
/// Version number. If Version is left empty, then Tag plus current /// Version number. If Version is left empty, then Tag plus current
/// date (in the format YYMMDD) is used as a version number. /// date (in the format YYMMDD) is used as a version number.
static const string Version = "2.2"; static const string Version = "2.2.1";
static const string Tag = ""; static const string Tag = "";

View File

@@ -33,8 +33,8 @@ using std::string;
const string move_to_uci(Move m, bool chess960) { const string move_to_uci(Move m, bool chess960) {
Square from = move_from(m); Square from = from_sq(m);
Square to = move_to(m); Square to = to_sq(m);
string promotion; string promotion;
if (m == MOVE_NONE) if (m == MOVE_NONE)
@@ -83,13 +83,13 @@ const string move_to_san(Position& pos, Move m) {
Bitboard attackers; Bitboard attackers;
bool ambiguousMove, ambiguousFile, ambiguousRank; bool ambiguousMove, ambiguousFile, ambiguousRank;
Square sq, from = move_from(m); Square sq, from = from_sq(m);
Square to = move_to(m); Square to = to_sq(m);
PieceType pt = type_of(pos.piece_on(from)); PieceType pt = type_of(pos.piece_on(from));
string san; string san;
if (is_castle(m)) if (is_castle(m))
san = (move_to(m) < move_from(m) ? "O-O-O" : "O-O"); san = (to_sq(m) < from_sq(m) ? "O-O-O" : "O-O");
else else
{ {
if (pt != PAWN) if (pt != PAWN)

View File

@@ -101,8 +101,6 @@ namespace {
FORCE_INLINE MoveStack* generate_piece_moves(const Position& p, MoveStack* m, Color us, Bitboard t) { FORCE_INLINE MoveStack* generate_piece_moves(const Position& p, MoveStack* m, Color us, Bitboard t) {
assert(Pt == PAWN); assert(Pt == PAWN);
assert(Type == MV_CAPTURE || Type == MV_NON_CAPTURE || Type == MV_EVASION);
return (us == WHITE ? generate_pawn_moves<WHITE, Type>(p, m, t, SQ_NONE) return (us == WHITE ? generate_pawn_moves<WHITE, Type>(p, m, t, SQ_NONE)
: generate_pawn_moves<BLACK, Type>(p, m, t, SQ_NONE)); : generate_pawn_moves<BLACK, Type>(p, m, t, SQ_NONE));
} }
@@ -151,27 +149,22 @@ namespace {
template<MoveType Type> template<MoveType Type>
MoveStack* generate(const Position& pos, MoveStack* mlist) { MoveStack* generate(const Position& pos, MoveStack* mlist) {
assert(Type == MV_CAPTURE || Type == MV_NON_CAPTURE || Type == MV_NON_EVASION);
assert(!pos.in_check()); assert(!pos.in_check());
Color us = pos.side_to_move(); Color us = pos.side_to_move();
Bitboard target; Bitboard target;
if (Type == MV_CAPTURE || Type == MV_NON_EVASION) if (Type == MV_CAPTURE)
target = pos.pieces(flip(us)); target = pos.pieces(flip(us));
else if (Type == MV_NON_CAPTURE) else if (Type == MV_NON_CAPTURE)
target = pos.empty_squares(); target = pos.empty_squares();
else
assert(false);
if (Type == MV_NON_EVASION) else if (Type == MV_NON_EVASION)
{ target = pos.pieces(flip(us)) | pos.empty_squares();
mlist = generate_piece_moves<PAWN, MV_CAPTURE>(pos, mlist, us, target);
mlist = generate_piece_moves<PAWN, MV_NON_CAPTURE>(pos, mlist, us, pos.empty_squares());
target |= pos.empty_squares();
}
else
mlist = generate_piece_moves<PAWN, Type>(pos, mlist, us, target); mlist = generate_piece_moves<PAWN, Type>(pos, mlist, us, target);
mlist = generate_piece_moves<KNIGHT>(pos, mlist, us, target); mlist = generate_piece_moves<KNIGHT>(pos, mlist, us, target);
mlist = generate_piece_moves<BISHOP>(pos, mlist, us, target); mlist = generate_piece_moves<BISHOP>(pos, mlist, us, target);
mlist = generate_piece_moves<ROOK>(pos, mlist, us, target); mlist = generate_piece_moves<ROOK>(pos, mlist, us, target);
@@ -339,7 +332,7 @@ namespace {
Delta == DELTA_NW ? p << 7 : Delta == DELTA_SW ? p >> 9 : p; Delta == DELTA_NW ? p << 7 : Delta == DELTA_SW ? p >> 9 : p;
} }
template<MoveType Type, Square Delta> template<Square Delta>
inline MoveStack* generate_pawn_captures(MoveStack* mlist, Bitboard pawns, Bitboard target) { inline MoveStack* generate_pawn_captures(MoveStack* mlist, Bitboard pawns, Bitboard target) {
const Bitboard TFileABB = (Delta == DELTA_NE || Delta == DELTA_SE ? FileABB : FileHBB); const Bitboard TFileABB = (Delta == DELTA_NE || Delta == DELTA_SE ? FileABB : FileHBB);
@@ -371,21 +364,21 @@ namespace {
{ {
to = pop_1st_bit(&b); to = pop_1st_bit(&b);
if (Type == MV_CAPTURE || Type == MV_EVASION) if (Type == MV_CAPTURE || Type == MV_EVASION || Type == MV_NON_EVASION)
(*mlist++).move = make_promotion_move(to - Delta, to, QUEEN); (*mlist++).move = make_promotion(to - Delta, to, QUEEN);
if (Type == MV_NON_CAPTURE || Type == MV_EVASION) if (Type == MV_NON_CAPTURE || Type == MV_EVASION || Type == MV_NON_EVASION)
{ {
(*mlist++).move = make_promotion_move(to - Delta, to, ROOK); (*mlist++).move = make_promotion(to - Delta, to, ROOK);
(*mlist++).move = make_promotion_move(to - Delta, to, BISHOP); (*mlist++).move = make_promotion(to - Delta, to, BISHOP);
(*mlist++).move = make_promotion_move(to - Delta, to, KNIGHT); (*mlist++).move = make_promotion(to - Delta, to, KNIGHT);
} }
// This is the only possible under promotion that can give a check // This is the only possible under promotion that can give a check
// not already included in the queen-promotion. // not already included in the queen-promotion.
if ( Type == MV_CHECK if ( Type == MV_CHECK
&& bit_is_set(pos.attacks_from<KNIGHT>(to), pos.king_square(Delta > 0 ? BLACK : WHITE))) && bit_is_set(pos.attacks_from<KNIGHT>(to), pos.king_square(Delta > 0 ? BLACK : WHITE)))
(*mlist++).move = make_promotion_move(to - Delta, to, KNIGHT); (*mlist++).move = make_promotion(to - Delta, to, KNIGHT);
else (void)pos; // Silence a warning under MSVC else (void)pos; // Silence a warning under MSVC
} }
return mlist; return mlist;
@@ -435,10 +428,10 @@ namespace {
} }
// Standard captures // Standard captures
if (Type == MV_CAPTURE || Type == MV_EVASION) if (Type == MV_CAPTURE || Type == MV_EVASION || Type == MV_NON_EVASION)
{ {
mlist = generate_pawn_captures<Type, RIGHT_UP>(mlist, pawns, enemyPieces); mlist = generate_pawn_captures<RIGHT_UP>(mlist, pawns, enemyPieces);
mlist = generate_pawn_captures<Type, LEFT_UP>(mlist, pawns, enemyPieces); mlist = generate_pawn_captures<LEFT_UP>(mlist, pawns, enemyPieces);
} }
// Single and double pawn pushes // Single and double pawn pushes
@@ -470,7 +463,8 @@ namespace {
} }
// En passant captures // En passant captures
if ((Type == MV_CAPTURE || Type == MV_EVASION) && pos.ep_square() != SQ_NONE) if ( (Type == MV_CAPTURE || Type == MV_EVASION || Type == MV_NON_EVASION)
&& pos.ep_square() != SQ_NONE)
{ {
assert(Us != WHITE || rank_of(pos.ep_square()) == RANK_6); assert(Us != WHITE || rank_of(pos.ep_square()) == RANK_6);
assert(Us != BLACK || rank_of(pos.ep_square()) == RANK_3); assert(Us != BLACK || rank_of(pos.ep_square()) == RANK_3);
@@ -488,7 +482,7 @@ namespace {
while (b1) while (b1)
{ {
to = pop_1st_bit(&b1); to = pop_1st_bit(&b1);
(*mlist++).move = make_enpassant_move(to, pos.ep_square()); (*mlist++).move = make_enpassant(to, pos.ep_square());
} }
} }
return mlist; return mlist;
@@ -535,7 +529,7 @@ namespace {
return mlist; return mlist;
} }
(*mlist++).move = make_castle_move(kfrom, rfrom); (*mlist++).move = make_castle(kfrom, rfrom);
return mlist; return mlist;
} }

View File

@@ -254,8 +254,8 @@ void MovePicker::score_captures() {
for (MoveStack* cur = moves; cur != lastMove; cur++) for (MoveStack* cur = moves; cur != lastMove; cur++)
{ {
m = cur->move; m = cur->move;
cur->score = PieceValueMidgame[pos.piece_on(move_to(m))] cur->score = PieceValueMidgame[pos.piece_on(to_sq(m))]
- type_of(pos.piece_on(move_from(m))); - type_of(pos.piece_on(from_sq(m)));
if (is_promotion(m)) if (is_promotion(m))
cur->score += PieceValueMidgame[Piece(promotion_piece_type(m))]; cur->score += PieceValueMidgame[Piece(promotion_piece_type(m))];
@@ -270,8 +270,8 @@ void MovePicker::score_noncaptures() {
for (MoveStack* cur = moves; cur != lastMove; cur++) for (MoveStack* cur = moves; cur != lastMove; cur++)
{ {
m = cur->move; m = cur->move;
from = move_from(m); from = from_sq(m);
cur->score = H.value(pos.piece_on(from), move_to(m)); cur->score = H.value(pos.piece_on(from), to_sq(m));
} }
} }
@@ -293,10 +293,10 @@ void MovePicker::score_evasions() {
if ((seeScore = pos.see_sign(m)) < 0) if ((seeScore = pos.see_sign(m)) < 0)
cur->score = seeScore - History::MaxValue; // Be sure we are at the bottom cur->score = seeScore - History::MaxValue; // Be sure we are at the bottom
else if (pos.is_capture(m)) else if (pos.is_capture(m))
cur->score = PieceValueMidgame[pos.piece_on(move_to(m))] cur->score = PieceValueMidgame[pos.piece_on(to_sq(m))]
- type_of(pos.piece_on(move_from(m))) + History::MaxValue; - type_of(pos.piece_on(from_sq(m))) + History::MaxValue;
else else
cur->score = H.value(pos.piece_on(move_from(m)), move_to(m)); cur->score = H.value(pos.piece_on(from_sq(m)), to_sq(m));
} }
} }
@@ -378,7 +378,7 @@ Move MovePicker::next_move() {
case PH_QRECAPTURES: case PH_QRECAPTURES:
move = (curMove++)->move; move = (curMove++)->move;
if (move_to(move) == recaptureSquare) if (to_sq(move) == recaptureSquare)
return move; return move;
break; break;

View File

@@ -420,8 +420,8 @@ bool Position::move_attacks_square(Move m, Square s) const {
assert(square_is_ok(s)); assert(square_is_ok(s));
Bitboard occ, xray; Bitboard occ, xray;
Square from = move_from(m); Square from = from_sq(m);
Square to = move_to(m); Square to = to_sq(m);
Piece piece = piece_on(from); Piece piece = piece_on(from);
assert(!square_is_empty(from)); assert(!square_is_empty(from));
@@ -451,7 +451,7 @@ bool Position::pl_move_is_legal(Move m, Bitboard pinned) const {
assert(pinned == pinned_pieces()); assert(pinned == pinned_pieces());
Color us = side_to_move(); Color us = side_to_move();
Square from = move_from(m); Square from = from_sq(m);
assert(color_of(piece_on(from)) == us); assert(color_of(piece_on(from)) == us);
assert(piece_on(king_square(us)) == make_piece(us, KING)); assert(piece_on(king_square(us)) == make_piece(us, KING));
@@ -462,7 +462,7 @@ bool Position::pl_move_is_legal(Move m, Bitboard pinned) const {
if (is_enpassant(m)) if (is_enpassant(m))
{ {
Color them = flip(us); Color them = flip(us);
Square to = move_to(m); Square to = to_sq(m);
Square capsq = to + pawn_push(them); Square capsq = to + pawn_push(them);
Square ksq = king_square(us); Square ksq = king_square(us);
Bitboard b = occupied_squares(); Bitboard b = occupied_squares();
@@ -484,13 +484,13 @@ bool Position::pl_move_is_legal(Move m, Bitboard pinned) const {
// square is attacked by the opponent. Castling moves are checked // square is attacked by the opponent. Castling moves are checked
// for legality during move generation. // for legality during move generation.
if (type_of(piece_on(from)) == KING) if (type_of(piece_on(from)) == KING)
return is_castle(m) || !(attackers_to(move_to(m)) & pieces(flip(us))); return is_castle(m) || !(attackers_to(to_sq(m)) & pieces(flip(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 !pinned return !pinned
|| !bit_is_set(pinned, from) || !bit_is_set(pinned, from)
|| squares_aligned(from, move_to(m), king_square(us)); || squares_aligned(from, to_sq(m), king_square(us));
} }
@@ -516,8 +516,8 @@ bool Position::is_pseudo_legal(const Move m) const {
Color us = sideToMove; Color us = sideToMove;
Color them = flip(sideToMove); Color them = flip(sideToMove);
Square from = move_from(m); Square from = from_sq(m);
Square to = move_to(m); Square to = to_sq(m);
Piece pc = piece_on(from); Piece pc = piece_on(from);
// Use a slower but simpler function for uncommon cases // Use a slower but simpler function for uncommon cases
@@ -613,7 +613,7 @@ bool Position::is_pseudo_legal(const Move m) const {
{ {
Bitboard b = occupied_squares(); Bitboard b = occupied_squares();
clear_bit(&b, from); clear_bit(&b, from);
if (attackers_to(move_to(m), b) & pieces(flip(us))) if (attackers_to(to_sq(m), b) & pieces(flip(us)))
return false; return false;
} }
else else
@@ -626,7 +626,7 @@ bool Position::is_pseudo_legal(const Move m) const {
// Our move must be a blocking evasion or a capture of the checking piece // Our move must be a blocking evasion or a capture of the checking piece
target = squares_between(checksq, king_square(us)) | checkers(); target = squares_between(checksq, king_square(us)) | checkers();
if (!bit_is_set(target, move_to(m))) if (!bit_is_set(target, to_sq(m)))
return false; return false;
} }
} }
@@ -641,10 +641,10 @@ bool Position::move_gives_check(Move m, const CheckInfo& ci) const {
assert(is_ok(m)); assert(is_ok(m));
assert(ci.dcCandidates == discovered_check_candidates()); assert(ci.dcCandidates == discovered_check_candidates());
assert(color_of(piece_on(move_from(m))) == side_to_move()); assert(color_of(piece_on(from_sq(m))) == side_to_move());
Square from = move_from(m); Square from = from_sq(m);
Square to = move_to(m); Square to = to_sq(m);
PieceType pt = type_of(piece_on(from)); PieceType pt = type_of(piece_on(from));
// Direct check ? // Direct check ?
@@ -766,8 +766,8 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI
Color us = side_to_move(); Color us = side_to_move();
Color them = flip(us); Color them = flip(us);
Square from = move_from(m); Square from = from_sq(m);
Square to = move_to(m); Square to = to_sq(m);
Piece piece = piece_on(from); Piece piece = piece_on(from);
PieceType pt = type_of(piece); PieceType pt = type_of(piece);
PieceType capture = is_enpassant(m) ? PAWN : type_of(piece_on(to)); PieceType capture = is_enpassant(m) ? PAWN : type_of(piece_on(to));
@@ -982,8 +982,8 @@ void Position::undo_move(Move m) {
Color us = side_to_move(); Color us = side_to_move();
Color them = flip(us); Color them = flip(us);
Square from = move_from(m); Square from = from_sq(m);
Square to = move_to(m); Square to = to_sq(m);
Piece piece = piece_on(to); Piece piece = piece_on(to);
PieceType pt = type_of(piece); PieceType pt = type_of(piece);
PieceType capture = st->capturedType; PieceType capture = st->capturedType;
@@ -1077,8 +1077,8 @@ void Position::do_castle_move(Move m) {
Square kto, kfrom, rfrom, rto, kAfter, rAfter; Square kto, kfrom, rfrom, rto, kAfter, rAfter;
Color us = side_to_move(); Color us = side_to_move();
Square kBefore = move_from(m); Square kBefore = from_sq(m);
Square rBefore = move_to(m); Square rBefore = to_sq(m);
// Find after-castle squares for king and rook // Find after-castle squares for king and rook
if (rBefore > kBefore) // O-O if (rBefore > kBefore) // O-O
@@ -1228,8 +1228,8 @@ int Position::see_sign(Move m) const {
assert(is_ok(m)); assert(is_ok(m));
Square from = move_from(m); Square from = from_sq(m);
Square to = move_to(m); Square to = to_sq(m);
// Early return if SEE cannot be negative because captured piece value // Early return if SEE cannot be negative because captured piece value
// is not less then capturing one. Note that king moves always return // is not less then capturing one. Note that king moves always return
@@ -1256,8 +1256,8 @@ int Position::see(Move m) const {
if (is_castle(m)) if (is_castle(m))
return 0; return 0;
from = move_from(m); from = from_sq(m);
to = move_to(m); to = to_sq(m);
capturedType = type_of(piece_on(to)); capturedType = type_of(piece_on(to));
occ = occupied_squares(); occ = occupied_squares();

View File

@@ -428,8 +428,8 @@ inline Value Position::non_pawn_material(Color c) const {
inline bool Position::is_passed_pawn_push(Move m) const { inline bool Position::is_passed_pawn_push(Move m) const {
return board[move_from(m)] == make_piece(sideToMove, PAWN) return board[from_sq(m)] == make_piece(sideToMove, PAWN)
&& pawn_is_passed(sideToMove, move_to(m)); && pawn_is_passed(sideToMove, to_sq(m));
} }
inline int Position::startpos_ply_counter() const { inline int Position::startpos_ply_counter() const {
@@ -454,14 +454,14 @@ inline bool Position::is_chess960() const {
inline bool Position::is_capture_or_promotion(Move m) const { inline bool Position::is_capture_or_promotion(Move m) const {
assert(is_ok(m)); assert(is_ok(m));
return is_special(m) ? !is_castle(m) : !square_is_empty(move_to(m)); return is_special(m) ? !is_castle(m) : !square_is_empty(to_sq(m));
} }
inline bool Position::is_capture(Move m) const { inline bool Position::is_capture(Move m) const {
// Note that castle is coded as "king captures the rook" // Note that castle is coded as "king captures the rook"
assert(is_ok(m)); assert(is_ok(m));
return (!square_is_empty(move_to(m)) && !is_castle(m)) || is_enpassant(m); return (!square_is_empty(to_sq(m)) && !is_castle(m)) || is_enpassant(m);
} }
inline PieceType Position::captured_piece_type() const { inline PieceType Position::captured_piece_type() const {

View File

@@ -139,6 +139,9 @@ namespace {
// better than the second best move. // better than the second best move.
const Value EasyMoveMargin = Value(0x150); const Value EasyMoveMargin = Value(0x150);
// This is the minimum interval in msec between two check_time() calls
const int TimerResolution = 5;
/// Namespace variables /// Namespace variables
@@ -197,19 +200,19 @@ namespace {
FORCE_INLINE bool is_dangerous(const Position& pos, Move m, bool captureOrPromotion) { FORCE_INLINE bool is_dangerous(const Position& pos, Move m, bool captureOrPromotion) {
// Test for a pawn pushed to 7th or a passed pawn move // Test for a pawn pushed to 7th or a passed pawn move
if (type_of(pos.piece_on(move_from(m))) == PAWN) if (type_of(pos.piece_on(from_sq(m))) == PAWN)
{ {
Color c = pos.side_to_move(); Color c = pos.side_to_move();
if ( relative_rank(c, move_to(m)) == RANK_7 if ( relative_rank(c, to_sq(m)) == RANK_7
|| pos.pawn_is_passed(c, move_to(m))) || pos.pawn_is_passed(c, to_sq(m)))
return true; return true;
} }
// Test for a capture that triggers a pawn endgame // Test for a capture that triggers a pawn endgame
if ( captureOrPromotion if ( captureOrPromotion
&& type_of(pos.piece_on(move_to(m))) != PAWN && type_of(pos.piece_on(to_sq(m))) != PAWN
&& ( pos.non_pawn_material(WHITE) + pos.non_pawn_material(BLACK) && ( pos.non_pawn_material(WHITE) + pos.non_pawn_material(BLACK)
- PieceValueMidgame[pos.piece_on(move_to(m))] == VALUE_ZERO) - PieceValueMidgame[pos.piece_on(to_sq(m))] == VALUE_ZERO)
&& !is_special(m)) && !is_special(m))
return true; return true;
@@ -290,22 +293,17 @@ void Search::think() {
// Populate RootMoves with all the legal moves (default) or, if a SearchMoves // Populate RootMoves with all the legal moves (default) or, if a SearchMoves
// is given, with the subset of legal moves to search. // is given, with the subset of legal moves to search.
for (MoveList<MV_LEGAL> ml(pos); !ml.end(); ++ml) for (MoveList<MV_LEGAL> ml(pos); !ml.end(); ++ml)
if ( SearchMoves.empty() if (SearchMoves.empty() || count(SearchMoves.begin(), SearchMoves.end(), ml.move()))
|| count(SearchMoves.begin(), SearchMoves.end(), ml.move()))
RootMoves.push_back(RootMove(ml.move())); RootMoves.push_back(RootMove(ml.move()));
if (Options["OwnBook"]) if (Options["OwnBook"])
{ {
if (book.name() != (string)Options["Book File"]) Move bookMove = book.probe(pos, Options["Book File"], Options["Best Book Move"]);
book.open(Options["Book File"]);
Move bookMove = book.probe(pos, Options["Best Book Move"]); if (bookMove && count(RootMoves.begin(), RootMoves.end(), bookMove))
if ( bookMove != MOVE_NONE
&& count(RootMoves.begin(), RootMoves.end(), bookMove))
{ {
std::swap(RootMoves[0], *find(RootMoves.begin(), RootMoves.end(), bookMove)); std::swap(RootMoves[0], *find(RootMoves.begin(), RootMoves.end(), bookMove));
goto finish; goto finalize;
} }
} }
@@ -348,8 +346,8 @@ void Search::think() {
// Set best timer interval to avoid lagging under time pressure. Timer is // Set best timer interval to avoid lagging under time pressure. Timer is
// used to check for remaining available thinking time. // used to check for remaining available thinking time.
if (TimeMgr.available_time()) if (Limits.use_time_management())
Threads.set_timer(std::min(100, std::max(TimeMgr.available_time() / 8, 20))); Threads.set_timer(std::min(100, std::max(TimeMgr.available_time() / 16, TimerResolution)));
else else
Threads.set_timer(100); Threads.set_timer(100);
@@ -375,7 +373,7 @@ void Search::think() {
pos.undo_move(RootMoves[0].pv[0]); pos.undo_move(RootMoves[0].pv[0]);
} }
finish: finalize:
// When we reach max depth we arrive here even without a StopRequest, but if // When we reach max depth we arrive here even without a StopRequest, but if
// we are pondering or in infinite search, we shouldn't print the best move // we are pondering or in infinite search, we shouldn't print the best move
@@ -518,7 +516,7 @@ namespace {
bestMoveNeverChanged = false; bestMoveNeverChanged = false;
// Do we have time for the next iteration? Can we stop searching now? // Do we have time for the next iteration? Can we stop searching now?
if (!Signals.stop && !Signals.stopOnPonderhit && Limits.useTimeManagement()) if (!Signals.stop && !Signals.stopOnPonderhit && Limits.use_time_management())
{ {
bool stop = false; // Local variable, not the volatile Signals.stop bool stop = false; // Local variable, not the volatile Signals.stop
@@ -706,7 +704,7 @@ namespace {
&& pos.captured_piece_type() == NO_PIECE_TYPE && pos.captured_piece_type() == NO_PIECE_TYPE
&& !is_special(move)) && !is_special(move))
{ {
Square to = move_to(move); Square to = to_sq(move);
H.update_gain(pos.piece_on(to), to, -(ss-1)->eval - ss->eval); H.update_gain(pos.piece_on(to), to, -(ss-1)->eval - ss->eval);
} }
@@ -870,7 +868,8 @@ split_point_start: // At split points actual search starts from here
// Loop through all pseudo-legal moves until no moves remain or a beta cutoff occurs // Loop through all pseudo-legal moves until no moves remain or a beta cutoff occurs
while ( bestValue < beta while ( bestValue < beta
&& (move = mp.next_move()) != MOVE_NONE && (move = mp.next_move()) != MOVE_NONE
&& !thread.cutoff_occurred()) && !thread.cutoff_occurred()
&& !Signals.stop)
{ {
assert(is_ok(move)); assert(is_ok(move));
@@ -971,7 +970,7 @@ split_point_start: // At split points actual search starts from here
// but fixing this made program slightly weaker. // but fixing this made program slightly weaker.
Depth predictedDepth = newDepth - reduction<PvNode>(depth, moveCount); Depth predictedDepth = newDepth - reduction<PvNode>(depth, moveCount);
futilityValue = futilityBase + futility_margin(predictedDepth, moveCount) futilityValue = futilityBase + futility_margin(predictedDepth, moveCount)
+ H.gain(pos.piece_on(move_from(move)), move_to(move)); + H.gain(pos.piece_on(from_sq(move)), to_sq(move));
if (futilityValue < beta) if (futilityValue < beta)
{ {
@@ -1155,13 +1154,13 @@ split_point_start: // At split points actual search starts from here
// Increase history value of the cut-off move // Increase history value of the cut-off move
Value bonus = Value(int(depth) * int(depth)); Value bonus = Value(int(depth) * int(depth));
H.add(pos.piece_on(move_from(move)), move_to(move), bonus); H.add(pos.piece_on(from_sq(move)), to_sq(move), bonus);
// Decrease history of all the other played non-capture moves // Decrease history of all the other played non-capture moves
for (int i = 0; i < playedMoveCount - 1; i++) for (int i = 0; i < playedMoveCount - 1; i++)
{ {
Move m = movesSearched[i]; Move m = movesSearched[i];
H.add(pos.piece_on(move_from(m)), move_to(m), -bonus); H.add(pos.piece_on(from_sq(m)), to_sq(m), -bonus);
} }
} }
} }
@@ -1267,7 +1266,7 @@ split_point_start: // At split points actual search starts from here
// to search the moves. Because the depth is <= 0 here, only captures, // to search the moves. Because the depth is <= 0 here, only captures,
// queen promotions and checks (only if depth >= DEPTH_QS_CHECKS) will // queen promotions and checks (only if depth >= DEPTH_QS_CHECKS) will
// be generated. // be generated.
MovePicker mp(pos, ttMove, depth, H, move_to((ss-1)->currentMove)); MovePicker mp(pos, ttMove, depth, H, to_sq((ss-1)->currentMove));
CheckInfo ci(pos); CheckInfo ci(pos);
// Loop through the moves until no moves remain or a beta cutoff occurs // Loop through the moves until no moves remain or a beta cutoff occurs
@@ -1288,7 +1287,7 @@ split_point_start: // At split points actual search starts from here
&& !pos.is_passed_pawn_push(move)) && !pos.is_passed_pawn_push(move))
{ {
futilityValue = futilityBase futilityValue = futilityBase
+ PieceValueEndgame[pos.piece_on(move_to(move))] + PieceValueEndgame[pos.piece_on(to_sq(move))]
+ (is_enpassant(move) ? PawnValueEndgame : VALUE_ZERO); + (is_enpassant(move) ? PawnValueEndgame : VALUE_ZERO);
if (futilityValue < beta) if (futilityValue < beta)
@@ -1392,8 +1391,8 @@ split_point_start: // At split points actual search starts from here
Color them; Color them;
Value futilityValue, bv = *bestValue; Value futilityValue, bv = *bestValue;
from = move_from(move); from = from_sq(move);
to = move_to(move); to = to_sq(move);
them = flip(pos.side_to_move()); them = flip(pos.side_to_move());
ksq = pos.king_square(them); ksq = pos.king_square(them);
kingAtt = pos.attacks_from<KING>(ksq); kingAtt = pos.attacks_from<KING>(ksq);
@@ -1453,14 +1452,14 @@ split_point_start: // At split points actual search starts from here
assert(is_ok(m2)); assert(is_ok(m2));
// Case 1: The moving piece is the same in both moves // Case 1: The moving piece is the same in both moves
f2 = move_from(m2); f2 = from_sq(m2);
t1 = move_to(m1); t1 = to_sq(m1);
if (f2 == t1) if (f2 == t1)
return true; return true;
// Case 2: The destination square for m2 was vacated by m1 // Case 2: The destination square for m2 was vacated by m1
t2 = move_to(m2); t2 = to_sq(m2);
f1 = move_from(m1); f1 = from_sq(m1);
if (t2 == f1) if (t2 == f1)
return true; return true;
@@ -1533,10 +1532,10 @@ split_point_start: // At split points actual search starts from here
Square mfrom, mto, tfrom, tto; Square mfrom, mto, tfrom, tto;
mfrom = move_from(m); mfrom = from_sq(m);
mto = move_to(m); mto = to_sq(m);
tfrom = move_from(threat); tfrom = from_sq(threat);
tto = move_to(threat); tto = to_sq(threat);
// Case 1: Don't prune moves which move the threatened piece // Case 1: Don't prune moves which move the threatened piece
if (mfrom == tto) if (mfrom == tto)
@@ -1962,11 +1961,11 @@ void Thread::idle_loop(SplitPoint* sp) {
} }
/// do_timer_event() is called by the timer thread when the timer triggers. It /// check_time() is called by the timer thread when the timer triggers. It is
/// is used to print debug info and, more important, to detect when we are out of /// used to print debug info and, more important, to detect when we are out of
/// available time and so stop the search. /// available time and so stop the search.
void do_timer_event() { void check_time() {
static int lastInfoTime; static int lastInfoTime;
int e = elapsed_time(); int e = elapsed_time();
@@ -1984,10 +1983,10 @@ void do_timer_event() {
&& !Signals.failedLowAtRoot && !Signals.failedLowAtRoot
&& e > TimeMgr.available_time(); && e > TimeMgr.available_time();
bool noMoreTime = e > TimeMgr.maximum_time() bool noMoreTime = e > TimeMgr.maximum_time() - 2 * TimerResolution
|| stillAtFirstMove; || stillAtFirstMove;
if ( (Limits.useTimeManagement() && noMoreTime) if ( (Limits.use_time_management() && noMoreTime)
|| (Limits.maxTime && e >= Limits.maxTime) || (Limits.maxTime && e >= Limits.maxTime)
/* missing nodes limit */ ) // FIXME /* missing nodes limit */ ) // FIXME
Signals.stop = true; Signals.stop = true;

View File

@@ -55,7 +55,7 @@ struct Stack {
struct LimitsType { struct LimitsType {
LimitsType() { memset(this, 0, sizeof(LimitsType)); } LimitsType() { memset(this, 0, sizeof(LimitsType)); }
bool useTimeManagement() const { return !(maxTime | maxDepth | maxNodes | infinite); } bool use_time_management() const { return !(maxTime | maxDepth | maxNodes | infinite); }
int time, increment, movesToGo, maxTime, maxDepth, maxNodes, infinite, ponder; int time, increment, movesToGo, maxTime, maxDepth, maxNodes, infinite, ponder;
}; };

View File

@@ -172,7 +172,7 @@ void ThreadsManager::init() {
for (int i = 0; i <= MAX_THREADS; i++) for (int i = 0; i <= MAX_THREADS; i++)
{ {
threads[i].is_searching = false; threads[i].is_searching = false;
threads[i].do_sleep = true; threads[i].do_sleep = (i != 0); // Avoid a race with start_thinking()
threads[i].threadID = i; threads[i].threadID = i;
#if defined(_MSC_VER) #if defined(_MSC_VER)
@@ -202,7 +202,7 @@ void ThreadsManager::exit() {
// Wait for thread termination // Wait for thread termination
#if defined(_MSC_VER) #if defined(_MSC_VER)
WaitForSingleObject(threads[i].handle, 0); WaitForSingleObject(threads[i].handle, INFINITE);
CloseHandle(threads[i].handle); CloseHandle(threads[i].handle);
#else #else
pthread_join(threads[i].handle, NULL); pthread_join(threads[i].handle, NULL);
@@ -367,7 +367,7 @@ template Value ThreadsManager::split<true>(Position&, Stack*, Value, Value, Valu
// Thread::timer_loop() is where the timer thread waits maxPly milliseconds and // Thread::timer_loop() is where the timer thread waits maxPly milliseconds and
// then calls do_timer_event(). If maxPly is 0 thread sleeps until is woken up. // then calls do_timer_event(). If maxPly is 0 thread sleeps until is woken up.
extern void do_timer_event(); extern void check_time();
void Thread::timer_loop() { void Thread::timer_loop() {
@@ -376,7 +376,7 @@ void Thread::timer_loop() {
lock_grab(&sleepLock); lock_grab(&sleepLock);
timed_wait(&sleepCond, &sleepLock, maxPly ? maxPly : INT_MAX); timed_wait(&sleepCond, &sleepLock, maxPly ? maxPly : INT_MAX);
lock_release(&sleepLock); lock_release(&sleepLock);
do_timer_event(); check_time();
} }
} }
@@ -452,6 +452,7 @@ void ThreadsManager::start_thinking(const Position& pos, const LimitsType& limit
cond_signal(&main.sleepCond); // Wake up main thread and start searching cond_signal(&main.sleepCond); // Wake up main thread and start searching
if (!asyncMode) if (!asyncMode)
while (!main.do_sleep)
cond_wait(&sleepCond, &main.sleepLock); cond_wait(&sleepCond, &main.sleepLock);
lock_release(&main.sleepLock); lock_release(&main.sleepLock);

View File

@@ -432,11 +432,11 @@ inline Square pawn_push(Color c) {
return c == WHITE ? DELTA_N : DELTA_S; return c == WHITE ? DELTA_N : DELTA_S;
} }
inline Square move_from(Move m) { inline Square from_sq(Move m) {
return Square((m >> 6) & 0x3F); return Square((m >> 6) & 0x3F);
} }
inline Square move_to(Move m) { inline Square to_sq(Move m) {
return Square(m & 0x3F); return Square(m & 0x3F);
} }
@@ -464,20 +464,20 @@ inline Move make_move(Square from, Square to) {
return Move(to | (from << 6)); return Move(to | (from << 6));
} }
inline Move make_promotion_move(Square from, Square to, PieceType promotion) { inline Move make_promotion(Square from, Square to, PieceType pt) {
return Move(to | (from << 6) | (1 << 14) | ((promotion - 2) << 12)) ; return Move(to | (from << 6) | (1 << 14) | ((pt - 2) << 12)) ;
} }
inline Move make_enpassant_move(Square from, Square to) { inline Move make_enpassant(Square from, Square to) {
return Move(to | (from << 6) | (2 << 14)); return Move(to | (from << 6) | (2 << 14));
} }
inline Move make_castle_move(Square from, Square to) { inline Move make_castle(Square from, Square to) {
return Move(to | (from << 6) | (3 << 14)); return Move(to | (from << 6) | (3 << 14));
} }
inline bool is_ok(Move m) { inline bool is_ok(Move m) {
return move_from(m) != move_to(m); // Catches also MOVE_NULL and MOVE_NONE return from_sq(m) != to_sq(m); // Catches also MOVE_NULL and MOVE_NONE
} }
#include <string> #include <string>