X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fposition.cpp;h=a41dd52b66777aad041bfbd3bb914be8ff6c2f30;hp=23370ca3f73d4ed8fedbd14595c8b30af2b332b7;hb=158864270a055fe20dca4a87f4b7a8aa9cedfeb9;hpb=888a1d34454121c3682cbd68751bcebeca8bd308 diff --git a/src/position.cpp b/src/position.cpp index 23370ca3..a41dd52b 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -27,22 +27,17 @@ #include "movegen.h" #include "position.h" #include "psqtab.h" -#include "rkiss.h" +#include "misc.h" #include "thread.h" #include "tt.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]; @@ -56,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. @@ -107,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. @@ -115,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(); + Zobrist::psq[c][pt][s] = rng.rand(); for (File f = FILE_A; f <= FILE_H; ++f) - Zobrist::enpassant[f] = rk.rand(); + Zobrist::enpassant[f] = rng.rand(); - 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(); + Zobrist::castling[cr] ^= k ? k : rng.rand(); } } - Zobrist::side = rk.rand(); - Zobrist::exclusion = rk.rand(); + Zobrist::side = rng.rand(); + Zobrist::exclusion = rng.rand(); for (PieceType pt = PAWN; pt <= KING; ++pt) { @@ -341,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); @@ -375,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]; } @@ -408,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)); } @@ -496,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(s, BLACK) & pieces(WHITE, PAWN)) - | (attacks_from(s, WHITE) & pieces(BLACK, PAWN)) - | (attacks_from(s) & pieces(KNIGHT)) - | (attacks_bb(s, occ) & pieces(ROOK, QUEEN)) - | (attacks_bb(s, occ) & pieces(BISHOP, QUEEN)) - | (attacks_from(s) & pieces(KING)); + return (attacks_from(s, BLACK) & pieces(WHITE, PAWN)) + | (attacks_from(s, WHITE) & pieces(BLACK, PAWN)) + | (attacks_from(s) & pieces(KNIGHT)) + | (attacks_bb(s, occupied) & pieces(ROOK, QUEEN)) + | (attacks_bb(s, occupied) & pieces(BISHOP, QUEEN)) + | (attacks_from(s) & pieces(KING)); } @@ -530,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(ksq, occ) & pieces(~us, QUEEN, BISHOP)); + return !(attacks_bb< ROOK>(ksq, occupied) & pieces(~us, QUEEN, ROOK)) + && !(attacks_bb(ksq, occupied) & pieces(~us, QUEEN, BISHOP)); } // If the moving piece is a king, check whether the destination @@ -771,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); @@ -806,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); @@ -844,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 @@ -1015,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. @@ -1116,10 +1129,6 @@ Value Position::see(Move m) const { bool Position::is_draw() const { - if ( !pieces(PAWN) - && (non_pawn_material(WHITE) + non_pawn_material(BLACK) <= BishopValueMg)) - return true; - if (st->rule50 > 99 && (!checkers() || MoveList(*this).size())) return true; @@ -1225,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;