X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fposition.cpp;h=bc94fe82acb02b064c4d7b1203efed8d4d36ace8;hp=bb9ec00c9f66f84caf03cc89e88420028d14ad88;hb=ffb638995d21077f5a7632b6d57e4edc7637611b;hpb=ae2f5f25cd8a6bc2762eefc032436052c0db679e diff --git a/src/position.cpp b/src/position.cpp index bb9ec00c..bc94fe82 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -48,8 +48,8 @@ Score Position::PieceSquareTable[16][64]; 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 } @@ -158,74 +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); clear(); - ss >> std::noskipws; + ss >> token >> std::noskipws; - // 1. Piece placement field - while ((ss >> token) && !isspace(token)) + // 1. Piece placement + while (!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; + + ss >> token; } // 2. Active color - if (!(ss >> token) || (token != 'w' && token != 'b')) - goto incorrect_fen; - + ss >> token; sideToMove = (token == 'w' ? WHITE : BLACK); - - if (!(ss >> token) || !isspace(token)) - goto incorrect_fen; + ss >> token; // 3. Castling availability while ((ss >> token) && !isspace(token)) - if (!set_castling_rights(token)) - goto incorrect_fen; + set_castling_rights(token); - // 4. En passant square - char col, row; + // 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') + FILE_A, Rank(row - '1') + RANK_1); - - // Ignore if no capture is possible + 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 + ss >> 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(); @@ -235,10 +217,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. -incorrect_fen: - cout << "Error in FEN string: " << fen << endl; +void Position::set_castle(int f, Square ksq, Square rsq) { + + st->castleRights |= f; + castleRightsMask[ksq] ^= f; + castleRightsMask[rsq] ^= f; + castleRookSquare[f] = rsq; } @@ -249,54 +239,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 = islower(token) ? BLACK : WHITE; - 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); + Square sqA = relative_square(c, SQ_A1); + Square sqH = relative_square(c, SQ_H1); - initialKFile = square_file(king_square(c)); - token = char(toupper(token)); + Square rsq, ksq = king_square(c); + token = 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); } @@ -337,17 +304,17 @@ const string Position::to_fen() const { 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 += '-'; @@ -593,8 +560,8 @@ 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 +/// Position::move_is_pl_slow() takes 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 { @@ -613,8 +580,8 @@ bool Position::move_is_pl_slow(const Move m) const { } -/// 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 { @@ -839,6 +806,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 +817,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(); @@ -1591,7 +1559,7 @@ void Position::clear() { st = &startState; memset(st, 0, sizeof(StateInfo)); st->epSquare = SQ_NONE; - startPosPlyCounter = 0; + fullMoves = 1; nodes = 0; memset(byColorBB, 0, sizeof(Bitboard) * 2); @@ -1610,9 +1578,6 @@ void Position::clear() { castleRightsMask[sq] = ALL_CASTLES; sideToMove = WHITE; - initialKFile = FILE_E; - initialKRFile = FILE_H; - initialQRFile = FILE_A; } @@ -1686,16 +1651,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; } @@ -1834,21 +1796,14 @@ 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) @@ -1909,14 +1864,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) @@ -2030,24 +1977,17 @@ bool Position::is_ok(int* failedStep) const { 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)) + Piece rook = (f & (WHITE_OO | WHITE_OOO) ? WR : BR); + + if ( castleRightsMask[castleRookSquare[f]] != (ALL_CASTLES ^ f) + || piece_on(castleRookSquare[f]) != rook) return false; } - 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)) - return false; - } if (failedStep) *failedStep = 0; return true;