You are on page 1of 33

/*

Stockfish, a UCI chess playing engine derived from Glaurung


2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord
Romstad
Stockfish is free software: you can redistribute it and/or
modify
it under the terms of the GNU General Public License as
published by
the Free Software Foundation, either version 3 of the
License, or
(at your option) any later version.
Stockfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty

of

MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.


the
GNU General Public License for more details.

See

You should have received a copy of the GNU General Public


License
along with this program. If not, see <http://www.gnu.org/
licenses/>.
*/
#include
#include
#include
#include
#include

<algorithm>
<cassert>
<cstring>
<iomanip>
<sstream>

#include
#include
#include
#include
#include
#include
#include
#include

"bitcount.h"
"movegen.h"
"notation.h"
"position.h"
"psqtab.h"
"rkiss.h"
"thread.h"
"tt.h"

using std::string;
static const string PieceToChar(" PNBRQK

pnbrqk");

CACHE_LINE_ALIGNMENT
Value PieceValue[PHASE_NB][PIECE_NB] = {
{ VALUE_ZERO, PawnValueMg, KnightValueMg, BishopValueMg,
RookValueMg, QueenValueMg },
{ VALUE_ZERO, PawnValueEg, KnightValueEg, BishopValueEg,
RookValueEg, QueenValueEg } };
static Score psq[COLOR_NB][PIECE_TYPE_NB][SQUARE_NB];
namespace Zobrist {

Key
Key
Key
Key
Key

psq[COLOR_NB][PIECE_TYPE_NB][SQUARE_NB];
enpassant[FILE_NB];
castling[CASTLING_RIGHT_NB];
side;
exclusion;

Key Position::exclusion_key() const { return st->key ^


Zobrist::exclusion;}
namespace {
// min_attacker() is a helper function used by see() to locate
the least
// valuable attacker for the side to move, remove the attacker
we just found
// from the bitboards and scan for new X-ray attacks behind
it.
template<int Pt> FORCE_INLINE
PieceType min_attacker(const Bitboard* bb, const Square& to,
const Bitboard& stmAttackers,
Bitboard& occupied, Bitboard&
attackers) {
Bitboard b = stmAttackers & bb[Pt];
if (!b)
return min_attacker<Pt+1>(bb, to, stmAttackers,
occupied, attackers);
occupied ^= b & ~(b - 1);
if (Pt == PAWN || Pt == BISHOP || Pt == QUEEN)
attackers |= attacks_bb<BISHOP>(to, occupied) &
(bb[BISHOP] | bb[QUEEN]);

if (Pt == ROOK || Pt == QUEEN)


attackers |= attacks_bb<ROOK>(to, occupied) & (bb[ROOK]
| bb[QUEEN]);
attackers &= occupied; // After X-ray that may add already
processed pieces
return (PieceType)Pt;
}
template<> FORCE_INLINE
PieceType min_attacker<KING>(const Bitboard*, const Square&,
const Bitboard&, Bitboard&, Bitboard&) {
return KING; // No need to update bitboards: it is the last
cycle
}
} // namespace
/// CheckInfo c'tor
CheckInfo::CheckInfo(const Position& pos) {
Color them = ~pos.side_to_move();
ksq = pos.king_square(them);
pinned = pos.pinned_pieces(pos.side_to_move());
dcCandidates = pos.discovered_check_candidates();

checkSq[PAWN]
checkSq[KNIGHT]
checkSq[BISHOP]
checkSq[ROOK]
checkSq[QUEEN]
checkSq[KING]

=
=
=
=
=
=

pos.attacks_from<PAWN>(ksq, them);
pos.attacks_from<KNIGHT>(ksq);
pos.attacks_from<BISHOP>(ksq);
pos.attacks_from<ROOK>(ksq);
checkSq[BISHOP] | checkSq[ROOK];
0;

/// Position::init() initializes at startup the various arrays


used to compute
/// hash keys and the piece square tables. The latter is a
two-step operation:
/// Firstly, the white halves of the tables are copied from
PSQT[] tables.
/// Secondly, the black halves of the tables are initialized
by flipping and

/// changing the sign of the white scores.


void Position::init() {
RKISS rk;
for (Color c = WHITE; c <= BLACK; ++c)
for (PieceType pt = PAWN; pt <= KING; ++pt)
for (Square s = SQ_A1; s <= SQ_H8; ++s)
Zobrist::psq[c][pt][s] = rk.rand<Key>();
for (File f = FILE_A; f <= FILE_H; ++f)
Zobrist::enpassant[f] = rk.rand<Key>();
for (int cf = NO_CASTLING; cf <= ANY_CASTLING; ++cf)
{
Bitboard b = cf;
while (b)
{
Key k = Zobrist::castling[1ULL << pop_lsb(&b)];
Zobrist::castling[cf] ^= k ? k : rk.rand<Key>();
}
}
Zobrist::side = rk.rand<Key>();
Zobrist::exclusion = rk.rand<Key>();
for (PieceType pt = PAWN; pt <= KING; ++pt)
{
PieceValue[MG][make_piece(BLACK, pt)] = PieceValue[MG]
[pt];
PieceValue[EG][make_piece(BLACK, pt)] = PieceValue[EG]
[pt];
[pt]);

Score v = make_score(PieceValue[MG][pt], PieceValue[EG]


for (Square s = SQ_A1; s <= SQ_H8; ++s)
{
psq[WHITE][pt][ s] = (v + PSQT[pt][s]);
psq[BLACK][pt][~s] = -(v + PSQT[pt][s]);
}

/// Position::operator=() creates a copy of 'pos'. We want the

new born Position


/// object to not depend on any external data so we detach
state pointer from
/// the source one.
Position& Position::operator=(const Position& pos) {
std::memcpy(this, &pos, sizeof(Position));
startState = *st;
st = &startState;
nodes = 0;
assert(pos_is_ok());
}

return *this;

/// Position::clear() erases the position object to a pristine


state, with an
/// empty board, white to move, and no castling rights.
void Position::clear() {
std::memset(this, 0, sizeof(Position));
startState.epSquare = SQ_NONE;
st = &startState;
for (int i = 0; i < PIECE_TYPE_NB; ++i)
for (int j = 0; j < 16; ++j)
pieceList[WHITE][i][j] = pieceList[BLACK][i][j] =
SQ_NONE;
}
/// Position::set() initializes the position object with the
given FEN string.
/// This function is not very robust - make sure that input
FENs are correct,
/// this is assumed to be the responsibility of the GUI.
void Position::set(const string& fenStr, bool isChess960,
Thread* th) {
/*
A FEN string defines a particular position using only the
ASCII character set.

A FEN string contains six fields separated by a space. The


fields are:
1) Piece placement (from white's perspective). Each rank is
described, starting
with rank 8 and ending with rank 1. Within each rank,
the contents of each
square are described from file A through file H.
Following the Standard
Algebraic Notation (SAN), each piece is identified by a
single letter taken
from the standard English names. White pieces are
designated using upper-case
letters ("PNBRQK") whilst Black uses lowercase
("pnbrqk"). Blank squares are
noted using digits 1 through 8 (the number of blank
squares), and "/"
separates ranks.
2) Active color. "w" means white moves next, "b" means
black.
3) Castling availability. If neither side can castle, this
is "-". Otherwise,
this has one or more letters: "K" (White can castle
kingside), "Q" (White
can castle queenside), "k" (Black can castle kingside),
and/or "q" (Black
can castle queenside).
4) En passant target square (in algebraic notation). If
there's no en passant
target square, this is "-". If a pawn has just made a 2square move, this
is the position "behind" the pawn. This is recorded
regardless of whether
there is a pawn in position to make an en passant
capture.
5) Halfmove clock. This is the number of halfmoves since
the last pawn advance
or capture. This is used to determine if a draw can be
claimed under the
fifty-move rule.
6) Fullmove number. The number of the full move. It starts
at 1, and is

*/

incremented after Black's move.


char col, row, token;
size_t idx;
Square sq = SQ_A8;
std::istringstream ss(fenStr);
clear();
ss >> std::noskipws;

// 1. Piece placement
while ((ss >> token) && !isspace(token))
{
if (isdigit(token))
sq += Square(token - '0'); // Advance the given
number of files
else if (token == '/')
sq -= Square(16);
else if ((idx = PieceToChar.find(token)) !=
string::npos)
{
put_piece(sq, color_of(Piece(idx)),
type_of(Piece(idx)));
++sq;
}
}
// 2. Active color
ss >> token;
sideToMove = (token == 'w' ? WHITE : BLACK);
ss >> token;
// 3. Castling availability. Compatible with 3 standards:
Normal FEN standard,
// Shredder-FEN that uses the letters of the columns on
which the rooks began
// the game instead of KQkq and also X-FEN standard that, in
case of Chess960,
// if an inner rook is associated with the castling right,
the castling tag is
// replaced by the file letter of the involved rook, as for
the Shredder-FEN.
while ((ss >> token) && !isspace(token))
{

Square rsq;
Color c = islower(token) ? BLACK : WHITE;
token = char(toupper(token));
if (token == 'K')
for (rsq = relative_square(c, SQ_H1);
type_of(piece_on(rsq)) != ROOK; --rsq) {}
else if (token == 'Q')
for (rsq = relative_square(c, SQ_A1);
type_of(piece_on(rsq)) != ROOK; ++rsq) {}
else if (token >= 'A' && token <= 'H')
rsq = make_square(File(token - 'A'),
relative_rank(c, RANK_1));
else

continue;

set_castling_right(c, rsq);

// 4. En passant square. Ignore if no pawn capture is


possible
if (
((ss >> col) && (col >= 'a' && col <= 'h'))
&& ((ss >> row) && (row == '3' || row == '6')))
{
st->epSquare = make_square(File(col - 'a'), Rank(row '1'));
if (!(attackers_to(st->epSquare) & pieces(sideToMove,
PAWN)))
st->epSquare = SQ_NONE;
}
// 5-6. Halfmove clock and fullmove number
ss >> std::skipws >> st->rule50 >> gamePly;
// Convert from fullmove starting from 1 to ply starting
from 0,
// handle also common incorrect FEN with fullmove = 0.
gamePly = std::max(2 * (gamePly - 1), 0) + (sideToMove ==
BLACK);
chess960 = isChess960;
thisThread = th;

set_state(st);
}

assert(pos_is_ok());

/// Position::set_castling_right() is a helper function used


to set castling
/// rights given the corresponding color and the rook starting
square.
void Position::set_castling_right(Color c, Square rfrom) {
Square kfrom = king_square(c);
CastlingSide cs = kfrom < rfrom ? KING_SIDE : QUEEN_SIDE;
CastlingRight cr = (c | cs);
st->castlingRights |= cr;
castlingRightsMask[kfrom] |= cr;
castlingRightsMask[rfrom] |= cr;
castlingRookSquare[cr] = rfrom;
Square kto = relative_square(c, cs == KING_SIDE ? SQ_G1 :
SQ_C1);
Square rto = relative_square(c, cs == KING_SIDE ? SQ_F1 :
SQ_D1);
for (Square s = std::min(rfrom, rto); s <= std::max(rfrom,
rto); ++s)
if (s != kfrom && s != rfrom)
castlingPath[cr] |= s;
for (Square s = std::min(kfrom, kto); s <= std::max(kfrom,
kto); ++s)
if (s != kfrom && s != rfrom)
castlingPath[cr] |= s;
}
/// Position::set_state() computes the hash keys of the
position, and other
/// data that once computed is updated incrementally as moves
are made.
/// The function is only used when a new position is set up,
and to verify
/// the correctness of the StateInfo data when running in
debug mode.

void Position::set_state(StateInfo* si) const {


si->key = si->pawnKey = si->materialKey = 0;
si->npMaterial[WHITE] = si->npMaterial[BLACK] = VALUE_ZERO;
si->psq = SCORE_ZERO;
si->checkersBB = attackers_to(king_square(sideToMove)) &
pieces(~sideToMove);
for (Bitboard b = pieces(); b; )
{
Square s = pop_lsb(&b);
Piece pc = piece_on(s);
si->key ^= Zobrist::psq[color_of(pc)][type_of(pc)][s];
si->psq += psq[color_of(pc)][type_of(pc)][s];
}
if (ep_square() != SQ_NONE)
si->key ^= Zobrist::enpassant[file_of(ep_square())];
if (sideToMove == BLACK)
si->key ^= Zobrist::side;
si->key ^= Zobrist::castling[st->castlingRights];
for (Bitboard b = pieces(PAWN); b; )
{
Square s = pop_lsb(&b);
si->pawnKey ^= Zobrist::psq[color_of(piece_on(s))][PAWN]
[s];
}
for (Color c = WHITE; c <= BLACK; ++c)
for (PieceType pt = PAWN; pt <= KING; ++pt)
for (int cnt = 0; cnt < pieceCount[c][pt]; ++cnt)
si->materialKey ^= Zobrist::psq[c][pt][cnt];
for (Color c = WHITE; c <= BLACK; ++c)
for (PieceType pt = KNIGHT; pt <= QUEEN; ++pt)
si->npMaterial[c] += pieceCount[c][pt] *
PieceValue[MG][pt];
}
/// Position::fen() returns a FEN representation of the
position. In case of

/// Chess960 the Shredder-FEN notation is used. This is mainly


a debugging function.
const string Position::fen() const {
int emptyCnt;
std::ostringstream ss;
for (Rank r = RANK_8; r >= RANK_1; --r)
{
for (File f = FILE_A; f <= FILE_H; ++f)
{
for (emptyCnt = 0; f <= FILE_H &&
empty(make_square(f, r)); ++f)
++emptyCnt;
if (emptyCnt)
ss << emptyCnt;

if (f <= FILE_H)
ss << PieceToChar[piece_on(make_square(f, r))];

if (r > RANK_1)
ss << '/';

ss << (sideToMove == WHITE ? " w " : " b ");


if (can_castle(WHITE_OO))
ss << (chess960 ?
to_char(file_of(castling_rook_square(WHITE |
false) : 'K');

KING_SIDE)),

if (can_castle(WHITE_OOO))
ss << (chess960 ?
to_char(file_of(castling_rook_square(WHITE | QUEEN_SIDE)),
false) : 'Q');
if (can_castle(BLACK_OO))
ss << (chess960 ?
to_char(file_of(castling_rook_square(BLACK |
true) : 'k');

KING_SIDE)),

if (can_castle(BLACK_OOO))
ss << (chess960 ?
to_char(file_of(castling_rook_square(BLACK | QUEEN_SIDE)),

true) : 'q');
if (!can_castle(WHITE) && !can_castle(BLACK))
ss << '-';
ss << (ep_square() == SQ_NONE ? " - " : " " +
to_string(ep_square()) + " ")
<< st->rule50 << " " << 1 + (gamePly - (sideToMove ==
BLACK)) / 2;
}

return ss.str();

/// Position::pretty() returns an ASCII representation of the


position to be
/// printed to the standard output together with the move's
san notation.
const string Position::pretty(Move m) const {
std::ostringstream ss;
if (m)
ss << "\nMove: " << (sideToMove == BLACK ? ".." : "")
<< move_to_san(*const_cast<Position*>(this), m);
ss << "\n +---+---+---+---+---+---+---+---+\n";
for (Rank r = RANK_8; r >= RANK_1; --r)
{
for (File f = FILE_A; f <= FILE_H; ++f)
ss << " | " << PieceToChar[piece_on(make_square(f,
r))];
}

ss << " |\n +---+---+---+---+---+---+---+---+\n";

ss << "\nFen: " << fen() << "\nKey: " << std::hex <<
std::uppercase
<< std::setfill('0') << std::setw(16) << st->key <<
"\nCheckers: ";
for (Bitboard b = checkers(); b; )
ss << to_string(pop_lsb(&b)) << " ";
ss << "\nLegal moves: ";

for (const ExtMove& ms : MoveList<LEGAL>(*this))


ss << move_to_san(*const_cast<Position*>(this), ms.move)
<< " ";
}

return ss.str();

/// Position::check_blockers() returns a bitboard of all the


pieces with color
/// 'c' that are blocking check on the king with color
'kingColor'. A piece
/// blocks a check if removing that piece from the board would
result in a
/// position where the king is in check. A check blocking
piece can be either a
/// pinned or a discovered check piece, according if its color
'c' is the same
/// or the opposite of 'kingColor'.
Bitboard Position::check_blockers(Color c, Color kingColor)
const {
Bitboard b, pinners, result = 0;
Square ksq = king_square(kingColor);
// Pinners are sliders that give check when a pinned piece
is removed
pinners = ( (pieces( ROOK, QUEEN) & PseudoAttacks[ROOK ]
[ksq])
| (pieces(BISHOP, QUEEN) & PseudoAttacks[BISHOP]
[ksq])) & pieces(~kingColor);
while (pinners)
{
b = between_bb(ksq, pop_lsb(&pinners)) & pieces();
if (!more_than_one(b))
result |= b & pieces(c);

}
return result;

/// Position::attackers_to() computes a bitboard of all pieces


which attack a
/// given square. Slider attacks use the occ bitboard to

indicate occupancy.
Bitboard Position::attackers_to(Square s, Bitboard occ) const
{
return
|
|
|
|
QUEEN))
|
}

(attacks_from<PAWN>(s, BLACK)
(attacks_from<PAWN>(s, WHITE)
(attacks_from<KNIGHT>(s)
(attacks_bb<ROOK>(s, occ)
(attacks_bb<BISHOP>(s, occ)

&
&
&
&
&

pieces(WHITE, PAWN))
pieces(BLACK, PAWN))
pieces(KNIGHT))
pieces(ROOK, QUEEN))
pieces(BISHOP,

(attacks_from<KING>(s)

& pieces(KING));

/// Position::legal() tests whether a pseudo-legal move is


legal
bool Position::legal(Move m, Bitboard pinned) const {
assert(is_ok(m));
assert(pinned == pinned_pieces(sideToMove));
Color us = sideToMove;
Square from = from_sq(m);
assert(color_of(moved_piece(m)) == us);
assert(piece_on(king_square(us)) == make_piece(us, KING));
// 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
// the move is made.
if (type_of(m) == ENPASSANT)
{
Square ksq = king_square(us);
Square to = to_sq(m);
Square capsq = to - pawn_push(us);
Bitboard occ = (pieces() ^ from ^ capsq) | to;
assert(to == ep_square());
assert(moved_piece(m) == make_piece(us, PAWN));
assert(piece_on(capsq) == make_piece(~us, PAWN));
assert(piece_on(to) == NO_PIECE);
return

!(attacks_bb<

ROOK>(ksq, occ) & pieces(~us,

QUEEN, ROOK))
&& !(attacks_bb<BISHOP>(ksq, occ) & pieces(~us,
QUEEN, BISHOP));
}
// If the moving piece is a king, check whether the
destination
// square is attacked by the opponent. Castling moves are
checked
// for legality during move generation.
if (type_of(piece_on(from)) == KING)
return type_of(m) == CASTLING || !
(attackers_to(to_sq(m)) & pieces(~us));
// 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.
return
!pinned
|| !(pinned & from)
|| aligned(from, to_sq(m), king_square(us));
}
/// Position::pseudo_legal() takes a random move and tests
whether the move is
/// pseudo legal. It is used to validate moves from TT that
can be corrupted
/// due to SMP concurrent access or hash position key
aliasing.
bool Position::pseudo_legal(const Move m) const {
Color us = sideToMove;
Square from = from_sq(m);
Square to = to_sq(m);
Piece pc = moved_piece(m);
// Use a slower but simpler function for uncommon cases
if (type_of(m) != NORMAL)
return MoveList<LEGAL>(*this).contains(m);
// Is not a promotion, so promotion piece must be empty
if (promotion_type(m) - 2 != NO_PIECE_TYPE)
return false;
// If the 'from' square is not occupied by a piece belonging
to the side to

// move, the move is obviously not legal.


if (pc == NO_PIECE || color_of(pc) != us)
return false;
// The destination square cannot be occupied by a friendly
piece
if (pieces(us) & to)
return false;
// Handle the special case of a pawn move
if (type_of(pc) == PAWN)
{
// We have already handled promotion moves, so
destination
// cannot be on the 8th/1st rank.
if (rank_of(to) == relative_rank(us, RANK_8))
return false;
if (
!(attacks_from<PAWN>(from, us) & pieces(~us) &
to) // Not a capture
&& !((from + pawn_push(us) == to) &&
empty(to))
// Not a single push
to)

&& !(

(from + 2 * pawn_push(us) ==
// Not a double push
&& (rank_of(from) == relative_rank(us, RANK_2))
&& empty(to)
&& empty(to - pawn_push(us))))
return false;

}
else if (!(attacks_from(pc, from) & to))
return false;

// Evasions generator already takes care to avoid some kind


of illegal moves
// and legal() relies on this. We therefore have to take
care that the same
// kind of moves are filtered out here.
if (checkers())
{
if (type_of(pc) != KING)
{
// Double check? In this case a king move is
required
if (more_than_one(checkers()))
return false;

// Our move must be a blocking evasion or a capture


of the checking piece
if (!((between_bb(lsb(checkers()), king_square(us))
| checkers()) & to))
return false;
}
// In case of king moves under check we have to remove
king so as to catch
// invalid moves like b1a1 when opposite queen is on c1.
else if (attackers_to(to, pieces() ^ from) &
pieces(~us))
return false;
}
}

return true;

/// Position::gives_check() tests whether a pseudo-legal move


gives a check
bool Position::gives_check(Move m, const CheckInfo& ci) const
{
assert(is_ok(m));
assert(ci.dcCandidates == discovered_check_candidates());
assert(color_of(moved_piece(m)) == sideToMove);
Square from = from_sq(m);
Square to = to_sq(m);
PieceType pt = type_of(piece_on(from));
// Is there a direct check?
if (ci.checkSq[pt] & to)
return true;
// Is there a discovered check?
if (
unlikely(ci.dcCandidates)
&& (ci.dcCandidates & from)
&& !aligned(from, to, ci.ksq))
return true;
switch (type_of(m))
{
case NORMAL:
return false;

case PROMOTION:
return attacks_bb(Piece(promotion_type(m)), to, pieces()
^ from) & ci.ksq;
// 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 is the unusual case of a discovered check
through
// the captured pawn.
case ENPASSANT:
{
Square capsq = make_square(file_of(to), rank_of(from));
Bitboard b = (pieces() ^ from ^ capsq) | to;
return (attacks_bb< ROOK>(ci.ksq, b) &
pieces(sideToMove, QUEEN, ROOK))
| (attacks_bb<BISHOP>(ci.ksq, b) &
pieces(sideToMove, QUEEN, BISHOP));
}
case CASTLING:
{
Square kfrom = from;
Square rfrom = to; // Castling is encoded as 'King
captures the rook'
Square kto = relative_square(sideToMove, rfrom > kfrom ?
SQ_G1 : SQ_C1);
Square rto = relative_square(sideToMove, rfrom > kfrom ?
SQ_F1 : SQ_D1);
return
(PseudoAttacks[ROOK][rto] & ci.ksq)
&& (attacks_bb<ROOK>(rto, (pieces() ^ kfrom ^
rfrom) | rto | kto) & ci.ksq);
}
default:
assert(false);
return false;
}
}
/// Position::do_move() makes a move, and saves all
information necessary
/// to a StateInfo object. The move is assumed to be legal.
Pseudo-legal

/// moves should be filtered out before this function is


called.
void Position::do_move(Move m, StateInfo& newSt) {

CheckInfo ci(*this);
do_move(m, newSt, ci, gives_check(m, ci));

void Position::do_move(Move m, StateInfo& newSt, const


CheckInfo& ci, bool moveIsCheck) {
assert(is_ok(m));
assert(&newSt != st);
++nodes;
Key k = st->key;
// Copy some fields of the old state to our new StateInfo
object except the
// ones which are going to be recalculated from scratch
anyway and then switch
// our state pointer to point to the new (ready to be
updated) state.
std::memcpy(&newSt, st, StateCopySize64 * sizeof(uint64_t));
newSt.previous = st;
st = &newSt;
// Update side to move
k ^= Zobrist::side;
// Increment ply counters. In particular, rule50 will be
reset to zero later on
// in case of a capture or a pawn move.
++gamePly;
++st->rule50;
++st->pliesFromNull;
Color us = sideToMove;
Color them = ~us;
Square from = from_sq(m);
Square to = to_sq(m);
Piece pc = piece_on(from);
PieceType pt = type_of(pc);
PieceType captured = type_of(m) == ENPASSANT ? PAWN :
type_of(piece_on(to));

assert(color_of(pc) == us);
assert(piece_on(to) == NO_PIECE || color_of(piece_on(to)) ==
them || type_of(m) == CASTLING);
assert(captured != KING);
if (type_of(m) == CASTLING)
{
assert(pc == make_piece(us, KING));
Square rfrom, rto;
do_castling<true>(from, to, rfrom, rto);
captured = NO_PIECE_TYPE;
st->psq += psq[us][ROOK][rto] - psq[us][ROOK][rfrom];
k ^= Zobrist::psq[us][ROOK][rfrom] ^ Zobrist::psq[us]
[ROOK][rto];
}
if (captured)
{
Square capsq = to;
// If the captured piece is a pawn, update pawn hash
key, otherwise
// update non-pawn material.
if (captured == PAWN)
{
if (type_of(m) == ENPASSANT)
{
capsq += pawn_push(them);
assert(pt == PAWN);
assert(to == st->epSquare);
assert(relative_rank(us, to) == RANK_6);
assert(piece_on(to) == NO_PIECE);
assert(piece_on(capsq) == make_piece(them,

PAWN));
}

board[capsq] = NO_PIECE;

st->pawnKey ^= Zobrist::psq[them][PAWN][capsq];

}
else

st->npMaterial[them] -= PieceValue[MG][captured];

// Update board and piece lists


remove_piece(capsq, them, captured);
// Update material hash key and prefetch access to
materialTable
k ^= Zobrist::psq[them][captured][capsq];
st->materialKey ^= Zobrist::psq[them][captured]
[pieceCount[them][captured]];
prefetch((char*)thisThread->materialTable[st>materialKey]);
// Update incremental scores
st->psq -= psq[them][captured][capsq];

// Reset rule 50 counter


st->rule50 = 0;

// Update hash key


k ^= Zobrist::psq[us][pt][from] ^ Zobrist::psq[us][pt][to];
// Reset en passant square
if (st->epSquare != SQ_NONE)
{
k ^= Zobrist::enpassant[file_of(st->epSquare)];
st->epSquare = SQ_NONE;
}
// Update castling rights if needed
if (st->castlingRights && (castlingRightsMask[from] |
castlingRightsMask[to]))
{
int cr = castlingRightsMask[from] |
castlingRightsMask[to];
k ^= Zobrist::castling[st->castlingRights & cr];
st->castlingRights &= ~cr;
}
// Prefetch TT access as soon as we know the new hash key
prefetch((char*)TT.first_entry(k));
// Move the piece. The tricky Chess960 castling is handled
earlier
if (type_of(m) != CASTLING)
move_piece(from, to, us, pt);
// If the moving piece is a pawn do some special extra work

if (pt == PAWN)
{
// Set en-passant square if the moved pawn can be
captured
if (
(int(to) ^ int(from)) == 16
&& (attacks_from<PAWN>(from + pawn_push(us), us) &
pieces(them, PAWN)))
{
st->epSquare = Square((from + to) / 2);
k ^= Zobrist::enpassant[file_of(st->epSquare)];
}
else if (type_of(m) == PROMOTION)
{
PieceType promotion = promotion_type(m);
assert(relative_rank(us, to) == RANK_8);
assert(promotion >= KNIGHT && promotion <= QUEEN);
remove_piece(to, us, PAWN);
put_piece(to, us, promotion);
// Update hash keys
k ^= Zobrist::psq[us][PAWN][to] ^ Zobrist::psq[us]
[promotion][to];
st->pawnKey ^= Zobrist::psq[us][PAWN][to];
st->materialKey ^= Zobrist::psq[us][promotion]
[pieceCount[us][promotion]-1]
^ Zobrist::psq[us][PAWN]
[pieceCount[us][PAWN]];
// Update incremental score
st->psq += psq[us][promotion][to] - psq[us][PAWN]

[to];

// Update material
st->npMaterial[us] += PieceValue[MG][promotion];

// Update pawn hash key and prefetch access to


pawnsTable
st->pawnKey ^= Zobrist::psq[us][PAWN][from] ^
Zobrist::psq[us][PAWN][to];
prefetch((char*)thisThread->pawnsTable[st->pawnKey]);
// Reset rule 50 draw counter
st->rule50 = 0;

}
// Update incremental scores
st->psq += psq[us][pt][to] - psq[us][pt][from];
// Set capture piece
st->capturedType = captured;
// Update the key with the final value
st->key = k;
// Update checkers bitboard: piece must be already moved due
to attacks_from()
st->checkersBB = 0;
if (moveIsCheck)
{
if (type_of(m) != NORMAL)
st->checkersBB = attackers_to(king_square(them)) &
pieces(us);
else
{
// Direct checks
if (ci.checkSq[pt] & to)
st->checkersBB |= to;

from))

// Discovered checks
if (unlikely(ci.dcCandidates) && (ci.dcCandidates &
{

if (pt != ROOK)
st->checkersBB |=
attacks_from<ROOK>(king_square(them)) & pieces(us, QUEEN,
ROOK);
if (pt != BISHOP)
st->checkersBB |=
attacks_from<BISHOP>(king_square(them)) & pieces(us, QUEEN,
BISHOP);
}
}
}
sideToMove = ~sideToMove;
}

assert(pos_is_ok());

/// Position::undo_move() unmakes a move. When it returns, the


position should
/// be restored to exactly the same state as before the move
was made.
void Position::undo_move(Move m) {
assert(is_ok(m));
sideToMove = ~sideToMove;
Color us = sideToMove;
Square from = from_sq(m);
Square to = to_sq(m);
PieceType pt = type_of(piece_on(to));
assert(empty(from) || type_of(m) == CASTLING);
assert(st->capturedType != KING);
if (type_of(m) == PROMOTION)
{
assert(pt == promotion_type(m));
assert(relative_rank(us, to) == RANK_8);
assert(promotion_type(m) >= KNIGHT && promotion_type(m)
<= QUEEN);

remove_piece(to, us, promotion_type(m));


put_piece(to, us, PAWN);
pt = PAWN;

if (type_of(m) == CASTLING)
{
Square rfrom, rto;
do_castling<false>(from, to, rfrom, rto);
}
else
{
move_piece(to, from, us, pt); // Put the piece back at
the source square
if (st->capturedType)
{
Square capsq = to;

if (type_of(m) == ENPASSANT)
{
capsq -= pawn_push(us);

assert(pt == PAWN);
assert(to == st->previous->epSquare);
assert(relative_rank(us, to) == RANK_6);
assert(piece_on(capsq) == NO_PIECE);

put_piece(capsq, ~us, st->capturedType); // Restore


the captured piece
}
}
// Finally point our state pointer back to the previous
state
st = st->previous;
--gamePly;
}

assert(pos_is_ok());

/// Position::do_castling() is a helper used to do/undo a


castling move. This
/// is a bit tricky, especially in Chess960.
template<bool Do>
void Position::do_castling(Square from, Square& to, Square&
rfrom, Square& rto) {
bool kingSide = to > from;
rfrom = to; // Castling is encoded as "king captures
friendly rook"
rto = relative_square(sideToMove, kingSide ? SQ_F1 : SQ_D1);
to = relative_square(sideToMove, kingSide ? SQ_G1 : SQ_C1);
// Remove both pieces first since squares could overlap in
Chess960
remove_piece(Do ? from : to, sideToMove, KING);
remove_piece(Do ? rfrom : rto, sideToMove, ROOK);
board[Do ? from : to] = board[Do ? rfrom : rto] =
NO_PIECE; // Since remove_piece doesn't do it for us
put_piece(Do ? to : from, sideToMove, KING);
put_piece(Do ? rto : rfrom, sideToMove, ROOK);
}

/// Position::do(undo)_null_move() is used to do(undo) a "null


move": It flips
/// the side to move without executing any move on the board.
void Position::do_null_move(StateInfo& newSt) {
assert(!checkers());
std::memcpy(&newSt, st, sizeof(StateInfo)); // Fully copy
here
newSt.previous = st;
st = &newSt;
if (st->epSquare != SQ_NONE)
{
st->key ^= Zobrist::enpassant[file_of(st->epSquare)];
st->epSquare = SQ_NONE;
}
st->key ^= Zobrist::side;
prefetch((char*)TT.first_entry(st->key));
++st->rule50;
st->pliesFromNull = 0;
sideToMove = ~sideToMove;
}

assert(pos_is_ok());

void Position::undo_null_move() {
assert(!checkers());

st = st->previous;
sideToMove = ~sideToMove;

/// Position::see() is a static exchange evaluator: It tries


to estimate the
/// material gain or loss resulting from a move.
Value Position::see_sign(Move m) const {

assert(is_ok(m));
// Early return if SEE cannot be negative because captured
piece value
// is not less then capturing one. Note that king moves
always return
// here because king midgame value is set to 0.
if (PieceValue[MG][moved_piece(m)] <= PieceValue[MG]
[piece_on(to_sq(m))])
return VALUE_KNOWN_WIN;
}

return see(m);

Value Position::see(Move m) const {


Square from, to;
Bitboard occupied, attackers, stmAttackers;
Value swapList[32];
int slIndex = 1;
PieceType captured;
Color stm;
assert(is_ok(m));
from = from_sq(m);
to = to_sq(m);
swapList[0] = PieceValue[MG][piece_on(to)];
stm = color_of(piece_on(from));
occupied = pieces() ^ from;
// Castling moves are implemented as king capturing the rook
so cannot be
// handled correctly. Simply return 0 that is always the
correct value
// unless in the rare case the rook ends up under attack.
if (type_of(m) == CASTLING)
return VALUE_ZERO;
if (type_of(m) == ENPASSANT)
{
occupied ^= to - pawn_push(stm); // Remove the captured
pawn
swapList[0] = PieceValue[MG][PAWN];
}
// Find all attackers to the destination square, with the

moving piece
// removed, but possibly an X-ray attacker added behind it.
attackers = attackers_to(to, occupied) & occupied;
// If the opponent has no attackers we are finished
stm = ~stm;
stmAttackers = attackers & pieces(stm);
if (!stmAttackers)
return swapList[0];
// The destination square is defended, which makes things
rather more
// difficult to compute. We proceed by building up a "swap
list" containing
// the material gain or loss at each stop in a sequence of
captures to the
// destination square, where the sides alternately capture,
and always
// capture with the least valuable piece. After each
capture, we look for
// new X-ray attacks from behind the capturing piece.
captured = type_of(piece_on(from));
do {

assert(slIndex < 32);

// Add the new entry to the swap list


swapList[slIndex] = -swapList[slIndex - 1] +
PieceValue[MG][captured];
// Locate and remove the next least valuable attacker
captured = min_attacker<PAWN>(byTypeBB, to,
stmAttackers, occupied, attackers);
// Stop before processing a king capture
if (captured == KING)
{
if (stmAttackers == attackers)
++slIndex;
}

break;

stm = ~stm;
stmAttackers = attackers & pieces(stm);
++slIndex;

} while (stmAttackers);
// Having built the swap list, we negamax through it to find
the best
// achievable score from the point of view of the side to
move.
while (--slIndex)
swapList[slIndex - 1] = std::min(-swapList[slIndex],
swapList[slIndex - 1]);
}

return swapList[0];

/// Position::is_draw() tests whether the position is drawn by


material, 50 moves
/// rule or repetition. It does not detect stalemates.
bool Position::is_draw() const {
if (

!pieces(PAWN)
&& (non_pawn_material(WHITE) + non_pawn_material(BLACK)
<= BishopValueMg))
return true;
if (st->rule50 > 99 && (!checkers() ||
MoveList<LEGAL>(*this).size()))
return true;
StateInfo* stp = st;
for (int i = 2, e = std::min(st->rule50, st->pliesFromNull);
i <= e; i += 2)
{
stp = stp->previous->previous;

}
}

if (stp->key == st->key)
return true; // Draw at first repetition

return false;

/// Position::flip() flips position with the white and black


sides reversed. This
/// is only useful for debugging e.g. for finding evaluation
symmetry bugs.

static char toggle_case(char c) {


return char(islower(c) ? toupper(c) : tolower(c));
}
void Position::flip() {
string f, token;
std::stringstream ss(fen());
for (Rank r = RANK_8; r >= RANK_1; --r) // Piece placement
{
std::getline(ss, token, r > RANK_1 ? '/' : ' ');
f.insert(0, token + (f.empty() ? " " : "/"));
}
ss >> token; // Active color
f += (token == "w" ? "B " : "W "); // Will be lowercased
later
ss >> token; // Castling availability
f += token + " ";
std::transform(f.begin(), f.end(), f.begin(), toggle_case);
ss >> token; // En passant square
f += (token == "-" ? token : token.replace(1, 1, token[1] ==
'3' ? "6" : "3"));
std::getline(ss, token); // Half and full moves
f += token;
set(f, is_chess960(), this_thread());
}

assert(pos_is_ok());

/// Position::pos_is_ok() performs some consistency checks for


the position object.
/// This is meant to be helpful when debugging.
bool Position::pos_is_ok(int* step) const {
// Which parts of the position should be verified?
const bool all = false;

const
const
const
const
const
const
const

bool
bool
bool
bool
bool
bool
bool

testBitboards
testState
testKingCount
testKingCapture
testPieceCounts
testPieceList
testCastlingSquares

=
=
=
=
=
=
=

all
all
all
all
all
all
all

||
||
||
||
||
||
||

false;
false;
false;
false;
false;
false;
false;

if (step)
*step = 1;
if (

(sideToMove != WHITE && sideToMove != BLACK)


|| piece_on(king_square(WHITE)) != W_KING
|| piece_on(king_square(BLACK)) != B_KING
|| (
ep_square() != SQ_NONE
&& relative_rank(sideToMove, ep_square()) !=
RANK_6))
return false;
if (step && ++*step, testBitboards)
{
// The intersection of the white and black pieces must
be empty
if (pieces(WHITE) & pieces(BLACK))
return false;
to all

// The union of the white and black pieces must be equal


// occupied squares
if ((pieces(WHITE) | pieces(BLACK)) != pieces())
return false;

// Separate piece type bitboards must have empty


intersections
for (PieceType p1 = PAWN; p1 <= KING; ++p1)
for (PieceType p2 = PAWN; p2 <= KING; ++p2)
if (p1 != p2 && (pieces(p1) & pieces(p2)))
return false;
}
if (step && ++*step, testState)
{
StateInfo si;
set_state(&si);
if (
st->key != si.key
|| st->pawnKey != si.pawnKey
|| st->materialKey != si.materialKey

|| st->npMaterial[WHITE] != si.npMaterial[WHITE]
|| st->npMaterial[BLACK] != si.npMaterial[BLACK]
|| st->psq != si.psq
|| st->checkersBB != si.checkersBB)
return false;

if (step && ++*step, testKingCount)


if (
std::count(board, board + SQUARE_NB, W_KING) != 1
|| std::count(board, board + SQUARE_NB, B_KING) !=

1)

return false;

if (step && ++*step, testKingCapture)


if (attackers_to(king_square(~sideToMove)) &
pieces(sideToMove))
return false;
if (step && ++*step, testPieceCounts)
for (Color c = WHITE; c <= BLACK; ++c)
for (PieceType pt = PAWN; pt <= KING; ++pt)
if (pieceCount[c][pt] !=
popcount<Full>(pieces(c, pt)))
return false;
if (step && ++*step, testPieceList)
for (Color c = WHITE; c <= BLACK; ++c)
for (PieceType pt = PAWN; pt <= KING; ++pt)
for (int i = 0; i < pieceCount[c][pt]; ++i)
if (
board[pieceList[c][pt][i]] !=
make_piece(c, pt)
|| index[pieceList[c][pt][i]] != i)
return false;
if (step && ++*step, testCastlingSquares)
for (Color c = WHITE; c <= BLACK; ++c)
for (CastlingSide s = KING_SIDE; s <= QUEEN_SIDE; s
= CastlingSide(s + 1))
{
if (!can_castle(c | s))
continue;
if ( (castlingRightsMask[king_square(c)] & (c |
s)) != (c | s)
|| piece_on(castlingRookSquare[c | s]) !=
make_piece(c, ROOK)
|| castlingRightsMask[castlingRookSquare[c |

s]] != (c | s))
}
}

return true;

return false;

You might also like