Compare commits

...

291 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
49 changed files with 4331 additions and 4263 deletions
+29 -11
View File
@@ -9,7 +9,7 @@ matrix:
addons: addons:
apt: apt:
sources: ['ubuntu-toolchain-r-test'] sources: ['ubuntu-toolchain-r-test']
packages: ['g++-6', 'g++-6-multilib', 'g++-multilib', 'valgrind'] packages: ['g++-6', 'g++-6-multilib', 'g++-multilib', 'valgrind', 'expect']
env: env:
- COMPILER=g++-6 - COMPILER=g++-6
- COMP=gcc - COMP=gcc
@@ -19,7 +19,7 @@ matrix:
addons: addons:
apt: apt:
sources: ['ubuntu-toolchain-r-test'] sources: ['ubuntu-toolchain-r-test']
packages: ['clang', 'g++-multilib', 'valgrind'] packages: ['clang', 'g++-multilib', 'valgrind', 'expect']
env: env:
- COMPILER=clang++ - COMPILER=clang++
- COMP=clang - COMP=clang
@@ -44,12 +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 #
# if valgrind is available check the build is without error, reduce depth to speedup testing, but not too shallow to catch more cases. # Verify bench number against various builds
- if [ -x "$(command -v valgrind )" ] ; then make clean && make ARCH=x86-64 debug=yes build && valgrind --error-exitcode=42 ./stockfish bench 128 1 10 default depth 1>/dev/null ; fi - export CXXFLAGS=-Werror
# use g++-6 as a proxy for having sanitizers ... might need revision as they become available for more recent versions of clang/gcc than trusty provides - make clean && make -j2 ARCH=x86-64 optimize=no debug=yes build && ../tests/signature.sh $benchref
- if [[ "$COMPILER" == "g++-6" ]]; then make clean && make ARCH=x86-64 sanitize=yes build && ! ./stockfish bench 2>&1 | grep "runtime error:" ; fi - 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
+9 -1
View File
@@ -10,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.
@@ -96,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
+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
+40 -14
View File
@@ -1,5 +1,5 @@
version: 1.0.{build} version: 1.0.{build}
clone_depth: 5 clone_depth: 50
branches: branches:
only: only:
@@ -13,10 +13,11 @@ os: Visual Studio 2015
platform: platform:
- x86 - x86
- x64 - x64
- Any CPU
# build Configuration, i.e. Debug, Release, etc. # build Configuration, i.e. Debug, Release, etc.
configuration: Debug configuration:
- Debug
- Release
matrix: matrix:
# The build fail immediately once one of the job fails # The build fail immediately once one of the job fails
@@ -28,18 +29,43 @@ init:
- msbuild /version - msbuild /version
before_build: before_build:
- cd src - ps: |
- echo project (Stockfish) >> CMakeLists.txt # Get sources
- echo add_executable(stockfish benchmark.cpp bitbase.cpp bitboard.cpp endgame.cpp evaluate.cpp >> CMakeLists.txt $src = get-childitem -Path *.cpp -Recurse | select -ExpandProperty FullName
- echo main.cpp material.cpp misc.cpp movegen.cpp movepick.cpp pawns.cpp position.cpp psqt.cpp >> CMakeLists.txt $src = $src -join ' '
- echo search.cpp thread.cpp timeman.cpp tt.cpp uci.cpp ucioption.cpp syzygy/tbprobe.cpp) >> CMakeLists.txt $src = $src.Replace("\", "/")
- echo set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/src) >> CMakeLists.txt
# - echo target_compile_options(stockfish PUBLIC "/Ox") >> CMakeLists.txt # 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: build_script:
- cmake -G "Visual Studio 14 2015 Win64" . - cmake --build . --config %CONFIGURATION% -- /verbosity:minimal
- cmake --build .
before_test: before_test:
- cd Debug - cd src/%CONFIGURATION%
- stockfish.exe bench > null - 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 }
+58 -43
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
@@ -50,7 +50,9 @@ 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 = yes/no --- (-fsanitize ) --- enable undefined behavior checks # 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
@@ -139,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)
@@ -155,9 +157,11 @@ ifeq ($(COMP),gcc)
ifeq ($(ARCH),armv7) ifeq ($(ARCH),armv7)
ifeq ($(OS),Android) ifeq ($(OS),Android)
CXXFLAGS += -m$(bits) CXXFLAGS += -m$(bits)
LDFLAGS += -m$(bits)
endif endif
else else
CXXFLAGS += -m$(bits) CXXFLAGS += -m$(bits)
LDFLAGS += -m$(bits)
endif endif
ifneq ($(KERNEL),Darwin) ifneq ($(KERNEL),Darwin)
@@ -200,6 +204,11 @@ ifeq ($(COMP),clang)
comp=clang comp=clang
CXX=clang++ CXX=clang++
CXXFLAGS += -pedantic -Wextra -Wshadow CXXFLAGS += -pedantic -Wextra -Wshadow
ifneq ($(KERNEL),Darwin)
ifneq ($(KERNEL),OpenBSD)
LDFLAGS += -latomic
endif
endif
ifeq ($(ARCH),armv7) ifeq ($(ARCH),armv7)
ifeq ($(OS),Android) ifeq ($(OS),Android)
@@ -210,23 +219,19 @@ ifeq ($(COMP),clang)
CXXFLAGS += -m$(bits) CXXFLAGS += -m$(bits)
LDFLAGS += -m$(bits) LDFLAGS += -m$(bits)
endif endif
ifeq ($(KERNEL),Darwin)
CXXFLAGS += -stdlib=libc++
DEPENDFLAGS += -stdlib=libc++
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 ($(KERNEL),Darwin) ifeq ($(KERNEL),Darwin)
@@ -263,8 +268,9 @@ else
endif endif
### 3.2.2 Debugging with undefined behavior sanitizers ### 3.2.2 Debugging with undefined behavior sanitizers
ifeq ($(sanitize),yes) ifneq ($(sanitize),no)
CXXFLAGS += -g3 -fsanitize=undefined CXXFLAGS += -g3 -fsanitize=$(sanitize) -fuse-ld=gold
LDFLAGS += -fsanitize=$(sanitize) -fuse-ld=gold
endif endif
### 3.3 Optimization ### 3.3 Optimization
@@ -296,10 +302,8 @@ ifeq ($(optimize),yes)
ifeq ($(comp),clang) ifeq ($(comp),clang)
ifeq ($(KERNEL),Darwin) ifeq ($(KERNEL),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
@@ -423,30 +427,27 @@ help:
@echo "" @echo ""
.PHONY: build profile-build .PHONY: help build profile-build strip install clean objclean profileclean help \
build: config-sanity icc-profile-use icc-profile-make gcc-profile-use gcc-profile-make \
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) config-sanity 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)
@@ -456,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
@@ -472,6 +484,7 @@ 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)'"
@@ -490,6 +503,7 @@ 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"
@@ -503,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) \
@@ -518,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
@@ -535,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
+38 -65
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",
@@ -79,28 +76,35 @@ const vector<string> Defaults = {
"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 // 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 - -", "8/8/8/8/8/6k1/6p1/6K1 w - -",
"5k2/5P2/5K2/8/8/8/8/8 b - -", "7k/7P/6K1/8/3B4/8/8/8 b - -",
"8/8/8/8/8/4k3/4p3/4K3 w - -",
"8/8/8/8/8/5K2/8/3Q1k2 b - -", // Chess 960
"7k/7P/6K1/8/3B4/8/8/8 b - -" "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";
@@ -109,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;
@@ -139,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))
@@ -149,35 +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);
Position pos; list.emplace_back("setoption name Hash value " + ttSize);
for (size_t i = 0; i < fens.size(); ++i)
{
StateListPtr states(new std::deque<StateInfo>(1));
pos.set(fens[i], Options["UCI_Chess960"], &states->back(), 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
{ {
limits.startTime = now(); list.emplace_back("position fen " + fen);
Threads.start_thinking(pos, states, limits); list.emplace_back(go);
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 exiting
cerr << "\n==========================="
<< "\nTotal time (ms) : " << elapsed
<< "\nNodes searched : " << nodes
<< "\nNodes/second : " << 1000 * nodes / elapsed << endl;
} }
+7 -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
@@ -111,13 +111,13 @@ 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
@@ -125,13 +125,13 @@ namespace {
&& rank_of(psq) == RANK_7 && rank_of(psq) == RANK_7
&& ksq[us] != psq + NORTH && ksq[us] != psq + NORTH
&& ( distance(ksq[~us], psq + NORTH) > 1 && ( distance(ksq[~us], psq + NORTH) > 1
|| (StepAttacksBB[KING][ksq[us]] & (psq + NORTH)))) || (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)]
+60 -67
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,29 +26,22 @@
uint8_t PopCnt16[1 << 16]; 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.
@@ -173,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)
@@ -191,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[] = { NORTH, EAST, SOUTH, WEST }; Direction RookDirections[] = { NORTH, EAST, SOUTH, WEST };
Square BishopDeltas[] = { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST }; 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]);
} }
} }
} }
@@ -231,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;
@@ -255,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)
{ {
@@ -277,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(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;
@@ -306,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((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); }
} }
} }
} }
+54 -53
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;
@@ -65,15 +66,41 @@ 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
@@ -99,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.
@@ -126,8 +152,8 @@ inline Bitboard file_bb(Square s) {
/// shift() moves a bitboard one step along direction D. Mainly for pawns /// shift() moves a bitboard one step along direction D. Mainly for pawns
template<Square D> template<Direction D>
inline Bitboard shift(Bitboard b) { constexpr Bitboard shift(Bitboard b) {
return D == NORTH ? b << 8 : D == SOUTH ? b >> 8 return D == NORTH ? b << 8 : D == SOUTH ? b >> 8
: D == NORTH_EAST ? (b & ~FileHBB) << 9 : D == SOUTH_EAST ? (b & ~FileHBB) >> 7 : D == NORTH_EAST ? (b & ~FileHBB) << 9 : D == SOUTH_EAST ? (b & ~FileHBB) >> 7
: D == NORTH_WEST ? (b & ~FileABB) << 7 : D == SOUTH_WEST ? (b & ~FileABB) >> 9 : D == NORTH_WEST ? (b & ~FileABB) << 7 : D == SOUTH_WEST ? (b & ~FileABB) >> 9
@@ -153,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];
@@ -183,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];
@@ -210,50 +236,25 @@ 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) {
extern Bitboard RookMasks[SQUARE_NB];
extern Bitboard RookMagics[SQUARE_NB];
extern unsigned RookShifts[SQUARE_NB];
extern Bitboard BishopMasks[SQUARE_NB];
extern Bitboard BishopMagics[SQUARE_NB];
extern unsigned BishopShifts[SQUARE_NB];
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) {
extern Bitboard* RookAttacks[SQUARE_NB]; const Magic& m = Pt == ROOK ? RookMagics[s] : BishopMagics[s];
extern Bitboard* BishopAttacks[SQUARE_NB]; return m.attacks[m.index(occupied)];
return (Pt == ROOK ? RookAttacks : BishopAttacks)[s][magic_index<Pt>(s, 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];
} }
} }
@@ -291,7 +292,7 @@ inline Square lsb(Bitboard b) {
inline Square msb(Bitboard b) { inline Square msb(Bitboard b) {
assert(b); assert(b);
return Square(63 - __builtin_clzll(b)); return Square(63 ^ __builtin_clzll(b));
} }
#elif defined(_WIN64) && defined(_MSC_VER) #elif defined(_WIN64) && defined(_MSC_VER)
+13 -42
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
@@ -83,26 +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";
StateInfo st;
return Position().set(fen, false, &st, 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;
@@ -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:
+451 -426
View File
File diff suppressed because it is too large Load Diff
+3 -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,9 +31,10 @@ namespace Eval {
const Value Tempo = Value(20); // Must be visible to search const Value Tempo = Value(20); // Must be visible to search
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);
} }
+4 -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
@@ -43,12 +43,13 @@ int main(int argc, char* argv[]) {
Bitbases::init(); Bitbases::init();
Search::init(); Search::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;
} }
+13 -10
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
@@ -35,11 +35,11 @@ namespace {
// OUR PIECES // OUR PIECES
// pair pawn knight bishop rook queen // pair pawn knight bishop rook queen
{1667 }, // 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] = {
@@ -50,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
@@ -91,7 +91,7 @@ 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])
@@ -129,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
@@ -150,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;
} }
@@ -166,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))
+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
@@ -56,11 +56,11 @@ struct Entry {
} }
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;
}; };
+136 -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
@@ -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 = "8"; 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;
@@ -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
+13 -1
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,6 +31,7 @@
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 prefetch2(void* addr);
void start_logger(const std::string& fname); void start_logger(const std::string& fname);
void dbg_hit_on(bool b); void dbg_hit_on(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
+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
@@ -42,8 +42,8 @@ namespace {
assert(!pos.checkers()); assert(!pos.checkers());
const Square K = Chess960 ? kto > kfrom ? WEST : EAST const Direction K = Chess960 ? kto > kfrom ? WEST : EAST
: KingSide ? WEST : EAST; : 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)
@@ -65,7 +65,7 @@ namespace {
} }
template<GenType Type, Square D> template<GenType Type, Direction D>
ExtMove* make_promotions(ExtMove* moveList, Square to, Square ksq) { 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)
@@ -80,7 +80,7 @@ namespace {
// 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] & ksq)) if (Type == QUIET_CHECKS && (PseudoAttacks[KNIGHT][to] & ksq))
*moveList++ = make<PROMOTION>(to - D, to, KNIGHT); *moveList++ = make<PROMOTION>(to - D, to, KNIGHT);
else else
(void)ksq; // Silence a warning under MSVC (void)ksq; // Silence a warning under MSVC
@@ -94,13 +94,13 @@ namespace {
// 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 ? NORTH : SOUTH); const Direction Up = (Us == WHITE ? NORTH : SOUTH);
const Square Right = (Us == WHITE ? NORTH_EAST : SOUTH_WEST); const Direction Right = (Us == WHITE ? NORTH_EAST : SOUTH_WEST);
const Square Left = (Us == WHITE ? NORTH_WEST : SOUTH_EAST); const Direction Left = (Us == WHITE ? NORTH_WEST : SOUTH_EAST);
Bitboard emptySquares; Bitboard emptySquares;
@@ -346,7 +346,7 @@ 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][pos.square<KING>(~us)]; b &= ~PseudoAttacks[QUEEN][pos.square<KING>(~us)];
+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:
+77 -93
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 <cassert> #include <cassert>
#include "movepick.h" #include "movepick.h"
#include "thread.h"
namespace { namespace {
@@ -34,27 +33,28 @@ namespace {
QSEARCH_RECAPTURES, QRECAPTURES QSEARCH_RECAPTURES, QRECAPTURES
}; };
// 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
@@ -66,21 +66,22 @@ namespace {
/// 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, Search::Stack* s) /// MovePicker constructor for the main search
: pos(p), ss(s), depth(d) { MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh,
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);
Square prevSq = to_sq((ss-1)->currentMove);
countermove = pos.this_thread()->counterMoves[pos.piece_on(prevSq)][prevSq];
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;
stage += (ttMove == MOVE_NONE); stage += (ttMove == MOVE_NONE);
} }
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, Square s) /// MovePicker constructor for quiescence search
: pos(p) { MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh, const CapturePieceToHistory* cph, Square s)
: pos(p), mainHistory(mh), captureHistory(cph) {
assert(d <= DEPTH_ZERO); assert(d <= DEPTH_ZERO);
@@ -104,81 +105,57 @@ MovePicker::MovePicker(const Position& p, Move ttm, Depth d, Square s)
stage += (ttMove == MOVE_NONE); stage += (ttMove == MOVE_NONE);
} }
MovePicker::MovePicker(const Position& p, Move ttm, Value th) /// MovePicker constructor for ProbCut: we generate captures with SEE higher
: pos(p), 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_ge(ttm, threshold + 1)? ttm : MOVE_NONE; && pos.see_ge(ttm, threshold) ? ttm : MOVE_NONE;
stage += (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 the 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>() {
const HistoryStats& history = pos.this_thread()->history;
const FromToStats& fromTo = pos.this_thread()->fromTo;
const CounterMoveStats* cm = (ss-1)->counterMoves;
const CounterMoveStats* fm = (ss-2)->counterMoves;
const CounterMoveStats* f2 = (ss-4)->counterMoves;
Color c = pos.side_to_move();
for (auto& m : *this) for (auto& m : *this)
m.value = history[pos.moved_piece(m)][to_sq(m)] if (Type == CAPTURES)
+ (cm ? (*cm)[pos.moved_piece(m)][to_sq(m)] : VALUE_ZERO)
+ (fm ? (*fm)[pos.moved_piece(m)][to_sq(m)] : VALUE_ZERO)
+ (f2 ? (*f2)[pos.moved_piece(m)][to_sq(m)] : VALUE_ZERO)
+ fromTo.get(c, m);
}
template<>
void MovePicker::score<EVASIONS>() {
// Try captures ordered by MVV/LVA, then non-captures ordered by history value
const HistoryStats& history = pos.this_thread()->history;
const FromToStats& fromTo = pos.this_thread()->fromTo;
Color c = pos.side_to_move();
for (auto& m : *this)
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)] + fromTo.get(c, 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);
}
}
/// 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;
@@ -194,6 +171,7 @@ Move MovePicker::next_move() {
endMoves = generate<CAPTURES>(pos, cur); endMoves = generate<CAPTURES>(pos, cur);
score<CAPTURES>(); score<CAPTURES>();
++stage; ++stage;
/* fallthrough */
case GOOD_CAPTURES: case GOOD_CAPTURES:
while (cur < endMoves) while (cur < endMoves)
@@ -201,7 +179,7 @@ Move MovePicker::next_move() {
move = pick_best(cur++, endMoves); move = pick_best(cur++, endMoves);
if (move != ttMove) if (move != ttMove)
{ {
if (pos.see_ge(move, VALUE_ZERO)) if (pos.see_ge(move, Value(-55 * (cur-1)->value / 1024)))
return move; return move;
// Losing capture, move it to the beginning of the array // Losing capture, move it to the beginning of the array
@@ -210,58 +188,59 @@ Move MovePicker::next_move() {
} }
++stage; ++stage;
move = ss->killers[0]; // First killer move 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;
/* fallthrough */
case KILLERS: case KILLERS:
++stage; ++stage;
move = ss->killers[1]; // Second killer move move = killers[1]; // Second 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;
/* fallthrough */
case COUNTERMOVE: case COUNTERMOVE:
++stage; ++stage;
move = countermove; move = countermove;
if ( move != MOVE_NONE if ( move != MOVE_NONE
&& move != ttMove && move != ttMove
&& move != ss->killers[0] && move != killers[0]
&& move != ss->killers[1] && move != killers[1]
&& pos.pseudo_legal(move) && pos.pseudo_legal(move)
&& !pos.capture(move)) && !pos.capture(move))
return move; return move;
/* fallthrough */
case QUIET_INIT: case QUIET_INIT:
cur = endBadCaptures; cur = endBadCaptures;
endMoves = generate<QUIETS>(pos, cur); endMoves = generate<QUIETS>(pos, cur);
score<QUIETS>(); score<QUIETS>();
if (depth < 3 * ONE_PLY) partial_insertion_sort(cur, endMoves, -4000 * depth / ONE_PLY);
{
ExtMove* goodQuiet = std::partition(cur, endMoves, [](const ExtMove& m)
{ return m.value > VALUE_ZERO; });
insertion_sort(cur, goodQuiet);
} else
insertion_sort(cur, endMoves);
++stage; ++stage;
/* fallthrough */
case QUIET: case QUIET:
while (cur < endMoves) while ( cur < endMoves
&& (!skipQuiets || cur->value >= VALUE_ZERO))
{ {
move = *cur++; move = *cur++;
if ( move != ttMove if ( move != ttMove
&& move != ss->killers[0] && move != killers[0]
&& move != ss->killers[1] && move != killers[1]
&& move != countermove) && move != countermove)
return move; return move;
} }
++stage; ++stage;
cur = moves; // Point to beginning of bad captures cur = moves; // Point to beginning of bad captures
/* fallthrough */
case BAD_CAPTURES: case BAD_CAPTURES:
if (cur < endBadCaptures) if (cur < endBadCaptures)
@@ -273,6 +252,7 @@ Move MovePicker::next_move() {
endMoves = generate<EVASIONS>(pos, cur); endMoves = generate<EVASIONS>(pos, cur);
score<EVASIONS>(); score<EVASIONS>();
++stage; ++stage;
/* fallthrough */
case ALL_EVASIONS: case ALL_EVASIONS:
while (cur < endMoves) while (cur < endMoves)
@@ -288,13 +268,14 @@ Move MovePicker::next_move() {
endMoves = generate<CAPTURES>(pos, cur); endMoves = generate<CAPTURES>(pos, cur);
score<CAPTURES>(); score<CAPTURES>();
++stage; ++stage;
/* fallthrough */
case PROBCUT_CAPTURES: case PROBCUT_CAPTURES:
while (cur < endMoves) while (cur < endMoves)
{ {
move = pick_best(cur++, endMoves); move = pick_best(cur++, endMoves);
if ( move != ttMove if ( move != ttMove
&& pos.see_ge(move, threshold + 1)) && pos.see_ge(move, threshold))
return move; return move;
} }
break; break;
@@ -304,6 +285,7 @@ Move MovePicker::next_move() {
endMoves = generate<CAPTURES>(pos, cur); endMoves = generate<CAPTURES>(pos, cur);
score<CAPTURES>(); score<CAPTURES>();
++stage; ++stage;
/* fallthrough */
case QCAPTURES_1: case QCAPTURES_2: case QCAPTURES_1: case QCAPTURES_2:
while (cur < endMoves) while (cur < endMoves)
@@ -317,6 +299,7 @@ Move MovePicker::next_move() {
cur = moves; cur = moves;
endMoves = generate<QUIET_CHECKS>(pos, cur); endMoves = generate<QUIET_CHECKS>(pos, cur);
++stage; ++stage;
/* fallthrough */
case QCHECKS: case QCHECKS:
while (cur < endMoves) while (cur < endMoves)
@@ -332,6 +315,7 @@ Move MovePicker::next_move() {
endMoves = generate<CAPTURES>(pos, cur); endMoves = generate<CAPTURES>(pos, cur);
score<CAPTURES>(); score<CAPTURES>();
++stage; ++stage;
/* fallthrough */
case QRECAPTURES: case QRECAPTURES:
while (cur < endMoves) while (cur < endMoves)
+89 -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
@@ -21,68 +21,98 @@
#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 "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) { table[pc][to] = m; }
void update(Piece pc, Square to, Value v) {
if (abs(int(v)) >= 324)
return;
table[pc][to] -= table[pc][to] * abs(int(v)) / (CM ? 936 : 324);
table[pc][to] += int(v) * 32;
} }
private: void update(T& entry, int bonus, const int D) {
T table[PIECE_NB][SQUARE_NB];
assert(abs(bonus) <= D); // Ensure range is [-32 * D, 32 * D]
assert(abs(32 * D) < (std::numeric_limits<T>::max)()); // Ensure we don't overflow
entry += bonus * 32 - entry * abs(bonus) / D;
assert(abs(entry) <= 32 * D);
}
}; };
typedef Stats<Move> MoveStats; /// 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> CounterMoveStats; struct StatCubes : public std::array<std::array<std::array<T, Size3>, Size2>, Size1> {
typedef Stats<CounterMoveStats> CounterMoveHistoryStats;
struct FromToStats { void fill(const T& v) {
T* p = &(*this)[0][0][0];
Value get(Color c, Move m) const { return table[c][from_sq(m)][to_sq(m)]; } std::fill(p, p + sizeof(*this) / sizeof(*p), v);
void clear() { std::memset(table, 0, sizeof(table)); }
void update(Color c, Move m, Value v) {
if (abs(int(v)) >= 324)
return;
Square from = from_sq(m);
Square to = to_sq(m);
table[c][from][to] -= table[c][from][to] * abs(int(v)) / 324;
table[c][from][to] += int(v) * 32;
} }
private: void update(T& entry, int bonus, const int D, const int W) {
Value table[COLOR_NB][SQUARE_NB][SQUARE_NB];
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
/// current position. The most important method is next_move(), which returns a /// current position. The most important method is next_move(), which returns a
@@ -90,18 +120,15 @@ private:
/// when MOVE_NONE is returned. In order to improve the efficiency of the alpha /// when MOVE_NONE is returned. In order to improve the efficiency of the alpha
/// beta algorithm, MovePicker attempts to return the moves which are most likely /// beta algorithm, MovePicker attempts to return the moves which are most likely
/// to get a cut-off first. /// to get a cut-off first.
namespace Search { struct Stack; }
class MovePicker { 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, Value); MovePicker(const Position&, Move, Depth, const ButterflyHistory*, const CapturePieceToHistory*, Square);
MovePicker(const Position&, Move, Depth, Square); MovePicker(const Position&, Move, Depth, const ButterflyHistory*, const CapturePieceToHistory*, const PieceToHistory**, Move, Move*);
MovePicker(const Position&, Move, Depth, Search::Stack*); Move next_move(bool skipQuiets = false);
Move next_move();
private: private:
template<GenType> void score(); template<GenType> void score();
@@ -109,14 +136,15 @@ private:
ExtMove* end() { return endMoves; } ExtMove* end() { return endMoves; }
const Position& pos; const Position& pos;
const Search::Stack* ss; const ButterflyHistory* mainHistory;
Move countermove; const CapturePieceToHistory* captureHistory;
Depth depth; const PieceToHistory** contHistory;
Move ttMove; Move ttMove, countermove, killers[2];
ExtMove *cur, *endMoves, *endBadCaptures;
int stage;
Square recaptureSquare; Square recaptureSquare;
Value threshold; Value threshold;
int stage; Depth depth;
ExtMove *cur, *endMoves, *endBadCaptures;
ExtMove moves[MAX_MOVES]; ExtMove moves[MAX_MOVES];
}; };
+89 -81
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,53 +31,51 @@ 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 // Isolated pawn penalty
const Score Isolated[2] = { S(45, 40), S(30, 27) }; const Score Isolated = S(13, 18);
// Backward pawn penalty by opposed flag // Backward pawn penalty
const Score Backward[2] = { S(56, 33), S(41, 19) }; 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(17, 8); Score Connected[2][2][3][RANK_NB];
// Connected pawn bonus by opposed, phalanx, twice supported and rank
Score Connected[2][2][2][RANK_NB];
// Doubled pawn penalty // Doubled pawn penalty
const Score Doubled = S(18,38); const Score Doubled = S(18, 38);
// Lever bonus by rank // Weakness of our pawn shelter in front of the king by [isKingFile][distance from edge][rank].
const Score Lever[RANK_NB] = { // RANK_1 = 0 is used for files where we have no pawns or our pawn is behind our king.
S( 0, 0), S( 0, 0), S(0, 0), S(0, 0), const Value ShelterWeakness[][int(FILE_NB) / 2][RANK_NB] = {
S(17, 16), S(33, 32), S(0, 0), S(0, 0) { { 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) } }
}; };
// Weakness of our pawn shelter in front of the king by [distance from edge][rank] // Danger of enemy pawns moving toward our king by [type][distance from edge][rank].
const Value ShelterWeakness[][RANK_NB] = { // For the unopposed and unblocked cases, RANK_1 = 0 is used when opponent has
{ V( 97), V(21), V(26), V(51), V(87), V( 89), V( 99) }, // no pawn on the given file, or their pawn is behind our king.
{ 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
@@ -90,22 +88,22 @@ 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 ? NORTH : SOUTH); const Direction Up = (Us == WHITE ? NORTH : SOUTH);
const Square Right = (Us == WHITE ? NORTH_EAST : SOUTH_WEST); const Direction Right = (Us == WHITE ? NORTH_EAST : SOUTH_WEST);
const Square Left = (Us == WHITE ? NORTH_WEST : SOUTH_EAST); const Direction Left = (Us == WHITE ? NORTH_WEST : SOUTH_EAST);
Bitboard b, neighbours, stoppers, doubled, supported, phalanx; Bitboard b, neighbours, stoppers, doubled, supported, phalanx;
Bitboard lever, leverPush;
Square s; Square s;
bool opposed, lever, connected, backward; 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->semiopenFiles[Us] = 0xFF; e->semiopenFiles[Us] = 0xFF;
e->kingSquares[Us] = SQ_NONE; e->kingSquares[Us] = SQ_NONE;
e->pawnAttacks[Us] = shift<Right>(ourPawns) | shift<Left>(ourPawns); e->pawnAttacks[Us] = shift<Right>(ourPawns) | shift<Left>(ourPawns);
@@ -123,14 +121,14 @@ namespace {
e->pawnAttacksSpan[Us] |= pawn_attack_span(Us, s); e->pawnAttacksSpan[Us] |= pawn_attack_span(Us, s);
// Flag the pawn // Flag the pawn
opposed = theirPawns & forward_bb(Us, s); opposed = theirPawns & forward_file_bb(Us, s);
stoppers = theirPawns & passed_pawn_mask(Us, s); stoppers = theirPawns & passed_pawn_mask(Us, s);
lever = theirPawns & pawnAttacksBB[s]; lever = theirPawns & PawnAttacks[Us][s];
doubled = ourPawns & (s + Up); leverPush = theirPawns & PawnAttacks[Us][s + Up];
doubled = ourPawns & (s - Up);
neighbours = ourPawns & adjacent_files_bb(f); neighbours = ourPawns & adjacent_files_bb(f);
phalanx = neighbours & rank_bb(s); phalanx = neighbours & rank_bb(s);
supported = neighbours & rank_bb(s - Up); supported = neighbours & rank_bb(s - Up);
connected = supported | phalanx;
// A pawn is backward when it is behind all pawns of the same color on the // A pawn is backward when it is behind all pawns of the same color on the
// adjacent files and cannot be safely advanced. // adjacent files and cannot be safely advanced.
@@ -146,32 +144,40 @@ namespace {
// stopper on adjacent file which controls the way to that rank. // stopper on adjacent file which controls the way to that rank.
backward = (b | shift<Up>(b & adjacent_files_bb(f))) & stoppers; backward = (b | shift<Up>(b & adjacent_files_bb(f))) & stoppers;
assert(!backward || !(pawn_attack_span(Them, s + Up) & neighbours)); assert(!(backward && (forward_ranks_bb(Them, s + Up) & neighbours)));
} }
// 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. // full attack info to evaluate them. Include also not passed pawns
if (!stoppers && !(ourPawns & forward_bb(Us, s))) // which could become passed after one or two pawn pushes when are
// 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 (!neighbours) if (supported | phalanx)
score -= Isolated[opposed]; 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;
if (connected)
score += Connected[opposed][!!phalanx][more_than_one(supported)][relative_rank(Us, s)];
if (doubled)
score -= Doubled; score -= Doubled;
if (lever)
score += Lever[relative_rank(Us, s)];
} }
return score; return score;
@@ -187,16 +193,17 @@ namespace Pawns {
void init() { void init() {
static const int Seed[RANK_NB] = { 0, 8, 19, 13, 71, 94, 169, 324 }; 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(v, v * 5 / 8);
Connected[opposed][phalanx][support][r] = make_score(v, v * (r - 2) / 4);
} }
} }
@@ -223,35 +230,36 @@ Entry* probe(const Position& pos) {
/// 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;
+4 -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
@@ -37,6 +37,7 @@ 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 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 open_files() const { return openFiles; }
@@ -49,7 +50,7 @@ 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>
@@ -71,6 +72,7 @@ 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 pawnsOnSquares[COLOR_NB][COLOR_NB]; // [color][light/dark squares] int pawnsOnSquares[COLOR_NB][COLOR_NB]; // [color][light/dark squares]
+177 -132
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
@@ -32,6 +32,7 @@
#include "thread.h" #include "thread.h"
#include "tt.h" #include "tt.h"
#include "uci.h" #include "uci.h"
#include "syzygy/tbprobe.h"
using std::string; using std::string;
@@ -44,14 +45,17 @@ namespace Zobrist {
Key psq[PIECE_NB][SQUARE_NB]; Key psq[PIECE_NB][SQUARE_NB];
Key enpassant[FILE_NB]; Key enpassant[FILE_NB];
Key castling[CASTLING_RIGHT_NB]; Key castling[CASTLING_RIGHT_NB];
Key side; Key side, noPawns;
} }
namespace { namespace {
const string PieceToChar(" PNBRQK pnbrqk"); const string PieceToChar(" PNBRQK pnbrqk");
// min_attacker() is a helper function used by see() to locate the least const Piece Pieces[] = { W_PAWN, W_KNIGHT, W_BISHOP, W_ROOK, W_QUEEN, W_KING,
B_PAWN, B_KNIGHT, B_BISHOP, B_ROOK, B_QUEEN, B_KING };
// min_attacker() is a helper function used by see_ge() to locate the least
// valuable attacker for the side to move, remove the attacker we just found // valuable attacker for the side to move, remove the attacker we just found
// from the bitboards and scan for new X-ray attacks behind it. // from the bitboards and scan for new X-ray attacks behind it.
@@ -61,7 +65,7 @@ PieceType min_attacker(const Bitboard* bb, Square to, Bitboard stmAttackers,
Bitboard b = stmAttackers & bb[Pt]; Bitboard b = stmAttackers & bb[Pt];
if (!b) if (!b)
return min_attacker<Pt+1>(bb, to, stmAttackers, occupied, attackers); return min_attacker<Pt + 1>(bb, to, stmAttackers, occupied, attackers);
occupied ^= b & ~(b - 1); occupied ^= b & ~(b - 1);
@@ -98,11 +102,25 @@ std::ostream& operator<<(std::ostream& os, const Position& pos) {
} }
os << "\nFen: " << pos.fen() << "\nKey: " << std::hex << std::uppercase os << "\nFen: " << pos.fen() << "\nKey: " << std::hex << std::uppercase
<< std::setfill('0') << std::setw(16) << pos.key() << std::dec << "\nCheckers: "; << std::setfill('0') << std::setw(16) << pos.key()
<< std::setfill(' ') << std::dec << "\nCheckers: ";
for (Bitboard b = pos.checkers(); b; ) for (Bitboard b = pos.checkers(); b; )
os << UCI::square(pop_lsb(&b)) << " "; os << UCI::square(pop_lsb(&b)) << " ";
if ( int(Tablebases::MaxCardinality) >= popcount(pos.pieces())
&& !pos.can_castle(ANY_CASTLING))
{
StateInfo st;
Position p;
p.set(pos.fen(), pos.is_chess960(), &st, pos.this_thread());
Tablebases::ProbeState s1, s2;
Tablebases::WDLScore wdl = Tablebases::probe_wdl(p, &s1);
int dtz = Tablebases::probe_dtz(p, &s2);
os << "\nTablebases WDL: " << std::setw(4) << wdl << " (" << s1 << ")"
<< "\nTablebases DTZ: " << std::setw(4) << dtz << " (" << s2 << ")";
}
return os; return os;
} }
@@ -133,6 +151,7 @@ void Position::init() {
} }
Zobrist::side = rng.rand<Key>(); Zobrist::side = rng.rand<Key>();
Zobrist::noPawns = rng.rand<Key>();
} }
@@ -164,8 +183,9 @@ Position& Position::set(const string& fenStr, bool isChess960, StateInfo* si, Th
4) En passant target square (in algebraic notation). If there's no en passant 4) En passant target square (in algebraic notation). If there's no en passant
target square, this is "-". If a pawn has just made a 2-square move, this target square, this is "-". If a pawn has just made a 2-square move, this
is the position "behind" the pawn. This is recorded regardless of whether is the position "behind" the pawn. This is recorded only if there is a pawn
there is a pawn in position to make an en passant capture. in position to make an en passant capture, and if there really is a pawn
that might have advanced two squares.
5) Halfmove clock. This is the number of halfmoves since the last pawn advance 5) Halfmove clock. This is the number of halfmoves since the last pawn advance
or capture. This is used to determine if a draw can be claimed under the or capture. This is used to determine if a draw can be claimed under the
@@ -191,10 +211,10 @@ Position& Position::set(const string& fenStr, bool isChess960, StateInfo* si, Th
while ((ss >> token) && !isspace(token)) while ((ss >> token) && !isspace(token))
{ {
if (isdigit(token)) if (isdigit(token))
sq += Square(token - '0'); // Advance the given number of files sq += (token - '0') * EAST; // Advance the given number of files
else if (token == '/') else if (token == '/')
sq -= Square(16); sq += 2 * SOUTH;
else if ((idx = PieceToChar.find(token)) != string::npos) else if ((idx = PieceToChar.find(token)) != string::npos)
{ {
@@ -242,7 +262,8 @@ Position& Position::set(const string& fenStr, bool isChess960, StateInfo* si, Th
{ {
st->epSquare = make_square(File(col - 'a'), Rank(row - '1')); st->epSquare = make_square(File(col - 'a'), Rank(row - '1'));
if (!(attackers_to(st->epSquare) & pieces(sideToMove, PAWN))) if ( !(attackers_to(st->epSquare) & pieces(sideToMove, PAWN))
|| !(pieces(~sideToMove, PAWN) & (st->epSquare + pawn_push(~sideToMove))))
st->epSquare = SQ_NONE; st->epSquare = SQ_NONE;
} }
else else
@@ -251,7 +272,7 @@ Position& Position::set(const string& fenStr, bool isChess960, StateInfo* si, Th
// 5-6. Halfmove clock and fullmove number // 5-6. Halfmove clock and fullmove number
ss >> std::skipws >> st->rule50 >> gamePly; ss >> std::skipws >> st->rule50 >> gamePly;
// Convert from fullmove starting from 1 to ply starting from 0, // Convert from fullmove starting from 1 to gamePly starting from 0,
// handle also common incorrect FEN with fullmove = 0. // handle also common incorrect FEN with fullmove = 0.
gamePly = std::max(2 * (gamePly - 1), 0) + (sideToMove == BLACK); gamePly = std::max(2 * (gamePly - 1), 0) + (sideToMove == BLACK);
@@ -317,7 +338,8 @@ void Position::set_check_info(StateInfo* si) const {
void Position::set_state(StateInfo* si) const { void Position::set_state(StateInfo* si) const {
si->key = si->pawnKey = si->materialKey = 0; si->key = si->materialKey = 0;
si->pawnKey = Zobrist::noPawns;
si->nonPawnMaterial[WHITE] = si->nonPawnMaterial[BLACK] = VALUE_ZERO; si->nonPawnMaterial[WHITE] = si->nonPawnMaterial[BLACK] = VALUE_ZERO;
si->psq = SCORE_ZERO; si->psq = SCORE_ZERO;
si->checkersBB = attackers_to(square<KING>(sideToMove)) & pieces(~sideToMove); si->checkersBB = attackers_to(square<KING>(sideToMove)) & pieces(~sideToMove);
@@ -357,6 +379,27 @@ void Position::set_state(StateInfo* si) const {
} }
/// Position::set() is an overload to initialize the position object with
/// the given endgame code string like "KBPKN". It is mainly a helper to
/// get the material key out of an endgame code.
Position& Position::set(const string& code, Color c, StateInfo* si) {
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 fenStr = "8/" + sides[0] + char(8 - sides[0].length() + '0') + "/8/8/8/8/"
+ sides[1] + char(8 - sides[1].length() + '0') + "/8 w - - 0 10";
return set(fenStr, false, si, nullptr);
}
/// Position::fen() returns a FEN representation of the position. In case of /// Position::fen() returns a FEN representation of the position. In case of
/// Chess960 the Shredder-FEN notation is used. This is mainly a debugging function. /// Chess960 the Shredder-FEN notation is used. This is mainly a debugging function.
@@ -407,19 +450,6 @@ const string Position::fen() const {
} }
/// Position::game_phase() calculates the game phase interpolating total non-pawn
/// material between endgame and midgame limits.
Phase Position::game_phase() const {
Value npm = st->nonPawnMaterial[WHITE] + st->nonPawnMaterial[BLACK];
npm = std::max(EndgameLimit, std::min(npm, MidgameLimit));
return Phase(((npm - EndgameLimit) * PHASE_MIDGAME) / (MidgameLimit - EndgameLimit));
}
/// Position::slider_blockers() returns a bitboard of all the pieces (both colors) /// Position::slider_blockers() returns a bitboard of all the pieces (both colors)
/// that are blocking attacks on the square 's' from 'sliders'. A piece blocks a /// that are blocking attacks on the square 's' from 'sliders'. A piece blocks a
/// slider if removing that piece from the board would result in a position where /// slider if removing that piece from the board would result in a position where
@@ -433,7 +463,7 @@ Bitboard Position::slider_blockers(Bitboard sliders, Square s, Bitboard& pinners
pinners = 0; pinners = 0;
// Snipers are sliders that attack 's' when a piece is removed // Snipers are sliders that attack 's' when a piece is removed
Bitboard snipers = ( (PseudoAttacks[ROOK ][s] & pieces(QUEEN, ROOK)) Bitboard snipers = ( (PseudoAttacks[ ROOK][s] & pieces(QUEEN, ROOK))
| (PseudoAttacks[BISHOP][s] & pieces(QUEEN, BISHOP))) & sliders; | (PseudoAttacks[BISHOP][s] & pieces(QUEEN, BISHOP))) & sliders;
while (snipers) while (snipers)
@@ -460,7 +490,7 @@ Bitboard Position::attackers_to(Square s, Bitboard occupied) const {
return (attacks_from<PAWN>(s, BLACK) & pieces(WHITE, PAWN)) return (attacks_from<PAWN>(s, BLACK) & pieces(WHITE, PAWN))
| (attacks_from<PAWN>(s, WHITE) & pieces(BLACK, PAWN)) | (attacks_from<PAWN>(s, WHITE) & pieces(BLACK, PAWN))
| (attacks_from<KNIGHT>(s) & pieces(KNIGHT)) | (attacks_from<KNIGHT>(s) & pieces(KNIGHT))
| (attacks_bb<ROOK >(s, occupied) & pieces(ROOK, QUEEN)) | (attacks_bb< ROOK>(s, occupied) & pieces( ROOK, QUEEN))
| (attacks_bb<BISHOP>(s, occupied) & pieces(BISHOP, QUEEN)) | (attacks_bb<BISHOP>(s, occupied) & pieces(BISHOP, QUEEN))
| (attacks_from<KING>(s) & pieces(KING)); | (attacks_from<KING>(s) & pieces(KING));
} }
@@ -554,7 +584,7 @@ bool Position::pseudo_legal(const Move m) const {
&& empty(to - pawn_push(us)))) && empty(to - pawn_push(us))))
return false; return false;
} }
else if (!(attacks_from(pc, from) & to)) else if (!(attacks_from(type_of(pc), from) & to))
return false; return false;
// Evasions generator already takes care to avoid some kind of illegal moves // Evasions generator already takes care to avoid some kind of illegal moves
@@ -607,7 +637,7 @@ bool Position::gives_check(Move m) const {
return false; return false;
case PROMOTION: case PROMOTION:
return attacks_bb(Piece(promotion_type(m)), to, pieces() ^ from) & square<KING>(~sideToMove); return attacks_bb(promotion_type(m), to, pieces() ^ from) & square<KING>(~sideToMove);
// En passant capture with check? We have already handled the case // En passant capture with check? We have already handled the case
// of direct checks and ordinary discovered check, so the only case we // of direct checks and ordinary discovered check, so the only case we
@@ -647,7 +677,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
assert(is_ok(m)); assert(is_ok(m));
assert(&newSt != st); assert(&newSt != st);
++nodes; thisThread->nodes.fetch_add(1, std::memory_order_relaxed);
Key k = st->key ^ Zobrist::side; Key k = st->key ^ Zobrist::side;
// Copy some fields of the old state to our new StateInfo object except the // Copy some fields of the old state to our new StateInfo object except the
@@ -757,7 +787,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
if ( (int(to) ^ int(from)) == 16 if ( (int(to) ^ int(from)) == 16
&& (attacks_from<PAWN>(to - pawn_push(us), us) & pieces(them, PAWN))) && (attacks_from<PAWN>(to - pawn_push(us), us) & pieces(them, PAWN)))
{ {
st->epSquare = (from + to) / 2; st->epSquare = to - pawn_push(us);
k ^= Zobrist::enpassant[file_of(st->epSquare)]; k ^= Zobrist::enpassant[file_of(st->epSquare)];
} }
@@ -786,7 +816,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
// Update pawn hash key and prefetch access to pawnsTable // Update pawn hash key and prefetch access to pawnsTable
st->pawnKey ^= Zobrist::psq[pc][from] ^ Zobrist::psq[pc][to]; st->pawnKey ^= Zobrist::psq[pc][from] ^ Zobrist::psq[pc][to];
prefetch(thisThread->pawnsTable[st->pawnKey]); prefetch2(thisThread->pawnsTable[st->pawnKey]);
// Reset rule 50 draw counter // Reset rule 50 draw counter
st->rule50 = 0; st->rule50 = 0;
@@ -956,18 +986,16 @@ Key Position::key_after(Move m) const {
/// Position::see_ge (Static Exchange Evaluation Greater or Equal) tests if the /// Position::see_ge (Static Exchange Evaluation Greater or Equal) tests if the
/// SEE value of move is greater or equal to the given value. We'll use an /// SEE value of move is greater or equal to the given threshold. We'll use an
/// algorithm similar to alpha-beta pruning with a null window. /// algorithm similar to alpha-beta pruning with a null window.
bool Position::see_ge(Move m, Value v) const { bool Position::see_ge(Move m, Value threshold) const {
assert(is_ok(m)); assert(is_ok(m));
// Castling moves are implemented as king capturing the rook so cannot be // Only deal with normal moves, assume others pass a simple see
// handled correctly. Simply assume the SEE value is VALUE_ZERO that is always if (type_of(m) != NORMAL)
// correct unless in the rare case the rook ends up under attack. return VALUE_ZERO >= threshold;
if (type_of(m) == CASTLING)
return VALUE_ZERO >= v;
Square from = from_sq(m), to = to_sq(m); Square from = from_sq(m), to = to_sq(m);
PieceType nextVictim = type_of(piece_on(from)); PieceType nextVictim = type_of(piece_on(from));
@@ -975,30 +1003,22 @@ bool Position::see_ge(Move m, Value v) const {
Value balance; // Values of the pieces taken by us minus opponent's ones Value balance; // Values of the pieces taken by us minus opponent's ones
Bitboard occupied, stmAttackers; Bitboard occupied, stmAttackers;
if (type_of(m) == ENPASSANT) // The opponent may be able to recapture so this is the best result
{ // we can hope for.
occupied = SquareBB[to - pawn_push(~stm)]; // Remove the captured pawn balance = PieceValue[MG][piece_on(to)] - threshold;
balance = PieceValue[MG][PAWN];
}
else
{
balance = PieceValue[MG][piece_on(to)];
occupied = 0;
}
if (balance < v) if (balance < VALUE_ZERO)
return false; return false;
if (nextVictim == KING) // Now assume the worst possible result: that the opponent can
return true; // capture our piece for free.
balance -= PieceValue[MG][nextVictim]; balance -= PieceValue[MG][nextVictim];
if (balance >= v) if (balance >= VALUE_ZERO) // Always true if nextVictim == KING
return true; return true;
bool relativeStm = true; // True if the opponent is to move bool opponentToMove = true;
occupied ^= pieces() ^ from ^ to; occupied = pieces() ^ from ^ to;
// Find all attackers to the destination square, with the moving piece removed, // Find all attackers to the destination square, with the moving piece removed,
// but possibly an X-ray attacker added behind it. // but possibly an X-ray attacker added behind it.
@@ -1006,6 +1026,12 @@ bool Position::see_ge(Move m, Value v) const {
while (true) while (true)
{ {
// The balance is negative only because we assumed we could win
// the last piece for free. We are truly winning only if we can
// win the last piece _cheaply enough_. Test if we can actually
// do this otherwise "give up".
assert(balance < VALUE_ZERO);
stmAttackers = attackers & pieces(stm); stmAttackers = attackers & pieces(stm);
// Don't allow pinned pieces to attack pieces except the king as long all // Don't allow pinned pieces to attack pieces except the king as long all
@@ -1013,43 +1039,68 @@ bool Position::see_ge(Move m, Value v) const {
if (!(st->pinnersForKing[stm] & ~occupied)) if (!(st->pinnersForKing[stm] & ~occupied))
stmAttackers &= ~st->blockersForKing[stm]; stmAttackers &= ~st->blockersForKing[stm];
// If we have no more attackers we must give up
if (!stmAttackers) if (!stmAttackers)
return relativeStm; break;
// Locate and remove the next least valuable attacker // Locate and remove the next least valuable attacker
nextVictim = min_attacker<PAWN>(byTypeBB, to, stmAttackers, occupied, attackers); nextVictim = min_attacker<PAWN>(byTypeBB, to, stmAttackers, occupied, attackers);
if (nextVictim == KING) if (nextVictim == KING)
return relativeStm == bool(attackers & pieces(~stm)); {
// Our only attacker is the king. If the opponent still has
// attackers we must give up. Otherwise we make the move and
// (having no more attackers) the opponent must give up.
if (!(attackers & pieces(~stm)))
opponentToMove = !opponentToMove;
break;
}
balance += relativeStm ? PieceValue[MG][nextVictim] // Assume the opponent can win the next piece for free and switch sides
: -PieceValue[MG][nextVictim]; balance += PieceValue[MG][nextVictim];
opponentToMove = !opponentToMove;
relativeStm = !relativeStm; // If balance is negative after receiving a free piece then give up
if (balance < VALUE_ZERO)
if (relativeStm == (balance >= v)) break;
return relativeStm;
// Complete the process of switching sides. The first line swaps
// all negative numbers with non-negative numbers. The compiler
// probably knows that it is just the bitwise negation ~balance.
balance = -balance-1;
stm = ~stm; stm = ~stm;
} }
// If the opponent gave up we win, otherwise we lose.
return opponentToMove;
} }
/// Position::is_draw() tests whether the position is drawn by 50-move rule /// Position::is_draw() tests whether the position is drawn by 50-move rule
/// or by repetition. It does not detect stalemates. /// or by repetition. It does not detect stalemates.
bool Position::is_draw() const { bool Position::is_draw(int ply) const {
if (st->rule50 > 99 && (!checkers() || MoveList<LEGAL>(*this).size())) if (st->rule50 > 99 && (!checkers() || MoveList<LEGAL>(*this).size()))
return true; return true;
StateInfo* stp = st; int end = std::min(st->rule50, st->pliesFromNull);
for (int i = 2, e = std::min(st->rule50, st->pliesFromNull); i <= e; i += 2)
if (end < 4)
return false;
StateInfo* stp = st->previous->previous;
int cnt = 0;
for (int i = 4; i <= end; i += 2)
{ {
stp = stp->previous->previous; stp = stp->previous->previous;
if (stp->key == st->key) // Return a draw score if a position repeats once earlier but strictly
return true; // Draw at first repetition // after the root, or repeats twice before or at the root.
if ( stp->key == st->key
&& ++cnt + (ply > i) == 2)
return true;
} }
return false; return false;
@@ -1091,78 +1142,72 @@ void Position::flip() {
} }
/// Position::pos_is_ok() performs some consistency checks for the position object. /// Position::pos_is_ok() performs some consistency checks for the
/// position object and raises an asserts if something wrong is detected.
/// This is meant to be helpful when debugging. /// This is meant to be helpful when debugging.
bool Position::pos_is_ok(int* failedStep) const { bool Position::pos_is_ok() const {
const bool Fast = true; // Quick (default) or full check? const bool Fast = true; // Quick (default) or full check?
enum { Default, King, Bitboards, State, Lists, Castling }; if ( (sideToMove != WHITE && sideToMove != BLACK)
|| piece_on(square<KING>(WHITE)) != W_KING
|| piece_on(square<KING>(BLACK)) != B_KING
|| ( ep_square() != SQ_NONE
&& relative_rank(sideToMove, ep_square()) != RANK_6))
assert(0 && "pos_is_ok: Default");
for (int step = Default; step <= (Fast ? Default : Castling); step++) if (Fast)
return true;
if ( pieceCount[W_KING] != 1
|| pieceCount[B_KING] != 1
|| attackers_to(square<KING>(~sideToMove)) & pieces(sideToMove))
assert(0 && "pos_is_ok: Kings");
if ( (pieces(PAWN) & (Rank1BB | Rank8BB))
|| pieceCount[W_PAWN] > 8
|| pieceCount[B_PAWN] > 8)
assert(0 && "pos_is_ok: Pawns");
if ( (pieces(WHITE) & pieces(BLACK))
|| (pieces(WHITE) | pieces(BLACK)) != pieces()
|| popcount(pieces(WHITE)) > 16
|| popcount(pieces(BLACK)) > 16)
assert(0 && "pos_is_ok: Bitboards");
for (PieceType p1 = PAWN; p1 <= KING; ++p1)
for (PieceType p2 = PAWN; p2 <= KING; ++p2)
if (p1 != p2 && (pieces(p1) & pieces(p2)))
assert(0 && "pos_is_ok: Bitboards");
StateInfo si = *st;
set_state(&si);
if (std::memcmp(&si, st, sizeof(StateInfo)))
assert(0 && "pos_is_ok: State");
for (Piece pc : Pieces)
{ {
if (failedStep) if ( pieceCount[pc] != popcount(pieces(color_of(pc), type_of(pc)))
*failedStep = step; || pieceCount[pc] != std::count(board, board + SQUARE_NB, pc))
assert(0 && "pos_is_ok: Pieces");
if (step == Default) for (int i = 0; i < pieceCount[pc]; ++i)
if ( (sideToMove != WHITE && sideToMove != BLACK) if (board[pieceList[pc][i]] != pc || index[pieceList[pc][i]] != i)
|| piece_on(square<KING>(WHITE)) != W_KING assert(0 && "pos_is_ok: Index");
|| piece_on(square<KING>(BLACK)) != B_KING
|| ( ep_square() != SQ_NONE
&& relative_rank(sideToMove, ep_square()) != RANK_6))
return false;
if (step == King)
if ( std::count(board, board + SQUARE_NB, W_KING) != 1
|| std::count(board, board + SQUARE_NB, B_KING) != 1
|| attackers_to(square<KING>(~sideToMove)) & pieces(sideToMove))
return false;
if (step == Bitboards)
{
if ( (pieces(WHITE) & pieces(BLACK))
||(pieces(WHITE) | pieces(BLACK)) != pieces())
return false;
for (PieceType p1 = PAWN; p1 <= KING; ++p1)
for (PieceType p2 = PAWN; p2 <= KING; ++p2)
if (p1 != p2 && (pieces(p1) & pieces(p2)))
return false;
}
if (step == State)
{
StateInfo si = *st;
set_state(&si);
if (std::memcmp(&si, st, sizeof(StateInfo)))
return false;
}
if (step == Lists)
for (Piece pc : Pieces)
{
if (pieceCount[pc] != popcount(pieces(color_of(pc), type_of(pc))))
return false;
for (int i = 0; i < pieceCount[pc]; ++i)
if (board[pieceList[pc][i]] != pc || index[pieceList[pc][i]] != i)
return false;
}
if (step == Castling)
for (Color c = WHITE; c <= BLACK; ++c)
for (CastlingSide s = KING_SIDE; s <= QUEEN_SIDE; s = CastlingSide(s + 1))
{
if (!can_castle(c | s))
continue;
if ( piece_on(castlingRookSquare[c | s]) != make_piece(c, ROOK)
|| castlingRightsMask[castlingRookSquare[c | s]] != (c | s)
||(castlingRightsMask[square<KING>(c)] & (c | s)) != (c | s))
return false;
}
} }
for (Color c = WHITE; c <= BLACK; ++c)
for (CastlingSide s = KING_SIDE; s <= QUEEN_SIDE; s = CastlingSide(s + 1))
{
if (!can_castle(c | s))
continue;
if ( piece_on(castlingRookSquare[c | s]) != make_piece(c, ROOK)
|| castlingRightsMask[castlingRookSquare[c | s]] != (c | s)
|| (castlingRightsMask[square<KING>(c)] & (c | s)) != (c | s))
assert(0 && "pos_is_ok: Castling");
}
return true; return true;
} }
+32 -19
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
@@ -56,7 +56,10 @@ struct StateInfo {
Bitboard checkSquares[PIECE_TYPE_NB]; Bitboard checkSquares[PIECE_TYPE_NB];
}; };
// In a std::deque references to elements are unaffected upon resizing /// 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; typedef std::unique_ptr<std::deque<StateInfo>> StateListPtr;
@@ -76,6 +79,7 @@ public:
// FEN string input/output // FEN string input/output
Position& set(const std::string& fenStr, bool isChess960, StateInfo* si, 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
@@ -89,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;
@@ -107,7 +112,7 @@ public:
// 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; Bitboard slider_blockers(Bitboard sliders, Square s, Bitboard& pinners) const;
@@ -127,13 +132,14 @@ public:
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
bool see_ge(Move m, Value value) const; bool see_ge(Move m, Value threshold = VALUE_ZERO) const;
// Accessing hash keys // Accessing hash keys
Key key() const; Key key() const;
@@ -143,18 +149,17 @@ public:
// 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;
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:
@@ -180,7 +185,6 @@ private:
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];
uint64_t nodes;
int gamePly; int gamePly;
Color sideToMove; Color sideToMove;
Thread* thisThread; Thread* thisThread;
@@ -234,6 +238,10 @@ template<PieceType Pt> inline int Position::count(Color c) const {
return pieceCount[make_piece(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[make_piece(c, Pt)]; return pieceList[make_piece(c, Pt)];
} }
@@ -265,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 {
@@ -328,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;
} }
@@ -336,10 +349,6 @@ inline int Position::rule50_count() const {
return st->rule50; return st->rule50;
} }
inline uint64_t Position::nodes_searched() const {
return nodes;
}
inline bool Position::opposite_bishops() const { inline bool Position::opposite_bishops() const {
return pieceCount[W_BISHOP] == 1 return pieceCount[W_BISHOP] == 1
&& pieceCount[B_BISHOP] == 1 && pieceCount[B_BISHOP] == 1
@@ -411,4 +420,8 @@ inline void Position::move_piece(Piece pc, Square from, Square to) {
pieceList[pc][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
+40 -40
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,32 +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(-16, 7), S( 1,-4), S( 7, 8), S( 3,-2) }, { S(-11, 7), S( 6,-4), S( 7, 8), S( 3,-2) },
{ S(-23,-4), S( -7,-5), S( 19, 5), S(24, 4) }, { S(-18,-4), S( -2,-5), S( 19, 5), S(24, 4) },
{ S(-22, 3), S(-14, 3), S( 20,-8), S(35,-3) }, { S(-17, 3), S( -9, 3), S( 20,-8), S(35,-3) },
{ S(-11, 8), S( 0, 9), S( 3, 7), S(21,-6) }, { S( -6, 8), S( 5, 9), S( 3, 7), S(21,-6) },
{ S(-11, 8), S(-13,-5), S( -6, 2), S(-2, 4) }, { S( -6, 8), S( -8,-5), S( -6, 2), S(-2, 4) },
{ S( -9, 3), S( 15,-9), S( -8, 1), S(-4,18) } { S( -4, 3), S( 20,-9), S( -8, 1), S(-4,18) }
}, },
{ // 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) },
@@ -77,24 +77,24 @@ 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) }
} }
}; };
@@ -116,7 +116,7 @@ void init() {
for (Square s = SQ_A1; s <= SQ_H8; ++s) for (Square s = SQ_A1; s <= SQ_H8; ++s)
{ {
File f = std::min(file_of(s), FILE_H - file_of(s)); File f = std::min(file_of(s), ~file_of(s));
psq[ pc][ s] = v + Bonus[pc][rank_of(s)][f]; psq[ pc][ s] = v + Bonus[pc][rank_of(s)][f];
psq[~pc][~s] = -psq[pc][s]; psq[~pc][~s] = -psq[pc][s];
} }
+428 -431
View File
File diff suppressed because it is too large Load Diff
+18 -23
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 @@
#ifndef SEARCH_H_INCLUDED #ifndef SEARCH_H_INCLUDED
#define SEARCH_H_INCLUDED #define SEARCH_H_INCLUDED
#include <atomic>
#include <vector> #include <vector>
#include "misc.h" #include "misc.h"
@@ -32,21 +31,24 @@ 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;
Value history; int statScore;
bool skipEarlyPruning;
int moveCount; int moveCount;
CounterMoveStats* counterMoves;
}; };
@@ -57,13 +59,16 @@ 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; }
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;
}; };
@@ -71,40 +76,30 @@ 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] = nodes = time[WHITE] = time[BLACK] = inc[WHITE] = inc[BLACK] =
npmsec = movestogo = 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;
}; };
/// 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;
};
extern SignalsType Signals;
extern LimitsType Limits; extern LimitsType Limits;
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
+1586 -708
View File
File diff suppressed because it is too large Load Diff
+63 -3
View File
@@ -1,19 +1,79 @@
/*
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::RootMoves& rootMoves, Value& score); bool root_probe(Position& pos, Search::RootMoves& rootMoves, Value& score);
bool root_probe_wdl(Position& pos, Search::RootMoves& rootMoves, Value& score); bool root_probe_wdl(Position& pos, Search::RootMoves& rootMoves, Value& score);
void filter_root_moves(Position& pos, Search::RootMoves& rootMoves); 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;
}
} }
#endif #endif
+94 -118
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
@@ -29,172 +29,144 @@
ThreadPool Threads; // Global object ThreadPool Threads; // Global object
/// Thread constructor launches the thread and then waits 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;
tbHits = 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 waits 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() waits on sleep condition /// Thread::clear() reset histories, usually before a new game
/// until not searching
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() waits 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() wakes 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() creates and launches 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() terminates threads before the program exits. Cannot be void ThreadPool::clear() {
/// done in destructor because threads must be terminated before deleting any
/// static objects 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() returns the number of nodes searched
uint64_t ThreadPool::nodes_searched() const {
uint64_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
/// ThreadPool::tb_hits() returns the number of TB hits /// returns immediately. Main thread will wake up other threads and start the search.
uint64_t ThreadPool::tb_hits() const {
uint64_t hits = 0;
for (Thread* th : *this)
hits += th->tbHits;
return hits;
}
/// ThreadPool::start_thinking() wakes up the main thread sleeping in idle_loop()
/// and starts a new search, then returns immediately.
void ThreadPool::start_thinking(Position& pos, StateListPtr& states, void ThreadPool::start_thinking(Position& pos, StateListPtr& states,
const Search::LimitsType& limits) { const Search::LimitsType& limits, bool ponderMode) {
main()->wait_for_search_finished(); main()->wait_for_search_finished();
Search::Signals.stopOnPonderhit = Search::Signals.stop = false; stopOnPonderhit = stop = false;
ponder = ponderMode;
Search::Limits = limits; Search::Limits = limits;
Search::RootMoves rootMoves; Search::RootMoves rootMoves;
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))
rootMoves.push_back(Search::RootMove(m)); rootMoves.emplace_back(m);
if (!rootMoves.empty()) if (!rootMoves.empty())
Tablebases::filter_root_moves(pos, rootMoves); Tablebases::filter_root_moves(pos, rootMoves);
@@ -206,18 +178,22 @@ void ThreadPool::start_thinking(Position& pos, StateListPtr& states,
if (states.get()) if (states.get())
setupStates = std::move(states); // Ownership transfer, states is now empty 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(); StateInfo tmp = setupStates->back();
for (Thread* th : Threads) for (Thread* th : *this)
{ {
th->maxPly = 0; th->nodes = th->tbHits = th->nmp_ply = th->nmp_odd = 0;
th->tbHits = 0; th->rootDepth = th->completedDepth = DEPTH_ZERO;
th->rootDepth = DEPTH_ZERO;
th->rootMoves = rootMoves; th->rootMoves = rootMoves;
th->rootPos.set(pos.fen(), pos.is_chess960(), &setupStates->back(), th); th->rootPos.set(pos.fen(), pos.is_chess960(), &setupStates->back(), th);
} }
setupStates->back() = tmp; // Restore st->previous, cleared by Position::set() setupStates->back() = tmp;
main()->start_searching(); main()->start_searching();
} }
+46 -34
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,74 +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;
uint64_t tbHits; std::atomic<uint64_t> nodes, tbHits;
Position rootPos; Position rootPos;
Search::RootMoves rootMoves; Search::RootMoves rootMoves;
Depth rootDepth; Depth rootDepth, completedDepth;
Depth completedDepth; CounterMoveHistory counterMoves;
std::atomic_bool resetCalls; ButterflyHistory mainHistory;
HistoryStats history; CapturePieceToHistory captureHistory;
MoveStats counterMoves; ContinuationHistory contHistory;
FromToStats fromTo;
CounterMoveHistoryStats counterMoveHistory;
}; };
/// 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; 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(Position&, StateListPtr&, const Search::LimitsType&); uint64_t nodes_searched() const { return accumulate(&Thread::nodes); }
void read_uci_options(); uint64_t tb_hits() const { return accumulate(&Thread::tbHits); }
uint64_t nodes_searched() const;
uint64_t tb_hits() const; std::atomic_bool stop, ponder, stopOnPonderhit;
private: private:
StateListPtr setupStates; 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;
+1 -1
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
+1 -1
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
+1 -1
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
+4 -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
@@ -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();
} }
+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
@@ -104,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:
+96 -65
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
@@ -76,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
@@ -128,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 {
@@ -146,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;
}; };
@@ -183,11 +183,11 @@ 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 = 188, PawnValueEg = 248, PawnValueMg = 171, PawnValueEg = 240,
KnightValueMg = 753, KnightValueEg = 832, KnightValueMg = 764, KnightValueEg = 848,
BishopValueMg = 826, BishopValueEg = 897, BishopValueMg = 826, BishopValueEg = 891,
RookValueMg = 1285, RookValueEg = 1371, RookValueMg = 1282, RookValueEg = 1373,
QueenValueMg = 2513, QueenValueEg = 2650, QueenValueMg = 2526, QueenValueEg = 2646,
MidgameLimit = 15258, EndgameLimit = 3915 MidgameLimit = 15258, EndgameLimit = 3915
}; };
@@ -195,6 +195,7 @@ enum Value : int {
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
}; };
@@ -205,11 +206,9 @@ enum Piece {
PIECE_NB = 16 PIECE_NB = 16
}; };
const Piece Pieces[] = { W_PAWN, W_KNIGHT, W_BISHOP, W_ROOK, W_QUEEN, W_KING,
B_PAWN, B_KNIGHT, B_BISHOP, B_ROOK, B_QUEEN, B_KING };
extern Value PieceValue[PHASE_NB][PIECE_NB]; extern Value PieceValue[PHASE_NB][PIECE_NB];
enum Depth { enum Depth : int {
ONE_PLY = 1, ONE_PLY = 1,
@@ -224,7 +223,7 @@ enum Depth {
static_assert(!(ONE_PLY & (ONE_PLY - 1)), "ONE_PLY is not a power of 2"); static_assert(!(ONE_PLY & (ONE_PLY - 1)), "ONE_PLY is not a power of 2");
enum Square { 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,
@@ -235,12 +234,14 @@ 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
};
enum Direction : int {
NORTH = 8, NORTH = 8,
EAST = 1, EAST = 1,
SOUTH = -8, SOUTH = -NORTH,
WEST = -1, WEST = -EAST,
NORTH_EAST = NORTH + EAST, NORTH_EAST = NORTH + EAST,
SOUTH_EAST = SOUTH + EAST, SOUTH_EAST = SOUTH + EAST,
@@ -263,7 +264,7 @@ enum Rank : int {
/// care to avoid left-shifting a signed int to avoid undefined behavior. /// 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((int)((unsigned int)eg << 16) + mg); return Score((int)((unsigned int)eg << 16) + mg);
} }
@@ -271,97 +272,123 @@ inline Score make_score(int mg, int eg) {
/// 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 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 + 0x8000) >> 16) };
return Value(eg.s); return Value(eg.s);
} }
inline Value mg_value(Score s) { inline Value mg_value(Score s) {
union { uint16_t u; int16_t s; } mg = { uint16_t(unsigned(s)) }; union { uint16_t u; int16_t s; } mg = { uint16_t(unsigned(s)) };
return Value(mg.s); return Value(mg.s);
} }
#define ENABLE_BASE_OPERATORS_ON(T) \ #define ENABLE_BASE_OPERATORS_ON(T) \
inline T operator+(T d1, T d2) { return T(int(d1) + int(d2)); } \ constexpr T operator+(T d1, T d2) { return T(int(d1) + int(d2)); } \
inline T operator-(T d1, T d2) { return T(int(d1) - int(d2)); } \ constexpr T operator-(T d1, T d2) { return T(int(d1) - int(d2)); } \
inline T operator*(int i, T d) { return T(i * int(d)); } \ 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 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& 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_INCR_OPERATORS_ON(T) \
ENABLE_BASE_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); } \ inline T& operator--(T& d) { return d = T(int(d) - 1); }
inline T& operator--(T& d) { return d = T(int(d) - 1); } \
inline T operator/(T d, int i) { return T(int(d) / i); } \ #define ENABLE_FULL_OPERATORS_ON(T) \
inline int operator/(T d1, T d2) { return int(d1) / int(d2); } \ 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);
} }
inline Color operator~(Color c) { /// Multiplication of a Score by an integer. We check for overflow in debug mode.
inline Score operator*(Score s, int i) {
Score result = Score(int(s) * i);
assert(eg_value(result) == (i * eg_value(s)));
assert(mg_value(result) == (i * mg_value(s)));
assert((i == 0) || (result / i) == s );
return result;
}
constexpr Color operator~(Color c) {
return Color(c ^ BLACK); // Toggle color return Color(c ^ BLACK); // Toggle color
} }
inline Square operator~(Square s) { 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 Piece operator~(Piece pc) { 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 return Piece(pc ^ 8); // Swap color of piece B_KNIGHT -> W_KNIGHT
} }
inline CastlingRight operator|(Color c, CastlingSide s) { 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);
} }
@@ -370,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));
} }
@@ -399,23 +426,27 @@ 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 ? NORTH : SOUTH; 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);
} }
@@ -424,11 +455,11 @@ inline Move make_move(Square from, Square 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(T + ((pt - KNIGHT) << 12) + (from << 6) + to); 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
} }
+82 -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";
// 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.
StateListPtr States(new std::deque<StateInfo>(1));
// 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;
States = StateListPtr(new std::deque<StateInfo>(1)); states = StateListPtr(new std::deque<StateInfo>(1)); // Drop old and create a new one
pos.set(fen, Options["UCI_Chess960"], &States->back(), Threads.main()); 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)
{ {
States->push_back(StateInfo()); states->emplace_back();
pos.do_move(m, States->back(), pos.gives_check(m)); 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(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, States, limits); 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
@@ -148,8 +190,10 @@ void UCI::loop(int argc, char* argv[]) {
Position pos; 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(), Threads.main()); 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]) + " ";
@@ -160,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();
} }
@@ -227,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&);
+6 -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
@@ -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["Debug Log File"] << Option("", 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);
+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