1
0
Fork 0
mirror of https://github.com/sockspls/badfish synced 2025-04-30 00:33:09 +00:00

Always initialize and evaluate king safety

Recent tests by @xoto10, @Vizvezdenec, and myself seemed to hint that Elo could
be gained by expanding the number of cases where king safety is applied. Several
users (@Spliffjiffer, @Vizvezdenec) have anticipated benefits specifically in
evaluation of tactics. It appears that we actually do not need to restrict the
cases in which we initialize and evaluate king safety at all: initializing and
evaluating it in every position appears roughly Elo-neutral at STC and possibly
a substantial Elo gain at LTC.

Any explanation for this scaling is, at this point, conjecture. Assuming it is
not due to chance, my hypothesis is that initialization of king safety in all
positions is a mild slowdown, offset by an Elo gain of evaluating king safety
in all positions. At STC this produces Elo gains and losses that offset each
other, while at longer time control the slowdown is much less important, leaving
only the Elo gain. It probably helps SF to explore king attacks much earlier in
search with high numbers of enemy pieces concentrating but not essentially attacking
king ring.

Thanks to @xoto10 and @Vizvezdenec for helping run my LTC!

Closes https://github.com/official-stockfish/Stockfish/pull/1906

STC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 35432 W: 7815 L: 7721 D: 19896
http://tests.stockfishchess.org/tests/view/5c24779d0ebc5902ba131b26

LTC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 12887 W: 2217 L: 2084 D: 8586
http://tests.stockfishchess.org/tests/view/5c25049a0ebc5902ba132586

Bench: 3163951

------------------

How to continue from there?

* Next step will be to tune all the king danger terms once more after that :-)
This commit is contained in:
31m059 2018-12-27 01:51:43 -05:00 committed by Stéphane Nicolet
parent 14c4a40dc7
commit 69dc5568b3

View file

