X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fposition.cpp;h=5b2efabec3181399592b564bbbaddf1758a4b064;hp=f42377de24577ec6f87aded6099b86a159a4b2ab;hb=805afcbf3d5db39c85b759232cfb99ab0a250311;hpb=d30994ecd54bf96db88016fb6d92ff2c4614bc2e diff --git a/src/position.cpp b/src/position.cpp index f42377de..5b2efabe 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -81,25 +81,6 @@ PieceType min_attacker(const Bitboard*, Square, Bitboard, Bitboard&, Bitbo } // namespace -/// CheckInfo constructor - -CheckInfo::CheckInfo(const Position& pos) { - - Color them = ~pos.side_to_move(); - ksq = pos.square(them); - - pinned = pos.pinned_pieces(pos.side_to_move()); - dcCandidates = pos.discovered_check_candidates(); - - checkSquares[PAWN] = pos.attacks_from(ksq, them); - checkSquares[KNIGHT] = pos.attacks_from(ksq); - checkSquares[BISHOP] = pos.attacks_from(ksq); - checkSquares[ROOK] = pos.attacks_from(ksq); - checkSquares[QUEEN] = checkSquares[BISHOP] | checkSquares[ROOK]; - checkSquares[KING] = 0; -} - - /// operator<<(Position) returns an ASCII representation of the position std::ostream& operator<<(std::ostream& os, const Position& pos) { @@ -155,42 +136,11 @@ void Position::init() { } -/// Position::operator=() creates a copy of 'pos' but detaching the state pointer -/// from the source to be self-consistent and not depending on any external data. - -Position& Position::operator=(const Position& pos) { - - std::memcpy(this, &pos, sizeof(Position)); - std::memcpy(&startState, st, sizeof(StateInfo)); - st = &startState; - nodes = 0; - - assert(pos_is_ok()); - - return *this; -} - - -/// Position::clear() erases the position object to a pristine state, with an -/// empty board, white to move, and no castling rights. - -void Position::clear() { - - std::memset(this, 0, sizeof(Position)); - startState.epSquare = SQ_NONE; - st = &startState; - - for (int i = 0; i < PIECE_TYPE_NB; ++i) - for (int j = 0; j < 16; ++j) - pieceList[WHITE][i][j] = pieceList[BLACK][i][j] = SQ_NONE; -} - - /// Position::set() initializes the position object with the given FEN 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::set(const string& fenStr, bool isChess960, Thread* th) { +Position& Position::set(const string& fenStr, bool isChess960, StateInfo* si, Thread* th) { /* A FEN string defines a particular position using only the ASCII character set. @@ -230,7 +180,11 @@ void Position::set(const string& fenStr, bool isChess960, Thread* th) { Square sq = SQ_A8; std::istringstream ss(fenStr); - clear(); + std::memset(this, 0, sizeof(Position)); + std::memset(si, 0, sizeof(StateInfo)); + std::fill_n(&pieceList[0][0][0], sizeof(pieceList) / sizeof(Square), SQ_NONE); + st = si; + ss >> std::noskipws; // 1. Piece placement @@ -291,6 +245,8 @@ void Position::set(const string& fenStr, bool isChess960, Thread* th) { if (!(attackers_to(st->epSquare) & pieces(sideToMove, PAWN))) st->epSquare = SQ_NONE; } + else + st->epSquare = SQ_NONE; // 5-6. Halfmove clock and fullmove number ss >> std::skipws >> st->rule50 >> gamePly; @@ -304,6 +260,8 @@ void Position::set(const string& fenStr, bool isChess960, Thread* th) { set_state(st); assert(pos_is_ok()); + + return *this; } @@ -334,6 +292,24 @@ void Position::set_castling_right(Color c, Square rfrom) { } +/// Position::set_check_info() sets king attacks to detect if a move gives check + +void Position::set_check_info(CheckInfo* ci) const { + + ci->blockersForKing[WHITE] = slider_blockers(pieces(BLACK), square(WHITE)); + ci->blockersForKing[BLACK] = slider_blockers(pieces(WHITE), square(BLACK)); + + Square ksq = ci->ksq = square(~sideToMove); + + ci->checkSquares[PAWN] = attacks_from(ksq, ~sideToMove); + ci->checkSquares[KNIGHT] = attacks_from(ksq); + ci->checkSquares[BISHOP] = attacks_from(ksq); + ci->checkSquares[ROOK] = attacks_from(ksq); + ci->checkSquares[QUEEN] = ci->checkSquares[BISHOP] | ci->checkSquares[ROOK]; + ci->checkSquares[KING] = 0; +} + + /// Position::set_state() computes the hash keys of the position, and other /// data that once computed is updated incrementally as moves are made. /// The function is only used when a new position is set up, and to verify @@ -344,9 +320,10 @@ void Position::set_state(StateInfo* si) const { si->key = si->pawnKey = si->materialKey = 0; si->nonPawnMaterial[WHITE] = si->nonPawnMaterial[BLACK] = VALUE_ZERO; si->psq = SCORE_ZERO; - si->checkersBB = attackers_to(square(sideToMove)) & pieces(~sideToMove); + set_check_info(&si->ci); + for (Bitboard b = pieces(); b; ) { Square s = pop_lsb(&b); @@ -443,28 +420,27 @@ Phase Position::game_phase() const { } -/// Position::check_blockers() returns a bitboard of all the pieces with color -/// 'c' that are blocking check on the king with color 'kingColor'. A piece -/// blocks a check if removing that piece from the board would result in a -/// position where the king is in check. A check blocking piece can be either a -/// pinned or a discovered check piece, according if its color 'c' is the same -/// or the opposite of 'kingColor'. +/// Position::slider_blockers() returns a bitboard of all the pieces (both colors) that +/// are blocking attacks on the square 's' from 'sliders'. A piece blocks a slider +/// if removing that piece from the board would result in a position where square 's' +/// is attacked. For example, a king-attack blocking piece can be either a pinned or +/// a discovered check piece, according if its color is the opposite or the same of +/// the color of the slider. -Bitboard Position::check_blockers(Color c, Color kingColor) const { +Bitboard Position::slider_blockers(Bitboard sliders, Square s) const { Bitboard b, pinners, result = 0; - Square ksq = square(kingColor); - // Pinners are sliders that give check when a pinned piece is removed - pinners = ( (pieces( ROOK, QUEEN) & PseudoAttacks[ROOK ][ksq]) - | (pieces(BISHOP, QUEEN) & PseudoAttacks[BISHOP][ksq])) & pieces(~kingColor); + // Pinners are sliders that attack 's' when a pinned piece is removed + pinners = ( (PseudoAttacks[ROOK ][s] & pieces(QUEEN, ROOK)) + | (PseudoAttacks[BISHOP][s] & pieces(QUEEN, BISHOP))) & sliders; while (pinners) { - b = between_bb(ksq, pop_lsb(&pinners)) & pieces(); + b = between_bb(s, pop_lsb(&pinners)) & pieces(); if (!more_than_one(b)) - result |= b & pieces(c); + result |= b; } return result; } @@ -486,10 +462,9 @@ Bitboard Position::attackers_to(Square s, Bitboard occupied) const { /// Position::legal() tests whether a pseudo-legal move is legal -bool Position::legal(Move m, Bitboard pinned) const { +bool Position::legal(Move m) const { assert(is_ok(m)); - assert(pinned == pinned_pieces(sideToMove)); Color us = sideToMove; Square from = from_sq(m); @@ -524,8 +499,7 @@ bool Position::legal(Move m, Bitboard pinned) const { // 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. - return !pinned - || !(pinned & from) + return !(pinned_pieces(us) & from) || aligned(from, to_sq(m), square(us)); } @@ -604,23 +578,21 @@ bool Position::pseudo_legal(const Move m) const { /// Position::gives_check() tests whether a pseudo-legal move gives a check -bool Position::gives_check(Move m, const CheckInfo& ci) const { +bool Position::gives_check(Move m) const { assert(is_ok(m)); - assert(ci.dcCandidates == discovered_check_candidates()); assert(color_of(moved_piece(m)) == sideToMove); Square from = from_sq(m); Square to = to_sq(m); // Is there a direct check? - if (ci.checkSquares[type_of(piece_on(from))] & to) + if (st->ci.checkSquares[type_of(piece_on(from))] & to) return true; // Is there a discovered check? - if ( ci.dcCandidates - && (ci.dcCandidates & from) - && !aligned(from, to, ci.ksq)) + if ( (discovered_check_candidates() & from) + && !aligned(from, to, st->ci.ksq)) return true; switch (type_of(m)) @@ -629,7 +601,7 @@ bool Position::gives_check(Move m, const CheckInfo& ci) const { return false; case PROMOTION: - return attacks_bb(Piece(promotion_type(m)), to, pieces() ^ from) & ci.ksq; + return attacks_bb(Piece(promotion_type(m)), to, pieces() ^ from) & st->ci.ksq; // En passant capture with check? We have already handled the case // of direct checks and ordinary discovered check, so the only case we @@ -640,8 +612,8 @@ bool Position::gives_check(Move m, const CheckInfo& ci) const { Square capsq = make_square(file_of(to), rank_of(from)); Bitboard b = (pieces() ^ from ^ capsq) | to; - return (attacks_bb< ROOK>(ci.ksq, b) & pieces(sideToMove, QUEEN, ROOK)) - | (attacks_bb(ci.ksq, b) & pieces(sideToMove, QUEEN, BISHOP)); + return (attacks_bb< ROOK>(st->ci.ksq, b) & pieces(sideToMove, QUEEN, ROOK)) + | (attacks_bb(st->ci.ksq, b) & pieces(sideToMove, QUEEN, BISHOP)); } case CASTLING: { @@ -650,8 +622,8 @@ bool Position::gives_check(Move m, const CheckInfo& ci) const { Square kto = relative_square(sideToMove, rfrom > kfrom ? SQ_G1 : SQ_C1); Square rto = relative_square(sideToMove, rfrom > kfrom ? SQ_F1 : SQ_D1); - return (PseudoAttacks[ROOK][rto] & ci.ksq) - && (attacks_bb(rto, (pieces() ^ kfrom ^ rfrom) | rto | kto) & ci.ksq); + return (PseudoAttacks[ROOK][rto] & st->ci.ksq) + && (attacks_bb(rto, (pieces() ^ kfrom ^ rfrom) | rto | kto) & st->ci.ksq); } default: assert(false); @@ -827,6 +799,9 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) { sideToMove = ~sideToMove; + // Update CheckInfo + set_check_info(&st->ci); + assert(pos_is_ok()); } @@ -940,6 +915,8 @@ void Position::do_null_move(StateInfo& newSt) { sideToMove = ~sideToMove; + set_check_info(&st->ci); + assert(pos_is_ok()); } @@ -1108,7 +1085,7 @@ void Position::flip() { std::getline(ss, token); // Half and full moves f += token; - set(f, is_chess960(), this_thread()); + set(f, is_chess960(), st, this_thread()); assert(pos_is_ok()); }