-/// Position::from_fen() 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).
+/// 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.
// 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.
// 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.
- if ( ((fen >> col) && (col >= 'a' && col <= 'h'))
- && ((fen >> row) && (row == '3' || row == '6')))
+ if ( ((ss >> col) && (col >= 'a' && col <= 'h'))
+ && ((ss >> row) && (row == '3' || row == '6')))
// Convert from fullmove starting from 1 to ply starting from 0,
// handle also common incorrect FEN with fullmove = 0.
// Convert from fullmove starting from 1 to ply starting from 0,
// handle also common incorrect FEN with fullmove = 0.
-/// Position::print() prints an ASCII representation of the position to
-/// the standard output. If a move is given then also the san is printed.
+/// 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 dottedLine = "\n+---+---+---+---+---+---+---+---+";
const string twoRows = dottedLine + "\n| | . | | . | | . | | . |"
const string dottedLine = "\n+---+---+---+---+---+---+---+---+";
const string twoRows = dottedLine + "\n| | . | | . | | . | | . |"
- cout << "\nMove is: " << (sideToMove == BLACK ? ".." : "")
- << move_to_san(*const_cast<Position*>(this), move);
+ ss << "\nMove: " << (sideToMove == BLACK ? ".." : "")
+ << move_to_san(*const_cast<Position*>(this), move);
for (Square sq = SQ_A1; sq <= SQ_H8; sq++)
if (piece_on(sq) != NO_PIECE)
brd[513 - 68*rank_of(sq) + 4*file_of(sq)] = PieceToChar[piece_on(sq)];
for (Square sq = SQ_A1; sq <= SQ_H8; sq++)
if (piece_on(sq) != NO_PIECE)
brd[513 - 68*rank_of(sq) + 4*file_of(sq)] = PieceToChar[piece_on(sq)];
- cout << brd << "\nFen is: " << to_fen() << "\nKey is: " << st->key << sync_endl;
+ ss << brd << "\nFen: " << fen() << "\nKey: " << st->key << "\nCheckers: ";
+
+ for (Bitboard b = checkers(); b; )
+ ss << square_to_string(pop_lsb(&b)) << " ";
+
+ ss << "\nLegal moves: ";
+ for (MoveList<LEGAL> ml(*this); !ml.end(); ++ml)
+ ss << move_to_san(*const_cast<Position*>(this), ml.move()) << " ";
+
+ return ss.str();
-/// Position::move_is_legal() takes a random move and tests whether the move
-/// is legal. This version is not very fast and should be used only in non
-/// time-critical paths.
-
-bool Position::move_is_legal(const Move m) const {
-
- for (MoveList<LEGAL> ml(*this); !ml.end(); ++ml)
- if (ml.move() == m)
- return true;
-
- return false;
-}
-
-
/// Position::is_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.
/// Position::is_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.
Square from = from_sq(m);
Square to = to_sq(m);
Piece pc = piece_moved(m);
// Use a slower but simpler function for uncommon cases
if (type_of(m) != NORMAL)
Square from = from_sq(m);
Square to = to_sq(m);
Piece pc = piece_moved(m);
// Use a slower but simpler function for uncommon cases
if (type_of(m) != NORMAL)
// Is not a promotion, so promotion piece must be empty
if (promotion_type(m) - 2 != NO_PIECE_TYPE)
// Is not a promotion, so promotion piece must be empty
if (promotion_type(m) - 2 != NO_PIECE_TYPE)
case DELTA_SE:
// Capture. The destination square must be occupied by an enemy
// piece (en passant captures was handled earlier).
case DELTA_SE:
// Capture. The destination square must be occupied by an enemy
// piece (en passant captures was handled earlier).
// Evasions generator already takes care to avoid some kind of illegal moves
// and pl_move_is_legal() relies on this. So we have to take care that the
// same kind of moves are filtered out here.
// Evasions generator already takes care to avoid some kind of illegal moves
// and pl_move_is_legal() relies on this. So we have to take care that the
// same kind of moves are filtered out here.
- Bitboard b = checkers();
- Square checksq = pop_lsb(&b);
-
- if (b) // double check ? In this case a king move is required
+ // Double check? In this case a king move is required
+ if (more_than_one(checkers()))
// For pawn and king moves we need to verify also direction
if ( (pt != PAWN && pt != KING)
|| !squares_aligned(from, to, king_square(~sideToMove)))
// For pawn and king moves we need to verify also direction
if ( (pt != PAWN && pt != KING)
|| !squares_aligned(from, to, king_square(~sideToMove)))
- // Promotion with check ?
- if (type_of(m) == PROMOTION)
- return attacks_from(Piece(promotion_type(m)), to, pieces() ^ from) & ksq ? DIRECT_CHECK : NO_CHECK;
+ switch (type_of(m))
+ {
+ case PROMOTION:
+ return attacks_from(Piece(promotion_type(m)), to, pieces() ^ from) & ksq;
// En passant capture with check ? We have already handled the case
// of direct checks and ordinary discovered check, the only case we
// need to handle is the unusual case of a discovered check through
// the captured pawn.
// En passant capture with check ? We have already handled the case
// of direct checks and ordinary discovered check, the only case we
// need to handle is the unusual case of a discovered check through
// the captured pawn.
{
Square capsq = file_of(to) | rank_of(from);
Bitboard b = (pieces() ^ from ^ capsq) | to;
return (attacks_bb< ROOK>(ksq, b) & pieces(us, QUEEN, ROOK))
{
Square capsq = file_of(to) | rank_of(from);
Bitboard b = (pieces() ^ from ^ capsq) | to;
return (attacks_bb< ROOK>(ksq, b) & pieces(us, QUEEN, ROOK))
- | (attacks_bb<BISHOP>(ksq, b) & pieces(us, QUEEN, BISHOP)) ? DISCO_CHECK : NO_CHECK;
+ | (attacks_bb<BISHOP>(ksq, b) & pieces(us, QUEEN, BISHOP));
Square rto = relative_square(us, rfrom > kfrom ? SQ_F1 : SQ_D1);
Bitboard b = (pieces() ^ kfrom ^ rfrom) | rto | kto;
Square rto = relative_square(us, rfrom > kfrom ? SQ_F1 : SQ_D1);
Bitboard b = (pieces() ^ kfrom ^ rfrom) | rto | kto;
PieceType capture = type_of(m) == ENPASSANT ? PAWN : type_of(piece_on(to));
assert(color_of(piece) == us);
PieceType capture = type_of(m) == ENPASSANT ? PAWN : type_of(piece_on(to));
assert(color_of(piece) == us);
pieceList[them][capture][index[lastSquare]] = lastSquare;
pieceList[them][capture][pieceCount[them][capture]] = SQ_NONE;
pieceList[them][capture][index[lastSquare]] = lastSquare;
pieceList[them][capture][pieceCount[them][capture]] = SQ_NONE;
k ^= Zobrist::psq[them][capture][capsq];
st->materialKey ^= Zobrist::psq[them][capture][pieceCount[them][capture]];
k ^= Zobrist::psq[them][capture][capsq];
st->materialKey ^= Zobrist::psq[them][capture][pieceCount[them][capture]];
// Update incremental scores
st->psqScore -= pieceSquareTable[make_piece(them, capture)][capsq];
// Update incremental scores
st->psqScore -= pieceSquareTable[make_piece(them, capture)][capsq];
// Update incremental scores
st->psqScore += psq_delta(piece, from, to);
// Update incremental scores
st->psqScore += psq_delta(piece, from, to);
- // Find after-castle squares for king and rook
- if (rBefore > kBefore) // O-O
+ bool kingSide = to_sq(m) > from_sq(m);
+ kfrom = kto = from_sq(m);
+ rfrom = rto = to_sq(m);
+
+ if (Do)
- kAfter = relative_square(us, SQ_G1);
- rAfter = relative_square(us, SQ_F1);
+ kto = relative_square(us, kingSide ? SQ_G1 : SQ_C1);
+ rto = relative_square(us, kingSide ? SQ_F1 : SQ_D1);
- kAfter = relative_square(us, SQ_C1);
- rAfter = relative_square(us, SQ_D1);
+ kfrom = relative_square(us, kingSide ? SQ_G1 : SQ_C1);
+ rfrom = relative_square(us, kingSide ? SQ_F1 : SQ_D1);
assert(piece_on(kfrom) == make_piece(us, KING));
assert(piece_on(rfrom) == make_piece(us, ROOK));
assert(piece_on(kfrom) == make_piece(us, KING));
assert(piece_on(rfrom) == make_piece(us, ROOK));
- st->psqScore += psq_delta(king, kfrom, kto);
- st->psqScore += psq_delta(rook, rfrom, rto);
+ st->psqScore += psq_delta(make_piece(us, KING), kfrom, kto);
+ st->psqScore += psq_delta(make_piece(us, ROOK), rfrom, rto);
-/// Position::do_null_move() is used to do/undo a "null move": It flips the side
-/// to move and updates the hash key without executing any move on the board.
-template<bool Do>
-void Position::do_null_move(StateInfo& backupSt) {
+/// 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.
- // Back up the information necessary to undo the null move to the supplied
- // StateInfo object. Note that differently from normal case here backupSt
- // is actually used as a backup storage not as the new state. This reduces
- // the number of fields to be copied.
- StateInfo* src = Do ? st : &backupSt;
- StateInfo* dst = Do ? &backupSt : st;
- dst->key = src->key;
- dst->epSquare = src->epSquare;
- dst->psqScore = src->psqScore;
- dst->rule50 = src->rule50;
- dst->pliesFromNull = src->pliesFromNull;
+ memcpy(&newSt, st, sizeof(StateInfo)); // Fully copy here
- if (st->epSquare != SQ_NONE)
- st->key ^= Zobrist::enpassant[file_of(st->epSquare)];
-
- st->key ^= Zobrist::side;
- prefetch((char*)TT.first_entry(st->key));
-
+ st->key ^= Zobrist::enpassant[file_of(st->epSquare)];
-// Explicit template instantiations
-template void Position::do_null_move<false>(StateInfo& backupSt);
-template void Position::do_null_move<true>(StateInfo& backupSt);
+void Position::undo_null_move() {
+
+ assert(!checkers());
+
+ st = st->previous;
+ sideToMove = ~sideToMove;
+}