X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fposition.cpp;h=cc320b4b3e45d55aba64cbc2194f71795ba5d35f;hp=d43554d18e20fd9ff14a52014ee2a5dbcf086dd6;hb=8b0fee9998e2ae530fa57e55f6cf145779aef3d0;hpb=5644e14d0e3d69b3f845e475771564ffb3e25445 diff --git a/src/position.cpp b/src/position.cpp index d43554d1..cc320b4b 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -1,7 +1,7 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) - Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad + Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -19,31 +19,25 @@ #include #include -#include +#include // For std::memset #include #include #include "bitcount.h" +#include "misc.h" #include "movegen.h" #include "position.h" #include "psqtab.h" -#include "rkiss.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]; @@ -53,10 +47,13 @@ namespace Zobrist { Key exclusion; } -Key Position::exclusion_key() const { return st->key ^ Zobrist::exclusion;} +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. @@ -123,10 +120,10 @@ std::ostream& operator<<(std::ostream& os, const Position& pos) { } os << "\nFen: " << pos.fen() << "\nKey: " << std::hex << std::uppercase - << std::setfill('0') << std::setw(16) << pos.st->key << "\nCheckers: "; + << 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)) << " "; + os << UCI::square(pop_lsb(&b)) << " "; return os; } @@ -140,28 +137,28 @@ std::ostream& operator<<(std::ostream& os, 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) { @@ -179,9 +176,8 @@ void Position::init() { } -/// Position::operator=() creates a copy of 'pos'. We want the new born Position -/// object to not depend on any external data so we detach state pointer from -/// the source one. +/// Position::operator=() creates a copy of 'pos' but detaching the state pointer +/// from the source to be self-consistent and not depending on any external data. Position& Position::operator=(const Position& pos) { @@ -366,7 +362,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); @@ -400,7 +396,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]; } @@ -433,21 +429,21 @@ const string Position::fen() const { ss << (sideToMove == WHITE ? " w " : " b "); if (can_castle(WHITE_OO)) - ss << (chess960 ? 'A' + file_of(castling_rook_square(WHITE | KING_SIDE)) : 'K'); + ss << (chess960 ? char('A' + file_of(castling_rook_square(WHITE | KING_SIDE))) : 'K'); if (can_castle(WHITE_OOO)) - ss << (chess960 ? 'A' + file_of(castling_rook_square(WHITE | QUEEN_SIDE)) : 'Q'); + ss << (chess960 ? char('A' + file_of(castling_rook_square(WHITE | QUEEN_SIDE))) : 'Q'); if (can_castle(BLACK_OO)) - ss << (chess960 ? 'a' + file_of(castling_rook_square(BLACK | KING_SIDE)) : 'k'); + ss << (chess960 ? char('a' + file_of(castling_rook_square(BLACK | KING_SIDE))) : 'k'); if (can_castle(BLACK_OOO)) - ss << (chess960 ? 'a' + file_of(castling_rook_square(BLACK | QUEEN_SIDE)) : '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 ? " - " : " " + UCI::format_square(ep_square()) + " ") + ss << (ep_square() == SQ_NONE ? " - " : " " + UCI::square(ep_square()) + " ") << st->rule50 << " " << 1 + (gamePly - (sideToMove == BLACK)) / 2; return ss.str(); @@ -459,11 +455,11 @@ const string Position::fen() const { 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)); } @@ -495,16 +491,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)); } @@ -529,15 +525,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 @@ -645,7 +641,7 @@ bool Position::gives_check(Move m, const CheckInfo& ci) const { return true; // Is there a discovered check? - if ( unlikely(ci.dcCandidates) + if ( ci.dcCandidates && (ci.dcCandidates & from) && !aligned(from, to, ci.ksq)) return true; @@ -770,7 +766,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); @@ -840,7 +836,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 @@ -874,7 +870,7 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI st->checkersBB |= to; // Discovered checks - if (unlikely(ci.dcCandidates) && (ci.dcCandidates & from)) + if (ci.dcCandidates && (ci.dcCandidates & from)) { if (pt != ROOK) st->checkersBB |= attacks_from(king_square(them)) & pieces(us, QUEEN, ROOK); @@ -1011,7 +1007,7 @@ void Position::undo_null_move() { } -/// Position::key_after() computes the new hash key after the given moven. Needed +/// 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. @@ -1064,8 +1060,8 @@ Value Position::see(Move m) const { stm = color_of(piece_on(from)); occupied = pieces() ^ from; - // Castling moves are implemented as king capturing the rook so cannot be - // handled correctly. Simply return 0 that is always the correct value + // Castling moves are implemented as king capturing the rook so cannot + // be handled correctly. Simply return VALUE_ZERO that is always correct // unless in the rare case the rook ends up under attack. if (type_of(m) == CASTLING) return VALUE_ZERO; @@ -1151,10 +1147,6 @@ bool Position::is_draw() const { /// Position::flip() flips position with the white and black sides reversed. This /// is only useful for debugging e.g. for finding evaluation symmetry bugs. -static char toggle_case(char c) { - return char(islower(c) ? toupper(c) : tolower(c)); -} - void Position::flip() { string f, token; @@ -1172,7 +1164,8 @@ void Position::flip() { ss >> token; // Castling availability f += token + " "; - std::transform(f.begin(), f.end(), f.begin(), toggle_case); + std::transform(f.begin(), f.end(), f.begin(), + [](char c) { return char(islower(c) ? toupper(c) : tolower(c)); }); ss >> token; // En passant square f += (token == "-" ? token : token.replace(1, 1, token[1] == '3' ? "6" : "3")); @@ -1237,8 +1230,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;