X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fposition.cpp;h=0dbbbddf81449b399386e7ae8e87585ffb4f90ca;hp=7166e8f1e8cf1aca22a216d46be5671556948ddb;hb=c9b24c3358a26afdec5e33e369b6192039562971;hpb=351ef5c85b6d4b9c71e9da367f0be5ab6e6f8117 diff --git a/src/position.cpp b/src/position.cpp index 7166e8f1..0dbbbddf 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 } @@ -159,64 +159,56 @@ void Position::from_fen(const string& fen, bool isChess960) { */ char token; - int hmc, fmn; size_t p; + string ep; Square sq = SQ_A8; std::istringstream ss(fen); clear(); - ss >> std::noskipws; + ss >> std::skipws >> 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 >> std::skipws >> token; sideToMove = (token == 'w' ? WHITE : BLACK); - if (!(ss >> token) || !isspace(token)) - goto incorrect_fen; - // 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'))) + ss >> token >> std::noskipws; + while (token != '-' && !isspace(token)) + { + set_castling_rights(token); + ss >> token; + } + + // 4. En passant square. Ignore if no pawn capture is possible + ss >> std::skipws >> ep; + if (ep.size() == 2) { - st->epSquare = make_square(File(col - 'a') + FILE_A, Rank(row - '1') + RANK_1); + st->epSquare = make_square(File(ep[0] - 'a'), Rank(ep[1] - '1')); - // Ignore if no capture is possible - Color them = opposite_color(sideToMove); - if (!(attacks_from(st->epSquare, them) & pieces(PAWN, sideToMove))) + if (!(attackers_to(st->epSquare) & 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 >> st->rule50 >> fullMoves; // Various initialisations castleRightsMask[make_square(initialKFile, RANK_1)] ^= WHITE_OO | WHITE_OOO; @@ -235,10 +227,6 @@ 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; - -incorrect_fen: - cout << "Error in FEN string: " << fen << endl; } @@ -249,39 +237,39 @@ 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)); - if (token == 'K') + if (toupper(token) == 'K') { for (Square sq = sqH; sq >= sqA; sq--) - if (piece_on(sq) == rook) + if (piece_on(sq) == make_piece(c, ROOK)) { set_castle_kingside(c); initialKRFile = square_file(sq); break; } } - else if (token == 'Q') + else if (toupper(token) == 'Q') { for (Square sq = sqA; sq <= sqH; sq++) - if (piece_on(sq) == rook) + if (piece_on(sq) == make_piece(c, ROOK)) { set_castle_queenside(c); initialQRFile = square_file(sq); break; } } - else if (token >= 'A' && token <= 'H') + else if (toupper(token) >= 'A' && toupper(token) <= 'H') { - File rookFile = File(token - 'A') + FILE_A; + File rookFile = File(toupper(token) - 'A'); + if (rookFile < initialKFile) { set_castle_queenside(c); @@ -293,10 +281,6 @@ bool Position::set_castling_rights(char token) { initialKRFile = rookFile; } } - else - return token == '-'; - - return true; } @@ -366,7 +350,7 @@ void Position::print(Move move) const { if (move) { Position p(*this, thread()); - string dd = (color_of_piece_on(move_from(move)) == BLACK ? ".." : ""); + string dd = (piece_color(piece_on(move_from(move))) == BLACK ? ".." : ""); cout << "\nMove is: " << dd << move_to_san(p, move); } @@ -381,7 +365,7 @@ void Position::print(Move move) const { if (piece == PIECE_NONE && square_color(sq) == DARK) piece = PIECE_NONE_DARK_SQ; - char c = (color_of_piece_on(sq) == BLACK ? '=' : ' '); + char c = (piece_color(piece_on(sq)) == BLACK ? '=' : ' '); cout << c << PieceToChar[piece] << c << '|'; } } @@ -520,7 +504,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(color_of_piece_on(f)); + & pieces_of_color(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. @@ -552,7 +536,7 @@ bool Position::pl_move_is_legal(Move m, Bitboard pinned) const { Color us = side_to_move(); Square from = move_from(m); - assert(color_of_piece_on(from) == us); + 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 @@ -582,7 +566,7 @@ bool Position::pl_move_is_legal(Move m, Bitboard pinned) const { // If the moving piece is a king, check whether the destination // square is attacked by the opponent. Castling moves are checked // for legality during move generation. - if (type_of_piece_on(from) == KING) + if (piece_type(piece_on(from)) == KING) return move_is_castle(m) || !(attackers_to(move_to(m)) & pieces_of_color(opposite_color(us))); // A non-king move is legal if and only if it is not pinned or it @@ -593,8 +577,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 +597,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 { @@ -636,15 +620,15 @@ bool Position::move_is_pl(const Move m) const { // If the from square is not occupied by a piece belonging to the side to // move, the move is obviously not legal. - if (pc == PIECE_NONE || color_of_piece(pc) != us) + if (pc == PIECE_NONE || piece_color(pc) != us) return false; // The destination square cannot be occupied by a friendly piece - if (color_of_piece_on(to) == us) + if (piece_color(piece_on(to)) == us) return false; // Handle the special case of a pawn move - if (type_of_piece(pc) == PAWN) + if (piece_type(pc) == PAWN) { // Move direction must be compatible with pawn color int direction = to - from; @@ -666,7 +650,7 @@ bool Position::move_is_pl(const Move m) const { case DELTA_SE: // Capture. The destination square must be occupied by an enemy // piece (en passant captures was handled earlier). - if (color_of_piece_on(to) != them) + if (piece_color(piece_on(to)) != them) return false; // From and to files must be one file apart, avoids a7h5 @@ -712,7 +696,7 @@ bool Position::move_is_pl(const Move m) const { { // In case of king moves under check we have to remove king so to catch // as invalid moves like b1a1 when opposite queen is on c1. - if (type_of_piece_on(from) == KING) + if (piece_type(piece_on(from)) == KING) { Bitboard b = occupied_squares(); clear_bit(&b, from); @@ -745,11 +729,11 @@ bool Position::move_gives_check(Move m, const CheckInfo& ci) const { assert(is_ok()); assert(move_is_ok(m)); assert(ci.dcCandidates == discovered_check_candidates(side_to_move())); - assert(color_of_piece_on(move_from(m)) == side_to_move()); + assert(piece_color(piece_on(move_from(m))) == side_to_move()); Square from = move_from(m); Square to = move_to(m); - PieceType pt = type_of_piece_on(from); + PieceType pt = piece_type(piece_on(from)); // Direct check ? if (bit_is_set(ci.checkSq[pt], to)) @@ -839,6 +823,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 +834,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(); @@ -917,11 +902,11 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI bool pm = move_is_promotion(m); Piece piece = piece_on(from); - PieceType pt = type_of_piece(piece); - PieceType capture = ep ? PAWN : type_of_piece_on(to); + PieceType pt = piece_type(piece); + PieceType capture = ep ? PAWN : piece_type(piece_on(to)); - assert(color_of_piece_on(from) == us); - assert(color_of_piece_on(to) == them || square_is_empty(to)); + assert(piece_color(piece_on(from)) == us); + assert(piece_color(piece_on(to)) == them || square_is_empty(to)); assert(!(ep || pm) || piece == make_piece(us, PAWN)); assert(!pm || relative_rank(us, to) == RANK_8); @@ -1255,10 +1240,10 @@ void Position::undo_move(Move m) { bool ep = move_is_ep(m); bool pm = move_is_promotion(m); - PieceType pt = type_of_piece_on(to); + PieceType pt = piece_type(piece_on(to)); assert(square_is_empty(from)); - assert(color_of_piece_on(to) == us); + assert(piece_color(piece_on(to)) == us); assert(!pm || relative_rank(us, to) == RANK_8); assert(!ep || to == st->previous->epSquare); assert(!ep || relative_rank(us, to) == RANK_6); @@ -1502,16 +1487,16 @@ int Position::see(Move m) const { from = move_from(m); to = move_to(m); - capturedType = type_of_piece_on(to); + capturedType = piece_type(piece_on(to)); occupied = occupied_squares(); // Handle en passant moves - if (st->epSquare == to && type_of_piece_on(from) == PAWN) + if (st->epSquare == to && piece_type(piece_on(from)) == PAWN) { Square capQq = (side_to_move() == WHITE ? to - DELTA_N : to - DELTA_S); assert(capturedType == PIECE_TYPE_NONE); - assert(type_of_piece_on(capQq) == PAWN); + assert(piece_type(piece_on(capQq)) == PAWN); // Remove the captured pawn clear_bit(&occupied, capQq); @@ -1524,7 +1509,7 @@ int Position::see(Move m) const { attackers = attackers_to(to, occupied); // If the opponent has no attackers we are finished - stm = opposite_color(color_of_piece_on(from)); + stm = opposite_color(piece_color(piece_on(from))); stmAttackers = attackers & pieces_of_color(stm); if (!stmAttackers) return PieceValueMidgame[capturedType]; @@ -1536,7 +1521,7 @@ int Position::see(Move m) const { // capture with the least valuable piece. After each capture, we look for // new X-ray attacks from behind the capturing piece. swapList[0] = PieceValueMidgame[capturedType]; - capturedType = type_of_piece_on(from); + capturedType = piece_type(piece_on(from)); do { // Locate the least valuable attacker for the side to move. The loop @@ -1591,7 +1576,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); @@ -1621,8 +1606,8 @@ void Position::clear() { void Position::put_piece(Piece p, Square s) { - Color c = color_of_piece(p); - PieceType pt = type_of_piece(p); + Color c = piece_color(p); + PieceType pt = piece_type(p); board[s] = p; index[s] = pieceCount[c][pt]++; @@ -1645,7 +1630,7 @@ Key Position::compute_key() const { for (Square s = SQ_A1; s <= SQ_H8; s++) if (square_is_occupied(s)) - result ^= zobrist[color_of_piece_on(s)][type_of_piece_on(s)][s]; + result ^= zobrist[piece_color(piece_on(s))][piece_type(piece_on(s))][s]; if (ep_square() != SQ_NONE) result ^= zobEp[ep_square()]; @@ -1923,8 +1908,8 @@ bool Position::is_ok(int* failedStep) const { { int kingCount[2] = {0, 0}; for (Square s = SQ_A1; s <= SQ_H8; s++) - if (type_of_piece_on(s) == KING) - kingCount[color_of_piece_on(s)]++; + if (piece_type(piece_on(s)) == KING) + kingCount[piece_color(piece_on(s))]++; if (kingCount[0] != 1 || kingCount[1] != 1) return false;