]> git.sesse.net Git - stockfish/blobdiff - src/position.cpp
Simpler PRNG and faster magics search
[stockfish] / src / position.cpp
index db4c857b0d25401cf97e3f70b56c8aeb10a46ee1..a41dd52b66777aad041bfbd3bb914be8ff6c2f30 100644 (file)
 #include "movegen.h"
 #include "position.h"
 #include "psqtab.h"
-#include "rkiss.h"
+#include "misc.h"
 #include "thread.h"
 #include "tt.h"
-#include "notation.h"
+#include "uci.h"
 
 using std::string;
 
-static const string PieceToChar(" PNBRQK  pnbrqk");
-
-CACHE_LINE_ALIGNMENT
-
 Value PieceValue[PHASE_NB][PIECE_NB] = {
 { VALUE_ZERO, PawnValueMg, KnightValueMg, BishopValueMg, RookValueMg, QueenValueMg },
 { VALUE_ZERO, PawnValueEg, KnightValueEg, BishopValueEg, RookValueEg, QueenValueEg } };
 
-static Score psq[COLOR_NB][PIECE_TYPE_NB][SQUARE_NB];
-
 namespace Zobrist {
 
   Key psq[COLOR_NB][PIECE_TYPE_NB][SQUARE_NB];
@@ -57,6 +51,9 @@ Key Position::exclusion_key() const { return st->key ^ Zobrist::exclusion;}
 
 namespace {
 
+const string PieceToChar(" PNBRQK  pnbrqk");
+Score psq[COLOR_NB][PIECE_TYPE_NB][SQUARE_NB];
+
 // min_attacker() is a helper function used by see() to locate the least
 // valuable attacker for the side to move, remove the attacker we just found
 // from the bitboards and scan for new X-ray attacks behind it.
@@ -108,6 +105,30 @@ CheckInfo::CheckInfo(const Position& pos) {
 }
 
 
+/// operator<<(Position) returns an ASCII representation of the position
+
+std::ostream& operator<<(std::ostream& os, const Position& pos) {
+
+  os << "\n +---+---+---+---+---+---+---+---+\n";
+
+  for (Rank r = RANK_8; r >= RANK_1; --r)
+  {
+      for (File f = FILE_A; f <= FILE_H; ++f)
+          os << " | " << PieceToChar[pos.piece_on(make_square(f, r))];
+
+      os << " |\n +---+---+---+---+---+---+---+---+\n";
+  }
+
+  os << "\nFen: " << pos.fen() << "\nKey: " << std::hex << std::uppercase
+     << std::setfill('0') << std::setw(16) << pos.st->key << std::dec << "\nCheckers: ";
+
+  for (Bitboard b = pos.checkers(); b; )
+      os << UCI::format_square(pop_lsb(&b)) << " ";
+
+  return os;
+}
+
+
 /// Position::init() initializes at startup the various arrays used to compute
 /// hash keys and the piece square tables. The latter is a two-step operation:
 /// Firstly, the white halves of the tables are copied from PSQT[] tables.
@@ -116,28 +137,28 @@ CheckInfo::CheckInfo(const Position& pos) {
 
 void Position::init() {
 
-  RKISS rk;
+  PRNG rng(1070372);
 
   for (Color c = WHITE; c <= BLACK; ++c)
       for (PieceType pt = PAWN; pt <= KING; ++pt)
           for (Square s = SQ_A1; s <= SQ_H8; ++s)
-              Zobrist::psq[c][pt][s] = rk.rand<Key>();
+              Zobrist::psq[c][pt][s] = rng.rand<Key>();
 
   for (File f = FILE_A; f <= FILE_H; ++f)
-      Zobrist::enpassant[f] = rk.rand<Key>();
+      Zobrist::enpassant[f] = rng.rand<Key>();
 
-  for (int cf = NO_CASTLING; cf <= ANY_CASTLING; ++cf)
+  for (int cr = NO_CASTLING; cr <= ANY_CASTLING; ++cr)
   {
-      Bitboard b = cf;
+      Bitboard b = cr;
       while (b)
       {
           Key k = Zobrist::castling[1ULL << pop_lsb(&b)];
-          Zobrist::castling[cf] ^= k ? k : rk.rand<Key>();
+          Zobrist::castling[cr] ^= k ? k : rng.rand<Key>();
       }
   }
 
-  Zobrist::side = rk.rand<Key>();
-  Zobrist::exclusion  = rk.rand<Key>();
+  Zobrist::side = rng.rand<Key>();
+  Zobrist::exclusion  = rng.rand<Key>();
 
   for (PieceType pt = PAWN; pt <= KING; ++pt)
   {
@@ -342,7 +363,7 @@ void Position::set_castling_right(Color c, Square rfrom) {
 void Position::set_state(StateInfo* si) const {
 
   si->key = si->pawnKey = si->materialKey = 0;
-  si->npMaterial[WHITE] = si->npMaterial[BLACK] = VALUE_ZERO;
+  si->nonPawnMaterial[WHITE] = si->nonPawnMaterial[BLACK] = VALUE_ZERO;
   si->psq = SCORE_ZERO;
 
   si->checkersBB = attackers_to(king_square(sideToMove)) & pieces(~sideToMove);
@@ -376,7 +397,7 @@ void Position::set_state(StateInfo* si) const {
 
   for (Color c = WHITE; c <= BLACK; ++c)
       for (PieceType pt = KNIGHT; pt <= QUEEN; ++pt)
-          si->npMaterial[c] += pieceCount[c][pt] * PieceValue[MG][pt];
+          si->nonPawnMaterial[c] += pieceCount[c][pt] * PieceValue[MG][pt];
 }
 
 
@@ -409,63 +430,37 @@ const string Position::fen() const {
   ss << (sideToMove == WHITE ? " w " : " b ");
 
   if (can_castle(WHITE_OO))
-      ss << (chess960 ? to_char(file_of(castling_rook_square(WHITE |  KING_SIDE)), false) : 'K');
+      ss << (chess960 ? char('A' + file_of(castling_rook_square(WHITE |  KING_SIDE))) : 'K');
 
   if (can_castle(WHITE_OOO))
-      ss << (chess960 ? to_char(file_of(castling_rook_square(WHITE | QUEEN_SIDE)), false) : 'Q');
+      ss << (chess960 ? char('A' + file_of(castling_rook_square(WHITE | QUEEN_SIDE))) : 'Q');
 
   if (can_castle(BLACK_OO))
-      ss << (chess960 ? to_char(file_of(castling_rook_square(BLACK |  KING_SIDE)),  true) : 'k');
+      ss << (chess960 ? char('a' + file_of(castling_rook_square(BLACK |  KING_SIDE))) : 'k');
 
   if (can_castle(BLACK_OOO))
-      ss << (chess960 ? to_char(file_of(castling_rook_square(BLACK | QUEEN_SIDE)),  true) : 'q');
+      ss << (chess960 ? char('a' + file_of(castling_rook_square(BLACK | QUEEN_SIDE))) : 'q');
 
   if (!can_castle(WHITE) && !can_castle(BLACK))
       ss << '-';
 
-  ss << (ep_square() == SQ_NONE ? " - " : " " + to_string(ep_square()) + " ")
+  ss << (ep_square() == SQ_NONE ? " - " : " " + UCI::format_square(ep_square()) + " ")
      << st->rule50 << " " << 1 + (gamePly - (sideToMove == BLACK)) / 2;
 
   return ss.str();
 }
 
 
-/// Position::pretty() returns an ASCII representation of the position
-
-const string Position::pretty() const {
-
-  std::ostringstream ss;
-
-  ss << "\n +---+---+---+---+---+---+---+---+\n";
-
-  for (Rank r = RANK_8; r >= RANK_1; --r)
-  {
-      for (File f = FILE_A; f <= FILE_H; ++f)
-          ss << " | " << PieceToChar[piece_on(make_square(f, r))];
-
-      ss << " |\n +---+---+---+---+---+---+---+---+\n";
-  }
-
-  ss << "\nFen: " << fen() << "\nKey: " << std::hex << std::uppercase
-     << std::setfill('0') << std::setw(16) << st->key << "\nCheckers: ";
-
-  for (Bitboard b = checkers(); b; )
-      ss << to_string(pop_lsb(&b)) << " ";
-
-  return ss.str();
-}
-
-
 /// Position::game_phase() calculates the game phase interpolating total non-pawn
 /// material between endgame and midgame limits.
 
 Phase Position::game_phase() const {
 
-  Value npm = st->npMaterial[WHITE] + st->npMaterial[BLACK];
+  Value npm = st->nonPawnMaterial[WHITE] + st->nonPawnMaterial[BLACK];
 
   npm = std::max(EndgameLimit, std::min(npm, MidgameLimit));
 
-  return Phase(((npm - EndgameLimit) * 128) / (MidgameLimit - EndgameLimit));
+  return Phase(((npm - EndgameLimit) * PHASE_MIDGAME) / (MidgameLimit - EndgameLimit));
 }
 
 
@@ -497,16 +492,16 @@ Bitboard Position::check_blockers(Color c, Color kingColor) const {
 
 
 /// Position::attackers_to() computes a bitboard of all pieces which attack a
-/// given square. Slider attacks use the occ bitboard to indicate occupancy.
+/// given square. Slider attacks use the occupied bitboard to indicate occupancy.
 
-Bitboard Position::attackers_to(Square s, Bitboard occ) const {
+Bitboard Position::attackers_to(Square s, Bitboard occupied) const {
 
-  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))
-        | (attacks_from<KING>(s)        & pieces(KING));
+  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, occupied)   & pieces(ROOK, QUEEN))
+        | (attacks_bb<BISHOP>(s, occupied) & pieces(BISHOP, QUEEN))
+        | (attacks_from<KING>(s)           & pieces(KING));
 }
 
 
@@ -531,15 +526,15 @@ bool Position::legal(Move m, Bitboard pinned) const {
       Square ksq = king_square(us);
       Square to = to_sq(m);
       Square capsq = to - pawn_push(us);
-      Bitboard occ = (pieces() ^ from ^ capsq) | to;
+      Bitboard occupied = (pieces() ^ from ^ capsq) | to;
 
       assert(to == ep_square());
       assert(moved_piece(m) == make_piece(us, PAWN));
       assert(piece_on(capsq) == make_piece(~us, PAWN));
       assert(piece_on(to) == NO_PIECE);
 
-      return   !(attacks_bb<  ROOK>(ksq, occ) & pieces(~us, QUEEN, ROOK))
-            && !(attacks_bb<BISHOP>(ksq, occ) & pieces(~us, QUEEN, BISHOP));
+      return   !(attacks_bb<  ROOK>(ksq, occupied) & pieces(~us, QUEEN, ROOK))
+            && !(attacks_bb<BISHOP>(ksq, occupied) & pieces(~us, QUEEN, BISHOP));
   }
 
   // If the moving piece is a king, check whether the destination
@@ -772,7 +767,7 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI
           st->pawnKey ^= Zobrist::psq[them][PAWN][capsq];
       }
       else
-          st->npMaterial[them] -= PieceValue[MG][captured];
+          st->nonPawnMaterial[them] -= PieceValue[MG][captured];
 
       // Update board and piece lists
       remove_piece(capsq, them, captured);
@@ -807,9 +802,6 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI
       st->castlingRights &= ~cr;
   }
 
-  // Prefetch TT access as soon as we know the new hash key
-  prefetch((char*)TT.first_entry(k));
-
   // Move the piece. The tricky Chess960 castling is handled earlier
   if (type_of(m) != CASTLING)
       move_piece(from, to, us, pt);
@@ -845,7 +837,7 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI
           st->psq += psq[us][promotion][to] - psq[us][PAWN][to];
 
           // Update material
-          st->npMaterial[us] += PieceValue[MG][promotion];
+          st->nonPawnMaterial[us] += PieceValue[MG][promotion];
       }
 
       // Update pawn hash key and prefetch access to pawnsTable
@@ -1016,6 +1008,26 @@ void Position::undo_null_move() {
 }
 
 
+/// Position::key_after() computes the new hash key after the given move. Needed
+/// for speculative prefetch. It doesn't recognize special moves like castling,
+/// en-passant and promotions.
+
+Key Position::key_after(Move m) const {
+
+  Color us = sideToMove;
+  Square from = from_sq(m);
+  Square to = to_sq(m);
+  PieceType pt = type_of(piece_on(from));
+  PieceType captured = type_of(piece_on(to));
+  Key k = st->key ^ Zobrist::side;
+
+  if (captured)
+      k ^= Zobrist::psq[~us][captured][to];
+
+  return k ^ Zobrist::psq[us][pt][to] ^ Zobrist::psq[us][pt][from];
+}
+
+
 /// Position::see() is a static exchange evaluator: It tries to estimate the
 /// material gain or loss resulting from a move.
 
@@ -1222,8 +1234,8 @@ bool Position::pos_is_ok(int* step) const {
       if (   st->key != si.key
           || st->pawnKey != si.pawnKey
           || st->materialKey != si.materialKey
-          || st->npMaterial[WHITE] != si.npMaterial[WHITE]
-          || st->npMaterial[BLACK] != si.npMaterial[BLACK]
+          || st->nonPawnMaterial[WHITE] != si.nonPawnMaterial[WHITE]
+          || st->nonPawnMaterial[BLACK] != si.nonPawnMaterial[BLACK]
           || st->psq != si.psq
           || st->checkersBB != si.checkersBB)
           return false;