]> git.sesse.net Git - stockfish/blobdiff - src/position.cpp
Fix a wrong check in pos_is_ok()
[stockfish] / src / position.cpp
index 5ee0107f4252ec59f7dedbbea6ab85aa60e07292..9376aa91ad5b06fbf06ca3f27a0b9a79f78e8db6 100644 (file)
@@ -36,7 +36,7 @@ using std::cout;
 using std::endl;
 
 Key Position::zobrist[2][8][64];
-Key Position::zobEp[64];
+Key Position::zobEp[8];
 Key Position::zobCastle[16];
 Key Position::zobSideToMove;
 Key Position::zobExclusion;
@@ -247,8 +247,8 @@ void Position::set_castle_right(Color c, Square rsq) {
   int f = (rsq < king_square(c) ? WHITE_OOO : WHITE_OO) << c;
 
   st->castleRights |= f;
-  castleRightsMask[king_square(c)] ^= f;
-  castleRightsMask[rsq] ^= f;
+  castleRightsMask[king_square(c)] |= f;
+  castleRightsMask[rsq] |= f;
   castleRookSquare[f] = rsq;
 }
 
@@ -386,8 +386,8 @@ Bitboard Position::attackers_to(Square s, Bitboard occ) const {
   return  (attacks_from<PAWN>(s, BLACK) & pieces(PAWN, WHITE))
         | (attacks_from<PAWN>(s, WHITE) & pieces(PAWN, BLACK))
         | (attacks_from<KNIGHT>(s)      & pieces(KNIGHT))
-        | (rook_attacks_bb(s, occ)      & pieces(ROOK, QUEEN))
-        | (bishop_attacks_bb(s, occ)    & pieces(BISHOP, QUEEN))
+        | (attacks_bb<ROOK>(s, occ)     & pieces(ROOK, QUEEN))
+        | (attacks_bb<BISHOP>(s, occ)   & pieces(BISHOP, QUEEN))
         | (attacks_from<KING>(s)        & pieces(KING));
 }
 
@@ -401,9 +401,9 @@ Bitboard Position::attacks_from(Piece p, Square s, Bitboard occ) {
 
   switch (type_of(p))
   {
-  case BISHOP: return bishop_attacks_bb(s, occ);
-  case ROOK  : return rook_attacks_bb(s, occ);
-  case QUEEN : return bishop_attacks_bb(s, occ) | rook_attacks_bb(s, occ);
+  case BISHOP: return attacks_bb<BISHOP>(s, occ);
+  case ROOK  : return attacks_bb<ROOK>(s, occ);
+  case QUEEN : return attacks_bb<BISHOP>(s, occ) | attacks_bb<ROOK>(s, occ);
   default    : return StepAttacksBB[p][s];
   }
 }
