X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fposition.cpp;h=cb5370d5b581412af7b800a6ffc891abcca75739;hb=fbdabe2975c0e86a04b01c36c9f3eec5494ecf0d;hp=42fdd62da8bfc3c121c61916164449682a2ed630;hpb=93059830181b7167525ef4adad7d4ca3115b0701;p=stockfish diff --git a/src/position.cpp b/src/position.cpp index 42fdd62d..cb5370d5 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -42,14 +42,14 @@ Key Position::zobCastle[16]; Key Position::zobSideToMove; Key Position::zobExclusion; -Score Position::PieceSquareTable[16][64]; +Score Position::pieceSquareTable[16][64]; // Material values arrays, indexed by Piece const Value PieceValueMidgame[17] = { VALUE_ZERO, PawnValueMidgame, KnightValueMidgame, BishopValueMidgame, - RookValueMidgame, QueenValueMidgame, VALUE_ZERO, - VALUE_ZERO, VALUE_ZERO, + RookValueMidgame, QueenValueMidgame, + VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, PawnValueMidgame, KnightValueMidgame, BishopValueMidgame, RookValueMidgame, QueenValueMidgame }; @@ -57,8 +57,8 @@ const Value PieceValueMidgame[17] = { const Value PieceValueEndgame[17] = { VALUE_ZERO, PawnValueEndgame, KnightValueEndgame, BishopValueEndgame, - RookValueEndgame, QueenValueEndgame, VALUE_ZERO, - VALUE_ZERO, VALUE_ZERO, + RookValueEndgame, QueenValueEndgame, + VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, PawnValueEndgame, KnightValueEndgame, BishopValueEndgame, RookValueEndgame, QueenValueEndgame }; @@ -121,7 +121,7 @@ void Position::detach() { startState = *st; st = &startState; - st->previous = NULL; // as a safe guard + st->previous = NULL; // As a safe guard } @@ -129,7 +129,7 @@ void Position::detach() { /// 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::from_fen(const string& fen, bool isChess960) { +void Position::from_fen(const string& fenStr, bool isChess960) { /* A FEN string defines a particular position using only the ASCII character set. @@ -158,76 +158,56 @@ void Position::from_fen(const string& fen, bool isChess960) { 6) Fullmove number: The number of the full move. It starts at 1, and is incremented after Black's move. */ - char token; - int hmc, fmn; + char col, row, token; size_t p; Square sq = SQ_A8; - std::istringstream ss(fen); + std::istringstream fen(fenStr); clear(); - ss >> std::noskipws; + fen >> std::noskipws; - // 1. Piece placement field - while ((ss >> token) && !isspace(token)) + // 1. Piece placement + while ((fen >> token) && !isspace(token)) { - if ((p = PieceToChar.find(token)) != string::npos) + if (token == '/') + sq -= Square(16); // Jump back of 2 rows + + else if (isdigit(token)) + sq += Square(token - '0'); // Skip the given number of files + + else if ((p = PieceToChar.find(token)) != string::npos) { put_piece(Piece(p), sq); sq++; } - else if (isdigit(token)) - sq += Square(token - '0'); // Skip the given number of files - else if (token == '/') - sq -= SQ_A3; // Jump back of 2 rows - else - goto incorrect_fen; } // 2. Active color - if (!(ss >> token) || (token != 'w' && token != 'b')) - goto incorrect_fen; - + fen >> token; sideToMove = (token == 'w' ? WHITE : BLACK); - - if (!(ss >> token) || !isspace(token)) - goto incorrect_fen; + fen >> token; // 3. Castling availability - while ((ss >> token) && !isspace(token)) - if (!set_castling_rights(token)) - goto incorrect_fen; - - // 4. En passant square - char col, row; - if ( ((ss >> col) && (col >= 'a' && col <= 'h')) - && ((ss >> row) && (row == '3' || row == '6'))) - { - st->epSquare = make_square(File(col - 'a') + FILE_A, Rank(row - '1') + RANK_1); + while ((fen >> token) && !isspace(token)) + set_castling_rights(token); - // Ignore if no capture is possible + // 4. En passant square. Ignore if no pawn capture is possible + if ( ((fen >> col) && (col >= 'a' && col <= 'h')) + && ((fen >> row) && (row == '3' || row == '6'))) + { + st->epSquare = make_square(File(col - 'a'), Rank(row - '1')); Color them = opposite_color(sideToMove); + if (!(attacks_from(st->epSquare, them) & pieces(PAWN, sideToMove))) st->epSquare = SQ_NONE; } - // 5. Halfmove clock - if (ss >> std::skipws >> hmc) - st->rule50 = hmc; - - // 6. Fullmove number - if (ss >> fmn) - startPosPlyCounter = (fmn - 1) * 2 + int(sideToMove == BLACK); + // 5-6. Halfmove clock and fullmove number + fen >> std::skipws >> st->rule50 >> fullMoves; // Various initialisations - castleRightsMask[make_square(initialKFile, RANK_1)] ^= WHITE_OO | WHITE_OOO; - castleRightsMask[make_square(initialKFile, RANK_8)] ^= BLACK_OO | BLACK_OOO; - castleRightsMask[make_square(initialKRFile, RANK_1)] ^= WHITE_OO; - castleRightsMask[make_square(initialKRFile, RANK_8)] ^= BLACK_OO; - castleRightsMask[make_square(initialQRFile, RANK_1)] ^= WHITE_OOO; - castleRightsMask[make_square(initialQRFile, RANK_8)] ^= BLACK_OOO; - chess960 = isChess960; - find_checkers(); + st->checkersBB = attackers_to(king_square(sideToMove)) & pieces(opposite_color(sideToMove)); st->key = compute_key(); st->pawnKey = compute_pawn_key(); @@ -235,10 +215,18 @@ void Position::from_fen(const string& fen, bool isChess960) { st->value = compute_value(); st->npMaterial[WHITE] = compute_non_pawn_material(WHITE); st->npMaterial[BLACK] = compute_non_pawn_material(BLACK); - return; +} + + +/// Position::set_castle() is an helper function used to set +/// correct castling related flags. + +void Position::set_castle(int f, Square ksq, Square rsq) { -incorrect_fen: - cout << "Error in FEN string: " << fen << endl; + st->castleRights |= f; + castleRightsMask[ksq] ^= f; + castleRightsMask[rsq] ^= f; + castleRookSquare[f] = rsq; } @@ -249,54 +237,31 @@ incorrect_fen: /// associated with the castling right, the traditional castling tag will be replaced /// by the file letter of the involved rook as for the Shredder-FEN. -bool Position::set_castling_rights(char token) { +void Position::set_castling_rights(char token) { - Color c = token >= 'a' ? BLACK : WHITE; - Square sqA = (c == WHITE ? SQ_A1 : SQ_A8); - Square sqH = (c == WHITE ? SQ_H1 : SQ_H8); - Piece rook = (c == WHITE ? WR : BR); + Color c = islower(token) ? BLACK : WHITE; + + Square sqA = relative_square(c, SQ_A1); + Square sqH = relative_square(c, SQ_H1); + Square rsq, ksq = king_square(c); - initialKFile = square_file(king_square(c)); token = char(toupper(token)); if (token == 'K') - { - for (Square sq = sqH; sq >= sqA; sq--) - if (piece_on(sq) == rook) - { - set_castle_kingside(c); - initialKRFile = square_file(sq); - break; - } - } + for (rsq = sqH; piece_on(rsq) != make_piece(c, ROOK); rsq--) {} + else if (token == 'Q') - { - for (Square sq = sqA; sq <= sqH; sq++) - if (piece_on(sq) == rook) - { - set_castle_queenside(c); - initialQRFile = square_file(sq); - break; - } - } + for (rsq = sqA; piece_on(rsq) != make_piece(c, ROOK); rsq++) {} + else if (token >= 'A' && token <= 'H') - { - File rookFile = File(token - 'A') + FILE_A; - if (rookFile < initialKFile) - { - set_castle_queenside(c); - initialQRFile = rookFile; - } - else - { - set_castle_kingside(c); - initialKRFile = rookFile; - } - } - else - return token == '-'; + rsq = make_square(File(token - 'A'), relative_rank(c, RANK_1)); - return true; + else return; + + if (square_file(rsq) < square_file(ksq)) + set_castle(WHITE_OOO << c, ksq, rsq); + else + set_castle(WHITE_OO << c, ksq, rsq); } @@ -305,54 +270,60 @@ bool Position::set_castling_rights(char token) { const string Position::to_fen() const { - string fen; + std::ostringstream fen; Square sq; - char emptyCnt; + int emptyCnt; - for (Rank rank = RANK_8; rank >= RANK_1; rank--, fen += '/') + for (Rank rank = RANK_8; rank >= RANK_1; rank--) { - emptyCnt = '0'; + emptyCnt = 0; for (File file = FILE_A; file <= FILE_H; file++) { sq = make_square(file, rank); - if (square_is_occupied(sq)) + if (!square_is_empty(sq)) { - if (emptyCnt != '0') + if (emptyCnt) { - fen += emptyCnt; - emptyCnt = '0'; + fen << emptyCnt; + emptyCnt = 0; } - fen += PieceToChar[piece_on(sq)]; - } else + fen << PieceToChar[piece_on(sq)]; + } + else emptyCnt++; } - if (emptyCnt != '0') - fen += emptyCnt; + if (emptyCnt) + fen << emptyCnt; + + if (rank > RANK_1) + fen << '/'; } - fen += (sideToMove == WHITE ? " w " : " b "); + fen << (sideToMove == WHITE ? " w " : " b "); if (st->castleRights != CASTLES_NONE) { - if (can_castle_kingside(WHITE)) - fen += chess960 ? char(toupper(file_to_char(initialKRFile))) : 'K'; + if (can_castle(WHITE_OO)) + fen << (chess960 ? char(toupper(file_to_char(square_file(castle_rook_square(WHITE_OO))))) : 'K'); - if (can_castle_queenside(WHITE)) - fen += chess960 ? char(toupper(file_to_char(initialQRFile))) : 'Q'; + if (can_castle(WHITE_OOO)) + fen << (chess960 ? char(toupper(file_to_char(square_file(castle_rook_square(WHITE_OOO))))) : 'Q'); - if (can_castle_kingside(BLACK)) - fen += chess960 ? file_to_char(initialKRFile) : 'k'; + if (can_castle(BLACK_OO)) + fen << (chess960 ? file_to_char(square_file(castle_rook_square(BLACK_OO))) : 'k'); - if (can_castle_queenside(BLACK)) - fen += chess960 ? file_to_char(initialQRFile) : 'q'; + if (can_castle(BLACK_OOO)) + fen << (chess960 ? file_to_char(square_file(castle_rook_square(BLACK_OOO))) : 'q'); } else - fen += '-'; + fen << '-'; + + fen << (ep_square() == SQ_NONE ? " -" : " " + square_to_string(ep_square())) + << " " << st->rule50 << " " << fullMoves; - fen += (ep_square() == SQ_NONE ? " -" : " " + square_to_string(ep_square())); - return fen; + return fen.str(); } @@ -366,7 +337,7 @@ void Position::print(Move move) const { if (move) { Position p(*this, thread()); - string dd = (piece_color(piece_on(move_from(move))) == BLACK ? ".." : ""); + string dd = (sideToMove == BLACK ? ".." : ""); cout << "\nMove is: " << dd << move_to_san(p, move); } @@ -399,7 +370,7 @@ template Bitboard Position::hidden_checkers(Color c) const { Bitboard result = EmptyBoardBB; - Bitboard pinners = pieces_of_color(FindPinned ? opposite_color(c) : c); + Bitboard pinners = pieces(FindPinned ? opposite_color(c) : c); // Pinned pieces protect our king, dicovery checks attack // the enemy king. @@ -419,7 +390,7 @@ Bitboard Position::hidden_checkers(Color c) const { assert(b); if ( !(b & (b - 1)) // Only one bit set? - && (b & pieces_of_color(c))) // Is an our piece? + && (b & pieces(c))) // Is an our piece? result |= b; } return result; @@ -510,7 +481,7 @@ bool Position::move_attacks_square(Move m, Square s) const { Bitboard occ, xray; Square f = move_from(m), t = move_to(m); - assert(square_is_occupied(f)); + assert(!square_is_empty(f)); if (bit_is_set(attacks_from(piece_on(f), t), s)) return true; @@ -520,7 +491,7 @@ bool Position::move_attacks_square(Move m, Square s) const { do_move_bb(&occ, make_move_bb(f, t)); xray = ( (rook_attacks_bb(s, occ) & pieces(ROOK, QUEEN)) |(bishop_attacks_bb(s, occ) & pieces(BISHOP, QUEEN))) - & pieces_of_color(piece_color(piece_on(f))); + & pieces(piece_color(piece_on(f))); // If we have attacks we need to verify that are caused by our move // and are not already existent ones. @@ -528,19 +499,6 @@ bool Position::move_attacks_square(Move m, Square s) const { } -/// Position::find_checkers() computes the checkersBB bitboard, which -/// contains a nonzero bit for each checking piece (0, 1 or 2). It -/// currently works by calling Position::attackers_to, which is probably -/// inefficient. Consider rewriting this function to use the last move -/// played, like in non-bitboard versions of Glaurung. - -void Position::find_checkers() { - - Color us = side_to_move(); - st->checkersBB = attackers_to(king_square(us)) & pieces_of_color(opposite_color(us)); -} - - /// Position::pl_move_is_legal() tests whether a pseudo-legal move is legal bool Position::pl_move_is_legal(Move m, Bitboard pinned) const { @@ -555,14 +513,14 @@ bool Position::pl_move_is_legal(Move m, Bitboard pinned) const { assert(piece_color(piece_on(from)) == 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 + // 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 (move_is_ep(m)) { Color them = opposite_color(us); Square to = move_to(m); - Square capsq = make_square(square_file(to), square_rank(from)); + Square capsq = to + Square(us == WHITE ? -8 : 8); Square ksq = king_square(us); Bitboard b = occupied_squares(); @@ -583,7 +541,7 @@ bool Position::pl_move_is_legal(Move m, Bitboard pinned) const { // square is attacked by the opponent. Castling moves are checked // for legality during move generation. if (piece_type(piece_on(from)) == KING) - return move_is_castle(m) || !(attackers_to(move_to(m)) & pieces_of_color(opposite_color(us))); + return move_is_castle(m) || !(attackers_to(move_to(m)) & pieces(opposite_color(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. @@ -593,28 +551,22 @@ bool Position::pl_move_is_legal(Move m, Bitboard pinned) const { } -/// Position::move_is_pl_slow() takes a position and a move and tests whether -/// the move is pseudo legal. This version is not very fast and should be used -/// only in non time-critical paths. - -bool Position::move_is_pl_slow(const Move m) const { - - MoveStack mlist[MAX_MOVES]; - MoveStack *cur, *last; +/// Position::move_is_legal() takes a move and tests whether the move +/// is legal. This version is not very fast and should be used only +/// in non time-critical paths. - last = in_check() ? generate(*this, mlist) - : generate(*this, mlist); +bool Position::move_is_legal(const Move m) const { - for (cur = mlist; cur != last; cur++) - if (cur->move == m) + for (MoveList ml(*this); !ml.end(); ++ml) + if (ml.move() == m) return true; return false; } -/// Fast version of Position::move_is_pl() that takes a position a move and a -/// bitboard of pinned pieces as input, and tests whether the move is pseudo legal. +/// Fast version of Position::move_is_pl() that takes a move and a bitboard +/// of pinned pieces as input, and tests whether the move is pseudo legal. bool Position::move_is_pl(const Move m) const { @@ -628,7 +580,7 @@ bool Position::move_is_pl(const Move m) const { // Use a slower but simpler function for uncommon cases if (move_is_special(m)) - return move_is_pl_slow(m); + return move_is_legal(m); // Is not a promotion, so promotion piece must be empty if (promotion_piece_type(m) - 2 != PIECE_TYPE_NONE) @@ -716,7 +668,7 @@ bool Position::move_is_pl(const Move m) const { { Bitboard b = occupied_squares(); clear_bit(&b, from); - if (attackers_to(move_to(m), b) & pieces_of_color(opposite_color(us))) + if (attackers_to(move_to(m), b) & pieces(opposite_color(us))) return false; } else @@ -839,6 +791,10 @@ void Position::do_setup_move(Move m) { StateInfo newSt; + // Update the number of full moves after black's move + if (sideToMove == BLACK) + fullMoves++; + do_move(m, newSt); // Reset "game ply" in case we made a non-reversible move. @@ -846,9 +802,6 @@ void Position::do_setup_move(Move m) { if (st->rule50 == 0) st->gamePly = 0; - // Update the number of plies played from the starting position - startPosPlyCounter++; - // Our StateInfo newSt is about going out of scope so copy // its content before it disappears. detach(); @@ -952,9 +905,9 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI // Move the piece Bitboard move_bb = make_move_bb(from, to); - do_move_bb(&(byColorBB[us]), move_bb); - do_move_bb(&(byTypeBB[pt]), move_bb); - do_move_bb(&(byTypeBB[0]), move_bb); // HACK: byTypeBB[0] == occupied squares + do_move_bb(&byColorBB[us], move_bb); + do_move_bb(&byTypeBB[pt], move_bb); + do_move_bb(&byTypeBB[0], move_bb); // HACK: byTypeBB[0] == occupied squares board[to] = board[from]; board[from] = PIECE_NONE; @@ -991,8 +944,8 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI assert(promotion >= KNIGHT && promotion <= QUEEN); // Insert promoted piece instead of pawn - clear_bit(&(byTypeBB[PAWN]), to); - set_bit(&(byTypeBB[promotion]), to); + clear_bit(&byTypeBB[PAWN], to); + set_bit(&byTypeBB[promotion], to); board[to] = make_piece(us, promotion); // Update piece counts @@ -1017,8 +970,8 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI st->pawnKey ^= zobrist[us][PAWN][to]; // Partially revert and update incremental scores - st->value -= pst(us, PAWN, to); - st->value += pst(us, promotion, to); + st->value -= pst(make_piece(us, PAWN), to); + st->value += pst(make_piece(us, promotion), to); // Update material st->npMaterial[us] += PieceValueMidgame[promotion]; @@ -1044,7 +997,7 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI if (moveIsCheck) { if (ep | pm) - st->checkersBB = attackers_to(king_square(them)) & pieces_of_color(us); + st->checkersBB = attackers_to(king_square(them)) & pieces(us); else { // Direct checks @@ -1101,15 +1054,15 @@ void Position::do_capture_move(Key& key, PieceType capture, Color them, Square t st->npMaterial[them] -= PieceValueMidgame[capture]; // Remove captured piece - clear_bit(&(byColorBB[them]), capsq); - clear_bit(&(byTypeBB[capture]), capsq); - clear_bit(&(byTypeBB[0]), capsq); + clear_bit(&byColorBB[them], capsq); + clear_bit(&byTypeBB[capture], capsq); + clear_bit(&byTypeBB[0], capsq); // Update hash key key ^= zobrist[them][capture][capsq]; // Update incremental scores - st->value -= pst(them, capture, capsq); + st->value -= pst(make_piece(them, capture), capsq); // Update piece count pieceCount[them][capture]--; @@ -1147,12 +1100,9 @@ void Position::do_castle_move(Move m) { Color us = side_to_move(); Color them = opposite_color(us); - // Reset capture field - st->capturedType = PIECE_TYPE_NONE; - // Find source squares for king and rook Square kfrom = move_from(m); - Square rfrom = move_to(m); // HACK: See comment at beginning of function + Square rfrom = move_to(m); Square kto, rto; assert(piece_on(kfrom) == make_piece(us, KING)); @@ -1163,28 +1113,30 @@ void Position::do_castle_move(Move m) { { kto = relative_square(us, SQ_G1); rto = relative_square(us, SQ_F1); - } else { // O-O-O + } + else // O-O-O + { kto = relative_square(us, SQ_C1); rto = relative_square(us, SQ_D1); } - // Remove pieces from source squares: - clear_bit(&(byColorBB[us]), kfrom); - clear_bit(&(byTypeBB[KING]), kfrom); - clear_bit(&(byTypeBB[0]), kfrom); // HACK: byTypeBB[0] == occupied squares - clear_bit(&(byColorBB[us]), rfrom); - clear_bit(&(byTypeBB[ROOK]), rfrom); - clear_bit(&(byTypeBB[0]), rfrom); // HACK: byTypeBB[0] == occupied squares - - // Put pieces on destination squares: - set_bit(&(byColorBB[us]), kto); - set_bit(&(byTypeBB[KING]), kto); - set_bit(&(byTypeBB[0]), kto); // HACK: byTypeBB[0] == occupied squares - set_bit(&(byColorBB[us]), rto); - set_bit(&(byTypeBB[ROOK]), rto); - set_bit(&(byTypeBB[0]), rto); // HACK: byTypeBB[0] == occupied squares - - // Update board array + // Remove pieces from source squares + clear_bit(&byColorBB[us], kfrom); + clear_bit(&byTypeBB[KING], kfrom); + clear_bit(&byTypeBB[0], kfrom); + clear_bit(&byColorBB[us], rfrom); + clear_bit(&byTypeBB[ROOK], rfrom); + clear_bit(&byTypeBB[0], rfrom); + + // Put pieces on destination squares + set_bit(&byColorBB[us], kto); + set_bit(&byTypeBB[KING], kto); + set_bit(&byTypeBB[0], kto); + set_bit(&byColorBB[us], rto); + set_bit(&byTypeBB[ROOK], rto); + set_bit(&byTypeBB[0], rto); + + // Update board Piece king = make_piece(us, KING); Piece rook = make_piece(us, ROOK); board[kfrom] = board[rfrom] = PIECE_NONE; @@ -1194,10 +1146,13 @@ void Position::do_castle_move(Move m) { // Update piece lists pieceList[us][KING][index[kfrom]] = kto; pieceList[us][ROOK][index[rfrom]] = rto; - int tmp = index[rfrom]; // In Chess960 could be rto == kfrom + int tmp = index[rfrom]; // In Chess960 could be kto == rfrom index[kto] = index[kfrom]; index[rto] = tmp; + // Reset capture field + st->capturedType = PIECE_TYPE_NONE; + // Update incremental scores st->value += pst_delta(king, kfrom, kto); st->value += pst_delta(rook, rfrom, rto); @@ -1222,7 +1177,7 @@ void Position::do_castle_move(Move m) { st->rule50 = 0; // Update checkers BB - st->checkersBB = attackers_to(king_square(them)) & pieces_of_color(us); + st->checkersBB = attackers_to(king_square(them)) & pieces(us); // Finish sideToMove = opposite_color(sideToMove); @@ -1273,8 +1228,8 @@ void Position::undo_move(Move m) { assert(piece_on(to) == make_piece(us, promotion)); // Replace promoted piece with a pawn - clear_bit(&(byTypeBB[promotion]), to); - set_bit(&(byTypeBB[PAWN]), to); + clear_bit(&byTypeBB[promotion], to); + set_bit(&byTypeBB[PAWN], to); // Update piece counts pieceCount[us][promotion]--; @@ -1291,9 +1246,9 @@ void Position::undo_move(Move m) { // Put the piece back at the source square Bitboard move_bb = make_move_bb(to, from); - do_move_bb(&(byColorBB[us]), move_bb); - do_move_bb(&(byTypeBB[pt]), move_bb); - do_move_bb(&(byTypeBB[0]), move_bb); // HACK: byTypeBB[0] == occupied squares + do_move_bb(&byColorBB[us], move_bb); + do_move_bb(&byTypeBB[pt], move_bb); + do_move_bb(&byTypeBB[0], move_bb); // HACK: byTypeBB[0] == occupied squares board[from] = make_piece(us, pt); board[to] = PIECE_NONE; @@ -1313,9 +1268,9 @@ void Position::undo_move(Move m) { assert(!ep || square_is_empty(capsq)); // Restore the captured piece - set_bit(&(byColorBB[them]), capsq); - set_bit(&(byTypeBB[st->capturedType]), capsq); - set_bit(&(byTypeBB[0]), capsq); + set_bit(&byColorBB[them], capsq); + set_bit(&byTypeBB[st->capturedType], capsq); + set_bit(&byTypeBB[0], capsq); board[capsq] = make_piece(them, st->capturedType); @@ -1345,13 +1300,13 @@ void Position::undo_castle_move(Move m) { assert(move_is_castle(m)); // When we have arrived here, some work has already been done by - // Position::undo_move. In particular, the side to move has been switched, + // Position::undo_move. In particular, the side to move has been switched, // so the code below is correct. Color us = side_to_move(); // Find source squares for king and rook Square kfrom = move_from(m); - Square rfrom = move_to(m); // HACK: See comment at beginning of function + Square rfrom = move_to(m); Square kto, rto; // Find destination squares for king and rook @@ -1359,7 +1314,9 @@ void Position::undo_castle_move(Move m) { { kto = relative_square(us, SQ_G1); rto = relative_square(us, SQ_F1); - } else { // O-O-O + } + else // O-O-O + { kto = relative_square(us, SQ_C1); rto = relative_square(us, SQ_D1); } @@ -1367,26 +1324,28 @@ void Position::undo_castle_move(Move m) { assert(piece_on(kto) == make_piece(us, KING)); assert(piece_on(rto) == make_piece(us, ROOK)); - // Remove pieces from destination squares: - clear_bit(&(byColorBB[us]), kto); - clear_bit(&(byTypeBB[KING]), kto); - clear_bit(&(byTypeBB[0]), kto); // HACK: byTypeBB[0] == occupied squares - clear_bit(&(byColorBB[us]), rto); - clear_bit(&(byTypeBB[ROOK]), rto); - clear_bit(&(byTypeBB[0]), rto); // HACK: byTypeBB[0] == occupied squares - - // Put pieces on source squares: - set_bit(&(byColorBB[us]), kfrom); - set_bit(&(byTypeBB[KING]), kfrom); - set_bit(&(byTypeBB[0]), kfrom); // HACK: byTypeBB[0] == occupied squares - set_bit(&(byColorBB[us]), rfrom); - set_bit(&(byTypeBB[ROOK]), rfrom); - set_bit(&(byTypeBB[0]), rfrom); // HACK: byTypeBB[0] == occupied squares + // Remove pieces from destination squares + clear_bit(&byColorBB[us], kto); + clear_bit(&byTypeBB[KING], kto); + clear_bit(&byTypeBB[0], kto); + clear_bit(&byColorBB[us], rto); + clear_bit(&byTypeBB[ROOK], rto); + clear_bit(&byTypeBB[0], rto); + + // Put pieces on source squares + set_bit(&byColorBB[us], kfrom); + set_bit(&byTypeBB[KING], kfrom); + set_bit(&byTypeBB[0], kfrom); + set_bit(&byColorBB[us], rfrom); + set_bit(&byTypeBB[ROOK], rfrom); + set_bit(&byTypeBB[0], rfrom); // Update board - board[rto] = board[kto] = PIECE_NONE; - board[rfrom] = make_piece(us, ROOK); - board[kfrom] = make_piece(us, KING); + Piece king = make_piece(us, KING); + Piece rook = make_piece(us, ROOK); + board[kto] = board[rto] = PIECE_NONE; + board[kfrom] = king; + board[rfrom] = rook; // Update piece lists pieceList[us][KING][index[kto]] = kfrom; @@ -1525,7 +1484,7 @@ int Position::see(Move m) const { // If the opponent has no attackers we are finished stm = opposite_color(piece_color(piece_on(from))); - stmAttackers = attackers & pieces_of_color(stm); + stmAttackers = attackers & pieces(stm); if (!stmAttackers) return PieceValueMidgame[capturedType]; @@ -1563,7 +1522,7 @@ int Position::see(Move m) const { // move before beginning the next iteration. capturedType = pt; stm = opposite_color(stm); - stmAttackers = attackers & pieces_of_color(stm); + stmAttackers = attackers & pieces(stm); // Stop before processing a king capture if (capturedType == KING && stmAttackers) @@ -1591,28 +1550,24 @@ void Position::clear() { st = &startState; memset(st, 0, sizeof(StateInfo)); st->epSquare = SQ_NONE; - startPosPlyCounter = 0; - nodes = 0; memset(byColorBB, 0, sizeof(Bitboard) * 2); memset(byTypeBB, 0, sizeof(Bitboard) * 8); memset(pieceCount, 0, sizeof(int) * 2 * 8); memset(index, 0, sizeof(int) * 64); - for (int i = 0; i < 64; i++) - board[i] = PIECE_NONE; - for (int i = 0; i < 8; i++) for (int j = 0; j < 16; j++) pieceList[0][i][j] = pieceList[1][i][j] = SQ_NONE; for (Square sq = SQ_A1; sq <= SQ_H8; sq++) + { + board[sq] = PIECE_NONE; castleRightsMask[sq] = ALL_CASTLES; - + } sideToMove = WHITE; - initialKFile = FILE_E; - initialKRFile = FILE_H; - initialQRFile = FILE_A; + fullMoves = 1; + nodes = 0; } @@ -1628,9 +1583,9 @@ void Position::put_piece(Piece p, Square s) { index[s] = pieceCount[c][pt]++; pieceList[c][pt][index[s]] = s; - set_bit(&(byTypeBB[pt]), s); - set_bit(&(byColorBB[c]), s); - set_bit(&(byTypeBB[0]), s); // HACK: byTypeBB[0] contains all occupied squares. + set_bit(&byTypeBB[pt], s); + set_bit(&byColorBB[c], s); + set_bit(&byTypeBB[0], s); // HACK: byTypeBB[0] contains all occupied squares. } @@ -1644,7 +1599,7 @@ Key Position::compute_key() const { Key result = zobCastle[st->castleRights]; for (Square s = SQ_A1; s <= SQ_H8; s++) - if (square_is_occupied(s)) + if (!square_is_empty(s)) result ^= zobrist[piece_color(piece_on(s))][piece_type(piece_on(s))][s]; if (ep_square() != SQ_NONE) @@ -1686,16 +1641,13 @@ Key Position::compute_pawn_key() const { Key Position::compute_material_key() const { - int count; Key result = 0; for (Color c = WHITE; c <= BLACK; c++) for (PieceType pt = PAWN; pt <= QUEEN; pt++) - { - count = piece_count(c, pt); - for (int i = 0; i < count; i++) + for (int i = 0, cnt = piece_count(c, pt); i < cnt; i++) result ^= zobrist[c][pt][i]; - } + return result; } @@ -1714,7 +1666,7 @@ Score Position::compute_value() const { { b = pieces(pt, c); while (b) - result += pst(c, pt, pop_1st_bit(&b)); + result += pst(make_piece(c, pt), pop_1st_bit(&b)); } result += (side_to_move() == WHITE ? TempoValue / 2 : -TempoValue / 2); @@ -1772,8 +1724,7 @@ template bool Position::is_draw() const; bool Position::is_mate() const { - MoveStack moves[MAX_MOVES]; - return in_check() && generate(*this, moves) == moves; + return in_check() && !MoveList(*this).size(); } @@ -1804,11 +1755,11 @@ void Position::init() { for (Square s = SQ_A1; s <= SQ_H8; s++) for (Piece p = WP; p <= WK; p++) - PieceSquareTable[p][s] = make_score(MgPST[p][s], EgPST[p][s]); + pieceSquareTable[p][s] = make_score(MgPST[p][s], EgPST[p][s]); for (Square s = SQ_A1; s <= SQ_H8; s++) for (Piece p = BP; p <= BK; p++) - PieceSquareTable[p][s] = -PieceSquareTable[p-8][flip_square(s)]; + pieceSquareTable[p][s] = -pieceSquareTable[p-8][flip_square(s)]; } @@ -1834,28 +1785,21 @@ void Position::flip() { sideToMove = opposite_color(pos.side_to_move()); // Castling rights - if (pos.can_castle_kingside(WHITE)) set_castle_kingside(BLACK); - if (pos.can_castle_queenside(WHITE)) set_castle_queenside(BLACK); - if (pos.can_castle_kingside(BLACK)) set_castle_kingside(WHITE); - if (pos.can_castle_queenside(BLACK)) set_castle_queenside(WHITE); - - initialKFile = pos.initialKFile; - initialKRFile = pos.initialKRFile; - initialQRFile = pos.initialQRFile; - - castleRightsMask[make_square(initialKFile, RANK_1)] ^= (WHITE_OO | WHITE_OOO); - castleRightsMask[make_square(initialKFile, RANK_8)] ^= (BLACK_OO | BLACK_OOO); - castleRightsMask[make_square(initialKRFile, RANK_1)] ^= WHITE_OO; - castleRightsMask[make_square(initialKRFile, RANK_8)] ^= BLACK_OO; - castleRightsMask[make_square(initialQRFile, RANK_1)] ^= WHITE_OOO; - castleRightsMask[make_square(initialQRFile, RANK_8)] ^= BLACK_OOO; + if (pos.can_castle(WHITE_OO)) + set_castle(BLACK_OO, king_square(BLACK), flip_square(pos.castle_rook_square(WHITE_OO))); + if (pos.can_castle(WHITE_OOO)) + set_castle(BLACK_OOO, king_square(BLACK), flip_square(pos.castle_rook_square(WHITE_OOO))); + if (pos.can_castle(BLACK_OO)) + set_castle(WHITE_OO, king_square(WHITE), flip_square(pos.castle_rook_square(BLACK_OO))); + if (pos.can_castle(BLACK_OOO)) + set_castle(WHITE_OOO, king_square(WHITE), flip_square(pos.castle_rook_square(BLACK_OOO))); // En passant square if (pos.st->epSquare != SQ_NONE) st->epSquare = flip_square(pos.st->epSquare); // Checkers - find_checkers(); + st->checkersBB = attackers_to(king_square(sideToMove)) & pieces(opposite_color(sideToMove)); // Hash keys st->key = compute_key(); @@ -1909,14 +1853,6 @@ bool Position::is_ok(int* failedStep) const { if (piece_on(king_square(BLACK)) != BK) return false; - // Castle files OK? - if (failedStep) (*failedStep)++; - if (!square_is_ok(make_square(initialKRFile, RANK_1))) - return false; - - if (!square_is_ok(make_square(initialQRFile, RANK_1))) - return false; - // Do both sides have exactly one king? if (failedStep) (*failedStep)++; if (debugKingCount) @@ -1937,7 +1873,7 @@ bool Position::is_ok(int* failedStep) const { Color us = side_to_move(); Color them = opposite_color(us); Square ksq = king_square(them); - if (attackers_to(ksq) & pieces_of_color(us)) + if (attackers_to(ksq) & pieces(us)) return false; } @@ -1951,12 +1887,12 @@ bool Position::is_ok(int* failedStep) const { if (debugBitboards) { // The intersection of the white and black pieces must be empty - if ((pieces_of_color(WHITE) & pieces_of_color(BLACK)) != EmptyBoardBB) + if ((pieces(WHITE) & pieces(BLACK)) != EmptyBoardBB) return false; // The union of the white and black pieces must be equal to all // occupied squares - if ((pieces_of_color(WHITE) | pieces_of_color(BLACK)) != occupied_squares()) + if ((pieces(WHITE) | pieces(BLACK)) != occupied_squares()) return false; // Separate piece type bitboards must have empty intersections @@ -2021,38 +1957,26 @@ bool Position::is_ok(int* failedStep) const { for (PieceType pt = PAWN; pt <= KING; pt++) for (int i = 0; i < pieceCount[c][pt]; i++) { - if (piece_on(piece_list(c, pt, i)) != make_piece(c, pt)) + if (piece_on(piece_list(c, pt)[i]) != make_piece(c, pt)) return false; - if (index[piece_list(c, pt, i)] != i) + if (index[piece_list(c, pt)[i]] != i) return false; } if (failedStep) (*failedStep)++; if (debugCastleSquares) - { - for (Color c = WHITE; c <= BLACK; c++) + for (CastleRight f = WHITE_OO; f <= BLACK_OOO; f = CastleRight(f << 1)) { - if (can_castle_kingside(c) && piece_on(initial_kr_square(c)) != make_piece(c, ROOK)) - return false; + if (!can_castle(f)) + continue; - if (can_castle_queenside(c) && piece_on(initial_qr_square(c)) != make_piece(c, ROOK)) - return false; - } - // If we cannot castle castleRightsMask[] could be not valid, for instance when - // king initial file is FILE_A as queen rook. - if (can_castle(WHITE) || can_castle(BLACK)) - { - if (castleRightsMask[initial_kr_square(WHITE)] != (ALL_CASTLES ^ WHITE_OO)) - return false; - if (castleRightsMask[initial_qr_square(WHITE)] != (ALL_CASTLES ^ WHITE_OOO)) - return false; - if (castleRightsMask[initial_kr_square(BLACK)] != (ALL_CASTLES ^ BLACK_OO)) - return false; - if (castleRightsMask[initial_qr_square(BLACK)] != (ALL_CASTLES ^ BLACK_OOO)) + Piece rook = (f & (WHITE_OO | WHITE_OOO) ? WR : BR); + + if ( castleRightsMask[castleRookSquare[f]] != (ALL_CASTLES ^ f) + || piece_on(castleRookSquare[f]) != rook) return false; } - } if (failedStep) *failedStep = 0; return true;