X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fposition.cpp;h=e8689ea727316d8f474abcd679999f2326826de6;hp=21022ae1b2c18dc7655eef0460d80cd3bdc054db;hb=9cdca7516c9397f991b2c0194f5de1ade26622e8;hpb=b84af67f4c88f3e3f7b61bf2035475f79fb3e62e diff --git a/src/position.cpp b/src/position.cpp index 21022ae1..e8689ea7 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -102,6 +102,37 @@ void init() { } // namespace Zobrist +/// next_attacker() is an helper function used by see() to locate the least +/// valuable attacker for the side to move, remove the attacker we just found +/// from the 'occupied' bitboard and scan for new X-ray attacks behind it. + +template static FORCE_INLINE +PieceType next_attacker(const Bitboard* bb, const Square& to, const Bitboard& stmAttackers, + Bitboard& occupied, Bitboard& attackers) { + + const PieceType NextPt = PieceType((int)Pt + 1); + + if (!(stmAttackers & bb[Pt])) + return next_attacker(bb, to, stmAttackers, occupied, attackers); + + Bitboard b = stmAttackers & bb[Pt]; + occupied ^= b & ~(b - 1); + + if (Pt == PAWN || Pt == BISHOP || Pt == QUEEN) + attackers |= attacks_bb(to, occupied) & (bb[BISHOP] | bb[QUEEN]); + + if (Pt == ROOK || Pt == QUEEN) + attackers |= attacks_bb(to, occupied) & (bb[ROOK] | bb[QUEEN]); + + return Pt; +} + +template<> FORCE_INLINE +PieceType next_attacker(const Bitboard*, const Square&, const Bitboard&, Bitboard&, Bitboard&) { + return KING; // No need to update bitboards, it is the last cycle +} + + /// CheckInfo c'tor CheckInfo::CheckInfo(const Position& pos) { @@ -363,6 +394,8 @@ void Position::print(Move move) const { string brd = twoRows + twoRows + twoRows + twoRows + dottedLine; + sync_cout; + if (move) { Position p(*this); @@ -373,7 +406,7 @@ void Position::print(Move move) const { if (piece_on(sq) != NO_PIECE) brd[513 - 68*rank_of(sq) + 4*file_of(sq)] = PieceToChar[piece_on(sq)]; - cout << brd << "\nFen is: " << to_fen() << "\nKey is: " << st->key << endl; + cout << brd << "\nFen is: " << to_fen() << "\nKey is: " << st->key << sync_endl; } @@ -1216,47 +1249,45 @@ int Position::see_sign(Move m) const { int Position::see(Move m) const { Square from, to; - Bitboard occ, attackers, stmAttackers, b; + Bitboard occupied, attackers, stmAttackers; int swapList[32], slIndex = 1; - PieceType capturedType, pt; + PieceType captured; Color stm; 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 (type_of(m) == CASTLE) - return 0; - from = from_sq(m); to = to_sq(m); - capturedType = type_of(piece_on(to)); - occ = pieces(); + captured = type_of(piece_on(to)); + occupied = pieces() ^ from; // Handle en passant moves if (type_of(m) == ENPASSANT) { Square capQq = to - pawn_push(sideToMove); - assert(!capturedType); + assert(!captured); assert(type_of(piece_on(capQq)) == PAWN); // Remove the captured pawn - occ ^= capQq; - capturedType = PAWN; + occupied ^= capQq; + captured = PAWN; } + else if (type_of(m) == CASTLE) + // Castle moves are implemented as king capturing the rook so cannot be + // handled correctly. Simply return 0 that is always the correct value + // unless the rook is ends up under attack. + return 0; // Find all attackers to the destination square, with the moving piece // removed, but possibly an X-ray attacker added behind it. - occ ^= from; - attackers = attackers_to(to, occ); + attackers = attackers_to(to, occupied); // If the opponent has no attackers we are finished stm = ~color_of(piece_on(from)); stmAttackers = attackers & pieces(stm); if (!stmAttackers) - return PieceValue[Mg][capturedType]; + return PieceValue[Mg][captured]; // The destination square is defended, which makes things rather more // difficult to compute. We proceed by building up a "swap list" containing @@ -1264,43 +1295,31 @@ int 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. - swapList[0] = PieceValue[Mg][capturedType]; - capturedType = type_of(piece_on(from)); + swapList[0] = PieceValue[Mg][captured]; + captured = type_of(piece_on(from)); do { - // Locate the least valuable attacker for the side to move. The loop - // below looks like it is potentially infinite, but it isn't. We know - // that the side to move still has at least one attacker left. - for (pt = PAWN; !(stmAttackers & pieces(pt)); pt++) - assert(pt < KING); - - // Remove the attacker we just found from the 'occupied' bitboard, - // and scan for new X-ray attacks behind the attacker. - b = stmAttackers & pieces(pt); - occ ^= (b & (~b + 1)); - attackers |= (attacks_bb(to, occ) & pieces(ROOK, QUEEN)) - | (attacks_bb(to, occ) & pieces(BISHOP, QUEEN)); - - attackers &= occ; // Cut out pieces we've already done + assert(slIndex < 32); // Add the new entry to the swap list - assert(slIndex < 32); - swapList[slIndex] = -swapList[slIndex - 1] + PieceValue[Mg][capturedType]; + swapList[slIndex] = -swapList[slIndex - 1] + PieceValue[Mg][captured]; slIndex++; - // Remember the value of the capturing piece, and change the side to - // move before beginning the next iteration. - capturedType = pt; + // Locate and remove from 'occupied' the next least valuable attacker + captured = next_attacker(byTypeBB, to, stmAttackers, occupied, attackers); + + attackers &= occupied; // Remove the just found attacker stm = ~stm; stmAttackers = attackers & pieces(stm); // Stop before processing a king capture - if (capturedType == KING && stmAttackers) + if (captured == KING && stmAttackers) { assert(slIndex < 32); swapList[slIndex++] = QueenValueMg * 16; break; } + } while (stmAttackers); // Having built the swap list, we negamax through it to find the best