@ -258,25 +258,20 @@ namespace {
attackedBy[Us][ALL_PIECES] = attackedBy[Us][KING] | attackedBy[Us][PAWN];
attackedBy2[Us] = attackedBy[Us][KING] & attackedBy[Us][PAWN];
kingRing[Us] = kingAttackersCount[Them] = 0;
// Init our king safety tables
kingRing[Us] = attackedBy[Us][KING];
if (relative_rank(Us, pos.square<KING>(Us)) == RANK_1)
kingRing[Us] |= shift<Up>(kingRing[Us]);
// Init our king safety tables only if we are going to use them
if (pos.non_pawn_material(Them) >= RookValueMg + KnightValueMg)
{
kingRing[Us] = attackedBy[Us][KING];
if (relative_rank(Us, pos.square<KING>(Us)) == RANK_1)
kingRing[Us] |= shift<Up>(kingRing[Us]);
if (file_of(pos.square<KING>(Us)) == FILE_H)
kingRing[Us] |= shift<WEST>(kingRing[Us]);
if (file_of(pos.square<KING>(Us)) == FILE_H)
kingRing[Us] |= shift<WEST>(kingRing[Us]);
else if (file_of(pos.square<KING>(Us)) == FILE_A)
kingRing[Us] |= shift<EAST>(kingRing[Us]);
else if (file_of(pos.square<KING>(Us)) == FILE_A)
kingRing[Us] |= shift<EAST>(kingRing[Us]);
kingAttackersCount[Them] = popcount(kingRing[Us] & pe->pawn_attacks(Them));
kingRing[Us] &= ~double_pawn_attacks_bb<Us>(pos.pieces(Us, PAWN));
kingAttacksCount[Them] = kingAttackersWeight[Them] = 0;
}
kingAttackersCount[Them] = popcount(kingRing[Us] & pe->pawn_attacks(Them));
kingRing[Us] &= ~double_pawn_attacks_bb<Us>(pos.pieces(Us, PAWN));
kingAttacksCount[Them] = kingAttackersWeight[Them] = 0;
}
@ -424,67 +419,64 @@ namespace {
int tropism = popcount(b1) + popcount(b2);
// Main king safety evaluation
if (kingAttackersCount[Them] > 1 - pos.count<QUEEN>(Them))
{
int kingDanger = 0;
unsafeChecks = 0;
int kingDanger = 0;
unsafeChecks = 0;
// Attacked squares defended at most once by our queen or king
weak = attackedBy[Them][ALL_PIECES]
& ~attackedBy2[Us]
& (~attackedBy[Us][ALL_PIECES] | attackedBy[Us][KING] | attackedBy[Us][QUEEN]);
// Attacked squares defended at most once by our queen or king
weak = attackedBy[Them][ALL_PIECES]
& ~attackedBy2[Us]
& (~attackedBy[Us][ALL_PIECES] | attackedBy[Us][KING] | attackedBy[Us][QUEEN]);
// Analyse the safe enemy's checks which are possible on next move
safe = ~pos.pieces(Them);
safe &= ~attackedBy[Us][ALL_PIECES] | (weak & attackedBy2[Them]);
// Analyse the safe enemy's checks which are possible on next move
safe = ~pos.pieces(Them);
safe &= ~attackedBy[Us][ALL_PIECES] | (weak & attackedBy2[Them]);
b1 = attacks_bb<ROOK >(ksq, pos.pieces() ^ pos.pieces(Us, QUEEN));
b2 = attacks_bb<BISHOP>(ksq, pos.pieces() ^ pos.pieces(Us, QUEEN));
b1 = attacks_bb<ROOK >(ksq, pos.pieces() ^ pos.pieces(Us, QUEEN));
b2 = attacks_bb<BISHOP>(ksq, pos.pieces() ^ pos.pieces(Us, QUEEN));
// Enemy queen safe checks
if ((b1 | b2) & attackedBy[Them][QUEEN] & safe & ~attackedBy[Us][QUEEN])
kingDanger += QueenSafeCheck;
// Enemy queen safe checks
if ((b1 | b2) & attackedBy[Them][QUEEN] & safe & ~attackedBy[Us][QUEEN])
kingDanger += QueenSafeCheck;
b1 &= attackedBy[Them][ROOK];
b2 &= attackedBy[Them][BISHOP];
b1 &= attackedBy[Them][ROOK];
b2 &= attackedBy[Them][BISHOP];
// Enemy rooks checks
if (b1 & safe)
kingDanger += RookSafeCheck;
else
unsafeChecks |= b1;
// Enemy rooks checks
if (b1 & safe)
kingDanger += RookSafeCheck;
else
unsafeChecks |= b1;
// Enemy bishops checks
if (b2 & safe)
kingDanger += BishopSafeCheck;
else
unsafeChecks |= b2;
// Enemy bishops checks
if (b2 & safe)
kingDanger += BishopSafeCheck;
else
unsafeChecks |= b2;
// Enemy knights checks
b = pos.attacks_from<KNIGHT>(ksq) & attackedBy[Them][KNIGHT];
if (b & safe)
kingDanger += KnightSafeCheck;
else
unsafeChecks |= b;
// Enemy knights checks
b = pos.attacks_from<KNIGHT>(ksq) & attackedBy[Them][KNIGHT];
if (b & safe)
kingDanger += KnightSafeCheck;
else
unsafeChecks |= b;
// Unsafe or occupied checking squares will also be considered, as long as
// the square is in the attacker's mobility area.
unsafeChecks &= mobilityArea[Them];
// Unsafe or occupied checking squares will also be considered, as long as
// the square is in the attacker's mobility area.
unsafeChecks &= mobilityArea[Them];
kingDanger += kingAttackersCount[Them] * kingAttackersWeight[Them]
+ 69 * kingAttacksCount[Them]
+ 185 * popcount(kingRing[Us] & weak)
+ 150 * popcount(pos.blockers_for_king(Us) | unsafeChecks)
+ tropism * tropism / 4
- 873 * !pos.count<QUEEN>(Them)
- 6 * mg_value(score) / 8
+ mg_value(mobility[Them] - mobility[Us])
- 30;
kingDanger += kingAttackersCount[Them] * kingAttackersWeight[Them]
+ 69 * kingAttacksCount[Them]
+ 185 * popcount(kingRing[Us] & weak)
+ 150 * popcount(pos.blockers_for_king(Us) | unsafeChecks)
+ tropism * tropism / 4
- 873 * !pos.count<QUEEN>(Them)
- 6 * mg_value(score) / 8
+ mg_value(mobility[Them] - mobility[Us])
- 30;
// Transform the kingDanger units into a Score, and subtract it from the evaluation
if (kingDanger > 0)
score -= make_score(kingDanger * kingDanger / 4096, kingDanger / 16);
}
// Transform the kingDanger units into a Score, and subtract it from the evaluation
if (kingDanger > 0)
score -= make_score(kingDanger * kingDanger / 4096, kingDanger / 16);
// Penalty when our king is on a pawnless flank
if (!(pos.pieces(PAWN) & kingFlank))