mirror of
https://github.com/sockspls/badfish
synced 2025-05-01 01:03:09 +00:00
Assorted code style and comments in pawns.cpp and pawns.h
The only interesting thing is that a backward or isolated pawn cannot be a candidate passer, so code this condition. No functional change. Signed-off-by: Marco Costalba <mcostalba@gmail.com>
This commit is contained in:
parent
8e71ee7ec6
commit
2f1935078d
4 changed files with 65 additions and 83 deletions
101
src/pawns.cpp
101
src/pawns.cpp
|
@ -17,27 +17,15 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
////
|
|
||||||
//// Includes
|
|
||||||
////
|
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
|
#include "bitboard.h"
|
||||||
#include "bitcount.h"
|
#include "bitcount.h"
|
||||||
#include "pawns.h"
|
#include "pawns.h"
|
||||||
#include "position.h"
|
#include "position.h"
|
||||||
|
|
||||||
|
|
||||||
////
|
|
||||||
//// Local definitions
|
|
||||||
////
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
/// Constants and variables
|
|
||||||
|
|
||||||
#define S(mg, eg) make_score(mg, eg)
|
#define S(mg, eg) make_score(mg, eg)
|
||||||
|
|
||||||
// Doubled pawn penalty by opposed flag and file
|
// Doubled pawn penalty by opposed flag and file
|
||||||
|
@ -77,14 +65,9 @@ namespace {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////
|
|
||||||
//// Functions
|
|
||||||
////
|
|
||||||
|
|
||||||
|
|
||||||
/// PawnInfoTable::get_pawn_info() takes a position object as input, computes
|
/// PawnInfoTable::get_pawn_info() takes a position object as input, computes
|
||||||
/// a PawnInfo object, and returns a pointer to it. The result is also stored
|
/// a PawnInfo 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
|
/// in an hash table, so we don't have to recompute everything when the same
|
||||||
/// pawn structure occurs again.
|
/// pawn structure occurs again.
|
||||||
|
|
||||||
PawnInfo* PawnInfoTable::get_pawn_info(const Position& pos) const {
|
PawnInfo* PawnInfoTable::get_pawn_info(const Position& pos) const {
|
||||||
|
@ -100,11 +83,11 @@ PawnInfo* PawnInfoTable::get_pawn_info(const Position& pos) const {
|
||||||
if (pi->key == key)
|
if (pi->key == key)
|
||||||
return pi;
|
return pi;
|
||||||
|
|
||||||
// Clear the PawnInfo object, and set the key
|
// Initialize PawnInfo entry
|
||||||
memset(pi, 0, sizeof(PawnInfo));
|
|
||||||
pi->halfOpenFiles[WHITE] = pi->halfOpenFiles[BLACK] = 0xFF;
|
|
||||||
pi->kingSquares[WHITE] = pi->kingSquares[BLACK] = SQ_NONE;
|
|
||||||
pi->key = key;
|
pi->key = key;
|
||||||
|
pi->passedPawns[WHITE] = pi->passedPawns[BLACK] = 0;
|
||||||
|
pi->kingSquares[WHITE] = pi->kingSquares[BLACK] = SQ_NONE;
|
||||||
|
pi->halfOpenFiles[WHITE] = pi->halfOpenFiles[BLACK] = 0xFF;
|
||||||
|
|
||||||
// Calculate pawn attacks
|
// Calculate pawn attacks
|
||||||
Bitboard wPawns = pos.pieces(PAWN, WHITE);
|
Bitboard wPawns = pos.pieces(PAWN, WHITE);
|
||||||
|
@ -124,13 +107,16 @@ PawnInfo* PawnInfoTable::get_pawn_info(const Position& pos) const {
|
||||||
template<Color Us>
|
template<Color Us>
|
||||||
Score PawnInfoTable::evaluate_pawns(const Position& pos, Bitboard ourPawns,
|
Score PawnInfoTable::evaluate_pawns(const Position& pos, Bitboard ourPawns,
|
||||||
Bitboard theirPawns, PawnInfo* pi) const {
|
Bitboard theirPawns, PawnInfo* pi) const {
|
||||||
|
|
||||||
|
const BitCountType Max15 = CpuIs64Bit ? CNT64_MAX15 : CNT32_MAX15;
|
||||||
|
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
||||||
|
|
||||||
Bitboard b;
|
Bitboard b;
|
||||||
Square s;
|
Square s;
|
||||||
File f;
|
File f;
|
||||||
Rank r;
|
Rank r;
|
||||||
bool passed, isolated, doubled, opposed, chain, backward, candidate;
|
bool passed, isolated, doubled, opposed, chain, backward, candidate;
|
||||||
Score value = SCORE_ZERO;
|
Score value = SCORE_ZERO;
|
||||||
const BitCountType Max15 = CpuIs64Bit ? CNT64_MAX15 : CNT32_MAX15;
|
|
||||||
const Square* ptr = pos.piece_list_begin(Us, PAWN);
|
const Square* ptr = pos.piece_list_begin(Us, PAWN);
|
||||||
|
|
||||||
// Loop through all pawns of the current color and score each pawn
|
// Loop through all pawns of the current color and score each pawn
|
||||||
|
@ -144,11 +130,11 @@ Score PawnInfoTable::evaluate_pawns(const Position& pos, Bitboard ourPawns,
|
||||||
// This file cannot be half open
|
// This file cannot be half open
|
||||||
pi->halfOpenFiles[Us] &= ~(1 << f);
|
pi->halfOpenFiles[Us] &= ~(1 << f);
|
||||||
|
|
||||||
// Our rank plus previous one. Used for chain detection.
|
// Our rank plus previous one. Used for chain detection
|
||||||
b = rank_bb(r) | rank_bb(Us == WHITE ? r - Rank(1) : r + Rank(1));
|
b = rank_bb(r) | rank_bb(Us == WHITE ? r - Rank(1) : r + Rank(1));
|
||||||
|
|
||||||
// Passed, isolated, doubled or member of a pawn
|
// Flag the pawn as passed, isolated, doubled or member of a pawn
|
||||||
// chain (but not the backward one) ?
|
// chain (but not the backward one).
|
||||||
passed = !(theirPawns & passed_pawn_mask(Us, s));
|
passed = !(theirPawns & passed_pawn_mask(Us, s));
|
||||||
doubled = ourPawns & squares_in_front_of(Us, s);
|
doubled = ourPawns & squares_in_front_of(Us, s);
|
||||||
opposed = theirPawns & squares_in_front_of(Us, s);
|
opposed = theirPawns & squares_in_front_of(Us, s);
|
||||||
|
@ -156,15 +142,13 @@ Score PawnInfoTable::evaluate_pawns(const Position& pos, Bitboard ourPawns,
|
||||||
chain = ourPawns & neighboring_files_bb(f) & b;
|
chain = ourPawns & neighboring_files_bb(f) & b;
|
||||||
|
|
||||||
// Test for backward pawn
|
// Test for backward pawn
|
||||||
//
|
|
||||||
backward = false;
|
backward = false;
|
||||||
|
|
||||||
// If the pawn is passed, isolated, or member of a pawn chain
|
// If the pawn is passed, isolated, or member of a pawn chain it cannot
|
||||||
// it cannot be backward. If can capture an enemy pawn or if
|
// be backward. If there are friendly pawns behind on neighboring files
|
||||||
// there are friendly pawns behind on neighboring files it cannot
|
// or if can capture an enemy pawn it cannot be backward either.
|
||||||
// be backward either.
|
|
||||||
if ( !(passed | isolated | chain)
|
if ( !(passed | isolated | chain)
|
||||||
&& !(ourPawns & attack_span_mask(opposite_color(Us), s))
|
&& !(ourPawns & attack_span_mask(Them, s))
|
||||||
&& !(pos.attacks_from<PAWN>(s, Us) & theirPawns))
|
&& !(pos.attacks_from<PAWN>(s, Us) & theirPawns))
|
||||||
{
|
{
|
||||||
// We now know that there are no friendly pawns beside or behind this
|
// We now know that there are no friendly pawns beside or behind this
|
||||||
|
@ -178,21 +162,24 @@ Score PawnInfoTable::evaluate_pawns(const Position& pos, Bitboard ourPawns,
|
||||||
while (!(b & (ourPawns | theirPawns)))
|
while (!(b & (ourPawns | theirPawns)))
|
||||||
Us == WHITE ? b <<= 8 : b >>= 8;
|
Us == WHITE ? b <<= 8 : b >>= 8;
|
||||||
|
|
||||||
// The friendly pawn needs to be at least two ranks closer than the enemy
|
// The friendly pawn needs to be at least two ranks closer than the
|
||||||
// pawn in order to help the potentially backward pawn advance.
|
// enemy pawn in order to help the potentially backward pawn advance.
|
||||||
backward = (b | (Us == WHITE ? b << 8 : b >> 8)) & theirPawns;
|
backward = (b | (Us == WHITE ? b << 8 : b >> 8)) & theirPawns;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(passed | opposed | (attack_span_mask(Us, s) & theirPawns));
|
assert(opposed | passed | (attack_span_mask(Us, s) & theirPawns));
|
||||||
|
|
||||||
// Test for candidate passed pawn
|
// A not passed pawn is a candidate to become passed if it is free to
|
||||||
candidate = !(opposed | passed)
|
// advance and if the number of friendly pawns beside or behind this
|
||||||
&& (b = attack_span_mask(opposite_color(Us), s + pawn_push(Us)) & ourPawns) != EmptyBoardBB
|
// pawn on neighboring files is higher or equal than the number of
|
||||||
|
// enemy pawns in the forward direction on the neighboring files.
|
||||||
|
candidate = !(opposed | passed | backward | isolated)
|
||||||
|
&& (b = attack_span_mask(Them, s + pawn_push(Us)) & ourPawns) != EmptyBoardBB
|
||||||
&& count_1s<Max15>(b) >= count_1s<Max15>(attack_span_mask(Us, s) & theirPawns);
|
&& count_1s<Max15>(b) >= count_1s<Max15>(attack_span_mask(Us, s) & theirPawns);
|
||||||
|
|
||||||
// Mark the pawn as passed. Pawn will be properly scored in evaluation
|
// Passed pawns will be properly scored in evaluation because we need
|
||||||
// because we need full attack info to evaluate passed pawns. Only the
|
// full attack info to evaluate passed pawns. Only the frontmost passed
|
||||||
// frontmost passed pawn on each file is considered a true passed pawn.
|
// pawn on each file is considered a true passed pawn.
|
||||||
if (passed && !doubled)
|
if (passed && !doubled)
|
||||||
set_bit(&(pi->passedPawns[Us]), s);
|
set_bit(&(pi->passedPawns[Us]), s);
|
||||||
|
|
||||||
|
@ -214,3 +201,33 @@ Score PawnInfoTable::evaluate_pawns(const Position& pos, Bitboard ourPawns,
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// PawnInfo::updateShelter() calculates and caches king shelter. It is called
|
||||||
|
/// only when king square changes, about 20% of total king_shelter() calls.
|
||||||
|
template<Color Us>
|
||||||
|
Score PawnInfo::updateShelter(const Position& pos, Square ksq) {
|
||||||
|
|
||||||
|
const int Shift = (Us == WHITE ? 8 : -8);
|
||||||
|
|
||||||
|
Bitboard pawns;
|
||||||
|
int r, shelter = 0;
|
||||||
|
|
||||||
|
if (relative_rank(Us, ksq) <= RANK_4)
|
||||||
|
{
|
||||||
|
pawns = pos.pieces(PAWN, Us) & this_and_neighboring_files_bb(ksq);
|
||||||
|
r = ksq & (7 << 3);
|
||||||
|
for (int i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
r += Shift;
|
||||||
|
shelter += BitCount8Bit[(pawns >> r) & 0xFF] * (64 >> i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
kingSquares[Us] = ksq;
|
||||||
|
kingShelters[Us] = make_score(shelter, 0);
|
||||||
|
return kingShelters[Us];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Explicit template instantiation
|
||||||
|
template Score PawnInfo::updateShelter<WHITE>(const Position& pos, Square ksq);
|
||||||
|
template Score PawnInfo::updateShelter<BLACK>(const Position& pos, Square ksq);
|
||||||
|
|
42
src/pawns.h
42
src/pawns.h
|
@ -20,7 +20,6 @@
|
||||||
#if !defined(PAWNS_H_INCLUDED)
|
#if !defined(PAWNS_H_INCLUDED)
|
||||||
#define PAWNS_H_INCLUDED
|
#define PAWNS_H_INCLUDED
|
||||||
|
|
||||||
#include "bitboard.h"
|
|
||||||
#include "position.h"
|
#include "position.h"
|
||||||
#include "tt.h"
|
#include "tt.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
@ -66,28 +65,14 @@ private:
|
||||||
/// method is get_pawn_info, which returns a pointer to a PawnInfo object.
|
/// method is get_pawn_info, which returns a pointer to a PawnInfo object.
|
||||||
|
|
||||||
class PawnInfoTable : public SimpleHash<PawnInfo, PawnTableSize> {
|
class PawnInfoTable : public SimpleHash<PawnInfo, PawnTableSize> {
|
||||||
|
|
||||||
enum SideType { KingSide, QueenSide };
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PawnInfo* get_pawn_info(const Position& pos) const;
|
PawnInfo* get_pawn_info(const Position& pos) const;
|
||||||
void prefetch(Key key) const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template<Color Us>
|
template<Color Us>
|
||||||
Score evaluate_pawns(const Position& pos, Bitboard ourPawns, Bitboard theirPawns, PawnInfo* pi) const;
|
Score evaluate_pawns(const Position& pos, Bitboard ourPawns, Bitboard theirPawns, PawnInfo* pi) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline Square pawn_push(Color c) {
|
|
||||||
return c == WHITE ? DELTA_N : DELTA_S;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void PawnInfoTable::prefetch(Key key) const {
|
|
||||||
|
|
||||||
unsigned index = unsigned(key & (PawnTableSize - 1));
|
|
||||||
PawnInfo* pi = entries + index;
|
|
||||||
::prefetch((char*) pi);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline Score PawnInfo::pawns_value() const {
|
inline Score PawnInfo::pawns_value() const {
|
||||||
return value;
|
return value;
|
||||||
|
@ -102,7 +87,7 @@ inline Bitboard PawnInfo::passed_pawns(Color c) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int PawnInfo::file_is_half_open(Color c, File f) const {
|
inline int PawnInfo::file_is_half_open(Color c, File f) const {
|
||||||
return (halfOpenFiles[c] & (1 << int(f)));
|
return halfOpenFiles[c] & (1 << int(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int PawnInfo::has_open_file_to_left(Color c, File f) const {
|
inline int PawnInfo::has_open_file_to_left(Color c, File f) const {
|
||||||
|
@ -113,31 +98,6 @@ inline int PawnInfo::has_open_file_to_right(Color c, File f) const {
|
||||||
return halfOpenFiles[c] & ~((1 << int(f+1)) - 1);
|
return halfOpenFiles[c] & ~((1 << int(f+1)) - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// PawnInfo::updateShelter() calculates and caches king shelter. It is called
|
|
||||||
/// only when king square changes, about 20% of total king_shelter() calls.
|
|
||||||
template<Color Us>
|
|
||||||
Score PawnInfo::updateShelter(const Position& pos, Square ksq) {
|
|
||||||
|
|
||||||
const int Shift = (Us == WHITE ? 8 : -8);
|
|
||||||
|
|
||||||
Bitboard pawns;
|
|
||||||
int r, shelter = 0;
|
|
||||||
|
|
||||||
if (relative_rank(Us, ksq) <= RANK_4)
|
|
||||||
{
|
|
||||||
pawns = pos.pieces(PAWN, Us) & this_and_neighboring_files_bb(ksq);
|
|
||||||
r = square_rank(ksq) * 8;
|
|
||||||
for (int i = 1; i < 4; i++)
|
|
||||||
{
|
|
||||||
r += Shift;
|
|
||||||
shelter += BitCount8Bit[(pawns >> r) & 0xFF] * (128 >> i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
kingSquares[Us] = ksq;
|
|
||||||
kingShelters[Us] = make_score(shelter, 0);
|
|
||||||
return kingShelters[Us];
|
|
||||||
}
|
|
||||||
|
|
||||||
template<Color Us>
|
template<Color Us>
|
||||||
inline Score PawnInfo::king_shelter(const Position& pos, Square ksq) {
|
inline Score PawnInfo::king_shelter(const Position& pos, Square ksq) {
|
||||||
return kingSquares[Us] == ksq ? kingShelters[Us] : updateShelter<Us>(pos, ksq);
|
return kingSquares[Us] == ksq ? kingShelters[Us] : updateShelter<Us>(pos, ksq);
|
||||||
|
|
1
src/tt.h
1
src/tt.h
|
@ -51,6 +51,7 @@ public:
|
||||||
virtual ~SimpleHash() { delete [] entries; }
|
virtual ~SimpleHash() { delete [] entries; }
|
||||||
|
|
||||||
Entry* find(Key key) const { return entries + ((uint32_t)key & (HashSize - 1)); }
|
Entry* find(Key key) const { return entries + ((uint32_t)key & (HashSize - 1)); }
|
||||||
|
void prefetch(Key key) const { ::prefetch((char*)find(key)); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Entry* entries;
|
Entry* entries;
|
||||||
|
|
|
@ -463,4 +463,8 @@ inline bool square_is_ok(Square s) {
|
||||||
return s >= SQ_A1 && s <= SQ_H8;
|
return s >= SQ_A1 && s <= SQ_H8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline Square pawn_push(Color c) {
|
||||||
|
return c == WHITE ? DELTA_N : DELTA_S;
|
||||||
|
}
|
||||||
|
|
||||||
#endif // !defined(TYPES_H_INCLUDED)
|
#endif // !defined(TYPES_H_INCLUDED)
|
||||||
|
|
Loading…
Add table
Reference in a new issue