@@ -420,7 +420,7 @@ bool Position::move_attacks_square(Move m, Square s) const {
   Bitboard occ, xray;
   Square from = from_sq(m);
   Square to = to_sq(m);
-  Piece piece = piece_on(from);
+  Piece piece = piece_moved(m);
 
   assert(!square_is_empty(from));
 
@@ -434,8 +434,8 @@ bool Position::move_attacks_square(Move m, Square s) const {
       return true;
 
   // Scan for possible X-ray attackers behind the moved piece
-  xray = (rook_attacks_bb(s, occ)   & pieces(ROOK, QUEEN, color_of(piece)))
-        |(bishop_attacks_bb(s, occ) & pieces(BISHOP, QUEEN, color_of(piece)));
+  xray = (attacks_bb<ROOK>(s, occ)   & pieces(ROOK, QUEEN, color_of(piece)))
+        |(attacks_bb<BISHOP>(s, occ) & pieces(BISHOP, QUEEN, color_of(piece)));
 
   // Verify attackers are triggered by our move and not already existing
   return xray && (xray ^ (xray & attacks_from<QUEEN>(s)));
@@ -452,7 +452,7 @@ bool Position::pl_move_is_legal(Move m, Bitboard pinned) const {
   Color us = sideToMove;
   Square from = from_sq(m);
 
-  assert(color_of(piece_on(from)) == us);
+  assert(color_of(piece_moved(m)) == us);
   assert(piece_on(king_square(us)) == make_piece(us, KING));
 
   // En passant captures are a tricky special case. Because they are rather
@@ -467,7 +467,7 @@ bool Position::pl_move_is_legal(Move m, Bitboard pinned) const {
       Bitboard b = occupied_squares();
 
       assert(to == ep_square());
-      assert(piece_on(from) == make_piece(us, PAWN));
+      assert(piece_moved(m) == make_piece(us, PAWN));
       assert(piece_on(capsq) == make_piece(them, PAWN));
       assert(piece_on(to) == NO_PIECE);
 
@@ -475,8 +475,8 @@ bool Position::pl_move_is_legal(Move m, Bitboard pinned) const {
       b ^= capsq;
       b |= to;
 
-      return   !(rook_attacks_bb(ksq, b) & pieces(ROOK, QUEEN, them))
-            && !(bishop_attacks_bb(ksq, b) & pieces(BISHOP, QUEEN, them));
+      return   !(attacks_bb<ROOK>(ksq, b) & pieces(ROOK, QUEEN, them))
+            && !(attacks_bb<BISHOP>(ksq, b) & pieces(BISHOP, QUEEN, them));
   }
 
   // If the moving piece is a king, check whether the destination
@@ -517,7 +517,7 @@ bool Position::is_pseudo_legal(const Move m) const {
   Color them = ~sideToMove;
   Square from = from_sq(m);
   Square to = to_sq(m);
-  Piece pc = piece_on(from);
+  Piece pc = piece_moved(m);
 
   // Use a slower but simpler function for uncommon cases
   if (is_special(m))
@@ -608,11 +608,11 @@ bool Position::is_pseudo_legal(const Move m) const {
   {
       // In case of king moves under check we have to remove king so to catch
       // as invalid moves like b1a1 when opposite queen is on c1.
-      if (type_of(piece_on(from)) == KING)
+      if (type_of(pc) == KING)
       {
           Bitboard b = occupied_squares();
           b ^= from;
-          if (attackers_to(to_sq(m), b) & pieces(~us))
+          if (attackers_to(to, b) & pieces(~us))
               return false;
       }
       else
@@ -625,7 +625,7 @@ bool Position::is_pseudo_legal(const Move m) const {
 
           // Our move must be a blocking evasion or a capture of the checking piece
           target = squares_between(checksq, king_square(us)) | checkers();
-          if (!(target & to_sq(m)))
+          if (!(target & to))
               return false;
       }
   }
@@ -684,8 +684,8 @@ bool Position::move_gives_check(Move m, const CheckInfo& ci) const {
       b ^= from;
       b ^= capsq;
       b |= to;
-      return  (rook_attacks_bb(ksq, b) & pieces(ROOK, QUEEN, us))
-            ||(bishop_attacks_bb(ksq, b) & pieces(BISHOP, QUEEN, us));
+      return  (attacks_bb<ROOK>(ksq, b) & pieces(ROOK, QUEEN, us))
+            ||(attacks_bb<BISHOP>(ksq, b) & pieces(BISHOP, QUEEN, us));
   }
 
   // Castling with check ?
@@ -707,7 +707,7 @@ bool Position::move_gives_check(Move m, const CheckInfo& ci) const {
       b ^= rfrom;
       b |= rto;
       b |= kto;
-      return rook_attacks_bb(rto, b) & ksq;
+      return attacks_bb<ROOK>(rto, b) & ksq;
   }
 
   return false;
@@ -752,7 +752,7 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI
   k ^= zobSideToMove;
 
   // Increment the 50 moves rule draw counter. Resetting it to zero in the
-  // case of non-reversible moves is taken care of later.
+  // case of a capture or a pawn move is taken care of later.
   st->rule50++;
   st->pliesFromNull++;
 
@@ -835,17 +835,16 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI
   // Reset en passant square
   if (st->epSquare != SQ_NONE)
   {
-      k ^= zobEp[st->epSquare];
+      k ^= zobEp[file_of(st->epSquare)];
       st->epSquare = SQ_NONE;
   }
 
   // Update castle rights if needed
-  if (    st->castleRights != CASTLES_NONE
-      && (castleRightsMask[from] & castleRightsMask[to]) != ALL_CASTLES)
+  if (st->castleRights && (castleRightsMask[from] | castleRightsMask[to]))
   {
-      k ^= zobCastle[st->castleRights];
-      st->castleRights &= castleRightsMask[from] & castleRightsMask[to];
-      k ^= zobCastle[st->castleRights];
+      int cr = castleRightsMask[from] | castleRightsMask[to];
+      k ^= zobCastle[st->castleRights & cr];
+      st->castleRights &= ~cr;
   }
 
   // Prefetch TT access as soon as we know key is updated
@@ -873,7 +872,7 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI
           && (attacks_from<PAWN>(from + pawn_push(us), us) & pieces(PAWN, them)))
       {
           st->epSquare = Square((from + to) / 2);
-          k ^= zobEp[st->epSquare];
+          k ^= zobEp[file_of(st->epSquare)];
       }
 
       if (is_promotion(m))
@@ -1146,17 +1145,13 @@ void Position::do_castle_move(Move m) {
       // Clear en passant square
       if (st->epSquare != SQ_NONE)
       {
-          st->key ^= zobEp[st->epSquare];
+          st->key ^= zobEp[file_of(st->epSquare)];
           st->epSquare = SQ_NONE;
       }
 
       // Update castling rights
-      st->key ^= zobCastle[st->castleRights];
-      st->castleRights &= castleRightsMask[kfrom];
-      st->key ^= zobCastle[st->castleRights];
-
-      // Reset rule 50 counter
-      st->rule50 = 0;
+      st->key ^= zobCastle[st->castleRights & castleRightsMask[kfrom]];
+      st->castleRights &= ~castleRightsMask[kfrom];
 
       // Update checkers BB
       st->checkersBB = attackers_to(king_square(~us)) & pieces(us);
@@ -1198,7 +1193,7 @@ void Position::do_null_move(StateInfo& backupSt) {
   if (Do)
   {
       if (st->epSquare != SQ_NONE)
-          st->key ^= zobEp[st->epSquare];
+          st->key ^= zobEp[file_of(st->epSquare)];
 
       st->key ^= zobSideToMove;
       prefetch((char*)TT.first_entry(st->key));
@@ -1227,13 +1222,10 @@ int Position::see_sign(Move m) const {
 
   assert(is_ok(m));
 
-  Square from = from_sq(m);
-  Square to = to_sq(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 (PieceValueMidgame[piece_on(to)] >= PieceValueMidgame[piece_on(from)])
+  if (PieceValueMidgame[piece_on(to_sq(m))] >= PieceValueMidgame[piece_moved(m)])
       return 1;
 
   return see(m);
@@ -1304,8 +1296,8 @@ int Position::see(Move m) const {
       // and scan for new X-ray attacks behind the attacker.
       b = stmAttackers & pieces(pt);
       occ ^= (b & (~b + 1));
-      attackers |=  (rook_attacks_bb(to, occ)   & pieces(ROOK, QUEEN))
-                  | (bishop_attacks_bb(to, occ) & pieces(BISHOP, QUEEN));
+      attackers |=  (attacks_bb<ROOK>(to, occ)   & pieces(ROOK, QUEEN))
+                  | (attacks_bb<BISHOP>(to, occ) & pieces(BISHOP, QUEEN));
 
       attackers &= occ; // Cut out pieces we've already done
 
@@ -1343,27 +1335,16 @@ int Position::see(Move m) const {
 
 void Position::clear() {
 
+  memset(this, 0, sizeof(Position));
+  startState.epSquare = SQ_NONE;
   st = &startState;
-  memset(st, 0, sizeof(StateInfo));
-  st->epSquare = SQ_NONE;
-
-  memset(byColorBB,  0, sizeof(Bitboard) * 2);
-  memset(byTypeBB,   0, sizeof(Bitboard) * 8);
-  memset(pieceCount, 0, sizeof(int) * 2 * 8);
-  memset(index,      0, sizeof(int) * 64);
 
   for (int i = 0; i < 8; i++)
       for (int j = 0; j < 16; j++)
           pieceList[0][i][j] = pieceList[1][i][j] = SQ_NONE;
 
   for (Square sq = SQ_A1; sq <= SQ_H8; sq++)
-  {
       board[sq] = NO_PIECE;
-      castleRightsMask[sq] = ALL_CASTLES;
-  }
-  sideToMove = WHITE;
-  nodes = 0;
-  occupied = 0;
 }
 
 
@@ -1399,7 +1380,7 @@ Key Position::compute_key() const {
           result ^= zobrist[color_of(piece_on(s))][type_of(piece_on(s))][s];
 
   if (ep_square() != SQ_NONE)
-      result ^= zobEp[ep_square()];
+      result ^= zobEp[file_of(ep_square())];
 
   if (sideToMove == BLACK)
       result ^= zobSideToMove;
@@ -1545,11 +1526,18 @@ void Position::init() {
           for (Square s = SQ_A1; s <= SQ_H8; s++)
               zobrist[c][pt][s] = rk.rand<Key>();
 
-  for (Square s = SQ_A1; s <= SQ_H8; s++)
-      zobEp[s] = rk.rand<Key>();
+  for (File f = FILE_A; f <= FILE_H; f++)
+      zobEp[f] = rk.rand<Key>();
 
-  for (int i = 0; i < 16; i++)
-      zobCastle[i] = rk.rand<Key>();
+  for (int cr = CASTLES_NONE; cr <= ALL_CASTLES; cr++)
+  {
+      Bitboard b = cr;
+      while (b)
+      {
+          Key k = zobCastle[1 << pop_1st_bit(&b)];
+          zobCastle[cr] ^= k ? k : rk.rand<Key>();
+      }
+  }
 
   zobSideToMove = rk.rand<Key>();
   zobExclusion  = rk.rand<Key>();
@@ -1689,7 +1677,7 @@ bool Position::pos_is_ok(int* failedStep) const {
   if (debugBitboards)
   {
       // The intersection of the white and black pieces must be empty
-      if (!(pieces(WHITE) & pieces(BLACK)))
+      if (pieces(WHITE) & pieces(BLACK))
           return false;
 
       // The union of the white and black pieces must be equal to all
@@ -1775,8 +1763,8 @@ bool Position::pos_is_ok(int* failedStep) const {
 
           Piece rook = (f & (WHITE_OO | WHITE_OOO) ? W_ROOK : B_ROOK);
 
-          if (   castleRightsMask[castleRookSquare[f]] != (ALL_CASTLES ^ f)
-              || piece_on(castleRookSquare[f]) != rook)
+          if (   piece_on(castleRookSquare[f]) != rook
+              || castleRightsMask[castleRookSquare[f]] != f)
               return false;
       }