Compare commits

..

459 Commits

Author SHA1 Message Date
mstembera 378c8bdbb8 Stockfish 9
Official release version of Stockfish 9

Bench 5023629
2018-01-31 11:41:09 +01:00
Torsten Franz 2e11388581 Retire lever (#1378)
Retire the lever bonus from pawns evaluation

STC: http://tests.stockfishchess.org/tests/view/5a6aef5c0ebc590d945d59c8
LLR: 2.94 (-2.94,2.94) [-3.00,1.00]
Total: 88290 W: 19549 L: 19560 D: 49181

LTC: http://tests.stockfishchess.org/tests/view/5a6b70140ebc590d945d59f7
LLR: 3.22 (-2.94,2.94) [-3.00,1.00]
Total: 104603 W: 18105 L: 18108 D: 68390

Bench 5023629
2018-01-30 09:40:56 +01:00
Rocky640 0a5b03af3f Limit the king distance factor when evaluating passed pawns (#1373)
Limit the king distance factor when evaluating passed pawns
Passed STC
http://tests.stockfishchess.org/tests/view/5a6bf7290ebc590d945d5a3a
LLR: 3.31 (-2.94,2.94) [0.00,5.00]
Total: 23987 W: 5550 L: 5281 D: 13156

and LTC
http://tests.stockfishchess.org/tests/view/5a6c57710ebc590297c36af2
LLR: 2.97 (-2.94,2.94) [0.00,5.00]
Total: 16926 W: 3014 L: 2820 D: 11092

Bench: 5059457
2018-01-28 14:56:45 +01:00
syzygy1 fd4d800c98 This modifies the in-search TB probing to continue searching for a mate "behind" a TB win (or loss). (#1285)
It does the following:

- If a TB win or loss value allows an alpha or beta cutoff, the cutoff is taken.
- Otherwise, the search of the current subtree continues. In PV nodes, the final value returned is adjusted to reflect that the position is a TB win (or loss).

The patch also fixes a potential problem caused by root_probe() and root_probe_wdl() dirtying the root-move scores.

This patch removes the limitation of current master that a mate is never found if the root position is not yet in the TBs, but the path to mate at some point enters the TBs. The patch is intended to preserve the efficiency and effectiveness of the current TB probing approach.

No functional change (withouth TB)
2018-01-28 14:40:07 +01:00
mibere a5a98d822e Top CPU Contributors as of January 2018 (#1367)
No functional change.
2018-01-24 16:54:04 +01:00
Stéphane Nicolet 254d995e18 Contempt 20
Set the default contempt value of Stockfish to 20 centipawns.

The contempt feature of Stockfish tries to prevent the engine from
simplifying the position too quickly when it feels that it is very
slightly behind, instead keeping the tension a little bit longer.

Various tests in November 2017 have proved that our current imple-
mentation works well against SF7 (which is about 130 Elo weaker than
current master) and than the Elo gain is an increasing function of
contempt, going (against SF7) from +0 Elo when contempt is set at
zero centipawns, to +30 Elo when contempt is 40 centipawns.

See pull request 1325 for details:

https://github.com/official-stockfish/Stockfish/pull/1325

This november discussion left open the decision of which "default"
value for contempt we should use for Stockfish, taking into account
the various uses ofStockfish (opening preparation for humans, computer
online tournaments,analysis tool for web pages, human/computer play,
etc).

This pull request proposes to set the default contempt value of SF
to twenty centipawns, which turns out to be the highest value which
is not a regression against current master, as this seemed to be a
good compromise between risk and safety. A couple of SPRT[-3..1]
tests were done to bisect this value:

Contempt 10: http://tests.stockfishchess.org/tests/view/5a5d42d20ebc5902977e2901 (PASSED)
Contempt 15: http://tests.stockfishchess.org/tests/view/5a5d41740ebc5902977e28fa (PASSED)
Contempt 20: http://tests.stockfishchess.org/tests/view/5a5d42060ebc5902977e28fc (PASSED)
Contempt 25: http://tests.stockfishchess.org/tests/view/5a5d433f0ebc5902977e2904 (FAILED)

Surprisingly, a test at "very long time control" hinted that using
contempt 20 is not only be non-regressive against contempt 0, but
may actually exhibit some small Elo gain, giving a likehood of superio-
rity of 88.7% after 8500 games:

VLTC:
ELO: 2.28 +-3.7 (95%) LOS: 88.7%
Total: 8521 W: 1096 L: 1040 D: 6385
http://tests.stockfishchess.org/tests/view/5a60b2820ebc590297b9b7e0

Finally, there was some concerns that a contempt value of 20 would
be worse than a value of 7, but a test with 20000 games at STC was
neutral:

STC:
ELO: 0.45 +-3.1 (95%) LOS: 61.2%
Total: 20000 W: 4222 L: 4196 D: 11582
http://tests.stockfishchess.org/tests/view/5a64d2fd0ebc590297903868

See the comments in pull request 1361 for the long, nice discussion
(180 entries :-)) leading to the decision to propose contempt 20 as
the default value:

https://github.com/official-stockfish/Stockfish/pull/1361

Whether Stockfish should strictly adhere to the Komodo and Houdini
semantics and add the UCI commands to force the contempt to be White
in the so-called "analysis mode" is still under discussion, and may
be or may not be the object of a future commit.

Bench: 5783344
2018-01-23 14:26:45 +01:00
Tom Vijlbrief 5451687efb Make razor margin depth independent
STC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 37171 W: 6680 L: 6587 D: 23904

LTC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 11632 W: 1574 L: 1442 D: 8616

bench: 5098576
2018-01-23 14:15:05 +01:00
Fabian Fichter b61759e907 Simplify away redundant SEE pruning condition (#1363)
SEE immediately returns true for promotions,
so excluding them before checking SEE is redundant.

STC
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 56758 W: 10166 L: 10106 D: 36486
http://tests.stockfishchess.org/tests/view/5a645eaf0ebc590297903833

No functional change.
2018-01-23 14:05:48 +01:00
Marco Costalba b508f9561c Fix bench number
Incorrect bench number in master. Fix it.

bench: 4971497
2018-01-13 09:21:23 +01:00
Günther Demetz 1b6459195c Simplify verification search (#1362)
1. avoid recursive call of verification.
   For the interested side to move recursion makes no sense.
   For the other side it could make sense in case of mutual zugzwang,
   but I was not able to figure out any concrete problematic position.
   Allows the removal of 2 local variables.
   
2. avoid further reduction by removing R += ONE_PLY;

Benchmark with zugzwang-suite (see #1338), max 45 secs per position:
Patch  solves 33 out of 37
Master solves 31 out of 37

STC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 76188 W: 13866 L: 13840 D: 48482
http://tests.stockfishchess.org/tests/view/5a5612ed0ebc590297da516c

LTC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 40479 W: 5247 L: 5152 D: 30080
http://tests.stockfishchess.org/tests/view/5a56f7d30ebc590299e4550e

bench: 5340015
2018-01-13 09:01:23 +01:00
IIvec aa88261a8f Revert to old time management (#1351)
As many users reported some problems with new time management,
and recent tests on longer time controls

http://tests.stockfishchess.org/tests/view/5a460e160ebc590ccbb8c35d
http://tests.stockfishchess.org/tests/view/5a462f4d0ebc590ccbb8c37a

are even little in favor of old time management, this revert seems as a logical step.

STC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 14060 W: 2562 L: 2430 D: 9068

LTC:
LLR: 3.44 (-2.94,2.94) [-3.00,1.00]
Total: 31611 W: 3958 L: 3827 D: 23826

bench: 5365777 (same as master)
2018-01-13 08:59:20 +01:00
mbootsector 33682bfb98 Use mobility in kingsafety (#1360)
Use mobility in kingsafety

STC: http://tests.stockfishchess.org/tests/view/5a55134d0ebc590296938a28
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 32651 W: 6057 L: 5792 D: 20802

LTC: http://tests.stockfishchess.org/tests/view/5a5618f40ebc590297da516f
LLR: 2.94 (-2.94,2.94) [0.00,5.00]
Total: 17875 W: 2421 L: 2245 D: 13209

bench: 5365777
2018-01-13 08:56:42 +01:00
hxim 66ce8ad5fd Remove ThreatByHangingPawn bonus (#1356)
* no ThreatByHangingPawn

* bench: 4919682
2018-01-04 22:31:30 +01:00
Joost VandeVondele 9afa1d7330 New Year 2018
Adjust copyright headers.

No functional change.
2018-01-01 13:18:10 +01:00
Joost VandeVondele 2ba47416cb Explicitly zero TT upon resize.
as discussed in issue #1349, the way pages are allocated with calloc might imply some overhead on first write.
This overhead can be large and slow down the first search after a TT resize significantly, especially for large TT.
Using an explicit clear of the TT on resize fixes this problem.

Not implemented, but possibly useful for large TT, is to do this zero-ing using all search threads. Not only would this be faster, it could also lead to a more favorable memory allocation on numa systems with a first touch policy.

No functional change.
2018-01-01 13:17:51 +01:00
Guenther Demetz 7d4d3a2c3a Include x-ray attacks through all queens independently of the color.
When calculating attacks from rooks/bishops current master includes
x-rays through own queen. This patch includes also x-rays through
opponent queen.

Credits go to Brian who inspired for this idea
https://groups.google.com/forum/?fromgroups=#!topic/fishcooking/Z3APRYpQeMU

STC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 41549 W: 7544 L: 7244 D: 26761
Elo	2.05 [-0.29,4.19] (95%)
http://tests.stockfishchess.org/tests/view/5a3b5fe50ebc590ccbb8bf9a

LTC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 110010 W: 14208 L: 13739 D: 82063
Elo	1.20 [-0.27,2.55] (95%)
http://tests.stockfishchess.org/tests/view/5a3b8e7c0ebc590ccbb8bfad

bench: 5544445
2017-12-26 10:42:24 +01:00
Joost VandeVondele 1c50d8cbf5 Upon changing the number of threads, make sure all threads are bound
The heuristic to avoid thread binding if less than 8 threads are requested resulted in the first 7 threads not being bound.
The branch was verified to yield a roughly 13% speedup by @CoffeeOne on the appropriate hardware and OS, and an earlier version of this patch tested well on his machine:

http://tests.stockfishchess.org/tests/view/5a3693480ebc590ccbb8be5a
ELO: 9.24 +-4.6 (95%) LOS: 100.0%
Total: 5000 W: 634 L: 501 D: 3865

To make sure all threads (including mainThread) are bound as soon as the total number exceeds 7, recreate all threads on a change of thread number.
To do this, unify Threads::init, Threads::exit and Threads::set are unified in a single Threads::set function that goes through the needed steps.
The code includes several suggestions from @joergoster.

Fixes issue #1312 

No functional change
2017-12-26 10:40:42 +01:00
Joost VandeVondele 2198cd0524 Allow for general transposition table sizes. (#1341)
For efficiency reasons current master only allows for transposition table sizes that are N = 2^k in size, the index computation can be done efficiently as (hash % N) can be written instead as (hash & 2^k - 1). On a typical computer (with 4, 8... etc Gb of RAM), this implies roughly half the RAM is left unused in analysis.

This issue was mentioned on fishcooking by Mindbreaker:
http://tests.stockfishchess.org/tests/view/5a3587de0ebc590ccbb8be04

Recently a neat trick was proposed to map a hash into the range [0,N[ more efficiently than (hash % N) for general N, nearly as efficiently as (hash % 2^k):

https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/

namely computing (hash * N / 2^32) for 32 bit hashes. This patch implements this trick and now allows for general hash sizes. Note that for N = 2^k this just amounts to using a different subset of bits from the hash. Master will use the lower k bits, this trick will use the upper k bits (of the 32 bit hash).

There is no slowdown as measured with [-3, 1] test:

http://tests.stockfishchess.org/tests/view/5a3587de0ebc590ccbb8be04
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 128498 W: 23332 L: 23395 D: 81771

There are two (smaller) caveats:

1) the patch is implemented for a 32 bit hash (so that a 64 bit multiply can be used), this effectively limits the number of clusters that can be used to 2^32 or to 128Gb of transpostion table. That's a change in the maximum allowed TT size, which could bother those using 256Gb or more regularly.

2) Already in master, an excluded move is hashed into the position key in rather simple way, essentially only affecting the lower 16 bits of the key. This is OK in master, since bits 0-15 end up in the index, but not in the new scheme, which picks the higher bits. This is 'fixed' by shifting the excluded move a few bits up. Eventually a better hashing scheme seems wise.

Despite these two caveats, I think this is a nice improvement in usability.

Bench: 5346341
2017-12-18 16:32:21 +01:00
Günther Demetz b53239d641 Enhanced verify search (#1338)
by disabling null-move-pruning for the side to move for first part of
the remaining search tree. This helps to better recognize zugzwang.

STC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 18220 W: 3379 L: 3253 D: 11588
http://tests.stockfishchess.org/tests/view/5a2fa6460ebc590ccbb8bc2f

LTC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 41899 W: 5359 L: 5265 D: 31275
http://tests.stockfishchess.org/tests/view/5a2fcf440ebc590ccbb8bc47

For further detail see commit notes and discussion at 
https://github.com/pb00068/Stockfish/commit/6401a80ab91df5c54390ac357409fef2e51ff5bb

bench: 5776193
2017-12-18 16:30:27 +01:00
Gontran Lemaire 83e829c9dc Remove QueenMinorsImbalance array #1340
Remove QMI array and adjust bishop, knight and queen coefficients
in QuadraticOurs and QuadraticTheirs arrays in compensation of
this removal.

STC : http://tests.stockfishchess.org/tests/view/5a21d8350ebc590ccbb8b5fe
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 49659 W: 9029 L: 8957 D: 31673

LTC : http://tests.stockfishchess.org/tests/view/5a33c0dd0ebc590ccbb8bd7e
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 45905 W: 5834 L: 5745 D: 34326

Bench: 5176807
2017-12-17 09:20:17 +01:00
Joost VandeVondele f6981b1321 Make staticEval independent of the search path
Current master can yield different staticEvals depending on the path
used to reach the position. The reason for this is that the evaluation after a
null move is always computed subtracting 2 * Eval::Tempo, while this is not
the case for lazy or specialized evals. This patch always adds tempo to evals,
which doesn't affect playing strength:

LTC
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 59911 W: 7616 L: 7545 D: 44750

STC
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 104947 W: 18897 L: 18919 D: 67131

Fixes issue #1335

Bench: 5208264
2017-12-17 09:11:55 +01:00
Rocky640 be6fafd079 Simplify other checks (#1337)
Replace an intricate definition with a more natural one.

Master was excluding squares occupied by a pawn which was blocked by a pawn.
This version excludes any squares occupied by a pawn which is blocked by "something"

Passed STC
http://tests.stockfishchess.org/tests/view/5a2f557b0ebc590ccbb8bc0d
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 44211 W: 8009 L: 7928 D: 28274

and LTC
http://tests.stockfishchess.org/tests/view/5a301d440ebc590ccbb8bc80
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 31958 W: 4108 L: 4002 D: 23848

Bench 5000136
2017-12-17 08:50:45 +01:00
Alain SAVARD 020dd69a35 Simplify other checks #1334
Simplify the other check penalty computation. Compared to current master,

a) it uses a 143 kingDanger penalty instead of S(10, 10) for the "otherCheck"
(credits to ElbertoOne for finding a suitable kingDanger range to replace the score
and to Guardian for showing this could also be a neutral change at LTC).
This makes our king safety model more consistent and simpler.

b) it might also score more than one "otherCheck" penalty for a given piece type instead of just one

c) it might score many pinned penalties instead of just one.

d) It also remove 3 conditionals and uses simpler expressions.
So it was tested as a SPRT[-3, 1]

Passed STC
http://tests.stockfishchess.org/tests/view/5a2b560b0ebc590ccbb8ba6b
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 11705 W: 2217 L: 2080 D: 7408

And LTC
http://tests.stockfishchess.org/tests/view/5a2bfd0d0ebc590ccbb8bab0
LLR: 2.94 (-2.94,2.94) [-3.00,1.00]
Total: 26812 W: 3575 L: 3463 D: 19774

Trying to improve on b) another attempt was made to score also the
"otherchecks" for piece types which had some safe checks, but this
failed STC http://tests.stockfishchess.org/tests/view/5a2c79e60ebc590ccbb8badd

bench: 5149133
2017-12-11 15:27:44 +01:00
Ben Koshy 70262f2027 Add Resources to understand code base (#1332)
No functional change.
2017-12-10 13:46:43 +01:00
Günther Demetz 196ae7c38b Don't consider defending queen as check blocker (#1328)
STC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 22636 W: 4212 L: 3990 D: 14434
http://tests.stockfishchess.org/tests/view/5a2506140ebc590ccbb8b75a

LTC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 63448 W: 8287 L: 7965 D: 47196
http://tests.stockfishchess.org/tests/view/5a253a610ebc590ccbb8b776

bench: 5767699
2017-12-06 14:23:41 +01:00
Stéphane Nicolet be382bb0cf A better contempt implementation for Stockfish (#1325)
* A better contempt implementation for Stockfish

The round 2 of TCEC season 10 demonstrated the benefit of having a nice contempt implementation: it gives the strongest programs in the tournament the ability to slow down the game when they feel the position is slightly worse, prefering to stay in a complicated (even if slightly risky) middle game rather than simplifying by force into a drawn endgame.

The current contempt implementation of Stockfish is inadequate, and this patch is an attempt to provide a better one.

Passed STC non-regression test against master:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 83360 W: 15089 L: 15075 D: 53196
http://tests.stockfishchess.org/tests/view/5a1bf2de0ebc590ccbb8b370

This contempt implementation is showing promising results in certains situations. For instance, it obtained a nice +30 Elo gain when playing with contempt=40 against Stockfish 7, compared to current master:

• master against SF 7 (20000 games at LTC): +121.2 Elo
• this patch with contempt=40 (20000 games at LTC): +154.11 Elo

This was the result of real cooperative work from the Stockfish team, with key ideas coming from Stefan Geschwentner (locutus2) and Chris Cain (ceebo) while most of the community helped with feedback and computer time.

In this commit the bench is unchanged by default, but you can test at home with the new contempt in the UCI options. The style of play will change a lot when using contempt different of zero (I repeat: not done in this version by default, however)!

The Stockfish team is still deliberating over the best default contempt value in self-play and the best contempt modeling strategy, to help users choosing a contempt value when playing against much weaker programs. These informations will be given in future commits when available :-)

Bench: 5051254

* Remove the prefetch

No functional change.
2017-12-05 07:25:42 +01:00
Joost VandeVondele d193482213 Pawn endgames directly skip early pruning.
Instead of checking individual steps. Idea by @Stefano80.

passed STC
http://tests.stockfishchess.org/tests/view/5a23e5d20ebc590ccbb8b6d5
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 37445 W: 6866 L: 6773 D: 23806

passed LTC
http://tests.stockfishchess.org/tests/view/5a24260c0ebc590ccbb8b716
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 38780 W: 4946 L: 4848 D: 28986

Bench: 5466219
2017-12-04 17:57:36 +01:00
Stéphane Nicolet 54f6ce70fd Avoid warnings by the Clang compiler
Clang gave a couple of warnings for unused parameters after the recnet commit "Use constexpr when makes sense".

No functional change.
2017-12-04 17:53:42 +01:00
syzygy1 822695d4d3 Use a Direction enum for Square deltas
Currently the NORTH/WEST/SOUTH/EAST values are of type Square, but conceptually they are not squares but directions. This patch separates these values into a Direction enum and overloads addition and subtraction to allow adding a Square to a Direction (to get a new Square).

I have also slightly trimmed the possible overloadings to improve type safety. For example, it would normally not make sense to add a Color to a Color or a Piece to a Piece, or to multiply or divide them by an integer. It would also normally not make sense to add a Square to a Square.

This is a non-functional change.
2017-12-04 17:52:31 +01:00
Joost VandeVondele 2acda1fde3 Use bool(Bitboard b) instead of !!b (#1321)
The idiom !!b is confusing newcomers (e.g. Stefan needs explaining here https://groups.google.com/d/msg/fishcooking/vYqnsRI4brY/Gaf60QuACwAJ).

No functional change.
2017-12-03 18:29:55 +01:00
Guy Vreuls 28b6a457c2 Use constexpr when makes sense
No functional change.
2017-12-03 12:44:24 +01:00
Stéphane Nicolet ccd6bad512 Compile without exceptions
Add the -fno-exceptions flag to the Makefile to avoid the unecessary exceptions support in the executable (we do not use any exception in Stockfish at the moment).

This change gives a 9.2% reduction in size for the executable binary.

Before : executable size = 376956 bytes
After: executable size = 347652 bytes

No functional change.
2017-12-03 12:30:09 +01:00
syzygy 8a5a64eac5 Minor cleanup of search.cpp
Four very minor edits. Note that tte->save() uses posKey and
not pos.key() in other places.

Originally I also added a futility_move_counts() function to
make things more consistent with the futility_margin() and
reduction() functions. But then razor_margin[] should probably
also be turned into a function, etc. Maybe a good idea, maybe not.
So I did not include it.

Non functional change.
2017-12-03 12:24:46 +01:00
Stefan Geschwentner a87a1005ad Attack threats
Give bonus for safe attack threats from bishops and rooks on opponent queen

STC:
LLR: 2.97 (-2.94,2.94) [0.00,5.00]
Total: 8629 W: 1599 L: 1438 D: 5592
http://tests.stockfishchess.org/tests/view/5a1ad4490ebc590ccbb8b30d

LTC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 7093 W: 987 L: 846 D: 5260
http://tests.stockfishchess.org/tests/view/5a1aec5d0ebc590ccbb8b317

Bench: 5051254
2017-12-03 10:41:48 +01:00
basepr1me 7dd1f4a7c0 OpenBSD friendly start. 2017-11-18 16:45:33 +01:00
Stefan Geschwentner d64ffd9621 Simplify good/bad capture detection. bench 5336313 2017-11-18 16:27:44 +01:00
Stefano Cardanobile c769d4df84 Fix comments. Bench: 5109559. 2017-11-18 14:08:06 +01:00
Stéphane Nicolet 03a9b3bd8d Simplify away the PawnSet[] imbalance array (#1308)
Simplify away the PawnSet[] imbalance array

STC:
LLR: 2.94 (-2.94,2.94) [-3.00,1.00]
Total: 52977 W: 9550 L: 9484 D: 33943
http://tests.stockfishchess.org/tests/view/5a06b4780ebc590ccbb8a833

LTC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 83717 W: 10599 L: 10559 D: 62559
http://tests.stockfishchess.org/tests/view/5a0aa36a0ebc590ccbb8aa99

Bench: 5340212
2017-11-18 11:24:23 +01:00
Rocky640 53239d7d3d Simplify some kingring penalties expressions
The new "weak" expression helps simplify the safe check calculations for rooks or minors, (but the end result for all the safe checks is the exactly the same as in current master)

The only functional change is for the "outer king ring" (for example, squares f3 g3 h3 when white king is on g1). In current master, there was a 191 penalty if any of these was not defended at all.
With this pr, there is this 191 penalty if any of these is not defended at all or is only defended by a white queen.

Tested as a simplification
STC
http://tests.stockfishchess.org/tests/view/59fb03d80ebc590ccbb89fee
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 66167 W: 12015 L: 11971 D: 42181
(against master (Update Copyright year inMakefile))

LTC
http://tests.stockfishchess.org/tests/view/5a0106ae0ebc590ccbb8a55f
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 15790 W: 2095 L: 1968 D: 11727
(against master (Handle BxN trade as good capture when history scor))

same as #1296 but rebased on latest master
bench: 5109559
2017-11-11 13:37:29 +01:00
ceebo 3f44f5303b Add comments to pos.see_ge()
In terms of technical changes this patch eliminates the return
statements from the main loop of pos.see_ge() and replaces two conditional
computations with a single bitwise negation.

No functional change
2017-11-10 12:14:53 +01:00
VoyagerOne 87452f3a8c Capture Stat Simplification- Bench: 5363761 2017-11-10 12:12:58 +01:00
Gian-Carlo Pascutto 8cfcca12d1 Always do MaxCardinality checks.
Stockfish currently relies on the "filter_root_moves" function also
having the side effect of clamping Cardinality against MaxCardinality
(the actual piece count in the tablebases). So if we skip this function,
we will end up probing in the search even without tablebases installed.

We cannot bail out of this function before this check is done, so move
the MultiPV hack a few lines below.
2017-11-08 13:45:14 +01:00
Joost VandeVondele 0a74c16ffe Simplify Null Move Search condition
Removes depth condition, adjust parameters.

passed STC:
http://tests.stockfishchess.org/tests/view/5a008cbc0ebc590ccbb8a512
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 29282 W: 5317 L: 5210 D: 18755

passed LTC:
http://tests.stockfishchess.org/tests/view/5a00d8530ebc590ccbb8a541
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 26893 W: 3458 L: 3345 D: 20090

Bench: 5015773
2017-11-08 13:44:24 +01:00
Günther Demetz 652199d840 Handle BxN trade as good capture when history score is good
STC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 19374 W: 3499 L: 3294 D: 12581
http://tests.stockfishchess.org/tests/view/59fc23f50ebc590ccbb8a0bf

LTC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 91030 W: 11680 L: 11274 D: 68076
http://tests.stockfishchess.org/tests/view/59fc43ad0ebc590ccbb8a0d0

Bench: 5482249
2017-11-05 22:05:51 +01:00
Stefan Geschwentner 4bc11984fc Introduce capture history table for capture move sorting
Introduce capture move history table indexed by moved piece,
target square and captured piece type for sorting capture moves.

STC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 11374 W: 2096 L: 1924 D: 7354
http://tests.stockfishchess.org/tests/view/59fac8dc0ebc590ccbb89fc5

LTC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 24791 W: 3196 L: 3001 D: 18594
http://tests.stockfishchess.org/tests/view/59fae4d20ebc590ccbb89fd9

Bench: 5536775
2017-11-03 13:57:18 +01:00
Joost VandeVondele 486c8175c4 Replace easyMove with simple scheme
Reduces time for a stable bestMove, giving some of the won time for the next move.

the version before the pvDraw passed both STC and LTC

passed STC:
http://tests.stockfishchess.org/tests/view/59e98d5a0ebc590ccbb896ec
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 78561 W: 13945 L: 13921 D: 50695
elo =    0.106 +-    1.445 LOS:   55.716%

passed LTC:
http://tests.stockfishchess.org/tests/view/59eb9df90ebc590ccbb897ae
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 29056 W: 3640 L: 3530 D: 21886
elo =    1.315 +-    1.982 LOS:   90.314%

This version, rebased on pvDrawPR with the obvious change, was verified again on STC:

http://tests.stockfishchess.org/tests/view/59ee104e0ebc590ccbb89899
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 19890 W: 3648 L: 3525 D: 12717
elo =    2.149 +-    2.895 LOS:   92.692%

and LTC:
http://tests.stockfishchess.org/tests/view/59f9673a0ebc590ccbb89ea0
Total             :    17966
Win               :     2273 (  12.652%)
Loss              :     2149 (  11.961%)
Draw              :    13544 (  75.387%)
Score             :   50.345%
Sensitivity       :    0.014%
2*(W-L)/(W+L)     :    5.608%

LLR  [-3.0,  1.0] :     2.95

BayesElo range    : [  -1.161,   4.876,  10.830] (DrawElo:  341.132)
LogisticElo range : [  -0.501,   2.105,   4.677]
LOS               :   94.369 %

LTC again:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 17966 W: 2273 L: 2149 D: 13544
LogisticElo range : [ -0.501, 2.105, 4.677]
LOS : 94.369 %

unchanged bench: 5234652
2017-11-03 13:51:53 +01:00
Cooffe e0d2fdc843 Update Copyright year inMakefile
No functional change.
2017-10-28 12:35:44 +02:00
Joost VandeVondele e50af36a00 Extra thinking before accepting draw PVs.
If the PV leads to a draw (3-fold / 50-moves) position
and we're ahead of time, think a little longer, possibly
finding a better way.

As this is most likely effective at higher draw rates,
tried speculative LTC after a yellow STC:

STC:
http://tests.stockfishchess.org/tests/view/59eb173a0ebc590ccbb8975d
LLR: -2.95 (-2.94,2.94) [0.00,5.00]
Total: 56095 W: 10013 L: 9902 D: 36180
elo =    0.688 +-    1.711 LOS:   78.425%

LTC:
http://tests.stockfishchess.org/tests/view/59eba1670ebc590ccbb897b4
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 59579 W: 7577 L: 7273 D: 44729
elo =    1.773 +-    1.391 LOS:   99.381%

bench: 5234652
2017-10-28 12:33:48 +02:00
IIvec 287e2e2f74 Fix premature using of all available time in x/y TC
In x/y time controls there was a theoretical possibility
to use all available time few moves before the clock will
be updated with new time. This patch fixes that issue.

Tested at 60/15 time control:

LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 113963 W: 20008 L: 20042 D: 73913

The test was done without adjudication rules!

Bench 5234652
2017-10-22 07:43:37 +02:00
Gian-Carlo Pascutto 86ac50403d Don't filter root moves if MultiPV mode is enabled
A band-aid patch to workaround current TB code
limitations with multi PV.

Hopefully this will be removed after committing the
big update of TB impementation, now under discussion.

No functional change.
2017-10-22 07:18:48 +02:00
ceebo 0dc3b0978d Add initiative to trace
No functional change
2017-10-22 07:00:46 +02:00
Joost VandeVondele 9d79138682 Fix issue #1268
If the search is quit before skill.pick_best is called,
skill.best_move might be MOVE_NONE.

Ensure skill.best is always assigned anyhow.

Also retire the tricky best_move() and let the underlying
semantic to be clear and explicit.

No functional change.
2017-10-11 11:47:50 +02:00
Alain SAVARD 43c186c645 Simplify bonus for bishop on long diagonal
Removing 2 conditions, and increase the ThreatbyPawn to compensate.

Passed STC
http://tests.stockfishchess.org/tests/view/59dbde900ebc5916ff64be6d
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 14236 W: 2615 L: 2483 D: 9138

Passed LTC
http://tests.stockfishchess.org/tests/view/59dc26470ebc5916ff64be92
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 16552 W: 2136 L: 2010 D: 12406

Bench: 5234652
2017-10-11 11:13:44 +02:00
Niklas Fiekas b36489742b WLDEntryPiece -> WDLEntryPiece for consistency
No functional change.
2017-10-05 11:00:01 +02:00
Stéphane Nicolet 452e5154cf Good bishops on the main diagonals
Bonus in midgame for bishops on long diagonals when the central squares are not occupied by pawns.

Author: ElbertoOne

Passed STC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 10801 W: 1955 L: 1786 D: 7060
http://tests.stockfishchess.org/tests/view/59cf5c1d0ebc5916ff64b9da

and LTC:
LLR: 2.97 (-2.94,2.94) [0.00,5.00]
Total: 83978 W: 10685 L: 10303 D: 62990
http://tests.stockfishchess.org/tests/view/59cf6f6c0ebc5916ff64b9e4

Bench: 5620312
2017-10-02 07:53:28 +02:00
VoyagerOne 07b5a28a68 Decrease reduction for exact PV nodes
STC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 59004 W: 10621 L: 10249 D: 38134

LTC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 25801 W: 3306 L: 3108 D: 19387

Bench: 5742466
2017-09-30 20:56:27 +02:00
Joost VandeVondele c33af32dad Measure nodes after search finished.
Only affects nmpsec in the multithreaded case.

No functional change.
2017-09-29 16:39:12 +02:00
GuardianRM 0e949ac2c9 Tweak statScore condition
The first change (ss->statScore >= 0) does nothing.

The second change ((ss-1)->statScore >= 0 ) has a massive change.
(ss-1)->statScore is not set until (ss-1) begins to apply LMR to moves.
So we now increase the reduction for bad quiets when our opponent is
running through the first captures and the hash move.

STC
LLR: 2.95 (-2.94,2.94) [0.00,4.00]
Total: 57762 W: 10533 L: 10181 D: 37048

LTC
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 19973 W: 2662 L: 2480 D: 14831

Bench: 5037819
2017-09-22 16:48:08 +02:00
syzygy ba4e215493 Let ss->ply denote the number of plies from the root to the current node
This patch lets ss->ply be equal to 0 at the root of the search.

Currently, the root has ss->ply == 1, which is less intuitive:

- Setting the rootNode bool has to check (ss-1)->ply == 0.

- All mate values are off by one: the code seems to assume that mated-in-0
  is -VALUE_MATE, mate-1-in-ply is VALUE_MATE-1, mated-in-2-ply is VALUE_MATE+2, etc.
  But the mate_in() and mated_in() functions are called with ss->ply, which is 1 in
  at the root.

- The is_draw() function currently needs to explain why it has "ply - 1 > i" instead
  of simply "ply > i".

- The ss->ply >= MAX_PLY tests in search() and qsearch() already assume that
  ss->ply == 0 at the root. If we start at ss->ply == 1, it would make more sense to
  go up to and including ss->ply == MAX_PLY, so stop at ss->ply > MAX_PLY. See also
  the asserts testing for 0 <= ss->ply && ss->ply < MAX_PLY.

The reason for ss->ply == 1 at the root is the line "ss->ply = (ss-1)->ply + 1" at
the start for search() and qsearch(). By replacing this with "(ss+1)->ply = ss->ply + 1"
we keep ss->ply == 0 at the root. Note that search() already clears killers in (ss+2),
so there is no danger in accessing ss+1.

I have NOT changed pv[MAX_PLY + 1] to pv[MAX_PLY + 2] in search() and qsearch().
It seems to me that MAX_PLY + 1 is exactly right:

- MAX_PLY entries for ss->ply running from 0 to MAX_PLY-1, and 1 entry for the
  final MOVE_NONE.

I have verified that mate scores are reported correctly. (They were already reported
correctly due to the extra ply being rounded down when converting to moves.)

The value of seldepth output to the user should probably not change, so I add 1 to it.
(Humans count from 1, computers from 0.)

A small optimisation I did not include: instead of setting ss->ply in every invocation
of search() and qsearch(), it could be set once for all plies at the start of
Thread::search(). This saves a couple of instructions per node.

No functional change (unless the search searches a branch MAX_PLY deep), so bench
does not change.
2017-09-17 10:44:10 +02:00
Stéphane Nicolet 043a469f83 Score unopposed weak pawns only if majors
Do not use the opposed flag for scoring backward and isolated pawns
in pawns.cpp, instead give a S(5,25) bonus for each opponent unopposed
weak pawns when we have a rook or a queen on the board.

STC run stopped after 113188 games:
LLR: 1.63 (-2.94,2.94) [0.00,5.00]
Total: 113188 W: 20804 L: 20251 D: 72133
http://tests.stockfishchess.org/tests/view/59b58e4d0ebc5916ff64b12e

LTC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 66673 W: 8672 L: 8341 D: 49660
http://tests.stockfishchess.org/tests/view/59b902580ebc5916ff64b231

This is Alain Savard's idea, just with a different bonus.
Original patch there:

green STC, http://tests.stockfishchess.org/tests/view/597dcd2b0ebc5916ff64a09b
yellow LTC, http://tests.stockfishchess.org/tests/view/597ea69e0ebc5916ff64a0e6

Bench: 6259498
2017-09-17 09:52:27 +02:00
IIvec 21926ce2d8 Higher Move Overhead
This shoudl reduce time losses experienced by
users after new time management code.

Verified for no regression in very short TC (4sec + 0.1)
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 35262 W: 7426 L: 7331 D: 20505

Bench 5322108
2017-09-12 12:31:53 +02:00
ianfab ed8286eb1b Extend ShelterWeakness array by dimension isKingFile
Use different penalties for weaknesses in the pawn shelter
depending on whether it is on the king's file or not.

STC
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 71617 W: 13471 L: 13034 D: 45112

LTC
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 48708 W: 6463 L: 6187 D: 36058

Bench: 5322108
2017-09-09 12:23:34 +02:00
VoyagerOne 3ac47c84d3 Streamlline reduction based on movecount
Use MoveCount History only at quiet moves and simply reduce
reduction by one depth instead of increasing moveCount in formula.

STC:
LLR: 2.96 (-2.94,2.94) [0.00,4.00]
Total: 27511 W: 5171 L: 4919 D: 17421

LTC:
LLR: 2.96 (-2.94,2.94) [0.00,4.00]
Total: 92337 W: 12135 L: 11748 D: 68454

Bench: 6351176
2017-09-05 11:03:50 +02:00
syzygy 741523eda8 Small simplication of see_ge()
Two simplifications:

- Remove the initialisation to 0 of occupied, which is now unnecessary.
- Remove the initial check for nextVictim == KING

If nextVictim == KING, then PieceValue[MG][nextVictim] will be 0, so that
balance >= threshold is true. So see_ge() returns true anyway.

No functional change.
2017-09-05 10:57:10 +02:00
Marco Costalba 04eb87fd08 Travis CI: Make all warnings into errors
Compile with -Werror flag. To make debugging easier
also show compile ourput.

This flag is enabled only in Travis CI, not in the shipped
Makefile becuase we can't test on every possible platform.
2017-09-05 10:40:34 +02:00
Joost VandeVondele 323925b91c Remove unneeded compile options.
In light of issue #1232, a test was performed about the value of '-fno-exceptions' and a second one of the combination '-fno-exceptions -fno-rtti'. It turns out these options are can be removed without introducing slowdown.

STC for removing '-fno-exceptions'
LLR: 2.94 (-2.94,2.94) [-3.00,1.00]
Total: 13678 W: 2572 L: 2439 D: 8667

STC for removing '-fno-exceptions -fno-rtti' (current patch)
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 32557 W: 6074 L: 5973 D: 20510

No functional change.
2017-09-02 16:58:23 +02:00
syzygy 5ba4373522 Prevent Stockfish from exiting if DTZ table is not present
During TB initialisation, Stockfish checks for the presence of WDL
tables but not for the presence of DTZ tables. When attempting to probe
a DTZ table, it is therefore possible that the table is not present.
In that case, Stockfish should neither exit nor report an error.

To verify the bug:
$ ./stockfish
setoption name SyzygyTable value <path_to_WDL_dir>
position fen 8/8/4r3/4k3/8/1K2P3/3P4/6R1 w - -
go infinite
Could not mmap() /opt/tb/regular/KRPPvKR.rtbz
$

(On my system, the WDL tables are in one directory and the DTZ tables
in another. If they are in the same directory, it will be difficult
to trigger the bug.)

The fix is trivial: check the file descriptor/handle after opening
the file.

No functional change.
2017-09-02 09:59:04 +02:00
Marco Costalba 3fd7e37868 Fix a warning with MSVC
warning C4244: '*=': conversion from 'double' to 'int', possible loss of data

No functional change.
2017-09-01 20:23:31 +02:00
Joost VandeVondele 9d95d43c57 Multi-threaded search testing with valgrind
Also check with valgrind the multi-threaded search.

On top of the fix for issue #1227 (PR #1235).

No functional change.
2017-09-01 20:19:43 +02:00
Joost VandeVondele e385f194e9 Fix uninitialized memory usage
After increasing the number of threads, the histories were not cleared,
resulting in uninitialized memory usage.

This patch fixes this by clearing threads histories in Thread c'tor as
is the idomatic way.

This fixes issue 1227

No functional change.
2017-09-01 20:16:56 +02:00
VoyagerOne 7b4c9852e1 Adjust moveCount history only at LMR
STC:
LLR: 3.32 (-2.94,2.94) [-3.00,1.00]
Total: 17584 W: 3277 L: 3131 D: 11176

LTC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 26412 W: 3447 L: 3334 D: 19631

Bench: 5417521
2017-08-31 08:53:37 +02:00
Joost VandeVondele bf485f4aff Simplify away non-normal moves in SEE
credit goes to @mstembera for suggesting this approach.
SEE now deals with castling, promotion and en passant in a similar way.

passed STC
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 32902 W: 6079 L: 5979 D: 20844

passed LTC
LLR: 3.92 (-2.94,2.94) [-3.00,1.00]
Total: 110698 W: 14198 L: 14145 D: 82355

Bench: 5713905
2017-08-30 15:02:40 +02:00
Marco Costalba a2b8f91cfa Appveyor: do a Debug and Release build
And set x86 and x64 platforms for real.

Currently this is broken and the same binary is compiled for all platforms.

This is becuase we use a custom build step. OTH the default
build step seems not compatible with cmake generated *sln file.

No functional change.
2017-08-26 11:50:27 +02:00
Joost VandeVondele d5f883ab29 Improve multi-threaded mate finding
If any thread found a 'mate in x' stop the search. Previously only
mainThread would do so. Requires the bestThread selection to be
adjusted to always prefer mate scores, even if the search depth is less.

I've tried to collect some data for this patch. On 30 cores, mate finding
seems 5-30% faster on average. It is not so easy to get numbers for this,
as the time to find a mate fluctuates significantly with multi-threaded runs,
so it is an average over 100 searches for the same position. Furthermore,
hash size and position make a difference as well.

Bench: 5965302
2017-08-26 09:53:34 +02:00
Stéphane Nicolet 92c39522b1 Count all weak squares in the king ring with a single popcount
Passed STC:
LLR: 2.95 (-2.94,2.94) [0.00,4.00]
Total: 26966 W: 4993 L: 4745 D: 17228
http://tests.stockfishchess.org/tests/view/599e798a0ebc5916ff64aa8c

and LTC:
LLR: 2.95 (-2.94,2.94) [0.00,4.00]
Total: 39570 W: 5104 L: 4857 D: 29609
http://tests.stockfishchess.org/tests/view/599ee5230ebc5916ff64aabe

Bench: 5965302
2017-08-26 09:34:27 +02:00
Joost VandeVondele 5ef94eb970 Use moveCount history for reduction
Use less reduction for moves with larger moveCount if your
opponent did an unexpected (== high moveCount) move in the
previous ply... unexpected moves might need unexpected answers.

passed STC:
http://tests.stockfishchess.org/tests/view/599f08cc0ebc5916ff64aace
LLR: 2.97 (-2.94,2.94) [0.00,5.00]
Total: 9638 W: 1889 L: 1720 D: 6029

passed LTC:
http://tests.stockfishchess.org/tests/view/599f1e5c0ebc5916ff64aadc
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 28308 W: 3742 L: 3533 D: 21033

Bench: 5747429
2017-08-26 09:30:42 +02:00
Stéphane Nicolet 002bf4d8db Avoid constructing an empty tuple in qsearch
Avoid constructing, passing as a parameter and binding a useless empty tuple of pointers in the qsearch move picker constructor.

Also reformat the scoring function in movepicker.cpp and do some cleaning in evaluate.cpp while there.

No functional change.
2017-08-22 10:16:19 +02:00
Marco Costalba 5ea327d924 Improve appeyor build
Check bench number and do not
hard-code *.cpp file names.

No functional change.
2017-08-20 19:22:11 +02:00
lucasart fe60caba94 Restore safety margin of 60ms
What this patch does is:
* increase safety margin from 40ms to 60ms. It's worth noting that the previous
  code not only used 60ms incompressible safety margin, but also an additional
  buffer of 30ms for each "move to go".
* remove a whart, integrating the extra 10ms in Move Overhead value instead.
  Additionally, this ensures that optimumtime doesn't become bigger than maximum
  time after maximum time has been artificially discounted by 10ms. So it keeps
  the code more logical.

Tested at 3 different time controls:

Standard 10+0.1
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 58008 W: 10674 L: 10617 D: 36717

Sudden death 16+0
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 59664 W: 10945 L: 10891 D: 37828

Tournament 40/10
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 16371 W: 3092 L: 2963 D: 10316

bench: 5479946
2017-08-20 20:00:31 +08:00
Marco Costalba 7aa7dfd4df Fix some Clang warnings
Found by Clang in extra verbose mode :-)

No functional change.
2017-08-19 14:32:31 +02:00
Marco Costalba fa5b0936ee Wide bench coverage
Add tests for:

- Positions with move list
- Chess960 positions

Now bench covers almost all cases, only few endgames
are still out of reach (verified with lcov)

It is a non functionality patch, but bench
changed because we added new test positions.

bench: 5479946
2017-08-19 13:58:12 +02:00
Marco Costalba 45e254a0a0 Restore perft
Rewrite perft to be placed naturally inside new
bench code. In particular we don't have special
custom code to run perft anymore but perft is
just a new parameter of 'go' command.

So user API is now changed, old style command:

$perft 5

becomes

$go perft 4

No functional change.
2017-08-18 09:04:38 -07:00
Marco Costalba 444d99b6d2 Rewrite benchmark
First step in improving bench to handle
arbitrary UCI commands so to test many
more code paths.

This first patch just set the new code
structure.

No functional change.
2017-08-18 09:04:38 -07:00
Marco Costalba e10255339f Reformat time manager code
In particular clarify that 'sd'
parameter is used only in !movesToGo
case.

Verified with Ivan's check tool it is
equivalent to original code.

No functional change.
2017-08-18 08:54:38 -07:00
Joost VandeVondele daf0fe1f57 Collect more corrections to optimum/maximum
The only call site of Time.maximum() corrected by 10.
Do this directly in remaining().

Ponder increased Time.optimum by 25% in init(). Idem.
Delete unused includes.

No functional change.
2017-08-18 08:38:40 -07:00
Marco Costalba 4d511512d2 Speed up Trevis CI
Avoid a couple of redundant rebuilds and compile
with 2 threads since travis gives 2vCPUs.

Also enable -O1 optimization for valgrind and
sanitizers, it should be safe withouth false
positives and it gives a very sensible speed
up, especially with valgrind.

The spee dup allow us to increase testing to
depth 10, useful for thread sanitizer.

No functional change.
2017-08-18 03:07:41 -07:00
Marco Costalba 9c35b9365d Clarify stats range
Current update formula ensures that the
possible value range is [-32 * D, 32 * D].

So we never overflow if abs(32 * D) < INT16_MAX

Thanks to Joost and mstembera to clarify this.

No functional change.
2017-08-18 02:02:35 -07:00
IIvec 01d97521fd Time management simplification
STC (http://tests.stockfishchess.org/tests/view/598188a40ebc5916ff64a21b):
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 25363 W: 4658 L: 4545 D: 16160

LTC (http://tests.stockfishchess.org/tests/view/5981d59a0ebc5916ff64a229):
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 75356 W: 9690 L: 9640 D: 56026

40/10 TC (http://tests.stockfishchess.org/tests/view/5980c5780ebc5916ff64a1ed):
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 19377 W: 3650 L: 3526 D: 12201

15+0 TC (http://tests.stockfishchess.org/tests/view/5982cb730ebc5916ff64a25d):
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 5913 W: 1217 L: 1069 D: 3627

This time management handles base time and movestogo cases separatelly. One can test one case without affecting the other. Also, increment usage can be tested separately without (necessarily) affecting sudden death or x moves in y seconds performance.

On stable machines there are no time losses on 0.1+0.001 time control (tested on i7 + Windows 10 platform).

Bench 5608839
2017-08-17 14:42:22 -07:00
Marco Costalba d482e3a890 Fix involuntary conversions of ExtMove to Move
The trick is to create an ambiguity for the
compiler in case an unwanted conversion to
Move is attempted like in:

    ExtMove m1{Move(17),4}, m2{Move(4),17};

    std::cout << (m1 < m2) << std::endl; // 1
    std::cout << (m1 > m2) << std::endl; // 1(!)

This fixes issue #1204

No functional change.
2017-08-17 02:04:00 -07:00
Marco Costalba 9001f55147 Unify stats update()
Now that is a bit bigger makes sense to
unify some duplicated code.

No functional change.
2017-08-17 01:52:26 -07:00
lucasart ae6a4ebf1f Use int16_t in History values
Reduces memory footprint by ~1.2MB (per thread).

Strong pressure: small but mesurable gain
LLR: 2.96 (-2.94,2.94) [0.00,4.00]
Total: 258430 W: 46977 L: 45943 D: 165510

Low pressure: no regression
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 73542 W: 13058 L: 13026 D: 47458

Strong pressure + LTC: elo gain confirmed
LLR: 2.96 (-2.94,2.94) [0.00,4.00]
Total: 31489 W: 4532 L: 4295 D: 22662

Tested for crashing on overflow and after 70K
games at STC we have only 4 time losses,
possible candidate for an overflow.

No functional change.
2017-08-17 00:32:44 -07:00
Marco Costalba 232c50fed0 Fix incorrect StateInfo
We use Position::set() to set root position across
threads. But there are some StateInfo fields (previous,
pliesFromNull, capturedPiece) that cannot be deduced
from a fen string, so set() clears them and to not lose
the info we need to backup and later restore setupStates->back().
Note that setupStates is shared by threads but is accessed
in read-only mode.

This fixes regression introduced by df6cb446ea

Tested with 3 threads at STC:
LLR: 2.95 (-2.94,2.94) [-4.00,0.00]
Total: 14436 W: 2304 L: 2196 D: 9936

Bench: 5608839
2017-08-14 23:01:58 -07:00
Marco Costalba c3e964f35e Run clang-tidy 'modernize'
Some warnings after a run of:

$ clang-tidy-3.8 -checks='modernize-*' *.cpp syzygy/*.cpp -header-filter=.* -- -std=c++11

I have not fixed all suggestions, for instance I still prefer
to declare the type instead of a spread use of 'auto'. I also
perfer good old 'typedef' to the new 'using' form.

I have not fixed some warnings in the last functions of
syzygy code because those are still the original functions
and need to be completely rewritten anyhow.

Thanks to erbsenzaehler for the original idea.

No functional change.
2017-08-13 05:46:21 -07:00
Marco Costalba df6cb446ea Thread code reformat
Simplify out low level sync stuff (mutex
and friends) and avoid to use them directly
in many functions.

Also some renaming and better comment while
there.

No functional change.
2017-08-13 04:41:59 -07:00
Marco Costalba bdeda52efd Retire States global variable
And other small touches in uci.cpp

No functional change.
2017-08-12 23:54:48 -07:00
tthsqe12 5837228aa0 Fix the handling of opposite bishops in KXK endgame evaluation
The case of three or more bishops against a long king must look at all of the
bishops and not just the first two in the piece lists. This patch makes sure
that the position is treated as a win when there are bishops on opposite
colors. This functional change is very small because bench remains the same.

LLR: 2.95 (-2.94,2.94) [-4.00,0.00]
Total: 24249 W: 4349 L: 4275 D: 15625
http://tests.stockfishchess.org/tests/view/598186530ebc5916ff64a218

Bench: 5608839
2017-08-12 02:47:11 -07:00
Joost VandeVondele 2783203428 Simplify finished search in ponder/infinite mode.
In this rare case (e.g. go infinite on a stalemate),
just spin till ponderhit/stop comes.

The Thread::wait() is a renmant of the old YBWC
code, today with lazy SMP, threads don't need to
wait when outside of their idle loop.

No functional change.
2017-08-10 22:42:52 -07:00
Marco Costalba 66c5eaebd8 Re-apply the fix for Limits::ponder race
But this time correctly set Threads.ponder

We avoid using 'limits' for passing pondering
flag because we don't want to have 2 ponder
variables in search scope: Search::Limits.ponder
and Threads.ponder. This would be confusing also
because limits.ponder is set at the beginning of
the search and never changes, instead Threads.ponder
can change value asynchronously during search.

No functional change.
2017-08-10 12:47:31 -07:00
Marco Costalba 44236f4ed9 Revert "Fix a race on Limits::ponder"
This reverts commit 5410424e3d.

After the commit pondering is broken, so revert for now. I will
resubmit with a proper fix.

The issue is mine, Joost original code is correct.

No functional change.
2017-08-10 10:59:38 -07:00
Joost VandeVondele 5410424e3d Fix a race on Limits::ponder
Limits::ponder was used as a signal between uci and search threads,
but is not an atomic variable, leading to the following race as
flagged by a sanitized binary.

Expect input:
```
 spawn  ./stockfish
 send "uci\n"
 expect "uciok"
 send "setoption name Ponder value true\n"
 send "go wtime 4000 btime 4000\n"
 expect "bestmove"
 send "position startpos e2e4 d7d5\n"
 send "go wtime 4000 btime 4000 ponder\n"
 sleep 0.01
 send "ponderhit\n"
 expect "bestmove"
 send "quit\n"
 expect eof
```

Race:
```
WARNING: ThreadSanitizer: data race (pid=7191)
  Read of size 4 at 0x0000005c2260 by thread T1:

  Previous write of size 4 at 0x0000005c2260 by main thread:

  Location is global 'Search::Limits' of size 88 at 0x0000005c2220 (stockfish+0x0000005c2260)
```

The reason of teh race is that ponder is not just set in UCI go()
assignment but also is signaled by an async ponderhit in uci.cpp:

      else if (token == "ponderhit")
          Search::Limits.ponder = 0; // Switch to normal search

The fix is to add an atomic bool to the threads structure to
signal the ponder status, letting Search::Limits to reflect just
what was passed to 'go'.

No functional change.
2017-08-10 10:46:46 -07:00
Marco Costalba 750dfa0521 Fix some races and clarify the code
Better split code that should be run at
startup from code run at ucinewgame. Also
fix several races when 'bench', 'perft' and
'ucinewgame' are sent just after 'bestomve'
from the engine threads are still running.

Also use a specific UI thread instead of
main thread when setting up the Position
object used by UI uci loop. This fixes a
race when sending 'eval' command while searching.

We accept a race on 'setoption' to allow the
GUI to change an option while engine is searching
withouth stalling the pipe. Note that changing an
option while searchingg is anyhow not mandated by
UCI protocol.

No functional change.
2017-08-10 10:19:56 -07:00
AndyGrant dbc984d9f8 Make variable naming consistent
moved_piece is the only variable in search not using camel case
2017-08-10 10:04:30 -07:00
Joost VandeVondele f731bcadb7 Unify scoring functions in MovePicker
No functional change.
2017-08-10 02:06:21 -07:00
Joost VandeVondele b40e45c1cc Remove Stack/thread dependence in movepick
as a lower level routine, movepicker should not depend on the
search stack or the thread class, removing a circular dependency.
Instead of copying the search stack into the movepicker object,
as well as accessing the thread class for one of the histories,
pass the required fields explicitly to the constructor (removing
the need for thread.h and implicitly search.h in movepick.cpp).
The signature is thus longer, but more explicit:

Also some renaming of histories structures while there.

passed STC [-3,1], suggesting a small elo impact:

LLR: 3.13 (-2.94,2.94) [-3.00,1.00]
Total: 381053 W: 68071 L: 68551 D: 244431
elo =   -0.438 +-    0.660 LOS:    9.7%

No functional change.
2017-08-06 01:45:54 -07:00
snicolet 53c2d9df5e Tweak connected pawns seed[] array values
Raise a little bit the values in the connected pawns seed[] array.

STC:
LLR: 2.96 (-2.94,2.94) [0.00,4.00]
Total: 99033 W: 17939 L: 17448 D: 63646
http://tests.stockfishchess.org/tests/view/597355630ebc5916ff649e3e

LTC:
LLR: 2.95 (-2.94,2.94) [0.00,4.00]
Total: 48044 W: 6371 L: 6099 D: 35574
http://tests.stockfishchess.org/tests/view/597596610ebc5916ff649eba

Bench: 5608839

Closes #1182
2017-08-01 18:41:29 -07:00
Rocky640 b24bd762b2 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 18:37:54 -07:00
VoyagerOne 722e1e0da6 Remove redundant if-statements
No functional change

Closes #1173
2017-07-27 02:14:18 -07:00
mstembera 973ede008a Tuned PSQT using a custom tuner.
bench: 5878420

Closes #1177
2017-07-23 17:35:44 -07:00
VoyagerOne a6ae2d3a31 Simplify aspiration window
Don't modify alpha window on fail-high

Bench: 5875983

Closes #1172
2017-07-23 17:25:23 -07:00
Joost VandeVondele 272e4d1ac7 Faster travis checks
in the last month a couple of timeouts have been seen in travis valgrind testing, leading to undesired false positives. The precise cause of this is unclear: a normal valgrind instrumented run is about 6min, the timeout is 10min. Either there are rare hangs (not reproduced locally), or maybe the actual runtime fluctuates on the travis infrastructure (which uses VMs on AWS as far as I know). This patch leads to roughly a 2x speedup of the instrumented testing by reducing the depth from 10 to 9. If timeouts persist, it needs further analysis.

No functional change.

Closes #1171
2017-07-23 17:23:14 -07:00
Marco Costalba e551afbab7 Move game_phase() to material.cpp
For some reason, although game phase is used
only in material, it is computed in Position.

Move computation to material, where it belongs,
and remove the useless call chain.

No functional change.
2017-07-15 07:28:38 +02:00
Joona Kiiski d31f068312 Revert "Remove questionable gcc flags from profile-build"
This reverts commit 0371a8f8c4.
2017-07-13 16:36:27 -07:00
joergoster 377d77dbe9 Provide selective search depth info for each pv move
No functional change

Closes #1166
2017-07-13 16:30:03 -07:00
Joost VandeVondele 36a93d90f7 Move stop signal to Threads
Instead of having Signals in the search namespace,
make the stop variables part of the Threads structure.
This moves more of the shared (atomic) variables towards
the thread-related structures, making their role more clear.

No functional change

Closes #1149
2017-07-13 16:08:37 -07:00
Joona Kiiski 0371a8f8c4 Remove questionable gcc flags from profile-build
Optimization options for official stockfish should be
consistent, easy, future proof and simple.

We don't want to optimize for any specific version of gcc

No functional change

Closes #1165
2017-07-08 14:20:46 -07:00
GuardianRM c8e5384c3a Queen vs. Minors imbalance
Addition of correction values in case of Imbalance of queens,
depending on the number of light pieces on the side without a queen.

Passed patch:

STC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 29036 W: 5379 L: 5130 D: 18527

LTC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 13680 W: 1836 L: 1674 D: 10170

Bench: 6258930

Closes #1155
2017-07-08 14:14:14 -07:00
Marco Costalba 802fca6fdd Don't uselessy share rootDepth
It is not needed becuase the only case is a real special
one (bench on depth with many threads) and can be easily
rewritten to avoid sharing rootDepth.

Verified with ThreadSanitizer.

No functional change.

Closes #1159
2017-07-02 22:06:47 -07:00
Marco Costalba 01b6cdb76b Fix some warnings with clang static analyzer
Only one remains (also in tbprobe.cpp), but is bougus.

As a side note, tbprobe.cpp is almost clean, only the last 3
functions probe_wdl(), root_probe() and root_probe_wdl()
are still the original ones and are quite hacky.

Somewhere in the future we will reformat also the last 3
ones. The reason why has not been done before it is because
these functions are really wrong by design and should be
rewritten entirely, not only reformatted.

No functional change.

Closes #1160
2017-07-02 22:02:11 -07:00
Marco Costalba c0cb713a00 Indentation fix in index()
No functional change.

Closes #1158
2017-07-02 22:00:29 -07:00
Alain SAVARD 6d24ef8585 Tidy up
No functional change

Closes #1148
2017-07-02 21:53:45 -07:00
mstembera 69eb391cd7 Magic::index()
Make magic_index() a member of Magic since it uses all it's members
and keep us from having to pass the function pointer around to
init_magics().

No functional change

Closes #1146
2017-06-28 17:11:17 -07:00
Joost VandeVondele 7e897a64f2 Remove race suppression.
Pull #1134 fixed another race, so that can be removed from the thread sanitizer suppressions.

No functional change.

Closes #1150
2017-06-28 17:06:52 -07:00
Marco Costalba 05513a6641 Only main thread checks time
The main change of the patch is that now time check
is done only by main thread. In the past, before lazy
SMP, we needed all the threds to check for available
time because main thread could have been blocked on
a split point, now this is no more the case and main
thread can do the job alone, greatly simplifying the logic.

Verified for regression testing on STC with 7 threads:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 11895 W: 1741 L: 1608 D: 8546

No functional change.

Closes #1152
2017-06-28 17:03:35 -07:00
Marco Costalba fa1e3427bd Simplify pos_is_ok()
Now we don't need anymore the tricky pointer to
show the failed test. Added some few tests too.

Also small rename in see_ge() while there.

No functional change

Closes #1151
2017-06-28 16:54:59 -07:00
VoyagerOne 77342126d8 Increase reduction if tt-move is a capture
The idea is that chances are the tt-move is best and will be difficult to raise alpha when playing a quiet move.

STC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 7582 W: 1415 L: 1259 D: 4908

LTC:
LLR: 2.97 (-2.94,2.94) [0.00,5.00]
Total: 59553 W: 7885 L: 7573 D: 44095

Bench: 5725676

Closes #1147
2017-06-21 14:06:05 -07:00
snicolet 612d93234b Improve readability of evaluation functions
This patch puts the evaluation helper functions inside EvalInfo struct, which simplifies a bit their signature and (most importantly, IMHO) makes their C++ code much cleaner and simpler to read (by removing the "ei." qualifiers all around in evaluate.cpp).

Also rename the EvalInfo struct into Evaluation class to get a natural invocation v = Evaluation(p).value() to evaluation position p.

The downside is an increase of 20 lines in evaluate.cpp (for the prototypes of the helper functions). The upsides are better readability and a speed-up of 0.6% (by generating all the helpers for the NO_TRACE case together, which helps the instruction cache).

No functional change

Closes #1135
2017-06-21 14:01:59 -07:00
VoyagerOne 0149a4c3d6 Update Top CPU - Bench: 6599721
Closes #1145
2017-06-21 13:47:10 -07:00
Joona Kiiski 336901fdb0 Revert "Prefetch earlier in qsearch()"
This reverts commit b73016bb41.

No functional change

Closes #1144
2017-06-21 13:45:03 -07:00
Joost VandeVondele 3cb0200459 Fix four data races.
the nodes, tbHits, rootDepth and lastInfoTime variables are read by multiple threads, but not declared atomic, leading to data races as found by -fsanitize=thread. This patch fixes this issue. It is based on top of the CI-threading branch (PR #1129), and should fix the corresponding CI error messages.

The patch passed an STC check for no regression:

http://tests.stockfishchess.org/tests/view/5925d5590ebc59035df34b9f
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 169597 W: 29938 L: 30066 D: 109593

Whereas rootDepth and lastInfoTime are not performance critical, nodes and tbHits are. Indeed, an earlier version using relaxed atomic updates on the latter two variables failed STC testing (http://tests.stockfishchess.org/tests/view/592001700ebc59035df34924), which can be shown to be due to x86-32 (http://tests.stockfishchess.org/tests/view/592330ac0ebc59035df34a89). Indeed, the latter have no instruction to atomically update a 64bit variable. The proposed solution thus uses a variable in Position that is accessed only by one thread, which is copied every few thousand nodes to the shared variable in Thread.

No functional change.

Closes #1130
Closes #1129
2017-06-21 13:37:58 -07:00
Alain SAVARD 2c237da546 Misc coding style fixes
a few comment and blank fixes.

No functional change

Closes #1141
2017-06-16 19:55:30 -07:00
snicolet b73016bb41 Prefetch earlier in qsearch()
Closes #1139
2017-06-16 19:52:38 -07:00
Marco Costalba 27ba611a3d Better naming in endgame code
And small clean-up of magic bitboards code.

No functional change.

Closes #1138
2017-06-16 19:33:44 -07:00
Brian Sheppard f907d5b7d9 Move depth calculation in probCut
The change passed an STC regression:

LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 59350 W: 10793 L: 10738 D: 37819

I verified that there was no change in performance on my machine, but of course YMMV:

Results for 40 tests for each version:

                Base      Test      Diff
        Mean    2014338   2016121   -1783
        StDev   62655     63441     3860

p-value: 0.678
speedup: 0.001

No functional change.

Closes #1137
2017-06-16 19:30:19 -07:00
Joost VandeVondele ebc563059c Call TT.new_search() earlier.
TT.new_search() was being called by mainThread in Thread::search(). However, mainThread is the last to start searching, and helper threads could reach a measured rootDepth 10 (on 64 cores) before mainThread increments the TT generation. Fixed by moving the call to MaintThread::search() before helper threads start searching.

No functional change.

Closes #1134
2017-06-16 19:20:01 -07:00
mstembera 659990b43f Reordering magic data
Gather all magic relevant data into a struct.

This changes memory layout putting everything necessary for processing a single square
in the same memory location thus speeding up access.

Original patch by @snicolet

No functional change.

Closes #1127
Closes #1128
2017-06-06 10:22:12 -07:00
atumanian 6d89d0b64a Don't score as an immediate draw 2-fold repetitions of the root position
In the current version a search stops when the current position is the same as
any position earlier in the search stack,
including the root position but excluding positions before the root.
The new version makes an exception for repeating the root position.

This gives correct scores for moves in the MultiPV > 1 mode.

Fixes #948 (see it for the detailed description of the bug).

LTC: http://tests.stockfishchess.org/tests/view/587910bc0ebc5915193f754b
ELO: 0.38 +-1.7 (95%) LOS: 66.8%
Total: 40000 W: 5166 L: 5122 D: 29712

STC: http://tests.stockfishchess.org/tests/view/5922e6230ebc59035df34a50
LLR: 2.94 (-2.94,2.94) [-3.00,1.00]
Total: 94622 W: 17059 L: 17064 D: 60499

 LTC: http://tests.stockfishchess.org/tests/view/59273a000ebc59035df34c03
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 61259 W: 7965 L: 7897 D: 45397

Bench: 6599721

Closes #1126
2017-06-06 10:15:13 -07:00
Joost VandeVondele 1781439fc2 use auto& for histories
No functional change.

Closes #1113
2017-06-06 09:56:13 -07:00
Marco Costalba ecd3218b6b History code rewrite (#1122)
Rearrange and rename all history heuristic code. Naming
is now based on chessprogramming.wikispaces.com conventions
and the relations among the various heuristics are now more
clear and consistent.

No functional change.
2017-05-26 08:42:50 +02:00
Nathan Rugg 24df0f72c0 Changed spelling back to "Bishops" in eval output
No functional change.

Closes #1124
2017-05-23 20:27:30 -07:00
VoyagerOne 1d31065e1d Evasion Pruning Tweak
Use moveCount to decide when to prune for evasion pruning

STC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 24476 W: 4518 L: 4289 D: 15669

LTC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 18362 W: 2476 L: 2298 D: 13588

Bench: 6469989

Closes #1120
2017-05-21 18:27:57 -07:00
snicolet c216dcbe7b Do check analysis later in the game
The previous patch has added a fraction of the king danger score to the
endgame score of the tapered eval, so it seems natural to perform the
king danger computation later in the endgame.

With this patch we extend the limit of such check analysis down to the
material of Rook+Knight, when we have at least two pieces attacking the
opponent king zone.

Passed STC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 7446 W: 1409 L: 1253 D: 4784
http://tests.stockfishchess.org/tests/view/591c097c0ebc59035df3477c

and LTC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 14234 W: 1946 L: 1781 D: 10507
http://tests.stockfishchess.org/tests/view/591c24f10ebc59035df3478c

Bench: 5975183

Closes #1121
2017-05-17 18:24:43 -07:00
snicolet cf893bcded Use a fraction of king danger in endgame score
When SF has an attack on the opponent king in one flank, the huge
midgame -> endgame gradient of the tapered eval prevents us to properly
evaluate neutral exchanges on the other flank as the current king
danger score is a pure midgame term. This may affect SF's ability to
switch to defense in some positions. We add a small contribution
of the king danger to the endgame score to limit this
effect.

Again suggested in the following forum thread:
https://groups.google.com/forum/?fromgroups=#!topic/fishcooking/xrUCQ7b0ObE

Passed STC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 12719 W: 2371 L: 2192 D: 8156
http://tests.stockfishchess.org/tests/view/5919761a0ebc59035df3468f

And LTC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 31293 W: 4194 L: 3974 D: 23125
http://tests.stockfishchess.org/tests/view/591980450ebc59035df34695

Bench: 5961548

Closes #1118
2017-05-17 18:19:47 -07:00
Joost VandeVondele 732aa34e3d Fix memory access in Search::clear()
Fixes a bug in Search::clear, where the filling of CounterMoveStats&, overwrote (currently presumably unused) memory because sizeof(cm) returns the size in bytes, whereas elements was needed.

No functional change

Closes #1119
2017-05-17 18:15:01 -07:00
snicolet 862934d7ae Limit king ring to eight squares
In current master the size of the king ring varies abruptly from eight
squares when the king is in g8, to 12 squares when it is in g7. Because
the king ring is used for estimating attack strength, this may lead to
an overestimation of king danger in some positions. This patch limits
the king ring to eight squares in all cases.

 Inspired by the following forum thread:
https://groups.google.com/forum/?fromgroups=#!topic/fishcooking/xrUCQ7b0ObE

Passed STC:
LLR: 2.97 (-2.94,2.94) [0.00,5.00]
Total: 9244 W: 1777 L: 1611 D: 5856

and LTC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 87121 W: 11765 L: 11358 D: 63998

Bench: 6121121

Closes #1115
2017-05-15 19:28:37 -07:00
Joost VandeVondele 7edd1f7ccd Execute an implied ucinewgame at startup
execute an implied ucinewgame upon entering the UCI::loop,
to make sure that searches starting with and without an (optional) ucinewgame
command yield the same search.

This is needed now that seach::clear() initializes tables to non-zero default values.

No functional change

Closes #1101
Closes #1104
2017-05-15 18:54:13 -07:00
Marco Costalba 0c1f119069 Default argument for see_ge()
No functional change.

Closes #1111
2017-05-10 18:20:45 +02:00
Joost VandeVondele 99d914985f Remove int to int conversion, unused include.
No functional change.

Closes #1112
2017-05-09 18:36:32 -07:00
FauziAkram 6b4959e3e0 Linear Protector bonus by distance
Replacing the old Protector table with a simple linear formula which takes into account a different slope for each different piece type.

The idea of this simplification of Protector is originated by Alain (Rocky)

STC: LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 70382 W: 12859 L: 12823 D: 44700

LTC: LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 61554 W: 8098 L: 8031 D: 45425

Bench: 6107863

Closes #1099
2017-05-07 21:11:51 -07:00
IIvec ae97941628 King safety and rook mobility parameters tweak
STC:
LLR: 2.95 (-2.94,2.94) [0.00,4.00]
Total: 19280 W: 3595 L: 3373 D: 12312

LTC:
LLR: 2.95 (-2.94,2.94) [0.00,4.00]
Total: 221405 W: 28940 L: 28220 D: 164245

Bench: 6506664

Closes #1105
2017-05-07 20:57:29 -07:00
Stefan Geschwentner 69ec09bd4b Bonus for pawn scrifice which create passed pawn
STC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 16752 W: 3141 L: 2944 D: 10667

LTC:
LLR: 3.34 (-2.94,2.94) [0.00,5.00]
Total: 33928 W: 4544 L: 4300 D: 25084

Bench: 5639223

Closes #1092
2017-05-07 20:51:52 -07:00
Marco Costalba 25296547d0 Move Pieces[] out of global visibility
It is an helper array used only in position.cpp

Also small code tidy up while there.

No functional change.

Closes #1106
2017-05-07 20:20:02 -07:00
mstembera 321a27fbe3 Avoid *begin always being included in the sorted list regardless of its value.
This was a minor criticism by @zamar in the original pull request
https://github.com/official-stockfish/Stockfish/pull/1065
necessitating a comment explanation.

No functional change.

Closes #1091
2017-05-07 20:15:56 -07:00
joergoster 8b15961349 Fix multiPV issue #502
In general, this patch handles the cases where we don't have a valid score for each PV line in a multiPV search. This can happen if the search has been stopped in an unfortunate moment while still in the aspiration loop. The patch consists of two parts.

Part 1: The new PVIdx was already part of the k-best pv's in the last iteration, and we therefore have a valid pv and score to output from the last iteration. This is taken care of with:

      bool updated = (i <= PVIdx && rootMoves[i].score != -VALUE_INFINITE);

Case 2: The new PVIdx was NOT part of the k-best pv's in the last iteration, and we have no valid pv and score to output. Not from the current nor from the previous iteration. To avoid this, we are now also considering the previous score when sorting, so that the PV lines with no actual but with a valid previous score are pushed up again, and the previous score can be displayed.

  bool operator<(const RootMove& m) const {
    return m.score != score ? m.score < score : m.previousScore < previousScore; } // Descending sort

I also added an assertion in UCI::value() to possibly catch similar issues earlier.

No functional change.

Closes #502
Closes #1074
2017-05-03 19:46:40 -07:00
Joost VandeVondele e9f26cccdd gcc 7 port
Testing the release candidate revealed only one minor issue, namely a new warning -Wimplicit-fallthrough (part of -Wextra) triggers in the movepicker. This can be silenced by adding a comment, and once we move to c++17 by adding a standard annotation [[fallthrough]];.

No functional change.

Closes #1090
2017-04-30 08:43:43 -07:00
VoyagerOne a18c2c2c3f Don't do InCheck Pruning at the root of QS
STC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 34603 W: 6441 L: 6167 D: 21995

LTC:
LLR: 2.97 (-2.94,2.94) [0.00,5.00]
Total: 24474 W: 3274 L: 3076 D: 18124

Bench: 5934421

Closes #1089
2017-04-28 20:40:45 -07:00
Rocky640 b948b037a5 Remove cap in kingDanger initialization
Passed STC
http://tests.stockfishchess.org/tests/view/58fd53be0ebc59035df33eb5
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 52048 W: 9397 L: 9329 D: 33322

Passed LTC
http://tests.stockfishchess.org/tests/view/58ff9e0a0ebc59035df33f5c
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 35382 W: 4650 L: 4549 D: 26183

Bench: 5872717

Closes #1087
2017-04-28 20:38:03 -07:00
Marco Costalba e06a117d5e Retire the misdesigned StepAttacks[] array.
StepAttacks[] is misdesigned, the color dependance is specific
to pawns, and trying to generalise to king and knights, proves
neither useful nor convinient in practice.

So this patch reformats the code with the following changes:

- Use PieceType instead of Piece in attacks_() functions

- Use PseudoAttacks for KING and KNIGHT

- Rename StepAttacks[] into PawnAttacks[]

Original patch and idea from Alain Savard.

No functional change.

Closes #1086
2017-04-28 20:33:30 -07:00
Joost VandeVondele b1b19343cd Copy killers in the movepicker
ss->killers can change while the movepicker is active.
The reason ss->killers changes is related to the singular
extension search in the moves loop that calls search<>
recursively with ss instead of ss+1,
effectively using the same stack entry for caller and callee.
By making a copy of the killers,
the movepicker does the right thing nevertheless.

Tested as a bug fix

STC:
http://tests.stockfishchess.org/tests/view/58ff130f0ebc59035df33f37
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 70845 W: 12752 L: 12716 D: 45377

LTC:
http://tests.stockfishchess.org/tests/view/58ff48000ebc59035df33f3d
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 28368 W: 3730 L: 3619 D: 21019

Bench: 6465887

Closes #1085
2017-04-28 20:29:04 -07:00
snicolet 49a9d4cf99 Avoid misuse of StepAttacksBB for pawns
Make it explicit that first index of StepAttacksBB is a piece, not a piece type.

No functional change

Closes #1083
2017-04-25 17:57:49 -07:00
Joost VandeVondele d06a8d0c18 Zero unused constant
No functional change

Closes #1081
2017-04-25 17:21:36 -07:00
Marco Costalba b48439e906 Assorted code style issues
I have removed the check for

 pieceCount[PAWN] > FILE_NB

because totally useless.

No functional change.
2017-04-24 09:49:44 +02:00
Joost VandeVondele 6b9a22b40d Sort moves partially: linear depth dependence
STC: http://tests.stockfishchess.org/tests/view/58f98d260ebc59035df33d5e
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 58958 W: 10862 L: 10485 D: 37611

LTC: http://tests.stockfishchess.org/tests/view/58fa45d40ebc59035df33d86
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 18607 W: 2427 L: 2251 D: 13929

Bench: 6065528

Closes #1079
2017-04-23 08:37:55 -07:00
IIvec 0868de705d King safety parameters improved
STC:
LLR: 2.97 (-2.94,2.94) [0.00,4.00]
Total: 58648 W: 10883 L: 10524 D: 37241

LTC:
LLR: 2.95 (-2.94,2.94) [0.00,4.00]
Total: 52546 W: 7131 L: 6844 D: 38571

Bench 6121479

Closes #1078
2017-04-23 08:04:03 -07:00
Joost VandeVondele 9da3b44ddc Use int instead of Value for history related stats.
history related scores are not related to evaluation based scores.
For example, can easily exceed the range -VALUE_INFINITE,VALUE_INFINITE.
As such the current type is confusing, and a plain int is a better match.

tested for no regression:

STC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 43693 W: 7909 L: 7827 D: 27957

No functional change.

Closes #1070
2017-04-23 07:59:28 -07:00
Joost VandeVondele ced29248c9 simplify logic for history based pruning
STC
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 34255 W: 6292 L: 6194 D: 21769

LTC
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 89914 W: 11769 L: 11739 D: 66406

Bench: 6581936

Closes #1066
2017-04-20 11:28:11 -07:00
Joost VandeVondele 2d96e8fbe9 Partial insertion sort
the order of elements returned by std::partition is implementation defined (since not stable) and could depend on the version of libstdc++ linked.
As std::stable_partition was tested to be too slow (http://tests.stockfishchess.org/tests/view/585cdfd00ebc5903140c6082).
Instead combine partition with our custom implementation of insert_sort, which fixes this issue.
Implementation based on a patch by mstembera (http://tests.stockfishchess.org/tests/view/58d4d3460ebc59035df3315c), which suggests some benefit by itself.
Higher depth moves are all sorted (INT_MIN version), as in current master.

STC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 33116 W: 6161 L: 6061 D: 20894

LTC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 88703 W: 11572 L: 11540 D: 65591

Bench: 6256522

Closes #1058
Closes #1065
2017-04-20 11:19:01 -07:00
Stefano Cardanobile d4b9ee0f1d Update Readme.md
Update number of threads.

Closes #1072
2017-04-17 10:38:37 -07:00
Joost VandeVondele 57a3334322 Prefer std::find over a hand-coded loop
tested for no regression.

STC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 37378 W: 6649 L: 6556 D: 24173

No functional change.

Closes #1071
2017-04-17 09:25:27 -07:00
VoyagerOne 9d3ed9ed2e Move-Count Formula Tweak
STC:
LLR: 3.18 (-2.94,2.94) [0.00,4.00]
Total: 55004 W: 10289 L: 9930 D: 34785

LTC:
LLR: 2.96 (-2.94,2.94) [0.00,4.00]
Total: 48184 W: 6401 L: 6128 D: 35655

Bench: 5960754
2017-04-17 09:22:10 -07:00
Stefano80 06175c6055 Remove cap from space score contribution and increase bonus
STC
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 58462 W: 10615 L: 10558 D: 37289

LTC
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 65061 W: 8539 L: 8477 D: 48045

It is worth noting that an attempt to only increase the bonus passed STC but failed LTC, and
an attempt to remove the cap without increasing the bonus is still running at STC, but will probably fail after more than 100k.

Bench: 6188591

Closes #1063
2017-04-17 09:19:36 -07:00
Stéphane Nicolet 1454831220 Doubled and supported pawns
Do not give the doubled pawn penalty when the frontmost pawn is
supported, for instance f2-g2-g3

STC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 55927 W: 10418 L: 10052 D: 35457
http://tests.stockfishchess.org/tests/view/58eb9fc20ebc59035df33858

LTC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 32078 W: 4257 L: 4035 D: 23786
http://tests.stockfishchess.org/tests/view/58ec48420ebc59035df3388b

Bench: 5995472

Closes #1062
2017-04-16 06:22:48 -07:00
Stefano80 b258b4fee7 Remove minimum to contribution from king danger to score.
STC
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 24858 W: 4559 L: 4445 D: 15854

LTC
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 40789 W: 5338 L: 5244 D: 30207

Bench: 7027489

Closes #1059
2017-04-09 07:48:58 -07:00
joergoster 72a501c6fe Fix zugzwang pruning issues
By adding pos.non_pawn_material(pos.side_to_move()) as a precondition in step 13,
which is already in use in Futility Pruning (child node) and Null Move Pruning for similar reasons.

Pawn endgames, especially those with only 1 or 2 pawns, are simply heavily influenced by zugzwang situations.

Since we are using a bitbase for KPK endgames, I see no reason to accept buggy evals as shown in #760

Patch looks neutral at STC
LLR: 2.32 (-2.94,2.94) [-3.00,1.00]
Total: 79580 W: 10789 L: 10780 D: 58011

and LTC
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 27071 W: 3502 L: 3390 D: 20179

Bench: 6259071

Closes #1051
Closes #760
2017-04-07 17:15:00 -07:00
VoyagerOne 35b77b120e Standardize stat penalty
STC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 90631 W: 16325 L: 16323 D: 57983

LTC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 97679 W: 12779 L: 12759 D: 72141

Bench: 6340591

Closes #1053
2017-04-07 17:02:31 -07:00
VoyagerOne ebe021f6a5 Don't update TT at excluded move ply
STC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 38906 W: 7125 L: 6835 D: 24946

LTC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 28600 W: 3752 L: 3543 D: 21305

Bench:  6861050

Closes #1048
2017-04-02 20:32:54 -07:00
Daniel Dugovic 06eba14dc9 Add assertion for the maximum number of pawns
No functionl change

Closes #1039
2017-03-27 15:55:48 -07:00
Joost VandeVondele c5de4080db Introduce assert for stats update
Make sure updates to the stats are done in a stable way.

No functional change

Closes #1038
Closes #1037
2017-03-25 17:57:07 -07:00
Joost VandeVondele 3b7c1a17e4 Increase maximum number of threads
a single Xeon Phi can present itself as a single numa node with up to 288 threads (4 threads per hardware core).
Tested to work as expected with a Xeon Phi CPU 7230 up to 256 threads.

No functional change

Closes #1045
2017-03-25 10:35:17 -07:00
joergoster afe75571d8 Simplify ThreatBySafePawn scoring
Bench: 6197938

Closes #1047
2017-03-25 10:22:20 -07:00
VoyagerOne 30c583204f Singular extension and check extension tweak
If singular extension fails to trigger extension then don't consider check extension.

STC:
LLR: 2.96 (-2.94,2.94) [0.00,4.00]
Total: 69428 W: 12663 L: 12271 D: 44494

LTC:
LLR: 2.96 (-2.94,2.94) [0.00,4.00]
Total: 44023 W: 5875 L: 5612 D: 32536

Bench: 6170444

Closes #1043
2017-03-25 10:13:25 -07:00
VoyagerOne 352bd6f5aa Skip quiet moves based on moveCount pruning threshold and history stats
If we can moveCountPrune and next quiet move has negative stats,
then go directly to the next move stage (Bad_Captures).

Reduction formula is tweaked to compensate for the decrease in move count that is used in LMR.

STC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 6847 W: 1276 L: 1123 D: 4448

LTC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 48687 W: 6503 L: 6226 D: 35958

Bench: 5919519

Closes #1036
2017-03-18 15:44:49 -07:00
Joost VandeVondele c80d52c845 History stat bonus: Move condition to bonus calculation
about 0.5% speedup.

No functional change

Closes #1034
2017-03-17 14:46:47 -07:00
joergoster c076216a32 Pawns count imbalance table
Instead of having a continuous increasing bonus for our number of pawns when calculating imbalance, use a separate lookup array with tuned values.
Idea by GuardianRM.

STC
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 16155 W: 2980 L: 2787 D: 10388

LTC
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 100478 W: 13055 L: 12615 D: 74808

Bench: 6128779

Closes #1030
2017-03-17 14:41:08 -07:00
Marco Costalba a6d6a2c2fa Assorted code style fixes
No functional change

Closes #1029
2017-03-14 21:02:21 -07:00
mstembera d01b66ae8f Fix pawn entry prefetch
No functional change

Closes #1026
2017-03-14 20:56:26 -07:00
snicolet c3d2e6aba9 Helper functions to count material for both sides
Syntactic sugar: helper functions to count material or pieces for both sides.

No functional change

Closes #1025
2017-03-08 18:45:38 -08:00
Joost VandeVondele d490bb9973 Always have counterMoves associated
Simplifies away all associated checks, leading to a ~0.5% speedup.
The code now explicitly checks if moves are OK, rather than using nullptr checks.

Verified for no regression:

LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 32218 W: 5762 L: 5660 D: 20796

No functional change

Closes #1021
2017-03-08 18:35:23 -08:00
pb00068 cc76524c2e Further simplify skipping of plies with threads
No functional change

Closes #1020
2017-03-08 18:03:01 -08:00
VoyagerOne 3627348e2b Allow pruning advance pawn pushes if not near endgame
STC:
LLR: -2.95 (-2.94,2.94) [0.00,5.00]
Total: 101088 W: 18016 L: 17717 D: 65355

LTC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 61194 W: 8108 L: 7791 D: 45295

Bench: 5803228

Closes #1023
2017-03-05 18:58:06 -08:00
snicolet 728ce2195c Speed-up some arrays reading
This patch removes the empty rows at the beginning and at the end of
MobilityBonus[] and Protector[] arrays:

• reducing the size of MobilityBonus from 768 bytes to 512 bytes
• reducing the size of Protector from 1024 to 512 bytes

Also adds some comments and cleaner code for the arrays in pawns.cpp

No speed penalty (measured speed-up of 0.4%).

No functional change.

Closes #1018
2017-03-05 18:20:27 -08:00
Joost VandeVondele 1810c4d758 Simplify skipping of plies with helper threads
Replaces the HalfDensity array with an equivalent, compact implementation.
Includes suggestions by mcostalba & snicolet.

No functional change

Closes #1004
2017-02-26 16:41:58 -08:00
snicolet 8f7e032b8c Change definition of "weak" in threats calculation
By defining "strongly protected" as "protected by a pawn, or protected
by two pieces and not attacked by two enemy pieces".

Passed STC:
LLR: 2.97 (-2.94,2.94) [0.00,5.00]
Total: 17050 W: 3128 L: 2931 D: 10991

Passed LTC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 120995 W: 15852 L: 15343 D: 89800

Bench : 6269229

Closes #1016
2017-02-25 17:43:54 -08:00
mstembera f1e3dfea74 Reorder members of Material::Entry
This eliminates alignment padding and reduces size from 48 to 40 bytes.
This makes the material HashTable smaller and more cache friendly.

No functional change

Closes #1013
2017-02-23 21:33:03 -08:00
GuardianRM 9f48e1ec15 Pieces protecting king
Initial protective idea by Snicolet for knight, for other pieces too
Patch add penalties and bonuses for pieces, depending on the distance from the own king

STC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 21192 W: 3919 L: 3704 D: 13569

LTC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 26177 W: 3642 L: 3435 D: 19100

Bench : 6687377

Closes #1012
2017-02-23 21:26:59 -08:00
snicolet eefbe967c2 Keep pawns on both flanks
Positions with pawns on only one flank tend to be more drawish. We add
a term to the initiative bonus to help the attacking player keep pawns
on both flanks.

STC: yellowish run stopped after 257137 games
LLR: -0.92 (-2.94,2.94) [0.00,5.00]
Total: 257137 W: 46560 L: 45511 D: 165066

LTC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 15602 W: 2125 L: 1956 D: 11521

Bench : 6976310

Closes #1009
2017-02-19 14:27:03 -08:00
FauziAkram c243cd5f4a Variable tuning
A tuning patch which cover the following changes:

increase the importance of queen and rook mobility in endgame and
decrease it in mg, since if we use the heavy pieces too early in the game
we will just make opponent develop their pieces by threatening ours.

King Psqt:
1)King will be encouraged more to stay in the first ranks in the MG
2)and will be encouraged more to go to the middle of the board/last ranks in the EG

Bishop scale better in EG
Logical changes on various psqt tables
1/6 of the changes of the last tuning session on mobility tables

STC: LLR: 2.95 (-2.94,2.94) [0.00,4.00]
Total: 227879 W: 41240 L: 40313 D: 146326
LTC : LLR: 2.95 (-2.94,2.94) [0.00,4.00]
Total: 167047 W: 21871 L: 21291 D: 123885

Bench: 5695960

Closes #1008
2017-02-19 14:00:44 -08:00
VoyagerOne 05cf45f2d1 Razor Simplification
Remove code that restrict using tt-moves for razoring.

STC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 67442 W: 12039 L: 11997 D: 43406

LTC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 38541 W: 5044 L: 4947 D: 28550

Bench: 5667216

Closes #1002
2017-02-18 22:50:37 -08:00
torfranz faedcf08a8 Retire loose enemies bonus
STC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 44727 W: 7943 L: 7862 D: 28922

LTC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 148343 W: 19044 L: 19088 D: 110211

Bench: 5669076

Closes #1005
2017-02-14 21:26:08 -08:00
VoyagerOne 83fb4547f6 search(): Move nullValue variable into local scope
No functional change

Closes #1003
2017-02-14 21:22:58 -08:00
Joost VandeVondele 1e814e0ca0 Fix makefile: 32 bit builds without optimization.
Fixes failing build for

make ARCH=x86-32 clean && make ARCH=x86-32 optimize=no build

by passing -m32 also to the link step.

Extend travis testing accordingly.

No functional change.

Closes #999
2017-02-14 21:11:44 -08:00
torfranz e0d91f4c44 Retire small bonus in passed pawn evaluation
STC: http://tests.stockfishchess.org/tests/view/5899824d0ebc59099759f3ee
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 33370 W: 6061 L: 5961 D: 21348

LTC: http://tests.stockfishchess.org/tests/view/5899e3820ebc59099759f415
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 36206 W: 4664 L: 4563 D: 26979

Bench: 6072262

Closes #998
2017-02-10 16:52:34 -08:00
Joona Kiiski a753e20bd4 A small tweak in doEasyMove()
Time.elapsed() > Time.optimum() * 5 / 44
instaed of:
Time.elapsed() > Time.optimum() * 5 / 42

This was yellow on STC:
LLR: -2.96 (-2.94,2.94) [0.00,4.00]
Total: 156856 W: 28317 L: 27942 D: 100597

Passed on LTC:
LLR: 2.96 (-2.94,2.94) [0.00,4.00]
Total: 36909 W: 4926 L: 4682 D: 27301

Note: Patch was originally submitted by user GuardianRM.
However his repo was deleted before merge.

No functional change

Closes #995
2017-02-10 16:44:13 -08:00
Stefano80 5205d44f87 Simplify scale factor computation
Minor non-functional simplifications in computing the scale factor.

In my opinion, the code is now slightly more readable:

- remove one condition which can never be satisfied.
- immediately return instead of assigning the sf variable.

Tested for non-regression:

LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 62162 W: 11166 L: 11115 D: 39881

No functional change

Closes #992
2017-02-05 16:06:37 -08:00
VoyagerOne 0553b46829 Simplify Queen Mobility
STC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 85997 W: 15550 L: 15540 D: 54907

LTC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 25333 W: 3370 L: 3256 D: 18707

Bench: 6459194

Closes #991
2017-02-05 15:40:30 -08:00
Stéphane Nicolet ddecdc97d7 Simplify away QueenContactChecks
Changing the definition of safe checks to include
squares protected only by the king, but twice
attacked by the opponent.

STC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 8691 W: 1683 L: 1541 D: 5467
http://tests.stockfishchess.org/tests/view/588f53b50ebc5915193f7dc7

LTC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 31266 W: 4150 L: 4043 D: 23073
http://tests.stockfishchess.org/tests/view/588f68ab0ebc5915193f7dda

Bench : 5885815
2017-01-31 09:54:38 +01:00
VoyagerOne fa24cc25a4 Simplify TT penalty stat (#980)
STC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 20251 W: 3692 L: 3570 D: 12989

LTC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 16432 W: 2155 L: 2029 D: 12248

Bench: 5941174
2017-01-29 08:54:58 +01:00
VoyagerOne 5254a6040c Penalty for a quiet ttMove that fails low
Also the penalty/bonus function is misleading, we
should simply change it to stat_bonus(depth) for
bonus and -stat_bonus(depth+ ONE_PLY) for extra
penalty.

STC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 11656 W: 2183 L: 2008 D: 7465

LTC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 11152 W: 1531 L: 1377 D: 8244

Bench: 6101931
2017-01-28 09:32:07 +01:00
Stefan Geschwentner 471f7a1b5c Candidate passed pawns
Detect safe candidate passers.

STC: http://tests.stockfishchess.org/tests/view/5882395c0ebc5915193f78b3
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 53569 W: 9925 L: 9570 D: 34074

LTC: http://tests.stockfishchess.org/tests/view/5882b4fb0ebc5915193f78e2
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 77576 W: 10387 L: 10014 D: 57175

Bench: 5325829
2017-01-28 09:04:24 +01:00
pb00068 58c181de9a Simplify away pinnedPieces bitboard in EvalInfo (#975)
Results for 20 tests for each version (pgo-builds):

            Base      Test      Diff      
    Mean    2110519   2118116   -7597     
    StDev   8727      4906      10112     

p-value: 0,774
speedup: 0,004

Further verified for no regression:
http://tests.stockfishchess.org/tests/view/5885abd10ebc5915193f79e6
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 21786 W: 3959 L: 3840 D: 13987

No functional change
2017-01-28 08:43:54 +01:00
Alain SAVARD cf4a38e0cb Simplification of lazy threshold
Passed STC
http://tests.stockfishchess.org/tests/view/587846c10ebc5915193f74ec
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 217236 W: 39041 L: 39254 D: 138941

Passed LTC
http://tests.stockfishchess.org/tests/view/587e157a0ebc5915193f76e7
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 52396 W: 6883 L: 6804 D: 38709

This submitted version (using if (abs(mg + eg) > 1500) )
seems more logical than the following other green simplification (using if (abs(mg)>1500))
since it can happen than mg_value is > eg_value (about 20% of the time)
and the submitted version seems stronger at LTC

STC
http://tests.stockfishchess.org/tests/view/5879702d0ebc5915193f7585
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 39958 W: 7315 L: 7227 D: 25416

LTC
http://tests.stockfishchess.org/tests/view/5879af3e0ebc5915193f7592
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 204322 W: 26529 L: 26648 D: 151145

bench: 6406285
2017-01-21 10:47:54 +01:00
Alain SAVARD 9eed183489 Outpost array simplification
The ReachableOutpost values were almost exactly half the Outpost values.

Passed STC
http://tests.stockfishchess.org/tests/view/588020510ebc5915193f781e
LLR: 3.86 (-2.94,2.94) [-3.00,1.00]
Total: 119238 W: 21462 L: 21460 D: 76316

Passed LTC
http://tests.stockfishchess.org/tests/view/5880ae090ebc5915193f7843
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 23540 W: 3097 L: 2980 D: 17463

Curiously, using a division by 2, with slightly different values, did not passed
http://tests.stockfishchess.org/tests/view/587fece00ebc5915193f780a

bench: 5828283
2017-01-21 10:36:46 +01:00
Alain SAVARD 243a9f5484 Reformat eval_init()
Move more code into eval_init, removing some
clutter in the main routine.

Write eval_init only from "our" point of view
(do not init the attackedBy[Them] bitboards).

Add mobilityArea to the evalinfo

A few edits while being there

tested for non-regression at STC
http://tests.stockfishchess.org/tests/view/587fab230ebc5915193f77d9
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 39585 W: 7183 L: 7094 D: 25308

Non functional change.
2017-01-21 10:13:49 +01:00
Stéphane Nicolet 9f8f093fd6 Update some comments (#973)
Use somewhat more precise comments in a couple of places.

No functional change.
2017-01-17 14:50:03 +01:00
Stefano Cardanobile de02768af7 Introduce lazy evaluation
After we have taken into account all cheap evaluation
terms, we check whether the score exceeds a given threshold.
If this is the case, we return a scaled down evaluation.

STC:
LLR: 3.35 (-2.94,2.94) [0.00,5.00]
Total: 12575 W: 2316 L: 2122 D: 8137

LTC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 67480 W: 9016 L: 8677 D: 49787

Current version is the one rewritten by ceebo
further edited by me.

Bench: 5367704
2017-01-13 09:17:48 +01:00
loco-loco 99cd513264 Removing CM parameter from the Stats struct. (#970)
After the history simplifications, we are only using Value Stats for CounterMoveHistory table. Therefore the parameter CM is not necessary.

No functional change.
2017-01-12 08:46:46 +01:00
Stéphane Nicolet d2971f3fca Check for overflow in Score * int multiplication (#969)
Add asserts to check for overflow in Score * int multiplication.

There is no overflow in current master, but it would be easy to
create one as the scale of the current eval does not leave many
spare bits. For instance, adding the following unused variables
in master at the end of evaluate() (line 882 of evaluate.cpp)
overflows:

Score s1 = score * 4;  // no overflow
Score s2 = score * 5;  // overflow

Assertion failed: (eg_value(result) == (i * eg_value(s))),
function operator*, file ./types.h, line 336.

Same md5 checksum as current master for non debug compiles.

No functional change.
2017-01-11 18:11:17 +01:00
Rocky640 d40351243b StormDanger CleanUp (#964)
Order the enum and the array the same way they appear around line 250.
Makes it much easier to follow.

Add comments in the array definition and critical rows.
Use same terminology as elsewhere in pawns.cpp

No functional change.
2017-01-11 08:56:38 +01:00
Joost VandeVondele d8f683760c Adjust copyright headers to 2017 (#965)
No functional change.
2017-01-11 08:46:29 +01:00
Marco Costalba 332b5013b5 Travis: fix bench fetch in case of PR (#968)
When Travis tests a PR, a commit merge is created
but master branch is not updated, although HEAD is.

No functional change.
2017-01-11 08:44:06 +01:00
lucasart 34e47ca87d Rename FromTo -> History (#963)
Previously, we had duplicated History:

- one with (piece,to) called History
- one with (from,to) called FromTo

Now that we have only one, rename it to History, which is the generally accepted
name in the chess programming litterature for this technique.

Also correct some comments that had not been updated since the introduction of CMH.

No functional change.
2017-01-10 08:47:56 +01:00
lucasart e0504ab876 Remove HistoryStats
STC:
LLR: 3.44 (-2.94,2.94) [-3.00,1.00]
Total: 120831 W: 21572 L: 21594 D: 77665

LTC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 26565 W: 3519 L: 3406 D: 19640

bench 5920493
2017-01-09 15:50:12 +01:00
Marco Costalba d9dd520896 Fix previous patch for OS X (#961)
Use posix version of sed that is available on all
platforms.

No functional change.
2017-01-09 15:37:09 +01:00
Marco Costalba 394e9cd892 Trevis CI: use commit bench number as a reference
No functional change.
2017-01-09 12:51:28 +01:00
Joost VandeVondele ba15781be8 New shell scripts for testing, used for travis CI (#957)
Perform more complex verification and validation.

- signature.sh : extract and optionally compare Bench/Signature/Node count.
- perft.sh : verify perft counts for a number of positions.
- instrumented.sh : run a few commands or uci sequences through valgrind/sanitizer instrumented binaries.
- reprosearch.sh : verify reproducibility of search.

These script can be used from directly from the command line in the src directory.

Update travis script to use these shell scripts.

No functional change.
2017-01-09 10:30:57 +01:00
ElbertoOne d39ffbeea6 Simplified select best thread (#958)
Only select best thread if score is better and depth equal or larger.

STC (7 threads): http://tests.stockfishchess.org/tests/view/586a4d090ebc5903140c64b2
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 120297 W: 18652 L: 18682 D: 82963

LTC (7 threads): http://tests.stockfishchess.org/tests/view/586e31b30ebc5903140c663d
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 57187 W: 7035 L: 6959 D: 43193

bench: 4940355
2017-01-09 10:26:50 +01:00
Marco Costalba 3ab3e55bb5 Drop Stats c'tors
Now taht we correctly value-initialize Thread objects,
we don't need c'tors anymore because tables will be
zero-initialized by the compier when Thread object
is instanced.

Verified that we have no errors with Valgrind.

No functional change.
2017-01-07 10:14:39 +01:00
Joost VandeVondele 1c316c41bb Correctly zero-initialize MainThread
It can be used uninitialized in time management.
Fixes all valgrind errors on './stockfish go wtime 8000 btime 8000 winc 500 binc 500'

This is one (of the many) quirks of C++. There is a subtle difference between:

new Foo
new Foo()

The first statement calls the default constructor (that in case of a POD leaves data members
uninitialized), the second one performs a value-initialization (that in case of POD is
equivalent to a zero-initialization)

See:
http://stackoverflow.com/questions/620137/do-the-parentheses-after-the-type-name-make-a-difference-with-new
http://stackoverflow.com/questions/5116541/difference-between-creating-object-with-or-without

No functional change.
2017-01-07 10:02:43 +01:00
Joost VandeVondele 90b052462c Zero init fromToStats in constructor. (#953)
Extend commit fe99de to fromToStats, which fixes the last valgrind errors on 
a simple 'go depth 12' at startup.

No functional change.
2017-01-06 10:43:18 +01:00
pb00068 8b2c81d3ea Rejoin lines that belong to HalfDensity map (#952)
No functional change.
2017-01-05 09:00:41 +01:00
Marco Costalba fe99de20ff Correct zero-init of Thread data members
If not explicitly initialized in a class constructor,
then all data members are default-initialized when
the corresponing struct/class is instanced.

For array and built-in types (int, char, etc..)
default-initialization is a no-op and we need to
explicitly zero them.

No functional change.
2017-01-05 08:50:17 +01:00
Joost VandeVondele 6b16ebc825 Use consistent variable names for counterMoveStats (#949)
Unify naming in movepick and search, by adopting the latter convention (cmh,fmh,fmh2).

No functional change.
2017-01-02 09:36:43 +01:00
Stéphane Nicolet e3a8b8bcff Simplify unstoppable again (#950)
Assign a small bonus for our passed pawns when the opponent has no
pieces left.

STC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 51124 W: 9036 L: 8966 D: 33122

LTC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 114560 W: 14604 L: 14604 D: 85352

Bench: 4940355
2017-01-02 09:33:40 +01:00
Jonathan Calovski 1052ce74f6 Tweak best thread selection logic
STC 7 threads:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 26881 W: 4161 L: 3941 D: 18779
http://tests.stockfishchess.org/tests/view/58667a830ebc5903140c632f

LTC 7 threads:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 22988 W: 2767 L: 2583 D: 17638
http://tests.stockfishchess.org/tests/view/586722690ebc5903140c636d

bench: 5468995
2017-01-01 11:28:50 +01:00
lucasart e258c5a779 WDL: rename WDLCursedLoss into WDLBlessedLoss
Tested using syzygy bench method:

- 2016 random positions ranging between 3 and 10 pieces
- each searched using bench at depth=10

Same node count (and no speed regression).

No functional change.
2017-01-01 11:11:52 +01:00
Aram Tumanian b7b9d7c9c7 Don't clear EasyMove in search()
EasyMove is cleared after every iteration of the
search if the 3rd move in the PV of the main thread
changes from the previous iteration. Therefore,
clearing EasyMove during a search iteration may be
excessive. The tests show that this is indeed unnecessary.
In the new version the EasyMove variable is used only in
the Thread::search function.

STC
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 47719 W: 8438 L: 8362 D: 30919

LTC
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 122841 W: 15448 L: 15457 D: 91936

bench: 5468995
2017-01-01 11:04:24 +01:00
Sergei Antonov 881a9dfb0a Threefold repetition detection
Implement a threefold repetition detection. Below are the examples of
problems fixed by this change.

    Loosing move in a drawn position.
    position fen 8/k7/3p4/p2P1p2/P2P1P2/8/8/K7 w - - 0 1 moves a1a2 a7a8 a2a1
    The old code suggested a loosing move "bestmove a8a7", the new code suggests "bestmove a8b7" leading to a draw.

    Incorrect evaluation (happened in a real game in TCEC Season 9).
    position fen 4rbkr/1q3pp1/b3pn2/7p/1pN5/1P1BBP1P/P1R2QP1/3R2K1 w - - 5 31 moves e3d4 h8h6 d4e3
    The old code evaluated it as "cp 0", the new code evaluation is around "cp -50" which is adequate.

Brings 0.5-1 ELO gain. Passes [-3.00,1.00].

STC: http://tests.stockfishchess.org/tests/view/584ece040ebc5903140c5aea
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 47744 W: 8537 L: 8461 D: 30746

LTC: http://tests.stockfishchess.org/tests/view/584f134d0ebc5903140c5b37
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 36775 W: 4739 L: 4639 D: 27397

Patch has been rewritten into current form for simplification and
logic slightly changed so that return a draw score if the position
repeats once earlier but after or at the root, or repeats twice
strictly before the root. In its original form, repetition at root
was not returned as an immediate draw.

After retestimng testing both version with SPRT[-3, 1], both passed
succesfully, but this version was chosen becuase more natural. There is
an argument about MultiPV in which an extended draw at root may be sensible.
See discussion here:

   https://github.com/official-stockfish/Stockfish/pull/925

For documentation, current version passed both at STC and LTC:

STC
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 51562 W: 9314 L: 9245 D: 33003

LTC
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 115663 W: 14904 L: 14906 D: 85853

bench: 5468995
2017-01-01 10:56:46 +01:00
Alain SAVARD 43f6b33e50 Small eval cleanup and renaming
Non-functional changes

a) splitting the threat array to avoid using an enum
b) reorder the scores according to functions where they are used.
c) declarations in evaluate_pieces after the const(s) like elsewhere
d) more compact definitions of KingFlank,
now that we need it also for the PanwLessFlank penalty.
e) reuse CenterFiles in evaluate_space
f) move one line inside next popcount

No functional change.
2016-12-31 14:15:57 +01:00
lucasart ab4f498bbc Remove SafeCheck (#946)
It was a bit of a hack, without intrinsic value, but rather compensating for the
fact that checks were mistuned.

STC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 88308 W: 15553 L: 15545 D: 57210

LTC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 53115 W: 6741 L: 6662 D: 39712

bench 5468995
2016-12-31 13:52:42 +01:00
Jörg Oster 8765f9ce16 Further simplify unstoppable (#938)
By finally moving it into passed pawns eval.

Tested for no regression:
STC
LLR: 3.25 (-2.94,2.94) [-3.00,1.00]
Total: 57109 W: 10023 L: 9947 D: 37139

LTC
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 21511 W: 2800 L: 2680 D: 16031

Bench: 5255881
2016-12-25 10:44:56 +01:00
hxim 3728e833aa Fix psqt format and use smaller numbers in king psqt (#940)
Fix minus sign in pawn psqt and use smaller numbers in king psqt.

No functional change.
2016-12-25 10:40:17 +01:00
Joost VandeVondele af7412e58a Explicitly use alpha+1 for beta in NonPV search (#939)
Fixes the only exception, in razoring.

The code already does assert(PvNode || (alpha == beta - 1)), and it can be verified by studying the program flow that this is indeed the case, also for the modified line.

No functional change.
2016-12-25 10:34:48 +01:00
Joost VandeVondele 1ceaea701b Simplify threshold handling for probcut. (#936)
Just use greater equal as this is what see_ge does now.

passed STC
LLR: 2.94 (-2.94,2.94) [-3.00,1.00]
Total: 226506 W: 39755 L: 39978 D: 146773

passed LTC
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 138483 W: 17450 L: 17479 D: 103554

Bench: 5212921
2016-12-22 16:02:32 +01:00
Stefano Cardanobile f72b7dc99a piecesCount (#932)
All counts in search.cpp are of the form xxxCount. Conform piecesCnt to this unwritten rule.

No functional change.
2016-12-20 11:18:19 +01:00
Joost VandeVondele ee22b61f5e Use DEPTH_ZERO initializer for depth in qsearch (#931)
Simplifies the main search function.

No functional change.
2016-12-20 11:17:38 +01:00
VoyagerOne 8c61bbda54 Another simplification for SEE pruning
STC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 29310 W: 5225 L: 5118 D: 18967

LTC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 128454 W: 16424 L: 16442 D: 95588

Bench: 4556848
2016-12-17 08:37:58 +01:00
Stefan Geschwentner 847bc0e80f Simplify pruning
STC: http://tests.stockfishchess.org/tests/view/5842be140ebc5903140c5619
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 16014 W: 2839 L: 2710 D: 10465

LTC: http://tests.stockfishchess.org/tests/view/584316a50ebc5903140c5638
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 182360 W: 22830 L: 22914 D: 136616

Retested at LTC
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 45502 W: 5821 L: 5732 D: 33949

Bench: 4684146
2016-12-12 12:01:16 +01:00
Joost VandeVondele 1b62d413c1 Clean-up skipEarlyPruning (#921)
make skipEarlyPruning a search argument instead of managing this by hand.

Verified for no regression at STC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 96754 W: 17089 L: 17095 D: 62570

No functional change.
2016-12-11 20:05:25 +01:00
Jonathan Calovski 589049a0e5 Simplify unstoppable condition
STC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 86389 W: 15165 L: 15153 D: 56071

LTC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 98143 W: 12311 L: 12288 D: 73544

Bench: 5437987
2016-12-11 19:57:02 +01:00
Joost VandeVondele a47bbca0ea Refactor bonus and penalty calculation (#917)
* Refactor bonus and penalty calculation

Compute common terms in a helper function.

No functional change.

* Further refactoring

Remove some parenthesis that are now useless.
Define prevSq once, use repeatedly.

No functional change.

bench: 5884767 (bench of previous patch is wrong)
2016-12-05 18:58:12 +01:00
Stéphane Nicolet 0d33466bcd Pawn flank attacks
This patch tweaks some pawn values to favor flank attacks.

The first part of the patch increases the midgame psqt values of external pawns to launch more attacks (credits to user GuardianRM for this idea), while the second part increases the endgame connection values for pawns on upper ranks.

Passed STC:
LLR: 2.95 (-2.94,2.94) [0.00,4.00]
Total: 34997 W: 6328 L: 6055 D: 22614

and LTC:
LLR: 2.96 (-2.94,2.94) [0.00,4.00]
Total: 13844 W: 1832 L: 1650 D: 10362

Bench: 5884767
2016-12-05 18:49:07 +01:00
ElbertoOne 46d066b041 Remove piece condition in decrease lmr reduction check
STC: http://tests.stockfishchess.org/tests/view/584154780ebc5903140c55cf
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 40866 W: 7251 L: 7164 D: 26451

LTC: http://tests.stockfishchess.org/tests/view/5841e6e50ebc5903140c5605
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 62413 W: 7948 L: 7881 D: 46584

Bench: 5807913
2016-12-04 09:28:55 +01:00
Andrey Neporada bf8b45fe63 Help GCC to optimize msb() to single instruction
GCC compiles builtin_clzll to “63 ^ BSR”. BSR is processor instruction "Bit Scan Reverse".
So old msb() function is basically 63 - 63 ^ BSR.
Unfortunately, GCC fails to simplify this expression.

Old function compiles to

    bsrq    %rdi, %rdi
    movl    $63, %eax
    xorq    $63, %rdi
    subl    %edi, %eax
    ret

New function compiles to

    bsrq    %rdi, %rax
    ret

BTW, Clang compiles both function to the same (optimal) code.

No functional change.
2016-12-03 09:37:07 +01:00
goodkov e70da0d2eb Simplify pruning rule
STC: http://tests.stockfishchess.org/tests/view/583df86d0ebc5903140c5481
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 43283 W: 7761 L: 7678 D: 27844

LTC: http://tests.stockfishchess.org/tests/view/583f42670ebc5903140c5525
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 56587 W: 7232 L: 7157 D: 42198

bench: 5084980
2016-12-02 09:04:45 +01:00
Joost VandeVondele 1e76ba7cec WeakQueen Parameter tweak
New tuned values.

passed STC
http://tests.stockfishchess.org/tests/view/5834573c0ebc5903140c507b
LLR: 3.16 (-2.94,2.94) [0.00,4.00]
Total: 157415 W: 27917 L: 27227 D: 102271

passed LTC
http://tests.stockfishchess.org/tests/view/58388d2b0ebc5903140c523b
LLR: 2.95 (-2.94,2.94) [0.00,4.00]
Total: 95405 W: 12350 L: 11959 D: 71096

Bench: 4912054
2016-12-01 14:55:00 +01:00
ElbertoOne 535435b7fc TrappedRook simplification
Just remove rank checks for rook and king for TrappedRook evaluation.

STC: http://tests.stockfishchess.org/tests/view/5833fdfc0ebc5903140c5050
LLR: 3.03 (-2.94,2.94) [-3.00,1.00]
Total: 34474 W: 6088 L: 5986 D: 22400

LTC: http://tests.stockfishchess.org/tests/view/58392f3f0ebc5903140c5276
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 48358 W: 6221 L: 6136 D: 36001

bench: 5536128
2016-11-27 17:42:20 +01:00
theo77186 7a3844e6ef Fix PGO build with GCC (#904) 2016-11-27 14:43:52 +01:00
Michael Byrne fbb2ffacfd Fix PGO Build for clang
This fixes https://github.com/official-stockfish/Stockfish/issues/167.

Additional improvments by Joost VandeVondele.
2016-11-27 10:03:52 +01:00
joergoster 8f30d233f8 Fix trace in case of space evaluation
We only compute space eval during the opening/early midgame.
Apply the same logic for DoTrace.

No functional change.
2016-11-27 09:28:32 +01:00
Marco Costalba ec83e8a72c Fix regression: print const position
Fix a regression introduced with new TB code.

No functional change.
2016-11-27 09:11:56 +01:00
mbootsector e7289465b9 Rank based threats
STC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 19404 W: 3581 L: 3374 D: 12449

LTC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 16204 W: 2194 L: 2023 D: 11987

Bench: 5757843
2016-11-27 09:05:57 +01:00
Joost VandeVondele 8ceb1ff53b Fix undefined behavior
This fixes #892. Undefined behavior as seen with
clang -fsanitize=undefined.

No functional change.
2016-11-26 16:49:59 +01:00
Marco Costalba 2ec626ddae Fix compile under Windows XP
The needed Windows API for processor groups could be missed from old Windows
versions, so instead of calling them directly (forcing the linker to resolve
the calls at compile time), try to load them at runtime. To do this we need
first to define the corresponding function pointers.

Also don't interfere with running fishtest on numa hardware with Windows.
Avoid all stockfish one-threaded processes will run on the same node

No functional change.
2016-11-26 07:04:17 +01:00
Aram Tumanian 9eccba7761 Fix the pawn hash failure when the pawn key is 0
This patch fixed bugs #859 and #882.
At initialization we generate a new random key (Zobrist::noPawns).
It's added to the pawn key of all positions, so that the pawn key
of a pawnless position is no longer 0.

STC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 21307 W: 3738 L: 3618 D: 13951

LTC:
LLR: 2.94 (-2.94,2.94) [-3.00,1.00]
Total: 45270 W: 5737 L: 5648 D: 33885

No functional change.
2016-11-25 08:48:35 +01:00
erbsenzaehler ca464fc89e Cleanup Makfile for MacOs
1) Explicitly setting the default lib to the system-default is not
   needed on a Mac. See:
   http://libcxx.llvm.org/docs/UsingLibcxx.html

2) We do no longer need to exclude bmi2-builds from LTO. See:
   https://llvm.org/bugs/show_bug.cgi?id=19416

Changes tested and discussed on FishCooking:
   https://groups.google.com/forum/?fromgroups=#!topic/fishcooking/acUQtKtEzMM

No functional change.
2016-11-25 08:46:20 +01:00
Marco Costalba 0d9a9f5e98 Handle Windows Processors Groups
Under Windows it is not possible for a process to run on more than one
logical processor group. This usually means to be limited to use max 64
cores. To overcome this, some special platform specific API should be
called to set group affinity for each thread. Original code from Texel by
Peter sterlund.

Tested by Jean-Paul Vael on a Xeon E7-8890 v4 with 88 threads and confimed
speed up between 44 and 88 threads is about 30%, as expected.

No functional change.
2016-11-22 07:56:04 +01:00
Joost VandeVondele 6036303bb6 Avoid touching source files in profile-build
This refines the profile-build target to avoid 'touch'ing the sources,
keeping meaningful modification dates and avoiding editor warnings like vi's:

WARNING: The file has been changed since reading it!!!
Do you really want to write to it (y/n)?

Instead of touching sources, the (instrumented) object files are removed,
which has the same effect of rebuilding them in the next step.

As a side effect, this simplifies the Makefile a bit.

No functional change.
2016-11-20 10:51:42 +01:00
Fabian Beuke b5d10d17c2 Reduce variable scope in swap_byte
Added a specialization to remove the 'if' condition

No functional change.
2016-11-19 21:31:24 +01:00
Aram Tumanian 797602938d Start searching for a repetition from the 4th ply behind
A position can never repeat the one on the previous move.
Thus we can start searching for a repetition from the 4th
ply behind. In the case:

 std::min(st->rule50, st->pliesFromNull) < 4

We don't need to do any more calculations. This case happens
very often - in more than a half of all calls of the function.

No functional change.
2016-11-19 10:20:28 +01:00
Alain SAVARD 76d113f5f0 Pawn shelter and pawn storm tuned
Based on SPSA tuned values

Passed STC
http://tests.stockfishchess.org/tests/view/582363b30ebc5910626b9ca8
LLR: 2.95 (-2.94,2.94) [0.00,4.00]
Total: 40628 W: 7380 L: 7087 D: 26161

and passed LTC
http://tests.stockfishchess.org/tests/view/5823b73b0ebc5910626b9cb5
LLR: 2.96 (-2.94,2.94) [0.00,4.00]
Total: 273312 W: 35991 L: 35131 D: 202190

bench: 5773672
2016-11-19 09:42:11 +01:00
Marco Costalba 18df1698f4 Fix compile error from previous patch
Due to different types on some platforms.

No functional change.
2016-11-19 09:35:57 +01:00
Stéphane Nicolet 7f4de0196b Do not use GCC extension for anonymous unions
Anonymous struct inside anonymous unions are a GCC extension.
This patch uses named structs to stick to the C+11 standard.

Avoids a string of warnings on the Clang compiler.

Non functional change (same bench and same MD5 signature,
so compiled code is exactly the same as in current master)
2016-11-19 09:22:49 +01:00
Joost VandeVondele cddc8d4546 More accurate 'go nodes' searches at low count
Makes the actual number of nodes searched match closely
the number of nodes requested, by increasing the frequency
of checking the number of nodes searched at low node count.
All other searches retain the default checking frequency of
once per 4096 nodes, and are thus unaffected.

Passed STC as non-regression
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 26643 W: 4766 L: 4655 D: 17222

No functional change.
2016-11-19 08:47:41 +01:00
Stefan Geschwentner a90fc4c877 Non-quiet pruning tweak
Count in the difference of static evaluation
and alpha for pruning threshold.

STC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 16885 W: 3061 L: 2866 D: 10958

LTC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 33566 W: 4428 L: 4202 D: 24936

Bench: 5513149
2016-11-19 08:37:52 +01:00
Aram Tumanian e6c2899020 Make a version of Position::do_move() without the givesCheck parameter
In 10 of 12 calls total to Position::do_move()the givesCheck argument is
simply gives_check(m). So it's reasonable to make an overload without
this parameter, which wraps the existing version.

No functional change.
2016-11-12 09:55:12 +01:00
joergoster de269ee18e FEN parsing: add a second check for correctly setting e.p. square
Currently, we only check if there is a pawn in place
to make the en-passant capture. Now also check that
there is a pawn that could just have advanced two
squares. Also update the corresponding comment.

This makes the parsing of FENs a bit more robust, and
now correctly handles positions like the one reported by Dann Corbit.

position fen rnbqkb1r/ppp3pp/3p1n2/3P4/8/2P5/PP3PPP/RNBQKB1R w KQkq e6
d

 +---+---+---+---+---+---+---+---+
 | r | n | b | q | k | b |   | r |
 +---+---+---+---+---+---+---+---+
 | p | p | p |   |   |   | p | p |
 +---+---+---+---+---+---+---+---+
 |   |   |   | p |   | n |   |   |
 +---+---+---+---+---+---+---+---+
 |   |   |   | P |   |   |   |   |
 +---+---+---+---+---+---+---+---+
 |   |   |   |   |   |   |   |   |
 +---+---+---+---+---+---+---+---+
 |   |   | P |   |   |   |   |   |
 +---+---+---+---+---+---+---+---+
 | P | P |   |   |   | P | P | P |
 +---+---+---+---+---+---+---+---+
 | R | N | B | Q | K | B |   | R |
 +---+---+---+---+---+---+---+---+

Fen: rnbqkb1r/ppp3pp/3p1n2/3P4/8/2P5/PP3PPP/RNBQKB1R w KQkq - 0 1

No functional change.
2016-11-10 11:45:51 +01:00
Mira dc4655e1f9 Stack offset changed from -5 to -4
Non functional change, tests under sanitizers OK.

Rationales for change

- Offset in code is in range -4 ... 2
- There was an error by (pathological) corner case MAX_PLY=0

No functional change.
2016-11-10 11:43:21 +01:00
atumanian 0fa80c9ba3 Update comments related after new see_ge()
Update comments according to changes from my patch: #822

No functional change.
2016-11-10 11:40:31 +01:00
Joost VandeVondele 61c727fdcb Allow benches with more than 2G nodes.
./stockfish bench 128 1 4000000000 default nodes

    crashes before, works after.

    No functional change.
2016-11-07 13:35:28 +01:00
Joost VandeVondele 876f07cbee Fix undefined behaviour with unaligned loads in syzygy code
Casting a pointer to a different type with stricter alignment
requirements yields to implementation dependent behaviour.
Practicaly everything is fine for common platforms because the
CPU/OS/compiler will generate correct code, but anyhow it is
better to be safe than sorry.

Testing with dbg_hit_on() shows that the unalignment accesses are
very rare (below 0.1%) so it makes sense to split the code in a
fast path for the common case and a slower path as a fallback.

No functional change (verified with TB enabled).
2016-11-06 11:48:07 +01:00
ppigazzini f5d3f0ded6 Update AUTHORS for SF8
And format top contriutor (space instead of tabs, proper Unix
line endings).
2016-11-06 10:28:17 +01:00
Marco Costalba e4659693de Fix a warning with debug=no
Warning in TB code due to unused variable.

Verified same bench with TB code enabled.

No functional change.
2016-11-06 09:45:25 +01:00
Joost VandeVondele 52cb348023 Reproducible searches after ucinewgame
Fixes issue #859.

thisThread->callsCnt in search<>() was different (by 1) for the first and second game played.

No functional change.
2016-11-05 22:25:55 +01:00
Marco Costalba 0d669be76c Restore development version
No functional change.
2016-11-05 09:32:39 +01:00
Marco Costalba 23f384cac3 Add explicit braces and fix a warning
Warning under both gcc and clang.

No functional change.
2016-11-05 09:29:22 +01:00
VoyagerOne b915fdc889 Reduction Simplification
Simplify reduction formula by removing a parameter.

STC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 35798 W: 6368 L: 6272 D: 23158

LTC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 125375 W: 15827 L: 15839 D: 93709

Bench: 4735038
2016-11-05 08:17:42 +01:00
Joost VandeVondele 67d19447f4 Makefile fix for sanitize
Small fixes for compilation with sanitize=yes optimize=no,
by always adding -fsanitize=undefined to the LDFLAGS as required.
Updates config-sanity to check&report the status of the flag.

No functional change.
2016-11-05 08:15:56 +01:00
VoyagerOne d4abf54247 Top CPU Contributors
Give some well needed credit...

No functional change.
2016-11-05 08:12:22 +01:00
Miroslav Fontán 445aade39c Simplify code, delete else after return 2016-11-05 08:08:25 +01:00
Miroslav Fontán f3cd7002aa Sync variable names in decl vs def 2016-11-05 08:05:22 +01:00
Joost VandeVondele c43146edb7 Travis-ci: integrate perft checking
makes verifying perft numbers for a few positions
part of travis-ci. Adds <5s testing time.

No functional change.
2016-11-05 08:03:34 +01:00
Marco Costalba c0bb041539 Rewrite syzygy in C++
Rewrite the code in SF style, simplify and
document it.

Code is now much clear and bug free (no mem-leaks and
other small issues) and is also smaller (more than
600 lines of code removed).

All the code has been rewritten but root_probe() and
root_probe_wdl() that are completely misplaced and should
be retired altogheter. For now just leave them in the
original version.

Code is fully and deeply tested for equivalency both in
functionality and in speed with hundreds of games and
test positions and is guaranteed to be 100% equivalent
to the original.

Tested with tb_dbg branch for functional equivalency on
more than 12M positions.

stockfish.exe bench 128 1 16 syzygy.epd

Position: 2016/2016
Total 12121156 Hits 0 hit rate (%) 0
Total time (ms) : 4417851
Nodes searched : 1100151204
Nodes/second : 249024

Tested with 5,000 games match against master, 1 Thread,
128 MB Hash each, tc 40+0.4, which is almost equivalent
to LTC in Fishtest on this machine. 3-, 4- and 5-men syzygy
bases on SSD, 12-moves opening book to emphasize mid- and endgame.

Score of SF-SyzygyC++ vs SF-Master: 633 - 617 - 3750  [0.502] 5000
ELO difference: 1

No functional change.
2016-11-05 07:55:08 +01:00
Marco Costalba 369eff437c Stockfish 8
Bench: 5926706

No functional change
2016-11-01 10:19:17 +01:00
Stefan Geschwentner 344616e917 Bonus for attacked passed pawn promotion path
Bonus for each attacked square on the promotion path
of an enemy passed pawn.

STC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 141511 W: 25295 L: 24579 D: 91637

LTC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 23161 W: 3022 L: 2831 D: 17308

Bench: 5926706
2016-10-30 13:48:03 +01:00
Joost Vandevondele 40b1b27178 Fix a series of undefined behaviours
Avoid shifting negative signed integers and use typed
enum to avoids decrementing a variable beyond its defined
range, like:
       for (Rank r = RANK_8; r >= RANK_1; --r)

Changes were tested individually and passed SPRT[-3, 1].

With this patch gcc --sanitize builds cleanly.

No functional change.
2016-10-27 06:44:41 +02:00
Joost VandeVondele bf51b4796a travis-ci: Enable undefined behavior checking 2016-10-27 06:29:24 +02:00
syzygy e18e557e77 Output PV if last iteration does not complete
Instead of outputting "info nodes ... time ..." when the last
iteration is interrupted, simply call UCI::pv() to output the PV.

I thought about calling UCI:pv() with bounds -VALUE_INFINITE, VALUE_INFINITE
to avoid "lowerbound" or "upperbound" appearing in it, but I'm not sure that
would be any better.

This patch fixes rare inconsistencies between the first move of
the last PV output and the bestmove played. It also makes sure
that all the latest statistics are sent to the GUI (not only nodes
and time but also nps, tbhits, hashfull).

No functional change.
2016-10-27 06:26:22 +02:00
Stéphane Nicolet 818b4a126d Endgame malus for having a king in a pawnless flank
Original idea by "ElbertoOne", while "FauziAkram" suggested to put a
small midgame penalty too.

STC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 71808 W: 13038 L: 12610 D: 46160

LTC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 150874 W: 19828 L: 19221 D: 111825

Bench: 6077005
2016-10-25 06:57:29 +02:00
VoyagerOne e77f38c431 History Stat Comparison
Adjust LMR by comparing history stats
with opponent (prior ply).

STC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 27754 W: 5066 L: 4824 D: 17864

LTC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 216596 W: 28157 L: 27343 D: 161096

Bench: 5437729
2016-10-25 06:44:19 +02:00
Marco Costalba e18321f55a Correcty resey TB hit counter
Restore original behaviour to reset
the counter before a new move search.

Also fixed some warnings and added const
qualifier to a couple of functions, as
suggested by m_stembera.

Thanks to Werner Bergmans for reporting
the regression.

No functional change.
2016-10-22 08:22:13 +02:00
syzygy ca67752645 Per-thread TB hit counters
Use a per-thread counter to reduce contention
with many cores and endgame positions.

Measured around 1% speed-up on a 12 core and 8%
on 28 cores with 6-men, searching on:
 7R/1p3k2/2p2P2/3nR1P1/8/3b1P2/7K/r7 b - - 3 38

Also retire the unused set_nodes_searched() and fix
a couple of return types and naming conventions.

No functional change.
2016-10-21 06:15:45 +02:00
Joost Vandevondele 3686e719a1 Simplify next_move by always scoring evasions
For a default bench, this fixes the last valgrind
error (jump on uninitialised value).

Passed STC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 187869 W: 33303 L: 33463 D: 121103

No functional change.
2016-10-20 17:17:14 +02:00
Joost Vandevondele 9893e7fd53 Make valgrind testing part of travis ci. 2016-10-19 21:29:00 +02:00
ajithcj 99f3ad6858 Remove useless assignments to currentMove
We reference (ss-1)->currentMove, i.e. we peek
current move of the parent node, so currentMove
should be valid in the main move loop, when we
search() the subtree, but outside of main loop
it is useless.

No functional change.
2016-10-18 09:00:52 +02:00
VoyagerOne e27d3bb884 Use explicit logic for pruning
Also a speedup since we don't need to recalculate SEE
for extensions...as it already determined to be positive.

Results for 12 tests for each version:

        Base      Test      Diff
Mean    2132395   2191002   -58607
StDev   128058    85917     134239
p-value: 0.669
speedup: 0.027

Non functional change.
2016-10-18 08:53:51 +02:00
Jacques 16e1881126 Fixes for ARM compilation: take 2
The target:

Odroid U3 (http://www.hardkernel.com/main/products/prdt_info.php?g_code=g138745696275)
Debian Jessie
As listed in #550 and #638 three modifications are needed for compilation to work:

float-abi flag for GCC If an FPU is present and supported by the installed os then passed value need to be hard.
I didn't find any better solution than using readelf to check for the availibilty of Tag_ABI_VFP_args which sould indicate support for the FPU. The check is only done if the arch is arm and if readelf is not present
on the system, there will be an error (/bin/sh: 1: readelf: not found) but it will not break and will continue with the default softfp value. Outputing the error is not really acceptable but I wanted some feedback on the
check itself.

-lpthread is needed on armv7 outside of Android
I replaced UNAME with KERNEL and OS to allow to differentiate Android.

m32 flag
My understanding is that outside of Android the flag is generating errors on armv7.

These modifications should introduce change only for non Android armv7 build.

No functional change.
2016-10-14 08:58:07 +02:00
Marco Costalba e1f600f186 Revert "Fixes for ARM compilation"
This reverts commit a3fe80c36a.

Break compilation on mingw for me.
2016-10-13 08:36:30 +02:00
Jacques a3fe80c36a Fixes for ARM compilation
The target:

Odroid U3 (http://www.hardkernel.com/main/products/prdt_info.php?g_code=g138745696275)
Debian Jessie
As listed in #550 and #638 three modifications are needed for compilation to work:

float-abi flag for GCC If an FPU is present and supported by the installed os then passed value need to be hard.
I didn't find any better solution than using readelf to check for the availibilty of Tag_ABI_VFP_args which sould indicate support for the FPU. The check is only done if the arch is arm and if readelf is not present
on the system, there will be an error (/bin/sh: 1: readelf: not found) but it will not break and will continue with the default softfp value. Outputing the error is not really acceptable but I wanted some feedback on the
check itself.

-lpthread is needed on armv7 outside of Android
I replaced UNAME with KERNEL and OS to allow to differentiate Android.

m32 flag
My understanding is that outside of Android the flag is generating errors on armv7.

These modifications should introduce change only for non Android armv7 build.

No functional change.
2016-10-13 08:34:04 +02:00
Marco Costalba fdf3a51c68 AppVeyor: run bench after build
And show resulting bench signature.

The run is very slow becuase optimizations
are all disabled by default /Od /RTC1

No functional change.
2016-10-10 21:00:59 +02:00
Marco Costalba e61f7b1e6d Add AppVeyor integration
It is like Trevis CI but for Windows platform.

Currently just compile builds, wthouth benching
the resulting executable.

No functional change.
2016-10-10 16:29:29 +02:00
ajithcj f799610d4b Simplify futility pruning return value
Return eval as it is while doing futility pruning.

STC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 167687 W: 29778 L: 29904 D: 108005

LTC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 26905 W: 3503 L: 3390 D: 20012

Bench: 5936728
2016-10-09 09:54:43 +02:00
atumanian 073eed590e Optimisation of Position::see and Position::see_sign
Stephane's patch removes the only usage of Position::see, where the
returned value isn't immediately compared with a value. So I replaced
this function by its optimised and more specific version see_ge. This
function also supersedes the function Position::see_sign.

bool Position::see_ge(Move m, Value v) const;

This function tests if the SEE of a move is greater or equal than a
given value. We use forward iteration on captures instread of backward
one, therefore we don't need the swapList array. Also we stop as soon
as we have enough information to obtain the result, avoiding unnecessary
calls to the min_attacker function.

Speed tests (Windows 7), 20 runs for each engine:
Test engine: mean 866648, st. dev. 5964
Base engine: mean 846751, st. dev. 22846
Speedup: 1.023

Speed test by Stephane Nicolet

Fishtest STC test:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 26040 W: 4675 L: 4442 D: 16923
http://tests.stockfishchess.org/tests/view/57f648990ebc59038170fa03

No functional change.
2016-10-08 06:38:36 +02:00
Stéphane Nicolet 1e586288ca Do not use SEE in evasion scoring
Idea by Aram Tumanian (atumanian)

STC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 43889 W: 7849 L: 7767 D: 28273

LTC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 29333 W: 3809 L: 3700 D: 21824

Bench: 6421663
2016-10-06 00:00:27 +02:00
Stefano Cardanobile 0162fb83c2 Retire implicit malus for stonewalls
STC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 75864 W: 13466 L: 13437 D: 48961

LTC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 99050 W: 12472 L: 12451 D: 74127

bench: 6098474
2016-10-05 09:32:08 +02:00
VoyagerOne ab26c61971 Allow inCheck pruning
This is a bit tricky because we don't want
to prune the only legal evasions, even if
with negative SEE. So add an assert to avoid
this subtle bug to slip in later.

STC:
LLR: 2.96 (-2.94,2.94) [0.00,4.00]
Total: 14140 W: 2625 L: 2421 D: 9094

LTC:
LLR: 2.95 (-2.94,2.94) [0.00,4.00]
Total: 11558 W: 1555 L: 1379 D: 8624

bench: 5256717
2016-10-03 16:18:53 +02:00
Marco Costalba eccccba0ce Remove useless razoring condition
Condition is always true! For any value of the
array index! Even an out of bound array, like
razor_margin[120]!!!!

No functional change.
2016-09-29 15:24:36 +02:00
HiraokaTakuya b77bae0529 Make razor_margin[4] ONE_PLY value independent
No functional change.
2016-09-29 15:20:07 +02:00
Stéphane Nicolet 7ae3c05795 Rename shift_bb() to shift()
Rename shift_bb() to shift(), and DELTA_S to SOUTH, etc.
to improve code readability, especially in evaluate.cpp
when they are used together:

    old b = shift_bb<DELTA_S>(pos.pieces(PAWN))
    new b = shift<SOUTH>(pos.pieces(PAWN))

While there fix some small code style issues.

No functional change.
2016-09-25 10:45:10 +02:00
joergoster 351844061e Allowing singular extension in mate positions
Drop useless condition

abs(ttValue) < VALUE_KNOWN_WIN

And extend singular extension search to cases when ttValue
stores a mate score. This improves mate finding and does
not introduce any regression.

Yery tested this patch against current master on the 6500+
Chest mate suite with 200K fixed nodes:

    shortest mates found: master: 1206 patch:1205
    any mate found: master: 1903 patch: 2003

with 1 sec time:

    shortest mates found: master: 2667 patch: 2628
    any mate found: master: 3585 patch: 3646

Verified for no regression:

STC
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 25655 W: 4578 L: 4465 D: 16612

LTC
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 66247 W: 8618 L: 8557 D: 49072

bench: 6335042
2016-09-24 19:56:02 +02:00
Marco Costalba 8662bdfa12 Fix crash when passing a mate/stalemate position
Both Tablebases::filter_root_moves() and
extract_ponder_from_tt(9 were unable to handle
a mate/stalemate position.

Spotted and reported by Dann Corbit.

Added some mate/stalemate positions to bench so
to early catch this regression in the future.

No functional change.
2016-09-24 07:37:52 +02:00
Stéphane Nicolet 28240d375c Simplify pinners conditions in SEE()
Use the following transformations:

- to check that A is included in B, testing "(A & ~B) == 0" is faster
than "(A & B) == A"

- to remove the intersection of A and B from A, doing "A &= ~B;" is as
fast as "if (A & B) A &= ~B;" but is simpler.

Overall, the simpler patch version is 0.3% than current master.

No functional change.
2016-09-22 08:31:23 +02:00
Guenther Demetz 943ae89be1 Fix pin-aware SEE
Correct pinners calculation and fix bug with pinned
pieces giving check. With this patch 'pinners' only
returns sliders with exactly one defensive piece between
the slider and the attacked square (in other words, pinners
returns exact pinners).

This was a co-operation between Marco Costalba,
Stphane Nicolet and me.

Special thanks to Ronald de Man for reporting the bug with
pinned pieces giving check, discussed here:
https://groups.google.com/forum/?fromgroups=#!topic/fishcooking/S_4E_Xs5HaE

STC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 132118 W: 23578 L: 23645 D: 84895

LTC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 36424 W: 4770 L: 4670 D: 26984

bench: 6272231
2016-09-21 08:42:25 +02:00
Joost Vandevondele 4b0043ae7c Use fixed depth bench to make PGO builds more reproducible
Discussed on fishcooking

proposal and objdump verification:
https://groups.google.com/d/msg/fishcooking/4_ausUwMXP0/EGPsMYqOFAAJ

verified no significant speed difference between depth and time:
https://groups.google.com/d/msg/fishcooking/4_ausUwMXP0/KazW5QZmFgAJ

stockfish_time - stats:
mean = 2207232.56        std = 7079.51        std/mean = 0.003207

stockfish_depth - stats:
mean = 2201783.57        std = 6356.69        std/mean = 0.002887

No functional change
2016-09-18 08:13:34 +02:00
Marco Costalba 92f01aa2bd Fix a warning with MSVC
warning C4706: assignment within conditional expression

No functional change.
2016-09-17 10:14:28 +02:00
Stéphane Nicolet ea41f18e6e Swap mg and eg in internal representation of Score
Instrumentation shows that in make_score(mg, eg) calls, the mg value is
zero in 25,9% of the calls while the eg value is zero in 36,8% of the
calls.

Swapping the internal fields of mg and eg in the internal
representation of Score allows the compiler to optimize away the shift
in (eg << 16) + mg in more cases, thus resulting in a 0.3% speed-up
overall.

No functional change
2016-09-17 09:56:36 +02:00
Marco Costalba 057d710fc2 Fix indentation in struct FromToStats
And other little trivial stuff.

No functional change.
2016-09-17 09:51:20 +02:00
Stéphane Nicolet 01f2466f6e Retire KingDanger array
Rescales the king danger variables in evaluate_king() to
suppress the KingDanger[] array. This avoids the cost of
the memory accesses to the array and simplifies the non-linear
transformation used.

Full credits to "hxim" for the seminal idea and implementation,
see pull request #786.
https://github.com/official-stockfish/Stockfish/pull/786

Passed STC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 9649 W: 1829 L: 1689 D: 6131

Passed LTC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 53494 W: 7254 L: 7178 D: 39062

Bench: 6116200
2016-09-16 08:30:06 +02:00
Marco Costalba 5c58d1f5cb Use per-thread counterMoveHistory
Drops a scalability bottleneck due to memory contention
of a single shared table across threads. The effect starts
to be sensible with a high number of threads. Specifically
we have a small regression with 7 threads both at 60 and
180 seconds TC:

10000 @ 60+0.6 th 7
ELO: -2.46 +-3.2 (95%) LOS: 6.5%
Total: 9896 W: 1037 L: 1107 D: 7752

5000 @ 180+0.6 th 7
ELO: -1.95 +-4.1 (95%) LOS: 17.7%
Total: 5000 W: 444 L: 472 D: 4084

We have a regression because counterMoveHistory table is
quite big and it takes time for a single thread to fill it.
Sharing the table yields to a higher fill rate and better
quality of moves and up to 7 threads the benefits of sharing
more then compensate the loss in speed due to contention.
Interestingly even with a 3X longer TC, so with more time
for the single thread to catch up, the improvment is quite
limited and below noise level. It seems we really need much
longer TC to saturate the table.

When we move to high threads number it's another story:

5000 @ 60+0.6 th 22
ELO: 3.49 +-4.3 (95%) LOS: 94.6%
Total: 4880 W: 490 L: 441 D: 3949

2000 @ 60+0.6 th 32
ELO: 8.34 +-6.9 (95%) LOS: 99.1%
Total: 2000 W: 229 L: 181 D: 1590

As expected the speed-up more than compensates the filling
rate, and we expect that with tournament TC, where single
thread is able to saturate the table, the difference will
be even stronger. For instance for TCEC 9 super-final time
control will be 180 minutes + 15 seconds and this scalability
improvement seems definitely the way to go.

So, summarizing:

GOOD:

Measured big improvement in high core scenario

Suitable for TCEC 9 superfinal (big hardware, very long TC)

Consistent and natural patch that extends to counterMoveHistory
what we already do for remaining history tables, that are all per-thread

Non functional change for the common case of a single core

Very simple (just 6 lines modified, no added ones)

BAD:

Small regression (within 2-3 ELO) with few threads and short TC

bench: 5341477
2016-09-16 08:15:07 +02:00
Marco Costalba b96dd754ed Renaming in MovePicker
Rename stages and simplify a bit the code.

No functional change.
2016-09-15 09:07:49 +02:00
Marco Costalba 01ee509a5c Retire MovePicker::see_sign()
No more used after last patch.

No functional change.
2016-09-14 15:43:56 +02:00
VoyagerOne 95ad2b51b7 Tweak SEE margin in pruning conditions
Use 35 * depth^2 to calculate see_margin.

STC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 22636 W: 4212 L: 3990 D: 14434

LTC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 47241 W: 6314 L: 6041 D: 34886

The Movepick SEE is now dead code, retire it.

Bench: 5341477
2016-09-14 15:38:38 +02:00
syzygy 438805aee8 Integrate next_stage() logic into next_move()
Measured bench speed up goes from 0,7% to 2%,
given the unreliable measure a reverse simmplification
test was done on fishtest:

master vs patch
LLR: -2.94 (-2.94,2.94) [-3.00,1.00]
Total: 15499 W: 2685 L: 2867 D: 9947

Test result is positive, master is weaker.

No functional change.
2016-09-13 07:14:09 +02:00
Guenther Demetz ace8e951d7 Simplify code for pinaware SEE
This is the most compact and neatest version
is was able to produce.

On normal builds I have a small slowdown:
normal builds base vs. simplification (gcc 4.8.1 Win7-64 i7-3770 @ 3.4GHz x86-64-modern)
Results for 20 tests for each version:

        Base      Test      Diff
Mean    1974744   1969333   5411
StDev   11825     10281     5874
p-value: 0,178
speedup: -0,003

On pgo-builds however I measure a nice 1.1% speedup

pgo-builds base vs. simplification
Results for 20 tests for each version:

        Base      Test      Diff
Mean    1974119   1995444   -21325
StDev   8703      5717      4623
p-value: 1
speedup: 0,011

No functional change.
2016-09-12 15:45:00 +02:00
Guenther Demetz 90ce24b11e Pinned aware SEE
Don't allow pinned pieces to attack the exchange-square as long all
pinners (this includes also potential ones) are on their original
square.
As soon a pinner moves to the exchange-square or get captured on it, we
fall back to standard SEE behaviour.

This correctly handles the majority of cases with absolute pins.

bench: 6883133
2016-09-12 09:31:09 +02:00
Stefano Cardanobile 4c95edddbf Reorder evaluation start
In evaluate, we start by initializing the pos.psq_score
and adding the material imbalance. After that, we check
whether a specialized eval exists and if yes we return
that value and discard whatever we have computed until now.

It sounds more logical to first probe material entry and
return if we have a specialized eval, and only if it is
not the case initialize eval with some values. There is
no measurable speed-difference on my computer.

Non functional change.
2016-09-11 07:42:12 +02:00
Marco Costalba 602d7fbb07 Use Movepick SEE value in search
This halves the calls to the costly pos.see_sign(),
speed up is about 1-1.3%

Non functional change.
2016-09-09 17:11:54 +02:00
Marco Costalba d909d10f33 Refactor previous patch
No functional change.
2016-09-08 06:02:42 +02:00
ajithcj 38428ada54 Prune dangerous moves at low depth
At very low depths prune captures,
promotions and checks if see is negative.

STC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 6772 W: 1328 L: 1173 D: 4271

LTC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 8917 W: 1270 L: 1122 D: 6525

bench: 6024713
2016-09-08 05:55:10 +02:00
Marco Costalba e340ce221c Syntactic sugar to loop across pieces
Also add some comments to the new operator~(Piece).

No functional change.
2016-09-04 15:33:17 +02:00
syzygy ca6c9f85a5 Change from [Color][PieceType] to [Piece]
Speed up of almost 1% in both normal and
pgo builds.

No functional change.
2016-09-04 09:22:09 +02:00
Marco Costalba c5828c4eba Fix syzygy with partial TB
In case we have installed a not complete set of 6-men tables and
there is 6 piece position on board, but no corresponding
tablebase engine is not using any syzygy at all.

Reported by Jouni Uski, fix by Peter Österlund,
confirmed as a bug by Ronald de Man.

bench: 7591630
2016-09-03 08:21:05 +02:00
Stéphane Nicolet d37dfe9ae4 Space bonus in presence of open files
If the opponent has a cramped position, opening a file often
helps him/her to exchange pieces, so it makes sense to reduce
the space bonus if there are open files.

Credits: Leonardo Ljubičić for the strategic idea, Alain Savard for the
implementation of the open files calculation, "CrunchyNYC" for the
compensation of the numerator.

STC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 49112 W: 9239 L: 8900 D: 30973

LTC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 89415 W: 12014 L: 11601 D: 65800

Bench: 7591630
2016-09-03 00:04:20 +02:00
lucasart 13b4444d9e Change exclusion key setup
Should depend on which move is excluded. This
allow us to remove the dedicated Position::exclusion_key().

STC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 59814 W: 11136 L: 11083 D: 37595

LTC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 31023 W: 4187 L: 4080 D: 22756

bench 7553379
2016-09-02 08:37:01 +02:00
Stefano80 7f2eb10e93 Retire linear imbalance
Retire linear imbalance and compensate
in piece values enumeration.

STC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 43596 W: 8105 L: 8023 D: 27468

LTC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 24482 W: 3352 L: 3237 D: 17893

Bench: 7777707
2016-09-02 08:25:17 +02:00
ajithcj 5cffc032da Optimize order of a few conditions in search
Also fix size of KingDanger array to reduce memory footprint.

Small speed up of around 0.5%

No functional change.
2016-08-31 13:47:45 +02:00
VoyagerOne 2731bbaf6b Remove condition on killers in history pruning
Now allows main killer to be history prune.

STC:
LLR: 2.94 (-2.94,2.94) [-3.00,1.00]
Total: 15852 W: 2910 L: 2781 D: 10161

LTC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 56428 W: 7610 L: 7537 D: 41281

Bench: 8032058
2016-08-30 09:09:55 +02:00
Stefan Geschwentner 6aa9308f08 Tweak probcut threshold
Use better threshold for capture move generation.

STC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 23265 W: 4415 L: 4188 D: 14662

LTC:
LLR: 2.95 (-2.94,2.94) [0.00,4.00]
Total: 36618 W: 5083 L: 4836 D: 26699

bench: 7030088
2016-08-29 22:15:03 +02:00
Andrew Grant b4f6728e61 Removed an extra space
No functional change.
2016-08-28 09:47:30 +02:00
Alain SAVARD 2b57b61cb1 Move king tropism to evaluate_king
No functional change.
2016-08-28 08:49:40 +02:00
Marco Costalba 1ee2838214 Retire CheckInfo
Move its content directly under StateInfo.

Verified for no speed regression.

No functional change.
2016-08-28 08:08:13 +02:00
Marco Costalba 0b944c7186 Silence some warnings with MSVC 2013
No functional change.
2016-08-27 12:16:13 +02:00
Stéphane Nicolet 805afcbf3d Move CheckInfo under StateInfo
This greately simplifies usage because hides to the
search the implementation specific CheckInfo.

This is based on the work done by Marco in pull request #716,
implementing on top of it the ideas in the discussion: caching
the calls to slider_blockers() in the CheckInfo structure,
and simplifying the slider_blockers() function by removing its
first parameter.

Compared to master, bench is identical but the number of calls
to slider_blockers() during bench goes down from 22461515 to 18853422,
hopefully being a little bit faster overall.

archlinux, gcc-6
make profile-build ARCH=x86-64-bmi2
50 runs each

bench:
base = 2356320 +/- 981
test = 2403811 +/- 981
diff = 47490 +/- 1828

speedup = 0.0202
P(speedup > 0) = 1.0000

perft 6:
base = 175498484 +/- 429925
test = 183997959 +/- 429925
diff = 8499474 +/- 469401

speedup = 0.0484
P(speedup > 0) = 1.0000

perft 7 (but only 10 runs):
base = 185403228 +/- 468705
test = 188777591 +/- 468705
diff = 3374363 +/- 476687

speedup = 0.0182
P(speedup > 0) = 1.0000

$ ./pyshbench ../Stockfish/master ../Stockfish/test 20
run base     test     diff
...

base = 2501728 +/- 182034
test = 2532997 +/- 182034
diff = 31268 +/- 5116

speedup = 0.0125
P(speedup > 0) = 1.0000

No functional change.
2016-08-27 09:53:26 +02:00
Marco Costalba 4c5cbb1b14 Make engine ONE_PLY value independent
This non-functional change patch is a deep work to allow SF to be independent
from the actual value of ONE_PLY (currently set to 1). I have verified SF is
now independent for ONE_PLY values 1, 2, 4, 8, 16, 32 and 256.

This patch gives consistency to search code and enables future work, opening
the door to safely tweaking the ONE_PLY value for any reason.

Verified for no speed regression at STC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 95643 W: 17728 L: 17737 D: 60178

No functional change.
2016-08-27 09:12:25 +02:00
gamander 133808851d Fixed wrong definition of WhiteCamp and BlackCamp
No functional change.
2016-08-27 08:48:07 +02:00
hxim 9bd856e28e Simplify stats update
Simplify code by moving countermove and follow-up move
history update into procedure.

No functional change.
2016-08-27 08:39:32 +02:00
Marco Costalba 3e739f883f Reformat stats update
Rewritten in a way to have explicit in the search
the bonus/penalty we apply: hopefully this will lead
to further simplification/fix of current rather messy
stats update code.

No functional change.
2016-08-25 09:51:50 +02:00
VoyagerOne 0b4f6e562b Refutation penalty on captures
Apply refutation penalty for prior PV quiet move on captures

LTC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 8208 W: 1153 L: 1008 D: 6047
http://tests.stockfishchess.org/tests/view/57bc5a9f0ebc59030fbe47b5

Only LTC because a very similar patch already passed STC + LTC

bench: 7038730
2016-08-24 08:26:32 +02:00
VoyagerOne 5596492f6e Simplify IID
STC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 30468 W: 5687 L: 5582 D: 19199
http://tests.stockfishchess.org/tests/view/57b1ddd80ebc591c761f63e2

LTC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 87406 W: 11756 L: 11725 D: 63925
http://tests.stockfishchess.org/tests/view/57b212590ebc591c761f63f9

bench: 6554900
2016-08-19 08:59:18 +02:00
VoyagerOne 8493c8c6b8 Do LMR on captures
STC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 5361 W: 1086 L: 936 D: 3339
http://tests.stockfishchess.org/tests/view/57b31b0f0ebc591c761f643d

LTC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 54694 W: 7591 L: 7287 D: 39816
http://tests.stockfishchess.org/tests/view/57b3442b0ebc591c761f6450

bench: 6881120
2016-08-19 08:50:14 +02:00
Marco Costalba e3af492142 Remove a stale assignment
No more used after previous patch.

Spotted by Jekaa .

No functional change.
2016-08-18 10:40:56 +02:00
Stefano80 9585f8ef58 Retire pawn span
Retire pawn span and replace with pawn count in evaluate_scale_factor.

STC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 26482 W: 4929 L: 4818 D: 16735

LTC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 61938 W: 8400 L: 8335 D: 45203

Bench: 7662861
2016-08-18 10:16:56 +02:00
VoyagerOne 7396c08b79 Use predicted depth for history pruning
STC: (Yellow)
LLR: -2.96 (-2.94,2.94) [0.00,4.00]
Total: 69115 W: 12880 L: 12797 D: 43438

LTC:
LLR: 2.96 (-2.94,2.94) [0.00,4.00]
Total: 124163 W: 16923 L: 16442 D: 90798

Note: Note based off past experiments / patches... history pruning
is quite TC sensitive. I believe the reason for this TC dependency
is that the CMH/FMH is a very large table that takes time to fill
up with. In addition having more time for will increase the accuracy
of the stats' value.

Bench: 7351698
2016-08-15 14:45:40 +02:00
Luca Brivio 3d10cfcdd2 Cap space evaluation bonus
When computing space evaluation, limit the bonus square count to 16.

STC @ 10+0.1 th 1:
LLR: 2.97 (-2.94,2.94) [0.00,5.00]
Total: 30793 W: 5910 L: 5648 D: 19235

LTC @ 60+0.6 th 1:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 31361 W: 4410 L: 4184 D: 22767

Bench: 7165385
2016-08-13 10:12:09 +02:00
Alain SAVARD 8abb98455f Simplify space formula
STC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 16868 W: 3260 L: 3132 D: 10476

LTC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 16910 W: 2381 L: 2255 D: 12274

bench: 6663531
2016-08-10 12:49:24 +02:00
VoyagerOne b3525fa9ea Use Color-From-To history stats to help sort moves
STC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 33502 W: 6498 L: 6223 D: 20781
http://tests.stockfishchess.org/tests/view/578abb940ebc5972faa169e2

LTC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 50782 W: 7124 L: 6832 D: 36826
http://tests.stockfishchess.org/tests/view/578b8e5d0ebc5972faa169fd

LTC: (Sanity test against latest master)
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 32759 W: 4600 L: 4370 D: 23789
http://tests.stockfishchess.org/tests/view/5798b7d30ebc591c761f5b72

bench: 6985912

P.S. Thanks @mstembera for rewriting my code to make it smp compatible. A BIG thank you!
2016-08-02 09:17:14 +02:00
VoyagerOne 85924db496 Futility tweak
Use a different margin for pruning child nodes.

STC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 16692 W: 3251 L: 3051 D: 10390
http://tests.stockfishchess.org/tests/view/579b95d10ebc591c761f5c03

LTC:
LLR: 2.97 (-2.94,2.94) [0.00,5.00]
Total: 24140 W: 3501 L: 3297 D: 17342
http://tests.stockfishchess.org/tests/view/579bb15d0ebc591c761f5c0b

Bench: 7927017
2016-08-01 21:47:42 +02:00
ajithcj f2f3a06a1a Allow null pruning at depth 1
This removes a check that prevents null pruning at depth 1 PLY.

STC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 23445 W: 4638 L: 4521 D: 14286

LTC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 61416 W: 8627 L: 8563 D: 44226

bench: 8145304
2016-07-24 09:54:07 +02:00
Stefano80 714329dbdc See prune at higher depth
Allow SEE pruning at higher depths in shallow depth
pruning using a threshold increasing with depth.

STC
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 35366 W: 7011 L: 6724 D: 21631

LTC
LLR: 2.97 (-2.94,2.94) [0.00,5.00]
Total: 15578 W: 2243 L: 2070 D: 11265

Bench: 8417887
2016-07-24 08:55:58 +02:00
ajithcj 76971d8acb Gradually relax the NMP staticEval check
Gradually relax the NMP staticEval check as we go to
higher depths.

Use tuned values.

STC
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 16745 W: 3371 L: 3168 D: 10206

LTC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 5906 W: 875 L: 736 D: 4295

bench: 8548212
2016-07-16 07:35:31 +02:00
Lyudmil Antonov f619f1d38c Workaround gcc stack alignment bug
GCC uses SSE instructions to move data but in 32-bit gcc version used
by abrok the stack is not 16-byte aligned due to a bug.

This patch workaround teh bug by not using the stack
to store KingFlank[]

Fixes issue #721.

No functional change.
2016-07-16 07:06:13 +02:00
joergoster 82d02a3133 Fix extract_ponder_from_tt()
Checking for legality of a possible ponder move
must be done before we undo the first pv move,
of course. (spotted by mohammed li.)

This obviously only has any effect when playing in ponder mode.

No functional change.
2016-07-12 08:47:21 +02:00
Stéphane Nicolet 1d09ee70f7 King tropism
Bonus for each square that we attack in the flank where the opponent
king is. Squares that we attack twice and are not protected by an enemy
pawn count double.

Passed STC:
http://tests.stockfishchess.org/tests/view/577dfca60ebc5972faa166b8
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 48373 W: 9832 L: 9481 D: 29060

And LTC:
http://tests.stockfishchess.org/tests/view/577e77870ebc5972faa166df
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 8881 W: 1408 L: 1255 D: 6218

Bench: 7577046
2016-07-08 09:35:22 +02:00
Alain SAVARD eb20a87c67 More safe checks
Consider a check given by a rook or a minor to be a "safe check"
also in the case where supported by another piece,
and given on a square only defended by a queen

Was yellow STC
http://tests.stockfishchess.org/tests/view/576fcbc80ebc5972faa163e8
LLR: -2.96 (-2.94,2.94) [0.00,5.00]
Total: 55453 W: 10431 L: 10315 D: 34707

Passed LTC
http://tests.stockfishchess.org/tests/view/57733a0b0ebc5972faa164b7
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 54550 W: 7671 L: 7365 D: 39514

bench: 7398346
2016-07-07 08:39:58 +02:00
ajithcj ade3bb9a4e Use staticEval in null prune condition
Don't null prune at depth < 12 if staticEval < beta

STC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 62858 W: 12035 L: 11632 D: 39191

LTC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 49784 W: 7009 L: 6720 D: 36055

bench: 8054611
2016-07-02 16:43:49 +02:00
loco-loco 716a145a6c Removing inCheck condition for counter move bonus
STC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 20206 W: 3946 L: 3823 D:

LTC:
LLR: 3.10 (-2.94,2.94) [-3.00,1.00]
Total: 25004 W: 3512 L: 3390 D: 18102

Bench: 8172428
2016-06-26 10:25:05 +02:00
Marco Costalba 190d2ea4bc Restore standard passed pawn definition
Use the usual and accepted passed pawn semantic
instead of a non-standard one and remove a FIXME.

STC (http://tests.stockfishchess.org/tests/view/576401350ebc5972faa1608d):
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 29646 W: 5663 L: 5557 D: 18426

LTC (http://tests.stockfishchess.org/tests/view/5764e4e90ebc5972faa160c3):
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 40224 W: 5578 L: 5484 D: 29162

bench: 7543902
2016-06-25 11:46:17 +02:00
ElbertoOne c2c0e6b07d Remove redundant PvNode condition
After commit 6d58bf777c we always call PvNodes
with cutNode set to false.

No functional change.
2016-06-24 08:46:36 +02:00
VoyagerOne c94145b65c Comment out a redundant condition
Take advantage that VALUE_NONE = 32002 to remove
the condition.

Commented out and not removed becuase it is tricky
to rely on the hidden value of VALUE_NONE and code
can break in case we change VALUE_NONE in the future.

No functional change.
2016-06-24 08:26:39 +02:00
Jonathan Calovski 09efbf915e Remove scalefactor dependency
STC
http://tests.stockfishchess.org/tests/view/5764539e0ebc5972faa160a4
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 43878 W: 8289 L: 8208 D: 27381

LTC
http://tests.stockfishchess.org/tests/view/5764f0130ebc5972faa160c9
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 39338 W: 5408 L: 5313 D: 28617

bench: 7977279
2016-06-21 09:01:39 +02:00
ElbertoOne 6d58bf777c On IID do not always search with cutNode = true
On IID now search with cutNode value instead of fixed value true.

STC (http://tests.stockfishchess.org/tests/view/575fa3860ebc5972faa15f67):
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 163974 W: 30744 L: 30874 D: 102356

LTC (http://tests.stockfishchess.org/tests/view/5763b0640ebc5972faa16075):
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 48363 W: 6611 L: 6528 D: 35224

Bench: 7806393
2016-06-19 18:04:22 +02:00
VoyagerOne 1c0c4db677 Simplify Check Extension
STC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 32704 W: 6146 L: 6045 D: 20513

LTC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 146622 W: 19967 L: 20017 D: 106638

Bench: 8245662
2016-06-18 08:32:25 +02:00
ajithcj 8e45e70e55 Don't insert pv back into tt
This code was added before the accurate pv patch, when
we retrieved PV directly from TT.

It's not required for correct (and long) PVs any more and
should be safe to remove it.

Also, allowing helper threads to repeatedly over-write
TT doesn't seem to make sense(that was probably an un-intended
side-effect of lazy smp). Before Lazy SMP only Main Thread used
to run ID loop and insert PV into TT.

STC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 74346 W: 13946 L: 13918 D: 46482

LTC
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 47265 W: 6531 L: 6447 D: 34287

bench: 8819179
2016-06-15 08:55:40 +02:00
lucasart 126036abb0 Do not hardcode Debug Log File
Allow to specifiy the log file name, this comes
handy in case of self-matches so that each SF
instance writes into a different log file.

No functional change.
2016-06-15 08:47:08 +02:00
Marco Costalba ca14345ba2 Filter root moves filter before copy to threads
Currently root moves are copied to all teh threads
but are DTZ filtered only in main thread at the
beginning of teh search.

This patch moves the TB filtering before the
copy of root moves fixing issue #679

https://github.com/official-stockfish/Stockfish/issues/679

No bench change.
2016-06-11 09:24:40 +02:00
VoyagerOne 7d2a79f037 Stat Formula Tweak
bonus = d * d + 2 * d - 2

STC:
LLR: 2.94 (-2.94,2.94) [0.00,4.00]
Total: 99444 W: 18274 L: 17778 D: 63392

LTC:
LLR: 2.95 (-2.94,2.94) [0.00,4.00]
Total: 89757 W: 12285 L: 11896 D: 65576

bench: 8276130
2016-06-10 07:27:47 +02:00
VoyagerOne 7c5d724724 Tweak check extension condition
There are two concepts with this patch:

Limit check extensions by using move count.
The idea is to limit search explosion.

Always extend check if the first move gives check.
The idea is to save expensive SEE calls, since the vast
majority of first move will have SEE value >= 0, also
first move may still be strong even if the SEE is negative.

STC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 16503 W: 3068 L: 2873 D: 10562

LTC:
LLR: 2.97 (-2.94,2.94) [0.00,5.00]
Total: 37202 W: 5261 L: 5014 D: 26927

bench: 8543366
2016-06-10 07:15:56 +02:00
Alain SAVARD 6fed8ff22a Small Queen simplification
Moving a few lines from evaluate_threats to evaluate_pieces allows to
a) Remove a condition pos.count<QUEEN>(Them) == 1
b) use precalculated s instead of pos.square(Them)
c) do not check the condition at all in queenless endings

Passed STC
http://tests.stockfishchess.org/tests/view/5752e0410ebc59029919b1f4
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 67175 W: 12194 L: 12152 D: 42829

and LTC
http://tests.stockfishchess.org/tests/view/57587b140ebc59029919b2f4
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 20276 W: 2774 L: 2653 D: 14849

bench: 7907962
2016-06-10 06:53:07 +02:00
mstembera 0c076f1136 Avoid some redundant scaling function calls
Posted by Mohammed Li here:
https://groups.google.com/forum/?fromgroups=#!topic/fishcooking/N-PHfN0O79o

No functional change.
2016-06-10 06:43:37 +02:00
ElbertoOne e48c7547c5 LMR reduction parameter tweak
More reduction for cut nodes, less for moves that escape a capture:

STC (http://tests.stockfishchess.org/tests/view/57548c1e0ebc59029919b247):
LLR: 2.96 (-2.94,2.94) [0.00,4.00]
Total: 60165 W: 11519 L: 11149 D: 37497

LTC (http://tests.stockfishchess.org/tests/view/57555b570ebc59029919b260):
LLR: 2.95 (-2.94,2.94) [0.00,4.00]
Total: 10353 W: 1493 L: 1317 D: 7543

Bench: 8902859
2016-06-07 15:15:49 +02:00
Marco Costalba 6e2ca97d93 Fix syzygy DTZ bug
In this position: 3K4/8/3k4/8/4p3/4B3/5P2/8 w - - 0 5

Current DTZ probe returns 1 instead of 15

What happens is that the double push f4 is erroneously detected as a win move.

After the push we have:

[D]3K4/8/3k4/8/4pP2/4B3/8/8 b - f3 0 5

And here the code misses the possible ep capture exf3.

The bug is in probe_dtz_no_ep() where is used probe_ab() that is
blind to ep captures so it returns v == 2 (win) for position

3K4/8/3k4/8/4pP2/4B3/8/8 b - f3 0 5

Note that at the caller site the original position did not have any
possible ep capture, so probe_dtz() returns immediately after calling
probe_dtz_no_ep().

The fix is to call the ep-aware probe_wdl() instead of probe_ab()

I have verified that DTZ is correct now and also there are no more
mistmatches compared to the new 'syzygy' branch. Tested on a set of
more than 600 endgame positions, included some tricky ones.

For people interested to redo the test or doing additional tests
please pull branch tb_dbg from https://github.com/mcostalba/Stockfish repo.

bench: 8450534 (bench unaffected because syzygy is not exercized during bench)
2016-06-07 15:06:26 +02:00
VoyagerOne 5f096e9bef Simplify Futility Pruning
Don't update bestValue when futility pruning.

STC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 21933 W: 4031 L: 3912 D: 13990

LTC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 46225 W: 6115 L: 6028 D: 34082

Bench: 8450534
2016-06-03 19:58:42 +02:00
ElbertoOne 20023ac9b8 LMR Simplification
LMR simplification that also gives a slight ELO gain, especially at LTC:

STC (http://tests.stockfishchess.org/tests/view/574ec8e20ebc59029919b147):
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 32402 W: 5967 L: 5866 D: 20569

LTC (http://tests.stockfishchess.org/tests/view/574fbebf0ebc59029919b16d):
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 15103 W: 2103 L: 1975 D: 11025

Bench: 8248133
2016-06-03 19:53:04 +02:00
joergoster 3549d98d07 Tuned values for piece check and attack unit factors
A middle ground patch of two successful tuning patches,
one at STC, the other at LTC, which now passed both.

LLR: 2.95 (-2.94,2.94) [0.00,4.00]
Total: 67893 W: 12777 L: 12384 D: 42732

LLR: 2.95 (-2.94,2.94) [0.00,4.00]
Total: 30165 W: 4189 L: 3960 D: 22016

bench: 9209507
2016-06-03 07:39:27 +02:00
Stéphane Nicolet 07b247f943 Pins or discovered attacks on the opponent's queen
Bonus for pins or discovered attacks on the opponent's queen

STC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 32020 W: 5914 L: 5652 D: 20454

LTC:
LLR: 2.97 (-2.94,2.94) [0.00,5.00]
Total: 10946 W: 1530 L: 1375 D: 8041

Bench: 7031649
2016-05-28 14:57:58 +02:00
Stéphane Nicolet abac509ccb Teach check_blockers to check also non-king pieces
This is a prerequisite for next patch

No functional change.
2016-05-28 14:52:21 +02:00
Stéphane Nicolet ab0f4c0353 Simplify doubled pawn
Only use doubled pawn malus when the doubled pawns are on consecutive squares.

Passed STC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 7678 W: 1469 L: 1325 D: 4884

And LTC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 26739 W: 3562 L: 3449 D: 19728

Bench: 8211685
2016-05-26 12:33:44 +02:00
Leonid Pechenik 71bfbb22fc More detailed dependence of time allocation on the magnitude of score change
10+0.1:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 5657 W: 1130 L: 979 D: 3548

60+0.6:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 36884 W: 5002 L: 4762 D: 27120

bench: 8428997
2016-05-20 19:44:50 +02:00
loco-loco 7cb8cbb403 Assorted pruning tweaks
LTC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 38257 W: 5206 L: 4961 D: 28090

STC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 16550 W: 3110 L: 2914 D: 10526

Bench: 8428997
2016-05-20 19:34:49 +02:00
mstembera 0784bd542b Fix a multiPV bug in lazy SMP
Where the helper threads were not doing multiPV at all.

Regression tested sprt @ 5+0.05 th 7

LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 73918 W: 11891 L: 11853 D: 50174

bench: 8716243
2016-05-14 21:34:55 +02:00
Stéphane Nicolet 16c603ce9b Double pawn simplification
Try doubled pawn simplification, with psq
table compensation.

STC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 36094 W: 6558 L: 6463 D: 23073

LTC:
LLR: 2.94 (-2.94,2.94) [-3.00,1.00]
Total: 102352 W: 13417 L: 13404 D: 75531

Bench: 8716243
2016-05-13 13:01:59 +02:00
loco-loco 969982406c Merge good and bad quiets
STC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 58613 W: 10779 L: 10723 D: 37111

LTC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 33608 W: 4539 L: 4436 D: 24633

Bench: 9441294
2016-05-10 18:15:16 +02:00
Alain SAVARD 4b9ed6566a Unsafe checks
Introducing a new multi-purpose penalty related to King safety, which
includes all kind of potential checks (from unsafe or unavailable
squares currently occupied by some other piece)

This will indirectly detect and reward some pins, discovered checks, and
motifs such as square vacation, or rook behind its pawn and aligned with
King (example Black Rg8, g7 against Kg1),
and penalize some pawn blockers (if they move, it allows a discovered
check by the pawn).

And since it looks also at protected squares, it detects some potential
defense overloading.

Finally, the rook contact checks had been removed some time ago. This
test will give a small bonus for them, as well as for bishop contact
checks.

Passed STC
http://tests.stockfishchess.org/tests/view/5729ec740ebc59301a354b36
LLR: 2.94 (-2.94,2.94) [0.00,5.00]
Total: 13306 W: 2477 L: 2296 D: 8533

and LTC
http://tests.stockfishchess.org/tests/view/572a5be00ebc59301a354b65
LLR: 2.97 (-2.94,2.94) [0.00,5.00]
Total: 20369 W: 2750 L: 2565 D: 15054

bench: 9298175
2016-05-06 20:04:57 +02:00
Marco Costalba 5e4cd3fc0d Retire __popcnt64 intrinsic
Just use _mm_popcnt_u64() that is available
both for MSVC abd Intel compiler.

Verified on MSVC that the produced assembly
has the hardware 'popcnt' instruction.

No functional change.
2016-05-05 09:09:07 +02:00
VoyagerOne 5486911e01 Simplify History LMR Formula
STC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 41713 W: 7589 L: 7504 D: 26620

LTC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 41353 W: 5484 L: 5391 D: 30478

Bench: 8946983
2016-05-05 08:53:50 +02:00
Marco Costalba 3487eb9f9e Fix a warning with MSVC
Introduced by 2dd24dc4e6 ("Use popcount intrinsic with Intel")

No functional change.
2016-05-01 15:10:33 +02:00
joergoster dc0030de4f Fix LazySMP when searching to a fixed depth.
Currently, helper threads will only search up to the
specified depth limit. Now let them search until the
main thread has finished the specified depth.

On the other hand, we don't want to pick a thread with
a higher search depth.

This may be considered cheating. ;-)

No functional change.
2016-05-01 14:30:50 +02:00
erbsenzaehler 2dd24dc4e6 Use popcount intrinsic with Interl compiler
It seems that icc used our fallback version of popcount.
Now use intrinsics.

icc version 16.0.2 (gcc version 5.3.0 compatibility)
bmi2 compile
uname -r 4.5.1-1-ARCH

20xbench gives a nice speedup
./stockfish-icc-master 2161515 +- 34462
./stockfish-icc-sse42 2260857 +- 50349
2016-05-01 14:18:16 +02:00
Krgp 8f934dff9a Remove useless -mbmi flag in Makefile
I could not find anything documented that is necessary that prepending -mbmi to -mbmi2 gives some benefit.
Instead at
https://gcc.gnu.org/onlinedocs/gcc/x86-Built-in-Functions.html#x86-Built-in-Functions

The following built-in functions are available when -mbmi is used. All of them generate the machine instruction that is part of the name.
unsigned int __builtin_ia32_bextr_u32(unsigned int, unsigned int);
unsigned long long __builtin_ia32_bextr_u64 (unsigned long long, unsigned long long);

The following built-in functions are available when -mbmi2 is used. All of them generate the machine instruction that is part of the name.
unsigned int _bzhi_u32 (unsigned int, unsigned int)
unsigned int _pdep_u32 (unsigned int, unsigned int)
unsigned int _pext_u32 (unsigned int, unsigned int)
unsigned long long _bzhi_u64 (unsigned long long, unsigned long long)
unsigned long long _pdep_u64 (unsigned long long, unsigned long long)
unsigned long long _pext_u64 (unsigned long long, unsigned long long)

and at
https://gcc.gnu.org/ml/gcc/2014-02/msg00204.html

( "... The real optimization comes from being able to use pext
(parallel bit extract), which can implement several bextr expressions in
parallel.")

Apart from that we don't use all -msse -msse2 -msse3 -msse4.2 etc. but just -msse3 (or -msse4.2) only.

As regards to the speedup within noise level - this pull request is actually reversal of mcostalba#198 wherein prepending -mbmi to -mbmi2 was claimed to be 0.3% faster and here (removing -mbmi) gives 0.4% speed gain.
2016-05-01 14:11:28 +02:00
Stéphane Nicolet 2694ef23c3 Isolated pawn simplification
STC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 117822 W: 21697 L: 21744 D: 74381

LTC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 92307 W: 12330 L: 12305 D: 67672

Bench: 8813983

Resolves #659
2016-04-30 22:23:22 +01:00
VoyagerOne e082112cfe Use FMHs to assist with LMR formula.
STC:
LLR: 2.99 (-2.94,2.94) [0.00,5.00]
Total: 52232 W: 9654 L: 9304 D: 33274

LTC:
LLR: 2.97 (-2.94,2.94) [0.00,5.00]
Total: 115988 W: 15550 L: 15049 D: 85389

Bench: 7890808

Resolves #651
2016-04-24 01:00:58 +01:00
erbsenzaehler 4048bae47b Use -O3 for all compilers (including ICC)
There seems to be no benefit from using -fast over -O3 with icc.
So use -O3 everywhere.

No functional change

Resolves #652
2016-04-24 00:55:56 +01:00
DU-jdto c737062436 Remove some pointless micro-optimizations
Seems to give around 1% speed-up for CPUs with popcnt support.
Seems to give a very minor speed-up for CPUs without popcnt.

No functional change

Resolves #646
2016-04-23 02:04:28 +01:00
Marco Costalba 94e41274bb Fix incorrect draw detection
In this position we should have draw for repetition:

position fen rnbqkbnr/2pppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1 moves g1f3 g8f6 f3g1
go infinite

But latest patch broke it.

Actually we had two(!) very subtle bugs, the first is that Position::set()
clears the passed state and in particular 'previous' member, so
that on passing setupStates, 'previous' pointer was reset.

Second bug is even more subtle: SetupStates was based on std::vector
as container, but when vector grows, std::vector copies all its contents
to a new location invalidating all references to its entries. Because
all StateInfo records are linked by 'previous' pointer, this made pointers
go stale upon adding more element to setupStates. So revert to use a
std::deque that ensures references are preserved when pushing back new
elements.

No functional change.
2016-04-18 00:13:16 +02:00
loco-loco ec6aab0136 Add a second level of follow-up moves
STC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 6438 W: 1229 L: 1077 D: 4132

LTC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 4000 W: 605 L: 473 D: 2922

bench: 7378965

Resolves #636
2016-04-17 15:19:20 +01:00
Marco Costalba 7eaea3848c StateInfo is usually allocated on the stack by search()
And passed in do_move(), this ensures maximum efficiency and
speed and at the same time unlimited move numbers.

The draw back is that to handle Position init we need to
reserve a StateInfo inside Position itself and use at
init time and when copying from another Position.

After lazy SMP we don't need anymore this gimmick and we can
get rid of this special case and always pass an external
StateInfo to Position object.

Also rewritten and simplified Position constructors.

Verified it does not regress with a 3 threads SMP test:
ELO: -0.00 +-12.7 (95%) LOS: 50.0%
Total: 1000 W: 173 L: 173 D: 654

No functional change.
2016-04-17 08:29:33 +02:00
Niklas Fiekas ee7a68ea5f Fix last search info carried over to mate position
When starting search in a mate or stalemate position, Stockfish does not
even care to reinitialize and start worker threads. However after search
all threads are checked for the best move.

This can lead to bestmove and info beeing carried over from the last
search.

Example session:

    setoption name threads value 7
    go movetime 4000
    position startpos moves f2f3 e7e5 g2g4 d8h4
    go movetime 4000

Actual output is like (almost always):

    [...]
    bestmove e2e4
    info depth 0 score mate 0
    info depth 20 seldepth 29 multipv 1 score cp 28 [...] pv e2e4
    bestmove e2e4

Expected output / output after fix:

    [...]
    bestmove e2e4 ponder e7e6
    info depth 0 score mate 0
    bestmove (none)

Resolves #623
2016-04-16 10:22:36 +01:00
Marco Costalba d30994ecd5 Hide global visibility when not needed
Also move PieceValue definition in psqt.cpp,
where it is initialized.

Fix a warning in popcount16() with Intel compiler

No functional change.
2016-04-09 10:42:04 +02:00
Marco Costalba bd04f9a0f1 Fix Travis Cl
Broken after "32-bit/64-bit Makefile fix" commit.

Ubuntu "Precise" 12.04.5 supports multilib only until
g++ 4.6 that is not enough to compile Stockfish.

So move to Ubuntu 14.04.4 LTS (Trusty Tahr)

No functional change.
2016-04-09 09:35:19 +02:00
DU-jdto 1cbba8d6fa Small passed pawn simplification
STC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 21993 W: 4197 L: 4078 D: 13718

LTC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 67213 W: 9135 L: 9077 D: 49001

Bench: 7482426

Resolves #622
2016-04-08 19:48:03 +01:00
Alain SAVARD e9e5f72c74 Undefended King Ring
There was already a penalty for squares only defended by King (undefended)

This test records a penalty for completely undefended squares in the so called extended king-ring
(so if we exclude squares defended by a Kg8 for example, we only look at h6 g6 and f6)

We also exclude squares occupied by opponent pieces in this computation,
based on the following results

Was yellow at STC
LLR: -2.97 (-2.94,2.94) [0.00,5.00]
Total: 112499 W: 20649 L: 20293 D: 71557

and passed LTC
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 36805 W: 5100 L: 4857 D: 26848

Bench: 8430233

Resolves: #619
2016-04-08 19:22:33 +01:00
Alain SAVARD 29b5842da8 Backward simplication
On top of the usual conditions
a) some opponent in front (but no lever)
b) some neighbours (in front) (but no neighbour behind or same rank)
c) < rank_5

to find out if a pawn is backward we look at the squares in front of this pawn to reach the same rank as the next neighbour.

In current master, a pawn is backward if any of those squares is controlled by an enemy pawn on an adjacent file

In this version, a pawn is ALSO backward if any of those squares is occupied by an enemy pawn.

STC:
http://tests.stockfishchess.org/tests/view/56fe7efd0ebc59301a3541f1
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 19051 W: 3557 L: 3433 D: 12061

LTC:
http://tests.stockfishchess.org/tests/view/56febc2d0ebc59301a354209
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 40810 W: 5619 L: 5526 D: 29665

Bench: 7525245

Resolves #614
2016-04-08 19:12:55 +01:00
mstembera 8fb45caade Simplify popcnt
Also a speedup(about 1%) on 64-bit w/o hardware popcnt

Retire Max15 and Full template parameters
(Contributed by Marco Costalba)

Now that we have just SW and HW versions, use
template default parameter to get rid of explicit
template parameters.

Retire bitcount.h and move the only defined
function to bitboard.h

No functional change

Resolves #620
2016-04-08 18:52:15 +01:00
lucasart 900279a06f 32-bit/64-bit Makefile fix
Counter intuitively, make build ARCH=x86-32 does NOT produce a 32-bit compile
when running a 64-bit OS. Nor would ARCH=x86-64 produce a 64-bit compile when
running a 32-bit OS (assuming it compiled w/o errors).

No functional change

Resolves #621
2016-04-08 18:47:31 +01:00
NicklasPersson d5b24ad77b A combo patch of two tuning patches
STC:
LLR: 2.96 (-2.94,2.94) [0.00,4.00]
Total: 14223 W: 2700 L: 2494 D: 9029

LTC:
LLR: 2.96 (-2.94,2.94) [0.00,4.00]
Total: 66294 W: 9065 L: 8739 D: 48490

Bench: 7607385

Resolves #612
2016-03-31 13:26:00 +01:00
lucasart f256388e08 Guard against UB in lsb/msb
lsb(b) and msb(b) are undefined when b == 0. This can lead to subtle bugs, where
the resulting code behaves differently on different configurations:
- It can be the home grown software LSB/MSB
- It can be the compiler generated software LSB/MSB (when using compiler
  intrinsics without the right compiler flags to allow compiler to use hardware
  LSB/MSB). Which of course depends on the compiler.
- It can be hardware LSB/MSB generated by the compiler.
- Not to mention that hardware LSB/MSB can return different value on different
  hardware when b == 0.

No functional change

Resolves #610
2016-03-31 13:22:37 +01:00
Marco Costalba db4b0d8b7d Rewrite bsfq management
Use compiler intrinsics when possible to
avoid writing platform specific asm code.

Tested on Windows 7 with MSVC 2013 and mingw 4.8.3 (32 and 64 bit)
and on Linux Mint with g++ 4.8.4 and clang 3.4 (32 and 64 bit).

No functional change

Resolves #609
2016-03-28 15:46:55 +01:00
snicolet 24dac5ccd3 Bonus for loose enemies
STC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 30504 W: 5743 L: 5485 D: 19276

LTC:
LLR: 2.97 (-2.94,2.94) [0.00,5.00]
Total: 11936 W: 1651 L: 1493 D: 8792

Bench: 8880041

Resolves #606
2016-03-27 20:56:54 +01:00
mbootsector 8788612828 Raise endgame passed pawn and material values
STC:
LLR: 2.95 (-2.94,2.94) [0.00,4.00]
Total: 136149 W: 25213 L: 24588 D: 86348

LTC:
LLR: 2.95 (-2.94,2.94) [0.00,4.00]
Total: 54637 W: 7533 L: 7238 D: 39866

Bench: 8546808

Resolves #608
2016-03-27 20:22:48 +01:00
fanon 5d1644ba69 Simplify pawns King Safety calculation
STC
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 130209 W: 23516 L: 23581 D: 83112

LTC
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 33541 W: 4563 L: 4460 D: 24518

Bench: 8644370

Resolves #604
2016-03-27 20:08:56 +01:00
VoyagerOne 60590577f2 A small simplification in movepick.h
No functional change

Resolves #597
2016-03-14 20:54:49 -07:00
mstembera 04be84e0e2 Simplify Safe Checks
STC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 11796 W: 2211 L: 2074 D: 7511

LTC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 14324 W: 1935 L: 1806 D: 10583

Bench: 8075202

Resolves #600
2016-03-14 20:51:16 -07:00
Marco Costalba 647402ff79 Assorted cleanup of latest commits
No functional change.

Resolves #601
2016-03-14 20:42:44 -07:00
Stefan Geschwentner a273b6ef8c Add followup moves history for move ordering
STC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 7955 W: 1538 L: 1378 D: 5039

LTC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 5323 W: 778 L: 642 D: 3903

Bench: 8261839

Resolves #599
2016-03-10 14:26:06 -08:00
mbootsector e1a7d135b2 Passed pawn bonus simplification
STC: (yellow)

LLR: -2.96 (-2.94,2.94) [0.00,4.00]
Total: 86114 W: 16063 L: 15921 D: 54130

LTC:

LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 14347 W: 2025 L: 1896 D: 10426

Bench: 8576437

Resolves #595
2016-03-02 19:10:56 +00:00
snicolet c1be0c68c7 Tweak initiative formula
Give more weight to the pawns number and
the vertical king distance in evaluate_initiative()

Passed STC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 26729 W: 5067 L: 4825 D: 16837

and LTC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 60480 W: 8338 L: 8016 D: 44126

Bench: 8295162

Resolves #594
2016-03-02 00:02:03 +00:00
ElbertoOne c13052f344 Clean up depth reduction calculation
Might also be a slight speed up

No functional change

Resolves #593
2016-02-28 13:40:47 +00:00
joergoster 8de29390f2 Pass endgame value to evaluate_scale_factor()
No functional change

Resolves #592
2016-02-28 13:35:34 +00:00
VoyagerOne 45a309d92e Simplify Reduction Formula
Formula now only contains one coefficient. Making it much easier to tune.

STC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 187443 W: 34858 L: 35028 D: 117557

LTC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 88329 W: 11982 L: 11953 D: 64394

Bench: 7521394

Resolves #591
2016-02-28 13:31:25 +00:00
Leonid Pechenik d5ba8e827d Revert "Remove slowMover"
This reverts commit 77fa960f89.

Resolves #590
2016-02-28 13:25:05 +00:00
IIvec 77fa960f89 Remove slowMover
Removes a slowMover and one paramater from move_importance function.

STC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 77023 W: 14456 L: 14433 D: 48134

LTC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 37175 W: 5190 L: 5092 D: 26893

Resolves #589
2016-02-21 20:16:28 +00:00
VoyagerOne bfe9044ad9 History Stat Formula Simplification
STC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 67476 W: 12561 L: 12521 D: 42394

LTC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 111923 W: 15147 L: 15149 D: 81627

Bench: 8430465

Resolves #588
2016-02-21 20:12:33 +00:00
VoyagerOne 744ed85a4d Fix futility pruning bug
PredictedDepth can be negative, causing the futility_margin to be negative.
It will be very difficult to tweak moveCount pruning and reduction formula, as they are tuned to prevent this behavior.

No functional change

Resolves #587
2016-02-14 19:48:46 +00:00
hxim 56dd58e6f9 Remove Weights
Removed remaining redundant weights for pawn structure,
passed pawns, space and king safety by redistributing them
into individual evaluation terms.

STC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 15173 W: 2790 L: 2659 D: 9724

LTC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 43433 W: 5936 L: 5846 D: 31651

Bench: 7156237

Resolves #586
2016-02-07 21:00:24 +00:00
Marco Costalba 4f6aa15228 Document HalfDensityMap
No functional change.

Resolves #584
2016-02-07 20:54:25 +00:00
Leonid Pechenik aedebe35cf Time management simplification
10+0.1:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 41963 W: 7967 L: 7883 D: 26113

60+0.6:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 132314 W: 17939 L: 17969 D: 96406

Resolves #580
2016-01-29 00:47:07 +00:00
Guenther Demetz 9a10313a9d rotating symmetric patterns with increasing skipsize
STC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00] sprt @ 5+0.1 th 21
Total: 7068 W: 1121 L: 975 D: 4972

LTC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00] sprt @ 12+0.12 th 21
Total: 26691 W: 3594 L: 3481 D: 19616

No functional change with a single thread

Resolves #574
2016-01-24 14:08:01 +00:00
Joona Kiiski 8c3a5bbc52 Do not probe syzygy bases when castling is possible
Almost no functional change. Bench is unchanged.

Resolves #230
Resolves #573
2016-01-20 15:24:21 +00:00
lucasart 28933a580e Retire RootNode template
There is no reason to compile 3 different copies of search(). PV nodes are on
the cold path, and PvNode is a template parameter, so there is no cost in
computing:

const bool RootNode = PvNode && (ss-1)->ply == 0;

And this simplifies code a tiny bit as well.

Speed impact is negligible on my machine (i7-3770k, linux 4.2, gcc 5.2):

            nps   +/-
test    2378605  3118
master  2383128  2793
diff      -4523  2746

Bench: 7751425

No functional change.

Resolves #568
2016-01-18 22:21:42 +00:00
Guenther Demetz 12eb345ebd Depth margin parameter-tweak in TT-save
Verified that is improvement with multiple threads:

LLR: 2.95 (-2.94,2.94) [0.00,4.00] sprt @ 30+0.3 th 3
Total: 14817 W: 2103 L: 1915 D: 10799

LLR: 2.96 (-2.94,2.94) [0.00,4.00] sprt @ 15+0.15 th 7
Total: 10264 W: 1498 L: 1321 D: 7445

Verified that is not a significant regression with a single thread:

LLR: 2.96 (-2.94,2.94) [-4.00,0.00] sprt @ 60+0.6 th 1
Total: 23975 W: 3294 L: 3210 D: 17471

Resolves #575
2016-01-18 22:04:38 +00:00
Joona Kiiski ebec2fa48e Remove redundant -std=c++0x flag
This flag is functionally identical to '-std=c++11' flag which
is part of standard flags.

No functional change

Resolves #571
2016-01-18 21:54:40 +00:00
Joona Kiiski 552b3ccb66 Makefile: Allow specifying compiler executable
No functional change

Resolves #570
2016-01-18 21:47:52 +00:00
Marco Costalba 356147d99a Rewrite time formula
Time management is really too complex, our aim is
to simplify it, but for time being at least rewrite
in an understandable way.

No functional change.
2016-01-18 17:12:18 +01:00
Lyudmil Antonov 89723339d9 Assorted English grammar changes
No functional change

Resolves #567
2016-01-16 21:34:29 +00:00
Stefano80 74e2fa97b7 Adjust reductions based on history and cmh tables
STC:
LLR: 4.06 (-2.94,2.94) [0.00,5.00]
Total: 149395 W: 28029 L: 27208 D: 94158

LTC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 9628 W: 1368 L: 1217 D: 7043

bench: 8076724

Resolves #565
2016-01-13 16:18:35 +00:00
Stefano80 dcd8ce7094 Update comments in LMR step
No functional change

Resolves #564
2016-01-13 16:03:53 +00:00
Leonid Pechenik 4d1220d672 Tune time management for LTC
60+0.6:
LLR: 2.96 (-2.94,2.94) [0.00,4.00]
Total: 102533 W: 14270 L: 13842 D: 74421

Resolves #558
2016-01-09 09:21:52 +00:00
lucasart aa31f7f096 Retire CenterBind
And compensate in the PSQT.

STC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 27714 W: 5161 L: 5052 D: 17501

LTC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 36354 W: 5008 L: 4909 D: 26437

Bench: 8603285

Resolves #556
2016-01-03 17:33:36 +00:00
Alain SAVARD 1de97337c2 Fine tuning of unsupported pawn penalty
Adjust the unsupported pawn penalty when the pawn is supporting 2 pawns
(for example g7 in f6-g7-h6)

Passed STC
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 23833 W: 4384 L: 4158 D: 15291

Passed LTC
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 42711 W: 5918 L: 5655 D: 31138

Bench: 8390233

Resolves #549
2016-01-03 14:15:29 +00:00
Leonid Pechenik 9eceb894ac Adjust time used for move based on previous score
Use less time if evaluation is not worse than for previous move and even less time if in addition no fail low encountered for current iteration.

STC: 10+0.1
ELO: 5.37 +-2.9 (95%) LOS: 100.0%
Total: 20000 W: 3832 L: 3523 D: 12645

STC: 10+0.1
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 17527 W: 3334 L: 3132 D: 11061

LTC: 60+0.6
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 28233 W: 3939 L: 3725 D: 20569

LTC: 60+0.6
ELO: 2.43 +-1.4 (95%) LOS: 100.0%
Total: 60000 W: 8266 L: 7847 D: 43887

LTC: 60+0.06
LLR: 2.95 (-2.94,2.94) [-1.00,3.00]
Total: 38932 W: 5408 L: 5207 D: 28317

Resolves #547
2016-01-03 14:01:15 +00:00
Joona Kiiski 5972c4a678 Restore development version 2016-01-03 13:52:01 +00:00
50 changed files with 5363 additions and 5240 deletions
+35 -11
View File
@@ -1,4 +1,6 @@
language: cpp language: cpp
sudo: required
dist: trusty
matrix: matrix:
include: include:
@@ -7,25 +9,25 @@ matrix:
addons: addons:
apt: apt:
sources: ['ubuntu-toolchain-r-test'] sources: ['ubuntu-toolchain-r-test']
packages: ['g++-4.8'] packages: ['g++-6', 'g++-6-multilib', 'g++-multilib', 'valgrind', 'expect']
env: env:
- COMPILER=g++-4.8 - COMPILER=g++-6
- COMP=gcc - COMP=gcc
- os: linux - os: linux
compiler: clang compiler: clang
addons: addons:
apt: apt:
sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.7'] sources: ['ubuntu-toolchain-r-test']
packages: ['clang-3.7'] packages: ['clang', 'g++-multilib', 'valgrind', 'expect']
env: env:
- COMPILER=clang++-3.7 - COMPILER=clang++
- COMP=clang - COMP=clang
- os: osx - os: osx
compiler: gcc compiler: gcc
env: env:
- COMPILER=g++-4.8 - COMPILER=g++
- COMP=gcc - COMP=gcc
- os: osx - os: osx
@@ -42,8 +44,30 @@ before_script:
- cd src - cd src
script: script:
- make clean && make build ARCH=x86-64 && ./stockfish bench 2>&1 >/dev/null | grep 'Nodes searched' | tee bench1 # Obtain bench reference from git log
- make clean && make build ARCH=x86-32 && ./stockfish bench 2>&1 >/dev/null | grep 'Nodes searched' | tee bench2 - git log HEAD | grep "\b[Bb]ench[ :]\+[0-9]\{7\}" | head -n 1 | sed "s/[^0-9]*\([0-9][0-9]*\)/\1/g" > git_sig
- echo "Checking for same bench numbers..." - export benchref=$(cat git_sig)
- diff bench1 bench2 > result - echo "Reference bench:" $benchref
- test ! -s result #
# Verify bench number against various builds
- export CXXFLAGS=-Werror
- make clean && make -j2 ARCH=x86-64 optimize=no debug=yes build && ../tests/signature.sh $benchref
- make clean && make -j2 ARCH=x86-32 optimize=no debug=yes build && ../tests/signature.sh $benchref
- make clean && make -j2 ARCH=x86-32 build && ../tests/signature.sh $benchref
- make clean && make -j2 ARCH=x86-64 build && ../tests/signature.sh $benchref
#
# Check perft and reproducible search
- ../tests/perft.sh
- ../tests/reprosearch.sh
#
# Valgrind
#
- export CXXFLAGS=-O1
- if [ -x "$(command -v valgrind )" ]; then make clean && make -j2 ARCH=x86-64 debug=yes optimize=no build > /dev/null && ../tests/instrumented.sh --valgrind; fi
- if [ -x "$(command -v valgrind )" ]; then ../tests/instrumented.sh --valgrind-thread; fi
#
# Sanitizer
#
# Use g++-6 as a proxy for having sanitizers, might need revision as they become available for more recent versions of clang/gcc
- if [[ "$COMPILER" == "g++-6" ]]; then make clean && make -j2 ARCH=x86-64 sanitize=undefined optimize=no debug=yes build > /dev/null && ../tests/instrumented.sh --sanitizer-undefined; fi
- if [[ "$COMPILER" == "g++-6" ]]; then make clean && make -j2 ARCH=x86-64 sanitize=thread optimize=no debug=yes build > /dev/null && ../tests/instrumented.sh --sanitizer-thread; fi
+42 -42
View File
@@ -1,98 +1,98 @@
# Generated with git shortlog -sn | cut -c8-', which sorts by commits (manually ordered the first four authors) # Generated with 'git shortlog -sn | cut -c8-', which sorts by commits, manually ordered the first four authors, merged duplicates
Tord Romstad Tord Romstad
Marco Costalba Marco Costalba (mcostalba)
Joona Kiiski Joona Kiiski (zamar)
Gary Linscott Gary Linscott (glinscott)
lucasart Lucas Braesch (lucasart)
Bill Henry (VoyagerOne)
mstembera mstembera
Lucas Braesch Stéphane Nicolet (Stephane Nicolet, snicolet)
Stefan Geschwentner Stefan Geschwentner
Alain SAVARD (Rocky640)
Jörg Oster (Joerg Oster, joergoster)
Reuven Peleg Reuven Peleg
Chris Caino Chris Caino (Chris Cain, ceebo)
joergoster
VoyagerOne
Jean-Francois Romang Jean-Francois Romang
homoSapiensSapiens homoSapiensSapiens
Alain SAVARD
Arjun Temurnikar
Stéphane Nicolet
Uri Blass
jundery
Ralph Stößer
Ajith
Leonid Pechenik Leonid Pechenik
Stefano80 Stefano Cardanobile (Stefano80)
Tom Vijlbrief Arjun Temurnikar
Uri Blass (uriblass)
jundery
Ajith (ajithcj)
hxim hxim
snicolet Ralph Stößer (Ralph Stoesser)
Daylen Yang Guenther Demetz
Henri Wiechers Jonathan Calovski (Mysseno)
Jonathan Calovski Tom Vijlbrief
mbootsector mbootsector
Daylen Yang
ElbertoOne
Henri Wiechers
loco-loco
Joost VandeVondele (Joost Vandevondele)
Ronald de Man (syzygy)
DU-jdto
David Zar David Zar
Eelco de Groot Eelco de Groot
Jerry Donald Jerry Donald
Joerg Oster NicklasPersson
Jörg Oster
Ryan Schmitt Ryan Schmitt
mcostalba
Alexander Kure Alexander Kure
Dan Schmidt Dan Schmidt
H. Felix Wittmann H. Felix Wittmann
Jacques
Joseph R. Prostko Joseph R. Prostko
Justin Blanchard Justin Blanchard
Linus Arver Linus Arver
NicklasPersson Luca Brivio
Lyudmil Antonov
Rodrigo Exterckötter Tjäder Rodrigo Exterckötter Tjäder
Ron Britvich Ron Britvich
Ronald de Man
RyanTaker RyanTaker
Vince Negri Vince Negri
ceebo erbsenzaehler
jhellis3 Joseph Hellis (jhellis3)
ppigazzini
shane31 shane31
Andrew Grant
Andy Duplain Andy Duplain
Auguste Pop Auguste Pop
Balint Pfliegel Balint Pfliegel
Chris Cain
DU-jdto
Dariusz Orzechowski Dariusz Orzechowski
DiscanX DiscanX
Ernesto Gatti Ernesto Gatti
Gregor Cramer Gregor Cramer
Guenther Demetz Hiraoka Takuya (HiraokaTakuya)
Hiraoka Takuya
Hongzhi Cheng Hongzhi Cheng
Joseph Hellis IIvec
Kelly Wilson Kelly Wilson
Ken T Takusagawa Ken T Takusagawa
Kojirion Kojirion
Luca Brivio Krgp
Matt Sullivan Matt Sullivan
Matthew Lai Matthew Lai
Matthew Sullivan Matthew Sullivan
Michel Van den Bergh Michel Van den Bergh
Mysseno Niklas Fiekas
Oskar Werkelin Ahlin Oskar Werkelin Ahlin
Pablo Vazquez Pablo Vazquez
Pascal Romaret Pascal Romaret
Ralph Stoesser
Ralph Stößer
Raminder Singh Raminder Singh
Richard Lloyd Richard Lloyd
Ryan Takker Ryan Takker
Stephane Nicolet
Thanar2 Thanar2
absimaldata absimaldata
atumanian
braich braich
fanon
gamander
gguliash gguliash
kinderchocolate kinderchocolate
loco-loco
pellanda pellanda
ppigazzini
renouve renouve
sf-x sf-x
thaspel thaspel
unknown unknown
uriblass
+11 -2
View File
@@ -1,6 +1,7 @@
### Overview ### Overview
[![Build Status](https://travis-ci.org/official-stockfish/Stockfish.svg?branch=master)](https://travis-ci.org/official-stockfish/Stockfish) [![Build Status](https://travis-ci.org/official-stockfish/Stockfish.svg?branch=master)](https://travis-ci.org/official-stockfish/Stockfish)
[![Build Status](https://ci.appveyor.com/api/projects/status/github/official-stockfish/Stockfish?svg=true)](https://ci.appveyor.com/project/mcostalba/stockfish)
Stockfish is a free UCI chess engine derived from Glaurung 2.1. It is Stockfish is a free UCI chess engine derived from Glaurung 2.1. It is
not a complete chess program and requires some UCI-compatible GUI not a complete chess program and requires some UCI-compatible GUI
@@ -9,7 +10,7 @@ Partner or Fritz) in order to be used comfortably. Read the
documentation for your GUI of choice for information about how to use documentation for your GUI of choice for information about how to use
Stockfish with it. Stockfish with it.
This version of Stockfish supports up to 128 cores. The engine defaults This version of Stockfish supports up to 512 cores. The engine defaults
to one search thread, so it is therefore recommended to inspect the value of to one search thread, so it is therefore recommended to inspect the value of
the *Threads* UCI parameter, and to make sure it equals the number of CPU the *Threads* UCI parameter, and to make sure it equals the number of CPU
cores on your computer. cores on your computer.
@@ -95,6 +96,14 @@ compile (for instance with Microsoft MSVC) you need to manually
set/unset some switches in the compiler command line; see file *types.h* set/unset some switches in the compiler command line; see file *types.h*
for a quick reference. for a quick reference.
### Resource For Understanding the Code Base
* [Chessprogramingwiki](https://chessprogramming.wikispaces.com) has good overall chess engines explanations
(techniques used here are well explained like hash maps etc), it was
also recommended by the [support at stockfish.](http://support.stockfishchess.org/discussions/questions/1132-how-to-understand-stockfish-sources)
* [Here](https://chessprogramming.wikispaces.com/Stockfish) you can find a set of features and techniques used by stockfish and each of them is explained at the wiki, however, it's a generic way rather than focusing on stockfish's own implementation, but it will still help you.
### Terms of use ### Terms of use
@@ -111,4 +120,4 @@ to where the source code can be found. If you make any changes to the
source code, these changes must also be made available under the GPL. source code, these changes must also be made available under the GPL.
For full details, read the copy of the GPL found in the file named For full details, read the copy of the GPL found in the file named
*Copying.txt* *Copying.txt*.
+132
View File
@@ -0,0 +1,132 @@
Contributors with >10,000 CPU hours as of January 23, 2018
Thank you!
Username CPU Hours Games played
mibere 518300 41835669
crunchy 375564 29121434
cw 371664 28748719
fastgm 299773 20765374
JojoM 220590 15299913
glinscott 204517 13932027
bking_US 187568 12233168
ctoks 169342 13475495
spams 149531 10940322
Thanar 137015 11714855
velislav 127305 10047749
vdbergh 121741 9056874
malala 117291 8126488
vdv 117218 8289983
leszek 114825 8331897
dsmith 114010 7622414
CSU_Dynasty 113516 9582758
sqrt2 112407 8782694
marrco 111143 8222921
drabel 108168 9061580
BrunoBanani 104938 7448565
Data 94621 8433010
CoffeeOne 90394 3964243
BRAVONE 80811 5341681
psk 77195 6156031
brabos 70284 5685893
Fisherman 66650 5572406
nssy 64587 5369140
Pking_cda 64499 5704075
sterni1971 63488 5070004
mgrabiak 62385 5420812
tvijlbrief 58957 4154234
jromang 58854 4704502
dv8silencer 57421 3961325
sunu 56620 4609155
tinker 56039 4204914
biffhero 55743 4810039
teddybaer 52982 4740444
bcross 50548 5071599
renouve 50318 3544864
Freja 50296 3805120
robnjr 47504 4131742
eva42 46542 4044694
davar 46538 4030604
finfish 46244 3481661
rap 46201 3219490
ttruscott 45037 3645430
solarlight 44155 4074841
TueRens 41372 3891510
ElbertoOne 41321 3920894
Antihistamine 39218 2792761
mhunt 38991 2697512
bigpen0r 37820 3149955
homyur 35569 3009637
VoyagerOne 35137 3302650
mhoram 34770 2684128
racerschmacer 33022 3231055
speedycpu 32043 2531964
EthanOConnor 31638 2143255
oryx 29574 2767730
Pyafue 28885 1986098
jkiiski 28014 1923255
Garf 27579 2770144
slakovv 27017 2031279
Bobo1239 27000 2488707
pb00067 26817 2306694
robal 26337 2316795
hyperbolic.tom 26248 2200777
rkl 24898 2236013
SC 23988 2126825
nabildanial 23524 1586321
achambord 23495 1942546
Sharaf_DG 22975 1790697
chriswk 22876 1947731
anst 22568 2013953
Patrick_G 22435 1682293
cuistot 22201 1383031
gri 21901 1820968
Prcuvu 21182 1890546
Zirie 21171 1493227
JanErik 20596 1791991
Isidor 20560 1730290
xor12 20535 1819280
team-oh 20364 1653708
nesoneg 20264 1493435
rstoesser 19802 1335177
grandphish2 19402 1834196
sg4032 18427 1671742
dew 18263 1423326
ianh2105 18133 1668562
MazeOfGalious 18022 1644593
ville 17900 1539130
j3corre 17607 975954
eudhan 17502 1424648
iisiraider 17175 1118788
jundery 17172 1115855
SFTUser 16635 1363975
purplefishies 16621 1106850
DragonLord 16599 1252348
chris 15274 1575333
xoto 14900 1486261
dju 14861 901552
dex 14647 1228763
nordlandia 14551 1369718
ronaldjerum 14361 1210607
OssumOpossum 14149 1029265
IgorLeMasson 13844 1228391
enedene 13762 935618
ako027ako 13442 1250249
AdrianSA 13324 924980
bpfliegel 13318 886523
ncfish1 13056 932344
wei 12863 1369596
jpulman 12776 854815
horst.prack 12436 1151505
joster 12424 986622
cisco2015 12265 1205019
fatmurphy 12015 901134
modolief 11228 926456
Dark_wizzie 11214 1017910
mschmidt 10973 818594
eastorwest 10970 1117836
infinity 10762 746397
SapphireBrand 10692 1024604
Thomas A. 10553 736094
pgontarz 10294 878746
Andrew Grant 10195 922933
stocky 10083 718114
+71
View File
@@ -0,0 +1,71 @@
version: 1.0.{build}
clone_depth: 50
branches:
only:
- master
- appveyor
# Operating system (build VM template)
os: Visual Studio 2015
# Build platform, i.e. x86, x64, AnyCPU. This setting is optional.
platform:
- x86
- x64
# build Configuration, i.e. Debug, Release, etc.
configuration:
- Debug
- Release
matrix:
# The build fail immediately once one of the job fails
fast_finish: true
# Scripts that are called at very beginning, before repo cloning
init:
- cmake --version
- msbuild /version
before_build:
- ps: |
# Get sources
$src = get-childitem -Path *.cpp -Recurse | select -ExpandProperty FullName
$src = $src -join ' '
$src = $src.Replace("\", "/")
# Build CMakeLists.txt
$t = 'cmake_minimum_required(VERSION 3.8)',
'project(Stockfish)',
'set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/src)',
'set(source_files', $src, ')',
'add_executable(stockfish ${source_files})'
# Write CMakeLists.txt withouth BOM
$MyPath = (Get-Item -Path "." -Verbose).FullName + '\CMakeLists.txt'
$Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding $False
[System.IO.File]::WriteAllLines($MyPath, $t, $Utf8NoBomEncoding)
# Obtain bench reference from git log
$b = git log HEAD | sls "\b[Bb]ench[ :]+[0-9]{7}" | select -first 1
$bench = $b -match '\D+(\d+)' | % { $matches[1] }
Write-Host "Reference bench:" $bench
$g = "Visual Studio 14 2015"
If (${env:PLATFORM} -eq 'x64') { $g = $g + ' Win64' }
cmake -G "${g}" .
Write-Host "Generated files for: " $g
build_script:
- cmake --build . --config %CONFIGURATION% -- /verbosity:minimal
before_test:
- cd src/%CONFIGURATION%
- ps: |
# Verify bench number
./stockfish bench 2> out.txt 1> null
$s = (gc "./out.txt" | out-string)
$r = ($s -match 'Nodes searched \D+(\d+)' | % { $matches[1] })
Write-Host "Engine bench:" $r
Write-Host "Reference bench:" $bench
If ($r -ne $bench) { exit 1 }
+127 -90
View File
@@ -1,7 +1,7 @@
# Stockfish, a UCI chess playing engine derived from Glaurung 2.1 # Stockfish, a UCI chess playing engine derived from Glaurung 2.1
# Copyright (C) 2004-2008 Tord Romstad (Glaurung author) # Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
# Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad # Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
# Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad # Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
# #
# Stockfish is free software: you can redistribute it and/or modify # Stockfish is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
@@ -22,7 +22,10 @@
### ========================================================================== ### ==========================================================================
### Establish the operating system name ### Establish the operating system name
UNAME = $(shell uname) KERNEL = $(shell uname -s)
ifeq ($(KERNEL),Linux)
OS = $(shell uname -o)
endif
### Executable name ### Executable name
EXE = stockfish EXE = stockfish
@@ -32,7 +35,7 @@ PREFIX = /usr/local
BINDIR = $(PREFIX)/bin BINDIR = $(PREFIX)/bin
### Built-in benchmark for pgo-builds ### Built-in benchmark for pgo-builds
PGOBENCH = ./$(EXE) bench 16 1 1000 default time PGOBENCH = ./$(EXE) bench
### Object files ### Object files
OBJS = benchmark.o bitbase.o bitboard.o endgame.o evaluate.o main.o \ OBJS = benchmark.o bitbase.o bitboard.o endgame.o evaluate.o main.o \
@@ -47,13 +50,14 @@ OBJS = benchmark.o bitbase.o bitboard.o endgame.o evaluate.o main.o \
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
# #
# debug = yes/no --- -DNDEBUG --- Enable/Disable debug mode # debug = yes/no --- -DNDEBUG --- Enable/Disable debug mode
# sanitize = undefined/thread/no (-fsanitize )
# --- ( undefined ) --- enable undefined behavior checks
# --- ( thread ) --- enable threading error checks
# optimize = yes/no --- (-O3/-fast etc.) --- Enable/Disable optimizations # optimize = yes/no --- (-O3/-fast etc.) --- Enable/Disable optimizations
# arch = (name) --- (-arch) --- Target architecture # arch = (name) --- (-arch) --- Target architecture
# bits = 64/32 --- -DIS_64BIT --- 64-/32-bit operating system # bits = 64/32 --- -DIS_64BIT --- 64-/32-bit operating system
# prefetch = yes/no --- -DUSE_PREFETCH --- Use prefetch x86 asm-instruction # prefetch = yes/no --- -DUSE_PREFETCH --- Use prefetch asm-instruction
# bsfq = yes/no --- -DUSE_BSFQ --- Use bsfq x86_64 asm-instruction (only # popcnt = yes/no --- -DUSE_POPCNT --- Use popcnt asm-instruction
# with GCC and ICC 64-bit)
# popcnt = yes/no --- -DUSE_POPCNT --- Use popcnt x86_64 asm-instruction
# sse = yes/no --- -msse --- Use Intel Streaming SIMD Extensions # sse = yes/no --- -msse --- Use Intel Streaming SIMD Extensions
# pext = yes/no --- -DUSE_PEXT --- Use pext x86_64 asm-instruction # pext = yes/no --- -DUSE_PEXT --- Use pext x86_64 asm-instruction
# #
@@ -64,9 +68,9 @@ OBJS = benchmark.o bitbase.o bitboard.o endgame.o evaluate.o main.o \
### 2.1. General and architecture defaults ### 2.1. General and architecture defaults
optimize = yes optimize = yes
debug = no debug = no
sanitize = no
bits = 32 bits = 32
prefetch = no prefetch = no
bsfq = no
popcnt = no popcnt = no
sse = no sse = no
pext = no pext = no
@@ -96,7 +100,6 @@ ifeq ($(ARCH),x86-64)
arch = x86_64 arch = x86_64
bits = 64 bits = 64
prefetch = yes prefetch = yes
bsfq = yes
sse = yes sse = yes
endif endif
@@ -104,7 +107,6 @@ ifeq ($(ARCH),x86-64-modern)
arch = x86_64 arch = x86_64
bits = 64 bits = 64
prefetch = yes prefetch = yes
bsfq = yes
popcnt = yes popcnt = yes
sse = yes sse = yes
endif endif
@@ -113,7 +115,6 @@ ifeq ($(ARCH),x86-64-bmi2)
arch = x86_64 arch = x86_64
bits = 64 bits = 64
prefetch = yes prefetch = yes
bsfq = yes
popcnt = yes popcnt = yes
sse = yes sse = yes
pext = yes pext = yes
@@ -122,7 +123,6 @@ endif
ifeq ($(ARCH),armv7) ifeq ($(ARCH),armv7)
arch = armv7 arch = armv7
prefetch = yes prefetch = yes
bsfq = yes
endif endif
ifeq ($(ARCH),ppc-32) ifeq ($(ARCH),ppc-32)
@@ -141,7 +141,7 @@ endif
### 3.1 Selecting compiler (default = gcc) ### 3.1 Selecting compiler (default = gcc)
CXXFLAGS += -Wall -Wcast-qual -fno-exceptions -fno-rtti -std=c++11 $(EXTRACXXFLAGS) CXXFLAGS += -Wall -Wcast-qual -fno-exceptions -std=c++11 $(EXTRACXXFLAGS)
DEPENDFLAGS += -std=c++11 DEPENDFLAGS += -std=c++11
LDFLAGS += $(EXTRALDFLAGS) LDFLAGS += $(EXTRALDFLAGS)
@@ -153,7 +153,18 @@ ifeq ($(COMP),gcc)
comp=gcc comp=gcc
CXX=g++ CXX=g++
CXXFLAGS += -pedantic -Wextra -Wshadow CXXFLAGS += -pedantic -Wextra -Wshadow
ifneq ($(UNAME),Darwin)
ifeq ($(ARCH),armv7)
ifeq ($(OS),Android)
CXXFLAGS += -m$(bits)
LDFLAGS += -m$(bits)
endif
else
CXXFLAGS += -m$(bits)
LDFLAGS += -m$(bits)
endif
ifneq ($(KERNEL),Darwin)
LDFLAGS += -Wl,--no-as-needed LDFLAGS += -Wl,--no-as-needed
endif endif
endif endif
@@ -161,7 +172,7 @@ endif
ifeq ($(COMP),mingw) ifeq ($(COMP),mingw)
comp=mingw comp=mingw
ifeq ($(UNAME),Linux) ifeq ($(KERNEL),Linux)
ifeq ($(bits),64) ifeq ($(bits),64)
ifeq ($(shell which x86_64-w64-mingw32-c++-posix),) ifeq ($(shell which x86_64-w64-mingw32-c++-posix),)
CXX=x86_64-w64-mingw32-c++ CXX=x86_64-w64-mingw32-c++
@@ -193,59 +204,83 @@ ifeq ($(COMP),clang)
comp=clang comp=clang
CXX=clang++ CXX=clang++
CXXFLAGS += -pedantic -Wextra -Wshadow CXXFLAGS += -pedantic -Wextra -Wshadow
ifeq ($(UNAME),Darwin) ifneq ($(KERNEL),Darwin)
CXXFLAGS += -std=c++0x -stdlib=libc++ ifneq ($(KERNEL),OpenBSD)
DEPENDFLAGS += -std=c++0x -stdlib=libc++ LDFLAGS += -latomic
endif
endif
ifeq ($(ARCH),armv7)
ifeq ($(OS),Android)
CXXFLAGS += -m$(bits)
LDFLAGS += -m$(bits)
endif
else
CXXFLAGS += -m$(bits)
LDFLAGS += -m$(bits)
endif endif
endif endif
ifeq ($(comp),icc) ifeq ($(comp),icc)
profile_prepare = icc-profile-prepare
profile_make = icc-profile-make profile_make = icc-profile-make
profile_use = icc-profile-use profile_use = icc-profile-use
profile_clean = icc-profile-clean
else else
profile_prepare = gcc-profile-prepare ifeq ($(comp),clang)
profile_make = clang-profile-make
profile_use = clang-profile-use
else
profile_make = gcc-profile-make profile_make = gcc-profile-make
profile_use = gcc-profile-use profile_use = gcc-profile-use
profile_clean = gcc-profile-clean endif
endif endif
ifeq ($(UNAME),Darwin) ifeq ($(KERNEL),Darwin)
CXXFLAGS += -arch $(arch) -mmacosx-version-min=10.9 CXXFLAGS += -arch $(arch) -mmacosx-version-min=10.9
LDFLAGS += -arch $(arch) -mmacosx-version-min=10.9 LDFLAGS += -arch $(arch) -mmacosx-version-min=10.9
endif endif
### Travis CI script uses COMPILER to overwrite CXX ### Travis CI script uses COMPILER to overwrite CXX
ifdef COMPILER ifdef COMPILER
CXX=$(COMPILER) COMPCXX=$(COMPILER)
endif
### Allow overwriting CXX from command line
ifdef COMPCXX
CXX=$(COMPCXX)
endif endif
### On mingw use Windows threads, otherwise POSIX ### On mingw use Windows threads, otherwise POSIX
ifneq ($(comp),mingw) ifneq ($(comp),mingw)
# On Android Bionic's C library comes with its own pthread implementation bundled in # On Android Bionic's C library comes with its own pthread implementation bundled in
ifneq ($(arch),armv7) ifneq ($(OS),Android)
# Haiku has pthreads in its libroot, so only link it in on other platforms # Haiku has pthreads in its libroot, so only link it in on other platforms
ifneq ($(UNAME),Haiku) ifneq ($(KERNEL),Haiku)
LDFLAGS += -lpthread LDFLAGS += -lpthread
endif endif
endif endif
endif endif
### 3.4 Debugging ### 3.2.1 Debugging
ifeq ($(debug),no) ifeq ($(debug),no)
CXXFLAGS += -DNDEBUG CXXFLAGS += -DNDEBUG
else else
CXXFLAGS += -g CXXFLAGS += -g
endif endif
### 3.5 Optimization ### 3.2.2 Debugging with undefined behavior sanitizers
ifneq ($(sanitize),no)
CXXFLAGS += -g3 -fsanitize=$(sanitize) -fuse-ld=gold
LDFLAGS += -fsanitize=$(sanitize) -fuse-ld=gold
endif
### 3.3 Optimization
ifeq ($(optimize),yes) ifeq ($(optimize),yes)
ifeq ($(comp),gcc) CXXFLAGS += -O3
CXXFLAGS += -O3
ifeq ($(UNAME),Darwin) ifeq ($(comp),gcc)
ifeq ($(KERNEL),Darwin)
ifeq ($(arch),i386) ifeq ($(arch),i386)
CXXFLAGS += -mdynamic-no-pic CXXFLAGS += -mdynamic-no-pic
endif endif
@@ -254,31 +289,21 @@ ifeq ($(optimize),yes)
endif endif
endif endif
ifeq ($(arch),armv7) ifeq ($(OS), Android)
CXXFLAGS += -fno-gcse -mthumb -march=armv7-a -mfloat-abi=softfp CXXFLAGS += -fno-gcse -mthumb -march=armv7-a -mfloat-abi=softfp
endif endif
endif endif
ifeq ($(comp),mingw)
CXXFLAGS += -O3
endif
ifeq ($(comp),icc) ifeq ($(comp),icc)
ifeq ($(UNAME),Darwin) ifeq ($(KERNEL),Darwin)
CXXFLAGS += -fast -mdynamic-no-pic CXXFLAGS += -mdynamic-no-pic
else
CXXFLAGS += -fast
endif endif
endif endif
ifeq ($(comp),clang) ifeq ($(comp),clang)
CXXFLAGS += -O3 ifeq ($(KERNEL),Darwin)
ifeq ($(UNAME),Darwin)
ifeq ($(pext),no)
CXXFLAGS += -flto CXXFLAGS += -flto
LDFLAGS += $(CXXFLAGS) LDFLAGS += $(CXXFLAGS)
endif
ifeq ($(arch),i386) ifeq ($(arch),i386)
CXXFLAGS += -mdynamic-no-pic CXXFLAGS += -mdynamic-no-pic
endif endif
@@ -289,12 +314,12 @@ ifeq ($(optimize),yes)
endif endif
endif endif
### 3.6. Bits ### 3.4 Bits
ifeq ($(bits),64) ifeq ($(bits),64)
CXXFLAGS += -DIS_64BIT CXXFLAGS += -DIS_64BIT
endif endif
### 3.7 prefetch ### 3.5 prefetch
ifeq ($(prefetch),yes) ifeq ($(prefetch),yes)
ifeq ($(sse),yes) ifeq ($(sse),yes)
CXXFLAGS += -msse CXXFLAGS += -msse
@@ -304,12 +329,7 @@ else
CXXFLAGS += -DNO_PREFETCH CXXFLAGS += -DNO_PREFETCH
endif endif
### 3.8 bsfq ### 3.6 popcnt
ifeq ($(bsfq),yes)
CXXFLAGS += -DUSE_BSFQ
endif
### 3.9 popcnt
ifeq ($(popcnt),yes) ifeq ($(popcnt),yes)
ifeq ($(comp),icc) ifeq ($(comp),icc)
CXXFLAGS += -msse3 -DUSE_POPCNT CXXFLAGS += -msse3 -DUSE_POPCNT
@@ -318,15 +338,15 @@ ifeq ($(popcnt),yes)
endif endif
endif endif
### 3.10 pext ### 3.7 pext
ifeq ($(pext),yes) ifeq ($(pext),yes)
CXXFLAGS += -DUSE_PEXT CXXFLAGS += -DUSE_PEXT
ifeq ($(comp),$(filter $(comp),gcc clang mingw)) ifeq ($(comp),$(filter $(comp),gcc clang mingw))
CXXFLAGS += -mbmi -mbmi2 CXXFLAGS += -mbmi2
endif endif
endif endif
### 3.11 Link Time Optimization, it works since gcc 4.5 but not on mingw under Windows. ### 3.8 Link Time Optimization, it works since gcc 4.5 but not on mingw under Windows.
### This is a mix of compile and link time options because the lto link phase ### This is a mix of compile and link time options because the lto link phase
### needs access to the optimization flags. ### needs access to the optimization flags.
ifeq ($(comp),gcc) ifeq ($(comp),gcc)
@@ -339,7 +359,7 @@ ifeq ($(comp),gcc)
endif endif
ifeq ($(comp),mingw) ifeq ($(comp),mingw)
ifeq ($(UNAME),Linux) ifeq ($(KERNEL),Linux)
ifeq ($(optimize),yes) ifeq ($(optimize),yes)
ifeq ($(debug),no) ifeq ($(debug),no)
CXXFLAGS += -flto CXXFLAGS += -flto
@@ -349,9 +369,9 @@ ifeq ($(comp),mingw)
endif endif
endif endif
### 3.12 Android 5 can only run position independent executables. Note that this ### 3.9 Android 5 can only run position independent executables. Note that this
### breaks Android 4.0 and earlier. ### breaks Android 4.0 and earlier.
ifeq ($(arch),armv7) ifeq ($(OS), Android)
CXXFLAGS += -fPIE CXXFLAGS += -fPIE
LDFLAGS += -fPIE -pie LDFLAGS += -fPIE -pie
endif endif
@@ -365,7 +385,7 @@ help:
@echo "" @echo ""
@echo "To compile stockfish, type: " @echo "To compile stockfish, type: "
@echo "" @echo ""
@echo "make target ARCH=arch [COMP=comp]" @echo "make target ARCH=arch [COMP=compiler] [COMPCXX=cxx]"
@echo "" @echo ""
@echo "Supported targets:" @echo "Supported targets:"
@echo "" @echo ""
@@ -395,36 +415,39 @@ help:
@echo "clang > LLVM Clang compiler" @echo "clang > LLVM Clang compiler"
@echo "icc > Intel compiler" @echo "icc > Intel compiler"
@echo "" @echo ""
@echo "Examples. If you don't know what to do, you likely want to run: " @echo "Simple examples. If you don't know what to do, you likely want to run: "
@echo "" @echo ""
@echo "make build ARCH=x86-64 (This is for 64-bit systems)" @echo "make build ARCH=x86-64 (This is for 64-bit systems)"
@echo "make build ARCH=x86-32 (This is for 32-bit systems)" @echo "make build ARCH=x86-32 (This is for 32-bit systems)"
@echo "" @echo ""
@echo "Advanced examples, for experienced users: "
@echo ""
@echo "make build ARCH=x86-64 COMP=clang"
@echo "make profile-build ARCH=x86-64-modern COMP=gcc COMPCXX=g++-4.8"
@echo ""
.PHONY: build profile-build
build: .PHONY: help build profile-build strip install clean objclean profileclean help \
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) config-sanity config-sanity icc-profile-use icc-profile-make gcc-profile-use gcc-profile-make \
clang-profile-use clang-profile-make
build: config-sanity
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) all $(MAKE) ARCH=$(ARCH) COMP=$(COMP) all
profile-build: profile-build: config-sanity objclean profileclean
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) config-sanity
@echo "" @echo ""
@echo "Step 0/4. Preparing for profile build." @echo "Step 1/4. Building instrumented executable ..."
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_prepare)
@echo ""
@echo "Step 1/4. Building executable for benchmark ..."
@touch *.cpp *.h syzygy/*.cpp syzygy/*.h
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_make) $(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_make)
@echo "" @echo ""
@echo "Step 2/4. Running benchmark for pgo-build ..." @echo "Step 2/4. Running benchmark for pgo-build ..."
$(PGOBENCH) > /dev/null $(PGOBENCH) > /dev/null
@echo "" @echo ""
@echo "Step 3/4. Building final executable ..." @echo "Step 3/4. Building optimized executable ..."
@touch *.cpp *.h syzygy/*.cpp syzygy/*.h $(MAKE) ARCH=$(ARCH) COMP=$(COMP) objclean
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_use) $(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_use)
@echo "" @echo ""
@echo "Step 4/4. Deleting profile data ..." @echo "Step 4/4. Deleting profile data ..."
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_clean) $(MAKE) ARCH=$(ARCH) COMP=$(COMP) profileclean
strip: strip:
strip $(EXE) strip $(EXE)
@@ -434,8 +457,19 @@ install:
-cp $(EXE) $(BINDIR) -cp $(EXE) $(BINDIR)
-strip $(BINDIR)/$(EXE) -strip $(BINDIR)/$(EXE)
clean: #clean all
$(RM) $(EXE) $(EXE).exe *.o .depend *~ core bench.txt *.gcda ./syzygy/*.o ./syzygy/*.gcda clean: objclean profileclean
@rm -f .depend *~ core
# clean binaries and objects
objclean:
@rm -f $(EXE) $(EXE).exe *.o ./syzygy/*.o
# clean auxiliary profiling files
profileclean:
@rm -rf profdir
@rm -f bench.txt *.gcda ./syzygy/*.gcda *.gcno ./syzygy/*.gcno
@rm -f stockfish.profdata *.profraw
default: default:
help help
@@ -450,11 +484,13 @@ config-sanity:
@echo "" @echo ""
@echo "Config:" @echo "Config:"
@echo "debug: '$(debug)'" @echo "debug: '$(debug)'"
@echo "sanitize: '$(sanitize)'"
@echo "optimize: '$(optimize)'" @echo "optimize: '$(optimize)'"
@echo "arch: '$(arch)'" @echo "arch: '$(arch)'"
@echo "bits: '$(bits)'" @echo "bits: '$(bits)'"
@echo "kernel: '$(KERNEL)'"
@echo "os: '$(OS)'"
@echo "prefetch: '$(prefetch)'" @echo "prefetch: '$(prefetch)'"
@echo "bsfq: '$(bsfq)'"
@echo "popcnt: '$(popcnt)'" @echo "popcnt: '$(popcnt)'"
@echo "sse: '$(sse)'" @echo "sse: '$(sse)'"
@echo "pext: '$(pext)'" @echo "pext: '$(pext)'"
@@ -467,12 +503,12 @@ config-sanity:
@echo "Testing config sanity. If this fails, try 'make help' ..." @echo "Testing config sanity. If this fails, try 'make help' ..."
@echo "" @echo ""
@test "$(debug)" = "yes" || test "$(debug)" = "no" @test "$(debug)" = "yes" || test "$(debug)" = "no"
@test "$(sanitize)" = "undefined" || test "$(sanitize)" = "thread" || test "$(sanitize)" = "no"
@test "$(optimize)" = "yes" || test "$(optimize)" = "no" @test "$(optimize)" = "yes" || test "$(optimize)" = "no"
@test "$(arch)" = "any" || test "$(arch)" = "x86_64" || test "$(arch)" = "i386" || \ @test "$(arch)" = "any" || test "$(arch)" = "x86_64" || test "$(arch)" = "i386" || \
test "$(arch)" = "ppc64" || test "$(arch)" = "ppc" || test "$(arch)" = "armv7" test "$(arch)" = "ppc64" || test "$(arch)" = "ppc" || test "$(arch)" = "armv7"
@test "$(bits)" = "32" || test "$(bits)" = "64" @test "$(bits)" = "32" || test "$(bits)" = "64"
@test "$(prefetch)" = "yes" || test "$(prefetch)" = "no" @test "$(prefetch)" = "yes" || test "$(prefetch)" = "no"
@test "$(bsfq)" = "yes" || test "$(bsfq)" = "no"
@test "$(popcnt)" = "yes" || test "$(popcnt)" = "no" @test "$(popcnt)" = "yes" || test "$(popcnt)" = "no"
@test "$(sse)" = "yes" || test "$(sse)" = "no" @test "$(sse)" = "yes" || test "$(sse)" = "no"
@test "$(pext)" = "yes" || test "$(pext)" = "no" @test "$(pext)" = "yes" || test "$(pext)" = "no"
@@ -481,8 +517,18 @@ config-sanity:
$(EXE): $(OBJS) $(EXE): $(OBJS)
$(CXX) -o $@ $(OBJS) $(LDFLAGS) $(CXX) -o $@ $(OBJS) $(LDFLAGS)
gcc-profile-prepare: clang-profile-make:
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) gcc-profile-clean $(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
EXTRACXXFLAGS='-fprofile-instr-generate ' \
EXTRALDFLAGS=' -fprofile-instr-generate' \
all
clang-profile-use:
llvm-profdata merge -output=stockfish.profdata *.profraw
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
EXTRACXXFLAGS='-fprofile-instr-use=stockfish.profdata' \
EXTRALDFLAGS='-fprofile-use ' \
all
gcc-profile-make: gcc-profile-make:
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \ $(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
@@ -496,14 +542,8 @@ gcc-profile-use:
EXTRALDFLAGS='-lgcov' \ EXTRALDFLAGS='-lgcov' \
all all
gcc-profile-clean:
@rm -rf *.gcda *.gcno syzygy/*.gcda syzygy/*.gcno bench.txt
icc-profile-prepare:
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) icc-profile-clean
@mkdir profdir
icc-profile-make: icc-profile-make:
@mkdir -p profdir
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \ $(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
EXTRACXXFLAGS='-prof-gen=srcpos -prof_dir ./profdir' \ EXTRACXXFLAGS='-prof-gen=srcpos -prof_dir ./profdir' \
all all
@@ -513,9 +553,6 @@ icc-profile-use:
EXTRACXXFLAGS='-prof_use -prof_dir ./profdir' \ EXTRACXXFLAGS='-prof_use -prof_dir ./profdir' \
all all
icc-profile-clean:
@rm -rf profdir bench.txt
.depend: .depend:
-@$(CXX) $(DEPENDFLAGS) -MM $(OBJS:.o=.cpp) > $@ 2> /dev/null -@$(CXX) $(DEPENDFLAGS) -MM $(OBJS:.o=.cpp) > $@ 2> /dev/null
+42 -61
View File
@@ -2,7 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -23,23 +23,20 @@
#include <istream> #include <istream>
#include <vector> #include <vector>
#include "misc.h"
#include "position.h" #include "position.h"
#include "search.h"
#include "thread.h"
#include "uci.h"
using namespace std; using namespace std;
namespace { namespace {
const vector<string> Defaults = { const vector<string> Defaults = {
"setoption name UCI_Chess960 value false",
"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1", "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1",
"r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 10", "r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 10",
"8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - - 0 11", "8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - - 0 11",
"4rrk1/pp1n3p/3q2pQ/2p1pb2/2PP4/2P3N1/P2B2PP/4RRK1 b - - 7 19", "4rrk1/pp1n3p/3q2pQ/2p1pb2/2PP4/2P3N1/P2B2PP/4RRK1 b - - 7 19",
"rq3rk1/ppp2ppp/1bnpb3/3N2B1/3NP3/7P/PPPQ1PP1/2KR3R w - - 7 14", "rq3rk1/ppp2ppp/1bnpb3/3N2B1/3NP3/7P/PPPQ1PP1/2KR3R w - - 7 14 moves d4e6",
"r1bq1r1k/1pp1n1pp/1p1p4/4p2Q/4Pp2/1BNP4/PPP2PPP/3R1RK1 w - - 2 14", "r1bq1r1k/1pp1n1pp/1p1p4/4p2Q/4Pp2/1BNP4/PPP2PPP/3R1RK1 w - - 2 14 moves g2g4",
"r3r1k1/2p2ppp/p1p1bn2/8/1q2P3/2NPQN2/PPP3PP/R4RK1 b - - 2 15", "r3r1k1/2p2ppp/p1p1bn2/8/1q2P3/2NPQN2/PPP3PP/R4RK1 b - - 2 15",
"r1bbk1nr/pp3p1p/2n5/1N4p1/2Np1B2/8/PPP2PPP/2KR1B1R w kq - 0 13", "r1bbk1nr/pp3p1p/2n5/1N4p1/2Np1B2/8/PPP2PPP/2KR1B1R w kq - 0 13",
"r1bq1rk1/ppp1nppp/4n3/3p3Q/3P4/1BP1B3/PP1N2PP/R4RK1 w - - 1 16", "r1bq1rk1/ppp1nppp/4n3/3p3Q/3P4/1BP1B3/PP1N2PP/R4RK1 w - - 1 16",
@@ -52,7 +49,7 @@ const vector<string> Defaults = {
"3q2k1/pb3p1p/4pbp1/2r5/PpN2N2/1P2P2P/5PP1/Q2R2K1 b - - 4 26", "3q2k1/pb3p1p/4pbp1/2r5/PpN2N2/1P2P2P/5PP1/Q2R2K1 b - - 4 26",
"6k1/6p1/6Pp/ppp5/3pn2P/1P3K2/1PP2P2/3N4 b - - 0 1", "6k1/6p1/6Pp/ppp5/3pn2P/1P3K2/1PP2P2/3N4 b - - 0 1",
"3b4/5kp1/1p1p1p1p/pP1PpP1P/P1P1P3/3KN3/8/8 w - - 0 1", "3b4/5kp1/1p1p1p1p/pP1PpP1P/P1P1P3/3KN3/8/8 w - - 0 1",
"2K5/p7/7P/5pR1/8/5k2/r7/8 w - - 0 1", "2K5/p7/7P/5pR1/8/5k2/r7/8 w - - 0 1 moves g5g6 f3e3 g6g5 e3f3",
"8/6pk/1p6/8/PP3p1p/5P2/4KP1q/3Q4 w - - 0 1", "8/6pk/1p6/8/PP3p1p/5P2/4KP1q/3Q4 w - - 0 1",
"7k/3p2pp/4q3/8/4Q3/5Kp1/P6b/8 w - - 0 1", "7k/3p2pp/4q3/8/4Q3/5Kp1/P6b/8 w - - 0 1",
"8/2p5/8/2kPKp1p/2p4P/2P5/3P4/8 w - - 0 1", "8/2p5/8/2kPKp1p/2p4P/2P5/3P4/8 w - - 0 1",
@@ -76,24 +73,38 @@ const vector<string> Defaults = {
"8/8/3P3k/8/1p6/8/1P6/1K3n2 b - - 0 1", // Nd2 - draw "8/8/3P3k/8/1p6/8/1P6/1K3n2 b - - 0 1", // Nd2 - draw
// 7-man positions // 7-man positions
"8/R7/2q5/8/6k1/8/1P5p/K6R w - - 0 124" // Draw "8/R7/2q5/8/6k1/8/1P5p/K6R w - - 0 124", // Draw
// Mate and stalemate positions
"6k1/3b3r/1p1p4/p1n2p2/1PPNpP1q/P3Q1p1/1R1RB1P1/5K2 b - - 0 1",
"r2r1n2/pp2bk2/2p1p2p/3q4/3PN1QP/2P3R1/P4PP1/5RK1 w - - 0 1",
"8/8/8/8/8/6k1/6p1/6K1 w - -",
"7k/7P/6K1/8/3B4/8/8/8 b - -",
// Chess 960
"setoption name UCI_Chess960 value true",
"bbqnnrkr/pppppppp/8/8/8/8/PPPPPPPP/BBQNNRKR w KQkq - 0 1 moves g2g3 d7d5 d2d4 c8h3 c1g5 e8d6 g5e7 f7f6",
"setoption name UCI_Chess960 value false"
}; };
} // namespace } // namespace
/// benchmark() runs a simple benchmark by letting Stockfish analyze a set /// setup_bench() builds a list of UCI commands to be run by bench. There
/// of positions for a given limit each. There are five parameters: the /// are five parameters: TT size in MB, number of search threads that
/// transposition table size, the number of search threads that should /// should be used, the limit value spent for each position, a file name
/// be used, the limit value spent for each position (optional, default is /// where to look for positions in FEN format and the type of the limit:
/// depth 13), an optional file name where to look for positions in FEN /// depth, perft, nodes and movetime (in millisecs).
/// format (defaults are the positions defined above) and the type of the ///
/// limit value: depth (default), time in millisecs or number of nodes. /// bench -> search default positions up to depth 13
/// bench 64 1 15 -> search default positions up to depth 15 (TT = 64MB)
/// bench 64 4 5000 current movetime -> search current position with 4 threads for 5 sec
/// bench 64 1 100000 default nodes -> search default positions for 100K nodes each
/// bench 16 1 5 default perft -> run a perft 5 on default positions
void benchmark(const Position& current, istream& is) { vector<string> setup_bench(const Position& current, istream& is) {
string token; vector<string> fens, list;
vector<string> fens; string go, token;
Search::LimitsType limits;
// Assign default values to missing arguments // Assign default values to missing arguments
string ttSize = (is >> token) ? token : "16"; string ttSize = (is >> token) ? token : "16";
@@ -102,21 +113,7 @@ void benchmark(const Position& current, istream& is) {
string fenFile = (is >> token) ? token : "default"; string fenFile = (is >> token) ? token : "default";
string limitType = (is >> token) ? token : "depth"; string limitType = (is >> token) ? token : "depth";
Options["Hash"] = ttSize; go = "go " + limitType + " " + limit;
Options["Threads"] = threads;
Search::clear();
if (limitType == "time")
limits.movetime = stoi(limit); // movetime is in millisecs
else if (limitType == "nodes")
limits.nodes = stoi(limit);
else if (limitType == "mate")
limits.mate = stoi(limit);
else
limits.depth = stoi(limit);
if (fenFile == "default") if (fenFile == "default")
fens = Defaults; fens = Defaults;
@@ -132,7 +129,7 @@ void benchmark(const Position& current, istream& is) {
if (!file.is_open()) if (!file.is_open())
{ {
cerr << "Unable to open file " << fenFile << endl; cerr << "Unable to open file " << fenFile << endl;
return; exit(EXIT_FAILURE);
} }
while (getline(file, fen)) while (getline(file, fen))
@@ -142,34 +139,18 @@ void benchmark(const Position& current, istream& is) {
file.close(); file.close();
} }
uint64_t nodes = 0; list.emplace_back("ucinewgame");
TimePoint elapsed = now(); list.emplace_back("setoption name Threads value " + threads);
list.emplace_back("setoption name Hash value " + ttSize);
for (size_t i = 0; i < fens.size(); ++i)
{
Position pos(fens[i], Options["UCI_Chess960"], Threads.main());
cerr << "\nPosition: " << i + 1 << '/' << fens.size() << endl;
if (limitType == "perft")
nodes += Search::perft(pos, limits.depth * ONE_PLY);
for (const string& fen : fens)
if (fen.find("setoption") != string::npos)
list.emplace_back(fen);
else else
{ {
Search::StateStackPtr st; list.emplace_back("position fen " + fen);
limits.startTime = now(); list.emplace_back(go);
Threads.start_thinking(pos, limits, st);
Threads.main()->wait_for_search_finished();
nodes += Threads.nodes_searched();
} }
}
elapsed = now() - elapsed + 1; // Ensure positivity to avoid a 'divide by zero' return list;
dbg_print(); // Just before to exit
cerr << "\n==========================="
<< "\nTotal time (ms) : " << elapsed
<< "\nNodes searched : " << nodes
<< "\nNodes/second : " << 1000 * nodes / elapsed << endl;
} }
+13 -13
View File
@@ -2,7 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -111,27 +111,27 @@ namespace {
ksq[WHITE] = Square((idx >> 0) & 0x3F); ksq[WHITE] = Square((idx >> 0) & 0x3F);
ksq[BLACK] = Square((idx >> 6) & 0x3F); ksq[BLACK] = Square((idx >> 6) & 0x3F);
us = Color ((idx >> 12) & 0x01); us = Color ((idx >> 12) & 0x01);
psq = make_square(File((idx >> 13) & 0x3), RANK_7 - Rank((idx >> 15) & 0x7)); psq = make_square(File((idx >> 13) & 0x3), Rank(RANK_7 - ((idx >> 15) & 0x7)));
// Check if two pieces are on the same square or if a king can be captured // Check if two pieces are on the same square or if a king can be captured
if ( distance(ksq[WHITE], ksq[BLACK]) <= 1 if ( distance(ksq[WHITE], ksq[BLACK]) <= 1
|| ksq[WHITE] == psq || ksq[WHITE] == psq
|| ksq[BLACK] == psq || ksq[BLACK] == psq
|| (us == WHITE && (StepAttacksBB[PAWN][psq] & ksq[BLACK]))) || (us == WHITE && (PawnAttacks[WHITE][psq] & ksq[BLACK])))
result = INVALID; result = INVALID;
// Immediate win if a pawn can be promoted without getting captured // Immediate win if a pawn can be promoted without getting captured
else if ( us == WHITE else if ( us == WHITE
&& rank_of(psq) == RANK_7 && rank_of(psq) == RANK_7
&& ksq[us] != psq + DELTA_N && ksq[us] != psq + NORTH
&& ( distance(ksq[~us], psq + DELTA_N) > 1 && ( distance(ksq[~us], psq + NORTH) > 1
|| (StepAttacksBB[KING][ksq[us]] & (psq + DELTA_N)))) || (PseudoAttacks[KING][ksq[us]] & (psq + NORTH))))
result = WIN; result = WIN;
// Immediate draw if it is a stalemate or a king captures undefended pawn // Immediate draw if it is a stalemate or a king captures undefended pawn
else if ( us == BLACK else if ( us == BLACK
&& ( !(StepAttacksBB[KING][ksq[us]] & ~(StepAttacksBB[KING][ksq[~us]] | StepAttacksBB[PAWN][psq])) && ( !(PseudoAttacks[KING][ksq[us]] & ~(PseudoAttacks[KING][ksq[~us]] | PawnAttacks[~us][psq]))
|| (StepAttacksBB[KING][ksq[us]] & psq & ~StepAttacksBB[KING][ksq[~us]]))) || (PseudoAttacks[KING][ksq[us]] & psq & ~PseudoAttacks[KING][ksq[~us]])))
result = DRAW; result = DRAW;
// Position will be classified later // Position will be classified later
@@ -157,7 +157,7 @@ namespace {
const Result Bad = (Us == WHITE ? DRAW : WIN); const Result Bad = (Us == WHITE ? DRAW : WIN);
Result r = INVALID; Result r = INVALID;
Bitboard b = StepAttacksBB[KING][ksq[Us]]; Bitboard b = PseudoAttacks[KING][ksq[Us]];
while (b) while (b)
r |= Us == WHITE ? db[index(Them, ksq[Them] , pop_lsb(&b), psq)] r |= Us == WHITE ? db[index(Them, ksq[Them] , pop_lsb(&b), psq)]
@@ -166,12 +166,12 @@ namespace {
if (Us == WHITE) if (Us == WHITE)
{ {
if (rank_of(psq) < RANK_7) // Single push if (rank_of(psq) < RANK_7) // Single push
r |= db[index(Them, ksq[Them], ksq[Us], psq + DELTA_N)]; r |= db[index(Them, ksq[Them], ksq[Us], psq + NORTH)];
if ( rank_of(psq) == RANK_2 // Double push if ( rank_of(psq) == RANK_2 // Double push
&& psq + DELTA_N != ksq[Us] && psq + NORTH != ksq[Us]
&& psq + DELTA_N != ksq[Them]) && psq + NORTH != ksq[Them])
r |= db[index(Them, ksq[Them], ksq[Us], psq + DELTA_N + DELTA_N)]; r |= db[index(Them, ksq[Them], ksq[Us], psq + NORTH + NORTH)];
} }
return result = r & Good ? Good : r & UNKNOWN ? UNKNOWN : Bad; return result = r & Good ? Good : r & UNKNOWN ? UNKNOWN : Bad;
+78 -70
View File
@@ -2,7 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -21,34 +21,27 @@
#include <algorithm> #include <algorithm>
#include "bitboard.h" #include "bitboard.h"
#include "bitcount.h"
#include "misc.h" #include "misc.h"
uint8_t PopCnt16[1 << 16];
int SquareDistance[SQUARE_NB][SQUARE_NB]; int SquareDistance[SQUARE_NB][SQUARE_NB];
Bitboard RookMasks [SQUARE_NB];
Bitboard RookMagics [SQUARE_NB];
Bitboard* RookAttacks[SQUARE_NB];
unsigned RookShifts [SQUARE_NB];
Bitboard BishopMasks [SQUARE_NB];
Bitboard BishopMagics [SQUARE_NB];
Bitboard* BishopAttacks[SQUARE_NB];
unsigned BishopShifts [SQUARE_NB];
Bitboard SquareBB[SQUARE_NB]; Bitboard SquareBB[SQUARE_NB];
Bitboard FileBB[FILE_NB]; Bitboard FileBB[FILE_NB];
Bitboard RankBB[RANK_NB]; Bitboard RankBB[RANK_NB];
Bitboard AdjacentFilesBB[FILE_NB]; Bitboard AdjacentFilesBB[FILE_NB];
Bitboard InFrontBB[COLOR_NB][RANK_NB]; Bitboard ForwardRanksBB[COLOR_NB][RANK_NB];
Bitboard StepAttacksBB[PIECE_NB][SQUARE_NB];
Bitboard BetweenBB[SQUARE_NB][SQUARE_NB]; Bitboard BetweenBB[SQUARE_NB][SQUARE_NB];
Bitboard LineBB[SQUARE_NB][SQUARE_NB]; Bitboard LineBB[SQUARE_NB][SQUARE_NB];
Bitboard DistanceRingBB[SQUARE_NB][8]; Bitboard DistanceRingBB[SQUARE_NB][8];
Bitboard ForwardBB[COLOR_NB][SQUARE_NB]; Bitboard ForwardFileBB[COLOR_NB][SQUARE_NB];
Bitboard PassedPawnMask[COLOR_NB][SQUARE_NB]; Bitboard PassedPawnMask[COLOR_NB][SQUARE_NB];
Bitboard PawnAttackSpan[COLOR_NB][SQUARE_NB]; Bitboard PawnAttackSpan[COLOR_NB][SQUARE_NB];
Bitboard PseudoAttacks[PIECE_TYPE_NB][SQUARE_NB]; Bitboard PseudoAttacks[PIECE_TYPE_NB][SQUARE_NB];
Bitboard PawnAttacks[COLOR_NB][SQUARE_NB];
Magic RookMagics[SQUARE_NB];
Magic BishopMagics[SQUARE_NB];
namespace { namespace {
@@ -61,10 +54,7 @@ namespace {
Bitboard RookTable[0x19000]; // To store rook attacks Bitboard RookTable[0x19000]; // To store rook attacks
Bitboard BishopTable[0x1480]; // To store bishop attacks Bitboard BishopTable[0x1480]; // To store bishop attacks
typedef unsigned (Fn)(Square, Bitboard); void init_magics(Bitboard table[], Magic magics[], Direction directions[]);
void init_magics(Bitboard table[], Bitboard* attacks[], Bitboard magics[],
Bitboard masks[], unsigned shifts[], Square deltas[], Fn index);
// bsf_index() returns the index into BSFTable[] to look up the bitscan. Uses // bsf_index() returns the index into BSFTable[] to look up the bitscan. Uses
// Matt Taylor's folding for 32 bit case, extended to 64 bit by Kim Walisch. // Matt Taylor's folding for 32 bit case, extended to 64 bit by Kim Walisch.
@@ -74,18 +64,30 @@ namespace {
return Is64Bit ? (b * DeBruijn64) >> 58 return Is64Bit ? (b * DeBruijn64) >> 58
: ((unsigned(b) ^ unsigned(b >> 32)) * DeBruijn32) >> 26; : ((unsigned(b) ^ unsigned(b >> 32)) * DeBruijn32) >> 26;
} }
// popcount16() counts the non-zero bits using SWAR-Popcount algorithm
unsigned popcount16(unsigned u) {
u -= (u >> 1) & 0x5555U;
u = ((u >> 2) & 0x3333U) + (u & 0x3333U);
u = ((u >> 4) + u) & 0x0F0FU;
return (u * 0x0101U) >> 8;
}
} }
#ifndef USE_BSFQ #ifdef NO_BSF
/// Software fall-back of lsb() and msb() for CPU lacking hardware support /// Software fall-back of lsb() and msb() for CPU lacking hardware support
Square lsb(Bitboard b) { Square lsb(Bitboard b) {
assert(b);
return BSFTable[bsf_index(b)]; return BSFTable[bsf_index(b)];
} }
Square msb(Bitboard b) { Square msb(Bitboard b) {
assert(b);
unsigned b32; unsigned b32;
int result = 0; int result = 0;
@@ -112,7 +114,7 @@ Square msb(Bitboard b) {
return Square(result + MSBTable[b32]); return Square(result + MSBTable[b32]);
} }
#endif // ifndef USE_BSFQ #endif // ifdef NO_BSF
/// Bitboards::pretty() returns an ASCII representation of a bitboard suitable /// Bitboards::pretty() returns an ASCII representation of a bitboard suitable
@@ -139,6 +141,9 @@ const std::string Bitboards::pretty(Bitboard b) {
void Bitboards::init() { void Bitboards::init() {
for (unsigned i = 0; i < (1 << 16); ++i)
PopCnt16[i] = (uint8_t) popcount16(i);
for (Square s = SQ_A1; s <= SQ_H8; ++s) for (Square s = SQ_A1; s <= SQ_H8; ++s)
{ {
SquareBB[s] = 1ULL << s; SquareBB[s] = 1ULL << s;
@@ -158,14 +163,14 @@ void Bitboards::init() {
AdjacentFilesBB[f] = (f > FILE_A ? FileBB[f - 1] : 0) | (f < FILE_H ? FileBB[f + 1] : 0); AdjacentFilesBB[f] = (f > FILE_A ? FileBB[f - 1] : 0) | (f < FILE_H ? FileBB[f + 1] : 0);
for (Rank r = RANK_1; r < RANK_8; ++r) for (Rank r = RANK_1; r < RANK_8; ++r)
InFrontBB[WHITE][r] = ~(InFrontBB[BLACK][r + 1] = InFrontBB[BLACK][r] | RankBB[r]); ForwardRanksBB[WHITE][r] = ~(ForwardRanksBB[BLACK][r + 1] = ForwardRanksBB[BLACK][r] | RankBB[r]);
for (Color c = WHITE; c <= BLACK; ++c) for (Color c = WHITE; c <= BLACK; ++c)
for (Square s = SQ_A1; s <= SQ_H8; ++s) for (Square s = SQ_A1; s <= SQ_H8; ++s)
{ {
ForwardBB[c][s] = InFrontBB[c][rank_of(s)] & FileBB[file_of(s)]; ForwardFileBB [c][s] = ForwardRanksBB[c][rank_of(s)] & FileBB[file_of(s)];
PawnAttackSpan[c][s] = InFrontBB[c][rank_of(s)] & AdjacentFilesBB[file_of(s)]; PawnAttackSpan[c][s] = ForwardRanksBB[c][rank_of(s)] & AdjacentFilesBB[file_of(s)];
PassedPawnMask[c][s] = ForwardBB[c][s] | PawnAttackSpan[c][s]; PassedPawnMask[c][s] = ForwardFileBB [c][s] | PawnAttackSpan[c][s];
} }
for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1) for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1)
@@ -176,39 +181,43 @@ void Bitboards::init() {
DistanceRingBB[s1][SquareDistance[s1][s2] - 1] |= s2; DistanceRingBB[s1][SquareDistance[s1][s2] - 1] |= s2;
} }
int steps[][9] = { {}, { 7, 9 }, { 17, 15, 10, 6, -6, -10, -15, -17 }, int steps[][5] = { {}, { 7, 9 }, { 6, 10, 15, 17 }, {}, {}, {}, { 1, 7, 8, 9 } };
{}, {}, {}, { 9, 7, -7, -9, 8, 1, -1, -8 } };
for (Color c = WHITE; c <= BLACK; ++c) for (Color c = WHITE; c <= BLACK; ++c)
for (PieceType pt = PAWN; pt <= KING; ++pt) for (PieceType pt : { PAWN, KNIGHT, KING })
for (Square s = SQ_A1; s <= SQ_H8; ++s) for (Square s = SQ_A1; s <= SQ_H8; ++s)
for (int i = 0; steps[pt][i]; ++i) for (int i = 0; steps[pt][i]; ++i)
{ {
Square to = s + Square(c == WHITE ? steps[pt][i] : -steps[pt][i]); Square to = s + Direction(c == WHITE ? steps[pt][i] : -steps[pt][i]);
if (is_ok(to) && distance(s, to) < 3) if (is_ok(to) && distance(s, to) < 3)
StepAttacksBB[make_piece(c, pt)][s] |= to; {
if (pt == PAWN)
PawnAttacks[c][s] |= to;
else
PseudoAttacks[pt][s] |= to;
}
} }
Square RookDeltas[] = { DELTA_N, DELTA_E, DELTA_S, DELTA_W }; Direction RookDirections[] = { NORTH, EAST, SOUTH, WEST };
Square BishopDeltas[] = { DELTA_NE, DELTA_SE, DELTA_SW, DELTA_NW }; Direction BishopDirections[] = { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST };
init_magics(RookTable, RookAttacks, RookMagics, RookMasks, RookShifts, RookDeltas, magic_index<ROOK>); init_magics(RookTable, RookMagics, RookDirections);
init_magics(BishopTable, BishopAttacks, BishopMagics, BishopMasks, BishopShifts, BishopDeltas, magic_index<BISHOP>); init_magics(BishopTable, BishopMagics, BishopDirections);
for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1) for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1)
{ {
PseudoAttacks[QUEEN][s1] = PseudoAttacks[BISHOP][s1] = attacks_bb<BISHOP>(s1, 0); PseudoAttacks[QUEEN][s1] = PseudoAttacks[BISHOP][s1] = attacks_bb<BISHOP>(s1, 0);
PseudoAttacks[QUEEN][s1] |= PseudoAttacks[ ROOK][s1] = attacks_bb< ROOK>(s1, 0); PseudoAttacks[QUEEN][s1] |= PseudoAttacks[ ROOK][s1] = attacks_bb< ROOK>(s1, 0);
for (Piece pc = W_BISHOP; pc <= W_ROOK; ++pc) for (PieceType pt : { BISHOP, ROOK })
for (Square s2 = SQ_A1; s2 <= SQ_H8; ++s2) for (Square s2 = SQ_A1; s2 <= SQ_H8; ++s2)
{ {
if (!(PseudoAttacks[pc][s1] & s2)) if (!(PseudoAttacks[pt][s1] & s2))
continue; continue;
LineBB[s1][s2] = (attacks_bb(pc, s1, 0) & attacks_bb(pc, s2, 0)) | s1 | s2; LineBB[s1][s2] = (attacks_bb(pt, s1, 0) & attacks_bb(pt, s2, 0)) | s1 | s2;
BetweenBB[s1][s2] = attacks_bb(pc, s1, SquareBB[s2]) & attacks_bb(pc, s2, SquareBB[s1]); BetweenBB[s1][s2] = attacks_bb(pt, s1, SquareBB[s2]) & attacks_bb(pt, s2, SquareBB[s1]);
} }
} }
} }
@@ -216,14 +225,14 @@ void Bitboards::init() {
namespace { namespace {
Bitboard sliding_attack(Square deltas[], Square sq, Bitboard occupied) { Bitboard sliding_attack(Direction directions[], Square sq, Bitboard occupied) {
Bitboard attack = 0; Bitboard attack = 0;
for (int i = 0; i < 4; ++i) for (int i = 0; i < 4; ++i)
for (Square s = sq + deltas[i]; for (Square s = sq + directions[i];
is_ok(s) && distance(s, s - deltas[i]) == 1; is_ok(s) && distance(s, s - directions[i]) == 1;
s += deltas[i]) s += directions[i])
{ {
attack |= s; attack |= s;
@@ -240,17 +249,14 @@ namespace {
// chessprogramming.wikispaces.com/Magic+Bitboards. In particular, here we // chessprogramming.wikispaces.com/Magic+Bitboards. In particular, here we
// use the so called "fancy" approach. // use the so called "fancy" approach.
void init_magics(Bitboard table[], Bitboard* attacks[], Bitboard magics[], void init_magics(Bitboard table[], Magic magics[], Direction directions[]) {
Bitboard masks[], unsigned shifts[], Square deltas[], Fn index) {
// Optimal PRNG seeds to pick the correct magics in the shortest time
int seeds[][RANK_NB] = { { 8977, 44560, 54343, 38998, 5731, 95205, 104912, 17020 }, int seeds[][RANK_NB] = { { 8977, 44560, 54343, 38998, 5731, 95205, 104912, 17020 },
{ 728, 10316, 55013, 32803, 12281, 15100, 16645, 255 } }; { 728, 10316, 55013, 32803, 12281, 15100, 16645, 255 } };
Bitboard occupancy[4096], reference[4096], edges, b; Bitboard occupancy[4096], reference[4096], edges, b;
int age[4096] = {0}, current = 0, i, size; int epoch[4096] = {}, cnt = 0, size = 0;
// attacks[s] is a pointer to the beginning of the attacks table for square 's'
attacks[SQ_A1] = table;
for (Square s = SQ_A1; s <= SQ_H8; ++s) for (Square s = SQ_A1; s <= SQ_H8; ++s)
{ {
@@ -262,28 +268,28 @@ namespace {
// all the attacks for each possible subset of the mask and so is 2 power // all the attacks for each possible subset of the mask and so is 2 power
// the number of 1s of the mask. Hence we deduce the size of the shift to // the number of 1s of the mask. Hence we deduce the size of the shift to
// apply to the 64 or 32 bits word to get the index. // apply to the 64 or 32 bits word to get the index.
masks[s] = sliding_attack(deltas, s, 0) & ~edges; Magic& m = magics[s];
shifts[s] = (Is64Bit ? 64 : 32) - popcount<Max15>(masks[s]); m.mask = sliding_attack(directions, s, 0) & ~edges;
m.shift = (Is64Bit ? 64 : 32) - popcount(m.mask);
// Set the offset for the attacks table of the square. We have individual
// table sizes for each square with "Fancy Magic Bitboards".
m.attacks = s == SQ_A1 ? table : magics[s - 1].attacks + size;
// Use Carry-Rippler trick to enumerate all subsets of masks[s] and // Use Carry-Rippler trick to enumerate all subsets of masks[s] and
// store the corresponding sliding attack bitboard in reference[]. // store the corresponding sliding attack bitboard in reference[].
b = size = 0; b = size = 0;
do { do {
occupancy[size] = b; occupancy[size] = b;
reference[size] = sliding_attack(deltas, s, b); reference[size] = sliding_attack(directions, s, b);
if (HasPext) if (HasPext)
attacks[s][pext(b, masks[s])] = reference[size]; m.attacks[pext(b, m.mask)] = reference[size];
size++; size++;
b = (b - masks[s]) & masks[s]; b = (b - m.mask) & m.mask;
} while (b); } while (b);
// Set the offset for the table of the next square. We have individual
// table sizes for each square with "Fancy Magic Bitboards".
if (s < SQ_H8)
attacks[s + 1] = attacks[s] + size;
if (HasPext) if (HasPext)
continue; continue;
@@ -291,28 +297,30 @@ namespace {
// Find a magic for square 's' picking up an (almost) random number // Find a magic for square 's' picking up an (almost) random number
// until we find the one that passes the verification test. // until we find the one that passes the verification test.
do { for (int i = 0; i < size; )
do {
magics[s] = rng.sparse_rand<Bitboard>(); for (m.magic = 0; popcount((m.magic * m.mask) >> 56) < 6; )
while (popcount<Max15>((magics[s] * masks[s]) >> 56) < 6); m.magic = rng.sparse_rand<Bitboard>();
// A good magic must map every possible occupancy to an index that // A good magic must map every possible occupancy to an index that
// looks up the correct sliding attack in the attacks[s] database. // looks up the correct sliding attack in the attacks[s] database.
// Note that we build up the database for square 's' as a side // Note that we build up the database for square 's' as a side
// effect of verifying the magic. // effect of verifying the magic. Keep track of the attempt count
for (++current, i = 0; i < size; ++i) // and save it in epoch[], little speed-up trick to avoid resetting
// m.attacks[] after every failed attempt.
for (++cnt, i = 0; i < size; ++i)
{ {
unsigned idx = index(s, occupancy[i]); unsigned idx = m.index(occupancy[i]);
if (age[idx] < current) if (epoch[idx] < cnt)
{ {
age[idx] = current; epoch[idx] = cnt;
attacks[s][idx] = reference[i]; m.attacks[idx] = reference[i];
} }
else if (attacks[s][idx] != reference[i]) else if (m.attacks[idx] != reference[i])
break; break;
} }
} while (i < size); }
} }
} }
} }
+97 -90
View File
@@ -2,7 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -39,6 +39,7 @@ const std::string pretty(Bitboard b);
} }
const Bitboard AllSquares = ~Bitboard(0);
const Bitboard DarkSquares = 0xAA55AA55AA55AA55ULL; const Bitboard DarkSquares = 0xAA55AA55AA55AA55ULL;
const Bitboard FileABB = 0x0101010101010101ULL; const Bitboard FileABB = 0x0101010101010101ULL;
@@ -61,29 +62,45 @@ const Bitboard Rank8BB = Rank1BB << (8 * 7);
extern int SquareDistance[SQUARE_NB][SQUARE_NB]; extern int SquareDistance[SQUARE_NB][SQUARE_NB];
extern Bitboard RookMasks [SQUARE_NB];
extern Bitboard RookMagics [SQUARE_NB];
extern Bitboard* RookAttacks[SQUARE_NB];
extern unsigned RookShifts [SQUARE_NB];
extern Bitboard BishopMasks [SQUARE_NB];
extern Bitboard BishopMagics [SQUARE_NB];
extern Bitboard* BishopAttacks[SQUARE_NB];
extern unsigned BishopShifts [SQUARE_NB];
extern Bitboard SquareBB[SQUARE_NB]; extern Bitboard SquareBB[SQUARE_NB];
extern Bitboard FileBB[FILE_NB]; extern Bitboard FileBB[FILE_NB];
extern Bitboard RankBB[RANK_NB]; extern Bitboard RankBB[RANK_NB];
extern Bitboard AdjacentFilesBB[FILE_NB]; extern Bitboard AdjacentFilesBB[FILE_NB];
extern Bitboard InFrontBB[COLOR_NB][RANK_NB]; extern Bitboard ForwardRanksBB[COLOR_NB][RANK_NB];
extern Bitboard StepAttacksBB[PIECE_NB][SQUARE_NB];
extern Bitboard BetweenBB[SQUARE_NB][SQUARE_NB]; extern Bitboard BetweenBB[SQUARE_NB][SQUARE_NB];
extern Bitboard LineBB[SQUARE_NB][SQUARE_NB]; extern Bitboard LineBB[SQUARE_NB][SQUARE_NB];
extern Bitboard DistanceRingBB[SQUARE_NB][8]; extern Bitboard DistanceRingBB[SQUARE_NB][8];
extern Bitboard ForwardBB[COLOR_NB][SQUARE_NB]; extern Bitboard ForwardFileBB[COLOR_NB][SQUARE_NB];
extern Bitboard PassedPawnMask[COLOR_NB][SQUARE_NB]; extern Bitboard PassedPawnMask[COLOR_NB][SQUARE_NB];
extern Bitboard PawnAttackSpan[COLOR_NB][SQUARE_NB]; extern Bitboard PawnAttackSpan[COLOR_NB][SQUARE_NB];
extern Bitboard PseudoAttacks[PIECE_TYPE_NB][SQUARE_NB]; extern Bitboard PseudoAttacks[PIECE_TYPE_NB][SQUARE_NB];
extern Bitboard PawnAttacks[COLOR_NB][SQUARE_NB];
/// Magic holds all magic bitboards relevant data for a single square
struct Magic {
Bitboard mask;
Bitboard magic;
Bitboard* attacks;
unsigned shift;
// Compute the attack's index using the 'magic bitboards' approach
unsigned index(Bitboard occupied) const {
if (HasPext)
return unsigned(pext(occupied, mask));
if (Is64Bit)
return unsigned(((occupied & mask) * magic) >> shift);
unsigned lo = unsigned(occupied) & unsigned(mask);
unsigned hi = unsigned(occupied >> 32) & unsigned(mask >> 32);
return (lo * unsigned(magic) ^ hi * unsigned(magic >> 32)) >> shift;
}
};
extern Magic RookMagics[SQUARE_NB];
extern Magic BishopMagics[SQUARE_NB];
/// Overloads of bitwise operators between a Bitboard and a Square for testing /// Overloads of bitwise operators between a Bitboard and a Square for testing
@@ -109,11 +126,10 @@ inline Bitboard& operator^=(Bitboard& b, Square s) {
return b ^= SquareBB[s]; return b ^= SquareBB[s];
} }
inline bool more_than_one(Bitboard b) { constexpr bool more_than_one(Bitboard b) {
return b & (b - 1); return b & (b - 1);
} }
/// rank_bb() and file_bb() return a bitboard representing all the squares on /// rank_bb() and file_bb() return a bitboard representing all the squares on
/// the given file or rank. /// the given file or rank.
@@ -134,13 +150,13 @@ inline Bitboard file_bb(Square s) {
} }
/// shift_bb() moves a bitboard one step along direction Delta. Mainly for pawns /// shift() moves a bitboard one step along direction D. Mainly for pawns
template<Square Delta> template<Direction D>
inline Bitboard shift_bb(Bitboard b) { constexpr Bitboard shift(Bitboard b) {
return Delta == DELTA_N ? b << 8 : Delta == DELTA_S ? b >> 8 return D == NORTH ? b << 8 : D == SOUTH ? b >> 8
: Delta == DELTA_NE ? (b & ~FileHBB) << 9 : Delta == DELTA_SE ? (b & ~FileHBB) >> 7 : D == NORTH_EAST ? (b & ~FileHBB) << 9 : D == SOUTH_EAST ? (b & ~FileHBB) >> 7
: Delta == DELTA_NW ? (b & ~FileABB) << 7 : Delta == DELTA_SW ? (b & ~FileABB) >> 9 : D == NORTH_WEST ? (b & ~FileABB) << 7 : D == SOUTH_WEST ? (b & ~FileABB) >> 9
: 0; : 0;
} }
@@ -163,28 +179,28 @@ inline Bitboard between_bb(Square s1, Square s2) {
} }
/// in_front_bb() returns a bitboard representing all the squares on all the ranks /// forward_ranks_bb() returns a bitboard representing all the squares on all the ranks
/// in front of the given one, from the point of view of the given color. For /// in front of the given one, from the point of view of the given color. For
/// instance, in_front_bb(BLACK, RANK_3) will return the squares on ranks 1 and 2. /// instance, forward_ranks_bb(BLACK, SQ_D3) will return the 16 squares on ranks 1 and 2.
inline Bitboard in_front_bb(Color c, Rank r) { inline Bitboard forward_ranks_bb(Color c, Square s) {
return InFrontBB[c][r]; return ForwardRanksBB[c][rank_of(s)];
} }
/// forward_bb() returns a bitboard representing all the squares along the line /// forward_file_bb() returns a bitboard representing all the squares along the line
/// in front of the given one, from the point of view of the given color: /// in front of the given one, from the point of view of the given color:
/// ForwardBB[c][s] = in_front_bb(c, s) & file_bb(s) /// ForwardFileBB[c][s] = forward_ranks_bb(c, s) & file_bb(s)
inline Bitboard forward_bb(Color c, Square s) { inline Bitboard forward_file_bb(Color c, Square s) {
return ForwardBB[c][s]; return ForwardFileBB[c][s];
} }
/// pawn_attack_span() returns a bitboard representing all the squares that can be /// pawn_attack_span() returns a bitboard representing all the squares that can be
/// attacked by a pawn of the given color when it moves along its file, starting /// attacked by a pawn of the given color when it moves along its file, starting
/// from the given square: /// from the given square:
/// PawnAttackSpan[c][s] = in_front_bb(c, s) & adjacent_files_bb(s); /// PawnAttackSpan[c][s] = forward_ranks_bb(c, s) & adjacent_files_bb(file_of(s));
inline Bitboard pawn_attack_span(Color c, Square s) { inline Bitboard pawn_attack_span(Color c, Square s) {
return PawnAttackSpan[c][s]; return PawnAttackSpan[c][s];
@@ -193,7 +209,7 @@ inline Bitboard pawn_attack_span(Color c, Square s) {
/// passed_pawn_mask() returns a bitboard mask which can be used to test if a /// passed_pawn_mask() returns a bitboard mask which can be used to test if a
/// pawn of the given color and on the given square is a passed pawn: /// pawn of the given color and on the given square is a passed pawn:
/// PassedPawnMask[c][s] = pawn_attack_span(c, s) | forward_bb(c, s) /// PassedPawnMask[c][s] = pawn_attack_span(c, s) | forward_file_bb(c, s)
inline Bitboard passed_pawn_mask(Color c, Square s) { inline Bitboard passed_pawn_mask(Color c, Square s) {
return PassedPawnMask[c][s]; return PassedPawnMask[c][s];
@@ -220,93 +236,84 @@ template<> inline int distance<Rank>(Square x, Square y) { return distance(rank_
/// attacks_bb() returns a bitboard representing all the squares attacked by a /// attacks_bb() returns a bitboard representing all the squares attacked by a
/// piece of type Pt (bishop or rook) placed on 's'. The helper magic_index() /// piece of type Pt (bishop or rook) placed on 's'.
/// looks up the index using the 'magic bitboards' approach.
template<PieceType Pt>
inline unsigned magic_index(Square s, Bitboard occupied) {
Bitboard* const Masks = Pt == ROOK ? RookMasks : BishopMasks;
Bitboard* const Magics = Pt == ROOK ? RookMagics : BishopMagics;
unsigned* const Shifts = Pt == ROOK ? RookShifts : BishopShifts;
if (HasPext)
return unsigned(pext(occupied, Masks[s]));
if (Is64Bit)
return unsigned(((occupied & Masks[s]) * Magics[s]) >> Shifts[s]);
unsigned lo = unsigned(occupied) & unsigned(Masks[s]);
unsigned hi = unsigned(occupied >> 32) & unsigned(Masks[s] >> 32);
return (lo * unsigned(Magics[s]) ^ hi * unsigned(Magics[s] >> 32)) >> Shifts[s];
}
template<PieceType Pt> template<PieceType Pt>
inline Bitboard attacks_bb(Square s, Bitboard occupied) { inline Bitboard attacks_bb(Square s, Bitboard occupied) {
return (Pt == ROOK ? RookAttacks : BishopAttacks)[s][magic_index<Pt>(s, occupied)];
const Magic& m = Pt == ROOK ? RookMagics[s] : BishopMagics[s];
return m.attacks[m.index(occupied)];
} }
inline Bitboard attacks_bb(Piece pc, Square s, Bitboard occupied) { inline Bitboard attacks_bb(PieceType pt, Square s, Bitboard occupied) {
switch (type_of(pc)) assert(pt != PAWN);
switch (pt)
{ {
case BISHOP: return attacks_bb<BISHOP>(s, occupied); case BISHOP: return attacks_bb<BISHOP>(s, occupied);
case ROOK : return attacks_bb<ROOK>(s, occupied); case ROOK : return attacks_bb< ROOK>(s, occupied);
case QUEEN : return attacks_bb<BISHOP>(s, occupied) | attacks_bb<ROOK>(s, occupied); case QUEEN : return attacks_bb<BISHOP>(s, occupied) | attacks_bb<ROOK>(s, occupied);
default : return StepAttacksBB[pc][s]; default : return PseudoAttacks[pt][s];
} }
} }
/// popcount() counts the number of non-zero bits in a bitboard
inline int popcount(Bitboard b) {
#ifndef USE_POPCNT
extern uint8_t PopCnt16[1 << 16];
union { Bitboard bb; uint16_t u[4]; } v = { b };
return PopCnt16[v.u[0]] + PopCnt16[v.u[1]] + PopCnt16[v.u[2]] + PopCnt16[v.u[3]];
#elif defined(_MSC_VER) || defined(__INTEL_COMPILER)
return (int)_mm_popcnt_u64(b);
#else // Assumed gcc or compatible compiler
return __builtin_popcountll(b);
#endif
}
/// lsb() and msb() return the least/most significant bit in a non-zero bitboard /// lsb() and msb() return the least/most significant bit in a non-zero bitboard
#ifdef USE_BSFQ #if defined(__GNUC__)
# if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
inline Square lsb(Bitboard b) { inline Square lsb(Bitboard b) {
assert(b);
return Square(__builtin_ctzll(b));
}
inline Square msb(Bitboard b) {
assert(b);
return Square(63 ^ __builtin_clzll(b));
}
#elif defined(_WIN64) && defined(_MSC_VER)
inline Square lsb(Bitboard b) {
assert(b);
unsigned long idx; unsigned long idx;
_BitScanForward64(&idx, b); _BitScanForward64(&idx, b);
return (Square) idx; return (Square) idx;
} }
inline Square msb(Bitboard b) { inline Square msb(Bitboard b) {
assert(b);
unsigned long idx; unsigned long idx;
_BitScanReverse64(&idx, b); _BitScanReverse64(&idx, b);
return (Square) idx; return (Square) idx;
} }
# elif defined(__arm__) #else
inline int lsb32(uint32_t v) { #define NO_BSF // Fallback on software implementation for other cases
__asm__("rbit %0, %1" : "=r"(v) : "r"(v));
return __builtin_clz(v);
}
inline Square msb(Bitboard b) {
return (Square) (63 - __builtin_clzll(b));
}
inline Square lsb(Bitboard b) {
return (Square) (uint32_t(b) ? lsb32(uint32_t(b)) : 32 + lsb32(uint32_t(b >> 32)));
}
# else // Assumed gcc or compatible compiler
inline Square lsb(Bitboard b) { // Assembly code by Heinz van Saanen
Bitboard idx;
__asm__("bsfq %1, %0": "=r"(idx): "rm"(b) );
return (Square) idx;
}
inline Square msb(Bitboard b) {
Bitboard idx;
__asm__("bsrq %1, %0": "=r"(idx): "rm"(b) );
return (Square) idx;
}
# endif
#else // ifdef(USE_BSFQ)
Square lsb(Bitboard b); Square lsb(Bitboard b);
Square msb(Bitboard b); Square msb(Bitboard b);
-105
View File
@@ -1,105 +0,0 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
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.
Stockfish is distributed in the hope that it will be useful,
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.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef BITCOUNT_H_INCLUDED
#define BITCOUNT_H_INCLUDED
#include <cassert>
#include "types.h"
enum BitCountType {
CNT_64,
CNT_64_MAX15,
CNT_32,
CNT_32_MAX15,
CNT_HW_POPCNT
};
/// Determine at compile time the best popcount<> specialization according to
/// whether the platform is 32 or 64 bit, the maximum number of non-zero
/// bits to count and if the hardware popcnt instruction is available.
const BitCountType Full = HasPopCnt ? CNT_HW_POPCNT : Is64Bit ? CNT_64 : CNT_32;
const BitCountType Max15 = HasPopCnt ? CNT_HW_POPCNT : Is64Bit ? CNT_64_MAX15 : CNT_32_MAX15;
/// popcount() counts the number of non-zero bits in a bitboard
template<BitCountType> inline int popcount(Bitboard);
template<>
inline int popcount<CNT_64>(Bitboard b) {
b -= (b >> 1) & 0x5555555555555555ULL;
b = ((b >> 2) & 0x3333333333333333ULL) + (b & 0x3333333333333333ULL);
b = ((b >> 4) + b) & 0x0F0F0F0F0F0F0F0FULL;
return (b * 0x0101010101010101ULL) >> 56;
}
template<>
inline int popcount<CNT_64_MAX15>(Bitboard b) {
b -= (b >> 1) & 0x5555555555555555ULL;
b = ((b >> 2) & 0x3333333333333333ULL) + (b & 0x3333333333333333ULL);
return (b * 0x1111111111111111ULL) >> 60;
}
template<>
inline int popcount<CNT_32>(Bitboard b) {
unsigned w = unsigned(b >> 32), v = unsigned(b);
v -= (v >> 1) & 0x55555555; // 0-2 in 2 bits
w -= (w >> 1) & 0x55555555;
v = ((v >> 2) & 0x33333333) + (v & 0x33333333); // 0-4 in 4 bits
w = ((w >> 2) & 0x33333333) + (w & 0x33333333);
v = ((v >> 4) + v + (w >> 4) + w) & 0x0F0F0F0F;
return (v * 0x01010101) >> 24;
}
template<>
inline int popcount<CNT_32_MAX15>(Bitboard b) {
unsigned w = unsigned(b >> 32), v = unsigned(b);
v -= (v >> 1) & 0x55555555; // 0-2 in 2 bits
w -= (w >> 1) & 0x55555555;
v = ((v >> 2) & 0x33333333) + (v & 0x33333333); // 0-4 in 4 bits
w = ((w >> 2) & 0x33333333) + (w & 0x33333333);
return ((v + w) * 0x11111111) >> 28;
}
template<>
inline int popcount<CNT_HW_POPCNT>(Bitboard b) {
#ifndef USE_POPCNT
assert(false);
return b != 0; // Avoid 'b not used' warning
#elif defined(_MSC_VER) && defined(__INTEL_COMPILER)
return _mm_popcnt_u64(b);
#elif defined(_MSC_VER)
return (int)__popcnt64(b);
#else // Assumed gcc or compatible compiler
return __builtin_popcountll(b);
#endif
}
#endif // #ifndef BITCOUNT_H_INCLUDED
+18 -47
View File
@@ -2,7 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -22,7 +22,6 @@
#include <cassert> #include <cassert>
#include "bitboard.h" #include "bitboard.h"
#include "bitcount.h"
#include "endgame.h" #include "endgame.h"
#include "movegen.h" #include "movegen.h"
@@ -84,25 +83,6 @@ namespace {
return sq; return sq;
} }
// Get the material key of Position out of the given endgame key code
// like "KBPKN". The trick here is to first forge an ad-hoc FEN string
// and then let a Position object do the work for us.
Key key(const string& code, Color c) {
assert(code.length() > 0 && code.length() < 8);
assert(code[0] == 'K');
string sides[] = { code.substr(code.find('K', 1)), // Weak
code.substr(0, code.find('K', 1)) }; // Strong
std::transform(sides[c].begin(), sides[c].end(), sides[c].begin(), tolower);
string fen = sides[0] + char(8 - sides[0].length() + '0') + "/8/8/8/8/8/8/"
+ sides[1] + char(8 - sides[1].length() + '0') + " w - - 0 10";
return Position(fen, false, nullptr).material_key();
}
} // namespace } // namespace
@@ -130,13 +110,6 @@ Endgames::Endgames() {
} }
template<EndgameType E, typename T>
void Endgames::add(const string& code) {
map<T>()[key(code, WHITE)] = std::unique_ptr<EndgameBase<T>>(new Endgame<E>(WHITE));
map<T>()[key(code, BLACK)] = std::unique_ptr<EndgameBase<T>>(new Endgame<E>(BLACK));
}
/// Mate with KX vs K. This function is used to evaluate positions with /// Mate with KX vs K. This function is used to evaluate positions with
/// king and plenty of material vs a lone king. It simply gives the /// king and plenty of material vs a lone king. It simply gives the
/// attacking side a bonus for driving the defending king towards the edge /// attacking side a bonus for driving the defending king towards the edge
@@ -162,8 +135,8 @@ Value Endgame<KXK>::operator()(const Position& pos) const {
if ( pos.count<QUEEN>(strongSide) if ( pos.count<QUEEN>(strongSide)
|| pos.count<ROOK>(strongSide) || pos.count<ROOK>(strongSide)
||(pos.count<BISHOP>(strongSide) && pos.count<KNIGHT>(strongSide)) ||(pos.count<BISHOP>(strongSide) && pos.count<KNIGHT>(strongSide))
||(pos.count<BISHOP>(strongSide) > 1 && opposite_colors(pos.squares<BISHOP>(strongSide)[0], || ( (pos.pieces(strongSide, BISHOP) & ~DarkSquares)
pos.squares<BISHOP>(strongSide)[1]))) && (pos.pieces(strongSide, BISHOP) & DarkSquares)))
result = std::min(result + VALUE_KNOWN_WIN, VALUE_MATE_IN_MAX_PLY - 1); result = std::min(result + VALUE_KNOWN_WIN, VALUE_MATE_IN_MAX_PLY - 1);
return strongSide == pos.side_to_move() ? result : -result; return strongSide == pos.side_to_move() ? result : -result;
@@ -259,8 +232,8 @@ Value Endgame<KRKP>::operator()(const Position& pos) const {
result = Value(80) - 8 * distance(wksq, psq); result = Value(80) - 8 * distance(wksq, psq);
else else
result = Value(200) - 8 * ( distance(wksq, psq + DELTA_S) result = Value(200) - 8 * ( distance(wksq, psq + SOUTH)
- distance(bksq, psq + DELTA_S) - distance(bksq, psq + SOUTH)
- distance(psq, queeningSq)); - distance(psq, queeningSq));
return strongSide == pos.side_to_move() ? result : -result; return strongSide == pos.side_to_move() ? result : -result;
@@ -496,7 +469,7 @@ ScaleFactor Endgame<KRPKR>::operator()(const Position& pos) const {
// If the defending king blocks the pawn and the attacking king is too far // If the defending king blocks the pawn and the attacking king is too far
// away, it's a draw. // away, it's a draw.
if ( r <= RANK_5 if ( r <= RANK_5
&& bksq == wpsq + DELTA_N && bksq == wpsq + NORTH
&& distance(wksq, wpsq) - tempo >= 2 && distance(wksq, wpsq) - tempo >= 2
&& distance(wksq, brsq) - tempo >= 2) && distance(wksq, brsq) - tempo >= 2)
return SCALE_FACTOR_DRAW; return SCALE_FACTOR_DRAW;
@@ -517,10 +490,10 @@ ScaleFactor Endgame<KRPKR>::operator()(const Position& pos) const {
&& file_of(wrsq) == f && file_of(wrsq) == f
&& wrsq < wpsq && wrsq < wpsq
&& (distance(wksq, queeningSq) < distance(bksq, queeningSq) - 2 + tempo) && (distance(wksq, queeningSq) < distance(bksq, queeningSq) - 2 + tempo)
&& (distance(wksq, wpsq + DELTA_N) < distance(bksq, wpsq + DELTA_N) - 2 + tempo) && (distance(wksq, wpsq + NORTH) < distance(bksq, wpsq + NORTH) - 2 + tempo)
&& ( distance(bksq, wrsq) + tempo >= 3 && ( distance(bksq, wrsq) + tempo >= 3
|| ( distance(wksq, queeningSq) < distance(bksq, wrsq) + tempo || ( distance(wksq, queeningSq) < distance(bksq, wrsq) + tempo
&& (distance(wksq, wpsq + DELTA_N) < distance(bksq, wrsq) + tempo)))) && (distance(wksq, wpsq + NORTH) < distance(bksq, wrsq) + tempo))))
return ScaleFactor( SCALE_FACTOR_MAX return ScaleFactor( SCALE_FACTOR_MAX
- 8 * distance(wpsq, queeningSq) - 8 * distance(wpsq, queeningSq)
- 2 * distance(wksq, queeningSq)); - 2 * distance(wksq, queeningSq));
@@ -551,7 +524,7 @@ ScaleFactor Endgame<KRPKB>::operator()(const Position& pos) const {
Square bsq = pos.square<BISHOP>(weakSide); Square bsq = pos.square<BISHOP>(weakSide);
Square psq = pos.square<PAWN>(strongSide); Square psq = pos.square<PAWN>(strongSide);
Rank rk = relative_rank(strongSide, psq); Rank rk = relative_rank(strongSide, psq);
Square push = pawn_push(strongSide); Direction push = pawn_push(strongSide);
// If the pawn is on the 5th rank and the pawn (currently) is on // If the pawn is on the 5th rank and the pawn (currently) is on
// the same color square as the bishop then there is a chance of // the same color square as the bishop then there is a chance of
@@ -625,7 +598,7 @@ ScaleFactor Endgame<KPsK>::operator()(const Position& pos) const {
// If all pawns are ahead of the king, on a single rook file and // If all pawns are ahead of the king, on a single rook file and
// the king is within one file of the pawns, it's a draw. // the king is within one file of the pawns, it's a draw.
if ( !(pawns & ~in_front_bb(weakSide, rank_of(ksq))) if ( !(pawns & ~forward_ranks_bb(weakSide, ksq))
&& !((pawns & ~FileABB) && (pawns & ~FileHBB)) && !((pawns & ~FileABB) && (pawns & ~FileHBB))
&& distance<File>(ksq, lsb(pawns)) <= 1) && distance<File>(ksq, lsb(pawns)) <= 1)
return SCALE_FACTOR_DRAW; return SCALE_FACTOR_DRAW;
@@ -671,17 +644,15 @@ ScaleFactor Endgame<KBPKB>::operator()(const Position& pos) const {
if (relative_rank(strongSide, pawnSq) <= RANK_5) if (relative_rank(strongSide, pawnSq) <= RANK_5)
return SCALE_FACTOR_DRAW; return SCALE_FACTOR_DRAW;
else
{
Bitboard path = forward_bb(strongSide, pawnSq);
if (path & pos.pieces(weakSide, KING)) Bitboard path = forward_file_bb(strongSide, pawnSq);
return SCALE_FACTOR_DRAW;
if ( (pos.attacks_from<BISHOP>(weakBishopSq) & path) if (path & pos.pieces(weakSide, KING))
&& distance(weakBishopSq, pawnSq) >= 3) return SCALE_FACTOR_DRAW;
return SCALE_FACTOR_DRAW;
} if ( (pos.attacks_from<BISHOP>(weakBishopSq) & path)
&& distance(weakBishopSq, pawnSq) >= 3)
return SCALE_FACTOR_DRAW;
} }
return SCALE_FACTOR_NONE; return SCALE_FACTOR_NONE;
} }
@@ -809,7 +780,7 @@ ScaleFactor Endgame<KNPKB>::operator()(const Position& pos) const {
// King needs to get close to promoting pawn to prevent knight from blocking. // King needs to get close to promoting pawn to prevent knight from blocking.
// Rules for this are very tricky, so just approximate. // Rules for this are very tricky, so just approximate.
if (forward_bb(strongSide, pawnSq) & pos.attacks_from<BISHOP>(bishopSq)) if (forward_file_bb(strongSide, pawnSq) & pos.attacks_from<BISHOP>(bishopSq))
return ScaleFactor(distance(weakKingSq, pawnSq)); return ScaleFactor(distance(weakKingSq, pawnSq));
return SCALE_FACTOR_NONE; return SCALE_FACTOR_NONE;
+22 -22
View File
@@ -2,7 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -31,12 +31,11 @@
#include "types.h" #include "types.h"
/// EndgameType lists all supported endgames /// EndgameCode lists all supported endgame functions by corresponding codes
enum EndgameType { enum EndgameCode {
// Evaluation functions
EVALUATION_FUNCTIONS,
KNNK, // KNN vs K KNNK, // KNN vs K
KXK, // Generic "mate lone king" eval KXK, // Generic "mate lone king" eval
KBNK, // KBN vs K KBNK, // KBN vs K
@@ -47,10 +46,7 @@ enum EndgameType {
KQKP, // KQ vs KP KQKP, // KQ vs KP
KQKR, // KQ vs KR KQKR, // KQ vs KR
// Scaling functions
SCALING_FUNCTIONS, SCALING_FUNCTIONS,
KBPsK, // KB and pawns vs K KBPsK, // KB and pawns vs K
KQKRPs, // KQ vs KR and pawns KQKRPs, // KQ vs KR and pawns
KRPKR, // KRP vs KR KRPKR, // KRP vs KR
@@ -68,30 +64,28 @@ enum EndgameType {
/// Endgame functions can be of two types depending on whether they return a /// Endgame functions can be of two types depending on whether they return a
/// Value or a ScaleFactor. /// Value or a ScaleFactor.
template<EndgameType E> using template<EndgameCode E> using
eg_type = typename std::conditional<(E < SCALING_FUNCTIONS), Value, ScaleFactor>::type; eg_type = typename std::conditional<(E < SCALING_FUNCTIONS), Value, ScaleFactor>::type;
/// Base and derived templates for endgame evaluation and scaling functions /// Base and derived functors for endgame evaluation and scaling functions
template<typename T> template<typename T>
struct EndgameBase { struct EndgameBase {
explicit EndgameBase(Color c) : strongSide(c), weakSide(~c) {}
virtual ~EndgameBase() = default; virtual ~EndgameBase() = default;
virtual Color strong_side() const = 0;
virtual T operator()(const Position&) const = 0; virtual T operator()(const Position&) const = 0;
const Color strongSide, weakSide;
}; };
template<EndgameType E, typename T = eg_type<E>> template<EndgameCode E, typename T = eg_type<E>>
struct Endgame : public EndgameBase<T> { struct Endgame : public EndgameBase<T> {
explicit Endgame(Color c) : strongSide(c), weakSide(~c) {} explicit Endgame(Color c) : EndgameBase<T>(c) {}
Color strong_side() const { return strongSide; } T operator()(const Position&) const override;
T operator()(const Position&) const;
private:
Color strongSide, weakSide;
}; };
@@ -101,16 +95,22 @@ private:
class Endgames { class Endgames {
template<typename T> using Map = std::map<Key, std::unique_ptr<EndgameBase<T>>>; template<typename T> using Ptr = std::unique_ptr<EndgameBase<T>>;
template<typename T> using Map = std::map<Key, Ptr<T>>;
template<EndgameType E, typename T = eg_type<E>>
void add(const std::string& code);
template<typename T> template<typename T>
Map<T>& map() { Map<T>& map() {
return std::get<std::is_same<T, ScaleFactor>::value>(maps); return std::get<std::is_same<T, ScaleFactor>::value>(maps);
} }
template<EndgameCode E, typename T = eg_type<E>, typename P = Ptr<T>>
void add(const std::string& code) {
StateInfo st;
map<T>()[Position().set(code, WHITE, &st).material_key()] = P(new Endgame<E>(WHITE));
map<T>()[Position().set(code, BLACK, &st).material_key()] = P(new Endgame<E>(BLACK));
}
std::pair<Map<Value>, Map<ScaleFactor>> maps; std::pair<Map<Value>, Map<ScaleFactor>> maps;
public: public:
+512 -469
View File
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -2,7 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -31,10 +31,10 @@ namespace Eval {
const Value Tempo = Value(20); // Must be visible to search const Value Tempo = Value(20); // Must be visible to search
void init(); extern Score Contempt;
std::string trace(const Position& pos); std::string trace(const Position& pos);
template<bool DoTrace = false>
Value evaluate(const Position& pos); Value evaluate(const Position& pos);
} }
+8 -5
View File
@@ -2,7 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -21,7 +21,6 @@
#include <iostream> #include <iostream>
#include "bitboard.h" #include "bitboard.h"
#include "evaluate.h"
#include "position.h" #include "position.h"
#include "search.h" #include "search.h"
#include "thread.h" #include "thread.h"
@@ -29,6 +28,10 @@
#include "uci.h" #include "uci.h"
#include "syzygy/tbprobe.h" #include "syzygy/tbprobe.h"
namespace PSQT {
void init();
}
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
std::cout << engine_info() << std::endl; std::cout << engine_info() << std::endl;
@@ -39,14 +42,14 @@ int main(int argc, char* argv[]) {
Position::init(); Position::init();
Bitbases::init(); Bitbases::init();
Search::init(); Search::init();
Eval::init();
Pawns::init(); Pawns::init();
Threads.init();
Tablebases::init(Options["SyzygyPath"]); Tablebases::init(Options["SyzygyPath"]);
TT.resize(Options["Hash"]); TT.resize(Options["Hash"]);
Threads.set(Options["Threads"]);
Search::clear(); // After threads are up
UCI::loop(argc, argv); UCI::loop(argc, argv);
Threads.exit(); Threads.set(0);
return 0; return 0;
} }
+15 -15
View File
@@ -2,7 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -31,18 +31,15 @@ namespace {
// Polynomial material imbalance parameters // Polynomial material imbalance parameters
// pair pawn knight bishop rook queen
const int Linear[6] = { 1667, -168, -1027, -166, 238, -138 };
const int QuadraticOurs[][PIECE_TYPE_NB] = { const int QuadraticOurs[][PIECE_TYPE_NB] = {
// OUR PIECES // OUR PIECES
// pair pawn knight bishop rook queen // pair pawn knight bishop rook queen
{ 0 }, // Bishop pair {1667 }, // Bishop pair
{ 40, 2 }, // Pawn { 40, 0 }, // Pawn
{ 32, 255, -3 }, // Knight OUR PIECES { 32, 255, -3 }, // Knight OUR PIECES
{ 0, 104, 4, 0 }, // Bishop { 0, 104, 4, 0 }, // Bishop
{ -26, -2, 47, 105, -149 }, // Rook { -26, -2, 47, 105, -149 }, // Rook
{-185, 24, 122, 137, -134, 0 } // Queen {-189, 24, 117, 133, -134, -10 } // Queen
}; };
const int QuadraticTheirs[][PIECE_TYPE_NB] = { const int QuadraticTheirs[][PIECE_TYPE_NB] = {
@@ -53,7 +50,7 @@ namespace {
{ 9, 63, 0 }, // Knight OUR PIECES { 9, 63, 0 }, // Knight OUR PIECES
{ 59, 65, 42, 0 }, // Bishop { 59, 65, 42, 0 }, // Bishop
{ 46, 39, 24, -24, 0 }, // Rook { 46, 39, 24, -24, 0 }, // Rook
{ 101, 100, -37, 141, 268, 0 } // Queen { 97, 100, -42, 137, 268, 0 } // Queen
}; };
// Endgame evaluation and scaling functions are accessed directly and not through // Endgame evaluation and scaling functions are accessed directly and not through
@@ -94,13 +91,13 @@ namespace {
int bonus = 0; int bonus = 0;
// Second-degree polynomial material imbalance by Tord Romstad // Second-degree polynomial material imbalance, by Tord Romstad
for (int pt1 = NO_PIECE_TYPE; pt1 <= QUEEN; ++pt1) for (int pt1 = NO_PIECE_TYPE; pt1 <= QUEEN; ++pt1)
{ {
if (!pieceCount[Us][pt1]) if (!pieceCount[Us][pt1])
continue; continue;
int v = Linear[pt1]; int v = 0;
for (int pt2 = NO_PIECE_TYPE; pt2 <= pt1; ++pt2) for (int pt2 = NO_PIECE_TYPE; pt2 <= pt1; ++pt2)
v += QuadraticOurs[pt1][pt2] * pieceCount[Us][pt2] v += QuadraticOurs[pt1][pt2] * pieceCount[Us][pt2]
@@ -132,7 +129,13 @@ Entry* probe(const Position& pos) {
std::memset(e, 0, sizeof(Entry)); std::memset(e, 0, sizeof(Entry));
e->key = key; e->key = key;
e->factor[WHITE] = e->factor[BLACK] = (uint8_t)SCALE_FACTOR_NORMAL; e->factor[WHITE] = e->factor[BLACK] = (uint8_t)SCALE_FACTOR_NORMAL;
e->gamePhase = pos.game_phase();
Value npm_w = pos.non_pawn_material(WHITE);
Value npm_b = pos.non_pawn_material(BLACK);
Value npm = std::max(EndgameLimit, std::min(npm_w + npm_b, MidgameLimit));
// Map total non-pawn material into [PHASE_ENDGAME, PHASE_MIDGAME]
e->gamePhase = Phase(((npm - EndgameLimit) * PHASE_MIDGAME) / (MidgameLimit - EndgameLimit));
// Let's look if we have a specialized evaluation function for this particular // Let's look if we have a specialized evaluation function for this particular
// material configuration. Firstly we look for a fixed configuration one, then // material configuration. Firstly we look for a fixed configuration one, then
@@ -153,7 +156,7 @@ Entry* probe(const Position& pos) {
if ((sf = pos.this_thread()->endgames.probe<ScaleFactor>(key)) != nullptr) if ((sf = pos.this_thread()->endgames.probe<ScaleFactor>(key)) != nullptr)
{ {
e->scalingFunction[sf->strong_side()] = sf; // Only strong color assigned e->scalingFunction[sf->strongSide] = sf; // Only strong color assigned
return e; return e;
} }
@@ -169,9 +172,6 @@ Entry* probe(const Position& pos) {
e->scalingFunction[c] = &ScaleKQKRPs[c]; e->scalingFunction[c] = &ScaleKQKRPs[c];
} }
Value npm_w = pos.non_pawn_material(WHITE);
Value npm_b = pos.non_pawn_material(BLACK);
if (npm_w + npm_b == VALUE_ZERO && pos.pieces(PAWN)) // Only pawns on the board if (npm_w + npm_b == VALUE_ZERO && pos.pieces(PAWN)) // Only pawns on the board
{ {
if (!pos.count<PAWN>(BLACK)) if (!pos.count<PAWN>(BLACK))
+6 -6
View File
@@ -2,7 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -50,17 +50,17 @@ struct Entry {
// the position. For instance, in KBP vs K endgames, the scaling function looks // the position. For instance, in KBP vs K endgames, the scaling function looks
// for rook pawns and wrong-colored bishops. // for rook pawns and wrong-colored bishops.
ScaleFactor scale_factor(const Position& pos, Color c) const { ScaleFactor scale_factor(const Position& pos, Color c) const {
return !scalingFunction[c] ScaleFactor sf = scalingFunction[c] ? (*scalingFunction[c])(pos)
|| (*scalingFunction[c])(pos) == SCALE_FACTOR_NONE ? ScaleFactor(factor[c]) : SCALE_FACTOR_NONE;
: (*scalingFunction[c])(pos); return sf != SCALE_FACTOR_NONE ? sf : ScaleFactor(factor[c]);
} }
Key key; Key key;
int16_t value;
uint8_t factor[COLOR_NB];
EndgameBase<Value>* evaluationFunction; EndgameBase<Value>* evaluationFunction;
EndgameBase<ScaleFactor>* scalingFunction[COLOR_NB]; // Could be one for each EndgameBase<ScaleFactor>* scalingFunction[COLOR_NB]; // Could be one for each
// side (e.g. KPKP, KBPsKs) // side (e.g. KPKP, KBPsKs)
int16_t value;
uint8_t factor[COLOR_NB];
Phase gamePhase; Phase gamePhase;
}; };
+142 -12
View File
@@ -2,7 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -18,10 +18,29 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifdef _WIN32
#if _WIN32_WINNT < 0x0601
#undef _WIN32_WINNT
#define _WIN32_WINNT 0x0601 // Force to include needed API prototypes
#endif
#include <windows.h>
// The needed Windows API for processor groups could be missed from old Windows
// versions, so instead of calling them directly (forcing the linker to resolve
// the calls at compile time), try to load them at runtime. To do this we need
// first to define the corresponding function pointers.
extern "C" {
typedef bool(*fun1_t)(LOGICAL_PROCESSOR_RELATIONSHIP,
PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, PDWORD);
typedef bool(*fun2_t)(USHORT, PGROUP_AFFINITY);
typedef bool(*fun3_t)(HANDLE, CONST GROUP_AFFINITY*, PGROUP_AFFINITY);
}
#endif
#include <fstream> #include <fstream>
#include <iomanip> #include <iomanip>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <vector>
#include "misc.h" #include "misc.h"
#include "thread.h" #include "thread.h"
@@ -32,7 +51,7 @@ namespace {
/// Version number. If Version is left empty, then compile date in the format /// Version number. If Version is left empty, then compile date in the format
/// DD-MM-YY and show in engine_info. /// DD-MM-YY and show in engine_info.
const string Version = "7"; const string Version = "9";
/// Our fancy logging facility. The trick here is to replace cin.rdbuf() and /// Our fancy logging facility. The trick here is to replace cin.rdbuf() and
/// cout.rdbuf() with two Tie objects that tie cin and cout to a file stream. We /// cout.rdbuf() with two Tie objects that tie cin and cout to a file stream. We
@@ -44,10 +63,10 @@ struct Tie: public streambuf { // MSVC requires split streambuf for cin and cout
Tie(streambuf* b, streambuf* l) : buf(b), logBuf(l) {} Tie(streambuf* b, streambuf* l) : buf(b), logBuf(l) {}
int sync() { return logBuf->pubsync(), buf->pubsync(); } int sync() override { return logBuf->pubsync(), buf->pubsync(); }
int overflow(int c) { return log(buf->sputc((char)c), "<< "); } int overflow(int c) override { return log(buf->sputc((char)c), "<< "); }
int underflow() { return buf->sgetc(); } int underflow() override { return buf->sgetc(); }
int uflow() { return log(buf->sbumpc(), ">> "); } int uflow() override { return log(buf->sbumpc(), ">> "); }
streambuf *buf, *logBuf; streambuf *buf, *logBuf;
@@ -65,23 +84,23 @@ struct Tie: public streambuf { // MSVC requires split streambuf for cin and cout
class Logger { class Logger {
Logger() : in(cin.rdbuf(), file.rdbuf()), out(cout.rdbuf(), file.rdbuf()) {} Logger() : in(cin.rdbuf(), file.rdbuf()), out(cout.rdbuf(), file.rdbuf()) {}
~Logger() { start(false); } ~Logger() { start(""); }
ofstream file; ofstream file;
Tie in, out; Tie in, out;
public: public:
static void start(bool b) { static void start(const std::string& fname) {
static Logger l; static Logger l;
if (b && !l.file.is_open()) if (!fname.empty() && !l.file.is_open())
{ {
l.file.open("io_log.txt", ifstream::out); l.file.open(fname, ifstream::out);
cin.rdbuf(&l.in); cin.rdbuf(&l.in);
cout.rdbuf(&l.out); cout.rdbuf(&l.out);
} }
else if (!b && l.file.is_open()) else if (fname.empty() && l.file.is_open())
{ {
cout.rdbuf(l.out.buf); cout.rdbuf(l.out.buf);
cin.rdbuf(l.in.buf); cin.rdbuf(l.in.buf);
@@ -157,7 +176,7 @@ std::ostream& operator<<(std::ostream& os, SyncCout sc) {
/// Trampoline helper to avoid moving Logger to misc.h /// Trampoline helper to avoid moving Logger to misc.h
void start_logger(bool b) { Logger::start(b); } void start_logger(const std::string& fname) { Logger::start(fname); }
/// prefetch() preloads the given address in L1/L2 cache. This is a non-blocking /// prefetch() preloads the given address in L1/L2 cache. This is a non-blocking
@@ -185,3 +204,114 @@ void prefetch(void* addr) {
} }
#endif #endif
void prefetch2(void* addr) {
prefetch(addr);
prefetch((uint8_t*)addr + 64);
}
namespace WinProcGroup {
#ifndef _WIN32
void bindThisThread(size_t) {}
#else
/// get_group() retrieves logical processor information using Windows specific
/// API and returns the best group id for the thread with index idx. Original
/// code from Texel by Peter Österlund.
int get_group(size_t idx) {
int threads = 0;
int nodes = 0;
int cores = 0;
DWORD returnLength = 0;
DWORD byteOffset = 0;
// Early exit if the needed API is not available at runtime
HMODULE k32 = GetModuleHandle("Kernel32.dll");
auto fun1 = (fun1_t)GetProcAddress(k32, "GetLogicalProcessorInformationEx");
if (!fun1)
return -1;
// First call to get returnLength. We expect it to fail due to null buffer
if (fun1(RelationAll, nullptr, &returnLength))
return -1;
// Once we know returnLength, allocate the buffer
SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *buffer, *ptr;
ptr = buffer = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)malloc(returnLength);
// Second call, now we expect to succeed
if (!fun1(RelationAll, buffer, &returnLength))
{
free(buffer);
return -1;
}
while (ptr->Size > 0 && byteOffset + ptr->Size <= returnLength)
{
if (ptr->Relationship == RelationNumaNode)
nodes++;
else if (ptr->Relationship == RelationProcessorCore)
{
cores++;
threads += (ptr->Processor.Flags == LTP_PC_SMT) ? 2 : 1;
}
byteOffset += ptr->Size;
ptr = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)(((char*)ptr) + ptr->Size);
}
free(buffer);
std::vector<int> groups;
// Run as many threads as possible on the same node until core limit is
// reached, then move on filling the next node.
for (int n = 0; n < nodes; n++)
for (int i = 0; i < cores / nodes; i++)
groups.push_back(n);
// In case a core has more than one logical processor (we assume 2) and we
// have still threads to allocate, then spread them evenly across available
// nodes.
for (int t = 0; t < threads - cores; t++)
groups.push_back(t % nodes);
// If we still have more threads than the total number of logical processors
// then return -1 and let the OS to decide what to do.
return idx < groups.size() ? groups[idx] : -1;
}
/// bindThisThread() set the group affinity of the current thread
void bindThisThread(size_t idx) {
// Use only local variables to be thread-safe
int group = get_group(idx);
if (group == -1)
return;
// Early exit if the needed API are not available at runtime
HMODULE k32 = GetModuleHandle("Kernel32.dll");
auto fun2 = (fun2_t)GetProcAddress(k32, "GetNumaNodeProcessorMaskEx");
auto fun3 = (fun3_t)GetProcAddress(k32, "SetThreadGroupAffinity");
if (!fun2 || !fun3)
return;
GROUP_AFFINITY affinity;
if (fun2(group, &affinity))
fun3(GetCurrentThread(), &affinity, nullptr);
}
#endif
} // namespace WinProcGroup
+14 -2
View File
@@ -2,7 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -31,7 +31,8 @@
const std::string engine_info(bool to_uci = false); const std::string engine_info(bool to_uci = false);
void prefetch(void* addr); void prefetch(void* addr);
void start_logger(bool b); void prefetch2(void* addr);
void start_logger(const std::string& fname);
void dbg_hit_on(bool b); void dbg_hit_on(bool b);
void dbg_hit_on(bool c, bool b); void dbg_hit_on(bool c, bool b);
@@ -97,4 +98,15 @@ public:
{ return T(rand64() & rand64() & rand64()); } { return T(rand64() & rand64() & rand64()); }
}; };
/// Under Windows it is not possible for a process to run on more than one
/// logical processor group. This usually means to be limited to use max 64
/// cores. To overcome this, some special platform specific API should be
/// called to set group affinity for each thread. Original code from Texel by
/// Peter Österlund.
namespace WinProcGroup {
void bindThisThread(size_t idx);
}
#endif // #ifndef MISC_H_INCLUDED #endif // #ifndef MISC_H_INCLUDED
+62 -62
View File
@@ -2,7 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -26,7 +26,7 @@
namespace { namespace {
template<CastlingRight Cr, bool Checks, bool Chess960> template<CastlingRight Cr, bool Checks, bool Chess960>
ExtMove* generate_castling(const Position& pos, ExtMove* moveList, Color us, const CheckInfo* ci) { ExtMove* generate_castling(const Position& pos, ExtMove* moveList, Color us) {
static const bool KingSide = (Cr == WHITE_OO || Cr == BLACK_OO); static const bool KingSide = (Cr == WHITE_OO || Cr == BLACK_OO);
@@ -42,8 +42,8 @@ namespace {
assert(!pos.checkers()); assert(!pos.checkers());
const Square K = Chess960 ? kto > kfrom ? DELTA_W : DELTA_E const Direction K = Chess960 ? kto > kfrom ? WEST : EAST
: KingSide ? DELTA_W : DELTA_E; : KingSide ? WEST : EAST;
for (Square s = kto; s != kfrom; s += K) for (Square s = kto; s != kfrom; s += K)
if (pos.attackers_to(s) & enemies) if (pos.attackers_to(s) & enemies)
@@ -57,53 +57,50 @@ namespace {
Move m = make<CASTLING>(kfrom, rfrom); Move m = make<CASTLING>(kfrom, rfrom);
if (Checks && !pos.gives_check(m, *ci)) if (Checks && !pos.gives_check(m))
return moveList; return moveList;
else
(void)ci; // Silence a warning under MSVC
*moveList++ = m; *moveList++ = m;
return moveList; return moveList;
} }
template<GenType Type, Square Delta> template<GenType Type, Direction D>
ExtMove* make_promotions(ExtMove* moveList, Square to, const CheckInfo* ci) { ExtMove* make_promotions(ExtMove* moveList, Square to, Square ksq) {
if (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS) if (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS)
*moveList++ = make<PROMOTION>(to - Delta, to, QUEEN); *moveList++ = make<PROMOTION>(to - D, to, QUEEN);
if (Type == QUIETS || Type == EVASIONS || Type == NON_EVASIONS) if (Type == QUIETS || Type == EVASIONS || Type == NON_EVASIONS)
{ {
*moveList++ = make<PROMOTION>(to - Delta, to, ROOK); *moveList++ = make<PROMOTION>(to - D, to, ROOK);
*moveList++ = make<PROMOTION>(to - Delta, to, BISHOP); *moveList++ = make<PROMOTION>(to - D, to, BISHOP);
*moveList++ = make<PROMOTION>(to - Delta, to, KNIGHT); *moveList++ = make<PROMOTION>(to - D, to, KNIGHT);
} }
// Knight promotion is the only promotion that can give a direct check // Knight promotion is the only promotion that can give a direct check
// that's not already included in the queen promotion. // that's not already included in the queen promotion.
if (Type == QUIET_CHECKS && (StepAttacksBB[W_KNIGHT][to] & ci->ksq)) if (Type == QUIET_CHECKS && (PseudoAttacks[KNIGHT][to] & ksq))
*moveList++ = make<PROMOTION>(to - Delta, to, KNIGHT); *moveList++ = make<PROMOTION>(to - D, to, KNIGHT);
else else
(void)ci; // Silence a warning under MSVC (void)ksq; // Silence a warning under MSVC
return moveList; return moveList;
} }
template<Color Us, GenType Type> template<Color Us, GenType Type>
ExtMove* generate_pawn_moves(const Position& pos, ExtMove* moveList, ExtMove* generate_pawn_moves(const Position& pos, ExtMove* moveList, Bitboard target) {
Bitboard target, const CheckInfo* ci) {
// Compute our parametrized parameters at compile time, named according to // Compute our parametrized parameters at compile time, named according to
// the point of view of white side. // the point of view of white side.
const Color Them = (Us == WHITE ? BLACK : WHITE); const Color Them = (Us == WHITE ? BLACK : WHITE);
const Bitboard TRank8BB = (Us == WHITE ? Rank8BB : Rank1BB); const Bitboard TRank8BB = (Us == WHITE ? Rank8BB : Rank1BB);
const Bitboard TRank7BB = (Us == WHITE ? Rank7BB : Rank2BB); const Bitboard TRank7BB = (Us == WHITE ? Rank7BB : Rank2BB);
const Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB); const Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB);
const Square Up = (Us == WHITE ? DELTA_N : DELTA_S); const Direction Up = (Us == WHITE ? NORTH : SOUTH);
const Square Right = (Us == WHITE ? DELTA_NE : DELTA_SW); const Direction Right = (Us == WHITE ? NORTH_EAST : SOUTH_WEST);
const Square Left = (Us == WHITE ? DELTA_NW : DELTA_SE); const Direction Left = (Us == WHITE ? NORTH_WEST : SOUTH_EAST);
Bitboard emptySquares; Bitboard emptySquares;
@@ -118,8 +115,8 @@ namespace {
{ {
emptySquares = (Type == QUIETS || Type == QUIET_CHECKS ? target : ~pos.pieces()); emptySquares = (Type == QUIETS || Type == QUIET_CHECKS ? target : ~pos.pieces());
Bitboard b1 = shift_bb<Up>(pawnsNotOn7) & emptySquares; Bitboard b1 = shift<Up>(pawnsNotOn7) & emptySquares;
Bitboard b2 = shift_bb<Up>(b1 & TRank3BB) & emptySquares; Bitboard b2 = shift<Up>(b1 & TRank3BB) & emptySquares;
if (Type == EVASIONS) // Consider only blocking squares if (Type == EVASIONS) // Consider only blocking squares
{ {
@@ -129,17 +126,20 @@ namespace {
if (Type == QUIET_CHECKS) if (Type == QUIET_CHECKS)
{ {
b1 &= pos.attacks_from<PAWN>(ci->ksq, Them); Square ksq = pos.square<KING>(Them);
b2 &= pos.attacks_from<PAWN>(ci->ksq, Them);
b1 &= pos.attacks_from<PAWN>(ksq, Them);
b2 &= pos.attacks_from<PAWN>(ksq, Them);
// Add pawn pushes which give discovered check. This is possible only // Add pawn pushes which give discovered check. This is possible only
// if the pawn is not on the same file as the enemy king, because we // if the pawn is not on the same file as the enemy king, because we
// don't generate captures. Note that a possible discovery check // don't generate captures. Note that a possible discovery check
// promotion has been already generated amongst the captures. // promotion has been already generated amongst the captures.
if (pawnsNotOn7 & ci->dcCandidates) Bitboard dcCandidates = pos.discovered_check_candidates();
if (pawnsNotOn7 & dcCandidates)
{ {
Bitboard dc1 = shift_bb<Up>(pawnsNotOn7 & ci->dcCandidates) & emptySquares & ~file_bb(ci->ksq); Bitboard dc1 = shift<Up>(pawnsNotOn7 & dcCandidates) & emptySquares & ~file_bb(ksq);
Bitboard dc2 = shift_bb<Up>(dc1 & TRank3BB) & emptySquares; Bitboard dc2 = shift<Up>(dc1 & TRank3BB) & emptySquares;
b1 |= dc1; b1 |= dc1;
b2 |= dc2; b2 |= dc2;
@@ -168,25 +168,27 @@ namespace {
if (Type == EVASIONS) if (Type == EVASIONS)
emptySquares &= target; emptySquares &= target;
Bitboard b1 = shift_bb<Right>(pawnsOn7) & enemies; Bitboard b1 = shift<Right>(pawnsOn7) & enemies;
Bitboard b2 = shift_bb<Left >(pawnsOn7) & enemies; Bitboard b2 = shift<Left >(pawnsOn7) & enemies;
Bitboard b3 = shift_bb<Up >(pawnsOn7) & emptySquares; Bitboard b3 = shift<Up >(pawnsOn7) & emptySquares;
Square ksq = pos.square<KING>(Them);
while (b1) while (b1)
moveList = make_promotions<Type, Right>(moveList, pop_lsb(&b1), ci); moveList = make_promotions<Type, Right>(moveList, pop_lsb(&b1), ksq);
while (b2) while (b2)
moveList = make_promotions<Type, Left >(moveList, pop_lsb(&b2), ci); moveList = make_promotions<Type, Left >(moveList, pop_lsb(&b2), ksq);
while (b3) while (b3)
moveList = make_promotions<Type, Up >(moveList, pop_lsb(&b3), ci); moveList = make_promotions<Type, Up >(moveList, pop_lsb(&b3), ksq);
} }
// Standard and en-passant captures // Standard and en-passant captures
if (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS) if (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS)
{ {
Bitboard b1 = shift_bb<Right>(pawnsNotOn7) & enemies; Bitboard b1 = shift<Right>(pawnsNotOn7) & enemies;
Bitboard b2 = shift_bb<Left >(pawnsNotOn7) & enemies; Bitboard b2 = shift<Left >(pawnsNotOn7) & enemies;
while (b1) while (b1)
{ {
@@ -225,7 +227,7 @@ namespace {
template<PieceType Pt, bool Checks> template<PieceType Pt, bool Checks>
ExtMove* generate_moves(const Position& pos, ExtMove* moveList, Color us, ExtMove* generate_moves(const Position& pos, ExtMove* moveList, Color us,
Bitboard target, const CheckInfo* ci) { Bitboard target) {
assert(Pt != KING && Pt != PAWN); assert(Pt != KING && Pt != PAWN);
@@ -236,17 +238,17 @@ namespace {
if (Checks) if (Checks)
{ {
if ( (Pt == BISHOP || Pt == ROOK || Pt == QUEEN) if ( (Pt == BISHOP || Pt == ROOK || Pt == QUEEN)
&& !(PseudoAttacks[Pt][from] & target & ci->checkSquares[Pt])) && !(PseudoAttacks[Pt][from] & target & pos.check_squares(Pt)))
continue; continue;
if (ci->dcCandidates && (ci->dcCandidates & from)) if (pos.discovered_check_candidates() & from)
continue; continue;
} }
Bitboard b = pos.attacks_from<Pt>(from) & target; Bitboard b = pos.attacks_from<Pt>(from) & target;
if (Checks) if (Checks)
b &= ci->checkSquares[Pt]; b &= pos.check_squares(Pt);
while (b) while (b)
*moveList++ = make_move(from, pop_lsb(&b)); *moveList++ = make_move(from, pop_lsb(&b));
@@ -257,16 +259,15 @@ namespace {
template<Color Us, GenType Type> template<Color Us, GenType Type>
ExtMove* generate_all(const Position& pos, ExtMove* moveList, Bitboard target, ExtMove* generate_all(const Position& pos, ExtMove* moveList, Bitboard target) {
const CheckInfo* ci = nullptr) {
const bool Checks = Type == QUIET_CHECKS; const bool Checks = Type == QUIET_CHECKS;
moveList = generate_pawn_moves<Us, Type>(pos, moveList, target, ci); moveList = generate_pawn_moves<Us, Type>(pos, moveList, target);
moveList = generate_moves<KNIGHT, Checks>(pos, moveList, Us, target, ci); moveList = generate_moves<KNIGHT, Checks>(pos, moveList, Us, target);
moveList = generate_moves<BISHOP, Checks>(pos, moveList, Us, target, ci); moveList = generate_moves<BISHOP, Checks>(pos, moveList, Us, target);
moveList = generate_moves< ROOK, Checks>(pos, moveList, Us, target, ci); moveList = generate_moves< ROOK, Checks>(pos, moveList, Us, target);
moveList = generate_moves< QUEEN, Checks>(pos, moveList, Us, target, ci); moveList = generate_moves< QUEEN, Checks>(pos, moveList, Us, target);
if (Type != QUIET_CHECKS && Type != EVASIONS) if (Type != QUIET_CHECKS && Type != EVASIONS)
{ {
@@ -280,13 +281,13 @@ namespace {
{ {
if (pos.is_chess960()) if (pos.is_chess960())
{ {
moveList = generate_castling<MakeCastling<Us, KING_SIDE>::right, Checks, true>(pos, moveList, Us, ci); moveList = generate_castling<MakeCastling<Us, KING_SIDE>::right, Checks, true>(pos, moveList, Us);
moveList = generate_castling<MakeCastling<Us, QUEEN_SIDE>::right, Checks, true>(pos, moveList, Us, ci); moveList = generate_castling<MakeCastling<Us, QUEEN_SIDE>::right, Checks, true>(pos, moveList, Us);
} }
else else
{ {
moveList = generate_castling<MakeCastling<Us, KING_SIDE>::right, Checks, false>(pos, moveList, Us, ci); moveList = generate_castling<MakeCastling<Us, KING_SIDE>::right, Checks, false>(pos, moveList, Us);
moveList = generate_castling<MakeCastling<Us, QUEEN_SIDE>::right, Checks, false>(pos, moveList, Us, ci); moveList = generate_castling<MakeCastling<Us, QUEEN_SIDE>::right, Checks, false>(pos, moveList, Us);
} }
} }
@@ -335,8 +336,7 @@ ExtMove* generate<QUIET_CHECKS>(const Position& pos, ExtMove* moveList) {
assert(!pos.checkers()); assert(!pos.checkers());
Color us = pos.side_to_move(); Color us = pos.side_to_move();
CheckInfo ci(pos); Bitboard dc = pos.discovered_check_candidates();
Bitboard dc = ci.dcCandidates;
while (dc) while (dc)
{ {
@@ -346,17 +346,17 @@ ExtMove* generate<QUIET_CHECKS>(const Position& pos, ExtMove* moveList) {
if (pt == PAWN) if (pt == PAWN)
continue; // Will be generated together with direct checks continue; // Will be generated together with direct checks
Bitboard b = pos.attacks_from(Piece(pt), from) & ~pos.pieces(); Bitboard b = pos.attacks_from(pt, from) & ~pos.pieces();
if (pt == KING) if (pt == KING)
b &= ~PseudoAttacks[QUEEN][ci.ksq]; b &= ~PseudoAttacks[QUEEN][pos.square<KING>(~us)];
while (b) while (b)
*moveList++ = make_move(from, pop_lsb(&b)); *moveList++ = make_move(from, pop_lsb(&b));
} }
return us == WHITE ? generate_all<WHITE, QUIET_CHECKS>(pos, moveList, ~pos.pieces(), &ci) return us == WHITE ? generate_all<WHITE, QUIET_CHECKS>(pos, moveList, ~pos.pieces())
: generate_all<BLACK, QUIET_CHECKS>(pos, moveList, ~pos.pieces(), &ci); : generate_all<BLACK, QUIET_CHECKS>(pos, moveList, ~pos.pieces());
} }
@@ -411,7 +411,7 @@ ExtMove* generate<LEGAL>(const Position& pos, ExtMove* moveList) {
: generate<NON_EVASIONS>(pos, moveList); : generate<NON_EVASIONS>(pos, moveList);
while (cur != moveList) while (cur != moveList)
if ( (pinned || from_sq(*cur) == ksq || type_of(*cur) == ENPASSANT) if ( (pinned || from_sq(*cur) == ksq || type_of(*cur) == ENPASSANT)
&& !pos.legal(*cur, pinned)) && !pos.legal(*cur))
*cur = (--moveList)->move; *cur = (--moveList)->move;
else else
++cur; ++cur;
+9 -4
View File
@@ -2,7 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -21,6 +21,8 @@
#ifndef MOVEGEN_H_INCLUDED #ifndef MOVEGEN_H_INCLUDED
#define MOVEGEN_H_INCLUDED #define MOVEGEN_H_INCLUDED
#include <algorithm>
#include "types.h" #include "types.h"
class Position; class Position;
@@ -36,10 +38,14 @@ enum GenType {
struct ExtMove { struct ExtMove {
Move move; Move move;
Value value; int value;
operator Move() const { return move; } operator Move() const { return move; }
void operator=(Move m) { move = m; } void operator=(Move m) { move = m; }
// Inhibit unwanted implicit conversions to Move
// with an ambiguity that yields to a compile error.
operator float() const = delete;
}; };
inline bool operator<(const ExtMove& f, const ExtMove& s) { inline bool operator<(const ExtMove& f, const ExtMove& s) {
@@ -59,8 +65,7 @@ struct MoveList {
const ExtMove* end() const { return last; } const ExtMove* end() const { return last; }
size_t size() const { return last - moveList; } size_t size() const { return last - moveList; }
bool contains(Move move) const { bool contains(Move move) const {
for (const auto& m : *this) if (m == move) return true; return std::find(begin(), end(), move) != end();
return false;
} }
private: private:
+211 -195
View File
@@ -2,7 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -21,41 +21,40 @@
#include <cassert> #include <cassert>
#include "movepick.h" #include "movepick.h"
#include "thread.h"
namespace { namespace {
enum Stages { enum Stages {
MAIN_SEARCH, GOOD_CAPTURES, KILLERS, GOOD_QUIETS, BAD_QUIETS, BAD_CAPTURES, MAIN_SEARCH, CAPTURES_INIT, GOOD_CAPTURES, KILLERS, COUNTERMOVE, QUIET_INIT, QUIET, BAD_CAPTURES,
EVASION, ALL_EVASIONS, EVASION, EVASIONS_INIT, ALL_EVASIONS,
QSEARCH_WITH_CHECKS, QCAPTURES_1, CHECKS, PROBCUT, PROBCUT_INIT, PROBCUT_CAPTURES,
QSEARCH_WITHOUT_CHECKS, QCAPTURES_2, QSEARCH_WITH_CHECKS, QCAPTURES_1_INIT, QCAPTURES_1, QCHECKS,
PROBCUT, PROBCUT_CAPTURES, QSEARCH_NO_CHECKS, QCAPTURES_2_INIT, QCAPTURES_2,
RECAPTURE, RECAPTURES, QSEARCH_RECAPTURES, QRECAPTURES
STOP
}; };
// Our insertion sort, which is guaranteed to be stable, as it should be // partial_insertion_sort() sorts moves in descending order up to and including
void insertion_sort(ExtMove* begin, ExtMove* end) // a given limit. The order of moves smaller than the limit is left unspecified.
{ void partial_insertion_sort(ExtMove* begin, ExtMove* end, int limit) {
ExtMove tmp, *p, *q;
for (p = begin + 1; p < end; ++p) for (ExtMove *sortedEnd = begin, *p = begin + 1; p < end; ++p)
{ if (p->value >= limit)
tmp = *p; {
for (q = p; q != begin && *(q-1) < tmp; --q) ExtMove tmp = *p, *q;
*q = *(q-1); *p = *++sortedEnd;
*q = tmp; for (q = sortedEnd; q != begin && *(q - 1) < tmp; --q)
} *q = *(q - 1);
*q = tmp;
}
} }
// pick_best() finds the best move in the range (begin, end) and moves it to // pick_best() finds the best move in the range (begin, end) and moves it to
// the front. It's faster than sorting all the moves in advance when there // the front. It's faster than sorting all the moves in advance when there
// are few moves e.g. the possible captures. // are few moves, e.g., the possible captures.
Move pick_best(ExtMove* begin, ExtMove* end) Move pick_best(ExtMove* begin, ExtMove* end) {
{
std::swap(*begin, *std::max_element(begin, end)); std::swap(*begin, *std::max_element(begin, end));
return *begin; return *begin;
} }
} // namespace } // namespace
@@ -64,23 +63,25 @@ namespace {
/// Constructors of the MovePicker class. As arguments we pass information /// Constructors of the MovePicker class. As arguments we pass information
/// to help it to return the (presumably) good moves first, to decide which /// to help it to return the (presumably) good moves first, to decide which
/// moves to return (in the quiescence search, for instance, we only want to /// moves to return (in the quiescence search, for instance, we only want to
/// search captures, promotions and some checks) and how important good move /// search captures, promotions, and some checks) and how important good move
/// ordering is at the current node. /// ordering is at the current node.
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const HistoryStats& h, /// MovePicker constructor for the main search
const CounterMovesStats& cmh, Move cm, Search::Stack* s) MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh,
: pos(p), history(h), counterMovesHistory(&cmh), ss(s), countermove(cm), depth(d) { const CapturePieceToHistory* cph, const PieceToHistory** ch, Move cm, Move* killers_p)
: pos(p), mainHistory(mh), captureHistory(cph), contHistory(ch), countermove(cm),
killers{killers_p[0], killers_p[1]}, depth(d){
assert(d > DEPTH_ZERO); assert(d > DEPTH_ZERO);
stage = pos.checkers() ? EVASION : MAIN_SEARCH; stage = pos.checkers() ? EVASION : MAIN_SEARCH;
ttMove = ttm && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE; ttMove = ttm && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE;
endMoves += (ttMove != MOVE_NONE); stage += (ttMove == MOVE_NONE);
} }
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, /// MovePicker constructor for quiescence search
const HistoryStats& h, Square s) MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh, const CapturePieceToHistory* cph, Square s)
: pos(p), history(h), counterMovesHistory(nullptr) { : pos(p), mainHistory(mh), captureHistory(cph) {
assert(d <= DEPTH_ZERO); assert(d <= DEPTH_ZERO);
@@ -91,228 +92,243 @@ MovePicker::MovePicker(const Position& p, Move ttm, Depth d,
stage = QSEARCH_WITH_CHECKS; stage = QSEARCH_WITH_CHECKS;
else if (d > DEPTH_QS_RECAPTURES) else if (d > DEPTH_QS_RECAPTURES)
stage = QSEARCH_WITHOUT_CHECKS; stage = QSEARCH_NO_CHECKS;
else else
{ {
stage = RECAPTURE; stage = QSEARCH_RECAPTURES;
recaptureSquare = s; recaptureSquare = s;
ttm = MOVE_NONE; return;
} }
ttMove = ttm && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE; ttMove = ttm && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE;
endMoves += (ttMove != MOVE_NONE); stage += (ttMove == MOVE_NONE);
} }
MovePicker::MovePicker(const Position& p, Move ttm, const HistoryStats& h, Value th) /// MovePicker constructor for ProbCut: we generate captures with SEE higher
: pos(p), history(h), counterMovesHistory(nullptr), threshold(th) { /// than or equal to the given threshold.
MovePicker::MovePicker(const Position& p, Move ttm, Value th, const CapturePieceToHistory* cph)
: pos(p), captureHistory(cph), threshold(th) {
assert(!pos.checkers()); assert(!pos.checkers());
stage = PROBCUT; stage = PROBCUT;
// In ProbCut we generate captures with SEE higher than the given threshold
ttMove = ttm ttMove = ttm
&& pos.pseudo_legal(ttm) && pos.pseudo_legal(ttm)
&& pos.capture(ttm) && pos.capture(ttm)
&& pos.see(ttm) > threshold ? ttm : MOVE_NONE; && pos.see_ge(ttm, threshold) ? ttm : MOVE_NONE;
endMoves += (ttMove != MOVE_NONE); stage += (ttMove == MOVE_NONE);
} }
/// score() assigns a numerical value to each move in a list, used for sorting.
/// Captures are ordered by Most Valuable Victim (MVV), preferring captures
/// with a good history. Quiets are ordered using the histories.
template<GenType Type>
void MovePicker::score() {
/// score() assigns a numerical value to each move in a move list. The moves with static_assert(Type == CAPTURES || Type == QUIETS || Type == EVASIONS, "Wrong type");
/// highest values will be picked first.
template<>
void MovePicker::score<CAPTURES>() {
// Winning and equal captures in the main search are ordered by MVV, preferring
// captures near our home rank. Surprisingly, this appears to perform slightly
// better than SEE based move ordering: exchanging big pieces before capturing
// a hanging piece probably helps to reduce the subtree size.
// In main search we want to push captures with negative SEE values to the
// badCaptures[] array, but instead of doing it now we delay until the move
// has been picked up, saving some SEE calls in case we get a cutoff.
for (auto& m : *this)
m.value = PieceValue[MG][pos.piece_on(to_sq(m))]
- Value(200 * relative_rank(pos.side_to_move(), to_sq(m)));
}
template<>
void MovePicker::score<QUIETS>() {
for (auto& m : *this) for (auto& m : *this)
m.value = history[pos.moved_piece(m)][to_sq(m)] if (Type == CAPTURES)
+ (*counterMovesHistory)[pos.moved_piece(m)][to_sq(m)];
}
template<>
void MovePicker::score<EVASIONS>() {
// Try winning and equal captures captures ordered by MVV/LVA, then non-captures
// ordered by history value, then bad-captures and quiet moves with a negative
// SEE ordered by SEE value.
Value see;
for (auto& m : *this)
if ((see = pos.see_sign(m)) < VALUE_ZERO)
m.value = see - HistoryStats::Max; // At the bottom
else if (pos.capture(m))
m.value = PieceValue[MG][pos.piece_on(to_sq(m))] m.value = PieceValue[MG][pos.piece_on(to_sq(m))]
- Value(type_of(pos.moved_piece(m))) + HistoryStats::Max; + Value((*captureHistory)[pos.moved_piece(m)][to_sq(m)][type_of(pos.piece_on(to_sq(m)))]);
else
m.value = history[pos.moved_piece(m)][to_sq(m)]; else if (Type == QUIETS)
m.value = (*mainHistory)[pos.side_to_move()][from_to(m)]
+ (*contHistory[0])[pos.moved_piece(m)][to_sq(m)]
+ (*contHistory[1])[pos.moved_piece(m)][to_sq(m)]
+ (*contHistory[3])[pos.moved_piece(m)][to_sq(m)];
else // Type == EVASIONS
{
if (pos.capture(m))
m.value = PieceValue[MG][pos.piece_on(to_sq(m))]
- Value(type_of(pos.moved_piece(m)));
else
m.value = (*mainHistory)[pos.side_to_move()][from_to(m)] - (1 << 28);
}
} }
/// generate_next_stage() generates, scores and sorts the next bunch of moves,
/// when there are no more moves to try for the current stage.
void MovePicker::generate_next_stage() {
assert(stage != STOP);
cur = moves;
switch (++stage) {
case GOOD_CAPTURES: case QCAPTURES_1: case QCAPTURES_2:
case PROBCUT_CAPTURES: case RECAPTURES:
endMoves = generate<CAPTURES>(pos, moves);
score<CAPTURES>();
break;
case KILLERS:
killers[0] = ss->killers[0];
killers[1] = ss->killers[1];
killers[2] = countermove;
cur = killers;
endMoves = cur + 2 + (countermove != killers[0] && countermove != killers[1]);
break;
case GOOD_QUIETS:
endQuiets = endMoves = generate<QUIETS>(pos, moves);
score<QUIETS>();
endMoves = std::partition(cur, endMoves, [](const ExtMove& m) { return m.value > VALUE_ZERO; });
insertion_sort(cur, endMoves);
break;
case BAD_QUIETS:
cur = endMoves;
endMoves = endQuiets;
if (depth >= 3 * ONE_PLY)
insertion_sort(cur, endMoves);
break;
case BAD_CAPTURES:
// Just pick them in reverse order to get correct ordering
cur = moves + MAX_MOVES - 1;
endMoves = endBadCaptures;
break;
case ALL_EVASIONS:
endMoves = generate<EVASIONS>(pos, moves);
if (endMoves - moves > 1)
score<EVASIONS>();
break;
case CHECKS:
endMoves = generate<QUIET_CHECKS>(pos, moves);
break;
case EVASION: case QSEARCH_WITH_CHECKS: case QSEARCH_WITHOUT_CHECKS:
case PROBCUT: case RECAPTURE: case STOP:
stage = STOP;
break;
default:
assert(false);
}
}
/// next_move() is the most important method of the MovePicker class. It returns /// next_move() is the most important method of the MovePicker class. It returns
/// a new pseudo legal move every time it is called, until there are no more moves /// a new pseudo legal move every time it is called, until there are no more moves
/// left. It picks the move with the biggest value from a list of generated moves /// left. It picks the move with the biggest value from a list of generated moves
/// taking care not to return the ttMove if it has already been searched. /// taking care not to return the ttMove if it has already been searched.
Move MovePicker::next_move() { Move MovePicker::next_move(bool skipQuiets) {
Move move; Move move;
while (true) switch (stage) {
{
while (cur == endMoves && stage != STOP)
generate_next_stage();
switch (stage) { case MAIN_SEARCH: case EVASION: case QSEARCH_WITH_CHECKS:
case QSEARCH_NO_CHECKS: case PROBCUT:
++stage;
return ttMove;
case MAIN_SEARCH: case EVASION: case QSEARCH_WITH_CHECKS: case CAPTURES_INIT:
case QSEARCH_WITHOUT_CHECKS: case PROBCUT: endBadCaptures = cur = moves;
++cur; endMoves = generate<CAPTURES>(pos, cur);
return ttMove; score<CAPTURES>();
++stage;
/* fallthrough */
case GOOD_CAPTURES: case GOOD_CAPTURES:
while (cur < endMoves)
{
move = pick_best(cur++, endMoves); move = pick_best(cur++, endMoves);
if (move != ttMove) if (move != ttMove)
{ {
if (pos.see_sign(move) >= VALUE_ZERO) if (pos.see_ge(move, Value(-55 * (cur-1)->value / 1024)))
return move; return move;
// Losing capture, move it to the tail of the array // Losing capture, move it to the beginning of the array
*endBadCaptures-- = move; *endBadCaptures++ = move;
} }
break; }
case KILLERS: ++stage;
move = *cur++; move = killers[0]; // First killer move
if ( move != MOVE_NONE if ( move != MOVE_NONE
&& move != ttMove && move != ttMove
&& pos.pseudo_legal(move) && pos.pseudo_legal(move)
&& !pos.capture(move)) && !pos.capture(move))
return move; return move;
break; /* fallthrough */
case GOOD_QUIETS: case BAD_QUIETS: case KILLERS:
++stage;
move = killers[1]; // Second killer move
if ( move != MOVE_NONE
&& move != ttMove
&& pos.pseudo_legal(move)
&& !pos.capture(move))
return move;
/* fallthrough */
case COUNTERMOVE:
++stage;
move = countermove;
if ( move != MOVE_NONE
&& move != ttMove
&& move != killers[0]
&& move != killers[1]
&& pos.pseudo_legal(move)
&& !pos.capture(move))
return move;
/* fallthrough */
case QUIET_INIT:
cur = endBadCaptures;
endMoves = generate<QUIETS>(pos, cur);
score<QUIETS>();
partial_insertion_sort(cur, endMoves, -4000 * depth / ONE_PLY);
++stage;
/* fallthrough */
case QUIET:
while ( cur < endMoves
&& (!skipQuiets || cur->value >= VALUE_ZERO))
{
move = *cur++; move = *cur++;
if ( move != ttMove if ( move != ttMove
&& move != killers[0] && move != killers[0]
&& move != killers[1] && move != killers[1]
&& move != killers[2]) && move != countermove)
return move; return move;
break; }
++stage;
cur = moves; // Point to beginning of bad captures
/* fallthrough */
case BAD_CAPTURES: case BAD_CAPTURES:
return *cur--; if (cur < endBadCaptures)
return *cur++;
break;
case ALL_EVASIONS: case QCAPTURES_1: case QCAPTURES_2: case EVASIONS_INIT:
cur = moves;
endMoves = generate<EVASIONS>(pos, cur);
score<EVASIONS>();
++stage;
/* fallthrough */
case ALL_EVASIONS:
while (cur < endMoves)
{
move = pick_best(cur++, endMoves); move = pick_best(cur++, endMoves);
if (move != ttMove) if (move != ttMove)
return move; return move;
}
break;
case PROBCUT_INIT:
cur = moves;
endMoves = generate<CAPTURES>(pos, cur);
score<CAPTURES>();
++stage;
/* fallthrough */
case PROBCUT_CAPTURES:
while (cur < endMoves)
{
move = pick_best(cur++, endMoves);
if ( move != ttMove
&& pos.see_ge(move, threshold))
return move;
}
break;
case QCAPTURES_1_INIT: case QCAPTURES_2_INIT:
cur = moves;
endMoves = generate<CAPTURES>(pos, cur);
score<CAPTURES>();
++stage;
/* fallthrough */
case QCAPTURES_1: case QCAPTURES_2:
while (cur < endMoves)
{
move = pick_best(cur++, endMoves);
if (move != ttMove)
return move;
}
if (stage == QCAPTURES_2)
break; break;
cur = moves;
endMoves = generate<QUIET_CHECKS>(pos, cur);
++stage;
/* fallthrough */
case PROBCUT_CAPTURES: case QCHECKS:
move = pick_best(cur++, endMoves); while (cur < endMoves)
if (move != ttMove && pos.see(move) > threshold) {
return move; move = cur++->move;
break; if (move != ttMove)
return move;
}
break;
case RECAPTURES: case QSEARCH_RECAPTURES:
cur = moves;
endMoves = generate<CAPTURES>(pos, cur);
score<CAPTURES>();
++stage;
/* fallthrough */
case QRECAPTURES:
while (cur < endMoves)
{
move = pick_best(cur++, endMoves); move = pick_best(cur++, endMoves);
if (to_sq(move) == recaptureSquare) if (to_sq(move) == recaptureSquare)
return move; return move;
break;
case CHECKS:
move = *cur++;
if (move != ttMove)
return move;
break;
case STOP:
return MOVE_NONE;
default:
assert(false);
} }
break;
default:
assert(false);
} }
return MOVE_NONE;
} }
+92 -54
View File
@@ -2,7 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -21,54 +21,97 @@
#ifndef MOVEPICK_H_INCLUDED #ifndef MOVEPICK_H_INCLUDED
#define MOVEPICK_H_INCLUDED #define MOVEPICK_H_INCLUDED
#include <algorithm> // For std::max #include <array>
#include <cstring> // For std::memset #include <limits>
#include "movegen.h" #include "movegen.h"
#include "position.h" #include "position.h"
#include "search.h"
#include "types.h" #include "types.h"
/// StatBoards is a generic 2-dimensional array used to store various statistics
template<int Size1, int Size2, typename T = int16_t>
struct StatBoards : public std::array<std::array<T, Size2>, Size1> {
/// The Stats struct stores moves statistics. According to the template parameter void fill(const T& v) {
/// the class can store History and Countermoves. History records how often T* p = &(*this)[0][0];
/// different moves have been successful or unsuccessful during the current search std::fill(p, p + sizeof(*this) / sizeof(*p), v);
/// and is used for reduction and move ordering decisions.
/// Countermoves store the move that refute a previous one. Entries are stored
/// using only the moving piece and destination square, hence two moves with
/// different origin but same destination and piece will be considered identical.
template<typename T, bool CM = false>
struct Stats {
static const Value Max = Value(1 << 28);
const T* operator[](Piece pc) const { return table[pc]; }
T* operator[](Piece pc) { return table[pc]; }
void clear() { std::memset(table, 0, sizeof(table)); }
void update(Piece pc, Square to, Move m) {
if (m != table[pc][to])
table[pc][to] = m;
} }
void update(Piece pc, Square to, Value v) { void update(T& entry, int bonus, const int D) {
if (abs(int(v)) >= 324) assert(abs(bonus) <= D); // Ensure range is [-32 * D, 32 * D]
return; assert(abs(32 * D) < (std::numeric_limits<T>::max)()); // Ensure we don't overflow
table[pc][to] -= table[pc][to] * abs(int(v)) / (CM ? 512 : 324); entry += bonus * 32 - entry * abs(bonus) / D;
table[pc][to] += int(v) * (CM ? 64 : 32);
assert(abs(entry) <= 32 * D);
} }
private:
T table[PIECE_NB][SQUARE_NB];
}; };
typedef Stats<Move> MovesStats; /// StatCubes is a generic 3-dimensional array used to store various statistics
typedef Stats<Value, false> HistoryStats; template<int Size1, int Size2, int Size3, typename T = int16_t>
typedef Stats<Value, true> CounterMovesStats; struct StatCubes : public std::array<std::array<std::array<T, Size3>, Size2>, Size1> {
typedef Stats<CounterMovesStats> CounterMovesHistoryStats;
void fill(const T& v) {
T* p = &(*this)[0][0][0];
std::fill(p, p + sizeof(*this) / sizeof(*p), v);
}
void update(T& entry, int bonus, const int D, const int W) {
assert(abs(bonus) <= D); // Ensure range is [-W * D, W * D]
assert(abs(W * D) < (std::numeric_limits<T>::max)()); // Ensure we don't overflow
entry += bonus * W - entry * abs(bonus) / D;
assert(abs(entry) <= W * D);
}
};
/// ButterflyBoards are 2 tables (one for each color) indexed by the move's from
/// and to squares, see chessprogramming.wikispaces.com/Butterfly+Boards
typedef StatBoards<COLOR_NB, int(SQUARE_NB) * int(SQUARE_NB)> ButterflyBoards;
/// PieceToBoards are addressed by a move's [piece][to] information
typedef StatBoards<PIECE_NB, SQUARE_NB> PieceToBoards;
/// CapturePieceToBoards are addressed by a move's [piece][to][captured piece type] information
typedef StatCubes<PIECE_NB, SQUARE_NB, PIECE_TYPE_NB> CapturePieceToBoards;
/// ButterflyHistory records how often quiet moves have been successful or
/// unsuccessful during the current search, and is used for reduction and move
/// ordering decisions. It uses ButterflyBoards as backing store.
struct ButterflyHistory : public ButterflyBoards {
void update(Color c, Move m, int bonus) {
StatBoards::update((*this)[c][from_to(m)], bonus, 324);
}
};
/// PieceToHistory is like ButterflyHistory, but is based on PieceToBoards
struct PieceToHistory : public PieceToBoards {
void update(Piece pc, Square to, int bonus) {
StatBoards::update((*this)[pc][to], bonus, 936);
}
};
/// CapturePieceToHistory is like PieceToHistory, but is based on CapturePieceToBoards
struct CapturePieceToHistory : public CapturePieceToBoards {
void update(Piece pc, Square to, PieceType captured, int bonus) {
StatCubes::update((*this)[pc][to][captured], bonus, 324, 2);
}
};
/// CounterMoveHistory stores counter moves indexed by [piece][to] of the previous
/// move, see chessprogramming.wikispaces.com/Countermove+Heuristic
typedef StatBoards<PIECE_NB, SQUARE_NB, Move> CounterMoveHistory;
/// ContinuationHistory is the history of a given pair of moves, usually the
/// current one given a previous one. History table is based on PieceToBoards
/// instead of ButterflyBoards.
typedef StatBoards<PIECE_NB, SQUARE_NB, PieceToHistory> ContinuationHistory;
/// MovePicker class is used to pick one pseudo legal move at a time from the /// MovePicker class is used to pick one pseudo legal move at a time from the
@@ -82,32 +125,27 @@ class MovePicker {
public: public:
MovePicker(const MovePicker&) = delete; MovePicker(const MovePicker&) = delete;
MovePicker& operator=(const MovePicker&) = delete; MovePicker& operator=(const MovePicker&) = delete;
MovePicker(const Position&, Move, Value, const CapturePieceToHistory*);
MovePicker(const Position&, Move, Depth, const HistoryStats&, Square); MovePicker(const Position&, Move, Depth, const ButterflyHistory*, const CapturePieceToHistory*, Square);
MovePicker(const Position&, Move, const HistoryStats&, Value); MovePicker(const Position&, Move, Depth, const ButterflyHistory*, const CapturePieceToHistory*, const PieceToHistory**, Move, Move*);
MovePicker(const Position&, Move, Depth, const HistoryStats&, const CounterMovesStats&, Move, Search::Stack*); Move next_move(bool skipQuiets = false);
Move next_move();
private: private:
template<GenType> void score(); template<GenType> void score();
void generate_next_stage(); ExtMove* begin() { return cur; }
ExtMove* begin() { return moves; }
ExtMove* end() { return endMoves; } ExtMove* end() { return endMoves; }
const Position& pos; const Position& pos;
const HistoryStats& history; const ButterflyHistory* mainHistory;
const CounterMovesStats* counterMovesHistory; const CapturePieceToHistory* captureHistory;
Search::Stack* ss; const PieceToHistory** contHistory;
Move countermove; Move ttMove, countermove, killers[2];
Depth depth; ExtMove *cur, *endMoves, *endBadCaptures;
Move ttMove; int stage;
ExtMove killers[3];
Square recaptureSquare; Square recaptureSquare;
Value threshold; Value threshold;
int stage; Depth depth;
ExtMove *endQuiets, *endBadCaptures = moves + MAX_MOVES - 1; ExtMove moves[MAX_MOVES];
ExtMove moves[MAX_MOVES], *cur = moves, *endMoves = moves;
}; };
#endif // #ifndef MOVEPICK_H_INCLUDED #endif // #ifndef MOVEPICK_H_INCLUDED
+116 -136
View File
@@ -2,7 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -22,7 +22,6 @@
#include <cassert> #include <cassert>
#include "bitboard.h" #include "bitboard.h"
#include "bitcount.h"
#include "pawns.h" #include "pawns.h"
#include "position.h" #include "position.h"
#include "thread.h" #include "thread.h"
@@ -32,60 +31,52 @@ namespace {
#define V Value #define V Value
#define S(mg, eg) make_score(mg, eg) #define S(mg, eg) make_score(mg, eg)
// Isolated pawn penalty by opposed flag and file // Isolated pawn penalty
const Score Isolated[2][FILE_NB] = { const Score Isolated = S(13, 18);
{ S(37, 45), S(54, 52), S(60, 52), S(60, 52),
S(60, 52), S(60, 52), S(54, 52), S(37, 45) },
{ S(25, 30), S(36, 35), S(40, 35), S(40, 35),
S(40, 35), S(40, 35), S(36, 35), S(25, 30) } };
// Backward pawn penalty by opposed flag // Backward pawn penalty
const Score Backward[2] = { S(67, 42), S(49, 24) }; const Score Backward = S(24, 12);
// Unsupported pawn penalty, for pawns which are neither isolated or backward // Connected pawn bonus by opposed, phalanx, #support and rank
const Score Unsupported = S(20, 10); Score Connected[2][2][3][RANK_NB];
// Connected pawn bonus by opposed, phalanx, twice supported and rank // Doubled pawn penalty
Score Connected[2][2][2][RANK_NB]; const Score Doubled = S(18, 38);
// Doubled pawn penalty by file // Weakness of our pawn shelter in front of the king by [isKingFile][distance from edge][rank].
const Score Doubled[FILE_NB] = { // RANK_1 = 0 is used for files where we have no pawns or our pawn is behind our king.
S(13, 43), S(20, 48), S(23, 48), S(23, 48), const Value ShelterWeakness[][int(FILE_NB) / 2][RANK_NB] = {
S(23, 48), S(23, 48), S(20, 48), S(13, 43) }; { { V( 97), V(17), V( 9), V(44), V( 84), V( 87), V( 99) }, // Not On King file
{ V(106), V( 6), V(33), V(86), V( 87), V(104), V(112) },
{ V(101), V( 2), V(65), V(98), V( 58), V( 89), V(115) },
{ V( 73), V( 7), V(54), V(73), V( 84), V( 83), V(111) } },
{ { V(104), V(20), V( 6), V(27), V( 86), V( 93), V( 82) }, // On King file
{ V(123), V( 9), V(34), V(96), V(112), V( 88), V( 75) },
{ V(120), V(25), V(65), V(91), V( 66), V( 78), V(117) },
{ V( 81), V( 2), V(47), V(63), V( 94), V( 93), V(104) } }
};
// Lever bonus by rank // Danger of enemy pawns moving toward our king by [type][distance from edge][rank].
const Score Lever[RANK_NB] = { // For the unopposed and unblocked cases, RANK_1 = 0 is used when opponent has
S( 0, 0), S( 0, 0), S(0, 0), S(0, 0), // no pawn on the given file, or their pawn is behind our king.
S(20, 20), S(40, 40), S(0, 0), S(0, 0) };
// Center bind bonus, when two pawns controls the same central square
const Score CenterBind = S(16, 0);
// Weakness of our pawn shelter in front of the king by [distance from edge][rank]
const Value ShelterWeakness[][RANK_NB] = {
{ V( 97), V(21), V(26), V(51), V(87), V( 89), V( 99) },
{ V(120), V( 0), V(28), V(76), V(88), V(103), V(104) },
{ V(101), V( 7), V(54), V(78), V(77), V( 92), V(101) },
{ V( 80), V(11), V(44), V(68), V(87), V( 90), V(119) } };
// Danger of enemy pawns moving toward our king by [type][distance from edge][rank]
const Value StormDanger[][4][RANK_NB] = { const Value StormDanger[][4][RANK_NB] = {
{ { V( 0), V( 67), V( 134), V(38), V(32) }, { { V( 0), V(-290), V(-274), V(57), V(41) }, // BlockedByKing
{ V( 0), V( 57), V( 139), V(37), V(22) }, { V( 0), V( 60), V( 144), V(39), V(13) },
{ V( 0), V( 43), V( 115), V(43), V(27) }, { V( 0), V( 65), V( 141), V(41), V(34) },
{ V( 0), V( 68), V( 124), V(57), V(32) } }, { V( 0), V( 53), V( 127), V(56), V(14) } },
{ { V(20), V( 43), V( 100), V(56), V(20) }, { { V( 4), V( 73), V( 132), V(46), V(31) }, // Unopposed
{ V(23), V( 20), V( 98), V(40), V(15) }, { V( 1), V( 64), V( 143), V(26), V(13) },
{ V(23), V( 39), V( 103), V(36), V(18) }, { V( 1), V( 47), V( 110), V(44), V(24) },
{ V(28), V( 19), V( 108), V(42), V(26) } }, { V( 0), V( 72), V( 127), V(50), V(31) } },
{ { V( 0), V( 0), V( 75), V(14), V( 2) }, { { V( 0), V( 0), V( 79), V(23), V( 1) }, // BlockedByPawn
{ V( 0), V( 0), V( 150), V(30), V( 4) }, { V( 0), V( 0), V( 148), V(27), V( 2) },
{ V( 0), V( 0), V( 160), V(22), V( 5) }, { V( 0), V( 0), V( 161), V(16), V( 1) },
{ V( 0), V( 0), V( 166), V(24), V(13) } }, { V( 0), V( 0), V( 171), V(22), V(15) } },
{ { V( 0), V(-283), V(-281), V(57), V(31) }, { { V(22), V( 45), V( 104), V(62), V( 6) }, // Unblocked
{ V( 0), V( 58), V( 141), V(39), V(18) }, { V(31), V( 30), V( 99), V(39), V(19) },
{ V( 0), V( 65), V( 142), V(48), V(32) }, { V(23), V( 29), V( 96), V(41), V(15) },
{ V( 0), V( 60), V( 126), V(51), V(19) } } }; { V(21), V( 23), V( 116), V(41), V(15) } }
};
// Max bonus for king safety. Corresponds to start position with all the pawns // Max bonus for king safety. Corresponds to start position with all the pawns
// in front of the king and no enemy pawn on the horizon. // in front of the king and no enemy pawn on the horizon.
@@ -97,30 +88,26 @@ namespace {
template<Color Us> template<Color Us>
Score evaluate(const Position& pos, Pawns::Entry* e) { Score evaluate(const Position& pos, Pawns::Entry* e) {
const Color Them = (Us == WHITE ? BLACK : WHITE); const Color Them = (Us == WHITE ? BLACK : WHITE);
const Square Up = (Us == WHITE ? DELTA_N : DELTA_S); const Direction Up = (Us == WHITE ? NORTH : SOUTH);
const Square Right = (Us == WHITE ? DELTA_NE : DELTA_SW); const Direction Right = (Us == WHITE ? NORTH_EAST : SOUTH_WEST);
const Square Left = (Us == WHITE ? DELTA_NW : DELTA_SE); const Direction Left = (Us == WHITE ? NORTH_WEST : SOUTH_EAST);
const Bitboard CenterBindMask = Bitboard b, neighbours, stoppers, doubled, supported, phalanx;
Us == WHITE ? (FileDBB | FileEBB) & (Rank5BB | Rank6BB | Rank7BB) Bitboard lever, leverPush;
: (FileDBB | FileEBB) & (Rank4BB | Rank3BB | Rank2BB);
Bitboard b, neighbours, doubled, supported, phalanx;
Square s; Square s;
bool passed, isolated, opposed, backward, lever, connected; bool opposed, backward;
Score score = SCORE_ZERO; Score score = SCORE_ZERO;
const Square* pl = pos.squares<PAWN>(Us); const Square* pl = pos.squares<PAWN>(Us);
const Bitboard* pawnAttacksBB = StepAttacksBB[make_piece(Us, PAWN)];
Bitboard ourPawns = pos.pieces(Us , PAWN); Bitboard ourPawns = pos.pieces( Us, PAWN);
Bitboard theirPawns = pos.pieces(Them, PAWN); Bitboard theirPawns = pos.pieces(Them, PAWN);
e->passedPawns[Us] = e->pawnAttacksSpan[Us] = 0; e->passedPawns[Us] = e->pawnAttacksSpan[Us] = e->weakUnopposed[Us] = 0;
e->kingSquares[Us] = SQ_NONE;
e->semiopenFiles[Us] = 0xFF; e->semiopenFiles[Us] = 0xFF;
e->pawnAttacks[Us] = shift_bb<Right>(ourPawns) | shift_bb<Left>(ourPawns); e->kingSquares[Us] = SQ_NONE;
e->pawnsOnSquares[Us][BLACK] = popcount<Max15>(ourPawns & DarkSquares); e->pawnAttacks[Us] = shift<Right>(ourPawns) | shift<Left>(ourPawns);
e->pawnsOnSquares[Us][BLACK] = popcount(ourPawns & DarkSquares);
e->pawnsOnSquares[Us][WHITE] = pos.count<PAWN>(Us) - e->pawnsOnSquares[Us][BLACK]; e->pawnsOnSquares[Us][WHITE] = pos.count<PAWN>(Us) - e->pawnsOnSquares[Us][BLACK];
// Loop through all pawns of the current color and score each pawn // Loop through all pawns of the current color and score each pawn
@@ -130,76 +117,69 @@ namespace {
File f = file_of(s); File f = file_of(s);
e->semiopenFiles[Us] &= ~(1 << f); e->semiopenFiles[Us] &= ~(1 << f);
e->pawnAttacksSpan[Us] |= pawn_attack_span(Us, s); e->pawnAttacksSpan[Us] |= pawn_attack_span(Us, s);
// Flag the pawn // Flag the pawn
neighbours = ourPawns & adjacent_files_bb(f); opposed = theirPawns & forward_file_bb(Us, s);
doubled = ourPawns & forward_bb(Us, s); stoppers = theirPawns & passed_pawn_mask(Us, s);
opposed = theirPawns & forward_bb(Us, s); lever = theirPawns & PawnAttacks[Us][s];
passed = !(theirPawns & passed_pawn_mask(Us, s)); leverPush = theirPawns & PawnAttacks[Us][s + Up];
lever = theirPawns & pawnAttacksBB[s]; doubled = ourPawns & (s - Up);
phalanx = neighbours & rank_bb(s); neighbours = ourPawns & adjacent_files_bb(f);
supported = neighbours & rank_bb(s - Up); phalanx = neighbours & rank_bb(s);
connected = supported | phalanx; supported = neighbours & rank_bb(s - Up);
isolated = !neighbours;
// Test for backward pawn. // A pawn is backward when it is behind all pawns of the same color on the
// If the pawn is passed, isolated, lever or connected it cannot be // adjacent files and cannot be safely advanced.
// backward. If there are friendly pawns behind on adjacent files if (!neighbours || lever || relative_rank(Us, s) >= RANK_5)
// or if it is sufficiently advanced, it cannot be backward either.
if ( (passed | isolated | lever | connected)
|| (ourPawns & pawn_attack_span(Them, s))
|| (relative_rank(Us, s) >= RANK_5))
backward = false; backward = false;
else else
{ {
// We now know there are no friendly pawns beside or behind this // Find the backmost rank with neighbours or stoppers
// pawn on adjacent files. We now check whether the pawn is b = rank_bb(backmost_sq(Us, neighbours | stoppers));
// backward by looking in the forward direction on the adjacent
// files, and picking the closest pawn there.
b = pawn_attack_span(Us, s) & (ourPawns | theirPawns);
b = pawn_attack_span(Us, s) & rank_bb(backmost_sq(Us, b));
// If we have an enemy pawn in the same or next rank, the pawn is // The pawn is backward when it cannot safely progress to that rank:
// backward because it cannot advance without being captured. // either there is a stopper in the way on this rank, or there is a
backward = (b | shift_bb<Up>(b)) & theirPawns; // stopper on adjacent file which controls the way to that rank.
backward = (b | shift<Up>(b & adjacent_files_bb(f))) & stoppers;
assert(!(backward && (forward_ranks_bb(Them, s + Up) & neighbours)));
} }
assert(opposed | passed | (pawn_attack_span(Us, s) & theirPawns));
// Passed pawns will be properly scored in evaluation because we need // Passed pawns will be properly scored in evaluation because we need
// full attack info to evaluate them. Only the frontmost passed // full attack info to evaluate them. Include also not passed pawns
// pawn on each file is considered a true passed pawn. // which could become passed after one or two pawn pushes when are
if (passed && !doubled) // not attacked more times than defended.
if ( !(stoppers ^ lever ^ leverPush)
&& !(ourPawns & forward_file_bb(Us, s))
&& popcount(supported) >= popcount(lever)
&& popcount(phalanx) >= popcount(leverPush))
e->passedPawns[Us] |= s; e->passedPawns[Us] |= s;
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)]))
e->passedPawns[Us] |= s;
}
// Score this pawn // Score this pawn
if (isolated) if (supported | phalanx)
score -= Isolated[opposed][f]; score += Connected[opposed][bool(phalanx)][popcount(supported)][relative_rank(Us, s)];
else if (!neighbours)
score -= Isolated, e->weakUnopposed[Us] += !opposed;
else if (backward) else if (backward)
score -= Backward[opposed]; score -= Backward, e->weakUnopposed[Us] += !opposed;
else if (!supported) if (doubled && !supported)
score -= Unsupported; score -= Doubled;
if (connected)
score += Connected[opposed][!!phalanx][more_than_one(supported)][relative_rank(Us, s)];
if (doubled)
score -= Doubled[f] / distance<Rank>(s, frontmost_sq(Us, doubled));
if (lever)
score += Lever[relative_rank(Us, s)];
} }
b = e->semiopenFiles[Us] ^ 0xFF;
e->pawnSpan[Us] = b ? int(msb(b) - lsb(b)) : 0;
b = shift_bb<Right>(ourPawns) & shift_bb<Left>(ourPawns) & CenterBindMask;
score += CenterBind * popcount<Max15>(b);
return score; return score;
} }
@@ -211,18 +191,19 @@ namespace Pawns {
/// hard-coded tables, when makes sense, we prefer to calculate them with a formula /// 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. /// to reduce independent parameters and to allow easier tuning and better insight.
void init() void init() {
{
static const int Seed[RANK_NB] = { 0, 6, 15, 10, 57, 75, 135, 258 }; static const int Seed[RANK_NB] = { 0, 13, 24, 18, 76, 100, 175, 330 };
for (int opposed = 0; opposed <= 1; ++opposed) for (int opposed = 0; opposed <= 1; ++opposed)
for (int phalanx = 0; phalanx <= 1; ++phalanx) for (int phalanx = 0; phalanx <= 1; ++phalanx)
for (int apex = 0; apex <= 1; ++apex) for (int support = 0; support <= 2; ++support)
for (Rank r = RANK_2; r < RANK_8; ++r) for (Rank r = RANK_2; r < RANK_8; ++r)
{ {
int v = (Seed[r] + (phalanx ? (Seed[r + 1] - Seed[r]) / 2 : 0)) >> opposed; int v = 17 * support;
v += (apex ? v / 2 : 0); v += (Seed[r] + (phalanx ? (Seed[r + 1] - Seed[r]) / 2 : 0)) >> opposed;
Connected[opposed][phalanx][apex][r] = make_score(3 * v / 2, v);
Connected[opposed][phalanx][support][r] = make_score(v, v * (r - 2) / 4);
} }
} }
@@ -242,41 +223,43 @@ Entry* probe(const Position& pos) {
e->key = key; e->key = key;
e->score = evaluate<WHITE>(pos, e) - evaluate<BLACK>(pos, e); e->score = evaluate<WHITE>(pos, e) - evaluate<BLACK>(pos, e);
e->asymmetry = popcount<Max15>(e->semiopenFiles[WHITE] ^ e->semiopenFiles[BLACK]); e->asymmetry = popcount(e->semiopenFiles[WHITE] ^ e->semiopenFiles[BLACK]);
e->openFiles = popcount(e->semiopenFiles[WHITE] & e->semiopenFiles[BLACK]);
return e; return e;
} }
/// Entry::shelter_storm() calculates shelter and storm penalties for the file /// Entry::shelter_storm() calculates shelter and storm penalties for the file
/// the king is on, as well as the two adjacent files. /// the king is on, as well as the two closest files.
template<Color Us> template<Color Us>
Value Entry::shelter_storm(const Position& pos, Square ksq) { Value Entry::shelter_storm(const Position& pos, Square ksq) {
const Color Them = (Us == WHITE ? BLACK : WHITE); const Color Them = (Us == WHITE ? BLACK : WHITE);
enum { NoFriendlyPawn, Unblocked, BlockedByPawn, BlockedByKing }; enum { BlockedByKing, Unopposed, BlockedByPawn, Unblocked };
Bitboard b = pos.pieces(PAWN) & (in_front_bb(Us, rank_of(ksq)) | rank_bb(ksq)); Bitboard b = pos.pieces(PAWN) & (forward_ranks_bb(Us, ksq) | rank_bb(ksq));
Bitboard ourPawns = b & pos.pieces(Us); Bitboard ourPawns = b & pos.pieces(Us);
Bitboard theirPawns = b & pos.pieces(Them); Bitboard theirPawns = b & pos.pieces(Them);
Value safety = MaxSafetyBonus; Value safety = MaxSafetyBonus;
File center = std::max(FILE_B, std::min(FILE_G, file_of(ksq))); File center = std::max(FILE_B, std::min(FILE_G, file_of(ksq)));
for (File f = center - File(1); f <= center + File(1); ++f) for (File f = File(center - 1); f <= File(center + 1); ++f)
{ {
b = ourPawns & file_bb(f); b = ourPawns & file_bb(f);
Rank rkUs = b ? relative_rank(Us, backmost_sq(Us, b)) : RANK_1; Rank rkUs = b ? relative_rank(Us, backmost_sq(Us, b)) : RANK_1;
b = theirPawns & file_bb(f); b = theirPawns & file_bb(f);
Rank rkThem = b ? relative_rank(Us, frontmost_sq(Them, b)) : RANK_1; Rank rkThem = b ? relative_rank(Us, frontmost_sq(Them, b)) : RANK_1;
safety -= ShelterWeakness[std::min(f, FILE_H - f)][rkUs] int d = std::min(f, ~f);
safety -= ShelterWeakness[f == file_of(ksq)][d][rkUs]
+ StormDanger + StormDanger
[f == file_of(ksq) && rkThem == relative_rank(Us, ksq) + 1 ? BlockedByKing : [f == file_of(ksq) && rkThem == relative_rank(Us, ksq) + 1 ? BlockedByKing :
rkUs == RANK_1 ? NoFriendlyPawn : rkUs == RANK_1 ? Unopposed :
rkThem == rkUs + 1 ? BlockedByPawn : Unblocked] rkThem == rkUs + 1 ? BlockedByPawn : Unblocked]
[std::min(f, FILE_H - f)][rkThem]; [d][rkThem];
} }
return safety; return safety;
@@ -297,9 +280,6 @@ Score Entry::do_king_safety(const Position& pos, Square ksq) {
if (pawns) if (pawns)
while (!(DistanceRingBB[ksq][minKingPawnDistance++] & pawns)) {} while (!(DistanceRingBB[ksq][minKingPawnDistance++] & pawns)) {}
if (relative_rank(Us, ksq) > RANK_4)
return make_score(0, -16 * minKingPawnDistance);
Value bonus = shelter_storm<Us>(pos, ksq); Value bonus = shelter_storm<Us>(pos, ksq);
// If we can castle use the bonus after the castling if it is bigger // If we can castle use the bonus after the castling if it is bigger
+7 -5
View File
@@ -2,7 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -37,8 +37,9 @@ struct Entry {
Bitboard pawn_attacks(Color c) const { return pawnAttacks[c]; } Bitboard pawn_attacks(Color c) const { return pawnAttacks[c]; }
Bitboard passed_pawns(Color c) const { return passedPawns[c]; } Bitboard passed_pawns(Color c) const { return passedPawns[c]; }
Bitboard pawn_attacks_span(Color c) const { return pawnAttacksSpan[c]; } Bitboard pawn_attacks_span(Color c) const { return pawnAttacksSpan[c]; }
int pawn_span(Color c) const { return pawnSpan[c]; } int weak_unopposed(Color c) const { return weakUnopposed[c]; }
int pawn_asymmetry() const { return asymmetry; } int pawn_asymmetry() const { return asymmetry; }
int open_files() const { return openFiles; }
int semiopen_file(Color c, File f) const { int semiopen_file(Color c, File f) const {
return semiopenFiles[c] & (1 << f); return semiopenFiles[c] & (1 << f);
@@ -49,11 +50,11 @@ struct Entry {
} }
int pawns_on_same_color_squares(Color c, Square s) const { int pawns_on_same_color_squares(Color c, Square s) const {
return pawnsOnSquares[c][!!(DarkSquares & s)]; return pawnsOnSquares[c][bool(DarkSquares & s)];
} }
template<Color Us> template<Color Us>
Score king_safety(const Position& pos, Square ksq) { Score king_safety(const Position& pos, Square ksq) {
return kingSquares[Us] == ksq && castlingRights[Us] == pos.can_castle(Us) return kingSquares[Us] == ksq && castlingRights[Us] == pos.can_castle(Us)
? kingSafety[Us] : (kingSafety[Us] = do_king_safety<Us>(pos, ksq)); ? kingSafety[Us] : (kingSafety[Us] = do_king_safety<Us>(pos, ksq));
} }
@@ -71,11 +72,12 @@ struct Entry {
Bitboard pawnAttacksSpan[COLOR_NB]; Bitboard pawnAttacksSpan[COLOR_NB];
Square kingSquares[COLOR_NB]; Square kingSquares[COLOR_NB];
Score kingSafety[COLOR_NB]; Score kingSafety[COLOR_NB];
int weakUnopposed[COLOR_NB];
int castlingRights[COLOR_NB]; int castlingRights[COLOR_NB];
int semiopenFiles[COLOR_NB]; int semiopenFiles[COLOR_NB];
int pawnSpan[COLOR_NB];
int pawnsOnSquares[COLOR_NB][COLOR_NB]; // [color][light/dark squares] int pawnsOnSquares[COLOR_NB][COLOR_NB]; // [color][light/dark squares]
int asymmetry; int asymmetry;
int openFiles;
}; };
typedef HashTable<Entry, 16384> Table; typedef HashTable<Entry, 16384> Table;
+343 -327
View File
File diff suppressed because it is too large Load Diff
+92 -102
View File
@@ -2,7 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -22,35 +22,13 @@
#define POSITION_H_INCLUDED #define POSITION_H_INCLUDED
#include <cassert> #include <cassert>
#include <cstddef> // For offsetof() #include <deque>
#include <memory> // For std::unique_ptr
#include <string> #include <string>
#include "bitboard.h" #include "bitboard.h"
#include "types.h" #include "types.h"
class Position;
class Thread;
namespace PSQT {
extern Score psq[COLOR_NB][PIECE_TYPE_NB][SQUARE_NB];
void init();
}
/// CheckInfo struct is initialized at constructor time and keeps info used to
/// detect if a move gives check.
struct CheckInfo {
explicit CheckInfo(const Position&);
Bitboard dcCandidates;
Bitboard pinned;
Bitboard checkSquares[PIECE_TYPE_NB];
Square ksq;
};
/// StateInfo struct stores information needed to restore a Position object to /// StateInfo struct stores information needed to restore a Position object to
/// its previous state when we retract a move. Whenever a move is made on the /// its previous state when we retract a move. Whenever a move is made on the
@@ -68,32 +46,40 @@ struct StateInfo {
Score psq; Score psq;
Square epSquare; Square epSquare;
// Not copied when making a move // Not copied when making a move (will be recomputed anyhow)
Key key; Key key;
Bitboard checkersBB; Bitboard checkersBB;
PieceType capturedType; Piece capturedPiece;
StateInfo* previous; StateInfo* previous;
Bitboard blockersForKing[COLOR_NB];
Bitboard pinnersForKing[COLOR_NB];
Bitboard checkSquares[PIECE_TYPE_NB];
}; };
/// A list to keep track of the position states along the setup moves (from the
/// start position to the position just before the search starts). Needed by
/// 'draw by repetition' detection. Use a std::deque because pointers to
/// elements are not invalidated upon list resizing.
typedef std::unique_ptr<std::deque<StateInfo>> StateListPtr;
/// Position class stores information regarding the board representation as /// Position class stores information regarding the board representation as
/// pieces, side to move, hash keys, castling info, etc. Important methods are /// pieces, side to move, hash keys, castling info, etc. Important methods are
/// do_move() and undo_move(), used by the search to update node info when /// do_move() and undo_move(), used by the search to update node info when
/// traversing the search tree. /// traversing the search tree.
class Thread;
class Position { class Position {
public: public:
static void init(); static void init();
Position() = default; // To define the global object RootPos Position() = default;
Position(const Position&) = delete; Position(const Position&) = delete;
Position(const Position& pos, Thread* th) { *this = pos; thisThread = th; } Position& operator=(const Position&) = delete;
Position(const std::string& f, bool c960, Thread* th) { set(f, c960, th); }
Position& operator=(const Position&); // To assign RootPos from UCI
// FEN string input/output // FEN string input/output
void set(const std::string& fenStr, bool isChess960, Thread* th); Position& set(const std::string& fenStr, bool isChess960, StateInfo* si, Thread* th);
Position& set(const std::string& code, Color c, StateInfo* si);
const std::string fen() const; const std::string fen() const;
// Position representation // Position representation
@@ -107,6 +93,7 @@ public:
Square ep_square() const; Square ep_square() const;
bool empty(Square s) const; bool empty(Square s) const;
template<PieceType Pt> int count(Color c) const; template<PieceType Pt> int count(Color c) const;
template<PieceType Pt> int count() const;
template<PieceType Pt> const Square* squares(Color c) const; template<PieceType Pt> const Square* squares(Color c) const;
template<PieceType Pt> Square square(Color c) const; template<PieceType Pt> Square square(Color c) const;
@@ -120,73 +107,71 @@ public:
Bitboard checkers() const; Bitboard checkers() const;
Bitboard discovered_check_candidates() const; Bitboard discovered_check_candidates() const;
Bitboard pinned_pieces(Color c) const; Bitboard pinned_pieces(Color c) const;
Bitboard check_squares(PieceType pt) const;
// Attacks to/from a given square // Attacks to/from a given square
Bitboard attackers_to(Square s) const; Bitboard attackers_to(Square s) const;
Bitboard attackers_to(Square s, Bitboard occupied) const; Bitboard attackers_to(Square s, Bitboard occupied) const;
Bitboard attacks_from(Piece pc, Square s) const; Bitboard attacks_from(PieceType pt, Square s) const;
template<PieceType> Bitboard attacks_from(Square s) const; template<PieceType> Bitboard attacks_from(Square s) const;
template<PieceType> Bitboard attacks_from(Square s, Color c) const; template<PieceType> Bitboard attacks_from(Square s, Color c) const;
Bitboard slider_blockers(Bitboard sliders, Square s, Bitboard& pinners) const;
// Properties of moves // Properties of moves
bool legal(Move m, Bitboard pinned) const; bool legal(Move m) const;
bool pseudo_legal(const Move m) const; bool pseudo_legal(const Move m) const;
bool capture(Move m) const; bool capture(Move m) const;
bool capture_or_promotion(Move m) const; bool capture_or_promotion(Move m) const;
bool gives_check(Move m, const CheckInfo& ci) const; bool gives_check(Move m) const;
bool advanced_pawn_push(Move m) const; bool advanced_pawn_push(Move m) const;
Piece moved_piece(Move m) const; Piece moved_piece(Move m) const;
PieceType captured_piece_type() const; Piece captured_piece() const;
// Piece specific // Piece specific
bool pawn_passed(Color c, Square s) const; bool pawn_passed(Color c, Square s) const;
bool opposite_bishops() const; bool opposite_bishops() const;
// Doing and undoing moves // Doing and undoing moves
void do_move(Move m, StateInfo& st, bool givesCheck); void do_move(Move m, StateInfo& newSt);
void do_move(Move m, StateInfo& newSt, bool givesCheck);
void undo_move(Move m); void undo_move(Move m);
void do_null_move(StateInfo& st); void do_null_move(StateInfo& newSt);
void undo_null_move(); void undo_null_move();
// Static exchange evaluation // Static Exchange Evaluation
Value see(Move m) const; bool see_ge(Move m, Value threshold = VALUE_ZERO) const;
Value see_sign(Move m) const;
// Accessing hash keys // Accessing hash keys
Key key() const; Key key() const;
Key key_after(Move m) const; Key key_after(Move m) const;
Key exclusion_key() const;
Key material_key() const; Key material_key() const;
Key pawn_key() const; Key pawn_key() const;
// Other properties of the position // Other properties of the position
Color side_to_move() const; Color side_to_move() const;
Phase game_phase() const;
int game_ply() const; int game_ply() const;
bool is_chess960() const; bool is_chess960() const;
Thread* this_thread() const; Thread* this_thread() const;
uint64_t nodes_searched() const; bool is_draw(int ply) const;
void set_nodes_searched(uint64_t n);
bool is_draw() const;
int rule50_count() const; int rule50_count() const;
Score psq_score() const; Score psq_score() const;
Value non_pawn_material(Color c) const; Value non_pawn_material(Color c) const;
Value non_pawn_material() const;
// Position consistency check, for debugging // Position consistency check, for debugging
bool pos_is_ok(int* failedStep = nullptr) const; bool pos_is_ok() const;
void flip(); void flip();
private: private:
// Initialization helpers (used while setting up a position) // Initialization helpers (used while setting up a position)
void clear();
void set_castling_right(Color c, Square rfrom); void set_castling_right(Color c, Square rfrom);
void set_state(StateInfo* si) const; void set_state(StateInfo* si) const;
void set_check_info(StateInfo* si) const;
// Other helpers // Other helpers
Bitboard check_blockers(Color c, Color kingColor) const; void put_piece(Piece pc, Square s);
void put_piece(Color c, PieceType pt, Square s); void remove_piece(Piece pc, Square s);
void remove_piece(Color c, PieceType pt, Square s); void move_piece(Piece pc, Square from, Square to);
void move_piece(Color c, PieceType pt, Square from, Square to);
template<bool Do> template<bool Do>
void do_castling(Color us, Square from, Square& to, Square& rfrom, Square& rto); void do_castling(Color us, Square from, Square& to, Square& rfrom, Square& rto);
@@ -194,14 +179,12 @@ private:
Piece board[SQUARE_NB]; Piece board[SQUARE_NB];
Bitboard byTypeBB[PIECE_TYPE_NB]; Bitboard byTypeBB[PIECE_TYPE_NB];
Bitboard byColorBB[COLOR_NB]; Bitboard byColorBB[COLOR_NB];
int pieceCount[COLOR_NB][PIECE_TYPE_NB]; int pieceCount[PIECE_NB];
Square pieceList[COLOR_NB][PIECE_TYPE_NB][16]; Square pieceList[PIECE_NB][16];
int index[SQUARE_NB]; int index[SQUARE_NB];
int castlingRightsMask[SQUARE_NB]; int castlingRightsMask[SQUARE_NB];
Square castlingRookSquare[CASTLING_RIGHT_NB]; Square castlingRookSquare[CASTLING_RIGHT_NB];
Bitboard castlingPath[CASTLING_RIGHT_NB]; Bitboard castlingPath[CASTLING_RIGHT_NB];
StateInfo startState;
uint64_t nodes;
int gamePly; int gamePly;
Color sideToMove; Color sideToMove;
Thread* thisThread; Thread* thisThread;
@@ -252,16 +235,20 @@ inline Bitboard Position::pieces(Color c, PieceType pt1, PieceType pt2) const {
} }
template<PieceType Pt> inline int Position::count(Color c) const { template<PieceType Pt> inline int Position::count(Color c) const {
return pieceCount[c][Pt]; return pieceCount[make_piece(c, Pt)];
}
template<PieceType Pt> inline int Position::count() const {
return pieceCount[make_piece(WHITE, Pt)] + pieceCount[make_piece(BLACK, Pt)];
} }
template<PieceType Pt> inline const Square* Position::squares(Color c) const { template<PieceType Pt> inline const Square* Position::squares(Color c) const {
return pieceList[c][Pt]; return pieceList[make_piece(c, Pt)];
} }
template<PieceType Pt> inline Square Position::square(Color c) const { template<PieceType Pt> inline Square Position::square(Color c) const {
assert(pieceCount[c][Pt] == 1); assert(pieceCount[make_piece(c, Pt)] == 1);
return pieceList[c][Pt][0]; return pieceList[make_piece(c, Pt)][0];
} }
inline Square Position::ep_square() const { inline Square Position::ep_square() const {
@@ -286,18 +273,19 @@ inline Square Position::castling_rook_square(CastlingRight cr) const {
template<PieceType Pt> template<PieceType Pt>
inline Bitboard Position::attacks_from(Square s) const { inline Bitboard Position::attacks_from(Square s) const {
assert(Pt != PAWN);
return Pt == BISHOP || Pt == ROOK ? attacks_bb<Pt>(s, byTypeBB[ALL_PIECES]) return Pt == BISHOP || Pt == ROOK ? attacks_bb<Pt>(s, byTypeBB[ALL_PIECES])
: Pt == QUEEN ? attacks_from<ROOK>(s) | attacks_from<BISHOP>(s) : Pt == QUEEN ? attacks_from<ROOK>(s) | attacks_from<BISHOP>(s)
: StepAttacksBB[Pt][s]; : PseudoAttacks[Pt][s];
} }
template<> template<>
inline Bitboard Position::attacks_from<PAWN>(Square s, Color c) const { inline Bitboard Position::attacks_from<PAWN>(Square s, Color c) const {
return StepAttacksBB[make_piece(c, PAWN)][s]; return PawnAttacks[c][s];
} }
inline Bitboard Position::attacks_from(Piece pc, Square s) const { inline Bitboard Position::attacks_from(PieceType pt, Square s) const {
return attacks_bb(pc, s, byTypeBB[ALL_PIECES]); return attacks_bb(pt, s, byTypeBB[ALL_PIECES]);
} }
inline Bitboard Position::attackers_to(Square s) const { inline Bitboard Position::attackers_to(Square s) const {
@@ -309,11 +297,15 @@ inline Bitboard Position::checkers() const {
} }
inline Bitboard Position::discovered_check_candidates() const { inline Bitboard Position::discovered_check_candidates() const {
return check_blockers(sideToMove, ~sideToMove); return st->blockersForKing[~sideToMove] & pieces(sideToMove);
} }
inline Bitboard Position::pinned_pieces(Color c) const { inline Bitboard Position::pinned_pieces(Color c) const {
return check_blockers(c, c); return st->blockersForKing[c] & pieces(c);
}
inline Bitboard Position::check_squares(PieceType pt) const {
return st->checkSquares[pt];
} }
inline bool Position::pawn_passed(Color c, Square s) const { inline bool Position::pawn_passed(Color c, Square s) const {
@@ -345,6 +337,10 @@ inline Value Position::non_pawn_material(Color c) const {
return st->nonPawnMaterial[c]; return st->nonPawnMaterial[c];
} }
inline Value Position::non_pawn_material() const {
return st->nonPawnMaterial[WHITE] + st->nonPawnMaterial[BLACK];
}
inline int Position::game_ply() const { inline int Position::game_ply() const {
return gamePly; return gamePly;
} }
@@ -353,17 +349,9 @@ inline int Position::rule50_count() const {
return st->rule50; return st->rule50;
} }
inline uint64_t Position::nodes_searched() const {
return nodes;
}
inline void Position::set_nodes_searched(uint64_t n) {
nodes = n;
}
inline bool Position::opposite_bishops() const { inline bool Position::opposite_bishops() const {
return pieceCount[WHITE][BISHOP] == 1 return pieceCount[W_BISHOP] == 1
&& pieceCount[BLACK][BISHOP] == 1 && pieceCount[B_BISHOP] == 1
&& opposite_colors(square<BISHOP>(WHITE), square<BISHOP>(BLACK)); && opposite_colors(square<BISHOP>(WHITE), square<BISHOP>(BLACK));
} }
@@ -372,66 +360,68 @@ inline bool Position::is_chess960() const {
} }
inline bool Position::capture_or_promotion(Move m) const { inline bool Position::capture_or_promotion(Move m) const {
assert(is_ok(m)); assert(is_ok(m));
return type_of(m) != NORMAL ? type_of(m) != CASTLING : !empty(to_sq(m)); return type_of(m) != NORMAL ? type_of(m) != CASTLING : !empty(to_sq(m));
} }
inline bool Position::capture(Move m) const { inline bool Position::capture(Move m) const {
// Castling is encoded as "king captures the rook"
assert(is_ok(m)); assert(is_ok(m));
// Castling is encoded as "king captures rook"
return (!empty(to_sq(m)) && type_of(m) != CASTLING) || type_of(m) == ENPASSANT; return (!empty(to_sq(m)) && type_of(m) != CASTLING) || type_of(m) == ENPASSANT;
} }
inline PieceType Position::captured_piece_type() const { inline Piece Position::captured_piece() const {
return st->capturedType; return st->capturedPiece;
} }
inline Thread* Position::this_thread() const { inline Thread* Position::this_thread() const {
return thisThread; return thisThread;
} }
inline void Position::put_piece(Color c, PieceType pt, Square s) { inline void Position::put_piece(Piece pc, Square s) {
board[s] = make_piece(c, pt); board[s] = pc;
byTypeBB[ALL_PIECES] |= s; byTypeBB[ALL_PIECES] |= s;
byTypeBB[pt] |= s; byTypeBB[type_of(pc)] |= s;
byColorBB[c] |= s; byColorBB[color_of(pc)] |= s;
index[s] = pieceCount[c][pt]++; index[s] = pieceCount[pc]++;
pieceList[c][pt][index[s]] = s; pieceList[pc][index[s]] = s;
pieceCount[c][ALL_PIECES]++; pieceCount[make_piece(color_of(pc), ALL_PIECES)]++;
} }
inline void Position::remove_piece(Color c, PieceType pt, Square s) { inline void Position::remove_piece(Piece pc, Square s) {
// WARNING: This is not a reversible operation. If we remove a piece in // WARNING: This is not a reversible operation. If we remove a piece in
// do_move() and then replace it in undo_move() we will put it at the end of // do_move() and then replace it in undo_move() we will put it at the end of
// the list and not in its original place, it means index[] and pieceList[] // the list and not in its original place, it means index[] and pieceList[]
// are not guaranteed to be invariant to a do_move() + undo_move() sequence. // are not invariant to a do_move() + undo_move() sequence.
byTypeBB[ALL_PIECES] ^= s; byTypeBB[ALL_PIECES] ^= s;
byTypeBB[pt] ^= s; byTypeBB[type_of(pc)] ^= s;
byColorBB[c] ^= s; byColorBB[color_of(pc)] ^= s;
/* board[s] = NO_PIECE; Not needed, overwritten by the capturing one */ /* board[s] = NO_PIECE; Not needed, overwritten by the capturing one */
Square lastSquare = pieceList[c][pt][--pieceCount[c][pt]]; Square lastSquare = pieceList[pc][--pieceCount[pc]];
index[lastSquare] = index[s]; index[lastSquare] = index[s];
pieceList[c][pt][index[lastSquare]] = lastSquare; pieceList[pc][index[lastSquare]] = lastSquare;
pieceList[c][pt][pieceCount[c][pt]] = SQ_NONE; pieceList[pc][pieceCount[pc]] = SQ_NONE;
pieceCount[c][ALL_PIECES]--; pieceCount[make_piece(color_of(pc), ALL_PIECES)]--;
} }
inline void Position::move_piece(Color c, PieceType pt, Square from, Square to) { inline void Position::move_piece(Piece pc, Square from, Square to) {
// index[from] is not updated and becomes stale. This works as long as index[] // index[from] is not updated and becomes stale. This works as long as index[]
// is accessed just by known occupied squares. // is accessed just by known occupied squares.
Bitboard from_to_bb = SquareBB[from] ^ SquareBB[to]; Bitboard from_to_bb = SquareBB[from] ^ SquareBB[to];
byTypeBB[ALL_PIECES] ^= from_to_bb; byTypeBB[ALL_PIECES] ^= from_to_bb;
byTypeBB[pt] ^= from_to_bb; byTypeBB[type_of(pc)] ^= from_to_bb;
byColorBB[c] ^= from_to_bb; byColorBB[color_of(pc)] ^= from_to_bb;
board[from] = NO_PIECE; board[from] = NO_PIECE;
board[to] = make_piece(c, pt); board[to] = pc;
index[to] = index[from]; index[to] = index[from];
pieceList[c][pt][index[to]] = to; pieceList[pc][index[to]] = to;
}
inline void Position::do_move(Move m, StateInfo& newSt) {
do_move(m, newSt, gives_check(m));
} }
#endif // #ifndef POSITION_H_INCLUDED #endif // #ifndef POSITION_H_INCLUDED
+55 -48
View File
@@ -2,7 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -18,8 +18,15 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <algorithm>
#include "types.h" #include "types.h"
Value PieceValue[PHASE_NB][PIECE_NB] = {
{ VALUE_ZERO, PawnValueMg, KnightValueMg, BishopValueMg, RookValueMg, QueenValueMg },
{ VALUE_ZERO, PawnValueEg, KnightValueEg, BishopValueEg, RookValueEg, QueenValueEg }
};
namespace PSQT { namespace PSQT {
#define S(mg, eg) make_score(mg, eg) #define S(mg, eg) make_score(mg, eg)
@@ -32,33 +39,32 @@ const Score Bonus[][RANK_NB][int(FILE_NB) / 2] = {
{ }, { },
{ // Pawn { // Pawn
{ S( 0, 0), S( 0, 0), S( 0, 0), S( 0, 0) }, { S( 0, 0), S( 0, 0), S( 0, 0), S( 0, 0) },
{ S(-19, 5), S( 1,-4), S( 7, 8), S( 3,-2) }, { S(-11, 7), S( 6,-4), S( 7, 8), S( 3,-2) },
{ S(-26,-6), S( -7,-5), S( 19, 5), S(24, 4) }, { S(-18,-4), S( -2,-5), S( 19, 5), S(24, 4) },
{ S(-25, 1), S(-14, 3), S( 16,-8), S(31,-3) }, { S(-17, 3), S( -9, 3), S( 20,-8), S(35,-3) },
{ S(-14, 6), S( 0, 9), S( -1, 7), S(17,-6) }, { S( -6, 8), S( 5, 9), S( 3, 7), S(21,-6) },
{ S(-14, 6), S(-13,-5), S(-10, 2), S(-6, 4) }, { S( -6, 8), S( -8,-5), S( -6, 2), S(-2, 4) },
{ S(-12, 1), S( 15,-9), S( -8, 1), S(-4,18) }, { S( -4, 3), S( 20,-9), S( -8, 1), S(-4,18) }
{ S( 0, 0), S( 0, 0), S( 0, 0), S( 0, 0) }
}, },
{ // Knight { // Knight
{ S(-143, -97), S(-96,-82), S(-80,-46), S(-73,-14) }, { S(-161,-105), S(-96,-82), S(-80,-46), S(-73,-14) },
{ S( -83, -69), S(-43,-55), S(-21,-17), S(-10, 9) }, { S( -83, -69), S(-43,-54), S(-21,-17), S(-10, 9) },
{ S( -71, -50), S(-22,-39), S( 0, -8), S( 9, 28) }, { S( -71, -50), S(-22,-39), S( 0, -7), S( 9, 28) },
{ S( -25, -41), S( 18,-25), S( 43, 7), S( 47, 38) }, { S( -25, -41), S( 18,-25), S( 43, 6), S( 47, 38) },
{ S( -26, -46), S( 16,-25), S( 38, 2), S( 50, 41) }, { S( -26, -46), S( 16,-25), S( 38, 3), S( 50, 40) },
{ S( -11, -55), S( 37,-38), S( 56, -8), S( 71, 27) }, { S( -11, -54), S( 37,-38), S( 56, -7), S( 65, 27) },
{ S( -62, -64), S(-17,-50), S( 5,-24), S( 14, 13) }, { S( -63, -65), S(-19,-50), S( 5,-24), S( 14, 13) },
{ S(-195,-110), S(-66,-90), S(-42,-50), S(-29,-13) } { S(-195,-109), S(-67,-89), S(-42,-50), S(-29,-13) }
}, },
{ // Bishop { // Bishop
{ S(-54,-68), S(-23,-40), S(-35,-46), S(-44,-28) }, { S(-44,-58), S(-13,-31), S(-25,-37), S(-34,-19) },
{ S(-30,-43), S( 10,-17), S( 2,-23), S( -9, -5) }, { S(-20,-34), S( 20, -9), S( 12,-14), S( 1, 4) },
{ S(-19,-32), S( 17, -9), S( 11,-13), S( 1, 8) }, { S( -9,-23), S( 27, 0), S( 21, -3), S( 11, 16) },
{ S(-21,-36), S( 18,-13), S( 11,-15), S( 0, 7) }, { S(-11,-26), S( 28, -3), S( 21, -5), S( 10, 16) },
{ S(-21,-36), S( 14,-14), S( 6,-17), S( -1, 3) }, { S(-11,-26), S( 27, -4), S( 16, -7), S( 9, 14) },
{ S(-27,-35), S( 6,-13), S( 2,-10), S( -8, 1) }, { S(-17,-24), S( 16, -2), S( 12, 0), S( 2, 13) },
{ S(-33,-44), S( 7,-21), S( -4,-22), S(-12, -4) }, { S(-23,-34), S( 17,-10), S( 6,-12), S( -2, 6) },
{ S(-45,-65), S(-21,-42), S(-29,-46), S(-39,-27) } { S(-35,-55), S(-11,-32), S(-19,-36), S(-29,-17) }
}, },
{ // Rook { // Rook
{ S(-25, 0), S(-16, 0), S(-16, 0), S(-9, 0) }, { S(-25, 0), S(-16, 0), S(-16, 0), S(-9, 0) },
@@ -71,47 +77,48 @@ const Score Bonus[][RANK_NB][int(FILE_NB) / 2] = {
{ S(-23, 0), S(-15, 0), S(-11, 0), S(-5, 0) } { S(-23, 0), S(-15, 0), S(-11, 0), S(-5, 0) }
}, },
{ // Queen { // Queen
{ S( 0,-70), S(-3,-57), S(-4,-41), S(-1,-29) }, { S( 0,-71), S(-4,-56), S(-3,-42), S(-1,-29) },
{ S(-4,-58), S( 6,-30), S( 9,-21), S( 8, -4) }, { S(-4,-56), S( 6,-30), S( 9,-21), S( 8, -5) },
{ S(-2,-39), S( 6,-17), S( 9, -7), S( 9, 5) }, { S(-2,-39), S( 6,-17), S( 9, -8), S( 9, 5) },
{ S(-1,-29), S( 8, -5), S(10, 9), S( 7, 17) }, { S(-1,-29), S( 8, -5), S(10, 9), S( 7, 19) },
{ S(-3,-27), S( 9, -5), S( 8, 10), S( 7, 23) }, { S(-3,-27), S( 9, -5), S( 8, 10), S( 7, 21) },
{ S(-2,-40), S( 6,-16), S( 8,-11), S(10, 3) }, { S(-2,-40), S( 6,-16), S( 8,-10), S(10, 3) },
{ S(-2,-54), S( 7,-30), S( 7,-21), S( 6, -7) }, { S(-2,-55), S( 7,-30), S( 7,-21), S( 6, -6) },
{ S(-1,-75), S(-4,-54), S(-1,-44), S( 0,-30) } { S(-1,-74), S(-4,-55), S(-1,-43), S( 0,-30) }
}, },
{ // King { // King
{ S(291, 28), S(344, 76), S(294,103), S(219,112) }, { S(267, 0), S(320, 48), S(270, 75), S(195, 84) },
{ S(289, 70), S(329,119), S(263,170), S(205,159) }, { S(264, 43), S(304, 92), S(238,143), S(180,132) },
{ S(226,109), S(271,164), S(202,195), S(136,191) }, { S(200, 83), S(245,138), S(176,167), S(110,165) },
{ S(204,131), S(212,194), S(175,194), S(137,204) }, { S(177,106), S(185,169), S(148,169), S(110,179) },
{ S(177,132), S(205,187), S(143,224), S( 94,227) }, { S(149,108), S(177,163), S(115,200), S( 66,203) },
{ S(147,118), S(188,178), S(113,199), S( 70,197) }, { S(118, 95), S(159,155), S( 84,176), S( 41,174) },
{ S(116, 72), S(158,121), S( 93,142), S( 48,161) }, { S( 87, 50), S(128, 99), S( 63,122), S( 20,139) },
{ S( 94, 30), S(120, 76), S( 78,101), S( 31,111) } { S( 63, 9), S( 88, 55), S( 47, 80), S( 0, 90) }
} }
}; };
#undef S #undef S
Score psq[COLOR_NB][PIECE_TYPE_NB][SQUARE_NB]; Score psq[PIECE_NB][SQUARE_NB];
// init() initializes piece square tables: the white halves of the tables are // init() initializes piece-square tables: the white halves of the tables are
// copied from Bonus[] adding the piece value, then the black halves of the // copied from Bonus[] adding the piece value, then the black halves of the
// tables are initialized by flipping and changing the sign of the white scores. // tables are initialized by flipping and changing the sign of the white scores.
void init() { void init() {
for (PieceType pt = PAWN; pt <= KING; ++pt) for (Piece pc = W_PAWN; pc <= W_KING; ++pc)
{ {
PieceValue[MG][make_piece(BLACK, pt)] = PieceValue[MG][pt]; PieceValue[MG][~pc] = PieceValue[MG][pc];
PieceValue[EG][make_piece(BLACK, pt)] = PieceValue[EG][pt]; PieceValue[EG][~pc] = PieceValue[EG][pc];
Score v = make_score(PieceValue[MG][pt], PieceValue[EG][pt]); Score v = make_score(PieceValue[MG][pc], PieceValue[EG][pc]);
for (Square s = SQ_A1; s <= SQ_H8; ++s) for (Square s = SQ_A1; s <= SQ_H8; ++s)
{ {
int edgeDistance = file_of(s) < FILE_E ? file_of(s) : FILE_H - file_of(s); File f = std::min(file_of(s), ~file_of(s));
psq[BLACK][pt][~s] = -(psq[WHITE][pt][s] = v + Bonus[pt][rank_of(s)][edgeDistance]); psq[ pc][ s] = v + Bonus[pc][rank_of(s)][f];
psq[~pc][~s] = -psq[pc][s];
} }
} }
} }
+630 -597
View File
File diff suppressed because it is too large Load Diff
+25 -29
View File
@@ -2,7 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -21,32 +21,37 @@
#ifndef SEARCH_H_INCLUDED #ifndef SEARCH_H_INCLUDED
#define SEARCH_H_INCLUDED #define SEARCH_H_INCLUDED
#include <atomic>
#include <memory> // For std::unique_ptr
#include <stack>
#include <vector> #include <vector>
#include "misc.h" #include "misc.h"
#include "position.h" #include "movepick.h"
#include "types.h" #include "types.h"
class Position;
namespace Search { namespace Search {
/// Threshold used for countermoves based pruning
const int CounterMovePruneThreshold = 0;
/// Stack struct keeps track of the information we need to remember from nodes /// Stack struct keeps track of the information we need to remember from nodes
/// shallower and deeper in the tree during the search. Each search thread has /// shallower and deeper in the tree during the search. Each search thread has
/// its own array of Stack objects, indexed by the current ply. /// its own array of Stack objects, indexed by the current ply.
struct Stack { struct Stack {
Move* pv; Move* pv;
PieceToHistory* contHistory;
int ply; int ply;
Move currentMove; Move currentMove;
Move excludedMove; Move excludedMove;
Move killers[2]; Move killers[2];
Value staticEval; Value staticEval;
bool skipEarlyPruning; int statScore;
int moveCount; int moveCount;
}; };
/// RootMove struct is used for moves at the root of the tree. For each root move /// RootMove struct is used for moves at the root of the tree. For each root move
/// we store a score and a PV (really a refutation in the case of moves which /// we store a score and a PV (really a refutation in the case of moves which
/// fail low). Score is normally set at -VALUE_INFINITE for all non-pv moves. /// fail low). Score is normally set at -VALUE_INFINITE for all non-pv moves.
@@ -54,56 +59,47 @@ struct Stack {
struct RootMove { struct RootMove {
explicit RootMove(Move m) : pv(1, m) {} explicit RootMove(Move m) : pv(1, m) {}
bool operator<(const RootMove& m) const { return m.score < score; } // Descending sort
bool operator==(const Move& m) const { return pv[0] == m; }
void insert_pv_in_tt(Position& pos);
bool extract_ponder_from_tt(Position& pos); bool extract_ponder_from_tt(Position& pos);
bool operator==(const Move& m) const { return pv[0] == m; }
bool operator<(const RootMove& m) const { // Sort in descending order
return m.score != score ? m.score < score
: m.previousScore < previousScore;
}
Value score = -VALUE_INFINITE; Value score = -VALUE_INFINITE;
Value previousScore = -VALUE_INFINITE; Value previousScore = -VALUE_INFINITE;
int selDepth = 0;
std::vector<Move> pv; std::vector<Move> pv;
}; };
typedef std::vector<RootMove> RootMoveVector; typedef std::vector<RootMove> RootMoves;
/// LimitsType struct stores information sent by GUI about available time to /// LimitsType struct stores information sent by GUI about available time to
/// search the current move, maximum depth/time, if we are in analysis mode or /// search the current move, maximum depth/time, or if we are in analysis mode.
/// if we have to ponder while it's our opponent's turn to move.
struct LimitsType { struct LimitsType {
LimitsType() { // Init explicitly due to broken value-initialization of non POD in MSVC LimitsType() { // Init explicitly due to broken value-initialization of non POD in MSVC
nodes = time[WHITE] = time[BLACK] = inc[WHITE] = inc[BLACK] = npmsec = movestogo = nodes = time[WHITE] = time[BLACK] = inc[WHITE] = inc[BLACK] =
depth = movetime = mate = infinite = ponder = 0; npmsec = movestogo = depth = movetime = mate = perft = infinite = 0;
} }
bool use_time_management() const { bool use_time_management() const {
return !(mate | movetime | depth | nodes | infinite); return !(mate | movetime | depth | nodes | perft | infinite);
} }
std::vector<Move> searchmoves; std::vector<Move> searchmoves;
int time[COLOR_NB], inc[COLOR_NB], npmsec, movestogo, depth, movetime, mate, infinite, ponder; int time[COLOR_NB], inc[COLOR_NB], npmsec, movestogo, depth,
movetime, mate, perft, infinite;
int64_t nodes; int64_t nodes;
TimePoint startTime; TimePoint startTime;
}; };
/// The SignalsType struct stores atomic flags updated during the search
/// typically in an async fashion e.g. to stop the search by the GUI.
struct SignalsType {
std::atomic_bool stop, stopOnPonderhit;
};
typedef std::unique_ptr<std::stack<StateInfo>> StateStackPtr;
extern SignalsType Signals;
extern LimitsType Limits; extern LimitsType Limits;
extern StateStackPtr SetupStates;
void init(); void init();
void clear(); void clear();
template<bool Root = true> uint64_t perft(Position& pos, Depth depth);
} // namespace Search } // namespace Search
File diff suppressed because it is too large Load Diff
-169
View File
@@ -1,169 +0,0 @@
/*
Copyright (c) 2011-2013 Ronald de Man
*/
#ifndef TBCORE_H
#define TBCORE_H
#ifndef _WIN32
#include <pthread.h>
#define SEP_CHAR ':'
#define FD int
#define FD_ERR -1
#else
#include <windows.h>
#define SEP_CHAR ';'
#define FD HANDLE
#define FD_ERR INVALID_HANDLE_VALUE
#endif
#ifndef _WIN32
#define LOCK_T pthread_mutex_t
#define LOCK_INIT(x) pthread_mutex_init(&(x), NULL)
#define LOCK(x) pthread_mutex_lock(&(x))
#define UNLOCK(x) pthread_mutex_unlock(&(x))
#else
#define LOCK_T HANDLE
#define LOCK_INIT(x) do { x = CreateMutex(NULL, FALSE, NULL); } while (0)
#define LOCK(x) WaitForSingleObject(x, INFINITE)
#define UNLOCK(x) ReleaseMutex(x)
#endif
#ifndef _MSC_VER
#define BSWAP32(v) __builtin_bswap32(v)
#define BSWAP64(v) __builtin_bswap64(v)
#else
#define BSWAP32(v) _byteswap_ulong(v)
#define BSWAP64(v) _byteswap_uint64(v)
#endif
#define WDLSUFFIX ".rtbw"
#define DTZSUFFIX ".rtbz"
#define WDLDIR "RTBWDIR"
#define DTZDIR "RTBZDIR"
#define TBPIECES 6
typedef unsigned long long uint64;
typedef unsigned int uint32;
typedef unsigned char ubyte;
typedef unsigned short ushort;
const ubyte WDL_MAGIC[4] = { 0x71, 0xe8, 0x23, 0x5d };
const ubyte DTZ_MAGIC[4] = { 0xd7, 0x66, 0x0c, 0xa5 };
#define TBHASHBITS 10
struct TBHashEntry;
typedef uint64 base_t;
struct PairsData {
char *indextable;
ushort *sizetable;
ubyte *data;
ushort *offset;
ubyte *symlen;
ubyte *sympat;
int blocksize;
int idxbits;
int min_len;
base_t base[1]; // C++ complains about base[]...
};
struct TBEntry {
char *data;
uint64 key;
uint64 mapping;
ubyte ready;
ubyte num;
ubyte symmetric;
ubyte has_pawns;
}
#ifndef _WIN32
__attribute__((__may_alias__))
#endif
;
struct TBEntry_piece {
char *data;
uint64 key;
uint64 mapping;
ubyte ready;
ubyte num;
ubyte symmetric;
ubyte has_pawns;
ubyte enc_type;
struct PairsData *precomp[2];
int factor[2][TBPIECES];
ubyte pieces[2][TBPIECES];
ubyte norm[2][TBPIECES];
};
struct TBEntry_pawn {
char *data;
uint64 key;
uint64 mapping;
ubyte ready;
ubyte num;
ubyte symmetric;
ubyte has_pawns;
ubyte pawns[2];
struct {
struct PairsData *precomp[2];
int factor[2][TBPIECES];
ubyte pieces[2][TBPIECES];
ubyte norm[2][TBPIECES];
} file[4];
};
struct DTZEntry_piece {
char *data;
uint64 key;
uint64 mapping;
ubyte ready;
ubyte num;
ubyte symmetric;
ubyte has_pawns;
ubyte enc_type;
struct PairsData *precomp;
int factor[TBPIECES];
ubyte pieces[TBPIECES];
ubyte norm[TBPIECES];
ubyte flags; // accurate, mapped, side
ushort map_idx[4];
ubyte *map;
};
struct DTZEntry_pawn {
char *data;
uint64 key;
uint64 mapping;
ubyte ready;
ubyte num;
ubyte symmetric;
ubyte has_pawns;
ubyte pawns[2];
struct {
struct PairsData *precomp;
int factor[TBPIECES];
ubyte pieces[TBPIECES];
ubyte norm[TBPIECES];
} file[4];
ubyte flags[4];
ushort map_idx[4][4];
ubyte *map;
};
struct TBHashEntry {
uint64 key;
struct TBEntry *ptr;
};
struct DTZTableEntry {
uint64 key1;
uint64 key2;
struct TBEntry *entry;
};
#endif
+1588 -719
View File
File diff suppressed because it is too large Load Diff
+66 -5
View File
@@ -1,17 +1,78 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (c) 2013 Ronald de Man
Copyright (C) 2016-2018 Marco Costalba, Lucas Braesch
Stockfish is free software: you can redistribute it and/or modify
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.
Stockfish is distributed in the hope that it will be useful,
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.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TBPROBE_H #ifndef TBPROBE_H
#define TBPROBE_H #define TBPROBE_H
#include <ostream>
#include "../search.h" #include "../search.h"
namespace Tablebases { namespace Tablebases {
enum WDLScore {
WDLLoss = -2, // Loss
WDLBlessedLoss = -1, // Loss, but draw under 50-move rule
WDLDraw = 0, // Draw
WDLCursedWin = 1, // Win, but draw under 50-move rule
WDLWin = 2, // Win
WDLScoreNone = -1000
};
// Possible states after a probing operation
enum ProbeState {
FAIL = 0, // Probe failed (missing file table)
OK = 1, // Probe succesful
CHANGE_STM = -1, // DTZ should check the other side
ZEROING_BEST_MOVE = 2 // Best move zeroes DTZ (capture or pawn move)
};
extern int MaxCardinality; extern int MaxCardinality;
void init(const std::string& path); void init(const std::string& paths);
int probe_wdl(Position& pos, int *success); WDLScore probe_wdl(Position& pos, ProbeState* result);
int probe_dtz(Position& pos, int *success); int probe_dtz(Position& pos, ProbeState* result);
bool root_probe(Position& pos, Search::RootMoveVector& rootMoves, Value& score); bool root_probe(Position& pos, Search::RootMoves& rootMoves, Value& score);
bool root_probe_wdl(Position& pos, Search::RootMoveVector& rootMoves, Value& score); bool root_probe_wdl(Position& pos, Search::RootMoves& rootMoves, Value& score);
void filter_root_moves(Position& pos, Search::RootMoves& rootMoves);
inline std::ostream& operator<<(std::ostream& os, const WDLScore v) {
os << (v == WDLLoss ? "Loss" :
v == WDLBlessedLoss ? "Blessed loss" :
v == WDLDraw ? "Draw" :
v == WDLCursedWin ? "Cursed win" :
v == WDLWin ? "Win" : "None");
return os;
}
inline std::ostream& operator<<(std::ostream& os, const ProbeState v) {
os << (v == FAIL ? "Failed" :
v == OK ? "Success" :
v == CHANGE_STM ? "Probed opponent side" :
v == ZEROING_BEST_MOVE ? "Best move zeroes DTZ" : "None");
return os;
}
} }
+116 -112
View File
@@ -2,7 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -25,171 +25,175 @@
#include "search.h" #include "search.h"
#include "thread.h" #include "thread.h"
#include "uci.h" #include "uci.h"
#include "syzygy/tbprobe.h"
using namespace Search;
ThreadPool Threads; // Global object ThreadPool Threads; // Global object
/// Thread constructor launch the thread and then wait until it goes to sleep
/// in idle_loop().
Thread::Thread() { /// Thread constructor launches the thread and waits until it goes to sleep
/// in idle_loop(). Note that 'searching' and 'exit' should be alredy set.
resetCalls = exit = false; Thread::Thread(size_t n) : idx(n), stdThread(&Thread::idle_loop, this) {
maxPly = callsCnt = 0;
history.clear();
counterMoves.clear();
idx = Threads.size(); // Start from 0
std::unique_lock<Mutex> lk(mutex); wait_for_search_finished();
searching = true;
nativeThread = std::thread(&Thread::idle_loop, this);
sleepCondition.wait(lk, [&]{ return !searching; });
} }
/// Thread destructor wait for thread termination before returning /// Thread destructor wakes up the thread in idle_loop() and waits
/// for its termination. Thread should be already waiting.
Thread::~Thread() { Thread::~Thread() {
mutex.lock(); assert(!searching);
exit = true; exit = true;
sleepCondition.notify_one(); start_searching();
mutex.unlock(); stdThread.join();
nativeThread.join();
} }
/// Thread::wait_for_search_finished() wait on sleep condition until not searching /// Thread::clear() reset histories, usually before a new game
void Thread::clear() {
counterMoves.fill(MOVE_NONE);
mainHistory.fill(0);
captureHistory.fill(0);
for (auto& to : contHistory)
for (auto& h : to)
h.fill(0);
contHistory[NO_PIECE][0].fill(Search::CounterMovePruneThreshold - 1);
}
/// Thread::start_searching() wakes up the thread that will start the search
void Thread::start_searching() {
std::lock_guard<Mutex> lk(mutex);
searching = true;
cv.notify_one(); // Wake up the thread in idle_loop()
}
/// Thread::wait_for_search_finished() blocks on the condition variable
/// until the thread has finished searching.
void Thread::wait_for_search_finished() { void Thread::wait_for_search_finished() {
std::unique_lock<Mutex> lk(mutex); std::unique_lock<Mutex> lk(mutex);
sleepCondition.wait(lk, [&]{ return !searching; }); cv.wait(lk, [&]{ return !searching; });
} }
/// Thread::wait() wait on sleep condition until condition is true /// Thread::idle_loop() is where the thread is parked, blocked on the
/// condition variable, when it has no work to do.
void Thread::wait(std::atomic_bool& condition) {
std::unique_lock<Mutex> lk(mutex);
sleepCondition.wait(lk, [&]{ return bool(condition); });
}
/// Thread::start_searching() wake up the thread that will start the search
void Thread::start_searching(bool resume) {
std::unique_lock<Mutex> lk(mutex);
if (!resume)
searching = true;
sleepCondition.notify_one();
}
/// Thread::idle_loop() is where the thread is parked when it has no work to do
void Thread::idle_loop() { void Thread::idle_loop() {
while (!exit) // If OS already scheduled us on a different group than 0 then don't overwrite
// the choice, eventually we are one of many one-threaded processes running on
// some Windows NUMA hardware, for instance in fishtest. To make it simple,
// just check if running threads are below a threshold, in this case all this
// NUMA machinery is not needed.
if (Options["Threads"] >= 8)
WinProcGroup::bindThisThread(idx);
while (true)
{ {
std::unique_lock<Mutex> lk(mutex); std::unique_lock<Mutex> lk(mutex);
searching = false; searching = false;
cv.notify_one(); // Wake up anyone waiting for search finished
cv.wait(lk, [&]{ return searching; });
while (!searching && !exit) if (exit)
{ return;
sleepCondition.notify_one(); // Wake up any waiting thread
sleepCondition.wait(lk);
}
lk.unlock(); lk.unlock();
if (!exit) search();
search();
} }
} }
/// ThreadPool::set() creates/destroys threads to match the requested number.
/// Created and launced threads wil go immediately to sleep in idle_loop.
/// Upon resizing, threads are recreated to allow for binding if necessary.
/// ThreadPool::init() create and launch requested threads, that will go void ThreadPool::set(size_t requested) {
/// immediately to sleep. We cannot use a constructor because Threads is a
/// static object and we need a fully initialized engine at this point due to
/// allocation of Endgames in the Thread constructor.
void ThreadPool::init() { if (size() > 0) { // destroy any existing thread(s)
main()->wait_for_search_finished();
push_back(new MainThread); while (size() > 0)
read_uci_options(); delete back(), pop_back();
}
if (requested > 0) { // create new thread(s)
push_back(new MainThread(0));
while (size() < requested)
push_back(new Thread(size()));
clear();
}
} }
/// ThreadPool::clear() sets threadPool data to initial values.
/// ThreadPool::exit() terminate threads before the program exits. Cannot be void ThreadPool::clear() {
/// done in destructor because threads must be terminated before deleting any
/// static objects, so while still in main().
void ThreadPool::exit() {
while (size())
delete back(), pop_back();
}
/// ThreadPool::read_uci_options() updates internal threads parameters from the
/// corresponding UCI options and creates/destroys threads to match requested
/// number. Thread objects are dynamically allocated.
void ThreadPool::read_uci_options() {
size_t requested = Options["Threads"];
assert(requested > 0);
while (size() < requested)
push_back(new Thread);
while (size() > requested)
delete back(), pop_back();
}
/// ThreadPool::nodes_searched() return the number of nodes searched
int64_t ThreadPool::nodes_searched() {
int64_t nodes = 0;
for (Thread* th : *this) for (Thread* th : *this)
nodes += th->rootPos.nodes_searched(); th->clear();
return nodes;
main()->callsCnt = 0;
main()->previousScore = VALUE_INFINITE;
main()->previousTimeReduction = 1;
} }
/// ThreadPool::start_thinking() wakes up main thread waiting in idle_loop() and
/// returns immediately. Main thread will wake up other threads and start the search.
/// ThreadPool::start_thinking() wake up the main thread sleeping in idle_loop() void ThreadPool::start_thinking(Position& pos, StateListPtr& states,
/// and start a new search, then return immediately. const Search::LimitsType& limits, bool ponderMode) {
void ThreadPool::start_thinking(const Position& pos, const LimitsType& limits,
StateStackPtr& states) {
main()->wait_for_search_finished(); main()->wait_for_search_finished();
Signals.stopOnPonderhit = Signals.stop = false; stopOnPonderhit = stop = false;
ponder = ponderMode;
main()->rootMoves.clear(); Search::Limits = limits;
main()->rootPos = pos; Search::RootMoves rootMoves;
Limits = limits;
if (states.get()) // If we don't set a new position, preserve current state
{
SetupStates = std::move(states); // Ownership transfer here
assert(!states.get());
}
for (const auto& m : MoveList<LEGAL>(pos)) for (const auto& m : MoveList<LEGAL>(pos))
if ( limits.searchmoves.empty() if ( limits.searchmoves.empty()
|| std::count(limits.searchmoves.begin(), limits.searchmoves.end(), m)) || std::count(limits.searchmoves.begin(), limits.searchmoves.end(), m))
main()->rootMoves.push_back(RootMove(m)); rootMoves.emplace_back(m);
if (!rootMoves.empty())
Tablebases::filter_root_moves(pos, rootMoves);
// After ownership transfer 'states' becomes empty, so if we stop the search
// and call 'go' again without setting a new position states.get() == NULL.
assert(states.get() || setupStates.get());
if (states.get())
setupStates = std::move(states); // Ownership transfer, states is now empty
// We use Position::set() to set root position across threads. But there are
// some StateInfo fields (previous, pliesFromNull, capturedPiece) that cannot
// be deduced from a fen string, so set() clears them and to not lose the info
// we need to backup and later restore setupStates->back(). Note that setupStates
// is shared by threads but is accessed in read-only mode.
StateInfo tmp = setupStates->back();
for (Thread* th : *this)
{
th->nodes = th->tbHits = th->nmp_ply = th->nmp_odd = 0;
th->rootDepth = th->completedDepth = DEPTH_ZERO;
th->rootMoves = rootMoves;
th->rootPos.set(pos.fen(), pos.is_chess960(), &setupStates->back(), th);
}
setupStates->back() = tmp;
main()->start_searching(); main()->start_searching();
} }
+52 -32
View File
@@ -2,7 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -22,7 +22,6 @@
#define THREAD_H_INCLUDED #define THREAD_H_INCLUDED
#include <atomic> #include <atomic>
#include <bitset>
#include <condition_variable> #include <condition_variable>
#include <mutex> #include <mutex>
#include <thread> #include <thread>
@@ -36,66 +35,87 @@
#include "thread_win32.h" #include "thread_win32.h"
/// Thread struct keeps together all the thread related stuff. We also use /// Thread class keeps together all the thread-related stuff. We use
/// per-thread pawn and material hash tables so that once we get a pointer to an /// per-thread pawn and material hash tables so that once we get a
/// entry its life time is unlimited and we don't have to care about someone /// pointer to an entry its life time is unlimited and we don't have
/// changing the entry under our feet. /// to care about someone changing the entry under our feet.
class Thread { class Thread {
std::thread nativeThread;
Mutex mutex; Mutex mutex;
ConditionVariable sleepCondition; ConditionVariable cv;
bool exit, searching; size_t idx;
bool exit = false, searching = true; // Set before starting std::thread
std::thread stdThread;
public: public:
Thread(); explicit Thread(size_t);
virtual ~Thread(); virtual ~Thread();
virtual void search(); virtual void search();
void clear();
void idle_loop(); void idle_loop();
void start_searching(bool resume = false); void start_searching();
void wait_for_search_finished(); void wait_for_search_finished();
void wait(std::atomic_bool& b);
Pawns::Table pawnsTable; Pawns::Table pawnsTable;
Material::Table materialTable; Material::Table materialTable;
Endgames endgames; Endgames endgames;
size_t idx, PVIdx; size_t PVIdx;
int maxPly, callsCnt; int selDepth, nmp_ply, nmp_odd;
std::atomic<uint64_t> nodes, tbHits;
Position rootPos; Position rootPos;
Search::RootMoveVector rootMoves; Search::RootMoves rootMoves;
Depth rootDepth; Depth rootDepth, completedDepth;
HistoryStats history; CounterMoveHistory counterMoves;
MovesStats counterMoves; ButterflyHistory mainHistory;
Depth completedDepth; CapturePieceToHistory captureHistory;
std::atomic_bool resetCalls; ContinuationHistory contHistory;
}; };
/// MainThread is a derived class with a specific overload for the main thread /// MainThread is a derived class specific for main thread
struct MainThread : public Thread { struct MainThread : public Thread {
virtual void search();
bool easyMovePlayed, failedLow; using Thread::Thread;
double bestMoveChanges;
void search() override;
void check_time();
bool failedLow;
double bestMoveChanges, previousTimeReduction;
Value previousScore;
int callsCnt;
}; };
/// ThreadPool struct handles all the threads related stuff like init, starting, /// ThreadPool struct handles all the threads-related stuff like init, starting,
/// parking and, most importantly, launching a thread. All the access to threads /// parking and, most importantly, launching a thread. All the access to threads
/// data is done through this class. /// is done through this class.
struct ThreadPool : public std::vector<Thread*> { struct ThreadPool : public std::vector<Thread*> {
void init(); // No constructor and destructor, threads rely on globals that should void start_thinking(Position&, StateListPtr&, const Search::LimitsType&, bool = false);
void exit(); // be initialized and valid during the whole thread lifetime. void clear();
void set(size_t);
MainThread* main() { return static_cast<MainThread*>(at(0)); } MainThread* main() const { return static_cast<MainThread*>(front()); }
void start_thinking(const Position&, const Search::LimitsType&, Search::StateStackPtr&); uint64_t nodes_searched() const { return accumulate(&Thread::nodes); }
void read_uci_options(); uint64_t tb_hits() const { return accumulate(&Thread::tbHits); }
int64_t nodes_searched();
std::atomic_bool stop, ponder, stopOnPonderhit;
private:
StateListPtr setupStates;
uint64_t accumulate(std::atomic<uint64_t> Thread::* member) const {
uint64_t sum = 0;
for (Thread* th : *this)
sum += (th->*member).load(std::memory_order_relaxed);
return sum;
}
}; };
extern ThreadPool Threads; extern ThreadPool Threads;
+3 -3
View File
@@ -2,7 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -25,11 +25,11 @@
/// relies on libwinpthread. Currently libwinpthread implements mutexes directly /// relies on libwinpthread. Currently libwinpthread implements mutexes directly
/// on top of Windows semaphores. Semaphores, being kernel objects, require kernel /// on top of Windows semaphores. Semaphores, being kernel objects, require kernel
/// mode transition in order to lock or unlock, which is very slow compared to /// mode transition in order to lock or unlock, which is very slow compared to
/// interlocked operations (about 30% slower on bench test). To workaround this /// interlocked operations (about 30% slower on bench test). To work around this
/// issue, we define our wrappers to the low level Win32 calls. We use critical /// issue, we define our wrappers to the low level Win32 calls. We use critical
/// sections to support Windows XP and older versions. Unfortunately, cond_wait() /// sections to support Windows XP and older versions. Unfortunately, cond_wait()
/// is racy between unlock() and WaitForSingleObject() but they have the same /// is racy between unlock() and WaitForSingleObject() but they have the same
/// speed performance of SRW locks. /// speed performance as the SRW locks.
#include <condition_variable> #include <condition_variable>
#include <mutex> #include <mutex>
+13 -14
View File
@@ -2,7 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -33,27 +33,27 @@ namespace {
enum TimeType { OptimumTime, MaxTime }; enum TimeType { OptimumTime, MaxTime };
const int MoveHorizon = 50; // Plan time management at most this many moves ahead const int MoveHorizon = 50; // Plan time management at most this many moves ahead
const double MaxRatio = 6.93; // When in trouble, we can step over reserved time with this ratio const double MaxRatio = 7.09; // When in trouble, we can step over reserved time with this ratio
const double StealRatio = 0.36; // However we must not steal time from remaining moves over this ratio const double StealRatio = 0.35; // However we must not steal time from remaining moves over this ratio
// move_importance() is a skew-logistic function based on naive statistical // move_importance() is a skew-logistic function based on naive statistical
// analysis of "how many games are still undecided after n half-moves". Game // analysis of "how many games are still undecided after n half-moves". Game
// is considered "undecided" as long as neither side has >275cp advantage. // is considered "undecided" as long as neither side has >275cp advantage.
// Data was extracted from CCRL game database with some simple filtering criteria. // Data was extracted from the CCRL game database with some simple filtering criteria.
double move_importance(int ply) { double move_importance(int ply) {
const double XScale = 8.27; const double XScale = 7.64;
const double XShift = 59.; const double XShift = 58.4;
const double Skew = 0.179; const double Skew = 0.183;
return pow((1 + exp((ply - XShift) / XScale)), -Skew) + DBL_MIN; // Ensure non-zero return pow((1 + exp((ply - XShift) / XScale)), -Skew) + DBL_MIN; // Ensure non-zero
} }
template<TimeType T> template<TimeType T>
int remaining(int myTime, int movesToGo, int ply, int slowMover) int remaining(int myTime, int movesToGo, int ply, int slowMover) {
{
const double TMaxRatio = (T == OptimumTime ? 1 : MaxRatio); const double TMaxRatio = (T == OptimumTime ? 1 : MaxRatio);
const double TStealRatio = (T == OptimumTime ? 0 : StealRatio); const double TStealRatio = (T == OptimumTime ? 0 : StealRatio);
@@ -66,7 +66,7 @@ namespace {
double ratio1 = (TMaxRatio * moveImportance) / (TMaxRatio * moveImportance + otherMovesImportance); double ratio1 = (TMaxRatio * moveImportance) / (TMaxRatio * moveImportance + otherMovesImportance);
double ratio2 = (moveImportance + TStealRatio * otherMovesImportance) / (moveImportance + otherMovesImportance); double ratio2 = (moveImportance + TStealRatio * otherMovesImportance) / (moveImportance + otherMovesImportance);
return int(myTime * std::min(ratio1, ratio2)); // Intel C++ asks an explicit cast return int(myTime * std::min(ratio1, ratio2)); // Intel C++ asks for an explicit cast
} }
} // namespace } // namespace
@@ -81,8 +81,8 @@ namespace {
/// inc > 0 && movestogo == 0 means: x basetime + z increment /// inc > 0 && movestogo == 0 means: x basetime + z increment
/// inc > 0 && movestogo != 0 means: x moves in y minutes + z increment /// inc > 0 && movestogo != 0 means: x moves in y minutes + z increment
void TimeManagement::init(Search::LimitsType& limits, Color us, int ply) void TimeManagement::init(Search::LimitsType& limits, Color us, int ply) {
{
int minThinkingTime = Options["Minimum Thinking Time"]; int minThinkingTime = Options["Minimum Thinking Time"];
int moveOverhead = Options["Move Overhead"]; int moveOverhead = Options["Move Overhead"];
int slowMover = Options["Slow Mover"]; int slowMover = Options["Slow Mover"];
@@ -91,7 +91,7 @@ void TimeManagement::init(Search::LimitsType& limits, Color us, int ply)
// If we have to play in 'nodes as time' mode, then convert from time // If we have to play in 'nodes as time' mode, then convert from time
// to nodes, and use resulting values in time management formulas. // to nodes, and use resulting values in time management formulas.
// WARNING: Given npms (nodes per millisecond) must be much lower then // WARNING: Given npms (nodes per millisecond) must be much lower then
// real engine speed to avoid time losses. // the real engine speed to avoid time losses.
if (npmsec) if (npmsec)
{ {
if (!availableNodes) // Only once at game start if (!availableNodes) // Only once at game start
@@ -104,7 +104,6 @@ void TimeManagement::init(Search::LimitsType& limits, Color us, int ply)
} }
startTime = limits.startTime; startTime = limits.startTime;
unstablePvFactor = 1;
optimumTime = maximumTime = std::max(limits.time[us], minThinkingTime); optimumTime = maximumTime = std::max(limits.time[us], minThinkingTime);
const int MaxMTG = limits.movestogo ? std::min(limits.movestogo, MoveHorizon) : MoveHorizon; const int MaxMTG = limits.movestogo ? std::min(limits.movestogo, MoveHorizon) : MoveHorizon;
+2 -4
View File
@@ -2,7 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -31,8 +31,7 @@
class TimeManagement { class TimeManagement {
public: public:
void init(Search::LimitsType& limits, Color us, int ply); void init(Search::LimitsType& limits, Color us, int ply);
void pv_instability(double bestMoveChanges) { unstablePvFactor = 1 + bestMoveChanges; } int optimum() const { return optimumTime; }
int available() const { return int(optimumTime * unstablePvFactor * 1.016); }
int maximum() const { return maximumTime; } int maximum() const { return maximumTime; }
int elapsed() const { return int(Search::Limits.npmsec ? Threads.nodes_searched() : now() - startTime); } int elapsed() const { return int(Search::Limits.npmsec ? Threads.nodes_searched() : now() - startTime); }
@@ -42,7 +41,6 @@ private:
TimePoint startTime; TimePoint startTime;
int optimumTime; int optimumTime;
int maximumTime; int maximumTime;
double unstablePvFactor;
}; };
extern TimeManagement Time; extern TimeManagement Time;
+10 -9
View File
@@ -2,7 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -33,7 +33,7 @@ TranspositionTable TT; // Our global transposition table
void TranspositionTable::resize(size_t mbSize) { void TranspositionTable::resize(size_t mbSize) {
size_t newClusterCount = size_t(1) << msb((mbSize * 1024 * 1024) / sizeof(Cluster)); size_t newClusterCount = mbSize * 1024 * 1024 / sizeof(Cluster);
if (newClusterCount == clusterCount) if (newClusterCount == clusterCount)
return; return;
@@ -41,7 +41,7 @@ void TranspositionTable::resize(size_t mbSize) {
clusterCount = newClusterCount; clusterCount = newClusterCount;
free(mem); free(mem);
mem = calloc(clusterCount * sizeof(Cluster) + CacheLineSize - 1, 1); mem = malloc(clusterCount * sizeof(Cluster) + CacheLineSize - 1);
if (!mem) if (!mem)
{ {
@@ -51,6 +51,7 @@ void TranspositionTable::resize(size_t mbSize) {
} }
table = (Cluster*)((uintptr_t(mem) + CacheLineSize - 1) & ~(CacheLineSize - 1)); table = (Cluster*)((uintptr_t(mem) + CacheLineSize - 1) & ~(CacheLineSize - 1));
clear();
} }
@@ -92,19 +93,19 @@ TTEntry* TranspositionTable::probe(const Key key, bool& found) const {
// nature we add 259 (256 is the modulus plus 3 to keep the lowest // nature we add 259 (256 is the modulus plus 3 to keep the lowest
// two bound bits from affecting the result) to calculate the entry // two bound bits from affecting the result) to calculate the entry
// age correctly even after generation8 overflows into the next cycle. // age correctly even after generation8 overflows into the next cycle.
if ( replace->depth8 - ((259 + generation8 - replace->genBound8) & 0xFC) * 2 * ONE_PLY if ( replace->depth8 - ((259 + generation8 - replace->genBound8) & 0xFC) * 2
> tte[i].depth8 - ((259 + generation8 - tte[i].genBound8) & 0xFC) * 2 * ONE_PLY) > tte[i].depth8 - ((259 + generation8 - tte[i].genBound8) & 0xFC) * 2)
replace = &tte[i]; replace = &tte[i];
return found = false, replace; return found = false, replace;
} }
/// Returns an approximation of the hashtable occupation during a search. The /// TranspositionTable::hashfull() returns an approximation of the hashtable
/// hash is x permill full, as per UCI protocol. /// occupation during a search. The hash is x permill full, as per UCI protocol.
int TranspositionTable::hashfull() const {
int TranspositionTable::hashfull() const
{
int cnt = 0; int cnt = 0;
for (int i = 0; i < 1000 / ClusterSize; i++) for (int i = 0; i < 1000 / ClusterSize; i++)
{ {
+8 -6
View File
@@ -2,7 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -39,18 +39,20 @@ struct TTEntry {
Move move() const { return (Move )move16; } Move move() const { return (Move )move16; }
Value value() const { return (Value)value16; } Value value() const { return (Value)value16; }
Value eval() const { return (Value)eval16; } Value eval() const { return (Value)eval16; }
Depth depth() const { return (Depth)depth8; } Depth depth() const { return (Depth)(depth8 * int(ONE_PLY)); }
Bound bound() const { return (Bound)(genBound8 & 0x3); } Bound bound() const { return (Bound)(genBound8 & 0x3); }
void save(Key k, Value v, Bound b, Depth d, Move m, Value ev, uint8_t g) { void save(Key k, Value v, Bound b, Depth d, Move m, Value ev, uint8_t g) {
assert(d / ONE_PLY * ONE_PLY == d);
// Preserve any existing move for the same position // Preserve any existing move for the same position
if (m || (k >> 48) != key16) if (m || (k >> 48) != key16)
move16 = (uint16_t)m; move16 = (uint16_t)m;
// Don't overwrite more valuable entries // Don't overwrite more valuable entries
if ( (k >> 48) != key16 if ( (k >> 48) != key16
|| d > depth8 - 2 || d / ONE_PLY > depth8 - 4
/* || g != (genBound8 & 0xFC) // Matching non-zero keys are already refreshed by probe() */ /* || g != (genBound8 & 0xFC) // Matching non-zero keys are already refreshed by probe() */
|| b == BOUND_EXACT) || b == BOUND_EXACT)
{ {
@@ -58,7 +60,7 @@ struct TTEntry {
value16 = (int16_t)v; value16 = (int16_t)v;
eval16 = (int16_t)ev; eval16 = (int16_t)ev;
genBound8 = (uint8_t)(g | b); genBound8 = (uint8_t)(g | b);
depth8 = (int8_t)d; depth8 = (int8_t)(d / ONE_PLY);
} }
} }
@@ -102,9 +104,9 @@ public:
void resize(size_t mbSize); void resize(size_t mbSize);
void clear(); void clear();
// The lowest order bits of the key are used to get the index of the cluster // The 32 lowest order bits of the key are used to get the index of the cluster
TTEntry* first_entry(const Key key) const { TTEntry* first_entry(const Key key) const {
return &table[(size_t)key & (clusterCount - 1)].entry[0]; return &table[(uint32_t(key) * uint64_t(clusterCount)) >> 32].entry[0];
} }
private: private:
+138 -101
View File
@@ -2,7 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -60,13 +60,12 @@
/// _WIN64 Building on Windows 64 bit /// _WIN64 Building on Windows 64 bit
#if defined(_WIN64) && defined(_MSC_VER) // No Makefile used #if defined(_WIN64) && defined(_MSC_VER) // No Makefile used
# include <intrin.h> // MSVC popcnt and bsfq instrinsics # include <intrin.h> // Microsoft header for _BitScanForward64()
# define IS_64BIT # define IS_64BIT
# define USE_BSFQ
#endif #endif
#if defined(USE_POPCNT) && defined(__INTEL_COMPILER) && defined(_MSC_VER) #if defined(USE_POPCNT) && (defined(__INTEL_COMPILER) || defined(_MSC_VER))
# include <nmmintrin.h> // Intel header for _mm_popcnt_u64() intrinsic # include <nmmintrin.h> // Intel and Microsoft header for _mm_popcnt_u64()
#endif #endif
#if !defined(NO_PREFETCH) && (defined(__INTEL_COMPILER) || defined(_MSC_VER)) #if !defined(NO_PREFETCH) && (defined(__INTEL_COMPILER) || defined(_MSC_VER))
@@ -77,7 +76,7 @@
# include <immintrin.h> // Header for _pext_u64() intrinsic # include <immintrin.h> // Header for _pext_u64() intrinsic
# define pext(b, m) _pext_u64(b, m) # define pext(b, m) _pext_u64(b, m)
#else #else
# define pext(b, m) (0) # define pext(b, m) 0
#endif #endif
#ifdef USE_POPCNT #ifdef USE_POPCNT
@@ -116,7 +115,7 @@ const int MAX_PLY = 128;
/// any normal move destination square is always different from origin square /// any normal move destination square is always different from origin square
/// while MOVE_NONE and MOVE_NULL have the same origin and destination square. /// while MOVE_NONE and MOVE_NULL have the same origin and destination square.
enum Move { enum Move : int {
MOVE_NONE, MOVE_NONE,
MOVE_NULL = 65 MOVE_NULL = 65
}; };
@@ -129,7 +128,7 @@ enum MoveType {
}; };
enum Color { enum Color {
WHITE, BLACK, NO_COLOR, COLOR_NB = 2 WHITE, BLACK, COLOR_NB = 2
}; };
enum CastlingSide { enum CastlingSide {
@@ -147,7 +146,7 @@ enum CastlingRight {
}; };
template<Color C, CastlingSide S> struct MakeCastling { template<Color C, CastlingSide S> struct MakeCastling {
static const CastlingRight static constexpr CastlingRight
right = C == WHITE ? S == QUEEN_SIDE ? WHITE_OOO : WHITE_OO right = C == WHITE ? S == QUEEN_SIDE ? WHITE_OOO : WHITE_OO
: S == QUEEN_SIDE ? BLACK_OOO : BLACK_OO; : S == QUEEN_SIDE ? BLACK_OOO : BLACK_OO;
}; };
@@ -184,18 +183,19 @@ enum Value : int {
VALUE_MATE_IN_MAX_PLY = VALUE_MATE - 2 * MAX_PLY, VALUE_MATE_IN_MAX_PLY = VALUE_MATE - 2 * MAX_PLY,
VALUE_MATED_IN_MAX_PLY = -VALUE_MATE + 2 * MAX_PLY, VALUE_MATED_IN_MAX_PLY = -VALUE_MATE + 2 * MAX_PLY,
PawnValueMg = 198, PawnValueEg = 258, PawnValueMg = 171, PawnValueEg = 240,
KnightValueMg = 817, KnightValueEg = 846, KnightValueMg = 764, KnightValueEg = 848,
BishopValueMg = 836, BishopValueEg = 857, BishopValueMg = 826, BishopValueEg = 891,
RookValueMg = 1270, RookValueEg = 1281, RookValueMg = 1282, RookValueEg = 1373,
QueenValueMg = 2521, QueenValueEg = 2558, QueenValueMg = 2526, QueenValueEg = 2646,
MidgameLimit = 15581, EndgameLimit = 3998 MidgameLimit = 15258, EndgameLimit = 3915
}; };
enum PieceType { enum PieceType {
NO_PIECE_TYPE, PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING, NO_PIECE_TYPE, PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING,
ALL_PIECES = 0, ALL_PIECES = 0,
QUEEN_DIAGONAL = 7,
PIECE_TYPE_NB = 8 PIECE_TYPE_NB = 8
}; };
@@ -206,20 +206,24 @@ enum Piece {
PIECE_NB = 16 PIECE_NB = 16
}; };
enum Depth { extern Value PieceValue[PHASE_NB][PIECE_NB];
enum Depth : int {
ONE_PLY = 1, ONE_PLY = 1,
DEPTH_ZERO = 0, DEPTH_ZERO = 0 * ONE_PLY,
DEPTH_QS_CHECKS = 0, DEPTH_QS_CHECKS = 0 * ONE_PLY,
DEPTH_QS_NO_CHECKS = -1, DEPTH_QS_NO_CHECKS = -1 * ONE_PLY,
DEPTH_QS_RECAPTURES = -5, DEPTH_QS_RECAPTURES = -5 * ONE_PLY,
DEPTH_NONE = -6, DEPTH_NONE = -6 * ONE_PLY,
DEPTH_MAX = MAX_PLY DEPTH_MAX = MAX_PLY * ONE_PLY
}; };
enum Square { static_assert(!(ONE_PLY & (ONE_PLY - 1)), "ONE_PLY is not a power of 2");
enum Square : int {
SQ_A1, SQ_B1, SQ_C1, SQ_D1, SQ_E1, SQ_F1, SQ_G1, SQ_H1, SQ_A1, SQ_B1, SQ_C1, SQ_D1, SQ_E1, SQ_F1, SQ_G1, SQ_H1,
SQ_A2, SQ_B2, SQ_C2, SQ_D2, SQ_E2, SQ_F2, SQ_G2, SQ_H2, SQ_A2, SQ_B2, SQ_C2, SQ_D2, SQ_E2, SQ_F2, SQ_G2, SQ_H2,
SQ_A3, SQ_B3, SQ_C3, SQ_D3, SQ_E3, SQ_F3, SQ_G3, SQ_H3, SQ_A3, SQ_B3, SQ_C3, SQ_D3, SQ_E3, SQ_F3, SQ_G3, SQ_H3,
@@ -230,132 +234,161 @@ enum Square {
SQ_A8, SQ_B8, SQ_C8, SQ_D8, SQ_E8, SQ_F8, SQ_G8, SQ_H8, SQ_A8, SQ_B8, SQ_C8, SQ_D8, SQ_E8, SQ_F8, SQ_G8, SQ_H8,
SQ_NONE, SQ_NONE,
SQUARE_NB = 64, SQUARE_NB = 64
DELTA_N = 8,
DELTA_E = 1,
DELTA_S = -8,
DELTA_W = -1,
DELTA_NN = DELTA_N + DELTA_N,
DELTA_NE = DELTA_N + DELTA_E,
DELTA_SE = DELTA_S + DELTA_E,
DELTA_SS = DELTA_S + DELTA_S,
DELTA_SW = DELTA_S + DELTA_W,
DELTA_NW = DELTA_N + DELTA_W
}; };
enum File { enum Direction : int {
NORTH = 8,
EAST = 1,
SOUTH = -NORTH,
WEST = -EAST,
NORTH_EAST = NORTH + EAST,
SOUTH_EAST = SOUTH + EAST,
SOUTH_WEST = SOUTH + WEST,
NORTH_WEST = NORTH + WEST
};
enum File : int {
FILE_A, FILE_B, FILE_C, FILE_D, FILE_E, FILE_F, FILE_G, FILE_H, FILE_NB FILE_A, FILE_B, FILE_C, FILE_D, FILE_E, FILE_F, FILE_G, FILE_H, FILE_NB
}; };
enum Rank { enum Rank : int {
RANK_1, RANK_2, RANK_3, RANK_4, RANK_5, RANK_6, RANK_7, RANK_8, RANK_NB RANK_1, RANK_2, RANK_3, RANK_4, RANK_5, RANK_6, RANK_7, RANK_8, RANK_NB
}; };
/// Score enum stores a middlegame and an endgame value in a single integer /// Score enum stores a middlegame and an endgame value in a single integer
/// (enum). The least significant 16 bits are used to store the endgame value /// (enum). The least significant 16 bits are used to store the endgame value
/// and the upper 16 bits are used to store the middlegame value. /// and the upper 16 bits are used to store the middlegame value. Take some
/// care to avoid left-shifting a signed int to avoid undefined behavior.
enum Score : int { SCORE_ZERO }; enum Score : int { SCORE_ZERO };
inline Score make_score(int mg, int eg) { constexpr Score make_score(int mg, int eg) {
return Score((mg << 16) + eg); return Score((int)((unsigned int)eg << 16) + mg);
} }
/// Extracting the signed lower and upper 16 bits is not so trivial because /// Extracting the signed lower and upper 16 bits is not so trivial because
/// according to the standard a simple cast to short is implementation defined /// according to the standard a simple cast to short is implementation defined
/// and so is a right shift of a signed integer. /// and so is a right shift of a signed integer.
inline Value mg_value(Score s) {
union { uint16_t u; int16_t s; } mg = { uint16_t(unsigned(s + 0x8000) >> 16) };
return Value(mg.s);
}
inline Value eg_value(Score s) { inline Value eg_value(Score s) {
union { uint16_t u; int16_t s; } eg = { uint16_t(unsigned(s + 0x8000) >> 16) };
union { uint16_t u; int16_t s; } eg = { uint16_t(unsigned(s)) };
return Value(eg.s); return Value(eg.s);
} }
#define ENABLE_BASE_OPERATORS_ON(T) \ inline Value mg_value(Score s) {
inline T operator+(T d1, T d2) { return T(int(d1) + int(d2)); } \ union { uint16_t u; int16_t s; } mg = { uint16_t(unsigned(s)) };
inline T operator-(T d1, T d2) { return T(int(d1) - int(d2)); } \ return Value(mg.s);
inline T operator*(int i, T d) { return T(i * int(d)); } \ }
inline T operator*(T d, int i) { return T(int(d) * i); } \
inline T operator-(T d) { return T(-int(d)); } \
inline T& operator+=(T& d1, T d2) { return d1 = d1 + d2; } \
inline T& operator-=(T& d1, T d2) { return d1 = d1 - d2; } \
inline T& operator*=(T& d, int i) { return d = T(int(d) * i); }
#define ENABLE_FULL_OPERATORS_ON(T) \ #define ENABLE_BASE_OPERATORS_ON(T) \
ENABLE_BASE_OPERATORS_ON(T) \ constexpr T operator+(T d1, T d2) { return T(int(d1) + int(d2)); } \
inline T& operator++(T& d) { return d = T(int(d) + 1); } \ constexpr T operator-(T d1, T d2) { return T(int(d1) - int(d2)); } \
inline T& operator--(T& d) { return d = T(int(d) - 1); } \ constexpr T operator-(T d) { return T(-int(d)); } \
inline T operator/(T d, int i) { return T(int(d) / i); } \ inline T& operator+=(T& d1, T d2) { return d1 = d1 + d2; } \
inline int operator/(T d1, T d2) { return int(d1) / int(d2); } \ inline T& operator-=(T& d1, T d2) { return d1 = d1 - d2; }
#define ENABLE_INCR_OPERATORS_ON(T) \
inline T& operator++(T& d) { return d = T(int(d) + 1); } \
inline T& operator--(T& d) { return d = T(int(d) - 1); }
#define ENABLE_FULL_OPERATORS_ON(T) \
ENABLE_BASE_OPERATORS_ON(T) \
ENABLE_INCR_OPERATORS_ON(T) \
constexpr T operator*(int i, T d) { return T(i * int(d)); } \
constexpr T operator*(T d, int i) { return T(int(d) * i); } \
constexpr T operator/(T d, int i) { return T(int(d) / i); } \
constexpr int operator/(T d1, T d2) { return int(d1) / int(d2); } \
inline T& operator*=(T& d, int i) { return d = T(int(d) * i); } \
inline T& operator/=(T& d, int i) { return d = T(int(d) / i); } inline T& operator/=(T& d, int i) { return d = T(int(d) / i); }
ENABLE_FULL_OPERATORS_ON(Value) ENABLE_FULL_OPERATORS_ON(Value)
ENABLE_FULL_OPERATORS_ON(PieceType)
ENABLE_FULL_OPERATORS_ON(Piece)
ENABLE_FULL_OPERATORS_ON(Color)
ENABLE_FULL_OPERATORS_ON(Depth) ENABLE_FULL_OPERATORS_ON(Depth)
ENABLE_FULL_OPERATORS_ON(Square) ENABLE_FULL_OPERATORS_ON(Direction)
ENABLE_FULL_OPERATORS_ON(File)
ENABLE_FULL_OPERATORS_ON(Rank) ENABLE_INCR_OPERATORS_ON(PieceType)
ENABLE_INCR_OPERATORS_ON(Piece)
ENABLE_INCR_OPERATORS_ON(Color)
ENABLE_INCR_OPERATORS_ON(Square)
ENABLE_INCR_OPERATORS_ON(File)
ENABLE_INCR_OPERATORS_ON(Rank)
ENABLE_BASE_OPERATORS_ON(Score) ENABLE_BASE_OPERATORS_ON(Score)
#undef ENABLE_FULL_OPERATORS_ON #undef ENABLE_FULL_OPERATORS_ON
#undef ENABLE_INCR_OPERATORS_ON
#undef ENABLE_BASE_OPERATORS_ON #undef ENABLE_BASE_OPERATORS_ON
/// Additional operators to add integers to a Value /// Additional operators to add integers to a Value
inline Value operator+(Value v, int i) { return Value(int(v) + i); } constexpr Value operator+(Value v, int i) { return Value(int(v) + i); }
inline Value operator-(Value v, int i) { return Value(int(v) - i); } constexpr Value operator-(Value v, int i) { return Value(int(v) - i); }
inline Value& operator+=(Value& v, int i) { return v = v + i; } inline Value& operator+=(Value& v, int i) { return v = v + i; }
inline Value& operator-=(Value& v, int i) { return v = v - i; } inline Value& operator-=(Value& v, int i) { return v = v - i; }
/// Additional operators to add a Direction to a Square
inline Square operator+(Square s, Direction d) { return Square(int(s) + int(d)); }
inline Square operator-(Square s, Direction d) { return Square(int(s) - int(d)); }
inline Square& operator+=(Square &s, Direction d) { return s = s + d; }
inline Square& operator-=(Square &s, Direction d) { return s = s - d; }
/// Only declared but not defined. We don't want to multiply two scores due to /// Only declared but not defined. We don't want to multiply two scores due to
/// a very high risk of overflow. So user should explicitly convert to integer. /// a very high risk of overflow. So user should explicitly convert to integer.
inline Score operator*(Score s1, Score s2); Score operator*(Score, Score) = delete;
/// Division of a Score must be handled separately for each term /// Division of a Score must be handled separately for each term
inline Score operator/(Score s, int i) { inline Score operator/(Score s, int i) {
return make_score(mg_value(s) / i, eg_value(s) / i); return make_score(mg_value(s) / i, eg_value(s) / i);
} }
extern Value PieceValue[PHASE_NB][PIECE_NB]; /// Multiplication of a Score by an integer. We check for overflow in debug mode.
inline Score operator*(Score s, int i) {
inline Color operator~(Color c) { Score result = Score(int(s) * i);
return Color(c ^ BLACK);
assert(eg_value(result) == (i * eg_value(s)));
assert(mg_value(result) == (i * mg_value(s)));
assert((i == 0) || (result / i) == s );
return result;
} }
inline Square operator~(Square s) { constexpr Color operator~(Color c) {
return Color(c ^ BLACK); // Toggle color
}
constexpr Square operator~(Square s) {
return Square(s ^ SQ_A8); // Vertical flip SQ_A1 -> SQ_A8 return Square(s ^ SQ_A8); // Vertical flip SQ_A1 -> SQ_A8
} }
inline CastlingRight operator|(Color c, CastlingSide s) { constexpr File operator~(File f) {
return File(f ^ FILE_H); // Horizontal flip FILE_A -> FILE_H
}
constexpr Piece operator~(Piece pc) {
return Piece(pc ^ 8); // Swap color of piece B_KNIGHT -> W_KNIGHT
}
constexpr CastlingRight operator|(Color c, CastlingSide s) {
return CastlingRight(WHITE_OO << ((s == QUEEN_SIDE) + 2 * c)); return CastlingRight(WHITE_OO << ((s == QUEEN_SIDE) + 2 * c));
} }
inline Value mate_in(int ply) { constexpr Value mate_in(int ply) {
return VALUE_MATE - ply; return VALUE_MATE - ply;
} }
inline Value mated_in(int ply) { constexpr Value mated_in(int ply) {
return -VALUE_MATE + ply; return -VALUE_MATE + ply;
} }
inline Square make_square(File f, Rank r) { constexpr Square make_square(File f, Rank r) {
return Square((r << 3) | f); return Square((r << 3) + f);
} }
inline Piece make_piece(Color c, PieceType pt) { constexpr Piece make_piece(Color c, PieceType pt) {
return Piece((c << 3) | pt); return Piece((c << 3) + pt);
} }
inline PieceType type_of(Piece pc) { constexpr PieceType type_of(Piece pc) {
return PieceType(pc & 7); return PieceType(pc & 7);
} }
@@ -364,27 +397,27 @@ inline Color color_of(Piece pc) {
return Color(pc >> 3); return Color(pc >> 3);
} }
inline bool is_ok(Square s) { constexpr bool is_ok(Square s) {
return s >= SQ_A1 && s <= SQ_H8; return s >= SQ_A1 && s <= SQ_H8;
} }
inline File file_of(Square s) { constexpr File file_of(Square s) {
return File(s & 7); return File(s & 7);
} }
inline Rank rank_of(Square s) { constexpr Rank rank_of(Square s) {
return Rank(s >> 3); return Rank(s >> 3);
} }
inline Square relative_square(Color c, Square s) { constexpr Square relative_square(Color c, Square s) {
return Square(s ^ (c * 56)); return Square(s ^ (c * 56));
} }
inline Rank relative_rank(Color c, Rank r) { constexpr Rank relative_rank(Color c, Rank r) {
return Rank(r ^ (c * 7)); return Rank(r ^ (c * 7));
} }
inline Rank relative_rank(Color c, Square s) { constexpr Rank relative_rank(Color c, Square s) {
return relative_rank(c, rank_of(s)); return relative_rank(c, rank_of(s));
} }
@@ -393,36 +426,40 @@ inline bool opposite_colors(Square s1, Square s2) {
return ((s >> 3) ^ s) & 1; return ((s >> 3) ^ s) & 1;
} }
inline Square pawn_push(Color c) { constexpr Direction pawn_push(Color c) {
return c == WHITE ? DELTA_N : DELTA_S; return c == WHITE ? NORTH : SOUTH;
} }
inline Square from_sq(Move m) { constexpr Square from_sq(Move m) {
return Square((m >> 6) & 0x3F); return Square((m >> 6) & 0x3F);
} }
inline Square to_sq(Move m) { constexpr Square to_sq(Move m) {
return Square(m & 0x3F); return Square(m & 0x3F);
} }
inline MoveType type_of(Move m) { constexpr int from_to(Move m) {
return m & 0xFFF;
}
constexpr MoveType type_of(Move m) {
return MoveType(m & (3 << 14)); return MoveType(m & (3 << 14));
} }
inline PieceType promotion_type(Move m) { constexpr PieceType promotion_type(Move m) {
return PieceType(((m >> 12) & 3) + KNIGHT); return PieceType(((m >> 12) & 3) + KNIGHT);
} }
inline Move make_move(Square from, Square to) { inline Move make_move(Square from, Square to) {
return Move(to | (from << 6)); return Move((from << 6) + to);
} }
template<MoveType T> template<MoveType T>
inline Move make(Square from, Square to, PieceType pt = KNIGHT) { constexpr Move make(Square from, Square to, PieceType pt = KNIGHT) {
return Move(to | (from << 6) | T | ((pt - KNIGHT) << 12)); return Move(T + ((pt - KNIGHT) << 12) + (from << 6) + to);
} }
inline bool is_ok(Move m) { constexpr bool is_ok(Move m) {
return from_sq(m) != to_sq(m); // Catch MOVE_NULL and MOVE_NONE return from_sq(m) != to_sq(m); // Catch MOVE_NULL and MOVE_NONE
} }
+84 -55
View File
@@ -2,7 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -18,6 +18,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <cassert>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <string> #include <string>
@@ -27,30 +28,27 @@
#include "position.h" #include "position.h"
#include "search.h" #include "search.h"
#include "thread.h" #include "thread.h"
#include "tt.h"
#include "timeman.h" #include "timeman.h"
#include "uci.h" #include "uci.h"
#include "syzygy/tbprobe.h"
using namespace std; using namespace std;
extern void benchmark(const Position& pos, istream& is); extern vector<string> setup_bench(const Position&, istream&);
namespace { namespace {
// FEN string of the initial position, normal chess // FEN string of the initial position, normal chess
const char* StartFEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"; const char* StartFEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
// Stack to keep track of the position states along the setup moves (from the
// start position to the position just before the search starts). Needed by
// 'draw by repetition' detection.
Search::StateStackPtr SetupStates;
// position() is called when engine receives the "position" UCI command. // position() is called when engine receives the "position" UCI command.
// The function sets up the position described in the given FEN string ("fen") // The function sets up the position described in the given FEN string ("fen")
// or the starting position ("startpos") and then makes the moves given in the // or the starting position ("startpos") and then makes the moves given in the
// following move list ("moves"). // following move list ("moves").
void position(Position& pos, istringstream& is) { void position(Position& pos, istringstream& is, StateListPtr& states) {
Move m; Move m;
string token, fen; string token, fen;
@@ -68,14 +66,14 @@ namespace {
else else
return; return;
pos.set(fen, Options["UCI_Chess960"], Threads.main()); states = StateListPtr(new std::deque<StateInfo>(1)); // Drop old and create a new one
SetupStates = Search::StateStackPtr(new std::stack<StateInfo>); pos.set(fen, Options["UCI_Chess960"], &states->back(), Threads.main());
// Parse move list (if any) // Parse move list (if any)
while (is >> token && (m = UCI::to_move(pos, token)) != MOVE_NONE) while (is >> token && (m = UCI::to_move(pos, token)) != MOVE_NONE)
{ {
SetupStates->push(StateInfo()); states->emplace_back();
pos.do_move(m, SetupStates->top(), pos.gives_check(m, CheckInfo(pos))); pos.do_move(m, states->back());
} }
} }
@@ -108,10 +106,11 @@ namespace {
// the thinking time and other parameters from the input string, then starts // the thinking time and other parameters from the input string, then starts
// the search. // the search.
void go(const Position& pos, istringstream& is) { void go(Position& pos, istringstream& is, StateListPtr& states) {
Search::LimitsType limits; Search::LimitsType limits;
string token; string token;
bool ponderMode = false;
limits.startTime = now(); // As early as possible! limits.startTime = now(); // As early as possible!
@@ -129,10 +128,53 @@ namespace {
else if (token == "nodes") is >> limits.nodes; else if (token == "nodes") is >> limits.nodes;
else if (token == "movetime") is >> limits.movetime; else if (token == "movetime") is >> limits.movetime;
else if (token == "mate") is >> limits.mate; else if (token == "mate") is >> limits.mate;
else if (token == "perft") is >> limits.perft;
else if (token == "infinite") limits.infinite = 1; else if (token == "infinite") limits.infinite = 1;
else if (token == "ponder") limits.ponder = 1; else if (token == "ponder") ponderMode = true;
Threads.start_thinking(pos, limits, SetupStates); Threads.start_thinking(pos, states, limits, ponderMode);
}
// bench() is called when engine receives the "bench" command. Firstly
// a list of UCI commands is setup according to bench parameters, then
// it is run one by one printing a summary at the end.
void bench(Position& pos, istream& args, StateListPtr& states) {
string token;
uint64_t num, nodes = 0, cnt = 1;
vector<string> list = setup_bench(pos, args);
num = count_if(list.begin(), list.end(), [](string s) { return s.find("go ") == 0; });
TimePoint elapsed = now();
for (const auto& cmd : list)
{
istringstream is(cmd);
is >> skipws >> token;
if (token == "go")
{
cerr << "\nPosition: " << cnt++ << '/' << num << endl;
go(pos, is, states);
Threads.main()->wait_for_search_finished();
nodes += Threads.nodes_searched();
}
else if (token == "setoption") setoption(is);
else if (token == "position") position(pos, is, states);
else if (token == "ucinewgame") Search::clear();
}
elapsed = now() - elapsed + 1; // Ensure positivity to avoid a 'divide by zero'
dbg_print(); // Just before exiting
cerr << "\n==========================="
<< "\nTotal time (ms) : " << elapsed
<< "\nNodes searched : " << nodes
<< "\nNodes/second : " << 1000 * nodes / elapsed << endl;
} }
} // namespace } // namespace
@@ -146,8 +188,12 @@ namespace {
void UCI::loop(int argc, char* argv[]) { void UCI::loop(int argc, char* argv[]) {
Position pos(StartFEN, false, Threads.main()); // The root position Position pos;
string token, cmd; string token, cmd;
StateListPtr states(new std::deque<StateInfo>(1));
auto uiThread = std::make_shared<Thread>(0);
pos.set(StartFEN, false, &states->back(), uiThread.get());
for (int i = 1; i < argc; ++i) for (int i = 1; i < argc; ++i)
cmd += std::string(argv[i]) + " "; cmd += std::string(argv[i]) + " ";
@@ -158,61 +204,42 @@ void UCI::loop(int argc, char* argv[]) {
istringstream is(cmd); istringstream is(cmd);
token.clear(); // getline() could return empty or blank line token.clear(); // Avoid a stale if getline() returns empty or blank line
is >> skipws >> token; is >> skipws >> token;
// The GUI sends 'ponderhit' to tell us to ponder on the same move the // The GUI sends 'ponderhit' to tell us the user has played the expected move.
// opponent has played. In case Signals.stopOnPonderhit is set we are // So 'ponderhit' will be sent if we were told to ponder on the same move the
// waiting for 'ponderhit' to stop the search (for instance because we // user has played. We should continue searching but switch from pondering to
// already ran out of time), otherwise we should continue searching but // normal search. In case Threads.stopOnPonderhit is set we are waiting for
// switching from pondering to normal search. // 'ponderhit' to stop the search, for instance if max search depth is reached.
if ( token == "quit" if ( token == "quit"
|| token == "stop" || token == "stop"
|| (token == "ponderhit" && Search::Signals.stopOnPonderhit)) || (token == "ponderhit" && Threads.stopOnPonderhit))
{ Threads.stop = true;
Search::Signals.stop = true;
Threads.main()->start_searching(true); // Could be sleeping
}
else if (token == "ponderhit") else if (token == "ponderhit")
Search::Limits.ponder = 0; // Switch to normal search Threads.ponder = false; // Switch to normal search
else if (token == "uci") else if (token == "uci")
sync_cout << "id name " << engine_info(true) sync_cout << "id name " << engine_info(true)
<< "\n" << Options << "\n" << Options
<< "\nuciok" << sync_endl; << "\nuciok" << sync_endl;
else if (token == "ucinewgame")
{
Search::clear();
Time.availableNodes = 0;
}
else if (token == "isready") sync_cout << "readyok" << sync_endl;
else if (token == "go") go(pos, is);
else if (token == "position") position(pos, is);
else if (token == "setoption") setoption(is); else if (token == "setoption") setoption(is);
else if (token == "go") go(pos, is, states);
else if (token == "position") position(pos, is, states);
else if (token == "ucinewgame") Search::clear();
else if (token == "isready") sync_cout << "readyok" << sync_endl;
// Additional custom non-UCI commands, useful for debugging // Additional custom non-UCI commands, mainly for debugging
else if (token == "flip") pos.flip(); else if (token == "flip") pos.flip();
else if (token == "bench") benchmark(pos, is); else if (token == "bench") bench(pos, is, states);
else if (token == "d") sync_cout << pos << sync_endl; else if (token == "d") sync_cout << pos << sync_endl;
else if (token == "eval") sync_cout << Eval::trace(pos) << sync_endl; else if (token == "eval") sync_cout << Eval::trace(pos) << sync_endl;
else if (token == "perft")
{
int depth;
stringstream ss;
is >> depth;
ss << Options["Hash"] << " "
<< Options["Threads"] << " " << depth << " current perft";
benchmark(pos, ss);
}
else else
sync_cout << "Unknown command: " << cmd << sync_endl; sync_cout << "Unknown command: " << cmd << sync_endl;
} while (token != "quit" && argc == 1); // Passed args have one-shot behaviour } while (token != "quit" && argc == 1); // Command line args are one-shot
Threads.main()->wait_for_search_finished();
} }
@@ -225,6 +252,8 @@ void UCI::loop(int argc, char* argv[]) {
string UCI::value(Value v) { string UCI::value(Value v) {
assert(-VALUE_INFINITE < v && v < VALUE_INFINITE);
stringstream ss; stringstream ss;
if (abs(v) < VALUE_MATE - MAX_PLY) if (abs(v) < VALUE_MATE - MAX_PLY)
+2 -2
View File
@@ -2,7 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -49,7 +49,7 @@ public:
Option(OnChange = nullptr); Option(OnChange = nullptr);
Option(bool v, OnChange = nullptr); Option(bool v, OnChange = nullptr);
Option(const char* v, OnChange = nullptr); Option(const char* v, OnChange = nullptr);
Option(int v, int min, int max, OnChange = nullptr); Option(int v, int minv, int maxv, OnChange = nullptr);
Option& operator=(const std::string&); Option& operator=(const std::string&);
void operator<<(const Option&); void operator<<(const Option&);
+8 -7
View File
@@ -2,7 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -39,7 +39,7 @@ namespace UCI {
void on_clear_hash(const Option&) { Search::clear(); } void on_clear_hash(const Option&) { Search::clear(); }
void on_hash_size(const Option& o) { TT.resize(o); } void on_hash_size(const Option& o) { TT.resize(o); }
void on_logger(const Option& o) { start_logger(o); } void on_logger(const Option& o) { start_logger(o); }
void on_threads(const Option&) { Threads.read_uci_options(); } void on_threads(const Option& o) { Threads.set(o); }
void on_tb_path(const Option& o) { Tablebases::init(o); } void on_tb_path(const Option& o) { Tablebases::init(o); }
@@ -55,11 +55,12 @@ bool CaseInsensitiveLess::operator() (const string& s1, const string& s2) const
void init(OptionsMap& o) { void init(OptionsMap& o) {
const int MaxHashMB = Is64Bit ? 1024 * 1024 : 2048; // at most 2^32 clusters.
const int MaxHashMB = Is64Bit ? 131072 : 2048;
o["Write Debug Log"] << Option(false, on_logger); o["Debug Log File"] << Option("", on_logger);
o["Contempt"] << Option(0, -100, 100); o["Contempt"] << Option(20, -100, 100);
o["Threads"] << Option(1, 1, 128, on_threads); o["Threads"] << Option(1, 1, 512, on_threads);
o["Hash"] << Option(16, 1, MaxHashMB, on_hash_size); o["Hash"] << Option(16, 1, MaxHashMB, on_hash_size);
o["Clear Hash"] << Option(on_clear_hash); o["Clear Hash"] << Option(on_clear_hash);
o["Ponder"] << Option(false); o["Ponder"] << Option(false);
@@ -67,7 +68,7 @@ void init(OptionsMap& o) {
o["Skill Level"] << Option(20, 0, 20); o["Skill Level"] << Option(20, 0, 20);
o["Move Overhead"] << Option(30, 0, 5000); o["Move Overhead"] << Option(30, 0, 5000);
o["Minimum Thinking Time"] << Option(20, 0, 5000); o["Minimum Thinking Time"] << Option(20, 0, 5000);
o["Slow Mover"] << Option(84, 10, 1000); o["Slow Mover"] << Option(89, 10, 1000);
o["nodestime"] << Option(0, 0, 10000); o["nodestime"] << Option(0, 0, 10000);
o["UCI_Chess960"] << Option(false); o["UCI_Chess960"] << Option(false);
o["SyzygyPath"] << Option("<empty>", on_tb_path); o["SyzygyPath"] << Option("<empty>", on_tb_path);
+123
View File
@@ -0,0 +1,123 @@
#!/bin/bash
# check for errors under valgrind or sanitizers.
error()
{
echo "instrumented testing failed on line $1"
exit 1
}
trap 'error ${LINENO}' ERR
# define suitable post and prefixes for testing options
case $1 in
--valgrind)
echo "valgrind testing started"
prefix=''
exeprefix='valgrind --error-exitcode=42'
postfix='1>/dev/null'
threads="1"
;;
--valgrind-thread)
echo "valgrind-thread testing started"
prefix=''
exeprefix='valgrind --error-exitcode=42'
postfix='1>/dev/null'
threads="2"
;;
--sanitizer-undefined)
echo "sanitizer-undefined testing started"
prefix='!'
exeprefix=''
postfix='2>&1 | grep "runtime error:"'
threads="1"
;;
--sanitizer-thread)
echo "sanitizer-thread testing started"
prefix='!'
exeprefix=''
postfix='2>&1 | grep "WARNING: ThreadSanitizer:"'
threads="2"
cat << EOF > tsan.supp
race:TTEntry::move
race:TTEntry::depth
race:TTEntry::bound
race:TTEntry::save
race:TTEntry::value
race:TTEntry::eval
race:TranspositionTable::probe
race:TranspositionTable::hashfull
EOF
export TSAN_OPTIONS="suppressions=./tsan.supp"
;;
*)
echo "unknown testing started"
prefix=''
exeprefix=''
postfix=''
threads="1"
;;
esac
# simple command line testing
for args in "eval" \
"go nodes 1000" \
"go depth 10" \
"go movetime 1000" \
"go wtime 8000 btime 8000 winc 500 binc 500" \
"bench 128 $threads 10 default depth"
do
echo "$prefix $exeprefix ./stockfish $args $postfix"
eval "$prefix $exeprefix ./stockfish $args $postfix"
done
# more general testing, following an uci protocol exchange
cat << EOF > game.exp
set timeout 10
spawn $exeprefix ./stockfish
send "uci\n"
expect "uciok"
send "setoption name Threads value $threads\n"
send "ucinewgame\n"
send "position startpos\n"
send "go nodes 1000\n"
expect "bestmove"
send "position startpos moves e2e4 e7e6\n"
send "go nodes 1000\n"
expect "bestmove"
send "position fen 5rk1/1K4p1/8/8/3B4/8/8/8 b - - 0 1\n"
send "go depth 30\n"
expect "bestmove"
send "quit\n"
expect eof
# return error code of the spawned program, useful for valgrind
lassign [wait] pid spawnid os_error_flag value
exit \$value
EOF
for exps in game.exp
do
echo "$prefix expect $exps $postfix"
eval "$prefix expect $exps $postfix"
rm $exps
done
rm -f tsan.supp
echo "instrumented testing OK"
Executable
+32
View File
@@ -0,0 +1,32 @@
#!/bin/bash
# verify perft numbers (positions from https://chessprogramming.wikispaces.com/Perft+Results)
error()
{
echo "perft testing failed on line $1"
exit 1
}
trap 'error ${LINENO}' ERR
echo "perft testing started"
cat << EOF > perft.exp
set timeout 10
lassign \$argv pos depth result
spawn ./stockfish
send "position \$pos\\ngo perft \$depth\\n"
expect "Nodes searched? \$result" {} timeout {exit 1}
send "quit\\n"
expect eof
EOF
expect perft.exp startpos 5 4865609 > /dev/null
expect perft.exp "fen r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq -" 5 193690690 > /dev/null
expect perft.exp "fen 8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - -" 6 11030083 > /dev/null
expect perft.exp "fen r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/q4N2/Pp1P2PP/R2Q1RK1 w kq - 0 1" 5 15833292 > /dev/null
expect perft.exp "fen rnbq1k1r/pp1Pbppp/2p5/8/2B5/8/PPP1NnPP/RNBQK2R w KQ - 1 8" 5 89941194 > /dev/null
expect perft.exp "fen r4rk1/1pp1qppp/p1np1n2/2b1p1B1/2B1P1b1/P1NP1N2/1PP1QPPP/R4RK1 w - - 0 10" 5 164075551 > /dev/null
rm perft.exp
echo "perft testing OK"
+61
View File
@@ -0,0 +1,61 @@
#!/bin/bash
# verify reproducible search
error()
{
echo "reprosearch testing failed on line $1"
exit 1
}
trap 'error ${LINENO}' ERR
echo "reprosearch testing started"
# repeat two short games, separated by ucinewgame.
# with go nodes $nodes they should result in exactly
# the same node count for each iteration.
cat << EOF > repeat.exp
set timeout 10
spawn ./stockfish
lassign \$argv nodes
send "uci\n"
expect "uciok"
send "ucinewgame\n"
send "position startpos\n"
send "go nodes \$nodes\n"
expect "bestmove"
send "position startpos moves e2e4 e7e6\n"
send "go nodes \$nodes\n"
expect "bestmove"
send "ucinewgame\n"
send "position startpos\n"
send "go nodes \$nodes\n"
expect "bestmove"
send "position startpos moves e2e4 e7e6\n"
send "go nodes \$nodes\n"
expect "bestmove"
send "quit\n"
expect eof
EOF
# to increase the likelyhood of finding a non-reproducible case,
# the allowed number of nodes are varied systematically
for i in `seq 1 20`
do
nodes=$((100*3**i/2**i))
echo "reprosearch testing with $nodes nodes"
# each line should appear exactly an even number of times
expect repeat.exp $nodes 2>&1 | grep -o "nodes [0-9]*" | sort | uniq -c | awk '{if ($1%2!=0) exit(1)}'
done
rm repeat.exp
echo "reprosearch testing OK"
+27
View File
@@ -0,0 +1,27 @@
#!/bin/bash
# obtain and optionally verify Bench / signature
# if no reference is given, the output is deliberately limited to just the signature
error()
{
echo "running bench for signature failed on line $1"
exit 1
}
trap 'error ${LINENO}' ERR
# obtain
signature=`./stockfish bench 2>&1 | grep "Nodes searched : " | awk '{print $4}'`
if [ $# -gt 0 ]; then
# compare to given reference
if [ "$1" != "$signature" ]; then
echo "signature mismatch: reference $1 obtained $signature"
exit 1
else
echo "signature OK: $signature"
fi
else
# just report signature
echo $signature
fi