2008-08-31 23:59:13 -06:00
|
|
|
/*
|
2008-10-19 10:56:28 -06:00
|
|
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
|
|
|
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
2016-01-02 02:43:25 -07:00
|
|
|
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
|
2020-01-07 13:35:47 -07:00
|
|
|
Copyright (C) 2015-2020 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
|
2008-08-31 23:59:13 -06:00
|
|
|
|
2008-10-19 10:56:28 -06:00
|
|
|
Stockfish is free software: you can redistribute it and/or modify
|
2008-08-31 23:59:13 -06:00
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
2009-01-07 06:26:58 -07:00
|
|
|
|
2008-10-19 10:56:28 -06:00
|
|
|
Stockfish is distributed in the hope that it will be useful,
|
2008-08-31 23:59:13 -06:00
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
2009-01-07 06:26:58 -07:00
|
|
|
|
2008-08-31 23:59:13 -06:00
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2019-03-31 04:02:19 -06:00
|
|
|
#include <algorithm>
|
2008-08-31 23:59:13 -06:00
|
|
|
#include <cassert>
|
|
|
|
|
2011-04-09 12:50:56 -06:00
|
|
|
#include "bitboard.h"
|
2008-08-31 23:59:13 -06:00
|
|
|
#include "pawns.h"
|
2009-03-18 08:36:03 -06:00
|
|
|
#include "position.h"
|
2014-12-30 02:31:50 -07:00
|
|
|
#include "thread.h"
|
2008-08-31 23:59:13 -06:00
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
2012-03-28 23:04:44 -06:00
|
|
|
#define V Value
|
2009-11-13 09:23:21 -07:00
|
|
|
#define S(mg, eg) make_score(mg, eg)
|
2008-08-31 23:59:13 -06:00
|
|
|
|
2018-06-02 09:41:37 -06:00
|
|
|
// Pawn penalties
|
2019-06-09 07:07:36 -06:00
|
|
|
constexpr Score Backward = S( 9, 24);
|
2019-08-24 00:16:20 -06:00
|
|
|
constexpr Score BlockedStorm = S(82, 82);
|
2019-06-09 07:07:36 -06:00
|
|
|
constexpr Score Doubled = S(11, 56);
|
|
|
|
constexpr Score Isolated = S( 5, 15);
|
2019-07-25 01:02:26 -06:00
|
|
|
constexpr Score WeakLever = S( 0, 56);
|
Exclude passed pawns from Attacked2Unsupported
We recently added a bonus for double pawn attacks on unsupported enemy pawns,
on June 27. However, it is possible that the unsupported pawn may become a passer
by simply pushing forward out of the double attack. By rewarding double attacks,
we may inadvertently reward the creation of enemy passers, by encouraging both of
our would-be stoppers to attack the enemy pawn even if there is no opposing
friendly pawn on the same file.
Here, we revise this term to exclude passed pawns. In order to simplify the code
with this change included, we non-functionally rewrite Attacked2Unsupported to
be a penalty for enemy attacks on friendly pawns, rather than a bonus for our
attacks on enemy pawns. This allows us to exclude passed pawns with a simple
& ~e->passedPawns[Us], while passedPawns[Them] is not yet defined in this part
of the code.
This dramatically reduces the proportion of positions in which Attacked2Unsupported
is applied, to about a third of the original. To compensate, maintaining the same
average effect across our bench positions, we nearly triple Attacked2Unsupported
from S(0, 20) to S(0, 56). Although this pawn formation is rare, it is worth more
than half a pawn in the endgame!
STC: (stopped automatically by fishtest after 250,000 games)
LLR: -0.87 (-2.94,2.94) [0.50,4.50]
Total: 250000 W: 56585 L: 55383 D: 138032
http://tests.stockfishchess.org/tests/view/5d25795e0ebc5925cf0cfb51
LTC:
LLR: 2.96 (-2.94,2.94) [0.00,3.50]
Total: 81038 W: 13965 L: 13558 D: 53515
http://tests.stockfishchess.org/tests/view/5d25f3920ebc5925cf0d10dd
Closes https://github.com/official-stockfish/Stockfish/pull/2233
Bench: 3765158
2019-07-11 07:14:57 -06:00
|
|
|
constexpr Score WeakUnopposed = S(13, 27);
|
2016-01-16 14:34:29 -07:00
|
|
|
|
2019-03-25 13:04:14 -06:00
|
|
|
// Connected pawn bonus
|
2019-04-23 12:26:58 -06:00
|
|
|
constexpr int Connected[RANK_NB] = { 0, 7, 8, 12, 29, 48, 86 };
|
2016-01-16 14:34:29 -07:00
|
|
|
|
2018-04-23 01:48:53 -06:00
|
|
|
// Strength of pawn shelter for our king by [distance from edge][rank].
|
|
|
|
// RANK_1 = 0 is used for files where we have no pawn, or pawn is behind our king.
|
2018-07-15 06:30:59 -06:00
|
|
|
constexpr Value ShelterStrength[int(FILE_NB) / 2][RANK_NB] = {
|
2018-08-17 02:19:32 -06:00
|
|
|
{ V( -6), V( 81), V( 93), V( 58), V( 39), V( 18), V( 25) },
|
|
|
|
{ V(-43), V( 61), V( 35), V(-49), V(-29), V(-11), V( -63) },
|
|
|
|
{ V(-10), V( 75), V( 23), V( -2), V( 32), V( 3), V( -45) },
|
|
|
|
{ V(-39), V(-13), V(-29), V(-52), V(-48), V(-67), V(-166) }
|
2016-09-23 11:28:34 -06:00
|
|
|
};
|
2012-03-26 05:52:10 -06:00
|
|
|
|
2018-05-24 10:46:38 -06:00
|
|
|
// Danger of enemy pawns moving toward our king by [distance from edge][rank].
|
2018-06-02 09:41:37 -06:00
|
|
|
// RANK_1 = 0 is used for files where the enemy has no pawn, or their pawn
|
2019-08-14 14:15:41 -06:00
|
|
|
// is behind our king. Note that UnblockedStorm[0][1-2] accommodate opponent pawn
|
|
|
|
// on edge, likely blocked by our king.
|
2018-05-24 10:46:38 -06:00
|
|
|
constexpr Value UnblockedStorm[int(FILE_NB) / 2][RANK_NB] = {
|
2019-11-29 10:15:21 -07:00
|
|
|
{ V( 85), V(-289), V(-166), V(97), V(50), V( 45), V( 50) },
|
|
|
|
{ V( 46), V( -25), V( 122), V(45), V(37), V(-10), V( 20) },
|
|
|
|
{ V( -6), V( 51), V( 168), V(34), V(-2), V(-22), V(-14) },
|
|
|
|
{ V(-15), V( -11), V( 101), V( 4), V(11), V(-15), V(-29) }
|
2016-09-23 11:28:34 -06:00
|
|
|
};
|
2012-03-28 04:44:41 -06:00
|
|
|
|
2012-03-28 23:04:44 -06:00
|
|
|
#undef S
|
|
|
|
#undef V
|
2012-12-22 03:21:06 -07:00
|
|
|
|
|
|
|
template<Color Us>
|
2013-06-16 02:51:17 -06:00
|
|
|
Score evaluate(const Position& pos, Pawns::Entry* e) {
|
2012-12-22 03:21:06 -07:00
|
|
|
|
2020-03-30 14:45:35 -06:00
|
|
|
constexpr Color Them = ~Us;
|
2019-10-31 10:17:46 -06:00
|
|
|
constexpr Direction Up = pawn_push(Us);
|
2012-12-22 03:21:06 -07:00
|
|
|
|
2019-09-27 02:18:22 -06:00
|
|
|
Bitboard neighbours, stoppers, support, phalanx, opposed;
|
2019-10-06 16:48:19 -06:00
|
|
|
Bitboard lever, leverPush, blocked;
|
2012-12-22 03:21:06 -07:00
|
|
|
Square s;
|
2019-09-27 02:18:22 -06:00
|
|
|
bool backward, passed, doubled;
|
2014-12-27 02:47:21 -07:00
|
|
|
Score score = SCORE_ZERO;
|
2015-08-04 01:00:52 -06:00
|
|
|
const Square* pl = pos.squares<PAWN>(Us);
|
2012-12-22 03:21:06 -07:00
|
|
|
|
2017-06-11 15:31:15 -06:00
|
|
|
Bitboard ourPawns = pos.pieces( Us, PAWN);
|
2013-06-16 02:51:17 -06:00
|
|
|
Bitboard theirPawns = pos.pieces(Them, PAWN);
|
|
|
|
|
2019-07-25 01:02:26 -06:00
|
|
|
Bitboard doubleAttackThem = pawn_double_attacks_bb<Them>(theirPawns);
|
|
|
|
|
2019-10-06 16:48:19 -06:00
|
|
|
e->passedPawns[Us] = 0;
|
Bonus for double attacks on unsupported pawns
This is a functional change that rewards double attacks on an unsupported pawns.
STC (non-functional difference)
LLR: 2.96 (-2.94,2.94) [0.50,4.50]
Total: 83276 W: 18981 L: 18398 D: 45897
http://tests.stockfishchess.org/tests/view/5d0970500ebc5925cf0a77d4
LTC (incomplete looping version)
LLR: 0.50 (-2.94,2.94) [0.00,3.50]
Total: 82999 W: 14244 L: 13978 D: 54777
http://tests.stockfishchess.org/tests/view/5d0a8d480ebc5925cf0a8d58
LTC (completed non-looping version).
LLR: 2.96 (-2.94,2.94) [0.00,3.50]
Total: 223381 W: 38323 L: 37512 D: 147546
http://tests.stockfishchess.org/tests/view/5d0e80510ebc5925cf0ad320
Closes https://github.com/official-stockfish/Stockfish/pull/2205
Bench 3633546
----------------------------------
Comments by Alain SAVARD:
interesting result ! I would have expected that search would resolve such positions
correctly on the very next move. This is not a very common pattern, and when it happens,
it will quickly disappear. So I'm quite surprised that it passed LTC.
I would be even more surprised if this would resist a simplification.
Anyway, let's try to imagine a few cases.
a) If you have White d5 f5 against Black e6, and White to move
last move by Black was probably a capture on e6 and White is about to recapture on e6
b) If you have White d5 f5 against e6, and Black to move
last move by White was possibly a capture on d5 or f5
or the pawn on e6 was pinned or could not move for some reason.
and white wants to blast open the position and just pushed d4-d5 or f4-f5
Some possible follow-ups
a) Motif is so rare that the popcount() can be safely replaced with a bool()
But this would not pass a SPRT[0,4],
So try a simplification with bool() and also without the & ~theirAttacks
b) If it works, we probably can simply have this in the loop
if (lever) score += S(0, 20);
c) remove all this and tweak something in search for pawn captures (priority, SEE, extension,..)
2019-06-27 01:45:53 -06:00
|
|
|
e->kingSquares[Us] = SQ_NONE;
|
2019-10-06 16:48:19 -06:00
|
|
|
e->pawnAttacks[Us] = e->pawnAttacksSpan[Us] = pawn_attacks_bb<Us>(ourPawns);
|
Scale up space weight with number of blocked pawns
This idea is loosely based on stockfish losses in closed positions in different tournaments. Space weight symmetrically increases for both sides the more blocked position is.
passed STC
https://tests.stockfishchess.org/tests/view/5e919eefaf0a0143109dc8ce
LLR: 2.94 (-2.94,2.94) {-0.50,1.50}
Total: 16994 W: 3389 L: 3172 D: 10433
Ptnml(0-2): 277, 1931, 3918, 2040, 331
passed LTC
https://tests.stockfishchess.org/tests/view/5e91d04faf0a0143109dc8ea
LLR: 2.94 (-2.94,2.94) {0.25,1.75}
Total: 133386 W: 17316 L: 16763 D: 99307
Ptnml(0-2): 945, 12407, 39524, 12784, 1033
closes https://github.com/official-stockfish/Stockfish/pull/2626
Bench: 4966867
2020-04-12 18:48:52 -06:00
|
|
|
e->blockedCount[Us] = 0;
|
Bonus for double attacks on unsupported pawns
This is a functional change that rewards double attacks on an unsupported pawns.
STC (non-functional difference)
LLR: 2.96 (-2.94,2.94) [0.50,4.50]
Total: 83276 W: 18981 L: 18398 D: 45897
http://tests.stockfishchess.org/tests/view/5d0970500ebc5925cf0a77d4
LTC (incomplete looping version)
LLR: 0.50 (-2.94,2.94) [0.00,3.50]
Total: 82999 W: 14244 L: 13978 D: 54777
http://tests.stockfishchess.org/tests/view/5d0a8d480ebc5925cf0a8d58
LTC (completed non-looping version).
LLR: 2.96 (-2.94,2.94) [0.00,3.50]
Total: 223381 W: 38323 L: 37512 D: 147546
http://tests.stockfishchess.org/tests/view/5d0e80510ebc5925cf0ad320
Closes https://github.com/official-stockfish/Stockfish/pull/2205
Bench 3633546
----------------------------------
Comments by Alain SAVARD:
interesting result ! I would have expected that search would resolve such positions
correctly on the very next move. This is not a very common pattern, and when it happens,
it will quickly disappear. So I'm quite surprised that it passed LTC.
I would be even more surprised if this would resist a simplification.
Anyway, let's try to imagine a few cases.
a) If you have White d5 f5 against Black e6, and White to move
last move by Black was probably a capture on e6 and White is about to recapture on e6
b) If you have White d5 f5 against e6, and Black to move
last move by White was possibly a capture on d5 or f5
or the pawn on e6 was pinned or could not move for some reason.
and white wants to blast open the position and just pushed d4-d5 or f4-f5
Some possible follow-ups
a) Motif is so rare that the popcount() can be safely replaced with a bool()
But this would not pass a SPRT[0,4],
So try a simplification with bool() and also without the & ~theirAttacks
b) If it works, we probably can simply have this in the loop
if (lever) score += S(0, 20);
c) remove all this and tweak something in search for pawn captures (priority, SEE, extension,..)
2019-06-27 01:45:53 -06:00
|
|
|
|
2012-12-22 03:21:06 -07:00
|
|
|
// 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));
|
|
|
|
|
2019-04-11 08:38:53 -06:00
|
|
|
Rank r = relative_rank(Us, s);
|
2012-12-22 03:21:06 -07:00
|
|
|
|
2015-02-24 03:33:40 -07:00
|
|
|
// Flag the pawn
|
2017-06-22 22:03:58 -06:00
|
|
|
opposed = theirPawns & forward_file_bb(Us, s);
|
2019-10-06 16:48:19 -06:00
|
|
|
blocked = theirPawns & (s + Up);
|
2019-02-08 02:36:03 -07:00
|
|
|
stoppers = theirPawns & passed_pawn_span(Us, s);
|
2017-04-28 21:33:30 -06:00
|
|
|
lever = theirPawns & PawnAttacks[Us][s];
|
|
|
|
leverPush = theirPawns & PawnAttacks[Us][s + Up];
|
2017-04-11 11:50:24 -06:00
|
|
|
doubled = ourPawns & (s - Up);
|
2019-06-09 06:31:16 -06:00
|
|
|
neighbours = ourPawns & adjacent_files_bb(s);
|
2016-04-08 12:05:36 -06:00
|
|
|
phalanx = neighbours & rank_bb(s);
|
2018-12-11 05:47:56 -07:00
|
|
|
support = neighbours & rank_bb(s - Up);
|
2016-04-08 12:05:36 -06:00
|
|
|
|
Space bonus and number of blocked pawns
This patch refines the recently introduced interaction between
the space bonus and the number of blocked pawns in a position.
* pawns count as blocked also if their push square is attacked by 2 enemy pawns;
* overall dependence is stronger as well as offset;
* bonus increase is capped at 9 blocked pawns in position;
passed STC
https://tests.stockfishchess.org/tests/view/5e94560663d105aebbab243d
LLR: 2.96 (-2.94,2.94) {-0.50,1.50}
Total: 29500 W: 5842 L: 5603 D: 18055
Ptnml(0-2): 504, 3443, 6677, 3562, 564
passed LTC
https://tests.stockfishchess.org/tests/view/5e95b383c2aaa99f75d1a14d
LLR: 2.95 (-2.94,2.94) {0.25,1.75}
Total: 63504 W: 8329 L: 7974 D: 47201
Ptnml(0-2): 492, 5848, 18720, 6197, 495
closes https://github.com/official-stockfish/Stockfish/pull/2631
bench 4956028
2020-04-14 19:13:50 -06:00
|
|
|
e->blockedCount[Us] += blocked || more_than_one(leverPush);
|
Scale up space weight with number of blocked pawns
This idea is loosely based on stockfish losses in closed positions in different tournaments. Space weight symmetrically increases for both sides the more blocked position is.
passed STC
https://tests.stockfishchess.org/tests/view/5e919eefaf0a0143109dc8ce
LLR: 2.94 (-2.94,2.94) {-0.50,1.50}
Total: 16994 W: 3389 L: 3172 D: 10433
Ptnml(0-2): 277, 1931, 3918, 2040, 331
passed LTC
https://tests.stockfishchess.org/tests/view/5e91d04faf0a0143109dc8ea
LLR: 2.94 (-2.94,2.94) {0.25,1.75}
Total: 133386 W: 17316 L: 16763 D: 99307
Ptnml(0-2): 945, 12407, 39524, 12784, 1033
closes https://github.com/official-stockfish/Stockfish/pull/2626
Bench: 4966867
2020-04-12 18:48:52 -06:00
|
|
|
|
2019-06-09 07:07:36 -06:00
|
|
|
// A pawn is backward when it is behind all pawns of the same color on
|
2019-10-06 16:48:19 -06:00
|
|
|
// the adjacent files and cannot safely advance.
|
|
|
|
backward = !(neighbours & forward_ranks_bb(Them, s + Up))
|
2019-10-18 18:20:38 -06:00
|
|
|
&& (leverPush | blocked);
|
2019-10-06 16:48:19 -06:00
|
|
|
|
|
|
|
// Compute additional span if pawn is not backward nor blocked
|
|
|
|
if (!backward && !blocked)
|
|
|
|
e->pawnAttacksSpan[Us] |= pawn_attack_span(Us, s);
|
2019-09-27 02:18:22 -06:00
|
|
|
|
2019-07-25 01:02:26 -06:00
|
|
|
// A pawn is passed if one of the three following conditions is true:
|
|
|
|
// (a) there is no stoppers except some levers
|
|
|
|
// (b) the only stoppers are the leverPush, but we outnumber them
|
|
|
|
// (c) there is only one front stopper which can be levered.
|
Remove candidate passers w/o feasible lever
+-------+
| o . . | o their pawns
| x . . | x our pawns
| . x . | <- Can sacrifice to create passer?
+-------+
yes
1 2 3 4 5
+-------+ +-------+ +-------+ +-------+ +-------+
| o . . | | o r . | | o r . | | o . b | | o . b | lowercase: theirs
| x b . | | x . . | | x . R | | x . R | | x . . | uppercase: ours
| . x . | | . x . | | . x . | | . x . | | . x B |
+-------+ +-------+ +-------+ +-------+ +-------+
no no yes no yes
The value of our top pawn depends on our ability to advance our bottom
pawn, levering their blocker. Previously, this pawn configuration was
always scored as passer (although a blocked one).
Add requirements for the square s above our (possibly) sacrificed pawn:
- s must not be occupied by them (1).
- If they attack s (2), we must attack s (3).
- If they attack s with a minor (4), we must attack s with a minor (5).
The attack from their blocker is ignored because it is inherent in the
structure; we are ok with sacrificing our bottom pawn.
LTC
LLR: 2.95 (-2.94,2.94) {0.25,1.75}
Total: 37030 W: 4962 L: 4682 D: 27386
Ptnml(0-2): 266, 3445, 10863, 3625, 316
https://tests.stockfishchess.org/tests/view/5e92a2b4be6ede5b954bf239
STC
LLR: 2.94 (-2.94,2.94) {-0.50,1.50}
Total: 40874 W: 8066 L: 7813 D: 24995
Ptnml(0-2): 706, 4753, 9324, 4890, 764
https://tests.stockfishchess.org/tests/view/5e922199af0a0143109dc90e
closes https://github.com/official-stockfish/Stockfish/pull/2624
Bench: 4828294
2020-04-11 09:28:45 -06:00
|
|
|
// (Refined in Evaluation::passed)
|
2019-07-25 01:02:26 -06:00
|
|
|
passed = !(stoppers ^ lever)
|
|
|
|
|| ( !(stoppers ^ leverPush)
|
|
|
|
&& popcount(phalanx) >= popcount(leverPush))
|
2019-10-06 16:48:19 -06:00
|
|
|
|| ( stoppers == blocked && r >= RANK_5
|
2019-07-25 01:02:26 -06:00
|
|
|
&& (shift<Up>(support) & ~(theirPawns | doubleAttackThem)));
|
|
|
|
|
Count only the most advanced passed pawn for each file.
This patch adjusts definition of passed pawns - if there is a pawn of our color in the same file in front of a current pawn it's no longer counts as passed.
passed STC
https://tests.stockfishchess.org/tests/view/5e802037e42a5c3b3ca2ed07
LLR: 2.94 (-2.94,2.94) {-0.50,1.50}
Total: 215296 W: 41843 L: 41341 D: 132112
Ptnml(0-2): 3688, 25313, 49304, 25495, 3848
passed LTC
https://tests.stockfishchess.org/tests/view/5e806441e42a5c3b3ca2ed2b
LLR: 2.95 (-2.94,2.94) {0.25,1.75}
Total: 74050 W: 9761 L: 9379 D: 54910
Ptnml(0-2): 510, 6838, 22025, 7064, 588
closes https://github.com/official-stockfish/Stockfish/pull/2602
bench: 4902237
2020-03-29 11:04:20 -06:00
|
|
|
passed &= !(forward_file_bb(Us, s) & ourPawns);
|
|
|
|
|
2019-07-25 01:02:26 -06:00
|
|
|
// Passed pawns will be properly scored later in evaluation when we have
|
|
|
|
// full attack info.
|
|
|
|
if (passed)
|
2012-12-22 03:21:06 -07:00
|
|
|
e->passedPawns[Us] |= s;
|
|
|
|
|
|
|
|
// Score this pawn
|
2018-12-11 05:47:56 -07:00
|
|
|
if (support | phalanx)
|
2019-03-25 13:04:14 -06:00
|
|
|
{
|
less bonus for blocked connected pawn
Use less bonus for blocked connected pawns so closed positions are less worth.
STC:
LLR: 2.96 (-2.94,2.94) {-0.50,1.50}
Total: 60004 W: 11904 L: 11619 D: 36481
Ptnml(0-2): 1066, 7083, 13535, 7136, 1182
https://tests.stockfishchess.org/tests/view/5e941a8063d105aebbab23e3
LTC:
LLR: 2.95 (-2.94,2.94) {0.25,1.75}
Total: 36606 W: 4831 L: 4556 D: 27219
Ptnml(0-2): 252, 3353, 10872, 3520, 306
https://tests.stockfishchess.org/tests/view/5e9444b963d105aebbab2427
closes https://github.com/official-stockfish/Stockfish/pull/2629
Bench: 4961260
2020-04-13 15:01:38 -06:00
|
|
|
int v = Connected[r] * (4 + 2 * bool(phalanx) - 2 * bool(opposed) - bool(blocked)) / 2
|
2019-09-24 04:41:45 -06:00
|
|
|
+ 21 * popcount(support);
|
2019-04-23 12:26:58 -06:00
|
|
|
|
2019-03-25 13:04:14 -06:00
|
|
|
score += make_score(v, v * (r - 2) / 4);
|
|
|
|
}
|
2019-06-09 07:07:36 -06:00
|
|
|
|
Rework the "unsupported" penalty into a "supported" bonus
A pawn (according to all the searched positions of a bench run) is not supported 85% of the time,
(in current master it is either isolated, backward or "unsupported").
So it made sense to try moving the S(17, 8) "unsupported" penalty value into the base pawn value hoping for a more representative pawn value, and accordingly
a) adjust backward and isolated so that they stay more or less the same as master
b) increase the mg connected bonus in the supported case by S(17, 0) and let the Connected formula find a suitable eg value according to rank.
Tested as a simplification SPRT(-3, 1)
Passed STC
http://tests.stockfishchess.org/tests/view/5970dbd30ebc5916ff649dd6
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 19613 W: 3663 L: 3540 D: 12410
Passed LTC
http://tests.stockfishchess.org/tests/view/597137780ebc5916ff649de3
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 24721 W: 3306 L: 3191 D: 18224
Bench: 5581946
Closes #1179
2017-08-01 19:36:33 -06:00
|
|
|
else if (!neighbours)
|
2019-09-27 02:18:22 -06:00
|
|
|
score -= Isolated
|
|
|
|
+ WeakUnopposed * !opposed;
|
2015-03-29 01:24:17 -06:00
|
|
|
|
2015-03-28 17:30:46 -06:00
|
|
|
else if (backward)
|
2019-09-27 02:18:22 -06:00
|
|
|
score -= Backward
|
|
|
|
+ WeakUnopposed * !opposed;
|
2015-03-29 01:24:17 -06:00
|
|
|
|
2019-09-11 12:36:58 -06:00
|
|
|
if (!support)
|
|
|
|
score -= Doubled * doubled
|
|
|
|
+ WeakLever * more_than_one(lever);
|
2012-12-22 03:21:06 -07:00
|
|
|
}
|
|
|
|
|
2014-12-27 02:47:21 -07:00
|
|
|
return score;
|
2012-12-22 03:21:06 -07:00
|
|
|
}
|
2013-06-16 02:51:17 -06:00
|
|
|
|
|
|
|
} // namespace
|
2008-08-31 23:59:13 -06:00
|
|
|
|
2012-12-22 03:21:06 -07:00
|
|
|
namespace Pawns {
|
2008-08-31 23:59:13 -06:00
|
|
|
|
2014-12-30 02:31:50 -07:00
|
|
|
/// Pawns::probe() looks up the current position's pawns configuration in
|
|
|
|
/// the pawns hash table. It returns a pointer to the Entry if the position
|
|
|
|
/// is found. Otherwise a new Entry is computed and stored there, so we don't
|
|
|
|
/// have to recompute all when the same pawns configuration occurs again.
|
2008-08-31 23:59:13 -06:00
|
|
|
|
2014-12-30 02:31:50 -07:00
|
|
|
Entry* probe(const Position& pos) {
|
2008-12-09 08:46:10 -07:00
|
|
|
|
2011-12-25 03:50:59 -07:00
|
|
|
Key key = pos.pawn_key();
|
2014-12-30 02:31:50 -07:00
|
|
|
Entry* e = pos.this_thread()->pawnsTable[key];
|
2008-08-31 23:59:13 -06:00
|
|
|
|
2012-03-31 05:15:57 -06:00
|
|
|
if (e->key == key)
|
|
|
|
return e;
|
2008-08-31 23:59:13 -06:00
|
|
|
|
2012-03-31 05:15:57 -06:00
|
|
|
e->key = key;
|
2018-02-20 09:10:37 -07:00
|
|
|
e->scores[WHITE] = evaluate<WHITE>(pos, e);
|
|
|
|
e->scores[BLACK] = evaluate<BLACK>(pos, e);
|
|
|
|
|
2012-03-31 05:15:57 -06:00
|
|
|
return e;
|
2008-08-31 23:59:13 -06:00
|
|
|
}
|
2009-07-24 04:16:18 -06:00
|
|
|
|
|
|
|
|
2018-04-23 01:48:53 -06:00
|
|
|
/// Entry::evaluate_shelter() calculates the shelter bonus and the storm
|
|
|
|
/// penalty for a king, looking at the king file and the two closest files.
|
2012-03-28 23:04:44 -06:00
|
|
|
|
2012-03-26 05:52:10 -06:00
|
|
|
template<Color Us>
|
2019-08-24 00:16:20 -06:00
|
|
|
Score Entry::evaluate_shelter(const Position& pos, Square ksq) {
|
2012-03-28 04:44:41 -06:00
|
|
|
|
2020-03-30 14:45:35 -06:00
|
|
|
constexpr Color Them = ~Us;
|
2012-03-28 04:44:41 -06:00
|
|
|
|
2018-07-21 00:17:27 -06:00
|
|
|
Bitboard b = pos.pieces(PAWN) & ~forward_ranks_bb(Them, ksq);
|
2013-07-25 14:23:15 -06:00
|
|
|
Bitboard ourPawns = b & pos.pieces(Us);
|
2012-03-28 04:44:41 -06:00
|
|
|
Bitboard theirPawns = b & pos.pieces(Them);
|
2018-04-23 01:48:53 -06:00
|
|
|
|
2019-07-09 14:03:00 -06:00
|
|
|
Score bonus = make_score(5, 5);
|
2018-05-01 15:50:23 -06:00
|
|
|
|
2020-03-05 10:37:08 -07:00
|
|
|
File center = Utility::clamp(file_of(ksq), FILE_B, FILE_G);
|
2017-12-04 09:52:31 -07:00
|
|
|
for (File f = File(center - 1); f <= File(center + 1); ++f)
|
2012-03-28 04:44:41 -06:00
|
|
|
{
|
2013-10-24 12:34:11 -06:00
|
|
|
b = ourPawns & file_bb(f);
|
2019-08-14 14:15:41 -06:00
|
|
|
int ourRank = b ? relative_rank(Us, frontmost_sq(Them, b)) : 0;
|
2012-03-28 04:44:41 -06:00
|
|
|
|
2017-06-22 22:03:58 -06:00
|
|
|
b = theirPawns & file_bb(f);
|
2019-08-14 14:15:41 -06:00
|
|
|
int theirRank = b ? relative_rank(Us, frontmost_sq(Them, b)) : 0;
|
2014-01-10 19:00:17 -07:00
|
|
|
|
2020-04-12 12:30:08 -06:00
|
|
|
File d = File(edge_distance(f));
|
2019-07-09 14:03:00 -06:00
|
|
|
bonus += make_score(ShelterStrength[d][ourRank], 0);
|
2019-05-12 15:20:51 -06:00
|
|
|
|
|
|
|
if (ourRank && (ourRank == theirRank - 1))
|
2019-08-24 00:16:20 -06:00
|
|
|
bonus -= BlockedStorm * int(theirRank == RANK_3);
|
2019-05-12 15:20:51 -06:00
|
|
|
else
|
2019-07-09 14:03:00 -06:00
|
|
|
bonus -= make_score(UnblockedStorm[d][theirRank], 0);
|
2012-03-26 05:52:10 -06:00
|
|
|
}
|
2012-03-28 04:44:41 -06:00
|
|
|
|
2019-08-24 00:16:20 -06:00
|
|
|
return bonus;
|
2012-03-26 05:52:10 -06:00
|
|
|
}
|
2011-04-09 12:50:56 -06:00
|
|
|
|
2012-03-28 04:44:41 -06:00
|
|
|
|
2014-04-13 05:35:58 -06:00
|
|
|
/// Entry::do_king_safety() calculates a bonus for king safety. It is called only
|
|
|
|
/// when king square changes, which is about 20% of total king_safety() calls.
|
2012-03-28 04:44:41 -06:00
|
|
|
|
2011-04-09 12:50:56 -06:00
|
|
|
template<Color Us>
|
2018-11-10 20:49:13 -07:00
|
|
|
Score Entry::do_king_safety(const Position& pos) {
|
2012-03-28 04:44:41 -06:00
|
|
|
|
2018-11-10 20:49:13 -07:00
|
|
|
Square ksq = pos.square<KING>(Us);
|
2012-03-28 23:04:44 -06:00
|
|
|
kingSquares[Us] = ksq;
|
2018-12-11 05:47:56 -07:00
|
|
|
castlingRights[Us] = pos.castling_rights(Us);
|
2019-10-05 03:15:24 -06:00
|
|
|
auto compare = [](Score a, Score b) { return mg_value(a) < mg_value(b); };
|
2012-06-17 02:03:05 -06:00
|
|
|
|
2019-08-24 16:04:41 -06:00
|
|
|
Score shelter = evaluate_shelter<Us>(pos, ksq);
|
2019-08-24 00:16:20 -06:00
|
|
|
|
|
|
|
// If we can castle use the bonus after castling if it is bigger
|
2019-08-24 16:04:41 -06:00
|
|
|
|
2019-08-24 00:16:20 -06:00
|
|
|
if (pos.can_castle(Us & KING_SIDE))
|
2019-08-24 16:04:41 -06:00
|
|
|
shelter = std::max(shelter, evaluate_shelter<Us>(pos, relative_square(Us, SQ_G1)), compare);
|
2019-08-24 00:16:20 -06:00
|
|
|
|
|
|
|
if (pos.can_castle(Us & QUEEN_SIDE))
|
2019-08-24 16:04:41 -06:00
|
|
|
shelter = std::max(shelter, evaluate_shelter<Us>(pos, relative_square(Us, SQ_C1)), compare);
|
2019-08-24 00:16:20 -06:00
|
|
|
|
|
|
|
// In endgame we like to bring our king near our closest pawn
|
2012-06-17 02:03:05 -06:00
|
|
|
Bitboard pawns = pos.pieces(Us, PAWN);
|
Simplify minPawnDistance
This is a functional simplification which fixes an awkward numerical cliff.
With master king_safety, no pawns is scored higher than pawn(s) that is/are far from the king. This may motivate SF to throw away pawns to increase king safety. With this patch, there is a consistent value for minPawnDistance where losing a pawn never increases king safety.
STC
LLR: 2.94 (-2.94,2.94) {-1.50,0.50}
Total: 45548 W: 8624 L: 8525 D: 28399
Ptnml(0-2): 592, 4937, 11587, 5096, 562
https://tests.stockfishchess.org/tests/view/5e98ced630be947a14e9ddc5
LTC
LLR: 2.94 (-2.94,2.94) {-1.50,0.50}
Total: 42084 W: 5292 L: 5242 D: 31550
Ptnml(0-2): 193, 3703, 13252, 3649, 245
https://tests.stockfishchess.org/tests/view/5e98e22e30be947a14e9de07
closes https://github.com/official-stockfish/Stockfish/pull/2639
bench 4600292
2020-04-16 23:12:43 -06:00
|
|
|
int minPawnDist = 6;
|
2019-04-17 12:38:38 -06:00
|
|
|
|
|
|
|
if (pawns & PseudoAttacks[KING][ksq])
|
|
|
|
minPawnDist = 1;
|
|
|
|
else while (pawns)
|
|
|
|
minPawnDist = std::min(minPawnDist, distance(ksq, pop_lsb(&pawns)));
|
2011-04-09 12:50:56 -06:00
|
|
|
|
2019-08-24 16:04:41 -06:00
|
|
|
return shelter - make_score(0, 16 * minPawnDist);
|
2011-04-09 12:50:56 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// Explicit template instantiation
|
2018-11-10 20:49:13 -07:00
|
|
|
template Score Entry::do_king_safety<WHITE>(const Position& pos);
|
|
|
|
template Score Entry::do_king_safety<BLACK>(const Position& pos);
|
2012-12-22 03:21:06 -07:00
|
|
|
|
|
|
|
} // namespace Pawns
|