1
0
Fork 0
mirror of https://github.com/sockspls/badfish synced 2025-05-01 01:03:09 +00:00

Define Score as an enum

Increases performance because now we use one integer
for both midgame and endgame scores.

Unfortunatly the latest patches seem to have reduced a bit
the speed so at the end we are more or less at the same
performance level of the beginning. But this patch series
introduced also some code cleanup so it is the main reason
we commit anyway.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
This commit is contained in:
Marco Costalba 2009-11-07 22:21:50 +01:00
parent fea46a8212
commit ef6fca98a0
7 changed files with 83 additions and 83 deletions

View file

@ -56,18 +56,18 @@ namespace {
// parameters at 100, which looks prettier.
//
// Values modified by Joona Kiiski
const Score WeightMobilityInternal = Score(248, 271);
const Score WeightPawnStructureInternal = Score(233, 201);
const Score WeightPassedPawnsInternal = Score(252, 259);
const Score WeightSpaceInternal = Score( 46, 0);
const Score WeightKingSafetyInternal = Score(247, 0);
const Score WeightKingOppSafetyInternal = Score(259, 0);
const Score WeightMobilityInternal = make_score(248, 271);
const Score WeightPawnStructureInternal = make_score(233, 201);
const Score WeightPassedPawnsInternal = make_score(252, 259);
const Score WeightSpaceInternal = make_score( 46, 0);
const Score WeightKingSafetyInternal = make_score(247, 0);
const Score WeightKingOppSafetyInternal = make_score(259, 0);
// Mobility and outposts bonus modified by Joona Kiiski
//
// Visually better to define tables constants
typedef Value V;
typedef Score S;
#define S(mg, eg) make_score(mg, eg)
// Knight mobility bonus in middle game and endgame, indexed by the number
// of attacked squares not occupied by friendly piecess.
@ -140,12 +140,12 @@ namespace {
const Value UnstoppablePawnValue = Value(0x500);
// Rooks and queens on the 7th rank (modified by Joona Kiiski)
const Score RookOn7thBonus = Score(47, 98);
const Score QueenOn7thBonus = Score(27, 54);
const Score RookOn7thBonus = make_score(47, 98);
const Score QueenOn7thBonus = make_score(27, 54);
// Rooks on open files (modified by Joona Kiiski)
const Score RookOpenFileBonus = Score(43, 43);
const Score RookHalfOpenFileBonus = Score(19, 19);
const Score RookOpenFileBonus = make_score(43, 43);
const Score RookHalfOpenFileBonus = make_score(19, 19);
// Penalty for rooks trapped inside a friendly king which has lost the
// right to castle.
@ -153,7 +153,7 @@ namespace {
// Penalty for a bishop on a7/h7 (a2/h2 for black) which is trapped by
// enemy pawns.
const Score TrappedBishopA7H7Penalty = Score(300, 300);
const Score TrappedBishopA7H7Penalty = make_score(300, 300);
// Bitboard masks for detecting trapped bishops on a7/h7 (a2/h2 for black)
const Bitboard MaskA7H7[2] = {
@ -164,7 +164,7 @@ namespace {
// Penalty for a bishop on a1/h1 (a8/h8 for black) which is trapped by
// a friendly pawn on b2/g2 (b7/g7 for black). This can obviously only
// happen in Chess960 games.
const Score TrappedBishopA1H1Penalty = Score(100, 100);
const Score TrappedBishopA1H1Penalty = make_score(100, 100);
// Bitboard masks for detecting trapped bishops on a1/h1 (a8/h8 for black)
const Bitboard MaskA1H1[2] = {
@ -210,7 +210,7 @@ namespace {
// ThreatBonus[][] contains bonus according to which piece type
// attacks which one.
#define Z Score(0, 0)
#define Z make_score(0, 0)
const Score ThreatBonus[8][8] = {
{ Z, Z, Z, Z, Z, Z, Z, Z }, // not used
@ -230,6 +230,7 @@ namespace {
};
#undef Z
#undef S
// InitKingDanger[] contains bonuses based on the position of the defending
// king.
@ -375,12 +376,12 @@ Value do_evaluate(const Position& pos, EvalInfo& ei, int threadID) {
if ( square_file(pos.king_square(WHITE)) >= FILE_E
&& square_file(pos.king_square(BLACK)) <= FILE_D)
ei.value += Score(ei.pi->queenside_storm_value(WHITE) - ei.pi->kingside_storm_value(BLACK), 0);
ei.value += make_score(ei.pi->queenside_storm_value(WHITE) - ei.pi->kingside_storm_value(BLACK), 0);
else if ( square_file(pos.king_square(WHITE)) <= FILE_D
&& square_file(pos.king_square(BLACK)) >= FILE_E)
ei.value += Score(ei.pi->kingside_storm_value(WHITE) - ei.pi->queenside_storm_value(BLACK), 0);
ei.value += make_score(ei.pi->kingside_storm_value(WHITE) - ei.pi->queenside_storm_value(BLACK), 0);
// Evaluate space for both sides
if (ei.mi->space_weight() > 0)
@ -397,8 +398,8 @@ Value do_evaluate(const Position& pos, EvalInfo& ei, int threadID) {
// colored bishop endgames, and use a lower scale for those
if ( phase < PHASE_MIDGAME
&& pos.opposite_colored_bishops()
&& ( (factor[WHITE] == SCALE_FACTOR_NORMAL && ei.value.eg() > Value(0))
|| (factor[BLACK] == SCALE_FACTOR_NORMAL && ei.value.eg() < Value(0))))
&& ( (factor[WHITE] == SCALE_FACTOR_NORMAL && eg_value(ei.value) > Value(0))
|| (factor[BLACK] == SCALE_FACTOR_NORMAL && eg_value(ei.value) < Value(0))))
{
ScaleFactor sf;
@ -564,7 +565,7 @@ namespace {
else
bonus += bonus / 2;
}
ei.value += Sign[Us] * Score(bonus, bonus);
ei.value += Sign[Us] * make_score(bonus, bonus);
}
@ -654,8 +655,8 @@ namespace {
{
// Is there a half-open file between the king and the edge of the board?
if (!ei.pi->has_open_file_to_right(Us, square_file(ksq)))
ei.value -= Sign[Us] * Score(pos.can_castle(Us) ? (TrappedRookPenalty - mob * 16) / 2
: (TrappedRookPenalty - mob * 16), 0);
ei.value -= Sign[Us] * make_score(pos.can_castle(Us) ? (TrappedRookPenalty - mob * 16) / 2
: (TrappedRookPenalty - mob * 16), 0);
}
else if ( square_file(ksq) <= FILE_D
&& square_file(s) < square_file(ksq)
@ -663,8 +664,8 @@ namespace {
{
// Is there a half-open file between the king and the edge of the board?
if (!ei.pi->has_open_file_to_left(Us, square_file(ksq)))
ei.value -= Sign[Us] * Score(pos.can_castle(Us) ? (TrappedRookPenalty - mob * 16) / 2
: (TrappedRookPenalty - mob * 16), 0);
ei.value -= Sign[Us] * make_score(pos.can_castle(Us) ? (TrappedRookPenalty - mob * 16) / 2
: (TrappedRookPenalty - mob * 16), 0);
}
}
}
@ -680,7 +681,7 @@ namespace {
const Color Them = (Us == WHITE ? BLACK : WHITE);
Bitboard b;
Score bonus(0, 0);
Score bonus = make_score(0, 0);
// Enemy pieces not defended by a pawn and under our attack
Bitboard weakEnemies = pos.pieces_of_color(Them)
@ -735,7 +736,7 @@ namespace {
if (relative_rank(Us, s) <= RANK_4)
{
shelter = ei.pi->get_king_shelter(pos, Us, s);
ei.value += Sign[Us] * Score(shelter, 0);
ei.value += Sign[Us] * make_score(shelter, 0);
}
// King safety. This is quite complicated, and is almost certainly far
@ -882,12 +883,12 @@ namespace {
// that the king safety scores can sometimes be very big, and that
// capturing a single attacking piece can therefore result in a score
// change far bigger than the value of the captured piece.
Score v = apply_weight(Score(SafetyTable[attackUnits], 0), WeightKingSafety[Us]);
Score v = apply_weight(make_score(SafetyTable[attackUnits], 0), WeightKingSafety[Us]);
ei.value -= Sign[Us] * v;
if (Us == pos.side_to_move())
ei.futilityMargin += v.mg();
ei.futilityMargin += mg_value(v);
}
}
@ -1015,7 +1016,7 @@ namespace {
}
// Add the scores for this pawn to the middle game and endgame eval.
ei.value += Sign[Us] * apply_weight(Score(mbonus, ebonus), WeightPassedPawns);
ei.value += Sign[Us] * apply_weight(make_score(mbonus, ebonus), WeightPassedPawns);
} // while
}
@ -1040,7 +1041,7 @@ namespace {
if (!movesToGo[WHITE] || !movesToGo[BLACK])
{
Color winnerSide = movesToGo[WHITE] ? WHITE : BLACK;
ei.value += Score(0, Sign[winnerSide] * (UnstoppablePawnValue - Value(0x40 * movesToGo[winnerSide])));
ei.value += make_score(0, Sign[winnerSide] * (UnstoppablePawnValue - Value(0x40 * movesToGo[winnerSide])));
}
else
{ // Both sides have unstoppable pawns! Try to find out who queens
@ -1055,7 +1056,7 @@ namespace {
// If one side queens at least three plies before the other, that side wins
if (movesToGo[winnerSide] <= movesToGo[loserSide] - 3)
ei.value += Sign[winnerSide] * Score(0, UnstoppablePawnValue - Value(0x40 * (movesToGo[winnerSide]/2)));
ei.value += Sign[winnerSide] * make_score(0, UnstoppablePawnValue - Value(0x40 * (movesToGo[winnerSide]/2)));
// If one side queens one ply before the other and checks the king or attacks
// the undefended opponent's queening square, that side wins. To avoid cases
@ -1076,7 +1077,7 @@ namespace {
if ( (b & pos.pieces(KING, loserSide))
||(bit_is_set(b, loserQSq) && !bit_is_set(ei.attacked_by(loserSide), loserQSq)))
ei.value += Sign[winnerSide] * Score(0, UnstoppablePawnValue - Value(0x40 * (movesToGo[winnerSide]/2)));
ei.value += Sign[winnerSide] * make_score(0, UnstoppablePawnValue - Value(0x40 * (movesToGo[winnerSide]/2)));
}
}
}
@ -1175,14 +1176,14 @@ namespace {
int space = count_1s_max_15<HasPopCnt>(safeSquares)
+ count_1s_max_15<HasPopCnt>(behindFriendlyPawns & safeSquares);
ei.value += Sign[Us] * apply_weight(Score(space * ei.mi->space_weight(), 0), WeightSpace);
ei.value += Sign[Us] * apply_weight(make_score(space * ei.mi->space_weight(), 0), WeightSpace);
}
// apply_weight() applies an evaluation weight to a value
// apply_weight() applies an evaluation weight to a value trying to prevent overflow
inline Score apply_weight(Score v, Score w) {
return v * w / 0x100;
return make_score((int(mg_value(v)) * mg_value(w)) / 0x100, (int(eg_value(v)) * eg_value(w)) / 0x100);
}
@ -1192,14 +1193,14 @@ namespace {
Value scale_by_game_phase(const Score& v, Phase ph, const ScaleFactor sf[]) {
assert(v.mg() > -VALUE_INFINITE && v.mg() < VALUE_INFINITE);
assert(v.eg() > -VALUE_INFINITE && v.eg() < VALUE_INFINITE);
assert(mg_value(v) > -VALUE_INFINITE && mg_value(v) < VALUE_INFINITE);
assert(eg_value(v) > -VALUE_INFINITE && eg_value(v) < VALUE_INFINITE);
assert(ph >= PHASE_ENDGAME && ph <= PHASE_MIDGAME);
Value ev = apply_scale_factor(v.eg(), sf[(v.eg() > Value(0) ? WHITE : BLACK)]);
Value ev = apply_scale_factor(eg_value(v), sf[(eg_value(v) > Value(0) ? WHITE : BLACK)]);
Value result = Value(int((v.mg() * ph + ev * (128 - ph)) / 128));
return Value(int(result) & ~(GrainSize - 1));
int result = (mg_value(v) * ph + ev * (128 - ph)) / 128;
return Value(result & ~(GrainSize - 1));
}
@ -1208,11 +1209,18 @@ namespace {
Score weight_option(const std::string& mgOpt, const std::string& egOpt, Score internalWeight) {
Score uciWeight(get_option_value_int(mgOpt), get_option_value_int(egOpt));
uciWeight = (uciWeight * 0x100) / 100;
return (uciWeight * internalWeight) / 0x100;
}
Score uciWeight = make_score(get_option_value_int(mgOpt), get_option_value_int(egOpt));
// Convert to integer to prevent overflow
int mg = mg_value(uciWeight);
int eg = eg_value(uciWeight);
mg = (mg * 0x100) / 100;
eg = (eg * 0x100) / 100;
mg = (mg * mg_value(internalWeight)) / 0x100;
eg = (eg * eg_value(internalWeight)) / 0x100;
return make_score(mg, eg);
}
// init_safety() initizes the king safety evaluation, based on UCI
// parameters. It is called from read_weights().
@ -1255,8 +1263,3 @@ namespace {
}
}
}
std::ostream& operator<<(std::ostream &os, Score s) {
return os << "(" << s.mg() << ", " << s.eg() << ")";
}

View file

@ -97,7 +97,7 @@ private:
inline Score MaterialInfo::material_value() const {
return Score(value, value);
return make_score(value, value);
}

View file

@ -221,7 +221,7 @@ void MovePicker::score_noncaptures() {
hs += 1000;
// pst based scoring
cur->score = hs + pos.pst_delta(piece, from, to).mg();
cur->score = hs + mg_value(pos.pst_delta(piece, from, to));
}
}

View file

@ -99,7 +99,7 @@ private:
////
inline Score PawnInfo::value() const {
return Score(mgValue, egValue);
return make_score(mgValue, egValue);
}
inline Bitboard PawnInfo::passed_pawns() const {

View file

@ -894,7 +894,7 @@ void Position::do_move(Move m, StateInfo& newSt, Bitboard dcCandidates) {
// Finish
sideToMove = opposite_color(sideToMove);
st->value += (sideToMove == WHITE) ? TempoValue : -TempoValue;
st->value += (sideToMove == WHITE ? TempoValue : -TempoValue);
assert(is_ok());
}
@ -1054,7 +1054,7 @@ void Position::do_castle_move(Move m) {
// Finish
sideToMove = opposite_color(sideToMove);
st->value += (sideToMove == WHITE) ? TempoValue : -TempoValue;
st->value += (sideToMove == WHITE ? TempoValue : -TempoValue);
assert(is_ok());
}
@ -1631,7 +1631,7 @@ Key Position::compute_material_key() const {
/// updated by do_move and undo_move when the program is running in debug mode.
Score Position::compute_value() const {
Score result(0, 0);
Score result = make_score(0, 0);
Bitboard b;
Square s;
@ -1647,7 +1647,7 @@ Score Position::compute_value() const {
}
}
result += (side_to_move() == WHITE)? TempoValue / 2 : -TempoValue / 2;
result += (side_to_move() == WHITE ? TempoValue / 2 : -TempoValue / 2);
return result;
}
@ -1796,7 +1796,7 @@ void Position::init_piece_square_tables() {
for (Piece p = WP; p <= WK; p++)
{
i = (r == 0)? 0 : (genrand_int32() % (r*2) - r);
PieceSquareTable[p][s] = Score(MgPST[p][s] + i, EgPST[p][s] + i);
PieceSquareTable[p][s] = make_score(MgPST[p][s] + i, EgPST[p][s] + i);
}
for (Square s = SQ_A1; s <= SQ_H8; s++)

View file

@ -148,8 +148,8 @@ namespace {
else if (token == "eval")
{
EvalInfo ei;
cout << "Incremental mg: " << RootPosition.value().mg()
<< "\nIncremental eg: " << RootPosition.value().eg()
cout << "Incremental mg: " << mg_value(RootPosition.value())
<< "\nIncremental eg: " << eg_value(RootPosition.value())
<< "\nFull eval: " << evaluate(RootPosition, ei, 0) << endl;
}
else if (token == "key")

View file

@ -55,36 +55,33 @@ enum Value {
/// Score struct keeps a midgame and an endgame value in a single
/// ScoreValue 64 bit union.
typedef int score_t;
enum Score;
struct Score {
inline Value eg_value(Score s) { return Value(int16_t(s & 0xffff)); }
inline Value mg_value(Score s) { return Value((int(s) + 32768) >> 16); }
Score() {}
Score(score_t mg, score_t eg) { mgv = mg; egv = eg; }
inline Score make_score(int mg, int eg) { return Score((mg << 16) + eg); }
Score& operator+=(const Score& s) { mgv += s.mg(); egv += s.eg(); return *this; }
Score& operator-=(const Score& s) { mgv -= s.mg(); egv -= s.eg(); return *this; }
Score operator+(const Score& s) { return Score(mg() + s.mg(), eg() + s.eg()); }
Score operator-(const Score& s) { return Score(mg() - s.mg(), eg() - s.eg()); }
inline Score operator-(Score s) { return Score(-int(s)); }
inline Score operator+(Score s1, Score s2) { return Score(int(s1) + int(s2)); }
inline Score operator-(Score s1, Score s2) { return Score(int(s1) - int(s2)); }
inline void operator+=(Score& s1, Score s2) { s1 = Score(int(s1) + int(s2)); }
inline void operator-=(Score& s1, Score s2) { s1 = Score(int(s1) - int(s2)); }
inline Score operator*(int i, Score s) { return Score(i * int(s)); }
inline Score operator/(Score s, int i) { return Score(int(s) / i); }
bool operator==(const Score& s) { return mgv == s.mg() && egv == s.eg(); }
bool operator!=(const Score& s) { return !(*this == s); }
// Only declared but not defined. We don't want to multiply two scores due to
// a very high risk of overflow. So user should explicitly convert to integer.
inline Score operator*(Score s1, Score s2);
Value mg() const { return Value(mgv); }
Value eg() const { return Value(egv); }
// Following are only declared to prevent erroneus instantations
inline Score operator*(Score s, int i);
inline Score operator/(Score s1, Score s2);
inline Score operator+(Score s, int i);
inline Score operator+(int i, Score s);
inline Score operator-(Score s, int i);
inline Score operator-(int i, Score s);
private:
score_t mgv;
score_t egv;
};
inline Score operator*(Score s1, Score s2) { return Score(s1.mg() * s2.mg(), s1.eg() * s2.eg()); }
inline Score operator*(int i, Score s) { return Score(i * s.mg(), i * s.eg()); }
inline Score operator*(Score s, int i) { return Score(s.mg() * i, s.eg() * i); }
inline Score operator/(Score s, int i) { return Score(s.mg() / i, s.eg() / i); }
inline Score operator-(Score s) { return Score(-s.mg(), -s.eg()); }
extern std::ostream& operator<<(std::ostream& os, Score s);
////
//// Constants and variables
@ -131,7 +128,7 @@ const Value PieceValueEndgame[17] = {
/// Bonus for having the side to move (modified by Joona Kiiski)
const Score TempoValue = Score(48, 22);
const Score TempoValue = make_score(48, 22);
////