X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fposition.cpp;h=9fe5f893c9da5f199577abeb283fa7942d4bee6e;hp=eeedbbb22d1fd8d332ed25deb83acdeb07dda9d3;hb=0162fb83c21b9ac4d5ed302d4bc5a12b7a0cfc43;hpb=ca6c9f85a5c3a45a248716b8fe68821b20eee201 diff --git a/src/position.cpp b/src/position.cpp index eeedbbb2..9fe5f893 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -20,7 +20,8 @@ #include #include -#include // For std::memset, std::memcmp +#include // For offsetof() +#include // For std::memset, std::memcmp #include #include @@ -34,6 +35,10 @@ using std::string; +namespace PSQT { + extern Score psq[PIECE_NB][SQUARE_NB]; +} + namespace Zobrist { Key psq[PIECE_NB][SQUARE_NB]; @@ -109,10 +114,9 @@ void Position::init() { PRNG rng(1070372); - for (Color c = WHITE; c <= BLACK; ++c) - for (PieceType pt = PAWN; pt <= KING; ++pt) - for (Square s = SQ_A1; s <= SQ_H8; ++s) - Zobrist::psq[make_piece(c, pt)][s] = rng.rand(); + for (Piece pc : Pieces) + for (Square s = SQ_A1; s <= SQ_H8; ++s) + Zobrist::psq[pc][s] = rng.rand(); for (File f = FILE_A; f <= FILE_H; ++f) Zobrist::enpassant[f] = rng.rand(); @@ -292,8 +296,8 @@ void Position::set_castling_right(Color c, Square rfrom) { void Position::set_check_info(StateInfo* si) const { - si->blockersForKing[WHITE] = slider_blockers(pieces(BLACK), square(WHITE)); - si->blockersForKing[BLACK] = slider_blockers(pieces(WHITE), square(BLACK)); + si->blockersForKing[WHITE] = slider_blockers(pieces(BLACK), square(WHITE), si->pinnersForKing[WHITE]); + si->blockersForKing[BLACK] = slider_blockers(pieces(WHITE), square(BLACK), si->pinnersForKing[BLACK]); Square ksq = square(~sideToMove); @@ -342,14 +346,14 @@ void Position::set_state(StateInfo* si) const { si->pawnKey ^= Zobrist::psq[piece_on(s)][s]; } - for (Color c = WHITE; c <= BLACK; ++c) - for (PieceType pt = PAWN; pt <= KING; ++pt) - for (int cnt = 0; cnt < pieceCount[make_piece(c, pt)]; ++cnt) - si->materialKey ^= Zobrist::psq[make_piece(c, pt)][cnt]; + for (Piece pc : Pieces) + { + if (type_of(pc) != PAWN && type_of(pc) != KING) + si->nonPawnMaterial[color_of(pc)] += pieceCount[pc] * PieceValue[MG][pc]; - for (Color c = WHITE; c <= BLACK; ++c) - for (PieceType pt = KNIGHT; pt <= QUEEN; ++pt) - si->nonPawnMaterial[c] += pieceCount[make_piece(c, pt)] * PieceValue[MG][pt]; + for (int cnt = 0; cnt < pieceCount[pc]; ++cnt) + si->materialKey ^= Zobrist::psq[pc][cnt]; + } } @@ -416,27 +420,33 @@ Phase Position::game_phase() const { } -/// 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. +/// 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::slider_blockers(Bitboard sliders, Square s) const { +Bitboard Position::slider_blockers(Bitboard sliders, Square s, Bitboard& pinners) const { - Bitboard b, pinners, result = 0; + Bitboard result = 0; + pinners = 0; - // 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; + // Snipers are sliders that attack 's' when a piece is removed + Bitboard snipers = ( (PseudoAttacks[ROOK ][s] & pieces(QUEEN, ROOK)) + | (PseudoAttacks[BISHOP][s] & pieces(QUEEN, BISHOP))) & sliders; - while (pinners) + while (snipers) { - b = between_bb(s, pop_lsb(&pinners)) & pieces(); - - if (!more_than_one(b)) - result |= b; + Square sniperSq = pop_lsb(&snipers); + Bitboard b = between_bb(s, sniperSq) & pieces(); + + if (!more_than_one(b)) + { + result |= b; + if (b & pieces(color_of(piece_on(s)))) + pinners |= sniperSq; + } } return result; } @@ -967,7 +977,7 @@ Value Position::see(Move m) const { Bitboard occupied, attackers, stmAttackers; Value swapList[32]; int slIndex = 1; - PieceType captured; + PieceType nextVictim; Color stm; assert(is_ok(m)); @@ -997,8 +1007,15 @@ Value Position::see(Move m) const { // If the opponent has no attackers we are finished stm = ~stm; stmAttackers = attackers & pieces(stm); + occupied ^= to; // For the case when captured piece is a pinner + + // Don't allow pinned pieces to attack pieces except the king as long all + // pinners are on their original square. + if (!(st->pinnersForKing[stm] & ~occupied)) + stmAttackers &= ~st->blockersForKing[stm]; + if (!stmAttackers) - return swapList[0]; + return swapList[0]; // The destination square is defended, which makes things rather more // difficult to compute. We proceed by building up a "swap list" containing @@ -1006,21 +1023,27 @@ Value Position::see(Move m) const { // destination square, where the sides alternately capture, and always // capture with the least valuable piece. After each capture, we look for // new X-ray attacks from behind the capturing piece. - captured = type_of(piece_on(from)); + nextVictim = type_of(piece_on(from)); do { assert(slIndex < 32); // Add the new entry to the swap list - swapList[slIndex] = -swapList[slIndex - 1] + PieceValue[MG][captured]; + swapList[slIndex] = -swapList[slIndex - 1] + PieceValue[MG][nextVictim]; // Locate and remove the next least valuable attacker - captured = min_attacker(byTypeBB, to, stmAttackers, occupied, attackers); + nextVictim = min_attacker(byTypeBB, to, stmAttackers, occupied, attackers); stm = ~stm; stmAttackers = attackers & pieces(stm); + + // Don't allow pinned pieces to attack pieces except the king + if ( nextVictim != KING + && !(st->pinnersForKing[stm] & ~occupied)) + stmAttackers &= ~st->blockersForKing[stm]; + ++slIndex; - } while (stmAttackers && (captured != KING || (--slIndex, false))); // Stop before a king capture + } while (stmAttackers && (nextVictim != KING || (--slIndex, false))); // Stop before a king capture // Having built the swap list, we negamax through it to find the best // achievable score from the point of view of the side to move. @@ -1136,18 +1159,15 @@ bool Position::pos_is_ok(int* failedStep) const { } if (step == Lists) - for (Color c = WHITE; c <= BLACK; ++c) - for (PieceType pt = PAWN; pt <= KING; ++pt) - { - Piece pc = make_piece(c, pt); + for (Piece pc : Pieces) + { + if (pieceCount[pc] != popcount(pieces(color_of(pc), type_of(pc)))) + return false; - if (pieceCount[pc] != popcount(pieces(c, pt))) + for (int i = 0; i < pieceCount[pc]; ++i) + if (board[pieceList[pc][i]] != pc || index[pieceList[pc][i]] != i) return false; - - for (int i = 0; i < pieceCount[pc]; ++i) - if (board[pieceList[pc][i]] != pc || index[pieceList[pc][i]] != i) - return false; - } + } if (step == Castling) for (Color c = WHITE; c <= BLACK; ++c)