]> git.sesse.net Git - stockfish/blobdiff - src/position.cpp
Guard against 'divide by zero' in bench
[stockfish] / src / position.cpp
index 6458bb39d6d3703c80c52bb6ead08cfeb4fe1190..4d3f32a4d984d3b8edc5c92a3aff05d808098078 100644 (file)
@@ -25,6 +25,7 @@
 
 #include "bitcount.h"
 #include "movegen.h"
+#include "notation.h"
 #include "position.h"
 #include "psqtab.h"
 #include "rkiss.h"
@@ -63,7 +64,7 @@ const Value PieceValueEndgame[17] = {
 };
 
 // To convert a Piece to and from a FEN char
-static const string PieceToChar(" PNBRQK  pnbrqk  .");
+static const string PieceToChar(" PNBRQK  pnbrqk");
 
 
 /// CheckInfo c'tor
@@ -89,7 +90,7 @@ CheckInfo::CheckInfo(const Position& pos) {
 /// object do not depend on any external data so we detach state pointer from
 /// the source one.
 
-void Position::operator=(const Position& pos) {
+Position& Position::operator=(const Position& pos) {
 
   memcpy(this, &pos, sizeof(Position));
   startState = *st;
@@ -97,6 +98,8 @@ void Position::operator=(const Position& pos) {
   nodes = 0;
 
   assert(pos_is_ok());
+
+  return *this;
 }
 
 
@@ -154,7 +157,7 @@ void Position::from_fen(const string& fenStr, bool isChess960, Thread* th) {
           sq += Square(token - '0'); // Advance the given number of files
 
       else if (token == '/')
-          sq = make_square(FILE_A, rank_of(sq) - Rank(2));
+          sq -= Square(16);
 
       else if ((p = PieceToChar.find(token)) != string::npos)
       {
@@ -187,7 +190,7 @@ void Position::from_fen(const string& fenStr, bool isChess960, Thread* th) {
           for (rsq = relative_square(c, SQ_A1); type_of(piece_on(rsq)) != ROOK; rsq++) {}
 
       else if (token >= 'A' && token <= 'H')
-          rsq = make_square(File(token - 'A'), relative_rank(c, RANK_1));
+          rsq = File(token - 'A') | relative_rank(c, RANK_1);
 
       else
           continue;
@@ -199,9 +202,9 @@ void Position::from_fen(const string& fenStr, bool isChess960, Thread* th) {
   if (   ((fen >> col) && (col >= 'a' && col <= 'h'))
       && ((fen >> row) && (row == '3' || row == '6')))
   {
-      st->epSquare = make_square(File(col - 'a'), Rank(row - '1'));
+      st->epSquare = File(col - 'a') | Rank(row - '1');
 
-      if (!(attackers_to(st->epSquare) & pieces(PAWN, sideToMove)))
+      if (!(attackers_to(st->epSquare) & pieces(sideToMove, PAWN)))
           st->epSquare = SQ_NONE;
   }
 
@@ -268,9 +271,9 @@ const string Position::to_fen() const {
 
       for (File file = FILE_A; file <= FILE_H; file++)
       {
-          sq = make_square(file, rank);
+          sq = file | rank;
 
-          if (square_empty(sq))
+          if (is_empty(sq))
               emptyCnt++;
           else
           {
@@ -319,7 +322,11 @@ const string Position::to_fen() const {
 
 void Position::print(Move move) const {
 
-  const char* dottedLine = "\n+---+---+---+---+---+---+---+---+\n";
+  const string dottedLine =            "\n+---+---+---+---+---+---+---+---+";
+  const string twoRows =  dottedLine + "\n|   | . |   | . |   | . |   | . |"
+                        + dottedLine + "\n| . |   | . |   | . |   | . |   |";
+
+  string brd = twoRows + twoRows + twoRows + twoRows + dottedLine;
 
   if (move)
   {
@@ -327,22 +334,11 @@ void Position::print(Move move) const {
       cout << "\nMove is: " << (sideToMove == BLACK ? ".." : "") << move_to_san(p, move);
   }
 
-  for (Rank rank = RANK_8; rank >= RANK_1; rank--)
-  {
-      cout << dottedLine << '|';
-      for (File file = FILE_A; file <= FILE_H; file++)
-      {
-          Square sq = make_square(file, rank);
-          Piece piece = piece_on(sq);
-          char c = (color_of(piece) == BLACK ? '=' : ' ');
-
-          if (piece == NO_PIECE && !opposite_colors(sq, SQ_A1))
-              piece++; // Index the dot
+  for (Square sq = SQ_A1; sq <= SQ_H8; sq++)
+      if (piece_on(sq) != NO_PIECE)
+          brd[513 - 68*rank_of(sq) + 4*file_of(sq)] = PieceToChar[piece_on(sq)];
 
-          cout << c << PieceToChar[piece] << c << '|';
-      }
-  }
-  cout << dottedLine << "Fen is: " << to_fen() << "\nKey is: " << st->key << endl;
+  cout << brd << "\nFen is: " << to_fen() << "\nKey is: " << st->key << endl;
 }
 
 
@@ -364,7 +360,7 @@ Bitboard Position::hidden_checkers() const {
 
   while (pinners)
   {
-      b = between_bb(ksq, pop_1st_bit(&pinners)) & pieces();
+      b = between_bb(ksq, pop_lsb(&pinners)) & pieces();
 
       if (b && !more_than_one(b) && (b & pieces(sideToMove)))
           result |= b;
@@ -382,8 +378,8 @@ template Bitboard Position::hidden_checkers<false>() const;
 
 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))
+  return  (attacks_from<PAWN>(s, BLACK) & pieces(WHITE, PAWN))
+        | (attacks_from<PAWN>(s, WHITE) & pieces(BLACK, PAWN))
         | (attacks_from<KNIGHT>(s)      & pieces(KNIGHT))
         | (attacks_bb<ROOK>(s, occ)     & pieces(ROOK, QUEEN))
         | (attacks_bb<BISHOP>(s, occ)   & pieces(BISHOP, QUEEN))
@@ -421,7 +417,7 @@ bool Position::move_attacks_square(Move m, Square s) const {
   Square to = to_sq(m);
   Piece piece = piece_moved(m);
 
-  assert(!square_empty(from));
+  assert(!is_empty(from));
 
   // Update occupancy as if the piece is moving
   occ = pieces() ^ from ^ to;
@@ -431,8 +427,8 @@ bool Position::move_attacks_square(Move m, Square s) const {
       return true;
 
   // Scan for possible X-ray attackers behind the moved piece
-  xray = (attacks_bb<ROOK>(s, occ)   & pieces(ROOK, QUEEN, color_of(piece)))
-        |(attacks_bb<BISHOP>(s, occ) & pieces(BISHOP, QUEEN, color_of(piece)));
+  xray =  (attacks_bb<  ROOK>(s, occ) & pieces(color_of(piece), QUEEN, ROOK))
+        | (attacks_bb<BISHOP>(s, occ) & pieces(color_of(piece), QUEEN, BISHOP));
 
   // Verify attackers are triggered by our move and not already existing
   return xray && (xray ^ (xray & attacks_from<QUEEN>(s)));
@@ -455,7 +451,7 @@ bool Position::pl_move_is_legal(Move m, Bitboard pinned) const {
   // En passant captures are a tricky special case. Because they are rather
   // uncommon, we do it simply by testing whether the king is attacked after
   // the move is made.
-  if (is_enpassant(m))
+  if (type_of(m) == ENPASSANT)
   {
       Color them = ~us;
       Square to = to_sq(m);
@@ -468,15 +464,15 @@ bool Position::pl_move_is_legal(Move m, Bitboard pinned) const {
       assert(piece_on(capsq) == make_piece(them, PAWN));
       assert(piece_on(to) == NO_PIECE);
 
-      return   !(attacks_bb<ROOK>(ksq, b) & pieces(ROOK, QUEEN, them))
-            && !(attacks_bb<BISHOP>(ksq, b) & pieces(BISHOP, QUEEN, them));
+      return   !(attacks_bb<  ROOK>(ksq, b) & pieces(them, QUEEN, ROOK))
+            && !(attacks_bb<BISHOP>(ksq, b) & pieces(them, QUEEN, BISHOP));
   }
 
   // If the moving piece is a king, check whether the destination
   // square is attacked by the opponent. Castling moves are checked
   // for legality during move generation.
   if (type_of(piece_on(from)) == KING)
-      return is_castle(m) || !(attackers_to(to_sq(m)) & pieces(~us));
+      return type_of(m) == CASTLE || !(attackers_to(to_sq(m)) & pieces(~us));
 
   // A non-king move is legal if and only if it is not pinned or it
   // is moving along the ray towards or away from the king.
@@ -492,7 +488,7 @@ bool Position::pl_move_is_legal(Move m, Bitboard pinned) const {
 
 bool Position::move_is_legal(const Move m) const {
 
-  for (MoveList<MV_LEGAL> ml(*this); !ml.end(); ++ml)
+  for (MoveList<LEGAL> ml(*this); !ml.end(); ++ml)
       if (ml.move() == m)
           return true;
 
@@ -513,7 +509,7 @@ bool Position::is_pseudo_legal(const Move m) const {
   Piece pc = piece_moved(m);
 
   // Use a slower but simpler function for uncommon cases
-  if (is_special(m))
+  if (type_of(m) != NORMAL)
       return move_is_legal(m);
 
   // Is not a promotion, so promotion piece must be empty
@@ -563,7 +559,7 @@ bool Position::is_pseudo_legal(const Move m) const {
       case DELTA_N:
       case DELTA_S:
       // Pawn push. The destination square must be empty.
-      if (!square_empty(to))
+      if (!is_empty(to))
           return false;
       break;
 
@@ -571,9 +567,9 @@ bool Position::is_pseudo_legal(const Move m) const {
       // Double white pawn push. The destination square must be on the fourth
       // rank, and both the destination square and the square between the
       // source and destination squares must be empty.
-      if (   rank_of(to) != RANK_4
-          || !square_empty(to)
-          || !square_empty(from + DELTA_N))
+      if (    rank_of(to) != RANK_4
+          || !is_empty(to)
+          || !is_empty(from + DELTA_N))
           return false;
       break;
 
@@ -581,9 +577,9 @@ bool Position::is_pseudo_legal(const Move m) const {
       // Double black pawn push. The destination square must be on the fifth
       // rank, and both the destination square and the square between the
       // source and destination squares must be empty.
-      if (   rank_of(to) != RANK_5
-          || !square_empty(to)
-          || !square_empty(from + DELTA_S))
+      if (    rank_of(to) != RANK_5
+          || !is_empty(to)
+          || !is_empty(from + DELTA_S))
           return false;
       break;
 
@@ -602,7 +598,7 @@ bool Position::is_pseudo_legal(const Move m) const {
       if (type_of(pc) != KING)
       {
           Bitboard b = checkers();
-          Square checksq = pop_1st_bit(&b);
+          Square checksq = pop_lsb(&b);
 
           if (b) // double check ? In this case a king move is required
               return false;
@@ -641,37 +637,37 @@ bool Position::move_gives_check(Move m, const CheckInfo& ci) const {
   if (ci.dcCandidates && (ci.dcCandidates & from))
   {
       // For pawn and king moves we need to verify also direction
-      if (  (pt != PAWN && pt != KING)
+      if (   (pt != PAWN && pt != KING)
           || !squares_aligned(from, to, king_square(~sideToMove)))
           return true;
   }
 
   // Can we skip the ugly special cases ?
-  if (!is_special(m))
+  if (type_of(m) == NORMAL)
       return false;
 
   Color us = sideToMove;
   Square ksq = king_square(~us);
 
   // Promotion with check ?
-  if (is_promotion(m))
+  if (type_of(m) == PROMOTION)
       return attacks_from(Piece(promotion_type(m)), to, pieces() ^ from) & ksq;
 
   // En passant capture with check ? We have already handled the case
   // of direct checks and ordinary discovered check, the only case we
   // need to handle is the unusual case of a discovered check through
   // the captured pawn.
-  if (is_enpassant(m))
+  if (type_of(m) == ENPASSANT)
   {
-      Square capsq = make_square(file_of(to), rank_of(from));
+      Square capsq = file_of(to) | rank_of(from);
       Bitboard b = (pieces() ^ from ^ capsq) | to;
 
-      return  (attacks_bb<  ROOK>(ksq, b) & pieces(  ROOK, QUEEN, us))
-            | (attacks_bb<BISHOP>(ksq, b) & pieces(BISHOP, QUEEN, us));
+      return  (attacks_bb<  ROOK>(ksq, b) & pieces(us, QUEEN, ROOK))
+            | (attacks_bb<BISHOP>(ksq, b) & pieces(us, QUEEN, BISHOP));
   }
 
   // Castling with check ?
-  if (is_castle(m))
+  if (type_of(m) == CASTLE)
   {
       Square kfrom = from;
       Square rfrom = to; // 'King captures the rook' notation
@@ -707,14 +703,6 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI
   // Copy some fields of old state to our new StateInfo object except the ones
   // which are recalculated from scratch anyway, then switch our state pointer
   // to point to the new, ready to be updated, state.
-  struct ReducedStateInfo {
-    Key pawnKey, materialKey;
-    Value npMaterial[2];
-    int castleRights, rule50, pliesFromNull;
-    Score psq_score;
-    Square epSquare;
-  };
-
   memcpy(&newSt, st, sizeof(ReducedStateInfo));
 
   newSt.previous = st;
@@ -728,7 +716,7 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI
   st->rule50++;
   st->pliesFromNull++;
 
-  if (is_castle(m))
+  if (type_of(m) == CASTLE)
   {
       st->key = k;
       do_castle_move<true>(m);
@@ -741,7 +729,7 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI
   Square to = to_sq(m);
   Piece piece = piece_on(from);
   PieceType pt = type_of(piece);
-  PieceType capture = is_enpassant(m) ? PAWN : type_of(piece_on(to));
+  PieceType capture = type_of(m) == ENPASSANT ? PAWN : type_of(piece_on(to));
 
   assert(color_of(piece) == us);
   assert(color_of(piece_on(to)) != us);
@@ -755,7 +743,7 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI
       // update non-pawn material.
       if (capture == PAWN)
       {
-          if (is_enpassant(m))
+          if (type_of(m) == ENPASSANT)
           {
               capsq += pawn_push(them);
 
@@ -841,13 +829,13 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI
   {
       // Set en-passant square, only if moved pawn can be captured
       if (   (int(to) ^ int(from)) == 16
-          && (attacks_from<PAWN>(from + pawn_push(us), us) & pieces(PAWN, them)))
+          && (attacks_from<PAWN>(from + pawn_push(us), us) & pieces(them, PAWN)))
       {
           st->epSquare = Square((from + to) / 2);
           k ^= zobEp[file_of(st->epSquare)];
       }
 
-      if (is_promotion(m))
+      if (type_of(m) == PROMOTION)
       {
           PieceType promotion = promotion_type(m);
 
@@ -907,7 +895,7 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI
 
   if (moveIsCheck)
   {
-      if (is_special(m))
+      if (type_of(m) != NORMAL)
           st->checkersBB = attackers_to(king_square(them)) & pieces(us);
       else
       {
@@ -919,10 +907,10 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI
           if (ci.dcCandidates && (ci.dcCandidates & from))
           {
               if (pt != ROOK)
-                  st->checkersBB |= attacks_from<ROOK>(king_square(them)) & pieces(ROOK, QUEEN, us);
+                  st->checkersBB |= attacks_from<ROOK>(king_square(them)) & pieces(us, QUEEN, ROOK);
 
               if (pt != BISHOP)
-                  st->checkersBB |= attacks_from<BISHOP>(king_square(them)) & pieces(BISHOP, QUEEN, us);
+                  st->checkersBB |= attacks_from<BISHOP>(king_square(them)) & pieces(us, QUEEN, BISHOP);
           }
       }
   }
@@ -942,7 +930,7 @@ void Position::undo_move(Move m) {
 
   sideToMove = ~sideToMove;
 
-  if (is_castle(m))
+  if (type_of(m) == CASTLE)
   {
       do_castle_move<false>(m);
       return;
@@ -956,11 +944,11 @@ void Position::undo_move(Move m) {
   PieceType pt = type_of(piece);
   PieceType capture = st->capturedType;
 
-  assert(square_empty(from));
+  assert(is_empty(from));
   assert(color_of(piece) == us);
   assert(capture != KING);
 
-  if (is_promotion(m))
+  if (type_of(m) == PROMOTION)
   {
       PieceType promotion = promotion_type(m);
 
@@ -1003,7 +991,7 @@ void Position::undo_move(Move m) {
   {
       Square capsq = to;
 
-      if (is_enpassant(m))
+      if (type_of(m) == ENPASSANT)
       {
           capsq -= pawn_push(us);
 
@@ -1040,7 +1028,7 @@ template<bool Do>
 void Position::do_castle_move(Move m) {
 
   assert(is_ok(m));
-  assert(is_castle(m));
+  assert(type_of(m) == CASTLE);
 
   Square kto, kfrom, rfrom, rto, kAfter, rAfter;
 
@@ -1203,7 +1191,7 @@ int Position::see(Move m) const {
   // As castle moves are implemented as capturing the rook, they have
   // SEE == RookValueMidgame most of the times (unless the rook is under
   // attack).
-  if (is_castle(m))
+  if (type_of(m) == CASTLE)
       return 0;
 
   from = from_sq(m);
@@ -1212,7 +1200,7 @@ int Position::see(Move m) const {
   occ = pieces();
 
   // Handle en passant moves
-  if (is_enpassant(m))
+  if (type_of(m) == ENPASSANT)
   {
       Square capQq = to - pawn_push(sideToMove);
 
@@ -1336,7 +1324,7 @@ Key Position::compute_key() const {
 
   for (Bitboard b = pieces(); b; )
   {
-      Square s = pop_1st_bit(&b);
+      Square s = pop_lsb(&b);
       k ^= zobrist[color_of(piece_on(s))][type_of(piece_on(s))][s];
   }
 
@@ -1362,7 +1350,7 @@ Key Position::compute_pawn_key() const {
 
   for (Bitboard b = pieces(PAWN); b; )
   {
-      Square s = pop_1st_bit(&b);
+      Square s = pop_lsb(&b);
       k ^= zobrist[color_of(piece_on(s))][PAWN][s];
   }
 
@@ -1399,7 +1387,7 @@ Score Position::compute_psq_score() const {
 
   for (Bitboard b = pieces(); b; )
   {
-      Square s = pop_1st_bit(&b);
+      Square s = pop_lsb(&b);
       score += pieceSquareTable[piece_on(s)][s];
   }
 
@@ -1435,7 +1423,7 @@ bool Position::is_draw() const {
       return true;
 
   // Draw by the 50 moves rule?
-  if (st->rule50 > 99 && (!in_check() || MoveList<MV_LEGAL>(*this).size()))
+  if (st->rule50 > 99 && (!in_check() || MoveList<LEGAL>(*this).size()))
       return true;
 
   // Draw by repetition?
@@ -1490,7 +1478,7 @@ void Position::init() {
       Bitboard b = cr;
       while (b)
       {
-          Key k = zobCastle[1ULL << pop_1st_bit(&b)];
+          Key k = zobCastle[1ULL << pop_lsb(&b)];
           zobCastle[cr] ^= k ? k : rk.rand<Key>();
       }
   }
@@ -1527,7 +1515,7 @@ void Position::flip() {
   startPosPly = pos.startpos_ply_counter();
 
   for (Square s = SQ_A1; s <= SQ_H8; s++)
-      if (!pos.square_empty(s))
+      if (!pos.is_empty(s))
           put_piece(Piece(pos.piece_on(s) ^ 8), ~s);
 
   if (pos.can_castle(WHITE_OO))
@@ -1651,7 +1639,7 @@ bool Position::pos_is_ok(int* failedStep) const {
   if ((*step)++, debugPieceCounts)
       for (Color c = WHITE; c <= BLACK; c++)
           for (PieceType pt = PAWN; pt <= KING; pt++)
-              if (pieceCount[c][pt] != popcount<Full>(pieces(pt, c)))
+              if (pieceCount[c][pt] != popcount<Full>(pieces(c, pt)))
                   return false;
 
   if ((*step)++, debugPieceList)