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
|
2018-01-01 02:33:07 -07:00
|
|
|
Copyright (C) 2015-2018 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/>.
|
|
|
|
*/
|
|
|
|
|
2013-07-13 05:02:40 -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
|
|
|
|
2017-09-16 06:07:41 -06:00
|
|
|
// Isolated pawn penalty
|
2018-03-18 16:38:58 -06:00
|
|
|
constexpr Score Isolated = S(13, 18);
|
2010-10-09 06:20:49 -06:00
|
|
|
|
2017-09-16 06:07:41 -06:00
|
|
|
// Backward pawn penalty
|
2018-03-18 16:38:58 -06:00
|
|
|
constexpr Score Backward = S(24, 12);
|
2016-01-16 14:34:29 -07: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
|
|
|
// Connected pawn bonus by opposed, phalanx, #support and rank
|
|
|
|
Score Connected[2][2][3][RANK_NB];
|
2016-01-16 14:34:29 -07:00
|
|
|
|
2016-05-10 22:48:51 -06:00
|
|
|
// Doubled pawn penalty
|
2018-03-18 16:38:58 -06:00
|
|
|
constexpr Score Doubled = S(18, 38);
|
2008-08-31 23:59:13 -06:00
|
|
|
|
2017-09-06 00:12:32 -06:00
|
|
|
// Weakness of our pawn shelter in front of the king by [isKingFile][distance from edge][rank].
|
2017-01-17 06:50:03 -07:00
|
|
|
// RANK_1 = 0 is used for files where we have no pawns or our pawn is behind our king.
|
2018-03-18 16:38:58 -06:00
|
|
|
constexpr Value ShelterWeakness[][int(FILE_NB) / 2][RANK_NB] = {
|
2018-02-08 07:13:26 -07:00
|
|
|
{ { V( 98), V(20), V(11), V(42), V( 83), V( 84), V(101) }, // Not On King file
|
|
|
|
{ V(103), V( 8), V(33), V(86), V( 87), V(105), V(113) },
|
|
|
|
{ V(100), V( 2), V(65), V(95), V( 59), V( 89), V(115) },
|
|
|
|
{ V( 72), V( 6), V(52), V(74), V( 83), V( 84), V(112) } },
|
|
|
|
{ { V(105), V(19), V( 3), V(27), V( 85), V( 93), V( 84) }, // On King file
|
|
|
|
{ V(121), V( 7), V(33), V(95), V(112), V( 86), V( 72) },
|
|
|
|
{ V(121), V(26), V(65), V(90), V( 65), V( 76), V(117) },
|
|
|
|
{ V( 79), V( 0), V(45), V(65), V( 94), V( 92), V(105) } }
|
2016-09-23 11:28:34 -06:00
|
|
|
};
|
2012-03-26 05:52:10 -06:00
|
|
|
|
2017-01-11 00:56:38 -07:00
|
|
|
// Danger of enemy pawns moving toward our king by [type][distance from edge][rank].
|
2017-09-06 00:12:32 -06:00
|
|
|
// For the unopposed and unblocked cases, RANK_1 = 0 is used when opponent has
|
|
|
|
// no pawn on the given file, or their pawn is behind our king.
|
2018-03-18 16:38:58 -06:00
|
|
|
constexpr Value StormDanger[][4][RANK_NB] = {
|
2017-09-06 00:12:32 -06:00
|
|
|
{ { V( 0), V(-290), V(-274), V(57), V(41) }, // BlockedByKing
|
2017-01-11 00:56:38 -07:00
|
|
|
{ V( 0), V( 60), V( 144), V(39), V(13) },
|
|
|
|
{ V( 0), V( 65), V( 141), V(41), V(34) },
|
|
|
|
{ V( 0), V( 53), V( 127), V(56), V(14) } },
|
2017-09-06 00:12:32 -06:00
|
|
|
{ { V( 4), V( 73), V( 132), V(46), V(31) }, // Unopposed
|
2016-11-06 07:38:22 -07:00
|
|
|
{ V( 1), V( 64), V( 143), V(26), V(13) },
|
|
|
|
{ V( 1), V( 47), V( 110), V(44), V(24) },
|
|
|
|
{ V( 0), V( 72), V( 127), V(50), V(31) } },
|
2018-03-27 09:29:56 -06:00
|
|
|
{ { V( 0), V( 0), V( 19), V(23), V( 1) }, // BlockedByPawn
|
|
|
|
{ V( 0), V( 0), V( 88), V(27), V( 2) },
|
|
|
|
{ V( 0), V( 0), V( 101), V(16), V( 1) },
|
|
|
|
{ V( 0), V( 0), V( 111), V(22), V(15) } },
|
2017-09-06 00:12:32 -06:00
|
|
|
{ { V(22), V( 45), V( 104), V(62), V( 6) }, // Unblocked
|
2017-01-11 00:56:38 -07:00
|
|
|
{ V(31), V( 30), V( 99), V(39), V(19) },
|
|
|
|
{ V(23), V( 29), V( 96), V(41), V(15) },
|
|
|
|
{ V(21), V( 23), V( 116), V(41), V(15) } }
|
2016-09-23 11:28:34 -06:00
|
|
|
};
|
2012-03-28 04:44:41 -06:00
|
|
|
|
|
|
|
// Max bonus for king safety. Corresponds to start position with all the pawns
|
2013-11-10 07:24:32 -07:00
|
|
|
// in front of the king and no enemy pawn on the horizon.
|
2018-03-18 16:38:58 -06:00
|
|
|
constexpr Value MaxSafetyBonus = V(258);
|
2012-03-26 05:52:10 -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
|
|
|
|
2018-03-18 16:38:58 -06:00
|
|
|
constexpr Color Them = (Us == WHITE ? BLACK : WHITE);
|
|
|
|
constexpr Direction Up = (Us == WHITE ? NORTH : SOUTH);
|
2012-12-22 03:21:06 -07:00
|
|
|
|
2016-04-08 12:05:36 -06:00
|
|
|
Bitboard b, neighbours, stoppers, doubled, supported, phalanx;
|
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
|
|
|
Bitboard lever, leverPush;
|
2012-12-22 03:21:06 -07:00
|
|
|
Square s;
|
2017-01-19 10:16:23 -07:00
|
|
|
bool opposed, backward;
|
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);
|
|
|
|
|
2017-09-16 06:07:41 -06:00
|
|
|
e->passedPawns[Us] = e->pawnAttacksSpan[Us] = e->weakUnopposed[Us] = 0;
|
2013-06-16 02:51:17 -06:00
|
|
|
e->semiopenFiles[Us] = 0xFF;
|
2016-09-23 11:28:34 -06:00
|
|
|
e->kingSquares[Us] = SQ_NONE;
|
2018-02-21 14:31:38 -07:00
|
|
|
e->pawnAttacks[Us] = pawn_attacks_bb<Us>(ourPawns);
|
2016-04-08 11:52:15 -06:00
|
|
|
e->pawnsOnSquares[Us][BLACK] = popcount(ourPawns & DarkSquares);
|
2013-06-16 03:59:40 -06:00
|
|
|
e->pawnsOnSquares[Us][WHITE] = pos.count<PAWN>(Us) - e->pawnsOnSquares[Us][BLACK];
|
2013-06-16 02:51:17 -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));
|
|
|
|
|
2014-10-06 05:26:30 -06:00
|
|
|
File f = file_of(s);
|
2012-12-22 03:21:06 -07:00
|
|
|
|
2016-09-23 11:28:34 -06:00
|
|
|
e->semiopenFiles[Us] &= ~(1 << f);
|
2015-11-14 07:30:50 -07:00
|
|
|
e->pawnAttacksSpan[Us] |= pawn_attack_span(Us, s);
|
|
|
|
|
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);
|
2016-04-08 12:05:36 -06:00
|
|
|
stoppers = theirPawns & passed_pawn_mask(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);
|
2016-04-08 12:05:36 -06:00
|
|
|
neighbours = ourPawns & adjacent_files_bb(f);
|
|
|
|
phalanx = neighbours & rank_bb(s);
|
|
|
|
supported = neighbours & rank_bb(s - Up);
|
|
|
|
|
|
|
|
// A pawn is backward when it is behind all pawns of the same color on the
|
|
|
|
// adjacent files and cannot be safely advanced.
|
|
|
|
if (!neighbours || lever || relative_rank(Us, s) >= RANK_5)
|
2013-08-22 06:34:13 -06:00
|
|
|
backward = false;
|
|
|
|
else
|
2012-12-22 03:21:06 -07:00
|
|
|
{
|
2016-04-08 12:05:36 -06:00
|
|
|
// Find the backmost rank with neighbours or stoppers
|
|
|
|
b = rank_bb(backmost_sq(Us, neighbours | stoppers));
|
|
|
|
|
|
|
|
// The pawn is backward when it cannot safely progress to that rank:
|
|
|
|
// either there is a stopper in the way on this rank, or there is a
|
|
|
|
// stopper on adjacent file which controls the way to that rank.
|
2016-09-23 11:28:34 -06:00
|
|
|
backward = (b | shift<Up>(b & adjacent_files_bb(f))) & stoppers;
|
2016-05-10 22:48:51 -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
|
|
|
assert(!(backward && (forward_ranks_bb(Them, s + Up) & neighbours)));
|
2012-12-22 03:21:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Passed pawns will be properly scored in evaluation because we need
|
2017-01-19 10:16:23 -07:00
|
|
|
// full attack info to evaluate them. Include also not passed pawns
|
|
|
|
// which could become passed after one or two pawn pushes when are
|
|
|
|
// not attacked more times than defended.
|
|
|
|
if ( !(stoppers ^ lever ^ leverPush)
|
2017-06-22 22:03:58 -06:00
|
|
|
&& !(ourPawns & forward_file_bb(Us, s))
|
Candidate Passed Pawn
Include some not fully supported levers in the (candidate) passed pawns
bitboard, if otherwise unblocked. Maybe levers are usually very short
lived, and some inaccuracy in the lever balance for the definition of
candidate passed pawns just triggers a deeper search.
Here is a example of a case where the patch has an effect on the definition
of candidate passers: White c5/e5 pawns, against Black d6 pawn. Let's say
we want to test if e5 is a candidate passer. The previous master looks
only at files d, e and f (which is already very good) and reject e5 as
a candidate. However, the lever d6 is challenged by 2 pawns, so it should
not fully count. Indirectly, this patch will view such case (and a few more)
to be scored as candidates.
STC
http://tests.stockfishchess.org/tests/view/5abcd55d0ebc5902926cf1e1
LLR: 2.95 (-2.94,2.94) [0.00,4.00]
Total: 16492 W: 3419 L: 3198 D: 9875
LTC
http://tests.stockfishchess.org/tests/view/5abce1360ebc5902926cf1e6
LLR: 2.95 (-2.94,2.94) [0.00,4.00]
Total: 21156 W: 3201 L: 2990 D: 14965
This was inspired by this test of Jerry Donald Watson, except the case of
zero supporting pawns against two levers is excluded, and it seems that
not excluding that case is bad, while excluding is it beneficial. See the
following tests on fishtest:
https://github.com/official-stockfish/Stockfish/pull/1519
http://tests.stockfishchess.org/tests/view/5abccd850ebc5902926cf1dd
http://tests.stockfishchess.org/tests/view/5abcdd490ebc5902926cf1e4
Closes https://github.com/official-stockfish/Stockfish/pull/1521
Bench: 5568461
----
Comments by Jerry Donald Watson:
> My thinking as to why this works:
>
> The evaluation is either called in an interior node or in the qsearch.
> The calls at the end of the qsearch are the more important as they
> ultimately determine the scoring of each move, whereas the internal
> values are mainly used for pruning decisions with a margin. Some strong
> engines don't even call the eval at all nodes. Now the whole point of
> the qsearch is to find quiet positions where captures do not change the
> evaluation of the position with regards to the search bounds - i.e. if
> there were good captures they would be tried.* So when a candidate lever
> appears in the evaluation at the end of the qsearch, the qsearch has
> guaranteed that it cannot just be captured, or if it can, this does not
> take the score past the search bounds. Practically this may mean that
> the side with the candidate lever has the turn, or perhaps the stopping
> lever pawn is pinned, or that side is forced for other reasons to make
> some other move (e.g. d6 can only take one of the pawns in the example
> above).
>
> Hence granting the full score for only one lever defender makes some
> sense, at least, to me.
>
> IMO this is also why huge bonuses for possible captures in the evaluation
> (e.g. threat on queen and our turn), etc. don't tend to work. Such things
> are best left to the search to figure out.
2018-03-29 05:59:35 -06:00
|
|
|
&& popcount(supported) >= popcount(lever) - 1
|
2017-01-19 10:16:23 -07:00
|
|
|
&& popcount(phalanx) >= popcount(leverPush))
|
2012-12-22 03:21:06 -07:00
|
|
|
e->passedPawns[Us] |= s;
|
|
|
|
|
2017-05-09 05:50:05 -06:00
|
|
|
else if ( stoppers == SquareBB[s + Up]
|
|
|
|
&& relative_rank(Us, s) >= RANK_5)
|
|
|
|
{
|
|
|
|
b = shift<Up>(supported) & ~theirPawns;
|
|
|
|
while (b)
|
|
|
|
if (!more_than_one(theirPawns & PawnAttacks[Us][pop_lsb(&b)]))
|
2017-05-07 21:38:03 -06:00
|
|
|
e->passedPawns[Us] |= s;
|
2017-05-09 05:50:05 -06:00
|
|
|
}
|
2017-05-07 21:38:03 -06:00
|
|
|
|
2012-12-22 03:21:06 -07:00
|
|
|
// Score this pawn
|
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
|
|
|
if (supported | phalanx)
|
2017-12-03 10:29:55 -07:00
|
|
|
score += Connected[opposed][bool(phalanx)][popcount(supported)][relative_rank(Us, s)];
|
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)
|
2017-09-16 06:07:41 -06:00
|
|
|
score -= Isolated, e->weakUnopposed[Us] += !opposed;
|
2015-03-29 01:24:17 -06:00
|
|
|
|
2015-03-28 17:30:46 -06:00
|
|
|
else if (backward)
|
2017-09-16 06:07:41 -06:00
|
|
|
score -= Backward, e->weakUnopposed[Us] += !opposed;
|
2015-03-29 01:24:17 -06:00
|
|
|
|
2017-04-11 11:50:24 -06:00
|
|
|
if (doubled && !supported)
|
2017-05-09 05:50:05 -06:00
|
|
|
score -= Doubled;
|
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::init() initializes some tables needed by evaluation. Instead of using
|
|
|
|
/// hard-coded tables, when makes sense, we prefer to calculate them with a formula
|
|
|
|
/// to reduce independent parameters and to allow easier tuning and better insight.
|
2014-10-13 01:23:21 -06:00
|
|
|
|
2016-09-23 11:28:34 -06:00
|
|
|
void init() {
|
|
|
|
|
2018-03-18 16:38:58 -06:00
|
|
|
static constexpr int Seed[RANK_NB] = { 0, 13, 24, 18, 76, 100, 175, 330 };
|
2014-10-12 13:03:49 -06:00
|
|
|
|
2014-10-13 01:23:21 -06:00
|
|
|
for (int opposed = 0; opposed <= 1; ++opposed)
|
|
|
|
for (int phalanx = 0; phalanx <= 1; ++phalanx)
|
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
|
|
|
for (int support = 0; support <= 2; ++support)
|
2015-02-26 10:56:16 -07:00
|
|
|
for (Rank r = RANK_2; r < RANK_8; ++r)
|
|
|
|
{
|
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
|
|
|
int v = 17 * support;
|
|
|
|
v += (Seed[r] + (phalanx ? (Seed[r + 1] - Seed[r]) / 2 : 0)) >> opposed;
|
|
|
|
|
|
|
|
Connected[opposed][phalanx][support][r] = make_score(v, v * (r - 2) / 4);
|
2015-02-26 10:56:16 -07:00
|
|
|
}
|
2014-10-12 13:03:49 -06:00
|
|
|
}
|
|
|
|
|
2014-10-13 01:23:21 -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);
|
2018-02-25 07:12:19 -07:00
|
|
|
e->openFiles = popcount(e->semiopenFiles[WHITE] & e->semiopenFiles[BLACK]);
|
2018-02-25 16:55:01 -07:00
|
|
|
e->asymmetry = popcount( (e->passedPawns[WHITE] | e->passedPawns[BLACK])
|
|
|
|
| (e->semiopenFiles[WHITE] ^ e->semiopenFiles[BLACK]));
|
2018-02-20 09:10:37 -07:00
|
|
|
|
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
|
|
|
|
|
|
|
|
2012-12-22 03:21:06 -07:00
|
|
|
/// Entry::shelter_storm() calculates shelter and storm penalties for the file
|
2017-01-11 00:56:38 -07:00
|
|
|
/// the king is on, as well as the two closest files.
|
2012-03-28 23:04:44 -06:00
|
|
|
|
2012-03-26 05:52:10 -06:00
|
|
|
template<Color Us>
|
2012-12-22 03:21:06 -07:00
|
|
|
Value Entry::shelter_storm(const Position& pos, Square ksq) {
|
2012-03-28 04:44:41 -06:00
|
|
|
|
2018-03-05 17:32:16 -07:00
|
|
|
constexpr Color Them = (Us == WHITE ? BLACK : WHITE);
|
2012-03-28 04:44:41 -06:00
|
|
|
|
2017-01-11 00:56:38 -07:00
|
|
|
enum { BlockedByKing, Unopposed, BlockedByPawn, Unblocked };
|
2014-12-21 02:52:34 -07:00
|
|
|
|
Blocked pawn storm
In pawn structures like white pawns f6,h6 against black pawns f7,g6,h7
the attack on the king is blocked by the own pawns. So decrease the
penalty for king safety.
See diagram and discussion in
https://github.com/official-stockfish/Stockfish/pull/1434
A sample position that this patch wants to avoid is the following
1rr2bk1/3q1p1p/2n1bPpP/pp1pP3/2pP4/P1P1B3/1PBQN1P1/1K3R1R w - - 0 1
White pawn storm on the king side was a disaster, it locked the king
side completely. Therefore, all the king tropism bonus that white have
on the king side are useless, and kingadjacent attacks too. Master
gives White a static +4.5 advantage, but White cannot win that game.
The patch is lowering this evaluation artefact.
STC:
LLR: 2.94 (-2.94,2.94) [0.00,5.00]
Total: 16467 W: 3750 L: 3537 D: 9180
http://tests.stockfishchess.org/tests/view/5a92102d0ebc590297cc87d0
LTC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 64242 W: 11130 L: 10745 D: 42367
http://tests.stockfishchess.org/tests/view/5a923dc80ebc590297cc8806
This version includes reformatting and speed optimization by Alain Savard.
Bench: 5643527
2018-02-28 05:00:45 -07:00
|
|
|
File center = std::max(FILE_B, std::min(FILE_G, file_of(ksq)));
|
|
|
|
Bitboard b = pos.pieces(PAWN)
|
|
|
|
& (forward_ranks_bb(Us, ksq) | rank_bb(ksq))
|
|
|
|
& (adjacent_files_bb(center) | file_bb(center));
|
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);
|
2014-06-21 06:32:11 -06:00
|
|
|
Value safety = MaxSafetyBonus;
|
2012-03-28 04:44:41 -06:00
|
|
|
|
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);
|
2014-06-21 06:32:11 -06:00
|
|
|
Rank rkUs = b ? relative_rank(Us, backmost_sq(Us, b)) : RANK_1;
|
2012-03-28 04:44:41 -06:00
|
|
|
|
2017-06-22 22:03:58 -06:00
|
|
|
b = theirPawns & file_bb(f);
|
2014-06-21 06:32:11 -06:00
|
|
|
Rank rkThem = b ? relative_rank(Us, frontmost_sq(Them, b)) : RANK_1;
|
2014-01-10 19:00:17 -07:00
|
|
|
|
2017-12-04 09:52:31 -07:00
|
|
|
int d = std::min(f, ~f);
|
2017-09-06 00:12:32 -06:00
|
|
|
safety -= ShelterWeakness[f == file_of(ksq)][d][rkUs]
|
2014-12-21 02:52:34 -07:00
|
|
|
+ StormDanger
|
|
|
|
[f == file_of(ksq) && rkThem == relative_rank(Us, ksq) + 1 ? BlockedByKing :
|
2017-01-11 00:56:38 -07:00
|
|
|
rkUs == RANK_1 ? Unopposed :
|
2014-12-21 02:52:34 -07:00
|
|
|
rkThem == rkUs + 1 ? BlockedByPawn : Unblocked]
|
2017-03-05 19:20:27 -07:00
|
|
|
[d][rkThem];
|
2012-03-26 05:52:10 -06:00
|
|
|
}
|
2012-03-28 04:44:41 -06:00
|
|
|
|
|
|
|
return safety;
|
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>
|
2014-04-13 05:35:58 -06:00
|
|
|
Score Entry::do_king_safety(const Position& pos, Square ksq) {
|
2012-03-28 04:44:41 -06:00
|
|
|
|
2012-03-28 23:04:44 -06:00
|
|
|
kingSquares[Us] = ksq;
|
2014-03-08 07:08:55 -07:00
|
|
|
castlingRights[Us] = pos.can_castle(Us);
|
2015-03-07 02:03:19 -07:00
|
|
|
int minKingPawnDistance = 0;
|
2012-06-17 02:03:05 -06:00
|
|
|
|
|
|
|
Bitboard pawns = pos.pieces(Us, PAWN);
|
|
|
|
if (pawns)
|
2015-03-07 02:03:19 -07:00
|
|
|
while (!(DistanceRingBB[ksq][minKingPawnDistance++] & pawns)) {}
|
2011-04-09 12:50:56 -06:00
|
|
|
|
2012-03-28 23:04:44 -06:00
|
|
|
Value bonus = shelter_storm<Us>(pos, ksq);
|
2012-03-28 04:44:41 -06:00
|
|
|
|
2013-12-01 02:25:10 -07:00
|
|
|
// If we can castle use the bonus after the castling if it is bigger
|
2014-03-08 07:08:55 -07:00
|
|
|
if (pos.can_castle(MakeCastling<Us, KING_SIDE>::right))
|
2012-03-28 23:04:44 -06:00
|
|
|
bonus = std::max(bonus, shelter_storm<Us>(pos, relative_square(Us, SQ_G1)));
|
2012-03-28 04:44:41 -06:00
|
|
|
|
2014-03-08 07:08:55 -07:00
|
|
|
if (pos.can_castle(MakeCastling<Us, QUEEN_SIDE>::right))
|
2012-03-28 23:04:44 -06:00
|
|
|
bonus = std::max(bonus, shelter_storm<Us>(pos, relative_square(Us, SQ_C1)));
|
2012-03-26 05:52:10 -06:00
|
|
|
|
2015-03-07 02:03:19 -07:00
|
|
|
return make_score(bonus, -16 * minKingPawnDistance);
|
2011-04-09 12:50:56 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// Explicit template instantiation
|
2014-04-13 05:35:58 -06:00
|
|
|
template Score Entry::do_king_safety<WHITE>(const Position& pos, Square ksq);
|
|
|
|
template Score Entry::do_king_safety<BLACK>(const Position& pos, Square ksq);
|
2012-12-22 03:21:06 -07:00
|
|
|
|
|
|
|
} // namespace Pawns
|