When a node fails low and bestValue is still equal to
the original static node evaluation, then save this
in TT along with usual info.
This will allow us to avoid a future costly evaluation() call.
This patch extends to failed low nodes what we already do
for failed high ones.
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Still not clear if it helps and, especially, how it
helps. So revert for now to avoid any influence on
future feature now under test.
With this patch we come back to be functional
equivalent to patch e33c94883 F_53.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
After 828 games at 1+0
Mod vs Orig +191 =447 -190 50.06% 414.5/828
So almost no difference. Patch is committed more for
documentation purposes then for other reasons.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
It is in line with attackers_to() and is shorter and
piece is already redundant because is passed as template
parameter anyway.
Integrate also pawn_attacks_from() in the attacks_from()
family so to have an uniform attack info API.
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
It is a bit longer but much easier to understand especially
for people new to the sources. I remember it was not trivial
for me to understand the returned attack bitboard refers to
attacks launched from the given square and not attacking the
given square.
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Most of them are not required to be public and are
used in one place only so remove them and use its
definitions.
Also rename piece_attacks_square() in piece_attacks()
to be aligned to the current naming policy.
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
These functions return bitboard of attacking pieces,
not the attacks themselfs so reflect this in the name.
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
It seems that it works better without compensation
of drifted value when saving static evaluation in TT.
After 818 games at 1+0
Mod vs Orig +217 =429 -172 52.75% 431.5/818 +19 ELO
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
After 934 games at 1+0
Mod vs Orig +228 =493 -213 50.80% 474.5/934 +6 ELO
So it seems not negative and there is also the added
benefit to unify LMRPVMoves use in search_pv() and in
root list.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Because of a hard-to-spot single-character bug in connected_moves(),
the discovered check code had no effect whatsoever. The condition
in the if (...) statement at the beginning of the code would always
return false.
Thanks to Edsel Apostol for pointing out this bug!
It is more clear that only in that case the move number is
correct, otherwise is only a partial quantity: the number of
moves of that phase.
In case of PH_EVASIONS instead we have only one phase.
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
It seems that pos.has_mate_threat() changes the position !
So that calling MovePicker c'tor before or after the
has_mate_threat() call changes the things !
Bug was unhidden by previous patch that makes MovePicker c'tor
to generate, score and sort good captures under some circumstances.
Because scoring the captures is position dependent it seems that
the moves returned by MovePicker are different when c'tor is
called before has_mate_threat()
Of course this is only a workaround because the real bug is still
hidden :-(
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Does not seem to improve on the standard, latest results
from Joona after 2040 games are negative:
Orig - Mod: 454 - 424 - 1162
And is more or less the same I got few days ago.
So revert for now.
Verified same functionality of 595a90dfd
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
This avoids calculating the array entry position
at each access and gives another boost of almost 1%.
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Try good captures before null move when depth < 3 * OnePly.
Use this kind of null move also in Depth == OnePly.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Explicitly write the conditions for pawn to 7th
and passed pawn instead of wrapping in redundant
helpers.
Also retire the now unused move_is_pawn_push_to_7th()
and the never used move_was_passed_pawn_push() and
move_is_deep_pawn_push()
Function extension() is so time critical that this
simple patch speeds up the pgo compile of 0.5% and
it is also more clear what actually happens there.
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
This fix a compile error under Linux with gcc when
there aren't the intel dev libraries.
Also simplify the previous patch moving TT definition
from search.cpp to tt.cpp so to avoid using passing a
pointer to TT to the current position.
Finally simplify do_move(), now we miss a prefetch in the
rare case of setting an en-passant square but code is
much cleaner and performance penalty is almost zero.
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Move prefetching code inside do_move() so to allow a
very early prefetching and to put as many instructions
as possible between prefetching and following retrieve().
With this patch retrieve() times are cutted of another 25%
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
TT.retrieve() is the most time consuming function
because almost always involves a very slow RAM access.
TT table is so big that is never cached. This patch
prefetches TT data just after a move is done, so that
subsequent TT.retrieve will be very fast.
Profiling with VTune shows that TT:retrieve() times are
almost cutted in half !
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Current formula enable LMR when
i + MultiPV >= LMRPVMoves
It means that, for instance, if MultiPV == 1 then LMR
will be started to be considered at move i = LMRPVMoves - 1,
while if MultiPV == 3 then it will start before,
at move i = LMRPVMoves - 3.
With this patch the formula becomes
i >= MultiPV + LMRPVMoves - 2
So that LMR will always start after LMRPVMoves - 1 moves
from the last PV move.
No functional change when MultiPV == 1
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
down the transposition table.
When the search was stopped before a fail high at the root was
resolved, Stockfish would often print a very short PV, sometimes
consisting of just a single move. This was not only a little
user-unfriendly, but also harmed the strength a little in
ponder-on games: Single-move PVs mean that there is no ponder
move to search.
It is perhaps worth considering to remove the pv[][] array
entirely, and always build the entire PV from the transposition
table. This would simplify the source code somewhat and probably
make the program infinitesimally faster, at the expense of
sometimes getting shorter PVs or PVs with rubbish moves near
the end.
Added the UCI_LimitStrength and the UCI_Elo options, with an Elo
range of 2100-2900. When UCI_LimitStrength is enabled, the number
of threads is set to 1, and the search speed is slowed down according
to the chosen Elo level.
Todo:
1. Implement Elo levels below 2100 by blundering on purpose and/or
crippling the evaluation.
2. Automatically calibrate the maximum Elo by measuring the CPU speed
during program initialization, perhaps by doing some bitboard
computations and measuring the time taken.
No functional change when UCI_LimitStrength is false (the default).
Small micro-optimization in this very
time critical function.
Use bitwise 'or' instead of logic 'or' to avoid branches
in the assembly and use the result to skip an handful of checks.
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
We do not accept null search returned mate values,
but we always do a full search in those cases.
So the variable mateThreat that is set only if null move
search returns a mate value is always false.
Restore the functionality of mateThreat moving the
assignement where it can be triggered.
After 999 games at 1+0
Mod vs Orig +253 =517 -229 51.20% +8 ELO
Bug reported by xiaozhi
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Tord says that using a lower horizon at PV nodes
looks strange and inconsistent with the general
philosophy of our search (i.e. always being more
conservative at PV nodes). So set LMR at 3 also
on search_pv().
Test result after 601 games seems to confirm this.
Mod vs Orig +156 =318 -127 52.41% 315.0/601 +17 ELO
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Test extension of LMR horizon to 3 plies alone, without
touching null move search. To keep the patch minimal we still
don't change LMR horizon in PV search. This will be the object
of the next patch.
Result seems good after 998 games:
Mod vs Orig +252/=518/-228 51.20% 511.0/998 +8 ELO
So dynamic null move reduction seems a bit stronger then
fixed reduction even with LMR horizon set to 3.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Revert to LMR horizont of 2 plies. Only if parent move
is a null move increase to 3 so to avoid the bad combination
of null move reduction + LMR reduction. This is a more
aggressive patch then previous one, but it seems we are
going in the wromg direction.
After 531 games result is not good:
Mod vs Orig +123/=265/-143 48.12% 255.5/531 -13 ELO
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Set null move reduction to R=4, but increase the LMR horizon
to 3 plies. The two tweaks are related and should compensate
the combined effect of null move + LMR reduction at shallow
depths.
Idea from Tord.
After 999 games at 1+0
Mod vs Orig +251 =522 -225 51.30% + 9 ELO
On Tord iMac Core 2 Duo 2.8 GHz, one thread,
Mac OS X 10.6, at 1+0 time control we have:
Mod vs Orig 994-1006 -1.4 ELO
But Orig version is pgo compiled and Mod is not.
The PGO compiled version is about 8% faster, which
corresponds to about 7 Elo points. This means that
results are reasonably consistent.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
a static eval cached in the transposition table would always equal the static
eval of the current position. This is in general not true, because the cached
value could be from a previous search with different evaluation parameter
settings, or from a search from the opposite side (Stockfish's evaluation
function is assymmetric by default).
This feature makes sense during development, but
It doesn't seem to make sense for normal users.
Also fix a possible race where the GUI adjudicates
the game a fraction of second before the engine sets
looseOnTime flag so that it will bogusly waits until
it ran out of time at the beginning of the next new game.
The fix is to always reset looseOnTime at the beginning
of a new game.
Race condition spotted by Tord.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Mostly of times we are interested only in the sign of SEE,
namely if a capture is negative or not.
If the capturing piece is smaller then the captured one we
already know SEE cannot be negative and this information
is enough most of the times. And of course it is much
faster to detect then a full SEE.
Note that in case see_sign() is negative then the returned
value is exactly the see() value, this is very important,
especially for ordering capturing moves.
With this patch the calls to the costly see() are reduced
of almost 30%.
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Some variables were global due to some old and now removed code,
but now can be moved in local scope.
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Testing on Joona QUAD failed to give any
advantage. Actually we had a little loss:
Mod - Orig: 342.0 - 374.0
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Rename to move_is_promotion() to be more clear, also add
a new function move_promotion_piece() to get the
promotion piece type in the few places where is needed.
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
When we are hunting for mate, transposition table is filled in
with mate scores. Current implemenatation of aspiration search
can't cope with this very well.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Move TT object away from heavy write accessed NodesSincePoll
and also, inside TT isolate the heavy accessed writes variable.
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
This was needed by an old optimization in sorting of
non-captures that is now obsoleted by new std::sort()
approach.
Remove also the unused depth member data. Interestingly
this has always been unused since the Glaurung days.
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>