const string Position::fen() const {
std::ostringstream ss;
- Square sq;
- int emptyCnt;
for (Rank rank = RANK_8; rank >= RANK_1; rank--)
{
- emptyCnt = 0;
-
for (File file = FILE_A; file <= FILE_H; file++)
{
- sq = file | rank;
+ Square sq = file | rank;
if (is_empty(sq))
- emptyCnt++;
- else
{
- if (emptyCnt > 0)
- {
- ss << emptyCnt;
- emptyCnt = 0;
- }
- ss << PieceToChar[piece_on(sq)];
+ int emptyCnt = 1;
+
+ for ( ; file < FILE_H && is_empty(sq++); file++)
+ emptyCnt++;
+
+ ss << emptyCnt;
}
+ else
+ ss << PieceToChar[piece_on(sq)];
}
- if (emptyCnt > 0)
- ss << emptyCnt;
-
if (rank > RANK_1)
ss << '/';
}
ss << (sideToMove == WHITE ? " w " : " b ");
if (can_castle(WHITE_OO))
- ss << (chess960 ? char(toupper(file_to_char(file_of(castle_rook_square(WHITE, KING_SIDE))))) : 'K');
+ ss << (chess960 ? file_to_char(file_of(castle_rook_square(WHITE, KING_SIDE)), false) : 'K');
if (can_castle(WHITE_OOO))
- ss << (chess960 ? char(toupper(file_to_char(file_of(castle_rook_square(WHITE, QUEEN_SIDE))))) : 'Q');
+ ss << (chess960 ? file_to_char(file_of(castle_rook_square(WHITE, QUEEN_SIDE)), false) : 'Q');
if (can_castle(BLACK_OO))
- ss << (chess960 ? file_to_char(file_of(castle_rook_square(BLACK, KING_SIDE))) : 'k');
+ ss << (chess960 ? file_to_char(file_of(castle_rook_square(BLACK, KING_SIDE)), true) : 'k');
if (can_castle(BLACK_OOO))
- ss << (chess960 ? file_to_char(file_of(castle_rook_square(BLACK, QUEEN_SIDE))) : 'q');
+ ss << (chess960 ? file_to_char(file_of(castle_rook_square(BLACK, QUEEN_SIDE)), true) : 'q');
if (st->castleRights == CASTLES_NONE)
ss << '-';
std::ostringstream ss;
if (move)
- ss << "\nMove is: " << (sideToMove == BLACK ? ".." : "")
+ 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)];
- ss << brd << "\nFen is: " << fen() << "\nKey is: " << st->key;
+ 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.
bool Position::is_pseudo_legal(const Move m) const {
Color us = sideToMove;
- Color them = ~sideToMove;
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)
- return move_is_legal(m);
+ return MoveList<LEGAL>(*this).contains(m);
// 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).
- if (piece_on(to) == NO_PIECE || color_of(piece_on(to)) != them)
+ if (piece_on(to) == NO_PIECE || color_of(piece_on(to)) != ~us)
return false;
// From and to files must be one file apart, avoids a7h5
// 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.
- if (in_check())
+ if (checkers())
{
if (type_of(pc) != KING)
{
- 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()))
return false;
// Our move must be a blocking evasion or a capture of the checking piece
- if (!((between_bb(checksq, king_square(us)) | checkers()) & to))
+ 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 to catch
pieceList[them][capture][index[lastSquare]] = lastSquare;
pieceList[them][capture][pieceCount[them][capture]] = SQ_NONE;
- // Update hash keys
+ // Update material hash key and prefetch access to materialTable
k ^= Zobrist::psq[them][capture][capsq];
st->materialKey ^= Zobrist::psq[them][capture][pieceCount[them][capture]];
+ prefetch((char*)thisThread->materialTable[st->materialKey]);
// Update incremental scores
st->psqScore -= pieceSquareTable[make_piece(them, capture)][capsq];
st->castleRights &= ~cr;
}
- // Prefetch TT access as soon as we know key is updated
+ // Prefetch TT access as soon as we know the new hash key
prefetch((char*)TT.first_entry(k));
// Move the piece
st->npMaterial[us] += PieceValue[MG][promotion];
}
- // Update pawn hash key
+ // 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;
}
- // Prefetch pawn and material hash tables
- prefetch((char*)thisThread->pawnTable.entries[st->pawnKey]);
- prefetch((char*)thisThread->materialTable[st->materialKey]);
-
// Update incremental scores
st->psqScore += psq_delta(piece, from, to);
assert(is_ok(m));
assert(type_of(m) == CASTLE);
- Square kto, kfrom, rfrom, rto, kAfter, rAfter;
-
Color us = sideToMove;
- Square kBefore = from_sq(m);
- Square rBefore = to_sq(m);
+ Square kfrom, kto, rfrom, rto;
- // 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);
}
- else // O-O-O
+ else
{
- 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);
}
- kfrom = Do ? kBefore : kAfter;
- rfrom = Do ? rBefore : rAfter;
-
- kto = Do ? kAfter : kBefore;
- rto = Do ? rAfter : rBefore;
-
assert(piece_on(kfrom) == make_piece(us, KING));
assert(piece_on(rfrom) == make_piece(us, ROOK));
template<bool Do>
void Position::do_null_move(StateInfo& backupSt) {
- assert(!in_check());
+ assert(!checkers());
// Back up the information necessary to undo the null move to the supplied
// StateInfo object. Note that differently from normal case here backupSt
&& (non_pawn_material(WHITE) + non_pawn_material(BLACK) <= BishopValueMg))
return true;
- if (st->rule50 > 99 && (!in_check() || MoveList<LEGAL>(*this).size()))
+ if (st->rule50 > 99 && (!checkers() || MoveList<LEGAL>(*this).size()))
return true;
if (CheckRepetition)