X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fposition.cpp;h=c09a953b62e3a7612d53f03069266a2a00493d6d;hp=26e8e1ce1374662b6bcdbdf24e6a2f29783f339d;hb=073eed590edf992ed3aeb6c754cb0b3b394fe79d;hpb=e340ce221cc29113dc5f2f922d2759ca5fa52f8b diff --git a/src/position.cpp b/src/position.cpp index 26e8e1ce..c09a953b 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]; @@ -291,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); @@ -415,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; } @@ -944,89 +955,83 @@ Key Position::key_after(Move m) const { } -/// Position::see() is a static exchange evaluator: It tries to estimate the -/// material gain or loss resulting from a move. +/// Position::see_ge (Static Exchange Evaluation Greater or Equal) tests if the +/// SEE value of move is greater or equal to the given value. We'll use an +/// algorithm similar to alpha-beta pruning with a null window. -Value Position::see_sign(Move m) const { +bool Position::see_ge(Move m, Value v) const { assert(is_ok(m)); - // 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 (PieceValue[MG][moved_piece(m)] <= PieceValue[MG][piece_on(to_sq(m))]) - return VALUE_KNOWN_WIN; - - return see(m); -} + // Castling moves are implemented as king capturing the rook so cannot be + // handled correctly. Simply assume the SEE value is VALUE_ZERO that is always + // correct unless in the rare case the rook ends up under attack. + if (type_of(m) == CASTLING) + return VALUE_ZERO >= v; -Value Position::see(Move m) const { + Square from = from_sq(m), to = to_sq(m); + PieceType nextVictim = type_of(piece_on(from)); + Color stm = ~color_of(piece_on(from)); // First consider opponent's move + Value balance; // Values of the pieces taken by us minus opponent's ones + Bitboard occupied, stmAttackers; - Square from, to; - Bitboard occupied, attackers, stmAttackers; - Value swapList[32]; - int slIndex = 1; - PieceType captured; - Color stm; + if (type_of(m) == ENPASSANT) + { + occupied = SquareBB[to - pawn_push(~stm)]; // Remove the captured pawn + balance = PieceValue[MG][PAWN]; + } + else + { + balance = PieceValue[MG][piece_on(to)]; + occupied = 0; + } - assert(is_ok(m)); + if (balance < v) + return false; - from = from_sq(m); - to = to_sq(m); - swapList[0] = PieceValue[MG][piece_on(to)]; - stm = color_of(piece_on(from)); - occupied = pieces() ^ from; + if (nextVictim == KING) + return true; - // Castling moves are implemented as king capturing the rook so cannot - // be handled correctly. Simply return VALUE_ZERO that is always correct - // unless in the rare case the rook ends up under attack. - if (type_of(m) == CASTLING) - return VALUE_ZERO; + balance -= PieceValue[MG][nextVictim]; - if (type_of(m) == ENPASSANT) - { - occupied ^= to - pawn_push(stm); // Remove the captured pawn - swapList[0] = PieceValue[MG][PAWN]; - } + if (balance >= v) + return true; - // Find all attackers to the destination square, with the moving piece - // removed, but possibly an X-ray attacker added behind it. - attackers = attackers_to(to, occupied) & occupied; + bool relativeStm = true; // True if the opponent is to move + occupied ^= pieces() ^ from ^ to; - // If the opponent has no attackers we are finished - stm = ~stm; - stmAttackers = attackers & pieces(stm); - if (!stmAttackers) - return swapList[0]; + // Find all attackers to the destination square, with the moving piece removed, + // but possibly an X-ray attacker added behind it. + Bitboard attackers = attackers_to(to, occupied) & occupied; - // The destination square is defended, which makes things rather more - // difficult to compute. We proceed by building up a "swap list" containing - // the material gain or loss at each stop in a sequence of captures to the - // 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)); + while (true) + { + stmAttackers = attackers & pieces(stm); - do { - assert(slIndex < 32); + // 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]; - // Add the new entry to the swap list - swapList[slIndex] = -swapList[slIndex - 1] + PieceValue[MG][captured]; + if (!stmAttackers) + return relativeStm; // Locate and remove the next least valuable attacker - captured = min_attacker(byTypeBB, to, stmAttackers, occupied, attackers); - stm = ~stm; - stmAttackers = attackers & pieces(stm); - ++slIndex; + nextVictim = min_attacker(byTypeBB, to, stmAttackers, occupied, attackers); + + if (nextVictim == KING) + return relativeStm == bool(attackers & pieces(~stm)); - } while (stmAttackers && (captured != KING || (--slIndex, false))); // Stop before a king capture + balance += relativeStm ? PieceValue[MG][nextVictim] + : -PieceValue[MG][nextVictim]; - // 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. - while (--slIndex) - swapList[slIndex - 1] = std::min(-swapList[slIndex], swapList[slIndex - 1]); + relativeStm = !relativeStm; - return swapList[0]; + if (relativeStm == (balance >= v)) + return relativeStm; + + stm = ~stm; + } }