X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fposition.cpp;h=eb3cb895b51b7e1e2acccafe6899ff01ff41a432;hb=e5077dc11e8047eb8ce32a166a73e433a7e19b15;hp=0dbbbddf81449b399386e7ae8e87585ffb4f90ca;hpb=c9b24c3358a26afdec5e33e369b6192039562971;p=stockfish diff --git a/src/position.cpp b/src/position.cpp index 0dbbbddf..eb3cb895 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -158,17 +158,16 @@ 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; + char col, row, token; size_t p; - string ep; Square sq = SQ_A8; std::istringstream ss(fen); clear(); - ss >> std::skipws >> token >> std::noskipws; + ss >> std::noskipws; // 1. Piece placement - while (!isspace(token)) + while ((ss >> token) && !isspace(token)) { if (token == '/') sq -= Square(16); // Jump back of 2 rows @@ -181,43 +180,32 @@ void Position::from_fen(const string& fen, bool isChess960) { put_piece(Piece(p), sq); sq++; } - - ss >> token; } // 2. Active color - ss >> std::skipws >> token; + ss >> token; sideToMove = (token == 'w' ? WHITE : BLACK); + ss >> token; // 3. Castling availability - ss >> token >> std::noskipws; - while (token != '-' && !isspace(token)) - { + while ((ss >> 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) + if ( ((ss >> col) && (col >= 'a' && col <= 'h')) + && ((ss >> row) && (row == '3' || row == '6'))) { - st->epSquare = make_square(File(ep[0] - 'a'), Rank(ep[1] - '1')); + st->epSquare = make_square(File(col - 'a'), Rank(row - '1')); + Color them = opposite_color(sideToMove); - if (!(attackers_to(st->epSquare) & pieces(PAWN, sideToMove))) + if (!(attacks_from(st->epSquare, them) & pieces(PAWN, sideToMove))) st->epSquare = SQ_NONE; } // 5-6. Halfmove clock and fullmove number - ss >> st->rule50 >> fullMoves; + 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(); @@ -230,6 +218,18 @@ void Position::from_fen(const string& fen, bool isChess960) { } +/// Position::set_castle() is an helper function used to set +/// correct castling related flags. + +void Position::set_castle(int f, Square ksq, Square rsq) { + + st->castleRights |= f; + castleRightsMask[ksq] ^= f; + castleRightsMask[rsq] ^= f; + castleRookSquare[f] = rsq; +} + + /// Position::set_castling_rights() sets castling parameters castling avaiability. /// This function is compatible with 3 standards: Normal FEN standard, Shredder-FEN /// that uses the letters of the columns on which the rooks began the game instead @@ -243,44 +243,25 @@ void Position::set_castling_rights(char token) { 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 = toupper(token); - if (toupper(token) == 'K') - { - for (Square sq = sqH; sq >= sqA; sq--) - if (piece_on(sq) == make_piece(c, ROOK)) - { - set_castle_kingside(c); - initialKRFile = square_file(sq); - break; - } - } - else if (toupper(token) == 'Q') - { - for (Square sq = sqA; sq <= sqH; sq++) - if (piece_on(sq) == make_piece(c, ROOK)) - { - set_castle_queenside(c); - initialQRFile = square_file(sq); - break; - } - } - else if (toupper(token) >= 'A' && toupper(token) <= 'H') - { - File rookFile = File(toupper(token) - 'A'); + if (token == 'K') + for (rsq = sqH; piece_on(rsq) != make_piece(c, ROOK); rsq--) {} - if (rookFile < initialKFile) - { - set_castle_queenside(c); - initialQRFile = rookFile; - } - else - { - set_castle_kingside(c); - initialKRFile = rookFile; - } - } + else if (token == 'Q') + for (rsq = sqA; piece_on(rsq) != make_piece(c, ROOK); rsq++) {} + + else if (token >= 'A' && token <= 'H') + rsq = make_square(File(token - 'A'), relative_rank(c, RANK_1)); + + else return; + + if (square_file(rsq) < square_file(ksq)) + set_castle(WHITE_OOO << c, ksq, rsq); + else + set_castle(WHITE_OO << c, ksq, rsq); } @@ -301,7 +282,7 @@ const string Position::to_fen() const { { sq = make_square(file, rank); - if (square_is_occupied(sq)) + if (!square_is_empty(sq)) { if (emptyCnt != '0') { @@ -321,17 +302,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 += '-'; @@ -383,7 +364,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. @@ -403,7 +384,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; @@ -494,7 +475,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; @@ -504,7 +485,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. @@ -521,7 +502,7 @@ bool Position::move_attacks_square(Move m, Square s) const { void Position::find_checkers() { Color us = side_to_move(); - st->checkersBB = attackers_to(king_square(us)) & pieces_of_color(opposite_color(us)); + st->checkersBB = attackers_to(king_square(us)) & pieces(opposite_color(us)); } @@ -567,7 +548,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. @@ -700,7 +681,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 @@ -1002,8 +983,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]; @@ -1029,7 +1010,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 @@ -1094,7 +1075,7 @@ void Position::do_capture_move(Key& key, PieceType capture, Color them, Square t 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]--; @@ -1207,7 +1188,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); @@ -1510,7 +1491,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]; @@ -1548,7 +1529,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) @@ -1576,28 +1557,24 @@ void Position::clear() { st = &startState; memset(st, 0, sizeof(StateInfo)); st->epSquare = SQ_NONE; - fullMoves = 1; - 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; } @@ -1613,9 +1590,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. } @@ -1629,7 +1606,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) @@ -1671,16 +1648,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; } @@ -1699,7 +1673,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); @@ -1819,21 +1793,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) @@ -1894,14 +1861,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) @@ -1922,7 +1881,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; } @@ -1936,12 +1895,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 @@ -2015,24 +1974,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;