mirror of
https://github.com/sockspls/badfish
synced 2025-04-30 00:33:09 +00:00
Change the Move enum to a class
This changes the Move enum to a class, this way all move related functions can be moved into the class and be more self contained. closes https://github.com/official-stockfish/Stockfish/pull/4958 No functional change
This commit is contained in:
parent
28f8663f39
commit
cafbe8e8e8
12 changed files with 241 additions and 222 deletions
|
@ -34,13 +34,13 @@ ExtMove* make_promotions(ExtMove* moveList, [[maybe_unused]] Square to) {
|
||||||
constexpr bool all = Type == EVASIONS || Type == NON_EVASIONS;
|
constexpr bool all = Type == EVASIONS || Type == NON_EVASIONS;
|
||||||
|
|
||||||
if constexpr (Type == CAPTURES || all)
|
if constexpr (Type == CAPTURES || all)
|
||||||
*moveList++ = make<PROMOTION>(to - D, to, QUEEN);
|
*moveList++ = Move::make<PROMOTION>(to - D, to, QUEEN);
|
||||||
|
|
||||||
if constexpr ((Type == CAPTURES && Enemy) || (Type == QUIETS && !Enemy) || all)
|
if constexpr ((Type == CAPTURES && Enemy) || (Type == QUIETS && !Enemy) || all)
|
||||||
{
|
{
|
||||||
*moveList++ = make<PROMOTION>(to - D, to, ROOK);
|
*moveList++ = Move::make<PROMOTION>(to - D, to, ROOK);
|
||||||
*moveList++ = make<PROMOTION>(to - D, to, BISHOP);
|
*moveList++ = Move::make<PROMOTION>(to - D, to, BISHOP);
|
||||||
*moveList++ = make<PROMOTION>(to - D, to, KNIGHT);
|
*moveList++ = Move::make<PROMOTION>(to - D, to, KNIGHT);
|
||||||
}
|
}
|
||||||
|
|
||||||
return moveList;
|
return moveList;
|
||||||
|
@ -89,13 +89,13 @@ ExtMove* generate_pawn_moves(const Position& pos, ExtMove* moveList, Bitboard ta
|
||||||
while (b1)
|
while (b1)
|
||||||
{
|
{
|
||||||
Square to = pop_lsb(b1);
|
Square to = pop_lsb(b1);
|
||||||
*moveList++ = make_move(to - Up, to);
|
*moveList++ = Move(to - Up, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (b2)
|
while (b2)
|
||||||
{
|
{
|
||||||
Square to = pop_lsb(b2);
|
Square to = pop_lsb(b2);
|
||||||
*moveList++ = make_move(to - Up - Up, to);
|
*moveList++ = Move(to - Up - Up, to);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,13 +128,13 @@ ExtMove* generate_pawn_moves(const Position& pos, ExtMove* moveList, Bitboard ta
|
||||||
while (b1)
|
while (b1)
|
||||||
{
|
{
|
||||||
Square to = pop_lsb(b1);
|
Square to = pop_lsb(b1);
|
||||||
*moveList++ = make_move(to - UpRight, to);
|
*moveList++ = Move(to - UpRight, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (b2)
|
while (b2)
|
||||||
{
|
{
|
||||||
Square to = pop_lsb(b2);
|
Square to = pop_lsb(b2);
|
||||||
*moveList++ = make_move(to - UpLeft, to);
|
*moveList++ = Move(to - UpLeft, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pos.ep_square() != SQ_NONE)
|
if (pos.ep_square() != SQ_NONE)
|
||||||
|
@ -150,7 +150,7 @@ ExtMove* generate_pawn_moves(const Position& pos, ExtMove* moveList, Bitboard ta
|
||||||
assert(b1);
|
assert(b1);
|
||||||
|
|
||||||
while (b1)
|
while (b1)
|
||||||
*moveList++ = make<EN_PASSANT>(pop_lsb(b1), pos.ep_square());
|
*moveList++ = Move::make<EN_PASSANT>(pop_lsb(b1), pos.ep_square());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,7 +175,7 @@ ExtMove* generate_moves(const Position& pos, ExtMove* moveList, Bitboard target)
|
||||||
b &= pos.check_squares(Pt);
|
b &= pos.check_squares(Pt);
|
||||||
|
|
||||||
while (b)
|
while (b)
|
||||||
*moveList++ = make_move(from, pop_lsb(b));
|
*moveList++ = Move(from, pop_lsb(b));
|
||||||
}
|
}
|
||||||
|
|
||||||
return moveList;
|
return moveList;
|
||||||
|
@ -213,12 +213,12 @@ ExtMove* generate_all(const Position& pos, ExtMove* moveList) {
|
||||||
b &= ~attacks_bb<QUEEN>(pos.square<KING>(~Us));
|
b &= ~attacks_bb<QUEEN>(pos.square<KING>(~Us));
|
||||||
|
|
||||||
while (b)
|
while (b)
|
||||||
*moveList++ = make_move(ksq, pop_lsb(b));
|
*moveList++ = Move(ksq, pop_lsb(b));
|
||||||
|
|
||||||
if ((Type == QUIETS || Type == NON_EVASIONS) && pos.can_castle(Us & ANY_CASTLING))
|
if ((Type == QUIETS || Type == NON_EVASIONS) && pos.can_castle(Us & ANY_CASTLING))
|
||||||
for (CastlingRights cr : {Us & KING_SIDE, Us & QUEEN_SIDE})
|
for (CastlingRights cr : {Us & KING_SIDE, Us & QUEEN_SIDE})
|
||||||
if (!pos.castling_impeded(cr) && pos.can_castle(cr))
|
if (!pos.castling_impeded(cr) && pos.can_castle(cr))
|
||||||
*moveList++ = make<CASTLING>(ksq, pos.castling_rook_square(cr));
|
*moveList++ = Move::make<CASTLING>(ksq, pos.castling_rook_square(cr));
|
||||||
}
|
}
|
||||||
|
|
||||||
return moveList;
|
return moveList;
|
||||||
|
@ -268,9 +268,9 @@ ExtMove* generate<LEGAL>(const Position& pos, ExtMove* moveList) {
|
||||||
moveList =
|
moveList =
|
||||||
pos.checkers() ? generate<EVASIONS>(pos, moveList) : generate<NON_EVASIONS>(pos, moveList);
|
pos.checkers() ? generate<EVASIONS>(pos, moveList) : generate<NON_EVASIONS>(pos, moveList);
|
||||||
while (cur != moveList)
|
while (cur != moveList)
|
||||||
if (((pinned & from_sq(*cur)) || from_sq(*cur) == ksq || type_of(*cur) == EN_PASSANT)
|
if (((pinned & cur->from_sq()) || cur->from_sq() == ksq || cur->type_of() == EN_PASSANT)
|
||||||
&& !pos.legal(*cur))
|
&& !pos.legal(*cur))
|
||||||
*cur = (--moveList)->move;
|
*cur = *(--moveList);
|
||||||
else
|
else
|
||||||
++cur;
|
++cur;
|
||||||
|
|
||||||
|
|
|
@ -37,12 +37,10 @@ enum GenType {
|
||||||
LEGAL
|
LEGAL
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ExtMove {
|
struct ExtMove: public Move {
|
||||||
Move move;
|
|
||||||
int value;
|
int value;
|
||||||
|
|
||||||
operator Move() const { return move; }
|
void operator=(Move m) { data = m.raw(); }
|
||||||
void operator=(Move m) { move = m; }
|
|
||||||
|
|
||||||
// Inhibit unwanted implicit conversions to Move
|
// Inhibit unwanted implicit conversions to Move
|
||||||
// with an ambiguity that yields to a compile error.
|
// with an ambiguity that yields to a compile error.
|
||||||
|
|
|
@ -166,19 +166,19 @@ void MovePicker::score() {
|
||||||
for (auto& m : *this)
|
for (auto& m : *this)
|
||||||
if constexpr (Type == CAPTURES)
|
if constexpr (Type == CAPTURES)
|
||||||
m.value =
|
m.value =
|
||||||
(7 * int(PieceValue[pos.piece_on(to_sq(m))])
|
(7 * int(PieceValue[pos.piece_on(m.to_sq())])
|
||||||
+ (*captureHistory)[pos.moved_piece(m)][to_sq(m)][type_of(pos.piece_on(to_sq(m)))])
|
+ (*captureHistory)[pos.moved_piece(m)][m.to_sq()][type_of(pos.piece_on(m.to_sq()))])
|
||||||
/ 16;
|
/ 16;
|
||||||
|
|
||||||
else if constexpr (Type == QUIETS)
|
else if constexpr (Type == QUIETS)
|
||||||
{
|
{
|
||||||
Piece pc = pos.moved_piece(m);
|
Piece pc = pos.moved_piece(m);
|
||||||
PieceType pt = type_of(pos.moved_piece(m));
|
PieceType pt = type_of(pos.moved_piece(m));
|
||||||
Square from = from_sq(m);
|
Square from = m.from_sq();
|
||||||
Square to = to_sq(m);
|
Square to = m.to_sq();
|
||||||
|
|
||||||
// histories
|
// histories
|
||||||
m.value = 2 * (*mainHistory)[pos.side_to_move()][from_to(m)];
|
m.value = 2 * (*mainHistory)[pos.side_to_move()][m.from_to()];
|
||||||
m.value += 2 * (*pawnHistory)[pawn_structure_index(pos)][pc][to];
|
m.value += 2 * (*pawnHistory)[pawn_structure_index(pos)][pc][to];
|
||||||
m.value += 2 * (*continuationHistory[0])[pc][to];
|
m.value += 2 * (*continuationHistory[0])[pc][to];
|
||||||
m.value += (*continuationHistory[1])[pc][to];
|
m.value += (*continuationHistory[1])[pc][to];
|
||||||
|
@ -211,12 +211,12 @@ void MovePicker::score() {
|
||||||
else // Type == EVASIONS
|
else // Type == EVASIONS
|
||||||
{
|
{
|
||||||
if (pos.capture_stage(m))
|
if (pos.capture_stage(m))
|
||||||
m.value = PieceValue[pos.piece_on(to_sq(m))] - Value(type_of(pos.moved_piece(m)))
|
m.value = PieceValue[pos.piece_on(m.to_sq())] - Value(type_of(pos.moved_piece(m)))
|
||||||
+ (1 << 28);
|
+ (1 << 28);
|
||||||
else
|
else
|
||||||
m.value = (*mainHistory)[pos.side_to_move()][from_to(m)]
|
m.value = (*mainHistory)[pos.side_to_move()][m.from_to()]
|
||||||
+ (*continuationHistory[0])[pos.moved_piece(m)][to_sq(m)]
|
+ (*continuationHistory[0])[pos.moved_piece(m)][m.to_sq()]
|
||||||
+ (*pawnHistory)[pawn_structure_index(pos)][pos.moved_piece(m)][to_sq(m)];
|
+ (*pawnHistory)[pawn_structure_index(pos)][pos.moved_piece(m)][m.to_sq()];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,7 +235,7 @@ Move MovePicker::select(Pred filter) {
|
||||||
|
|
||||||
cur++;
|
cur++;
|
||||||
}
|
}
|
||||||
return MOVE_NONE;
|
return Move::none();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Most important method of the MovePicker class. It
|
// Most important method of the MovePicker class. It
|
||||||
|
@ -278,8 +278,7 @@ top:
|
||||||
endMoves = std::end(refutations);
|
endMoves = std::end(refutations);
|
||||||
|
|
||||||
// If the countermove is the same as a killer, skip it
|
// If the countermove is the same as a killer, skip it
|
||||||
if (refutations[0].move == refutations[2].move
|
if (refutations[0] == refutations[2] || refutations[1] == refutations[2])
|
||||||
|| refutations[1].move == refutations[2].move)
|
|
||||||
--endMoves;
|
--endMoves;
|
||||||
|
|
||||||
++stage;
|
++stage;
|
||||||
|
@ -287,7 +286,7 @@ top:
|
||||||
|
|
||||||
case REFUTATION :
|
case REFUTATION :
|
||||||
if (select<Next>([&]() {
|
if (select<Next>([&]() {
|
||||||
return *cur != MOVE_NONE && !pos.capture_stage(*cur) && pos.pseudo_legal(*cur);
|
return *cur != Move::none() && !pos.capture_stage(*cur) && pos.pseudo_legal(*cur);
|
||||||
}))
|
}))
|
||||||
return *(cur - 1);
|
return *(cur - 1);
|
||||||
++stage;
|
++stage;
|
||||||
|
@ -308,8 +307,7 @@ top:
|
||||||
|
|
||||||
case QUIET :
|
case QUIET :
|
||||||
if (!skipQuiets && select<Next>([&]() {
|
if (!skipQuiets && select<Next>([&]() {
|
||||||
return *cur != refutations[0].move && *cur != refutations[1].move
|
return *cur != refutations[0] && *cur != refutations[1] && *cur != refutations[2];
|
||||||
&& *cur != refutations[2].move;
|
|
||||||
}))
|
}))
|
||||||
return *(cur - 1);
|
return *(cur - 1);
|
||||||
|
|
||||||
|
@ -343,7 +341,7 @@ top:
|
||||||
|
|
||||||
// If we did not find any move and we do not try checks, we have finished
|
// If we did not find any move and we do not try checks, we have finished
|
||||||
if (depth != DEPTH_QS_CHECKS)
|
if (depth != DEPTH_QS_CHECKS)
|
||||||
return MOVE_NONE;
|
return Move::none();
|
||||||
|
|
||||||
++stage;
|
++stage;
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
|
@ -360,7 +358,7 @@ top:
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(false);
|
assert(false);
|
||||||
return MOVE_NONE; // Silence warning
|
return Move::none(); // Silence warning
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Stockfish
|
} // namespace Stockfish
|
||||||
|
|
|
@ -142,7 +142,7 @@ using CorrectionHistory =
|
||||||
// MovePicker class is used to pick one pseudo-legal move at a time from the
|
// MovePicker class is used to pick one pseudo-legal move at a time from the
|
||||||
// current position. The most important method is next_move(), which returns a
|
// current position. The most important method is next_move(), which returns a
|
||||||
// new pseudo-legal move each time it is called, until there are no moves left,
|
// new pseudo-legal move each time it is called, until there are no moves left,
|
||||||
// when MOVE_NONE is returned. In order to improve the efficiency of the
|
// when Move::none() is returned. In order to improve the efficiency of the
|
||||||
// alpha-beta algorithm, MovePicker attempts to return the moves which are most
|
// alpha-beta algorithm, MovePicker attempts to return the moves which are most
|
||||||
// likely to get a cut-off first.
|
// likely to get a cut-off first.
|
||||||
class MovePicker {
|
class MovePicker {
|
||||||
|
|
|
@ -140,14 +140,14 @@ void Position::init() {
|
||||||
for (Square s2 = Square(s1 + 1); s2 <= SQ_H8; ++s2)
|
for (Square s2 = Square(s1 + 1); s2 <= SQ_H8; ++s2)
|
||||||
if ((type_of(pc) != PAWN) && (attacks_bb(type_of(pc), s1, 0) & s2))
|
if ((type_of(pc) != PAWN) && (attacks_bb(type_of(pc), s1, 0) & s2))
|
||||||
{
|
{
|
||||||
Move move = make_move(s1, s2);
|
Move move = Move(s1, s2);
|
||||||
Key key = Zobrist::psq[pc][s1] ^ Zobrist::psq[pc][s2] ^ Zobrist::side;
|
Key key = Zobrist::psq[pc][s1] ^ Zobrist::psq[pc][s2] ^ Zobrist::side;
|
||||||
int i = H1(key);
|
int i = H1(key);
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
std::swap(cuckoo[i], key);
|
std::swap(cuckoo[i], key);
|
||||||
std::swap(cuckooMove[i], move);
|
std::swap(cuckooMove[i], move);
|
||||||
if (move == MOVE_NONE) // Arrived at empty slot?
|
if (move == Move::none()) // Arrived at empty slot?
|
||||||
break;
|
break;
|
||||||
i = (i == H1(key)) ? H2(key) : H1(key); // Push victim to alternative slot
|
i = (i == H1(key)) ? H2(key) : H1(key); // Push victim to alternative slot
|
||||||
}
|
}
|
||||||
|
@ -487,11 +487,11 @@ Bitboard Position::attackers_to(Square s, Bitboard occupied) const {
|
||||||
// Tests whether a pseudo-legal move is legal
|
// Tests whether a pseudo-legal move is legal
|
||||||
bool Position::legal(Move m) const {
|
bool Position::legal(Move m) const {
|
||||||
|
|
||||||
assert(is_ok(m));
|
assert(m.is_ok());
|
||||||
|
|
||||||
Color us = sideToMove;
|
Color us = sideToMove;
|
||||||
Square from = from_sq(m);
|
Square from = m.from_sq();
|
||||||
Square to = to_sq(m);
|
Square to = m.to_sq();
|
||||||
|
|
||||||
assert(color_of(moved_piece(m)) == us);
|
assert(color_of(moved_piece(m)) == us);
|
||||||
assert(piece_on(square<KING>(us)) == make_piece(us, KING));
|
assert(piece_on(square<KING>(us)) == make_piece(us, KING));
|
||||||
|
@ -499,7 +499,7 @@ bool Position::legal(Move m) const {
|
||||||
// En passant captures are a tricky special case. Because they are rather
|
// En passant captures are a tricky special case. Because they are rather
|
||||||
// uncommon, we do it simply by testing whether the king is attacked after
|
// uncommon, we do it simply by testing whether the king is attacked after
|
||||||
// the move is made.
|
// the move is made.
|
||||||
if (type_of(m) == EN_PASSANT)
|
if (m.type_of() == EN_PASSANT)
|
||||||
{
|
{
|
||||||
Square ksq = square<KING>(us);
|
Square ksq = square<KING>(us);
|
||||||
Square capsq = to - pawn_push(us);
|
Square capsq = to - pawn_push(us);
|
||||||
|
@ -516,7 +516,7 @@ bool Position::legal(Move m) const {
|
||||||
|
|
||||||
// Castling moves generation does not check if the castling path is clear of
|
// Castling moves generation does not check if the castling path is clear of
|
||||||
// enemy attacks, it is delayed at a later time: now!
|
// enemy attacks, it is delayed at a later time: now!
|
||||||
if (type_of(m) == CASTLING)
|
if (m.type_of() == CASTLING)
|
||||||
{
|
{
|
||||||
// After castling, the rook and king final positions are the same in
|
// After castling, the rook and king final positions are the same in
|
||||||
// Chess960 as they would be in standard chess.
|
// Chess960 as they would be in standard chess.
|
||||||
|
@ -529,7 +529,7 @@ bool Position::legal(Move m) const {
|
||||||
|
|
||||||
// In case of Chess960, verify if the Rook blocks some checks.
|
// In case of Chess960, verify if the Rook blocks some checks.
|
||||||
// For instance an enemy queen in SQ_A1 when castling rook is in SQ_B1.
|
// For instance an enemy queen in SQ_A1 when castling rook is in SQ_B1.
|
||||||
return !chess960 || !(blockers_for_king(us) & to_sq(m));
|
return !chess960 || !(blockers_for_king(us) & m.to_sq());
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the moving piece is a king, check whether the destination square is
|
// If the moving piece is a king, check whether the destination square is
|
||||||
|
@ -549,18 +549,18 @@ bool Position::legal(Move m) const {
|
||||||
bool Position::pseudo_legal(const Move m) const {
|
bool Position::pseudo_legal(const Move m) const {
|
||||||
|
|
||||||
Color us = sideToMove;
|
Color us = sideToMove;
|
||||||
Square from = from_sq(m);
|
Square from = m.from_sq();
|
||||||
Square to = to_sq(m);
|
Square to = m.to_sq();
|
||||||
Piece pc = moved_piece(m);
|
Piece pc = moved_piece(m);
|
||||||
|
|
||||||
// Use a slower but simpler function for uncommon cases
|
// Use a slower but simpler function for uncommon cases
|
||||||
// yet we skip the legality check of MoveList<LEGAL>().
|
// yet we skip the legality check of MoveList<LEGAL>().
|
||||||
if (type_of(m) != NORMAL)
|
if (m.type_of() != NORMAL)
|
||||||
return checkers() ? MoveList<EVASIONS>(*this).contains(m)
|
return checkers() ? MoveList<EVASIONS>(*this).contains(m)
|
||||||
: MoveList<NON_EVASIONS>(*this).contains(m);
|
: MoveList<NON_EVASIONS>(*this).contains(m);
|
||||||
|
|
||||||
// Is not a promotion, so the promotion piece must be empty
|
// Is not a promotion, so the promotion piece must be empty
|
||||||
assert(promotion_type(m) - KNIGHT == NO_PIECE_TYPE);
|
assert(m.promotion_type() - KNIGHT == NO_PIECE_TYPE);
|
||||||
|
|
||||||
// If the 'from' square is not occupied by a piece belonging to the side to
|
// If the 'from' square is not occupied by a piece belonging to the side to
|
||||||
// move, the move is obviously not legal.
|
// move, the move is obviously not legal.
|
||||||
|
@ -615,11 +615,11 @@ bool Position::pseudo_legal(const Move m) const {
|
||||||
// Tests whether a pseudo-legal move gives a check
|
// Tests whether a pseudo-legal move gives a check
|
||||||
bool Position::gives_check(Move m) const {
|
bool Position::gives_check(Move m) const {
|
||||||
|
|
||||||
assert(is_ok(m));
|
assert(m.is_ok());
|
||||||
assert(color_of(moved_piece(m)) == sideToMove);
|
assert(color_of(moved_piece(m)) == sideToMove);
|
||||||
|
|
||||||
Square from = from_sq(m);
|
Square from = m.from_sq();
|
||||||
Square to = to_sq(m);
|
Square to = m.to_sq();
|
||||||
|
|
||||||
// Is there a direct check?
|
// Is there a direct check?
|
||||||
if (check_squares(type_of(piece_on(from))) & to)
|
if (check_squares(type_of(piece_on(from))) & to)
|
||||||
|
@ -627,15 +627,15 @@ bool Position::gives_check(Move m) const {
|
||||||
|
|
||||||
// Is there a discovered check?
|
// Is there a discovered check?
|
||||||
if (blockers_for_king(~sideToMove) & from)
|
if (blockers_for_king(~sideToMove) & from)
|
||||||
return !aligned(from, to, square<KING>(~sideToMove)) || type_of(m) == CASTLING;
|
return !aligned(from, to, square<KING>(~sideToMove)) || m.type_of() == CASTLING;
|
||||||
|
|
||||||
switch (type_of(m))
|
switch (m.type_of())
|
||||||
{
|
{
|
||||||
case NORMAL :
|
case NORMAL :
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
case PROMOTION :
|
case PROMOTION :
|
||||||
return attacks_bb(promotion_type(m), to, pieces() ^ from) & square<KING>(~sideToMove);
|
return attacks_bb(m.promotion_type(), to, pieces() ^ from) & square<KING>(~sideToMove);
|
||||||
|
|
||||||
// En passant capture with check? We have already handled the case of direct
|
// En passant capture with check? We have already handled the case of direct
|
||||||
// checks and ordinary discovered check, so the only case we need to handle
|
// checks and ordinary discovered check, so the only case we need to handle
|
||||||
|
@ -664,7 +664,7 @@ bool Position::gives_check(Move m) const {
|
||||||
// moves should be filtered out before this function is called.
|
// moves should be filtered out before this function is called.
|
||||||
void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
|
void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
|
||||||
|
|
||||||
assert(is_ok(m));
|
assert(m.is_ok());
|
||||||
assert(&newSt != st);
|
assert(&newSt != st);
|
||||||
|
|
||||||
thisThread->nodes.fetch_add(1, std::memory_order_relaxed);
|
thisThread->nodes.fetch_add(1, std::memory_order_relaxed);
|
||||||
|
@ -691,16 +691,16 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
|
||||||
|
|
||||||
Color us = sideToMove;
|
Color us = sideToMove;
|
||||||
Color them = ~us;
|
Color them = ~us;
|
||||||
Square from = from_sq(m);
|
Square from = m.from_sq();
|
||||||
Square to = to_sq(m);
|
Square to = m.to_sq();
|
||||||
Piece pc = piece_on(from);
|
Piece pc = piece_on(from);
|
||||||
Piece captured = type_of(m) == EN_PASSANT ? make_piece(them, PAWN) : piece_on(to);
|
Piece captured = m.type_of() == EN_PASSANT ? make_piece(them, PAWN) : piece_on(to);
|
||||||
|
|
||||||
assert(color_of(pc) == us);
|
assert(color_of(pc) == us);
|
||||||
assert(captured == NO_PIECE || color_of(captured) == (type_of(m) != CASTLING ? them : us));
|
assert(captured == NO_PIECE || color_of(captured) == (m.type_of() != CASTLING ? them : us));
|
||||||
assert(type_of(captured) != KING);
|
assert(type_of(captured) != KING);
|
||||||
|
|
||||||
if (type_of(m) == CASTLING)
|
if (m.type_of() == CASTLING)
|
||||||
{
|
{
|
||||||
assert(pc == make_piece(us, KING));
|
assert(pc == make_piece(us, KING));
|
||||||
assert(captured == make_piece(us, ROOK));
|
assert(captured == make_piece(us, ROOK));
|
||||||
|
@ -720,7 +720,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
|
||||||
// update non-pawn material.
|
// update non-pawn material.
|
||||||
if (type_of(captured) == PAWN)
|
if (type_of(captured) == PAWN)
|
||||||
{
|
{
|
||||||
if (type_of(m) == EN_PASSANT)
|
if (m.type_of() == EN_PASSANT)
|
||||||
{
|
{
|
||||||
capsq -= pawn_push(us);
|
capsq -= pawn_push(us);
|
||||||
|
|
||||||
|
@ -771,7 +771,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move the piece. The tricky Chess960 castling is handled earlier
|
// Move the piece. The tricky Chess960 castling is handled earlier
|
||||||
if (type_of(m) != CASTLING)
|
if (m.type_of() != CASTLING)
|
||||||
{
|
{
|
||||||
dp.piece[0] = pc;
|
dp.piece[0] = pc;
|
||||||
dp.from[0] = from;
|
dp.from[0] = from;
|
||||||
|
@ -791,9 +791,9 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
|
||||||
k ^= Zobrist::enpassant[file_of(st->epSquare)];
|
k ^= Zobrist::enpassant[file_of(st->epSquare)];
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (type_of(m) == PROMOTION)
|
else if (m.type_of() == PROMOTION)
|
||||||
{
|
{
|
||||||
Piece promotion = make_piece(us, promotion_type(m));
|
Piece promotion = make_piece(us, m.promotion_type());
|
||||||
|
|
||||||
assert(relative_rank(us, to) == RANK_8);
|
assert(relative_rank(us, to) == RANK_8);
|
||||||
assert(type_of(promotion) >= KNIGHT && type_of(promotion) <= QUEEN);
|
assert(type_of(promotion) >= KNIGHT && type_of(promotion) <= QUEEN);
|
||||||
|
@ -866,22 +866,22 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
|
||||||
// be restored to exactly the same state as before the move was made.
|
// be restored to exactly the same state as before the move was made.
|
||||||
void Position::undo_move(Move m) {
|
void Position::undo_move(Move m) {
|
||||||
|
|
||||||
assert(is_ok(m));
|
assert(m.is_ok());
|
||||||
|
|
||||||
sideToMove = ~sideToMove;
|
sideToMove = ~sideToMove;
|
||||||
|
|
||||||
Color us = sideToMove;
|
Color us = sideToMove;
|
||||||
Square from = from_sq(m);
|
Square from = m.from_sq();
|
||||||
Square to = to_sq(m);
|
Square to = m.to_sq();
|
||||||
Piece pc = piece_on(to);
|
Piece pc = piece_on(to);
|
||||||
|
|
||||||
assert(empty(from) || type_of(m) == CASTLING);
|
assert(empty(from) || m.type_of() == CASTLING);
|
||||||
assert(type_of(st->capturedPiece) != KING);
|
assert(type_of(st->capturedPiece) != KING);
|
||||||
|
|
||||||
if (type_of(m) == PROMOTION)
|
if (m.type_of() == PROMOTION)
|
||||||
{
|
{
|
||||||
assert(relative_rank(us, to) == RANK_8);
|
assert(relative_rank(us, to) == RANK_8);
|
||||||
assert(type_of(pc) == promotion_type(m));
|
assert(type_of(pc) == m.promotion_type());
|
||||||
assert(type_of(pc) >= KNIGHT && type_of(pc) <= QUEEN);
|
assert(type_of(pc) >= KNIGHT && type_of(pc) <= QUEEN);
|
||||||
|
|
||||||
remove_piece(to);
|
remove_piece(to);
|
||||||
|
@ -889,7 +889,7 @@ void Position::undo_move(Move m) {
|
||||||
put_piece(pc, to);
|
put_piece(pc, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type_of(m) == CASTLING)
|
if (m.type_of() == CASTLING)
|
||||||
{
|
{
|
||||||
Square rfrom, rto;
|
Square rfrom, rto;
|
||||||
do_castling<false>(us, from, to, rfrom, rto);
|
do_castling<false>(us, from, to, rfrom, rto);
|
||||||
|
@ -902,7 +902,7 @@ void Position::undo_move(Move m) {
|
||||||
{
|
{
|
||||||
Square capsq = to;
|
Square capsq = to;
|
||||||
|
|
||||||
if (type_of(m) == EN_PASSANT)
|
if (m.type_of() == EN_PASSANT)
|
||||||
{
|
{
|
||||||
capsq -= pawn_push(us);
|
capsq -= pawn_push(us);
|
||||||
|
|
||||||
|
@ -1011,8 +1011,8 @@ void Position::undo_null_move() {
|
||||||
// en passant and promotions.
|
// en passant and promotions.
|
||||||
Key Position::key_after(Move m) const {
|
Key Position::key_after(Move m) const {
|
||||||
|
|
||||||
Square from = from_sq(m);
|
Square from = m.from_sq();
|
||||||
Square to = to_sq(m);
|
Square to = m.to_sq();
|
||||||
Piece pc = piece_on(from);
|
Piece pc = piece_on(from);
|
||||||
Piece captured = piece_on(to);
|
Piece captured = piece_on(to);
|
||||||
Key k = st->key ^ Zobrist::side;
|
Key k = st->key ^ Zobrist::side;
|
||||||
|
@ -1031,13 +1031,13 @@ Key Position::key_after(Move m) const {
|
||||||
// algorithm similar to alpha-beta pruning with a null window.
|
// algorithm similar to alpha-beta pruning with a null window.
|
||||||
bool Position::see_ge(Move m, Value threshold) const {
|
bool Position::see_ge(Move m, Value threshold) const {
|
||||||
|
|
||||||
assert(is_ok(m));
|
assert(m.is_ok());
|
||||||
|
|
||||||
// Only deal with normal moves, assume others pass a simple SEE
|
// Only deal with normal moves, assume others pass a simple SEE
|
||||||
if (type_of(m) != NORMAL)
|
if (m.type_of() != NORMAL)
|
||||||
return VALUE_ZERO >= threshold;
|
return VALUE_ZERO >= threshold;
|
||||||
|
|
||||||
Square from = from_sq(m), to = to_sq(m);
|
Square from = m.from_sq(), to = m.to_sq();
|
||||||
|
|
||||||
int swap = PieceValue[piece_on(to)] - threshold;
|
int swap = PieceValue[piece_on(to)] - threshold;
|
||||||
if (swap < 0)
|
if (swap < 0)
|
||||||
|
@ -1182,8 +1182,8 @@ bool Position::has_game_cycle(int ply) const {
|
||||||
if ((j = H1(moveKey), cuckoo[j] == moveKey) || (j = H2(moveKey), cuckoo[j] == moveKey))
|
if ((j = H1(moveKey), cuckoo[j] == moveKey) || (j = H2(moveKey), cuckoo[j] == moveKey))
|
||||||
{
|
{
|
||||||
Move move = cuckooMove[j];
|
Move move = cuckooMove[j];
|
||||||
Square s1 = from_sq(move);
|
Square s1 = move.from_sq();
|
||||||
Square s2 = to_sq(move);
|
Square s2 = move.to_sq();
|
||||||
|
|
||||||
if (!((between_bb(s1, s2) ^ s2) & pieces()))
|
if (!((between_bb(s1, s2) ^ s2) & pieces()))
|
||||||
{
|
{
|
||||||
|
|
|
@ -210,7 +210,7 @@ inline Piece Position::piece_on(Square s) const {
|
||||||
|
|
||||||
inline bool Position::empty(Square s) const { return piece_on(s) == NO_PIECE; }
|
inline bool Position::empty(Square s) const { return piece_on(s) == NO_PIECE; }
|
||||||
|
|
||||||
inline Piece Position::moved_piece(Move m) const { return piece_on(from_sq(m)); }
|
inline Piece Position::moved_piece(Move m) const { return piece_on(m.from_sq()); }
|
||||||
|
|
||||||
inline Bitboard Position::pieces(PieceType pt) const { return byTypeBB[pt]; }
|
inline Bitboard Position::pieces(PieceType pt) const { return byTypeBB[pt]; }
|
||||||
|
|
||||||
|
@ -312,16 +312,16 @@ inline int Position::rule50_count() const { return st->rule50; }
|
||||||
inline bool Position::is_chess960() const { return chess960; }
|
inline bool Position::is_chess960() const { return chess960; }
|
||||||
|
|
||||||
inline bool Position::capture(Move m) const {
|
inline bool Position::capture(Move m) const {
|
||||||
assert(is_ok(m));
|
assert(m.is_ok());
|
||||||
return (!empty(to_sq(m)) && type_of(m) != CASTLING) || type_of(m) == EN_PASSANT;
|
return (!empty(m.to_sq()) && m.type_of() != CASTLING) || m.type_of() == EN_PASSANT;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if a move is generated from the capture stage, having also
|
// Returns true if a move is generated from the capture stage, having also
|
||||||
// queen promotions covered, i.e. consistency with the capture stage move generation
|
// queen promotions covered, i.e. consistency with the capture stage move generation
|
||||||
// is needed to avoid the generation of duplicate moves.
|
// is needed to avoid the generation of duplicate moves.
|
||||||
inline bool Position::capture_stage(Move m) const {
|
inline bool Position::capture_stage(Move m) const {
|
||||||
assert(is_ok(m));
|
assert(m.is_ok());
|
||||||
return capture(m) || promotion_type(m) == QUEEN;
|
return capture(m) || m.promotion_type() == QUEEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Piece Position::captured_piece() const { return st->capturedPiece; }
|
inline Piece Position::captured_piece() const { return st->capturedPiece; }
|
||||||
|
|
148
src/search.cpp
148
src/search.cpp
|
@ -130,7 +130,7 @@ struct Skill {
|
||||||
Move pick_best(size_t multiPV);
|
Move pick_best(size_t multiPV);
|
||||||
|
|
||||||
double level;
|
double level;
|
||||||
Move best = MOVE_NONE;
|
Move best = Move::none();
|
||||||
};
|
};
|
||||||
|
|
||||||
template<NodeType nodeType>
|
template<NodeType nodeType>
|
||||||
|
@ -226,7 +226,7 @@ void MainThread::search() {
|
||||||
|
|
||||||
if (rootMoves.empty())
|
if (rootMoves.empty())
|
||||||
{
|
{
|
||||||
rootMoves.emplace_back(MOVE_NONE);
|
rootMoves.emplace_back(Move::none());
|
||||||
sync_cout << "info depth 0 score "
|
sync_cout << "info depth 0 score "
|
||||||
<< UCI::value(rootPos.checkers() ? -VALUE_MATE : VALUE_DRAW) << sync_endl;
|
<< UCI::value(rootPos.checkers() ? -VALUE_MATE : VALUE_DRAW) << sync_endl;
|
||||||
}
|
}
|
||||||
|
@ -262,7 +262,7 @@ void MainThread::search() {
|
||||||
Skill(Options["Skill Level"], Options["UCI_LimitStrength"] ? int(Options["UCI_Elo"]) : 0);
|
Skill(Options["Skill Level"], Options["UCI_LimitStrength"] ? int(Options["UCI_Elo"]) : 0);
|
||||||
|
|
||||||
if (int(Options["MultiPV"]) == 1 && !Limits.depth && !skill.enabled()
|
if (int(Options["MultiPV"]) == 1 && !Limits.depth && !skill.enabled()
|
||||||
&& rootMoves[0].pv[0] != MOVE_NONE)
|
&& rootMoves[0].pv[0] != Move::none())
|
||||||
bestThread = Threads.get_best_thread();
|
bestThread = Threads.get_best_thread();
|
||||||
|
|
||||||
bestPreviousScore = bestThread->rootMoves[0].score;
|
bestPreviousScore = bestThread->rootMoves[0].score;
|
||||||
|
@ -293,7 +293,7 @@ void Thread::search() {
|
||||||
Stack stack[MAX_PLY + 10], *ss = stack + 7;
|
Stack stack[MAX_PLY + 10], *ss = stack + 7;
|
||||||
Move pv[MAX_PLY + 1];
|
Move pv[MAX_PLY + 1];
|
||||||
Value alpha, beta, delta;
|
Value alpha, beta, delta;
|
||||||
Move lastBestMove = MOVE_NONE;
|
Move lastBestMove = Move::none();
|
||||||
Depth lastBestMoveDepth = 0;
|
Depth lastBestMoveDepth = 0;
|
||||||
MainThread* mainThread = (this == Threads.main() ? Threads.main() : nullptr);
|
MainThread* mainThread = (this == Threads.main() ? Threads.main() : nullptr);
|
||||||
double timeReduction = 1, totBestMoveChanges = 0;
|
double timeReduction = 1, totBestMoveChanges = 0;
|
||||||
|
@ -604,11 +604,11 @@ Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, boo
|
||||||
|
|
||||||
assert(0 <= ss->ply && ss->ply < MAX_PLY);
|
assert(0 <= ss->ply && ss->ply < MAX_PLY);
|
||||||
|
|
||||||
(ss + 1)->excludedMove = bestMove = MOVE_NONE;
|
(ss + 1)->excludedMove = bestMove = Move::none();
|
||||||
(ss + 2)->killers[0] = (ss + 2)->killers[1] = MOVE_NONE;
|
(ss + 2)->killers[0] = (ss + 2)->killers[1] = Move::none();
|
||||||
(ss + 2)->cutoffCnt = 0;
|
(ss + 2)->cutoffCnt = 0;
|
||||||
ss->doubleExtensions = (ss - 1)->doubleExtensions;
|
ss->doubleExtensions = (ss - 1)->doubleExtensions;
|
||||||
Square prevSq = is_ok((ss - 1)->currentMove) ? to_sq((ss - 1)->currentMove) : SQ_NONE;
|
Square prevSq = ((ss - 1)->currentMove).is_ok() ? ((ss - 1)->currentMove).to_sq() : SQ_NONE;
|
||||||
ss->statScore = 0;
|
ss->statScore = 0;
|
||||||
|
|
||||||
// Step 4. Transposition table lookup.
|
// Step 4. Transposition table lookup.
|
||||||
|
@ -618,7 +618,7 @@ Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, boo
|
||||||
ttValue = ss->ttHit ? value_from_tt(tte->value(), ss->ply, pos.rule50_count()) : VALUE_NONE;
|
ttValue = ss->ttHit ? value_from_tt(tte->value(), ss->ply, pos.rule50_count()) : VALUE_NONE;
|
||||||
ttMove = rootNode ? thisThread->rootMoves[thisThread->pvIdx].pv[0]
|
ttMove = rootNode ? thisThread->rootMoves[thisThread->pvIdx].pv[0]
|
||||||
: ss->ttHit ? tte->move()
|
: ss->ttHit ? tte->move()
|
||||||
: MOVE_NONE;
|
: Move::none();
|
||||||
ttCapture = ttMove && pos.capture_stage(ttMove);
|
ttCapture = ttMove && pos.capture_stage(ttMove);
|
||||||
|
|
||||||
// At this point, if excluded, skip straight to step 6, static eval. However,
|
// At this point, if excluded, skip straight to step 6, static eval. However,
|
||||||
|
@ -650,8 +650,8 @@ Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, boo
|
||||||
else if (!ttCapture)
|
else if (!ttCapture)
|
||||||
{
|
{
|
||||||
int penalty = -stat_malus(depth);
|
int penalty = -stat_malus(depth);
|
||||||
thisThread->mainHistory[us][from_to(ttMove)] << penalty;
|
thisThread->mainHistory[us][ttMove.from_to()] << penalty;
|
||||||
update_continuation_histories(ss, pos.moved_piece(ttMove), to_sq(ttMove), penalty);
|
update_continuation_histories(ss, pos.moved_piece(ttMove), ttMove.to_sq(), penalty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -699,7 +699,7 @@ Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, boo
|
||||||
if (b == BOUND_EXACT || (b == BOUND_LOWER ? value >= beta : value <= alpha))
|
if (b == BOUND_EXACT || (b == BOUND_LOWER ? value >= beta : value <= alpha))
|
||||||
{
|
{
|
||||||
tte->save(posKey, value_to_tt(value, ss->ply), ss->ttPv, b,
|
tte->save(posKey, value_to_tt(value, ss->ply), ss->ttPv, b,
|
||||||
std::min(MAX_PLY - 1, depth + 6), MOVE_NONE, VALUE_NONE);
|
std::min(MAX_PLY - 1, depth + 6), Move::none(), VALUE_NONE);
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
@ -764,17 +764,17 @@ Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, boo
|
||||||
ss->staticEval = eval = to_static_eval(newEval);
|
ss->staticEval = eval = to_static_eval(newEval);
|
||||||
|
|
||||||
// Static evaluation is saved as it was before adjustment by correction history
|
// Static evaluation is saved as it was before adjustment by correction history
|
||||||
tte->save(posKey, VALUE_NONE, ss->ttPv, BOUND_NONE, DEPTH_NONE, MOVE_NONE,
|
tte->save(posKey, VALUE_NONE, ss->ttPv, BOUND_NONE, DEPTH_NONE, Move::none(),
|
||||||
unadjustedStaticEval);
|
unadjustedStaticEval);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use static evaluation difference to improve quiet move ordering (~9 Elo)
|
// Use static evaluation difference to improve quiet move ordering (~9 Elo)
|
||||||
if (is_ok((ss - 1)->currentMove) && !(ss - 1)->inCheck && !priorCapture)
|
if (((ss - 1)->currentMove).is_ok() && !(ss - 1)->inCheck && !priorCapture)
|
||||||
{
|
{
|
||||||
int bonus = std::clamp(-13 * int((ss - 1)->staticEval + ss->staticEval), -1652, 1546);
|
int bonus = std::clamp(-13 * int((ss - 1)->staticEval + ss->staticEval), -1652, 1546);
|
||||||
bonus = bonus > 0 ? 2 * bonus : bonus / 2;
|
bonus = bonus > 0 ? 2 * bonus : bonus / 2;
|
||||||
thisThread->mainHistory[~us][from_to((ss - 1)->currentMove)] << bonus;
|
thisThread->mainHistory[~us][((ss - 1)->currentMove).from_to()] << bonus;
|
||||||
if (type_of(pos.piece_on(prevSq)) != PAWN && type_of((ss - 1)->currentMove) != PROMOTION)
|
if (type_of(pos.piece_on(prevSq)) != PAWN && ((ss - 1)->currentMove).type_of() != PROMOTION)
|
||||||
thisThread->pawnHistory[pawn_structure_index(pos)][pos.piece_on(prevSq)][prevSq]
|
thisThread->pawnHistory[pawn_structure_index(pos)][pos.piece_on(prevSq)][prevSq]
|
||||||
<< bonus / 4;
|
<< bonus / 4;
|
||||||
}
|
}
|
||||||
|
@ -810,9 +810,9 @@ Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, boo
|
||||||
return beta > VALUE_TB_LOSS_IN_MAX_PLY ? (eval + beta) / 2 : eval;
|
return beta > VALUE_TB_LOSS_IN_MAX_PLY ? (eval + beta) / 2 : eval;
|
||||||
|
|
||||||
// Step 9. Null move search with verification search (~35 Elo)
|
// Step 9. Null move search with verification search (~35 Elo)
|
||||||
if (!PvNode && (ss - 1)->currentMove != MOVE_NULL && (ss - 1)->statScore < 17496 && eval >= beta
|
if (!PvNode && (ss - 1)->currentMove != Move::null() && (ss - 1)->statScore < 17496
|
||||||
&& eval >= ss->staticEval && ss->staticEval >= beta - 23 * depth + 304 && !excludedMove
|
&& eval >= beta && eval >= ss->staticEval && ss->staticEval >= beta - 23 * depth + 304
|
||||||
&& pos.non_pawn_material(us) && ss->ply >= thisThread->nmpMinPly
|
&& !excludedMove && pos.non_pawn_material(us) && ss->ply >= thisThread->nmpMinPly
|
||||||
&& beta > VALUE_TB_LOSS_IN_MAX_PLY)
|
&& beta > VALUE_TB_LOSS_IN_MAX_PLY)
|
||||||
{
|
{
|
||||||
assert(eval - beta >= 0);
|
assert(eval - beta >= 0);
|
||||||
|
@ -820,7 +820,7 @@ Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, boo
|
||||||
// Null move dynamic reduction based on depth and eval
|
// Null move dynamic reduction based on depth and eval
|
||||||
Depth R = std::min(int(eval - beta) / 144, 6) + depth / 3 + 4;
|
Depth R = std::min(int(eval - beta) / 144, 6) + depth / 3 + 4;
|
||||||
|
|
||||||
ss->currentMove = MOVE_NULL;
|
ss->currentMove = Move::null();
|
||||||
ss->continuationHistory = &thisThread->continuationHistory[0][0][NO_PIECE][0];
|
ss->continuationHistory = &thisThread->continuationHistory[0][0][NO_PIECE][0];
|
||||||
|
|
||||||
pos.do_null_move(st);
|
pos.do_null_move(st);
|
||||||
|
@ -883,7 +883,7 @@ Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, boo
|
||||||
|
|
||||||
MovePicker mp(pos, ttMove, probCutBeta - ss->staticEval, &captureHistory);
|
MovePicker mp(pos, ttMove, probCutBeta - ss->staticEval, &captureHistory);
|
||||||
|
|
||||||
while ((move = mp.next_move()) != MOVE_NONE)
|
while ((move = mp.next_move()) != Move::none())
|
||||||
if (move != excludedMove && pos.legal(move))
|
if (move != excludedMove && pos.legal(move))
|
||||||
{
|
{
|
||||||
assert(pos.capture_stage(move));
|
assert(pos.capture_stage(move));
|
||||||
|
@ -894,7 +894,7 @@ Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, boo
|
||||||
ss->currentMove = move;
|
ss->currentMove = move;
|
||||||
ss->continuationHistory =
|
ss->continuationHistory =
|
||||||
&thisThread
|
&thisThread
|
||||||
->continuationHistory[ss->inCheck][true][pos.moved_piece(move)][to_sq(move)];
|
->continuationHistory[ss->inCheck][true][pos.moved_piece(move)][move.to_sq()];
|
||||||
|
|
||||||
pos.do_move(move, st);
|
pos.do_move(move, st);
|
||||||
|
|
||||||
|
@ -938,7 +938,7 @@ moves_loop: // When in check, search starts here
|
||||||
(ss - 6)->continuationHistory};
|
(ss - 6)->continuationHistory};
|
||||||
|
|
||||||
Move countermove =
|
Move countermove =
|
||||||
prevSq != SQ_NONE ? thisThread->counterMoves[pos.piece_on(prevSq)][prevSq] : MOVE_NONE;
|
prevSq != SQ_NONE ? thisThread->counterMoves[pos.piece_on(prevSq)][prevSq] : Move::none();
|
||||||
|
|
||||||
MovePicker mp(pos, ttMove, depth, &thisThread->mainHistory, &captureHistory, contHist,
|
MovePicker mp(pos, ttMove, depth, &thisThread->mainHistory, &captureHistory, contHist,
|
||||||
&thisThread->pawnHistory, countermove, ss->killers);
|
&thisThread->pawnHistory, countermove, ss->killers);
|
||||||
|
@ -953,9 +953,9 @@ moves_loop: // When in check, search starts here
|
||||||
|
|
||||||
// Step 13. Loop through all pseudo-legal moves until no moves remain
|
// Step 13. Loop through all pseudo-legal moves until no moves remain
|
||||||
// or a beta cutoff occurs.
|
// or a beta cutoff occurs.
|
||||||
while ((move = mp.next_move(moveCountPruning)) != MOVE_NONE)
|
while ((move = mp.next_move(moveCountPruning)) != Move::none())
|
||||||
{
|
{
|
||||||
assert(is_ok(move));
|
assert(move.is_ok());
|
||||||
|
|
||||||
if (move == excludedMove)
|
if (move == excludedMove)
|
||||||
continue;
|
continue;
|
||||||
|
@ -1009,10 +1009,10 @@ moves_loop: // When in check, search starts here
|
||||||
// Futility pruning for captures (~2 Elo)
|
// Futility pruning for captures (~2 Elo)
|
||||||
if (!givesCheck && lmrDepth < 7 && !ss->inCheck)
|
if (!givesCheck && lmrDepth < 7 && !ss->inCheck)
|
||||||
{
|
{
|
||||||
Piece capturedPiece = pos.piece_on(to_sq(move));
|
Piece capturedPiece = pos.piece_on(move.to_sq());
|
||||||
int futilityEval =
|
int futilityEval =
|
||||||
ss->staticEval + 238 + 305 * lmrDepth + PieceValue[capturedPiece]
|
ss->staticEval + 238 + 305 * lmrDepth + PieceValue[capturedPiece]
|
||||||
+ captureHistory[movedPiece][to_sq(move)][type_of(capturedPiece)] / 7;
|
+ captureHistory[movedPiece][move.to_sq()][type_of(capturedPiece)] / 7;
|
||||||
if (futilityEval < alpha)
|
if (futilityEval < alpha)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -1024,15 +1024,16 @@ moves_loop: // When in check, search starts here
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int history =
|
int history =
|
||||||
(*contHist[0])[movedPiece][to_sq(move)] + (*contHist[1])[movedPiece][to_sq(move)]
|
(*contHist[0])[movedPiece][move.to_sq()]
|
||||||
+ (*contHist[3])[movedPiece][to_sq(move)]
|
+ (*contHist[1])[movedPiece][move.to_sq()]
|
||||||
+ thisThread->pawnHistory[pawn_structure_index(pos)][movedPiece][to_sq(move)];
|
+ (*contHist[3])[movedPiece][move.to_sq()]
|
||||||
|
+ thisThread->pawnHistory[pawn_structure_index(pos)][movedPiece][move.to_sq()];
|
||||||
|
|
||||||
// Continuation history based pruning (~2 Elo)
|
// Continuation history based pruning (~2 Elo)
|
||||||
if (lmrDepth < 6 && history < -3752 * depth)
|
if (lmrDepth < 6 && history < -3752 * depth)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
history += 2 * thisThread->mainHistory[us][from_to(move)];
|
history += 2 * thisThread->mainHistory[us][move.from_to()];
|
||||||
|
|
||||||
lmrDepth += history / 7838;
|
lmrDepth += history / 7838;
|
||||||
lmrDepth = std::max(lmrDepth, -1);
|
lmrDepth = std::max(lmrDepth, -1);
|
||||||
|
@ -1077,7 +1078,7 @@ moves_loop: // When in check, search starts here
|
||||||
ss->excludedMove = move;
|
ss->excludedMove = move;
|
||||||
value =
|
value =
|
||||||
search<NonPV>(pos, ss, singularBeta - 1, singularBeta, singularDepth, cutNode);
|
search<NonPV>(pos, ss, singularBeta - 1, singularBeta, singularDepth, cutNode);
|
||||||
ss->excludedMove = MOVE_NONE;
|
ss->excludedMove = Move::none();
|
||||||
|
|
||||||
if (value < singularBeta)
|
if (value < singularBeta)
|
||||||
{
|
{
|
||||||
|
@ -1125,12 +1126,13 @@ moves_loop: // When in check, search starts here
|
||||||
|
|
||||||
// Quiet ttMove extensions (~1 Elo)
|
// Quiet ttMove extensions (~1 Elo)
|
||||||
else if (PvNode && move == ttMove && move == ss->killers[0]
|
else if (PvNode && move == ttMove && move == ss->killers[0]
|
||||||
&& (*contHist[0])[movedPiece][to_sq(move)] >= 4325)
|
&& (*contHist[0])[movedPiece][move.to_sq()] >= 4325)
|
||||||
extension = 1;
|
extension = 1;
|
||||||
|
|
||||||
// Recapture extensions (~1 Elo)
|
// Recapture extensions (~1 Elo)
|
||||||
else if (PvNode && move == ttMove && to_sq(move) == prevSq
|
else if (PvNode && move == ttMove && move.to_sq() == prevSq
|
||||||
&& captureHistory[movedPiece][to_sq(move)][type_of(pos.piece_on(to_sq(move)))]
|
&& captureHistory[movedPiece][move.to_sq()]
|
||||||
|
[type_of(pos.piece_on(move.to_sq()))]
|
||||||
> 4146)
|
> 4146)
|
||||||
extension = 1;
|
extension = 1;
|
||||||
}
|
}
|
||||||
|
@ -1145,7 +1147,7 @@ moves_loop: // When in check, search starts here
|
||||||
// Update the current move (this must be done after singular extension search)
|
// Update the current move (this must be done after singular extension search)
|
||||||
ss->currentMove = move;
|
ss->currentMove = move;
|
||||||
ss->continuationHistory =
|
ss->continuationHistory =
|
||||||
&thisThread->continuationHistory[ss->inCheck][capture][movedPiece][to_sq(move)];
|
&thisThread->continuationHistory[ss->inCheck][capture][movedPiece][move.to_sq()];
|
||||||
|
|
||||||
// Step 16. Make the move
|
// Step 16. Make the move
|
||||||
pos.do_move(move, st, givesCheck);
|
pos.do_move(move, st, givesCheck);
|
||||||
|
@ -1187,10 +1189,10 @@ moves_loop: // When in check, search starts here
|
||||||
else if (move == ttMove)
|
else if (move == ttMove)
|
||||||
r = 0;
|
r = 0;
|
||||||
|
|
||||||
ss->statScore = 2 * thisThread->mainHistory[us][from_to(move)]
|
ss->statScore = 2 * thisThread->mainHistory[us][move.from_to()]
|
||||||
+ (*contHist[0])[movedPiece][to_sq(move)]
|
+ (*contHist[0])[movedPiece][move.to_sq()]
|
||||||
+ (*contHist[1])[movedPiece][to_sq(move)]
|
+ (*contHist[1])[movedPiece][move.to_sq()]
|
||||||
+ (*contHist[3])[movedPiece][to_sq(move)] - 3817;
|
+ (*contHist[3])[movedPiece][move.to_sq()] - 3817;
|
||||||
|
|
||||||
// Decrease/increase reduction for moves with a good/bad history (~25 Elo)
|
// Decrease/increase reduction for moves with a good/bad history (~25 Elo)
|
||||||
r -= ss->statScore / 14767;
|
r -= ss->statScore / 14767;
|
||||||
|
@ -1229,7 +1231,7 @@ moves_loop: // When in check, search starts here
|
||||||
: value >= beta ? stat_bonus(newDepth)
|
: value >= beta ? stat_bonus(newDepth)
|
||||||
: 0;
|
: 0;
|
||||||
|
|
||||||
update_continuation_histories(ss, movedPiece, to_sq(move), bonus);
|
update_continuation_histories(ss, movedPiece, move.to_sq(), bonus);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1249,7 +1251,7 @@ moves_loop: // When in check, search starts here
|
||||||
if (PvNode && (moveCount == 1 || value > alpha))
|
if (PvNode && (moveCount == 1 || value > alpha))
|
||||||
{
|
{
|
||||||
(ss + 1)->pv = pv;
|
(ss + 1)->pv = pv;
|
||||||
(ss + 1)->pv[0] = MOVE_NONE;
|
(ss + 1)->pv[0] = Move::none();
|
||||||
|
|
||||||
value = -search<PV>(pos, ss + 1, -beta, -alpha, newDepth, false);
|
value = -search<PV>(pos, ss + 1, -beta, -alpha, newDepth, false);
|
||||||
}
|
}
|
||||||
|
@ -1296,7 +1298,7 @@ moves_loop: // When in check, search starts here
|
||||||
|
|
||||||
assert((ss + 1)->pv);
|
assert((ss + 1)->pv);
|
||||||
|
|
||||||
for (Move* m = (ss + 1)->pv; *m != MOVE_NONE; ++m)
|
for (Move* m = (ss + 1)->pv; *m != Move::none(); ++m)
|
||||||
rm.pv.push_back(*m);
|
rm.pv.push_back(*m);
|
||||||
|
|
||||||
// We record how often the best move has been changed in each iteration.
|
// We record how often the best move has been changed in each iteration.
|
||||||
|
@ -1375,7 +1377,7 @@ moves_loop: // When in check, search starts here
|
||||||
+ ((ss - 1)->moveCount > 10);
|
+ ((ss - 1)->moveCount > 10);
|
||||||
update_continuation_histories(ss - 1, pos.piece_on(prevSq), prevSq,
|
update_continuation_histories(ss - 1, pos.piece_on(prevSq), prevSq,
|
||||||
stat_bonus(depth) * bonus);
|
stat_bonus(depth) * bonus);
|
||||||
thisThread->mainHistory[~us][from_to((ss - 1)->currentMove)]
|
thisThread->mainHistory[~us][((ss - 1)->currentMove).from_to()]
|
||||||
<< stat_bonus(depth) * bonus / 2;
|
<< stat_bonus(depth) * bonus / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1451,11 +1453,11 @@ Value qsearch(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth) {
|
||||||
if (PvNode)
|
if (PvNode)
|
||||||
{
|
{
|
||||||
(ss + 1)->pv = pv;
|
(ss + 1)->pv = pv;
|
||||||
ss->pv[0] = MOVE_NONE;
|
ss->pv[0] = Move::none();
|
||||||
}
|
}
|
||||||
|
|
||||||
Thread* thisThread = pos.this_thread();
|
Thread* thisThread = pos.this_thread();
|
||||||
bestMove = MOVE_NONE;
|
bestMove = Move::none();
|
||||||
ss->inCheck = pos.checkers();
|
ss->inCheck = pos.checkers();
|
||||||
moveCount = 0;
|
moveCount = 0;
|
||||||
|
|
||||||
|
@ -1476,7 +1478,7 @@ Value qsearch(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth) {
|
||||||
posKey = pos.key();
|
posKey = pos.key();
|
||||||
tte = TT.probe(posKey, ss->ttHit);
|
tte = TT.probe(posKey, ss->ttHit);
|
||||||
ttValue = ss->ttHit ? value_from_tt(tte->value(), ss->ply, pos.rule50_count()) : VALUE_NONE;
|
ttValue = ss->ttHit ? value_from_tt(tte->value(), ss->ply, pos.rule50_count()) : VALUE_NONE;
|
||||||
ttMove = ss->ttHit ? tte->move() : MOVE_NONE;
|
ttMove = ss->ttHit ? tte->move() : Move::none();
|
||||||
pvHit = ss->ttHit && tte->is_pv();
|
pvHit = ss->ttHit && tte->is_pv();
|
||||||
|
|
||||||
// At non-PV nodes we check for an early TT cutoff
|
// At non-PV nodes we check for an early TT cutoff
|
||||||
|
@ -1513,7 +1515,7 @@ Value qsearch(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth) {
|
||||||
{
|
{
|
||||||
// In case of null move search, use previous static eval with a different sign
|
// In case of null move search, use previous static eval with a different sign
|
||||||
unadjustedStaticEval = ss->staticEval = bestValue =
|
unadjustedStaticEval = ss->staticEval = bestValue =
|
||||||
(ss - 1)->currentMove != MOVE_NULL ? evaluate(pos) : -(ss - 1)->staticEval;
|
(ss - 1)->currentMove != Move::null() ? evaluate(pos) : -(ss - 1)->staticEval;
|
||||||
|
|
||||||
Value newEval =
|
Value newEval =
|
||||||
ss->staticEval
|
ss->staticEval
|
||||||
|
@ -1527,7 +1529,7 @@ Value qsearch(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth) {
|
||||||
{
|
{
|
||||||
if (!ss->ttHit)
|
if (!ss->ttHit)
|
||||||
tte->save(posKey, value_to_tt(bestValue, ss->ply), false, BOUND_LOWER, DEPTH_NONE,
|
tte->save(posKey, value_to_tt(bestValue, ss->ply), false, BOUND_LOWER, DEPTH_NONE,
|
||||||
MOVE_NONE, unadjustedStaticEval);
|
Move::none(), unadjustedStaticEval);
|
||||||
|
|
||||||
return bestValue;
|
return bestValue;
|
||||||
}
|
}
|
||||||
|
@ -1545,7 +1547,7 @@ Value qsearch(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth) {
|
||||||
// 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 other checks (only if depth >= DEPTH_QS_CHECKS)
|
// queen promotions, and other checks (only if depth >= DEPTH_QS_CHECKS)
|
||||||
// will be generated.
|
// will be generated.
|
||||||
Square prevSq = is_ok((ss - 1)->currentMove) ? to_sq((ss - 1)->currentMove) : SQ_NONE;
|
Square prevSq = ((ss - 1)->currentMove).is_ok() ? ((ss - 1)->currentMove).to_sq() : SQ_NONE;
|
||||||
MovePicker mp(pos, ttMove, depth, &thisThread->mainHistory, &thisThread->captureHistory,
|
MovePicker mp(pos, ttMove, depth, &thisThread->mainHistory, &thisThread->captureHistory,
|
||||||
contHist, &thisThread->pawnHistory);
|
contHist, &thisThread->pawnHistory);
|
||||||
|
|
||||||
|
@ -1553,9 +1555,9 @@ Value qsearch(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth) {
|
||||||
|
|
||||||
// Step 5. Loop through all pseudo-legal moves until no moves remain
|
// Step 5. Loop through all pseudo-legal moves until no moves remain
|
||||||
// or a beta cutoff occurs.
|
// or a beta cutoff occurs.
|
||||||
while ((move = mp.next_move()) != MOVE_NONE)
|
while ((move = mp.next_move()) != Move::none())
|
||||||
{
|
{
|
||||||
assert(is_ok(move));
|
assert(move.is_ok());
|
||||||
|
|
||||||
// Check for legality
|
// Check for legality
|
||||||
if (!pos.legal(move))
|
if (!pos.legal(move))
|
||||||
|
@ -1570,13 +1572,13 @@ Value qsearch(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth) {
|
||||||
if (bestValue > VALUE_TB_LOSS_IN_MAX_PLY && pos.non_pawn_material(us))
|
if (bestValue > VALUE_TB_LOSS_IN_MAX_PLY && pos.non_pawn_material(us))
|
||||||
{
|
{
|
||||||
// Futility pruning and moveCount pruning (~10 Elo)
|
// Futility pruning and moveCount pruning (~10 Elo)
|
||||||
if (!givesCheck && to_sq(move) != prevSq && futilityBase > VALUE_TB_LOSS_IN_MAX_PLY
|
if (!givesCheck && move.to_sq() != prevSq && futilityBase > VALUE_TB_LOSS_IN_MAX_PLY
|
||||||
&& type_of(move) != PROMOTION)
|
&& move.type_of() != PROMOTION)
|
||||||
{
|
{
|
||||||
if (moveCount > 2)
|
if (moveCount > 2)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
futilityValue = futilityBase + PieceValue[pos.piece_on(to_sq(move))];
|
futilityValue = futilityBase + PieceValue[pos.piece_on(move.to_sq())];
|
||||||
|
|
||||||
// If static eval + value of piece we are going to capture is much lower
|
// If static eval + value of piece we are going to capture is much lower
|
||||||
// than alpha we can prune this move.
|
// than alpha we can prune this move.
|
||||||
|
@ -1610,8 +1612,8 @@ Value qsearch(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Continuation history based pruning (~3 Elo)
|
// Continuation history based pruning (~3 Elo)
|
||||||
if (!capture && (*contHist[0])[pos.moved_piece(move)][to_sq(move)] < 0
|
if (!capture && (*contHist[0])[pos.moved_piece(move)][move.to_sq()] < 0
|
||||||
&& (*contHist[1])[pos.moved_piece(move)][to_sq(move)] < 0)
|
&& (*contHist[1])[pos.moved_piece(move)][move.to_sq()] < 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Do not search moves with bad enough SEE values (~5 Elo)
|
// Do not search moves with bad enough SEE values (~5 Elo)
|
||||||
|
@ -1626,7 +1628,7 @@ Value qsearch(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth) {
|
||||||
ss->currentMove = move;
|
ss->currentMove = move;
|
||||||
ss->continuationHistory =
|
ss->continuationHistory =
|
||||||
&thisThread
|
&thisThread
|
||||||
->continuationHistory[ss->inCheck][capture][pos.moved_piece(move)][to_sq(move)];
|
->continuationHistory[ss->inCheck][capture][pos.moved_piece(move)][move.to_sq()];
|
||||||
|
|
||||||
quietCheckEvasions += !capture && ss->inCheck;
|
quietCheckEvasions += !capture && ss->inCheck;
|
||||||
|
|
||||||
|
@ -1738,9 +1740,9 @@ Value value_from_tt(Value v, int ply, int r50c) {
|
||||||
// Adds current move and appends child pv[]
|
// Adds current move and appends child pv[]
|
||||||
void update_pv(Move* pv, Move move, const Move* childPv) {
|
void update_pv(Move* pv, Move move, const Move* childPv) {
|
||||||
|
|
||||||
for (*pv++ = move; childPv && *childPv != MOVE_NONE;)
|
for (*pv++ = move; childPv && *childPv != Move::none();)
|
||||||
*pv++ = *childPv++;
|
*pv++ = *childPv++;
|
||||||
*pv = MOVE_NONE;
|
*pv = Move::none();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1775,25 +1777,25 @@ void update_all_stats(const Position& pos,
|
||||||
update_quiet_stats(pos, ss, bestMove, bestMoveBonus);
|
update_quiet_stats(pos, ss, bestMove, bestMoveBonus);
|
||||||
|
|
||||||
int pIndex = pawn_structure_index(pos);
|
int pIndex = pawn_structure_index(pos);
|
||||||
thisThread->pawnHistory[pIndex][moved_piece][to_sq(bestMove)] << quietMoveBonus;
|
thisThread->pawnHistory[pIndex][moved_piece][bestMove.to_sq()] << quietMoveBonus;
|
||||||
|
|
||||||
// Decrease stats for all non-best quiet moves
|
// Decrease stats for all non-best quiet moves
|
||||||
for (int i = 0; i < quietCount; ++i)
|
for (int i = 0; i < quietCount; ++i)
|
||||||
{
|
{
|
||||||
thisThread
|
thisThread
|
||||||
->pawnHistory[pIndex][pos.moved_piece(quietsSearched[i])][to_sq(quietsSearched[i])]
|
->pawnHistory[pIndex][pos.moved_piece(quietsSearched[i])][quietsSearched[i].to_sq()]
|
||||||
<< -quietMoveMalus;
|
<< -quietMoveMalus;
|
||||||
|
|
||||||
thisThread->mainHistory[us][from_to(quietsSearched[i])] << -quietMoveMalus;
|
thisThread->mainHistory[us][quietsSearched[i].from_to()] << -quietMoveMalus;
|
||||||
update_continuation_histories(ss, pos.moved_piece(quietsSearched[i]),
|
update_continuation_histories(ss, pos.moved_piece(quietsSearched[i]),
|
||||||
to_sq(quietsSearched[i]), -quietMoveMalus);
|
quietsSearched[i].to_sq(), -quietMoveMalus);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Increase stats for the best move in case it was a capture move
|
// Increase stats for the best move in case it was a capture move
|
||||||
captured = type_of(pos.piece_on(to_sq(bestMove)));
|
captured = type_of(pos.piece_on(bestMove.to_sq()));
|
||||||
captureHistory[moved_piece][to_sq(bestMove)][captured] << quietMoveBonus;
|
captureHistory[moved_piece][bestMove.to_sq()][captured] << quietMoveBonus;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extra penalty for a quiet early move that was not a TT move or
|
// Extra penalty for a quiet early move that was not a TT move or
|
||||||
|
@ -1808,8 +1810,8 @@ void update_all_stats(const Position& pos,
|
||||||
for (int i = 0; i < captureCount; ++i)
|
for (int i = 0; i < captureCount; ++i)
|
||||||
{
|
{
|
||||||
moved_piece = pos.moved_piece(capturesSearched[i]);
|
moved_piece = pos.moved_piece(capturesSearched[i]);
|
||||||
captured = type_of(pos.piece_on(to_sq(capturesSearched[i])));
|
captured = type_of(pos.piece_on(capturesSearched[i].to_sq()));
|
||||||
captureHistory[moved_piece][to_sq(capturesSearched[i])][captured] << -quietMoveMalus;
|
captureHistory[moved_piece][capturesSearched[i].to_sq()][captured] << -quietMoveMalus;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1823,7 +1825,7 @@ void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus) {
|
||||||
// Only update the first 2 continuation histories if we are in check
|
// Only update the first 2 continuation histories if we are in check
|
||||||
if (ss->inCheck && i > 2)
|
if (ss->inCheck && i > 2)
|
||||||
break;
|
break;
|
||||||
if (is_ok((ss - i)->currentMove))
|
if (((ss - i)->currentMove).is_ok())
|
||||||
(*(ss - i)->continuationHistory)[pc][to] << bonus / (1 + 3 * (i == 3));
|
(*(ss - i)->continuationHistory)[pc][to] << bonus / (1 + 3 * (i == 3));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1841,13 +1843,13 @@ void update_quiet_stats(const Position& pos, Stack* ss, Move move, int bonus) {
|
||||||
|
|
||||||
Color us = pos.side_to_move();
|
Color us = pos.side_to_move();
|
||||||
Thread* thisThread = pos.this_thread();
|
Thread* thisThread = pos.this_thread();
|
||||||
thisThread->mainHistory[us][from_to(move)] << bonus;
|
thisThread->mainHistory[us][move.from_to()] << bonus;
|
||||||
update_continuation_histories(ss, pos.moved_piece(move), to_sq(move), bonus);
|
update_continuation_histories(ss, pos.moved_piece(move), move.to_sq(), bonus);
|
||||||
|
|
||||||
// Update countermove history
|
// Update countermove history
|
||||||
if (is_ok((ss - 1)->currentMove))
|
if (((ss - 1)->currentMove).is_ok())
|
||||||
{
|
{
|
||||||
Square prevSq = to_sq((ss - 1)->currentMove);
|
Square prevSq = ((ss - 1)->currentMove).to_sq();
|
||||||
thisThread->counterMoves[pos.piece_on(prevSq)][prevSq] = move;
|
thisThread->counterMoves[pos.piece_on(prevSq)][prevSq] = move;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1987,7 +1989,7 @@ bool RootMove::extract_ponder_from_tt(Position& pos) {
|
||||||
|
|
||||||
assert(pv.size() == 1);
|
assert(pv.size() == 1);
|
||||||
|
|
||||||
if (pv[0] == MOVE_NONE)
|
if (pv[0] == Move::none())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
pos.do_move(pv[0], st);
|
pos.do_move(pv[0], st);
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
#include <map>
|
#include <unordered_map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ Thread::~Thread() {
|
||||||
// Reset histories, usually before a new game
|
// Reset histories, usually before a new game
|
||||||
void Thread::clear() {
|
void Thread::clear() {
|
||||||
|
|
||||||
counterMoves.fill(MOVE_NONE);
|
counterMoves.fill(Move::none());
|
||||||
mainHistory.fill(0);
|
mainHistory.fill(0);
|
||||||
captureHistory.fill(0);
|
captureHistory.fill(0);
|
||||||
pawnHistory.fill(0);
|
pawnHistory.fill(0);
|
||||||
|
@ -221,7 +221,7 @@ void ThreadPool::start_thinking(Position& pos,
|
||||||
Thread* ThreadPool::get_best_thread() const {
|
Thread* ThreadPool::get_best_thread() const {
|
||||||
|
|
||||||
Thread* bestThread = threads.front();
|
Thread* bestThread = threads.front();
|
||||||
std::map<Move, int64_t> votes;
|
std::unordered_map<Move, int64_t, Move::MoveHash> votes;
|
||||||
Value minScore = VALUE_NONE;
|
Value minScore = VALUE_NONE;
|
||||||
|
|
||||||
// Find the minimum score of all threads
|
// Find the minimum score of all threads
|
||||||
|
|
|
@ -39,7 +39,7 @@ void TTEntry::save(Key k, Value v, bool pv, Bound b, Depth d, Move m, Value ev)
|
||||||
|
|
||||||
// Preserve any existing move for the same position
|
// Preserve any existing move for the same position
|
||||||
if (m || uint16_t(k) != key16)
|
if (m || uint16_t(k) != key16)
|
||||||
move16 = uint16_t(m);
|
move16 = m;
|
||||||
|
|
||||||
// Overwrite less valuable entries (cheapest checks first)
|
// Overwrite less valuable entries (cheapest checks first)
|
||||||
if (b == BOUND_EXACT || uint16_t(k) != key16 || d - DEPTH_OFFSET + 2 * pv > depth8 - 4)
|
if (b == BOUND_EXACT || uint16_t(k) != key16 || d - DEPTH_OFFSET + 2 * pv > depth8 - 4)
|
||||||
|
|
2
src/tt.h
2
src/tt.h
|
@ -53,7 +53,7 @@ struct TTEntry {
|
||||||
uint16_t key16;
|
uint16_t key16;
|
||||||
uint8_t depth8;
|
uint8_t depth8;
|
||||||
uint8_t genBound8;
|
uint8_t genBound8;
|
||||||
uint16_t move16;
|
Move move16;
|
||||||
int16_t value16;
|
int16_t value16;
|
||||||
int16_t eval16;
|
int16_t eval16;
|
||||||
};
|
};
|
||||||
|
|
117
src/types.h
117
src/types.h
|
@ -108,30 +108,6 @@ using Bitboard = uint64_t;
|
||||||
constexpr int MAX_MOVES = 256;
|
constexpr int MAX_MOVES = 256;
|
||||||
constexpr int MAX_PLY = 246;
|
constexpr int MAX_PLY = 246;
|
||||||
|
|
||||||
// A move needs 16 bits to be stored
|
|
||||||
//
|
|
||||||
// bit 0- 5: destination square (from 0 to 63)
|
|
||||||
// bit 6-11: origin square (from 0 to 63)
|
|
||||||
// bit 12-13: promotion piece type - 2 (from KNIGHT-2 to QUEEN-2)
|
|
||||||
// bit 14-15: special move flag: promotion (1), en passant (2), castling (3)
|
|
||||||
// NOTE: en passant bit is set only when a pawn can be captured
|
|
||||||
//
|
|
||||||
// Special cases are MOVE_NONE and MOVE_NULL. We can sneak these in because in
|
|
||||||
// any normal move destination square is always different from origin square
|
|
||||||
// while MOVE_NONE and MOVE_NULL have the same origin and destination square.
|
|
||||||
|
|
||||||
enum Move : int {
|
|
||||||
MOVE_NONE,
|
|
||||||
MOVE_NULL = 65
|
|
||||||
};
|
|
||||||
|
|
||||||
enum MoveType {
|
|
||||||
NORMAL,
|
|
||||||
PROMOTION = 1 << 14,
|
|
||||||
EN_PASSANT = 2 << 14,
|
|
||||||
CASTLING = 3 << 14
|
|
||||||
};
|
|
||||||
|
|
||||||
enum Color {
|
enum Color {
|
||||||
WHITE,
|
WHITE,
|
||||||
BLACK,
|
BLACK,
|
||||||
|
@ -353,8 +329,6 @@ inline Color color_of(Piece pc) {
|
||||||
return Color(pc >> 3);
|
return Color(pc >> 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr bool is_ok(Move m) { return m != MOVE_NONE && m != MOVE_NULL; }
|
|
||||||
|
|
||||||
constexpr bool is_ok(Square s) { return s >= SQ_A1 && s <= SQ_H8; }
|
constexpr bool is_ok(Square s) { return s >= SQ_A1 && s <= SQ_H8; }
|
||||||
|
|
||||||
constexpr File file_of(Square s) { return File(s & 7); }
|
constexpr File file_of(Square s) { return File(s & 7); }
|
||||||
|
@ -369,34 +343,81 @@ constexpr Rank relative_rank(Color c, Square s) { return relative_rank(c, rank_o
|
||||||
|
|
||||||
constexpr Direction pawn_push(Color c) { return c == WHITE ? NORTH : SOUTH; }
|
constexpr Direction pawn_push(Color c) { return c == WHITE ? NORTH : SOUTH; }
|
||||||
|
|
||||||
constexpr Square from_sq(Move m) {
|
|
||||||
assert(is_ok(m));
|
|
||||||
return Square((m >> 6) & 0x3F);
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr Square to_sq(Move m) {
|
|
||||||
assert(is_ok(m));
|
|
||||||
return Square(m & 0x3F);
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr int from_to(Move m) { return m & 0xFFF; }
|
|
||||||
|
|
||||||
constexpr MoveType type_of(Move m) { return MoveType(m & (3 << 14)); }
|
|
||||||
|
|
||||||
constexpr PieceType promotion_type(Move m) { return PieceType(((m >> 12) & 3) + KNIGHT); }
|
|
||||||
|
|
||||||
constexpr Move make_move(Square from, Square to) { return Move((from << 6) + to); }
|
|
||||||
|
|
||||||
template<MoveType T>
|
|
||||||
constexpr Move make(Square from, Square to, PieceType pt = KNIGHT) {
|
|
||||||
return Move(T + ((pt - KNIGHT) << 12) + (from << 6) + to);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Based on a congruential pseudo-random number generator
|
// Based on a congruential pseudo-random number generator
|
||||||
constexpr Key make_key(uint64_t seed) {
|
constexpr Key make_key(uint64_t seed) {
|
||||||
return seed * 6364136223846793005ULL + 1442695040888963407ULL;
|
return seed * 6364136223846793005ULL + 1442695040888963407ULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
enum MoveType {
|
||||||
|
NORMAL,
|
||||||
|
PROMOTION = 1 << 14,
|
||||||
|
EN_PASSANT = 2 << 14,
|
||||||
|
CASTLING = 3 << 14
|
||||||
|
};
|
||||||
|
|
||||||
|
// A move needs 16 bits to be stored
|
||||||
|
//
|
||||||
|
// bit 0- 5: destination square (from 0 to 63)
|
||||||
|
// bit 6-11: origin square (from 0 to 63)
|
||||||
|
// bit 12-13: promotion piece type - 2 (from KNIGHT-2 to QUEEN-2)
|
||||||
|
// bit 14-15: special move flag: promotion (1), en passant (2), castling (3)
|
||||||
|
// NOTE: en passant bit is set only when a pawn can be captured
|
||||||
|
//
|
||||||
|
// Special cases are Move::none() and Move::null(). We can sneak these in because in
|
||||||
|
// any normal move destination square is always different from origin square
|
||||||
|
// while Move::none() and Move::null() have the same origin and destination square.
|
||||||
|
class Move {
|
||||||
|
public:
|
||||||
|
Move() = default;
|
||||||
|
constexpr explicit Move(std::uint16_t d) :
|
||||||
|
data(d) {}
|
||||||
|
|
||||||
|
constexpr Move(Square from, Square to) :
|
||||||
|
data((from << 6) + to) {}
|
||||||
|
|
||||||
|
template<MoveType T>
|
||||||
|
static constexpr Move make(Square from, Square to, PieceType pt = KNIGHT) {
|
||||||
|
return Move(T + ((pt - KNIGHT) << 12) + (from << 6) + to);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr Square from_sq() const {
|
||||||
|
assert(is_ok());
|
||||||
|
return Square((data >> 6) & 0x3F);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr Square to_sq() const {
|
||||||
|
assert(is_ok());
|
||||||
|
return Square(data & 0x3F);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr int from_to() const { return data & 0xFFF; }
|
||||||
|
|
||||||
|
constexpr MoveType type_of() const { return MoveType(data & (3 << 14)); }
|
||||||
|
|
||||||
|
constexpr PieceType promotion_type() const { return PieceType(((data >> 12) & 3) + KNIGHT); }
|
||||||
|
|
||||||
|
constexpr bool is_ok() const { return none().data != data && null().data != data; }
|
||||||
|
|
||||||
|
static constexpr Move null() { return Move(65); }
|
||||||
|
static constexpr Move none() { return Move(0); }
|
||||||
|
|
||||||
|
constexpr bool operator==(const Move& m) const { return data == m.data; }
|
||||||
|
constexpr bool operator!=(const Move& m) const { return data != m.data; }
|
||||||
|
|
||||||
|
constexpr explicit operator bool() const { return data != 0; }
|
||||||
|
|
||||||
|
constexpr std::uint16_t raw() const { return data; }
|
||||||
|
|
||||||
|
struct MoveHash {
|
||||||
|
std::size_t operator()(const Move& m) const { return m.data; }
|
||||||
|
};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::uint16_t data;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace Stockfish
|
} // namespace Stockfish
|
||||||
|
|
||||||
#endif // #ifndef TYPES_H_INCLUDED
|
#endif // #ifndef TYPES_H_INCLUDED
|
||||||
|
|
18
src/uci.cpp
18
src/uci.cpp
|
@ -75,7 +75,7 @@ void position(Position& pos, std::istringstream& is, StateListPtr& states) {
|
||||||
pos.set(fen, Options["UCI_Chess960"], &states->back(), Threads.main());
|
pos.set(fen, Options["UCI_Chess960"], &states->back(), Threads.main());
|
||||||
|
|
||||||
// Parse the move list, if any
|
// Parse the move list, if any
|
||||||
while (is >> token && (m = UCI::to_move(pos, token)) != MOVE_NONE)
|
while (is >> token && (m = UCI::to_move(pos, token)) != Move::none())
|
||||||
{
|
{
|
||||||
states->emplace_back();
|
states->emplace_back();
|
||||||
pos.do_move(m, states->back());
|
pos.do_move(m, states->back());
|
||||||
|
@ -395,22 +395,22 @@ std::string UCI::square(Square s) {
|
||||||
// Internally, all castling moves are always encoded as 'king captures rook'.
|
// Internally, all castling moves are always encoded as 'king captures rook'.
|
||||||
std::string UCI::move(Move m, bool chess960) {
|
std::string UCI::move(Move m, bool chess960) {
|
||||||
|
|
||||||
if (m == MOVE_NONE)
|
if (m == Move::none())
|
||||||
return "(none)";
|
return "(none)";
|
||||||
|
|
||||||
if (m == MOVE_NULL)
|
if (m == Move::null())
|
||||||
return "0000";
|
return "0000";
|
||||||
|
|
||||||
Square from = from_sq(m);
|
Square from = m.from_sq();
|
||||||
Square to = to_sq(m);
|
Square to = m.to_sq();
|
||||||
|
|
||||||
if (type_of(m) == CASTLING && !chess960)
|
if (m.type_of() == CASTLING && !chess960)
|
||||||
to = make_square(to > from ? FILE_G : FILE_C, rank_of(from));
|
to = make_square(to > from ? FILE_G : FILE_C, rank_of(from));
|
||||||
|
|
||||||
std::string move = UCI::square(from) + UCI::square(to);
|
std::string move = UCI::square(from) + UCI::square(to);
|
||||||
|
|
||||||
if (type_of(m) == PROMOTION)
|
if (m.type_of() == PROMOTION)
|
||||||
move += " pnbrqk"[promotion_type(m)];
|
move += " pnbrqk"[m.promotion_type()];
|
||||||
|
|
||||||
return move;
|
return move;
|
||||||
}
|
}
|
||||||
|
@ -427,7 +427,7 @@ Move UCI::to_move(const Position& pos, std::string& str) {
|
||||||
if (str == UCI::move(m, pos.is_chess960()))
|
if (str == UCI::move(m, pos.is_chess960()))
|
||||||
return m;
|
return m;
|
||||||
|
|
||||||
return MOVE_NONE;
|
return Move::none();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Stockfish
|
} // namespace Stockfish
|
||||||
|
|
Loading…
Add table
Reference in a new issue