@@ -50,41 +50,6 @@ const string PieceToChar(" PNBRQK pnbrqk");
5050
5151constexpr Piece Pieces[] = { W_PAWN, W_KNIGHT, W_BISHOP, W_ROOK, W_QUEEN, W_KING,
5252 B_PAWN, B_KNIGHT, B_BISHOP, B_ROOK, B_QUEEN, B_KING };
53-
54- // min_attacker() is a helper function used by see_ge() to locate the least
55- // valuable attacker for the side to move, remove the attacker we just found
56- // from the bitboards and scan for new X-ray attacks behind it.
57-
58- template <PieceType Pt>
59- PieceType min_attacker (const Bitboard* byTypeBB, Square to, Bitboard stmAttackers,
60- Bitboard& occupied, Bitboard& attackers) {
61-
62- Bitboard b = stmAttackers & byTypeBB[Pt];
63- if (!b)
64- return min_attacker<PieceType (Pt + 1 )>(byTypeBB, to, stmAttackers, occupied, attackers);
65-
66- occupied ^= lsb (b); // Remove the attacker from occupied
67-
68- // Add any X-ray attack behind the just removed piece. For instance with
69- // rooks in a8 and a7 attacking a1, after removing a7 we add rook in a8.
70- // Note that new added attackers can be of any color.
71- if (Pt == PAWN || Pt == BISHOP || Pt == QUEEN)
72- attackers |= attacks_bb<BISHOP>(to, occupied) & (byTypeBB[BISHOP] | byTypeBB[QUEEN]);
73-
74- if (Pt == ROOK || Pt == QUEEN)
75- attackers |= attacks_bb<ROOK>(to, occupied) & (byTypeBB[ROOK] | byTypeBB[QUEEN]);
76-
77- // X-ray may add already processed pieces because byTypeBB[] is constant: in
78- // the rook example, now attackers contains _again_ rook in a7, so remove it.
79- attackers &= occupied;
80- return Pt;
81- }
82-
83- template <>
84- PieceType min_attacker<KING>(const Bitboard*, Square, Bitboard, Bitboard&, Bitboard&) {
85- return KING; // No need to update bitboards: it is the last cycle
86- }
87-
8853} // namespace
8954
9055
@@ -1052,77 +1017,96 @@ bool Position::see_ge(Move m, Value threshold) const {
10521017 if (type_of (m) != NORMAL)
10531018 return VALUE_ZERO >= threshold;
10541019
1055- Bitboard stmAttackers;
10561020 Square from = from_sq (m), to = to_sq (m);
1057- PieceType nextVictim = type_of (piece_on (from));
1058- Color us = color_of (piece_on (from));
1059- Color stm = ~us; // First consider opponent's move
1060- Value balance; // Values of the pieces taken by us minus opponent's ones
1061-
1062- // The opponent may be able to recapture so this is the best result
1063- // we can hope for.
1064- balance = PieceValue[MG][piece_on (to)] - threshold;
10651021
1066- if (balance < VALUE_ZERO)
1022+ int swap = PieceValue[MG][piece_on (to)] - threshold;
1023+ if (swap < 0 )
10671024 return false ;
10681025
1069- // Now assume the worst possible result: that the opponent can
1070- // capture our piece for free.
1071- balance -= PieceValue[MG][nextVictim];
1072-
1073- // If it is enough (like in PxQ) then return immediately. Note that
1074- // in case nextVictim == KING we always return here, this is ok
1075- // if the given move is legal.
1076- if (balance >= VALUE_ZERO)
1026+ swap = PieceValue[MG][piece_on (from)] - swap;
1027+ if (swap <= 0 )
10771028 return true ;
10781029
1079- // Find all attackers to the destination square, with the moving piece
1080- // removed, but possibly an X-ray attacker added behind it.
1081- Bitboard occupied = pieces () ^ from ^ to;
1082- Bitboard attackers = attackers_to (to, occupied) & occupied;
1030+ Bitboard occ = pieces () ^ from ^ to;
1031+ Color stm = color_of (piece_on (from));
1032+ Bitboard attackers = attackers_to (to, occ);
1033+ Bitboard stmAttackers, bb;
1034+ int res = 1 ;
10831035
10841036 while (true )
10851037 {
1086- stmAttackers = attackers & pieces (stm);
1038+ stm = ~stm;
1039+ attackers &= occ;
1040+
1041+ // If stm has no more attackers then give up: stm loses
1042+ if (!(stmAttackers = attackers & pieces (stm)))
1043+ break ;
10871044
10881045 // Don't allow pinned pieces to attack (except the king) as long as
1089- // any pinners are on their original square.
1090- if (st->pinners [~stm] & occupied )
1046+ // there are pinners on their original square.
1047+ if (st->pinners [~stm] & occ )
10911048 stmAttackers &= ~st->blockersForKing [stm];
10921049
1093- // If stm has no more attackers then give up: stm loses
10941050 if (!stmAttackers)
10951051 break ;
10961052
1053+ res ^= 1 ;
1054+
10971055 // Locate and remove the next least valuable attacker, and add to
1098- // the bitboard 'attackers' the possibly X-ray attackers behind it.
1099- nextVictim = min_attacker<PAWN>(byTypeBB, to, stmAttackers, occupied, attackers);
1056+ // the bitboard 'attackers' any X-ray attackers behind it.
1057+ if ((bb = stmAttackers & pieces (PAWN)))
1058+ {
1059+ if ((swap = PawnValueMg - swap) < res)
1060+ break ;
11001061
1101- stm = ~stm; // Switch side to move
1062+ occ ^= lsb (bb);
1063+ attackers |= attacks_bb<BISHOP>(to, occ) & pieces (BISHOP, QUEEN);
1064+ }
11021065
1103- // Negamax the balance with alpha = balance, beta = balance+1 and
1104- // add nextVictim's value.
1105- //
1106- // (balance, balance+1) -> (-balance-1, -balance)
1107- //
1108- assert (balance < VALUE_ZERO);
1066+ else if ((bb = stmAttackers & pieces (KNIGHT)))
1067+ {
1068+ if ((swap = KnightValueMg - swap) < res)
1069+ break ;
11091070
1110- balance = -balance - 1 - PieceValue[MG][nextVictim];
1071+ occ ^= lsb (bb);
1072+ }
11111073
1112- // If balance is still non-negative after giving away nextVictim then we
1113- // win. The only thing to be careful about it is that we should revert
1114- // stm if we captured with the king when the opponent still has attackers.
1115- if (balance >= VALUE_ZERO)
1074+ else if ((bb = stmAttackers & pieces (BISHOP)))
11161075 {
1117- if (nextVictim == KING && (attackers & pieces (stm)))
1118- stm = ~stm;
1119- break ;
1076+ if ((swap = BishopValueMg - swap) < res)
1077+ break ;
1078+
1079+ occ ^= lsb (bb);
1080+ attackers |= attacks_bb<BISHOP>(to, occ) & pieces (BISHOP, QUEEN);
1081+ }
1082+
1083+ else if ((bb = stmAttackers & pieces (ROOK)))
1084+ {
1085+ if ((swap = RookValueMg - swap) < res)
1086+ break ;
1087+
1088+ occ ^= lsb (bb);
1089+ attackers |= attacks_bb<ROOK>(to, occ) & pieces (ROOK, QUEEN);
1090+ }
1091+
1092+ else if ((bb = stmAttackers & pieces (QUEEN)))
1093+ {
1094+ if ((swap = QueenValueMg - swap) < res)
1095+ break ;
1096+
1097+ occ ^= lsb (bb);
1098+ attackers |= (attacks_bb<BISHOP>(to, occ) & pieces (BISHOP, QUEEN))
1099+ | (attacks_bb<ROOK >(to, occ) & pieces (ROOK , QUEEN));
11201100 }
1121- assert (nextVictim != KING);
1101+
1102+ else // KING
1103+ // If we "capture" with the king but opponent still has attackers,
1104+ // reverse the result.
1105+ return (attackers & ~pieces (stm)) ? res ^ 1 : res;
11221106 }
1123- return us != stm; // We break the above loop when stm loses
1124- }
11251107
1108+ return res;
1109+ }
11261110
11271111// / Position::is_draw() tests whether the position is drawn by 50-move rule
11281112// / or by repetition. It does not detect stalemates.
0 commit comments