X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;ds=sidebyside;f=src%2Fposition.cpp;h=9d7679ab0979e1daee7f38528d6b5bdb23d318e9;hb=f2e78d9f841b53b8d512ad2687ff982cf841df58;hp=6075117426972adf189674af9d0ce7ac4f5b8816;hpb=c2c185423b13b0227c86009c6006e48e8d258896;p=stockfish diff --git a/src/position.cpp b/src/position.cpp index 60751174..9d7679ab 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -102,7 +102,7 @@ Position::Position(const Position& pos, int th) { threadID = th; nodes = 0; - assert(is_ok()); + assert(pos_is_ok()); } Position::Position(const string& fen, bool isChess960, int th) { @@ -207,7 +207,7 @@ void Position::from_fen(const string& fenStr, bool isChess960) { st->npMaterial[WHITE] = compute_non_pawn_material(WHITE); st->npMaterial[BLACK] = compute_non_pawn_material(BLACK); - assert(is_ok()); + assert(pos_is_ok()); } @@ -342,7 +342,7 @@ void Position::print(Move move) const { Square sq = make_square(file, rank); Piece piece = piece_on(sq); - if (piece == PIECE_NONE && square_color(sq) == DARK) + if (piece == PIECE_NONE && color_of(sq) == DARK) piece = PIECE_NONE_DARK_SQ; char c = (color_of(piece_on(sq)) == BLACK ? '=' : ' '); @@ -400,18 +400,8 @@ Bitboard Position::discovered_check_candidates() const { return hidden_checkers(); } -/// Position::attackers_to() computes a bitboard containing all pieces which -/// attacks a given square. - -Bitboard Position::attackers_to(Square s) const { - - return (attacks_from(s, BLACK) & pieces(PAWN, WHITE)) - | (attacks_from(s, WHITE) & pieces(PAWN, BLACK)) - | (attacks_from(s) & pieces(KNIGHT)) - | (attacks_from(s) & pieces(ROOK, QUEEN)) - | (attacks_from(s) & pieces(BISHOP, QUEEN)) - | (attacks_from(s) & pieces(KING)); -} +/// Position::attackers_to() computes a bitboard of all pieces which attacks a +/// given square. Slider attacks use occ bitboard as occupancy. Bitboard Position::attackers_to(Square s, Bitboard occ) const { @@ -423,21 +413,8 @@ Bitboard Position::attackers_to(Square s, Bitboard occ) const { | (attacks_from(s) & pieces(KING)); } -/// Position::attacks_from() computes a bitboard of all attacks -/// of a given piece put in a given square. - -Bitboard Position::attacks_from(Piece p, Square s) const { - - assert(square_is_ok(s)); - - switch (p) - { - case WB: case BB: return attacks_from(s); - case WR: case BR: return attacks_from(s); - case WQ: case BQ: return attacks_from(s); - default: return StepAttacksBB[p][s]; - } -} +/// Position::attacks_from() computes a bitboard of all attacks of a given piece +/// put in a given square. Slider attacks use occ bitboard as occupancy. Bitboard Position::attacks_from(Piece p, Square s, Bitboard occ) { @@ -458,7 +435,7 @@ Bitboard Position::attacks_from(Piece p, Square s, Bitboard occ) { bool Position::move_attacks_square(Move m, Square s) const { - assert(move_is_ok(m)); + assert(is_ok(m)); assert(square_is_ok(s)); Bitboard occ, xray; @@ -486,7 +463,7 @@ bool Position::move_attacks_square(Move m, Square s) const { bool Position::pl_move_is_legal(Move m, Bitboard pinned) const { - assert(move_is_ok(m)); + assert(is_ok(m)); assert(pinned == pinned_pieces()); Color us = side_to_move(); @@ -498,7 +475,7 @@ bool Position::pl_move_is_legal(Move m, Bitboard pinned) const { // 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)) + if (is_enpassant(m)) { Color them = flip(us); Square to = move_to(m); @@ -523,7 +500,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 (type_of(piece_on(from)) == KING) - return move_is_castle(m) || !(attackers_to(move_to(m)) & pieces(flip(us))); + return is_castle(m) || !(attackers_to(move_to(m)) & pieces(flip(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. @@ -533,7 +510,7 @@ bool Position::pl_move_is_legal(Move m, Bitboard pinned) const { } -/// Position::move_is_legal() takes a move and tests whether the move +/// Position::move_is_legal() takes a random move and tests whether the move /// is legal. This version is not very fast and should be used only /// in non time-critical paths. @@ -547,10 +524,11 @@ bool Position::move_is_legal(const Move m) const { } -/// 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. +/// Position::is_pseudo_legal() takes a random move and tests whether the move +/// is pseudo legal. It is used to validate moves from TT that can be corrupted +/// due to SMP concurrent access or hash position key aliasing. -bool Position::move_is_pl(const Move m) const { +bool Position::is_pseudo_legal(const Move m) const { Color us = sideToMove; Color them = flip(sideToMove); @@ -559,7 +537,7 @@ bool Position::move_is_pl(const Move m) const { Piece pc = piece_on(from); // Use a slower but simpler function for uncommon cases - if (move_is_special(m)) + if (is_special(m)) return move_is_legal(m); // Is not a promotion, so promotion piece must be empty @@ -640,6 +618,9 @@ bool Position::move_is_pl(const Move m) const { else if (!bit_is_set(attacks_from(pc, from), to)) return false; + // Evasions generator already takes care to avoid some kind of illegal moves + // and pl_move_is_legal() relies on this. So we have to take care that the + // same kind of moves are filtered out here. if (in_check()) { // In case of king moves under check we have to remove king so to catch @@ -670,11 +651,11 @@ bool Position::move_is_pl(const Move m) const { } -/// Position::move_gives_check() tests whether a pseudo-legal move is a check +/// Position::move_gives_check() tests whether a pseudo-legal move gives a check bool Position::move_gives_check(Move m, const CheckInfo& ci) const { - assert(move_is_ok(m)); + assert(is_ok(m)); assert(ci.dcCandidates == discovered_check_candidates()); assert(color_of(piece_on(move_from(m))) == side_to_move()); @@ -696,7 +677,7 @@ bool Position::move_gives_check(Move m, const CheckInfo& ci) const { } // Can we skip the ugly special cases ? - if (!move_is_special(m)) + if (!is_special(m)) return false; Color us = side_to_move(); @@ -704,30 +685,17 @@ bool Position::move_gives_check(Move m, const CheckInfo& ci) const { Square ksq = king_square(flip(us)); // Promotion with check ? - if (move_is_promotion(m)) + if (is_promotion(m)) { clear_bit(&b, from); - - switch (promotion_piece_type(m)) - { - case KNIGHT: - return bit_is_set(attacks_from(to), ksq); - case BISHOP: - return bit_is_set(bishop_attacks_bb(to, b), ksq); - case ROOK: - return bit_is_set(rook_attacks_bb(to, b), ksq); - case QUEEN: - return bit_is_set(queen_attacks_bb(to, b), ksq); - default: - assert(false); - } + return bit_is_set(attacks_from(Piece(promotion_piece_type(m)), to, b), ksq); } // En passant capture with check ? We have already handled the case // of direct checks and ordinary discovered check, the only case we // need to handle is the unusual case of a discovered check through // the captured pawn. - if (move_is_ep(m)) + if (is_enpassant(m)) { Square capsq = make_square(file_of(to), rank_of(from)); clear_bit(&b, from); @@ -738,7 +706,7 @@ bool Position::move_gives_check(Move m, const CheckInfo& ci) const { } // Castling with check ? - if (move_is_castle(m)) + if (is_castle(m)) { Square kfrom, kto, rfrom, rto; kfrom = from; @@ -775,7 +743,7 @@ void Position::do_move(Move m, StateInfo& newSt) { void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveIsCheck) { - assert(move_is_ok(m)); + assert(is_ok(m)); assert(&newSt != st); nodes++; @@ -805,7 +773,7 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI st->rule50++; st->pliesFromNull++; - if (move_is_castle(m)) + if (is_castle(m)) { st->key = key; do_castle_move(m); @@ -816,8 +784,8 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI Color them = flip(us); Square from = move_from(m); Square to = move_to(m); - bool ep = move_is_ep(m); - bool pm = move_is_promotion(m); + bool ep = is_enpassant(m); + bool pm = is_promotion(m); Piece piece = piece_on(from); PieceType pt = type_of(piece); @@ -970,7 +938,7 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI sideToMove = flip(sideToMove); st->value += (sideToMove == WHITE ? TempoValue : -TempoValue); - assert(is_ok()); + assert(pos_is_ok()); } @@ -1044,8 +1012,8 @@ void Position::do_capture_move(Key& key, PieceType capture, Color them, Square t void Position::do_castle_move(Move m) { - assert(move_is_ok(m)); - assert(move_is_castle(m)); + assert(is_ok(m)); + assert(is_castle(m)); Color us = side_to_move(); Color them = flip(us); @@ -1133,7 +1101,7 @@ void Position::do_castle_move(Move m) { sideToMove = flip(sideToMove); st->value += (sideToMove == WHITE ? TempoValue : -TempoValue); - assert(is_ok()); + assert(pos_is_ok()); } @@ -1142,11 +1110,11 @@ void Position::do_castle_move(Move m) { void Position::undo_move(Move m) { - assert(move_is_ok(m)); + assert(is_ok(m)); sideToMove = flip(sideToMove); - if (move_is_castle(m)) + if (is_castle(m)) { undo_castle_move(m); return; @@ -1156,8 +1124,8 @@ void Position::undo_move(Move m) { Color them = flip(us); Square from = move_from(m); Square to = move_to(m); - bool ep = move_is_ep(m); - bool pm = move_is_promotion(m); + bool ep = is_enpassant(m); + bool pm = is_promotion(m); PieceType pt = type_of(piece_on(to)); @@ -1234,7 +1202,7 @@ void Position::undo_move(Move m) { // Finally point our state pointer back to the previous state st = st->previous; - assert(is_ok()); + assert(pos_is_ok()); } @@ -1245,8 +1213,8 @@ void Position::undo_move(Move m) { void Position::undo_castle_move(Move m) { - assert(move_is_ok(m)); - assert(move_is_castle(m)); + assert(is_ok(m)); + assert(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, @@ -1306,7 +1274,7 @@ void Position::undo_castle_move(Move m) { // Finally point our state pointer back to the previous state st = st->previous; - assert(is_ok()); + assert(pos_is_ok()); } @@ -1341,7 +1309,7 @@ void Position::do_null_move(StateInfo& backupSt) { st->pliesFromNull = 0; st->value += (sideToMove == WHITE) ? TempoValue : -TempoValue; - assert(is_ok()); + assert(pos_is_ok()); } @@ -1363,7 +1331,7 @@ void Position::undo_null_move() { sideToMove = flip(sideToMove); st->rule50--; - assert(is_ok()); + assert(pos_is_ok()); } @@ -1375,7 +1343,7 @@ void Position::undo_null_move() { int Position::see_sign(Move m) const { - assert(move_is_ok(m)); + assert(is_ok(m)); Square from = move_from(m); Square to = move_to(m); @@ -1383,7 +1351,7 @@ int Position::see_sign(Move m) const { // Early return if SEE cannot be negative because captured piece value // is not less then capturing one. Note that king moves always return // here because king midgame value is set to 0. - if (piece_value_midgame(piece_on(to)) >= piece_value_midgame(piece_on(from))) + if (PieceValueMidgame[piece_on(to)] >= PieceValueMidgame[piece_on(from)]) return 1; return see(m); @@ -1397,12 +1365,12 @@ int Position::see(Move m) const { PieceType capturedType, pt; Color stm; - assert(move_is_ok(m)); + assert(is_ok(m)); // As castle moves are implemented as capturing the rook, they have // SEE == RookValueMidgame most of the times (unless the rook is under // attack). - if (move_is_castle(m)) + if (is_castle(m)) return 0; from = move_from(m); @@ -1590,7 +1558,7 @@ Key Position::compute_material_key() const { for (Color c = WHITE; c <= BLACK; c++) for (PieceType pt = PAWN; pt <= QUEEN; pt++) - for (int i = 0, cnt = piece_count(c, pt); i < cnt; i++) + for (int i = 0; i < piece_count(c, pt); i++) result ^= zobrist[c][pt][i]; return result; @@ -1688,12 +1656,11 @@ bool Position::is_mate() const { } -/// Position::init() is a static member function which initializes at -/// startup the various arrays used to compute hash keys and the piece -/// square tables. The latter is a two-step operation: First, the white -/// halves of the tables are copied from the MgPST[][] and EgPST[][] arrays. -/// Second, the black halves of the tables are initialized by flipping -/// and changing the sign of the corresponding white scores. +/// Position::init() is a static member function which initializes at startup +/// the various arrays used to compute hash keys and the piece square tables. +/// The latter is a two-step operation: First, the white halves of the tables +/// are copied from PSQT[] tables. Second, the black halves of the tables are +/// initialized by flipping and changing the sign of the white scores. void Position::init() { @@ -1714,11 +1681,15 @@ void Position::init() { zobExclusion = rk.rand(); for (Piece p = WP; p <= WK; p++) + { + Score ps = make_score(PieceValueMidgame[p], PieceValueEndgame[p]); + for (Square s = SQ_A1; s <= SQ_H8; s++) { - pieceSquareTable[p][s] = make_score(MgPST[p][s], EgPST[p][s]); + pieceSquareTable[p][s] = ps + PSQT[p][s]; pieceSquareTable[p+8][flip(s)] = -pieceSquareTable[p][s]; } + } } @@ -1770,14 +1741,14 @@ void Position::flip_me() { st->npMaterial[WHITE] = compute_non_pawn_material(WHITE); st->npMaterial[BLACK] = compute_non_pawn_material(BLACK); - assert(is_ok()); + assert(pos_is_ok()); } -/// Position::is_ok() performs some consitency checks for the position object. +/// Position::pos_is_ok() performs some consitency checks for the position object. /// This is meant to be helpful when debugging. -bool Position::is_ok(int* failedStep) const { +bool Position::pos_is_ok(int* failedStep) const { // What features of the position should be verified? const bool debugAll = false;