From: Marco Costalba Date: Sat, 22 Dec 2012 10:21:06 +0000 (+0100) Subject: Introduce namespace Pawns X-Git-Url: https://git.sesse.net/?p=stockfish;a=commitdiff_plain;h=158014b39d69eaaf791d4913b98ffde5c4d7a874;hp=231f62baf7b6d9cee18bf7e85bed0fc9b78eed73 Introduce namespace Pawns And retire old struct PawnTable along the same lines of previous patch. No functional change. --- diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 4765094a..8d9d01a7 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -37,7 +37,7 @@ namespace { // Pointers to material and pawn hash table entries Material::Entry* mi; - PawnEntry* pi; + Pawns::Entry* pi; // attackedBy[color][piece type] is a bitboard representing all squares // attacked by a given color and piece type, attackedBy[color][0] contains @@ -405,7 +405,7 @@ Value do_evaluate(const Position& pos, Value& margin) { } // Probe the pawn hash table - ei.pi = pos.this_thread()->pawnTable.probe(pos); + ei.pi = Pawns::probe(pos, th->pawnsTable); score += ei.pi->pawns_value(); // Initialize attack and king safety bitboards diff --git a/src/pawns.cpp b/src/pawns.cpp index b4b8d9ee..9f0d50c0 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -80,18 +80,116 @@ namespace { #undef S #undef V + + template + Score evaluate_pawns(const Position& pos, Bitboard ourPawns, + Bitboard theirPawns, Pawns::Entry* e) { + + const Color Them = (Us == WHITE ? BLACK : WHITE); + + Bitboard b; + Square s; + File f; + Rank r; + bool passed, isolated, doubled, opposed, chain, backward, candidate; + Score value = SCORE_ZERO; + const Square* pl = pos.piece_list(Us, PAWN); + + // Loop through all pawns of the current color and score each pawn + while ((s = *pl++) != SQ_NONE) + { + assert(pos.piece_on(s) == make_piece(Us, PAWN)); + + f = file_of(s); + r = rank_of(s); + + // This file cannot be half open + e->halfOpenFiles[Us] &= ~(1 << f); + + // Our rank plus previous one. Used for chain detection + b = rank_bb(r) | rank_bb(Us == WHITE ? r - Rank(1) : r + Rank(1)); + + // Flag the pawn as passed, isolated, doubled or member of a pawn + // chain (but not the backward one). + chain = ourPawns & adjacent_files_bb(f) & b; + isolated = !(ourPawns & adjacent_files_bb(f)); + doubled = ourPawns & forward_bb(Us, s); + opposed = theirPawns & forward_bb(Us, s); + passed = !(theirPawns & passed_pawn_mask(Us, s)); + + // Test for backward pawn + backward = false; + + // If the pawn is passed, isolated, or member of a pawn chain it cannot + // be backward. If there are friendly pawns behind on adjacent files + // or if can capture an enemy pawn it cannot be backward either. + if ( !(passed | isolated | chain) + && !(ourPawns & attack_span_mask(Them, s)) + && !(pos.attacks_from(s, Us) & theirPawns)) + { + // We now know that there are no friendly pawns beside or behind this + // pawn on adjacent files. We now check whether the pawn is + // backward by looking in the forward direction on the adjacent + // files, and seeing whether we meet a friendly or an enemy pawn first. + b = pos.attacks_from(s, Us); + + // Note that we are sure to find something because pawn is not passed + // nor isolated, so loop is potentially infinite, but it isn't. + while (!(b & (ourPawns | theirPawns))) + Us == WHITE ? b <<= 8 : b >>= 8; + + // The friendly pawn needs to be at least two ranks closer than the + // enemy pawn in order to help the potentially backward pawn advance. + backward = (b | (Us == WHITE ? b << 8 : b >> 8)) & theirPawns; + } + + assert(opposed | passed | (attack_span_mask(Us, s) & theirPawns)); + + // A not passed pawn is a candidate to become passed if it is free to + // advance and if the number of friendly pawns beside or behind this + // pawn on adjacent files is higher or equal than the number of + // enemy pawns in the forward direction on the adjacent files. + candidate = !(opposed | passed | backward | isolated) + && (b = attack_span_mask(Them, s + pawn_push(Us)) & ourPawns) != 0 + && popcount(b) >= popcount(attack_span_mask(Us, s) & theirPawns); + + // Passed pawns will be properly scored in evaluation because we need + // full attack info to evaluate passed pawns. Only the frontmost passed + // pawn on each file is considered a true passed pawn. + if (passed && !doubled) + e->passedPawns[Us] |= s; + + // Score this pawn + if (isolated) + value -= IsolatedPawnPenalty[opposed][f]; + + if (doubled) + value -= DoubledPawnPenalty[opposed][f]; + + if (backward) + value -= BackwardPawnPenalty[opposed][f]; + + if (chain) + value += ChainBonus[f]; + + if (candidate) + value += CandidateBonus[relative_rank(Us, s)]; + } + + return value; + } } +namespace Pawns { -/// PawnTable::probe() takes a position object as input, computes a PawnEntry -/// object, and returns a pointer to it. The result is also stored in a hash -/// table, so we don't have to recompute everything when the same pawn structure -/// occurs again. +/// probe() takes a position object as input, computes a Entry object, and returns +/// a pointer to it. The result is also stored in a hash table, so we don't have +/// to recompute everything when the same pawn structure occurs again. -PawnEntry* PawnTable::probe(const Position& pos) { +Entry* probe(const Position& pos, Table& entries) { Key key = pos.pawn_key(); - PawnEntry* e = entries[key]; + Entry* e = entries[key]; // If e->key matches the position's pawn hash key, it means that we // have analysed this pawn structure before, and we can simply return @@ -118,112 +216,11 @@ PawnEntry* PawnTable::probe(const Position& pos) { } -/// PawnTable::evaluate_pawns() evaluates each pawn of the given color - -template -Score PawnTable::evaluate_pawns(const Position& pos, Bitboard ourPawns, - Bitboard theirPawns, PawnEntry* e) { - - const Color Them = (Us == WHITE ? BLACK : WHITE); - - Bitboard b; - Square s; - File f; - Rank r; - bool passed, isolated, doubled, opposed, chain, backward, candidate; - Score value = SCORE_ZERO; - const Square* pl = pos.piece_list(Us, PAWN); - - // Loop through all pawns of the current color and score each pawn - while ((s = *pl++) != SQ_NONE) - { - assert(pos.piece_on(s) == make_piece(Us, PAWN)); - - f = file_of(s); - r = rank_of(s); - - // This file cannot be half open - e->halfOpenFiles[Us] &= ~(1 << f); - - // Our rank plus previous one. Used for chain detection - b = rank_bb(r) | rank_bb(Us == WHITE ? r - Rank(1) : r + Rank(1)); - - // Flag the pawn as passed, isolated, doubled or member of a pawn - // chain (but not the backward one). - chain = ourPawns & adjacent_files_bb(f) & b; - isolated = !(ourPawns & adjacent_files_bb(f)); - doubled = ourPawns & forward_bb(Us, s); - opposed = theirPawns & forward_bb(Us, s); - passed = !(theirPawns & passed_pawn_mask(Us, s)); - - // Test for backward pawn - backward = false; - - // If the pawn is passed, isolated, or member of a pawn chain it cannot - // be backward. If there are friendly pawns behind on adjacent files - // or if can capture an enemy pawn it cannot be backward either. - if ( !(passed | isolated | chain) - && !(ourPawns & attack_span_mask(Them, s)) - && !(pos.attacks_from(s, Us) & theirPawns)) - { - // We now know that there are no friendly pawns beside or behind this - // pawn on adjacent files. We now check whether the pawn is - // backward by looking in the forward direction on the adjacent - // files, and seeing whether we meet a friendly or an enemy pawn first. - b = pos.attacks_from(s, Us); - - // Note that we are sure to find something because pawn is not passed - // nor isolated, so loop is potentially infinite, but it isn't. - while (!(b & (ourPawns | theirPawns))) - Us == WHITE ? b <<= 8 : b >>= 8; - - // The friendly pawn needs to be at least two ranks closer than the - // enemy pawn in order to help the potentially backward pawn advance. - backward = (b | (Us == WHITE ? b << 8 : b >> 8)) & theirPawns; - } - - assert(opposed | passed | (attack_span_mask(Us, s) & theirPawns)); - - // A not passed pawn is a candidate to become passed if it is free to - // advance and if the number of friendly pawns beside or behind this - // pawn on adjacent files is higher or equal than the number of - // enemy pawns in the forward direction on the adjacent files. - candidate = !(opposed | passed | backward | isolated) - && (b = attack_span_mask(Them, s + pawn_push(Us)) & ourPawns) != 0 - && popcount(b) >= popcount(attack_span_mask(Us, s) & theirPawns); - - // Passed pawns will be properly scored in evaluation because we need - // full attack info to evaluate passed pawns. Only the frontmost passed - // pawn on each file is considered a true passed pawn. - if (passed && !doubled) - e->passedPawns[Us] |= s; - - // Score this pawn - if (isolated) - value -= IsolatedPawnPenalty[opposed][f]; - - if (doubled) - value -= DoubledPawnPenalty[opposed][f]; - - if (backward) - value -= BackwardPawnPenalty[opposed][f]; - - if (chain) - value += ChainBonus[f]; - - if (candidate) - value += CandidateBonus[relative_rank(Us, s)]; - } - - return value; -} - - -/// PawnEntry::shelter_storm() calculates shelter and storm penalties for the file +/// Entry::shelter_storm() calculates shelter and storm penalties for the file /// the king is on, as well as the two adjacent files. template -Value PawnEntry::shelter_storm(const Position& pos, Square ksq) { +Value Entry::shelter_storm(const Position& pos, Square ksq) { const Color Them = (Us == WHITE ? BLACK : WHITE); @@ -253,11 +250,11 @@ Value PawnEntry::shelter_storm(const Position& pos, Square ksq) { } -/// PawnEntry::update_safety() calculates and caches a bonus for king safety. It is +/// Entry::update_safety() calculates and caches a bonus for king safety. It is /// called only when king square changes, about 20% of total king_safety() calls. template -Score PawnEntry::update_safety(const Position& pos, Square ksq) { +Score Entry::update_safety(const Position& pos, Square ksq) { kingSquares[Us] = ksq; castleRights[Us] = pos.can_castle(Us); @@ -283,5 +280,7 @@ Score PawnEntry::update_safety(const Position& pos, Square ksq) { } // Explicit template instantiation -template Score PawnEntry::update_safety(const Position& pos, Square ksq); -template Score PawnEntry::update_safety(const Position& pos, Square ksq); +template Score Entry::update_safety(const Position& pos, Square ksq); +template Score Entry::update_safety(const Position& pos, Square ksq); + +} // namespace Pawns diff --git a/src/pawns.h b/src/pawns.h index e1583fc0..212b1448 100644 --- a/src/pawns.h +++ b/src/pawns.h @@ -24,31 +24,30 @@ #include "position.h" #include "types.h" -const int PawnTableSize = 16384; +namespace Pawns { -/// PawnEntry is a class which contains various information about a pawn -/// structure. Currently, it only includes a middle game and an end game -/// pawn structure evaluation, and a bitboard of passed pawns. We may want -/// to add further information in the future. A lookup to the pawn hash -/// table (performed by calling the probe method in a PawnTable object) -/// returns a pointer to a PawnEntry object. +/// Pawns::Entry contains various information about a pawn structure. Currently, +/// it only includes a middle game and end game pawn structure evaluation, and a +/// bitboard of passed pawns. We may want to add further information in the future. +/// A lookup to the pawn hash table (performed by calling the probe function) +/// returns a pointer to an Entry object. -class PawnEntry { +struct Entry { - friend struct PawnTable; - -public: - Score pawns_value() const; - Bitboard pawn_attacks(Color c) const; - Bitboard passed_pawns(Color c) const; - int file_is_half_open(Color c, File f) const; - int has_open_file_to_left(Color c, File f) const; - int has_open_file_to_right(Color c, File f) const; + Score pawns_value() const { return value; } + Bitboard pawn_attacks(Color c) const { return pawnAttacks[c]; } + Bitboard passed_pawns(Color c) const { return passedPawns[c]; } + int file_is_half_open(Color c, File f) const { return halfOpenFiles[c] & (1 << int(f)); } + int has_open_file_to_left(Color c, File f) const { return halfOpenFiles[c] & ((1 << int(f)) - 1); } + int has_open_file_to_right(Color c, File f) const { return halfOpenFiles[c] & ~((1 << int(f+1)) - 1); } template - Score king_safety(const Position& pos, Square ksq); + Score king_safety(const Position& pos, Square ksq) { + + return kingSquares[Us] == ksq && castleRights[Us] == pos.can_castle(Us) + ? kingSafety[Us] : update_safety(pos, ksq); + } -private: template Score update_safety(const Position& pos, Square ksq); @@ -66,50 +65,10 @@ private: Score kingSafety[COLOR_NB]; }; +typedef HashTable Table; -/// The PawnTable class represents a pawn hash table. The most important -/// method is probe, which returns a pointer to a PawnEntry object. - -struct PawnTable { - - PawnEntry* probe(const Position& pos); - - template - static Score evaluate_pawns(const Position& pos, Bitboard ourPawns, - Bitboard theirPawns, PawnEntry* e); - - HashTable entries; -}; - - -inline Score PawnEntry::pawns_value() const { - return value; -} - -inline Bitboard PawnEntry::pawn_attacks(Color c) const { - return pawnAttacks[c]; -} - -inline Bitboard PawnEntry::passed_pawns(Color c) const { - return passedPawns[c]; -} - -inline int PawnEntry::file_is_half_open(Color c, File f) const { - return halfOpenFiles[c] & (1 << int(f)); -} - -inline int PawnEntry::has_open_file_to_left(Color c, File f) const { - return halfOpenFiles[c] & ((1 << int(f)) - 1); -} - -inline int PawnEntry::has_open_file_to_right(Color c, File f) const { - return halfOpenFiles[c] & ~((1 << int(f+1)) - 1); -} +Entry* probe(const Position& pos, Table& entries); -template -inline Score PawnEntry::king_safety(const Position& pos, Square ksq) { - return kingSquares[Us] == ksq && castleRights[Us] == pos.can_castle(Us) - ? kingSafety[Us] : update_safety(pos, ksq); } #endif // !defined(PAWNS_H_INCLUDED) diff --git a/src/position.cpp b/src/position.cpp index 0c19d820..0ed2fff4 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -918,7 +918,7 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI } // Prefetch pawn and material hash tables - prefetch((char*)thisThread->pawnTable.entries[st->pawnKey]); + prefetch((char*)thisThread->pawnsTable[st->pawnKey]); prefetch((char*)thisThread->materialTable[st->materialKey]); // Update incremental scores diff --git a/src/thread.h b/src/thread.h index 64a56ccb..c6dc8316 100644 --- a/src/thread.h +++ b/src/thread.h @@ -112,7 +112,7 @@ public: Eval::Table evalTable; Material::Table materialTable; Endgames endgames; - PawnTable pawnTable; + Pawns::Table pawnsTable; size_t idx; int maxPly; Mutex mutex;