}
+/// 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.
// handle also common incorrect FEN with fullmove = 0.
gamePly = std::max(2 * (gamePly - 1), 0) + int(sideToMove == BLACK);
- compute_keys(st);
- compute_non_pawn_material(st);
- st->psq = compute_psq_score();
- st->checkersBB = attackers_to(king_square(sideToMove)) & pieces(~sideToMove);
chess960 = isChess960;
thisThread = th;
+ set_state(st);
assert(pos_is_ok());
}
}
+/// 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.
{
assert(pc == make_piece(us, KING));
- bool kingSide = to > from;
- Square rfrom = to; // Castling is encoded as "king captures friendly rook"
- Square rto = relative_square(us, kingSide ? SQ_F1 : SQ_D1);
- to = relative_square(us, kingSide ? SQ_G1 : SQ_C1);
- captured = NO_PIECE_TYPE;
-
- do_castling(from, to, rfrom, rto);
+ 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 (type_of(m) == CASTLING)
{
- bool kingSide = to > from;
- Square rfrom = to; // Castling is encoded as "king captures friendly rook"
- Square rto = relative_square(us, kingSide ? SQ_F1 : SQ_D1);
- to = relative_square(us, kingSide ? SQ_G1 : SQ_C1);
+ Square rfrom, rto;
+ do_castling<false>(from, to, rfrom, rto);
+
captured = NO_PIECE_TYPE;
pt = KING;
- do_castling(to, from, rto, rfrom);
}
else
move_piece(to, from, us, pt); // Put the piece back at the source square
/// 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) {
-void Position::do_castling(Square kfrom, Square kto, 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(kfrom, sideToMove, KING);
- remove_piece(rfrom, sideToMove, ROOK);
- board[kfrom] = board[rfrom] = NO_PIECE; // Since remove_piece doesn't do it for us
- put_piece(kto, sideToMove, KING);
- put_piece(rto, sideToMove, ROOK);
+ 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::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::compute_keys() computes the hash keys of the position, pawns and
-/// material configuration. The hash keys are usually updated incrementally as
-/// moves are made and unmade. The function is only used when a new position is
-/// set up, and to verify the correctness of the keys when running in debug mode.
-
-void Position::compute_keys(StateInfo* si) const {
-
- si->key = si->pawnKey = si->materialKey = 0;
-
- for (Bitboard b = pieces(); b; )
- {
- Square s = pop_lsb(&b);
- si->key ^= Zobrist::psq[color_of(piece_on(s))][type_of(piece_on(s))][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];
-}
-
-
-/// Position::compute_non_pawn_material() computes the total non-pawn middlegame
-/// material value for each side. Material values are updated incrementally during
-/// the search. This function is only used when initializing a new Position object.
-
-void Position::compute_non_pawn_material(StateInfo* si) const {
-
- si->npMaterial[WHITE] = si->npMaterial[BLACK] = VALUE_ZERO;
-
- for (Color c = WHITE; c <= BLACK; ++c)
- for (PieceType pt = KNIGHT; pt <= QUEEN; ++pt)
- si->npMaterial[c] += pieceCount[c][pt] * PieceValue[MG][pt];
-}
-
-
-/// Position::compute_psq_score() computes the incremental scores for the middlegame
-/// and the endgame. These functions are used to initialize the incremental scores
-/// when a new position is set up, and to verify that the scores are correctly
-/// updated by do_move and undo_move when the program is running in debug mode.
-
-Score Position::compute_psq_score() const {
-
- Score score = SCORE_ZERO;
-
- for (Bitboard b = pieces(); b; )
- {
- Square s = pop_lsb(&b);
- Piece pc = piece_on(s);
- score += psq[color_of(pc)][type_of(pc)][s];
- }
-
- return score;
-}
-
-
/// Position::is_draw() tests whether the position is drawn by material, 50 moves
/// rule or repetition. It does not detect stalemates.
const bool testBitboards = all || false;
const bool testKingCount = all || false;
const bool testKingCapture = all || false;
+ const bool testState = all || false;
const bool testCheckerCount = all || false;
- const bool testKeys = all || false;
- const bool testIncrementalEval = all || false;
- const bool testNonPawnMaterial = all || false;
const bool testPieceCounts = all || false;
const bool testPieceList = all || false;
const bool testCastlingSquares = all || false;
if ((*step)++, piece_on(king_square(BLACK)) != B_KING)
return false;
+ if ((*step)++, ep_square() != SQ_NONE && relative_rank(sideToMove, ep_square()) != RANK_6)
+ return false;
+
if ((*step)++, testKingCount)
if ( std::count(board, board + SQUARE_NB, W_KING) != 1
|| std::count(board, board + SQUARE_NB, B_KING) != 1)
if (attackers_to(king_square(~sideToMove)) & pieces(sideToMove))
return false;
- if ((*step)++, testCheckerCount && popcount<Full>(st->checkersBB) > 2)
- return false;
-
if ((*step)++, testBitboards)
{
// The intersection of the white and black pieces must be empty
return false;
}
- if ((*step)++, ep_square() != SQ_NONE && relative_rank(sideToMove, ep_square()) != RANK_6)
- return false;
-
- if ((*step)++, testKeys)
- {
- StateInfo si;
- compute_keys(&si);
- if (st->key != si.key || st->pawnKey != si.pawnKey || st->materialKey != si.materialKey)
- return false;
- }
-
- if ((*step)++, testNonPawnMaterial)
+ if ((*step)++, testState)
{
StateInfo si;
- compute_non_pawn_material(&si);
- if ( st->npMaterial[WHITE] != si.npMaterial[WHITE]
- || st->npMaterial[BLACK] != si.npMaterial[BLACK])
+ 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)
return false;
}
- if ((*step)++, testIncrementalEval && st->psq != compute_psq_score())
+ if ((*step)++, testCheckerCount && popcount<Full>(st->checkersBB) > 2)
return false;
if ((*step)++, testPieceCounts)