Currently SF’s quiescence search like most alpha-beta based engines
doesn’t verify for stalemate because doing it each leaf position is to
expensive and costs elo. However in certain positions this creates a
blindspot for SF, not recognizing soon enough that the opponent can
reach a stalemate by sacrifycing his last mobile heavy piece(s). This
tactical motif & it’s measure are similar to zugzwang & verification
search: the measure itself does not gain elo, but prevents SF from
loosing/drawing games in an awkward way.
The fix consists of 3 measures:
1. Make qsearch verify for stalemate on transitions to pure KP-material
for the side to move with our last Rook/Queen just been captured. In
fact this is the scenario where stalemate happens with highest
frequency. The stalemate-verification itself is optimized by merely
checking for pawn pushes & king mobility (captures were already
tried by qssearch)
2. Another culprit for the issue figured out to be SEE based pruning for
checks in step 14. Here often the move forcing the stalemate (or
forcing the opponent to not retake) get pruned away and it need to
much time to reach enough depth. To encounter this we verify
following conditions:
- a) side to move is happy with a draw (alpha < 0)
- b) we are about to sacrify our last heavy & unique mobile piece in
this position.
- c) this piece doesn’t move away from our kingring giving the king a
new square to move.
When all 3 conditions meet we don’t prune the move, because there
is a good chance that capturing the piece means stalemate.
3. Store terminal nodes (mates & stalemates) in TT with higher depth
than searched depth. This prevents SF from:
- reanalyzing the node (=trying to generate legal moves) in vain at
each iterative deepening step.
- overwriting an already correct draw-evaluation from a previous shallow
normal search by a qsearch which doesn’t recognize stalemate and might
store a verry erratic evaluation.
This is due to the 4 constant in the TT-overwrite condition: d -
DEPTH_ENTRY_OFFSET + 2 * pv > depth8 – 4 which allows qs to override
entries made by normal searches with depth <=4.
This 3hrd measure however is not essential for fixing the issue, but
tests (one of vdv & one of mine) seem to suggest that this measure
brings some small benefit.
Another other position where SF benefits from this fix is for instance
Position FEN 8/8/8/1B6/6p1/8/3K1Ppp/3N2kr w - - 0 1 bm f4 +M9
P.S.: Also this issue higly depends on the used net, how good the net is
at evaluate such mobility restricted positions. SF16 was pretty good in
solving 2rr4/5pBk/PqP3p1/1N3pPp/1PQ1bP1P/8/3R4/R4K2 b - - 0 40 bm Rxc6
(< 1 second) while SF16_1 with introduction of the dual net needs about
1,5 minutes and SF17.1 requires 3 minutes to find the drawing move Rxc6.
P.S.2: Using more threads produces indeterminism & using high hash
pressure makes SF reevaluate explored positions more often which makes
it more likely to solve the position. To have stable meaningful results
I tested therfore with one single thread and low hash pressure.
Preliminary LTC test at 30k games
https://tests.stockfishchess.org/tests/view/67ece7a931d7cf8afdc44e18 Elo: 0.04 ± 2.0 (95%) LOS: 51.7%
Total: 24416 W: 6226 L: 6223 D: 11967
Ptnml(0-2): 12, 2497, 7185, 2504, 10
nElo: 0.09 ± 4.4 (95%) PairsRatio: 1.00
Passed LTC no-regression sprt
https://tests.stockfishchess.org/tests/view/67ee8e4631d7cf8afdc452fb
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 401556 W: 101612 L: 101776 D: 198168
Ptnml(0-2): 152, 42241, 116170, 42049, 166
closes https://github.com/official-stockfish/Stockfish/pull/5983
fixes https://github.com/official-stockfish/Stockfish/issues/5899
Bench: 1721673
In the move generation the moves are generated in the order pawns, knight, bishops, rooks, queens and king.
This follows increasing type_of(pos.moved_piece(m)) term, so in master a capturing was sorted after a capturing rook if the same piece was captured in evasion.
Because we use a stable sorting method (stable means the order of elements with the same value are not changed) and generate the moves in the above order we do'nt need the removed term.
Passed STC:
LLR: 2.98 (-2.94,2.94) <-1.75,0.25>
Total: 170560 W: 44222 L: 44148 D: 82190
Ptnml(0-2): 569, 18792, 46488, 18858, 573
https://tests.stockfishchess.org/tests/view/678530ee460e2910c51de21d
closes https://github.com/official-stockfish/Stockfish/pull/5784
No functional change
* Limit use of `StatsEntry` wrapper to arithmetic types
* Generalize `Stats` to `MultiArray` by discarding the template parameter `D`
* Allow `MultiArray::fill` to take any type assignable to element type
* Remove now-unused operator overloads on `StatsEntry`
closes https://github.com/official-stockfish/Stockfish/pull/5750
No functional change
Since no correction histories are ever used inside Movepick, and many
existing histories are closely integrated into search, it might be more
logical to separate them into their own header. PR based on #5650
closes https://github.com/official-stockfish/Stockfish/pull/5652
No functional change
Idea of this patch comes from the fact that current history heuristics
are mostly populated by low depth entries since our stat bonus reaches
maximum value at depth 5-6 and number of low depth nodes is much bigger
than number of high depth nodes. But it doesn't make a whole lost of
sense to use this low-depth centered histories to sort moves at root.
Current patch introduces special history table that is used exclusively
at root, it remembers which quiet moves were good and which quiet moves
were not good there and uses this information for move ordering.
Passed STC:
https://tests.stockfishchess.org/tests/view/66dda74adc53972b68218cc9
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 127680 W: 33579 L: 33126 D: 60975
Ptnml(0-2): 422, 15098, 32391, 15463, 466
Passed LTC:
https://tests.stockfishchess.org/tests/view/66dead2adc53972b68218d34
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 381978 W: 96958 L: 95923 D: 189097
Ptnml(0-2): 277, 42165, 105089, 43162, 296
closes https://github.com/official-stockfish/Stockfish/pull/5595
Bench: 1611283
- Capitalize comments
- Reformat multi-lines comments to equalize the widths of the lines
- Try to keep the width of comments around 85 characters
- Remove periods at the end of single-line comments
closes https://github.com/official-stockfish/Stockfish/pull/5469
No functional change
Also "fix" movepicker to allow depths between CHECKS and NO_CHECKS,
which makes them easier to tweak (not that they get tweaked hardly ever)
(This was more beneficial when there was a third stage to DEPTH_QS, but
it's still an improvement now)
closes https://github.com/official-stockfish/Stockfish/pull/5205
No functional change
Parameters Tune, adding also another tunable parameter (npmDiv) to be
variable for different nets (bignet, smallnet, psqtOnly smallnet). P.s:
The changed values are only the parameters where there is agreement
among the different time controls, so in other words, the tunings are
telling us that changing these specific values to this specific
direction is good in all time controls, so there shouldn't be a high
risk of regressing at longer time controls.
Passed STC:
LLR: 2.97 (-2.94,2.94) <0.00,2.00>
Total: 39552 W: 10329 L: 9999 D: 19224
Ptnml(0-2): 156, 4592, 9989, 4844, 195
https://tests.stockfishchess.org/tests/view/661be9a0bd68065432a088c0
Passed LTC:
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 56394 W: 14439 L: 14078 D: 27877
Ptnml(0-2): 30, 6152, 15480, 6497, 38
https://tests.stockfishchess.org/tests/view/661c746296961e72eb565406
closes https://github.com/official-stockfish/Stockfish/pull/5187
Bench: 1836777
Move divisor from capture scoring to good capture
check and sligthly increase it.
This has several effects:
- its a speedup because for quience and probcut
search the division now never happens. For main
search its delayed and can be avoided if a good
capture triggers a cutoff
- through the higher resolution of scores we have
a more granular sorting
STC: https://tests.stockfishchess.org/tests/view/65bf2a93c865510db027dc27
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 470016 W: 122150 L: 121173 D: 226693
Ptnml(0-2): 2133, 55705, 118374, 56644, 2152
LTC: https://tests.stockfishchess.org/tests/view/65c1d16dc865510db0281339
LLR: 2.96 (-2.94,2.94) <0.50,2.50>
Total: 98988 W: 25121 L: 24667 D: 49200
Ptnml(0-2): 77, 10998, 26884, 11464, 71
closes https://github.com/official-stockfish/Stockfish/pull/5036
Bench: 1233867
The primary rationale behind this lies in the fact that enums were not
originally designed to be employed in the manner we currently utilize them.
The Value enum was used like a type alias throughout the code and was often
misused. Furthermore, changing the underlying size of the enum to int16_t broke
everything, mostly because of the operator overloads for the Value enum, were
causing data to be truncated. Since Value is now a type alias, the operator
overloads are no longer required.
Passed Non-Regression STC:
https://tests.stockfishchess.org/tests/view/6593b8bb79aa8af82b95b401
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 235296 W: 59919 L: 59917 D: 115460
Ptnml(0-2): 743, 27085, 62054, 26959, 807
closes https://github.com/official-stockfish/Stockfish/pull/4960
No functional change
Idea from Caissa (https://github.com/Witek902/Caissa) chess engine.
With given pawn structure collect data with how often search result and by how
much it was better / worse than static evalution of position and use it to
adjust static evaluation of positions with given pawn structure. Details:
1. excludes positions with fail highs and moves producing it being a capture;
2. update value is function of not only difference between best value and static
evaluation but also is multiplied by linear function of depth;
3. maximum update value is maximum value of correction history divided by 2;
4. correction history itself is divided by 32 when applied so maximum value of
static evaluation adjustment is 32 internal units.
Passed STC:
https://tests.stockfishchess.org/tests/view/658fc7b679aa8af82b955cac
LLR: 2.96 (-2.94,2.94) <0.00,2.00>
Total: 128672 W: 32757 L: 32299 D: 63616
Ptnml(0-2): 441, 15241, 32543, 15641, 470
Passed LTC:
https://tests.stockfishchess.org/tests/view/65903f6979aa8af82b9566f1
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 97422 W: 24626 L: 24178 D: 48618
Ptnml(0-2): 41, 10837, 26527, 11245, 61
closes https://github.com/official-stockfish/Stockfish/pull/4950
Bench: 1157852
Original idea by Seer chess engine https://github.com/connormcmonigle/seer-nnue,
coding done by @Disservin, code refactoring done by @locutus2 to match the style
of other histories.
This patch introduces pawn structure based history, which assings moves values
based on last digits of pawn structure hash and piece type of moved piece and
landing square of the move. Idea is that good places for pieces are quite often
determined by pawn structure of position. Used in 3 different places
- sorting of quiet moves, sorting of quiet check evasions and in history based
pruning in search.
Passed STC:
https://tests.stockfishchess.org/tests/view/65391d08cc309ae83955dbaf
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 155488 W: 39408 L: 38913 D: 77167
Ptnml(0-2): 500, 18427, 39408, 18896, 513
Passed LTC:
https://tests.stockfishchess.org/tests/view/653a36a2cc309ae83955f181
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 70110 W: 17548 L: 17155 D: 35407
Ptnml(0-2): 33, 7859, 18889, 8230, 44
closes https://github.com/official-stockfish/Stockfish/pull/4849
Bench: 1257882
Co-Authored-By: Disservin <disservin.social@gmail.com>
Co-Authored-By: Stefan Geschwentner <locutus2@users.noreply.github.com>
- remove the blank line between the declaration of the function and it's
comment, leads to better IDE support when hovering over a function to see it's
description
- remove the unnecessary duplication of the function name in the functions
description
- slightly refactored code for lsb, msb in bitboard.h There are still a few
things we can be improved later on, move the description of a function where
it was declared (instead of implemented) and add descriptions to functions
which are behind macros ifdefs
closes https://github.com/official-stockfish/Stockfish/pull/4840
No functional change