Compare commits

..

1044 Commits

Author SHA1 Message Date
Joona Kiiski 5b555525d2 Stockfish 6
Stockfish bench signature is: 8918745
2015-01-27 20:27:38 +00:00
Joona Kiiski c4518e395e Stockfish 6 Release Candidate 3
- Fix a skill level problem: Don't allow move pruning at root node
- Revert "Fix profile build for gcc on Mac OSX". Results for a faster binary in x86-64.
- Fix a MSVC warning

Bench: 8918745
2015-01-25 22:03:57 +00:00
Stefan Geschwentner d8b3ad2208 Fix a skill level problem: Don't allow move pruning at root node
Bench: 8918745

Resolves #231
2015-01-25 21:57:13 +00:00
Joona Kiiski ec36b8dea9 Revert "Fix profile build for gcc on Mac OSX"
Seems to be a performance regression for standard build.

For SF6 people compiling on Mac OSX using profile-build option
just need to make necessary adjustments manually...

No functional change

Resolves #223
2015-01-25 21:51:09 +00:00
Marco Costalba 8ebf30d44a Fix a MSVC warning at W4
Warning is C4512 (assignment operator could not be generated)

Now, apart the foreign syzygy code, everything compiles
without warnings at warning level 4.

Backported from C++11 branch.

No functional change.
2015-01-25 09:36:05 +01:00
Joona Kiiski 5154ac9cff Stockfish 6 Release Candidate 2
- Fix a compilation issue related to BMI2 PEXT instruction
- Retrieve a ponder move from TT if PV is only one move long

Bench: 8080602

No functional change
2015-01-24 19:42:49 +00:00
Marco Costalba 54b5b528d9 Don't use _pext_u64() directly
This intrinsic to call BMI2 PEXT instruction is
defined in immintrin.h. This header should be
included only when USE_PEXT is defined, otherwise
we define _pext_u64 as 0 forcing a nop.

But under some mingw platforms, even if we don't
include the header, immintrin.h gets included
anyhow through an include chain that starts with
STL <algorithm> header. So we end up both defining
_pext_u64 function and at the same time defining
_pext_u64 as 0 leading to a compile error.

The correct solution is of not using _pext_u64 directly.

This patch fixes a compile error with some mingw64
package when compiling with x86-64.

No functional change.

Resolves #222
2015-01-24 19:38:06 +00:00
Marco Costalba 44643c2770 Try hard to retrieve a ponder move
In case we stop the search during a fail-high
it is possible we return to GUI without a ponder
move. This patch try harder to find a ponder move
retrieving it from TT. This is important in games
played with 'ponder on'.

bench: 8080602

Resolves #221
2015-01-24 19:35:31 +00:00
Joona Kiiski 97a034ad3e Stockfish 6 Release Candidate 1
Bench: 8080602

No functional change

Resolves #218
2015-01-18 14:53:11 +00:00
Joona Kiiski 1b62b47b62 Fix profile build for gcc on Mac OSX
Switch back to using -fprofile-generate and
-fprofile-use flags

No functional change

Resolves #219
Resolves #210
2015-01-18 14:42:30 +00:00
Joona Kiiski 7f51610103 Don't print fail-high or fail-lows in MultiPV mode
Supposed to give a better user experience when using MultiPV mode

No functional change

Resolves #217
2015-01-18 14:38:46 +00:00
Marco Costalba c73f33f37e Fix syzygy warnings with Intel compiler
Quick hack, a better job would require to
first move all syzygy code up to SF standard.

No functional change.
2015-01-18 07:29:51 +01:00
Marco Costalba 05cb58f4fc Fix some missing rename from previous patch
No functional change.
2015-01-17 22:15:15 +01:00
Marco Costalba 595fc342cf Fix a possible overflow in TT resize
On platforms where size_t is 32 bit, we
can have an overflow in this expression:

(mbSize * 1024 * 1024)

Fix it setting max hash size of 2GB on platforms
where size_t is 32 bit.

A small rename while there: now struct Cluster
is definied inside class TranspositionTable so
we should drop the redundant TT prefix.

No functional change.
2015-01-17 21:42:47 +01:00
mstembera 58fdb84b0d Simplify and optimize value extractors
Speed up results by Joona:

gcc-4.7 (1.5%)
gcc-4.8 (0.5%)
gcc-4.9 (1.0%)

Speed up results by mstembera:

gcc 474
p-value: 0.719

gcc 482
p-value: 1

gcc 492
p-value: 0.859

No functional change

Resolves #211
2015-01-16 19:03:49 +00:00
lucasart ab276357d7 Enable futility pruning for PV nodes in qsearch
STC:

LLR: 4.20 (-2.94,2.94) [-3.00,1.00]
Total: 85573 W: 17195 L: 17125 D: 51253

LTC:

LLR: 2.94 (-2.94,2.94) [-3.00,1.00]
Total: 43385 W: 7298 L: 7214 D: 28873

Bench: 8080602

Resolves #206
2015-01-14 20:21:54 +00:00
Stefan Geschwentner 4abe333e1f Enable Futility pruning in PV nodes
STC:

LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 21553 W: 4342 L: 4221 D: 12990

LTC:

LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 7675 W: 1351 L: 1209 D: 5115

Bench: 8668014

Resolves #205
2015-01-14 20:13:48 +00:00
hxim 7b20bb6e1a Use VALUE_ZERO instead of 0 when comparing with Value
This is the correct practice.

No functional change

Resolves #208
2015-01-13 21:07:18 +00:00
Marco Costalba 4eb2d8ce09 Assorted headers cleanup
Mostly comments fixing and other small things.

No functional change.
2015-01-11 22:56:35 +01:00
Marco Costalba b97df4c236 Fix a crash of syzygy on Android
On Android-ARM current TB code crashes at
random times even in single thread mode.

Reported, debugged, fixed and verified
by Peter Osterlund.

No functional change.

Resolves #201
2015-01-11 20:10:31 +00:00
Stefano80 17bcdb9212 Higher movetime resolution for benchmarks
Use a millisecond movetime precision for benchmarks

No functional change

Resolves #198
2015-01-11 20:07:11 +00:00
Marco Costalba 202a78e8e4 Fix compile for Android 5
Android 5 can only run position independent executables.

Note that this breaks Android 4.0 and earlier.

See here for more info:
http://stackoverflow.com/questions/24818902/running-a-native-library-on-android-l-error-only-position-independent-executab

Thanks to Peter Osterlund for the support.

No functional change
2015-01-11 10:52:42 +01:00
Marco Costalba 42b48b08e8 Update copyright year
No functional change.
2015-01-10 11:46:28 +01:00
Marco Costalba aea2fde611 Assorted formatting and comment tweaks in position.h
No functional change.
2015-01-07 09:09:41 +01:00
lucasart b73ae56ee1 Tune null search reduction
STC

LLR: 2.96 (-2.94,2.94) [-0.50,4.50]
Total: 107289 W: 21851 L: 21325 D: 64113

LTC

LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 83837 W: 14378 L: 13916 D: 55543

Bench: 7604776

Resolves #194
2015-01-05 22:09:12 +00:00
Marco Costalba 3fda064a66 Retire one implementation of pop_lsb()
We have two implementations that are equivalent,
so retire one.

Plus usual tidy up of comments and code reshuffle.

No functional change.
2015-01-03 22:16:30 +01:00
lucasart a6e292034a Remove a useless optimization
This optimization is aimed at old hardware only (withouth popcount), and even on
non popcount compile (ARCH=x86-64), it provides no mesurable speedup:

stat        test     master     diff
mean   2,341,779  2,354,699  -12,920
stdev     12,910     14,770   18,150

speedup      -0.55%
P(speedup>0)  23.8%

No functional change.

Resolves #187
2015-01-03 20:40:57 +00:00
Joona Kiiski c7332d5610 Smoother king safety
STC:

LLR: 4.03 (-2.94,2.94) [-1.50,4.50]
Total: 35707 W: 7352 L: 7106 D: 21249

LTC:

LLR: 2.95 (-2.94,2.94) [0.00,4.00]
Total: 24563 W: 4330 L: 4095 D: 16138

Bench: 8411409

Resolves #190
2015-01-03 20:34:20 +00:00
Marco Costalba 9d1e2c0e76 Assorted work in uci.cpp
- Change UCI::value() signature

This function should only return the value,
lowerbound and upperbound info is up to the
caller because it requires external knowledge,
out of the scope of this little helper.

- Retire 'key' command

It is not an UCI command and is absolutely
useless: never used.

- Comments fixing and other trivia

No functional change.
2015-01-03 18:46:59 +01:00
Marco Costalba c150f07291 Fix a silly warning with Intel compiler
Intel compiler cries for an explicit cast

warning #2259: non-pointer conversion from "double" to "int"
may lose significant bits

No functional change.
2015-01-03 10:17:04 +01:00
Marco Costalba 62f531254e Fix comments in thread.cpp
And reshuffle a bit the functions to place
them in a consistent order.

To be on the safe side, patch has been
validated for no regression/crashes with
a small 8K games test with 3 threads:

ELO: 3.98 +-4.4 (95%) LOS: 96.3%
Total: 8388 W: 1500 L: 1404 D: 5484

No functional change.
2015-01-03 09:34:58 +01:00
Marco Costalba 91cc82aa25 Let material probing to access per-thread table
It is up to material (and pawn) table look up
code to know where the per-thread tables are,
so change API to reflect this.

Also some comment fixing while there

No functional change.
2015-01-02 21:31:02 +01:00
Matthew Lai 19b8249ff4 Disable the default copy constructor for Position class
No functional change

Resolved #183
2015-01-02 20:19:11 +00:00
Stefan Geschwentner 25b492ab58 Big King Safety tuning
All king safety related terms (shelterweakness, stormdanger,
attackunits, ..) was tuned together. Additionally for attack units a
finer granularity (factor 4) is used.

STC
ELO: 9.22 +-3.1 (95%) LOS: 100.0%
Total: 19514 W: 4340 L: 3822 D: 11352

LTC
LLR: 2.96 (-2.94,2.94) [0.00,6.00]
Total: 6399 W: 1192 L: 1056 D: 4151

Bench: 8224782

Resolves #184
2015-01-03 03:33:02 +08:00
Marco Costalba 4c9b423161 Retire Material::space_weight()
Move all in evaluation.

Simplify the code and concentrate in a single place
all the logic behind space evaluation, making it much
more clear.

Verified also at STC it does not regress due to a possible
slow down:

LLR: 3.91 (-2.94,2.94) [-3.00,1.00]
Total: 65744 W: 13285 L: 13194 D: 39265

No functional change.
2015-01-02 10:02:28 +01:00
Marco Costalba 2416242c96 Additional tidy up in timeman.cpp
Fixed some comments and moved/renamed some
variables.

No functional change.
2014-12-30 09:49:54 +01:00
Marco Costalba 6933f05f4b Use score and value consistently
And other assorted small fixing, code style
tweaks and reshuffles in evaluate.cpp

No functional change.
2014-12-28 19:06:56 +01:00
Arjun Temurnikar f9571e8d57 Remove some comments in timeman.cpp
Commenst are obsolete now, an updated description
would be quite obscure, so better let the code
to talk and remove them all together.

No functional change.
2014-12-28 11:58:29 +01:00
Marco Costalba 2bfacf136c Reformat promotion generation
Use the same template of other pawns moves generation,
make the code more uniform, simplify generate_promotions
that has now been renamed.

No functional change (verified also with perft).
2014-12-25 11:09:07 +01:00
Marco Costalba 296534f234 Prefer names to numbers in storm code
Also replaces some tabs with spaces and
change StormDanger order to reflect
ShelterWeakness one.

No functional change.
2014-12-22 08:33:07 +01:00
Joona Kiiski e5c7b44f7a Use "rm -f" instead of "rm" for gcc profiling hack in Makefile
In some UNIX systems "rm" prompts user for confirmation.
However "rm -f" is always a guaranteed forced deletion.

Also move gcc profiling hack under the correct target

No Functional change

Resolves #168
2014-12-20 17:55:18 +00:00
Stefan Geschwentner 3231038262 Big King Safety tuning
ShelterWeakness and Stormdanger array are now indexed additionally by
file pair (a/h,b/g,c/f,d/e). The special case of king blocking a pawn
is incorporated in the StormDanger array.  Finally the 93 parameters
are tuned by SPSA on LTC.

STC
ELO: 3.46 +-2.2 (95%) LOS: 99.9%
Total: 40000 W: 8275 L: 7877 D: 23848

LTC
LLR: 2.96 (-2.94,2.94) [0.00,6.00]
Total: 10311 W: 1876 L: 1721 D: 6714

Bench: 9498821

Resolves #163
2014-12-21 01:53:44 +08:00
Marco Costalba 9cae6e66ce Don't account for Tempo in specialized endgames
The evaluation is already done by the specialized
function, don't need to add something elese later.

With this patch following positions are evaluated
correctly as draws:

8/6p1/1Pkp1p1p/2nNn2P/2P1K1P1/8/8/3B4 w - - 7
8/1k4p1/1P1p1p1p/3NnK1P/2P3P1/1n6/4B3/8 w - -

Verified it not regress with an STC test:
LLR: 3.15 (-2.94,2.94) [-3.00,1.00]
Total: 49812 W: 10095 L: 10016 D: 29701

Reported by Arjun Temurnikar.

bench: 8289983
2014-12-19 11:06:40 +01:00
mstembera 46d5fff01f Change profile-build options to produce 1% to 2% faster executables.
The "@rm ucioption.gc*" line is necessary to avoid a gcc 4.7.x bug.
Confirmed for gcc 4.7.4, 4.8.1, and 4.9.1
Suggested by Kiran Panditrao on fishcooking forum.
https://groups.google.com/forum/?fromgroups=#!topic/fishcooking/AY8gN53nG18

No functional change.

Resolves #160
2014-12-19 03:57:04 +08:00
Marco Costalba b8fd1a78dc Improve comments in UCI
And simplify naming while there.

No functional change.

Resolves #159
2014-12-14 23:50:33 +00:00
Marco Costalba 413b243809 Coding style in TT code
In particular seems more natural to return
bool and TTEntry on the same line, actually
we should pass and return them as a pair,
but due to limitations of C++ and not wanting
to use std::pair this can be an acceptable
compromise.

No functional change.

Resolves #157
2014-12-14 23:49:00 +00:00
Gary Linscott 0edb6348d2 Fix compile for some versions of mingw
The bswap intrinsics are specific to the compiler, not the
host platform.

No functional change.

Resolves #155
2014-12-14 14:45:43 -05:00
mstembera 14cf27e6f6 Avoid searching TT twice for the same key/position during probe() and store().
Just keep the pointer and remove code from tt.cpp

STC
LLR: 2.96 (-2.94,2.94) [-1.50,4.50]
Total: 13620 W: 2810 L: 2665 D: 8145

LTC
LLR: 2.97 (-2.94,2.94) [0.00,6.00]
Total: 13021 W: 2238 L: 2073 D: 8710STC http://tests.stockfishchess.org/tests/view/548436860ebc59331739b90c

STC 4MB
ELO: 2.41 +-2.2 (95%) LOS: 98.6%
Total: 40000 W: 8175 L: 7897 D: 23928

LTC 16MB
ELO: 1.78 +-2.0 (95%) LOS: 96.1%
Total: 39683 W: 6763 L: 6560 D: 26360

Resolves #151

Bench: 8116521
2014-12-13 07:22:37 +00:00
Gary Linscott 7b4828b68c Only use _ReadWriteBarrier on MSVC
It was causing compile errors when cross-compiling using mingw.

No functional change.
2014-12-11 14:56:24 -05:00
joergoster f6d220ab14 Halve StormDanger bonus for blocked pawn on A/H file
STC
LLR: 2.95 (-2.94,2.94) [-1.50,4.50]
Total: 3410 W: 758 L: 641 D: 2011

LTC
LLR: 2.95 (-2.94,2.94) [0.00,6.00]
Total: 33225 W: 5708 L: 5445 D: 22072

Bench: 8465811

Resolves #153
2014-12-11 13:08:29 -05:00
Gary Linscott afafdf7b73 MSVC compiling fixes
No functional change.

Resolves #150
2014-12-11 13:03:44 -05:00
Joona Kiiski b15dcd9774 Fix profile build for syzygy
Touch source files under syzygy directory to force recompilation
after collecting profile data.

No functional change

Resolves #149
2014-12-10 17:59:41 +00:00
Joona Kiiski 94dd204c3b Retire 'os' flag from Makefile
Appears to be unused

No functional change

Resolves #147
2014-12-10 17:57:55 +00:00
Marco Costalba 5943600a89 Assorted nitpicking code-style
No functional change.
2014-12-10 12:38:13 +01:00
Marco Costalba 589c711449 Clarify when forcing the moves loop
In some cases we want to go direcly to the moves loop
without checking for early return. The patch make this
logic more clear and consistent.

Tested for no regression, passed STC
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 25282 W: 5136 L: 5022 D: 15124

and LTC
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 72007 W: 12133 L: 12095 D: 47779

bench: 9316798
2014-12-10 12:35:21 +01:00
Ernesto Gatti 158864270a Simpler PRNG and faster magics search
This patch replaces RKISS by a simpler and faster PRNG, xorshift64* proposed
by S. Vigna (2014). It is extremely simple, has a large enough period for
Stockfish's needs (2^64), requires no warming-up (allowing such code to be
removed), and offers slightly better randomness than MT19937.

Paper: http://xorshift.di.unimi.it/
Reference source code (public domain):
http://xorshift.di.unimi.it/xorshift64star.c

The patch also simplifies how init_magics() searches for magics:

- Old logic: seed the PRNG always with the same seed,
  then use optimized bit rotations to tailor the RNG sequence per rank.

- New logic: seed the PRNG with an optimized seed per rank.

This has two advantages:
1. Less code and less computation to perform during magics search (not ROTL).
2. More choices for random sequence tuning. The old logic only let us choose
from 4096 bit rotation pairs. With the new one, we can look for the best seeds
among 2^64 values. Indeed, the set of seeds[][] provided in the patch reduces
the effort needed to find the magics:

64-bit SF:
Old logic -> 5,783,789 rand64() calls needed to find the magics
New logic -> 4,420,086 calls

32-bit SF:
Old logic -> 2,175,518 calls
New logic -> 1,895,955 calls

In the 64-bit case, init_magics() take 25 ms less to complete (Intel Core i5).

Finally, when playing with strength handicap, non-determinism is achieved
by setting the seed of the static RNG only once. Afterwards, there is no need
to skip output values.

The bench only changes because the Zobrist keys are now different (since they
are random numbers straight out of the PRNG).

The RNG seed has been carefully chosen so that the
resulting Zobrist keys are particularly well-behaved:

1. All triplets of XORed keys are unique, implying that it
   would take at least 7 keys to find a 64-bit collision
   (test suggested by ceebo)

2. All pairs of XORed keys are unique modulo 2^32

3. The cardinality of { (key1 ^ key2) >> 48 } is as close
   as possible to the maximum (65536)

Point 2 aims at ensuring a good distribution among the bits
that determine an TT entry's cluster, likewise point 3
among the bits that form the TT entry's key16 inside a
cluster.

Details:

     Bitset   card(key1^key2)
     ------   ---------------
RKISS
     key16     64894   = 99.020% of theoretical maximum
     low18    180117   = 99.293%
     low32    305362   = 99.997%

Xorshift64*, old seed
     key16     64918   = 99.057%
     low18    179994   = 99.225%
     low32    305350   = 99.993%

Xorshift64*, new seed
     key16     65027   = 99.223%
     low18    181118   = 99.845%
     low32    305371   = 100.000%

Bench: 9324905

Resolves #148
2014-12-08 08:18:26 +08:00
Gary Linscott a87da2c4b3 Add some tablebase positions to bench
This makes it easier to check for regressions in the tablebase code.

Bench: 9489202
5-man bench: 8943906

Resolves #145
2014-12-08 07:58:05 +08:00
hxim fbb53524ef Rename some variables for more clarity.
No functional change.

Resolves #131
2014-12-08 07:53:33 +08:00
Marco Costalba ba1464751d Explicitly pass RootMoves to TB probes
Currently Search::RootMoves is accessed and even
modified by TB probing functions in a hidden
and sneaky way.

This is bad practice and makes the code tricky.
Instead explicily pass the vector as function
argument so to clarify that the vector is modified
inside the functions.

No functional change.
2014-12-06 15:08:21 +00:00
Marco Costalba eeb6d923fa Move TB stuff under Tablebases namespace
Simplified also some logic while there.

TBLargest needs renaming too, but itis for
a future patch because touches also syzygy
directory stuff.

No functional change.
2014-12-06 14:58:00 +00:00
Marco Costalba c30eb4c9c9 Refactor syzygy code in search
Move to SF coding style.

Also skip calculating piece count in search()
when TB are not found (!TBCardinality)

No functional change.
2014-12-06 14:35:50 +00:00
Joona Kiiski 35c1ccef39 Retire support for Haiku installation directory from Makefile
- It is out of the scope of the project.
- It is the responsibility of Haiku package maintainer to
  configure this.

No functional change

Resolves #143
2014-12-06 14:23:08 +00:00
Joona Kiiski 0935dca9a6 Retire hackish support for aCC and HP-UX from Makefile
- It is out of scope of the project.
- We have no way to verify that it even works anymore

No functional change

Resolves #142
2014-12-06 14:19:39 +00:00
Marco Costalba 314d446518 Retire total_piece_count()
We really don't need to uglify in this way
our nice count() API with this ad-hoc hack.

So remove the hack and use the already
existing infrastructure.

No functional change.

Resolves #134
2014-11-30 20:37:24 +00:00
hxim c014444f09 Remove CONNECTED_KINGS from Syzygy code
No functional change

Resolves #140
2014-11-30 20:24:32 +00:00
Rodrigo Exterckötter Tjäder 9b4e123fbe Cleaning Syzygy profiling data
Updating the makefile so that the clean and gcc-profile-clean targets also
remove the profiling data files in the syzygy directory.

No functional change.

Resolves #136
2014-11-30 19:53:04 +00:00
Marco Costalba a43f633c19 Rewrite TBScore in uci_pv()
Streamline the code and make
it understandable.

No functional change.

Resolves #135
2014-11-30 19:35:35 +00:00
Marco Costalba 66f5cd3f9d Retire #ifdef SYZYGY macro
It just clutters the code for no
real reason.

No functional change.

Resolves #139
2014-11-30 19:23:17 +00:00
mstembera fe07ae4cb4 Bitbase index() from ADD to OR.
No functional change.

Resolves #132
2014-11-26 07:56:48 +08:00
lucasart 2c52147dbf Introduce ratio operation
Just like in Physics, the ratio of 2 things in the same unit, should be
without unit.

Example use case:
- Ratio of a Depth by a Depth (eg. ONE_PLY) should be an int.
- Ratio of a Value by a Value (eg. PawnValueEg) should be an int.

Remove a bunch of useless const while there.

No functional change.

Resolves #128
2014-11-26 07:55:57 +08:00
Ronald de Man 7caa6cd338 Syzygy tablebases
Adds support for Syzygy tablebases to Stockfish.  See
the Readme for information on using the tablebases.

Tablebase support can be enabled/disabled at the Makefile
level as well, by setting syzygy=yes or syzygy=no.

Big/little endian are both supported.

No functional change (if Tablebases are not used).

Resolves #6
2014-11-26 07:49:58 +08:00
Gary Linscott 4509eb1342 Fix out-of-bound array access printing ponder move
It is possible that we won't have a ponder move if our PV
is too short.  In that case, just don't print a ponder move.

No functional change

Resolves #130
2014-11-24 08:53:00 +08:00
Gary Linscott 7ad59d9ac9 Fix pondering
The UCI specification states that an engine can never exit the search
while pondering.

No functional change.

Resolves #118
2014-11-24 08:50:36 +08:00
Jonathan Calovski 48127fe5d3 Amend defended
Amend defended to remove now redundant condition.

No functional change.

Resolves #125
2014-11-22 05:46:59 +08:00
Marco Costalba 84408e5cd6 Fix doubled pawns asymmetry
When evaluating double pawns we use always
lsb() to extract the frontmost square.

This breaks evaluation color symmetry as is
possible to verify with an instrumented evaluate()

  Value evaluate(const Position& pos) {

    Value v = do_evaluate<false>(pos);
    Position p = pos;
    p.flip();
    assert(v == do_evaluate<false>(p));
    return v;
  }

Passed no regression test:

STC
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 21035 W: 4244 L: 4122 D: 12669

LTC
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 39839 W: 6662 L: 6572 D: 26605

bench: 8255966
2014-11-21 20:40:25 +01:00
Marco Costalba 79232be02a Further tweak accurate pv
It is a non functional change, but because
we now skip copying of pv[] in SpNode, patch
has been tested for regression with 3 threads:

STC
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 54668 W: 9873 L: 9809 D: 34986

No functional change.
2014-11-21 20:37:45 +01:00
hxim 0a1f54975f Fix some comments
No functional change.

Resolves #123
2014-11-19 06:39:17 +08:00
Gary Linscott bffe32f4fe Fix fen output for castling rights
This is a regression from 428962a

We have to cast to char here, otherwise the compiler
interprets it as an integer, and writes a number.

No functional change

Resolves #122
2014-11-19 06:37:59 +08:00
Marco Costalba 4aca11ae2a Codying style in accurate PV
This is the first of a patch series to
rearrange and simplify accurate PV.

In this patch there is simple coding
style and reformatting stuff.

Verified with fishtest it does not crash
with MAX_PLY = 8

No functional change.
2014-11-18 11:57:57 +01:00
Marco Costalba 1a939cd8c8 Fix a warning on Intel C++
warning #2259: non-pointer conversion from "int" to
"uint8_t={unsigned char}" may lose significant bits

No functional change.
2014-11-17 12:56:48 +01:00
sf-x d65c9a3262 Use PHASE_MIDGAME in game_phase()
No functional change

Resolves #117
2014-11-17 07:50:33 +08:00
Rodrigo Exterckötter Tjäder 99f2c1a2a6 Clear token before reading from input
Previously token would keep its value from the previous line when an empty
line was input, leading to unexpected behaviour.

No functional change

Resolves #119
2014-11-17 07:48:30 +08:00
lucasart 3b1f552b08 Half History Max
STC
LLR: 3.35 (-2.94,2.94) [-0.50,3.50]
Total: 17993 W: 3740 L: 3508 D: 10745

LTC
LLR: 3.25 (-2.94,2.94) [0.00,4.00]
Total: 21346 W: 3691 L: 3453 D: 14202

Bench: 7694316

Resolves #120
2014-11-17 07:04:58 +08:00
Marco Costalba 4840643fed Use DEPTH_MAX instead of MAX_PLY
When comparing to a Depth it is more
consistent to use DEPTH_MAX instead
of a int.

This is a subtle difference because we use
ply and depth almost interchangably in SF,
but they are different. FOr counting plies
makes ense to continue using ints, while
for Depth we have our specific enum.

This cleanly fixes a new Clang 3.5 warning:

No functional change.
2014-11-15 05:36:49 +01:00
Gary Linscott 4739037f96 100% accurate PV display
This gives SF accurate PVs, such that the evaluation of the leaf node in
the PV matches the score backed up to the root (99% of the time.
q-search will use the value stored in the hash table instead of the eval
value sometimes).

One drawback is that fail-high/low only get a minimal 2 move PV.

It doesn't add any additional overhead to the non-PV codepath except an
extra eight bytes to the SearchStack structure in multi-threaded
searches.

A core part of this is not pruning based on TT score in PV nodes. This
was measured as not being a regression at multiple TCs, except for one
exception, fast TC with huge hash, which is not realistic for longer
searches.

STC - 1 thread, 128 mb hash
ELO: 1.42 +-3.1 (95%) LOS: 81.9%
Total: 20000 W: 4078 L: 3996 D: 11926

STC - 3 thread, 128 mb hash
ELO: -3.60 +-2.9 (95%) LOS: 0.8%
Total: 20000 W: 3575 L: 3782 D: 12643

STC - 3 thread, 8 mb hash
ELO: 0.12 +-2.9 (95%) LOS: 53.3%
Total: 20000 W: 3654 L: 3647 D: 12699

LTC - 3 thread, 32mb hash
ELO: 2.29 +-2.0 (95%) LOS: 98.8%
Total: 35740 W: 5618 L: 5382 D: 24740

Bench: 6984058

Resolves #102
2014-11-12 16:16:33 -05:00
lucasart 234344500f Use quiet ttMove in qsearch() (7962287)
Daniel Jose reported that it was an elo gain in his engine:
http://www.talkchess.com/forum/viewtopic.php?t=54290

STC: Hash=16
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 33067 W: 6670 L: 6571 D: 19826

LTC: Hash=64
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 41181 W: 7008 L: 6920 D: 27253

And another one to verify no regression with hash pressure:

STC: Hash=4
LLR: 2.96 (-2.94,2.94) [-4.00,0.00]
Total: 25085 W: 5059 L: 4991 D: 15035

Verified that qsearch does not explode after this patch (recapture threshold).

Bench 7962287

Resolves #112
2014-11-12 21:06:14 +00:00
Marco Costalba b777b17f6f Use if/else instead of goto
Real men jump/branch by hand...but
we prefer the humble way.

Moved also some uci info code where it
belongs, while there.

No functional change.

Resolves #110
2014-11-12 21:02:20 +00:00
Marco Costalba db4b8ee000 Use Depth instead of int in search
And make it more ONE_PLY value independent,
although we are not there yet.

No functional change.

Resolves #111
2014-11-12 21:00:16 +00:00
lucasart c6d45c60b5 Profile Build with Hash=16
16MB for 1" searches is more comensurate with the average use case.

And 16 is the default used by stockfish bench, so it makes sense to be
consistent, if only to have the same minimum memory requirement for using
SF and compiling it with PGO.

No functional change.

Resolves #109
2014-11-10 23:06:12 +00:00
lucasart d709a5f1c5 Fix bounds of FutilityMoveCounts
This is a left-over from ONE_PLY == 2.

No functional change.

Resolves #107
2014-11-09 20:13:56 +00:00
Marco Costalba 1b0df1ae14 Retire pvMove in search()
Now we can directly replace it with
the definition resulting in simpler
and possibly faster code because
PvNode is evaluated at compile time.

No functional change.
2014-11-09 20:36:28 +01:00
Marco Costalba 57fdfdedcf Assorted code-style triviality
No functional change.
2014-11-09 20:17:29 +01:00
Marco Costalba 6fb0a1bc40 Introduce distance() and unify some API
Original work by Lucas.

No functional change.
2014-11-09 10:27:04 +01:00
lucasart 8631b08d97 Codestyle massage Search::init()
* remove some erroneous comments, that were based on the ONE_PLY == 2.
* rename hd to d, because there's no more half-depth in SF.
* rescope variables into the for loops.
* reindent the for loops correctly.
* add a comment to explain the eval improving part (not so obvious to read
this code as array has 4 dimensions).

No functional change.
2014-11-08 10:56:51 -05:00
lucasart 3d2aab11d8 Be more optimistic in aspiration window
Be more optimistic wrt search instability, and set the unviolated bound
half window.

STC
LLR: 2.96 (-2.94,2.94) [-1.00,4.00]
Total: 16362 W: 3371 L: 3197 D: 9794

LTC
LLR: 2.94 (-2.94,2.94) [0.00,5.00]
Total: 21666 W: 3780 L: 3569 D: 14317

Bench: 6807896

Resolves #105
2014-11-08 10:47:56 -05:00
lucasart 7ebb872409 Prune ttMove like any other
This should reduce search inconsistencies, and doesn't seem to have a measurable ELO Impact:

STC with Hash=16
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 49264 W: 10076 L: 10007 D: 29181

LTC with Hash=64
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 82149 W: 14044 L: 14023 D: 54082

Plus an extra test, to make sure it doesn't regress with strong hash pressure:

STC with Hash=4
LLR: 2.95 (-2.94,2.94) [-4.00,0.00]
Total: 21498 W: 4327 L: 4246 D: 12925

Bench: 7302735

Resolves #100
2014-11-07 21:40:24 +00:00
lucasart 375797d51c Retire CACHE_LINE_ALIGNMENT
Speed tests showed no benefit.

No functional change.

Resolves #97
2014-11-07 14:27:04 -05:00
lucasart 8e98bd616e Apply King Safety later in the endgame
Idea is to apply king safety later in the endgame. Previously, we didn't
apply KS in a RR vs. Q ending for example, which causes poor play.
Now we calculate king attacks when the attacking side has a queen or more.

STC with 8moves_v3
LLR: 3.06 (-2.94,2.94) [0.00,4.00]
Total: 38481 W: 6228 L: 5952 D: 26301

LTC with 2moves_v1
LLR: 2.95 (-2.94,2.94) [0.00,4.00]
Total: 51053 W: 8670 L: 8353 D: 34030

Bench: 7514010

Resolves #98
2014-11-06 13:01:47 -05:00
mstembera bc83515c9e Removing some superfluous extern declarations
No functional change.

Resolves #93
2014-11-05 21:17:19 +00:00
Marco Costalba bcbab19376 Assume UCI 'nodes' is int64_t instead of int
UCI specification is not clear on the size of
integers that are exchanged in the protocol, so
instead of a simple int, assume 'nodes' is a
int64_t because we need a bigger size to store
this value in many real cases, especialy with
very long searches.

No functional change.

Resolves #75
2014-11-05 21:11:05 +00:00
Marco Costalba d29a68f585 Rearrange check_time()
Remove an ugly workaround for a gcc
warning while there.

No functional change.
2014-11-05 21:09:21 +00:00
Ajith 0608d6aaec Add bonuses for each threat instead of max threat value.
Use SPSA tuned values for all threat bonuses

STC
LLR: 2.96 (-2.94,2.94) [-1.50,4.50]
Total: 6074 W: 1284 L: 1160 D: 3630

LTC
LLR: 2.97 (-2.94,2.94) [0.00,6.00]
Total: 13563 W: 2402 L: 2232 D: 8929

Bench: 6981908

Resolves #94
2014-11-04 23:50:54 +08:00
mstembera 2fd075d1ea Optimize TranspositionTable::store() and TranspositionTable::probe() for speed.
No functional change.

Resolves #85
2014-11-03 18:40:49 +00:00
lucasart d12378497c Do not assume that enum are signed
Clang 3.5 issues warning on constructs like: abs(f1 - f2). The thing is that
f1 and f2 are enum types, and the range given (all positive) allows the
compiler to choose an unsigned type (efficiency being one reason to prefer
unsigned arithmetic). If f1 < f2 are unsigned, then f1 - f2 wraps around zero
and the abs() becomes a no-op. It's the reinterpretation of the unsigned
result (large value) as a signed int that happens to give the correct result,
thanks to 2's complement. This is all tricky and dangerous!

In the spirit of the standard, we assume nothing on the signedness of enums,
and simply calculate the rank and file distances as:
- rank_dist(r1, r2) = r1 < r2 ? r2 - r1 : r1 - r2
- file_dist(f1, f2) = f1 < f2 ? f2 - f1 : f1 - f2
this logic can in fact be applied to any enum we may use, so for better
generality and to avoid code duplication, we use a template function diff()
here.

No functional change.

Resolves #95
2014-11-04 00:35:02 +08:00
lucasart 8ab9c2511a Cleanup MAX_PLY
This area has become obscure and tricky over the course of incremental
changes that did not respect the original's consistency and clarity. Now,
it's not clear why we use MAX_PLY = 120, or why we use MAX_PLY+6, among
other things.

This patch does the following:

* ID loop: depth ranges from 1 to MAX_PLY-1, and due to TT constraint (depth
must fit into an int8_t), MAX_PLY should be 128.

* stack[]: plies now range from 0 to MAX_PLY-1, hence stack[MAX_PLY+4],
because of the extra 2+2 padding elements (for ss-2 and ss+2). Document this
better, while we're at it.

* Enforce 0 <= ply < MAX_PLY:
  - stop condition is now ss->ply >= MAX_PLY and not ss->ply > MAX_PLY.
  - assert(ss->ply < MAX_PLY), before using ss+1 and ss+2.
  - as a result, we don't need the artificial MAX_PLY+6 range. Instead we
  can use MAX_PLY+4 and it's clear why (for ss-2 and ss+2).

* fix: extract_pv_from_tt() and insert_pv_in_tt() had no reason to use
MAX_PLY_PLUS_6, because the array is indexed by plies, so the range of
available plies applies (0..MAX_PLY before, and now 0..MAX_PLY-1).

Tested with debug compile, using MAX_PLY=16, and running bench at depth 17,
using 1 and 7 threads. No assert() fired. Feel free to submit to more severe
crash-tests, if you can think of any.

No functional change.
2014-11-03 23:36:24 +08:00
Marco Costalba fc0733087a Restore std::dec after std::hex
Code is leaking a std::hex, and causes subsequent
sync_cout output to be in hexadecimal.

Spotted by Lucas

No functional change.
2014-11-02 08:03:52 +01:00
Marco Costalba 42a20920e5 Retire ScalePawnSpan[]
Obscure, undocmented and misnamed array. Replace with
the direct formula: it is much more clear what the
code does.

No functional change.

Resolves #90
2014-11-01 22:10:25 +00:00
Marco Costalba 79fa72f392 Merge pull request #89 from official-stockfish/pull_no_pretty
Prefer operator<<() to pretty()

No functional change.
2014-11-01 22:24:33 +01:00
Marco Costalba d3091971b7 Retire PawnsFileSpan
It is useless. Tested as no regression:

STC
LLR: 4.06 (-2.94,2.94) [-3.00,1.00]
Total: 140718 W: 28527 L: 28568 D: 83623

LTC
LLR: 2.94 (-2.94,2.94) [-3.00,1.00]
Total: 60034 W: 10359 L: 10303 D: 39372

bench: 6564212

Resolves #88
2014-11-01 20:50:52 +00:00
lucasart d9caede324 Correctly describe POPCNT compile
SSE4.2 has nothing to do with POPCNT. We must dispell this myth, because
Stockfish is a reference and many will copy this mistake if they see it in Stockfish:
* SSE is an SIMD instruction set, relative to vectorization (using special 128-bit registers).
* POPCNT/LZCNT work on normal registers (eg. AL, AX, EAX, RAX).

The confusion comes from the fact that, in the Intel product line, it just
so happens that SSE4.2 and POPCNT/LZCNT came out at the same time. But this
is not true for AMD. For example, all AMD Pheniom II have SSE3 but no
POPCNT/LZCNT, and that is why the modern compile uses  -msse3 -popcnt and not -msse4.2.

No functional change.

Resolves #86
2014-11-01 20:43:57 +00:00
lucasart 8a7876d48d Consistent use of anonymous namespace
Objects that are only accessible at file-scope should be put in the anonymous namespace.
This is what the  C++ standard recommends, rather than using static, which is really C-style and results in static linkage.

Stockfish already does this throughout the code. So let's weed out the few exceptions,
because... they have no reason to be exceptional.

No functional change.

Resolves #84
2014-11-01 20:35:10 +00:00
lucasart 2ee1250294 Remove dead code
No functional change.

Closes #87
2014-11-01 20:16:29 +00:00
Marco Costalba 5644e14d0e Prefer operator<<() to pretty()
It is more idiomatic, we didn't used it
in the past because Position::pretty(Move)
had a calling argument, but now we can.

As an added benefit, we avoid a lot of string
copies in the process because now we avoid
std::ostringstream ss.

No functional change.
2014-11-01 19:02:35 +01:00
Marco Costalba d07a875398 Merge pull request #82 from official-stockfish/clean_up_bishop_code
Code style clean-up

No functional change.
2014-11-01 18:05:03 +01:00
Marco Costalba 460892382a Code style clean-up
This piece of code needs some love.

No functional change.
2014-10-30 12:32:43 +01:00
mstembera 5605cc7684 max_piece_type cleanup, and slight speed increase.
No functional change.

Resolves #81
2014-10-28 22:23:01 +08:00
Joona Kiiski 7d42752158 A small clean up of previous patch suggested by Marco
No functional change
2014-10-27 20:26:12 +00:00
Joona Kiiski fefb27bab4 Speed up max_piece_type()
Write code in the way that allows compiler to perform loop unrolling.

My measurement (32 cycles each):

Orig:

Time (Mean: 2466.59375, Trimmed mean: 2464.25, Std: 12.6869487803348)
Nodes (Mean: 4294458, Trimmed mean: 4294458, Std: 0)
Speed (Mean: 1741.09247987678, Trimmed mean: 1742.72879715475, Std: 8.93612608292678)

Time (Mean: 2470.15625, Trimmed mean: 2468.75, Std: 12.7484581610433)
Nodes (Mean: 4294458, Trimmed mean: 4294458, Std: 0)
Speed (Mean: 1738.58176151341, Trimmed mean: 1739.54618465403, Std: 8.95585822316946)

Mod:

Time (Mean: 2449.90625, Trimmed mean: 2445.9375, Std: 12.1000116635508)
Nodes (Mean: 4294458, Trimmed mean: 4294458, Std: 0)
Speed (Mean: 1752.94829372932, Trimmed mean: 1755.75934908231, Std: 8.61478453124504)

Time (Mean: 2442.78125, Trimmed mean: 2441.1875, Std: 8.17839157228837)
Nodes (Mean: 4294458, Trimmed mean: 4294458, Std: 0)
Speed (Mean: 1758.03872783803, Trimmed mean: 1759.16825356261, Std: 5.81131316346191)

No functional change
2014-10-27 20:25:57 +00:00
snicolet 7de40076ac Tune PawnsFileSpan
Passed the following SPRT tests:

STC:
LLR: 2.96 (-2.94,2.94) [-1.50,4.50]
Total: 24428 W: 5056 L: 4880 D: 14492

LTC:
LLR: 2.96 (-2.94,2.94) [0.00,4.00]
Total: 26590 W: 4715 L: 4472 D: 17403

Bench: 6615949

Resolves #78
2014-10-27 11:48:44 +00:00
Pascal Romaret f1359845de Improve compatibility with Shredder Classic GUI
This commit fixes two issues:

1) Don't print PVs after the search has been interrupted

    This solves the "mate 0 upperbound" scores that sometimes
    creep up when a multi-PV analysis gets interrupted with
    the `stop` command.

2) Print multipv before score

    Shredder Classic fails to identify the main PV
    (the one with multipv 1) if `score` comes first.
    This leads to an eval graph that doesn't reflect
    the scores actually reported by Stockfish when
    doing a multiPV analysis.

No functional change

Closes #76
2014-10-27 11:07:35 +00:00
Marco Costalba 5ab55827b8 Fix an obscure gcc warning
warning: narrowing conversion from ‘int’ to ‘char’ inside { }
is ill-formed in C++11 [-Wnarrowing]

When pedantic meets esoteric!

No functional change.
2014-10-26 19:40:20 +00:00
Marco Costalba 9ba391c5cb Retire notation.cpp
Now we can finally retire notation.cpp
and move UCI helpers under uci.cpp

No functional change.
2014-10-26 19:40:13 +00:00
Marco Costalba 2469daebb1 Final UCI helpers renaming
To reflect new changes, specifically that
now are all under UCI namespace.

No functional change.
2014-10-26 19:40:04 +00:00
Marco Costalba aa60c80ade Retire notation.h
And move the few remaining content
under UCI namespace where they belong.

No functional change.
2014-10-26 19:39:56 +00:00
Marco Costalba 5cbcff55cc Rename ucioption.h to uci.h
We are going to add all UCI related
functions here, so first rename it
to a more proper name.

No functional change.
2014-10-26 19:39:46 +00:00
Marco Costalba 428962a2e8 Retire to_char() helpers
Remove some useless wrappers and make
the conversion explicit and starightforward.

No functional change.
2014-10-26 19:39:37 +00:00
Marco Costalba 4f6b1bf3be Reformat max_threat()
Helper function should just know how to find the
biggest piece type in a bitboard. All the threat
logic and data shoud be in evaluate_threats().

This nicely separates the scope of the two functions
in a more consistent way and simplifies the code.

No functional change.
2014-10-26 09:12:56 +00:00
snicolet 8d62ece945 Calculate maximum threat for hanging pieces
Use the max_threat() helper function to estimate more precisely the
best hanging piece threat.  Also retunes the Threat array using SPSA.

STC
LLR: 2.95 (-2.94,2.94) [-1.50,4.50]
Total: 7598 W: 1596 L: 1468 D: 4534

LTC
LLR: 2.97 (-2.94,2.94) [0.00,6.00]
Total: 7896 W: 1495 L: 1350 D: 5051

Bench: 6816504

Resolves #73
2014-10-24 01:10:11 +08:00
Marco Costalba 480682b670 Document why initing eval tables
Instead of hard-code the weights in a big table,
we prefer to calculate them out of few parameters
at startup. This allows to keep low the number of
independent parameters and hence is good for tuning
and for a better insight in the meaning of the numbers.

No functional change.
2014-10-15 19:36:22 +01:00
Marco Costalba 89d9db2979 Rename Tracing methods
Easier to understand and more in line with
standard Trace classes naming like:

http://msdn.microsoft.com/en-us/library/system.diagnostics.trace.aspx

No functional change.
2014-10-12 20:35:19 +01:00
Marco Costalba 907f912463 Account for Tempo in do_evaluate()
This is more correct because we let evaluate()
to be a pure dispatcher and also now evaluate
and tracing outputs are consistent.

No functional change.
2014-10-12 20:35:07 +01:00
Marco Costalba c97b702f4d Fix some warnings with Intel C++ compiler
No functional change.
2014-10-12 20:34:54 +01:00
lucasart 91de6b0f37 Further streamline connected pawn evaluation
Make even more clear what are the terms that
contribute to evaluate connected pawns, and
completely separate them from the weights
that are now fully looked up in a table.

For future tuning makes sense to init the table with
a formula instead of hard-code it. This allows to
reduce problem space cardinality and makes tuning
easier.

And fix a MSVC warning while there:
warning C4804: '>>' : unsafe use of type 'bool' in operation

No functional change.
2014-10-12 20:03:49 +01:00
lucasart 069073ea68 Merge Connected and Candidate
These two notions are very correlated. Since connected has the most
generality, it makes sense to generalize it to encompass what is
covered by candidate.

STC:
LLR: 4.03 (-2.94,2.94) [-3.00,1.00]
Total: 11970 W: 2577 L: 2379 D: 7014

LTC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 13194 W: 2389 L: 2255 D: 8550

bench 7328585
2014-10-07 07:42:17 +01:00
joergoster 15e2191111 Remove the now redundant TT prefetch call from Position::do_move.
Tested for no regression and passed both
STC
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 48250 W: 9757 L: 9686 D: 28807

LTC
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 51412 W: 8887 L: 8816 D: 33709

No functional change.

Resolves #66
2014-10-06 23:59:56 +08:00
Luca Brivio 8a9b9ec96a Simplify futility move count array formula
No functional change
2014-10-05 12:49:18 +01:00
Marco Costalba 74829342ef Reformat and rename hash_after_move()
Align to standard coding style and properly use
enum types. Rename while there.

No functional change.
2014-10-04 10:36:29 +01:00
Ajith 4b926f227d Extend King Threats to all pieces (other than pawns).
STC
LLR: 2.99 (-2.94,2.94) [-1.50,4.50]
Total: 20559 W: 4261 L: 4095 D: 12203

LTC
LLR: 2.96 (-2.94,2.94) [0.00,4.00]
Total: 75232 W: 13097 L: 12696 D: 49439

Bench: 7543790

Resolves #63
2014-10-04 03:54:12 +08:00
joergoster 82d065b011 Speculative prefetch
Idea by Peter Oesterlund.
Implemented and tested by Joerg Oester

STC 3 threads
ELO: 3.19 +-2.1 (95%) LOS: 99.9%
Total: 40000 W: 7576 L: 7209 D: 25215

LTC
LLR: 2.96 (-2.94,2.94) [0.00,6.00]
Total: 22026 W: 3829 L: 3619 D: 14578

STC
LLR: 2.95 (-2.94,2.94) [-1.50,4.50]
Total: 7291 W: 1531 L: 1404 D: 4356

No functional change

Resolves #61
2014-10-02 22:19:14 +01:00
lucasart e60cdca9b0 Convert TT depth to int8_t
Now that half plies have been removed from the engine, we can encode
TT depth into an int8_t.

Range is -128 to +127, so it goes still further than the previous
limit of 121 plies (with ONE_PLY == 2 where depth - DEPTH_NONE was
encoded as an uint8_t).

No functional change.

Resolved #60
2014-10-01 20:51:32 +01:00
Marco Costalba a1b62d68ec Trivial code style fixes
Mainly to sync mine and official repo.

No functional change.
2014-09-30 09:05:20 +02:00
Marco Costalba 222f59b9c1 Move ONE_PLY to be 1 instead of 2: search()
Now that half-plies are no more used we can simplify
the code assuming that ONE_PLY is 1 and no more 2.

Verified with a SMP test:
LLR: 2.95 (-2.94,2.94) [-4.50,0.00]
Total: 8926 W: 1712 L: 1607 D: 5607

No functional change.
2014-09-29 15:17:12 +02:00
lucasart 27a1877299 Clean up VALUE_KNOWN_WIN conditions
A patch (+ some extra changes) passed with:

STC
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 14575 W: 3101 L: 2967 D: 8507

LTC
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 42579 W: 7580 L: 7496 D: 27503

Bench: 6545733

Resolves #52
2014-09-28 17:45:49 +01:00
Uri Blass ea9c424bba Remove use of half-ply reductions from LMR, Null-move, IID and
Singular extensions.

STC:
ELO: 3.80 +-3.1 (95%) LOS: 99.2%
Total: 19727 W: 4190 L: 3974 D: 11563

LTC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 7647 W: 1356 L: 1214 D: 5077

Bench: 6545733

Resolves #55
2014-09-28 04:33:28 +08:00
Joona Kiiski 7ed15af371 Cap evaluation based null move extra reduction to three plies
It's a zero elo patch, and a reasonable safeguard against uncontrolled extreme reductions.

STC:
ELO: -0.08 +-2.0 (95%) LOS: 46.9%
Total: 40000 W: 6728 L: 6737 D: 26535

LTC:
ELO: -0.14 +-1.8 (95%) LOS: 44.0%
Total: 40000 W: 5557 L: 5573 D: 28870

Bench: 7201830
2014-09-25 20:42:25 +01:00
Uri Blass d6613b7589 Change history reduction in LMR to be a full ply.
STC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 9829 W: 2142 L: 1998 D: 5689

LTC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 27162 W: 4802 L: 4692 D: 17668

Bench: 7284120

Resolves #53
2014-09-26 02:22:39 +08:00
uriblass fed3e752ae Evaluate king safety when no queen is present.
LLR: 2.97 (-2.94,2.94) [-1.50,4.50]
Total: 16657 W: 3547 L: 3391 D: 9719

LLR: 2.95 (-2.94,2.94) [0.00,6.00]
Total: 31258 W: 5664 L: 5403 D: 20191

Bench: 8331165

Resolves #51
2014-09-22 01:32:47 +08:00
Gary Linscott 766fb9c67d Fix spacing.
No functional change.
2014-09-22 01:27:34 +08:00
Marco Costalba b652720903 Rearrange evaluation constants definitions
Make them more uniform and consistent.

No functional change.

Conflicts:
	src/evaluate.cpp
2014-09-21 08:26:25 +08:00
Marco Costalba 4d0a6c5a6f Rename time variable to reflect UCI parameters
On top of previous patch, rename time variables to
reflect the simplification of UCI parameters.

It is more correct to use as varibales directly the
corresponding UCI option, without intorducing redundant
intermediate variables.

This allows also to simplify the code.

No functional change.
2014-09-21 08:23:12 +08:00
mbootsector 2eec710318 King-pawn threat bonus for endgames.
STC:
LLR: 2.95 (-2.94,2.94) [-1.50,4.50]
Total: 10224 W: 1765 L: 1638 D: 6821

LTC:
LLR: 2.96 (-2.94,2.94) [0.00,6.00]
Total: 6923 W: 1027 L: 899 D: 4997

bench 7818100

Resolves #49
2014-09-19 22:36:05 +08:00
Marco Costalba aa10d0aaa6 Rename "Contempt Factor" to "Contempt"
Suggested by Ronald and Lucas on talkchess.

No functional change.

Conflicts:
	src/ucioption.cpp
2014-09-16 21:14:00 +01:00
Marco Costalba ff480bdb83 Retire struct Log
No more used now that we have removed
"Write Search Log" UCI option.

No functional change.
2014-09-16 21:13:50 +01:00
lucasart b66552fc27 Simplify Time Management UCI options
No functional change
2014-09-15 20:24:51 +01:00
Marco Costalba cd065dd584 Small tweak to idle_loop()
In case of a succesful late join we set again
'searching' flag, so we can restart search
immediately without an useless lock/unlock
cycle.

No functional change.
2014-09-04 20:19:03 +01:00
Joona Kiiski 95b24083fb Simplify idle_loop()
No functional change
2014-08-30 21:03:41 +01:00
lucasart 877313a413 Retire Search Log
No functional change

Bench: 7461881
2014-08-24 16:28:51 +01:00
Marco Costalba 8b8885ab07 Fix perft 1
Compute correct number of moves for this corner case.

A smal bug crept in after recent perft rework.

No functional change.
2014-08-10 07:36:22 +08:00
lucasart a903ed07e0 Retire move_to_san()
Now "Write Search Log" will pring moves in UCI format, consistent with all the rest. This functionality is
not aimed at end-users anyway. It's hardly useful at all, in fact. Also, pretty-printing SAN moves is
something that better belongs in the GUI than in the engine.

No functional change.
2014-08-10 07:28:00 +08:00
lucasart 880e3cd7c8 Move to_char() and to_string() to notation
Where they better belong.

Also, this removes '#include <string>' from types.h, which reduces the amount of code to compile (every
translation unit includes types.h).

No functional change.
2014-08-09 13:25:05 +08:00
Marco Costalba a67c22611a Rework perft implementation
Unify various perft functions and move all the code
to search.cpp.

Avoid perft implementation to be splitted between
benchmark.cpp (where it has no reason to be) and
search.cpp

No functional and no speed change (tested).
2014-08-09 13:00:59 +08:00
lucasart 2efeded6e3 Write perft(N-1) into cout
So that one can redirect cout to /dev/null and only print print cerr in the terminal (for more accurate speed
tests).

Suggested by Marco.

No functional change.
2014-08-07 21:15:05 +08:00
lucasart 6044f25d71 Fix Hash in bench
The compiler tries to cast Options["Hash"] into a string, using:

Option::operator std::string() const {
  assert(type == "string");
  return currentValue;
}

And, as expected, the assert() fails.

std::to_string() would be the right solution, but it's C++11. And using a stringstream is too much code to
achieve so little. Let's keep it the way it was: hardcoded (ie. default hash defined in two places).

No functional change.
2014-08-07 18:51:07 +08:00
joergoster 9da015517c Remove insufficient material rule
The eval already returns zero in KK, KBK, KNK (see material.cpp). The difference is:
- we lose the "TB pruning" benefit of the draw rule (ie. search goes on even if eval is zero)
- we gain some speed by removing a useless test from the hot path

STC:
LLR: 0.05 (-2.94,2.94) [-3.00,1.00]
Total: 128000 W: 21357 L: 21560 D: 85083

LTC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 33023 W: 4613 L: 4509 D: 23901

bench 7461881
2014-08-06 18:42:10 +08:00
lucasart 888a1d3445 Remove useless code in Position::pretty()
First, remove some dead code (function never called with a Move argument).

Then, remove printing of legal moves, which does not belong here. Let's keep commands orthogonal and minimal:
- the "d" command should display the board, nothing more, or less.
- "perft 1" will display the list of legal moves.

No functional change.
2014-08-06 07:04:27 +08:00
lucasart 8b88ca9017 Reduce minimum memory requirement by 16MB
Stockfish allocates the default hash (32MB) in main(), before entering UCI::loop(). If there is not enough
memory, the program will crash even before UCI::loop() is entered and the GUI is given a change to specify a
lower Hash value.

This defective design could be resolved by doing a lazy allocation upon "isready" command, as the UCI protocol
guarantees that "isready" will be sent at least once before any search. But it's a bit cumbersome when using
Stockfish "manually" to have to remember to type "isready" everytime.

So leave the current design, but reduce the default hash to 16MB instread of 32MB. In order to perform such
quick searches (depth=13), there is no reason to use so much Hash anyway. Another benefit is to introduce a
bit of hash pressure in bench, which increases chances to detect rare bugs related to TT replacement, for
example.

This is not a functional change, although it obviously changes the bench.

bench 7461879
2014-08-05 11:42:48 +08:00
lucasart 94fe366779 Default Hash defined in a single place
Instead of defining it both in ucioption.cpp and benchmark.cpp. Obviously changing the default Hash will
change the bench as a result.

No functional change.
2014-08-05 11:40:25 +08:00
lucasart 535f70088e Retire divide command
The main purpose of perft is to help debugging. But without the breakdown in sum of perft(N-1), it is a
completely useless debugging tool.

So perft now displays the breakdown, and divide is therefore removed.

No functional change.
2014-08-04 13:54:09 +08:00
Marco Costalba 1b69910865 Ensure printing UCI info in multi-pv case
After commit 94b1bbb68b, in case available root moves are less than multiPV, we
could never reach condition:

PVIdx + 1 == multiPV

and as a consequence UCI output is not printed.

Fixed suggested by Joerg Oster.

No functional change.
2014-08-02 22:16:45 +08:00
Oskar Werkelin Ahlin 29451de874 Correct bench timing
No functional change.
2014-08-01 19:32:53 +08:00
lucasart 5adc678628 Document Threat[] indices
From Marco's repo.

No functional change.
2014-07-30 07:06:48 +08:00
Marco Costalba f2053ba19f Fix a warning with MSVC 2010
Warning C4267: 'argument' : conversion from 'size_t' to 'int', possible loss of data

No functional change.
2014-07-29 06:53:09 +08:00
David Zar 68171ecaca Small code style reformatting
No functional change.
2014-07-29 06:52:32 +08:00
lucasart 6b82a234d0 Aspiration: widen slower
STC:
LLR: -2.95 (-2.94,2.94) [0.00,4.00]
Total: 182323 W: 30664 L: 30234 D: 121425

LTC:
LLR: 3.51 (-2.94,2.94) [0.00,4.00]
Total: 59841 W: 8345 L: 8006 D: 43490

bench 7962536
2014-07-27 09:18:04 +08:00
David Zar 4758fd31b1 Outpost tuning
double mg bonus and half eg bonus.

STC:
LLR: 2.95 (-2.94,2.94) [-1.50,4.50]
Total: 18142 W: 3094 L: 2948 D: 12100

LTC:
LLR: 2.95 (-2.94,2.94) [0.00,4.00]
Total: 83561 W: 11706 L: 11329 D: 60526

bench 7831429
2014-07-23 07:05:10 +08:00
lucasart 7f68fc611c Revert Contempt = 20
Despite being neutral at STC, it turned out to be regressive at LTC:

40k games at LTC with Hash=8
ELO: -2.06 +-1.9 (95%) LOS: 1.4%
Total: 39720 W: 5740 L: 5976 D: 28004

40k games at LTC with Hash=128
ELO: -2.69 +-1.9 (95%) LOS: 0.2%
Total: 39149 W: 5702 L: 6005 D: 27442

bench 7477963
2014-07-20 08:50:54 +08:00
Marco Costalba 896bd917f8 Simplify evaluate_passed_pawns
From a suggestion by David Zar.

No functional change.
2014-07-15 20:59:32 +08:00
lucasart 67a5e1ecf9 Contempt = 20
Also raise the admissible bounds to (-100,100), as there is no reason to prevent users from using high
values if they want to.

Does not regress in self play:
ELO: 0.10 +-2.0 (95%) LOS: 53.7%
Total: 40000 W: 7084 L: 7073 D: 25843

master vs SF 3
ELO: 182.86 +-2.7 (95%) LOS: 100.0%
Total: 40000 W: 21843 L: 2541 D: 15616

Contempt = 20 vs SF 3
ELO: 189.25 +-2.8 (95%) LOS: 100.0%
Total: 40000 W: 22721 L: 2859 D: 14420

Diff is therefore 6.4 +/- 3.9 elo against a 180-190 elo weaker engine, which is significantly positive,
as expected. This elo difference is likely understated, because of FishTest aggressive draw adjudication
though.

We could push Contempt further, but after 20cp, it would get in the way of FishTest draw adjudication
rule, and is likely to reduce the testing throughput as a result.

bench 8198667
2014-07-15 07:14:58 +08:00
David Zar a9b8e8b931 Bonus passed pawn blocked by our pieces
passed STC:
LLR: 2.95 (-2.94,2.94) [-1.50,4.50]
Total: 63965 W: 10950 L: 10692 D: 42323

and LTC:
LLR: 2.95 (-2.94,2.94) [0.00,6.00]
Total: 19237 W: 2740 L: 2562 D: 13935

bench: 7477963
2014-07-14 21:19:07 +08:00
Marco Costalba 94b1bbb68b Small reformat to Skill class
Steamline a bit the implementation of
skill levels. As a side effect we can
retire MultiPV global and use a local
variable instead.

No functional change.
2014-07-11 18:08:27 +08:00
lucasart f133f61e3f Remove useless condition
Small simplification, suggested by Uri Blass.

passed STC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 25839 W: 4464 L: 4351 D: 17024

and LTC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 220039 W: 29981 L: 30131 D: 159927

No functional change.
2014-07-10 18:25:20 +08:00
Joona Kiiski eb50793cff Retire FakeSplit
- Currently broken
    - Never been really useful
    - Does not work well with new splitting model

Verified for no regression at STC with 3 threads:
LLR: 2.96 (-2.94,2.94) [-6.00,0.00]
Total: 81905 W: 12122 L: 12381 D: 57402

No functional change
2014-07-09 07:19:06 +08:00
Marco Costalba 9b30913996 Avoid 'double assigments' tricks
Bitboard init code is already noteasy to follow,
so don't make it even harder using 'smart' code.

Also reindent a while loop in standard way.

No functional change.
2014-07-07 21:53:25 +08:00
joergoster ac7780bd35 Tune trapped rook penalty
Passed STC
LLR: 2.96 (-2.94,2.94) [-1.50,4.50]
Total: 15687 W: 3352 L: 3199 D: 9136

and LTC (parameter tweaks)
LLR: 2.95 (-2.94,2.94) [0.00,4.00]
Total: 27983 W: 5046 L: 4797 D: 18140

bench: 8330705
2014-07-03 19:38:54 +08:00
lucasart c192b692cf size_t cast in TranspositionTable::first_entry()
32-bit truncation would make this function bogus when clusterCount >= 2^33 (ie. Hash >= 256 GB).

No function change.
2014-07-03 18:23:56 +08:00
lucasart 85b08ce3ad Use compiler intrinsic instead of assembly for popcnt
This time, do not break compatibility with some AMD machines that have SSE3 and popcnt, but do
not have SSE4.2.

No functional change.
2014-07-03 18:22:53 +08:00
Gary Linscott b9a88da4ab Revert "Use compiler intrinsic instead of assembly for popcnt"
This reverts commit a69f1d7c20.
2014-07-01 17:01:54 -04:00
lucasart a69f1d7c20 Use compiler intrinsic instead of assembly for popcnt
No functional change.
2014-07-01 20:50:33 +08:00
lucasart 24ba204931 Raise max Hash to 1TB
And use size_t where appropriate, as suggested on FishCooking.

No functional change.
2014-07-01 18:37:18 +08:00
Ajith 6b354305e1 Add bonuses for Minors attacking enemy pieces(except pawns) even when they are protected by enemy pawns.
Patch passed STC
LLR: 2.95 (-2.94,2.94) [-1.50,4.50]
Total: 8206 W: 1426 L: 1304 D: 5476

and LTC
LLR: 2.97 (-2.94,2.94) [0.00,6.00]
Total: 19534 W: 2821 L: 2640 D: 14073

Bench: 9942172
2014-06-30 10:55:10 -04:00
joergoster ffedfa3354 Fix Singular extension condition to handle mate scores
With Eelco's patch "Don't special case for abs(beta) >= VALUE_MATE_IN_MAX_PLY" condition "abs(ttValue) < VALUE_KNOWN_WIN" has been removed from singular extension search, and condition "abs(beta) < VALUE_KNOWN_WIN" was added to the SingularExtensionNode definition.
This might lead to problems, especially in positions, where a mate is due.
For example, this position 5rk1/4K1pp/8/5PPP/8/8/8/1R6 w - - 12 1 triggers an assert.
stockfish: search.cpp:434: Value {anonymous}::search(Position&, Search::Stack*, Value, Value, Depth, bool) [with {anonymous}::NodeType NT = (<unnamed>::NodeType)2u; bool SpNode = false]: Assertion `-VALUE_INFINITE <= alpha && alpha < beta && beta <= VALUE_INFINITE' failed.

So let's re-insert the removed condition.
First spotted by Uri Blass, fix by me.

Bench: 8759675
2014-06-29 20:17:40 +01:00
Joseph R. Prostko e4e423bb05 Change the install prefix for Haiku
* /boot/common was removed from Haiku
* The equivalent path now that package management has been implemented is /boot/system/non-packaged

No functional change

Bench: 8759681
2014-06-29 15:15:10 +01:00
Ron Britvich ccd823a4ff Pack 3 TT entries in 32 bytes cluster
Idea from Ron Britvich

Code reworked by Marco Costalba and Joona Kiiski

Bench: 8095369

Resolves #3
Resolves #10
2014-06-28 14:06:32 -04:00
Gary Linscott 7ff865b924 Merge pull request #9 from glinscott/pawnspan
Scale down endgames with pawns on one or two adjacent files

Passed STC
LLR: 2.95 (-2.94,2.94) [-1.50,4.50]
Total: 16081 W: 2745 L: 2604 D: 10732

Passed LTC
LLR: 2.95 (-2.94,2.94) [1.00,6.00]
Total: 123832 W: 17292 L: 16584 D: 89956

128k games to measure ELO at 15+0.05:
ELO: 2.07 +-1.1 (95%) LOS: 100.0%
Total: 128000 W: 21632 L: 20869 D: 85499

New bench: 8028792
2014-06-26 12:21:06 -07:00
Gary Linscott ec627911f0 A bit more cleanup 2014-06-26 15:20:30 -04:00
Gary Linscott 22ffb588e5 Merge pull request #8 from glinscott/revert_ce1c260
Revert "Check for an available slave early on"
2014-06-26 08:20:45 -07:00
Gary Linscott e6a8d03dd8 Revert "Check for an available slave early on"
This reverts commit ce1c260ea9.
2014-06-26 11:16:36 -04:00
Gary Linscott 747e035c7d Original version of shane's patch 2014-06-25 16:45:14 -04:00
shane31 6c9f4cf36f Scale down endgames with pawns on one or two adjacent files 2014-06-25 16:01:00 -04:00
Gary Linscott ab580106fd Merge pull request #5 from glinscott/authors
Add AUTHORS
2014-06-23 09:14:03 -07:00
Marco Costalba aa23eb4440 Some reformatting in pawns.cpp
No functional change.
2014-06-21 15:08:31 +02:00
Marco Costalba e8baf2b772 Ensure ttValue != VALUE_NONE in singular extension search
The assert:

  assert(ttValue != VALUE_NONE);

Could fire for multiple reasons (although is very rare),
for instance after an IID we can have ttMove != MOVE_NONE
while ttValue is still set at VALUE_NONE.

But not only this, actually SMP is a source of corrupted
ttValue and anyhow we can detect the condition:

 ttMove != MOVE_NONE && ttValue == VALUE_NONE

even north of IID.

Reported by Ronald de Man.

It is so rare that bench didn't change.

bench: 7710548
2014-06-21 13:07:29 +02:00
Gary Linscott 58bb23d0c3 Remove some duplicates 2014-06-21 00:49:49 -04:00
Gary Linscott bbacff5e01 Add AUTHORS 2014-06-20 21:35:09 -04:00
Marco Costalba 43efd7fad7 Better value clipping in game_phase()
No functional change.
2014-06-21 00:05:14 +02:00
Marco Costalba 3b315c9ada Move game_phase() to Position
It seems a more natural to place this
function there.

No functional change.
2014-06-20 23:44:46 +02:00
Marco Costalba f7926ea41e Small renaming in material weights
Also dropped some temporary variable: compiler
is more than able to push on stack temp values
by itself (verified).

No functional change.
2014-06-20 23:15:31 +02:00
Marco Costalba 264c8637a3 Simplify a condition in is_KXK()
No functional change.
2014-06-19 15:44:42 +02:00
Eelco de Groot 55a3e0af8d Don't special case for abs(beta) >= VALUE_MATE_IN_MAX_PLY
Remove from the search this special case and apply
null search and razoring also in mate positions.

Tested in no-regression mode and passed both

STC
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 65431 W: 10860 L: 10810 D: 43761

and LTC
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 34928 W: 4814 L: 4713 D: 25401

This patch kicks in only in mate positions and in
these cases it seems beneficial in finding mates
faster as Yery Spark measured on the Chest mate suite:

Total number of positions 6425
Fixed nodes 200K per position

master: 1049
new:    1154

And also the 5446 'hard' positions again with 2000K nodes
(those not found by both engines in 200K nodes):

master: 1069
new:    1395

bench: 7710548
2014-06-16 21:50:14 +02:00
Leonid Pechenik 66c93245e0 Simplify unstoppable pawns
Tested in no-regression mode and passed both

STC
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 17919 W: 3103 L: 2978 D: 11838

and LTC
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 31460 W: 4414 L: 4308 D: 22738

bench: 7709279
2014-06-16 12:39:50 +02:00
Marco Costalba 73ca93f3c0 Remove -ansi flag for Clang
It seems this flag is only for gcc and
yields a warning under OSX Mavericks:

clang: warning: argument unused during compilation: '-ansi'

No functional change.
2014-06-15 10:31:57 +02:00
Marco Costalba c6fc51c5ea Fix a warning with MSVC in 'analyze' mode
Here MSVC is worried that

StepAttacksBB[PAWN][psq]

could overflow, so change psq initialization
to clarify psq is always less than 64.

No functional change.
2014-06-14 12:46:58 +02:00
Marco Costalba 2cb4c7052e Triviality in UCI::loop
Code style paranoid in action here :-)

No functional change.
2014-06-14 12:26:08 +02:00
Marco Costalba 3c1201c20c Factor out pawn attacks in 'lever'
Improves readibility and possibly speed.

No functional change.
2014-06-14 12:20:54 +02:00
Ajith 84dabe5982 Simplify pawn threats and merge into ThreatenedByPawn[]
Tested in no-regression mode,

passed STC
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 14477 W: 2493 L: 2362 D: 9622

and LTC
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 51964 W: 7091 L: 7013 D: 37860

bench: 7875814
2014-06-12 08:32:16 +09:00
Reuven Peleg e10276f45d Tweak outpost name
This name is more accurate, since that function evaluates only one
outpost in every call.
No functional change.
2014-06-11 23:42:47 +09:00
Reuven Peleg 2312c26722 Add bonus for advanced lever
Passed both STC
LLR: 2.95 (-2.94,2.94) [-1.50,4.50]
Total: 15413 W: 2670 L: 2530 D: 10213

And LTC:
LLR: 2.95 (-2.94,2.94) [1.00,6.00]
Total: 66908 W: 9398 L: 8960 D: 48550

Bench : 7859385
2014-06-11 23:38:25 +09:00
Marco Costalba b6cd89aeaf Small renaming in Tracing
No functional change.
2014-06-09 05:30:18 +09:00
Marco Costalba ce1c260ea9 Check for an available slave early on
Don't take the split lock if we don't have
available slaves (about 30-40% of times).

This new condition allows to retire the now
redundant one on number of threads.

No functional change.
2014-06-09 04:56:31 +09:00
Marco Costalba 4d30126e4b Use unsigned char as argument of std::isspace
Although signature allows an int:

int isspace( int ch );

The behavior is undefined if the value of ch is
not representable as unsigned char and is not
equal to EOF.

See

http://en.cppreference.com/w/cpp/string/byte/isspace
http://www.greenend.org.uk/rjk/tech/cfu.html

This is really a tricky corner case of C standard!

Spotted and reported by Ron Britvich.

No functional change.
2014-06-07 01:21:47 +02:00
Marco Costalba 7f56d2949d Avoid to use nullChild
Use instead:

(ss-1)->currentMove == MOVE_NULL

No functional change.
2014-06-06 11:12:05 +02:00
Marco Costalba d10ae90dea Remove 'update gains' hack
Use (move != MOVE_NONE) condition to
filtering out updating gains at root.

bench: 8454456
2014-06-06 11:10:40 +02:00
Marco Costalba 2f75639485 Temporary revert previous patch
Split previous patch in 2 steps: first remove
the MOVE_NULL hack, then retire nullChild.

The first step is a prerequisite
for second one and affects bench.

The second step (next patch) just removes nullChild
without affecting bench.

bench: 8205159
2014-06-06 11:08:35 +02:00
Marco Costalba ad1167c482 Avoid to use nullChild
Should be a non functional change, but
for some reason bench is changed.

bench: 8454456
2014-06-06 10:07:48 +02:00
Marco Costalba 08753771fc Move Tempo to evaluation
No functional change.
2014-06-06 09:40:01 +02:00
Marco Costalba 69ac45d903 Revert "Score extractors"
Are broken for big-endian case and
I have verified with MSVC 2013 Premium
bench is correct and there is no
miscompilation, so the main reason
to change the original code drops.

No functional change.
2014-06-05 23:55:18 +02:00
Marco Costalba 323a006666 Fix a warning with MSVC Premium 2013
Reported by Ron Britvich.

No functional change.
2014-06-05 23:46:58 +02:00
pellanda 16e170d105 Update Readme.md
Retire line about polyglot.ini and
book as they are not used anymore.

No functional change.
2014-06-04 22:31:59 +02:00
Lucas Braesch adeded29fb Symmetric King Safety: take 2
Another attempt at retiring current asymmetric
king evaluation and use a much simpler symmetric
one. As a good side effect we can avoid recalculating
eval after a null move.

Tested in no-regression mode and passed

STC
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 21580 W: 3752 L: 3632 D: 14196

LTC
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 18253 W: 2593 L: 2469 D: 13191

And a LTC regression test against SF DD to
verify we don't have regression against
weaker engines due to some kind of 'contempt'
effect:

ELO: 54.69 +-2.1 (95%) LOS: 100.0%
Total: 40000 W: 11072 L: 4827 D: 24101

bench: 8205159
2014-06-03 20:01:36 +02:00
Marco Costalba 187a9fe5e7 Use see() instead of see_sign() in previous patch
Before it was working by accident in case of
see_sign() and failing with see() due to how
castle moves are coded (king captures the rook).

Better to explicitly filter out castling moves
and use see() without any surprise/trick.

No functional case.
2014-06-03 12:38:58 +02:00
kinderchocolate 6f48367094 Add some const qualifier
No functional change.
2014-06-03 11:43:52 +02:00
Reuven Peleg 83a574ff27 Decrease reduction for moves that escape a capture
Passed both STC
LLR: 2.96 (-2.94,2.94) [-1.50,4.50]
Total: 10094 W: 1833 L: 1704 D: 6557

and LTC
LLR: 2.95 (-2.94,2.94) [0.00,6.00]
Total: 27738 W: 4147 L: 3928 D: 19663

bench : 8599236
2014-06-03 11:33:19 +02:00
Marco Costalba f4dcec0b94 Retire Polyglot Book management
Book handling belongs to GUI, we kept this code
for historical reasons, but nowdays there is
really no need of this old, (mostly) unused
and especially incorrect designed functionality.

It is up to the GUI to choose the book (far easier for
the user) and to select the book parameters. In no
place, including fishtest, TCEC, rating lists, etc.
the "own book" is used, moreover currently SF is
released without any book and even if in the future we
bundle a book in the release package, it will be the GUI
that will take care of it.

This corrects a wrong design decision that Galurung
and later Stockfish inherited from what was common
practice many yeas ago.

No functional change.
2014-06-01 15:29:34 +02:00
Marco Costalba e4fc9d84d7 Retire eval weights UCI options
There is really little that user can achieve (apart
from a weakened engine) tweaking these parameters
that are already tuned and have no immediate or visible
effect.

So better do not expose them to the user and avoid the
typical "What is the best setup for my machine?" kind of
question (by far the most common, by far the most useless).

No functional change.
2014-06-01 13:37:21 +02:00
Marco Costalba 07a525cdfd Retire polyglot.ini
All actively maintained GUI are able
to understand UCI protocol, so there
is no more need for this obsolete file.

No functional change.
2014-05-31 23:48:23 +02:00
Marco Costalba f5622cd5ec Restore development version
bench: 8732553
2014-05-31 23:34:36 +02:00
Marco Costalba 54f8a9cb13 Stockfish 5
Stockfish bench signature is: 8732553
2014-05-31 09:16:54 +02:00
Marco Costalba ad937d0b2d Revert "Symmetric king safety"
Regression test of 40K games at 60 secs shows
this commit to be a 2-3 ELO regression.

So revert to original king safety.

bench: 8732553
2014-05-26 21:39:48 +02:00
Marco Costalba 495a0fa699 Fix a warning with Intel compiler
warning #2259: non-pointer conversion from
"int" to "int16_t={short}" may lose significant
bits.

No functional change.
2014-05-25 00:21:46 +02:00
Marco Costalba 585655b16e Tidy up tt.h
Backport some non-functional changes
found working on 'dense TT' patch.

No functional change.
2014-05-25 00:02:09 +02:00
Marco Costalba e49eb67119 Add perft 'divide' command
To show perft numbers for each move. Just
use 'divide' instead of 'perft', for instance:

position startpos moves e2e4 e7e5
divide 4

Inspired by Ronald de Man.

No functional change.
2014-05-24 09:56:32 +02:00
Marco Costalba 88b5100e29 Update polyglot.ini after last patch
No functional change.
2014-05-19 21:19:47 +02:00
Lucas Braesch 40f5abba10 Symmetric king safety
Retire current asymmetric king evaluation
and use a much simpler symmetric one.

As a side effect retire the infamous
'Aggressiveness' and 'Cowardice' UCI
options.

Tested in no-regression mode,

Passed both STC
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 33855 W: 5863 L: 5764 D: 22228

And LTC
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 40571 W: 5852 L: 5760 D: 28959

bench: 8321835
2014-05-19 14:24:39 +02:00
Marco Costalba 5e03734eac Fix an off-by-one bug in extract_pv_from_tt
At root we start counting plies from 1,
instead pv[] array starts from 0. So
the variable 'ply' we use in extract_pv_from_tt
to index pv[] is misnamed, indeed it is
not the real ply, but ply-1.

The fix is to leave ply name in extract_pv_from_tt
but assign it the correct start value and
consequentely change all the references to pv[].
Instead in insert_pv_in_tt it's simpler to rename
the misnamed 'ply' in 'idx'.

The off-by-one bug was unhidden when trying to use
'ply' for what it should have been, for instance in
this position:

position fen 8/6R1/8/3k4/8/8/8/2K5 w - - 0 1

at depth 24 mate line is erroneusly truncated due
to value_from_tt() using the wrong ply.

Spotted by Ronald de Man.

bench: 8732553
2014-05-17 22:59:07 +02:00
Marco Costalba e46a72dd1d Extract a reliable PV line
Truncate the extracted PV from the point where
the score stored in hash starts to deviate from
the root score.

Idea from Ronald de Man.

bench: 8732553
2014-05-17 12:49:52 +02:00
Michel Van den Bergh 5ec63eb6b6 Drop to qsearch at low depth in razoring
If razoring conditions are satisfied and
depth is low, then directly drop in qsearch.

Passed both STC
LLR: 2.98 (-2.94,2.94) [-1.50,4.50]
Total: 12914 W: 2345 L: 2208 D: 8361

And LTC
LLR: 2.95 (-2.94,2.94) [0.00,6.00]
Total: 50600 W: 7548 L: 7230 D: 35822

bench: 8739659
2014-05-13 22:37:28 +02:00
Arjun Temurnikar a3c8c4b70d Remove undefended minors
Tested in "no regression" mode.

Passed both STC
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 68026 W: 12277 L: 12236 D: 43513

And LTC
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 85682 W: 12861 L: 12836 D: 59985

bench: 7311935
2014-05-13 21:37:42 +02:00
Marco Costalba 696d6cedb9 Save stalemates in TT
When there aren't legal moves after
a search, instead of returning imediately,
save bestValue in TT as in the usual case.

There is really no reason to special case
this one.

With this patch is fully fixed (again) follwing
position:

    7k/6p1/6B1/5K1P/8/8/8/8 w - - 0 1

Also in SMP case.

bench: 8802105
2014-05-11 10:56:25 +02:00
Marco Costalba 9f843adf89 Retire "Idle Threads Sleep" UCI option
After last Joona's patch there is no measurable
difference between the option set or unset.

Tested by Andreas Strangmüller with 16 threads
on his Dual Opteron 6376.

After 5000 games at 15+0.05 the result is:

1 Stockfish_14050822_T16_on   : 3003  5000 (+849,=3396,-755), 50.9 %
2 Stockfish_14050822_T16_off  : 2997  5000 (+755,=3396,-849), 49.1 %

bench: 880215
2014-05-11 10:29:56 +02:00
Arjun Temurnikar bfd8704a7d Make imbalance table more clear
No functional change.
2014-05-10 08:54:31 +02:00
Reuven Peleg f89a8f0769 Pass Position as const ref in update_stats()
No functional change.
2014-05-08 22:36:30 +02:00
Marco Costalba 6ba1d3ead6 Clarify some comments in SMP code
Spotted by Joona.

No functional change.
2014-05-08 09:09:35 +02:00
Marco Costalba 7e3dba4f4c Reformat and simplify previous patch
No functional change.
2014-05-07 08:56:16 +02:00
Joona Kiiski f6e98a924a Allow a slave to 'late join' another splitpoint
Instead of waiting to be allocated, actively search
for another split point to join when finishes its
search. Also modify split conditions.

This patch has been tested with 7 threads SMP and
passed both STC:

LLR: 2.97 (-2.94,2.94) [-1.50,4.50]
Total: 2885 W: 519 L: 410 D: 1956

And a reduced-LTC at  25+0.05
LLR: 2.95 (-2.94,2.94) [0.00,6.00]
Total: 4401 W: 684 L: 566 D: 3151

Was then retested against regression in 3 thread case
at standard LTC of  60+0.05:

LLR: 2.96 (-2.94,2.94) [-4.00,0.00]
Total: 40809 W: 5446 L: 5406 D: 29957

bench: 8802105
2014-05-07 08:38:56 +02:00
Ron Britvich 8f6a494ad7 Rewrite Score extractors
Less tricky and even a bit faster. With this
version Visual Studio Ultimate 2013 Update 2 RC
runs fine even in O2 optimization.

No functional change.
2014-05-05 09:05:29 +02:00
Marco Costalba b8e6f83cfb Change search() signature
Pass SpNode as template parameter.

No functional change.
2014-05-04 13:35:30 +02:00
Marco Costalba 5413fda739 Revert dynamic contempt
On a final fixed game number test it failed
to prove better than standard version.

STC 15+0.05

ELO: -0.86 +-1.7 (95%) LOS: 15.8%
Total: 57578 W: 10070 L: 10213 D: 37295

bench: 8802105
2014-05-04 09:58:49 +02:00
Marco Costalba 145d293142 Revert stalemate detection in evaluation
Unfortunatly we have a slow down that causes
a regression in STC with no-regression mode:

LLR: -2.96 (-2.94,2.94) [-3.00,1.00]
Total: 22454 W: 3836 L: 4029 D: 14589

bench: 8678654
2014-05-04 09:42:32 +02:00
Marco Costalba f1240483fb Revert back KBPsK to latest Gary's version
The bug was found to be elsewhere. This version
is correct and also is able to detect as draw
positions like:

8/8/5b2/8/8/4k1p1/6P1/5K2 b - - 6 133

bench: 8678654
2014-05-04 09:34:22 +02:00
Ronald de Man c0d3010438 Fix KXK endgame
Position is win also if strong side has a bishop
and a knight (plus other material, otherwise
KBNK would be triggered instead of KXK).

This fixes a subtle bug where a search on position

k7/8/8/8/8/P7/PB6/K7 b - - 6 1

Instead of returning a draw score, suddendly returns
a big score. This happens because at one point in
search we reach this position:

8/Pk6/8/8/8/4B3/P7/K7 w - - 3 8

Where white can promote. In case of rook promotion (and also in case of
queen promotion) the resutling position gets a huge static eval that is
above VALUE_KNOWN_WIN (from the point of view of white). So for rook
promotion it is

          &&  futilityBase > -VALUE_KNOWN_WIN

that prevents futility pruning in qsearch. (Removing this condition indeed
lets the problem occur). Raising the static eval for K+B+N+X v K to a value
higher than VALUE_KNOWN_WIN fixes this particular problem without having to
introduce an extra futility pruning condition in qsearch.

I just checked and it seems K+R v K, K+2B v K and even K+B+N v K already get
a huge static eval. Why not K+B+N+P v K?

I think this fix corrects an oversight. There is special code for KBNK, but
KBNXK is handled by KXK, so the test for sufficient material should also test
for B+N.

bench: 8678654
2014-05-03 21:40:09 +02:00
Marco Costalba a9e93fa6a5 Fully correct stealmate detection
In the (rare) cases when the two conditions
are true, then fully check again with a slow
but correct MoveList<LEGAL>(pos).size().

This is able to detect false positives like
this one:

8/8/8/Q7/5k1p/5P2/4KP2/8 b - - 0 17

When we have a possible simple pawn push that
is not stored in attacks[] array. Because the
third condition triggers very rarely, even if
it is slow, it does not alters in a measurable
way the average speed of the engine.

bench: 8678654
2014-05-03 12:12:22 +02:00
Marco Costalba 9e8bf82350 Add stealmate detection to evaluation
Currently a stealmate position is misevaluated
in a negative/positive score, this leads qsearch(),
that does not detects stealmates too, to return the
wrong score and this yields to some kind of endgames
to be completely misevaluated.

With this patch is fully fixed follwing position

7k/6p1/6B1/5K1P/8/8/8/8 w - - 0 1

Also in SMP case.

Correct root cause analysys by Ronald de Man.

bench: 8678654
2014-05-03 11:47:49 +02:00
Marco Costalba dc87ec7258 Revert to Galurung's KBPsK endgame
After reverting to the original Tord's
endgame, a search on position

7k/6p1/6B1/5K1P/8/8/8/8 w - - 0 1

Reports, correctly, a draw score instead of
an advantage for white.

Issue reported by Uri Blass.

bench: 8678654
2014-05-02 11:04:18 +02:00
Marco Costalba 43973f43c6 Use only standard conforming eg_value()
Remove the optimization for Intel, is not
standard and can break at any time, moreover
our release build is not done with Intel C++
anymore so we don't need to sqeeze the extra
speed out from this compiler.

No functional change.
2014-05-01 23:08:07 +02:00
Marco Costalba bee4f1cf09 Don't save stale value in TT after split
If we return from split with a stale value
due to a stop or a cutoff upstream occurred,
then we exit moves loop and save a stale value
in TT before returning search().

This patch, from Joona, fixes this.

bench: 8678654
2014-05-01 16:26:18 +02:00
Marco Costalba da91a34c09 Better document search stop condition
Handling a stop or a cutoff in the search is
a tricky business, so better document this
difficult part of the code.

No functional change.
2014-05-01 08:48:59 +02:00
Marco Costalba 626dc8a03b Remove dead code in search
We can never have bestValue == -VALUE_INFINITE at
the end of move loop because if no legal move exists
we detect it with previous condition on !moveCount,
if a legal move exists we never prune it due to
futility pruning condition:

bestValue > VALUE_MATED_IN_MAX_PLY

So this code never executes, as I have also verified
directly.

Issue reported by Joona.

No functional change.
2014-05-01 07:46:44 +02:00
Marco Costalba cf50e265fa Fix a compile error with Intel C++
Intel compiler is very picky:
"error: this operation on an enumerated type requires an
applicable user-defined operator function"

Reported by Tony Gaor.

No functional change.
2014-04-30 08:55:45 +02:00
snicolet d3ffd0ffca Penalize hanging pieces
Passed both STC
LLR: 2.95 (-2.94,2.94) [-1.50,4.50]
Total: 8519 W: 1565 L: 1440 D: 5514

And LTC
LLR: 2.95 (-2.94,2.94) [0.00,6.00]
Total: 60618 W: 9141 L: 8777 D: 42700

bench: 8678654
2014-04-30 08:36:44 +02:00
Marco Costalba db229504e2 Rearrange interpolation formula
Put the division at the end to reduce
rounding errors. This alters the bench
due to different rounding errors, but
should not alter ELO in any way.

bench: 7615217
2014-04-28 17:27:49 +02:00
mstembera 918c29f83a Minor stuff scattered around
Just random minor stuff I found while browsing the code.

No functional change.
2014-04-28 17:07:43 +02:00
Marco Costalba a1f39c1ef9 Remove other useless floor()
No functional change.
2014-04-27 19:17:40 +02:00
Marco Costalba 9f2a64abd2 Don't need floor() in timeman.cpp
For positive numbers result is equivalent:
http://stackoverflow.com/questions/3300290/cast-to-int-vs-floor

Spotted by Joseph Ellis.

No functional change.
2014-04-27 19:10:00 +02:00
Marco Costalba 93e3b06fe2 Fix Intel compiler warnings
Fallout from previous patch: Intel compiler
is very noisy.

No functional change.
2014-04-27 12:02:36 +02:00
Marco Costalba 86c20416c8 Remove some useless casts
No functional change.
2014-04-27 11:44:16 +02:00
Marco Costalba c9e396b542 We can add an integer to a Value
We have defined corresponding operators,
so rely on them to streamline the code
and increase readibility.

No functional change.
2014-04-27 11:25:42 +02:00
Arjun Temurnikar fe23f27086 Remove rook passers eval completely
Tested in no-regression mode.

Passed STC
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 17727 W: 3248 L: 3122 D: 11357

And (a very long!) LTC
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 106327 W: 16258 L: 16265 D: 73804

bench: 7396783
2014-04-27 09:51:48 +02:00
Marco Costalba de6fe2cb4e Reformatting in material.h
No functional change.
2014-04-27 09:31:22 +02:00
Marco Costalba 057c3d60cd Move game phase constants to enum Value
No functional change.
2014-04-27 09:23:45 +02:00
Marco Costalba cb4ac4221e Speed up by almost 3%
This apparentely silly tweak allows
to speed up the bench by almost 3%.

Not clear why, repeating with perft,
the speed up vanishes.

Suggested by Jonathan Calovski.

No functional change.
2014-04-27 00:25:47 +02:00
Marco Costalba 55604f156b Fix issues detected by Coverity Scan
Most of Coverity Scan reports are false
positives, but in rare cases we have
confirmed (very small) issues.

No functional change.
2014-04-26 09:33:50 +02:00
Marco Costalba 7ddbcf7e87 Speed up picking of killers
Changing the order of the conditions gives
about 1% speed up!

No functional change.
2014-04-25 12:53:51 +02:00
Arjun Temurnikar 3705559fdb Remove RookOn7th and merge values into psqt
Tested in no-regression mode:

STC
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 55678 W: 9954 L: 9892 D: 35832

LTC
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 9238 W: 1448 L: 1311 D: 6479

bench: 7905850
2014-04-24 08:53:46 +02:00
Arjun Temurnikar 6579a65bbb Remove penalty for knight when few enemy pawns
Tested in standard mode at STC and no-regression
mode at LTC:

STC
LLR: 2.97 (-2.94,2.94) [-1.50,4.50]
Total: 19503 W: 3502 L: 3349 D: 12652

LTC
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 67474 W: 9974 L: 9921 D: 47579

bench: 8331217
2014-04-24 08:47:13 +02:00
Jonathan Calovski f70cef3b79 Shuffle movepicker score
Believed to be a speed optimization as benched
on Windows with bench realtime affinity 0x1 deleting
highest and lowest runs:

Base	Test
1549259	1608202
1538115	1583934
1543168	1556938
1536365	1554179
1533026	1582010

Signature remains unchanged and gives anywhere from 1-2% nps
boost in analysis depending on number of cores used.

No functional change.
2014-04-24 08:38:11 +02:00
Marco Costalba a89b26bedd Correctly apply previous patch
Apply the correct values from previous patch.

bench: 8082049
2014-04-24 08:35:13 +02:00
joergoster 8bfb53efe2 Move queen vs. 3 minors rule to imbalance tables
Tuned with CLOP after 57k games.

Simplification: tested in no-regression mode.

Passed both STC
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 17254 W: 3159 L: 3032 D: 11063

And LTC
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 32413 W: 4967 L: 4864 D: 22582

bench: 8082049
2014-04-23 08:51:34 +02:00
Marco Costalba a66e6e5ad9 Revert "Generalize shift_bb() to handle double pushes"
Seems to intorduce some compiler warning as
reported by Gary. Warning seems bogus, but
revert anyhow.

No functional change.
2014-04-21 20:56:12 +02:00
Marco Costalba 56273fca1e Reset DrawValue[] before new search
Spotted by Ronald de Man

bench: 7384368
2014-04-21 14:30:27 +02:00
Leonid Pechenik ef43e6b05d Rise contempt when in advantage
This is a very discussed patch with many
argumentations pro and against. The fact is
it passed both STC:

LLR: 2.96 (-2.94,2.94) [-1.50,4.50]
Total: 16305 W: 3001 L: 2855 D: 10449

And LTC
LLR: 2.95 (-2.94,2.94) [0.00,6.00]
Total: 34273 W: 5180 L: 4931 D: 24162

Although it is true that a correct test should
include foreign engines, we commit it anyhow so
people can test it out in the wild, under broader
conditions.

bench: 7384368
2014-04-21 12:23:03 +02:00
Marco Costalba 223ebe7b40 Streamline implementation of Position::pretty()
Simpler and more in line with Bitboards::pretty()

No functional change.
2014-04-21 11:47:01 +02:00
Stefan Geschwentner 0e8ad40ef0 Raise penalty blocked enemy pawn on 6th rank
Idea from Lyudmil Tsvetkov.

The value seems to be raised a bit abruptly, but as
Gary said, a blocked pawn on the sixth rank has been
instrumental in limiting king mobility in multiple
losses that I've seen from SF. A blocked pawn on fifth
rank is much less serious on the king safety impact.

Passed both STC
LLR: 2.97 (-2.94,2.94) [-1.50,4.50]
Total: 14551 W: 2750 L: 2607 D: 9194

and LTC
LLR: 2.96 (-2.94,2.94) [0.00,6.00]
Total: 43595 W: 6917 L: 6618 D: 30060

And even a retest at 60" fixed games 40K
ELO: 1.79 +-1.9 (95%) LOS: 97.0%
Total: 39889 W: 6018 L: 5813 D: 28058

bench: 7154916
2014-04-21 07:47:50 +02:00
Marco Costalba eced15fe36 Generalize shift_bb() to handle double pushes
And use it in evaluate_space.

No functional change.
2014-04-20 15:52:37 +02:00
Arjun Temurnikar a4d058bca2 Small simplification to passed pawns
Tested in no-regression mode.

Passed both STC
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 28521 W: 5066 L: 4958 D: 18497

And LTC
LLR: 3.04 (-2.94,2.94) [-3.00,1.00]
Total: 21939 W: 3261 L: 3138 D: 15540

bench: 8165681
2014-04-20 10:06:51 +02:00
Joseph Hellis 619d66b7ab Remove supporting pawns
Tested in no-regression mode

Passed both STC
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 44957 W: 7984 L: 7903 D: 29070

and LTC
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 12396 W: 1916 L: 1783 D: 8697

Bench: 7907885
2014-04-17 08:45:31 +02:00
Jean-Francois Romang 9073866491 Enable BMI1 too when using BMI2 ARCH
Adding BMI1 allows the compiler to use _blsr_u64
automatically (the advertised 0.3% speed gain).
I verified that the compiler does not use this
instruction with the -mbmi2 flag only. Also, all
processors supporting BMI2 is also supporting BMI1.

No functional change
2014-04-14 07:54:24 +02:00
Marco Costalba 7bce8831d3 More readable trapped rook condition
Prefer

file_of(s) < file_of(ksq)

to the inidrect

file_of(ksq) < FILE_E

To evaluate if semiopen side to check is the left side.

Also other small touches while there.

No functional change.
2014-04-13 14:29:42 +02:00
Daylen Yang 81a8c1118b Simplify Makefile by removing OS X targets
Right now the Makefile is cluttered with OS X equivalents
of all the x86 targets. We can get rid of all of them and
just check UNAME against "Darwin" for the few OS X-specific
things we need to do.

We also disable Clang LTO when using BMI2 instructions. For
some reason, LLVM cannot find the PEXT instruction when using
LTO. I don't know why, but disabling LTO for BMI2 fixes it.

No functional change.
2014-04-13 09:05:21 +02:00
Marco Costalba b2c0634d48 Move args parsing to UCI::loop
This leaves a very clean main.cpp

No functional change.
2014-04-12 13:51:52 +02:00
Marco Costalba ada55c5d0a Reshuffle in uci.cpp
Move function definitions before call site.

No functional change.
2014-04-12 12:05:25 +02:00
Marco Costalba 17cb7e7fa3 Reshuffle in timeman.cpp
Move template definitions before call site.

No functional change.
2014-04-12 12:00:37 +02:00
Marco Costalba 800ba28e83 Fix a typo in evaluate
Spotted by Lyudmil Antonov.

No functional change.
2014-04-12 10:17:41 +02:00
Marco Costalba 0b2794ae12 Retire signature-build
Does not seem used.

No functional change.
2014-04-12 09:18:55 +02:00
Jean-Francois Romang 226bbc1e63 Add ARCH x86-64-bmi2 support
Intel Haswell and newer CPUs can calculate sliders
attacks using special PEXT asm instructions instead
of magic bitboards. This gives a +3% speed up.

To enable it just compile with ARCH=x86-64-bmi2

No functional change.
2014-04-12 09:15:14 +02:00
Marco Costalba da2f8880b9 Switch to hardware PEXT
Retire software pext and introduce hardware
call when USE_PEXT is defined during compilation.

This is a full complete implementation of sliding
attacks using PEXT.

No functional change.
2014-04-12 08:55:30 +02:00
Marco Costalba c556fe1d71 Implement PEXT based attacks
According to:

https://chessprogramming.wikispaces.com/BMI2#PEXTBitboards

No functional change.
2014-04-12 08:55:30 +02:00
Marco Costalba 2bfe61c33b Add PEXT software implementation
For development/debug purposes.

No functional change.
2014-04-12 08:55:30 +02:00
Marco Costalba 2f92e3b525 Big reshuffle in evaluate.cpp
Reshuffle functions to define them in reverse
calling order (C style).

This allow us to define templates before they are
used. Currently it is not like this, for instance
evaluate_pieces is defined after do_evaluate that
calls it. This happens to work for some strange
reason (two phase lookup?) but we want to avoid
code that works 'by magic'.

As a nice side-effect we can now remove the function
prototypes.

No functional change.
2014-04-12 08:39:18 +02:00
Gary Linscott 0510112f91 Move LowMobPenalty into psq/mobility tables
Tested in no-regression mode.

Passed both STC
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 36705 W: 6537 L: 6443 D: 23725

and LTC
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 9358 W: 1495 L: 1358 D: 6505

bench: 6921356
2014-04-12 07:15:51 +02:00
Gary Linscott 4597324572 Reduce penalty for doubled pawns further away from each other
Passed both STC
LLR: 2.96 (-2.94,2.94) [-1.50,4.50]
Total: 38339 W: 6849 L: 6649 D: 24841

and LTC
LLR: 2.95 (-2.94,2.94) [0.00,6.00]
Total: 22693 W: 3455 L: 3256 D: 15982

bench: 7508468
2014-04-12 07:05:02 +02:00
Marco Costalba ce6b7a1b85 Further simplification in evaluate
No functional change
2014-04-11 08:38:09 +02:00
Marco Costalba e3b54235ad Get rid of an evaluate_pieces() overload
Rewrite and greatly simplify that part of code.

No functional change.
2014-04-10 19:45:18 +02:00
Gary Linscott 8863afeb84 Add a penalty for low mobility pieces
Passed both STC
LLR: 2.96 (-2.94,2.94) [-1.50,4.50]
Total: 81857 W: 14652 L: 14342 D: 52863

and LTC
LLR: 2.97 (-2.94,2.94) [0.00,6.00]
Total: 45400 W: 6999 L: 6697 D: 31704

bench: 7716978
2014-04-10 08:35:10 +02:00
Gary Linscott 5c75455c8e Restrict queen mobility to safe squares
Passed both STC
LLR: 2.95 (-2.94,2.94) [-1.50,4.50]
Total: 16188 W: 3119 L: 2971 D: 10098

and LTC
LLR: 2.95 (-2.94,2.94) [0.00,6.00]
Total: 6336 W: 1010 L: 882 D: 4444

bench: 7533692
2014-04-08 22:25:54 +02:00
Lucas Braesch 0d8a4c7565 Rescale UCI scores to PawnValueEg
This is more consistent with what other engines are doing.
Often people thinks that SF's scores are overblown. In the
end, it just boils down to the arbitrary way of rescaling them.

No functional change.
2014-04-06 11:53:28 +02:00
Marco Costalba 64d29a6330 Sync some common names
No functional change.
2014-04-06 11:26:12 +02:00
Marco Costalba fcf2a34080 Some more work in pretty_pv
No functional change.
2014-04-06 10:15:11 +02:00
Marco Costalba 698b645e10 Small tidy up in move_to_san
No functional change.
2014-04-05 19:05:37 +02:00
mstembera d28ea7b518 Smaller and faster profile-build binaries
I have noticed that increasing the bench depth produces
progressively smaller and slightly faster executables at
the cost of longer compile times.  Also using bench "time"
instead of "depth" seems to produce slightly smaller/faster
executables  given comparable compile times.

I have made a new Makefile that generates smaller and
about 1% to 2% faster profile executables at only a
little extra compile time.  On  my mobile 2GHz i7 a
full profile build time goes from 3'48" to 4'13" and
the exe goes down by 5% from 416,310 bytes to 395,567
bytes.

No functional change.
2014-04-05 12:48:20 +02:00
Lucas Braesch be641e881f Remove QueenOn7th and QueenOnPawn
Small simplification.

Passed SPRT(-3,1) both at STC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 17051 W: 3132 L: 3005 D: 10914

and LTC:
LLR: 4.55 (-2.94,2.94) [-3.00,1.00]
Total: 24890 W: 3842 L: 3646 D: 17402

The rationale behind this is that I've never managed to add a
Queen on 7th rank bonus in DiscoCheck, because it never showed
to be positive (evne slightly) in testing. The only thing that
worked is Rook on 7th rank.

In terms of SF code, it seemed natural to group it with QueenOnPawn
as well as those are done together. I know you're against groupping
in general, but when it comes to non regression test, you are being
more conservative by groupping. If the group passes SPRT(-3,1) it's
safer to commit, than test every component in SPRT(-3,1) and end up
with the risk of commiting several -1 elo regression instead of just
one -1 elo regression.

In chess terms, perhaps it's just easier to manouver a Queen (which
can more also diagonaly) than a Rook. Therefore you can let the search
do its job without needing eval ad-hoc terms to guide it. For the Rook
which takes more moves to manouver such eval terms can be (marginally)
useful.

bench: 7473314
2014-04-05 11:26:44 +02:00
mstembera 3b19ea6ae5 Speed up apply_weight
Speed up by about 2% this hot path function pre-calculating
midgame and endgame values of the weight.

No functional change.
2014-04-05 11:12:18 +02:00
Marco Costalba ccf59b0228 Update Readme to 128 max threads
No functional change.
2014-04-03 11:33:42 +02:00
Joerg Oster 299afcd886 Queen vs. 3 pieces imbalance
Passed both STC
LLR: 7.32 (-2.94,2.94) [-1.50,4.50]
Total: 98108 W: 18087 L: 17576 D: 62445

And LTC
LLR: 2.95 (-2.94,2.94) [0.00,6.00]
Total: 15082 W: 2417 L: 2248 D: 10417

bench: 7717336
2014-04-03 10:42:06 +02:00
Marco Costalba c15b132f03 Make operator<< to return void
This should help preventing misuse.

No functional change.
2014-04-03 10:34:25 +02:00
Stefan Geschwentner 0ba814b3ca Drop not defended by pawn condition
Passed no-regression test both at STC
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 96554 W: 17563 L: 17572 D: 61419

and at LTC
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 31891 W: 4905 L: 4801 D: 22185

bench: 7720896
2014-04-01 11:59:25 +02:00
Marco Costalba d2caba1f66 Do not workaround function argument evaluation
Rewrite options initialization to do not trying to
hack upon the undefined evaluation order of function
arguments.

No functional change.
2014-04-01 09:39:41 +02:00
Marco Costalba 1efc19ade0 Fix a compile error with Intel C++
Error: a value of type "int" cannot be assigned
to an entity of type "Value"

No functional change.
2014-03-30 14:20:12 +02:00
Marco Costalba 678425f274 Fix a warning with MSVC 2010
Warning C4804: '<' : unsafe use of type 'bool' in operation

No functional change.
2014-03-30 14:25:57 +02:00
Marco Costalba 422c9c2acd Show evaluation from white POV in trace
We chose this instead of negamax sign convention
(ie. from the point of view of the side to move)
because it is more in line to how the eval
table is presented.

Also some tweak to formatting while there.

No functional change.
2014-03-30 10:45:46 +02:00
Marco Costalba 9350d0dce5 Raise VALUE_INFINITE
In some legal positions like this one:
R6R/3Q4/1Q4Q1/4Q3/2Q4Q/Q4Q2/Np1Q4/kB1N1KB1  b -- 0 1

We can have a very high score, in this case 30177 and 29267
for midgame and endgame respectively, and because
VALUE_INFINITE = 30001 we have an assert in interpolate()

Midgame and endgame scores are stored in 16 bit signed integers
so we can rise VALUE_INFINITE a little bit. This does not fix
the possibility of overflow in general case, just makes the
condition more difficult to trigger and anyhow better uses all
the score width.

Raising VALUE_INFINITE to 32000 seems to fix the problem for this
particular case.

No functional change.
2014-03-29 11:13:42 +01:00
Jean-Francois Romang 4833887842 Further simplification of TT replace strategy
No functional change
2014-03-29 10:05:02 +01:00
Marco Costalba f811a5693e Restore old aspiration window to 16
Tested directly at LTC because previous long
test series on this topic shows it is TC dependant.

Tested with no-regression mode because gets rid of
an ugly and ad-hoc rule.

Test at LTC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 67918 W: 10590 L: 10541 D: 46787

bench: 7926803
2014-03-29 08:45:40 +01:00
Stefan Geschwentner af0c13ba6a Pinned pieces affect king safety
Here the new idea is to link pinned pieces
with king safety.

Passed both STC
LLR: 2.96 (-2.94,2.94) [-1.50,4.50]
Total: 10047 W: 1867 L: 1737 D: 6443

And LTC
LLR: 2.97 (-2.94,2.94) [0.00,6.00]
Total: 10419 W: 1692 L: 1543 D: 7184

bench: 8325087
2014-03-29 08:37:55 +01:00
Marco Costalba c7cf45241c Fix a bug in pawns eval tracing
Instead of totals we were showing white and
black values.

Spotted by Sven Schüle

No functional change.
2014-03-26 07:06:29 +01:00
Marco Costalba 865b71309c Simplify TT replace strategy
Tested for no-regression with SPRT[-3, 1] at STC
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 32046 W: 6020 L: 5918 D: 20108

No functional change.
2014-03-24 08:32:08 +01:00
snicolet e7362dae78 Introduce penalty for weak (=unsupported) pawns.
We add a penalty for each pawn which is not protected by another pawn
of the same color.

Passed both short TC
LLR: 2.96 (-2.94,2.94) [-1.50,4.50]
Total: 12107 W: 2411 L: 2272 D: 7424

And long TC
LLR: 2.96 (-2.94,2.94) [0.00,6.00]
Total: 9204 W: 1605 L: 1458 D: 6141

bench: 7682173
2014-03-24 08:27:40 +01:00
Marco Costalba 9e72e35942 Fix an incorrect 'friend' declaration
Spotted by Lee David.

No functional change.
2014-03-23 11:17:38 +01:00
Marco Costalba bc183b0c04 Retire last usage of operator|(File f, Rank r)
This for some reason was missed.

No functional change.
2014-03-23 10:42:37 +01:00
mstembera ffdf63ff7c Refresh TT entries generation automatically on probe
And other assorted simplifications, tested with SPRT[-3, 1]

Passed both short TC
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 18814 W: 3600 L: 3475 D: 11739

And long TC
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 20731 W: 3217 L: 3096 D: 14418

No functional change.
2014-03-23 09:46:15 +01:00
Marco Costalba f12449d492 Rename score to value in ExtMove
We use 'score' for the value mid-endgame pair.

No functional change.
2014-03-23 08:54:10 +01:00
Marco Costalba 441a34a1c6 Trivial formatting in ucioption.cpp
No functional change.
2014-03-23 00:06:26 +01:00
Marco Costalba 5f12069cbf Retire operator|(File f, Rank r)
Use make_square() instead. Less fancy but
more clear.

No functional change.
2014-03-22 23:54:18 +01:00
Marco Costalba 4eee603433 Fix a subtle bug in UCI options printing
We want all the UCI options are printed in the order in which are
assigned, so we use an index that, depending on Options.size(),
increases after each option is added to the map. The problem is
that, for instance, in the first assignment:

o["Write Debug Log"] = Option(false, on_logger);

Options.size() can value 0 or 1 according if the l-value (that
increments the size) has been evaluated after or before the
r-value (that uses the size value).

The culprit is that assignment operator in C++ is not a
sequence point:

http://en.wikipedia.org/wiki/Sequence_point

(Note: to be nitpick here we actually use std::map::operator=()
 that being a function can evaluate its arguments in any order)

So there is no guarantee on what term is evaluated first and
behavior is undefined by standard in this case. The net result
is that in case r-value is evaluated after l-value the last
idx is not size() - 1, but size() and in the printing loop
we miss the last option!

Bug was there since ages but only recently has been exposed by
the removal of UCI_Analyze option so that the last one becomes
UCI_Chess960 and when it is missing engine cannot play anymore
Chess960.

The fix is trivial (although a bit hacky): just increase the
last loop index.

Reported by Eric Mullins that found it on an ARM and MIPS
platforms with gcc 4.7

No functional change.
2014-03-22 11:30:06 +01:00
Marco Costalba c714b90594 Fix a typo
Spotted by Isaac Haïk Dunn.

No functional change.
2014-03-18 18:36:39 +01:00
Marco Costalba aab5863dd4 Increase max threads to 128
Thanks to std::bitset we can easily increase
the limit of active threads above 64.

Thanks to Lucas Braesch for pointing at the
correct solution of using std::bitset.

No functional change.
2014-03-18 12:07:26 +01:00
Marco Costalba fa3f6dcbea Fix a crash under MSVC
Using memset on a std::vector is undefined behavior,
so manually init all the data memebers of LimitsType.

Bug intorduced in 41641e3b1e

No functional change.
2014-03-16 10:55:58 +01:00
Marco Costalba a091ae4cc8 Split also if no slaves are found
Because we test for available slaves before
entering split(), we almost always allocate a
slave, only in the rare case of a race (less
then 2% of cases) this is not true, but to
special case this occurrence is not worth
the added complexity.

bench: 7451319
2014-03-15 23:43:35 +01:00
Marco Costalba a1a7bc84da Remove "Max Threads per Split Point" UCI option
Experimental patch to verify if drop of nps
in endgames at very long TC is due to this.

Suggested by Ronald de Man.

bench: 7451319
2014-03-15 21:26:04 +01:00
Marco Costalba 6e4b4c42ed Merge default tests in pos_is_ok
No functional change.
2014-03-15 15:34:31 +01:00
Marco Costalba 142874b058 Microptimize castling in undo_move()
We don't need to set 'captured' and 'pt' after we
castle back.

No functional change.
2014-03-15 11:47:30 +01:00
Mysseno 36c381154b Depth dependant aspiration window delta
Split delta value in aspiration window so that when
search depth is less than 24 a smaller delta value
is used. The idea is that the search is likely to
be more accurate at lower depths and so we can exclude
more possibilities, 25% to be exact.

Passed STC
LLR: 2.96 (-2.94, 2.94) [-1.50, 4.50]
Total: 20430 W: 3775 L: 3618 D: 13037

And LTC
LLR: 2.96 (-2.94, 2.94) [0.00, 6.00]
Total: 5032 W: 839 L: 715 D: 3478

Bench: 7451319
2014-03-14 19:47:41 +01:00
Marco Costalba d0587f2c7f Use legal positions for endgame initialization
During endgame initialization we get the material
hash key of each endgame forging and ad-hoc position
that in same cases is illegal (leaves teh king under
capture). This is not a problem for the material key,
but rises an assert when SF is run in debug mode with
'testKingCapture' set in pos_is_ok().

So rewrite the code to always produce legal positions.

No functional change.
2014-03-14 09:57:34 +01:00
Marco Costalba 1f4798a173 Further work in pos_is_ok()
No functional change.
2014-03-14 09:43:19 +01:00
Daylen Yang 61e4443342 Re-add link time optimization on OS X
In the new version of clang, -O4 does not imply -flto, so we set the
flag
2014-03-14 08:49:08 +01:00
Marco Costalba 6571acffaa Reformat do_castling()
No functional change.
2014-03-13 12:53:03 +01:00
Marco Costalba 6f3d787692 Further merge StateInfo setup functions
No functional change.
2014-03-12 22:46:17 +01:00
Marco Costalba 1e032ece92 Merge hash key computation functions
No functional change.
2014-03-12 09:14:38 +01:00
Marco Costalba cc3002ff04 Use std::count in pos_is_ok()
No functional change.
2014-03-11 23:19:47 +01:00
Marco Costalba c40d4e0133 Small simplification in gives_check
Use switch statement also for normal case.

No speed regression.

No functional change.
2014-03-11 22:58:08 +01:00
Marco Costalba ca0804dfe4 Print dbg counters after bench
Print last debug counters update just
before to exit benchmark.

Suggested by Stephane Nicolet.

No functional change.
2014-03-11 22:19:14 +01:00
Marco Costalba d2a8ba3299 Simplify pseudo_legal()
Big simplification of pawn move check.

Code has been tested with a brute force approach: for
every position reached during a bench search, the function
has been called for each combinations of Move(from, to)
and verified the result is the same of old code.

Actually this function is very critical becuase is the
one that ensures corrupted TT moves are discarded, so
to properly test it a simple bench is not enough.

Verified also speed is not changed.

No functional chnage.
2014-03-10 08:38:23 +01:00
Marco Costalba 20ff12e1be Simplify generate<EVASIONS>
No speed regression, tested with both perft and
bench.

No functional change.
2014-03-09 12:16:27 +01:00
Marco Costalba 5cf9e0b254 Retire SERIALIZE macros
Explicitly write the 'while' loops. This adds some
code but makes clear what's the code behind the
macro.

No functional change.
2014-03-09 11:10:33 +01:00
Marco Costalba 1d1b7df7c6 Rename castling flag to castling right
This is a more conventional naming as
reported also in:

http://chessprogramming.wikispaces.com/Castling+rights

No functional change.
2014-03-08 15:08:55 +01:00
Stephane Nicolet 13b9e1e098 Fix dbg_mean_of() for negative numbers
Type should be int64_t instead of uint64_t

No functional change.
2014-03-05 08:55:12 +01:00
mstembera 553ead429d Some minor cleanup stuff
I came across while browsing the code.

No functional change.
2014-03-03 08:57:20 +01:00
Marco Costalba bbd69c0260 Revert dynamic draw value
When tested with weaker engines did not
performed as expected, actually it was even
a regression from standard version.

bench: 8430785
2014-03-03 08:39:34 +01:00
Marco Costalba 708cb311a0 Pass CastlingFlag argument only
Instead of Color and CastlingSide. Change functions API
accordingly.

No functional change.
2014-03-02 13:21:19 +01:00
Marco Costalba 3e5470d88f Remove limit of minimumSplitDepth
There is no reason why an user cannot set
it at a value less than 4.

No functional change.
2014-03-01 23:22:14 +01:00
Marco Costalba 3d8c0f16c2 Rename xxx_to_char() -> to_char()
No functional change.
2014-03-01 22:07:41 +01:00
Marco Costalba de2ba70830 Simplify Bitboards::pretty
No functional change.
2014-03-01 13:10:05 +01:00
Marco Costalba 9f0485e343 Retire UCI_AnalyseMode option
It has been obsoleted out already some time ago
and currently there is no point in changing eval
score according to if we are in game or analyzing.

So retire the option.

No functional change.
2014-03-01 12:10:42 +01:00
Joerg Oster b917cd275e Dynamic draw value
Try to avoid repetition draws at early midgame,
this should give an edge against weaker opponents
and reduce draw rate.

Tested for regressions with SPRT[-3, 1] and
passed both short TC
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 68498 W: 12928 L: 12891 D: 42679

And long TC
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 40212 W: 6386 L: 6295 D: 27531

bench: 7990513
2014-02-26 19:33:52 +01:00
Marco Costalba 0949f06a60 Fix a warning with Intel compiler
warning #2259: non-pointer conversion from "int" to
"uint8_t={unsigned char}" may lose significant bits

No functional change
2014-02-22 12:00:14 +01:00
Marco Costalba 012f20d66e Fix an assert in Probcut
When running the following position:

8/kPp5/2P3p1/p1P1p1P1/2PpPp2/3p1p2/3P1P2/5K2 w - - 0 1

An assert is raised at depth 92:

assert(-VALUE_INFINITE <= alpha && alpha < beta && beta <= VALUE_INFINITE);

This is because it happens that beta = 29832,
so rbeta = 30032 that is > VALUE_INFINITE

Bug spotted and analyzed by Uri, fix suggested by Joerg.

Other fixes where possible but this one is pointed
exactly at the source of the bug, so it is the best
from a code documentation point of view.

bench: 8430785
2014-02-22 10:38:21 +01:00
Leonid Pechenik b8cfc255d4 Distribute part of first move time to other moves
Passed both short TC:
LLR: 2.97 (-2.94,2.94) [-1.50,4.50]
Total: 18907 W: 3475 L: 3322 D: 12110

And long TC:
LLR: 2.96 (-2.94,2.94) [0.00,6.00]
Total: 19044 W: 2997 L: 2811 D: 13236

bench: 8430785
2014-02-20 08:39:00 +01:00
Marco Costalba 9fcefb2760 Avoid recalculating CheckInfo in generate_castling()
No functional change.
2014-02-20 08:27:13 +01:00
Marco Costalba 64a71c3c02 Don't update pieceCount for ALL_PIECES
It is currently unused and only adds
overhead for nothing.

Also set proper type of chess960.

No functional change.
2014-02-18 16:41:24 +01:00
Marco Costalba 7b0a2f2a90 Update SEE to return a Value
It seems more natural because the actual returned
value is from PieceValue[] array.

No functional change.
2014-02-16 13:06:31 +01:00
Marco Costalba 17ffc22279 Sync code style in material.cpp
Update to use common code style.

No functional change.
2014-02-16 12:56:54 +01:00
Marco Costalba 52ebf87238 Increase MAX_PLY from 100 to 120
Under some very rare case 100 plies of search
could be not enough. Increasing more could lead
to crashes due to reached stack size limit on
some platforms.

Strongly requested by Uri.

bench: 8430785
2014-02-16 12:20:37 +01:00
Marco Costalba d91079d4b0 Fix material key for King
Currently king has no material key associated because
it can never happen to find a legal position without
both kings, so there is no need to keep track of it.

The consequence is that a position with only the two
kings has material key set at zero and if the material
hash table is empty any entry will match and this is
wrong.

Normally bug is hidden becuase the checking for a draw
with pos.is_draw() is done earlier than evaluate() call,
so that we never check in gameplay the material key of a
position with two kings.

Nevertheless the bug is there and can be reproduced setting
at startup a position with only two kings and typing
'eval' from prompt.

The fix is very simple: add a random key also for the king.

Also fixed the condition in material.cpp to avoid asserting
when a 'just 2 kings' postion is evaluated.

No functional change.
2014-02-16 11:51:30 +01:00
Marco Costalba 62c0dc5dea Restore PorbCut name
Actually MultiCut is too different from current scheme.
Note that neither ProbCut is exactly what we do because
we try just a handful of captures instead of all moves,
nevertheless it seems more in line with what we do.

Suggested by Joona.

No functional change.
2014-02-15 22:21:39 +01:00
Marco Costalba 7bdb8c9c5c Reformat of eval tracing code
Also assorted rename while there.

No functional change.
2014-02-15 14:11:26 +01:00
Marco Costalba 3336963185 Rename ProbCut to Multicut
The teqnique used is actually MultiCut:

https://chessprogramming.wikispaces.com/Multi-Cut

And not ProbCut:

https://chessprogramming.wikispaces.com/ProbCut

No functional change.
2014-02-15 09:37:55 +01:00
Marco Costalba 4808d15a85 Assorted renaming in search
Inspired by DON.

No functional change.
2014-02-15 09:20:27 +01:00
Joerg Oster 67f88f5e3e Return static eval when reaching MAX_PLY
Makes more sense than returning a draw score. Tested
with reduced MAX_PLY = 30 and passed both short TC
LLR: 2.95 (-2.94,2.94) [-1.50,4.50]
Total: 17434 W: 3345 L: 3194 D: 10895

And long TC
LLR: 2.97 (-2.94,2.94) [0.00,6.00]
Total: 2610 W: 488 L: 373 D: 1749

With current limit of MAX_PLY = 100 the patch should not
introduce any measurable change, nevertheless is the correct
approach.

Idea of returning eval is from  Michel Van den Bergh.

bench: 8430785
2014-02-15 08:20:33 +01:00
Marco Costalba b3470d7ab1 Fix magic boosters conversion
Fix small overflow error while converting
magic boosters from right rotate to left rotate,
in particular booster 38 was converted to 4122
instead of the corrcet value 26.

Formula used was:

s1 = original & 63, s2 = (original >> 6) & 63;
new = (64 - s1) | ((64 - s2) << 6);

Instead of:

s1 = original & 63, s2 = (original >> 6) & 63;
new = ((64 - s1) & 63) | (((64 - s2) & 63) << 6);

This has no impact in number of cycles needed, but
just in the resultig number that yields to a rotate
amount bigger than 63.

Spotted by Ehsan Rashid.

No functional change.
2014-02-14 10:43:37 +01:00
Marco Costalba e4695f15bc Additional renaming from DON
Assorted renaming and triviality.

No functional change.
2014-02-14 09:42:50 +01:00
joergoster ffd6685f79 Fix a compiler warning
Latest master triggers a compiler warning due
to comparing int64_t to uint64_t.

notation.cpp: In Funktion »std::string pretty_pv(Position&, int, Value, int64_t, Move*)«:
notation.cpp:230:30: Warnung: Vergleich zwischen vorzeichenbehafteten und vorzeichenlosen Ganzzahlausdrücken [-Wsign-compare]

This patch should fix it.

No functional change.
2014-02-12 21:52:21 +01:00
Leonid Pechenik 72e8640f4d Simplify time management
Tested with simplification mode SPRT[-4, 0]

Passed both short TC
LLR: 2.95 (-2.94,2.94) [-4.00,0.00]
Total: 34102 W: 6184 L: 6144 D: 21774

And long TC
LLR: 2.96 (-2.94,2.94) [-4.00,0.00]
Total: 16518 W: 2647 L: 2545 D: 11326

And also 40/10 TC
LLR: 2.95 (-2.94,2.94) [-4.00,0.00]
Total: 22406 W: 4390 L: 4312 D: 13704

bench: 8430785
2014-02-12 20:01:11 +01:00
Marco Costalba e6523e56b8 Move magic random to RKISS
When initializing the magic numbers used to
compute sliding attacks, we endless generate a
random and test it as a possible magic.

In the general case this takes a lot of iterations,
but here, insteaad of picking a casual random, we
rotate it a couple of times and generate a number that
we know has a good probability to be a magic candidate.

This is becuase the quantities by which we rotate the
number are known in advance to produce quickly a good
canidate.

The patch, inspired by DON, just moves the shuffle to RKISS
changing the boosters to take in account a left rotation
instead of a right rotation as in the original.

No functional change.
2014-02-12 14:47:36 +01:00
Marco Costalba b534176d4a Revert "Retire null search verification"
Although does not change ELO level, it seems
verification is useful in many zugzwang positions
as reported by many sources.

So revert this simplification.

bench: 8430785
2014-02-12 14:16:21 +01:00
Henri Wiechers ddeb01612b Faster handling of king captures in Position::see
Another SEE speed up that passed the SPRT short TC test!

LLR: 2.96 (-2.94,2.94) [-1.50,4.50]
Total: 81337 W: 15060 L: 14745 D: 51532

No functional change.
2014-02-09 19:42:24 +01:00
Marco Costalba 41641e3b1e Assorted tweaks from DON
Mainly renames and some little code style improvment,
inspired by looking at DON sources:

https://github.com/erashid/DON

No functional change.
2014-02-09 17:31:45 +01:00
Marco Costalba 2f5aaf7de6 Rewrite previous patch removing the macro
No functional change.
2014-02-08 13:27:44 +01:00
Thanar2 d48a304262 Inline common path of pos.gives_check
Test for common case which, when running default
stockfish bench, avoids 96% of 19 million calls to
pos.gives_check().

Yields to a 2-4% speed up according to platform.

Passed fishtest at STC
LLR: 2.97 (-2.94,2.94) [-1.50,4.50]
Total: 12441 W: 2333 L: 2196 D: 7912
http://tests.stockfishchess.org/tests/view/52f02d790ebc5901df50f887

Passed fishtest at LTC
LLR: 2.97 (-2.94,2.94) [0.00,6.00]
Total: 42175 W: 6702 L: 6409 D: 29064
http://tests.stockfishchess.org/tests/view/52f0dbe00ebc5901df50f8a0

No functional change.
2014-02-08 13:17:29 +01:00
Marco Costalba 0a1092f64e Don't fear races when are harmless
Actually race conditions do exist in an engine, just
think for a moment to TT concurrent access. Racy code
is not a problem per se, if the consequences are well
known and correctly handled.

In case of TT access we ensure that the TT move is validated
before to be tried, here we just retry the same move in less
that 1 case out of a million: this is totally harmless considering
that very probably the second time the move is tried we get
immediately a TT hit and search quickly returns.

So we simplify the code for no harm.

No fuctional change (in single thread case)
2014-02-08 13:07:57 +01:00
Lucas Braesch 399968f1d0 Retire null search verification
Tested with SPRT in simplification mode [-4.00,0.00],
this ensures that the patch is (very probably) not
a regression.

Passed both short TC
LLR: 2.95 (-2.94,2.94) [-4.00,0.00]
Total: 27543 W: 4278 L: 4209 D: 19056

And long TC
LLR: 2.95 (-2.94,2.94) [-4.00,0.00]
Total: 39483 W: 7325 L: 7305 D: 24853

bench: 8347121
2014-02-08 08:25:08 +01:00
Lucas Braesch e5c3effdb1 Better document null search window
Hopefully this patch makes the code more:

* Self-documenting: Null search is always a zero window search,
  because it is testing for a fail high. It should never be done
  on a full window! The current code only works because we don't
  do it at PV nodes, and therefore (alpha, beta) = (beta-1, beta):
  that's the kind of "clever" trick we should avoid.

* Idiot-proof: If we want to enable null search at PV nodes, all we
  need to do now is comment out the !PvNode condition. It's that simple!

In theory, null search should not be done at PV nodes, because PV nodes
should never fail high. But in practice, they DO fail high, because of
aspiration windows, and search inconsistencies, for example. So it makes
sense to keep that flexibility in the code.

No functional change.
2014-02-04 08:24:46 +01:00
Lucas Braesch e88ef801af Better document razoring
Use ralpha instead of rbeta

* rbeta is confusing people. It took THREE attempts to code razoring
at PV nodes correctly in a recent test, because of the rbeta trick.
Unnecessary tricks should be avoided.

* The more correct and self-documenting way of doing this, is to say
that we use a zero window around alpha-margin, not beta-margin.
The fact that, because we only do it at PV nodes, alpha happens to be
beta-1 and that the current stuff with rbeta works, may be correct,
but is confusing.

Remove the misleading and partially erroneous comment about returning
v + margin:

* comments should explain what the code does, not what it could have done.

* this comment is partially wrong in saying that v+margin is "logical",
  and that it is "surprising" that is doesn't work.

From a theoretical perspective, at least 3 ways of doing this are equally
defendable:

1/ fail hard: return alpha: The most conservative. We bet that the search
will fail low, but we don't know by how much and don't want to take risks.

2/ aggressive fail soft: return v (what the current code does). This
corresponds to normal fail soft, with the added assumption that we don't
care about the reduction effect (see below point 3/)

3/ conservative fail soft: return v + margin. If the reduced search (qsearch)
gives us a score <= v, we bet that the non reduced search will give us a
score <= v + margin.

* Saying that 2/ is "logical" implies that 1/ and 3/ are not, which is
arguably wrong. Besides, experimental results tell us that 2/ beats 3/,
and that's not something we can argue against: experimental results are
the only trusted metric.

* Also, with the benefit of hindsight, I don't think the fact that 2/ is
better than 3/ is surprising at all. The point is that it is YOUR turn to
move, and you are assuming that by NOT playing (and letting the opponent
capture your hanging pieces in QS) you cannot generally GAIN razor_margin(depth).

No functional change.
2014-02-03 21:37:14 +01:00
Joona Kiiski d8796fe7e9 H-file penalty and center bonus
After almost 50K at long TC it seems
slightly positive:

ELO: 1.73 +-1.8 (95%) LOS: 97.3%
Total: 47122 W: 7507 L: 7273 D: 32342

bench: 8430785
2014-02-03 21:23:49 +01:00
Joona Kiiski 77341f67f3 Tweak bishop PSQT tables
Tuned after 49K iterations of SPSA.

Passed both short TC:
LLR: 2.97 (-2.94,2.94) [-1.50,4.50]
Total: 14231 W: 2684 L: 2542 D: 9005

And long TC:
LLR: 2.94 (-2.94,2.94) [0.00,4.00]
Total: 87556 W: 13757 L: 13342 D: 60457

bench: 6875743
2014-01-29 18:02:13 +01:00
Uri Blass 93f95cc936 Reduce VALUE_KNOWN_WIN to 10000
With some positions like

8/8/8/2p2K2/1pp5/br1p1b2/2p2r2/qqkqq3 w - -

The eval score is higher than VALUE_INFINITE because
is the sum of VALUE_KNOWN_WIN plus a big material
advantage. This leads to an assert. Here are the
steps to reproduce:

Compile SF with debug=yes then do

./stockfish
position fen 8/8/8/2p2K2/1pp5/br1p1b2/2p2r2/qqkqq3 w - -
go depth 1

This patch fixes the issue in this case, but do exsist
other positions for which the patch is not enough and
we will need to limit the eval score to be sure not
overflow the limit.

Note that is not possible to increase the value of
VALUE_INFINITE because should remain within int16_t
type to be stored in a TT entry.

bench: 7356053
2014-01-27 20:09:51 +01:00
Marco Costalba f434cea287 Fix null reduction formula
Depth is already dependent on the actual value
of ONE_PLY, in particular can be expressed like:

Depth = n * ONE_PLY

And because formula is used to calculate R that is
also dependent on the value of ONE_PLY and can be
expressed like:

R = x * ONE_PLY

We don't want to divide depth by a 'ply' value but
directly by an integer number.

Spotted by sf-x

No functional change.
2014-01-27 08:18:48 +01:00
Marco Costalba 216972186e Grammar fix in MovePicker::next_move
Thanks to Lyudmil Antonov and Michel Van den Bergh
for spotting this and suggesting the fix.

No functional change.
2014-01-26 23:09:22 +01:00
Stefan Geschwentner 074c7a3c30 Variable null-move value based reduction
Instead of a fixed reduction of ONE_PLY, now
Null move dynamic reduction based on value can
grow larger in case we are above beta of a value
much higher then PawnValueMg.

Note that now an eval returning VALUE_KNOWN_WIN
makes null search to drop in qsearch.

Passed both short TC:
LLR: 2.95 (-2.94,2.94) [-1.50,4.50]
Total: 26141 W: 4871 L: 4699 D: 16571

And long TC:
LLR: 2.97 (-2.94,2.94) [0.00,6.00]
Total: 33695 W: 5309 L: 5056 D: 23330

bench: 7356053
2014-01-26 10:23:31 +01:00
Joona Kiiski cf95a55d76 Do not set default value for architeture in Makefile
Fixes a regression that ARCH parameter was not properly validated.
Invalid value would default to generic 32-bit build.

No functional change.
2014-01-25 11:29:32 +01:00
Henri Wiechers a08a21d5a0 Small simplification to Position::see
Verified there are no hidden bugs and is
actually a speed optimization:

Fixed games at 15+0.05 TC
ELO: 1.72 +-2.9 (95%) LOS: 87.5%
Total: 20000 W: 3741 L: 3642 D: 12617

No functional change
2014-01-19 11:16:34 +01:00
Joona Kiiski cabd512916 Fix +M0 score when low on time
When time remaining is less than Emergency Move Time,
we won't even complete one iteration and engine reports
a stale +M0 score.

To reproduce run "go wtime 10"

info depth 1 seldepth 1 score mate 0 upperbound nodes 2 nps 500 time 4 multipv 1 pv a2a3
info nodes 2 time 4
bestmove a2a3 ponder (none)

This patch fixes the issue.

Tested by Binky at very short TC: 0.05+0.05
ELO: 5.96 +-12.9 (95%) LOS: 81.7%
Total: 1458 W: 394 L: 369 D: 695

And at a bit longer TC:
ELO: 1.56 +-3.7 (95%) LOS: 79.8%
Total: 16511 W: 3983 L: 3909 D: 8619

bench: 7804908
2014-01-19 11:09:44 +01:00
Marco Costalba 40c863d41a Increase max hash size to 16GB
TCEC season 3, which is due to start in a few weeks, just
had its server upgraded to 64GB RAM and will therefore allow
16GB hash to be used per engine.

This is almost the upper limit without changing the
type of size and hashMask. After this we need to
move to uint64_t instead of uint32_t.

No functional change.
2014-01-18 18:22:32 +01:00
Joona Kiiski be61edbd19 Tweak knight PSQT tables
Passed both short TC:
LLR: 2.97 (-2.94,2.94) [-1.50,4.50]
Total: 31765 W: 6103 L: 5913 D: 19749

And long TC:
LLR: 2.96 (-2.94,2.94) [0.00,6.00]
Total: 38867 W: 6268 L: 5988 D: 26611

bench: 7804908
2014-01-18 17:52:37 +01:00
Chris Cain df201175c6 Simplify pawnless endgame evaluation
Retire KmmKm evaluation function. Instead give a very drawish
scale factor when the material advantage is small and not much
material remains.

Retire NoPawnsSF array. Pawnless endgames without a bishop will
now be scored higher. Pawnless endgames with a bishop pair will
be scored lower. The effect of this is hopefully small.

Consistent results both at short TC (fixed games):
ELO: -0.00 +-2.1 (95%) LOS: 50.0%
Total: 40000 W: 7405 L: 7405 D: 25190

And long TC (fixed games):
ELO: 0.77 +-1.9 (95%) LOS: 78.7%
Total: 39690 W: 6179 L: 6091 D: 27420

bench: 7213723
2014-01-18 17:22:54 +01:00
Stefan Geschwentner 53ab32ef0b Introduce 'follow up' moves
When we have a fail-high of a quiet move, store it in
a Followupmoves table indexed by the previous move of
the same color (instead of immediate previous move as
is in countermoves case).

Then use this table for quiet moves ordering in the same
way we are already doing with countermoves.

These followup moves will be tried just after countermoves
and before remaining quiet moves.

Passed both short TC
LLR: 2.95 (-2.94,2.94) [-1.50,4.50]
Total: 10350 W: 1998 L: 1866 D: 6486

And long TC
LLR: 2.95 (-2.94,2.94) [0.00,6.00]
Total: 14066 W: 2303 L: 2137 D: 9626

bench: 7205153
2014-01-14 09:24:35 +01:00
Ralph Stößer 402a7ae151 Ad-hoc shelter rule
This hacky rule allows to get an about right eval out of this position:
r2qk2r/ppp2p2/2npbn2/2b1p3/2P1P1P1/2NB1PPp/PPNP3K/R1BQ1R2 b kq - 0 13

And, more importantly, passed both short TC:
LLR: 2.95 (-2.94,2.94) [-1.50,4.50]
Total: 6239 W: 1249 L: 1127 D: 3863

And long TC:
LLR: 2.96 (-2.94,2.94) [0.00,6.00]
Total: 38371 W: 6165 L: 5888 D: 26318

bench: 8183238
2014-01-12 22:48:08 +01:00
Marco Costalba 3d58092ec1 Retire KBBKN endgame
As pointed out by Joona, Lucas and otehr people in
the forum, this endgame is not a known, there are many
positions where it takes more than 50 moves to claim the
win and becasue exact rules is not possible better to
retire and allow the search to workout the endgame for us.

bench: 8502826
2014-01-12 22:32:41 +01:00
Henri Wiechers db05b1f9f5 Rename Position::hidden_checkers to check_blockers
No functional change.
2014-01-12 04:10:46 +09:00
Henri Wiechers 262c380c4b Position::gives_check - use ci.ksq
Also remove a couple of local variables while
there.

No functional change.
2014-01-09 07:38:04 +09:00
Marco Costalba 6a6fd0b5f5 Fix early stop condition
While editing original Uri's messy patch
I have incorrectly simplified the logic
condition. Here is the correct original
version, as it was tested.

bench: 8502826
2014-01-09 06:58:25 +09:00
Ralph Stoesser f14cd1bb89 Retire easy move
Remove the easy move code and add the condition to
play instantly if only one legal move is available.

Verified there is no regression at 60+0.05
ELO: 0.17 +-1.9 (95%) LOS: 57.0%
Total: 40000 W: 6397 L: 6377 D: 27226

bench: 8502826
2014-01-08 23:57:06 +09:00
Uri Blass a5869d8d25 Stop earlier if iteration is taking too long
If we are still at first move, without a fail-low and
current iteration is taking too long to complete then
stop the search.

Passed short TC:
LLR: 2.97 (-2.94,2.94) [-1.50,4.50]
Total: 26030 W: 4959 L: 4785 D: 16286

Long TC:
LLR: 2.95 (-2.94,2.94) [0.00,6.00]
Total: 18019 W: 2936 L: 2752 D: 12331

And performed well at 40/30
ELO: 4.33 +-2.8 (95%) LOS: 99.9%
Total: 20000 W: 3480 L: 3231 D: 13289

bench: 8502826
2014-01-08 23:45:55 +09:00
renouve 45dbd9cd03 Retire grain size code
Seems useless at long TC.

Tested at 60+0.05
ELO: 2.98 +-2.2 (95%) LOS: 99.6%
Total: 30440 W: 4934 L: 4673 D: 20833

And at 120+0.05
ELO: 2.50 +-2.6 (95%) LOS: 97.1%
Total: 19633 W: 2848 L: 2707 D: 14078

bench: 8502826
2014-01-08 23:22:17 +09:00
Marco Costalba a646f74e6a Assorted grammar fixes
Mainly from Lyudmil Antonov and
one from Henri Wiechers and Louis Zulli.

No functional change.
2014-01-07 14:30:41 +09:00
Joona Kiiski 1fee23a598 Tweak King PST tables
First tested with 50K games at very short TC of 5+0.05
ELO: 3.11 +-2.0 (95%) LOS: 99.9%
Total: 49665 W: 10941 L: 10497 D: 28227

Then retested with usual SPRT at short TC
LLR: 2.96 (-2.94,2.94) [-1.50,4.50]
Total: 16875 W: 3198 L: 3049 D: 10628

And at long TC
LLR: 2.95 (-2.94,2.94) [0.00,6.00]
Total: 5890 W: 985 L: 857 D: 4048

bench: 7800379
2014-01-07 13:41:16 +09:00
Marco Costalba 1574428f64 Fix a typo
Spotted by Isaac H. Dunn.

No functional change.
2014-01-06 01:22:44 +01:00
Pablo Vazquez 0118623495 Remove duplicated code
Introduce update_stats() and remove correspondng
duplicated code.

No functional change.
2014-01-05 14:10:29 +01:00
H. Felix Wittmann 8454d871ec Ensure move_importance() is non-zero
In case ply is very high, function will round
to zero (although mathematically it is always
bigger than zero). On my system this happens at
movenumber 6661.

Although 6661 moves in a game is, of course,
probably impossible, for safety and to be locally
consistent makes sense to ensure returned value
is positive.

Non functional change.
2014-01-02 13:01:24 +01:00
shane31 153309e287 Scale eval when down to only one pawn
Passed both short TC
LLR: 2.97 (-2.94,2.94) [-1.50,4.50]
Total: 11921 W: 2346 L: 2208 D: 7367

And long TC
LLR: 2.97 (-2.94,2.94) [0.00,6.00]
Total: 21002 W: 3395 L: 3197 D: 14410

bench: 7602383
2014-01-02 12:44:46 +01:00
Marco Costalba c9dcda6ac4 Update copyright year
No functional change.
2014-01-02 01:49:18 +01:00
Marco Costalba 29e0d8caa7 Simplify move_importance(): take 3
Use pow() of a negative number instead of 1/x

No functional change.
2014-01-01 13:43:58 +01:00
Marco Costalba a795187c50 Further simplify move_importance()
Function move_importance() is already always
positive, so we don't need to add a constant
term to ensure it.

Becuase move_importance() is used to calculate
ratios of a linear combination (as explained in
previous patch), result is not affected. I have
also verified it directly.

No functional change.
2014-01-01 13:35:11 +01:00
H. Felix Wittmann 92faa74dfa Simplify move_importance()
Drop a useless parameter. This works because ratio1 and ratio2
are ratios of linear combinations of thisMoveImportance and
otherMovesImportance and so the yscale cancels out.

Therefore the values of ratio1 and ratio2 are independent
of yscale and yscale can be retired.

The same applies to yshift, but here we want to ensure
move_importance() > 0, so directly hard-code this safety
guard in function definition.

Actually there are some small differences due to rounding errors
and usually are at most few millisecond, that's means below 1% of
returned time, apart from very short intervals in which a difference
of just 1 msec can raise to 2-3% of total available time.

No functional change.
2014-01-01 12:58:10 +01:00
Marco Costalba c5d478b923 Rename pawn chain to connected
The flag raises also in case of a pawn duo, i.e.
when we have two adjacent pawns on the same rank,
and not only in case of a chain, i.e. when the two
pawns are on a diagonal line.

See this for a reference:
http://en.wikipedia.org/wiki/Connected_pawns

Renaming suggested by Ralph.

No functional change.
2014-01-01 10:56:57 +01:00
Gary Linscott 9b1d594456 Remove bishop pin bonus
Shows no regression at LTC after 20K games:

ELO: 0.03 +-2.7 (95%) LOS: 51.0%
Total: 20608 W: 3252 L: 3250 D: 14106

bench: 7516178
2013-12-31 15:27:52 +01:00
Arjun Temurnikar 71440cf77b Retire KingExposed[] array
And merge its values into KPSQT table.

Passed blazingly fast both short TC:
LLR: 2.95 (-2.94,2.94) [-1.50,4.50]
Total: 5348 W: 1091 L: 971 D: 3286

And long TC:
LLR: 2.96 (-2.94,2.94) [0.00,6.00]
Total: 3029 W: 530 L: 415 D: 2084

bench: 8702197
2013-12-31 12:05:22 +01:00
Henri Wiechers 082fbf4264 Remove asymmThreshold stale comment
No functional change.
2013-12-30 10:34:20 +01:00
Marco Costalba f7742669cb Retire asymmThreshold
Verified with 40K games at long TC does not regress:
ELO: 1.74 +-1.9 (95%) LOS: 96.2%
Total: 39624 W: 6402 L: 6203 D: 27019

bench: 7762310
2013-12-30 01:27:57 +01:00
Matt Sullivan 59a9bc9351 Retire MoveImportance[]
Use a skew-logistic function to replace the
MoveImportance[] array.

Verified it does not regress at fixed number
of games both at short TC:
LLR: -2.91 (-2.94,2.94) [-1.50,4.50]
Total: 39457 W: 7539 L: 7538 D: 24380

And long TC:
ELO: -0.49 +-1.9 (95%) LOS: 31.0%
Total: 39358 W: 6135 L: 6190 D: 27033

bench: 7335588
2013-12-29 10:33:39 +01:00
Stefan Geschwentner 8ca80cb0f1 Fine tune previous patch
Passed short TC
LLR: 2.95 (-2.94,2.94) [-1.50,4.50]
Total: 18331 W: 3608 L: 3453 D: 11270

And scored above 50% on a very long test in long TC
LLR: -2.97 (-2.94,2.94) [0.00,6.00]
Total: 51533 W: 8181 L: 8047 D: 35305

bench: 7335588
2013-12-27 18:46:49 +01:00
Marco Costalba 14aebe2b7c Further simplify previous patch
Use a single XOR instead of NEGATE + AND

No functional change.
2013-12-26 12:08:23 +01:00
Stefan Geschwentner cf0a2a26a9 Bonus for file distance of the outermost pawns
In endgame it's better to have pawns on both wings.
So give a bonus according to file distance between left
and right outermost pawns.

Passed both short TC
LLR: 2.97 (-2.94,2.94) [-1.50,4.50]
Total: 39073 W: 7749 L: 7536 D: 23788

And long TC
LLR: 2.96 (-2.94,2.94) [0.00,6.00]
Total: 6149 W: 1040 L: 910 D: 4199

bench: 7665034
2013-12-25 21:31:41 +01:00
Ralph Stößer 899a2c033e Loosened trigger condition for king safety
Reduce eval discontinuity becuase now we kick in
king safety evaluation in many more cases.

Passed both short TC:
LLR: 2.95 (-2.94,2.94) [-1.50,4.50]
Total: 8708 W: 1742 L: 1613 D: 5353

And long TC:
LLR: 2.95 (-2.94,2.94) [0.00,6.00]
Total: 6743 W: 1122 L: 990 D: 4631

bench: 6835416
2013-12-23 20:55:30 +01:00
Chris Caino 8aa4f3fde4 Increase pawn king attack weight
Tighter lower bound for pawn attacks so to
activate king safety in some cases like here:

6k1/2B3p1/2Pp1p2/2nPp3/2Q1P2K/P2n1qP1/R6P/1R6 w

Original patch by Chris, further simplified by
Jörg Oster.

Passed both short TC
LLR: 2.96 (-2.94,2.94) [-1.50,4.50]
Total: 30171 W: 5887 L: 5700 D: 18584

And long TC
LLR: 2.97 (-2.94,2.94) [0.00,6.00]
Total: 20706 W: 3402 L: 3204 D: 14100

bench: 7607562
2013-12-23 20:52:12 +01:00
Gary Linscott 26689d8c2a Faster and simplified threat eval
Add a bonus according if the attacking
pieces are minor or major.

Passed both short TC
LLR: 2.96 (-2.94,2.94) [-1.50,4.50]
Total: 13142 W: 2625 L: 2483 D: 8034

And long TC
LLR: 2.95 (-2.94,2.94) [0.00,6.00]
Total: 18059 W: 3031 L: 2844 D: 12184

bench: 7425809
2013-12-19 18:52:34 +01:00
Marco Costalba f196c1bad8 Further simplify Makefile
No functional change.
2013-12-17 10:16:00 +01:00
Marco Costalba e460ab74ad Reformat Makefile
No functional change.
2013-12-17 10:02:14 +01:00
Lucas Braesch f5727deee3 Remove threat move stuff
A great simplification that shows no regression
and it seems even a bit scalable.

Tested with fixed number of games:

Short TC
ELO: 0.60 +-2.1 (95%) LOS: 71.1%
Total: 39554 W: 7477 L: 7409 D: 24668

Long TC
ELO: 2.97 +-2.0 (95%) LOS: 99.8%
Total: 36424 W: 5894 L: 5583 D: 24947

bench: 8184352
2013-12-15 09:43:29 +01:00
Marco Costalba b96079f86b Sync history and counter moves updating
Change updating rule after a TT hit to match
the same one at the end of the search.

Small change in functionality, but we want to
have uniform rules in the code.

bench: 7767864
2013-12-10 07:05:06 +01:00
Lucas Braesch 86347100a5 Update History and Counter move on TT hit
We already update killers so it is natural to extend to
history and counter move too.

Passed both short TC
LLR: 2.95 (-2.94,2.94) [-1.50,4.50]
Total: 52690 W: 9955 L: 9712 D: 33023

And long TC
LLR: 2.96 (-2.94,2.94) [0.00,6.00]
Total: 5555 W: 935 L: 808 D: 3812

bench: 7876473
2013-12-10 06:57:06 +01:00
Ralph Stößer 8e9d4081ee Research at intermediate depth if LMR is very high
After a fail high in LMR, if reduction is very high do
a research at lower depth before teh full depth one.
Chances are that the re-search will fail low and the
full depth one is skipped.

Passed both short TC:
LLR: 2.95 (-2.94,2.94) [-1.50,4.50]
Total: 11363 W: 2204 L: 2069 D: 7090

And long TC:
LLR: 2.95 (-2.94,2.94) [0.00,6.00]
Total: 7292 W: 1195 L: 1061 D: 5036

bench: 7869223
2013-12-09 08:03:47 +01:00
Marco Costalba 4630ab5743 More work on Bitboards::init()
No functional change.
2013-12-07 12:32:18 +01:00
Marco Costalba 1ff5ce8863 More readable init of MS1BTable[]
Because now it uses lsb(), the BSFTable[] must be
already initialized.

No functional change.
2013-12-07 11:35:26 +01:00
Marco Costalba b71418defa Further simplify Bitboards init()
No functional change.
2013-12-07 10:57:05 +01:00
Marco Costalba 47b89f2e37 Clarify definition of capture_or_promotion()
No functional change.
2013-12-06 10:43:17 +01:00
Arjun Temurnikar 431c3ac485 Even more spelling fixes
No functional change.
2013-12-06 09:03:24 +01:00
Arjun Temurnikar 190aea4cdc Assorted spelling/grammar/captitalization
No functional change.
2013-12-04 23:30:37 +01:00
Chris Caino f026517e5e Micro-optimise dangerous condition
Since all ENPASSANT moves are now considered dangerous, this
change of order should give a slight speedup.

Also simplify futilityValue formula.

No functional change.
2013-12-04 17:51:25 +01:00
Marco Costalba b71cedb2b0 Retire TheirHalf[]
We avoid to use an ad-hoc table at the cost of a
relative_rank() call in advanced_pawn_push().

On my 32 bit system it is even slightly faster (on 64bit
may be different). This is the speed in nps alternating
old and new bench runs:

new

368890
368825
369972

old

367798
367635
368026

No functional change.
2013-12-04 17:45:09 +01:00
Chris Caino 69a14554ee Broader condition for dangerous pawn moves
Instead of a passed pawn now we just require the pawn to
be in the opponent camp to be considered a dangerous
move. Added some renaming to reflect the change.

Passed both short TC test
LLR: 2.95 (-2.94,2.94) [-1.50,4.50]
Total: 10358 W: 2033 L: 1900 D: 6425

And long TC
LLR: 2.95 (-2.94,2.94) [0.00,6.00]
Total: 21459 W: 3486 L: 3286 D: 14687

bench: 8322172
2013-12-04 17:19:45 +01:00
Marco Costalba 2408243cf4 Shrink Position::is_draw()
No functional change.
2013-12-03 11:40:31 +01:00
Marco Costalba 342fd6385b Remove redundant argument from hidden_checkers()
No functional change.
2013-12-03 11:15:39 +01:00
Marco Costalba e6c9ce6358 Small improvment to Position::fen()
No functional change.
2013-12-03 10:53:21 +01:00
Jerry Donald c7e7d9217b Re-fix a comment
No functional change.
2013-12-03 08:50:12 +01:00
Jerry Donald a8af78c833 Another round of spelling fixes
And also renamed a loop variable while there.

No functional change.
2013-12-02 23:51:29 +01:00
Richard Lloyd 13a73f67c0 Big assorted spelling fixes
No functional change.
2013-12-02 20:29:35 +01:00
Jerry Donald 500b9b0eb3 Assorted spelling fixes
No functional change.
2013-12-02 18:41:30 +01:00
Marco Costalba f99cb3dc27 Rename CASTLE to CASTLING
It is call 'castling move', not 'castle move'

Noticed while reading DiscoCheck sources.

No functional change.
2013-12-01 11:16:47 +01:00
Marco Costalba dd4e5db2be Simplify a condition in gives_check()
Now that aligned() is quite fast we can skip
some logic.

No functional change.
2013-12-01 10:09:30 +01:00
Marco Costalba 5f2bf91ad1 Rename Bitboards print to pretty
To align to same named Position function and
avoid using std::cout directly.

Also remove some stale <iostream> include while
there.

No functional change.
2013-11-30 11:32:49 +01:00
Marco Costalba 034a2b04f2 Rewrite some bitboard init code
And move the static function Position::attacks_from() to
bitboard code renaming it attacks_bb()

No functional change.
2013-11-30 11:02:56 +01:00
Daylen Yang 6ea5dc294c Makefile improvements for compiling on OS X
Add a Mac SSE4.2 target. Also change the Mac OS X minimum version to
10.6. Rationale: 97% of Macs run at least 10.6, version 10.9 is now
free, and using 10.6 as the minimum version gives a small 5% boost in
benchmark speed over versions using 10.0 as the minimum version.

Finally, enable Clang’s Link Time Optimization when compiling for the
Mac.

No functional change.
2013-11-30 00:09:17 +01:00
Marco Costalba 8f5deaea61 Restore development version
bench: 8596156
2013-11-29 10:50:43 +01:00
Marco Costalba c5bb9b9da9 Stockfish DD
Stockfish bench signature is: 8596156
2013-11-29 10:23:14 +01:00
Kelly Wilson 67e5581e37 Add support for PPC 64bit on Linux
In particular Debian Linux-3.9.8-1- PPC64

No functional change.
2013-11-29 10:06:54 +01:00
Joona Kiiski 3ede7daab3 Generate Qsearch checks only at depth 0
An old idea retested at SPRT(0, 3) with 60+0.05 TC:
LLR: 2.95 (-2.94,2.94) [0.00,3.00]
Total: 98872 W: 15549 L: 15123 D: 68200

This is a very small elo increase patch so it really
stresses the limits of fishtest.

bench: 8596156
2013-11-24 10:26:49 +01:00
Marco Costalba dbd6156fce Revert previous fix
It seems to intorduce a regression when tested
with 3 threads at 15+0.05:

ELO: -2.26 +-2.2 (95%) LOS: 2.4%
Total: 30000 W: 4813 L: 5008 D: 20179

bench: 8331357
2013-11-19 07:20:50 +01:00
Hongzhi Cheng 691ed425ba Get correct excluded moves for split nodes
Tested setting FakeSplit to true and running

./stockfish bench 128 2

There is a different signature with and without
the patch so it affects functionality but
only in SMP case.

bench: 8331357
2013-11-18 16:41:49 +01:00
Marco Costalba c376ffce0f Revert previous patch
It seems a regression at 15+0.05:
ELO: -4.82 +-2.1 (95%) LOS: 0.0%
Total: 40000 W: 7181 L: 7736 D: 25083

bench: 8331357
2013-11-17 23:47:18 +01:00
Marco Costalba 917944e9c5 Fix an assert in SMP case
SMP case is very tricky and raises an assert in stage_moves():

assert(stage == KILLERS_S1 || stage == QUIETS_1_S1 || stage == QUIETS_2_S1)

So rewrite the code to just return moves[] when we are sure
we are in quiet moves stages.

Also rename stage_moves to quiet_moves to reflect that.

No functional change (but needs testing in SMP case)
2013-11-17 10:24:25 +01:00
Marco Costalba d9c7cad630 Retire quietsSearched[]
Use MovePicker moves[] to access already tried
quiet moves. A bit of care shall be taken
to avoid calling stage_moves() when we are still
at ttMove stage, because moves are yet to be
generated. Actually our staging move generation
makes this code a bit more tricky than what I'd
like, but removing an ausiliary redundant
array like quietsSearched[] is a good thing.

Idea by DiscoCheck

bench: 9355734
2013-11-17 09:51:04 +01:00
Marco Costalba 9763c69fa5 Simplify generate<EVASIONS>
Use the newly introduced LineBB[] to simplify this
super hot-path function.

Verified with perft we don't have any speed regression, although
the number of squares removed is less than before in case of
contact check.

Insipred by DiscoCheck implementation.

Perft numbers are the same, but we have an harmless functional
change due to reorder of moves, because now some illegal moves
are no more detected at generation time, but in the search.

bench: 8331357
2013-11-11 19:53:19 +01:00
Gregor Cramer 555d9a8711 Faster castling in Chess960 case
Only rook attackers has to be considered, all other attackers are
already handled in the lines above.

No functional change.
2013-11-11 15:55:08 +01:00
Joona Kiiski b9768b8bc5 Reintroduce gains
This seems a die hard idea :-)

Passed both short TC
LLR: 2.97 (-2.94,2.94) [-1.50,4.50]
Total: 17485 W: 3307 L: 3156 D: 11022

And long TC
LLR: 2.97 (-2.94,2.94) [0.00,6.00]
Total: 38181 W: 6002 L: 5729 D: 26450

bench: 8659830
2013-11-11 08:46:11 +01:00
Jörg Oster 4ef6b2c32a Remove opposed flag for doubled pawns
Actually, it is not used, as both arrays have the
same values. Some local tests in either direction
showed no improvement.

Also some minor corrections in the comments.

No functional change.
2013-11-10 17:21:59 +01:00
Marco Costalba 1d18647e73 Rename squares_aligned()
Rename to the shorter but still
clear aligned()

No functional change.
2013-11-10 17:14:46 +01:00
Marco Costalba a518d5d3ad Simplify squares_aligned()
Use newly introduced LineBB[]

No functional change.
2013-11-10 12:05:19 +01:00
Chris Caino 091aff0445 Evaluate mobility of pinned pieces exactly
Previously some squares could be "incorrectly" awarded
to a pinned piece.

e.g. in 3k4/1q6/3b4/3Q4/8/5K2/B7/8 b - - 0 1 the black
bishop get 4 squares too many and the white queen gets 6.

Passed both short TC.
LLR: 2.97 (-2.94,2.94) [-1.50,4.50]
Total: 4871 W: 934 L: 817 D: 3120

And long TC:
LLR: 2.96 (-2.94,2.94) [0.00,6.00]
Total: 38968 W: 6113 L: 5837 D: 27018

bench: 9282549
2013-11-10 11:52:38 +01:00
Chris Caino 3ed86ed3f9 Remove RedundantMajor
But compensate by reducing rook and queen
value by 53 = (160 / 3)

Material imbalances are affected as follows:

       Red. Major   Rook  Queen  Total
QRR      +160      -2*53    -53     +1
QR       +160        -53    -53    +54
RR       +160      -2*53      0    +54
R           0        -53      0    -53
Q           0          0    -53    -53

so that the imbalance changes by at most 54 + 53 = 107 units.
This corresponds to appromximately 3.5cp in the final evaluation.

Verified with fixed number 40000 games at both short
and long TC it does not regress.

Short TC 15+0.05
ELO: 1.93 +-2.1 (95%) LOS: 96.6%
Total: 40000 W: 7520 L: 7298 D: 25182

Long TC 60+0.05
ELO: -0.33 +-1.9 (95%) LOS: 36.5%
Total: 39663 W: 6067 L: 6105 D: 27491

bench: 6703846
2013-11-10 09:48:49 +01:00
Marco Costalba e4d34e1815 Fix printing of incorrect PV in some cases
As, Gary (that analyzed the bug) says:

SF does not print a PV when the original best move fails low,
we hit our time allowance, and stop the search.  The output from
the SF search is below.  It was failing low on Ne1 at depth 34.
Then, we get bestmove Qd3, but no PV change.

info depth 34 seldepth 45 score cp 38 upperbound nodes 483484489 nps 15464575 time 31264 multipv 1 pv f3e1 h5h4 e1d3 h4g3 f2g3 a6f6 f1f6 e7f6 d1a4 f6e7 a1f1 d8f8 a4b3 b7b6 b3c2 f7f6 c2a4 h3g5 b2b3 g5f7 a4c6 f7d6 h1g2 f6f5 e4f5 d6f5
info depth 34 seldepth 45 score cp 38 upperbound nodes 483484489 nps 15464575 time 31264 multipv 1 pv f3e1 h5h4 e1d3 h4g3 f2g3 a6f6 f1f6 e7f6 d1a4 f6e7 a1f1 d8f8 a4b3 b7b6 b3c2 f7f6 c2a4 h3g5 b2b3 g5f7 a4c6 f7d6 h1g2 f6f5 e4f5 d6f5
info depth 34 seldepth 47 score cp 30 upperbound nodes 2112334132 nps 17255517 time 122415 multipv 1 pv f3e1 h5h4 d1a4 a6f6 e1d3 d8f8 a4c2 h4g3 f2g3 f6f1 a1f1 h7g8 b2b3 f7f6 a3a4 b7b6
info depth 34 seldepth 47 score cp 30 upperbound nodes 2112334132 nps 17255517 time 122415 multipv 1 pv f3e1 h5h4 d1a4 a6f6 e1d3 d8f8 a4c2 h4g3 f2g3 f6f1 a1f1 h7g8 b2b3 f7f6 a3a4 b7b6
info nodes 18235667001 time 969824
bestmove e2d3 ponder c8d7

Looking at the code, if we hit Signals.stop, we return from id_loop
before printing any PV.  It is possible for us to have resorted the
RootMove list though, which will change the move that is actually
played.

No functional change.
2013-11-09 19:05:43 +01:00
Marco Costalba 42caebfaa5 Fix compile in debug mode
No functional change.
2013-11-09 18:41:51 +01:00
Lucas Braesch eed508b444 Futility pruning simplification
1/ eval margin and gains removed:
16bit are now free on TT entries, due to the removal of eval margin. may be useful
in the future :) gains removed: use instead by Value(128). search() and qsearch()
are now consistent in this regard.

2/ futility_margin()
linear formula instead of complex (log(depth), movecount) formula.

3/ unify pre & post futility pruning
pre futility pruning used depth < 7 plies, while post futility pruning used
depth < 4 plies. Now it's always depth < 7.

Tested with fixed number of games both at short TC:
ELO: 0.82 +-2.1 (95%) LOS: 77.3%
Total: 40000 W: 7939 L: 7845 D: 24216

And long TC
ELO: 0.59 +-2.0 (95%) LOS: 71.9%
Total: 40000 W: 6876 L: 6808 D: 26316

bench 7243575
2013-11-09 10:17:27 +01:00
Marco Costalba 343544f3f7 Revert "Retire eval margin and gains"
This reverts commit ecd07e51d0.

Patch was incorrect and partial. It will be reapplied in
the correct form.

bench: 9189063
2013-11-07 22:32:13 +01:00
Gary Linscott 13d1f0ae43 Restrict mobility of pinned pieces
Passed both short TC:
LLR: 3.00 (-2.94,2.94) [-1.50,4.50]
Total: 54342 W: 10950 L: 10692 D: 32700

And long TC:
LLR: 2.95 (-2.94,2.94) [0.00,6.00]
Total: 61976 W: 10654 L: 10251 D: 41071

This patch introduces a slowdown of 3.5 % !!!!!

bench: 7911558
2013-11-07 22:26:03 +01:00
Lucas Braesch ecd07e51d0 Retire eval margin and gains
1/ eval margin and gains removed:
 - gains removed by Value(128): search() and qsearch() now behave consistently!

2/ futility_margin()
 - testing showed that there is no added value in this weird (log(depth), movecount)
   formula, and a much simpler linear formula is just as good. In fact, it is most
   likely better, as it is not yet optimally tuned.
 - the new simplified formula also means we get rid of FutilityMargins[], its
   initialization code, and more importantly ss->futilityMoveCount, and the hacky
   code that updates it throughout the search().
 - the current formula gives negative futility margins, and there is a hidden interaction
   between the move coutn pruning formula and the futility margin one: what happens is
   that MCP is supposed to be triggered before we use the non-sensical negative futility
   margins.

3/ unify pre & post futility pruning
 - pre futility pruning (what SF calls value based pruning) used depth < 7 plies,
   while post futility pruning (what SF calls static null move pruning) used depth < 4 plies.
 - also the condition depth < 7 in pre futility pruning was not obvious, and it seemd
   to be depth < 16 (futility_margin() returns an infinite value when depth >= 7).

Tested with fixed number of games both at short TC:
ELO: 0.82 +-2.1 (95%) LOS: 77.3%
Total: 40000 W: 7939 L: 7845 D: 24216

And long TC
ELO: 0.59 +-2.0 (95%) LOS: 71.9%
Total: 40000 W: 6876 L: 6808 D: 26316

bench: 10206576
2013-11-07 19:46:51 +01:00
Chris Caino 52ae0efccf Two more parameters eliminated
RedundantRook and RedundantQueen replaced by simple
variable RedundantMajor. Also the SameColor coefficient
for Queen<->Queen has been set by definition to 0.

The remaining 5 parameters:

LinearCoefficients[ROOK]
LinearCoefficients[QUEEN]
QuadraticCoefficientsSameColor[ROOK][ROOK]
QuadraticCoefficientsSameColor[QUEEN][ROOK]
RedundantMajor

are sufficient to equate the material imbalances for the
5 common material configurations of R, RR, Q, QR and QRR
to any desired values simultaneously.

With the chosen parameters there should be no functional
change unless one side has more than 2 rooks or more
than 1 queen. For example bench from the start position
using the commands:

./stockfish
go depth 16

produces identical output except for one extra node
in the last iteration.

bench: 8198094
2013-11-07 19:20:24 +01:00
Chris Caino 53c04c0429 Zero more redundant coefficients
Coefficients for Bishop<->BishopPair and Bishop<->Bishop
are also pretty much redundant. By altering the values
in LinearCoefficients[] these coefficients can be zeroed
without changing the imbalance calculations in any position
with less than 3 bishops for one side.

bench: 7995098
2013-11-05 20:08:39 +01:00
Chris Caino 1064288b38 Zero redundant material imbalance terms
First coefficient in the SameColor array does an
equivalent job when folded into the LinearCoefficients
array.

All of the diagonal terms in the OppositeColor array
are redundant due to cancellation.

No functional change.
2013-11-05 20:08:39 +01:00
Joona Kiiski d34bb889b1 Test Easy Move if no BestMoveChanges
In case we find a very good move after a
troubled start, we don't return immediately
anymore.

Tested directly at long TC where it passed:
LLR: 2.95 (-2.94,2.94) [0.00,6.00]
Total: 13910 W: 2397 L: 2228 D: 9285

bench: 7995098
2013-11-02 11:34:42 +01:00
Marco Costalba a3a0df92a3 Set timer to a fixed interval
And remove a complex (and broken) formula.

Indeed previous code was broken in case of TC with big
time increments where available_time() was too similar
to total time yielding to many time losses, so for instance:

go wtime 2600 winc 2600
info nodes 4432770 time 2601 <-- time forfeit!

maximum search time = 2530 ms
available_time = 2300 ms

For a reference and further details see:

https://groups.google.com/forum/?fromgroups=#!topic/fishcooking/dCPAvQDcm2E

Speed tested with bench disabling timer alltogheter vs timer set at
max resolution, showed we have no speed regressions both in single
core and when using all physical cores.

No functional change.
2013-11-01 08:56:15 +01:00
Ralph Ster e8f9447b11 Use a formula for chain membership bonus
Passed both short TC:
LLR: 2.96 (-2.94,2.94) [-1.50,4.50]
Total: 5087 W: 1072 L: 951 D: 3064

And long TC:
LLR: 2.95 (-2.94,2.94) [0.00,6.00]
Total: 28620 W: 5042 L: 4798 D: 18780

bench: 7995098
2013-10-31 06:13:30 +01:00
Marco Costalba 3cc47edf62 Tweak bishop pair and knight weight
A combo of two patches that failed SPRT with score
higher than 50% but togheter they succeed:

SPRT at 60+0.05
LLR: 2.95 (-2.94,2.94) [0.00,6.00]
Total: 7312 W: 1276 L: 1139 D: 4897

bench: 8029334
2013-10-28 19:31:25 +01:00
Matthew Sullivan d454cd4216 Fix divide by zero bug in late game
If the game got late enough that move_importance(currentPly) * slowMover / 100
rounds to 0, then we ended up dividing 0 by 0 when only looking 1 move ahead.

This apparently caused the search to almost immediately abort and Stockfish
would blunder in long games. So convert thisMoveImportance to a double.

No functional change.
2013-10-27 08:03:58 +01:00
Marco Costalba 48f38f3092 Retire mirror()
Inline the only caller site.

No functional change.
2013-10-24 20:40:26 +02:00
Marco Costalba 281472e50e Prefer file_bb() to FileBB[]
No functional change.
2013-10-24 20:34:23 +02:00
Jörg Oster f011a5af11 Penalty for Knight when enemy pawns are few
This seems more a material imbalance topic,
anyhow test is good and so patch is applied
as is.

Passed both short TC:
LLR: 2.96 (-2.94,2.94) [-1.50,4.50]
Total: 17391 W: 3548 L: 3393 D: 10450

And long TC:
LLR: 3.00 (-2.94,2.94) [0.00,6.00]
Total: 34660 W: 5972 L: 5700 D: 22988

bench: 8291883
2013-10-24 20:11:33 +02:00
Marco Costalba 67b0da83da Further smplify pawn endgames
Dumb down a bit the code and trade some possible
speed (but this is far from hot path anyhow) for
some added readability for the layman.

No functional change.
2013-10-23 19:56:35 +02:00
Chris Caino 3674f18b97 Use flip_sq idea in endgame.cpp
The normalising transformation is computed all at
once by the helper function get_flip_sq and then
applied immediately to the relevant squares as soon
as they are loaded from the position class.

bench: 8350690
2013-10-23 16:00:49 +02:00
Chris Caino 72f7282ad4 Simplify futility move count formula
Simpler formula but introduces some slight changes if d >= 10

Original code grows like  0.225 * d^1.8
New code grows like       0.222 * d^1.8

Full list of values:

d old new diff
--------------
0 2 2 0
1 2 2 0
2 3 3 0
3 4 4 0
4 5 5 0
5 6 6 0
6 7 7 0
7 9 9 0
8 11 11 0
9 13 13 0
10 15 16 1
11 18 19 1
12 21 21 0
13 24 24 0
14 27 28 1
15 31 31 0
16 35 35 0
17 39 38 -1
18 42 42 0
19 47 46 -1
20 51 51 0
21 55 55 0
22 60 60 0
23 65 65 0
24 70 70 0
25 75 75 0
26 81 80 -1
27 87 86 -1
28 92 91 -1
29 98 97 -1
30 104 103 -1
31 111 109 -2

Test code:

int main() {

  for(int d=0; d<32; d++)
  {
     int a = int(3 + 0.3 * pow(double(d), 1.8)) * 3/4 + (2 < d && d < 5);
     int b = int(2.4 + 0.222 * pow(d + 0.0, 1.8));

     std::cout << d << " " << a << " " << b << " " << b-a << std::endl;
  }

  return 0;
}

bench: 8350690
2013-10-22 23:09:40 +02:00
Chris Caino fbfce2132a Simplify futility margins formula
New formula mathces the old formula until d = 45

Test code:

int main() {

  for(int d=1; d<=45; d++)
  {
     int a = int(log(double(d * d) / 2) / log(2.0) + 1.001);
     int b = int(2.9 * log(double(d)));

     if (a != b) std::cout << d << std::endl;
  }

  return 0;
}

bench: 8455956
2013-10-22 23:06:06 +02:00
Marco Costalba 2c825294ec Tweak again chain pawn bonus
This is the first chain bonus version
from Ralph that also passed both

Short TC:
LLR: 2.96 (-2.94,2.94) [-1.50,4.50]
Total: 23460 W: 4727 L: 4556 D: 14177

And long TC:
LLR: 2.95 (-2.94,2.94) [0.00,6.00]
Total: 31858 W: 5497 L: 5240 D: 21121

And performed better against current
committed version, always at 60secs:

LLR: -2.94 (-2.94,2.94) [-3.00,3.00]
Total: 26301 W: 4477 L: 4580 D: 17244

This test was done by Leonid.

bench: 8455956
2013-10-22 17:47:16 +02:00
Marco Costalba f86d2aee29 Re-add "Further increase safe checks bonus"
After 40K games at 60 secs, result is still
not clear, but not a regression against SF 4

After
ELO: 50.11 +-2.1 (95%) LOS: 100.0%
Total: 40000 W: 10547 L: 4817 D: 24636

Before
ELO: 49.51 +-2.1 (95%) LOS: 100.0%
Total: 40000 W: 10483 L: 4821 D: 24696

So re-apply the patch to avoid to
special-case this one.

bench: 7403882
2013-10-22 17:33:11 +02:00
Marco Costalba 35ea39bed2 Restore behaviour after count<ALL_PIECES> fix
Because pos.count<ALL_PIECES>(Us) was always zero,
rewrite the formula as if this would still be
the case.

bench: 8510004
2013-10-22 17:27:58 +02:00
Ralph Stößer 97015afce8 Further improve chain pawn evaluation
Passed both short TC:
LLR: 2.96 (-2.94,2.94) [-1.50,4.50]
Total: 28299 W: 5854 L: 5667 D: 16778

And long TC:
LLR: 2.96 (-2.94,2.94) [0.00,6.00]
Total: 9738 W: 1797 L: 1644 D: 6297

bench: 9294116
2013-10-20 23:41:40 +02:00
Marco Costalba f22a63ce67 Fix pos.count<ALL_PIECES>()
It was never updated !

Currently it only affects evaluate_passed_pawns()
and in particularly the rule to increase the bonus
if we have more non-pawn pieces. We could simply use
popcount() instead and avoid the little slowdown
in put_piece() and remove_piece(), but this would
leave a very subtle and tricky hole where people
are forced to remember that pos.count<ALL_PIECES>()
does not work. This is not obvious and so dangerous.

Thanks to Ronald de Man for spotting this.

bench: 7931424
2013-10-20 23:36:46 +02:00
Marco Costalba c08e7419a0 Fix build on Intel compiler
Due to a strange issue (bug?) the ternary
operator does not return a BitCountType for
icc, so revert to the expression.

The same patch was already applied in
9749f1f14c

Thanks to NssY Wanyonyi for pointing out
this.

No functional change.
2013-10-20 23:19:08 +02:00
Marco Costalba 67f91bc5ea Revert "Further increase safe checks bonus"
This reverts commit 4bc2374450 for
two reasons.

First regression testing shows almost equal
score:

Before the patch:
ELO: 49.75 +-2.5 (95%) LOS: 100.0%
Total: 27205 W: 7113 L: 3244 D: 16848

After the patch:
ELO: 48.87 +-2.9 (95%) LOS: 100.0%
Total: 20860 W: 5478 L: 2563 D: 12819

Second, and more sensible to me, this patch
increases safe check bonuses to 4 times their
original value (!) and considering:

- Values were already well tuned

- Values are highly critical

- King safety is highly critical, very TC
  dependent and very difficult to test

- Our testing coverage is partial (self-testing,
  blitz times)

I think is better to be safe than sorry and so
I revert the patch.

bench: 8440524
2013-10-20 10:04:43 +02:00
Ralph Stößer 4bc2374450 Further increase safe checks bonus
Passed both short TC:
LLR: 2.95 (-2.94,2.94) [-1.50,4.50]
Total: 10466 W: 2087 L: 1953 D: 6426

And long TC:
LLR: 2.96 (-2.94,2.94) [0.00,6.00]
Total: 26334 W: 4540 L: 4310 D: 17484

And also proved stronger than a slightly
different patch, also succesful against master:

https://github.com/mcostalba/Stockfish/commit/dc6830a3b4ed12

But losing against current one in a match
at 60secs with SPRT [-3, 3]:

LLR: -2.96 (-2.94,2.94) [-3.00,3.00]
Total: 44484 W: 7360 L: 7463 D: 29661

bench: 9160831
2013-10-19 12:19:36 +02:00
Marco Costalba f5e872a0e3 Some evaluation code reshuffle
No functional change.
2013-10-18 09:49:38 -07:00
Jörg Oster 25cb851f8a Score chain pawn also by rank
Use the (rescaled) CandidatePassed[] table
that is already rank based.

Passed both short TC
LLR: 2.95 (-2.94,2.94) [-1.50,4.50]
Total: 11048 W: 2272 L: 2135 D: 6641

And long TC
LLR: 2.97 (-2.94,2.94) [0.00,6.00]
Total: 4116 W: 769 L: 645 D: 2702

bench: 8440524
2013-10-18 10:27:55 +02:00
Chris Caino 3cddb0c076 Simplification of KPsK function
Also the drawing criteria has been slightly loosened.
It now detects a draw if the king is ahead of all the
pawns and on the same file or the adjacent file.

bench: 7700683
2013-10-15 07:36:01 +02:00
Chris Caino 2bf18bfc63 Bug fix for KQKRPs endgame
This lost position 8/8/3q4/8/5k2/2P1R3/2K2P2/8 w - - 0 1
was previously evaluated as a draw.

The king and rook need to be correctly placed with
respect to the _same_ pawn.

(Note also that the check for the pawn being on RANK_2
in the old version is redundant: it must be on RANK_2 if
it hopes to protect a rook on RANK_3)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2013-10-15 07:34:29 +02:00
Ralph Stößer 5aeb907fa1 Double king safety weights
Good both at short TC:
LLR: 2.95 (-2.94,2.94) [-1.50,4.50]
Total: 5448 W: 1133 L: 1012 D: 3303

And at long TC:
LLR: 2.95 (-2.94,2.94) [0.00,6.00]
Total: 40509 W: 6836 L: 6541 D: 27132

bench: 7700683
2013-10-14 23:24:29 +02:00
Chris Caino 0c68971c13 Remove a drawing rule from KBPsK function
The rule can be incorrect if the attacking king is
well placed e.g. 8/6K1/8/8/7k/1B6/7P/8 w - - 0 1

bench: 8279065
2013-10-14 19:55:07 +02:00
Marco Costalba d9be00342c Massive stronger/weaker renming
No functional change.
2013-10-14 19:38:08 +02:00
Chris Caino 027d85e82a Add helper function verify_material
Allows to remove a lot of assert code in endgames.

No functional change.
2013-10-14 19:23:57 +02:00
ceebo 3bc3c069f1 Add some knowledge for KRPKB endgame
bench: 8279065
2013-10-14 07:44:02 +02:00
ceebo e9366fa155 Improve KBPsK endgame
Better endgame with bishop and blocked g-pawn

bench: 8279065
2013-10-14 07:44:01 +02:00
Marco Costalba 549b5c478f Remove unuseful optimization in RKISS
Don't need a struct here. Speed test shows
result is teh same. Moreover RKISS is used
mainly at startup to compute magics, so
prefer to keep it simple...RKISS ;-)

Also some assorted triviality while there.

No functional change.
2013-10-13 03:35:17 -07:00
Joona Kiiski b15e148b5e Smoother transition for LMR
Passed both short TC:
LLR: 2.95 (-2.94,2.94) [-1.50,4.50]
Total: 12376 W: 2596 L: 2454 D: 7326

And long TC:
LLR: 2.97 (-2.94,2.94) [0.00,6.00]
Total: 14798 W: 2584 L: 2409 D: 9805

bench: 8279065
2013-10-09 19:13:41 +02:00
Uri Blass bb83a417cb Increase slowmover and reduce instability
These two changes go in opposite directions and it
seems that the combination is stronger than original.

Here are the positive tests at various TC:

15+0.05
LLR: 2.96 (-2.94,2.94) [-1.50,4.50]
Total: 24561 W: 4946 L: 4772 D: 14843

60+0.05
LLR: 2.96 (-2.94,2.94) [0.00,6.00]
Total: 15259 W: 2598 L: 2423 D: 10238

40/30
LLR: 2.96 (-2.94,2.94) [-3.00,3.00]
Total: 2570 W: 527 L: 422 D: 1621

Unfortunately there is also a bad result
with one sec time increment that needs
to be further investigated:

12+1
LLR: -2.97 (-2.94,2.94) [-3.00,3.00]
Total: 2694 W: 438 L: 543 D: 1713

bench: 8340585
2013-10-08 21:24:21 +02:00
Lucas Braesch 984ee9d05b Use TT refined value to stand pat
Passed both short TC:
LLR: 2.95 (-2.94,2.94) [-1.50,4.50]
Total: 17811 W: 3520 L: 3366 D: 10925

And long TC:
LLR: 2.95 (-2.94,2.94) [0.00,6.00]
Total: 30255 W: 5070 L: 4825 D: 20360

bench: 8340585
2013-10-08 19:51:08 +02:00
Lucas Braesch a0cc15ccbc Use double everywhere
Rationale:

- Speed of double and float is about the same (not on the hot path anyway)

- Double makes code prettier (no need to write 1.0f, just 1.0)

- Only practical advantage of float is to use less memory, but since we never
  store large arrays of double, we don't care.

No functional change.
2013-10-05 18:12:52 +02:00
Lucas Braesch 7f142d6817 Use prefix operators wherever possible
No functional change.
2013-10-05 18:10:43 +02:00
Marco Costalba bd1c3ed7e3 Add more depth/positions to bench
Increase bench default depth from 12 to 13 and
add 15 new endgame positions to have broader
coverage and also more reliable nps calulcation
used for fishtest framework.

Due to the new endgame positions, where nps is higher,
the total nps is increased of about 15%.

Thanks to Lucas and Jörg for the suggestions.

No functional change, but bench number is now:

bench: 8336338
2013-09-29 09:43:10 +02:00
Marco Costalba cca34e234c Drop 'is' prefix from query functions
Most but not all.

No functional change.
2013-09-28 06:47:59 -07:00
Marco Costalba ed95ad1c0e Fix build on Mac OS X
For some users -stack_size,0x4000 does not work,
so revert for now.

osX 10.6.8
gcc version 4.7.3 (MacPorts gcc47 4.7.3_2)

g++: error: unrecognized command line option '-stack_size,0x4000'
make[2]: *** [stockfish] Error 1
make[1]: *** [gcc-profile-make] Error 2
make: *** [profile-build] Error 2

No functional change.
2013-09-28 04:16:16 -07:00
Marco Costalba c65d67feb5 Revert "Use a per-thread array"
This reverts commit 800410eef1 and instead increases
stack size.

I went through the old emails with Daylen that reported the
crash issue on Mac OS X and was fixed by 0049d3f337.

It was reported default stack size for a thread in Mac OS X is 8
megabytes while the patch that we are reverting allows to reduce
stack size at max of about 217KB, so the reason for the crash was
only marginal in MAX_MOVES value. On those emails Daylen also
hinted how to increase stack size for Mac OS X to 16MB.

So prefer to increase stack size to 16MB instad of re-inventing
the wheel and do our home grown stack as we did with the patch
that we are now reverting (it will remain anyhow in git history
for documentation purposes).

No functional change.
2013-09-28 10:10:51 +02:00
Lucas Braesch bc6faf633e Simplify extensions
Unify extensions between PV and not PV nodes
and remove all but check extensions.

This is a simplification so tested at fixed number
of games where proved to not regress.

About 45k games at 15+0.05
ELO: 1.23 +-2.0 (95%) LOS: 88.5%
Total: 45643 W: 9107 L: 8946 D: 27590

About 45k games at 60+0.05
ELO: 1.07 +-1.8 (95%) LOS: 87.8%
Total: 46786 W: 7728 L: 7584 D: 31474

bench: 3172206
2013-09-28 09:54:22 +02:00
Reuven Peleg 8d1c1074d5 Simplify tte use condition
No functional change.
2013-09-27 09:40:48 +02:00
Raminder Singh e654209211 Fix best move lookup bug
If the uci option 'Best Book Move' is set to true the lookup still
returns a move at random instead of the move with the highest
weight.

No functional change.
2013-09-27 09:04:24 +02:00
Marco Costalba b742a3f29a Increase MAX_MOVES to 256
This should be enough for any legal position, even
the handcrafted ones, like the one presented by Reuven:

1Q5R/4Q1K1/B1Q5/B4Q2/N2Q4/pQ4Q1/pn2Q3/krQ4R w - -

Where currently we crash. This reverts the patch
0049d3f337 of 8/4/2012 where stack
was shrinked due to crashes while in deep analysys.

No functional change.
2013-09-27 08:59:03 +02:00
Marco Costalba 800410eef1 Use a per-thread array for generated moves
This greately reduces stack usage and is a
prerequisite for next patch.

Verified with 40K games both in single and SMP
case that there are no regressions.

No functional change.
2013-09-27 08:44:36 +02:00
Jean-Francois Romang 7b2cda95d9 Update disabled warnings for Intel compiler
No functional change.
2013-09-23 08:11:43 +02:00
Jean-Francois Romang c2cefa6de0 Replace -O3 with -fast for intel compiler
No functional change.
2013-09-23 08:11:14 +02:00
Ralph Stößer d7f5f15d69 Reduce negative quiets by ONE_PLY / 2
Passed both short TC:
LLR: 2.96 (-2.94,2.94) [-1.50,4.50]
Total: 3402 W: 708 L: 593 D: 2101

And long TC:
LLR: 2.93 (-2.94,2.94) [0.00,6.00]
Total: 23379 W: 3972 L: 3759 D: 15648

bench: 3529630
2013-09-23 08:08:52 +02:00
Marco Costalba 84906b83ec Final time management setup
This is an even safer setup proposed and tested
by Alexandre Meirelles.

Regression testing of 40K games at 10+0.05 show
result is stable both against current master:

ELO: -0.29 +-2.2 (95%) LOS: 39.7%
Total: 40000 W: 8010 L: 8043 D: 23947

and again original master (the one with smallest
time parameters):

ELO: 1.71 +-2.2 (95%) LOS: 93.8%
Total: 40000 W: 8325 L: 8128 D: 23547

Alexandre verified with LittleBlitzer time losses are
greately reduced with this setup:

Games Completed = 2100 of 3000 (Avg game length = 35.745 sec)

Settings = RR/128MB/15000ms+50ms/M 1000cp for 12 moves, D 150 moves/
Time = 39200 sec elapsed, 16800 sec remaining
 1.  Stockfish 190913             1091.5/2100    803-720-577      (L: m=313 t=1 i=0 a=406)    (D: r=278 i=91 f=136 s=8 a=64)    (tpm=212.5 d=14.75 nps=925427)
 2.  Houdini 2.0 w32              1008.5/2100    720-803-577      (L: m=250 t=299 i=0 a=254)    (D: r=278 i=91 f=136 s=8 a=64)    (tpm=204.1 d=12.04 nps=1326351)

No functional change.
2013-09-23 07:59:51 +02:00
Marco Costalba 274079990a Increase Emergency Move Time to 20
Goes in the direction of avoiding time losses and seems
equivalent after almost 40K games at super fast TC of 10+0.05

ELO: 2.61 +-2.2 (95%) LOS: 99.1%
Total: 39869 W: 8258 L: 7959 D: 23652

No functional change.
2013-09-19 07:26:36 +02:00
Marco Costalba 10cb19d534 Increase Emergency Move Time to 10
Goes in the direction of avoiding time losses and seems
equivalent after almost 40K games at super fast TC of 10+0.05

ELO: 2.41 +-2.3 (95%) LOS: 98.1%
Total: 37222 W: 7843 L: 7585 D: 21794

No functional change.
2013-09-17 16:32:39 +02:00
Marco Costalba d50b33cacd Fix a silly unstoppable eval bug
The logic is broken for black side because we get more bonus
for pawn in 7th rank than for pawn in 2nd rank!

Spotted by Reuven Peleg

bench:3884409
2013-09-16 23:59:37 +02:00
Joona Kiiski 77b5ee0117 Fix time parameters for blitz games
The ideal setting for super-blitz might be something like:

    "Emergency Base Time" = 50
    "Emergency Move Time" = 5

This would give a total emergency time buffer of:

    50 + 40 * 5 = 250 ms

This setup replaces the previous half cooked hack
"Don't blunder under extreme time pressure".

Test results are very good at super blitz, but keep good even
at 60 secs.

At 5+0.05
ELO: 24.30 +-2.4 (95%) LOS: 100.0%
Total: 37802 W: 10060 L: 7420 D: 20322

At 15+0.05
ELO: 13.41 +-2.9 (95%) LOS: 100.0%
Total: 22271 W: 4853 L: 3994 D: 13424

At 60+0.05
ELO: 5.30 +-3.2 (95%) LOS: 99.9%
Total: 16000 W: 2897 L: 2653 D: 10450

No functional change.
2013-09-16 09:07:47 +02:00
Marco Costalba af750bd2ef Rewrite unstoppable pawns evaluation
Instead of current code, give a bonus according to the frontmost
square among candidate + passed pawns.

This is a big simplification that removes a lot of accurate code
substituting it with a statistically based one using the common
'bonus' scheme, leaving to the search to sort out the details.

Results are equivalent but code is much less and, as an added bonus,
we now store candidates bitboard in pawns hash and allow this
info to be used in evaluation. This paves the way to possible
candidate pawns evaluations together with all the other pieces,
as we do for passed.

Patch passed short TC
LLR: 2.96 (-2.94,2.94) [-1.50,4.50]
Total: 16927 W: 3462 L: 3308 D: 10157

Then failed (quite quickly) at long TC
LLR: -2.95 (-2.94,2.94) [0.00,6.00]
Total: 8451 W: 1386 L: 1448 D: 5617

But when ran with a conclusive 40K fixed games at 60 secs it proved
almost equivalent to original one.

ELO: 1.08 +-2.0 (95%) LOS: 85.8%
Total: 40000 W: 6739 L: 6615 D: 26646

bench: 3884003
2013-09-16 08:57:37 +02:00
Reuven Peleg 21cbfafc03 Code style at passed pawn eval
No functional change.
2013-09-15 21:49:06 +02:00
Reuven Peleg d3947b2f3e Nicer operator declerations
No functional change.
2013-09-15 21:45:18 +02:00
Kojirion a71209868b Use pre-increment also for native types
Now that we use pre-increment on enums, it
make sense, for code style uniformity, to
swith to pre-increment also for native types,
although there is no speed difference.

No functional change.
2013-09-15 09:17:21 +02:00
Marco Costalba 7a1ff6d8ff Fix operator++ definition
ENABLE_OPERATORS_ON has incorrect definitions of
post-increment and post-decrement operators.

In particularly the returned value is the variable
already incremented/decremented, while instead they
should return the variable _before_ inc/dec.

This has no real effect because are only used in loops
and where the returned value is never used, neverthless
it is wrong. The fix would be to copy the variable to a
dummy, then inc/dec the variable, then return the dummy.

So instead, rename to pre-increment that can be implemented
without the dummy, actually the current implementation
it is already the correct pre-increment, with the only change
to return a reference (an l-value) and not a copy, so
to properly mimic the pre-increment on native integers.

Spotted by Kojirion.

No functional change.
2013-09-15 09:09:06 +02:00
Marco Costalba 82f6779c2e Don't blunder under extreme time pressure
We always attempt to keep at least this emergencyBaseTime
at clock. But if available time is very low it means that
we will force ourself to play immediately to satisfy the
emergencyBaseTime constrain and so leading to blunders.

Patch is good at short and very short TC (15secs and 5secs respectively)
LLR: 2.96 (-2.94,2.94) [-1.50,4.50]
Total: 26590 W: 5426 L: 5245 D: 15919

LLR: 2.96 (-2.94,2.94) [-1.50,4.50]
Total: 5767 W: 1397 L: 1268 D: 3102

Instead seems has no influence at longer TC (60 secs)
LLR: -2.96 (-2.94,2.94) [0.00,6.00]
Total: 79862 W: 13623 L: 13339 D: 52900

So it is committed to have a broader testing but is
to be consider still EXPERIMENTAL and can be reverted
easily.

No functional change.
2013-09-15 07:59:09 +02:00
Marco Costalba 3abccdc82d Move classify_leaf() to c'tor in bitbases
No functional change.
2013-09-14 13:08:37 +02:00
Marco Costalba 8d6d0223bf Small touches to bitbase.cpp
Inspired by Lucas's code:

https://github.com/lucasart/chess/blob/master/src/kpk.cc

No functional change.
2013-09-14 11:19:12 +02:00
Reuven Peleg fc17d0de77 Increase passed bonus for having more pieces
Passed both short TC:
LLR: 2.95 (-2.94,2.94) [-1.50,4.50]
Total: 36463 W: 7575 L: 7365 D: 21523

And long TC:
LLR: 2.97 (-2.94,2.94) [0.00,6.00]
Total: 2953 W: 564 L: 446 D: 1943

bench: 3846852
2013-09-13 18:08:22 +02:00
Marco Costalba 27f2ce8f6e Revert "Move draw by material check"
Possible regression

bench: 4554579
2013-09-12 08:44:11 +02:00
Marco Costalba 45b0aea875 Revert "Fix random moves when time < 10ms"
Possible regression.

No functional change.
2013-09-12 08:38:19 +02:00
Marco Costalba 4803d5772c Extend checks more when below alpha
Passed both short TC:
LLR: 2.97 (-2.94,2.94) [-1.50,4.50]
Total: 8739 W: 1830 L: 1698 D: 5211

And long TC:
LLR: 2.96 (-2.94,2.94) [0.00,6.00]
Total: 6716 W: 1238 L: 1101 D: 4377

bench: 4554576
2013-09-11 19:15:28 +02:00
Uri Blass 738c5595ad Extend checks more in losing positions
Passed both short TC:
LLR: 2.98 (-2.94,2.94) [-1.50,4.50]
Total: 3974 W: 860 L: 741 D: 2373

And long TC:
LLR: 2.96 (-2.94,2.94) [0.00,6.00]
Total: 16807 W: 2917 L: 2733 D: 11157

bench: 3767999
2013-09-11 09:15:47 +02:00
Reuven Peleg bebd6e16f6 Simplify unstoppable pawns evaluation
No functional change
2013-09-10 23:02:05 +02:00
Marco Costalba 49e110c52b Fix random moves when time < 10ms
In case we have less then 10ms to think as soon as
we wake up the timer, it immediately fires and calls
check_time() where due to condition:

elapsed > TimeMgr.maximum_time() - 2 * TimerResolution

the stop flag is set and search returns immediately, without
actually search anything.

Here the somewhat hacky fix is to start the timer after
at least one iteration as been completed.

No functional change.
2013-09-10 21:23:20 +02:00
Reuven Peleg 4d90aeb0ab More readable space mask
No functional change.
2013-09-10 19:18:10 +02:00
homoSapiensSapiens 03cd049c68 Change condition to use relative rank
No functional change
2013-09-10 00:47:31 +02:00
Marco Costalba 6ab8b9b6c6 Fix some comments in position.cpp
No functional change.
2013-09-08 06:28:53 -07:00
Marco Costalba 490f67a3f8 Move draw by material check
It is more natural to test this case among
others material distributions.

No functional change.
2013-09-08 06:11:35 -07:00
Marco Costalba 0515ad0fb0 Remove unreachable values in mobility table
The possible maximum mobility cardinality (plus one in case of
zero squares available) is:

- Knights: max. 8  squares -> max. 9  entries
- Bishops: max. 13 squares -> max. 14 entries
- Rooks:   max. 14 squares -> max. 15 entries
- Queen:   max. 27 squares -> max. 28 entries

So remove the extra entries in the table.

Spotted by Dariusz Orzechowski.

No functional change.
2013-09-07 18:25:24 +02:00
Marco Costalba bf51db2526 Fix warning: double to float truncation
MSVC 2013 says:
warning C4305: '*=' : truncation from 'double' to 'float'

No functional change.
2013-09-07 12:30:44 +02:00
Lucas Braesch 59702aca0d Singular extension at 8 plies also for PV nodes
Passed both short TC:
LLR: 2.96 (-2.94,2.94)
Total: 11451 W: 2455 L: 2282 D: 6714

And long TC
LLR: 2.96 (-2.94,2.94)
Total: 15813 W: 2907 L: 2723 D: 10183

bench: 3864419
2013-09-07 09:34:22 +02:00
Lucas Braesch c86eee3918 Union of 2 changes
Union of

- LMR >= 3 plies from Gary tests.stockfishchess.org/tests/view/522522960ebc595d328fcafd

- allows() tweak from Reuven tests.stockfishchess.org/tests/view/5225fa1c0ebc595d328fcb53

Both passed Step I and failed Step II.

Instead this union passed both short TC:
LLR: 2.95 (-2.94,2.94)
Total: 14525 W: 3063 L: 2874 D: 8588

And long TC
LLR: 2.94 (-2.94,2.94)
Total: 31075 W: 5566 L: 5308 D: 20201

bench: 4238160
2013-09-07 09:25:45 +02:00
Lucas Braesch 10b53e1c5e Do not prune useless checks in QS
Passed both SPRT tests in "simplification mode", so with
elo0: -3.00 alpha: 0.05 elo1: 3.00 beta: 0.05

Short TC:
LLR: 2.96 (-2.94,2.94)
Total: 6243 W: 1302 L: 1195 D: 3746

Long TC
LLR: 2.96 (-2.94,2.94)
Total: 22972 W: 4124 L: 4020 D: 14828

bench: 4633330
2013-09-05 18:50:16 +02:00
Marco Costalba a30d3571ca Revert "Fix check for bishop pair in material imbalance"
Idea is sound but implementation is partial. Ryan and Joona noticed that
    we leave an hole in material table. Also we got another report by an user
    of an odd behaviour. Namely, if you start stockfish and from the prompt
    give 'bench' you get 3453941, then if you run again bench you get 3453940.

    The reason is that two different positions with the same number of pieces,
    but one with a bishop pair and another without have the same material key.
    But after Eelco patch also different material imbalance and this yields
    to this issue.

    Restesting at long TC shows the patch does not really contribute at
    ELO improvement. Actually patch failed at long TC.

    LLR: -2.97 (-2.94,2.94)
    Total: 23109 W: 4104 L: 4092 D: 14913

    So revert.

    bench: 3453945
2013-09-05 06:34:48 +02:00
Reuven Peleg 457ac26de5 Rewrite backward pawn detection
Use the new backmost_sq() instead of a loop.

No functional change.
2013-09-03 20:11:00 +02:00
Eelco de Groot 679c2ea227 Fix check for bishop pair in material imbalance
Prefer pos.bishop_pair() to pos.count<BISHOP>(WHITE) > 1
because the first checks that the two bishops are on
different color squares.

Although the change seems to kick in only in very rare cases,
quite surprisingly it was able to pass SPRT test at short TC.

LLR: 2.95 (-2.94,2.94)
Total: 39818 W: 8174 L: 7956 D: 23688

bench: 3453941
2013-09-03 19:40:34 +02:00
Marco Costalba 9ff594c3a9 Rewrite KBBKN endgame
This was thought to be a draw but the bishops generally win. However,
it takes up to 66 moves. The position in the diagram was thought to be
a draw for over one hundred years, but tablebases show that White wins
in 45 moves. All of the long wins go through this type of semi-fortress
position. It takes several moves to force Black out of the temporary
fortress in the corner; then precise play with the bishops prevents Black
from forming the temporary fortress in another corner (Nunn 1995:265ff).

Before computer analysis, Speelman listed this position as unresolved,
but "probably a draw" (Speelman 1981:109).

bench: 3453945
2013-09-02 11:03:01 +02:00
Marco Costalba 849b089a63 Don't use lpthread for Android
Thanks to Peter Osterlund for the feedback.

No functional change.
2013-09-01 13:48:09 -07:00
Marco Costalba aee404f532 Improve ARM compatibility
STANDALONE-TOOLCHAIN.html in Android NDK says:

It is recommended to use the -mthumb compiler flag to force the generation
of 16-bit Thumb-1 instructions (the default being 32-bit ARM ones).

If you want to target the 'armeabi-v7a' ABI, you will need ensure that the
following two flags are being used:

  CFLAGS='-march=armv7-a -mfloat-abi=softfp'

Note: The first flag enables Thumb-2 instructions, and the second one
      enables H/W FPU instructions while ensuring that floating-point
      parameters are passed in core registers, which is critical for
      ABI compatibility. Do *not* use these flags separately!

Thanks to Peter Osterlund for pointout this doc and for showing me
an example Makefile to follow.

No functional change.
2013-09-01 09:18:37 -07:00
Uri Blass 0915f85895 Union of 2 changes that failed with good score
This is a union of 2 changes:

A tweak of recaptures limit from Joona Kiiski
http://tests.stockfishchess.org/tests/view/52166d7c0ebc59319a242400

and a tweak of move count pruning from Leonid Pechenik
http://tests.stockfishchess.org/tests/view/5217c7e60ebc59319a242456

The set passed both short TC at 30+0.05
LLR: 2.96 (-2.94,2.94)
Total: 18936 W: 3723 L: 3566 D: 11647

And the usual long TC at 60+0.05
LLR: 2.95 (-2.94,2.94)
Total: 48962 W: 8837 L: 8487 D: 31638

bench: 3453945
2013-09-01 08:07:21 -07:00
Marco Costalba 5e8bc6ac2a Assorted clean up in endgames
No functional change.
2013-09-01 07:39:04 -07:00
Marco Costalba 3e4dcaa06e Fix a bogus assert in allows()
Becuase castle is coded as "king captures the rook"
the to_sq(move), A1/8 or H1/8 is empty after the move,
leading to assert assert(p != NO_PIECE) in color_of().

Teach allows() asserts about castle and fix the crash.

Bug reported by Ryan Takker and tracked down by Tom Vijlbrief.

No functional change.
2013-08-30 16:42:18 +02:00
Marco Costalba 14f47c8ac6 Use frontmost_sq() and backmost_sq helpers
Should easier to read than the lsb() / msb() low
level functions.

No functional change.
2013-08-30 16:22:22 +02:00
Gary Linscott 5d90c149b5 Enable LMR for dangerous moves
Passed both short TC
LLR: 2.96 (-2.94,2.94)
Total: 5598 W: 1250 L: 1125 D: 3223

And long TC
LLR: 2.97 (-2.94,2.94)
Total: 16441 W: 3102 L: 2912 D: 10427

bench: 4620975
2013-08-29 23:02:18 +02:00
homoSapiensSapiens 4b9e338541 Bonus for rook behind a passed
If our rook is behind a passed pawn, all
squares are defended.

One of the longest tests to pass !

Passed both short TC
LLR: 2.97 (-2.94,2.94)
Total: 44560 W: 9518 L: 9281 D: 25761

And long TC
LLR: 2.96 (-2.94,2.94)
Total: 61348 W: 11618 L: 11192 D: 38538

bench: 3787694
2013-08-29 22:53:21 +02:00
homoSapiensSapiens a0cf424cfc Replace hardcoded 128 by constant
No functional change.
2013-08-29 13:59:49 +02:00
Gary Linscott aecdbfc4a0 Add lsb() overload
Helper to find least significant bit relative to
the given color.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2013-08-28 19:50:11 +02:00
Uri Blass e6482b7d97 Time management: move faster if PV is stable
Move faster but compensate by allocating more
time when the best move changes.

Passed short TC at 15+0.05
LLR: 2.93 (-2.94,2.94)
Total: 13895 W: 3030 L: 2882 D: 798

Long TC at 60+0.05
LLR: 2.96 (-2.94,2.94)
Total: 9266 W: 1777 L: 1624 D: 5865

At time increment 30+0.5
LLR: 2.96 (-2.94,2.94)
Total: 6703 W: 1238 L: 1134 D: 4331

And at fixed game number, longer TC 120+0.05
ELO: 5.17 +-2.8 (95%) LOS: 100.0%
Total: 19306 W: 3378 L: 3091 D: 12837

bench: 4728533
2013-08-26 10:29:58 -07:00
homoSapiensSapiens 6e6c5b6103 Simplify chain detection
No functional change.
2013-08-25 18:36:49 +02:00
homoSapiensSapiens 04fd7efdfa Simplify kf definition in shelter_storm()
No functional change.
2013-08-25 18:31:47 +02:00
Chris Caino 5e331f9618 Fix KBPK bug
With

position fen 7k/8/8/8/8/7P/6K1/7B w - - 0 1
go depth 25

The evaluation at depth 22 is not draw as it should be. The reason is that
when search reaches the position 8/6kP/8/8/8/3B4/6K1/8 w - - 0 1 if white plays
h8R or h8N then we get a position that is a "KNOWN_WIN" and is _not_ a check, so
futility pruning in qsearch kicks in and black may think that it is "futile"
to reply Kxh8 since, according to the logic of the code, it cannot raise the score
back towards a draw.

bench: 4728533
2013-08-24 10:08:03 +02:00
homoSapiensSapiens b9f5d1c6ff Simplify condition for backward pawn
No functional changes.
2013-08-22 14:39:08 +02:00
Marco Costalba c4533e0d94 Retire redundant endgames
The case of two lone kings on the board is already considered
by the "No pawns" scaling factor rules in material.cpp as is
KBK and KNK.

Moreover we had a small leak in endgames map because for
KK endgame it happens white and black material keys are the
same (both equal to zero), so when adding the black endgame in
Endgames::add() we were overwriting the already exsisting
white one, leading to a memory leak found by Valgrind.

So remove the endgames althogheter and rely on scaling
to correctly set the endgames value to a draw.

No functional change.
2013-08-22 13:13:06 +02:00
Joona Kiiski f39cf1b008 Use null move when depth >= 2 plies
Passed both short TC:
LLR: 2.96 (-2.94,2.94)
Total: 23725 W: 5031 L: 4855 D: 13839

And long TC:
LLR: 2.96 (-2.94,2.94)
Total: 15730 W: 2939 L: 2754 D: 10037

bench: 4729333
2013-08-22 09:06:48 +02:00
Marco Costalba c6baefb79d Restore development version
No functional change.
2013-08-21 08:41:47 +02:00
Marco Costalba 4d120ee02e Stockfish 4
Stockfish bench signature is: 4132374
2013-08-20 09:01:25 +02:00
Tom Vijlbrief f45eee318b Fix crash when reaching max ply
Bug introduced in 1b7223a53c that
updated the ss base stack without increasing
the dimension.

No functional change.
2013-08-19 16:53:46 +02:00
Tom Vijlbrief 8c2fd2170a Remove useless condition in KXK endgame
Because eval is never called when in check.

No functional change.
2013-08-19 08:55:17 +02:00
Leonid Pechenik 91c2c44fb1 Further tweak movecount pruning
Passed both short TC
LLR: 2.95 (-2.94,2.94)
Total: 15140 W: 3125 L: 2976 D: 9039

And long TC
LLR: 2.95 (-2.94,2.94)
Total: 17118 W: 3165 L: 2974 D: 10979

bench: 4132374
2013-08-18 09:13:57 +02:00
Marco Costalba 27e9fc1067 Normalize "pawn in front of minor" patch
No functional change.
2013-08-17 11:05:55 +02:00
homoSapiensSapiens e005270fb6 Use constants arguments where possible
No functional changes.
2013-08-16 09:57:21 +02:00
Marco Costalba 4f55ed14d3 Revert using exceptions
Due to crashes. It will be reapplied once
we understand what's happening.

No functional change.
2013-08-15 09:36:26 +02:00
homoSapiensSapiens a6c0ba2100 Simplify DistanceRingsBB init
Verified by same benchmark and picking some random values.

No functional change.
2013-08-14 10:53:43 +02:00
homoSapiensSapiens fc316cbca9 Some renaming in TT store()
No functional change.
2013-08-14 09:38:35 +02:00
Marco Costalba 11b1a76f35 Use exceptions to stop the search
Instead of classical flags, throw an
exception when we want to immediately halt
the search. Currently only one type
is used for both UCI stop and threads
cut off.

No functional change.
2013-08-14 08:29:57 +02:00
Tom Vijlbrief bd8f463b7e Bonus for a pawn in front of knight/bishop
Idea originated from a post of Don Dailey
on talkchess and reported by Eelco.

This is the last succesful attempt of a long
series of trials (as usually happens, the
'idea' alone is not enough).

Passed both short 15secs TC
LLR: 2.97 (-2.94,2.94)
Total: 7629 W: 1645 L: 1515 D: 4469

And long 60secs TC
LLR: 2.96 (-2.94,2.94)
Total: 10218 W: 1932 L: 1775 D: 6511

bench: 4944581
2013-08-13 14:20:02 +02:00
Ryan Takker 4d14f97482 Remove Now Unneeded Help Text
With the new automatic setting of split depth
instead of a default, the user no longer needs
guidance on setting the split point.

Also threads now defaults to one.

No functional change.
2013-08-13 07:36:33 +02:00
Marco Costalba 15616ad199 Don't set Search::RootColor in Eval::trace
Search::RootColor is a global parameter set
before to start a search, it is not something
trace() should change.

This patch allows to add trace() calls, for
debugging, inside search itself without altering
the bench, and also ensures that the values
returned by trace() and evaluate() are fully
equivalent.

No functional change.
2013-08-11 07:02:50 +02:00
Marco Costalba 94a3608ab9 Fix GrainSize rounding error
The rounding formula is different between
positive and negative scores due to the
GrainSize/2 term that is asymmetric.

So use truncation instead of rounding. This
guarantees that evaluation is rounded to zero
in the same way for both positive and negative
scores.

Found with position's flip

bench: 4634244
2013-08-10 17:11:13 +02:00
Marco Costalba 5769509d72 Fix 'improving' condition
Because VALUE_NONE is 30002, it happens that
after a check the next move is never an improving
one.

After this patch bench signature is independent from
VALUE_NONE actual value.

bench: 4303194
2013-08-09 08:21:55 +02:00
Marco Costalba fff6b9f061 Increase LMR when not improving
Apply to LMR the same Eelco's idea
applied to move count pruning.

This is the result of a series of
attempts started by Thomas Kolarik.

Passed both short TC
LLR: 2.95 (-2.94, 2.94)
Total: 5675 W: 1241 L: 1117 D: 3317


And long TC:
LLR: 2.95 (-2.94, 2.94)
Total: 8748 W: 1689 L: 1539 D: 5520

bench: 4356801
2013-08-08 10:28:48 +02:00
Marco Costalba 56d2c3844a Further tweak Position::flip
No functional change.
2013-08-05 14:44:06 +02:00
Marco Costalba 23b6809f3d Rewrite flip() to use FEN string manipulation
Instead of dealing directly with internal parameters
just "flip" the FEN string and set the position from
that.

No functional change.
2013-08-05 12:58:14 +02:00
Marco Costalba f31847302d Streamline time computation
No functional change.
2013-08-03 18:30:43 +02:00
Marco Costalba b1a4a18d63 Update polyglot.ini with new "Min Split Depth" default
No functional change.
2013-08-03 16:41:18 +02:00
Dan Schmidt f7096ea7ce Refactor do_castle()
Not a real functional change, but bench changed due to different piecelist
reordering. To verify it a temporary my canonicalize_rooks function was
written as follows. It just ensures that the rook on the "smaller" square
is listed first.

void Position::canonicalize_rooks(Color c)
{
   if (pieceCount[c][ROOK] == 2)
   {
      Square s0 = pieceList[c][ROOK][0];
      Square s1 = pieceList[c][ROOK][1];
      if (s0 > s1)
      {
         pieceList[c][ROOK][0] = s1;
         pieceList[c][ROOK][1] = s0;
         index[s0] = 1;
         index[s1] = 0;
      }
   }
}

With this both bench and the test on Chess960 positions

./stockfish bench 128 1 8 Chess960.epd file > /dev/null

Gives same result.

bench: 4424151
2013-08-03 16:18:28 +02:00
Joona Kiiski a16ba5bbd1 Retire cpu_count()
Set threads number always to 1 at startup and let the
user explicitly to chose the number of threads.

Also preserve the useful behavior of automatically set
"Min Split Depth" according to the requested threads,
indeed this parameter is too technical for a casual user,
so, when left to zero, we set it on a sensible value.

No functional change
2013-08-02 16:48:25 +02:00
Marco Costalba 408e6ee9b6 Further factor out position update code
Along the lines of previous patch.

No functional change
2013-08-01 16:32:46 +02:00
Dan Schmidt 7b4f5c8f72 Factor out pieceList updating code
The new Position methods add_piece, move_piece, and remove_piece
now manage the member variables pieceList, pieceCount, and index,
and 9 blocks of code in Position that used to manipulate those
data structures by hand now call the new methods.

There is a slightly slowdown (< 1%) on Clang and on perft,
but the cleanup compensates the little speed loss.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2013-08-01 15:50:19 +02:00
Marco Costalba 55948623e7 Rework Thread hierarchy
Introduce ThreadBase struct that is search
agnostic and just handles low level stuff,
and derive all the other specialized classes
form here.

In particular TimerThread does not hinerits
anymore all the search related stuff from Thread.

Also some renaming while there.

Suggested by Steven Edwards

No functional change.
2013-07-31 18:35:52 +02:00
Marco Costalba 4d46d29efe Fix a race at thread creation
At thread creation start_routine() is called
and from there the virtual function idle_loop()
because we do this inside Thread c'tor, where the
virtual mechanism is disabled, it could happen that
the base class idle_loop() is called instead.

The issue happens with TimerThread and MainThread
where, at launch, start_routine calls
Thread::idle_loop instead of the derived ones.

Normally this bug is hidden because c'tor finishes
before start_routine() is actually called in the
just created execution thread, but on some platforms
and in some cases this is not guaranteed and the
engine hangs.

Reported by Ted Wong on talkchess

No functional change.
2013-07-31 18:35:32 +02:00
Marco Costalba cc608a7aba Tidy up Position::pretty
No functional change.
2013-07-29 19:33:30 +02:00
Marco Costalba 1f40cd6d02 Small renaming
No functional change.
2013-07-29 19:32:59 +02:00
Marco Costalba 28bc8ed462 Speed up move generation
Pass the color as template parameter
to generate_all()

Speedup of 1,3% in perft and 2,5% in bench !

No functional change.
2013-07-29 19:01:50 +02:00
Eelco de Groot 5ee16a180a Increase pruning if evaluation is not improving
Add an additional set of margins to movecount pruning
to be used when static evaluation is getting worse
than previous move.

Here are the margins table with changing
depth (fm0 not improving, fm1 improving):

    d: 0, fm0: 3, fm1: 3
    d: 1, fm0: 4, fm1: 4
    d: 2, fm0: 6, fm1: 6
    d: 3, fm0: 7, fm1: 10
    d: 4, fm0: 11, fm1: 15
    d: 5, fm0: 15, fm1: 21
    d: 6, fm0: 21, fm1: 29
    d: 7, fm0: 27, fm1: 37
    d: 8, fm0: 35, fm1: 47
    d: 9, fm0: 42, fm1: 57
    d: 10, fm0: 51, fm1: 68
    d: 11, fm0: 60, fm1: 81
    d: 12, fm0: 70, fm1: 94
    d: 13, fm0: 81, fm1: 108
    d: 14, fm0: 92, fm1: 123
    d: 15, fm0: 104, fm1: 139

Good at both short TC

LLR: 2.97 (-2.94,2.94)
Total: 11502 W: 2503 L: 2361 D: 6638

And long TC

LLR: 2.98 (-2.94,2.94)
Total: 7189 W: 1421 L: 1277 D: 4491

bench: 4364793
2013-07-29 01:21:21 +02:00
Marco Costalba d30dfc084c Annotate an unlikely condition
No functional change.
2013-07-27 11:34:15 +02:00
Marco Costalba 6373e88b5b Fix an assert in KBK endgame
The endgame king + minor vs king is erroneusly
detected as king + minor vs king + minor

Here the fix is to detect king + minor earlier,
in particular to add these trivial cases to
endgame evaluation functions.

Spotted by Reuven Peleg

bench: 4727133
2013-07-27 08:25:45 +02:00
Tom Vijlbrief 7487eb0dca Rewrite pawn shield and storm code
Passes quickly both short TC:
LLR: 2.95 (-2.94,2.94)
Total: 5755 W: 1349 L: 1222 D: 3184

And long TC:
LLR: 2.95 (-2.94,2.94)
Total: 2744 W: 628 L: 505 D: 1611

bench: 4727133
2013-07-26 00:12:46 +02:00
Marco Costalba 2067a99c07 Fix a typo in bitboard.h
Introduced by previous patch.

Spotted by Joerg Oster

No functional change.
2013-07-25 07:44:27 +02:00
homoSapiensSapiens 002062ae93 Use #ifndef instead of #if !defined
And #ifdef instead of #if defined

This is more standard form (see for example iostream file).

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2013-07-24 19:49:17 +02:00
Marco Costalba 4064ee5406 Simplify captures ordering
A big simplification and removing of useless code.

Finished at 50% both at short TC (with SPRT) than
at long TC at fixed number of games:
ELO: -0.14 +-3.4 (95%) LOS: 46.8%
Total: 15206 W: 2836 L: 2842 D: 9528

bench: 5059948
2013-07-24 07:53:32 +02:00
Marco Costalba b0fd2b6b98 Revert "Halve king eval margin"
This reverts commit 4b3a0fdab0.

As Gary says: " It failed when I tried it at long TC previously, and only
barely passed this time.  Some anecdotal evidence is that it hurts vs other
engines as well (the Lightspeed rating list showed a 16 elo drop from previous
best version - still +- 5 error bars on both, but that's still significant)"

I also agree that if we have some doubts (like in this case) it is better to
be safe than sorry.

bench: 4615572
2013-07-24 07:46:25 +02:00
Ryan Schmitt d0bc951835 Tune pawn PSQT values
Reduces the influence of PSQT for entries such as
the extended center and the h-file.

Passed both short TC test:
LLR: 2.95 (-2.94,2.94)
Total: 23919 W: 5207 L: 5029 D: 13683

And long TC one:
LLR: 2.96 (-2.94,2.94)
Total: 5762 W: 1108 L: 974 D: 3680

Bench: 4617880

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2013-07-24 07:41:51 +02:00
Reuven Peleg 73131e7c78 Use arrow operator instead of * and .
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2013-07-22 20:22:40 +02:00
Reuven Peleg 1cc18d8a7a Better condition in is_pseudo_legal()
Simplify occupied destination condition.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2013-07-22 20:02:31 +02:00
Marco Costalba c45c6d308f Small touches in move generation
No functional change.
2013-07-21 11:01:24 +02:00
Marco Costalba f73bb438aa Some renaming in MovePicker
No functional change.
2013-07-21 09:55:08 +02:00
Marco Costalba 71dd8a333f Rewrite and simplify SEE
This very speed critical code was full of clever (!)
tricks and subtle details.

So I have rewritten it in a more straithforward way
and, as very often happens, result is even faster
than original.

No functional change.
2013-07-21 01:04:29 +02:00
Marco Costalba 9207baed65 Revert "Fix critical SEE bug (take 2)"
This reverts commit 3e95800814

For some reason it fails the short TC test:
LLR: -2.96 (-2.94,2.94)
Total: 20033 W: 4214 L: 4265 D: 11554

bench: 4769737
2013-07-20 18:45:38 +02:00
Marco Costalba b191df5ebe Revert "Yet another attempt at signature-build"
Still broken on OS X

No functional change.
2013-07-20 15:15:31 +02:00
Marco Costalba 3e95800814 Fix critical SEE bug (take 2)
It is somewhat unbilievable but our SEE is broken !

    If the first SEE move is a king capture and square is
    defended then SEE continues instead of breaking.

    The bug shows only on normal SEE, not see_sign() so
    probing with a:

    dbg_hit_on_c(slIndex==1, captured == KING);

    reports just a tiny:

    Total 3465656 Hits 6646 hit rate (%) 0

    Bug was there since Retire seeValues[] and move PieceValue[] out of Position of 26/6/2011 (!)
    although for some reason didn't show immediately, indeed the
    bougous patch was a "No functional change" (!!)

    bench: 4699504
2013-07-20 14:24:47 +02:00
Marco Costalba 2ed56f4d5f Revert all the SEE stuff
The speed up seems to introduce some
functionality change.

Revert to original master for now.

bench: 4769737
2013-07-20 14:20:33 +02:00
Marco Costalba 7b0b463720 Yet another attempt at signature-build
This one should work on all flavours of sed

Suggested by by Louis Zulli

No functional change.
2013-07-20 14:05:04 +02:00
Marco Costalba a6c5b4c6fb Fix critical SEE bug
It is somewhat unbilievable but our SEE is broken !

If the first SEE move is a king capture and square is
defended then SEE continues instead of breaking.

The bug shows only on normal SEE, not see_sign() so
probing with a:

dbg_hit_on_c(slIndex==1, captured == KING);

reports just a tiny:

Total 3465656 Hits 6646 hit rate (%) 0

Bug was there since 351ef5c85b of 26/6/2011 (!)
although for some reason didn't show immediately, indeed the
bougous patch was a "No functional change" (!!)

bench: 4793754
2013-07-20 13:37:12 +02:00
Marco Costalba 0504a6975d Speedup see()
And rename next_attacker() SEE helper

This very simple patch is able to speed up
bench run of almost 2% !

No functional change.
2013-07-20 12:34:35 +02:00
Marco Costalba a5b5a91512 Fix signature-build under OSX
On OS X when you use -i an extension for the in-place
substitution a backup files is required.

http://stackoverflow.com/questions/4247068/sed-command-failing-on-mac-but-works-on-linux

So rewrite to make sed flushing sign.txt in one go and avoid
using -i option.

Reported by Louis Zulli

No functional change.
2013-07-20 02:38:14 +02:00
Reuven Peleg 1a8f63a896 Microptimize gives_check() for castling case
Without patch we have 333198 nps, with patch 334249.

A very small +0.3%, not a lot manily becuase this is a
side path that is taken very few times.

Anyhow idea is correct becuase first 'quick' condition
has an hit rate of about 95%.

No functional change.
2013-07-19 17:07:54 +02:00
Marco Costalba ee5514b8fd Small simplification in space eval scoring
No functional change.
2013-07-19 11:13:18 +02:00
Marco Costalba 99e547f4cb Rename MoveStack to ExtMove
Stack has no meaning here, while ExtMove (extended move),
better clarifies that we have a move + a score.

No functional change.
2013-07-19 10:27:58 +02:00
Marco Costalba 110644d918 Better document what we skip when in check
No functional change.
2013-07-19 09:37:31 +02:00
homoSapiensSapiens 4b3a0fdab0 Halve king eval margin
But still keep the same original
margin for score.

Passed both short TC test
LR: 2.95 (-2.94,2.94)
Total: 3710 W: 845 L: 726 D: 2139

And long TC
LLR: 2.95 (-2.94,2.94)
Total: 57859 W: 10939 L: 10532 D: 36388

bench: 4769737

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2013-07-19 08:16:39 +02:00
Marco Costalba 05e31c5e5f Drop grep and tr dependency in Makefile
Use only sed to get the bench signature.

No functional change.
2013-07-15 21:39:06 +02:00
Marco Costalba 46fdb14b2f Don't use __builtin_expect
Partially revert previous patch and use
unlikey() just as code annotation.

Actually it is better to rely on a profiler for branch prediction:

http://blog.man7.org/2012/10/how-much-do-builtinexpect-likely-and.html

"In fact, even when only one in ten thousand values is nonzero,
we're still at only roughly the break-even point"

No functional change,
2013-07-15 21:09:06 +02:00
Marco Costalba cbb1a8ed31 Better annotate unlikely conditions
And in case of gcc we win also a small
speed optimization due to better branch
prediction.

No functional change.
2013-07-15 21:01:02 +02:00
Reuven Peleg a6c5f60caa Simplify a condition in refutes()
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2013-07-15 20:40:49 +02:00
Marco Costalba 9518cc3254 Update 'make help'
No functional change.
2013-07-14 12:23:28 +02:00
Marco Costalba b0a177bc67 Add signature-profile-build make target
Extend patch 3f64a2af6a to profile builds.

here the make command is:

make signature-profile-build ARCH=xxx COMP=xxx

No functional change.
2013-07-14 11:57:06 +02:00
Marco Costalba 5b7b330616 Retire engine Tag
It is somewhat redundant and could make SF
name too long, so use just Version, in case
of a signature build Version will be set to
'sig-xxx' otherwise, if left empty, we fall
back on usual date stamp.

No functional change.
2013-07-14 11:13:13 +02:00
Marco Costalba 3f64a2af6a Add signature-build make target
When compiling with:

make signature-build ARCH=xxx COMP=xxx

After binary has been roduced, it will be run to
get the signature 'stockfish bench' and this
number will be used as Version, so that it
will be easy to track the original sources
from a binary.

No functinal change.
2013-07-14 10:59:25 +02:00
Marco Costalba 9749f1f14c Fix build on Intel compiler
Due to a strange issue (bug?) the ternary
operator does not return a BitCountType for
icc, so revert to the expression used
before bcbc9bfd1f

No functional change.
2013-07-13 23:13:30 +02:00
Marco Costalba 4ede49cd85 Fully qualify memset and memcpy
And other trivial touches.

Ispired by Lucas's DiscoCheck

No functional change.
2013-07-13 18:01:13 +02:00
Tom Vijlbrief 6960f41e03 Retire enoughMaterial + lower trapped rook threshold
Here speed up is the name of the game.

Speed up is gained:

- Removing the useless enoughMaterial code

- Limiting trapped rook evaluation to where it counts

Tested at long TC:
LLR: 2.97 (-2.94,2.94)
Total: 10061 W: 1948 L: 1790 D: 6323

bench: 4558173
2013-07-13 18:01:03 +02:00
Marco Costalba bf90499fc3 A useless assignment found by Clang’s static analyzer
Warning is: "Value stored to 'xxx' is never read" and
it is raised in SpNode case.

No functional change.
2013-07-13 16:57:03 +02:00
Marco Costalba 404c4122ce Fix build with MSVC 2013
Also add an assert hinted by MSVC code analysis tool.

No functional change.
2013-07-13 13:03:09 +02:00
Marco Costalba 2a0bbb9faa Fix printing of PV info: take 2
Now last PV line is printed twice, fix that.

No functional change.
2013-07-13 07:43:50 +02:00
Marco Costalba 128e097d03 Fix printing of PV info
It was erroneusly skipped after the
aspiration window rework.

Reported by Eelco.

No functional change.
2013-07-12 23:42:42 +02:00
Marco Costalba c1264e46d0 Rename some UCI options
Thanks to Don, Miguel, Louis and the other people
of talkchess forum for the suggestion:

http://www.talkchess.com/forum/viewtopic.php?t=48612

Also sync polyglot.ini with current UCI options

No functional change.
2013-07-11 16:07:10 +02:00
Marco Costalba 366f6b0dab Fix a crash with depth 1 perft
Bug recently introduced in e215a88cdd

No functional change.
2013-07-11 07:23:48 +02:00
Marco Costalba 58aee9a9ea Don't IID when in check also in PvNodes
This tiny functional change allows to
nicely simplify things.

Performed at 50% in short TC:
LLR: -0.43 (-2.94,2.94)
Total: 46406 W: 9681 L: 9565 D: 27160

And succesfully passed long TC reverse test:
LLR: -2.95 (-2.94,2.94)
Total: 4945 W: 858 L: 937 D: 3150

bench: 4507230
2013-07-09 19:03:11 +02:00
Marco Costalba 4b703b1429 Revert previous patch
Unfortunatly a reverse test at long TC failed:

master^ vs master
LLR: 1.37 (-2.94,2.94)
Total: 33682 W: 6294 L: 6071 D: 21317

So becuase short TC score is 50% there is a good
possibility patch is not scalable.

So revert it.

bench: 4507288
2013-07-09 08:04:12 +02:00
Marco Costalba 62d38f0196 Simplify "fail high upon reduction" in null search
Do not use threat move to detect the condition. This
let us to retire the big allows() function.

Test at short TC was within 50% score:
LLR: -2.95 (-2.94,2.94)
Total: 38272 W: 7941 L: 7940 D: 22391

To be verified with reverse long TC

bench: 4191565
2013-07-08 07:23:30 +02:00
Marco Costalba 7e575512ae Skip node-level cut-off tests when in check
No functional change.
2013-07-07 13:39:58 +02:00
Marco Costalba a55fb76dcc Simplify aspiration window code
Here the main difference is that now we center
aspiration window on last returned score. This allows
to simplify handling of mate scores.

We have done a reversed SPRT tests, where we wanted to
verify if master is stronger than this patch.

Long TC: master vs this patch (reverse test)
LLR: -2.95 (-2.94,2.94)
Total: 37992 W: 7012 L: 6920 D: 24060

bench: 4507288
2013-07-03 18:59:23 +02:00
Marco Costalba 838255ef91 Workaround github issue
Temporary revert aspiration window patch
so to be visible to everybody: it will be
re-applied with next patch

No functional change (together with next one)
2013-07-03 18:58:23 +02:00
Marco Costalba 6fbe027da0 Simplify aspiration window code
Here the main difference is that now we center
aspiration window on last returned score. This allows
to simplify handling of mate scores.

We have done a reversed SPRT tests, where we wanted to
verify if master is stronger than this patch.

Long TC: master vs this patch (reverse test)
LLR: -2.95 (-2.94,2.94)
Total: 37992 W: 7012 L: 6920 D: 24060

bench: 4507288
2013-07-03 09:06:03 +02:00
Marco Costalba ddcb572c41 Disable flto when debugging
Link-time optimization does not work well with
generation of debugging information:

http://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html

Reported by Louis Zulli

No functional change.
2013-07-03 08:21:21 +02:00
Marco Costalba 12c0dfc113 Revert "Remove confusing optimization"
This reverts commit e05c80a088.

we gain a speed up of 1.5% under gcc !

No functional change.
2013-07-02 20:12:57 +02:00
Marco Costalba db53883f06 Merge branch 'master' into aspiration
bench: 4507288
2013-07-02 07:27:08 +02:00
Marco Costalba 13ffb08136 Revert "Increase earlier aspiration window size"
This reverts commit b88bc7b766.
2013-07-02 07:25:39 +02:00
Marco Costalba 2d82db1d14 Entering a pawn endgame is no more dangerous
A simplification of the 'dangerous' definition.

Seems neutral at reverse test at long TC

master vs patch
LLR: -2.96 (-2.94,2.94)
Total: 16974 W: 3122 L: 3139 D: 10713

bench: 4689029
2013-07-02 07:24:17 +02:00
Marco Costalba b88bc7b766 Increase earlier aspiration window size
bench: 4377851
2013-07-01 19:29:38 +02:00
Marco Costalba e074a19f5c Merge branch 'master' into aspiration 2013-07-01 19:25:23 +02:00
Marco Costalba b8930d0c26 Fix a stale comment
No functional change.
2013-06-30 13:12:04 +02:00
Marco Costalba 4fc7734547 Simplify search results update
Also some rename while there.

No functional change.
2013-06-30 12:49:39 +02:00
Marco Costalba 92dcbfa658 Reorder conditions according to their frequency
This should minimize useless tests.

No functional change.
2013-06-30 11:35:53 +02:00
Marco Costalba b50eb6bea8 Center aspiration window on last returned score
bench: 4428212
2013-06-30 11:14:02 +02:00
Marco Costalba 6f079ae720 Simplify aspiration window loop
Don't open the window in case we find a mate score: this
will be takes care with next patch.

No functional change.
2013-06-30 10:54:09 +02:00
Marco Costalba 203fdc9ac1 Use calloc() in TranspositionTable::set_size()
Function calloc() already initializes memory to
zero, so avoid calling clear() afterwards.

Also some renaming while there (inspired by DiscoCheck).

No functional change.
2013-06-29 11:23:07 +02:00
Marco Costalba 17d41b3861 Fix some stale comments
No functional change.
2013-06-23 13:19:03 +02:00
Marco Costalba 8cff4862a6 Move SquareDistance[] to bitboard.cpp
No functional change.
2013-06-23 13:13:13 +02:00
Marco Costalba 908d98820b Don't explicitize enum values when not needed
Compiler will chose the correct values in sequential
order for you.

Also move file and rank bitboards definitions to
bitboard.h

No functional change.
2013-06-23 11:30:40 +02:00
Marco Costalba a4c11b71ac Retire in_front_bb(Color c, Square s) overload
Explciitly call rank_of() in the few places where
it is used.

No functional change.
2013-06-23 10:16:43 +02:00
Marco Costalba b2fadf32aa Retire ThisAndAdjacentFilesBB[]
It is unused. Also renamed attack_span_mask to
pawn_attack_span

No functional change.
2013-06-23 10:09:24 +02:00
Marco Costalba 378bcfe760 Simplify hidden_checkers()
De-templetize and pass color as function argument.
No speed change.

No functional change.
2013-06-23 09:03:40 +02:00
Marco Costalba fe2ed42661 Name functions along corresponding UCI commands
No functional change.
2013-06-22 12:46:03 +02:00
Marco Costalba e215a88cdd Micro-optimize perft
Avoid to call perft function when we just need to count
moves, at leaf nodes.

Speed up of almost 2%

No functional change.
2013-06-21 09:10:03 +02:00
Ryan Schmitt e95e69515a Include file attacks in 'major on pawn'
Passed both short TC:
LLR: 2.97 (-2.94,2.94)
Total: 57846 W: 12248 L: 11974 D: 33624

And long one:
LLR: 2.95 (-2.94,2.94)
Total: 9181 W: 1732 L: 1581 D: 5868

bench: 4609948
2013-06-19 07:22:10 +02:00
Reuven Peleg e05c80a088 Remove confusing optimization
Here we skip the call to pos.attacks_from<ROOK>(s) in the 98%
of cases, testing the first 2 members first. Unfortunatly
code is a bit triky and not clear. So we give up to the
speed optimization in exchange of more code clarity.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2013-06-17 18:12:15 +02:00
Reuven Peleg 7b31e81d77 Merge some if statements in pos_is_ok()
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2013-06-17 18:02:59 +02:00
Marco Costalba c0964fc70f Remove redundant condition in probcut
When !ss->skipNullMove it is assured that excludedMove == MOVE_NONE

No functional change.
2013-06-17 09:30:59 +02:00
Marco Costalba cd782c11ec Rename piece_count and piece_list
No functional change.
2013-06-16 13:21:10 +02:00
Marco Costalba 5ea984ac35 Don't calculate pawnsOnSquares twice
And reformat some code while there.

No functional change.
2013-06-16 11:32:10 +02:00
Marco Costalba 1fd020a8ba Use move_pawns() in Pawns::probe
And rename some stuff.

No functional change.
2013-06-16 10:40:36 +02:00
Marco Costalba 02420d4670 Revert "Reduce more CUT nodes only if parent node is reduced"
This reverts commit d54e8a5955.

It was not proved with SPRT this tweak is stronger. So revert it
for now to follow fishtest guidelines.

bench: 5108393
2013-06-14 08:27:06 +02:00
Marco Costalba 2c7ab488a8 Fix description of TT entry
It was way outdated and wrong !

No functional change.
2013-06-14 08:21:02 +02:00
Marco Costalba d54e8a5955 Reduce more CUT nodes only if parent node is reduced
So when we are doing a LMR search at the parent ALL node.

This patch didn't prove stronger at 60" TC
LLR: -2.97 (-2.94,2.94)
Total: 22398 W: 4070 L: 4060 D: 14268

But, first, it scores at 50%, second (and most important for me) the opposite,
i.e. normal reduction when parent node is not reduced, seems very bad:
LLR: -2.95 (-2.94,2.94)
Total: 7036 W: 1446 L: 1534 D: 4056

According to Don, this idea of increased reduction of CUT nodes
works because if parent node is reduced, missing a cut-off due to
reduced depth search (meaning position is somehow tricky) forces
a full depth research at parent node, giving due insight in this
set of sensible positions.

IOW if we expect a node to fail-high at depth n, then we assume it
should fail-high also at depth n-1, if this doesn't happen it means
position is tricky enough to deserve a research at depth n+1.

bench: 4687419
2013-06-13 20:05:02 +02:00
Marco Costalba 4bebb15e94 Reduce more CUT nodes
We got a good result from this tweak, in line with
what was already found by Don Dailey.

At short TC:
LLR: 2.95 (-2.94,2.94)
Total: 13097 W: 2742 L: 2598 D: 7757

At long TC:
LLR: 2.97 (-2.94,2.94)
Total: 7281 W: 1408 L: 1265 D: 4608

bench: 5108393
2013-06-13 19:50:32 +02:00
Marco Costalba 3b8f66f8ac Introduce Cut/All node definitions
Follow Don Dailey definition of cut/all node:

"If the previous node was a cut node, we consider this an ALL node.
The only exception is for PV nodes which are a special case of ALL nodes.
In the PVS framework, the first zero width window searched from a PV
node is by our definition a CUT node and if you have to do a re-search
then it is suddenly promoted to a PV nodes (as per PVS search) and only
then can the cut and all nodes swap positions. In other words, these
internal search failures can force the status of every node in the subtree
to swap if it propagates back to the last PV nodes."

http://talkchess.com/forum/viewtopic.php?topic_view=threads&p=519741&t=47577

With this definition we have an hit rate higher than 90% on:

    if (!PvNode && depth > 4 * ONE_PLY)
        dbg_hit_on_c(cutNode, (bestValue >= beta));

And an hit rate of just 28% on:

    if (!PvNode && depth > 4 * ONE_PLY)
        dbg_hit_on_c(!cutNode, (bestValue >= beta));

No functional change.
2013-06-13 19:46:49 +02:00
Marco Costalba b6e9d901b0 Don't use std::vector::data()
It is a C++11 only function.

Reported by Eelco.

No functional change.
2013-06-13 07:42:43 +02:00
Marco Costalba 1b7223a53c Fix again early stop ss pointer
Fix was wrong becuase search starts from ss+1,
code is a bit tricky here, so rewrite in a way
to be more easy to read and understand.

Spotted by Eelco.

No functional change.
2013-06-09 23:36:46 +02:00
Marco Costalba de1dc4f2de Don't need to expose namespace Zobrist
It can be local to position.cpp

No functional change.
2013-06-09 23:27:07 +02:00
Marco Costalba a6e0f62a4f Zobrist::init() should be Position::init()
No functional change.
2013-06-09 13:54:38 +02:00
Marco Costalba 81e242a96d Convert pieceSquareTable to 3 dimensions
No functional change.
2013-06-09 13:10:21 +02:00
Marco Costalba dd1855eb2f More consistent 'piece' variable naming
No functional change.
2013-06-09 12:56:05 +02:00
Marco Costalba db4cd89cb8 Introduce operator~(Piece c)
Small syntactic sugar to reverse piece color.

No functional change.
2013-06-09 12:44:04 +02:00
Marco Costalba 7e95495b35 Retire psq_delta()
No functional change.
2013-06-09 12:32:16 +02:00
Marco Costalba 55eb7dd1e9 Use alpha instead of beta-1
It is more directly related to a fail-low.

No functional change.
2013-06-09 11:52:39 +02:00
Marco Costalba 902c0566a6 Fix incorrect 'ss' pointer in early stop check
The exclusion search used to verify one move is much
better than other shall be called with 'ss' and not
'ss+1'

No functional change.
2013-06-09 11:01:11 +02:00
Dariusz Orzechowski bc02cc0c8a Fix a typo
No functional change.
2013-06-08 11:01:28 +02:00
Marco Costalba 05c6f7a40b Fix search log when using skills
In case of we pick a sub-optimal move be
sure to print this, and not the best one
on seach log file.

Bug spotted by Guenther Demetz.

No functional change.
2013-06-08 10:56:20 +02:00
Marco Costalba 2a98042c21 Fix a crash when 'go' multiple times
Search is started after setting a position and
issuing UCI 'go' command. Then if we stop the search
and call 'go' again without setting a new position it
is assumed that the previous setup is preserved, but
this is not the case because what happens is that
SetupStates is reset to NULL, leading to a crash as
soon as RootPos.is_draw() is called because st->previous
is now stale.

UCI protocol is not very clear about requiring that a
position is setup always before launching a search,
so here we easy the life of GUI developers assuming
that the current state is preserved after returning
from a 'stop' command.

Bug reported by Gregor Cramer.

No functional change.
2013-06-01 16:19:42 +02:00
Marco Costalba 46409a7852 Assorted renaming in evaluation
And some reshuffle too.

No functional change.
2013-06-01 13:17:39 +02:00
jundery d8b266af8b Passed pawn tuning
A small number of tests with simulated
annealing at 15s indicated these values
may be better

And this is verified at long 60+0.05 TC
LLR: 2.95 (-2.94,2.94)
Total: 40658 W: 7821 L: 7501 D: 25336

bench: 4931544
2013-05-31 09:17:48 +02:00
Marco Costalba abb40777bf Shrink engine UCI name
Some GUI have problems with long names.

Reported by George Speight.

No functional change.
2013-05-27 17:43:38 +02:00
Marco Costalba 90abcac1c7 Add Pawn Structure also to polyglot.ini
No functional change.
2013-05-25 13:14:41 +02:00
Marco Costalba 7222f47350 Re-add "Pawn Structure" UCI option
And reshuffle the code to not special case
this parameter.

No functional change.
2013-05-25 12:38:14 +02:00
Marco Costalba eafb66e1aa More uniform tracing code
No functional change.
2013-05-25 12:01:50 +02:00
Uri Blass d4a02b135d Bunch of 3 small patches
This patch is the sum of:

- Grainsize of 4 instead of 8

- Removing "depth < DEPTH_ZERO"

- Change DEPTH_QS_RECAPTURES = -5 to -7

All the patches individually failed to pass SPRT but scored
around 50%.

Together they pass easily short TC:
LLR: 2.96 (-2.94,2.94)
Total: 4429 W: 964 L: 844 D: 2621

And with some difficult long TC of 60+0.05:
LLR: 2.95 (-2.94,2.94)
Total: 64133 W: 11968 L: 11532 D: 40633

bench: 4821467
2013-05-23 17:59:39 +02:00
Marco Costalba d3608c4e79 Microptimize MoveList loop
Add MOVE_NONE at the tail, this allows to loop
across MoveList checking for *it != MOVE_NONE,
and because *it is used imediately after compiler
is able to reuse it.

With this small patch perft speed increased of 3%

And it is also a semplification !

No functional change.
2013-05-19 22:00:49 +02:00
Marco Costalba 38cfbeeb50 Delay killers[] initialization
Most of the time we cut-off earlier, at captures, so this
results in useless work.

There is a small functionality change becuase 'ss' can change
from MovePicker c'tor to when killers are tried due, for
instance, to singular search.

bench: 4603795
2013-05-19 21:41:56 +02:00
Marco Costalba 77547a4ef1 Reduce countermoves less in LMR
Passed SPRT for both short TC 15+0.05:
LLR: 2.95 (-2.94,2.94)
Total: 17724 W: 3756 L: 3598 D: 10370

And long TC 60+0.05:
LLR: 2.95 (-2.94,2.94)
Total: 22672 W: 4232 L: 4011 D: 14429

bench: 4418832
2013-05-19 21:36:23 +02:00
Marco Costalba 8ceef92266 Mimic an iterator for looping across MoveList
Seems more conventional.

No functional change.
2013-05-19 13:28:25 +02:00
Joona Kiiski f7c013edd0 Use two counter moves instead of one
Very good at long 60"+0.05 TC
LLR: 2.95 (-2.94,2.94)
Total: 5954 W: 1151 L: 1016 D: 3787

[edit: slightly changed form original patch to avoid useless loop
 across killers when killer is MOVE_NONE]

bench: 4327405
2013-05-16 16:20:50 +02:00
Marco Costalba 148490f04c Rename Refutation to Countermove
Use proper naming according to:

http://chessprogramming.wikispaces.com/Countermove+Heuristic

The name of this idea is "Countermove Heuristic" and was
first introduced by Jos Uiterwijk in 1992

No functional change.
2013-05-15 20:59:56 +02:00
Uri Blass 7c6f346c90 Increased mobility array
Performed more or less well at short TC
LLR: 2.95 (-2.94,2.94)
Total: 50517 W: 9815 L: 9574 D: 31128

And a bit better at long TC
LLR: 2.96 (-2.94,2.94)
Total: 15564 W: 2805 L: 2624 D: 10135

bench: 4375253
2013-05-15 00:34:05 +02:00
Marco Costalba 1a34496761 Revert trapped rook bug fix
It seems that do  not limiting checking the
trapped rook only on rank 1 improves the
score.

At long TC
LLR: 2.97 (-2.94,2.94)
Total: 6581 W: 1346 L: 1204 D: 4031

bench: 4985012
2013-05-15 00:06:11 +02:00
Gary Linscott 049e5ca191 Minor bugfixes to refutation table
Don't update refutation table in case of
previous move is MOVE_NULL or MOVE_NONE
and don't try refutation if is already
a killer move.

Pass both short TC
LLR: 2.96 (-2.94,2.94)
Total: 4310 W: 953 L: 869 D: 2488

And long one
LLR: 2.95 (-2.94,2.94)
Total: 6707 W: 1254 L: 1184 D: 4269

bench: 4785954
2013-05-14 23:52:44 +02:00
Marco Costalba 19dd0de4ff Reformat previous patch
No functional change.
2013-05-13 20:42:44 +02:00
Joona Kiiski 8a61b030a6 Enable refuation table
Very good result both at short TC 15+0.05
LLR: 2.95 (-2.94,2.94)
Total: 2803 W: 596 L: 483 D: 1724

And at long TC 60+0.05
LLR: 2.95 (-2.94,2.94)
Total: 2862 W: 548 L: 431 D: 1883

bench: 4329221
2013-05-13 19:48:41 +02:00
Joona Kiiski c7e31d5aa8 Simple always overwrite Refutation table 2013-05-12 21:21:46 +01:00
Marco Costalba 818a3537a7 Use Them instead of ~Us
Unortunatly we have no guarantee that the call to
operator~(Color c) is resolved at compile time.

Perhaps the solution would be to use C++11 const_expr,
but for now simply use the good old-style ternary operator
that works as expected.

No functional change.
2013-05-11 11:49:44 +02:00
Marco Costalba bcbc9bfd1f Some code reformat in evaluate_pieces
No functional change.
2013-05-11 11:13:06 +02:00
Marco Costalba 7eda7335fd Simplify previous patch
No functional change.
2013-05-09 19:09:51 +02:00
Marco Costalba 02606a8c83 Merge 'passed_pawns' tweaks
Good at both short and long TC

15+0.05
LLR: 2.96 (-2.94,2.94)
Total: 28220 W: 5531 L: 5349 D: 17340

TC 60+0.05
LLR: 2.95 (-2.94,2.94)
Total: 12612 W: 2221 L: 2057 D: 8334

bench: 4857939
2013-05-08 23:04:11 +02:00
Reuven Peleg e7505324f6 Avoid explicit bitwise operators
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2013-05-05 22:51:18 +02:00
jundery 653c0527a7 Passed pawn eval
Use a stepped function to evaluate bonuses and add the bonus to the
middle game

bench: 4857939
2013-05-05 11:12:04 -06:00
Marco Costalba 7f4c7cd785 Merge increased 'movecount' pruning
Good at both short and long TC

15+0.05
LLR: 2.95 (-2.94,2.94)
Total: 13814 W: 2731 L: 2588 D: 8495

TC 60+0.05
LLR: 2.95 (-2.94,2.94)
Total: 18013 W: 3136 L: 2946 D: 11931

bench: 4306557
2013-05-05 13:46:26 +02:00
Marco Costalba 0958e5c6d3 Simplify previous condition
No functional change.
2013-05-05 12:31:32 +02:00
Marco Costalba 9fc77bc414 Fix trapped rook condition
A rook is trapped if on rank 1 as is the king.
Currently the condition aloows for the rook
to be also in front of the pawns as long
as king is on first rank.

Verified with short TC test:
LLR: -1.71 (-2.94,2.94)
Total: 23234 W: 4317 L: 4317 D: 14600

Here what it counts is that after 23K games
result is equal.

bench: 4696542
2013-05-05 12:27:11 +02:00
Marco Costalba 3b92159908 Further simplify previous patch
No functional change.
2013-05-04 12:15:31 +02:00
homoSapiensSapiens e00bb13e85 Merge some conditions
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2013-05-04 11:13:22 +02:00
Marco Costalba 3b41e62666 Drop some redundant defined(_WIN64)
When it is already defined(_WIN32).

According to Microsoft documentation:
http://msdn.microsoft.com/en-us/library/b0084kay.aspx

_WIN32 Defined for applications for Win32 and Win64. Always defined.

_WIN64 Defined for applications for Win64.

Patch suggested by Joona.

No functional change.
2013-05-03 15:24:54 +02:00
Marco Costalba 37c91aa94c Print time and node count before search ends
This info is normally printed together with
PV info in uci_pv() but when search is stopped,
for instance when max search time is reached,
uci_pv is not called and we miss this bits.

Suggested by gravy_train

No functional change.
2013-05-03 10:26:03 +02:00
Marco Costalba 43f67eab5f Merge mobility area tweak
A nice improvment.

Was good at 15+0.05
LLR: 2.96 (-2.94,2.94)
Total: 10731 W: 2176 L: 2040 D: 6515

And at 60"+0.05
LLR: 2.96 (-2.94,2.94)
Total: 10601 W: 1968 L: 1810 D: 6823

bench: 4676606
2013-05-03 10:12:31 +02:00
Gary Linscott 11d30b6298 Fix rounding issue 2013-05-02 14:37:55 -04:00
Gary Linscott 3edb15d183 More aggressive move count pruning 2013-05-02 09:47:34 -04:00
Marco Costalba d44ac0a485 Another take at TT alignment
This time revert to original version but using
uintptr_t instead of size_t

Suggested by Lucas.

No functional change.
2013-05-02 09:38:23 +02:00
Marco Costalba 481eda4ca0 Re-add "Cache line aligned TT"
But this time do not play with pointers, in
particular do not assume that size_t is an
unsigned type of the same width as pointers.

This code should be fully portable.

No functional change.
2013-05-01 23:42:16 +02:00
jhellis3 7323231786 Tweak Mobility Area
Only consider pawns and the king as restricting.
2013-05-01 02:37:50 -05:00
Marco Costalba e381951a24 Restore development version
No functional change.
2013-04-30 20:01:07 +02:00
Marco Costalba aa2368a687 Stockfish 3
Stockfish bench signature is: 4176431
2013-04-30 19:42:43 +02:00
Marco Costalba 293c44bc09 Revert "Cache line aligned TT"
This reverts commit 083fe58124

It seems to break Android build

No functional change.
2013-04-30 19:42:21 +02:00
Marco Costalba 06b9140e5c Temporary revert "Expose EvalInfo struct to search"
It is not needed for the release and introduces
a slowdown, although very small.

Probably it will be readded after the release.

No functional change.
2013-04-29 00:55:32 +02:00
Marco Costalba 156635749b Fix a 'value > VALUE_INFINITE' assert
This fixes an assert while testing with debug on.

Assert was due to static null pruning returning value

eval - futility_margin(depth, (ss-1)->futilityMoveCount)

That was sometimes higher than VALUE_INFINITE triggering
an assert at the caller site.

Because eval con be equal to ttValue and anyhow is read from
TT that can be corrupted in SMP case, we need to sanity
check it before to use.

bench: 4176431
2013-04-27 13:08:11 +02:00
Marco Costalba 083fe58124 Cache line aligned TT
Let TT clusters (16*4=64 bytes) to hold on a singe cache line.
This avoids the need for the double prefetch.

Original patches by Lucas and Jean-Francois that has also tested
on his AMD FX:

BIG HASHTABLE

./stockfish bench 1024 1 18 > /dev/null

Before:
1437642 nps
1426519 nps
1438493 nps

After:
1474482 nps
1476375 nps
1475877 nps

SMALL HASHTABLE

./stockfish bench 128 1 18 > /dev/null

Before:
1435207 nps
1435586 nps
1433741 nps

After:
1479143 nps
1471042 nps
1472286 nps

No functional change.
2013-04-26 19:38:11 +02:00
Marco Costalba e508494a99 Fix a crash introduced few days ago
Crash is due to uninitialized ss->futilityMoveCount that
when happens to be negative, yields to an out of range
access in futility_margin().

Bug is subtle because it shows itself only in SMP case.
Indeed in single thread mode we only use the

Stack ss[MAX_PLY_PLUS_2];

Allocated at the begin of id_loop() and due to pure
(bad) luck, it happens that for all the MAX_PLY_PLUS_2
elements, ss[i].futilityMoveCount >= 0

Note that the patch does not prevent futilityMoveCount
to be overwritten after, for instance singular search
or null verification, but to keep things readable and
because the effect is almost unmeasurable, we here
prefer a slightly incorrect but simpler patch.

bench: 4311634
2013-04-26 12:14:01 +02:00
Marco Costalba 2ef53ee368 Store Eval::Info in Search::Stack
Instead of a pointer. This should fix the issue of
remaining with a stale pointer when for instance calling
IID, but also null search verification, singular search
and razoring where we call search with the same ss
pointer. In this case ss->ei is overwritten in the
search() call and upon returning remains stale.

This patch could have a performance hit because Eval::Info
is big (176 bytes) and during splitting we copy 4 ss entries.

On the good side, this patch is a clean solution.

Proposed by Gary.

No functional change.
2013-04-25 21:52:26 +02:00
Marco Costalba d810441b35 Expose EvalInfo struct to search
Allow to use EvalInfo struct, populated by
evaluation(), in search.

In particular we allocate Eval::Info on the stack
and pass a pointer to this to evaluate().

Also add to Search::Stack a pointer to Eval::Info,
this allows to reference eval info of previous/next
nodes.

WARNING: Eval::Info is NOT initialized and is populated
by evaluate(), only if the latter is called, and this
does not happen in all the code paths, so care should be
taken when accessing this struct.

No functional change.
2013-04-25 12:57:37 +02:00
Ryan Schmitt 79bcb2ca54 Increase rook/queen on 7th bonus
Shows an increase at 15+0.05
LLR: 3.01 (-2.94,2.94)
Total: 20450 W: 4091 L: 3927 D: 12432

And at 60+0.05
LLR: 2.97 (-2.94,2.94)
Total: 61432 W: 10849 L: 10441 D: 40142

bench: 4493356

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2013-04-25 12:13:17 +02:00
Marco Costalba 289a767ab3 Merge Joona's increased static null pruning
The idea is to fail high more easily in static
null test if in the parent node we are already
very deep in the move list, so the propability
to fail high there is very low.

[edit: I have slightly changed the functionality
moving

ss->futilityMoveCount = moveCount;

At the end of the pruning code, this should not affect
ELO in anyway, but makes code more natural and logic]

Test with SPRT is good at 15+0.05
LLR: 2.96 (-2.94,2.94)
Total: 50653 W: 10024 L: 9780 D: 30849

And at 60+0.05
LLR: 2.97 (-2.94,2.94)
Total: 40799 W: 7227 L: 6921 D: 26651

bench: 4530093
2013-04-25 12:05:00 +02:00
Marco Costalba 4381ea23fe Fix cpu_count() on some platforms
When we use sysconf(_SC_NPROCESSORS_ONLN) to get number of
cores, we have to include sysconf library that is unistd.h

Sometimes it happens to work just becuase unistd.h indirectly
included by some other libraries, but not always.

Reported and fixed by Eyal BD

No functional change.
2013-04-25 10:56:56 +02:00
Joona Kiiski 817ca1820b Fix potential overflow 2013-04-23 07:26:36 +01:00
Joona Kiiski 8df17204f4 More aggressive post-futility pruning 2013-04-21 14:53:27 +01:00
Marco Costalba f84f04742a Skip a couple of popcount in previous patch
And some little tidy up

No functional change.
2013-04-19 10:31:18 +02:00
Marco Costalba cc40d1c46a Merge Joona's bishop+pawn tweak
The idea is to penalize a bishop in case of
its pawns are on the same colored squares.

Good at short 15"+0.05 TC
LLR: 2.95 (-2.94,2.94)
Total: 4252 W: 925 L: 806 D: 2521

And at longer 60"+0.05 TC
LLR: 2.95 (-2.94,2.94)
Total: 15006 W: 2743 L: 2564 D: 9699

bench: 5274705
2013-04-19 09:36:00 +02:00
Joona Kiiski 818e0b2d2b Try more aggressive version 2013-04-17 07:58:59 +01:00
Joona Kiiski 3e4dfb49a7 Give a small penalty for bishop for each pawn on the same colored square 2013-04-16 21:20:31 +01:00
Marco Costalba 87436e5544 Skip a redundant check
Spotted by Joona

No functional change.
2013-04-14 23:29:25 +02:00
Marco Costalba fe72c93141 De-templetize Position::is_draw()
Now that we always check for repetition we don't
need a template anymore.

No functional change.
2013-04-10 22:23:48 +02:00
Joona Kiiski 75221fcf5e Always check repetition
It seems stronger both at fast 15+0.05 TC with fixed game number test:
ELO: 2.74 +-2.7 (95%) LOS: 97.6%
Total: 24000 W: 4698 L: 4509 D: 14793

And also at long 60+0.05 TC with SPRT
LLR: 3.05 (-2.94,2.94)
Total: 38986 W: 6845 L: 6547 D: 25594

bench: 5157061
2013-04-10 22:20:40 +02:00
Marco Costalba a95cbca568 Simplify and speed up previous patch
Use an optinal argument instead of a template
parameter. Interestingly, not only is simpler,
but also faster, perhaps due to less L1 instruction
cache pressure because we don't duplicate the very
used SEE code path.

No functional change.
2013-04-09 23:32:06 +02:00
Joona Kiiski d23454854e Document asymmetric SEE pruning trick
Here are the tests:

sprt @ 60+0.05
ELO: 3.53 +-2.8 (95%) LOS: 99.3%
Total: 18794 W: 3098 L: 2907 D: 12789

16000 @ 60+0.05
ELO: 1.39 +-3.1 (95%) LOS: 81.0%
Total: 16000 W: 2689 L: 2625 D: 10686

16000 @ 15+0.05
ELO: 2.82 +-3.3 (95%) LOS: 95.1%
Total: 16000 W: 3148 L: 3018 D: 9834

No functional change

Signature: 4969307
2013-04-09 23:31:57 +02:00
Joona Kiiski c2902112e5 Don't treat king safety differently in AnalysisMode
Rationale:

- Current settings seem to make engine *significantly* weaker in analysis mode.
- In practice this setting only has effect when king safety scores are high.
- Even in analysis mode its far more important to know if one side is getting mated,
rather than get evaluation correct with 1cp accuracy.

No functional change
2013-04-09 23:29:58 +02:00
Marco Costalba 9498b2af82 Rescale UCI parameters to 100
And correspondingly modify internal ones
to compensate it.

No functional change.
2013-04-09 23:29:58 +02:00
Marco Costalba 2a5ae34bb2 Tweak some UCI parameters
According to Jean-Paul this setup should be stronger
than default.

And SPRT test seems to confirm it:

At fast TC 15"+0.05
ELO: 3.33 +-2.7 (95%) LOS: 99.2%
Total: 25866 W: 5461 L: 5213 D: 15192

At longer TC 60"+0.05
ELO: 7.27 +-5.0 (95%) LOS: 99.8%
Total: 6544 W: 1212 L: 1075 D: 4257

bench: 5473339

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2013-04-09 23:29:58 +02:00
Marco Costalba d3fe153fe6 Re-add 'Cowardice' and 'Aggressiveness' UCI options
I have lost my bet with Jean-Paul, so now I re-add
the two options...and I am glad of it :-)

No functional change.
2013-04-09 23:29:58 +02:00
Marco Costalba 889922041b Increase null verification threshold to 12 plies
Increasing depth limit to 10 plies seems stronger
after 16K games at 15"+0.05 (ELO: +3.56) and also
repeating the test at 60"+0.05 TC:

ELO: 2.08 +-3.1 (95%) LOS: 90.9%
Total: 16000 W: 2641 L: 2545 D: 10814

Moreover setting the limit to 12 is proved stronger
then limit set to 10 by direct SPRT test at 15"+0.05:

ELO: 2.56 +-2.0 (95%) LOS: 99.5%
Total: 46568 W: 9240 L: 8897 D: 28431

So we directly set the limit to 12, the strongest setup.

bench: 4361224
2013-04-09 23:29:58 +02:00
Joona Kiiski 7bad50773a Make use of asymmetric SEE 2013-04-05 19:05:32 +01:00
Joona Kiiski d3c3c4f8e7 Fix a silly bug 2013-04-05 19:05:32 +01:00
Joona Kiiski 2097cd1221 Introduce asymmetric SEE.
No functional change
2013-04-05 19:05:32 +01:00
Marco Costalba 0c1b40c5e2 Lower minimum allowed TT size to 1 MB
Setting a very low TT size could be used
for some specific testing.

No functional change.
2013-04-05 16:56:01 +02:00
Marco Costalba 8c10029df1 Revert "Double Impact of Gain tables"
This reverts commit 36c82b751c

Seems a regression against 2.3.1 tested with 20K games at 60"+0.05

With patch applied
ELO: 15.44 +-2.8 (95%) LOS: 100.0%
Total: 20000 W: 3928 L: 3040 D: 13032

Without patch applied
ELO: 18.76 +-2.8 (95%) LOS: 100.0%
Total: 20000 W: 3903 L: 2824 D: 13273

bench: 4781239
2013-04-05 08:59:38 +02:00
Hiraoka Takuya 6e2371a86b Don't early stop if we have a mated score
No functional change.
2013-04-04 21:39:48 +02:00
Joona Kiiski 36c82b751c Double Impact of Gain tables
Very unorthodox idea.

After 16000 games at 60"+0.05
ELO: 3.14 +-3.4 (95%) LOS: 96.6%
Total: 13407 W: 2278 L: 2157 D: 8972

bench: 4705335
2013-04-03 19:14:59 +02:00
Marco Costalba 7d42d02ec7 Set IID half way between d/2 and d-4
Master IID formula is depth / 2
Previous patch is depth - 4 * ONE_PLY

This one is the middle way:

(dept/2 + depth-4*ONE_PLY)/2  -> depth-2*ONE_PLY-depth/4

After 16000 games at 60+0.05 th 1
ELO: 4.08 +-3.1 (95%) LOS: 99.5%
Total: 16000 W: 2742 L: 2554 D: 10704

bench: 4781239
2013-03-30 22:26:30 +01:00
Marco Costalba c89274d8fb Merge branch 'master' into increase_iid 2013-03-29 22:50:04 +01:00
Marco Costalba f2638816bf Raise Min Split Depth
Raise the limit to 12 so to allow people to test
on many cores machines.

Suggested by Gary and Martin.

No functional change.
2013-03-25 20:04:49 +01:00
Marco Costalba 0b4ea54da9 Update bestValue when futility pruning (2)
Same idea of 5af8179647
in qsearch() but applied to search()

After 15500 games at 15+0.05
ELO: 4.48 +-3.4 (95%) LOS: 99.5%
Total: 15500 W: 3061 L: 2861 D: 9578

bench: 4985829
2013-03-24 23:32:21 +01:00
Joona Kiiski 09f1fdf52f Fix bogus mate scores in some positions
Always before pruning the move, it's important to check that:

bestValue > VALUE_MATED_IN_MAX_PLY

See example position:

8/2p1p3/P1NpP3/3k4/1P1BN3/2P1P3/2Q5/6K1 w - - 0 1
http://support.stockfishchess.org/discussions/problems/268-wrong-declaring-a-forced-mate-in-3-moves

This problem was present in 2.3.1, then it was fixed by my patch.

After 24000 games at 15+0.05
ELO: 2.40 +-4.4 (95%) LOS: 95.7%
Total: 24000 W: 4774 L: 4608 D: 14618

bench: 4465997
2013-03-23 21:28:51 +01:00
jundery d39b22927e Use ALL_PIECES value to reference attackedBy
No functional change
2013-03-23 12:17:12 +01:00
Marco Costalba 81e9cf043a Increase non-PV IID search depth
bench: 5146380
2013-03-22 20:57:31 +01:00
Marco Costalba 077e32efc9 Better document bitbase loop
Thanks to Lucas to spot the weak comment and
to Jundery to suggest a better one.

No functional change.
2013-03-19 19:08:41 +01:00
Gary Linscott 52f3e717fa Add KNPKB endgame
In a game vs Junior, SF had the option to trade into a winning
pawn endgame, and failed to do so. PGN at bottom.

This FEN was one key position: 8/2Nb1k2/6pp/4Pp2/5K1P/5PP1/8/8 w - - 5 62.

SF master chooses h5 here, with a fail high, which goes into the drawn KNPKB
ending. With the patch, SF correctly chooses Ke3, which maintains chances to win.

[Event "nTCEC - Stage 2a - Season 1"]
[Site "http://www.tcec-chess.net"]
[Date "2013.03.05"]
[Round "11.3"]
[White "Stockfish 210213"]
[Black "Junior 13.3"]
[Result "1/2-1/2"]
[Variant "normal"]

1. d4 f5 2. g3 Nf6 3. Bg2 e6 4. c4 d5 5. Nh3 c6 6. O-O Bd6 7. Bf4 Be7 8. Nd2 O-O
9. Qb3 a5 10. Rfd1 Ne4 11. Be3 Nd7 12. Nf4 Ndf6 13. f3 a4 14. Qc2 Nxd2 15. Bxd2
dxc4 16. Qxc4 b5 17. Qc3 Qb6 18. Rac1 e5 19. Nd3 exd4 20. Qxc6 Qxc6 21. Rxc6
Bd7 22. Rcc1 Be6 23. Bb4 Rae8 24. Bxe7 Rxe7 25. Nb4 Bc4 26. Bf1 Rd7 27. Rd2 Re8
28. Rcd1 Rc7 29. Ra1 Rd8 30. Rc1 Rdd7 31. Rcd1 Re7 32. Ra1 Nd5 33. Nc2 Ne3
34. Nxd4 Bxa2 35. Nxb5 Rc5 36. Nd4 Bf7 37. Kf2 g6 38. Rd3 Nxf1 39. Kxf1 Rc4
40. b3 axb3 41. Nxb3 Kf8 42. Rd8+ Re8 43. Rxe8+ Bxe8 44. Kf2 Ke7 45. Ra7+ Bd7
46. Ke1 Rc3 47. Rb7 Rc2 48. Kd1 Rc4 49. Kd2 Kd6 50. Kd3 Rc7 51. Rxc7 Kxc7
52. Kd4 Kd6 53. Nc5 Bb5 54. e4 Be2 55. e5+ Ke7 56. Ke3 Bd1 57. Kf4 h6 58. h3
Kf7 59. h4 Bc2 60. Na6 Ba4 61. Nc7 Bd7 62. h5 g5+ 63. Ke3 Ba4 64. f4 Bd1
65. fxg5 hxg5 66. h6 Kg6 67. e6 f4+ 68. gxf4 gxf4+ 69. Kxf4 Bh5 70. Ke5 Kh7
71. Kf6 Kxh6 72. Na6 Bg4 73. e7 Bh5 74. Nc7 Bg6 75. Nd5 Be8 76. Ne3 Kh7 77. Nc4
Kh6 78. Nd2 Kh5 79. Nf3 Kg4 80. Nd4 Bh5 81. Ne6 Be8 82. Nc5 Kf3 83. Kf5 Ke3
84. Ke5 Ke2 85. Kf4 Kd2 86. Ne4+ Kd3 87. Ke5 Ke3 88. Nf6 Bf7 89. Nd5+ Kf3
90. Kf5 Ke2 91. Ke4 Be8 92. Nc3+ Kd2 93. Kd4 Kc2 94. Nd5 Kd1 95. Nf6 Bf7
96. Ne4 Be8 97. Ke3 Kc2 98. Nd6 Bd7 99. Kd4 Kd1 100. Kd3 Ba4 101. Nc4 Bb5
102. Kc3 Be8 103. Nb2+ Ke1 104. Kd3 Kf2 105. Nd1+ 1/2-1/2

No functional change (just because bench does not change)
2013-03-18 20:40:06 +01:00
Marco Costalba 0586b51f9c Further increase SEE prune depth
After 16000 games at 60+0.05
ELO: 2.89 +-5.4 (95%) LOS: 96.5%
Total: 16000 W: 2775 L: 2642 D: 10583

bench: 5442365
2013-03-16 11:20:03 +01:00
Marco Costalba d2eeef89aa Revert "Check for easy move just once"
This reverts commit a24da071f0

Seems a regression when tested against 2.3.1

With this patch, have after 20000 games at 60+0.05, we have

ELO: 13.42 +-4.8 (95%) LOS: 100.0%
Total: 20000 W: 3746 L: 2974 D: 13280

Instead with the patch reverted:

ELO: 16.62 +-4.8 (95%) LOS: 100.0%
Total: 20000 W: 3816 L: 2860 D: 13324

Although we are within error bounds here we take the conservative
approach of not introducing changes that are not proved stronger
It doesn't mean that the change shall be weaker, simply that we
don't want to take any risk.

No functional change.
2013-03-16 11:12:35 +01:00
RyanTaker 70d20326b0 Improved Readability of Material
This is a non-functional change that simply changes the look
of the code to help clarity.

No functional change.
2013-03-15 09:14:00 +01:00
jundery ccf4ec6768 Do more work between prefetch and querying transposition table
More time to load the cache line before access

No functional change.
2013-03-12 19:58:32 +01:00
Gary Linscott a24da071f0 Check for easy move just once
Here the rational seems to be that if after one try easy
move detection fails then the easy move is not so easy :-)

After 15563 games at 60+0.05
ELO: 3.04 +-5.5 (95%) LOS: 97.0%
Total: 15563 W: 2664 L: 2528 D: 10371

No functional change.
2013-03-11 22:23:19 +01:00
Gary Linscott 3698d9aa55 Be more aggressive on trying to finish iterations
Increase MaxRatio to use more time when in trouble.

After 16000 games at 60+0.05
ELO: 4.89 +-5.4 (95%) LOS: 99.9%
Total: 16000 W: 2700 L: 2475 D: 10825

No functional change.
2013-03-11 19:07:55 +01:00
Marco Costalba 10429dd616 Increase see prune depth
This seems good at short TC controls.

After 10000 games at 20+0.05
ELO: 9.56 +-6.8 (95%) LOS: 100.0%
Total: 10000 W: 1949 L: 1674 D: 6377

Testing at long TC and regression testing is still
ongoing. So this is a bit speculative commit and
could be reverted in the future.

Also re-testing at long TC the SEE pruning in PV nodes
seems less effective (perhaps even a regression, but
still ongoing) so disabled for now.

bench: 4968764
2013-03-04 09:41:56 +01:00
Marco Costalba db322e6a63 Revert "Store moves sent with "position" UCI command"
This reverts commit 0d68b523a3.

After easy move semplification this machinery is not
needed anymore (because of we don't need to know if a
root move is a recapture)

No functional change.
2013-03-04 09:29:46 +01:00
Marco Costalba 45dba12c5b Simplify "easy move" detection
Detect a move as easy only if it is the only one ;-)
or if is much better than remaining ones after we
have spent 20% of search time.

Tests are ongoing, but it seems this semplification
stands. Anyhow it is experimental for now and could
be reverted/improved with further work Gary is
testing right now.

No functional change.
2013-03-04 09:27:00 +01:00
Marco Costalba ccad601389 Avoid locking/unlocking in a tight loop
After previous patch if split point master is
waiting for job and "Use Sleeping Threads" is
false (our condition for official releases) then
it will lock/unlock splitPoint mutex in a super
tight loop badly affecting performance.

Rewrite the code to lock only when we are about
to finish. Note that race condition on slavesMask
is anyhow fixed.

No functional change.
2013-03-04 09:07:48 +01:00
jundery d165d5af91 Fix race condition where idle_loop() gets called from Split()
SplitPoint member slavesMask wasn't read under lock

No functional change.
2013-03-04 08:52:24 +01:00
jhellis3 3ce43c20de Stop search if only 1 legal move
There is no point searching a move that is forced.
It wastes time while allowing computer opponents to
fill hash with 100% accuracy.

[edit: Condition moved together with "easy move" ones]

Bench identical: 4922272
2013-03-04 08:30:55 +01:00
Marco Costalba def50020ad Fix easy re-capture case
We detect an easy move as a recapture with an
high margin on the second best move.

Unfortunatly the recapture detection is broken
becuase we identify as a recapture any move that
follows an opponent's previous capture !

This patch fix the logic to correctly detect a
real re-capture.

No functional change.
2013-03-02 13:20:40 +01:00
Marco Costalba 0d68b523a3 Store moves sent with "position" UCI command
Store all the game moves until current position.

This will be used by next patch.

No functional change.
2013-03-02 13:08:50 +01:00
Marco Costalba 0e1ad3ad33 Rename sp to splitPoint
Still keep 'sp' name when used as local
variable with limited scope.

From Jundery.

No functional change.
2013-03-01 09:44:19 +01:00
jundery 0fc9a01933 Remove strange use of the ternary operator
Note that we read shared data without lock
protection, so code is theoretically prone to
torn reads. But, first splitPoint pointer
never changes, and alpha is of integer type so
it is read in a single DWORD access.

No functional change.
2013-03-01 08:05:47 +01:00
jundery 68d1bebd8e Split() clean up locking
Only unlock and relock when idle_loop() is actually called

No functional change
2013-03-01 07:57:18 +01:00
Marco Costalba 57b6df4874 Merge Lucas's "SEE pruning at PV nodes"
bench: 4922272
2013-02-27 08:14:00 +01:00
Marco Costalba bc38efd128 Remove pruning condition on alpha
Further simplifying on Lucas's idea, seems reliable
in tests:

ELO: 2.15 +-7 (95%) LOS: 84.9%
Total: 9999 W: 1831 L: 1769 D: 6399
2013-02-27 08:07:26 +01:00
Lucas Braesch 335b57b5ef Prune negative SEE moves also in PV nodes
This patch is actually the sum of two contributions that
have been tested independently:

1) Pruning of negative SEE moves in PV

After 10000 games at 20+0.05
ELO: 5.18 +-7 (95%) LOS: 99.2%
Total: 10000 W: 1952 L: 1803 D: 6245

2) Remove of bestValue > VALUE_MATED_IN_MAX_PLY condition

After 23000 games at 20+0.05
ELO: 1.63 +-4 (95%) LOS: 88.1%
Total: 23000 W: 4232 L: 4124 D: 14644

The whole patch as been re-tested at long TC with positive results:

After 10000 games at 60+0.05
ELO: 4.31 +-7 (95%) LOS: 98.3%
Total: 10000 W: 1765 L: 1641 D: 6594
2013-02-27 08:04:32 +01:00
Marco Costalba dbd28bc7f8 Avoid a tricky line in shelter_storm()
kf = (kf == FILE_A) ? kf++ : ....

is tricky becuase kf is updated twice and it happens
to do the right thing just by accident.

Rewrite in a better way.

Spotted by pdimov

No functional change.
2013-02-23 19:27:32 +01:00
Marco Costalba ccf21f5595 Convert Readme to markdown format
Looks better on GitHub, that supports this format.

No functional change.
2013-02-23 17:05:28 +01:00
Marco Costalba 1d1fcf80a0 Use DD-MM-YY as date format
In engine name and version number.

No functional change.
2013-02-21 07:19:48 +01:00
Marco Costalba 373503f4a9 Statically link std libraries under mingw
Allows for easier redistribution.

No functional change.
2013-02-21 05:51:04 +01:00
Marco Costalba 9a1d5f0f1d Merge Gary's bishop_pin patch
Give a bonus if a bishop can pin a piece or can
give a discovered check through an x-ray attack.

Seems good after 24000 games at 15"+0.05 (single thread):

ELO: 12.30 +- 99%: 5.79 95%: 4.40 LOS: 100.00%
Total: 24000 W: 4931 L: 4082 D: 14987

bench: 4917064
2013-02-20 12:39:09 +01:00
jundery d5e49a3ad4 Print leading zeroes in hash keys
And convert to uppercase. Reset the stream to dec too.

[Edit: Also fixed the hash key in Position::pretty()]
2013-02-19 20:06:01 +01:00
Gary Linscott ea4e22be1d Merge branch 'master' into bishop_pin_clop 2013-02-19 10:31:52 -05:00
Gary Linscott dc8c6ea2d1 Bring back original bonus 2013-02-19 10:31:50 -05:00
Marco Costalba c5ec94d0f1 Update copyright year
No functional change.
2013-02-19 07:54:14 +01:00
Gary Linscott d570260a28 Back to CLOP average values 2013-02-16 22:36:58 -05:00
Marco Costalba 76caef8ba1 Account for gamePly after each move
Rename startPosPly to gamePly and increment/decrement
the variable after each do/undo move. This adds a little
overhead in do_move() but we will need to have the
game ply during the search for the next patches now
under test.

Currently we don't increment gamePly in do_null_move()
becuase it is not needed at the moment. Could change
in the future.

As a nice side effect we can now remove an hack in
startpos_ply_counter().

No functional change.
2013-02-16 12:44:17 +01:00
Marco Costalba 5a156df719 Merge Gary's king safety tweak
Still well within error bars, so probably not a big improvement,
but may be worthwhile. I will let the test keep running. The idea
for the tweak came from the TCEC game against Houdini. Stockfish saw
it as a draw, well past when it should have seen problems. King safety
was off, since it was QN and pawns only, but in fact the king was
quite vulnerable.

After 8000 games at 60/1 (Gary's test)

ELO: -0.43 +- 99%: 10.02 95%: 7.62
Wins: 1235 Losses: 1245 Draws: 5520 Total: 8000

PGN of game against houdini. Moves 55-59 it was seeing a draw, and
Houdini was seeing a good sized advantage for black. With the change,
Stockfish now recognizes that moving the king there is a bad idea.

[Event "nTCEC - Stage 1 - Season 1"]
[Site "http://www.tcec-chess.net"]
[Date "2013.02.07"]
[Round "4.2"]
[White "Stockfish 2.31"]
[Black "Houdini 3.0"]
[Result "0-1"]
[Variant "normal"]

1. Nf3 Nf6 2. c4 e6 3. Nc3 Bb4 4. Qc2 O-O 5. a3 Bxc3 6. Qxc3 b6 7. b4 a5 8. Bb2
axb4 9. axb4 Rxa1+ 10. Bxa1 Na6 11. e3 Qe7 12. b5 Nc5 13. Qc2 Bb7 14. Be2 d6
15. O-O Ra8 16. Bb2 h6 17. Ra1 Rxa1+ 18. Bxa1 e5 19. Qa2 Be4 20. Ne1 Bg6
21. Bb2 Kh7 22. f3 Nfd7 23. Bc3 h5 24. Qa1 h4 25. Kf1 Qf6 26. Qa7 Qd8 27. Qa2
e4 28. Qa1 h3 29. g3 exf3 30. Nxf3 Bf5 31. Bd4 g6 32. Kf2 Kg8 33. Qa3 Bg4
34. d3 Qc8 35. Bxc5 bxc5 36. Ke1 Qb7 37. e4 Bxf3 38. Bxf3 Ne5 39. Be2 Qc8
40. Qa6 Qd8 41. Qa5 Kh7 42. Kd1 Kg7 43. Qa7 Kg8 44. Qa5 Kh7 45. Qa7 Kg7 46. Qa5
Qb8 47. Kd2 Kh7 48. Kc2 Kg8 49. Qa6 Qd8 50. Qa5 Qf6 51. Qe1 Kg7 52. Qf1 Qe6
53. Qe1 Qd7 54. Qc1 Qe8 55. Kc3 Qa8 56. Kb3 Kh7 57. Qa3 Qd8 58. Qc1 c6 59. Qc3
Qb6 60. Ka4 Qb7 61. Qd2 Nd7 62. Qc3 Qa7+ 63. Kb3 Kg8 64. Bg4 cxb5 65. cxb5 Nb6
66. Bxh3 Qa4+ 67. Kb2 Qd1 68. Ka3 Qe2 69. Kb3 Qh5 70. Bg2 Qxh2 71. Qf6 Qxg3
72. Bf1 Qe3 73. Kc2 Na4 74. b6 Nxb6 75. Qd8+ Kg7 76. Qxb6 Qf2+ 77. Kc3 Qxf1
78. Qxd6 Qf6+ 79. Qxf6+ Kxf6 80. Kc4 g5 81. Kxc5 Ke5 82. d4+ Kxe4 83. d5 g4
84. d6 g3 85. d7 g2 86. d8=Q g1=Q+ 87. Kb5 Qb1+ 88. Ka4 Qa2+ 89. Kb4 f5
90. Qe8+ Kf4 91. Qg6 Qd5 92. Qg1 Qe4+ 93. Ka5 Qe2 94. Qg8 Kf3 95. Qd5+ Qe4
96. Qd1+ Kg2 97. Qd2+ Kf1 98. Qh2 f4 99. Qh3+ Ke2 100. Qg4+ Kd2 101. Qg5 Kc2
102. Qh4 0-1

bench: 5518286
2013-02-15 16:25:33 +01:00
Marco Costalba e0dfb0bc34 Further speed up bitbase generation
Another trick, along the same lines of previous
patch. This time we first check positions with
white side to move that, becuase we start with
pawn on rank 7, are easily classified as wins,
then black ones.

Number of cycles reduced to 15 !

Becuase now it is faster we can remove a lot of
code to detect theoretical draws. We will calculate
them anyhow, although a bit slower, but the speed
up trick more than compensates it.

Verified that generated bitbases match original ones.

No functional change.
2013-02-15 11:58:33 +01:00
Gary Linscott 3922ac2fe4 Add new clop tuned value 2013-02-14 20:29:24 -05:00
Gary Linscott 66a1a77487 Merge branch 'master' into bishop_pin_clop 2013-02-13 21:41:15 -05:00
Gary Linscott cd0ecace19 Revert "Use CLOP mean value instead of max"
This reverts commit d0c2faa5fd.
2013-02-13 21:40:38 -05:00
Marco Costalba 10d29add18 Speedup KPK bitbase of 25%
Change the way the index is coded so that
now looping from 0 to IndexMax generates
the pawns from RANK_7 down to RANK2.

Becuase positions with pawns at RANK_7
are easily classified as wins/draws, this
small trick allows to reduce the number
of needed iterations from 30 down to 26!

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2013-02-13 20:13:56 +01:00
Marco Costalba f2950ae206 Simplify bitbase.cpp
Use a std::vector to store positions and
rearrange KPKPosition.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2013-02-13 20:13:44 +01:00
Gary Linscott d0c2faa5fd Use CLOP mean value instead of max 2013-02-13 12:21:16 -05:00
Gary Linscott 671f24ff35 Merge branch 'simplify_eval' into bishop_pin_clop 2013-02-13 12:19:54 -05:00
Gary Linscott f32f899467 CLOP tuned 2013-02-13 00:12:02 -05:00
Gary Linscott 17b71fe51d Add clop parameters 2013-02-12 00:10:21 -05:00
Gary Linscott 30c2e3828a Merge branch 'master' into simplify_eval 2013-02-11 10:26:25 -05:00
Gary Linscott a7cdf7299a Bishop pins only 2013-02-11 10:26:18 -05:00
Marco Costalba 733d0099b2 Rename and de-templetize sort()
Rename to insertion_sort so to avoid confusion
with std::sort, also move it to movepicker.cpp
and use the bit slower std::stable_sort in
search.cpp where it is used in not performance
critical paths.

No functional change.
2013-02-11 00:09:21 +01:00
Marco Costalba 0be7b8c542 Further simplify first_entry()
We can encode the ClusterSize directly in the
hashMask, this allows to skip the left shift.

There is no real change, but bench number is now
different because instead of using the lowest order
bits of the key to index the start of the cluster,
now we don't use the last two lsb bits that are
always set to zero (cluster size is 4). So for
instance, if 10 bits are used to index the cluster,
instead of bits [9..0] now we use bits [11..2].
This changes the positions that end up in the same
cluster affecting TT hits and so bench is different.

Also some renaming while there.

bench: 5383795
2013-02-09 16:37:20 +01:00
Marco Costalba c698362680 Microptimize first_entry() for 32bits
Do a 32bit bitwise 'and' instead of a 64bit
subtract and bitwise 'and'.

This is possible because even in the biggest
hash table case (8GB) the number of entries
is 2^29 so storable in an unsigned int.

No functional change.
2013-02-09 10:55:38 +01:00
Marco Costalba fe3352665b Retire TTCluster and simplify TT
Also some renaming while there.

No functional change.
2013-02-09 10:55:20 +01:00
Marco Costalba 3f44be9baa Simplify move_to_san()
Nicely simplify disambiguation code.

No functional change.
2013-02-09 07:43:53 +01:00
Gary Linscott 0c06b4509d Slight tweak to king safety. Bench: 5534531 2013-02-08 08:53:13 -05:00
Marco Costalba e5bc79fb9c Retire slavesPositions
Save the current active position in each Thread
instead of keeping a centralized array in struct
SplitPoint.

This allow to skip a memset() call at each split.

No functional change.
2013-02-08 11:45:33 +01:00
Marco Costalba 880726c13a Add const qualifer to go()
Obsolete renmant of when position was directly
passed to the search instead of being copied
for the main thread as is now.

From Jundery.

No functional change.
2013-02-08 10:07:09 +01:00
Marco Costalba 50a7200b18 Workaround value-initialization in MSVC
The syntax splitPoints() should force the compiler to
value-initialize the array and because there is no
user defined c'tor it falls back on zero-initialization.

Unfortunatly this is broken in MSVC compilers, because
value initialization for non-POD types is not supported,
so left splitPoints un-initialized and add in split()
initialization of slavesPositions, that is the only
member not already set at split time.

This fixes an assert under MSVC when running with
more than one thread.

Spotted and reported by Jundery.

No functional change.
2013-02-08 09:20:40 +01:00
Gary Linscott c67fb8ef04 Add KBPKP endgame
It is a draw if pawns are on G or B files, weaker pawn is
on rank 7 and bishop can't attack the pawn.

No functional change (because it is very rare and does not appear in bench)
2013-02-07 06:51:55 +01:00
Marco Costalba 14c2c1395b Change slave_available() API
To return a pointer to the available
thread instead of a bool. This allows
to simplify the core loop in split().

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2013-02-06 20:48:26 +01:00
jundery 88c3670edf Rename posKey stored in the transposition table
[Edit: Slightly extended by me]

No functional change.
2013-02-06 08:03:37 +01:00
jundery f69c185e02 Add const qualifer to check_is_dangerous
No functional change.
2013-02-06 07:49:40 +01:00
Marco Costalba bf706c4a4f Slightly change split() API
This function "returns" two values: bestValue and bestMove

Instead of returning one and passing as pointer the other
be consistent and pass as pointers both.

No functional change.
2013-02-05 06:35:38 +01:00
Marco Costalba 1a414cd9cb Derive ThreadPool from std::vector
Prefer sub-classing to composition in this case.

No functional change.
2013-02-04 22:59:20 +01:00
Marco Costalba 91427c8242 Move split() under Thread
Previous renaming patch suggested this reformat:
when a better naming leads to a better code!

No functional change.
2013-02-04 22:17:04 +01:00
Marco Costalba b8c5ea869c Some renaming in split()
Naming suggested by jundery.

No functional change.
2013-02-04 22:00:41 +01:00
Marco Costalba 6560e4cc5b Be clear about not LMR the ttMove
Currently a ttMove is reduced with ss->reduction = DEPTH_ZERO,
so it is actually not reduced (as it should be), but the
trick works just becuase it happens that ttMove is the first
to be tried and

reduction(depth, 1)

Always returns zero. So explicitly forbid reduction of ttMove
in the LMR condition. This is much clear and self-documented.

No functional change.
2013-02-03 11:14:21 +01:00
Marco Costalba 08d615cc95 Templetize score_xxx() functions
So to be style-wise aligned with the corresponding
generate() functions.

No functional change.
2013-02-03 10:11:12 +01:00
Marco Costalba 1c4e6d7ea2 Rename prevents_move() to refutes()
Better! From DiscoCheck.

No functional change.
2013-02-03 09:23:04 +01:00
Marco Costalba 5f58db8c99 Correctly score enpassant captures
Surprisingly this rare case was not considered
when scoring a capture.

Also take in account that in the promotion case
we gain a new piece (typically a queen) but we
lose the promoting pawn.

These small issues were present since Glaurung times!

Found while browsing DiscoCheck sources

bench: 5400063
2013-02-03 09:08:32 +01:00
Marco Costalba ddbe6082c4 Unify History and Gains under a single Stats class
Handling of History and Gains is almost the same, with
the exception of the update logic, so unify both
classes under a single Stats struct.

No functional change.
2013-02-02 17:45:09 +01:00
Marco Costalba 53051eefc7 Retire history.h
And move the contents to movepick.cpp, where they are
mostly used.

Idea from DiscoCheck.

No functional change (bench 5379503)
2013-02-02 16:54:35 +01:00
Gary Linscott a72710c660 Simplify eval take 2. Bench 5097444 2013-02-02 10:19:59 -05:00
Marco Costalba 9f94d22801 Restore "fail-low of reduced" and close regression
This reverts "Threat Extensions" and is the last of
this revert series.

In single-thread tests we should now be on par with 2.3.1
2013-02-02 07:16:33 +01:00
Marco Costalba 0901e12102 Revert "Simplify Evaluation"
This reverts commit 496c7497cb
2013-02-02 06:44:04 +01:00
Marco Costalba 58c9fbacc7 Revert "Extend full 3 fold detection to PvNodes" 2013-02-02 06:41:05 +01:00
Marco Costalba 483c98a69e Rewrite do_castle_move()
And handle the castle directly in do/undo_move().
This allow to greatly simplify the code.

Here the beast is the nasty Chess960 that is
really tricky to get it right because could be
that 'from' and 'to' squares are the same or
that king's 'to' square is rook's 'from' square.

Anyhow should work: verified on all Chess960
starting positions.

No functional and no speed change also in Chess960.
2013-01-28 13:40:47 +01:00
Marco Costalba 2218a5836a Rewrite do_null_move()
Use a more traditional approach, along the same lines
of do_move().

It is true that we copy more in do_null_move(), but we
save the work in undo_null_move(). Speed test shows the
new code to be even a bit faster.

No functional change.
2013-01-27 12:15:02 +01:00
Marco Costalba 76a0d3c05a Get rid of some locals in do_castle_move()
Rewrite the logic to get rid of kBefore and rBefore.

No functional change.
2013-01-27 11:03:55 +01:00
Marco Costalba 52cab06fff Don't prefetch if not needed
Prefetch access to hash tables only in case we
have changed pawn or material hash keys.

No functional change.
2013-01-27 10:19:11 +01:00
Marco Costalba bd87ab9ff5 Retire generate_king_moves()
We have only one call place so inline its content.
BTW, function is already declared as FORCE_INLINE.

Also some small refactoring while there.

No functional change.
2013-01-26 22:43:58 +01:00
Gary Linscott 57797822f8 Bring back just bishop pins 2013-01-26 15:35:00 -05:00
Marco Costalba 7062db7cb2 Clarify slavesMask usage
When a thread is allocated a bit is set in slavesMask.
This bit corresponds to the thread's index field that,
because it happens to be the position in the threads
array, eventually it is equal to the loop index 'i'.

But instead of relying on this 'coincidence', explicitly
use the 'idx' field so to clarify slavesMask usage.

Backported from c++11 branch.

No functional change.
2013-01-26 14:38:51 +01:00
Marco Costalba 166cc0292c Revert "Further push singular extension"
This reverts commit 4c91dbc28e

Seems a regression on extended test by both Gary and me.
2013-01-26 10:20:46 +01:00
Marco Costalba 496c7497cb Merge branch 'simplify_eval' of https://github.com/glinscott/Stockfish
Test results are looking good after 12500 games.

ELO: 6.55 +- 99%: 8.02 95%: 6.09
LOS: 99.99%
Wins: 1968 Losses: 1732 Draws: 8813

Also, here are the noise.py results, which seem to have stabilized:
Games: 12526 , result: [1969, 1734, 8823]
Estimated ELO: 6.94963842777
Noise as function of number of games:
['81.89', '565.26', '110.87', '104.39', '38.22', '49.98', '18.56', '16.76',
'11.02', '8.90', '17.36', '9.84', '10.81', '5.13', '6.22', '3.32', '5.83',
'7.21', '15.27', '1.63', '4.04', '9.51', '0.54', '0.75', '1.06', '2.93',
'4.59', '6.85', '13.62', '9.87', '14.74', '20.46', '22.18', '24.33', '31.02',
'34.99', '35.22', '33.22', '32.46', '37.02', '29.10', '36.34', '42.11', '39.33',
'26.16', '28.25', '35.42', '31.04', '29.26', '23.91', '22.52', '23.49', '20.00',
'24.39', '17.22', '16.50', '10.69', '9.15', '9.57', '4.77', '6.67', '3.87', '2.57',
'2.84', '2.60', '3.32', '2.08', '2.93', '4.47', '4.41', '4.83', '4.86', '6.40',
'5.98', '6.10', '6.83', '5.83', '6.22', '5.71', '8.52', '9.25', '5.98', '7.52',
'7.76', '8.76', '8.55', '8.64', '7.19', '5.83', '4.59', '4.77', '4.26', '4.98',
'5.29', '5.41', '4.92', '5.59']

bench: 5229106
2013-01-26 10:18:36 +01:00
Gary Linscott e83b9075ff Simplify evaluation 2013-01-24 08:54:13 -05:00
Marco Costalba 6950d07bf4 Small reformat of split()
No functional chhange.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2013-01-21 23:31:33 +01:00
Marco Costalba 054d117d25 Fix an idiotic icc warning
Intel Compiler has 'invented' this pearl:

warning #1476: field uses tail padding of a base class

Just becuase we have subclassed MainThread and added
the field 'bool thinking'.

Pure nosense. Silence the warning.

No functional change.
2013-01-20 17:36:24 +01:00
Marco Costalba 62b32a4737 Futher renaming in thread.cpp
No functional change.
2013-01-20 17:35:55 +01:00
Marco Costalba 588670e8d2 Big renaming in thread stuff
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2013-01-16 20:00:05 +01:00
Marco Costalba c465f4c4df Fix race while exiting
Fix again TimerThread::idle_loop() to prevent a
theoretical race with 'exit' flag in ~Thread().

Indeed in Thread d'tor we raise 'exit' and then
call notify() that is lock protected, so we
have to check again for 'exit' before going to
sleep in idle_loop().

Also same change in Thread::idle_loop() where we
now check for 'exit' before to go to sleep.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2013-01-16 19:58:55 +01:00
Lucas Braesch 8737b26a23 Remove Threat Extension
Great code simplification: - instead do not futility
prune threat refutations. allows_move() is therefore removed.

4000 games at 50,000 nodes/move:
1085-989-1926 [51.2%] LOS=98.3%

4000 games in 10"+0.1"
756-751-2493 [50.1%] LOS=55.1%

EDIT: I have retested the patch of Lucas in a slightly different form
(without pruning in PvNode) and test mre or less confirms that
60 lines of code are totally unuseful:

After 6195 games at 15"+0.05"
1333 - 1325 - 3537 ELO 0

bench 5140990
2013-01-15 17:03:56 +01:00
Marco Costalba 78a9531773 Fix a bug in timer loop
Silly logic bug introduced in dda7de17e7

Timer thread, when msec = 0, instead of going
to sleep, calls check_time() in an endless loop.

Spotted and reported by snino64 due to abnormally
high CPU usage.

No functional change.
2013-01-14 19:32:30 +01:00
Marco Costalba d1143794a0 Polymorphic Thread hierarchy
Subclass MainThread and TimerThread and declare
idle_loop() virtual. This allow us to cleanly
remove a good bunch of hacks, relying on C++
polymorphism to do the job.

No functional change.
2013-01-14 02:01:37 +01:00
Marco Costalba e70eae2c91 Don't use do_sleep flag
Rename it is_finished and use it only in main
thread to signal search is finished. This allows
us to simplify the complex SMP logic.

Ultra tricky patch: deep test is required under
wide conditions like pondering on and option
"Use Sleeping Threads" set to false.

No functional change.
2013-01-14 00:02:32 +01:00
Marco Costalba 99ae47716a Re-add the hack
This reverts commit 869c924410

I misunderstood here. Actually it can happen that
thread is created but still not entered idle_loop
and at the same time start_searching() is called.

Becuase 'do_sleep' is set start_searching() will
set it to false and start the search, but when,
at last, the thread enters idle_loop(), resets
the flag and goes to sleep: not what we want.

Revert the hack waiting for a better solution
in the next patches.

No functional change.
2013-01-13 23:56:04 +01:00
Marco Costalba dda7de17e7 Retire set_timer()
Also assure in Thread::timer_loop() that when
timer interval is 0 (timer is disabled) we
never call check_time()

No functional change.
2013-01-13 18:24:43 +01:00
Marco Costalba 869c924410 Retire obsolete race hack
This hack was introduced in d282cf6964
to workaround a race with start_searching(),
but these days is no more needed.

No functional change.
2013-01-13 17:05:30 +01:00
Marco Costalba ea6c1f7a17 Retire Threads wake_up() and sleep()
These functions are used in just one place.
And generalize wait_for_stop()

No functional change.
2013-01-13 16:57:40 +01:00
Marco Costalba 81cd7d787e Rename wake_up() to notify_one()
To align to C++ std::thread conventions.

No functional change.
2013-01-13 16:43:26 +01:00
Marco Costalba a523cea772 Unify 'ponderhit' handling
Finally we can now merge the 'ponderhit' case with
'stop' and 'quit'.

The patches have been done step by step to help debugging
becuase this is really tricky code.

No functional change.
2013-01-13 14:39:41 +01:00
Marco Costalba a66a7c3870 Small change to "ponderhit" handling
Reset Limits.ponder only if search continue, but if
we are going to stop the search there is no need
(and is also confusing) to clear the 'ponder' flag.

This mimics the behaviour upon rceiving 'stop' when
pondering.

No functional change.
2013-01-13 14:32:30 +01:00
Marco Costalba 89a89eb605 Simplify and rename wait_for_stop_or_ponderhit()
Setting stopOnPonderhit is now done by the caller.

No functional change.
2013-01-13 14:15:19 +01:00
Marco Costalba 3b14b17664 Simplify a condition in search()
And rearrange best value update in case of SpNode.

No functional change.
2013-01-13 13:17:16 +01:00
Marco Costalba 3a836dab59 Clarify SAN disambiguation in case of a pinned piece
In SAN notation when two pieces of the same type can
move to a given destination square, a disambiguation
additional info (like starting file) shall be added
to the SAN move.

If one of the two pieces is pinned, the corresponding
move _could_ be illegal and in this case disambiguation
is not needed. But to be pinned alone it is not enough
to deduce that the move is illegal, for instance in this
position:

R3rk2/2r6/8/8/8/8/8/K7 b - - 0 1

The move Rc8 is ambiguous although the rook in e8 is pinned
and the correct SAN notation should be Rcc8.

No functional change.
2013-01-12 13:21:14 +01:00
Marco Costalba e1191b35e8 Async 'stop' command
Don't wait for the search to finish after a 'stop'
command, but keep processing the GUI input if any.

Also explicitly wake up the main thread (that could be
sleeping) after a 'stop' or 'quit' command and do not
rely on wait_for_search_finished() doing it for us.

This patch cleans up the code and functions's definitions,
but it is risky and needs a good test under different
conditions to be sure it does not introduces hungs up.

No functional change.
2013-01-12 12:06:55 +01:00
Marco Costalba edce2a8448 Revert so called "fromNull patch"
Revert patch c581b7ea36

Seems a regression after testing from Gary:
ELO: 7.24 +- 99%: 17.03 95%: 12.93
LOS: 97.86%
Wins: 439 Losses: 381 Draws: 1962

And mine:
After 5410 games at 15"+0.05
Wins: 936 Losses: 1141 Draws: 3333  ELO -13

Moreover we know that there is a regression in the range
of patches which include the fromNull patch.

Probably this is not the only regression since 2.3.1 and
perhaps the idea under fromNull is good, but at the moment,
while in deep regression hunting, better to be on the safe
side and revert it entirely.

My guess on why this is a regression is that using the
negated evaluation of previous ply in case of null search
fails to take in account the king safety asymmetry between
the two colors. This is of course just a guess.

bench 5503830
2013-01-06 23:06:20 +01:00
Marco Costalba 9b1cf3cf43 Have fun with union in book.cpp
Fancy way to use an union to map polyglot
zobrist keys in one go.

Also some renaming while there.

No functional change.
2013-01-06 12:06:19 +01:00
Marco Costalba bff65a211f Retire 'Cowardice' and 'Aggressiveness' UCI options
They are not self-describing and create a lot of user
requests about them.

Given that the values are already well tuned there
is no need to expose them as UCI options.

No functional change.
2013-01-04 17:11:24 +01:00
Marco Costalba 2d60995c00 Retire 'mate in x' hack
Sometimes is faster, but not always and on very long mates
produces strange scores probably due to truncation of PV
artifacts.

So simply perform normal search also in case of UCI 'mate x'
command, with the only difference that when a mate in x is
found search returns immediately.

No functional change.
2013-01-04 16:30:46 +01:00
Marco Costalba 0454bbc54f Don't exit if unable to find bench file
Now that we can call 'bench' command also from
interactive terminal it makes no more sense to
exit the application if the user types a wrong
file name.

No functional change.
2013-01-04 14:52:21 +01:00
Marco Costalba 900e2d4e1e Teach file_to_char() about upper/lower case
This allows to further simplify Position::fen()

No functional change.
2013-01-04 14:45:04 +01:00
Marco Costalba 9d1151575d Reformat FEN construction
Simplify and shrink code.

No functional change.
2013-01-04 13:38:14 +01:00
Marco Costalba 193741218c Remove some obsolete asserts on TT values
Now that insert_pv_in_tt() stores VALUE_NONE in
TT's position evaluation those 2 asserts are
obselete.

No functional change.
2012-12-31 17:20:39 +01:00
Marco Costalba 896420b166 Allow to pass a 'seed' to RKISS
This somewhat simplifies the code.

Suggested by Lucas Braesch.

No functional change.
2012-12-31 11:59:53 +01:00
Marco Costalba 009a0f88e0 Micro-optimization in evaluate_space()
Since &-ing with SpaceMask restricts the set to the home
half of the board, it is possible to use just one popcount
instead of 2 by shifting "safe" to the other half of the
board. This gives a small speedup especially on systems
where hardware popcount is not available.

Patch kindly sent by Richard Vida.

No functional change.
2012-12-31 11:34:18 +01:00
Marco Costalba e1d681458e Add 'mate' limit to 'bench' command
It is now possible to run SF on a 'mate in x' testsuite.

For instance in case of a file with fen strings of
positions with mate in 10 we can now 'bench' on it:

stockfish bench 128 1 10 mate_in_10.epd mate

No functional change.
2012-12-30 15:49:02 +01:00
Marco Costalba ce063f59cd Handle UCI command "mate in x moves"
Following a user request I added the handling of UCI:

go mate x

Currently we just return from a PV node if x moves have been
done. Probably not the best approach. I have looked at Fruit/Toga
sources and there is even simpler: engine falls back on a fixed
depth search.

No functional change.
2012-12-30 14:43:23 +01:00
Marco Costalba 3cf6471738 Revert evaluation cache
And return on using TT as backing store for position
evaluations.

Tests (even on single thread) show eval cache was a regression.
In multi thread result should be even worst because eval cache
is a per-thread struct, while TT is shared.

After 4957 games at 15"+0.05 (single thread)
eval cache vs master 969 - 1093 - 2895  -9 ELO

So previous reported result of +18 ELO was probably due to an
issue in the testing framework (a bug in cutechess-cli) that
has been fixed in the meanwhile.

bench: 5386711
2012-12-27 13:57:17 +01:00
Marco Costalba f78b68b7ff Add list of legal moves to Position::pretty()
Along the same lines of previous patch now we add
the list of the legal moves in the given position.

No functional change.
2012-12-27 11:34:48 +01:00
Marco Costalba e9ab7353de Add checkers info to Position::pretty()
In case current position is under check, list the
squares of the checker(s) pieces.

This should satisfy a specific user request.

No functional change.
2012-12-26 18:28:45 +01:00
Marco Costalba 9d1978e217 Remove two obsolete asserts in prevents_move
Now that this function is called also to calculate
move's extensions the asserts are no more valid.

No functional change.
2012-12-26 12:27:41 +01:00
Marco Costalba db097921bc Rename yields_to_threat and prevents_threat
Follow Lucas suggestions and better name these
two functions.

No functional change.
2012-12-26 12:21:59 +01:00
Marco Costalba 894c43a1d6 Introduce Null Threat extension
In case of null search at low depths returns a fail low
due to a threat then, rather than return beta-1 (to cause
a re-search at full depth in the parent node), we set a flag
threatExtension = true (false by default) that will cause
moves that prevent the threat to be extended of one ply
in the following search.

Idea and patch is by Lucas Braesch.

Lucas also did the tests:
1500 games in 5"+0.05":
SF_threatExtension vs SF_20121222: 366 - 331 - 803 [51.2%] LOS=90.8%

3000 games in 10"+0.1":
SF_threatExtension vs SF_20121222: 610 - 559 - 1831 [50.8%] LOS=93.2%

Tests confirmed by Gary after 10570 games,
ELO: 2.79 +- 99%: 8.72 95%: 6.63
LOS: 94.08%
Wins: 1523 Losses: 1438 Draws: 7607

And finally by me at 15"+0.05, single thread, 3824 games
threatExtension vs master 768 - 692 - 2364  +7 ELO

bench 4918443
2012-12-25 19:17:27 +01:00
Marco Costalba b5b799b5ab Fix a couple of extra spaces
No functional change.
2012-12-25 18:48:41 +01:00
Marco Costalba e82382703c Retire Position::in_check()
It is redundant with Position::checkers()

No functional change.
2012-12-25 17:59:35 +01:00
Marco Costalba 3b49aeb4f2 Retire Position::move_is_legal()
Use the new contains() method of struct MoveList

No functional change.
2012-12-25 11:51:08 +01:00
Marco Costalba 423c6d8a8a Small tweak in is_pseudo_legal()
This is difficult code becuase a bug here could lead
to very subtle crashes in case of SMP games where we
have TT move corruption due to concurrent access.

Anyhow I have fully verified te code throwing at it
random moves. It shoudl work.

No functional change.
2012-12-25 11:31:32 +01:00
Marco Costalba 158014b39d Introduce namespace Pawns
And retire old struct PawnTable along the same lines
of previous patch.

No functional change.
2012-12-22 11:38:36 +01:00
Marco Costalba 231f62baf7 Introduce namespace Material
And retire old struct MaterialTable simplifying the code.

No functional change.
2012-12-16 12:58:39 +01:00
Marco Costalba 52bbf372bb Don't need to check for bestValue < beta to split
With rearrangement of fail high code this condition
is no more necessary.

Found by Jörg Oster.

No fuctional change.
2012-12-15 13:11:10 +01:00
Marco Costalba 3ddf91d9d1 Remove an extra semicolon
No functional change.
2012-12-15 11:20:04 +01:00
Marco Costalba a2f46446cf Revert store of distinct upper and lower bounds
Test by Joona prooves the new feature don't value 70 added lines of code.

Grand totals after 10040 games (crashes: 0) for tt_both

master_9edc7 - 6a93488_6a934: 1756 - 1688 - 6596 ELO +2 (+- 2.7)

Confirmed by test of Gary:

After 8680 games:
ELO: 0.80 +- 99%: 9.62 95%: 7.31
LOS: 65.38%
Wins: 1288 Losses: 1268 Draws: 6130

Thanks a lot to both for testing it !!!

bench 5149248
2012-12-15 11:18:52 +01:00
Marco Costalba 9edc7d6958 Merge branch 'eval_cache'
Unusually good result. Defenitly needs further verifications.

After 2160 games at 15"+0.05
Mod vs Orig 486 - 367 - 1307 ELO +19

bench: 6261882
2012-12-10 09:26:02 +01:00
Marco Costalba 55db871472 Fix comparison with alpha, not beta
This silly bug seems the reason of the unsual bench
value.

bench: 6261882
2012-12-09 14:19:21 +01:00
Marco Costalba da98a45bcb Ensure valueLower <= valueUpper
In case a TTEntry stores both an upper and a lower bound
ensure that upper bound is not smaller than lower bound.

bench 1813815
2012-12-09 14:14:44 +01:00
Marco Costalba feeafb0a50 Store distinct upper and lower bound scores
This is more complex than what I'd like but I
was unable to split in small chunks.

Here we add 2 slots to TTEntry (valueUpper and depthUpper)
so that sizeof(TTEntry) returns to the original 16 bytes
and we can pack exactly 4 entries in a 64 bytes cache line.

Now we save an upper bound score alongside a lower (exact)
score. The idea is to increase TT cut-offs rates becuase
there is now an higher probability for a node to use TT info.

This patch is highly experimental and probably needs further
steps as is hinted by an unrealistic bench number:

bench: 2022385
2012-12-09 13:15:50 +01:00
Marco Costalba 22c557ca7c Micro-optimize color_of()
In almost all cases we already know in advance that
color_of() argument is different from NO_PIECE.

So avoid the check for NO_PIECE in color_of() and
test at caller site in the very few places where
this case could occur.

As a nice side effect, this patch fixes a (bogus)
warning under some versions of gcc.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2012-12-08 12:32:48 +01:00
thaspel 6a93488291 Update Readme.txt now that we support 64 threads
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2012-12-04 19:57:16 +01:00
Marco Costalba 6fa83f5188 Merge branch 'eval_cache'
Use an eval cache instead of TT to store node
position evaluations.

It is already an improvment and, because it frees
two TT entry slots, paves the way to extend TT to
store both upper and lower bounds.

After 4855 games, single thread, 15"+0.05
Mod vs Orig 1165 -920 - 2770 ELO +18

bench: 5149248
2012-12-04 08:05:15 +01:00
Marco Costalba ce248e7920 Increase MAX_THREADS to 64
And document why this is an hard limit. It
seems for some (lucky) people 32 threads
are not enough.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2012-12-04 07:57:15 +01:00
Marco Costalba 23bdd06442 Reintroduce eval optimizaion from null search
Now that conversion to eval cache is finished
we can reintroduce this optimization.

bench: 5149248
2012-12-01 18:11:01 +01:00
Marco Costalba 98cd8239cc Don't save eval score in TT
This patch completes the removal of eval info
in TT table.

No functional change.
2012-12-01 15:19:50 +01:00
Marco Costalba 2a585b63b8 Don't use TT just to save a node evaluation
In search(), after we evalute the position, in case there
isn't any TT entry we create one with just the evaluation
score.

This patches removes that code. The reason becuase the patch
deserves a single commit it is becuase introduces a (very small)
functional change due to the fact that the total number of
TT stores is less now and this slightly alters the TT hits
of our benchmark.

bench: 4983262
2012-12-01 15:13:08 +01:00
Marco Costalba a5ea3a202e Don't read eval from TT anymore
Rely fully on eval cache. Note that we still save eval
info to TT, this is not needed at this moment and will be
removed in future patches. We keep it so to have a "non
functional change" patch.

No functional change.
2012-12-01 15:01:00 +01:00
Marco Costalba 69de670353 Retire eval optimization from null search
Simplify things preparing for further changes.

bench: 4983282
2012-12-01 14:48:13 +01:00
Marco Costalba 4e5d834e8e Add eval cache infrastructure
With this patch series we want to introduce a per-thread
evaluation cache to store node evaluation and do not
rely anymore on the TT table for this.

This patch just introduces the infrastructure.

No functional change.
2012-12-01 14:01:20 +01:00
Marco Costalba 4502917665 Don't double check for move legality
In case of a RootNode or a SpNode move has
been already checked for legality so we can
skip a redundant check.

Spotted by Frank Genot.

No functional change.
2012-11-27 20:05:03 +01:00
Marco Costalba 5af8179647 Update bestValue when futility pruning
In qsearch we should update the bestValue as we do
in case of futilityValue < beta, also when pruning
moves with non-positive see.

Spotted by Lucas Braesch

Bench: 5695710
2012-11-26 16:13:36 +01:00
Marco Costalba 55df3fa2d7 Avoid spamming the GUI in multipv search
Send the PV lines to GUI only once at the end of the
PV search loop or just in case of long searches.

We need to sync also sending of "currmove" info to
avoid sending info on current move without first
informing the GUI on the PV line we are searching on.

No functional change.
2012-11-18 11:46:37 +01:00
Marco Costalba 8367cf15da Triviality in move_gives_check()
It seems even a bit faster, although handling of the special
cases is not the hot path.

No functional change.
2012-11-17 13:08:04 +01:00
Marco Costalba 942989939a Better document fail-high condition
At this point we have already verified (value > alpha)
and this implies, in case of a non-PV node, where search
window size is zero, that value >= beta.

This is not so self-evident, so document the code with
an assert condition.

No functional change.
2012-11-17 12:50:10 +01:00
Marco Costalba 239d7b3fd1 Don't access std::cout from Position::print()
Let the caller to decide where to redirect (cout or cerr) the
ASCII representation of the position. Rename the function to
reflect this.

Renamed also from_fen() and to_fen() to set() and fen() respectively.

No functional change.
2012-11-11 13:30:20 +01:00
Marco Costalba 116234d6c6 Restore old BOUND_EXACT logic in qsearch
In case a PvNode node has a static evaluation above alpha but
no available moves we want to flag the node as BOUND_EXACT,
not as BOUND_UPPER as is currently.

The behaviour was recently introduced with patch d471c49700
of 3/10/2012

Spotted by Hongzhi Cheng.

bench: 5558464
2012-11-11 11:52:11 +01:00
Marco Costalba c45a4e0b48 Revert "Don't prune discovered checks"
Both Lucas re-test and Jean-Francois confirrm it
is a regression.

Here Jean-Francois's results after 3600 games :
Score of 96d3b1c92b vs 3b87314: 690 - 729 - 2181 [0.495] 3600
ELO: -3.86 +- 99%: 14.94 95%: 11.35
LOS: 15.03%
Wins: 690 Losses: 729 Draws: 2181 Total: 3600

Bench: 5404066
2012-11-11 11:20:39 +01:00
Marco Costalba 96d3b1c92b Don't prune discovered checks
Don't prune and eventually extend check moves of type
DISCO_CHECK (pun intended, Lucas will understand :-) ).

Patch from Lucas Braesch that has also tested it:

Result: 879-661-2137, score=52.96%, LOS=100.00% (time 10"+0.1")

I have started a verification test right now.

bench: 6004966
2012-11-07 18:29:56 +01:00
Marco Costalba 3b87314331 Previous patch test results
From Jean-Francois's

Final result after 5000 games :
Score of c581b7e vs a878312: 1163 - 970 - 2867 [0.519] 5000
ELO: 13.35 +- 99%: 12.71 95%: 9.65
LOS: 100.00%
Wins: 1163 Losses: 970 Draws: 2867 Total: 5000

From me

After 3266 games at 20"+0,05
Score of c581b7e vs a878312: 612 - 607 - 2047

So no regression at longer TC and perhaps a little gain at
fast TC.
2012-11-07 18:07:03 +01:00
Marco Costalba c581b7ea36 Another attempt at evaluation shortcut
In this case we try a rather drastic
approach: we simply don't futility prune
in qsearch when arriving from a null move.

So we save evaluating and also save to mess
with eval margins at all because margin is used
only in futility.

Also accuracy should not be affected, actually it
improves because we don't prune anything anymore.

bench: 5404066
2012-11-05 16:12:28 +01:00
Marco Costalba a5b1f4774f Temporary revert previous patch
Performs well at very short TC of 40/4+0.05 (courtesy of Jean-Francois):
Wins: 2503 Losses: 2146 Draws: 5581 Total: 10230 +12 ELO

But is poor at longer TC of 20"+0.05
Wins: 321 Losses: 373 Draws: 1141 Total: 1808 -10 ELO

The patch was clearly a tradoff between speed and accuracy and
the most interesting part of it are test results that can be
commented as follows:

- A short TC is very sensible to any speed increase
- A longer TC is more sensible to accuracy and less to speed

So a patch that does not change speed is suitable to be tested at
short TC, while a speed/accuracy compromise patch is IMO better to
be tested at longer TC to verify loss of accuracy can be tolerated.

In this case the revert is only temporary. We will come back again
once we will be able to preserve the evaluation margin.

bench: 5809010
2012-11-05 07:41:28 +01:00
Marco Costalba 37e9802411 Skip evaluate() call after a null move
Reuse the evaluation of the parent with inverted sign and
set margin to zero (this is an hack!).

This is done only in qsearch where almost 15% of calls are
from a null move. In normal search the number of nodes where

(ss-1)->currentMove == MOVE_NULL

is almost zero and so there is no need of using this trick.

The big advantage of this patch is a speed-up due to skipped
evaluate() calls, that are very costly.

Functionality is of course affected and we will need to proper
test it later. For now we just register a 3-4% speed up.

Suggested by Hongzhi Cheng.

bench: 5051328
2012-11-04 10:48:14 +01:00
Marco Costalba a87831230d Correctly fix "break from split" patch
In case split cut-offs we return with still
some moves to go but we really want to break
out from the loop now.

No functional change.
2012-11-03 17:09:18 +01:00
Marco Costalba dd5b3086f5 Relax constrain in prevents_threat()
When testing if a move blocks the threat path there is no
reason to require the threat to be a slider. Indeed threat
can be a double pawn push like in this example:

r1bq1rk1/ppp1np1p/4n1p1/3p4/3P2Q1/2P1B3/PPBN2PP/R4RK1 w - - 0 16

Where white's move Rf6 blocks the threat f5.

As a nice side effect we can retire the now useless helper
piece_is_slider().

This patch kicks in only very rare cases, indeed the bench is
still the same!

bench: 5809010
2012-11-03 15:57:20 +01:00
Marco Costalba 47f988f05f Sync connected_threat() and yields_to_threat()
Rename stuff so to sync as much as posisble the
two related functions.

No functional change.
2012-11-03 15:36:12 +01:00
Marco Costalba 07989712af Don't 'break' upon returning from split()
There is no guarantee that split() consumes all the node's
moves. Indeed split() can return without performing any job
for instance because MAX_SPLITPOINTS_PER_THREAD is reached
or becuase no available threads are found (this latter case
is much more common).

So search must continue in those cases and we cannot force
exiting from move's loop.

Bug introduced by 1ac417edb8 of 5/10/2012

Spotted by Frank Genot.

No functional change.
2012-11-03 14:54:38 +01:00
Marco Costalba d0d69a5358 Remove a redundant condition in connected_moves()
If a previous move attacks the king (with the piece
of the threat move removed) then must be a discovered
check, otherwise it means that first move gave check
and we were not able to do a null move.

Also renamed stuff to better document the function's
context.

No functional change.
2012-11-03 14:24:29 +01:00
Marco Costalba 972de506a0 Relax constrain in connected_moves()
When testing if a piece is moving through the squares
vacated by a previous move there is no reason to require
the piece to be a slider, indeed we can have a double
pawn push like in this example:

r1q2rk1/2p1bppp/2Pp4/pN5b/Q1P1p3/4B2P/PP1R1PP1/1K5R w - - 3 18

Where black's move f5 is connected to previous move Be7 that
frees the path.

Or we can have a castle move:

r1bqkb1r/pppp1ppp/2n1pn2/1B6/4P3/2N2N2/PPPP1PPP/R1BQK2R b KQkq - 5 1

Where a previous move Bb5 allows the white to castle king side.

This time patch is mine ;-)

new bench: 5809010
2012-11-03 13:34:04 +01:00
Marco Costalba ed1574e46c Reformat connected_moves()
Prepare code for the next patch that
will affect functionality.

No functional change.
2012-11-03 13:27:44 +01:00
Marco Costalba 52f55179a8 Fix an off-by-one bug in multi pv print
We send to GUI multi-pv info after each cycle,
not just once at the end of the PV loop. This is
because at high depths a single root search can
be very slow and we want to update the gui as
soon as we have a new PV score.

Idea is good but implementation is broken because
sort() takes as arguments a pointer to the first
element and one past the last element.

So fix the bug and rename sort arguments to better
reflect their meaning.

Another hit by Hongzhi Cheng.  Impressive!

No functional change.
2012-11-03 00:36:40 +01:00
Marco Costalba bbdf9e4737 Fix a condition in connected_moves()
When checking if the moving piece p1 in a previous
move m1 defends the destination square of a move m2
we have to use the occupancy with the from square of
m2 removed so to take in account the case in which
f2 will block an x-ray attack from p1.

For instance in this position:
r2k3r/p1pp1pb1/qn3np1/1N2P3/1p3P2/2B5/PPP3QP/R3K2R b KQ - 1 9

The move eXf6 is connected to the previous move Bc3 that
defends the destination square f6.

With this patch we have about 10% more moves detected as
'connected'. Anyhow the absolute number is very low, about
4000 more moves out of 6M nodes searched.

Another issue spotted by Hongzhi "Hawk Eye" Cheng ;-)

new bench: 5757373
2012-11-02 17:18:38 +01:00
Marco Costalba 94ecdef8ac Micro-optimize pop_lsb() for 64bit case
On Intel, perhaps due to 'lea' instruction this way of
zeroing the lsb of *b seems faster than a shift+negate.

On perft (where any speed difference is magnified) I
got a 6% speed up on my Intel i5 64bit.

Suggested by Hongzhi Cheng.

No functional change.
2012-11-02 12:11:49 +01:00
Marco Costalba e3b0327812 Fix a warning under MSVC
Compiler complies that 'cnt' is initialized but
unused (in !CheckThreeFold case). Moving the
definition of 'cnt'out of the loop  seems to do
the trick.

No functional change.
2012-11-02 11:43:23 +01:00
Marco Costalba c039103b31 Pass InCheck as template parameter of qsearch()
Instead of use a variable so to resolve many conditions
already at compile time. In quiesce is also where we
have most of the InCheck nodes and is one of the most
performance critical code paths.

Speed up of 1.5% with Clang and 1% with gcc

Suggested by Hongzhi Cheng.

No functional change.
2012-11-01 18:45:38 +01:00
Marco Costalba fe1cbe2638 Use correct occupancy in connected_threat()
When checking if a move defends the threatened piece
we correctly remove from the occupancy bitboard the
moved piece. This patch removes from the occupancy also
the threatening piece so to consider the cases of moves
that defend the threatened piece x-raying through the
threat move.

As example in this position:
r3k2r/p1ppqp2/Bn4p1/3p1n2/4P1N1/5Q1P/PPP2P1P/R3K2R w KQkq - 1 10

The threat black move is dxe4. With this patch we include
(and so don't prune) white's Bb7 that would be pruned otherwise.

The number of affected position is very low, around 1% of cases,
so we don't expect ELO changes, neverthless this is the logical
and natural thing to do.

Patch suggested by Hongzhicheng.

new bench: 5323798
2012-10-30 20:27:07 +01:00
Marco Costalba 4e31c39a64 Retire move_attacks_square()
There is only one call site. This patch is a
preparation for the next one that will affect
functionality.

No functional change.
2012-10-30 20:03:35 +01:00
Marco Costalba 13f90a30ef Get rid of ReducedStateInfo struct
ReducedStateInfo is a redundant struct that is also
prone to errors, indeed must be updated any time is
updated StateInfo. It is a trick to partial copy a
StateInfo object in do_move().

This patch takes advantage of builtin macro offsetof()
to directly calculate the number of quad words to copy.
Note that we still use memcpy to do the actual job of
copying the (48 bytes) of data.

Idea by Richard Vida.

No functional and no performance change.
2012-10-29 08:07:17 +01:00
Marco Costalba ad1941fd00 Creative formatting in uci.cpp
Have some fun breaking the indentation rules :-)

No functional change.
2012-10-28 11:28:14 +01:00
Gary Linscott cee6336515 Detect drawish KQKP endings
Based off of the rules from the wikipedia page,
here: http://en.wikipedia.org/wiki/Queen_versus_pawn_endgame.

bench does not change: 5312693 but patch is real, has been
tested on specific positions.
2012-10-28 10:17:57 +01:00
Marco Costalba b3d030294b Reformat check_is_dangerous()
And shuffle some code at search.cpp tail.

No functional change.
2012-10-27 15:07:20 +02:00
Marco Costalba cd80762c13 Use std::stack instead of fixed size array
Only in not performance critical code like pretty_pv(),
otherwise continue to use the good old C-style arrays
like in extract/insert PV where I have done some code
refactoring anyhow.

No functional change.
2012-10-27 13:31:23 +02:00
Marco Costalba 00a853950f Fix broken uci notation for promotions
Silly typo (introduced in e304db9d1e) completely
messed up move notation in case of promotions causing
"Illegal move" warning in cutechess-cli.

Reported by Jörg Oster.

No functional change.
2012-10-26 16:06:47 +02:00
Marco Costalba 4c7a71a44b Fix asserts due to TT access races
In multi-threads runs with debug on we experience some
asserts due to the fact that TT access is intrinsecally
racy and its contents cannot be always trusted so must
be validated before to be used and this is what the
patch does.

No functional case.
2012-10-26 12:41:12 +02:00
Marco Costalba c594b989c0 Extend full 3 fold detection to PvNodes
And restore old behaviour of not returning from a RootNode
without updating RootMoves[].

Also renamed is_draw() template parameters to reflect a
'positive' logic (Check instead of Skip) that is easier
to follow.

New bench: 5312693
2012-10-26 11:56:33 +02:00
Marco Costalba 71f37ac1aa Merge pull request #34 from jromang/repetition
Improve 3 fold repetition detection
2012-10-26 02:01:10 -07:00
Jean-Francois Romang 77c91ac1ba Full three fold repetition detection only at root node 2012-10-25 15:57:44 +02:00
Jean-Francois Romang 5436d98fc5 Enable true 3 fold detection in search 2012-10-25 06:54:05 +00:00
Jean-Francois Romang 0587c5b605 Allow full repetition detection
Based on sshivaji 6ee19aa5389ce60181907ba53bbb50642f2d5657 commit
2012-10-25 06:28:55 +00:00
Marco Costalba c1f4000426 Fix an assert when we stop the search
When signal 'stop' is raised we return bestValue
that could be still set at -VALUE_INFINITE and
this triggers an assert. Fix it by returning
a value we know for sure is not +-VALUE_INFINITE.

Reported by 平岡拓也 Hiraoka.

No functional change.
2012-10-25 00:07:59 +02:00
Marco Costalba 22715259a0 Rename RootPosition and shuffle think()
Just slightly code reshuffles, noting interesting here...

No functional change.
2012-10-24 15:01:39 +02:00
Marco Costalba 4eda653a56 Drop Chess960 and UCIMultiPV globals and rename MultiPV
No functional change.
2012-10-24 14:31:33 +02:00
Marco Costalba e8e5b9f537 Wrap in a class Skill Level code
Note that the actual pickup is done in the class
d'tor so to be sure it is always triggered, even
in case of a sudden exit due to a 'stop' signal.

No functional change.
2012-10-24 12:52:29 +02:00
Marco Costalba 9c2b3faec4 Shuffle aspiration window loop
No functional change.
2012-10-24 11:35:53 +02:00
Marco Costalba 70b1b79264 Retire refine_eval()
Inline its content and better comment what it does through
some renaming.

No functional change.
2012-10-22 10:03:53 +02:00
Marco Costalba 5fc8b27db9 Don't copy a full Position object in print()
Function move_to_san() requires the Position to be
passed by referenced because a do/undo move is done
inside the function to detect a possible mate and to
add to the san string the corresponding '#' suffix.

Instead of passing a copy of current position pass
directly the original position object after const
casting it. This has the advantage to avoid a costly
Position copy, on the down side a bench test could
report different searched nodes if print(move) is
used, due to the additionals do_move() calls.

No functional change.
2012-10-22 00:55:16 +02:00
Marco Costalba dbbbd3880c Don't need to init board[] with NO_PIECE
Now that NO_PIECE == 0 the common memset() will
do the work.

No functional change.
2012-10-22 00:38:12 +02:00
Marco Costalba e40b06a050 Change NO_PIECE value and shrink PieceValue[]
This requires changing color_of() definition.

No functional change.
2012-10-21 11:50:56 +02:00
Marco Costalba e304db9d1e Use self-describing constants instead of numbers
And remove now useless comments.

No functional change.
2012-10-21 11:16:21 +02:00
Marco Costalba 6b909b2343 Move RootColor from Eval to Search
No functional change.
2012-10-21 09:12:02 +02:00
Marco Costalba 55bd27b8f0 Contempt factor: use DrawValue also in case of stealmates
Spotted by Jörg Oster.

No functional change (when contempt factor is not used).
2012-10-20 11:02:37 +02:00
Marco Costalba 1018474853 Fix compatibility with old Windows 95 and 98
Report and patches by bnemias.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2012-10-20 10:48:26 +02:00
Marco Costalba c11edd3b0b Merge pull request #33 from daylen/master
Further improve OS X compatibility

Change the minimum supported version from 10.6 to 10.0

No functional change.
2012-10-20 01:07:27 -07:00
Daylen Yang f0298862f5 Further improve compatibility when compiling on OS X
Change the minimum supported version from 10.6 to 10.0
2012-10-16 00:13:16 -07:00
Marco Costalba 739d23f2a3 Fix Makefile for PowerPC with prefetch enabled
Existing Makefile is buggy for PowerPC, it has no
SSE, yet it is given it if Prefetch is enabled,
because it isn't ARMv7.

Patch from Matthew Brades.

No functional change.
2012-10-15 01:13:41 +02:00
Marco Costalba 3aa2d6db18 Document why is safe ttValue == VALUE_NONE
We can have ttValue == VALUE_NONE when we use a TT
slot to just save a position static evaluation, but
in this case we also save DEPTH_NONE so to avoid
using the ttValue in search. This happens to work,
but due to a number of lucky and tricky cases that
we now documnet through a bunch of asserts and a
little change to value_from_tt() that has no real
effect but clarifing the code.

No functional change.
2012-10-14 12:47:16 +02:00
Marco Costalba 6a75291ab1 Set TT size to 32 MB during 'bench'
On some platforms 128 MB of RAM for TT is too much,
so run 'bench' with the default 32 MB size.

No functional change although of course now 'bench'
reports a different number: 5545018
2012-10-14 09:02:17 +02:00
Marco Costalba eb1a4f11fa Move all Contempt Factor code to search.cpp
Where it is used.

No functional change.
2012-10-13 14:49:01 +02:00
Marco Costalba d023be5a21 Retire BitCount8Bit[] table
Use popcount() instead in the only calling place.
It is used only at initialization so there is no
speed regression and anyhow even initialization
itself is not slowed down: magic bitboard setup
stays around 175 msec on my slow 32bit Core Duo.

No functional change.
2012-10-13 14:24:01 +02:00
Marco Costalba c2cd75843e Use new 64 bit De Bruijn BitScan
Allows to sync 32 and 64 bits implementations.

Idea by Kim Walisch, reported by Gerd Isenberg:
http://talkchess.com/forum/viewtopic.php?t=45554

No functional change.
2012-10-13 13:45:45 +02:00
Marco Costalba 189b6fc270 Retire can_return_tt() and rewirte TT-hit code
Simplify the code and doing this introduce a couple
of (very small) functional changes:

- Always compare to depth even in "mate value" condition
- TT cut-off in qsearch also in case of PvNode, as in search

Verified against regression with 2500 games at 30"+0.05
on 2 threads: 451 - 444 - 1602

Functional changed: new bench is 5544977
2012-10-13 11:45:14 +02:00
Marco Costalba 6c8663341e Scale contempt factor to zero at endgame
Contempt Factor is more effective at opening/middle game
and seems harmful at endgame phase. See:

http://chessprogramming.wikispaces.com/Contempt+Factor

http://web.archive.org/web/20070707023203/www.brucemo.com/compchess/programming/contempt.htm

Therefore we scale down the contempt factor while going
on with the game so to reach zero at endgame phase.

No functional change.
2012-10-13 10:40:38 +02:00
Marco Costalba aba152ea3a Fix a minor bug in search
As Joona says: "The problem is that when doing full
window search (-VALUE_INFINITE, VALUE_INFINITE), and
pruning all the moves will return fail low which is
mate score, because only clause touching alpha is
"mate distance pruning". So we are returning mate score
although we are just pruning all the moves. In reality
there probably is no mate in sight.

Bug spotted and fixed by Joona.
2012-10-11 21:12:43 +02:00
Jean-Francois Romang 7f9ebf8e86 ARM lsb/msb assembly
Implement lsb/msb using armv7 assembly instructions.
msb is the easiest one, using a gcc intrinsic that generates
code using the ARM's clz instruction. lsb is also using this
clz instruction, but with the help of ARM's 'rbit' (bit
reversing) instruction. This leads to a >2% speed gain.

I also renamed 'arm-32' to the more meaningfull 'armv7' in the Makefile

No functional change.
2012-10-11 21:01:52 +02:00
Jean-Francois Romang 4e7da9be3d Introduce arm-32 ARCH in Makefile
No functional change.
2012-10-11 07:34:48 +02:00
Marco Costalba 46c01b5083 Retire is_dangerous() and inline its content
No functional change.
2012-10-10 08:13:36 +02:00
Marco Costalba dae843d4d6 Rearrange prefetch code
No functional change.
2012-10-08 11:43:47 +02:00
Marco Costalba 78fe0cfb8d Merge pull request #29 from RyanTaker/patch-3
Add Contempt Factor to Polyglot.ini
2012-10-07 15:36:08 -07:00
RyanTaker d77d555c72 Add Contempt Factor in Polyglot
The contempt factor was previously not included in polyglot.ini
2012-10-07 09:49:55 -07:00
Marco Costalba bbaef048cd Sync qsearch with search
Port to qsearch() the same changes we recently
added to search().

Overall this search refactoring series shows
almost 2% speed up on gcc compile.

No functional change.
2012-10-07 13:15:41 +02:00
Daylen Yang 7e2d49368d Improve compatibility with older versions of Mac OS X
Use the -mmacosx-version-min flag to support older versions of Mac OS X
(like version 10.6 and 10.7) when compiled on a machine running version
10.8.
2012-10-06 17:56:12 -07:00
Marco Costalba 954fc950d9 Fix POPCNT support on mingw 64
When using asm 'popcnt' instruction the given
operand registers must be of the same type.

No functional change.
2012-10-06 13:01:44 +02:00
Marco Costalba d777c4d789 Fix mingw compile with ARCH=x86-64
When using the Makefile (as for the mingw case),
IS_64BIT and USE_BSFQ are already set with
ARCH=x86-64 and do not need to be redefined.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2012-10-06 12:34:09 +02:00
Marco Costalba cedbd3332a Fix Contempt Factor implementation
First disable Contempt Factor during analysis, then
calculate the modified draw score from the point of
view of the player, so from the point of view of
RootPosition color.

Thanks to Ryan Taker for suggesting the fixes.

No functional change.
2012-10-06 10:12:34 +02:00
Marco Costalba ff9ca3e76e Fix fallouts from previous patch
These kind of arch specific code is really nasty
to make it right becuase you need to verify on
all the platforms.

Now should compile properly also on ARM

Reported by Jean-Francois.

No functional change.
2012-10-06 09:09:27 +02:00
Jean-Francois Romang b8948e84b8 Allow prefetching on non-x86 platforms with gcc
In particular on ARM processors. Original patch by
Jean-Francois, sligtly modified by me to preserve
the meaning of NO_PREFETCH flag.

Verified with gcc, clang and icc that prefetch instruction
is correctly created.

No functional change.
2012-10-06 00:43:16 +02:00
Marco Costalba 1ac417edb8 Retire futility_move_count()
And remove (bestValue < beta) condition from
moves loop.

No functional change.
2012-10-05 18:24:38 +02:00
Marco Costalba d471c49700 Rewrite search best value update
A simplification and also a small speed-up of
about 1% mainly due to reducing calls to
thisThread->cutoff_occurred().

Worst case split point recovering time after a
cut-off occurred is limited to 3 msec on my slow
PC, and usually is below 1 msec, so it seems safe
to remove the cutoff_occurred() check.

No functional change.
2012-10-05 13:53:05 +02:00
Marco Costalba c9f9262a49 Add experimental contempt factor
This is very crude and very basic: simply in case
of a draw for repetition or 50 moves rule return
a negative score instead of zero according to the
contempt factor (in centipawns). If contempt is
positive engine will try to avoid draws (to use
with weaker opponents), if negative engine will
try to draw. If zero (default) there are no changes.

No functional change.
2012-10-05 08:28:23 +02:00
Marco Costalba bd7a0d4ce4 Retire EasyMoveMargin
Use a value related to PawnValue instead.

This is a different patch from previous one because
could affect game play and skill levels, although
in a mostly unmeasurable way. Indeed thresold has
been raised so easy move is a bit harder to trigger
and skill level is a bit more prone to blunders.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2012-10-03 18:59:24 +02:00
Marco Costalba 561eb34aea Don't hide thresolds values
Show the real value in the code, not hide it
behind a variable name, especially when there
is only once occurence.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2012-10-03 18:56:36 +02:00
Marco Costalba 4c91dbc28e Further push singular extension
Extend for an extra half-ply in case the node is (probably)
going to fail high. In this case the added overhead is limited.

A novelity is the way this patch has been tested: Always in
self-play but with a much longer TC to allow the singular
extension to fully kick in and also (my impression) to have
less noisy results.

Ater 1015 games on my QUAD at 60"+0.05
Mod vs Orig 173 - 150 - 692 ELO +8
2012-10-02 06:39:27 +02:00
Marco Costalba 1b6b711c44 Further rearrange search()
No functional change.
2012-10-01 10:44:04 +02:00
Marco Costalba faaa1f1116 Don't push on the stack 200KB in one go
This could be a limit on some platforms (as it seems
to be in Native Client). Patch from a SF fork on github:

https://github.com/ccherng/Stockfish/commit/47374afd6fdfabd9de183a7a67d645daad45fb21

No functional change.
2012-09-30 11:35:14 +02:00
Marco Costalba ed0fb0b05f Add support for node limited search
Handle also the SMP case. This has been quite tricky, not
trivial to enforce the node limit in SMP case becuase
with "helpful master" concept we can have recursive split
points and we cannot lock them all at once so there is the
risk of counting the same nodes more than once.

Anyhow this patch should be race free and counted nodes are
correct.

No functional change.
2012-09-30 10:19:22 +02:00
Marco Costalba e5463eb3ae Skip some useless initializations in search()
And rearrange a bit the initialization code. Still
some polishing to do, but it is a first step.

No functional change.
2012-09-29 23:12:39 +02:00
Marco Costalba d53c928261 Don't need to early check PV moves for legality
As long as isPvMove (renamed to pvMove) is set after
legality check, we can postpone legality even in PV case.

Patch aligns the PV case with the common non-pv one.

No functional change.
2012-09-29 18:05:49 +02:00
Marco Costalba bc8f5fe0bf Drop a magic in book.cpp
Mask out move's spacial flags without relying
on internal Move representation.

No functional change.
2012-09-22 11:19:10 +02:00
Marco Costalba 9204a60dbb Tweaks to bitcount functions
Seems even a bit faster now (almost 1% in 32bit case).

No functional change.
2012-09-22 10:59:33 +02:00
Marco Costalba 1cb2722c95 Restore development version 2012-09-22 00:37:18 +02:00
Marco Costalba 3caeabf73b Stockfish 2.3.1
Stockfish bench signature is: 5423738
2012-09-22 00:20:44 +02:00
Gary Linscott fdbe8006e0 Bonus for rook/queen attacking pawns on same rank
Patch and tuning by Gary Linscott from an idea of Ryan Taker.

Double tested by Gary:

Wins: 3390 Losses: 2972 Draws: 11323
LOS: 99.999992%
ELO: 8.213465 +- 99%: 6.746506 95%: 5.124415
Win%: 51.181792 +- 99%: 0.969791 95%: 0.736740

And by me:

After 5612 games 1255  1085  3271 +11 ELO
2012-09-21 23:25:13 +02:00
Marco Costalba 09acdac56b Fix compile on 64 bits
Reported by Quocvuong82.

No functional change.
2012-09-20 19:25:27 +02:00
Marco Costalba e4a0482e43 Simplify BSFTable initialization
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2012-09-19 20:47:53 +02:00
Marco Costalba 22a5f91aa7 Fix crash under Chess 960
We have a crash with this position:

rkqbnnbr/pppppppp/8/8/8/8/PPPPPPPP/RKQBNNBR w HAha -

What happens is that even if we are castling QUEEN_SIDE,
in this case we have kfrom (B8) < kto (C8) so the loop
that checks for attackers runs forever leading to a crash.

The fix is to check for (kto > kfrom) instead of
Side == KING_SIDE, but this is slower in the normal case of
ortodhox chess, so rewrite generate_castle() to handle the
chess960 case as a template parameter and allow the compiler
to optimize out the comparison in case of normal chess.

Reported by Ray Banks.
2012-09-16 14:14:55 +02:00
Marco Costalba 9ce7469846 Rename class Book to PolyglotBook
And move struct BookEntry out of the header where it is
not needed.

No functional change.
2012-09-16 10:32:57 +02:00
Marco Costalba 4b7dbb3922 Fix KpsK endgame
Broken by commit a44c5cf4f7 of 3 /12 / 2011 that
was labeled "No functional change" because our 'bench'
test didn't triggered that particular endgame. Indeed
we need to run a specific bench on a set of endgames
position when touching endgame.cpp because normal bench
does not cover endgames properly.

Found by MSVC 2012 code analyzer.
2012-09-16 08:57:26 +02:00
Marco Costalba e0035e9ca9 Restore development version
No functional change.
2012-09-15 11:02:08 +02:00
51 changed files with 8073 additions and 7666 deletions
+64
View File
@@ -0,0 +1,64 @@
# Generated with git shortlog -sn | cut -c8-', which sorts by commits (manually moved Tord to top)
Tord Romstad
Marco Costalba
Joona Kiiski
Gary Linscott
Lucas Braesch
Reuven Peleg
Chris Caino
homoSapiensSapiens
Jean-Francois Romang
jundery
Arjun Temurnikar
Uri Blass
Ralph Stößer
Stefan Geschwentner
Tom Vijlbrief
Daylen Yang
Henri Wiechers
Leonid Pechenik
mstembera
Eelco de Groot
Jerry Donald
Jörg Oster
Ryan Schmitt
mcostalba
Alexander Kure
Dan Schmidt
H. Felix Wittmann
Justin Blanchard
Linus Arver
RyanTaker
ceebo
Joseph H Ellis
Stephane Nicolet
Ajith
Andy Duplain
Auguste Pop
Balint Pfliegel
Chris Cain
Dariusz Orzechowski
Gregor Cramer
Hiraoka Takuya
Hongzhi Cheng
Jonathan Calovski
Joseph R. Prostko
Kelly Wilson
Kojirion
Matt Sullivan
Matthew Sullivan
Michel Van den Bergh
Mysseno
Pablo Vazquez
Raminder Singh
Richard Lloyd
Ron Britvich
Ronald de Man
Ryan Takker
Thanar2
kinderchocolate
pellanda
renouve
shane31
thaspel
+112
View File
@@ -0,0 +1,112 @@
### Overview
Stockfish is a free UCI chess engine derived from Glaurung 2.1. It is
not a complete chess program and requires some UCI-compatible GUI
(e.g. XBoard with PolyGlot, eboard, Arena, Sigma Chess, Shredder, Chess
Partner or Fritz) in order to be used comfortably. Read the
documentation for your GUI of choice for information about how to use
Stockfish with it.
This version of Stockfish supports up to 128 cores. The engine defaults
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
cores on your computer.
This version of Stockfish has support for Syzygybases.
### Files
This distribution of Stockfish consists of the following files:
* Readme.md, the file you are currently reading.
* Copying.txt, a text file containing the GNU General Public License.
* src, a subdirectory containing the full source code, including a Makefile
that can be used to compile Stockfish on Unix-like systems.
### Syzygybases
**Configuration**
Syzygybases are configured using the UCI options "SyzygyPath",
"SyzygyProbeDepth", "Syzygy50MoveRule" and "SyzygyProbeLimit".
The option "SyzygyPath" should be set to the directory or directories that
contain the .rtbw and .rtbz files. Multiple directories should be
separated by ";" on Windows and by ":" on Unix-based operating systems.
**Do not use spaces around the ";" or ":".**
Example: `C:\tablebases\wdl345;C:\tablebases\wdl6;D:\tablebases\dtz345;D:\tablebases\dtz6`
It is recommended to store .rtbw files on an SSD. There is no loss in
storing the .rtbz files on a regular HD.
Increasing the "SyzygyProbeDepth" option lets the engine probe less
aggressively. Set this option to a higher value if you experience too much
slowdown (in terms of nps) due to TB probing.
Set the "Syzygy50MoveRule" option to false if you want tablebase positions
that are drawn by the 50-move rule to count as win or loss. This may be useful
for correspondence games (because of tablebase adjudication).
The "SyzygyProbeLimit" option should normally be left at its default value.
**What to expect**
If the engine is searching a position that is not in the tablebases (e.g.
a position with 7 pieces), it will access the tablebases during the search.
If the engine reports a very large score (typically 123.xx), this means
that it has found a winning line into a tablebase position.
If the engine is given a position to search that is in the tablebases, it
will use the tablebases at the beginning of the search to preselect all
good moves, i.e. all moves that preserve the win or preserve the draw while
taking into account the 50-move rule.
It will then perform a search only on those moves. **The engine will not move
immediately**, unless there is only a single good move. **The engine likely
will not report a mate score even if the position is known to be won.**
It is therefore clear that behaviour is not identical to what one might
be used to with Nalimov tablebases. There are technical reasons for this
difference, the main technical reason being that Nalimov tablebases use the
DTM metric (distance-to-mate), while Syzygybases use a variation of the
DTZ metric (distance-to-zero, zero meaning any move that resets the 50-move
counter). This special metric is one of the reasons that Syzygybases are
more compact than Nalimov tablebases, while still storing all information
needed for optimal play and in addition being able to take into account
the 50-move rule.
### Compiling it yourself
On Unix-like systems, it should be possible to compile Stockfish
directly from the source code with the included Makefile.
Stockfish has support for 32 or 64-bit CPUs, the hardware POPCNT
instruction, big-endian machines such as Power PC, and other platforms.
In general it is recommended to run `make help` to see a list of make
targets with corresponding descriptions. When not using the Makefile to
compile (for instance with Microsoft MSVC) you need to manually
set/unset some switches in the compiler command line; see file *types.h*
for a quick reference.
### Terms of use
Stockfish is free, and distributed under the **GNU General Public License**
(GPL). Essentially, this means that you are free to do almost exactly
what you want with the program, including distributing it among your
friends, making it available for download from your web site, selling
it (either by itself or as part of some bigger software package), or
using it as the starting point for a software project of your own.
The only real limitation is that whenever you distribute Stockfish in
some way, you must always include the full source code, or a pointer
to where the source code can be found. If you make any changes to the
source code, these changes must also be made available under the GPL.
For full details, read the copy of the GPL found in the file named
*Copying.txt*
-81
View File
@@ -1,81 +0,0 @@
1. Introduction
---------------
Stockfish is a free UCI chess engine derived from Glaurung 2.1. It is
not a complete chess program and requires some UCI-compatible GUI
(e.g. XBoard with PolyGlot, eboard, Arena, Sigma Chess, Shredder, Chess
Partner or Fritz) in order to be used comfortably. Read the
documentation for your GUI of choice for information about how to use
Stockfish with it.
This version of Stockfish supports up to 32 CPUs, but has not been
tested thoroughly with more than 4. The program tries to detect the
number of CPUs on your computer and sets the number of search threads
accordingly, but please be aware that the detection is not always
correct. It is therefore recommended to inspect the value of the
"Threads" UCI parameter, and to make sure it equals the number of CPU
cores on your computer. If you are using more than eight threads, it is
recommended to raise the value of the "Min Split Depth" UCI parameter to
7.
2. Files
--------
This distribution of Stockfish consists of the following files:
* Readme.txt, the file you are currently reading.
* Copying.txt, a text file containing the GNU General Public License.
* src/, a subdirectory containing the full source code, including a
Makefile that can be used to compile Stockfish on Unix-like systems.
For further information about how to compile Stockfish yourself read
section 4 below.
* polyglot.ini, for using Stockfish with Fabien Letouzey's PolyGlot
adapter.
3. Opening books
----------------
This version of Stockfish has support for PolyGlot opening books. For
information about how to create such books, consult the PolyGlot
documentation. The book file can be selected by setting the "Book File"
UCI parameter.
4. Compiling it yourself
------------------------
On Unix-like systems, it should be possible to compile Stockfish
directly from the source code with the included Makefile.
Stockfish has support for 32 or 64-bit CPUs, the hardware POPCNT
instruction, big-endian machines such as Power PC, and other platforms.
In general it is recommended to run 'make help' to see a list of make
targets with corresponding descriptions. When not using Makefile to
compile (for instance with Microsoft MSVC) you need to manually
set/unset some switches in the compiler command line; see file "types.h"
for a quick reference.
5. Terms of use
---------------
Stockfish is free, and distributed under the GNU General Public License
(GPL). Essentially, this means that you are free to do almost exactly
what you want with the program, including distributing it among your
friends, making it available for download from your web site, selling
it (either by itself or as part of some bigger software package), or
using it as the starting point for a software project of your own.
The only real limitation is that whenever you distribute Stockfish in
some way, you must always include the full source code, or a pointer
to where the source code can be found. If you make any changes to the
source code, these changes must also be made available under the GPL.
For full details, read the copy of the GPL found in the file named
Copying.txt.
-43
View File
@@ -1,43 +0,0 @@
[PolyGlot]
EngineDir = .
EngineCommand = ./stockfish
Book = false
BookFile = book.bin
Log = false
LogFile = stockfish.log
Resign = true
ResignScore = 600
[Engine]
Use Search Log = false
Search Log Filename = SearchLog.txt
Book File = book.bin
Best Book Move = false
Mobility (Middle Game) = 100
Mobility (Endgame) = 100
Passed Pawns (Middle Game) = 100
Passed Pawns (Endgame) = 100
Space = 100
Aggressiveness = 100
Cowardice = 100
Min Split Depth = 4
Max Threads per Split Point = 5
Threads = 1
Use Sleeping Threads = false
Hash = 128
Ponder = true
OwnBook = false
MultiPV = 1
Skill Level = 20
Emergency Move Horizon = 40
Emergency Base Time = 200
Emergency Move Time = 70
Minimum Thinking Time = 20
UCI_Chess960 = false
UCI_AnalyseMode = false
+166 -193
View File
@@ -1,6 +1,6 @@
# 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-2012 Marco Costalba, Joona Kiiski, Tord Romstad # Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, 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
@@ -28,19 +28,15 @@ EXE = stockfish
### Installation dir definitions ### Installation dir definitions
PREFIX = /usr/local PREFIX = /usr/local
# Haiku has a non-standard filesystem layout
ifeq ($(UNAME),Haiku)
PREFIX=/boot/common
endif
BINDIR = $(PREFIX)/bin BINDIR = $(PREFIX)/bin
### Built-in benchmark for pgo-builds ### Built-in benchmark for pgo-builds
PGOBENCH = ./$(EXE) bench 32 1 10 default depth PGOBENCH = ./$(EXE) bench 16 1 1000 default time
### Object files ### Object files
OBJS = benchmark.o bitbase.o bitboard.o book.o endgame.o evaluate.o main.o \ OBJS = benchmark.o bitbase.o bitboard.o endgame.o evaluate.o main.o \
material.o misc.o movegen.o movepick.o notation.o pawns.o position.o \ material.o misc.o movegen.o movepick.o pawns.o position.o \
search.o thread.o timeman.o tt.o uci.o ucioption.o search.o thread.o timeman.o tt.o uci.o ucioption.o syzygy/tbprobe.o
### ========================================================================== ### ==========================================================================
### Section 2. High-level Configuration ### Section 2. High-level Configuration
@@ -52,114 +48,89 @@ OBJS = benchmark.o bitbase.o bitboard.o book.o endgame.o evaluate.o main.o \
# debug = yes/no --- -DNDEBUG --- Enable/Disable debug mode # debug = yes/no --- -DNDEBUG --- Enable/Disable debug mode
# 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
# os = (name) --- --- Target operating system
# bits = 64/32 --- -DIS_64BIT --- 64-/32-bit operating system # bits = 64/32 --- -DIS_64BIT --- 64-/32-bit operating system
# prefetch = yes/no --- -DUSE_PREFETCH --- Use prefetch x86 asm-instruction # prefetch = yes/no --- -DUSE_PREFETCH --- Use prefetch x86 asm-instruction
# bsfq = yes/no --- -DUSE_BSFQ --- Use bsfq x86_64 asm-instruction (only # bsfq = yes/no --- -DUSE_BSFQ --- Use bsfq x86_64 asm-instruction (only
# with GCC and ICC 64-bit) # with GCC and ICC 64-bit)
# popcnt = yes/no --- -DUSE_POPCNT --- Use popcnt x86_64 asm-instruction # popcnt = yes/no --- -DUSE_POPCNT --- Use popcnt x86_64 asm-instruction
# sse = yes/no --- -msse --- Use Intel Streaming SIMD Extensions
# pext = yes/no --- -DUSE_PEXT --- Use pext x86_64 asm-instruction
# #
# Note that Makefile is space sensitive, so when adding new architectures # Note that Makefile is space sensitive, so when adding new architectures
# or modifying existing flags, you have to make sure there are no extra spaces # or modifying existing flags, you have to make sure there are no extra spaces
# at the end of the line for flag values. # at the end of the line for flag values.
### 2.1. General ### 2.1. General and architecture defaults
debug = no
optimize = yes optimize = yes
debug = no
bits = 32
prefetch = no
bsfq = no
popcnt = no
sse = no
pext = no
### 2.2 Architecture specific ### 2.2 Architecture specific
# General-section
ifeq ($(ARCH),general-64)
arch = any
os = any
bits = 64
prefetch = no
bsfq = no
popcnt = no
endif
ifeq ($(ARCH),general-32) ifeq ($(ARCH),general-32)
arch = any arch = any
os = any
bits = 32
prefetch = no
bsfq = no
popcnt = no
endif
# x86-section
ifeq ($(ARCH),x86-64)
arch = x86_64
os = any
bits = 64
prefetch = yes
bsfq = yes
popcnt = no
endif
ifeq ($(ARCH),x86-64-modern)
arch = x86_64
os = any
bits = 64
prefetch = yes
bsfq = yes
popcnt = yes
endif
ifeq ($(ARCH),x86-32)
arch = i386
os = any
bits = 32
prefetch = yes
bsfq = no
popcnt = no
endif endif
ifeq ($(ARCH),x86-32-old) ifeq ($(ARCH),x86-32-old)
arch = i386 arch = i386
os = any
bits = 32
prefetch = no
bsfq = no
popcnt = no
endif endif
# osx-section ifeq ($(ARCH),x86-32)
ifeq ($(ARCH),osx-ppc-64) arch = i386
arch = ppc64 prefetch = yes
os = osx sse = yes
endif
ifeq ($(ARCH),general-64)
arch = any
bits = 64 bits = 64
prefetch = no
bsfq = no
popcnt = no
endif endif
ifeq ($(ARCH),osx-ppc-32) ifeq ($(ARCH),x86-64)
arch = ppc
os = osx
bits = 32
prefetch = no
bsfq = no
popcnt = no
endif
ifeq ($(ARCH),osx-x86-64)
arch = x86_64 arch = x86_64
os = osx
bits = 64 bits = 64
prefetch = yes prefetch = yes
bsfq = yes bsfq = yes
popcnt = no sse = yes
endif endif
ifeq ($(ARCH),osx-x86-32) ifeq ($(ARCH),x86-64-modern)
arch = i386 arch = x86_64
os = osx bits = 64
bits = 32
prefetch = yes prefetch = yes
bsfq = no bsfq = yes
popcnt = no popcnt = yes
sse = yes
endif
ifeq ($(ARCH),x86-64-bmi2)
arch = x86_64
bits = 64
prefetch = yes
bsfq = yes
popcnt = yes
sse = yes
pext = yes
endif
ifeq ($(ARCH),armv7)
arch = armv7
prefetch = yes
bsfq = yes
endif
ifeq ($(ARCH),ppc-32)
arch = ppc
endif
ifeq ($(ARCH),ppc-64)
arch = ppc64
bits = 64
endif endif
@@ -168,87 +139,72 @@ endif
### ========================================================================== ### ==========================================================================
### 3.1 Selecting compiler (default = gcc) ### 3.1 Selecting compiler (default = gcc)
CXXFLAGS += -Wall -Wcast-qual -fno-exceptions -fno-rtti $(EXTRACXXFLAGS)
LDFLAGS += $(EXTRALDFLAGS)
ifeq ($(COMP),) ifeq ($(COMP),)
COMP=gcc COMP=gcc
endif endif
ifeq ($(COMP),mingw)
comp=mingw
CXX=g++
profile_prepare = gcc-profile-prepare
profile_make = gcc-profile-make
profile_use = gcc-profile-use
profile_clean = gcc-profile-clean
endif
ifeq ($(COMP),gcc) ifeq ($(COMP),gcc)
comp=gcc comp=gcc
CXX=g++ CXX=g++
profile_prepare = gcc-profile-prepare CXXFLAGS += -ansi -pedantic -Wno-long-long -Wextra -Wshadow
profile_make = gcc-profile-make endif
profile_use = gcc-profile-use
profile_clean = gcc-profile-clean ifeq ($(COMP),mingw)
comp=mingw
CXX=g++
CXXFLAGS += -Wextra -Wshadow
LDFLAGS += -static-libstdc++ -static-libgcc
endif endif
ifeq ($(COMP),icc) ifeq ($(COMP),icc)
comp=icc comp=icc
CXX=icpc CXX=icpc
profile_prepare = icc-profile-prepare CXXFLAGS += -diag-disable 1476,10120 -Wcheck -Wabi -Wdeprecated -strict-ansi
profile_make = icc-profile-make
profile_use = icc-profile-use
profile_clean = icc-profile-clean
endif endif
ifeq ($(COMP),clang) ifeq ($(COMP),clang)
comp=clang comp=clang
CXX=clang++ CXX=clang++
CXXFLAGS += -pedantic -Wno-long-long -Wextra -Wshadow
endif
ifeq ($(comp),icc)
profile_prepare = icc-profile-prepare
profile_make = icc-profile-make
profile_use = icc-profile-use
profile_clean = icc-profile-clean
else
profile_prepare = gcc-profile-prepare profile_prepare = gcc-profile-prepare
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 profile_clean = gcc-profile-clean
endif endif
### 3.2 General compiler settings ifeq ($(UNAME),Darwin)
CXXFLAGS = -g -Wall -Wcast-qual -fno-exceptions -fno-rtti $(EXTRACXXFLAGS) CXXFLAGS += -arch $(arch) -mmacosx-version-min=10.6
LDFLAGS += -arch $(arch) -mmacosx-version-min=10.6
ifeq ($(comp),gcc)
CXXFLAGS += -ansi -pedantic -Wno-long-long -Wextra -Wshadow
endif endif
ifeq ($(comp),mingw)
CXXFLAGS += -Wextra -Wshadow
endif
ifeq ($(comp),icc)
CXXFLAGS += -wd383,981,1418,1419,10187,10188,11505,11503 -Wcheck -Wabi -Wdeprecated -strict-ansi
endif
ifeq ($(comp),clang)
CXXFLAGS += -ansi -pedantic -Wno-long-long -Wextra -Wshadow
endif
ifeq ($(os),osx)
CXXFLAGS += -arch $(arch)
endif
### 3.3 General linker settings
LDFLAGS = $(EXTRALDFLAGS)
### On mingw use Windows threads, otherwise POSIX ### On mingw use Windows threads, otherwise POSIX
ifneq ($(comp),mingw) ifneq ($(comp),mingw)
# Haiku has pthreads in its libroot, so only link it in on other platforms # On Android Bionic's C library comes with its own pthread implementation bundled in
ifneq ($(UNAME),Haiku) ifneq ($(arch),armv7)
LDFLAGS += -lpthread # Haiku has pthreads in its libroot, so only link it in on other platforms
ifneq ($(UNAME),Haiku)
LDFLAGS += -lpthread
endif
endif endif
endif endif
ifeq ($(os),osx)
LDFLAGS += -arch $(arch)
endif
### 3.4 Debugging ### 3.4 Debugging
ifeq ($(debug),no) ifeq ($(debug),no)
CXXFLAGS += -DNDEBUG CXXFLAGS += -DNDEBUG
else
CXXFLAGS += -g
endif endif
### 3.5 Optimization ### 3.5 Optimization
@@ -257,7 +213,7 @@ ifeq ($(optimize),yes)
ifeq ($(comp),gcc) ifeq ($(comp),gcc)
CXXFLAGS += -O3 CXXFLAGS += -O3
ifeq ($(os),osx) ifeq ($(UNAME),Darwin)
ifeq ($(arch),i386) ifeq ($(arch),i386)
CXXFLAGS += -mdynamic-no-pic CXXFLAGS += -mdynamic-no-pic
endif endif
@@ -265,6 +221,10 @@ ifeq ($(optimize),yes)
CXXFLAGS += -mdynamic-no-pic CXXFLAGS += -mdynamic-no-pic
endif endif
endif endif
ifeq ($(arch),armv7)
CXXFLAGS += -fno-gcse -mthumb -march=armv7-a -mfloat-abi=softfp
endif
endif endif
ifeq ($(comp),mingw) ifeq ($(comp),mingw)
@@ -272,18 +232,21 @@ ifeq ($(optimize),yes)
endif endif
ifeq ($(comp),icc) ifeq ($(comp),icc)
ifeq ($(os),osx) ifeq ($(UNAME),Darwin)
CXXFLAGS += -fast -mdynamic-no-pic CXXFLAGS += -fast -mdynamic-no-pic
else else
CXXFLAGS += -O3 CXXFLAGS += -fast
endif endif
endif endif
ifeq ($(comp),clang) ifeq ($(comp),clang)
### -O4 requires a linker that supports LLVM's LTO
CXXFLAGS += -O3 CXXFLAGS += -O3
ifeq ($(os),osx) ifeq ($(UNAME),Darwin)
ifeq ($(pext),no)
CXXFLAGS += -flto
LDFLAGS += $(CXXFLAGS)
endif
ifeq ($(arch),i386) ifeq ($(arch),i386)
CXXFLAGS += -mdynamic-no-pic CXXFLAGS += -mdynamic-no-pic
endif endif
@@ -301,8 +264,10 @@ endif
### 3.7 prefetch ### 3.7 prefetch
ifeq ($(prefetch),yes) ifeq ($(prefetch),yes)
CXXFLAGS += -msse ifeq ($(sse),yes)
DEPENDFLAGS += -msse CXXFLAGS += -msse
DEPENDFLAGS += -msse
endif
else else
CXXFLAGS += -DNO_PREFETCH CXXFLAGS += -DNO_PREFETCH
endif endif
@@ -314,14 +279,27 @@ endif
### 3.9 popcnt ### 3.9 popcnt
ifeq ($(popcnt),yes) ifeq ($(popcnt),yes)
CXXFLAGS += -msse3 -DUSE_POPCNT ifeq ($(comp),icc)
CXXFLAGS += -msse3 -DUSE_POPCNT
else
CXXFLAGS += -msse3 -mpopcnt -DUSE_POPCNT
endif
endif endif
### 3.10 Link Time Optimization, it works since gcc 4.5 but not on mingw. ### 3.10 pext
ifeq ($(pext),yes)
CXXFLAGS += -DUSE_PEXT
ifeq ($(comp),$(filter $(comp),gcc clang mingw))
CXXFLAGS += -mbmi -mbmi2
endif
endif
### 3.11 Link Time Optimization, it works since gcc 4.5 but not on mingw.
### This is a mix of compile and link time options because the lto link phase ### This is a mix of compile and link time options because the lto link phase
### needs access to the optimization flags. ### needs access to the optimization flags.
ifeq ($(comp),gcc) ifeq ($(comp),gcc)
ifeq ($(optimize),yes) ifeq ($(optimize),yes)
ifeq ($(debug),no)
GCC_MAJOR := `$(CXX) -dumpversion | cut -f1 -d.` GCC_MAJOR := `$(CXX) -dumpversion | cut -f1 -d.`
GCC_MINOR := `$(CXX) -dumpversion | cut -f2 -d.` GCC_MINOR := `$(CXX) -dumpversion | cut -f2 -d.`
ifeq (1,$(shell expr \( $(GCC_MAJOR) \> 4 \) \| \( $(GCC_MAJOR) \= 4 \& $(GCC_MINOR) \>= 5 \))) ifeq (1,$(shell expr \( $(GCC_MAJOR) \> 4 \) \| \( $(GCC_MAJOR) \= 4 \& $(GCC_MINOR) \>= 5 \)))
@@ -329,8 +307,17 @@ ifeq ($(comp),gcc)
LDFLAGS += $(CXXFLAGS) LDFLAGS += $(CXXFLAGS)
endif endif
endif endif
endif
endif endif
### 3.12 Android 5 can only run position independent executables. Note that this
### breaks Android 4.0 and earlier.
ifeq ($(arch),armv7)
CXXFLAGS += -fPIE
LDFLAGS += -fPIE -pie
endif
### ========================================================================== ### ==========================================================================
### Section 4. Public targets ### Section 4. Public targets
### ========================================================================== ### ==========================================================================
@@ -343,43 +330,39 @@ help:
@echo "" @echo ""
@echo "Supported targets:" @echo "Supported targets:"
@echo "" @echo ""
@echo "build > Build unoptimized version" @echo "build > Standard build"
@echo "profile-build > Build PGO-optimized version" @echo "profile-build > PGO build"
@echo "strip > Strip executable" @echo "strip > Strip executable"
@echo "install > Install executable" @echo "install > Install executable"
@echo "clean > Clean up" @echo "clean > Clean up"
@echo "testrun > Make sample run"
@echo "" @echo ""
@echo "Supported archs:" @echo "Supported archs:"
@echo "" @echo ""
@echo "x86-64 > x86 64-bit" @echo "x86-64 > x86 64-bit"
@echo "x86-64-modern > x86 64-bit with runtime support for popcnt instruction" @echo "x86-64-modern > x86 64-bit with popcnt support"
@echo "x86-32 > x86 32-bit excluding old hardware without SSE-support" @echo "x86-64-bmi2 > x86 64-bit with pext support"
@echo "x86-32-old > x86 32-bit including also very old hardware" @echo "x86-32 > x86 32-bit with SSE support"
@echo "osx-ppc-64 > PPC-Mac OS X 64 bit" @echo "x86-32-old > x86 32-bit fall back for old hardware"
@echo "osx-ppc-32 > PPC-Mac OS X 32 bit" @echo "ppc-64 > PPC 64-bit"
@echo "osx-x86-64 > x86-Mac OS X 64 bit" @echo "ppc-32 > PPC 32-bit"
@echo "osx-x86-32 > x86-Mac OS X 32 bit" @echo "armv7 > ARMv7 32-bit"
@echo "general-64 > unspecified 64-bit" @echo "general-64 > unspecified 64-bit"
@echo "general-32 > unspecified 32-bit" @echo "general-32 > unspecified 32-bit"
@echo "" @echo ""
@echo "Supported comps:" @echo "Supported compilers:"
@echo "" @echo ""
@echo "gcc > Gnu compiler (default)" @echo "gcc > Gnu compiler (default)"
@echo "icc > Intel compiler" @echo "mingw > Gnu compiler with MinGW under Windows"
@echo "mingw > Gnu compiler with MinGW under Windows" @echo "clang > LLVM Clang compiler"
@echo "clang > LLVM Clang compiler" @echo "icc > Intel compiler"
@echo ""
@echo "Non-standard targets:"
@echo ""
@echo "make hpux > Compile for HP-UX. Compiler = aCC"
@echo "" @echo ""
@echo "Examples. If you don't know what to do, you likely want to run: " @echo "Examples. If you don't know what to do, you likely want to run: "
@echo "" @echo ""
@echo "make profile-build ARCH=x86-64 (This is for 64-bit systems)" @echo "make build ARCH=x86-64 (This is for 64-bit systems)"
@echo "make profile-build ARCH=x86-32 (This is for 32-bit systems)" @echo "make build ARCH=x86-32 (This is for 32-bit systems)"
@echo "" @echo ""
.PHONY: build profile-build
build: build:
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) config-sanity $(MAKE) ARCH=$(ARCH) COMP=$(COMP) config-sanity
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) all $(MAKE) ARCH=$(ARCH) COMP=$(COMP) all
@@ -391,14 +374,14 @@ profile-build:
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_prepare) $(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_prepare)
@echo "" @echo ""
@echo "Step 1/4. Building executable for benchmark ..." @echo "Step 1/4. Building executable for benchmark ..."
@touch *.cpp *.h @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 final executable ..."
@touch *.cpp @touch *.cpp *.h syzygy/*.cpp syzygy/*.h
$(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 ..."
@@ -413,10 +396,7 @@ install:
-strip $(BINDIR)/$(EXE) -strip $(BINDIR)/$(EXE)
clean: clean:
$(RM) $(EXE) $(EXE).exe *.o .depend *~ core bench.txt *.gcda $(RM) $(EXE) $(EXE).exe *.o .depend *~ core bench.txt *.gcda ./syzygy/*.o ./syzygy/*.gcda
testrun:
@$(PGOBENCH)
default: default:
help help
@@ -433,11 +413,12 @@ config-sanity:
@echo "debug: '$(debug)'" @echo "debug: '$(debug)'"
@echo "optimize: '$(optimize)'" @echo "optimize: '$(optimize)'"
@echo "arch: '$(arch)'" @echo "arch: '$(arch)'"
@echo "os: '$(os)'"
@echo "bits: '$(bits)'" @echo "bits: '$(bits)'"
@echo "prefetch: '$(prefetch)'" @echo "prefetch: '$(prefetch)'"
@echo "bsfq: '$(bsfq)'" @echo "bsfq: '$(bsfq)'"
@echo "popcnt: '$(popcnt)'" @echo "popcnt: '$(popcnt)'"
@echo "sse: '$(sse)'"
@echo "pext: '$(pext)'"
@echo "" @echo ""
@echo "Flags:" @echo "Flags:"
@echo "CXX: $(CXX)" @echo "CXX: $(CXX)"
@@ -449,12 +430,13 @@ config-sanity:
@test "$(debug)" = "yes" || test "$(debug)" = "no" @test "$(debug)" = "yes" || test "$(debug)" = "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)" = "ppc64" || test "$(arch)" = "ppc" || test "$(arch)" = "armv7"
@test "$(os)" = "any" || test "$(os)" = "osx"
@test "$(bits)" = "32" || test "$(bits)" = "64" @test "$(bits)" = "32" || test "$(bits)" = "64"
@test "$(prefetch)" = "yes" || test "$(prefetch)" = "no" @test "$(prefetch)" = "yes" || test "$(prefetch)" = "no"
@test "$(bsfq)" = "yes" || test "$(bsfq)" = "no" @test "$(bsfq)" = "yes" || test "$(bsfq)" = "no"
@test "$(popcnt)" = "yes" || test "$(popcnt)" = "no" @test "$(popcnt)" = "yes" || test "$(popcnt)" = "no"
@test "$(sse)" = "yes" || test "$(sse)" = "no"
@test "$(pext)" = "yes" || test "$(pext)" = "no"
@test "$(comp)" = "gcc" || test "$(comp)" = "icc" || test "$(comp)" = "mingw" || test "$(comp)" = "clang" @test "$(comp)" = "gcc" || test "$(comp)" = "icc" || test "$(comp)" = "mingw" || test "$(comp)" = "clang"
$(EXE): $(OBJS) $(EXE): $(OBJS)
@@ -465,18 +447,21 @@ gcc-profile-prepare:
gcc-profile-make: gcc-profile-make:
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \ $(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
EXTRACXXFLAGS='-fprofile-generate' \ EXTRACXXFLAGS='-fprofile-arcs' \
EXTRALDFLAGS='-lgcov' \ EXTRALDFLAGS='-lgcov' \
all all
gcc-profile-use: gcc-profile-use:
# Deleting corrupt ucioption.gc* profile files is necessary to avoid an
# "internal compiler error" for gcc versions 4.7.x
@rm -f ucioption.gc*
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \ $(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
EXTRACXXFLAGS='-fprofile-use' \ EXTRACXXFLAGS='-fbranch-probabilities' \
EXTRALDFLAGS='-lgcov' \ EXTRALDFLAGS='-lgcov' \
all all
gcc-profile-clean: gcc-profile-clean:
@rm -rf *.gcda *.gcno bench.txt @rm -rf *.gcda *.gcno syzygy/*.gcda syzygy/*.gcno bench.txt
icc-profile-prepare: icc-profile-prepare:
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) icc-profile-clean $(MAKE) ARCH=$(ARCH) COMP=$(COMP) icc-profile-clean
@@ -500,15 +485,3 @@ icc-profile-clean:
-include .depend -include .depend
### ==========================================================================
### Section 6. Non-standard targets
### ==========================================================================
hpux:
$(MAKE) \
CXX='/opt/aCC/bin/aCC -AA +hpxstd98 -mt +O3 -DNDEBUG -DNO_PREFETCH' \
CXXFLAGS="" \
LDFLAGS="" \
all
+58 -25
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-2012 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, 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
@@ -17,6 +17,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 <algorithm>
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
#include <istream> #include <istream>
@@ -27,11 +28,13 @@
#include "search.h" #include "search.h"
#include "thread.h" #include "thread.h"
#include "tt.h" #include "tt.h"
#include "ucioption.h" #include "uci.h"
using namespace std; using namespace std;
static const char* Defaults[] = { namespace {
const char* Defaults[] = {
"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",
@@ -47,17 +50,45 @@ static const char* Defaults[] = {
"3r1rk1/p5pp/bpp1pp2/8/q1PP1P2/b3P3/P2NQRPP/1R2B1K1 b - - 6 22", "3r1rk1/p5pp/bpp1pp2/8/q1PP1P2/b3P3/P2NQRPP/1R2B1K1 b - - 6 22",
"r1q2rk1/2p1bppp/2Pp4/p6b/Q1PNp3/4B3/PP1R1PPP/2K4R w - - 2 18", "r1q2rk1/2p1bppp/2Pp4/p6b/Q1PNp3/4B3/PP1R1PPP/2K4R w - - 2 18",
"4k2r/1pb2ppp/1p2p3/1R1p4/3P4/2r1PN2/P4PPP/1R4K1 b - - 3 22", "4k2r/1pb2ppp/1p2p3/1R1p4/3P4/2r1PN2/P4PPP/1R4K1 b - - 3 22",
"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",
"3b4/5kp1/1p1p1p1p/pP1PpP1P/P1P1P3/3KN3/8/8 w - - 0 1",
"2K5/p7/7P/5pR1/8/5k2/r7/8 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",
"8/2p5/8/2kPKp1p/2p4P/2P5/3P4/8 w - - 0 1",
"8/1p3pp1/7p/5P1P/2k3P1/8/2K2P2/8 w - - 0 1",
"8/pp2r1k1/2p1p3/3pP2p/1P1P1P1P/P5KR/8/8 w - - 0 1",
"8/3p4/p1bk3p/Pp6/1Kp1PpPp/2P2P1P/2P5/5B2 b - - 0 1",
"5k2/7R/4P2p/5K2/p1r2P1p/8/8/8 b - - 0 1",
"6k1/6p1/P6p/r1N5/5p2/7P/1b3PP1/4R1K1 w - - 0 1",
"1r3k2/4q3/2Pp3b/3Bp3/2Q2p2/1p1P2P1/1P2KP2/3N4 w - - 0 1",
"6k1/4pp1p/3p2p1/P1pPb3/R7/1r2P1PP/3B1P2/6K1 w - - 0 1",
"8/3p3B/5p2/5P2/p7/PP5b/k7/6K1 w - - 0 1",
// 5-man positions
"8/8/8/8/5kp1/P7/8/1K1N4 w - - 0 1", // Kc2 - mate
"8/8/8/5N2/8/p7/8/2NK3k w - - 0 1", // Na2 - mate
"8/3k4/8/8/8/4B3/4KB2/2B5 w - - 0 1", // draw
// 6-man positions
"8/8/1P6/5pr1/8/4R3/7k/2K5 w - - 0 1", // Re5 - mate
"8/2p4P/8/kr6/6R1/8/8/1K6 w - - 0 1", // Ka2 - mate
"8/8/3P3k/8/1p6/8/1P6/1K3n2 b - - 0 1", // Nd2 - draw
// 7-man positions
"8/R7/2q5/8/6k1/8/1P5p/K6R w - - 0 124", // Draw
}; };
} // namespace
/// benchmark() runs a simple benchmark by letting Stockfish analyze a set /// benchmark() runs a simple benchmark by letting Stockfish analyze a set
/// of positions for a given limit each. There are five parameters; the /// of positions for a given limit each. There are five parameters: the
/// transposition table size, the number of search threads that should /// transposition table size, the number of search threads that should
/// be used, the limit value spent for each position (optional, default is /// be used, the limit value spent for each position (optional, default is
/// depth 12), an optional file name where to look for positions in fen /// depth 13), an optional file name where to look for positions in FEN
/// format (defaults are the positions defined above) and the type of the /// format (defaults are the positions defined above) and the type of the
/// limit value: depth (default), time in secs or number of nodes. /// limit value: depth (default), time in millisecs or number of nodes.
void benchmark(const Position& current, istream& is) { void benchmark(const Position& current, istream& is) {
@@ -66,9 +97,9 @@ void benchmark(const Position& current, istream& is) {
vector<string> fens; vector<string> fens;
// Assign default values to missing arguments // Assign default values to missing arguments
string ttSize = (is >> token) ? token : "128"; string ttSize = (is >> token) ? token : "16";
string threads = (is >> token) ? token : "1"; string threads = (is >> token) ? token : "1";
string limit = (is >> token) ? token : "12"; string limit = (is >> token) ? token : "13";
string fenFile = (is >> token) ? token : "default"; string fenFile = (is >> token) ? token : "default";
string limitType = (is >> token) ? token : "depth"; string limitType = (is >> token) ? token : "depth";
@@ -77,19 +108,22 @@ void benchmark(const Position& current, istream& is) {
TT.clear(); TT.clear();
if (limitType == "time") if (limitType == "time")
limits.movetime = 1000 * atoi(limit.c_str()); // movetime is in ms limits.movetime = atoi(limit.c_str()); // movetime is in ms
else if (limitType == "nodes") else if (limitType == "nodes")
limits.nodes = atoi(limit.c_str()); limits.nodes = atoi(limit.c_str());
else if (limitType == "mate")
limits.mate = atoi(limit.c_str());
else else
limits.depth = atoi(limit.c_str()); limits.depth = atoi(limit.c_str());
if (fenFile == "default") if (fenFile == "default")
fens.assign(Defaults, Defaults + 16); fens.assign(Defaults, Defaults + 37);
else if (fenFile == "current") else if (fenFile == "current")
fens.push_back(current.to_fen()); fens.push_back(current.fen());
else else
{ {
@@ -99,7 +133,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;
exit(EXIT_FAILURE); return;
} }
while (getline(file, fen)) while (getline(file, fen))
@@ -109,31 +143,30 @@ void benchmark(const Position& current, istream& is) {
file.close(); file.close();
} }
int64_t nodes = 0; uint64_t nodes = 0;
Search::StateStackPtr st; Search::StateStackPtr st;
Time::point elapsed = Time::now(); Time::point elapsed = Time::now();
for (size_t i = 0; i < fens.size(); i++) for (size_t i = 0; i < fens.size(); ++i)
{ {
Position pos(fens[i], Options["UCI_Chess960"], Threads.main_thread()); Position pos(fens[i], Options["UCI_Chess960"], Threads.main());
cerr << "\nPosition: " << i + 1 << '/' << fens.size() << endl; cerr << "\nPosition: " << i + 1 << '/' << fens.size() << endl;
if (limitType == "perft") if (limitType == "perft")
{ nodes += Search::perft<true>(pos, limits.depth * ONE_PLY);
size_t cnt = Search::perft(pos, limits.depth * ONE_PLY);
cerr << "\nPerft " << limits.depth << " leaf nodes: " << cnt << endl;
nodes += cnt;
}
else else
{ {
Threads.start_searching(pos, limits, vector<Move>(), st); Threads.start_thinking(pos, limits, st);
Threads.wait_for_search_finished(); Threads.wait_for_think_finished();
nodes += Search::RootPosition.nodes_searched(); nodes += Search::RootPos.nodes_searched();
} }
} }
elapsed = Time::now() - elapsed + 1; // Assure positive to avoid a 'divide by zero' elapsed = std::max(Time::now() - elapsed, Time::point(1)); // Avoid a 'divide by zero'
dbg_print(); // Just before to exit
cerr << "\n===========================" cerr << "\n==========================="
<< "\nTotal time (ms) : " << elapsed << "\nTotal time (ms) : " << elapsed
+97 -152
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-2012 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, 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,12 +18,32 @@
*/ */
#include <cassert> #include <cassert>
#include <vector>
#include "bitboard.h" #include "bitboard.h"
#include "types.h" #include "types.h"
namespace { namespace {
// There are 24 possible pawn squares: the first 4 files and ranks from 2 to 7
const unsigned MAX_INDEX = 2*24*64*64; // stm * psq * wksq * bksq = 196608
// Each uint32_t stores results of 32 positions, one per bit
uint32_t KPKBitbase[MAX_INDEX / 32];
// A KPK bitbase index is an integer in [0, IndexMax] range
//
// Information is mapped in a way that minimizes the number of iterations:
//
// bit 0- 5: white king square (from SQ_A1 to SQ_H8)
// bit 6-11: black king square (from SQ_A1 to SQ_H8)
// bit 12: side to move (WHITE or BLACK)
// bit 13-14: white pawn file (from FILE_A to FILE_D)
// bit 15-17: white pawn RANK_7 - rank (from RANK_7 - RANK_7 to RANK_7 - RANK_2)
unsigned index(Color us, Square bksq, Square wksq, Square psq) {
return wksq | (bksq << 6) | (us << 12) | (file_of(psq) << 13) | ((RANK_7 - rank_of(psq)) << 15);
}
enum Result { enum Result {
INVALID = 0, INVALID = 0,
UNKNOWN = 1, UNKNOWN = 1,
@@ -35,196 +55,121 @@ namespace {
struct KPKPosition { struct KPKPosition {
Result classify_leaf(int idx); KPKPosition(unsigned idx);
Result classify(int idx, Result db[]); operator Result() const { return result; }
Result classify(const std::vector<KPKPosition>& db)
{ return us == WHITE ? classify<WHITE>(db) : classify<BLACK>(db); }
private: private:
template<Color Us> Result classify(const Result db[]) const; template<Color Us> Result classify(const std::vector<KPKPosition>& db);
template<Color Us> Bitboard k_attacks() const { Color us;
return Us == WHITE ? StepAttacksBB[W_KING][wksq] : StepAttacksBB[B_KING][bksq]; Square bksq, wksq, psq;
} Result result;
Bitboard p_attacks() const { return StepAttacksBB[W_PAWN][psq]; }
void decode_index(int idx);
Square wksq, bksq, psq;
Color stm;
}; };
// The possible pawns squares are 24, the first 4 files and ranks from 2 to 7 } // namespace
const int IndexMax = 2 * 24 * 64 * 64; // stm * wp_sq * wk_sq * bk_sq = 196608
// Each uint32_t stores results of 32 positions, one per bit
uint32_t KPKBitbase[IndexMax / 32];
int index(Square wksq, Square bksq, Square psq, Color stm); bool Bitbases::probe(Square wksq, Square wpsq, Square bksq, Color us) {
assert(file_of(wpsq) <= FILE_D);
unsigned idx = index(us, bksq, wksq, wpsq);
return KPKBitbase[idx / 32] & (1 << (idx & 0x1F));
} }
uint32_t Bitbases::probe_kpk(Square wksq, Square wpsq, Square bksq, Color stm) { void Bitbases::init() {
int idx = index(wksq, bksq, wpsq, stm); unsigned idx, repeat = 1;
return KPKBitbase[idx / 32] & (1 << (idx & 31)); std::vector<KPKPosition> db;
} db.reserve(MAX_INDEX);
// Initialize db with known win / draw positions
for (idx = 0; idx < MAX_INDEX; ++idx)
db.push_back(KPKPosition(idx));
void Bitbases::init_kpk() { // Iterate through the positions until none of the unknown positions can be
// changed to either wins or draws (15 cycles needed).
Result db[IndexMax];
KPKPosition pos;
int idx, bit, repeat = 1;
// Initialize table with known win / draw positions
for (idx = 0; idx < IndexMax; idx++)
db[idx] = pos.classify_leaf(idx);
// Iterate until all positions are classified (30 cycles needed)
while (repeat) while (repeat)
for (repeat = idx = 0; idx < IndexMax; idx++) for (repeat = idx = 0; idx < MAX_INDEX; ++idx)
if (db[idx] == UNKNOWN && (db[idx] = pos.classify(idx, db)) != UNKNOWN) repeat |= (db[idx] == UNKNOWN && db[idx].classify(db) != UNKNOWN);
repeat = 1;
// Map 32 position results into one KPKBitbase[] entry // Map 32 results into one KPKBitbase[] entry
for (idx = 0; idx < IndexMax / 32; idx++) for (idx = 0; idx < MAX_INDEX; ++idx)
for (bit = 0; bit < 32; bit++) if (db[idx] == WIN)
if (db[32 * idx + bit] == WIN) KPKBitbase[idx / 32] |= 1 << (idx & 0x1F);
KPKBitbase[idx] |= 1 << bit;
} }
namespace { namespace {
// A KPK bitbase index is an integer in [0, IndexMax] range KPKPosition::KPKPosition(unsigned idx) {
//
// Information is mapped in this way
//
// bit 0: side to move (WHITE or BLACK)
// bit 1- 6: black king square (from SQ_A1 to SQ_H8)
// bit 7-12: white king square (from SQ_A1 to SQ_H8)
// bit 13-14: white pawn file (from FILE_A to FILE_D)
// bit 15-17: white pawn rank - 1 (from RANK_2 - 1 to RANK_7 - 1)
int index(Square w, Square b, Square p, Color c) { wksq = Square((idx >> 0) & 0x3F);
bksq = Square((idx >> 6) & 0x3F);
assert(file_of(p) <= FILE_D); us = Color ((idx >> 12) & 0x01);
psq = make_square(File((idx >> 13) & 0x3), RANK_7 - Rank((idx >> 15) & 0x7));
return c + (b << 1) + (w << 7) + (file_of(p) << 13) + ((rank_of(p) - 1) << 15); result = UNKNOWN;
}
void KPKPosition::decode_index(int idx) {
stm = Color(idx & 1);
bksq = Square((idx >> 1) & 63);
wksq = Square((idx >> 7) & 63);
psq = File((idx >> 13) & 3) | Rank((idx >> 15) + 1);
}
Result KPKPosition::classify_leaf(int idx) {
decode_index(idx);
// 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 ( wksq == psq || wksq == bksq || bksq == psq if ( distance(wksq, bksq) <= 1
|| (k_attacks<WHITE>() & bksq) || wksq == psq
|| (stm == WHITE && (p_attacks() & bksq))) || bksq == psq
return INVALID; || (us == WHITE && (StepAttacksBB[PAWN][psq] & bksq)))
result = INVALID;
// The position is an immediate win if it is white to move and the white else if (us == WHITE)
// pawn can be promoted without getting captured. {
if ( rank_of(psq) == RANK_7 // Immediate win if a pawn can be promoted without getting captured
&& stm == WHITE if ( rank_of(psq) == RANK_7
&& wksq != psq + DELTA_N && wksq != psq + DELTA_N
&& ( square_distance(bksq, psq + DELTA_N) > 1 && ( distance(bksq, psq + DELTA_N) > 1
||(k_attacks<WHITE>() & (psq + DELTA_N)))) ||(StepAttacksBB[KING][wksq] & (psq + DELTA_N))))
return WIN; result = WIN;
}
// Check for known draw positions // Immediate draw if it is a stalemate or a king captures undefended pawn
// else if ( !(StepAttacksBB[KING][bksq] & ~(StepAttacksBB[KING][wksq] | StepAttacksBB[PAWN][psq]))
// Case 1: Stalemate || (StepAttacksBB[KING][bksq] & psq & ~StepAttacksBB[KING][wksq]))
if ( stm == BLACK result = DRAW;
&& !(k_attacks<BLACK>() & ~(k_attacks<WHITE>() | p_attacks())))
return DRAW;
// Case 2: King can capture undefended pawn
if ( stm == BLACK
&& (k_attacks<BLACK>() & psq & ~k_attacks<WHITE>()))
return DRAW;
// Case 3: Black king in front of white pawn
if ( bksq == psq + DELTA_N
&& rank_of(psq) < RANK_7)
return DRAW;
// Case 4: White king in front of pawn and black has opposition
if ( stm == WHITE
&& wksq == psq + DELTA_N
&& bksq == wksq + DELTA_N + DELTA_N
&& rank_of(psq) < RANK_5)
return DRAW;
// Case 5: Stalemate with rook pawn
if ( bksq == SQ_A8
&& file_of(psq) == FILE_A)
return DRAW;
// Case 6: White king trapped on the rook file
if ( file_of(wksq) == FILE_A
&& file_of(psq) == FILE_A
&& rank_of(wksq) > rank_of(psq)
&& bksq == wksq + 2)
return DRAW;
return UNKNOWN;
} }
template<Color Us> template<Color Us>
Result KPKPosition::classify(const Result db[]) const { Result KPKPosition::classify(const std::vector<KPKPosition>& db) {
// White to Move: If one move leads to a position classified as RESULT_WIN, // White to Move: If one move leads to a position classified as WIN, the result
// the result of the current position is RESULT_WIN. If all moves lead to // of the current position is WIN. If all moves lead to positions classified
// positions classified as RESULT_DRAW, the current position is classified // as DRAW, the current position is classified as DRAW, otherwise the current
// RESULT_DRAW otherwise the current position is classified as RESULT_UNKNOWN. // position is classified as UNKNOWN.
// //
// Black to Move: If one move leads to a position classified as RESULT_DRAW, // Black to Move: If one move leads to a position classified as DRAW, the result
// the result of the current position is RESULT_DRAW. If all moves lead to // of the current position is DRAW. If all moves lead to positions classified
// positions classified as RESULT_WIN, the position is classified RESULT_WIN. // as WIN, the position is classified as WIN, otherwise the current position is
// Otherwise, the current position is classified as RESULT_UNKNOWN. // classified as UNKNOWN.
const Color Them = (Us == WHITE ? BLACK : WHITE);
Result r = INVALID; Result r = INVALID;
Bitboard b = k_attacks<Us>(); Bitboard b = StepAttacksBB[KING][Us == WHITE ? wksq : bksq];
while (b) while (b)
{ r |= Us == WHITE ? db[index(Them, bksq, pop_lsb(&b), psq)]
r |= Us == WHITE ? db[index(pop_lsb(&b), bksq, psq, BLACK)] : db[index(Them, pop_lsb(&b), wksq, psq)];
: db[index(wksq, pop_lsb(&b), psq, WHITE)];
if (Us == WHITE && (r & WIN))
return WIN;
if (Us == BLACK && (r & DRAW))
return DRAW;
}
if (Us == WHITE && rank_of(psq) < RANK_7) if (Us == WHITE && rank_of(psq) < RANK_7)
{ {
Square s = psq + DELTA_N; Square s = psq + DELTA_N;
r |= db[index(wksq, bksq, s, BLACK)]; // Single push r |= db[index(BLACK, bksq, wksq, s)]; // Single push
if (rank_of(s) == RANK_3 && s != wksq && s != bksq) if (rank_of(psq) == RANK_2 && s != wksq && s != bksq)
r |= db[index(wksq, bksq, s + DELTA_N, BLACK)]; // Double push r |= db[index(BLACK, bksq, wksq, s + DELTA_N)]; // Double push
if (r & WIN)
return WIN;
} }
return r & UNKNOWN ? UNKNOWN : Us == WHITE ? DRAW : WIN; if (Us == WHITE)
return result = r & WIN ? WIN : r & UNKNOWN ? UNKNOWN : DRAW;
else
return result = r & DRAW ? DRAW : r & UNKNOWN ? UNKNOWN : WIN;
} }
Result KPKPosition::classify(int idx, Result db[]) { } // namespace
decode_index(idx);
return stm == WHITE ? classify<WHITE>(db) : classify<BLACK>(db);
}
}
+129 -171
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-2012 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, 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,88 +18,70 @@
*/ */
#include <algorithm> #include <algorithm>
#include <cstring> #include <cstring> // For std::memset
#include <iostream>
#include "bitboard.h" #include "bitboard.h"
#include "bitcount.h" #include "bitcount.h"
#include "misc.h" #include "misc.h"
#include "rkiss.h"
CACHE_LINE_ALIGNMENT int SquareDistance[SQUARE_NB][SQUARE_NB];
Bitboard RMasks[64]; Bitboard RookMasks [SQUARE_NB];
Bitboard RMagics[64]; Bitboard RookMagics [SQUARE_NB];
Bitboard* RAttacks[64]; Bitboard* RookAttacks[SQUARE_NB];
unsigned RShifts[64]; unsigned RookShifts [SQUARE_NB];
Bitboard BMasks[64]; Bitboard BishopMasks [SQUARE_NB];
Bitboard BMagics[64]; Bitboard BishopMagics [SQUARE_NB];
Bitboard* BAttacks[64]; Bitboard* BishopAttacks[SQUARE_NB];
unsigned BShifts[64]; unsigned BishopShifts [SQUARE_NB];
Bitboard SquareBB[64]; Bitboard SquareBB[SQUARE_NB];
Bitboard FileBB[8]; Bitboard FileBB[FILE_NB];
Bitboard RankBB[8]; Bitboard RankBB[RANK_NB];
Bitboard AdjacentFilesBB[8]; Bitboard AdjacentFilesBB[FILE_NB];
Bitboard ThisAndAdjacentFilesBB[8]; Bitboard InFrontBB[COLOR_NB][RANK_NB];
Bitboard InFrontBB[2][8]; Bitboard StepAttacksBB[PIECE_NB][SQUARE_NB];
Bitboard StepAttacksBB[16][64]; Bitboard BetweenBB[SQUARE_NB][SQUARE_NB];
Bitboard BetweenBB[64][64]; Bitboard LineBB[SQUARE_NB][SQUARE_NB];
Bitboard DistanceRingsBB[64][8]; Bitboard DistanceRingBB[SQUARE_NB][8];
Bitboard ForwardBB[2][64]; Bitboard ForwardBB[COLOR_NB][SQUARE_NB];
Bitboard PassedPawnMask[2][64]; Bitboard PassedPawnMask[COLOR_NB][SQUARE_NB];
Bitboard AttackSpanMask[2][64]; Bitboard PawnAttackSpan[COLOR_NB][SQUARE_NB];
Bitboard PseudoAttacks[6][64]; Bitboard PseudoAttacks[PIECE_TYPE_NB][SQUARE_NB];
int SquareDistance[64][64];
namespace { namespace {
// De Bruijn sequences. See chessprogramming.wikispaces.com/BitScan // De Bruijn sequences. See chessprogramming.wikispaces.com/BitScan
const uint64_t DeBruijn_64 = 0x218A392CD3D5DBFULL; const uint64_t DeBruijn64 = 0x3F79D71B4CB0A89ULL;
const uint32_t DeBruijn_32 = 0x783A9B23; const uint32_t DeBruijn32 = 0x783A9B23;
CACHE_LINE_ALIGNMENT int MS1BTable[256]; // To implement software msb()
Square BSFTable[SQUARE_NB]; // To implement software bitscan
int BSFTable[64]; Bitboard RookTable[0x19000]; // To store rook attacks
int MS1BTable[256]; Bitboard BishopTable[0x1480]; // To store bishop attacks
Bitboard RTable[0x19000]; // Storage space for rook attacks
Bitboard BTable[0x1480]; // Storage space for bishop attacks
uint8_t BitCount8Bit[256];
typedef unsigned (Fn)(Square, Bitboard); typedef unsigned (Fn)(Square, Bitboard);
void init_magics(Bitboard table[], Bitboard* attacks[], Bitboard magics[], void init_magics(Bitboard table[], Bitboard* attacks[], Bitboard magics[],
Bitboard masks[], unsigned shifts[], Square deltas[], Fn index); Bitboard masks[], unsigned shifts[], Square deltas[], Fn index);
// 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.
FORCE_INLINE unsigned bsf_index(Bitboard b) {
b ^= b - 1;
return Is64Bit ? (b * DeBruijn64) >> 58
: ((unsigned(b) ^ unsigned(b >> 32)) * DeBruijn32) >> 26;
}
} }
/// lsb()/msb() finds the least/most significant bit in a nonzero bitboard. #ifndef USE_BSFQ
/// pop_lsb() finds and clears the least significant bit in a nonzero bitboard.
#if !defined(USE_BSFQ) /// Software fall-back of lsb() and msb() for CPU lacking hardware support
Square lsb(Bitboard b) { Square lsb(Bitboard b) {
return BSFTable[bsf_index(b)];
if (Is64Bit)
return Square(BSFTable[((b & -b) * DeBruijn_64) >> 58]);
b ^= (b - 1);
uint32_t fold = unsigned(b) ^ unsigned(b >> 32);
return Square(BSFTable[(fold * DeBruijn_32) >> 26]);
}
Square pop_lsb(Bitboard* b) {
Bitboard bb = *b;
*b = bb & (bb - 1);
if (Is64Bit)
return Square(BSFTable[((bb & -bb) * DeBruijn_64) >> 58]);
bb ^= (bb - 1);
uint32_t fold = unsigned(bb) ^ unsigned(bb >> 32);
return Square(BSFTable[(fold * DeBruijn_32) >> 26]);
} }
Square msb(Bitboard b) { Square msb(Bitboard b) {
@@ -130,126 +112,107 @@ Square msb(Bitboard b) {
return Square(result + MS1BTable[b32]); return Square(result + MS1BTable[b32]);
} }
#endif // !defined(USE_BSFQ) #endif // ifndef USE_BSFQ
/// Bitboards::print() prints a bitboard in an easily readable format to the /// Bitboards::pretty() returns an ASCII representation of a bitboard suitable
/// standard output. This is sometimes useful for debugging. /// to be printed to standard output. Useful for debugging.
void Bitboards::print(Bitboard b) { const std::string Bitboards::pretty(Bitboard b) {
sync_cout; std::string s = "+---+---+---+---+---+---+---+---+\n";
for (Rank rank = RANK_8; rank >= RANK_1; rank--) for (Rank r = RANK_8; r >= RANK_1; --r)
{ {
std::cout << "+---+---+---+---+---+---+---+---+" << '\n'; for (File f = FILE_A; f <= FILE_H; ++f)
s.append(b & make_square(f, r) ? "| X " : "| ");
for (File file = FILE_A; file <= FILE_H; file++) s.append("|\n+---+---+---+---+---+---+---+---+\n");
std::cout << "| " << (b & (file | rank) ? "X " : " ");
std::cout << "|\n";
} }
std::cout << "+---+---+---+---+---+---+---+---+" << sync_endl;
return s;
} }
/// Bitboards::init() initializes various bitboard arrays. It is called during /// Bitboards::init() initializes various bitboard tables. It is called at
/// program initialization. /// startup and relies on global objects to be already zero-initialized.
void Bitboards::init() { void Bitboards::init() {
for (int k = 0, i = 0; i < 8; i++) for (Square s = SQ_A1; s <= SQ_H8; ++s)
while (k < (2 << i)) {
MS1BTable[k++] = i;
for (Bitboard b = 0; b < 256; b++)
BitCount8Bit[b] = (uint8_t)popcount<Max15>(b);
for (Square s = SQ_A1; s <= SQ_H8; s++)
SquareBB[s] = 1ULL << s; SquareBB[s] = 1ULL << s;
BSFTable[bsf_index(SquareBB[s])] = s;
FileBB[FILE_A] = FileABB;
RankBB[RANK_1] = Rank1BB;
for (int i = 1; i < 8; i++)
{
FileBB[i] = FileBB[i - 1] << 1;
RankBB[i] = RankBB[i - 1] << 8;
} }
for (File f = FILE_A; f <= FILE_H; f++) for (Bitboard b = 1; b < 256; ++b)
{ MS1BTable[b] = more_than_one(b) ? MS1BTable[b - 1] : lsb(b);
for (File f = FILE_A; f <= FILE_H; ++f)
FileBB[f] = f > FILE_A ? FileBB[f - 1] << 1 : FileABB;
for (Rank r = RANK_1; r <= RANK_8; ++r)
RankBB[r] = r > RANK_1 ? RankBB[r - 1] << 8 : Rank1BB;
for (File f = FILE_A; f <= FILE_H; ++f)
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);
ThisAndAdjacentFilesBB[f] = FileBB[f] | AdjacentFilesBB[f];
}
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]); InFrontBB[WHITE][r] = ~(InFrontBB[BLACK][r + 1] = InFrontBB[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)]; ForwardBB[c][s] = InFrontBB[c][rank_of(s)] & FileBB[file_of(s)];
PassedPawnMask[c][s] = InFrontBB[c][rank_of(s)] & ThisAndAdjacentFilesBB[file_of(s)]; PawnAttackSpan[c][s] = InFrontBB[c][rank_of(s)] & AdjacentFilesBB[file_of(s)];
AttackSpanMask[c][s] = InFrontBB[c][rank_of(s)] & AdjacentFilesBB[file_of(s)]; PassedPawnMask[c][s] = ForwardBB[c][s] | PawnAttackSpan[c][s];
} }
for (Square s1 = SQ_A1; s1 <= SQ_H8; s1++) for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1)
for (Square s2 = SQ_A1; s2 <= SQ_H8; s2++) for (Square s2 = SQ_A1; s2 <= SQ_H8; ++s2)
SquareDistance[s1][s2] = std::max(file_distance(s1, s2), rank_distance(s1, s2)); if (s1 != s2)
{
for (Square s1 = SQ_A1; s1 <= SQ_H8; s1++) SquareDistance[s1][s2] = std::max(distance<File>(s1, s2), distance<Rank>(s1, s2));
for (int d = 1; d < 8; d++) DistanceRingBB[s1][SquareDistance[s1][s2] - 1] |= s2;
for (Square s2 = SQ_A1; s2 <= SQ_H8; s2++) }
if (SquareDistance[s1][s2] == d)
DistanceRingsBB[s1][d - 1] |= s2;
for (int i = 0; i < 64; i++)
if (!Is64Bit) // Matt Taylor's folding trick for 32 bit systems
{
Bitboard b = 1ULL << i;
b ^= b - 1;
b ^= b >> 32;
BSFTable[(uint32_t)(b * DeBruijn_32) >> 26] = i;
}
else
BSFTable[((1ULL << i) * DeBruijn_64) >> 58] = i;
int steps[][9] = { {}, { 7, 9 }, { 17, 15, 10, 6, -6, -10, -15, -17 }, int steps[][9] = { {}, { 7, 9 }, { 17, 15, 10, 6, -6, -10, -15, -17 },
{}, {}, {}, { 9, 7, -7, -9, 8, 1, -1, -8 } }; {}, {}, {}, { 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; pt <= KING; ++pt)
for (Square s = SQ_A1; s <= SQ_H8; s++) for (Square s = SQ_A1; s <= SQ_H8; ++s)
for (int k = 0; steps[pt][k]; k++) for (int i = 0; steps[pt][i]; ++i)
{ {
Square to = s + Square(c == WHITE ? steps[pt][k] : -steps[pt][k]); Square to = s + Square(c == WHITE ? steps[pt][i] : -steps[pt][i]);
if (is_ok(to) && square_distance(s, to) < 3) if (is_ok(to) && distance(s, to) < 3)
StepAttacksBB[make_piece(c, pt)][s] |= to; StepAttacksBB[make_piece(c, pt)][s] |= to;
} }
Square RDeltas[] = { DELTA_N, DELTA_E, DELTA_S, DELTA_W }; Square RookDeltas[] = { DELTA_N, DELTA_E, DELTA_S, DELTA_W };
Square BDeltas[] = { DELTA_NE, DELTA_SE, DELTA_SW, DELTA_NW }; Square BishopDeltas[] = { DELTA_NE, DELTA_SE, DELTA_SW, DELTA_NW };
init_magics(RTable, RAttacks, RMagics, RMasks, RShifts, RDeltas, magic_index<ROOK>); init_magics(RookTable, RookAttacks, RookMagics, RookMasks, RookShifts, RookDeltas, magic_index<ROOK>);
init_magics(BTable, BAttacks, BMagics, BMasks, BShifts, BDeltas, magic_index<BISHOP>); init_magics(BishopTable, BishopAttacks, BishopMagics, BishopMasks, BishopShifts, BishopDeltas, magic_index<BISHOP>);
for (Square s = SQ_A1; s <= SQ_H8; s++) for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1)
{ {
PseudoAttacks[QUEEN][s] = PseudoAttacks[BISHOP][s] = attacks_bb<BISHOP>(s, 0); PseudoAttacks[QUEEN][s1] = PseudoAttacks[BISHOP][s1] = attacks_bb<BISHOP>(s1, 0);
PseudoAttacks[QUEEN][s] |= PseudoAttacks[ ROOK][s] = attacks_bb< ROOK>(s, 0); PseudoAttacks[QUEEN][s1] |= PseudoAttacks[ ROOK][s1] = attacks_bb< ROOK>(s1, 0);
for (Square s2 = SQ_A1; s2 <= SQ_H8; ++s2)
{
Piece pc = (PseudoAttacks[BISHOP][s1] & s2) ? W_BISHOP :
(PseudoAttacks[ROOK][s1] & s2) ? W_ROOK : NO_PIECE;
if (pc == NO_PIECE)
continue;
LineBB[s1][s2] = (attacks_bb(pc, s1, 0) & attacks_bb(pc, s2, 0)) | s1 | s2;
BetweenBB[s1][s2] = attacks_bb(pc, s1, SquareBB[s2]) & attacks_bb(pc, s2, SquareBB[s1]);
}
} }
for (Square s1 = SQ_A1; s1 <= SQ_H8; s1++)
for (Square s2 = SQ_A1; s2 <= SQ_H8; s2++)
if (PseudoAttacks[QUEEN][s1] & s2)
{
Square delta = (s2 - s1) / square_distance(s1, s2);
for (Square s = s1 + delta; s != s2; s += delta)
BetweenBB[s1][s2] |= s;
}
} }
@@ -259,9 +222,9 @@ namespace {
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 + deltas[i];
is_ok(s) && square_distance(s, s - deltas[i]) == 1; is_ok(s) && distance(s, s - deltas[i]) == 1;
s += deltas[i]) s += deltas[i])
{ {
attack |= s; attack |= s;
@@ -274,20 +237,6 @@ namespace {
} }
Bitboard pick_random(RKISS& rk, int booster) {
// Values s1 and s2 are used to rotate the candidate magic of a
// quantity known to be the optimal to quickly find the magics.
int s1 = booster & 63, s2 = (booster >> 6) & 63;
Bitboard m = rk.rand<Bitboard>();
m = (m >> s1) | (m << (64 - s1));
m &= rk.rand<Bitboard>();
m = (m >> s2) | (m << (64 - s2));
return m & rk.rand<Bitboard>();
}
// init_magics() computes all rook and bishop attacks at startup. Magic // init_magics() computes all rook and bishop attacks at startup. Magic
// bitboards are used to look up attacks of sliding pieces. As a reference see // bitboards are used to look up attacks of sliding pieces. As a reference see
// chessprogramming.wikispaces.com/Magic+Bitboards. In particular, here we // chessprogramming.wikispaces.com/Magic+Bitboards. In particular, here we
@@ -296,16 +245,16 @@ namespace {
void init_magics(Bitboard table[], Bitboard* attacks[], Bitboard magics[], void init_magics(Bitboard table[], Bitboard* attacks[], Bitboard magics[],
Bitboard masks[], unsigned shifts[], Square deltas[], Fn index) { Bitboard masks[], unsigned shifts[], Square deltas[], Fn index) {
int MagicBoosters[][8] = { { 3191, 2184, 1310, 3618, 2091, 1308, 2452, 3996 }, int seeds[][RANK_NB] = { { 8977, 44560, 54343, 38998, 5731, 95205, 104912, 17020 },
{ 1059, 3608, 605, 3234, 3326, 38, 2029, 3043 } }; { 728, 10316, 55013, 32803, 12281, 15100, 16645, 255 } };
RKISS rk;
Bitboard occupancy[4096], reference[4096], edges, b; Bitboard occupancy[4096], reference[4096], edges, b;
int i, size, booster; int i, size;
// attacks[s] is a pointer to the beginning of the attacks table for square 's' // attacks[s] is a pointer to the beginning of the attacks table for square 's'
attacks[SQ_A1] = table; attacks[SQ_A1] = table;
for (Square s = SQ_A1; s <= SQ_H8; s++) for (Square s = SQ_A1; s <= SQ_H8; ++s)
{ {
// Board edges are not considered in the relevant occupancies // Board edges are not considered in the relevant occupancies
edges = ((Rank1BB | Rank8BB) & ~rank_bb(s)) | ((FileABB | FileHBB) & ~file_bb(s)); edges = ((Rank1BB | Rank8BB) & ~rank_bb(s)) | ((FileABB | FileHBB) & ~file_bb(s));
@@ -323,7 +272,12 @@ namespace {
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(deltas, s, b);
if (HasPext)
attacks[s][pext(b, masks[s])] = reference[size];
size++;
b = (b - masks[s]) & masks[s]; b = (b - masks[s]) & masks[s];
} while (b); } while (b);
@@ -332,32 +286,36 @@ namespace {
if (s < SQ_H8) if (s < SQ_H8)
attacks[s + 1] = attacks[s] + size; attacks[s + 1] = attacks[s] + size;
booster = MagicBoosters[Is64Bit][rank_of(s)]; if (HasPext)
continue;
PRNG rng(seeds[Is64Bit][rank_of(s)]);
// 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 { do {
do magics[s] = pick_random(rk, booster); do
while (BitCount8Bit[(magics[s] * masks[s]) >> 56] < 6); magics[s] = rng.sparse_rand<Bitboard>();
while (popcount<Max15>((magics[s] * masks[s]) >> 56) < 6);
memset(attacks[s], 0, size * sizeof(Bitboard)); std::memset(attacks[s], 0, size * sizeof(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.
for (i = 0; i < size; i++) for (i = 0; i < size; ++i)
{ {
Bitboard& attack = attacks[s][index(s, occupancy[i])]; Bitboard& attack = attacks[s][index(s, occupancy[i])];
if (attack && attack != reference[i]) if (attack && attack != reference[i])
break; break;
assert(reference[i] != 0); assert(reference[i]);
attack = reference[i]; attack = reference[i];
} }
} while (i != size); } while (i < size);
} }
} }
} }
+193 -133
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-2012 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, 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,50 +18,72 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#if !defined(BITBOARD_H_INCLUDED) #ifndef BITBOARD_H_INCLUDED
#define BITBOARD_H_INCLUDED #define BITBOARD_H_INCLUDED
#include <string>
#include "types.h" #include "types.h"
namespace Bitbases {
void init();
bool probe(Square wksq, Square wpsq, Square bksq, Color us);
}
namespace Bitboards { namespace Bitboards {
void init(); void init();
void print(Bitboard b); const std::string pretty(Bitboard b);
} }
namespace Bitbases { const Bitboard DarkSquares = 0xAA55AA55AA55AA55ULL;
void init_kpk(); const Bitboard FileABB = 0x0101010101010101ULL;
uint32_t probe_kpk(Square wksq, Square wpsq, Square bksq, Color stm); const Bitboard FileBBB = FileABB << 1;
const Bitboard FileCBB = FileABB << 2;
const Bitboard FileDBB = FileABB << 3;
const Bitboard FileEBB = FileABB << 4;
const Bitboard FileFBB = FileABB << 5;
const Bitboard FileGBB = FileABB << 6;
const Bitboard FileHBB = FileABB << 7;
} const Bitboard Rank1BB = 0xFF;
const Bitboard Rank2BB = Rank1BB << (8 * 1);
const Bitboard Rank3BB = Rank1BB << (8 * 2);
const Bitboard Rank4BB = Rank1BB << (8 * 3);
const Bitboard Rank5BB = Rank1BB << (8 * 4);
const Bitboard Rank6BB = Rank1BB << (8 * 5);
const Bitboard Rank7BB = Rank1BB << (8 * 6);
const Bitboard Rank8BB = Rank1BB << (8 * 7);
CACHE_LINE_ALIGNMENT extern int SquareDistance[SQUARE_NB][SQUARE_NB];
extern Bitboard RMasks[64]; extern Bitboard RookMasks [SQUARE_NB];
extern Bitboard RMagics[64]; extern Bitboard RookMagics [SQUARE_NB];
extern Bitboard* RAttacks[64]; extern Bitboard* RookAttacks[SQUARE_NB];
extern unsigned RShifts[64]; extern unsigned RookShifts [SQUARE_NB];
extern Bitboard BMasks[64]; extern Bitboard BishopMasks [SQUARE_NB];
extern Bitboard BMagics[64]; extern Bitboard BishopMagics [SQUARE_NB];
extern Bitboard* BAttacks[64]; extern Bitboard* BishopAttacks[SQUARE_NB];
extern unsigned BShifts[64]; extern unsigned BishopShifts [SQUARE_NB];
extern Bitboard SquareBB[64]; extern Bitboard SquareBB[SQUARE_NB];
extern Bitboard FileBB[8]; extern Bitboard FileBB[FILE_NB];
extern Bitboard RankBB[8]; extern Bitboard RankBB[RANK_NB];
extern Bitboard AdjacentFilesBB[8]; extern Bitboard AdjacentFilesBB[FILE_NB];
extern Bitboard ThisAndAdjacentFilesBB[8]; extern Bitboard InFrontBB[COLOR_NB][RANK_NB];
extern Bitboard InFrontBB[2][8]; extern Bitboard StepAttacksBB[PIECE_NB][SQUARE_NB];
extern Bitboard StepAttacksBB[16][64]; extern Bitboard BetweenBB[SQUARE_NB][SQUARE_NB];
extern Bitboard BetweenBB[64][64]; extern Bitboard LineBB[SQUARE_NB][SQUARE_NB];
extern Bitboard DistanceRingsBB[64][8]; extern Bitboard DistanceRingBB[SQUARE_NB][8];
extern Bitboard ForwardBB[2][64]; extern Bitboard ForwardBB[COLOR_NB][SQUARE_NB];
extern Bitboard PassedPawnMask[2][64]; extern Bitboard PassedPawnMask[COLOR_NB][SQUARE_NB];
extern Bitboard AttackSpanMask[2][64]; extern Bitboard PawnAttackSpan[COLOR_NB][SQUARE_NB];
extern Bitboard PseudoAttacks[6][64]; extern Bitboard PseudoAttacks[PIECE_TYPE_NB][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
@@ -71,14 +93,6 @@ inline Bitboard operator&(Bitboard b, Square s) {
return b & SquareBB[s]; return b & SquareBB[s];
} }
inline Bitboard& operator|=(Bitboard& b, Square s) {
return b |= SquareBB[s];
}
inline Bitboard& operator^=(Bitboard& b, Square s) {
return b ^= SquareBB[s];
}
inline Bitboard operator|(Bitboard b, Square s) { inline Bitboard operator|(Bitboard b, Square s) {
return b | SquareBB[s]; return b | SquareBB[s];
} }
@@ -87,16 +101,21 @@ inline Bitboard operator^(Bitboard b, Square s) {
return b ^ SquareBB[s]; return b ^ SquareBB[s];
} }
inline Bitboard& operator|=(Bitboard& b, Square s) {
return b |= SquareBB[s];
}
/// more_than_one() returns true if in 'b' there is more than one bit set inline Bitboard& operator^=(Bitboard& b, Square s) {
return b ^= SquareBB[s];
}
inline bool more_than_one(Bitboard b) { inline bool more_than_one(Bitboard b) {
return b & (b - 1); return b & (b - 1);
} }
/// rank_bb() and file_bb() take a file or a square as input and return /// rank_bb() and file_bb() return a bitboard representing all the squares on
/// a bitboard representing all squares on the given file or rank. /// the given file or rank.
inline Bitboard rank_bb(Rank r) { inline Bitboard rank_bb(Rank r) {
return RankBB[r]; return RankBB[r];
@@ -115,166 +134,207 @@ inline Bitboard file_bb(Square s) {
} }
/// adjacent_files_bb takes a file as input and returns a bitboard representing /// shift_bb() moves a bitboard one step along direction Delta. Mainly for pawns
/// all squares on the adjacent files.
template<Square Delta>
inline Bitboard shift_bb(Bitboard b) {
return Delta == DELTA_N ? b << 8 : Delta == DELTA_S ? b >> 8
: Delta == DELTA_NE ? (b & ~FileHBB) << 9 : Delta == DELTA_SE ? (b & ~FileHBB) >> 7
: Delta == DELTA_NW ? (b & ~FileABB) << 7 : Delta == DELTA_SW ? (b & ~FileABB) >> 9
: 0;
}
/// adjacent_files_bb() returns a bitboard representing all the squares on the
/// adjacent files of the given one.
inline Bitboard adjacent_files_bb(File f) { inline Bitboard adjacent_files_bb(File f) {
return AdjacentFilesBB[f]; return AdjacentFilesBB[f];
} }
/// this_and_adjacent_files_bb takes a file as input and returns a bitboard /// between_bb() returns a bitboard representing all the squares between the two
/// representing all squares on the given and adjacent files. /// given ones. For instance, between_bb(SQ_C4, SQ_F7) returns a bitboard with
/// the bits for square d5 and e6 set. If s1 and s2 are not on the same rank, file
inline Bitboard this_and_adjacent_files_bb(File f) { /// or diagonal, 0 is returned.
return ThisAndAdjacentFilesBB[f];
}
/// in_front_bb() takes a color and a rank or square as input, and returns a
/// bitboard representing all the squares on all ranks in front of the rank
/// (or square), from the given color's point of view. For instance,
/// in_front_bb(WHITE, RANK_5) will give all squares on ranks 6, 7 and 8, while
/// in_front_bb(BLACK, SQ_D3) will give all squares on ranks 1 and 2.
inline Bitboard in_front_bb(Color c, Rank r) {
return InFrontBB[c][r];
}
inline Bitboard in_front_bb(Color c, Square s) {
return InFrontBB[c][rank_of(s)];
}
/// between_bb returns a bitboard representing all squares between two squares.
/// For instance, between_bb(SQ_C4, SQ_F7) returns a bitboard with the bits for
/// square d5 and e6 set. If s1 and s2 are not on the same line, file or diagonal,
/// 0 is returned.
inline Bitboard between_bb(Square s1, Square s2) { inline Bitboard between_bb(Square s1, Square s2) {
return BetweenBB[s1][s2]; return BetweenBB[s1][s2];
} }
/// forward_bb takes a color and a square as input, and returns a bitboard /// in_front_bb() returns a bitboard representing all the squares on all the ranks
/// representing all squares along the line in front of the square, from the /// in front of the given one, from the point of view of the given color. For
/// point of view of the given color. Definition of the table is: /// instance, in_front_bb(BLACK, RANK_3) will return the squares on ranks 1 and 2.
/// ForwardBB[c][s] = in_front_bb(c, s) & file_bb(s)
inline Bitboard in_front_bb(Color c, Rank r) {
return InFrontBB[c][r];
}
/// forward_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:
/// ForwardBB[c][s] = in_front_bb(c, s) & file_bb(s)
inline Bitboard forward_bb(Color c, Square s) { inline Bitboard forward_bb(Color c, Square s) {
return ForwardBB[c][s]; return ForwardBB[c][s];
} }
/// passed_pawn_mask takes a color and a square as input, and returns a /// pawn_attack_span() returns a bitboard representing all the squares that can be
/// bitboard mask which can be used to test if a pawn of the given color on /// attacked by a pawn of the given color when it moves along its file, starting
/// the given square is a passed pawn. Definition of the table is: /// from the given square:
/// PassedPawnMask[c][s] = in_front_bb(c, s) & this_and_adjacent_files_bb(s) /// PawnAttackSpan[c][s] = in_front_bb(c, s) & adjacent_files_bb(s);
inline Bitboard pawn_attack_span(Color c, Square s) {
return PawnAttackSpan[c][s];
}
/// 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:
/// PassedPawnMask[c][s] = pawn_attack_span(c, s) | forward_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];
} }
/// attack_span_mask takes a color and a square as input, and returns a bitboard /// squares_of_color() returns a bitboard representing all the squares of the
/// representing all squares that can be attacked by a pawn of the given color /// same color of the given one.
/// when it moves along its file starting from the given square. Definition is:
/// AttackSpanMask[c][s] = in_front_bb(c, s) & adjacent_files_bb(s);
inline Bitboard attack_span_mask(Color c, Square s) { inline Bitboard squares_of_color(Square s) {
return AttackSpanMask[c][s]; return DarkSquares & s ? DarkSquares : ~DarkSquares;
} }
/// squares_aligned returns true if the squares s1, s2 and s3 are aligned /// aligned() returns true if the squares s1, s2 and s3 are aligned either on a
/// either on a straight or on a diagonal line. /// straight or on a diagonal line.
inline bool squares_aligned(Square s1, Square s2, Square s3) { inline bool aligned(Square s1, Square s2, Square s3) {
return (BetweenBB[s1][s2] | BetweenBB[s1][s3] | BetweenBB[s2][s3]) return LineBB[s1][s2] & s3;
& ( SquareBB[s1] | SquareBB[s2] | SquareBB[s3]);
} }
/// same_color_squares() returns a bitboard representing all squares with /// distance() functions return the distance between x and y, defined as the
/// the same color of the given square. /// number of steps for a king in x to reach y. Works with squares, ranks, files.
inline Bitboard same_color_squares(Square s) { template<typename T> inline int distance(T x, T y) { return x < y ? y - x : x - y; }
return Bitboard(0xAA55AA55AA55AA55ULL) & s ? 0xAA55AA55AA55AA55ULL template<> inline int distance<Square>(Square x, Square y) { return SquareDistance[x][y]; }
: ~0xAA55AA55AA55AA55ULL;
} template<typename T1, typename T2> inline int distance(T2 x, T2 y);
template<> inline int distance<File>(Square x, Square y) { return distance(file_of(x), file_of(y)); }
template<> inline int distance<Rank>(Square x, Square y) { return distance(rank_of(x), rank_of(y)); }
/// Functions for computing sliding attack bitboards. Function attacks_bb() takes /// attacks_bb() returns a bitboard representing all the squares attacked by a
/// a square and a bitboard of occupied squares as input, and returns a bitboard /// piece of type Pt (bishop or rook) placed on 's'. The helper magic_index()
/// representing all squares attacked by Pt (bishop or rook) on the given square. /// looks up the index using the 'magic bitboards' approach.
template<PieceType Pt> template<PieceType Pt>
FORCE_INLINE unsigned magic_index(Square s, Bitboard occ) { FORCE_INLINE unsigned magic_index(Square s, Bitboard occupied) {
Bitboard* const Masks = Pt == ROOK ? RMasks : BMasks; Bitboard* const Masks = Pt == ROOK ? RookMasks : BishopMasks;
Bitboard* const Magics = Pt == ROOK ? RMagics : BMagics; Bitboard* const Magics = Pt == ROOK ? RookMagics : BishopMagics;
unsigned* const Shifts = Pt == ROOK ? RShifts : BShifts; unsigned* const Shifts = Pt == ROOK ? RookShifts : BishopShifts;
if (HasPext)
return unsigned(pext(occupied, Masks[s]));
if (Is64Bit) if (Is64Bit)
return unsigned(((occ & Masks[s]) * Magics[s]) >> Shifts[s]); return unsigned(((occupied & Masks[s]) * Magics[s]) >> Shifts[s]);
unsigned lo = unsigned(occ) & unsigned(Masks[s]); unsigned lo = unsigned(occupied) & unsigned(Masks[s]);
unsigned hi = unsigned(occ >> 32) & unsigned(Masks[s] >> 32); unsigned hi = unsigned(occupied >> 32) & unsigned(Masks[s] >> 32);
return (lo * unsigned(Magics[s]) ^ hi * unsigned(Magics[s] >> 32)) >> Shifts[s]; 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 occ) { inline Bitboard attacks_bb(Square s, Bitboard occupied) {
return (Pt == ROOK ? RAttacks : BAttacks)[s][magic_index<Pt>(s, occ)]; return (Pt == ROOK ? RookAttacks : BishopAttacks)[s][magic_index<Pt>(s, occupied)];
}
inline Bitboard attacks_bb(Piece pc, Square s, Bitboard occupied) {
switch (type_of(pc))
{
case BISHOP: return attacks_bb<BISHOP>(s, occupied);
case ROOK : return attacks_bb<ROOK>(s, occupied);
case QUEEN : return attacks_bb<BISHOP>(s, occupied) | attacks_bb<ROOK>(s, occupied);
default : return StepAttacksBB[pc][s];
}
} }
/// lsb()/msb() finds the least/most significant bit in a nonzero bitboard. /// lsb() and msb() return the least/most significant bit in a non-zero bitboard
/// pop_lsb() finds and clears the least significant bit in a nonzero bitboard.
#if defined(USE_BSFQ) #ifdef USE_BSFQ
# if defined(_MSC_VER) && !defined(__INTEL_COMPILER) # if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
FORCE_INLINE Square lsb(Bitboard b) { FORCE_INLINE Square lsb(Bitboard b) {
unsigned long index; unsigned long idx;
_BitScanForward64(&index, b); _BitScanForward64(&idx, b);
return (Square) index; return (Square) idx;
} }
FORCE_INLINE Square msb(Bitboard b) { FORCE_INLINE Square msb(Bitboard b) {
unsigned long index; unsigned long idx;
_BitScanReverse64(&index, b); _BitScanReverse64(&idx, b);
return (Square) index; return (Square) idx;
} }
# else # elif defined(__arm__)
FORCE_INLINE int lsb32(uint32_t v) {
__asm__("rbit %0, %1" : "=r"(v) : "r"(v));
return __builtin_clz(v);
}
FORCE_INLINE Square msb(Bitboard b) {
return (Square) (63 - __builtin_clzll(b));
}
FORCE_INLINE Square lsb(Bitboard b) {
return (Square) (uint32_t(b) ? lsb32(uint32_t(b)) : 32 + lsb32(uint32_t(b >> 32)));
}
# else // Assumed gcc or compatible compiler
FORCE_INLINE Square lsb(Bitboard b) { // Assembly code by Heinz van Saanen FORCE_INLINE Square lsb(Bitboard b) { // Assembly code by Heinz van Saanen
Bitboard index; Bitboard idx;
__asm__("bsfq %1, %0": "=r"(index): "rm"(b) ); __asm__("bsfq %1, %0": "=r"(idx): "rm"(b) );
return (Square) index; return (Square) idx;
} }
FORCE_INLINE Square msb(Bitboard b) { FORCE_INLINE Square msb(Bitboard b) {
Bitboard index; Bitboard idx;
__asm__("bsrq %1, %0": "=r"(index): "rm"(b) ); __asm__("bsrq %1, %0": "=r"(idx): "rm"(b) );
return (Square) index; return (Square) idx;
} }
# endif # endif
FORCE_INLINE Square pop_lsb(Bitboard* b) { #else // ifdef(USE_BSFQ)
const Square s = lsb(*b);
*b &= ~(1ULL << s);
return s;
}
#else // if !defined(USE_BSFQ) Square lsb(Bitboard b);
Square msb(Bitboard b);
extern Square msb(Bitboard b);
extern Square lsb(Bitboard b);
extern Square pop_lsb(Bitboard* b);
#endif #endif
#endif // !defined(BITBOARD_H_INCLUDED)
/// pop_lsb() finds and clears the least significant bit in a non-zero bitboard
FORCE_INLINE Square pop_lsb(Bitboard* b) {
const Square s = lsb(*b);
*b &= *b - 1;
return s;
}
/// frontmost_sq() and backmost_sq() return the square corresponding to the
/// most/least advanced bit relative to the given color.
inline Square frontmost_sq(Color c, Bitboard b) { return c == WHITE ? msb(b) : lsb(b); }
inline Square backmost_sq(Color c, Bitboard b) { return c == WHITE ? lsb(b) : msb(b); }
#endif // #ifndef BITBOARD_H_INCLUDED
+30 -37
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-2012 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, 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,11 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#if !defined(BITCOUNT_H_INCLUDED) #ifndef BITCOUNT_H_INCLUDED
#define BITCOUNT_H_INCLUDED #define BITCOUNT_H_INCLUDED
#include <cassert> #include <cassert>
#include "types.h" #include "types.h"
enum BitCountType { enum BitCountType {
@@ -32,62 +33,56 @@ enum BitCountType {
CNT_HW_POPCNT CNT_HW_POPCNT
}; };
/// Determine at compile time the best popcount<> specialization according if /// Determine at compile time the best popcount<> specialization according to
/// platform is 32 or 64 bits, to the maximum number of nonzero bits to count or /// whether the platform is 32 or 64 bit, the maximum number of non-zero
/// use hardware popcnt instruction when available. /// bits to count and if the hardware popcnt instruction is available.
const BitCountType Full = HasPopCnt ? CNT_HW_POPCNT : Is64Bit ? CNT_64 : CNT_32; const BitCountType Full = HasPopCnt ? CNT_HW_POPCNT : Is64Bit ? CNT_64 : CNT_32;
const BitCountType Max15 = HasPopCnt ? CNT_HW_POPCNT : Is64Bit ? CNT_64_MAX15 : CNT_32_MAX15; const BitCountType Max15 = HasPopCnt ? CNT_HW_POPCNT : Is64Bit ? CNT_64_MAX15 : CNT_32_MAX15;
/// popcount() counts the number of nonzero bits in a bitboard /// popcount() counts the number of non-zero bits in a bitboard
template<BitCountType> inline int popcount(Bitboard); template<BitCountType> inline int popcount(Bitboard);
template<> template<>
inline int popcount<CNT_64>(Bitboard b) { inline int popcount<CNT_64>(Bitboard b) {
b -= ((b>>1) & 0x5555555555555555ULL); b -= (b >> 1) & 0x5555555555555555ULL;
b = ((b>>2) & 0x3333333333333333ULL) + (b & 0x3333333333333333ULL); b = ((b >> 2) & 0x3333333333333333ULL) + (b & 0x3333333333333333ULL);
b = ((b>>4) + b) & 0x0F0F0F0F0F0F0F0FULL; b = ((b >> 4) + b) & 0x0F0F0F0F0F0F0F0FULL;
b *= 0x0101010101010101ULL; return (b * 0x0101010101010101ULL) >> 56;
return int(b >> 56);
} }
template<> template<>
inline int popcount<CNT_64_MAX15>(Bitboard b) { inline int popcount<CNT_64_MAX15>(Bitboard b) {
b -= (b>>1) & 0x5555555555555555ULL; b -= (b >> 1) & 0x5555555555555555ULL;
b = ((b>>2) & 0x3333333333333333ULL) + (b & 0x3333333333333333ULL); b = ((b >> 2) & 0x3333333333333333ULL) + (b & 0x3333333333333333ULL);
b *= 0x1111111111111111ULL; return (b * 0x1111111111111111ULL) >> 60;
return int(b >> 60);
} }
template<> template<>
inline int popcount<CNT_32>(Bitboard b) { inline int popcount<CNT_32>(Bitboard b) {
unsigned w = unsigned(b >> 32), v = unsigned(b); unsigned w = unsigned(b >> 32), v = unsigned(b);
v -= (v >> 1) & 0x55555555; // 0-2 in 2 bits v -= (v >> 1) & 0x55555555; // 0-2 in 2 bits
w -= (w >> 1) & 0x55555555; w -= (w >> 1) & 0x55555555;
v = ((v >> 2) & 0x33333333) + (v & 0x33333333); // 0-4 in 4 bits v = ((v >> 2) & 0x33333333) + (v & 0x33333333); // 0-4 in 4 bits
w = ((w >> 2) & 0x33333333) + (w & 0x33333333); w = ((w >> 2) & 0x33333333) + (w & 0x33333333);
v = ((v >> 4) + v) & 0x0F0F0F0F; // 0-8 in 8 bits v = ((v >> 4) + v + (w >> 4) + w) & 0x0F0F0F0F;
v += (((w >> 4) + w) & 0x0F0F0F0F); // 0-16 in 8 bits return (v * 0x01010101) >> 24;
v *= 0x01010101; // mul is fast on amd procs
return int(v >> 24);
} }
template<> template<>
inline int popcount<CNT_32_MAX15>(Bitboard b) { inline int popcount<CNT_32_MAX15>(Bitboard b) {
unsigned w = unsigned(b >> 32), v = unsigned(b); unsigned w = unsigned(b >> 32), v = unsigned(b);
v -= (v >> 1) & 0x55555555; // 0-2 in 2 bits v -= (v >> 1) & 0x55555555; // 0-2 in 2 bits
w -= (w >> 1) & 0x55555555; w -= (w >> 1) & 0x55555555;
v = ((v >> 2) & 0x33333333) + (v & 0x33333333); // 0-4 in 4 bits v = ((v >> 2) & 0x33333333) + (v & 0x33333333); // 0-4 in 4 bits
w = ((w >> 2) & 0x33333333) + (w & 0x33333333); w = ((w >> 2) & 0x33333333) + (w & 0x33333333);
v += w; // 0-8 in 4 bits return ((v + w) * 0x11111111) >> 28;
v *= 0x11111111;
return int(v >> 28);
} }
template<> template<>
inline int popcount<CNT_HW_POPCNT>(Bitboard b) { inline int popcount<CNT_HW_POPCNT>(Bitboard b) {
#if !defined(USE_POPCNT) #ifndef USE_POPCNT
assert(false); assert(false);
return b != 0; // Avoid 'b not used' warning return b != 0; // Avoid 'b not used' warning
@@ -100,13 +95,11 @@ inline int popcount<CNT_HW_POPCNT>(Bitboard b) {
return (int)__popcnt64(b); return (int)__popcnt64(b);
#else #else // Assumed gcc or compatible compiler
unsigned long ret; return __builtin_popcountll(b);
__asm__("popcnt %1, %0" : "=r" (ret) : "r" (b));
return ret;
#endif #endif
} }
#endif // !defined(BITCOUNT_H_INCLUDED) #endif // #ifndef BITCOUNT_H_INCLUDED
-471
View File
@@ -1,471 +0,0 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2012 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Stockfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
The code in this file is based on the opening book code in PolyGlot
by Fabien Letouzey. PolyGlot is available under the GNU General
Public License, and can be downloaded from http://wbec-ridderkerk.nl
*/
#include <algorithm>
#include <cassert>
#include <iostream>
#include "book.h"
#include "misc.h"
#include "movegen.h"
using namespace std;
namespace {
// Random numbers from PolyGlot, used to compute book hash keys
const Key PolyGlotRandoms[781] = {
0x9D39247E33776D41ULL, 0x2AF7398005AAA5C7ULL, 0x44DB015024623547ULL,
0x9C15F73E62A76AE2ULL, 0x75834465489C0C89ULL, 0x3290AC3A203001BFULL,
0x0FBBAD1F61042279ULL, 0xE83A908FF2FB60CAULL, 0x0D7E765D58755C10ULL,
0x1A083822CEAFE02DULL, 0x9605D5F0E25EC3B0ULL, 0xD021FF5CD13A2ED5ULL,
0x40BDF15D4A672E32ULL, 0x011355146FD56395ULL, 0x5DB4832046F3D9E5ULL,
0x239F8B2D7FF719CCULL, 0x05D1A1AE85B49AA1ULL, 0x679F848F6E8FC971ULL,
0x7449BBFF801FED0BULL, 0x7D11CDB1C3B7ADF0ULL, 0x82C7709E781EB7CCULL,
0xF3218F1C9510786CULL, 0x331478F3AF51BBE6ULL, 0x4BB38DE5E7219443ULL,
0xAA649C6EBCFD50FCULL, 0x8DBD98A352AFD40BULL, 0x87D2074B81D79217ULL,
0x19F3C751D3E92AE1ULL, 0xB4AB30F062B19ABFULL, 0x7B0500AC42047AC4ULL,
0xC9452CA81A09D85DULL, 0x24AA6C514DA27500ULL, 0x4C9F34427501B447ULL,
0x14A68FD73C910841ULL, 0xA71B9B83461CBD93ULL, 0x03488B95B0F1850FULL,
0x637B2B34FF93C040ULL, 0x09D1BC9A3DD90A94ULL, 0x3575668334A1DD3BULL,
0x735E2B97A4C45A23ULL, 0x18727070F1BD400BULL, 0x1FCBACD259BF02E7ULL,
0xD310A7C2CE9B6555ULL, 0xBF983FE0FE5D8244ULL, 0x9F74D14F7454A824ULL,
0x51EBDC4AB9BA3035ULL, 0x5C82C505DB9AB0FAULL, 0xFCF7FE8A3430B241ULL,
0x3253A729B9BA3DDEULL, 0x8C74C368081B3075ULL, 0xB9BC6C87167C33E7ULL,
0x7EF48F2B83024E20ULL, 0x11D505D4C351BD7FULL, 0x6568FCA92C76A243ULL,
0x4DE0B0F40F32A7B8ULL, 0x96D693460CC37E5DULL, 0x42E240CB63689F2FULL,
0x6D2BDCDAE2919661ULL, 0x42880B0236E4D951ULL, 0x5F0F4A5898171BB6ULL,
0x39F890F579F92F88ULL, 0x93C5B5F47356388BULL, 0x63DC359D8D231B78ULL,
0xEC16CA8AEA98AD76ULL, 0x5355F900C2A82DC7ULL, 0x07FB9F855A997142ULL,
0x5093417AA8A7ED5EULL, 0x7BCBC38DA25A7F3CULL, 0x19FC8A768CF4B6D4ULL,
0x637A7780DECFC0D9ULL, 0x8249A47AEE0E41F7ULL, 0x79AD695501E7D1E8ULL,
0x14ACBAF4777D5776ULL, 0xF145B6BECCDEA195ULL, 0xDABF2AC8201752FCULL,
0x24C3C94DF9C8D3F6ULL, 0xBB6E2924F03912EAULL, 0x0CE26C0B95C980D9ULL,
0xA49CD132BFBF7CC4ULL, 0xE99D662AF4243939ULL, 0x27E6AD7891165C3FULL,
0x8535F040B9744FF1ULL, 0x54B3F4FA5F40D873ULL, 0x72B12C32127FED2BULL,
0xEE954D3C7B411F47ULL, 0x9A85AC909A24EAA1ULL, 0x70AC4CD9F04F21F5ULL,
0xF9B89D3E99A075C2ULL, 0x87B3E2B2B5C907B1ULL, 0xA366E5B8C54F48B8ULL,
0xAE4A9346CC3F7CF2ULL, 0x1920C04D47267BBDULL, 0x87BF02C6B49E2AE9ULL,
0x092237AC237F3859ULL, 0xFF07F64EF8ED14D0ULL, 0x8DE8DCA9F03CC54EULL,
0x9C1633264DB49C89ULL, 0xB3F22C3D0B0B38EDULL, 0x390E5FB44D01144BULL,
0x5BFEA5B4712768E9ULL, 0x1E1032911FA78984ULL, 0x9A74ACB964E78CB3ULL,
0x4F80F7A035DAFB04ULL, 0x6304D09A0B3738C4ULL, 0x2171E64683023A08ULL,
0x5B9B63EB9CEFF80CULL, 0x506AACF489889342ULL, 0x1881AFC9A3A701D6ULL,
0x6503080440750644ULL, 0xDFD395339CDBF4A7ULL, 0xEF927DBCF00C20F2ULL,
0x7B32F7D1E03680ECULL, 0xB9FD7620E7316243ULL, 0x05A7E8A57DB91B77ULL,
0xB5889C6E15630A75ULL, 0x4A750A09CE9573F7ULL, 0xCF464CEC899A2F8AULL,
0xF538639CE705B824ULL, 0x3C79A0FF5580EF7FULL, 0xEDE6C87F8477609DULL,
0x799E81F05BC93F31ULL, 0x86536B8CF3428A8CULL, 0x97D7374C60087B73ULL,
0xA246637CFF328532ULL, 0x043FCAE60CC0EBA0ULL, 0x920E449535DD359EULL,
0x70EB093B15B290CCULL, 0x73A1921916591CBDULL, 0x56436C9FE1A1AA8DULL,
0xEFAC4B70633B8F81ULL, 0xBB215798D45DF7AFULL, 0x45F20042F24F1768ULL,
0x930F80F4E8EB7462ULL, 0xFF6712FFCFD75EA1ULL, 0xAE623FD67468AA70ULL,
0xDD2C5BC84BC8D8FCULL, 0x7EED120D54CF2DD9ULL, 0x22FE545401165F1CULL,
0xC91800E98FB99929ULL, 0x808BD68E6AC10365ULL, 0xDEC468145B7605F6ULL,
0x1BEDE3A3AEF53302ULL, 0x43539603D6C55602ULL, 0xAA969B5C691CCB7AULL,
0xA87832D392EFEE56ULL, 0x65942C7B3C7E11AEULL, 0xDED2D633CAD004F6ULL,
0x21F08570F420E565ULL, 0xB415938D7DA94E3CULL, 0x91B859E59ECB6350ULL,
0x10CFF333E0ED804AULL, 0x28AED140BE0BB7DDULL, 0xC5CC1D89724FA456ULL,
0x5648F680F11A2741ULL, 0x2D255069F0B7DAB3ULL, 0x9BC5A38EF729ABD4ULL,
0xEF2F054308F6A2BCULL, 0xAF2042F5CC5C2858ULL, 0x480412BAB7F5BE2AULL,
0xAEF3AF4A563DFE43ULL, 0x19AFE59AE451497FULL, 0x52593803DFF1E840ULL,
0xF4F076E65F2CE6F0ULL, 0x11379625747D5AF3ULL, 0xBCE5D2248682C115ULL,
0x9DA4243DE836994FULL, 0x066F70B33FE09017ULL, 0x4DC4DE189B671A1CULL,
0x51039AB7712457C3ULL, 0xC07A3F80C31FB4B4ULL, 0xB46EE9C5E64A6E7CULL,
0xB3819A42ABE61C87ULL, 0x21A007933A522A20ULL, 0x2DF16F761598AA4FULL,
0x763C4A1371B368FDULL, 0xF793C46702E086A0ULL, 0xD7288E012AEB8D31ULL,
0xDE336A2A4BC1C44BULL, 0x0BF692B38D079F23ULL, 0x2C604A7A177326B3ULL,
0x4850E73E03EB6064ULL, 0xCFC447F1E53C8E1BULL, 0xB05CA3F564268D99ULL,
0x9AE182C8BC9474E8ULL, 0xA4FC4BD4FC5558CAULL, 0xE755178D58FC4E76ULL,
0x69B97DB1A4C03DFEULL, 0xF9B5B7C4ACC67C96ULL, 0xFC6A82D64B8655FBULL,
0x9C684CB6C4D24417ULL, 0x8EC97D2917456ED0ULL, 0x6703DF9D2924E97EULL,
0xC547F57E42A7444EULL, 0x78E37644E7CAD29EULL, 0xFE9A44E9362F05FAULL,
0x08BD35CC38336615ULL, 0x9315E5EB3A129ACEULL, 0x94061B871E04DF75ULL,
0xDF1D9F9D784BA010ULL, 0x3BBA57B68871B59DULL, 0xD2B7ADEEDED1F73FULL,
0xF7A255D83BC373F8ULL, 0xD7F4F2448C0CEB81ULL, 0xD95BE88CD210FFA7ULL,
0x336F52F8FF4728E7ULL, 0xA74049DAC312AC71ULL, 0xA2F61BB6E437FDB5ULL,
0x4F2A5CB07F6A35B3ULL, 0x87D380BDA5BF7859ULL, 0x16B9F7E06C453A21ULL,
0x7BA2484C8A0FD54EULL, 0xF3A678CAD9A2E38CULL, 0x39B0BF7DDE437BA2ULL,
0xFCAF55C1BF8A4424ULL, 0x18FCF680573FA594ULL, 0x4C0563B89F495AC3ULL,
0x40E087931A00930DULL, 0x8CFFA9412EB642C1ULL, 0x68CA39053261169FULL,
0x7A1EE967D27579E2ULL, 0x9D1D60E5076F5B6FULL, 0x3810E399B6F65BA2ULL,
0x32095B6D4AB5F9B1ULL, 0x35CAB62109DD038AULL, 0xA90B24499FCFAFB1ULL,
0x77A225A07CC2C6BDULL, 0x513E5E634C70E331ULL, 0x4361C0CA3F692F12ULL,
0xD941ACA44B20A45BULL, 0x528F7C8602C5807BULL, 0x52AB92BEB9613989ULL,
0x9D1DFA2EFC557F73ULL, 0x722FF175F572C348ULL, 0x1D1260A51107FE97ULL,
0x7A249A57EC0C9BA2ULL, 0x04208FE9E8F7F2D6ULL, 0x5A110C6058B920A0ULL,
0x0CD9A497658A5698ULL, 0x56FD23C8F9715A4CULL, 0x284C847B9D887AAEULL,
0x04FEABFBBDB619CBULL, 0x742E1E651C60BA83ULL, 0x9A9632E65904AD3CULL,
0x881B82A13B51B9E2ULL, 0x506E6744CD974924ULL, 0xB0183DB56FFC6A79ULL,
0x0ED9B915C66ED37EULL, 0x5E11E86D5873D484ULL, 0xF678647E3519AC6EULL,
0x1B85D488D0F20CC5ULL, 0xDAB9FE6525D89021ULL, 0x0D151D86ADB73615ULL,
0xA865A54EDCC0F019ULL, 0x93C42566AEF98FFBULL, 0x99E7AFEABE000731ULL,
0x48CBFF086DDF285AULL, 0x7F9B6AF1EBF78BAFULL, 0x58627E1A149BBA21ULL,
0x2CD16E2ABD791E33ULL, 0xD363EFF5F0977996ULL, 0x0CE2A38C344A6EEDULL,
0x1A804AADB9CFA741ULL, 0x907F30421D78C5DEULL, 0x501F65EDB3034D07ULL,
0x37624AE5A48FA6E9ULL, 0x957BAF61700CFF4EULL, 0x3A6C27934E31188AULL,
0xD49503536ABCA345ULL, 0x088E049589C432E0ULL, 0xF943AEE7FEBF21B8ULL,
0x6C3B8E3E336139D3ULL, 0x364F6FFA464EE52EULL, 0xD60F6DCEDC314222ULL,
0x56963B0DCA418FC0ULL, 0x16F50EDF91E513AFULL, 0xEF1955914B609F93ULL,
0x565601C0364E3228ULL, 0xECB53939887E8175ULL, 0xBAC7A9A18531294BULL,
0xB344C470397BBA52ULL, 0x65D34954DAF3CEBDULL, 0xB4B81B3FA97511E2ULL,
0xB422061193D6F6A7ULL, 0x071582401C38434DULL, 0x7A13F18BBEDC4FF5ULL,
0xBC4097B116C524D2ULL, 0x59B97885E2F2EA28ULL, 0x99170A5DC3115544ULL,
0x6F423357E7C6A9F9ULL, 0x325928EE6E6F8794ULL, 0xD0E4366228B03343ULL,
0x565C31F7DE89EA27ULL, 0x30F5611484119414ULL, 0xD873DB391292ED4FULL,
0x7BD94E1D8E17DEBCULL, 0xC7D9F16864A76E94ULL, 0x947AE053EE56E63CULL,
0xC8C93882F9475F5FULL, 0x3A9BF55BA91F81CAULL, 0xD9A11FBB3D9808E4ULL,
0x0FD22063EDC29FCAULL, 0xB3F256D8ACA0B0B9ULL, 0xB03031A8B4516E84ULL,
0x35DD37D5871448AFULL, 0xE9F6082B05542E4EULL, 0xEBFAFA33D7254B59ULL,
0x9255ABB50D532280ULL, 0xB9AB4CE57F2D34F3ULL, 0x693501D628297551ULL,
0xC62C58F97DD949BFULL, 0xCD454F8F19C5126AULL, 0xBBE83F4ECC2BDECBULL,
0xDC842B7E2819E230ULL, 0xBA89142E007503B8ULL, 0xA3BC941D0A5061CBULL,
0xE9F6760E32CD8021ULL, 0x09C7E552BC76492FULL, 0x852F54934DA55CC9ULL,
0x8107FCCF064FCF56ULL, 0x098954D51FFF6580ULL, 0x23B70EDB1955C4BFULL,
0xC330DE426430F69DULL, 0x4715ED43E8A45C0AULL, 0xA8D7E4DAB780A08DULL,
0x0572B974F03CE0BBULL, 0xB57D2E985E1419C7ULL, 0xE8D9ECBE2CF3D73FULL,
0x2FE4B17170E59750ULL, 0x11317BA87905E790ULL, 0x7FBF21EC8A1F45ECULL,
0x1725CABFCB045B00ULL, 0x964E915CD5E2B207ULL, 0x3E2B8BCBF016D66DULL,
0xBE7444E39328A0ACULL, 0xF85B2B4FBCDE44B7ULL, 0x49353FEA39BA63B1ULL,
0x1DD01AAFCD53486AULL, 0x1FCA8A92FD719F85ULL, 0xFC7C95D827357AFAULL,
0x18A6A990C8B35EBDULL, 0xCCCB7005C6B9C28DULL, 0x3BDBB92C43B17F26ULL,
0xAA70B5B4F89695A2ULL, 0xE94C39A54A98307FULL, 0xB7A0B174CFF6F36EULL,
0xD4DBA84729AF48ADULL, 0x2E18BC1AD9704A68ULL, 0x2DE0966DAF2F8B1CULL,
0xB9C11D5B1E43A07EULL, 0x64972D68DEE33360ULL, 0x94628D38D0C20584ULL,
0xDBC0D2B6AB90A559ULL, 0xD2733C4335C6A72FULL, 0x7E75D99D94A70F4DULL,
0x6CED1983376FA72BULL, 0x97FCAACBF030BC24ULL, 0x7B77497B32503B12ULL,
0x8547EDDFB81CCB94ULL, 0x79999CDFF70902CBULL, 0xCFFE1939438E9B24ULL,
0x829626E3892D95D7ULL, 0x92FAE24291F2B3F1ULL, 0x63E22C147B9C3403ULL,
0xC678B6D860284A1CULL, 0x5873888850659AE7ULL, 0x0981DCD296A8736DULL,
0x9F65789A6509A440ULL, 0x9FF38FED72E9052FULL, 0xE479EE5B9930578CULL,
0xE7F28ECD2D49EECDULL, 0x56C074A581EA17FEULL, 0x5544F7D774B14AEFULL,
0x7B3F0195FC6F290FULL, 0x12153635B2C0CF57ULL, 0x7F5126DBBA5E0CA7ULL,
0x7A76956C3EAFB413ULL, 0x3D5774A11D31AB39ULL, 0x8A1B083821F40CB4ULL,
0x7B4A38E32537DF62ULL, 0x950113646D1D6E03ULL, 0x4DA8979A0041E8A9ULL,
0x3BC36E078F7515D7ULL, 0x5D0A12F27AD310D1ULL, 0x7F9D1A2E1EBE1327ULL,
0xDA3A361B1C5157B1ULL, 0xDCDD7D20903D0C25ULL, 0x36833336D068F707ULL,
0xCE68341F79893389ULL, 0xAB9090168DD05F34ULL, 0x43954B3252DC25E5ULL,
0xB438C2B67F98E5E9ULL, 0x10DCD78E3851A492ULL, 0xDBC27AB5447822BFULL,
0x9B3CDB65F82CA382ULL, 0xB67B7896167B4C84ULL, 0xBFCED1B0048EAC50ULL,
0xA9119B60369FFEBDULL, 0x1FFF7AC80904BF45ULL, 0xAC12FB171817EEE7ULL,
0xAF08DA9177DDA93DULL, 0x1B0CAB936E65C744ULL, 0xB559EB1D04E5E932ULL,
0xC37B45B3F8D6F2BAULL, 0xC3A9DC228CAAC9E9ULL, 0xF3B8B6675A6507FFULL,
0x9FC477DE4ED681DAULL, 0x67378D8ECCEF96CBULL, 0x6DD856D94D259236ULL,
0xA319CE15B0B4DB31ULL, 0x073973751F12DD5EULL, 0x8A8E849EB32781A5ULL,
0xE1925C71285279F5ULL, 0x74C04BF1790C0EFEULL, 0x4DDA48153C94938AULL,
0x9D266D6A1CC0542CULL, 0x7440FB816508C4FEULL, 0x13328503DF48229FULL,
0xD6BF7BAEE43CAC40ULL, 0x4838D65F6EF6748FULL, 0x1E152328F3318DEAULL,
0x8F8419A348F296BFULL, 0x72C8834A5957B511ULL, 0xD7A023A73260B45CULL,
0x94EBC8ABCFB56DAEULL, 0x9FC10D0F989993E0ULL, 0xDE68A2355B93CAE6ULL,
0xA44CFE79AE538BBEULL, 0x9D1D84FCCE371425ULL, 0x51D2B1AB2DDFB636ULL,
0x2FD7E4B9E72CD38CULL, 0x65CA5B96B7552210ULL, 0xDD69A0D8AB3B546DULL,
0x604D51B25FBF70E2ULL, 0x73AA8A564FB7AC9EULL, 0x1A8C1E992B941148ULL,
0xAAC40A2703D9BEA0ULL, 0x764DBEAE7FA4F3A6ULL, 0x1E99B96E70A9BE8BULL,
0x2C5E9DEB57EF4743ULL, 0x3A938FEE32D29981ULL, 0x26E6DB8FFDF5ADFEULL,
0x469356C504EC9F9DULL, 0xC8763C5B08D1908CULL, 0x3F6C6AF859D80055ULL,
0x7F7CC39420A3A545ULL, 0x9BFB227EBDF4C5CEULL, 0x89039D79D6FC5C5CULL,
0x8FE88B57305E2AB6ULL, 0xA09E8C8C35AB96DEULL, 0xFA7E393983325753ULL,
0xD6B6D0ECC617C699ULL, 0xDFEA21EA9E7557E3ULL, 0xB67C1FA481680AF8ULL,
0xCA1E3785A9E724E5ULL, 0x1CFC8BED0D681639ULL, 0xD18D8549D140CAEAULL,
0x4ED0FE7E9DC91335ULL, 0xE4DBF0634473F5D2ULL, 0x1761F93A44D5AEFEULL,
0x53898E4C3910DA55ULL, 0x734DE8181F6EC39AULL, 0x2680B122BAA28D97ULL,
0x298AF231C85BAFABULL, 0x7983EED3740847D5ULL, 0x66C1A2A1A60CD889ULL,
0x9E17E49642A3E4C1ULL, 0xEDB454E7BADC0805ULL, 0x50B704CAB602C329ULL,
0x4CC317FB9CDDD023ULL, 0x66B4835D9EAFEA22ULL, 0x219B97E26FFC81BDULL,
0x261E4E4C0A333A9DULL, 0x1FE2CCA76517DB90ULL, 0xD7504DFA8816EDBBULL,
0xB9571FA04DC089C8ULL, 0x1DDC0325259B27DEULL, 0xCF3F4688801EB9AAULL,
0xF4F5D05C10CAB243ULL, 0x38B6525C21A42B0EULL, 0x36F60E2BA4FA6800ULL,
0xEB3593803173E0CEULL, 0x9C4CD6257C5A3603ULL, 0xAF0C317D32ADAA8AULL,
0x258E5A80C7204C4BULL, 0x8B889D624D44885DULL, 0xF4D14597E660F855ULL,
0xD4347F66EC8941C3ULL, 0xE699ED85B0DFB40DULL, 0x2472F6207C2D0484ULL,
0xC2A1E7B5B459AEB5ULL, 0xAB4F6451CC1D45ECULL, 0x63767572AE3D6174ULL,
0xA59E0BD101731A28ULL, 0x116D0016CB948F09ULL, 0x2CF9C8CA052F6E9FULL,
0x0B090A7560A968E3ULL, 0xABEEDDB2DDE06FF1ULL, 0x58EFC10B06A2068DULL,
0xC6E57A78FBD986E0ULL, 0x2EAB8CA63CE802D7ULL, 0x14A195640116F336ULL,
0x7C0828DD624EC390ULL, 0xD74BBE77E6116AC7ULL, 0x804456AF10F5FB53ULL,
0xEBE9EA2ADF4321C7ULL, 0x03219A39EE587A30ULL, 0x49787FEF17AF9924ULL,
0xA1E9300CD8520548ULL, 0x5B45E522E4B1B4EFULL, 0xB49C3B3995091A36ULL,
0xD4490AD526F14431ULL, 0x12A8F216AF9418C2ULL, 0x001F837CC7350524ULL,
0x1877B51E57A764D5ULL, 0xA2853B80F17F58EEULL, 0x993E1DE72D36D310ULL,
0xB3598080CE64A656ULL, 0x252F59CF0D9F04BBULL, 0xD23C8E176D113600ULL,
0x1BDA0492E7E4586EULL, 0x21E0BD5026C619BFULL, 0x3B097ADAF088F94EULL,
0x8D14DEDB30BE846EULL, 0xF95CFFA23AF5F6F4ULL, 0x3871700761B3F743ULL,
0xCA672B91E9E4FA16ULL, 0x64C8E531BFF53B55ULL, 0x241260ED4AD1E87DULL,
0x106C09B972D2E822ULL, 0x7FBA195410E5CA30ULL, 0x7884D9BC6CB569D8ULL,
0x0647DFEDCD894A29ULL, 0x63573FF03E224774ULL, 0x4FC8E9560F91B123ULL,
0x1DB956E450275779ULL, 0xB8D91274B9E9D4FBULL, 0xA2EBEE47E2FBFCE1ULL,
0xD9F1F30CCD97FB09ULL, 0xEFED53D75FD64E6BULL, 0x2E6D02C36017F67FULL,
0xA9AA4D20DB084E9BULL, 0xB64BE8D8B25396C1ULL, 0x70CB6AF7C2D5BCF0ULL,
0x98F076A4F7A2322EULL, 0xBF84470805E69B5FULL, 0x94C3251F06F90CF3ULL,
0x3E003E616A6591E9ULL, 0xB925A6CD0421AFF3ULL, 0x61BDD1307C66E300ULL,
0xBF8D5108E27E0D48ULL, 0x240AB57A8B888B20ULL, 0xFC87614BAF287E07ULL,
0xEF02CDD06FFDB432ULL, 0xA1082C0466DF6C0AULL, 0x8215E577001332C8ULL,
0xD39BB9C3A48DB6CFULL, 0x2738259634305C14ULL, 0x61CF4F94C97DF93DULL,
0x1B6BACA2AE4E125BULL, 0x758F450C88572E0BULL, 0x959F587D507A8359ULL,
0xB063E962E045F54DULL, 0x60E8ED72C0DFF5D1ULL, 0x7B64978555326F9FULL,
0xFD080D236DA814BAULL, 0x8C90FD9B083F4558ULL, 0x106F72FE81E2C590ULL,
0x7976033A39F7D952ULL, 0xA4EC0132764CA04BULL, 0x733EA705FAE4FA77ULL,
0xB4D8F77BC3E56167ULL, 0x9E21F4F903B33FD9ULL, 0x9D765E419FB69F6DULL,
0xD30C088BA61EA5EFULL, 0x5D94337FBFAF7F5BULL, 0x1A4E4822EB4D7A59ULL,
0x6FFE73E81B637FB3ULL, 0xDDF957BC36D8B9CAULL, 0x64D0E29EEA8838B3ULL,
0x08DD9BDFD96B9F63ULL, 0x087E79E5A57D1D13ULL, 0xE328E230E3E2B3FBULL,
0x1C2559E30F0946BEULL, 0x720BF5F26F4D2EAAULL, 0xB0774D261CC609DBULL,
0x443F64EC5A371195ULL, 0x4112CF68649A260EULL, 0xD813F2FAB7F5C5CAULL,
0x660D3257380841EEULL, 0x59AC2C7873F910A3ULL, 0xE846963877671A17ULL,
0x93B633ABFA3469F8ULL, 0xC0C0F5A60EF4CDCFULL, 0xCAF21ECD4377B28CULL,
0x57277707199B8175ULL, 0x506C11B9D90E8B1DULL, 0xD83CC2687A19255FULL,
0x4A29C6465A314CD1ULL, 0xED2DF21216235097ULL, 0xB5635C95FF7296E2ULL,
0x22AF003AB672E811ULL, 0x52E762596BF68235ULL, 0x9AEBA33AC6ECC6B0ULL,
0x944F6DE09134DFB6ULL, 0x6C47BEC883A7DE39ULL, 0x6AD047C430A12104ULL,
0xA5B1CFDBA0AB4067ULL, 0x7C45D833AFF07862ULL, 0x5092EF950A16DA0BULL,
0x9338E69C052B8E7BULL, 0x455A4B4CFE30E3F5ULL, 0x6B02E63195AD0CF8ULL,
0x6B17B224BAD6BF27ULL, 0xD1E0CCD25BB9C169ULL, 0xDE0C89A556B9AE70ULL,
0x50065E535A213CF6ULL, 0x9C1169FA2777B874ULL, 0x78EDEFD694AF1EEDULL,
0x6DC93D9526A50E68ULL, 0xEE97F453F06791EDULL, 0x32AB0EDB696703D3ULL,
0x3A6853C7E70757A7ULL, 0x31865CED6120F37DULL, 0x67FEF95D92607890ULL,
0x1F2B1D1F15F6DC9CULL, 0xB69E38A8965C6B65ULL, 0xAA9119FF184CCCF4ULL,
0xF43C732873F24C13ULL, 0xFB4A3D794A9A80D2ULL, 0x3550C2321FD6109CULL,
0x371F77E76BB8417EULL, 0x6BFA9AAE5EC05779ULL, 0xCD04F3FF001A4778ULL,
0xE3273522064480CAULL, 0x9F91508BFFCFC14AULL, 0x049A7F41061A9E60ULL,
0xFCB6BE43A9F2FE9BULL, 0x08DE8A1C7797DA9BULL, 0x8F9887E6078735A1ULL,
0xB5B4071DBFC73A66ULL, 0x230E343DFBA08D33ULL, 0x43ED7F5A0FAE657DULL,
0x3A88A0FBBCB05C63ULL, 0x21874B8B4D2DBC4FULL, 0x1BDEA12E35F6A8C9ULL,
0x53C065C6C8E63528ULL, 0xE34A1D250E7A8D6BULL, 0xD6B04D3B7651DD7EULL,
0x5E90277E7CB39E2DULL, 0x2C046F22062DC67DULL, 0xB10BB459132D0A26ULL,
0x3FA9DDFB67E2F199ULL, 0x0E09B88E1914F7AFULL, 0x10E8B35AF3EEAB37ULL,
0x9EEDECA8E272B933ULL, 0xD4C718BC4AE8AE5FULL, 0x81536D601170FC20ULL,
0x91B534F885818A06ULL, 0xEC8177F83F900978ULL, 0x190E714FADA5156EULL,
0xB592BF39B0364963ULL, 0x89C350C893AE7DC1ULL, 0xAC042E70F8B383F2ULL,
0xB49B52E587A1EE60ULL, 0xFB152FE3FF26DA89ULL, 0x3E666E6F69AE2C15ULL,
0x3B544EBE544C19F9ULL, 0xE805A1E290CF2456ULL, 0x24B33C9D7ED25117ULL,
0xE74733427B72F0C1ULL, 0x0A804D18B7097475ULL, 0x57E3306D881EDB4FULL,
0x4AE7D6A36EB5DBCBULL, 0x2D8D5432157064C8ULL, 0xD1E649DE1E7F268BULL,
0x8A328A1CEDFE552CULL, 0x07A3AEC79624C7DAULL, 0x84547DDC3E203C94ULL,
0x990A98FD5071D263ULL, 0x1A4FF12616EEFC89ULL, 0xF6F7FD1431714200ULL,
0x30C05B1BA332F41CULL, 0x8D2636B81555A786ULL, 0x46C9FEB55D120902ULL,
0xCCEC0A73B49C9921ULL, 0x4E9D2827355FC492ULL, 0x19EBB029435DCB0FULL,
0x4659D2B743848A2CULL, 0x963EF2C96B33BE31ULL, 0x74F85198B05A2E7DULL,
0x5A0F544DD2B1FB18ULL, 0x03727073C2E134B1ULL, 0xC7F6AA2DE59AEA61ULL,
0x352787BAA0D7C22FULL, 0x9853EAB63B5E0B35ULL, 0xABBDCDD7ED5C0860ULL,
0xCF05DAF5AC8D77B0ULL, 0x49CAD48CEBF4A71EULL, 0x7A4C10EC2158C4A6ULL,
0xD9E92AA246BF719EULL, 0x13AE978D09FE5557ULL, 0x730499AF921549FFULL,
0x4E4B705B92903BA4ULL, 0xFF577222C14F0A3AULL, 0x55B6344CF97AAFAEULL,
0xB862225B055B6960ULL, 0xCAC09AFBDDD2CDB4ULL, 0xDAF8E9829FE96B5FULL,
0xB5FDFC5D3132C498ULL, 0x310CB380DB6F7503ULL, 0xE87FBB46217A360EULL,
0x2102AE466EBB1148ULL, 0xF8549E1A3AA5E00DULL, 0x07A69AFDCC42261AULL,
0xC4C118BFE78FEAAEULL, 0xF9F4892ED96BD438ULL, 0x1AF3DBE25D8F45DAULL,
0xF5B4B0B0D2DEEEB4ULL, 0x962ACEEFA82E1C84ULL, 0x046E3ECAAF453CE9ULL,
0xF05D129681949A4CULL, 0x964781CE734B3C84ULL, 0x9C2ED44081CE5FBDULL,
0x522E23F3925E319EULL, 0x177E00F9FC32F791ULL, 0x2BC60A63A6F3B3F2ULL,
0x222BBFAE61725606ULL, 0x486289DDCC3D6780ULL, 0x7DC7785B8EFDFC80ULL,
0x8AF38731C02BA980ULL, 0x1FAB64EA29A2DDF7ULL, 0xE4D9429322CD065AULL,
0x9DA058C67844F20CULL, 0x24C0E332B70019B0ULL, 0x233003B5A6CFE6ADULL,
0xD586BD01C5C217F6ULL, 0x5E5637885F29BC2BULL, 0x7EBA726D8C94094BULL,
0x0A56A5F0BFE39272ULL, 0xD79476A84EE20D06ULL, 0x9E4C1269BAA4BF37ULL,
0x17EFEE45B0DEE640ULL, 0x1D95B0A5FCF90BC6ULL, 0x93CBE0B699C2585DULL,
0x65FA4F227A2B6D79ULL, 0xD5F9E858292504D5ULL, 0xC2B5A03F71471A6FULL,
0x59300222B4561E00ULL, 0xCE2F8642CA0712DCULL, 0x7CA9723FBB2E8988ULL,
0x2785338347F2BA08ULL, 0xC61BB3A141E50E8CULL, 0x150F361DAB9DEC26ULL,
0x9F6A419D382595F4ULL, 0x64A53DC924FE7AC9ULL, 0x142DE49FFF7A7C3DULL,
0x0C335248857FA9E7ULL, 0x0A9C32D5EAE45305ULL, 0xE6C42178C4BBB92EULL,
0x71F1CE2490D20B07ULL, 0xF1BCC3D275AFE51AULL, 0xE728E8C83C334074ULL,
0x96FBF83A12884624ULL, 0x81A1549FD6573DA5ULL, 0x5FA7867CAF35E149ULL,
0x56986E2EF3ED091BULL, 0x917F1DD5F8886C61ULL, 0xD20D8C88C8FFE65FULL,
0x31D71DCE64B2C310ULL, 0xF165B587DF898190ULL, 0xA57E6339DD2CF3A0ULL,
0x1EF6E6DBB1961EC9ULL, 0x70CC73D90BC26E24ULL, 0xE21A6B35DF0C3AD7ULL,
0x003A93D8B2806962ULL, 0x1C99DED33CB890A1ULL, 0xCF3145DE0ADD4289ULL,
0xD0E4427A5514FB72ULL, 0x77C621CC9FB3A483ULL, 0x67A34DAC4356550BULL,
0xF8D626AAAF278509ULL
};
// Offsets to the PolyGlotRandoms[] array of zobrist keys
const Key* ZobPiece = PolyGlotRandoms;
const Key* ZobCastle = ZobPiece + 12 * 64; // Pieces * squares
const Key* ZobEnPassant = ZobCastle + 4; // Castle flags
const Key* ZobTurn = ZobEnPassant + 8; // Number of files
// book_key() returns the PolyGlot hash key of the given position
uint64_t book_key(const Position& pos) {
uint64_t key = 0;
Bitboard b = pos.pieces();
while (b)
{
// In PolyGlotRandoms[] pieces are stored in the following sequence:
// BP = 0, WP = 1, BN = 2, WN = 3, ... BK = 10, WK = 11
Square s = pop_lsb(&b);
Piece p = pos.piece_on(s);
int pieceOfs = 2 * (type_of(p) - 1) + (color_of(p) == WHITE);
key ^= ZobPiece[64 * pieceOfs + s];
}
b = pos.can_castle(ALL_CASTLES);
while (b)
key ^= ZobCastle[pop_lsb(&b)];
if (pos.ep_square() != SQ_NONE)
key ^= ZobEnPassant[file_of(pos.ep_square())];
if (pos.side_to_move() == WHITE)
key ^= ZobTurn[0];
return key;
}
} // namespace
Book::Book() {
for (int i = Time::now() % 10000; i > 0; i--)
RKiss.rand<unsigned>(); // Make random number generation less deterministic
}
Book::~Book() { if (is_open()) close(); }
/// Book::operator>>() reads sizeof(T) chars from the file's binary byte stream
/// and converts them in a number of type T. A Polyglot book stores numbers in
/// big-endian format.
template<typename T> Book& Book::operator>>(T& n) {
n = 0;
for (size_t i = 0; i < sizeof(T); i++)
n = T((n << 8) + ifstream::get());
return *this;
}
template<> Book& Book::operator>>(BookEntry& e) {
return *this >> e.key >> e.move >> e.count >> e.learn;
}
/// Book::open() tries to open a book file with the given name after closing
/// any exsisting one.
bool Book::open(const char* fName) {
if (is_open()) // Cannot close an already closed file
close();
ifstream::open(fName, ifstream::in | ifstream::binary);
fileName = is_open() ? fName : "";
ifstream::clear(); // Reset any error flag to allow retry ifstream::open()
return !fileName.empty();
}
/// Book::probe() tries to find a book move for the given position. If no move
/// is found returns MOVE_NONE. If pickBest is true returns always the highest
/// rated move, otherwise randomly chooses one, based on the move score.
Move Book::probe(const Position& pos, const string& fName, bool pickBest) {
if (fileName != fName && !open(fName.c_str()))
return MOVE_NONE;
BookEntry e;
uint16_t best = 0;
unsigned sum = 0;
Move move = MOVE_NONE;
uint64_t key = book_key(pos);
seekg(find_first(key) * sizeof(BookEntry), ios_base::beg);
while (*this >> e, e.key == key && good())
{
best = max(best, e.count);
sum += e.count;
// Choose book move according to its score. If a move has a very
// high score it has higher probability to be choosen than a move
// with lower score. Note that first entry is always chosen.
if ( (sum && RKiss.rand<unsigned>() % sum < e.count)
|| (pickBest && e.count == best))
move = Move(e.move);
}
if (!move)
return MOVE_NONE;
// A PolyGlot book move is encoded as follows:
//
// bit 0- 5: destination square (from 0 to 63)
// bit 6-11: origin square (from 0 to 63)
// bit 12-14: promotion piece (from KNIGHT == 1 to QUEEN == 4)
//
// Castling moves follow "king captures rook" representation. So in case book
// move is a promotion we have to convert to our representation, in all the
// other cases we can directly compare with a Move after having masked out
// the special Move's flags (bit 14-15) that are not supported by PolyGlot.
int pt = (move >> 12) & 7;
if (pt)
move = make<PROMOTION>(from_sq(move), to_sq(move), PieceType(pt + 1));
// Add 'special move' flags and verify it is legal
for (MoveList<LEGAL> ml(pos); !ml.end(); ++ml)
if (move == (ml.move() & 0x3FFF))
return ml.move();
return MOVE_NONE;
}
/// Book::find_first() takes a book key as input, and does a binary search
/// through the book file for the given key. Returns the index of the leftmost
/// book entry with the same key as the input.
size_t Book::find_first(uint64_t key) {
seekg(0, ios::end); // Move pointer to end, so tellg() gets file's size
size_t low = 0, mid, high = (size_t)tellg() / sizeof(BookEntry) - 1;
BookEntry e;
assert(low <= high);
while (low < high && good())
{
mid = (low + high) / 2;
assert(mid >= low && mid < high);
seekg(mid * sizeof(BookEntry), ios_base::beg);
*this >> e;
if (key <= e.key)
high = mid;
else
low = mid + 1;
}
assert(low == high);
return low;
}
-57
View File
@@ -1,57 +0,0 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2012 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Stockfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined(BOOK_H_INCLUDED)
#define BOOK_H_INCLUDED
#include <fstream>
#include <string>
#include "position.h"
#include "rkiss.h"
/// A Polyglot book is a series of "entries" of 16 bytes. All integers are
/// stored highest byte first (regardless of size). The entries are ordered
/// according to key. Lowest key first.
struct BookEntry {
uint64_t key;
uint16_t move;
uint16_t count;
uint32_t learn;
};
class Book : private std::ifstream {
public:
Book();
~Book();
Move probe(const Position& pos, const std::string& fName, bool pickBest);
private:
template<typename T> Book& operator>>(T& n);
bool open(const char* fName);
size_t find_first(uint64_t key);
RKISS RKiss;
std::string fileName;
};
#endif // !defined(BOOK_H_INCLUDED)
+403 -440
View File
File diff suppressed because it is too large Load Diff
+26 -24
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-2012 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, 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
@@ -17,7 +17,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/>.
*/ */
#if !defined(ENDGAME_H_INCLUDED) #ifndef ENDGAME_H_INCLUDED
#define ENDGAME_H_INCLUDED #define ENDGAME_H_INCLUDED
#include <map> #include <map>
@@ -33,37 +33,38 @@ enum EndgameType {
// Evaluation functions // Evaluation functions
KNNK, // KNN vs K
KXK, // Generic "mate lone king" eval KXK, // Generic "mate lone king" eval
KBNK, // KBN vs K KBNK, // KBN vs K
KPK, // KP vs K KPK, // KP vs K
KRKP, // KR vs KP KRKP, // KR vs KP
KRKB, // KR vs KB KRKB, // KR vs KB
KRKN, // KR vs KN KRKN, // KR vs KN
KQKP, // KQ vs KP
KQKR, // KQ vs KR KQKR, // KQ vs KR
KBBKN, // KBB vs KN
KNNK, // KNN vs K
KmmKm, // K and two minors vs K and one or two minors
// Scaling functions // Scaling functions
SCALE_FUNS, SCALING_FUNCTIONS,
KBPsK, // KB+pawns vs K KBPsK, // KB and pawns vs K
KQKRPs, // KQ vs KR+pawns KQKRPs, // KQ vs KR and pawns
KRPKR, // KRP vs KR KRPKR, // KRP vs KR
KRPKB, // KRP vs KB
KRPPKRP, // KRPP vs KRP KRPPKRP, // KRPP vs KRP
KPsK, // King and pawns vs king KPsK, // K and pawns vs K
KBPKB, // KBP vs KB KBPKB, // KBP vs KB
KBPPKB, // KBPP vs KB KBPPKB, // KBPP vs KB
KBPKN, // KBP vs KN KBPKN, // KBP vs KN
KNPK, // KNP vs K KNPK, // KNP vs K
KNPKB, // KNP vs KB
KPKP // KP vs KP KPKP // KP vs KP
}; };
/// Endgame functions can be of two types according if return a Value or a /// Endgame functions can be of two types depending on whether they return a
/// ScaleFactor. Type eg_fun<int>::type equals to either ScaleFactor or Value /// Value or a ScaleFactor. Type eg_fun<int>::type returns either ScaleFactor
/// depending if the template parameter is 0 or 1. /// or Value depending on whether the template parameter is 0 or 1.
template<int> struct eg_fun { typedef Value type; }; template<int> struct eg_fun { typedef Value type; };
template<> struct eg_fun<1> { typedef ScaleFactor type; }; template<> struct eg_fun<1> { typedef ScaleFactor type; };
@@ -75,26 +76,26 @@ template<typename T>
struct EndgameBase { struct EndgameBase {
virtual ~EndgameBase() {} virtual ~EndgameBase() {}
virtual Color color() const = 0; virtual Color strong_side() const = 0;
virtual T operator()(const Position&) const = 0; virtual T operator()(const Position&) const = 0;
}; };
template<EndgameType E, typename T = typename eg_fun<(E > SCALE_FUNS)>::type> template<EndgameType E, typename T = typename eg_fun<(E > SCALING_FUNCTIONS)>::type>
struct Endgame : public EndgameBase<T> { struct Endgame : public EndgameBase<T> {
explicit Endgame(Color c) : strongerSide(c), weakerSide(~c) {} explicit Endgame(Color c) : strongSide(c), weakSide(~c) {}
Color color() const { return strongerSide; } Color strong_side() const { return strongSide; }
T operator()(const Position&) const; T operator()(const Position&) const;
private: private:
Color strongerSide, weakerSide; Color strongSide, weakSide;
}; };
/// Endgames class stores in two std::map the pointers to endgame evaluation /// The Endgames class stores the pointers to endgame evaluation and scaling
/// and scaling base objects. Then we use polymorphism to invoke the actual /// base objects in two std::map. We use polymorphism to invoke the actual
/// endgame function calling its operator() that is virtual. /// endgame function by calling its virtual operator().
class Endgames { class Endgames {
@@ -111,10 +112,11 @@ class Endgames {
public: public:
Endgames(); Endgames();
~Endgames(); ~Endgames();
template<typename T> T probe(Key key, T& eg) template<typename T> T probe(Key key, T& eg) {
{ return eg = map(eg).count(key) ? map(eg)[key] : NULL; } return eg = map(eg).count(key) ? map(eg)[key] : NULL;
}
}; };
#endif // !defined(ENDGAME_H_INCLUDED) #endif // #ifndef ENDGAME_H_INCLUDED
+577 -881
View File
File diff suppressed because it is too large Load Diff
+9 -7
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-2012 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, 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
@@ -17,21 +17,23 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#if !defined(EVALUATE_H_INCLUDED) #ifndef EVALUATE_H_INCLUDED
#define EVALUATE_H_INCLUDED #define EVALUATE_H_INCLUDED
#include <string>
#include "types.h" #include "types.h"
class Position; class Position;
namespace Eval { namespace Eval {
extern Color RootColor; const Value Tempo = Value(17); // Must be visible to search
extern void init(); void init();
extern Value evaluate(const Position& pos, Value& margin); Value evaluate(const Position& pos);
extern std::string trace(const Position& pos); std::string trace(const Position& pos);
} }
#endif // !defined(EVALUATE_H_INCLUDED) #endif // #ifndef EVALUATE_H_INCLUDED
-72
View File
@@ -1,72 +0,0 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2012 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Stockfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined(HISTORY_H_INCLUDED)
#define HISTORY_H_INCLUDED
#include <algorithm>
#include <cstring>
#include "types.h"
/// The History class stores statistics about how often different moves
/// have been successful or unsuccessful during the current search. These
/// statistics are used for reduction and move ordering decisions. History
/// entries are stored according only to moving piece and destination square,
/// in particular two moves with different origin but same destination and
/// same piece will be considered identical.
class History {
public:
void clear();
Value value(Piece p, Square to) const;
void add(Piece p, Square to, Value bonus);
Value gain(Piece p, Square to) const;
void update_gain(Piece p, Square to, Value g);
static const Value MaxValue = Value(2000);
private:
Value history[16][64]; // [piece][to_square]
Value maxGains[16][64]; // [piece][to_square]
};
inline void History::clear() {
memset(history, 0, 16 * 64 * sizeof(Value));
memset(maxGains, 0, 16 * 64 * sizeof(Value));
}
inline Value History::value(Piece p, Square to) const {
return history[p][to];
}
inline void History::add(Piece p, Square to, Value bonus) {
if (abs(history[p][to] + bonus) < MaxValue) history[p][to] += bonus;
}
inline Value History::gain(Piece p, Square to) const {
return maxGains[p][to];
}
inline void History::update_gain(Piece p, Square to, Value g) {
maxGains[p][to] = std::max(g, maxGains[p][to] - 1);
}
#endif // !defined(HISTORY_H_INCLUDED)
+9 -12
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-2012 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, 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,7 +18,6 @@
*/ */
#include <iostream> #include <iostream>
#include <string>
#include "bitboard.h" #include "bitboard.h"
#include "evaluate.h" #include "evaluate.h"
@@ -26,7 +25,8 @@
#include "search.h" #include "search.h"
#include "thread.h" #include "thread.h"
#include "tt.h" #include "tt.h"
#include "ucioption.h" #include "uci.h"
#include "syzygy/tbprobe.h"
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
@@ -34,19 +34,16 @@ int main(int argc, char* argv[]) {
UCI::init(Options); UCI::init(Options);
Bitboards::init(); Bitboards::init();
Zobrist::init(); Position::init();
Bitbases::init_kpk(); Bitbases::init();
Search::init(); Search::init();
Eval::init(); Eval::init();
Pawns::init();
Threads.init(); Threads.init();
TT.set_size(Options["Hash"]); Tablebases::init(Options["SyzygyPath"]);
TT.resize(Options["Hash"]);
std::string args; UCI::loop(argc, argv);
for (int i = 1; i < argc; i++)
args += std::string(argv[i]) + " ";
UCI::loop(args);
Threads.exit(); Threads.exit();
} }
+117 -155
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-2012 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, 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
@@ -17,41 +17,47 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <algorithm> #include <algorithm> // For std::min
#include <cassert> #include <cassert>
#include <cstring> #include <cstring> // For std::memset
#include "material.h" #include "material.h"
#include "thread.h"
using namespace std; using namespace std;
namespace { namespace {
// Values modified by Joona Kiiski // Polynomial material imbalance parameters
const Value MidgameLimit = Value(15581);
const Value EndgameLimit = Value(3998);
// Scale factors used when one side has no more pawns // pair pawn knight bishop rook queen
const int NoPawnsSF[4] = { 6, 12, 32 }; const int Linear[6] = { 1852, -162, -1122, -183, 249, -154 };
// Polynomial material balance parameters const int QuadraticOurs[][PIECE_TYPE_NB] = {
const Value RedundantQueenPenalty = Value(320); // OUR PIECES
const Value RedundantRookPenalty = Value(554); // pair pawn knight bishop rook queen
{ 0 }, // Bishop pair
{ 39, 2 }, // Pawn
{ 35, 271, -4 }, // Knight OUR PIECES
{ 0, 105, 4, 0 }, // Bishop
{ -27, -2, 46, 100, -141 }, // Rook
{-177, 25, 129, 142, -137, 0 } // Queen
};
const int LinearCoefficients[6] = { 1617, -162, -1172, -190, 105, 26 }; const int QuadraticTheirs[][PIECE_TYPE_NB] = {
// THEIR PIECES
// pair pawn knight bishop rook queen
{ 0 }, // Bishop pair
{ 37, 0 }, // Pawn
{ 10, 62, 0 }, // Knight OUR PIECES
{ 57, 64, 39, 0 }, // Bishop
{ 50, 40, 23, -22, 0 }, // Rook
{ 98, 105, -39, 141, 274, 0 } // Queen
};
const int QuadraticCoefficientsSameColor[][8] = { // Endgame evaluation and scaling functions are accessed directly and not through
{ 7, 7, 7, 7, 7, 7 }, { 39, 2, 7, 7, 7, 7 }, { 35, 271, -4, 7, 7, 7 }, // the function maps because they correspond to more than one material hash key.
{ 7, 25, 4, 7, 7, 7 }, { -27, -2, 46, 100, 56, 7 }, { 58, 29, 83, 148, -3, -25 } }; Endgame<KXK> EvaluateKXK[] = { Endgame<KXK>(WHITE), Endgame<KXK>(BLACK) };
const int QuadraticCoefficientsOppositeColor[][8] = {
{ 41, 41, 41, 41, 41, 41 }, { 37, 41, 41, 41, 41, 41 }, { 10, 62, 41, 41, 41, 41 },
{ 57, 64, 39, 41, 41, 41 }, { 50, 40, 23, -22, 41, 41 }, { 106, 101, 3, 151, 171, 41 } };
// Endgame evaluation and scaling functions accessed direcly and not through
// the function maps because correspond to more then one material hash key.
Endgame<KmmKm> EvaluateKmmKm[] = { Endgame<KmmKm>(WHITE), Endgame<KmmKm>(BLACK) };
Endgame<KXK> EvaluateKXK[] = { Endgame<KXK>(WHITE), Endgame<KXK>(BLACK) };
Endgame<KBPsK> ScaleKBPsK[] = { Endgame<KBPsK>(WHITE), Endgame<KBPsK>(BLACK) }; Endgame<KBPsK> ScaleKBPsK[] = { Endgame<KBPsK>(WHITE), Endgame<KBPsK>(BLACK) };
Endgame<KQKRPs> ScaleKQKRPs[] = { Endgame<KQKRPs>(WHITE), Endgame<KQKRPs>(BLACK) }; Endgame<KQKRPs> ScaleKQKRPs[] = { Endgame<KQKRPs>(WHITE), Endgame<KQKRPs>(BLACK) };
@@ -61,54 +67,79 @@ namespace {
// Helper templates used to detect a given material distribution // Helper templates used to detect a given material distribution
template<Color Us> bool is_KXK(const Position& pos) { template<Color Us> bool is_KXK(const Position& pos) {
const Color Them = (Us == WHITE ? BLACK : WHITE); const Color Them = (Us == WHITE ? BLACK : WHITE);
return pos.non_pawn_material(Them) == VALUE_ZERO return !more_than_one(pos.pieces(Them))
&& pos.piece_count(Them, PAWN) == 0 && pos.non_pawn_material(Us) >= RookValueMg;
&& pos.non_pawn_material(Us) >= RookValueMg;
} }
template<Color Us> bool is_KBPsKs(const Position& pos) { template<Color Us> bool is_KBPsKs(const Position& pos) {
return pos.non_pawn_material(Us) == BishopValueMg return pos.non_pawn_material(Us) == BishopValueMg
&& pos.piece_count(Us, BISHOP) == 1 && pos.count<BISHOP>(Us) == 1
&& pos.piece_count(Us, PAWN) >= 1; && pos.count<PAWN >(Us) >= 1;
} }
template<Color Us> bool is_KQKRPs(const Position& pos) { template<Color Us> bool is_KQKRPs(const Position& pos) {
const Color Them = (Us == WHITE ? BLACK : WHITE); const Color Them = (Us == WHITE ? BLACK : WHITE);
return pos.piece_count(Us, PAWN) == 0 return !pos.count<PAWN>(Us)
&& pos.non_pawn_material(Us) == QueenValueMg && pos.non_pawn_material(Us) == QueenValueMg
&& pos.piece_count(Us, QUEEN) == 1 && pos.count<QUEEN>(Us) == 1
&& pos.piece_count(Them, ROOK) == 1 && pos.count<ROOK>(Them) == 1
&& pos.piece_count(Them, PAWN) >= 1; && pos.count<PAWN>(Them) >= 1;
}
/// imbalance() calculates the imbalance by comparing the piece count of each
/// piece type for both colors.
template<Color Us>
int imbalance(const int pieceCount[][PIECE_TYPE_NB]) {
const Color Them = (Us == WHITE ? BLACK : WHITE);
int bonus = 0;
// Second-degree polynomial material imbalance by Tord Romstad
for (int pt1 = NO_PIECE_TYPE; pt1 <= QUEEN; ++pt1)
{
if (!pieceCount[Us][pt1])
continue;
int v = Linear[pt1];
for (int pt2 = NO_PIECE_TYPE; pt2 <= pt1; ++pt2)
v += QuadraticOurs[pt1][pt2] * pieceCount[Us][pt2]
+ QuadraticTheirs[pt1][pt2] * pieceCount[Them][pt2];
bonus += pieceCount[Us][pt1] * v;
}
return bonus;
} }
} // namespace } // namespace
namespace Material {
/// MaterialTable::probe() takes a position object as input, looks up a MaterialEntry /// Material::probe() looks up the current position's material configuration in
/// object, and returns a pointer to it. If the material configuration is not /// the material hash table. It returns a pointer to the Entry if the position
/// already present in the table, it is computed and stored there, so we don't /// is found. Otherwise a new Entry is computed and stored there, so we don't
/// have to recompute everything when the same material configuration occurs again. /// have to recompute all when the same material configuration occurs again.
MaterialEntry* MaterialTable::probe(const Position& pos) { Entry* probe(const Position& pos) {
Key key = pos.material_key(); Key key = pos.material_key();
MaterialEntry* e = entries[key]; Entry* e = pos.this_thread()->materialTable[key];
// If e->key matches the position's material hash key, it means that we
// have analysed this material configuration before, and we can simply
// return the information we found the last time instead of recomputing it.
if (e->key == key) if (e->key == key)
return e; return e;
memset(e, 0, sizeof(MaterialEntry)); 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 = MaterialTable::game_phase(pos); e->gamePhase = pos.game_phase();
// Let's look if we have a specialized evaluation function for this // Let's look if we have a specialized evaluation function for this particular
// particular material configuration. First we look for a fixed // material configuration. Firstly we look for a fixed configuration one, then
// configuration one, then a generic one if previous search failed. // for a generic one if the previous search failed.
if (endgames.probe(key, e->evaluationFunction)) if (pos.this_thread()->endgames.probe(key, e->evaluationFunction))
return e; return e;
if (is_KXK<WHITE>(pos)) if (is_KXK<WHITE>(pos))
@@ -123,37 +154,19 @@ MaterialEntry* MaterialTable::probe(const Position& pos) {
return e; return e;
} }
if (!pos.pieces(PAWN) && !pos.pieces(ROOK) && !pos.pieces(QUEEN)) // OK, we didn't find any special evaluation function for the current material
{ // configuration. Is there a suitable specialized scaling function?
// Minor piece endgame with at least one minor piece per side and
// no pawns. Note that the case KmmK is already handled by KXK.
assert((pos.pieces(WHITE, KNIGHT) | pos.pieces(WHITE, BISHOP)));
assert((pos.pieces(BLACK, KNIGHT) | pos.pieces(BLACK, BISHOP)));
if ( pos.piece_count(WHITE, BISHOP) + pos.piece_count(WHITE, KNIGHT) <= 2
&& pos.piece_count(BLACK, BISHOP) + pos.piece_count(BLACK, KNIGHT) <= 2)
{
e->evaluationFunction = &EvaluateKmmKm[pos.side_to_move()];
return e;
}
}
// OK, we didn't find any special evaluation function for the current
// material configuration. Is there a suitable scaling function?
//
// We face problems when there are several conflicting applicable
// scaling functions and we need to decide which one to use.
EndgameBase<ScaleFactor>* sf; EndgameBase<ScaleFactor>* sf;
if (endgames.probe(key, sf)) if (pos.this_thread()->endgames.probe(key, sf))
{ {
e->scalingFunction[sf->color()] = sf; e->scalingFunction[sf->strong_side()] = sf; // Only strong color assigned
return e; return e;
} }
// Generic scaling functions that refer to more then one material // We didn't find any specialized scaling function, so fall back on generic
// distribution. Should be probed after the specialized ones. // ones that refer to more than one material distribution. Note that in this
// Note that these ones don't return after setting the function. // case we don't return after setting the function.
if (is_KBPsKs<WHITE>(pos)) if (is_KBPsKs<WHITE>(pos))
e->scalingFunction[WHITE] = &ScaleKBPsK[WHITE]; e->scalingFunction[WHITE] = &ScaleKBPsK[WHITE];
@@ -169,19 +182,21 @@ MaterialEntry* MaterialTable::probe(const Position& pos) {
Value npm_w = pos.non_pawn_material(WHITE); Value npm_w = pos.non_pawn_material(WHITE);
Value npm_b = pos.non_pawn_material(BLACK); Value npm_b = pos.non_pawn_material(BLACK);
if (npm_w + npm_b == VALUE_ZERO) if (npm_w + npm_b == VALUE_ZERO && pos.pieces(PAWN)) // Only pawns on the board
{ {
if (pos.piece_count(BLACK, PAWN) == 0) if (!pos.count<PAWN>(BLACK))
{ {
assert(pos.piece_count(WHITE, PAWN) >= 2); assert(pos.count<PAWN>(WHITE) >= 2);
e->scalingFunction[WHITE] = &ScaleKPsK[WHITE]; e->scalingFunction[WHITE] = &ScaleKPsK[WHITE];
} }
else if (pos.piece_count(WHITE, PAWN) == 0) else if (!pos.count<PAWN>(WHITE))
{ {
assert(pos.piece_count(BLACK, PAWN) >= 2); assert(pos.count<PAWN>(BLACK) >= 2);
e->scalingFunction[BLACK] = &ScaleKPsK[BLACK]; e->scalingFunction[BLACK] = &ScaleKPsK[BLACK];
} }
else if (pos.piece_count(WHITE, PAWN) == 1 && pos.piece_count(BLACK, PAWN) == 1) else if (pos.count<PAWN>(WHITE) == 1 && pos.count<PAWN>(BLACK) == 1)
{ {
// This is a special case because we set scaling functions // This is a special case because we set scaling functions
// for both colors instead of only one. // for both colors instead of only one.
@@ -190,87 +205,34 @@ MaterialEntry* MaterialTable::probe(const Position& pos) {
} }
} }
// No pawns makes it difficult to win, even with a material advantage // Zero or just one pawn makes it difficult to win, even with a small material
if (pos.piece_count(WHITE, PAWN) == 0 && npm_w - npm_b <= BishopValueMg) // advantage. This catches some trivial draws like KK, KBK and KNK and gives a
{ // drawish scale factor for cases such as KRKBP and KmmKm (except for KBBKN).
e->factor[WHITE] = (uint8_t) if (!pos.count<PAWN>(WHITE) && npm_w - npm_b <= BishopValueMg)
(npm_w == npm_b || npm_w < RookValueMg ? 0 : NoPawnsSF[std::min(pos.piece_count(WHITE, BISHOP), 2)]); e->factor[WHITE] = uint8_t(npm_w < RookValueMg ? SCALE_FACTOR_DRAW :
} npm_b <= BishopValueMg ? 4 : 12);
if (pos.piece_count(BLACK, PAWN) == 0 && npm_b - npm_w <= BishopValueMg) if (!pos.count<PAWN>(BLACK) && npm_b - npm_w <= BishopValueMg)
{ e->factor[BLACK] = uint8_t(npm_b < RookValueMg ? SCALE_FACTOR_DRAW :
e->factor[BLACK] = (uint8_t) npm_w <= BishopValueMg ? 4 : 12);
(npm_w == npm_b || npm_b < RookValueMg ? 0 : NoPawnsSF[std::min(pos.piece_count(BLACK, BISHOP), 2)]);
}
// Compute the space weight if (pos.count<PAWN>(WHITE) == 1 && npm_w - npm_b <= BishopValueMg)
if (npm_w + npm_b >= 2 * QueenValueMg + 4 * RookValueMg + 2 * KnightValueMg) e->factor[WHITE] = (uint8_t) SCALE_FACTOR_ONEPAWN;
{
int minorPieceCount = pos.piece_count(WHITE, KNIGHT) + pos.piece_count(WHITE, BISHOP)
+ pos.piece_count(BLACK, KNIGHT) + pos.piece_count(BLACK, BISHOP);
e->spaceWeight = minorPieceCount * minorPieceCount; if (pos.count<PAWN>(BLACK) == 1 && npm_b - npm_w <= BishopValueMg)
} e->factor[BLACK] = (uint8_t) SCALE_FACTOR_ONEPAWN;
// Evaluate the material imbalance. We use PIECE_TYPE_NONE as a place holder // Evaluate the material imbalance. We use PIECE_TYPE_NONE as a place holder
// for the bishop pair "extended piece", this allow us to be more flexible // for the bishop pair "extended piece", which allows us to be more flexible
// in defining bishop pair bonuses. // in defining bishop pair bonuses.
const int pieceCount[2][8] = { const int PieceCount[COLOR_NB][PIECE_TYPE_NB] = {
{ pos.piece_count(WHITE, BISHOP) > 1, pos.piece_count(WHITE, PAWN), pos.piece_count(WHITE, KNIGHT), { pos.count<BISHOP>(WHITE) > 1, pos.count<PAWN>(WHITE), pos.count<KNIGHT>(WHITE),
pos.piece_count(WHITE, BISHOP) , pos.piece_count(WHITE, ROOK), pos.piece_count(WHITE, QUEEN) }, pos.count<BISHOP>(WHITE) , pos.count<ROOK>(WHITE), pos.count<QUEEN >(WHITE) },
{ pos.piece_count(BLACK, BISHOP) > 1, pos.piece_count(BLACK, PAWN), pos.piece_count(BLACK, KNIGHT), { pos.count<BISHOP>(BLACK) > 1, pos.count<PAWN>(BLACK), pos.count<KNIGHT>(BLACK),
pos.piece_count(BLACK, BISHOP) , pos.piece_count(BLACK, ROOK), pos.piece_count(BLACK, QUEEN) } }; pos.count<BISHOP>(BLACK) , pos.count<ROOK>(BLACK), pos.count<QUEEN >(BLACK) } };
e->value = (int16_t)((imbalance<WHITE>(pieceCount) - imbalance<BLACK>(pieceCount)) / 16); e->value = int16_t((imbalance<WHITE>(PieceCount) - imbalance<BLACK>(PieceCount)) / 16);
return e; return e;
} }
} // namespace Material
/// MaterialTable::imbalance() calculates imbalance comparing piece count of each
/// piece type for both colors.
template<Color Us>
int MaterialTable::imbalance(const int pieceCount[][8]) {
const Color Them = (Us == WHITE ? BLACK : WHITE);
int pt1, pt2, pc, v;
int value = 0;
// Redundancy of major pieces, formula based on Kaufman's paper
// "The Evaluation of Material Imbalances in Chess"
if (pieceCount[Us][ROOK] > 0)
value -= RedundantRookPenalty * (pieceCount[Us][ROOK] - 1)
+ RedundantQueenPenalty * pieceCount[Us][QUEEN];
// Second-degree polynomial material imbalance by Tord Romstad
for (pt1 = NO_PIECE_TYPE; pt1 <= QUEEN; pt1++)
{
pc = pieceCount[Us][pt1];
if (!pc)
continue;
v = LinearCoefficients[pt1];
for (pt2 = NO_PIECE_TYPE; pt2 <= pt1; pt2++)
v += QuadraticCoefficientsSameColor[pt1][pt2] * pieceCount[Us][pt2]
+ QuadraticCoefficientsOppositeColor[pt1][pt2] * pieceCount[Them][pt2];
value += pc * v;
}
return value;
}
/// MaterialTable::game_phase() calculates the phase given the current
/// position. Because the phase is strictly a function of the material, it
/// is stored in MaterialEntry.
Phase MaterialTable::game_phase(const Position& pos) {
Value npm = pos.non_pawn_material(WHITE) + pos.non_pawn_material(BLACK);
return npm >= MidgameLimit ? PHASE_MIDGAME
: npm <= EndgameLimit ? PHASE_ENDGAME
: Phase(((npm - EndgameLimit) * 128) / (MidgameLimit - EndgameLimit));
}
+32 -80
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-2012 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, 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
@@ -17,7 +17,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/>.
*/ */
#if !defined(MATERIAL_H_INCLUDED) #ifndef MATERIAL_H_INCLUDED
#define MATERIAL_H_INCLUDED #define MATERIAL_H_INCLUDED
#include "endgame.h" #include "endgame.h"
@@ -25,96 +25,48 @@
#include "position.h" #include "position.h"
#include "types.h" #include "types.h"
const int MaterialTableSize = 8192; namespace Material {
/// Game phase /// Material::Entry contains various information about a material configuration.
enum Phase { /// It contains a material imbalance evaluation, a function pointer to a special
PHASE_ENDGAME = 0, /// endgame evaluation function (which in most cases is NULL, meaning that the
PHASE_MIDGAME = 128 /// standard evaluation function will be used), and scale factors.
};
/// MaterialEntry is a class which contains various information about a
/// material configuration. It contains a material balance evaluation,
/// a function pointer to a special endgame evaluation function (which in
/// most cases is NULL, meaning that the standard evaluation function will
/// be used), and "scale factors" for black and white.
/// ///
/// The scale factors are used to scale the evaluation score up or down. /// The scale factors are used to scale the evaluation score up or down. For
/// For instance, in KRB vs KR endgames, the score is scaled down by a factor /// instance, in KRB vs KR endgames, the score is scaled down by a factor of 4,
/// of 4, which will result in scores of absolute value less than one pawn. /// which will result in scores of absolute value less than one pawn.
class MaterialEntry { struct Entry {
friend struct MaterialTable; Score imbalance() const { return make_score(value, value); }
Phase game_phase() const { return gamePhase; }
bool specialized_eval_exists() const { return evaluationFunction != NULL; }
Value evaluate(const Position& pos) const { return (*evaluationFunction)(pos); }
public: // scale_factor takes a position and a color as input and returns a scale factor
Score material_value() const; // for the given color. We have to provide the position in addition to the color
ScaleFactor scale_factor(const Position& pos, Color c) const; // because the scale factor may also be a function which should be applied to
int space_weight() const; // the position. For instance, in KBP vs K endgames, the scaling function looks
Phase game_phase() const; // for rook pawns and wrong-colored bishops.
bool specialized_eval_exists() const; ScaleFactor scale_factor(const Position& pos, Color c) const {
Value evaluate(const Position& pos) const; return !scalingFunction[c]
|| (*scalingFunction[c])(pos) == SCALE_FACTOR_NONE ? ScaleFactor(factor[c])
: (*scalingFunction[c])(pos);
}
private:
Key key; Key key;
int16_t value; int16_t value;
uint8_t factor[2]; uint8_t factor[COLOR_NB];
EndgameBase<Value>* evaluationFunction; EndgameBase<Value>* evaluationFunction;
EndgameBase<ScaleFactor>* scalingFunction[2]; EndgameBase<ScaleFactor>* scalingFunction[COLOR_NB]; // Could be one for each
int spaceWeight; // side (e.g. KPKP, KBPsKs)
Phase gamePhase; Phase gamePhase;
}; };
typedef HashTable<Entry, 8192> Table;
/// The MaterialTable class represents a material hash table. The most important Entry* probe(const Position& pos);
/// method is probe(), which returns a pointer to a MaterialEntry object.
struct MaterialTable { } // namespace Material
MaterialEntry* probe(const Position& pos); #endif // #ifndef MATERIAL_H_INCLUDED
static Phase game_phase(const Position& pos);
template<Color Us> static int imbalance(const int pieceCount[][8]);
HashTable<MaterialEntry, MaterialTableSize> entries;
Endgames endgames;
};
/// MaterialEntry::scale_factor takes a position and a color as input, and
/// returns a scale factor for the given color. We have to provide the
/// position in addition to the color, because the scale factor need not
/// to be a constant: It can also be a function which should be applied to
/// the position. For instance, in KBP vs K endgames, a scaling function
/// which checks for draws with rook pawns and wrong-colored bishops.
inline ScaleFactor MaterialEntry::scale_factor(const Position& pos, Color c) const {
if (!scalingFunction[c])
return ScaleFactor(factor[c]);
ScaleFactor sf = (*scalingFunction[c])(pos);
return sf == SCALE_FACTOR_NONE ? ScaleFactor(factor[c]) : sf;
}
inline Value MaterialEntry::evaluate(const Position& pos) const {
return (*evaluationFunction)(pos);
}
inline Score MaterialEntry::material_value() const {
return make_score(value, value);
}
inline int MaterialEntry::space_weight() const {
return spaceWeight;
}
inline Phase MaterialEntry::game_phase() const {
return gamePhase;
}
inline bool MaterialEntry::specialized_eval_exists() const {
return evaluationFunction != NULL;
}
#endif // !defined(MATERIAL_H_INCLUDED)
+75 -111
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-2012 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, 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
@@ -17,6 +17,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 <fstream>
#include <iomanip> #include <iomanip>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
@@ -24,81 +25,21 @@
#include "misc.h" #include "misc.h"
#include "thread.h" #include "thread.h"
#if defined(__hpux)
# include <sys/pstat.h>
#endif
using namespace std; using namespace std;
/// Version number. If Version is left empty, then Tag plus current namespace {
/// date (in the format YYMMDD) is used as a version number.
static const string Version = "2.3"; /// Version number. If Version is left empty, then compile date in the format
static const string Tag = ""; /// DD-MM-YY and show in engine_info.
const string Version = "6";
/// engine_info() returns the full name of the current Stockfish version.
/// This will be either "Stockfish YYMMDD" (where YYMMDD is the date when
/// the program was compiled) or "Stockfish <version number>", depending
/// on whether Version is empty.
const string engine_info(bool to_uci) {
const string months("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec");
const string cpu64(Is64Bit ? " 64bit" : "");
const string popcnt(HasPopCnt ? " SSE4.2" : "");
string month, day, year;
stringstream s, date(__DATE__); // From compiler, format is "Sep 21 2008"
s << "Stockfish " << Version;
if (Version.empty())
{
date >> month >> day >> year;
s << Tag << setfill('0') << " " << year.substr(2)
<< setw(2) << (1 + months.find(month) / 4) << setw(2) << day;
}
s << cpu64 << popcnt << (to_uci ? "\nid author ": " by ")
<< "Tord Romstad, Marco Costalba and Joona Kiiski";
return s.str();
}
/// Convert system time to milliseconds. That's all we need.
Time::point Time::now() {
sys_time_t t; system_time(&t); return time_to_msec(t);
}
/// Debug functions used mainly to collect run-time statistics
static uint64_t hits[2], means[2];
void dbg_hit_on(bool b) { hits[0]++; if (b) hits[1]++; }
void dbg_hit_on_c(bool c, bool b) { if (c) dbg_hit_on(b); }
void dbg_mean_of(int v) { means[0]++; means[1] += v; }
void dbg_print() {
if (hits[0])
cerr << "Total " << hits[0] << " Hits " << hits[1]
<< " hit rate (%) " << 100 * hits[1] / hits[0] << endl;
if (means[0])
cerr << "Total " << means[0] << " Mean "
<< (float)means[1] / means[0] << endl;
}
/// Debug counters
int64_t hits[2], means[2];
/// 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
/// can toggle the logging of std::cout and std:cin at runtime while preserving /// can toggle the logging of std::cout and std:cin at runtime whilst preserving
/// usual i/o functionality and without changing a single line of code! /// usual i/o functionality, all without changing a single line of code!
/// Idea from http://groups.google.com/group/comp.lang.c++/msg/1d941c0f26ea0d81 /// Idea from http://groups.google.com/group/comp.lang.c++/msg/1d941c0f26ea0d81
struct Tie: public streambuf { // MSVC requires splitted streambuf for cin and cout struct Tie: public streambuf { // MSVC requires splitted streambuf for cin and cout
@@ -152,18 +93,65 @@ public:
} }
}; };
} // namespace
/// Used to serialize access to std::cout to avoid multiple threads to write at /// engine_info() returns the full name of the current Stockfish version. This
/// will be either "Stockfish <Tag> DD-MM-YY" (where DD-MM-YY is the date when
/// the program was compiled) or "Stockfish <Version>", depending on whether
/// Version is empty.
const string engine_info(bool to_uci) {
const string months("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec");
string month, day, year;
stringstream ss, date(__DATE__); // From compiler, format is "Sep 21 2008"
ss << "Stockfish " << Version << setfill('0');
if (Version.empty())
{
date >> month >> day >> year;
ss << setw(2) << day << setw(2) << (1 + months.find(month) / 4) << year.substr(2);
}
ss << (Is64Bit ? " 64" : "")
<< (HasPext ? " BMI2" : (HasPopCnt ? " POPCNT" : ""))
<< (to_uci ? "\nid author ": " by ")
<< "Tord Romstad, Marco Costalba and Joona Kiiski";
return ss.str();
}
/// Debug functions used mainly to collect run-time statistics
void dbg_hit_on(bool b) { ++hits[0]; if (b) ++hits[1]; }
void dbg_hit_on_c(bool c, bool b) { if (c) dbg_hit_on(b); }
void dbg_mean_of(int v) { ++means[0]; means[1] += v; }
void dbg_print() {
if (hits[0])
cerr << "Total " << hits[0] << " Hits " << hits[1]
<< " hit rate (%) " << 100 * hits[1] / hits[0] << endl;
if (means[0])
cerr << "Total " << means[0] << " Mean "
<< (double)means[1] / means[0] << endl;
}
/// Used to serialize access to std::cout to avoid multiple threads writing at
/// the same time. /// the same time.
std::ostream& operator<<(std::ostream& os, SyncCout sc) { std::ostream& operator<<(std::ostream& os, SyncCout sc) {
static Mutex m; static Mutex m;
if (sc == io_lock) if (sc == IO_LOCK)
m.lock(); m.lock();
if (sc == io_unlock) if (sc == IO_UNLOCK)
m.unlock(); m.unlock();
return os; return os;
@@ -174,37 +162,12 @@ std::ostream& operator<<(std::ostream& os, SyncCout sc) {
void start_logger(bool b) { Logger::start(b); } void start_logger(bool b) { Logger::start(b); }
/// cpu_count() tries to detect the number of CPU cores /// timed_wait() waits for msec milliseconds. It is mainly a helper to wrap
/// the conversion from milliseconds to struct timespec, as used by pthreads.
int cpu_count() {
#if defined(_WIN32) || defined(_WIN64)
SYSTEM_INFO s;
GetSystemInfo(&s);
return s.dwNumberOfProcessors;
#else
# if defined(_SC_NPROCESSORS_ONLN)
return sysconf(_SC_NPROCESSORS_ONLN);
# elif defined(__hpux)
struct pst_dynamic psd;
if (pstat_getdynamic(&psd, sizeof(psd), (size_t)1, 0) == -1)
return 1;
return psd.psd_proc_cnt;
# else
return 1;
# endif
#endif
}
/// timed_wait() waits for msec milliseconds. It is mainly an helper to wrap
/// conversion from milliseconds to struct timespec, as used by pthreads.
void timed_wait(WaitCondition& sleepCond, Lock& sleepLock, int msec) { void timed_wait(WaitCondition& sleepCond, Lock& sleepLock, int msec) {
#if defined(_WIN32) || defined(_WIN64) #ifdef _WIN32
int tm = msec; int tm = msec;
#else #else
timespec ts, *tm = &ts; timespec ts, *tm = &ts;
@@ -218,27 +181,28 @@ void timed_wait(WaitCondition& sleepCond, Lock& sleepLock, int msec) {
} }
/// prefetch() preloads the given address in L1/L2 cache. This is a non /// prefetch() preloads the given address in L1/L2 cache. This is a non-blocking
/// blocking function and do not stalls the CPU waiting for data to be /// function that doesn't stall the CPU waiting for data to be loaded from memory,
/// loaded from memory, that can be quite slow. /// which can be quite slow.
#if defined(NO_PREFETCH) #ifdef NO_PREFETCH
void prefetch(char*) {} void prefetch(char*) {}
#else #else
# include <xmmintrin.h>
void prefetch(char* addr) { void prefetch(char* addr) {
# if defined(__INTEL_COMPILER) || defined(__ICL) # if defined(__INTEL_COMPILER)
// This hack prevents prefetches to be optimized away by // This hack prevents prefetches from being optimized away by
// Intel compiler. Both MSVC and gcc seems not affected. // Intel compiler. Both MSVC and gcc seem not be affected by this.
__asm__ (""); __asm__ ("");
# endif # endif
_mm_prefetch(addr, _MM_HINT_T2); # if defined(__INTEL_COMPILER) || defined(_MSC_VER)
_mm_prefetch(addr+64, _MM_HINT_T2); // 64 bytes ahead _mm_prefetch(addr, _MM_HINT_T0);
# else
__builtin_prefetch(addr);
# endif
} }
#endif #endif
+57 -26
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-2012 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, 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
@@ -17,53 +17,84 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#if !defined(MISC_H_INCLUDED) #ifndef MISC_H_INCLUDED
#define MISC_H_INCLUDED #define MISC_H_INCLUDED
#include <fstream> #include <cassert>
#include <ostream>
#include <string> #include <string>
#include <vector> #include <vector>
#include "types.h" #include "types.h"
extern const std::string engine_info(bool to_uci = false); const std::string engine_info(bool to_uci = false);
extern int cpu_count(); void timed_wait(WaitCondition&, Lock&, int);
extern void timed_wait(WaitCondition&, Lock&, int); void prefetch(char* addr);
extern void prefetch(char* addr); void start_logger(bool b);
extern void start_logger(bool b);
extern void dbg_hit_on(bool b); void dbg_hit_on(bool b);
extern void dbg_hit_on_c(bool c, bool b); void dbg_hit_on_c(bool c, bool b);
extern void dbg_mean_of(int v); void dbg_mean_of(int v);
extern void dbg_print(); void dbg_print();
struct Log : public std::ofstream {
Log(const std::string& f = "log.txt") : std::ofstream(f.c_str(), std::ios::out | std::ios::app) {}
~Log() { if (is_open()) close(); }
};
namespace Time { namespace Time {
typedef int64_t point; typedef int64_t point;
point now(); inline point now() { return system_time_to_msec(); }
} }
template<class Entry, int Size> template<class Entry, int Size>
struct HashTable { struct HashTable {
HashTable() : e(Size, Entry()) {} HashTable() : table(Size, Entry()) {}
Entry* operator[](Key k) { return &e[(uint32_t)k & (Size - 1)]; } Entry* operator[](Key key) { return &table[(uint32_t)key & (Size - 1)]; }
private: private:
std::vector<Entry> e; std::vector<Entry> table;
}; };
enum SyncCout { io_lock, io_unlock }; enum SyncCout { IO_LOCK, IO_UNLOCK };
std::ostream& operator<<(std::ostream&, SyncCout); std::ostream& operator<<(std::ostream&, SyncCout);
#define sync_cout std::cout << io_lock #define sync_cout std::cout << IO_LOCK
#define sync_endl std::endl << io_unlock #define sync_endl std::endl << IO_UNLOCK
#endif // !defined(MISC_H_INCLUDED)
/// xorshift64star Pseudo-Random Number Generator
/// This class is based on original code written and dedicated
/// to the public domain by Sebastiano Vigna (2014).
/// It has the following characteristics:
///
/// - Outputs 64-bit numbers
/// - Passes Dieharder and SmallCrush test batteries
/// - Does not require warm-up, no zeroland to escape
/// - Internal state is a single 64-bit integer
/// - Period is 2^64 - 1
/// - Speed: 1.60 ns/call (Core i7 @3.40GHz)
///
/// For further analysis see
/// <http://vigna.di.unimi.it/ftp/papers/xorshift.pdf>
class PRNG {
uint64_t s;
uint64_t rand64() {
s ^= s >> 12, s ^= s << 25, s ^= s >> 27;
return s * 2685821657736338717LL;
}
public:
PRNG(uint64_t seed) : s(seed) { assert(seed); }
template<typename T> T rand() { return T(rand64()); }
/// Special generator used to fast init magic numbers.
/// Output values only have 1/8th of their bits set on average.
template<typename T> T sparse_rand()
{ return T(rand64() & rand64() & rand64()); }
};
#endif // #ifndef MISC_H_INCLUDED
+171 -188
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-2012 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, 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,97 +22,76 @@
#include "movegen.h" #include "movegen.h"
#include "position.h" #include "position.h"
/// Simple macro to wrap a very common while loop, no facny, no flexibility,
/// hardcoded names 'mlist' and 'from'.
#define SERIALIZE(b) while (b) (*mlist++).move = make_move(from, pop_lsb(&b))
/// Version used for pawns, where the 'from' square is given as a delta from the 'to' square
#define SERIALIZE_PAWNS(b, d) while (b) { Square to = pop_lsb(&b); \
(*mlist++).move = make_move(to - (d), to); }
namespace { namespace {
template<CastlingSide Side, bool Checks> template<CastlingRight Cr, bool Checks, bool Chess960>
MoveStack* generate_castle(const Position& pos, MoveStack* mlist, Color us) { ExtMove* generate_castling(const Position& pos, ExtMove* moveList, Color us, const CheckInfo* ci) {
if (pos.castle_impeded(us, Side) || !pos.can_castle(make_castle_right(us, Side))) static const bool KingSide = (Cr == WHITE_OO || Cr == BLACK_OO);
return mlist;
if (pos.castling_impeded(Cr) || !pos.can_castle(Cr))
return moveList;
// After castling, the rook and king final positions are the same in Chess960 // After castling, the rook and king final positions are the same in Chess960
// as they would be in standard chess. // as they would be in standard chess.
Square kfrom = pos.king_square(us); Square kfrom = pos.king_square(us);
Square rfrom = pos.castle_rook_square(us, Side); Square rfrom = pos.castling_rook_square(Cr);
Square kto = relative_square(us, Side == KING_SIDE ? SQ_G1 : SQ_C1); Square kto = relative_square(us, KingSide ? SQ_G1 : SQ_C1);
Bitboard enemies = pos.pieces(~us); Bitboard enemies = pos.pieces(~us);
assert(!pos.in_check()); assert(!pos.checkers());
for (Square s = kto; s != kfrom; s += (Square)(Side == KING_SIDE ? -1 : 1)) const Square K = Chess960 ? kto > kfrom ? DELTA_W : DELTA_E
: KingSide ? DELTA_W : DELTA_E;
for (Square s = kto; s != kfrom; s += K)
if (pos.attackers_to(s) & enemies) if (pos.attackers_to(s) & enemies)
return mlist; return moveList;
// Because we generate only legal castling moves we need to verify that // Because we generate only legal castling moves we need to verify that
// when moving the castling rook we do not discover some hidden checker. // when moving the castling rook we do not discover some hidden checker.
// For instance an enemy queen in SQ_A1 when castling rook is in SQ_B1. // For instance an enemy queen in SQ_A1 when castling rook is in SQ_B1.
if ( pos.is_chess960() if (Chess960 && (attacks_bb<ROOK>(kto, pos.pieces() ^ rfrom) & pos.pieces(~us, ROOK, QUEEN)))
&& (pos.attackers_to(kto, pos.pieces() ^ rfrom) & enemies)) return moveList;
return mlist;
(*mlist++).move = make<CASTLE>(kfrom, rfrom); Move m = make<CASTLING>(kfrom, rfrom);
if (Checks && !pos.move_gives_check((mlist - 1)->move, CheckInfo(pos))) if (Checks && !pos.gives_check(m, *ci))
mlist--; return moveList;
return mlist; (moveList++)->move = m;
}
return moveList;
template<Square Delta>
inline Bitboard move_pawns(Bitboard p) {
return Delta == DELTA_N ? p << 8
: Delta == DELTA_S ? p >> 8
: Delta == DELTA_NE ? (p & ~FileHBB) << 9
: Delta == DELTA_SE ? (p & ~FileHBB) >> 7
: Delta == DELTA_NW ? (p & ~FileABB) << 7
: Delta == DELTA_SW ? (p & ~FileABB) >> 9 : 0;
} }
template<GenType Type, Square Delta> template<GenType Type, Square Delta>
inline MoveStack* generate_promotions(MoveStack* mlist, Bitboard pawnsOn7, inline ExtMove* make_promotions(ExtMove* moveList, Square to, const CheckInfo* ci) {
Bitboard target, const CheckInfo* ci) {
Bitboard b = move_pawns<Delta>(pawnsOn7) & target; if (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS)
(moveList++)->move = make<PROMOTION>(to - Delta, to, QUEEN);
while (b) if (Type == QUIETS || Type == EVASIONS || Type == NON_EVASIONS)
{ {
Square to = pop_lsb(&b); (moveList++)->move = make<PROMOTION>(to - Delta, to, ROOK);
(moveList++)->move = make<PROMOTION>(to - Delta, to, BISHOP);
if (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS) (moveList++)->move = make<PROMOTION>(to - Delta, to, KNIGHT);
(*mlist++).move = make<PROMOTION>(to - Delta, to, QUEEN);
if (Type == QUIETS || Type == EVASIONS || Type == NON_EVASIONS)
{
(*mlist++).move = make<PROMOTION>(to - Delta, to, ROOK);
(*mlist++).move = make<PROMOTION>(to - Delta, to, BISHOP);
(*mlist++).move = make<PROMOTION>(to - Delta, to, KNIGHT);
}
// Knight-promotion is the only one that can give a direct check not
// already included in the queen-promotion.
if (Type == QUIET_CHECKS && (StepAttacksBB[W_KNIGHT][to] & ci->ksq))
(*mlist++).move = make<PROMOTION>(to - Delta, to, KNIGHT);
else
(void)ci; // Silence a warning under MSVC
} }
return mlist; // Knight promotion is the only promotion that can give a direct check
// that's not already included in the queen promotion.
if (Type == QUIET_CHECKS && (StepAttacksBB[W_KNIGHT][to] & ci->ksq))
(moveList++)->move = make<PROMOTION>(to - Delta, to, KNIGHT);
else
(void)ci; // Silence a warning under MSVC
return moveList;
} }
template<Color Us, GenType Type> template<Color Us, GenType Type>
MoveStack* generate_pawn_moves(const Position& pos, MoveStack* mlist, ExtMove* generate_pawn_moves(const Position& pos, ExtMove* moveList,
Bitboard target, const CheckInfo* ci) { Bitboard target, const CheckInfo* ci) {
// Compute our parametrized parameters at compile time, named according to // Compute our parametrized parameters at compile time, named according to
// the point of view of white side. // the point of view of white side.
@@ -120,11 +99,11 @@ namespace {
const Bitboard TRank8BB = (Us == WHITE ? Rank8BB : Rank1BB); const Bitboard TRank8BB = (Us == WHITE ? Rank8BB : Rank1BB);
const Bitboard TRank7BB = (Us == WHITE ? Rank7BB : Rank2BB); const Bitboard TRank7BB = (Us == WHITE ? Rank7BB : Rank2BB);
const Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB); const Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB);
const Square UP = (Us == WHITE ? DELTA_N : DELTA_S); const Square Up = (Us == WHITE ? DELTA_N : DELTA_S);
const Square RIGHT = (Us == WHITE ? DELTA_NE : DELTA_SW); const Square Right = (Us == WHITE ? DELTA_NE : DELTA_SW);
const Square LEFT = (Us == WHITE ? DELTA_NW : DELTA_SE); const Square Left = (Us == WHITE ? DELTA_NW : DELTA_SE);
Bitboard b1, b2, dc1, dc2, emptySquares; Bitboard emptySquares;
Bitboard pawnsOn7 = pos.pieces(Us, PAWN) & TRank7BB; Bitboard pawnsOn7 = pos.pieces(Us, PAWN) & TRank7BB;
Bitboard pawnsNotOn7 = pos.pieces(Us, PAWN) & ~TRank7BB; Bitboard pawnsNotOn7 = pos.pieces(Us, PAWN) & ~TRank7BB;
@@ -137,8 +116,8 @@ namespace {
{ {
emptySquares = (Type == QUIETS || Type == QUIET_CHECKS ? target : ~pos.pieces()); emptySquares = (Type == QUIETS || Type == QUIET_CHECKS ? target : ~pos.pieces());
b1 = move_pawns<UP>(pawnsNotOn7) & emptySquares; Bitboard b1 = shift_bb<Up>(pawnsNotOn7) & emptySquares;
b2 = move_pawns<UP>(b1 & TRank3BB) & emptySquares; Bitboard b2 = shift_bb<Up>(b1 & TRank3BB) & emptySquares;
if (Type == EVASIONS) // Consider only blocking squares if (Type == EVASIONS) // Consider only blocking squares
{ {
@@ -154,19 +133,28 @@ namespace {
// Add pawn pushes which give discovered check. This is possible only // Add pawn pushes which give discovered check. This is possible only
// if the pawn is not on the same file as the enemy king, because we // if the pawn is not on the same file as the enemy king, because we
// don't generate captures. Note that a possible discovery check // don't generate captures. Note that a possible discovery check
// promotion has been already generated among captures. // promotion has been already generated amongst the captures.
if (pawnsNotOn7 & ci->dcCandidates) if (pawnsNotOn7 & ci->dcCandidates)
{ {
dc1 = move_pawns<UP>(pawnsNotOn7 & ci->dcCandidates) & emptySquares & ~file_bb(ci->ksq); Bitboard dc1 = shift_bb<Up>(pawnsNotOn7 & ci->dcCandidates) & emptySquares & ~file_bb(ci->ksq);
dc2 = move_pawns<UP>(dc1 & TRank3BB) & emptySquares; Bitboard dc2 = shift_bb<Up>(dc1 & TRank3BB) & emptySquares;
b1 |= dc1; b1 |= dc1;
b2 |= dc2; b2 |= dc2;
} }
} }
SERIALIZE_PAWNS(b1, UP); while (b1)
SERIALIZE_PAWNS(b2, UP + UP); {
Square to = pop_lsb(&b1);
(moveList++)->move = make_move(to - Up, to);
}
while (b2)
{
Square to = pop_lsb(&b2);
(moveList++)->move = make_move(to - Up - Up, to);
}
} }
// Promotions and underpromotions // Promotions and underpromotions
@@ -178,19 +166,37 @@ namespace {
if (Type == EVASIONS) if (Type == EVASIONS)
emptySquares &= target; emptySquares &= target;
mlist = generate_promotions<Type, RIGHT>(mlist, pawnsOn7, enemies, ci); Bitboard b1 = shift_bb<Right>(pawnsOn7) & enemies;
mlist = generate_promotions<Type, LEFT>(mlist, pawnsOn7, enemies, ci); Bitboard b2 = shift_bb<Left >(pawnsOn7) & enemies;
mlist = generate_promotions<Type, UP>(mlist, pawnsOn7, emptySquares, ci); Bitboard b3 = shift_bb<Up >(pawnsOn7) & emptySquares;
while (b1)
moveList = make_promotions<Type, Right>(moveList, pop_lsb(&b1), ci);
while (b2)
moveList = make_promotions<Type, Left >(moveList, pop_lsb(&b2), ci);
while (b3)
moveList = make_promotions<Type, Up >(moveList, pop_lsb(&b3), ci);
} }
// Standard and en-passant captures // Standard and en-passant captures
if (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS) if (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS)
{ {
b1 = move_pawns<RIGHT>(pawnsNotOn7) & enemies; Bitboard b1 = shift_bb<Right>(pawnsNotOn7) & enemies;
b2 = move_pawns<LEFT >(pawnsNotOn7) & enemies; Bitboard b2 = shift_bb<Left >(pawnsNotOn7) & enemies;
SERIALIZE_PAWNS(b1, RIGHT); while (b1)
SERIALIZE_PAWNS(b2, LEFT); {
Square to = pop_lsb(&b1);
(moveList++)->move = make_move(to - Right, to);
}
while (b2)
{
Square to = pop_lsb(&b2);
(moveList++)->move = make_move(to - Left, to);
}
if (pos.ep_square() != SQ_NONE) if (pos.ep_square() != SQ_NONE)
{ {
@@ -199,29 +205,29 @@ namespace {
// An en passant capture can be an evasion only if the checking piece // An en passant capture can be an evasion only if the checking piece
// is the double pushed pawn and so is in the target. Otherwise this // is the double pushed pawn and so is in the target. Otherwise this
// is a discovery check and we are forced to do otherwise. // is a discovery check and we are forced to do otherwise.
if (Type == EVASIONS && !(target & (pos.ep_square() - UP))) if (Type == EVASIONS && !(target & (pos.ep_square() - Up)))
return mlist; return moveList;
b1 = pawnsNotOn7 & pos.attacks_from<PAWN>(pos.ep_square(), Them); b1 = pawnsNotOn7 & pos.attacks_from<PAWN>(pos.ep_square(), Them);
assert(b1); assert(b1);
while (b1) while (b1)
(*mlist++).move = make<ENPASSANT>(pop_lsb(&b1), pos.ep_square()); (moveList++)->move = make<ENPASSANT>(pop_lsb(&b1), pos.ep_square());
} }
} }
return mlist; return moveList;
} }
template<PieceType Pt, bool Checks> FORCE_INLINE template<PieceType Pt, bool Checks> FORCE_INLINE
MoveStack* generate_moves(const Position& pos, MoveStack* mlist, Color us, ExtMove* generate_moves(const Position& pos, ExtMove* moveList, Color us,
Bitboard target, const CheckInfo* ci) { Bitboard target, const CheckInfo* ci) {
assert(Pt != KING && Pt != PAWN); assert(Pt != KING && Pt != PAWN);
const Square* pl = pos.piece_list(us, Pt); const Square* pl = pos.list<Pt>(us);
for (Square from = *pl; from != SQ_NONE; from = *++pl) for (Square from = *pl; from != SQ_NONE; from = *++pl)
{ {
@@ -240,46 +246,50 @@ namespace {
if (Checks) if (Checks)
b &= ci->checkSq[Pt]; b &= ci->checkSq[Pt];
SERIALIZE(b); while (b)
(moveList++)->move = make_move(from, pop_lsb(&b));
} }
return mlist; return moveList;
} }
FORCE_INLINE MoveStack* generate_king_moves(const Position& pos, MoveStack* mlist, template<Color Us, GenType Type> FORCE_INLINE
Color us, Bitboard target) { ExtMove* generate_all(const Position& pos, ExtMove* moveList, Bitboard target,
Square from = pos.king_square(us); const CheckInfo* ci = NULL) {
Bitboard b = pos.attacks_from<KING>(from) & target;
SERIALIZE(b);
return mlist;
}
const bool Checks = Type == QUIET_CHECKS;
template<GenType Type> FORCE_INLINE moveList = generate_pawn_moves<Us, Type>(pos, moveList, target, ci);
MoveStack* generate_all_moves(const Position& pos, MoveStack* mlist, Color us, moveList = generate_moves<KNIGHT, Checks>(pos, moveList, Us, target, ci);
Bitboard target, const CheckInfo* ci = NULL) { moveList = generate_moves<BISHOP, Checks>(pos, moveList, Us, target, ci);
moveList = generate_moves< ROOK, Checks>(pos, moveList, Us, target, ci);
mlist = (us == WHITE ? generate_pawn_moves<WHITE, Type>(pos, mlist, target, ci) moveList = generate_moves< QUEEN, Checks>(pos, moveList, Us, target, ci);
: generate_pawn_moves<BLACK, Type>(pos, mlist, target, ci));
mlist = generate_moves<KNIGHT, Type == QUIET_CHECKS>(pos, mlist, us, target, ci);
mlist = generate_moves<BISHOP, Type == QUIET_CHECKS>(pos, mlist, us, target, ci);
mlist = generate_moves<ROOK, Type == QUIET_CHECKS>(pos, mlist, us, target, ci);
mlist = generate_moves<QUEEN, Type == QUIET_CHECKS>(pos, mlist, us, target, ci);
if (Type != QUIET_CHECKS && Type != EVASIONS) if (Type != QUIET_CHECKS && Type != EVASIONS)
mlist = generate_king_moves(pos, mlist, us, target);
if (Type != CAPTURES && Type != EVASIONS && pos.can_castle(us))
{ {
mlist = generate_castle<KING_SIDE, Type == QUIET_CHECKS>(pos, mlist, us); Square ksq = pos.king_square(Us);
mlist = generate_castle<QUEEN_SIDE, Type == QUIET_CHECKS>(pos, mlist, us); Bitboard b = pos.attacks_from<KING>(ksq) & target;
while (b)
(moveList++)->move = make_move(ksq, pop_lsb(&b));
} }
return mlist; if (Type != CAPTURES && Type != EVASIONS && pos.can_castle(Us))
} {
if (pos.is_chess960())
{
moveList = generate_castling<MakeCastling<Us, KING_SIDE>::right, Checks, true>(pos, moveList, Us, ci);
moveList = generate_castling<MakeCastling<Us, QUEEN_SIDE>::right, Checks, true>(pos, moveList, Us, ci);
}
else
{
moveList = generate_castling<MakeCastling<Us, KING_SIDE>::right, Checks, false>(pos, moveList, Us, ci);
moveList = generate_castling<MakeCastling<Us, QUEEN_SIDE>::right, Checks, false>(pos, moveList, Us, ci);
}
}
return moveList;
}
} // namespace } // namespace
@@ -294,38 +304,33 @@ namespace {
/// non-captures. Returns a pointer to the end of the move list. /// non-captures. Returns a pointer to the end of the move list.
template<GenType Type> template<GenType Type>
MoveStack* generate(const Position& pos, MoveStack* mlist) { ExtMove* generate(const Position& pos, ExtMove* moveList) {
assert(Type == CAPTURES || Type == QUIETS || Type == NON_EVASIONS); assert(Type == CAPTURES || Type == QUIETS || Type == NON_EVASIONS);
assert(!pos.in_check()); assert(!pos.checkers());
Color us = pos.side_to_move(); Color us = pos.side_to_move();
Bitboard target;
if (Type == CAPTURES) Bitboard target = Type == CAPTURES ? pos.pieces(~us)
target = pos.pieces(~us); : Type == QUIETS ? ~pos.pieces()
: Type == NON_EVASIONS ? ~pos.pieces(us) : 0;
else if (Type == QUIETS) return us == WHITE ? generate_all<WHITE, Type>(pos, moveList, target)
target = ~pos.pieces(); : generate_all<BLACK, Type>(pos, moveList, target);
else if (Type == NON_EVASIONS)
target = ~pos.pieces(us);
return generate_all_moves<Type>(pos, mlist, us, target);
} }
// Explicit template instantiations // Explicit template instantiations
template MoveStack* generate<CAPTURES>(const Position&, MoveStack*); template ExtMove* generate<CAPTURES>(const Position&, ExtMove*);
template MoveStack* generate<QUIETS>(const Position&, MoveStack*); template ExtMove* generate<QUIETS>(const Position&, ExtMove*);
template MoveStack* generate<NON_EVASIONS>(const Position&, MoveStack*); template ExtMove* generate<NON_EVASIONS>(const Position&, ExtMove*);
/// generate<QUIET_CHECKS> generates all pseudo-legal non-captures and knight /// generate<QUIET_CHECKS> generates all pseudo-legal non-captures and knight
/// underpromotions that give check. Returns a pointer to the end of the move list. /// underpromotions that give check. Returns a pointer to the end of the move list.
template<> template<>
MoveStack* generate<QUIET_CHECKS>(const Position& pos, MoveStack* mlist) { ExtMove* generate<QUIET_CHECKS>(const Position& pos, ExtMove* moveList) {
assert(!pos.in_check()); assert(!pos.checkers());
Color us = pos.side_to_move(); Color us = pos.side_to_move();
CheckInfo ci(pos); CheckInfo ci(pos);
@@ -337,99 +342,77 @@ MoveStack* generate<QUIET_CHECKS>(const Position& pos, MoveStack* mlist) {
PieceType pt = type_of(pos.piece_on(from)); PieceType pt = type_of(pos.piece_on(from));
if (pt == PAWN) if (pt == PAWN)
continue; // Will be generated togheter 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(Piece(pt), from) & ~pos.pieces();
if (pt == KING) if (pt == KING)
b &= ~PseudoAttacks[QUEEN][ci.ksq]; b &= ~PseudoAttacks[QUEEN][ci.ksq];
SERIALIZE(b); while (b)
(moveList++)->move = make_move(from, pop_lsb(&b));
} }
return generate_all_moves<QUIET_CHECKS>(pos, mlist, us, ~pos.pieces(), &ci); return us == WHITE ? generate_all<WHITE, QUIET_CHECKS>(pos, moveList, ~pos.pieces(), &ci)
: generate_all<BLACK, QUIET_CHECKS>(pos, moveList, ~pos.pieces(), &ci);
} }
/// generate<EVASIONS> generates all pseudo-legal check evasions when the side /// generate<EVASIONS> generates all pseudo-legal check evasions when the side
/// to move is in check. Returns a pointer to the end of the move list. /// to move is in check. Returns a pointer to the end of the move list.
template<> template<>
MoveStack* generate<EVASIONS>(const Position& pos, MoveStack* mlist) { ExtMove* generate<EVASIONS>(const Position& pos, ExtMove* moveList) {
assert(pos.in_check());
Square from, checksq;
int checkersCnt = 0;
Color us = pos.side_to_move();
Square ksq = pos.king_square(us);
Bitboard sliderAttacks = 0;
Bitboard b = pos.checkers();
assert(pos.checkers()); assert(pos.checkers());
// Find squares attacked by slider checkers, we will remove them from the king Color us = pos.side_to_move();
// evasions so to skip known illegal moves avoiding useless legality check later. Square ksq = pos.king_square(us);
do Bitboard sliderAttacks = 0;
Bitboard sliders = pos.checkers() & ~pos.pieces(KNIGHT, PAWN);
// Find all the squares attacked by slider checkers. We will remove them from
// the king evasions in order to skip known illegal moves, which avoids any
// useless legality checks later on.
while (sliders)
{ {
checkersCnt++; Square checksq = pop_lsb(&sliders);
checksq = pop_lsb(&b); sliderAttacks |= LineBB[checksq][ksq] ^ checksq;
}
assert(color_of(pos.piece_on(checksq)) == ~us);
switch (type_of(pos.piece_on(checksq)))
{
case BISHOP: sliderAttacks |= PseudoAttacks[BISHOP][checksq]; break;
case ROOK: sliderAttacks |= PseudoAttacks[ROOK][checksq]; break;
case QUEEN:
// If queen and king are far or not on a diagonal line we can safely
// remove all the squares attacked in the other direction becuase are
// not reachable by the king anyway.
if (between_bb(ksq, checksq) || !(PseudoAttacks[BISHOP][checksq] & ksq))
sliderAttacks |= PseudoAttacks[QUEEN][checksq];
// Otherwise we need to use real rook attacks to check if king is safe
// to move in the other direction. For example: king in B2, queen in A1
// a knight in B1, and we can safely move to C1.
else
sliderAttacks |= PseudoAttacks[BISHOP][checksq] | pos.attacks_from<ROOK>(checksq);
default:
break;
}
} while (b);
// Generate evasions for king, capture and non capture moves // Generate evasions for king, capture and non capture moves
b = pos.attacks_from<KING>(ksq) & ~pos.pieces(us) & ~sliderAttacks; Bitboard b = pos.attacks_from<KING>(ksq) & ~pos.pieces(us) & ~sliderAttacks;
from = ksq; while (b)
SERIALIZE(b); (moveList++)->move = make_move(ksq, pop_lsb(&b));
if (checkersCnt > 1) if (more_than_one(pos.checkers()))
return mlist; // Double check, only a king move can save the day return moveList; // Double check, only a king move can save the day
// Generate blocking evasions or captures of the checking piece // Generate blocking evasions or captures of the checking piece
Bitboard target = between_bb(checksq, ksq) | pos.checkers(); Square checksq = lsb(pos.checkers());
Bitboard target = between_bb(checksq, ksq) | checksq;
return generate_all_moves<EVASIONS>(pos, mlist, us, target); return us == WHITE ? generate_all<WHITE, EVASIONS>(pos, moveList, target)
: generate_all<BLACK, EVASIONS>(pos, moveList, target);
} }
/// generate<LEGAL> generates all the legal moves in the given position /// generate<LEGAL> generates all the legal moves in the given position
template<> template<>
MoveStack* generate<LEGAL>(const Position& pos, MoveStack* mlist) { ExtMove* generate<LEGAL>(const Position& pos, ExtMove* moveList) {
MoveStack *end, *cur = mlist; Bitboard pinned = pos.pinned_pieces(pos.side_to_move());
Bitboard pinned = pos.pinned_pieces();
Square ksq = pos.king_square(pos.side_to_move()); Square ksq = pos.king_square(pos.side_to_move());
ExtMove* cur = moveList;
end = pos.in_check() ? generate<EVASIONS>(pos, mlist) moveList = pos.checkers() ? generate<EVASIONS >(pos, moveList)
: generate<NON_EVASIONS>(pos, mlist); : generate<NON_EVASIONS>(pos, moveList);
while (cur != end) while (cur != moveList)
if ( (pinned || from_sq(cur->move) == ksq || type_of(cur->move) == ENPASSANT) if ( (pinned || from_sq(cur->move) == ksq || type_of(cur->move) == ENPASSANT)
&& !pos.pl_move_is_legal(cur->move, pinned)) && !pos.legal(cur->move, pinned))
cur->move = (--end)->move; cur->move = (--moveList)->move;
else else
cur++; ++cur;
return end; return moveList;
} }
+26 -14
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-2012 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, 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
@@ -17,11 +17,13 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#if !defined(MOVEGEN_H_INCLUDED) #ifndef MOVEGEN_H_INCLUDED
#define MOVEGEN_H_INCLUDED #define MOVEGEN_H_INCLUDED
#include "types.h" #include "types.h"
class Position;
enum GenType { enum GenType {
CAPTURES, CAPTURES,
QUIETS, QUIETS,
@@ -31,25 +33,35 @@ enum GenType {
LEGAL LEGAL
}; };
class Position; struct ExtMove {
Move move;
Value value;
};
inline bool operator<(const ExtMove& f, const ExtMove& s) {
return f.value < s.value;
}
template<GenType> template<GenType>
MoveStack* generate(const Position& pos, MoveStack* mlist); ExtMove* generate(const Position& pos, ExtMove* moveList);
/// The MoveList struct is a simple wrapper around generate(), sometimes comes /// The MoveList struct is a simple wrapper around generate(). It sometimes comes
/// handy to use this class instead of the low level generate() function. /// in handy to use this class instead of the low level generate() function.
template<GenType T> template<GenType T>
struct MoveList { struct MoveList {
explicit MoveList(const Position& pos) : cur(mlist), last(generate<T>(pos, mlist)) {} explicit MoveList(const Position& pos) : cur(moveList), last(generate<T>(pos, moveList)) { last->move = MOVE_NONE; }
void operator++() { cur++; } void operator++() { ++cur; }
bool end() const { return cur == last; } Move operator*() const { return cur->move; }
Move move() const { return cur->move; } size_t size() const { return last - moveList; }
size_t size() const { return last - mlist; } bool contains(Move m) const {
for (const ExtMove* it(moveList); it != last; ++it) if (it->move == m) return true;
return false;
}
private: private:
MoveStack mlist[MAX_MOVES]; ExtMove moveList[MAX_MOVES];
MoveStack *cur, *last; ExtMove *cur, *last;
}; };
#endif // !defined(MOVEGEN_H_INCLUDED) #endif // #ifndef MOVEGEN_H_INCLUDED
+138 -117
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-2012 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, 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,16 +18,14 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <algorithm>
#include <cassert> #include <cassert>
#include "movegen.h"
#include "movepick.h" #include "movepick.h"
#include "thread.h" #include "thread.h"
namespace { namespace {
enum Sequencer { enum Stages {
MAIN_SEARCH, CAPTURES_S1, KILLERS_S1, QUIETS_1_S1, QUIETS_2_S1, BAD_CAPTURES_S1, MAIN_SEARCH, CAPTURES_S1, KILLERS_S1, QUIETS_1_S1, QUIETS_2_S1, BAD_CAPTURES_S1,
EVASION, EVASIONS_S2, EVASION, EVASIONS_S2,
QSEARCH_0, CAPTURES_S3, QUIET_CHECKS_S3, QSEARCH_0, CAPTURES_S3, QUIET_CHECKS_S3,
@@ -37,116 +35,110 @@ namespace {
STOP STOP
}; };
// Unary predicate used by std::partition to split positive scores from remaining // Our insertion sort, which is guaranteed (and also needed) to be stable
// ones so to sort separately the two sets, and with the second sort delayed. void insertion_sort(ExtMove* begin, ExtMove* end)
inline bool has_positive_score(const MoveStack& ms) { return ms.score > 0; } {
ExtMove tmp, *p, *q;
// Picks and moves to the front the best move in the range [begin, end), for (p = begin + 1; p < end; ++p)
// it is faster than sorting all the moves in advance when moves are few, as {
// normally are the possible captures. tmp = *p;
inline MoveStack* pick_best(MoveStack* begin, MoveStack* end) for (q = p; q != begin && *(q-1) < tmp; --q)
*q = *(q-1);
*q = tmp;
}
}
// Unary predicate used by std::partition to split positive values from remaining
// ones so as to sort the two sets separately, with the second sort delayed.
inline bool has_positive_value(const ExtMove& move) { return move.value > VALUE_ZERO; }
// Picks 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 are few
// moves e.g. possible captures.
inline ExtMove* 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
/// Constructors of the MovePicker class. As arguments we pass information /// Constructors of the MovePicker class. As arguments we pass information
/// to help it to return the presumably good moves first, to decide which /// to help it to return the (presumably) good moves first, to decide which
/// moves to return (in the quiescence search, for instance, we only want to /// moves to return (in the quiescence search, for instance, we only want to
/// search captures, promotions and some checks) and about how important good /// search captures, promotions and some checks) and how important good move
/// move ordering is at the current node. /// ordering is at the current node.
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const History& h, MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const HistoryStats& h,
Search::Stack* s, Value beta) : pos(p), H(h), depth(d) { Move* cm, Move* fm, Search::Stack* s) : pos(p), history(h), depth(d) {
assert(d > DEPTH_ZERO); assert(d > DEPTH_ZERO);
captureThreshold = 0;
cur = end = moves; cur = end = moves;
endBadCaptures = moves + MAX_MOVES - 1; endBadCaptures = moves + MAX_MOVES - 1;
countermoves = cm;
followupmoves = fm;
ss = s; ss = s;
if (p.in_check()) if (pos.checkers())
phase = EVASION; stage = EVASION;
else else
{ stage = MAIN_SEARCH;
phase = MAIN_SEARCH;
killers[0].move = ss->killers[0]; ttMove = (ttm && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE);
killers[1].move = ss->killers[1];
// Consider sligtly negative captures as good if at low depth and far from beta
if (ss && ss->eval < beta - PawnValueMg && d < 3 * ONE_PLY)
captureThreshold = -PawnValueMg;
// Consider negative captures as good if still enough to reach beta
else if (ss && ss->eval > beta)
captureThreshold = beta - ss->eval;
}
ttMove = (ttm && pos.is_pseudo_legal(ttm) ? ttm : MOVE_NONE);
end += (ttMove != MOVE_NONE); end += (ttMove != MOVE_NONE);
} }
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const History& h, MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const HistoryStats& h,
Square sq) : pos(p), H(h), cur(moves), end(moves) { Square s) : pos(p), history(h), cur(moves), end(moves) {
assert(d <= DEPTH_ZERO); assert(d <= DEPTH_ZERO);
if (p.in_check()) if (pos.checkers())
phase = EVASION; stage = EVASION;
else if (d > DEPTH_QS_NO_CHECKS) else if (d > DEPTH_QS_NO_CHECKS)
phase = QSEARCH_0; stage = QSEARCH_0;
else if (d > DEPTH_QS_RECAPTURES) else if (d > DEPTH_QS_RECAPTURES)
{ stage = QSEARCH_1;
phase = QSEARCH_1;
// Skip TT move if is not a capture or a promotion, this avoids qsearch
// tree explosion due to a possible perpetual check or similar rare cases
// when TT table is full.
if (ttm && !pos.is_capture_or_promotion(ttm))
ttm = MOVE_NONE;
}
else else
{ {
phase = RECAPTURE; stage = RECAPTURE;
recaptureSquare = sq; recaptureSquare = s;
ttm = MOVE_NONE; ttm = MOVE_NONE;
} }
ttMove = (ttm && pos.is_pseudo_legal(ttm) ? ttm : MOVE_NONE); ttMove = (ttm && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE);
end += (ttMove != MOVE_NONE); end += (ttMove != MOVE_NONE);
} }
MovePicker::MovePicker(const Position& p, Move ttm, const History& h, PieceType pt) MovePicker::MovePicker(const Position& p, Move ttm, const HistoryStats& h, PieceType pt)
: pos(p), H(h), cur(moves), end(moves) { : pos(p), history(h), cur(moves), end(moves) {
assert(!pos.in_check()); assert(!pos.checkers());
phase = PROBCUT; stage = PROBCUT;
// In ProbCut we generate only captures better than parent's captured piece // In ProbCut we generate only captures that are better than the parent's
captureThreshold = PieceValue[Mg][pt]; // captured piece.
ttMove = (ttm && pos.is_pseudo_legal(ttm) ? ttm : MOVE_NONE); captureThreshold = PieceValue[MG][pt];
ttMove = (ttm && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE);
if (ttMove && (!pos.is_capture(ttMove) || pos.see(ttMove) <= captureThreshold)) if (ttMove && (!pos.capture(ttMove) || pos.see(ttMove) <= captureThreshold))
ttMove = MOVE_NONE; ttMove = MOVE_NONE;
end += (ttMove != MOVE_NONE); end += (ttMove != MOVE_NONE);
} }
/// MovePicker::score_captures(), MovePicker::score_noncaptures() and /// score() assign a numerical value to each move in a move list. The moves with
/// MovePicker::score_evasions() assign a numerical move ordering score /// highest values will be picked first.
/// to each move in a move list. The moves with highest scores will be template<>
/// picked first by next_move(). void MovePicker::score<CAPTURES>() {
void MovePicker::score_captures() {
// Winning and equal captures in the main search are ordered by MVV/LVA. // Winning and equal captures in the main search are ordered by MVV/LVA.
// Suprisingly, this appears to perform slightly better than SEE based // Suprisingly, this appears to perform slightly better than SEE based
// move ordering. The reason is probably that in a position with a winning // move ordering. The reason is probably that in a position with a winning
@@ -156,89 +148,114 @@ void MovePicker::score_captures() {
// where it is possible to recapture with the hanging piece). Exchanging // where it is possible to recapture with the hanging piece). Exchanging
// big pieces before capturing a hanging piece probably helps to reduce // big pieces before capturing a hanging piece probably helps to reduce
// the subtree size. // the subtree size.
// In main search we want to push captures with negative SEE values to // In main search we want to push captures with negative SEE values to the
// badCaptures[] array, but instead of doing it now we delay till when // badCaptures[] array, but instead of doing it now we delay until the move
// the move has been picked up in pick_move_from_list(), this way we save // has been picked up in pick_move_from_list(). This way we save some SEE
// some SEE calls in case we get a cutoff (idea from Pablo Vazquez). // calls in case we get a cutoff.
Move m; Move m;
for (MoveStack* it = moves; it != end; ++it) for (ExtMove* it = moves; it != end; ++it)
{ {
m = it->move; m = it->move;
it->score = PieceValue[Mg][pos.piece_on(to_sq(m))] it->value = PieceValue[MG][pos.piece_on(to_sq(m))]
- type_of(pos.piece_moved(m)); - Value(type_of(pos.moved_piece(m)));
if (type_of(m) == PROMOTION) if (type_of(m) == ENPASSANT)
it->score += PieceValue[Mg][promotion_type(m)]; it->value += PieceValue[MG][PAWN];
else if (type_of(m) == PROMOTION)
it->value += PieceValue[MG][promotion_type(m)] - PieceValue[MG][PAWN];
} }
} }
void MovePicker::score_noncaptures() { template<>
void MovePicker::score<QUIETS>() {
Move m; Move m;
for (MoveStack* it = moves; it != end; ++it) for (ExtMove* it = moves; it != end; ++it)
{ {
m = it->move; m = it->move;
it->score = H.value(pos.piece_moved(m), to_sq(m)); it->value = history[pos.moved_piece(m)][to_sq(m)];
} }
} }
void MovePicker::score_evasions() { template<>
void MovePicker::score<EVASIONS>() {
// Try good captures ordered by MVV/LVA, then non-captures if destination square // Try good captures ordered by MVV/LVA, then non-captures if destination square
// is not under attack, ordered by history value, then bad-captures and quiet // is not under attack, ordered by history value, then bad-captures and quiet
// moves with a negative SEE. This last group is ordered by the SEE score. // moves with a negative SEE. This last group is ordered by the SEE value.
Move m; Move m;
int seeScore; Value see;
if (end < moves + 2) for (ExtMove* it = moves; it != end; ++it)
return;
for (MoveStack* it = moves; it != end; ++it)
{ {
m = it->move; m = it->move;
if ((seeScore = pos.see_sign(m)) < 0) if ((see = pos.see_sign(m)) < VALUE_ZERO)
it->score = seeScore - History::MaxValue; // Be sure we are at the bottom it->value = see - HistoryStats::Max; // At the bottom
else if (pos.is_capture(m))
it->score = PieceValue[Mg][pos.piece_on(to_sq(m))] else if (pos.capture(m))
- type_of(pos.piece_moved(m)) + History::MaxValue; it->value = PieceValue[MG][pos.piece_on(to_sq(m))]
- Value(type_of(pos.moved_piece(m))) + HistoryStats::Max;
else else
it->score = H.value(pos.piece_moved(m), to_sq(m)); it->value = history[pos.moved_piece(m)][to_sq(m)];
} }
} }
/// MovePicker::generate_next() generates, scores and sorts the next bunch of moves, /// generate_next_stage() generates, scores and sorts the next bunch of moves,
/// when there are no more moves to try for the current phase. /// when there are no more moves to try for the current stage.
void MovePicker::generate_next() { void MovePicker::generate_next_stage() {
cur = moves; cur = moves;
switch (++phase) { switch (++stage) {
case CAPTURES_S1: case CAPTURES_S3: case CAPTURES_S4: case CAPTURES_S5: case CAPTURES_S6: case CAPTURES_S1: case CAPTURES_S3: case CAPTURES_S4: case CAPTURES_S5: case CAPTURES_S6:
end = generate<CAPTURES>(pos, moves); end = generate<CAPTURES>(pos, moves);
score_captures(); score<CAPTURES>();
return; return;
case KILLERS_S1: case KILLERS_S1:
cur = killers; cur = killers;
end = cur + 2; end = cur + 2;
killers[0].move = ss->killers[0];
killers[1].move = ss->killers[1];
killers[2].move = killers[3].move = MOVE_NONE;
killers[4].move = killers[5].move = MOVE_NONE;
// Please note that following code is racy and could yield to rare (less
// than 1 out of a million) duplicated entries in SMP case. This is harmless.
// Be sure countermoves are different from killers
for (int i = 0; i < 2; ++i)
if ( countermoves[i] != (cur+0)->move
&& countermoves[i] != (cur+1)->move)
(end++)->move = countermoves[i];
// Be sure followupmoves are different from killers and countermoves
for (int i = 0; i < 2; ++i)
if ( followupmoves[i] != (cur+0)->move
&& followupmoves[i] != (cur+1)->move
&& followupmoves[i] != (cur+2)->move
&& followupmoves[i] != (cur+3)->move)
(end++)->move = followupmoves[i];
return; return;
case QUIETS_1_S1: case QUIETS_1_S1:
endQuiets = end = generate<QUIETS>(pos, moves); endQuiets = end = generate<QUIETS>(pos, moves);
score_noncaptures(); score<QUIETS>();
end = std::partition(cur, end, has_positive_score); end = std::partition(cur, end, has_positive_value);
sort<MoveStack>(cur, end); insertion_sort(cur, end);
return; return;
case QUIETS_2_S1: case QUIETS_2_S1:
cur = end; cur = end;
end = endQuiets; end = endQuiets;
if (depth >= 3 * ONE_PLY) if (depth >= 3 * ONE_PLY)
sort<MoveStack>(cur, end); insertion_sort(cur, end);
return; return;
case BAD_CAPTURES_S1: case BAD_CAPTURES_S1:
@@ -249,7 +266,8 @@ void MovePicker::generate_next() {
case EVASIONS_S2: case EVASIONS_S2:
end = generate<EVASIONS>(pos, moves); end = generate<EVASIONS>(pos, moves);
score_evasions(); if (end > moves + 1)
score<EVASIONS>();
return; return;
case QUIET_CHECKS_S3: case QUIET_CHECKS_S3:
@@ -257,7 +275,9 @@ void MovePicker::generate_next() {
return; return;
case EVASION: case QSEARCH_0: case QSEARCH_1: case PROBCUT: case RECAPTURE: case EVASION: case QSEARCH_0: case QSEARCH_1: case PROBCUT: case RECAPTURE:
phase = STOP; stage = STOP;
/* Fall through */
case STOP: case STOP:
end = cur + 1; // Avoid another next_phase() call end = cur + 1; // Avoid another next_phase() call
return; return;
@@ -268,11 +288,10 @@ void MovePicker::generate_next() {
} }
/// MovePicker::next_move() is the most important method of the MovePicker class. /// next_move() is the most important method of the MovePicker class. It returns
/// It returns a new pseudo legal move every time it is called, until there /// a new pseudo legal move every time it is called, until there are no more moves
/// are no more moves left. It picks the move with the biggest score from a list /// left. It picks the move with the biggest value from a list of generated moves
/// of generated moves taking care not to return the tt move if has already been /// taking care not to return the ttMove if it has already been searched.
/// searched previously.
template<> template<>
Move MovePicker::next_move<false>() { Move MovePicker::next_move<false>() {
@@ -281,21 +300,19 @@ Move MovePicker::next_move<false>() {
while (true) while (true)
{ {
while (cur == end) while (cur == end)
generate_next(); generate_next_stage();
switch (phase) { switch (stage) {
case MAIN_SEARCH: case EVASION: case QSEARCH_0: case QSEARCH_1: case PROBCUT: case MAIN_SEARCH: case EVASION: case QSEARCH_0: case QSEARCH_1: case PROBCUT:
cur++; ++cur;
return ttMove; return ttMove;
case CAPTURES_S1: case CAPTURES_S1:
move = pick_best(cur++, end)->move; move = pick_best(cur++, end)->move;
if (move != ttMove) if (move != ttMove)
{ {
assert(captureThreshold <= 0); // Otherwise we cannot use see_sign() if (pos.see_sign(move) >= VALUE_ZERO)
if (pos.see_sign(move) >= captureThreshold)
return move; return move;
// Losing capture, move it to the tail of the array // Losing capture, move it to the tail of the array
@@ -306,9 +323,9 @@ Move MovePicker::next_move<false>() {
case KILLERS_S1: case KILLERS_S1:
move = (cur++)->move; move = (cur++)->move;
if ( move != MOVE_NONE if ( move != MOVE_NONE
&& pos.is_pseudo_legal(move)
&& move != ttMove && move != ttMove
&& !pos.is_capture(move)) && pos.pseudo_legal(move)
&& !pos.capture(move))
return move; return move;
break; break;
@@ -316,7 +333,11 @@ Move MovePicker::next_move<false>() {
move = (cur++)->move; move = (cur++)->move;
if ( move != ttMove if ( move != ttMove
&& move != killers[0].move && move != killers[0].move
&& move != killers[1].move) && move != killers[1].move
&& move != killers[2].move
&& move != killers[3].move
&& move != killers[4].move
&& move != killers[5].move)
return move; return move;
break; break;
@@ -359,6 +380,6 @@ Move MovePicker::next_move<false>() {
/// Version of next_move() to use at split point nodes where the move is grabbed /// Version of next_move() to use at split point nodes where the move is grabbed
/// from the split point's shared MovePicker object. This function is not thread /// from the split point's shared MovePicker object. This function is not thread
/// safe so should be lock protected by the caller. /// safe so must be lock protected by the caller.
template<> template<>
Move MovePicker::next_move<true>() { return ss->sp->mp->next_move<false>(); } Move MovePicker::next_move<true>() { return ss->splitPoint->movePicker->next_move<false>(); }
+64 -16
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-2012 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, 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
@@ -17,15 +17,61 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#if !defined MOVEPICK_H_INCLUDED #ifndef MOVEPICK_H_INCLUDED
#define MOVEPICK_H_INCLUDED #define MOVEPICK_H_INCLUDED
#include "history.h" #include <algorithm> // For std::max
#include <cstring> // For std::memset
#include "movegen.h"
#include "position.h" #include "position.h"
#include "search.h" #include "search.h"
#include "types.h" #include "types.h"
/// The Stats struct stores moves statistics. According to the template parameter
/// the class can store History, Gains and Countermoves. History records how often
/// different moves have been successful or unsuccessful during the current search
/// and is used for reduction and move ordering decisions. Gains records the move's
/// best evaluation gain from one ply to the next and is used for pruning 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<bool Gain, typename T>
struct Stats {
static const Value Max = Value(250);
const T* operator[](Piece pc) const { return table[pc]; }
void clear() { std::memset(table, 0, sizeof(table)); }
void update(Piece pc, Square to, Move m) {
if (m == table[pc][to].first)
return;
table[pc][to].second = table[pc][to].first;
table[pc][to].first = m;
}
void update(Piece pc, Square to, Value v) {
if (Gain)
table[pc][to] = std::max(v, table[pc][to] - 1);
else if (abs(table[pc][to] + v) < Max)
table[pc][to] += v;
}
private:
T table[PIECE_NB][SQUARE_NB];
};
typedef Stats< true, Value> GainsStats;
typedef Stats<false, Value> HistoryStats;
typedef Stats<false, std::pair<Move, Move> > MovesStats;
/// 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
/// new pseudo legal move each time it is called, until there are no moves left, /// new pseudo legal move each time it is called, until there are no moves left,
@@ -38,27 +84,29 @@ class MovePicker {
MovePicker& operator=(const MovePicker&); // Silence a warning under MSVC MovePicker& operator=(const MovePicker&); // Silence a warning under MSVC
public: public:
MovePicker(const Position&, Move, Depth, const History&, Search::Stack*, Value); MovePicker(const Position&, Move, Depth, const HistoryStats&, Square);
MovePicker(const Position&, Move, Depth, const History&, Square); MovePicker(const Position&, Move, const HistoryStats&, PieceType);
MovePicker(const Position&, Move, const History&, PieceType); MovePicker(const Position&, Move, Depth, const HistoryStats&, Move*, Move*, Search::Stack*);
template<bool SpNode> Move next_move(); template<bool SpNode> Move next_move();
private: private:
void score_captures(); template<GenType> void score();
void score_noncaptures(); void generate_next_stage();
void score_evasions();
void generate_next();
const Position& pos; const Position& pos;
const History& H; const HistoryStats& history;
Search::Stack* ss; Search::Stack* ss;
Move* countermoves;
Move* followupmoves;
Depth depth; Depth depth;
Move ttMove; Move ttMove;
MoveStack killers[2]; ExtMove killers[6];
Square recaptureSquare; Square recaptureSquare;
int captureThreshold, phase; Value captureThreshold;
MoveStack *cur, *end, *endQuiets, *endBadCaptures; int stage;
MoveStack moves[MAX_MOVES]; ExtMove *cur, *end, *endQuiets, *endBadCaptures;
ExtMove moves[MAX_MOVES];
}; };
#endif // !defined(MOVEPICK_H_INCLUDED) #endif // #ifndef MOVEPICK_H_INCLUDED
-271
View File
@@ -1,271 +0,0 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2012 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Stockfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <cassert>
#include <iomanip>
#include <sstream>
#include <string>
#include "movegen.h"
#include "notation.h"
#include "position.h"
using namespace std;
static const char* PieceToChar = " PNBRQK pnbrqk";
/// score_to_uci() converts a value to a string suitable for use with the UCI
/// protocol specifications:
///
/// cp <x> The score from the engine's point of view in centipawns.
/// mate <y> Mate in y moves, not plies. If the engine is getting mated
/// use negative values for y.
string score_to_uci(Value v, Value alpha, Value beta) {
stringstream s;
if (abs(v) < VALUE_MATE_IN_MAX_PLY)
s << "cp " << v * 100 / int(PawnValueMg);
else
s << "mate " << (v > 0 ? VALUE_MATE - v + 1 : -VALUE_MATE - v) / 2;
s << (v >= beta ? " lowerbound" : v <= alpha ? " upperbound" : "");
return s.str();
}
/// move_to_uci() converts a move to a string in coordinate notation
/// (g1f3, a7a8q, etc.). The only special case is castling moves, where we print
/// in the e1g1 notation in normal chess mode, and in e1h1 notation in chess960
/// mode. Internally castle moves are always coded as "king captures rook".
const string move_to_uci(Move m, bool chess960) {
Square from = from_sq(m);
Square to = to_sq(m);
if (m == MOVE_NONE)
return "(none)";
if (m == MOVE_NULL)
return "0000";
if (type_of(m) == CASTLE && !chess960)
to = (to > from ? FILE_G : FILE_C) | rank_of(from);
string move = square_to_string(from) + square_to_string(to);
if (type_of(m) == PROMOTION)
move += PieceToChar[make_piece(BLACK, promotion_type(m))]; // Lower case
return move;
}
/// move_from_uci() takes a position and a string representing a move in
/// simple coordinate notation and returns an equivalent legal Move if any.
Move move_from_uci(const Position& pos, string& str) {
if (str.length() == 5) // Junior could send promotion piece in uppercase
str[4] = char(tolower(str[4]));
for (MoveList<LEGAL> ml(pos); !ml.end(); ++ml)
if (str == move_to_uci(ml.move(), pos.is_chess960()))
return ml.move();
return MOVE_NONE;
}
/// move_to_san() takes a position and a legal Move as input and returns its
/// short algebraic notation representation.
const string move_to_san(Position& pos, Move m) {
if (m == MOVE_NONE)
return "(none)";
if (m == MOVE_NULL)
return "(null)";
assert(pos.move_is_legal(m));
Bitboard attackers;
bool ambiguousMove, ambiguousFile, ambiguousRank;
string san;
Color us = pos.side_to_move();
Square from = from_sq(m);
Square to = to_sq(m);
Piece pc = pos.piece_on(from);
PieceType pt = type_of(pc);
if (type_of(m) == CASTLE)
san = to > from ? "O-O" : "O-O-O";
else
{
if (pt != PAWN)
{
san = PieceToChar[pt]; // Upper case
// Disambiguation if we have more then one piece with destination 'to'
// note that for pawns is not needed because starting file is explicit.
ambiguousMove = ambiguousFile = ambiguousRank = false;
attackers = (pos.attacks_from(pc, to) & pos.pieces(us, pt)) ^ from;
while (attackers)
{
Square sq = pop_lsb(&attackers);
// Pinned pieces are not included in the possible sub-set
if (!pos.pl_move_is_legal(make_move(sq, to), pos.pinned_pieces()))
continue;
ambiguousFile |= file_of(sq) == file_of(from);
ambiguousRank |= rank_of(sq) == rank_of(from);
ambiguousMove = true;
}
if (ambiguousMove)
{
if (!ambiguousFile)
san += file_to_char(file_of(from));
else if (!ambiguousRank)
san += rank_to_char(rank_of(from));
else
san += square_to_string(from);
}
}
else if (pos.is_capture(m))
san = file_to_char(file_of(from));
if (pos.is_capture(m))
san += 'x';
san += square_to_string(to);
if (type_of(m) == PROMOTION)
san += string("=") + PieceToChar[promotion_type(m)];
}
if (pos.move_gives_check(m, CheckInfo(pos)))
{
StateInfo st;
pos.do_move(m, st);
san += MoveList<LEGAL>(pos).size() ? "+" : "#";
pos.undo_move(m);
}
return san;
}
/// pretty_pv() formats human-readable search information, typically to be
/// appended to the search log file. It uses the two helpers below to pretty
/// format time and score respectively.
static string time_to_string(int64_t msecs) {
const int MSecMinute = 1000 * 60;
const int MSecHour = 1000 * 60 * 60;
int64_t hours = msecs / MSecHour;
int64_t minutes = (msecs % MSecHour) / MSecMinute;
int64_t seconds = ((msecs % MSecHour) % MSecMinute) / 1000;
stringstream s;
if (hours)
s << hours << ':';
s << setfill('0') << setw(2) << minutes << ':' << setw(2) << seconds;
return s.str();
}
static string score_to_string(Value v) {
stringstream s;
if (v >= VALUE_MATE_IN_MAX_PLY)
s << "#" << (VALUE_MATE - v + 1) / 2;
else if (v <= VALUE_MATED_IN_MAX_PLY)
s << "-#" << (VALUE_MATE + v) / 2;
else
s << setprecision(2) << fixed << showpos << float(v) / PawnValueMg;
return s.str();
}
string pretty_pv(Position& pos, int depth, Value value, int64_t msecs, Move pv[]) {
const int64_t K = 1000;
const int64_t M = 1000000;
StateInfo state[MAX_PLY_PLUS_2], *st = state;
Move* m = pv;
string san, padding;
size_t length;
stringstream s;
s << setw(2) << depth
<< setw(8) << score_to_string(value)
<< setw(8) << time_to_string(msecs);
if (pos.nodes_searched() < M)
s << setw(8) << pos.nodes_searched() / 1 << " ";
else if (pos.nodes_searched() < K * M)
s << setw(7) << pos.nodes_searched() / K << "K ";
else
s << setw(7) << pos.nodes_searched() / M << "M ";
padding = string(s.str().length(), ' ');
length = padding.length();
while (*m != MOVE_NONE)
{
san = move_to_san(pos, *m);
if (length + san.length() > 80)
{
s << "\n" + padding;
length = padding.length();
}
s << san << ' ';
length += san.length() + 1;
pos.do_move(*m++, *st++);
}
while (m != pv)
pos.undo_move(*--m);
return s.str();
}
-35
View File
@@ -1,35 +0,0 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2012 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Stockfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined(NOTATION_H_INCLUDED)
#define NOTATION_H_INCLUDED
#include <string>
#include "types.h"
class Position;
std::string score_to_uci(Value v, Value alpha = -VALUE_INFINITE, Value beta = VALUE_INFINITE);
Move move_from_uci(const Position& pos, std::string& str);
const std::string move_to_uci(Move m, bool chess960);
const std::string move_to_san(Position& pos, Move m);
std::string pretty_pv(Position& pos, int depth, Value score, int64_t msecs, Move pv[]);
#endif // !defined(NOTATION_H_INCLUDED)
+212 -187
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-2012 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, 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
@@ -17,271 +17,296 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <algorithm>
#include <cassert> #include <cassert>
#include "bitboard.h" #include "bitboard.h"
#include "bitcount.h" #include "bitcount.h"
#include "pawns.h" #include "pawns.h"
#include "position.h" #include "position.h"
#include "thread.h"
namespace { namespace {
#define V Value #define V Value
#define S(mg, eg) make_score(mg, eg) #define S(mg, eg) make_score(mg, eg)
// Doubled pawn penalty by opposed flag and file // Doubled pawn penalty by file
const Score DoubledPawnPenalty[2][8] = { const Score Doubled[FILE_NB] = {
{ S(13, 43), S(20, 48), S(23, 48), S(23, 48), S(13, 43), S(20, 48), S(23, 48), S(23, 48),
S(23, 48), S(23, 48), S(20, 48), S(13, 43) }, S(23, 48), S(23, 48), S(20, 48), S(13, 43) };
{ S(13, 43), S(20, 48), S(23, 48), S(23, 48),
S(23, 48), S(23, 48), S(20, 48), S(13, 43) }};
// Isolated pawn penalty by opposed flag and file // Isolated pawn penalty by opposed flag and file
const Score IsolatedPawnPenalty[2][8] = { const Score Isolated[2][FILE_NB] = {
{ S(37, 45), S(54, 52), S(60, 52), S(60, 52), { S(37, 45), S(54, 52), S(60, 52), S(60, 52),
S(60, 52), S(60, 52), S(54, 52), S(37, 45) }, S(60, 52), S(60, 52), S(54, 52), S(37, 45) },
{ S(25, 30), S(36, 35), S(40, 35), S(40, 35), { S(25, 30), S(36, 35), S(40, 35), S(40, 35),
S(40, 35), S(40, 35), S(36, 35), S(25, 30) }}; S(40, 35), S(40, 35), S(36, 35), S(25, 30) } };
// Backward pawn penalty by opposed flag and file // Backward pawn penalty by opposed flag and file
const Score BackwardPawnPenalty[2][8] = { const Score Backward[2][FILE_NB] = {
{ S(30, 42), S(43, 46), S(49, 46), S(49, 46), { S(30, 42), S(43, 46), S(49, 46), S(49, 46),
S(49, 46), S(49, 46), S(43, 46), S(30, 42) }, S(49, 46), S(49, 46), S(43, 46), S(30, 42) },
{ S(20, 28), S(29, 31), S(33, 31), S(33, 31), { S(20, 28), S(29, 31), S(33, 31), S(33, 31),
S(33, 31), S(33, 31), S(29, 31), S(20, 28) }}; S(33, 31), S(33, 31), S(29, 31), S(20, 28) } };
// Pawn chain membership bonus by file // Connected pawn bonus by opposed, phalanx flags and rank
const Score ChainBonus[8] = { Score Connected[2][2][RANK_NB];
S(11,-1), S(13,-1), S(13,-1), S(14,-1),
S(14,-1), S(13,-1), S(13,-1), S(11,-1)
};
// Candidate passed pawn bonus by rank // Levers bonus by rank
const Score CandidateBonus[8] = { const Score Lever[RANK_NB] = {
S( 0, 0), S( 6, 13), S(6,13), S(14,29), S( 0, 0), S( 0, 0), S(0, 0), S(0, 0),
S(34,68), S(83,166), S(0, 0), S( 0, 0) S(20,20), S(40,40), S(0, 0), S(0, 0) };
};
const Score PawnStructureWeight = S(233, 201); // Unsupported pawn penalty
const Score UnsupportedPawnPenalty = S(20, 10);
// Weakness of our pawn shelter in front of the king indexed by [king pawn][rank] // Weakness of our pawn shelter in front of the king by [distance from edge][rank]
const Value ShelterWeakness[2][8] = const Value ShelterWeakness[][RANK_NB] = {
{ { V(141), V(0), V(38), V(102), V(128), V(141), V(141) }, { V(100), V(13), V(24), V(64), V(89), V( 93), V(104) },
{ V( 61), V(0), V(16), V( 44), V( 56), V( 61), V( 61) } }; { V(110), V( 1), V(29), V(75), V(96), V(102), V(107) },
{ V(102), V( 0), V(39), V(74), V(88), V(101), V( 98) },
{ V( 88), V( 4), V(33), V(67), V(92), V( 94), V(107) } };
// Danger of enemy pawns moving toward our king indexed by [pawn blocked][rank] // Danger of enemy pawns moving toward our king by [type][distance from edge][rank]
const Value StormDanger[2][8] = const Value StormDanger[][4][RANK_NB] = {
{ { V(26), V(0), V(128), V(51), V(26) }, { { V( 0), V( 63), V( 128), V(43), V(27) },
{ V(13), V(0), V( 64), V(25), V(13) } }; { V( 0), V( 62), V( 131), V(44), V(26) },
{ V( 0), V( 59), V( 121), V(50), V(28) },
{ V( 0), V( 62), V( 127), V(54), V(28) } },
{ { V(24), V( 40), V( 93), V(42), V(22) },
{ V(24), V( 28), V( 101), V(38), V(20) },
{ V(24), V( 32), V( 95), V(36), V(23) },
{ V(27), V( 24), V( 99), V(36), V(24) } },
{ { V( 0), V( 0), V( 81), V(16), V( 6) },
{ V( 0), V( 0), V( 165), V(29), V( 9) },
{ V( 0), V( 0), V( 163), V(23), V(12) },
{ V( 0), V( 0), V( 161), V(28), V(13) } },
{ { V( 0), V(-296), V(-299), V(55), V(25) },
{ V( 0), V( 67), V( 131), V(46), V(21) },
{ V( 0), V( 65), V( 135), V(50), V(31) },
{ V( 0), V( 62), V( 128), V(51), V(24) } } };
// Max bonus for king safety. Corresponds to start position with all the pawns // Max bonus for king safety. Corresponds to start position with all the pawns
// in front of the king and no enemy pawn on the horizont. // in front of the king and no enemy pawn on the horizon.
const Value MaxSafetyBonus = V(263); const Value MaxSafetyBonus = V(257);
#undef S #undef S
#undef V #undef V
template<Color Us>
Score evaluate(const Position& pos, Pawns::Entry* e) {
const Color Them = (Us == WHITE ? BLACK : WHITE);
const Square Up = (Us == WHITE ? DELTA_N : DELTA_S);
const Square Right = (Us == WHITE ? DELTA_NE : DELTA_SW);
const Square Left = (Us == WHITE ? DELTA_NW : DELTA_SE);
Bitboard b, p, doubled, connected;
Square s;
bool passed, isolated, opposed, phalanx, backward, unsupported, lever;
Score score = SCORE_ZERO;
const Square* pl = pos.list<PAWN>(Us);
const Bitboard* pawnAttacksBB = StepAttacksBB[make_piece(Us, PAWN)];
Bitboard ourPawns = pos.pieces(Us , PAWN);
Bitboard theirPawns = pos.pieces(Them, PAWN);
e->passedPawns[Us] = 0;
e->kingSquares[Us] = SQ_NONE;
e->semiopenFiles[Us] = 0xFF;
e->pawnAttacks[Us] = shift_bb<Right>(ourPawns) | shift_bb<Left>(ourPawns);
e->pawnsOnSquares[Us][BLACK] = popcount<Max15>(ourPawns & DarkSquares);
e->pawnsOnSquares[Us][WHITE] = pos.count<PAWN>(Us) - e->pawnsOnSquares[Us][BLACK];
// Loop through all pawns of the current color and score each pawn
while ((s = *pl++) != SQ_NONE)
{
assert(pos.piece_on(s) == make_piece(Us, PAWN));
File f = file_of(s);
// This file cannot be semi-open
e->semiopenFiles[Us] &= ~(1 << f);
// Previous rank
p = rank_bb(s - pawn_push(Us));
// Flag the pawn as passed, isolated, doubled,
// unsupported or connected (but not the backward one).
connected = ourPawns & adjacent_files_bb(f) & (rank_bb(s) | p);
phalanx = connected & rank_bb(s);
unsupported = !(ourPawns & adjacent_files_bb(f) & p);
isolated = !(ourPawns & adjacent_files_bb(f));
doubled = ourPawns & forward_bb(Us, s);
opposed = theirPawns & forward_bb(Us, s);
passed = !(theirPawns & passed_pawn_mask(Us, s));
lever = theirPawns & pawnAttacksBB[s];
// Test for backward pawn.
// If the pawn is passed, isolated, or connected it cannot be
// backward. If there are friendly pawns behind on adjacent files
// or if it can capture an enemy pawn it cannot be backward either.
if ( (passed | isolated | connected)
|| (ourPawns & pawn_attack_span(Them, s))
|| (pos.attacks_from<PAWN>(s, Us) & theirPawns))
backward = false;
else
{
// We now know that there are no friendly pawns beside or behind this
// pawn on adjacent files. We now check whether the pawn is
// backward by looking in the forward direction on the adjacent
// files, and picking the closest pawn there.
b = pawn_attack_span(Us, s) & (ourPawns | theirPawns);
b = pawn_attack_span(Us, s) & rank_bb(backmost_sq(Us, b));
// If we have an enemy pawn in the same or next rank, the pawn is
// backward because it cannot advance without being captured.
backward = (b | shift_bb<Up>(b)) & theirPawns;
}
assert(opposed | passed | (pawn_attack_span(Us, s) & theirPawns));
// Passed pawns will be properly scored in evaluation because we need
// full attack info to evaluate passed pawns. Only the frontmost passed
// pawn on each file is considered a true passed pawn.
if (passed && !doubled)
e->passedPawns[Us] |= s;
// Score this pawn
if (isolated)
score -= Isolated[opposed][f];
if (unsupported && !isolated)
score -= UnsupportedPawnPenalty;
if (doubled)
score -= Doubled[f] / distance<Rank>(s, frontmost_sq(Us, doubled));
if (backward)
score -= Backward[opposed][f];
if (connected)
score += Connected[opposed][phalanx][relative_rank(Us, s)];
if (lever)
score += Lever[relative_rank(Us, s)];
}
b = e->semiopenFiles[Us] ^ 0xFF;
e->pawnSpan[Us] = b ? int(msb(b) - lsb(b)) : 0;
return score;
}
} // namespace
namespace Pawns {
/// Pawns::init() initializes some tables needed by evaluation. Instead of using
/// hard-coded tables, when makes sense, we prefer to calculate them with a formula
/// to reduce independent parameters and to allow easier tuning and better insight.
void init()
{
static const int Seed[RANK_NB] = { 0, 6, 15, 10, 57, 75, 135, 258 };
for (int opposed = 0; opposed <= 1; ++opposed)
for (int phalanx = 0; phalanx <= 1; ++phalanx)
for (Rank r = RANK_2; r < RANK_8; ++r)
{
int bonus = Seed[r] + (phalanx ? (Seed[r + 1] - Seed[r]) / 2 : 0);
Connected[opposed][phalanx][r] = make_score(bonus / 2, bonus >> opposed);
}
} }
/// PawnTable::probe() takes a position object as input, computes a PawnEntry /// Pawns::probe() looks up the current position's pawns configuration in
/// object, and returns a pointer to it. The result is also stored in a hash /// the pawns hash table. It returns a pointer to the Entry if the position
/// table, so we don't have to recompute everything when the same pawn structure /// is found. Otherwise a new Entry is computed and stored there, so we don't
/// occurs again. /// have to recompute all when the same pawns configuration occurs again.
PawnEntry* PawnTable::probe(const Position& pos) { Entry* probe(const Position& pos) {
Key key = pos.pawn_key(); Key key = pos.pawn_key();
PawnEntry* e = entries[key]; Entry* e = pos.this_thread()->pawnsTable[key];
// If e->key matches the position's pawn hash key, it means that we
// have analysed this pawn structure before, and we can simply return
// the information we found the last time instead of recomputing it.
if (e->key == key) if (e->key == key)
return e; return e;
e->key = key; e->key = key;
e->passedPawns[WHITE] = e->passedPawns[BLACK] = 0; e->score = evaluate<WHITE>(pos, e) - evaluate<BLACK>(pos, e);
e->kingSquares[WHITE] = e->kingSquares[BLACK] = SQ_NONE;
e->halfOpenFiles[WHITE] = e->halfOpenFiles[BLACK] = 0xFF;
Bitboard wPawns = pos.pieces(WHITE, PAWN);
Bitboard bPawns = pos.pieces(BLACK, PAWN);
e->pawnAttacks[WHITE] = ((wPawns & ~FileHBB) << 9) | ((wPawns & ~FileABB) << 7);
e->pawnAttacks[BLACK] = ((bPawns & ~FileHBB) >> 7) | ((bPawns & ~FileABB) >> 9);
e->value = evaluate_pawns<WHITE>(pos, wPawns, bPawns, e)
- evaluate_pawns<BLACK>(pos, bPawns, wPawns, e);
e->value = apply_weight(e->value, PawnStructureWeight);
return e; return e;
} }
/// PawnTable::evaluate_pawns() evaluates each pawn of the given color /// Entry::shelter_storm() calculates shelter and storm penalties for the file
template<Color Us>
Score PawnTable::evaluate_pawns(const Position& pos, Bitboard ourPawns,
Bitboard theirPawns, PawnEntry* e) {
const Color Them = (Us == WHITE ? BLACK : WHITE);
Bitboard b;
Square s;
File f;
Rank r;
bool passed, isolated, doubled, opposed, chain, backward, candidate;
Score value = SCORE_ZERO;
const Square* pl = pos.piece_list(Us, PAWN);
// Loop through all pawns of the current color and score each pawn
while ((s = *pl++) != SQ_NONE)
{
assert(pos.piece_on(s) == make_piece(Us, PAWN));
f = file_of(s);
r = rank_of(s);
// This file cannot be half open
e->halfOpenFiles[Us] &= ~(1 << f);
// Our rank plus previous one. Used for chain detection
b = rank_bb(r) | rank_bb(Us == WHITE ? r - Rank(1) : r + Rank(1));
// Flag the pawn as passed, isolated, doubled or member of a pawn
// chain (but not the backward one).
chain = ourPawns & adjacent_files_bb(f) & b;
isolated = !(ourPawns & adjacent_files_bb(f));
doubled = ourPawns & forward_bb(Us, s);
opposed = theirPawns & forward_bb(Us, s);
passed = !(theirPawns & passed_pawn_mask(Us, s));
// Test for backward pawn
backward = false;
// If the pawn is passed, isolated, or member of a pawn chain it cannot
// be backward. If there are friendly pawns behind on adjacent files
// or if can capture an enemy pawn it cannot be backward either.
if ( !(passed | isolated | chain)
&& !(ourPawns & attack_span_mask(Them, s))
&& !(pos.attacks_from<PAWN>(s, Us) & theirPawns))
{
// We now know that there are no friendly pawns beside or behind this
// pawn on adjacent files. We now check whether the pawn is
// backward by looking in the forward direction on the adjacent
// files, and seeing whether we meet a friendly or an enemy pawn first.
b = pos.attacks_from<PAWN>(s, Us);
// Note that we are sure to find something because pawn is not passed
// nor isolated, so loop is potentially infinite, but it isn't.
while (!(b & (ourPawns | theirPawns)))
Us == WHITE ? b <<= 8 : b >>= 8;
// The friendly pawn needs to be at least two ranks closer than the
// enemy pawn in order to help the potentially backward pawn advance.
backward = (b | (Us == WHITE ? b << 8 : b >> 8)) & theirPawns;
}
assert(opposed | passed | (attack_span_mask(Us, s) & theirPawns));
// A not passed pawn is a candidate to become passed if it is free to
// advance and if the number of friendly pawns beside or behind this
// pawn on adjacent files is higher or equal than the number of
// enemy pawns in the forward direction on the adjacent files.
candidate = !(opposed | passed | backward | isolated)
&& (b = attack_span_mask(Them, s + pawn_push(Us)) & ourPawns) != 0
&& popcount<Max15>(b) >= popcount<Max15>(attack_span_mask(Us, s) & theirPawns);
// Passed pawns will be properly scored in evaluation because we need
// full attack info to evaluate passed pawns. Only the frontmost passed
// pawn on each file is considered a true passed pawn.
if (passed && !doubled)
e->passedPawns[Us] |= s;
// Score this pawn
if (isolated)
value -= IsolatedPawnPenalty[opposed][f];
if (doubled)
value -= DoubledPawnPenalty[opposed][f];
if (backward)
value -= BackwardPawnPenalty[opposed][f];
if (chain)
value += ChainBonus[f];
if (candidate)
value += CandidateBonus[relative_rank(Us, s)];
}
return value;
}
/// PawnEntry::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 adjacent files.
template<Color Us> template<Color Us>
Value PawnEntry::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);
Value safety = MaxSafetyBonus; enum { NoFriendlyPawn, Unblocked, BlockedByPawn, BlockedByKing };
Bitboard b = pos.pieces(PAWN) & (in_front_bb(Us, ksq) | rank_bb(ksq));
Bitboard ourPawns = b & pos.pieces(Us) & ~rank_bb(ksq); Bitboard b = pos.pieces(PAWN) & (in_front_bb(Us, rank_of(ksq)) | rank_bb(ksq));
Bitboard ourPawns = b & pos.pieces(Us);
Bitboard theirPawns = b & pos.pieces(Them); Bitboard theirPawns = b & pos.pieces(Them);
Rank rkUs, rkThem; Value safety = MaxSafetyBonus;
File kf = file_of(ksq); File center = std::max(FILE_B, std::min(FILE_G, file_of(ksq)));
kf = (kf == FILE_A) ? kf++ : (kf == FILE_H) ? kf-- : kf; for (File f = center - File(1); f <= center + File(1); ++f)
for (int f = kf - 1; f <= kf + 1; f++)
{ {
// Shelter penalty is higher for the pawn in front of the king b = ourPawns & file_bb(f);
b = ourPawns & FileBB[f]; Rank rkUs = b ? relative_rank(Us, backmost_sq(Us, b)) : RANK_1;
rkUs = b ? rank_of(Us == WHITE ? lsb(b) : ~msb(b)) : RANK_1;
safety -= ShelterWeakness[f != kf][rkUs];
// Storm danger is smaller if enemy pawn is blocked b = theirPawns & file_bb(f);
b = theirPawns & FileBB[f]; Rank rkThem = b ? relative_rank(Us, frontmost_sq(Them, b)) : RANK_1;
rkThem = b ? rank_of(Us == WHITE ? lsb(b) : ~msb(b)) : RANK_1;
safety -= StormDanger[rkThem == rkUs + 1][rkThem]; safety -= ShelterWeakness[std::min(f, FILE_H - f)][rkUs]
+ StormDanger
[f == file_of(ksq) && rkThem == relative_rank(Us, ksq) + 1 ? BlockedByKing :
rkUs == RANK_1 ? NoFriendlyPawn :
rkThem == rkUs + 1 ? BlockedByPawn : Unblocked]
[std::min(f, FILE_H - f)][rkThem];
} }
return safety; return safety;
} }
/// PawnEntry::update_safety() calculates and caches a bonus for king safety. It is /// Entry::do_king_safety() calculates a bonus for king safety. It is called only
/// called only when king square changes, about 20% of total king_safety() calls. /// when king square changes, which is about 20% of total king_safety() calls.
template<Color Us> template<Color Us>
Score PawnEntry::update_safety(const Position& pos, Square ksq) { Score Entry::do_king_safety(const Position& pos, Square ksq) {
kingSquares[Us] = ksq; kingSquares[Us] = ksq;
castleRights[Us] = pos.can_castle(Us); castlingRights[Us] = pos.can_castle(Us);
minKPdistance[Us] = 0; minKingPawnDistance[Us] = 0;
Bitboard pawns = pos.pieces(Us, PAWN); Bitboard pawns = pos.pieces(Us, PAWN);
if (pawns) if (pawns)
while (!(DistanceRingsBB[ksq][minKPdistance[Us]++] & pawns)) {} while (!(DistanceRingBB[ksq][minKingPawnDistance[Us]++] & pawns)) {}
if (relative_rank(Us, ksq) > RANK_4) if (relative_rank(Us, ksq) > RANK_4)
return kingSafety[Us] = make_score(0, -16 * minKPdistance[Us]); return make_score(0, -16 * minKingPawnDistance[Us]);
Value bonus = shelter_storm<Us>(pos, ksq); Value bonus = shelter_storm<Us>(pos, ksq);
// If we can castle use the bonus after the castle if is bigger // If we can castle use the bonus after the castling if it is bigger
if (pos.can_castle(make_castle_right(Us, KING_SIDE))) if (pos.can_castle(MakeCastling<Us, KING_SIDE>::right))
bonus = std::max(bonus, shelter_storm<Us>(pos, relative_square(Us, SQ_G1))); bonus = std::max(bonus, shelter_storm<Us>(pos, relative_square(Us, SQ_G1)));
if (pos.can_castle(make_castle_right(Us, QUEEN_SIDE))) if (pos.can_castle(MakeCastling<Us, QUEEN_SIDE>::right))
bonus = std::max(bonus, shelter_storm<Us>(pos, relative_square(Us, SQ_C1))); bonus = std::max(bonus, shelter_storm<Us>(pos, relative_square(Us, SQ_C1)));
return kingSafety[Us] = make_score(bonus, -16 * minKPdistance[Us]); return make_score(bonus, -16 * minKingPawnDistance[Us]);
} }
// Explicit template instantiation // Explicit template instantiation
template Score PawnEntry::update_safety<WHITE>(const Position& pos, Square ksq); template Score Entry::do_king_safety<WHITE>(const Position& pos, Square ksq);
template Score PawnEntry::update_safety<BLACK>(const Position& pos, Square ksq); template Score Entry::do_king_safety<BLACK>(const Position& pos, Square ksq);
} // namespace Pawns
+42 -73
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-2012 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, 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
@@ -17,99 +17,68 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#if !defined(PAWNS_H_INCLUDED) #ifndef PAWNS_H_INCLUDED
#define PAWNS_H_INCLUDED #define PAWNS_H_INCLUDED
#include "misc.h" #include "misc.h"
#include "position.h" #include "position.h"
#include "types.h" #include "types.h"
const int PawnTableSize = 16384; namespace Pawns {
/// PawnEntry is a class which contains various information about a pawn /// Pawns::Entry contains various information about a pawn structure. A lookup
/// structure. Currently, it only includes a middle game and an end game /// to the pawn hash table (performed by calling the probe function) returns a
/// pawn structure evaluation, and a bitboard of passed pawns. We may want /// pointer to an Entry object.
/// to add further information in the future. A lookup to the pawn hash
/// table (performed by calling the probe method in a PawnTable object)
/// returns a pointer to a PawnEntry object.
class PawnEntry { struct Entry {
friend struct PawnTable; Score pawns_score() const { return score; }
Bitboard pawn_attacks(Color c) const { return pawnAttacks[c]; }
Bitboard passed_pawns(Color c) const { return passedPawns[c]; }
int pawn_span(Color c) const { return pawnSpan[c]; }
public: int semiopen_file(Color c, File f) const {
Score pawns_value() const; return semiopenFiles[c] & (1 << f);
Bitboard pawn_attacks(Color c) const; }
Bitboard passed_pawns(Color c) const;
int file_is_half_open(Color c, File f) const; int semiopen_side(Color c, File f, bool leftSide) const {
int has_open_file_to_left(Color c, File f) const; return semiopenFiles[c] & (leftSide ? (1 << f) - 1 : ~((1 << (f + 1)) - 1));
int has_open_file_to_right(Color c, File f) const; }
int pawns_on_same_color_squares(Color c, Square s) const {
return pawnsOnSquares[c][!!(DarkSquares & s)];
}
template<Color Us> template<Color Us>
Score king_safety(const Position& pos, Square ksq); Score king_safety(const Position& pos, Square ksq) {
return kingSquares[Us] == ksq && castlingRights[Us] == pos.can_castle(Us)
? kingSafety[Us] : (kingSafety[Us] = do_king_safety<Us>(pos, ksq));
}
private:
template<Color Us> template<Color Us>
Score update_safety(const Position& pos, Square ksq); Score do_king_safety(const Position& pos, Square ksq);
template<Color Us> template<Color Us>
Value shelter_storm(const Position& pos, Square ksq); Value shelter_storm(const Position& pos, Square ksq);
Key key; Key key;
Bitboard passedPawns[2]; Score score;
Bitboard pawnAttacks[2]; Bitboard passedPawns[COLOR_NB];
Square kingSquares[2]; Bitboard pawnAttacks[COLOR_NB];
int minKPdistance[2]; Square kingSquares[COLOR_NB];
int castleRights[2]; Score kingSafety[COLOR_NB];
Score value; int minKingPawnDistance[COLOR_NB];
int halfOpenFiles[2]; int castlingRights[COLOR_NB];
Score kingSafety[2]; int semiopenFiles[COLOR_NB];
int pawnSpan[COLOR_NB];
int pawnsOnSquares[COLOR_NB][COLOR_NB]; // [color][light/dark squares]
}; };
typedef HashTable<Entry, 16384> Table;
/// The PawnTable class represents a pawn hash table. The most important void init();
/// method is probe, which returns a pointer to a PawnEntry object. Entry* probe(const Position& pos);
struct PawnTable { } // namespace Pawns
PawnEntry* probe(const Position& pos); #endif // #ifndef PAWNS_H_INCLUDED
template<Color Us>
static Score evaluate_pawns(const Position& pos, Bitboard ourPawns,
Bitboard theirPawns, PawnEntry* e);
HashTable<PawnEntry, PawnTableSize> entries;
};
inline Score PawnEntry::pawns_value() const {
return value;
}
inline Bitboard PawnEntry::pawn_attacks(Color c) const {
return pawnAttacks[c];
}
inline Bitboard PawnEntry::passed_pawns(Color c) const {
return passedPawns[c];
}
inline int PawnEntry::file_is_half_open(Color c, File f) const {
return halfOpenFiles[c] & (1 << int(f));
}
inline int PawnEntry::has_open_file_to_left(Color c, File f) const {
return halfOpenFiles[c] & ((1 << int(f)) - 1);
}
inline int PawnEntry::has_open_file_to_right(Color c, File f) const {
return halfOpenFiles[c] & ~((1 << int(f+1)) - 1);
}
template<Color Us>
inline Score PawnEntry::king_safety(const Position& pos, Square ksq) {
return kingSquares[Us] == ksq && castleRights[Us] == pos.can_castle(Us)
? kingSafety[Us] : update_safety<Us>(pos, ksq);
}
#endif // !defined(PAWNS_H_INCLUDED)
+24 -17
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-2012 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, 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
@@ -17,12 +17,12 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#if !defined(PLATFORM_H_INCLUDED) #ifndef PLATFORM_H_INCLUDED
#define PLATFORM_H_INCLUDED #define PLATFORM_H_INCLUDED
#if defined(_MSC_VER) #ifdef _MSC_VER
// Disable some silly and noisy warning from MSVC compiler // Disable some silly and noisy warnings from MSVC compiler
#pragma warning(disable: 4127) // Conditional expression is constant #pragma warning(disable: 4127) // Conditional expression is constant
#pragma warning(disable: 4146) // Unary minus operator applied to unsigned type #pragma warning(disable: 4146) // Unary minus operator applied to unsigned type
#pragma warning(disable: 4800) // Forcing value to bool 'true' or 'false' #pragma warning(disable: 4800) // Forcing value to bool 'true' or 'false'
@@ -42,13 +42,15 @@ typedef unsigned __int64 uint64_t;
# include <inttypes.h> # include <inttypes.h>
#endif #endif
#if !defined(_WIN32) && !defined(_WIN64) // Linux - Unix #ifndef _WIN32 // Linux - Unix
# include <sys/time.h> # include <sys/time.h>
typedef timeval sys_time_t;
inline void system_time(sys_time_t* t) { gettimeofday(t, NULL); } inline int64_t system_time_to_msec() {
inline int64_t time_to_msec(const sys_time_t& t) { return t.tv_sec * 1000LL + t.tv_usec / 1000; } timeval t;
gettimeofday(&t, NULL);
return t.tv_sec * 1000LL + t.tv_usec / 1000;
}
# include <pthread.h> # include <pthread.h>
typedef pthread_mutex_t Lock; typedef pthread_mutex_t Lock;
@@ -65,18 +67,20 @@ typedef void*(*pt_start_fn)(void*);
# define cond_signal(x) pthread_cond_signal(&(x)) # define cond_signal(x) pthread_cond_signal(&(x))
# define cond_wait(x,y) pthread_cond_wait(&(x),&(y)) # define cond_wait(x,y) pthread_cond_wait(&(x),&(y))
# define cond_timedwait(x,y,z) pthread_cond_timedwait(&(x),&(y),z) # define cond_timedwait(x,y,z) pthread_cond_timedwait(&(x),&(y),z)
# define thread_create(x,f,t) !pthread_create(&(x),NULL,(pt_start_fn)f,t) # define thread_create(x,f,t) pthread_create(&(x),NULL,(pt_start_fn)f,t)
# define thread_join(x) pthread_join(x, NULL) # define thread_join(x) pthread_join(x, NULL)
#else // Windows and MinGW #else // Windows and MinGW
# include <sys/timeb.h> # include <sys/timeb.h>
typedef _timeb sys_time_t;
inline void system_time(sys_time_t* t) { _ftime(t); } inline int64_t system_time_to_msec() {
inline int64_t time_to_msec(const sys_time_t& t) { return t.time * 1000LL + t.millitm; } _timeb t;
_ftime(&t);
return t.time * 1000LL + t.millitm;
}
#if !defined(NOMINMAX) #ifndef NOMINMAX
# define NOMINMAX // disable macros min() and max() # define NOMINMAX // disable macros min() and max()
#endif #endif
@@ -85,13 +89,16 @@ inline int64_t time_to_msec(const sys_time_t& t) { return t.time * 1000LL + t.mi
#undef WIN32_LEAN_AND_MEAN #undef WIN32_LEAN_AND_MEAN
#undef NOMINMAX #undef NOMINMAX
// We use critical sections on Windows to support Windows XP and older versions, // We use critical sections on Windows to support Windows XP and older versions.
// unfortunatly cond_wait() is racy between lock_release() and WaitForSingleObject() // Unfortunately, cond_wait() is racy between lock_release() and WaitForSingleObject()
// but apart from this they have the same speed performance of SRW locks. // but apart from this they have the same speed performance of SRW locks.
typedef CRITICAL_SECTION Lock; typedef CRITICAL_SECTION Lock;
typedef HANDLE WaitCondition; typedef HANDLE WaitCondition;
typedef HANDLE NativeHandle; typedef HANDLE NativeHandle;
// On Windows 95 and 98 parameter lpThreadId may not be null
inline DWORD* dwWin9xKludge() { static DWORD dw; return &dw; }
# define lock_init(x) InitializeCriticalSection(&(x)) # define lock_init(x) InitializeCriticalSection(&(x))
# define lock_grab(x) EnterCriticalSection(&(x)) # define lock_grab(x) EnterCriticalSection(&(x))
# define lock_release(x) LeaveCriticalSection(&(x)) # define lock_release(x) LeaveCriticalSection(&(x))
@@ -101,9 +108,9 @@ typedef HANDLE NativeHandle;
# define cond_signal(x) SetEvent(x) # define cond_signal(x) SetEvent(x)
# define cond_wait(x,y) { lock_release(y); WaitForSingleObject(x, INFINITE); lock_grab(y); } # define cond_wait(x,y) { lock_release(y); WaitForSingleObject(x, INFINITE); lock_grab(y); }
# define cond_timedwait(x,y,z) { lock_release(y); WaitForSingleObject(x,z); lock_grab(y); } # define cond_timedwait(x,y,z) { lock_release(y); WaitForSingleObject(x,z); lock_grab(y); }
# define thread_create(x,f,t) (x = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)f,t,0,NULL), x != NULL) # define thread_create(x,f,t) (x = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)f,t,0,dwWin9xKludge()))
# define thread_join(x) { WaitForSingleObject(x, INFINITE); CloseHandle(x); } # define thread_join(x) { WaitForSingleObject(x, INFINITE); CloseHandle(x); }
#endif #endif
#endif // !defined(PLATFORM_H_INCLUDED) #endif // #ifndef PLATFORM_H_INCLUDED
+592 -1002
View File
File diff suppressed because it is too large Load Diff
+197 -190
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-2012 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, 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
@@ -17,19 +17,21 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#if !defined(POSITION_H_INCLUDED) #ifndef POSITION_H_INCLUDED
#define POSITION_H_INCLUDED #define POSITION_H_INCLUDED
#include <cassert> #include <cassert>
#include <cstddef> // For offsetof()
#include <string>
#include "bitboard.h" #include "bitboard.h"
#include "types.h" #include "types.h"
/// The checkInfo struct is initialized at c'tor time and keeps info used
/// to detect if a move gives check.
class Position; class Position;
class Thread; struct Thread;
/// CheckInfo struct is initialized at c'tor time and keeps info used to detect
/// if a move gives check.
struct CheckInfo { struct CheckInfo {
@@ -37,71 +39,62 @@ struct CheckInfo {
Bitboard dcCandidates; Bitboard dcCandidates;
Bitboard pinned; Bitboard pinned;
Bitboard checkSq[8]; Bitboard checkSq[PIECE_TYPE_NB];
Square ksq; Square ksq;
}; };
/// The StateInfo struct stores information we need to restore a Position /// StateInfo struct stores information needed to restore a Position object to
/// object to its previous state when we retract a move. Whenever a move /// its previous state when we retract a move. Whenever a move is made on the
/// is made on the board (by calling Position::do_move), an StateInfo object /// board (by calling Position::do_move), a StateInfo object must be passed.
/// must be passed as a parameter.
struct StateInfo { struct StateInfo {
Key pawnKey, materialKey;
Value npMaterial[2]; // Copied when making a move
int castleRights, rule50, pliesFromNull; Key pawnKey;
Score psqScore; Key materialKey;
Value nonPawnMaterial[COLOR_NB];
int castlingRights;
int rule50;
int pliesFromNull;
Score psq;
Square epSquare; Square epSquare;
Key key; // Not copied when making a move
Bitboard checkersBB; Key key;
PieceType capturedType; Bitboard checkersBB;
PieceType capturedType;
StateInfo* previous; StateInfo* previous;
}; };
struct ReducedStateInfo {
Key pawnKey, materialKey; /// When making a move the current StateInfo up to 'key' excluded is copied to
Value npMaterial[2]; /// the new one. Here we calculate the quad words (64 bit) needed to be copied.
int castleRights, rule50, pliesFromNull; const size_t StateCopySize64 = offsetof(StateInfo, key) / sizeof(uint64_t) + 1;
Score psqScore;
Square epSquare;
};
/// The position data structure. A position consists of the following data: /// Position class stores information regarding the board representation as
/// /// pieces, side to move, hash keys, castling info, etc. Important methods are
/// * For each piece type, a bitboard representing the squares occupied /// do_move() and undo_move(), used by the search to update node info when
/// by pieces of that type. /// traversing the search tree.
/// * For each color, a bitboard representing the squares occupied by
/// pieces of that color.
/// * A bitboard of all occupied squares.
/// * A bitboard of all checking pieces.
/// * A 64-entry array of pieces, indexed by the squares of the board.
/// * The current side to move.
/// * Information about the castling rights for both sides.
/// * The initial files of the kings and both pairs of rooks. This is
/// used to implement the Chess960 castling rules.
/// * The en passant square (which is SQ_NONE if no en passant capture is
/// possible).
/// * The squares of the kings for both sides.
/// * Hash keys for the position itself, the current pawn structure, and
/// the current material situation.
/// * Hash keys for all previous positions in the game for detecting
/// repetition draws.
/// * A counter for detecting 50 move rule draws.
class Position { class Position {
public:
Position() {}
Position(const Position& p, Thread* t) { *this = p; thisThread = t; }
Position(const std::string& f, bool c960, Thread* t) { from_fen(f, c960, t); }
Position& operator=(const Position&);
// Text input/output friend std::ostream& operator<<(std::ostream&, const Position&);
void from_fen(const std::string& fen, bool isChess960, Thread* th);
const std::string to_fen() const; Position(const Position&); // Disable the default copy constructor
void print(Move m = MOVE_NONE) const;
public:
static void init();
Position() {} // To define the global object RootPos
Position(const Position& pos, Thread* th) { *this = pos; thisThread = th; }
Position(const std::string& f, bool c960, Thread* th) { set(f, c960, th); }
Position& operator=(const Position&); // To assign RootPos from UCI
// FEN string input/output
void set(const std::string& fenStr, bool isChess960, Thread* th);
const std::string fen() const;
// Position representation // Position representation
Bitboard pieces() const; Bitboard pieces() const;
@@ -113,146 +106,127 @@ public:
Piece piece_on(Square s) const; Piece piece_on(Square s) const;
Square king_square(Color c) const; Square king_square(Color c) const;
Square ep_square() const; Square ep_square() const;
bool is_empty(Square s) const; bool empty(Square s) const;
const Square* piece_list(Color c, PieceType pt) const; template<PieceType Pt> int count(Color c) const;
int piece_count(Color c, PieceType pt) const; template<PieceType Pt> const Square* list(Color c) const;
// Castling // Castling
int can_castle(CastleRight f) const;
int can_castle(Color c) const; int can_castle(Color c) const;
bool castle_impeded(Color c, CastlingSide s) const; int can_castle(CastlingRight cr) const;
Square castle_rook_square(Color c, CastlingSide s) const; bool castling_impeded(CastlingRight cr) const;
Square castling_rook_square(CastlingRight cr) const;
// Checking // Checking
bool in_check() const;
Bitboard checkers() const; Bitboard checkers() const;
Bitboard discovered_check_candidates() const; Bitboard discovered_check_candidates() const;
Bitboard pinned_pieces() const; Bitboard pinned_pieces(Color c) const;
// Attacks to/from a given square // Attacks to/from a given square
Bitboard attackers_to(Square s) const; Bitboard attackers_to(Square s) const;
Bitboard attackers_to(Square s, Bitboard occ) const; Bitboard attackers_to(Square s, Bitboard occupied) const;
Bitboard attacks_from(Piece p, Square s) const; Bitboard attacks_from(Piece pc, Square s) const;
static Bitboard attacks_from(Piece p, Square s, Bitboard occ);
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;
// Properties of moves // Properties of moves
bool move_gives_check(Move m, const CheckInfo& ci) const; bool legal(Move m, Bitboard pinned) const;
bool move_attacks_square(Move m, Square s) const; bool pseudo_legal(const Move m) const;
bool move_is_legal(const Move m) const; bool capture(Move m) const;
bool pl_move_is_legal(Move m, Bitboard pinned) const; bool capture_or_promotion(Move m) const;
bool is_pseudo_legal(const Move m) const; bool gives_check(Move m, const CheckInfo& ci) const;
bool is_capture(Move m) const; bool advanced_pawn_push(Move m) const;
bool is_capture_or_promotion(Move m) const; Piece moved_piece(Move m) const;
bool is_passed_pawn_push(Move m) const;
Piece piece_moved(Move m) const;
PieceType captured_piece_type() const; PieceType captured_piece_type() const;
// Piece specific // Piece specific
bool pawn_is_passed(Color c, Square s) const; bool pawn_passed(Color c, Square s) const;
bool pawn_on_7th(Color c) const; bool pawn_on_7th(Color c) const;
bool opposite_bishops() const; bool opposite_bishops() const;
bool bishop_pair(Color c) const;
// Doing and undoing moves // Doing and undoing moves
void do_move(Move m, StateInfo& st); void do_move(Move m, StateInfo& st);
void do_move(Move m, StateInfo& st, const CheckInfo& ci, bool moveIsCheck); void do_move(Move m, StateInfo& st, const CheckInfo& ci, bool moveIsCheck);
void undo_move(Move m); void undo_move(Move m);
template<bool Do> void do_null_move(StateInfo& st); void do_null_move(StateInfo& st);
void undo_null_move();
// Static exchange evaluation // Static exchange evaluation
int see(Move m) const; Value see(Move m) const;
int see_sign(Move m) const; Value see_sign(Move m) const;
// Accessing hash keys // Accessing hash keys
Key key() const; Key key() const;
Key key_after(Move m) const;
Key exclusion_key() const; Key exclusion_key() const;
Key pawn_key() const;
Key material_key() const; Key material_key() const;
Key pawn_key() const;
// Incremental piece-square evaluation
Score psq_score() const;
Score psq_delta(Piece p, Square from, Square to) const;
Value non_pawn_material(Color c) const;
// Other properties of the position // Other properties of the position
Color side_to_move() const; Color side_to_move() const;
int startpos_ply_counter() const; Phase game_phase() const;
int game_ply() const;
bool is_chess960() const; bool is_chess960() const;
Thread* this_thread() const; Thread* this_thread() const;
int64_t nodes_searched() const; uint64_t nodes_searched() const;
void set_nodes_searched(int64_t n); void set_nodes_searched(uint64_t n);
template<bool SkipRepetition> bool is_draw() const; bool is_draw() const;
int rule50_count() const;
Score psq_score() const;
Value non_pawn_material(Color c) const;
// Position consistency check, for debugging // Position consistency check, for debugging
bool pos_is_ok(int* failedStep = NULL) const; bool pos_is_ok(int* step = NULL) const;
void flip(); void flip();
private: private:
// Initialization helpers (used while setting up a position) // Initialization helpers (used while setting up a position)
void clear(); void clear();
void put_piece(Piece p, Square s); void set_castling_right(Color c, Square rfrom);
void set_castle_right(Color c, Square rfrom); void set_state(StateInfo* si) const;
// Helper template functions // Other helpers
template<bool Do> void do_castle_move(Move m); Bitboard check_blockers(Color c, Color kingColor) const;
template<bool FindPinned> Bitboard hidden_checkers() const; void put_piece(Square s, Color c, PieceType pt);
void remove_piece(Square s, Color c, PieceType pt);
void move_piece(Square from, Square to, Color c, PieceType pt);
template<bool Do>
void do_castling(Square from, Square& to, Square& rfrom, Square& rto);
// Computing hash keys from scratch (for initialization and debugging) // Data members
Key compute_key() const; Piece board[SQUARE_NB];
Key compute_pawn_key() const; Bitboard byTypeBB[PIECE_TYPE_NB];
Key compute_material_key() const; Bitboard byColorBB[COLOR_NB];
int pieceCount[COLOR_NB][PIECE_TYPE_NB];
// Computing incremental evaluation scores and material counts Square pieceList[COLOR_NB][PIECE_TYPE_NB][16];
Score compute_psq_score() const; int index[SQUARE_NB];
Value compute_non_pawn_material(Color c) const; int castlingRightsMask[SQUARE_NB];
Square castlingRookSquare[CASTLING_RIGHT_NB];
// Board and pieces Bitboard castlingPath[CASTLING_RIGHT_NB];
Piece board[64]; // [square]
Bitboard byTypeBB[8]; // [pieceType]
Bitboard byColorBB[2]; // [color]
int pieceCount[2][8]; // [color][pieceType]
Square pieceList[2][8][16]; // [color][pieceType][index]
int index[64]; // [square]
// Other info
int castleRightsMask[64]; // [square]
Square castleRookSquare[2][2]; // [color][side]
Bitboard castlePath[2][2]; // [color][side]
StateInfo startState; StateInfo startState;
int64_t nodes; uint64_t nodes;
int startPosPly; int gamePly;
Color sideToMove; Color sideToMove;
Thread* thisThread; Thread* thisThread;
StateInfo* st; StateInfo* st;
int chess960; bool chess960;
}; };
inline int64_t Position::nodes_searched() const { inline Color Position::side_to_move() const {
return nodes; return sideToMove;
} }
inline void Position::set_nodes_searched(int64_t n) { inline bool Position::empty(Square s) const {
nodes = n; return board[s] == NO_PIECE;
} }
inline Piece Position::piece_on(Square s) const { inline Piece Position::piece_on(Square s) const {
return board[s]; return board[s];
} }
inline Piece Position::piece_moved(Move m) const { inline Piece Position::moved_piece(Move m) const {
return board[from_sq(m)]; return board[from_sq(m)];
} }
inline bool Position::is_empty(Square s) const {
return board[s] == NO_PIECE;
}
inline Color Position::side_to_move() const {
return sideToMove;
}
inline Bitboard Position::pieces() const { inline Bitboard Position::pieces() const {
return byTypeBB[ALL_PIECES]; return byTypeBB[ALL_PIECES];
} }
@@ -277,42 +251,41 @@ inline Bitboard Position::pieces(Color c, PieceType pt1, PieceType pt2) const {
return byColorBB[c] & (byTypeBB[pt1] | byTypeBB[pt2]); return byColorBB[c] & (byTypeBB[pt1] | byTypeBB[pt2]);
} }
inline int Position::piece_count(Color c, PieceType pt) const { template<PieceType Pt> inline int Position::count(Color c) const {
return pieceCount[c][pt]; return pieceCount[c][Pt];
} }
inline const Square* Position::piece_list(Color c, PieceType pt) const { template<PieceType Pt> inline const Square* Position::list(Color c) const {
return pieceList[c][pt]; return pieceList[c][Pt];
}
inline Square Position::ep_square() const {
return st->epSquare;
} }
inline Square Position::king_square(Color c) const { inline Square Position::king_square(Color c) const {
return pieceList[c][KING][0]; return pieceList[c][KING][0];
} }
inline int Position::can_castle(CastleRight f) const { inline Square Position::ep_square() const {
return st->castleRights & f; return st->epSquare;
}
inline int Position::can_castle(CastlingRight cr) const {
return st->castlingRights & cr;
} }
inline int Position::can_castle(Color c) const { inline int Position::can_castle(Color c) const {
return st->castleRights & ((WHITE_OO | WHITE_OOO) << (2 * c)); return st->castlingRights & ((WHITE_OO | WHITE_OOO) << (2 * c));
} }
inline bool Position::castle_impeded(Color c, CastlingSide s) const { inline bool Position::castling_impeded(CastlingRight cr) const {
return byTypeBB[ALL_PIECES] & castlePath[c][s]; return byTypeBB[ALL_PIECES] & castlingPath[cr];
} }
inline Square Position::castle_rook_square(Color c, CastlingSide s) const { inline Square Position::castling_rook_square(CastlingRight cr) const {
return castleRookSquare[c][s]; return castlingRookSquare[cr];
} }
template<PieceType Pt> template<PieceType Pt>
inline Bitboard Position::attacks_from(Square s) const { inline Bitboard Position::attacks_from(Square s) const {
return Pt == BISHOP || Pt == ROOK ? attacks_bb<Pt>(s, byTypeBB[ALL_PIECES])
return Pt == BISHOP || Pt == ROOK ? attacks_bb<Pt>(s, pieces())
: Pt == QUEEN ? attacks_from<ROOK>(s) | attacks_from<BISHOP>(s) : Pt == QUEEN ? attacks_from<ROOK>(s) | attacks_from<BISHOP>(s)
: StepAttacksBB[Pt][s]; : StepAttacksBB[Pt][s];
} }
@@ -322,8 +295,8 @@ inline Bitboard Position::attacks_from<PAWN>(Square s, Color c) const {
return StepAttacksBB[make_piece(c, PAWN)][s]; return StepAttacksBB[make_piece(c, PAWN)][s];
} }
inline Bitboard Position::attacks_from(Piece p, Square s) const { inline Bitboard Position::attacks_from(Piece pc, Square s) const {
return attacks_from(p, s, byTypeBB[ALL_PIECES]); return attacks_bb(pc, s, byTypeBB[ALL_PIECES]);
} }
inline Bitboard Position::attackers_to(Square s) const { inline Bitboard Position::attackers_to(Square s) const {
@@ -334,30 +307,27 @@ inline Bitboard Position::checkers() const {
return st->checkersBB; return st->checkersBB;
} }
inline bool Position::in_check() const {
return st->checkersBB != 0;
}
inline Bitboard Position::discovered_check_candidates() const { inline Bitboard Position::discovered_check_candidates() const {
return hidden_checkers<false>(); return check_blockers(sideToMove, ~sideToMove);
} }
inline Bitboard Position::pinned_pieces() const { inline Bitboard Position::pinned_pieces(Color c) const {
return hidden_checkers<true>(); return check_blockers(c, c);
} }
inline bool Position::pawn_is_passed(Color c, Square s) const { inline bool Position::pawn_passed(Color c, Square s) const {
return !(pieces(~c, PAWN) & passed_pawn_mask(c, s)); return !(pieces(~c, PAWN) & passed_pawn_mask(c, s));
} }
inline bool Position::advanced_pawn_push(Move m) const {
return type_of(moved_piece(m)) == PAWN
&& relative_rank(sideToMove, from_sq(m)) > RANK_4;
}
inline Key Position::key() const { inline Key Position::key() const {
return st->key; return st->key;
} }
inline Key Position::exclusion_key() const {
return st->key ^ Zobrist::exclusion;
}
inline Key Position::pawn_key() const { inline Key Position::pawn_key() const {
return st->pawnKey; return st->pawnKey;
} }
@@ -366,41 +336,36 @@ inline Key Position::material_key() const {
return st->materialKey; return st->materialKey;
} }
inline Score Position::psq_delta(Piece p, Square from, Square to) const {
return pieceSquareTable[p][to] - pieceSquareTable[p][from];
}
inline Score Position::psq_score() const { inline Score Position::psq_score() const {
return st->psqScore; return st->psq;
} }
inline Value Position::non_pawn_material(Color c) const { inline Value Position::non_pawn_material(Color c) const {
return st->npMaterial[c]; return st->nonPawnMaterial[c];
} }
inline bool Position::is_passed_pawn_push(Move m) const { inline int Position::game_ply() const {
return gamePly;
return type_of(piece_moved(m)) == PAWN
&& pawn_is_passed(sideToMove, to_sq(m));
} }
inline int Position::startpos_ply_counter() const { inline int Position::rule50_count() const {
return startPosPly + st->pliesFromNull; // HACK return st->rule50;
}
inline uint64_t Position::nodes_searched() const {
return nodes;
}
inline void Position::set_nodes_searched(uint64_t n) {
nodes = n;
} }
inline bool Position::opposite_bishops() const { inline bool Position::opposite_bishops() const {
return pieceCount[WHITE][BISHOP] == 1 return pieceCount[WHITE][BISHOP] == 1
&& pieceCount[BLACK][BISHOP] == 1 && pieceCount[BLACK][BISHOP] == 1
&& opposite_colors(pieceList[WHITE][BISHOP][0], pieceList[BLACK][BISHOP][0]); && opposite_colors(pieceList[WHITE][BISHOP][0], pieceList[BLACK][BISHOP][0]);
} }
inline bool Position::bishop_pair(Color c) const {
return pieceCount[c][BISHOP] >= 2
&& opposite_colors(pieceList[c][BISHOP][0], pieceList[c][BISHOP][1]);
}
inline bool Position::pawn_on_7th(Color c) const { inline bool Position::pawn_on_7th(Color c) const {
return pieces(c, PAWN) & rank_bb(relative_rank(c, RANK_7)); return pieces(c, PAWN) & rank_bb(relative_rank(c, RANK_7));
} }
@@ -409,17 +374,17 @@ inline bool Position::is_chess960() const {
return chess960; return chess960;
} }
inline bool Position::is_capture_or_promotion(Move m) const { inline bool Position::capture_or_promotion(Move m) const {
assert(is_ok(m)); assert(is_ok(m));
return type_of(m) ? type_of(m) != CASTLE : !is_empty(to_sq(m)); return type_of(m) != NORMAL ? type_of(m) != CASTLING : !empty(to_sq(m));
} }
inline bool Position::is_capture(Move m) const { inline bool Position::capture(Move m) const {
// Note that castle is coded as "king captures the rook" // Castling is encoded as "king captures the rook"
assert(is_ok(m)); assert(is_ok(m));
return (!is_empty(to_sq(m)) && type_of(m) != CASTLE) || type_of(m) == ENPASSANT; return (!empty(to_sq(m)) && type_of(m) != CASTLING) || type_of(m) == ENPASSANT;
} }
inline PieceType Position::captured_piece_type() const { inline PieceType Position::captured_piece_type() const {
@@ -430,4 +395,46 @@ inline Thread* Position::this_thread() const {
return thisThread; return thisThread;
} }
#endif // !defined(POSITION_H_INCLUDED) inline void Position::put_piece(Square s, Color c, PieceType pt) {
board[s] = make_piece(c, pt);
byTypeBB[ALL_PIECES] |= s;
byTypeBB[pt] |= s;
byColorBB[c] |= s;
index[s] = pieceCount[c][pt]++;
pieceList[c][pt][index[s]] = s;
pieceCount[c][ALL_PIECES]++;
}
inline void Position::move_piece(Square from, Square to, Color c, PieceType pt) {
// index[from] is not updated and becomes stale. This works as long as index[]
// is accessed just by known occupied squares.
Bitboard from_to_bb = SquareBB[from] ^ SquareBB[to];
byTypeBB[ALL_PIECES] ^= from_to_bb;
byTypeBB[pt] ^= from_to_bb;
byColorBB[c] ^= from_to_bb;
board[from] = NO_PIECE;
board[to] = make_piece(c, pt);
index[to] = index[from];
pieceList[c][pt][index[to]] = to;
}
inline void Position::remove_piece(Square s, Color c, PieceType pt) {
// WARNING: This is not a reversible operation. If we remove a piece in
// do_move() and then replace it in undo_move() we will put it at the end of
// the list and not in its original place, it means index[] and pieceList[]
// are not guaranteed to be invariant to a do_move() + undo_move() sequence.
byTypeBB[ALL_PIECES] ^= s;
byTypeBB[pt] ^= s;
byColorBB[c] ^= s;
/* board[s] = NO_PIECE; Not needed, overwritten by the capturing one */
Square lastSquare = pieceList[c][pt][--pieceCount[c][pt]];
index[lastSquare] = index[s];
pieceList[c][pt][index[lastSquare]] = lastSquare;
pieceList[c][pt][pieceCount[c][pt]] = SQ_NONE;
pieceCount[c][ALL_PIECES]--;
}
#endif // #ifndef POSITION_H_INCLUDED
+52 -52
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-2012 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, 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
@@ -17,7 +17,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/>.
*/ */
#if !defined(PSQTAB_H_INCLUDED) #ifndef PSQTAB_H_INCLUDED
#define PSQTAB_H_INCLUDED #define PSQTAB_H_INCLUDED
#include "types.h" #include "types.h"
@@ -26,73 +26,73 @@
/// PSQT[PieceType][Square] contains Piece-Square scores. For each piece type on /// PSQT[PieceType][Square] contains Piece-Square scores. For each piece type on
/// a given square a (midgame, endgame) score pair is assigned. PSQT is defined /// a given square a (middlegame, endgame) score pair is assigned. PSQT is defined
/// for white side, for black side the tables are symmetric. /// for the white side and the tables are symmetric for the black side.
static const Score PSQT[][64] = { static const Score PSQT[][SQUARE_NB] = {
{ }, { },
{ // 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( 0, 0), S( 0, 0), S( 0, 0), S( 0, 0), S(0, 0), S( 0, 0), S( 0, 0), S( 0, 0),
S(-28,-8), S(-6,-8), S( 4,-8), S(14,-8), S(14,-8), S( 4,-8), S(-6,-8), S(-28,-8), S(-20, 0), S( 0, 0), S( 0, 0), S( 0, 0), S(0, 0), S( 0, 0), S( 0, 0), S(-20, 0),
S(-28,-8), S(-6,-8), S( 9,-8), S(36,-8), S(36,-8), S( 9,-8), S(-6,-8), S(-28,-8), S(-20, 0), S( 0, 0), S(10, 0), S(20, 0), S(20, 0), S(10, 0), S( 0, 0), S(-20, 0),
S(-28,-8), S(-6,-8), S(17,-8), S(58,-8), S(58,-8), S(17,-8), S(-6,-8), S(-28,-8), S(-20, 0), S( 0, 0), S(20, 0), S(40, 0), S(40, 0), S(20, 0), S( 0, 0), S(-20, 0),
S(-28,-8), S(-6,-8), S(17,-8), S(36,-8), S(36,-8), S(17,-8), S(-6,-8), S(-28,-8), S(-20, 0), S( 0, 0), S(10, 0), S(20, 0), S(20, 0), S(10, 0), S( 0, 0), S(-20, 0),
S(-28,-8), S(-6,-8), S( 9,-8), S(14,-8), S(14,-8), S( 9,-8), S(-6,-8), S(-28,-8), S(-20, 0), S( 0, 0), S( 0, 0), S( 0, 0), S(0, 0), S( 0, 0), S( 0, 0), S(-20, 0),
S(-28,-8), S(-6,-8), S( 4,-8), S(14,-8), S(14,-8), S( 4,-8), S(-6,-8), S(-28,-8), S(-20, 0), S( 0, 0), S( 0, 0), S( 0, 0), S(0, 0), S( 0, 0), S( 0, 0), S(-20, 0),
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( 0, 0), S( 0, 0), S( 0, 0), S( 0, 0), S(0, 0), S( 0, 0), S( 0, 0), S( 0, 0)
}, },
{ // Knight { // Knight
S(-135,-104), S(-107,-79), S(-80,-55), S(-67,-42), S(-67,-42), S(-80,-55), S(-107,-79), S(-135,-104), S(-144,-98), S(-109,-83), S(-85,-51), S(-73,-16), S(-73,-16), S(-85,-51), S(-109,-83), S(-144,-98),
S( -93, -79), S( -67,-55), S(-39,-30), S(-25,-17), S(-25,-17), S(-39,-30), S( -67,-55), S( -93, -79), S( -88,-68), S( -43,-53), S(-19,-21), S( -7, 14), S( -7, 14), S(-19,-21), S( -43,-53), S( -88,-68),
S( -53, -55), S( -25,-30), S( 1, -6), S( 13, 5), S( 13, 5), S( 1, -6), S( -25,-30), S( -53, -55), S( -69,-53), S( -24,-38), S( 0, -6), S( 12, 29), S( 12, 29), S( 0, -6), S( -24,-38), S( -69,-53),
S( -25, -42), S( 1,-17), S( 27, 5), S( 41, 18), S( 41, 18), S( 27, 5), S( 1,-17), S( -25, -42), S( -28,-42), S( 17,-27), S( 41, 5), S( 53, 40), S( 53, 40), S( 41, 5), S( 17,-27), S( -28,-42),
S( -11, -42), S( 13,-17), S( 41, 5), S( 55, 18), S( 55, 18), S( 41, 5), S( 13,-17), S( -11, -42), S( -30,-42), S( 15,-27), S( 39, 5), S( 51, 40), S( 51, 40), S( 39, 5), S( 15,-27), S( -30,-42),
S( -11, -55), S( 13,-30), S( 41, -6), S( 55, 5), S( 55, 5), S( 41, -6), S( 13,-30), S( -11, -55), S( -10,-53), S( 35,-38), S( 59, -6), S( 71, 29), S( 71, 29), S( 59, -6), S( 35,-38), S( -10,-53),
S( -53, -79), S( -25,-55), S( 1,-30), S( 13,-17), S( 13,-17), S( 1,-30), S( -25,-55), S( -53, -79), S( -64,-68), S( -19,-53), S( 5,-21), S( 17, 14), S( 17, 14), S( 5,-21), S( -19,-53), S( -64,-68),
S(-193,-104), S( -67,-79), S(-39,-55), S(-25,-42), S(-25,-42), S(-39,-55), S( -67,-79), S(-193,-104) S(-200,-98), S( -65,-83), S(-41,-51), S(-29,-16), S(-29,-16), S(-41,-51), S( -65,-83), S(-200,-98)
}, },
{ // Bishop { // Bishop
S(-40,-59), S(-40,-42), S(-35,-35), S(-30,-26), S(-30,-26), S(-35,-35), S(-40,-42), S(-40,-59), S(-54,-65), S(-27,-42), S(-34,-44), S(-43,-26), S(-43,-26), S(-34,-44), S(-27,-42), S(-54,-65),
S(-17,-42), S( 0,-26), S( -4,-18), S( 0,-11), S( 0,-11), S( -4,-18), S( 0,-26), S(-17,-42), S(-29,-43), S( 8,-20), S( 1,-22), S( -8, -4), S( -8, -4), S( 1,-22), S( 8,-20), S(-29,-43),
S(-13,-35), S( -4,-18), S( 8,-11), S( 4, -4), S( 4, -4), S( 8,-11), S( -4,-18), S(-13,-35), S(-20,-33), S( 17,-10), S( 10,-12), S( 1, 6), S( 1, 6), S( 10,-12), S( 17,-10), S(-20,-33),
S( -8,-26), S( 0,-11), S( 4, -4), S( 17, 4), S( 17, 4), S( 4, -4), S( 0,-11), S( -8,-26), S(-19,-35), S( 18,-12), S( 11,-14), S( 2, 4), S( 2, 4), S( 11,-14), S( 18,-12), S(-19,-35),
S( -8,-26), S( 0,-11), S( 4, -4), S( 17, 4), S( 17, 4), S( 4, -4), S( 0,-11), S( -8,-26), S(-22,-35), S( 15,-12), S( 8,-14), S( -1, 4), S( -1, 4), S( 8,-14), S( 15,-12), S(-22,-35),
S(-13,-35), S( -4,-18), S( 8,-11), S( 4, -4), S( 4, -4), S( 8,-11), S( -4,-18), S(-13,-35), S(-28,-33), S( 9,-10), S( 2,-12), S( -7, 6), S( -7, 6), S( 2,-12), S( 9,-10), S(-28,-33),
S(-17,-42), S( 0,-26), S( -4,-18), S( 0,-11), S( 0,-11), S( -4,-18), S( 0,-26), S(-17,-42), S(-32,-43), S( 5,-20), S( -2,-22), S(-11, -4), S(-11, -4), S( -2,-22), S( 5,-20), S(-32,-43),
S(-17,-59), S(-17,-42), S(-13,-35), S( -8,-26), S( -8,-26), S(-13,-35), S(-17,-42), S(-17,-59) S(-49,-65), S(-22,-42), S(-29,-44), S(-38,-26), S(-38,-26), S(-29,-44), S(-22,-42), S(-49,-65)
}, },
{ // Rook { // Rook
S(-12, 3), S(-7, 3), S(-2, 3), S(2, 3), S(2, 3), S(-2, 3), S(-7, 3), S(-12, 3), S(-22, 3), S(-17, 3), S(-12, 3), S(-8, 3), S(-8, 3), S(-12, 3), S(-17, 3), S(-22, 3),
S(-12, 3), S(-7, 3), S(-2, 3), S(2, 3), S(2, 3), S(-2, 3), S(-7, 3), S(-12, 3), S(-22, 3), S( -7, 3), S( -2, 3), S( 2, 3), S( 2, 3), S( -2, 3), S( -7, 3), S(-22, 3),
S(-12, 3), S(-7, 3), S(-2, 3), S(2, 3), S(2, 3), S(-2, 3), S(-7, 3), S(-12, 3), S(-22, 3), S( -7, 3), S( -2, 3), S( 2, 3), S( 2, 3), S( -2, 3), S( -7, 3), S(-22, 3),
S(-12, 3), S(-7, 3), S(-2, 3), S(2, 3), S(2, 3), S(-2, 3), S(-7, 3), S(-12, 3), S(-22, 3), S( -7, 3), S( -2, 3), S( 2, 3), S( 2, 3), S( -2, 3), S( -7, 3), S(-22, 3),
S(-12, 3), S(-7, 3), S(-2, 3), S(2, 3), S(2, 3), S(-2, 3), S(-7, 3), S(-12, 3), S(-22, 3), S( -7, 3), S( -2, 3), S( 2, 3), S( 2, 3), S( -2, 3), S( -7, 3), S(-22, 3),
S(-12, 3), S(-7, 3), S(-2, 3), S(2, 3), S(2, 3), S(-2, 3), S(-7, 3), S(-12, 3), S(-22, 3), S( -7, 3), S( -2, 3), S( 2, 3), S( 2, 3), S( -2, 3), S( -7, 3), S(-22, 3),
S(-12, 3), S(-7, 3), S(-2, 3), S(2, 3), S(2, 3), S(-2, 3), S(-7, 3), S(-12, 3), S(-11, 3), S( 4, 3), S( 9, 3), S(13, 3), S(13, 3), S( 9, 3), S( 4, 3), S(-11, 3),
S(-12, 3), S(-7, 3), S(-2, 3), S(2, 3), S(2, 3), S(-2, 3), S(-7, 3), S(-12, 3) S(-22, 3), S(-17, 3), S(-12, 3), S(-8, 3), S(-8, 3), S(-12, 3), S(-17, 3), S(-22, 3)
}, },
{ // Queen { // Queen
S(8,-80), S(8,-54), S(8,-42), S(8,-30), S(8,-30), S(8,-42), S(8,-54), S(8,-80), S(-2,-80), S(-2,-54), S(-2,-42), S(-2,-30), S(-2,-30), S(-2,-42), S(-2,-54), S(-2,-80),
S(8,-54), S(8,-30), S(8,-18), S(8, -6), S(8, -6), S(8,-18), S(8,-30), S(8,-54), S(-2,-54), S( 8,-30), S( 8,-18), S( 8, -6), S( 8, -6), S( 8,-18), S( 8,-30), S(-2,-54),
S(8,-42), S(8,-18), S(8, -6), S(8, 6), S(8, 6), S(8, -6), S(8,-18), S(8,-42), S(-2,-42), S( 8,-18), S( 8, -6), S( 8, 6), S( 8, 6), S( 8, -6), S( 8,-18), S(-2,-42),
S(8,-30), S(8, -6), S(8, 6), S(8, 18), S(8, 18), S(8, 6), S(8, -6), S(8,-30), S(-2,-30), S( 8, -6), S( 8, 6), S( 8, 18), S( 8, 18), S( 8, 6), S( 8, -6), S(-2,-30),
S(8,-30), S(8, -6), S(8, 6), S(8, 18), S(8, 18), S(8, 6), S(8, -6), S(8,-30), S(-2,-30), S( 8, -6), S( 8, 6), S( 8, 18), S( 8, 18), S( 8, 6), S( 8, -6), S(-2,-30),
S(8,-42), S(8,-18), S(8, -6), S(8, 6), S(8, 6), S(8, -6), S(8,-18), S(8,-42), S(-2,-42), S( 8,-18), S( 8, -6), S( 8, 6), S( 8, 6), S( 8, -6), S( 8,-18), S(-2,-42),
S(8,-54), S(8,-30), S(8,-18), S(8, -6), S(8, -6), S(8,-18), S(8,-30), S(8,-54), S(-2,-54), S( 8,-30), S( 8,-18), S( 8, -6), S( 8, -6), S( 8,-18), S( 8,-30), S(-2,-54),
S(8,-80), S(8,-54), S(8,-42), S(8,-30), S(8,-30), S(8,-42), S(8,-54), S(8,-80) S(-2,-80), S(-2,-54), S(-2,-42), S(-2,-30), S(-2,-30), S(-2,-42), S(-2,-54), S(-2,-80)
}, },
{ // King { // King
S(287, 18), S(311, 77), S(262,105), S(214,135), S(214,135), S(262,105), S(311, 77), S(287, 18), S(298, 27), S(332, 81), S(273,108), S(225,116), S(225,116), S(273,108), S(332, 81), S(298, 27),
S(262, 77), S(287,135), S(238,165), S(190,193), S(190,193), S(238,165), S(287,135), S(262, 77), S(287, 74), S(321,128), S(262,155), S(214,163), S(214,163), S(262,155), S(321,128), S(287, 74),
S(214,105), S(238,165), S(190,193), S(142,222), S(142,222), S(190,193), S(238,165), S(214,105), S(224,111), S(258,165), S(199,192), S(151,200), S(151,200), S(199,192), S(258,165), S(224,111),
S(190,135), S(214,193), S(167,222), S(119,251), S(119,251), S(167,222), S(214,193), S(190,135), S(196,135), S(230,189), S(171,216), S(123,224), S(123,224), S(171,216), S(230,189), S(196,135),
S(167,135), S(190,193), S(142,222), S( 94,251), S( 94,251), S(142,222), S(190,193), S(167,135), S(173,135), S(207,189), S(148,216), S(100,224), S(100,224), S(148,216), S(207,189), S(173,135),
S(142,105), S(167,165), S(119,193), S( 69,222), S( 69,222), S(119,193), S(167,165), S(142,105), S(146,111), S(180,165), S(121,192), S( 73,200), S( 73,200), S(121,192), S(180,165), S(146,111),
S(119, 77), S(142,135), S( 94,165), S( 46,193), S( 46,193), S( 94,165), S(142,135), S(119, 77), S(119, 74), S(153,128), S( 94,155), S( 46,163), S( 46,163), S( 94,155), S(153,128), S(119, 74),
S(94, 18), S(119, 77), S( 69,105), S( 21,135), S( 21,135), S( 69,105), S(119, 77), S( 94, 18) S( 98, 27), S(132, 81), S( 73,108), S( 25,116), S( 25,116), S( 73,108), S(132, 81), S( 98, 27)
} }
}; };
#undef S #undef S
#endif // !defined(PSQTAB_H_INCLUDED) #endif // #ifndef PSQTAB_H_INCLUDED
-78
View File
@@ -1,78 +0,0 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2012 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Stockfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
This file is based on original code by Heinz van Saanen and is
available under 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.
*/
#if !defined(RKISS_H_INCLUDED)
#define RKISS_H_INCLUDED
#include "types.h"
/// RKISS is our pseudo random number generator (PRNG) used to compute hash keys.
/// George Marsaglia invented the RNG-Kiss-family in the early 90's. This is a
/// specific version that Heinz van Saanen derived from some public domain code
/// by Bob Jenkins. Following the feature list, as tested by Heinz.
///
/// - Quite platform independent
/// - Passes ALL dieharder tests! Here *nix sys-rand() e.g. fails miserably:-)
/// - ~12 times faster than my *nix sys-rand()
/// - ~4 times faster than SSE2-version of Mersenne twister
/// - Average cycle length: ~2^126
/// - 64 bit seed
/// - Return doubles with a full 53 bit mantissa
/// - Thread safe
class RKISS {
// Keep variables always together
struct S { uint64_t a, b, c, d; } s;
uint64_t rotate(uint64_t x, uint64_t k) const {
return (x << k) | (x >> (64 - k));
}
// Return 64 bit unsigned integer in between [0, 2^64 - 1]
uint64_t rand64() {
const uint64_t
e = s.a - rotate(s.b, 7);
s.a = s.b ^ rotate(s.c, 13);
s.b = s.c + rotate(s.d, 37);
s.c = s.d + e;
return s.d = e + s.a;
}
// Init seed and scramble a few rounds
void raninit() {
s.a = 0xf1ea5eed;
s.b = s.c = s.d = 0xd4e12c77;
for (int i = 0; i < 73; i++)
rand64();
}
public:
RKISS() { raninit(); }
template<typename T> T rand() { return T(rand64()); }
};
#endif // !defined(RKISS_H_INCLUDED)
+1016 -1096
View File
File diff suppressed because it is too large Load Diff
+41 -38
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-2012 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, 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
@@ -17,11 +17,10 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#if !defined(SEARCH_H_INCLUDED) #ifndef SEARCH_H_INCLUDED
#define SEARCH_H_INCLUDED #define SEARCH_H_INCLUDED
#include <cstring> #include <memory> // For std::auto_ptr
#include <memory>
#include <stack> #include <stack>
#include <vector> #include <vector>
@@ -33,79 +32,83 @@ struct SplitPoint;
namespace Search { namespace Search {
/// The Stack struct keeps track of the information we need to remember from /// Stack struct keeps track of the information we need to remember from nodes
/// nodes shallower and deeper in the tree during the search. Each search thread /// shallower and deeper in the tree during the search. Each search thread has
/// 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 {
SplitPoint* sp; SplitPoint* splitPoint;
Move* pv;
int ply; int ply;
Move currentMove; Move currentMove;
Move ttMove;
Move excludedMove; Move excludedMove;
Move killers[2]; Move killers[2];
Depth reduction; Depth reduction;
Value eval; Value staticEval;
Value evalMargin; bool skipEarlyPruning;
int skipNullMove;
}; };
/// RootMove struct is used for moves at the root of the tree. For each root move
/// we store a score and a PV (really a refutation in the case of moves which
/// fail low). Score is normally set at -VALUE_INFINITE for all non-pv moves.
/// RootMove struct is used for moves at the root of the tree. For each root
/// move we store a score, a node count, and a PV (really a refutation in the
/// case of moves which fail low). Score is normally set at -VALUE_INFINITE for
/// all non-pv moves.
struct RootMove { struct RootMove {
RootMove(){} // Needed by sort() RootMove(Move m) : score(-VALUE_INFINITE), previousScore(-VALUE_INFINITE), pv(1, m) {}
RootMove(Move m) : score(-VALUE_INFINITE), prevScore(-VALUE_INFINITE) {
pv.push_back(m); pv.push_back(MOVE_NONE);
}
bool operator<(const RootMove& m) const { return score < m.score; } bool operator<(const RootMove& m) const { return score > m.score; } // Ascending sort
bool operator==(const Move& m) const { return pv[0] == m; } bool operator==(const Move& m) const { return pv[0] == m; }
void extract_pv_from_tt(Position& pos);
void insert_pv_in_tt(Position& pos); void insert_pv_in_tt(Position& pos);
Move extract_ponder_from_tt(Position& pos);
Value score; Value score;
Value prevScore; Value previousScore;
std::vector<Move> pv; std::vector<Move> pv;
}; };
typedef std::vector<RootMove> RootMoveVector;
/// The LimitsType struct stores information sent by GUI about available time /// LimitsType struct stores information sent by GUI about available time to
/// to search the current move, maximum depth/time, if we are in analysis mode /// search the current move, maximum depth/time, if we are in analysis mode or
/// or if we have to ponder while is our opponent's side to move. /// if we have to ponder while it's our opponent's turn to move.
struct LimitsType { struct LimitsType {
LimitsType() { memset(this, 0, sizeof(LimitsType)); } LimitsType() { // Init explicitly due to broken value-initialization of non POD in MSVC
bool use_time_management() const { return !(movetime | depth | nodes | infinite); } nodes = time[WHITE] = time[BLACK] = inc[WHITE] = inc[BLACK] = movestogo =
depth = movetime = mate = infinite = ponder = 0;
}
int time[2], inc[2], movestogo, depth, nodes, movetime, infinite, ponder; bool use_time_management() const {
return !(mate | movetime | depth | nodes | infinite);
}
std::vector<Move> searchmoves;
int time[COLOR_NB], inc[COLOR_NB], movestogo, depth, movetime, mate, infinite, ponder;
int64_t nodes;
}; };
/// The SignalsType struct stores volatile flags updated during the search /// The SignalsType struct stores volatile flags updated during the search
/// typically in an async fashion, for instance to stop the search by the GUI. /// typically in an async fashion e.g. to stop the search by the GUI.
struct SignalsType { struct SignalsType {
bool stopOnPonderhit, firstRootMove, stop, failedLowAtRoot; bool stop, stopOnPonderhit, firstRootMove, failedLowAtRoot;
}; };
typedef std::auto_ptr<std::stack<StateInfo> > StateStackPtr; typedef std::auto_ptr<std::stack<StateInfo> > StateStackPtr;
extern volatile SignalsType Signals; extern volatile SignalsType Signals;
extern LimitsType Limits; extern LimitsType Limits;
extern std::vector<RootMove> RootMoves; extern RootMoveVector RootMoves;
extern Position RootPosition; extern Position RootPos;
extern Time::point SearchTime; extern Time::point SearchTime;
extern StateStackPtr SetupStates; extern StateStackPtr SetupStates;
extern void init(); void init();
extern size_t perft(Position& pos, Depth depth); void think();
extern void think(); template<bool Root> uint64_t perft(Position& pos, Depth depth);
} // namespace Search } // namespace Search
#endif // !defined(SEARCH_H_INCLUDED) #endif // #ifndef SEARCH_H_INCLUDED
File diff suppressed because it is too large Load Diff
+169
View File
@@ -0,0 +1,169 @@
/*
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
+831
View File
@@ -0,0 +1,831 @@
/*
Copyright (c) 2013 Ronald de Man
This file may be redistributed and/or modified without restrictions.
tbprobe.cpp contains the Stockfish-specific routines of the
tablebase probing code. It should be relatively easy to adapt
this code to other chess engines.
*/
#include <algorithm>
#include "../position.h"
#include "../movegen.h"
#include "../bitboard.h"
#include "../search.h"
#include "../bitcount.h"
#include "tbprobe.h"
#include "tbcore.h"
#include "tbcore.cpp"
namespace Zobrist {
extern Key psq[COLOR_NB][PIECE_TYPE_NB][SQUARE_NB];
}
int Tablebases::MaxCardinality = 0;
// Given a position with 6 or fewer pieces, produce a text string
// of the form KQPvKRP, where "KQP" represents the white pieces if
// mirror == 0 and the black pieces if mirror == 1.
static void prt_str(Position& pos, char *str, int mirror)
{
Color color;
PieceType pt;
int i;
color = !mirror ? WHITE : BLACK;
for (pt = KING; pt >= PAWN; --pt)
for (i = popcount<Max15>(pos.pieces(color, pt)); i > 0; i--)
*str++ = pchr[6 - pt];
*str++ = 'v';
color = ~color;
for (pt = KING; pt >= PAWN; --pt)
for (i = popcount<Max15>(pos.pieces(color, pt)); i > 0; i--)
*str++ = pchr[6 - pt];
*str++ = 0;
}
// Given a position, produce a 64-bit material signature key.
// If the engine supports such a key, it should equal the engine's key.
static uint64 calc_key(Position& pos, int mirror)
{
Color color;
PieceType pt;
int i;
uint64 key = 0;
color = !mirror ? WHITE : BLACK;
for (pt = PAWN; pt <= KING; ++pt)
for (i = popcount<Max15>(pos.pieces(color, pt)); i > 0; i--)
key ^= Zobrist::psq[WHITE][pt][i - 1];
color = ~color;
for (pt = PAWN; pt <= KING; ++pt)
for (i = popcount<Max15>(pos.pieces(color, pt)); i > 0; i--)
key ^= Zobrist::psq[BLACK][pt][i - 1];
return key;
}
// Produce a 64-bit material key corresponding to the material combination
// defined by pcs[16], where pcs[1], ..., pcs[6] is the number of white
// pawns, ..., kings and pcs[9], ..., pcs[14] is the number of black
// pawns, ..., kings.
static uint64 calc_key_from_pcs(int *pcs, int mirror)
{
int color;
PieceType pt;
int i;
uint64 key = 0;
color = !mirror ? 0 : 8;
for (pt = PAWN; pt <= KING; ++pt)
for (i = 0; i < pcs[color + pt]; i++)
key ^= Zobrist::psq[WHITE][pt][i];
color ^= 8;
for (pt = PAWN; pt <= KING; ++pt)
for (i = 0; i < pcs[color + pt]; i++)
key ^= Zobrist::psq[BLACK][pt][i];
return key;
}
bool is_little_endian() {
union {
int i;
char c[sizeof(int)];
} x;
x.i = 1;
return x.c[0] == 1;
}
static ubyte decompress_pairs(struct PairsData *d, uint64 idx)
{
static const bool isLittleEndian = is_little_endian();
return isLittleEndian ? decompress_pairs<true >(d, idx)
: decompress_pairs<false>(d, idx);
}
// probe_wdl_table and probe_dtz_table require similar adaptations.
static int probe_wdl_table(Position& pos, int *success)
{
struct TBEntry *ptr;
struct TBHashEntry *ptr2;
uint64 idx;
uint64 key;
int i;
ubyte res;
int p[TBPIECES];
// Obtain the position's material signature key.
key = pos.material_key();
// Test for KvK.
if (key == (Zobrist::psq[WHITE][KING][0] ^ Zobrist::psq[BLACK][KING][0]))
return 0;
ptr2 = TB_hash[key >> (64 - TBHASHBITS)];
for (i = 0; i < HSHMAX; i++)
if (ptr2[i].key == key) break;
if (i == HSHMAX) {
*success = 0;
return 0;
}
ptr = ptr2[i].ptr;
if (!ptr->ready) {
LOCK(TB_mutex);
if (!ptr->ready) {
char str[16];
prt_str(pos, str, ptr->key != key);
if (!init_table_wdl(ptr, str)) {
ptr2[i].key = 0ULL;
*success = 0;
UNLOCK(TB_mutex);
return 0;
}
// Memory barrier to ensure ptr->ready = 1 is not reordered.
#ifdef _MSC_VER
_ReadWriteBarrier();
#else
__asm__ __volatile__ ("" ::: "memory");
#endif
ptr->ready = 1;
}
UNLOCK(TB_mutex);
}
int bside, mirror, cmirror;
if (!ptr->symmetric) {
if (key != ptr->key) {
cmirror = 8;
mirror = 0x38;
bside = (pos.side_to_move() == WHITE);
} else {
cmirror = mirror = 0;
bside = !(pos.side_to_move() == WHITE);
}
} else {
cmirror = pos.side_to_move() == WHITE ? 0 : 8;
mirror = pos.side_to_move() == WHITE ? 0 : 0x38;
bside = 0;
}
// p[i] is to contain the square 0-63 (A1-H8) for a piece of type
// pc[i] ^ cmirror, where 1 = white pawn, ..., 14 = black king.
// Pieces of the same type are guaranteed to be consecutive.
if (!ptr->has_pawns) {
struct TBEntry_piece *entry = (struct TBEntry_piece *)ptr;
ubyte *pc = entry->pieces[bside];
for (i = 0; i < entry->num;) {
Bitboard bb = pos.pieces((Color)((pc[i] ^ cmirror) >> 3),
(PieceType)(pc[i] & 0x07));
do {
p[i++] = pop_lsb(&bb);
} while (bb);
}
idx = encode_piece(entry, entry->norm[bside], p, entry->factor[bside]);
res = decompress_pairs(entry->precomp[bside], idx);
} else {
struct TBEntry_pawn *entry = (struct TBEntry_pawn *)ptr;
int k = entry->file[0].pieces[0][0] ^ cmirror;
Bitboard bb = pos.pieces((Color)(k >> 3), (PieceType)(k & 0x07));
i = 0;
do {
p[i++] = pop_lsb(&bb) ^ mirror;
} while (bb);
int f = pawn_file(entry, p);
ubyte *pc = entry->file[f].pieces[bside];
for (; i < entry->num;) {
bb = pos.pieces((Color)((pc[i] ^ cmirror) >> 3),
(PieceType)(pc[i] & 0x07));
do {
p[i++] = pop_lsb(&bb) ^ mirror;
} while (bb);
}
idx = encode_pawn(entry, entry->file[f].norm[bside], p, entry->file[f].factor[bside]);
res = decompress_pairs(entry->file[f].precomp[bside], idx);
}
return ((int)res) - 2;
}
static int probe_dtz_table(Position& pos, int wdl, int *success)
{
struct TBEntry *ptr;
uint64 idx;
int i, res;
int p[TBPIECES];
// Obtain the position's material signature key.
uint64 key = pos.material_key();
if (DTZ_table[0].key1 != key && DTZ_table[0].key2 != key) {
for (i = 1; i < DTZ_ENTRIES; i++)
if (DTZ_table[i].key1 == key) break;
if (i < DTZ_ENTRIES) {
struct DTZTableEntry table_entry = DTZ_table[i];
for (; i > 0; i--)
DTZ_table[i] = DTZ_table[i - 1];
DTZ_table[0] = table_entry;
} else {
struct TBHashEntry *ptr2 = TB_hash[key >> (64 - TBHASHBITS)];
for (i = 0; i < HSHMAX; i++)
if (ptr2[i].key == key) break;
if (i == HSHMAX) {
*success = 0;
return 0;
}
ptr = ptr2[i].ptr;
char str[16];
int mirror = (ptr->key != key);
prt_str(pos, str, mirror);
if (DTZ_table[DTZ_ENTRIES - 1].entry)
free_dtz_entry(DTZ_table[DTZ_ENTRIES-1].entry);
for (i = DTZ_ENTRIES - 1; i > 0; i--)
DTZ_table[i] = DTZ_table[i - 1];
load_dtz_table(str, calc_key(pos, mirror), calc_key(pos, !mirror));
}
}
ptr = DTZ_table[0].entry;
if (!ptr) {
*success = 0;
return 0;
}
int bside, mirror, cmirror;
if (!ptr->symmetric) {
if (key != ptr->key) {
cmirror = 8;
mirror = 0x38;
bside = (pos.side_to_move() == WHITE);
} else {
cmirror = mirror = 0;
bside = !(pos.side_to_move() == WHITE);
}
} else {
cmirror = pos.side_to_move() == WHITE ? 0 : 8;
mirror = pos.side_to_move() == WHITE ? 0 : 0x38;
bside = 0;
}
if (!ptr->has_pawns) {
struct DTZEntry_piece *entry = (struct DTZEntry_piece *)ptr;
if ((entry->flags & 1) != bside && !entry->symmetric) {
*success = -1;
return 0;
}
ubyte *pc = entry->pieces;
for (i = 0; i < entry->num;) {
Bitboard bb = pos.pieces((Color)((pc[i] ^ cmirror) >> 3),
(PieceType)(pc[i] & 0x07));
do {
p[i++] = pop_lsb(&bb);
} while (bb);
}
idx = encode_piece((struct TBEntry_piece *)entry, entry->norm, p, entry->factor);
res = decompress_pairs(entry->precomp, idx);
if (entry->flags & 2)
res = entry->map[entry->map_idx[wdl_to_map[wdl + 2]] + res];
if (!(entry->flags & pa_flags[wdl + 2]) || (wdl & 1))
res *= 2;
} else {
struct DTZEntry_pawn *entry = (struct DTZEntry_pawn *)ptr;
int k = entry->file[0].pieces[0] ^ cmirror;
Bitboard bb = pos.pieces((Color)(k >> 3), (PieceType)(k & 0x07));
i = 0;
do {
p[i++] = pop_lsb(&bb) ^ mirror;
} while (bb);
int f = pawn_file((struct TBEntry_pawn *)entry, p);
if ((entry->flags[f] & 1) != bside) {
*success = -1;
return 0;
}
ubyte *pc = entry->file[f].pieces;
for (; i < entry->num;) {
bb = pos.pieces((Color)((pc[i] ^ cmirror) >> 3),
(PieceType)(pc[i] & 0x07));
do {
p[i++] = pop_lsb(&bb) ^ mirror;
} while (bb);
}
idx = encode_pawn((struct TBEntry_pawn *)entry, entry->file[f].norm, p, entry->file[f].factor);
res = decompress_pairs(entry->file[f].precomp, idx);
if (entry->flags[f] & 2)
res = entry->map[entry->map_idx[f][wdl_to_map[wdl + 2]] + res];
if (!(entry->flags[f] & pa_flags[wdl + 2]) || (wdl & 1))
res *= 2;
}
return res;
}
// Add underpromotion captures to list of captures.
static ExtMove *add_underprom_caps(Position& pos, ExtMove *stack, ExtMove *end)
{
ExtMove *moves, *extra = end;
for (moves = stack; moves < end; moves++) {
Move move = moves->move;
if (type_of(move) == PROMOTION && !pos.empty(to_sq(move))) {
(*extra++).move = (Move)(move - (1 << 12));
(*extra++).move = (Move)(move - (2 << 12));
(*extra++).move = (Move)(move - (3 << 12));
}
}
return extra;
}
static int probe_ab(Position& pos, int alpha, int beta, int *success)
{
int v;
ExtMove stack[64];
ExtMove *moves, *end;
StateInfo st;
// Generate (at least) all legal non-ep captures including (under)promotions.
// It is OK to generate more, as long as they are filtered out below.
if (!pos.checkers()) {
end = generate<CAPTURES>(pos, stack);
// Since underpromotion captures are not included, we need to add them.
end = add_underprom_caps(pos, stack, end);
} else
end = generate<EVASIONS>(pos, stack);
CheckInfo ci(pos);
for (moves = stack; moves < end; moves++) {
Move capture = moves->move;
if (!pos.capture(capture) || type_of(capture) == ENPASSANT
|| !pos.legal(capture, ci.pinned))
continue;
pos.do_move(capture, st, ci, pos.gives_check(capture, ci));
v = -probe_ab(pos, -beta, -alpha, success);
pos.undo_move(capture);
if (*success == 0) return 0;
if (v > alpha) {
if (v >= beta) {
*success = 2;
return v;
}
alpha = v;
}
}
v = probe_wdl_table(pos, success);
if (*success == 0) return 0;
if (alpha >= v) {
*success = 1 + (alpha > 0);
return alpha;
} else {
*success = 1;
return v;
}
}
// Probe the WDL table for a particular position.
// If *success != 0, the probe was successful.
// The return value is from the point of view of the side to move:
// -2 : loss
// -1 : loss, but draw under 50-move rule
// 0 : draw
// 1 : win, but draw under 50-move rule
// 2 : win
int Tablebases::probe_wdl(Position& pos, int *success)
{
int v;
*success = 1;
v = probe_ab(pos, -2, 2, success);
// If en passant is not possible, we are done.
if (pos.ep_square() == SQ_NONE)
return v;
if (!(*success)) return 0;
// Now handle en passant.
int v1 = -3;
// Generate (at least) all legal en passant captures.
ExtMove stack[192];
ExtMove *moves, *end;
StateInfo st;
if (!pos.checkers())
end = generate<CAPTURES>(pos, stack);
else
end = generate<EVASIONS>(pos, stack);
CheckInfo ci(pos);
for (moves = stack; moves < end; moves++) {
Move capture = moves->move;
if (type_of(capture) != ENPASSANT
|| !pos.legal(capture, ci.pinned))
continue;
pos.do_move(capture, st, ci, pos.gives_check(capture, ci));
int v0 = -probe_ab(pos, -2, 2, success);
pos.undo_move(capture);
if (*success == 0) return 0;
if (v0 > v1) v1 = v0;
}
if (v1 > -3) {
if (v1 >= v) v = v1;
else if (v == 0) {
// Check whether there is at least one legal non-ep move.
for (moves = stack; moves < end; moves++) {
Move capture = moves->move;
if (type_of(capture) == ENPASSANT) continue;
if (pos.legal(capture, ci.pinned)) break;
}
if (moves == end && !pos.checkers()) {
end = generate<QUIETS>(pos, end);
for (; moves < end; moves++) {
Move move = moves->move;
if (pos.legal(move, ci.pinned))
break;
}
}
// If not, then we are forced to play the losing ep capture.
if (moves == end)
v = v1;
}
}
return v;
}
// This routine treats a position with en passant captures as one without.
static int probe_dtz_no_ep(Position& pos, int *success)
{
int wdl, dtz;
wdl = probe_ab(pos, -2, 2, success);
if (*success == 0) return 0;
if (wdl == 0) return 0;
if (*success == 2)
return wdl == 2 ? 1 : 101;
ExtMove stack[192];
ExtMove *moves, *end = NULL;
StateInfo st;
CheckInfo ci(pos);
if (wdl > 0) {
// Generate at least all legal non-capturing pawn moves
// including non-capturing promotions.
if (!pos.checkers())
end = generate<NON_EVASIONS>(pos, stack);
else
end = generate<EVASIONS>(pos, stack);
for (moves = stack; moves < end; moves++) {
Move move = moves->move;
if (type_of(pos.moved_piece(move)) != PAWN || pos.capture(move)
|| !pos.legal(move, ci.pinned))
continue;
pos.do_move(move, st, ci, pos.gives_check(move, ci));
int v = -probe_ab(pos, -2, -wdl + 1, success);
pos.undo_move(move);
if (*success == 0) return 0;
if (v == wdl)
return v == 2 ? 1 : 101;
}
}
dtz = 1 + probe_dtz_table(pos, wdl, success);
if (*success >= 0) {
if (wdl & 1) dtz += 100;
return wdl >= 0 ? dtz : -dtz;
}
if (wdl > 0) {
int best = 0xffff;
for (moves = stack; moves < end; moves++) {
Move move = moves->move;
if (pos.capture(move) || type_of(pos.moved_piece(move)) == PAWN
|| !pos.legal(move, ci.pinned))
continue;
pos.do_move(move, st, ci, pos.gives_check(move, ci));
int v = -Tablebases::probe_dtz(pos, success);
pos.undo_move(move);
if (*success == 0) return 0;
if (v > 0 && v + 1 < best)
best = v + 1;
}
return best;
} else {
int best = -1;
if (!pos.checkers())
end = generate<NON_EVASIONS>(pos, stack);
else
end = generate<EVASIONS>(pos, stack);
for (moves = stack; moves < end; moves++) {
int v;
Move move = moves->move;
if (!pos.legal(move, ci.pinned))
continue;
pos.do_move(move, st, ci, pos.gives_check(move, ci));
if (st.rule50 == 0) {
if (wdl == -2) v = -1;
else {
v = probe_ab(pos, 1, 2, success);
v = (v == 2) ? 0 : -101;
}
} else {
v = -Tablebases::probe_dtz(pos, success) - 1;
}
pos.undo_move(move);
if (*success == 0) return 0;
if (v < best)
best = v;
}
return best;
}
}
static int wdl_to_dtz[] = {
-1, -101, 0, 101, 1
};
// Probe the DTZ table for a particular position.
// If *success != 0, the probe was successful.
// The return value is from the point of view of the side to move:
// n < -100 : loss, but draw under 50-move rule
// -100 <= n < -1 : loss in n ply (assuming 50-move counter == 0)
// 0 : draw
// 1 < n <= 100 : win in n ply (assuming 50-move counter == 0)
// 100 < n : win, but draw under 50-move rule
//
// The return value n can be off by 1: a return value -n can mean a loss
// in n+1 ply and a return value +n can mean a win in n+1 ply. This
// cannot happen for tables with positions exactly on the "edge" of
// the 50-move rule.
//
// This implies that if dtz > 0 is returned, the position is certainly
// a win if dtz + 50-move-counter <= 99. Care must be taken that the engine
// picks moves that preserve dtz + 50-move-counter <= 99.
//
// If n = 100 immediately after a capture or pawn move, then the position
// is also certainly a win, and during the whole phase until the next
// capture or pawn move, the inequality to be preserved is
// dtz + 50-movecounter <= 100.
//
// In short, if a move is available resulting in dtz + 50-move-counter <= 99,
// then do not accept moves leading to dtz + 50-move-counter == 100.
//
int Tablebases::probe_dtz(Position& pos, int *success)
{
*success = 1;
int v = probe_dtz_no_ep(pos, success);
if (pos.ep_square() == SQ_NONE)
return v;
if (*success == 0) return 0;
// Now handle en passant.
int v1 = -3;
ExtMove stack[192];
ExtMove *moves, *end;
StateInfo st;
if (!pos.checkers())
end = generate<CAPTURES>(pos, stack);
else
end = generate<EVASIONS>(pos, stack);
CheckInfo ci(pos);
for (moves = stack; moves < end; moves++) {
Move capture = moves->move;
if (type_of(capture) != ENPASSANT
|| !pos.legal(capture, ci.pinned))
continue;
pos.do_move(capture, st, ci, pos.gives_check(capture, ci));
int v0 = -probe_ab(pos, -2, 2, success);
pos.undo_move(capture);
if (*success == 0) return 0;
if (v0 > v1) v1 = v0;
}
if (v1 > -3) {
v1 = wdl_to_dtz[v1 + 2];
if (v < -100) {
if (v1 >= 0)
v = v1;
} else if (v < 0) {
if (v1 >= 0 || v1 < 100)
v = v1;
} else if (v > 100) {
if (v1 > 0)
v = v1;
} else if (v > 0) {
if (v1 == 1)
v = v1;
} else if (v1 >= 0) {
v = v1;
} else {
for (moves = stack; moves < end; moves++) {
Move move = moves->move;
if (type_of(move) == ENPASSANT) continue;
if (pos.legal(move, ci.pinned)) break;
}
if (moves == end && !pos.checkers()) {
end = generate<QUIETS>(pos, end);
for (; moves < end; moves++) {
Move move = moves->move;
if (pos.legal(move, ci.pinned))
break;
}
}
if (moves == end)
v = v1;
}
}
return v;
}
// Check whether there has been at least one repetition of positions
// since the last capture or pawn move.
static int has_repeated(StateInfo *st)
{
while (1) {
int i = 4, e = std::min(st->rule50, st->pliesFromNull);
if (e < i)
return 0;
StateInfo *stp = st->previous->previous;
do {
stp = stp->previous->previous;
if (stp->key == st->key)
return 1;
i += 2;
} while (i <= e);
st = st->previous;
}
}
static Value wdl_to_Value[5] = {
-VALUE_MATE + MAX_PLY + 1,
VALUE_DRAW - 2,
VALUE_DRAW,
VALUE_DRAW + 2,
VALUE_MATE - MAX_PLY - 1
};
// Use the DTZ tables to filter out moves that don't preserve the win or draw.
// If the position is lost, but DTZ is fairly high, only keep moves that
// maximise DTZ.
//
// A return value false indicates that not all probes were successful and that
// no moves were filtered out.
bool Tablebases::root_probe(Position& pos, Search::RootMoveVector& rootMoves, Value& score)
{
int success;
int dtz = probe_dtz(pos, &success);
if (!success) return false;
StateInfo st;
CheckInfo ci(pos);
// Probe each move.
for (size_t i = 0; i < rootMoves.size(); i++) {
Move move = rootMoves[i].pv[0];
pos.do_move(move, st, ci, pos.gives_check(move, ci));
int v = 0;
if (pos.checkers() && dtz > 0) {
ExtMove s[192];
if (generate<LEGAL>(pos, s) == s)
v = 1;
}
if (!v) {
if (st.rule50 != 0) {
v = -Tablebases::probe_dtz(pos, &success);
if (v > 0) v++;
else if (v < 0) v--;
} else {
v = -Tablebases::probe_wdl(pos, &success);
v = wdl_to_dtz[v + 2];
}
}
pos.undo_move(move);
if (!success) return false;
rootMoves[i].score = (Value)v;
}
// Obtain 50-move counter for the root position.
// In Stockfish there seems to be no clean way, so we do it like this:
int cnt50 = st.previous->rule50;
// Use 50-move counter to determine whether the root position is
// won, lost or drawn.
int wdl = 0;
if (dtz > 0)
wdl = (dtz + cnt50 <= 100) ? 2 : 1;
else if (dtz < 0)
wdl = (-dtz + cnt50 <= 100) ? -2 : -1;
// Determine the score to report to the user.
score = wdl_to_Value[wdl + 2];
// If the position is winning or losing, but too few moves left, adjust the
// score to show how close it is to winning or losing.
// NOTE: int(PawnValueEg) is used as scaling factor in score_to_uci().
if (wdl == 1 && dtz <= 100)
score = (Value)(((200 - dtz - cnt50) * int(PawnValueEg)) / 200);
else if (wdl == -1 && dtz >= -100)
score = -(Value)(((200 + dtz - cnt50) * int(PawnValueEg)) / 200);
// Now be a bit smart about filtering out moves.
size_t j = 0;
if (dtz > 0) { // winning (or 50-move rule draw)
int best = 0xffff;
for (size_t i = 0; i < rootMoves.size(); i++) {
int v = rootMoves[i].score;
if (v > 0 && v < best)
best = v;
}
int max = best;
// If the current phase has not seen repetitions, then try all moves
// that stay safely within the 50-move budget, if there are any.
if (!has_repeated(st.previous) && best + cnt50 <= 99)
max = 99 - cnt50;
for (size_t i = 0; i < rootMoves.size(); i++) {
int v = rootMoves[i].score;
if (v > 0 && v <= max)
rootMoves[j++] = rootMoves[i];
}
} else if (dtz < 0) { // losing (or 50-move rule draw)
int best = 0;
for (size_t i = 0; i < rootMoves.size(); i++) {
int v = rootMoves[i].score;
if (v < best)
best = v;
}
// Try all moves, unless we approach or have a 50-move rule draw.
if (-best * 2 + cnt50 < 100)
return true;
for (size_t i = 0; i < rootMoves.size(); i++) {
if (rootMoves[i].score == best)
rootMoves[j++] = rootMoves[i];
}
} else { // drawing
// Try all moves that preserve the draw.
for (size_t i = 0; i < rootMoves.size(); i++) {
if (rootMoves[i].score == 0)
rootMoves[j++] = rootMoves[i];
}
}
rootMoves.resize(j, Search::RootMove(MOVE_NONE));
return true;
}
// Use the WDL tables to filter out moves that don't preserve the win or draw.
// This is a fallback for the case that some or all DTZ tables are missing.
//
// A return value false indicates that not all probes were successful and that
// no moves were filtered out.
bool Tablebases::root_probe_wdl(Position& pos, Search::RootMoveVector& rootMoves, Value& score)
{
int success;
int wdl = Tablebases::probe_wdl(pos, &success);
if (!success) return false;
score = wdl_to_Value[wdl + 2];
StateInfo st;
CheckInfo ci(pos);
int best = -2;
// Probe each move.
for (size_t i = 0; i < rootMoves.size(); i++) {
Move move = rootMoves[i].pv[0];
pos.do_move(move, st, ci, pos.gives_check(move, ci));
int v = -Tablebases::probe_wdl(pos, &success);
pos.undo_move(move);
if (!success) return false;
rootMoves[i].score = (Value)v;
if (v > best)
best = v;
}
size_t j = 0;
for (size_t i = 0; i < rootMoves.size(); i++) {
if (rootMoves[i].score == best)
rootMoves[j++] = rootMoves[i];
}
rootMoves.resize(j, Search::RootMove(MOVE_NONE));
return true;
}
+18
View File
@@ -0,0 +1,18 @@
#ifndef TBPROBE_H
#define TBPROBE_H
#include "../search.h"
namespace Tablebases {
extern int MaxCardinality;
void init(const std::string& path);
int probe_wdl(Position& pos, int *success);
int probe_dtz(Position& pos, int *success);
bool root_probe(Position& pos, Search::RootMoveVector& rootMoves, Value& score);
bool root_probe_wdl(Position& pos, Search::RootMoveVector& rootMoves, Value& score);
}
#endif
+265 -316
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-2012 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, 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
@@ -17,113 +17,55 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <algorithm> // For std::count
#include <cassert> #include <cassert>
#include <iostream>
#include "movegen.h" #include "movegen.h"
#include "search.h" #include "search.h"
#include "thread.h" #include "thread.h"
#include "ucioption.h" #include "uci.h"
using namespace Search; using namespace Search;
ThreadPool Threads; // Global object ThreadPool Threads; // Global object
namespace { extern "C" {
// start_routine() is the C function which is called when a new thread
// is launched. It is a wrapper to member function pointed by start_fn.
long start_routine(Thread* th) { (th->*(th->start_fn))(); return 0; }
} }
// Thread c'tor starts a newly-created thread of execution that will call
// the idle loop function pointed by start_fn going immediately to sleep.
Thread::Thread(Fn fn) {
is_searching = do_exit = false;
maxPly = splitPointsCnt = 0;
curSplitPoint = NULL;
start_fn = fn;
idx = Threads.size();
do_sleep = (fn != &Thread::main_loop); // Avoid a race with start_searching()
if (!thread_create(handle, start_routine, this))
{
std::cerr << "Failed to create thread number " << idx << std::endl;
::exit(EXIT_FAILURE);
}
}
// Thread d'tor waits for thread termination before to return.
Thread::~Thread() {
assert(do_sleep);
do_exit = true; // Search must be already finished
wake_up();
thread_join(handle); // Wait for thread termination
}
// Thread::timer_loop() is where the timer thread waits maxPly milliseconds and
// then calls check_time(). If maxPly is 0 thread sleeps until is woken up.
extern void check_time(); extern void check_time();
void Thread::timer_loop() { namespace {
// start_routine() is the C function which is called when a new thread
// is launched. It is a wrapper to the virtual function idle_loop().
extern "C" { long start_routine(ThreadBase* th) { th->idle_loop(); return 0; } }
// Helpers to launch a thread after creation and joining before delete. Must be
// outside Thread c'tor and d'tor because the object must be fully initialized
// when start_routine (and hence virtual idle_loop) is called and when joining.
template<typename T> T* new_thread() {
T* th = new T();
thread_create(th->handle, start_routine, th); // Will go to sleep
return th;
}
void delete_thread(ThreadBase* th) {
th->mutex.lock();
th->exit = true; // Search must be already finished
th->mutex.unlock();
th->notify_one();
thread_join(th->handle); // Wait for thread termination
delete th;
}
while (!do_exit)
{
mutex.lock();
sleepCondition.wait_for(mutex, maxPly ? maxPly : INT_MAX);
mutex.unlock();
check_time();
}
} }
// Thread::main_loop() is where the main thread is parked waiting to be started // ThreadBase::notify_one() wakes up the thread when there is some work to do
// when there is a new search. Main thread will launch all the slave threads.
void Thread::main_loop() { void ThreadBase::notify_one() {
while (true)
{
mutex.lock();
do_sleep = true; // Always return to sleep after a search
is_searching = false;
while (do_sleep && !do_exit)
{
Threads.sleepCondition.notify_one(); // Wake up UI thread if needed
sleepCondition.wait(mutex);
}
mutex.unlock();
if (do_exit)
return;
is_searching = true;
Search::think();
assert(is_searching);
}
}
// Thread::wake_up() wakes up the thread, normally at the beginning of the search
// or, if "sleeping threads" is used at split time.
void Thread::wake_up() {
mutex.lock(); mutex.lock();
sleepCondition.notify_one(); sleepCondition.notify_one();
@@ -131,29 +73,35 @@ void Thread::wake_up() {
} }
// Thread::wait_for_stop_or_ponderhit() is called when the maximum depth is // ThreadBase::wait_for() set the thread to sleep until 'condition' turns true
// reached while the program is pondering. The point is to work around a wrinkle
// in the UCI protocol: When pondering, the engine is not allowed to give a
// "bestmove" before the GUI sends it a "stop" or "ponderhit" command. We simply
// wait here until one of these commands (that raise StopRequest) is sent and
// then return, after which the bestmove and pondermove will be printed.
void Thread::wait_for_stop_or_ponderhit() { void ThreadBase::wait_for(volatile const bool& condition) {
Signals.stopOnPonderhit = true;
mutex.lock(); mutex.lock();
while (!Signals.stop) sleepCondition.wait(mutex);; while (!condition) sleepCondition.wait(mutex);
mutex.unlock(); mutex.unlock();
} }
// Thread c'tor makes some init but does not launch any execution thread that
// will be started only when c'tor returns.
Thread::Thread() /* : splitPoints() */ { // Initialization of non POD broken in MSVC
searching = false;
maxPly = splitPointsSize = 0;
activeSplitPoint = NULL;
activePosition = NULL;
idx = Threads.size(); // Starts from 0
}
// Thread::cutoff_occurred() checks whether a beta cutoff has occurred in the // Thread::cutoff_occurred() checks whether a beta cutoff has occurred in the
// current active split point, or in some ancestor of the split point. // current active split point, or in some ancestor of the split point.
bool Thread::cutoff_occurred() const { bool Thread::cutoff_occurred() const {
for (SplitPoint* sp = curSplitPoint; sp; sp = sp->parent) for (SplitPoint* sp = activeSplitPoint; sp; sp = sp->parentSplitPoint)
if (sp->cutoff) if (sp->cutoff)
return true; return true;
@@ -161,276 +109,277 @@ bool Thread::cutoff_occurred() const {
} }
// Thread::is_available_to() checks whether the thread is available to help the // Thread::available_to() checks whether the thread is available to help the
// thread 'master' at a split point. An obvious requirement is that thread must // thread 'master' at a split point. An obvious requirement is that thread must
// be idle. With more than two threads, this is not sufficient: If the thread is // be idle. With more than two threads, this is not sufficient: If the thread is
// the master of some active split point, it is only available as a slave to the // the master of some split point, it is only available as a slave to the slaves
// slaves which are busy searching the split point at the top of slaves split // which are busy searching the split point at the top of slave's split point
// point stack (the "helpful master concept" in YBWC terminology). // stack (the "helpful master concept" in YBWC terminology).
bool Thread::is_available_to(Thread* master) const { bool Thread::available_to(const Thread* master) const {
if (is_searching) if (searching)
return false; return false;
// Make a local copy to be sure doesn't become zero under our feet while // Make a local copy to be sure it doesn't become zero under our feet while
// testing next condition and so leading to an out of bound access. // testing next condition and so leading to an out of bounds access.
int spCnt = splitPointsCnt; const int size = splitPointsSize;
// No active split points means that the thread is available as a slave for any // No split points means that the thread is available as a slave for any
// other thread otherwise apply the "helpful master" concept if possible. // other thread otherwise apply the "helpful master" concept if possible.
return !spCnt || (splitPoints[spCnt - 1].slavesMask & (1ULL << master->idx)); return !size || splitPoints[size - 1].slavesMask.test(master->idx);
} }
// init() is called at startup. Initializes lock and condition variable and // Thread::split() does the actual work of distributing the work at a node between
// launches requested threads sending them immediately to sleep. We cannot use // several available threads. If it does not succeed in splitting the node
// a c'tor becuase Threads is a static object and we need a fully initialized // (because no idle threads are available), the function immediately returns.
// engine at this point due to allocation of endgames in Thread c'tor. // If splitting is possible, a SplitPoint object is initialized with all the
// data that must be copied to the helper threads and then helper threads are
// informed that they have been assigned work. This will cause them to instantly
// leave their idle loops and call search(). When all threads have returned from
// search() then split() returns.
void Thread::split(Position& pos, Stack* ss, Value alpha, Value beta, Value* bestValue,
Move* bestMove, Depth depth, int moveCount,
MovePicker* movePicker, int nodeType, bool cutNode) {
assert(searching);
assert(-VALUE_INFINITE < *bestValue && *bestValue <= alpha && alpha < beta && beta <= VALUE_INFINITE);
assert(depth >= Threads.minimumSplitDepth);
assert(splitPointsSize < MAX_SPLITPOINTS_PER_THREAD);
// Pick and init the next available split point
SplitPoint& sp = splitPoints[splitPointsSize];
sp.masterThread = this;
sp.parentSplitPoint = activeSplitPoint;
sp.slavesMask = 0, sp.slavesMask.set(idx);
sp.depth = depth;
sp.bestValue = *bestValue;
sp.bestMove = *bestMove;
sp.alpha = alpha;
sp.beta = beta;
sp.nodeType = nodeType;
sp.cutNode = cutNode;
sp.movePicker = movePicker;
sp.moveCount = moveCount;
sp.pos = &pos;
sp.nodes = 0;
sp.cutoff = false;
sp.ss = ss;
// Try to allocate available threads and ask them to start searching setting
// 'searching' flag. This must be done under lock protection to avoid concurrent
// allocation of the same slave by another master.
Threads.mutex.lock();
sp.mutex.lock();
sp.allSlavesSearching = true; // Must be set under lock protection
++splitPointsSize;
activeSplitPoint = &sp;
activePosition = NULL;
Thread* slave;
while ((slave = Threads.available_slave(this)) != NULL)
{
sp.slavesMask.set(slave->idx);
slave->activeSplitPoint = &sp;
slave->searching = true; // Slave leaves idle_loop()
slave->notify_one(); // Could be sleeping
}
// Everything is set up. The master thread enters the idle loop, from which
// it will instantly launch a search, because its 'searching' flag is set.
// The thread will return from the idle loop when all slaves have finished
// their work at this split point.
sp.mutex.unlock();
Threads.mutex.unlock();
Thread::idle_loop(); // Force a call to base class idle_loop()
// In the helpful master concept, a master can help only a sub-tree of its
// split point and because everything is finished here, it's not possible
// for the master to be booked.
assert(!searching);
assert(!activePosition);
// We have returned from the idle loop, which means that all threads are
// finished. Note that setting 'searching' and decreasing splitPointsSize must
// be done under lock protection to avoid a race with Thread::available_to().
Threads.mutex.lock();
sp.mutex.lock();
searching = true;
--splitPointsSize;
activeSplitPoint = sp.parentSplitPoint;
activePosition = &pos;
pos.set_nodes_searched(pos.nodes_searched() + sp.nodes);
*bestMove = sp.bestMove;
*bestValue = sp.bestValue;
sp.mutex.unlock();
Threads.mutex.unlock();
}
// TimerThread::idle_loop() is where the timer thread waits Resolution milliseconds
// and then calls check_time(). When not searching, thread sleeps until it's woken up.
void TimerThread::idle_loop() {
while (!exit)
{
mutex.lock();
if (!exit)
sleepCondition.wait_for(mutex, run ? Resolution : INT_MAX);
mutex.unlock();
if (run)
check_time();
}
}
// MainThread::idle_loop() is where the main thread is parked waiting to be started
// when there is a new search. The main thread will launch all the slave threads.
void MainThread::idle_loop() {
while (!exit)
{
mutex.lock();
thinking = false;
while (!thinking && !exit)
{
Threads.sleepCondition.notify_one(); // Wake up the UI thread if needed
sleepCondition.wait(mutex);
}
mutex.unlock();
if (!exit)
{
searching = true;
Search::think();
assert(searching);
searching = false;
}
}
}
// ThreadPool::init() is called at startup to create and launch requested threads,
// that will go immediately to sleep. We cannot use a c'tor because Threads is a
// static object and we need a fully initialized engine at this point due to
// allocation of Endgames in Thread c'tor.
void ThreadPool::init() { void ThreadPool::init() {
timer = new Thread(&Thread::timer_loop); timer = new_thread<TimerThread>();
threads.push_back(new Thread(&Thread::main_loop)); push_back(new_thread<MainThread>());
read_uci_options(); read_uci_options();
} }
// exit() cleanly terminates the threads before the program exits. // ThreadPool::exit() terminates the threads before the program exits. Cannot be
// done in d'tor because threads must be terminated before freeing us.
void ThreadPool::exit() { void ThreadPool::exit() {
for (size_t i = 0; i < threads.size(); i++) delete_thread(timer); // As first because check_time() accesses threads data
delete threads[i];
delete timer; for (iterator it = begin(); it != end(); ++it)
delete_thread(*it);
} }
// read_uci_options() updates internal threads parameters from the corresponding // ThreadPool::read_uci_options() updates internal threads parameters from the
// UCI options and creates/destroys threads to match the requested number. Thread // corresponding UCI options and creates/destroys threads to match the requested
// objects are dynamically allocated to avoid creating in advance all possible // number. Thread objects are dynamically allocated to avoid creating all possible
// threads, with included pawns and material tables, if only few are used. // threads in advance (which include pawns and material tables), even if only a
// few are to be used.
void ThreadPool::read_uci_options() { void ThreadPool::read_uci_options() {
maxThreadsPerSplitPoint = Options["Max Threads per Split Point"]; minimumSplitDepth = Options["Min Split Depth"] * ONE_PLY;
minimumSplitDepth = Options["Min Split Depth"] * ONE_PLY; size_t requested = Options["Threads"];
useSleepingThreads = Options["Use Sleeping Threads"];
size_t requested = Options["Threads"];
assert(requested > 0); assert(requested > 0);
while (threads.size() < requested) // If zero (default) then set best minimum split depth automatically
threads.push_back(new Thread(&Thread::idle_loop)); if (!minimumSplitDepth)
minimumSplitDepth = requested < 8 ? 4 * ONE_PLY : 7 * ONE_PLY;
while (threads.size() > requested) while (size() < requested)
push_back(new_thread<Thread>());
while (size() > requested)
{ {
delete threads.back(); delete_thread(back());
threads.pop_back(); pop_back();
} }
} }
// wake_up() is called before a new search to start the threads that are waiting // ThreadPool::available_slave() tries to find an idle thread which is available
// on the sleep condition and to reset maxPly. When useSleepingThreads is set // as a slave for the thread 'master'.
// threads will be woken up at split time.
void ThreadPool::wake_up() const { Thread* ThreadPool::available_slave(const Thread* master) const {
for (size_t i = 0; i < threads.size(); i++) for (const_iterator it = begin(); it != end(); ++it)
{ if ((*it)->available_to(master))
threads[i]->maxPly = 0; return *it;
threads[i]->do_sleep = false;
if (!useSleepingThreads) return NULL;
threads[i]->wake_up();
}
} }
// sleep() is called after the search finishes to ask all the threads but the // ThreadPool::wait_for_think_finished() waits for main thread to finish the search
// main one to go waiting on a sleep condition.
void ThreadPool::sleep() const { void ThreadPool::wait_for_think_finished() {
// Main thread will go to sleep by itself to avoid a race with start_searching() MainThread* th = main();
for (size_t i = 1; i < threads.size(); i++) th->mutex.lock();
threads[i]->do_sleep = true; while (th->thinking) sleepCondition.wait(th->mutex);
th->mutex.unlock();
} }
// available_slave_exists() tries to find an idle thread which is available as // ThreadPool::start_thinking() wakes up the main thread sleeping in
// a slave for the thread 'master'. // MainThread::idle_loop() and starts a new search, then returns immediately.
bool ThreadPool::available_slave_exists(Thread* master) const { void ThreadPool::start_thinking(const Position& pos, const LimitsType& limits,
StateStackPtr& states) {
for (size_t i = 0; i < threads.size(); i++) wait_for_think_finished();
if (threads[i]->is_available_to(master))
return true;
return false;
}
// split() does the actual work of distributing the work at a node between
// several available threads. If it does not succeed in splitting the node
// (because no idle threads are available, or because we have no unused split
// point objects), the function immediately returns. If splitting is possible, a
// SplitPoint object is initialized with all the data that must be copied to the
// helper threads and then helper threads are told that they have been assigned
// work. This will cause them to instantly leave their idle loops and call
// search(). When all threads have returned from search() then split() returns.
template <bool Fake>
Value ThreadPool::split(Position& pos, Stack* ss, Value alpha, Value beta,
Value bestValue, Move* bestMove, Depth depth,
Move threatMove, int moveCount, MovePicker* mp, int nodeType) {
assert(pos.pos_is_ok());
assert(bestValue > -VALUE_INFINITE);
assert(bestValue <= alpha);
assert(alpha < beta);
assert(beta <= VALUE_INFINITE);
assert(depth > DEPTH_ZERO);
Thread* master = pos.this_thread();
if (master->splitPointsCnt >= MAX_SPLITPOINTS_PER_THREAD)
return bestValue;
// Pick the next available split point from the split point stack
SplitPoint& sp = master->splitPoints[master->splitPointsCnt];
sp.parent = master->curSplitPoint;
sp.master = master;
sp.cutoff = false;
sp.slavesMask = 1ULL << master->idx;
sp.depth = depth;
sp.bestMove = *bestMove;
sp.threatMove = threatMove;
sp.alpha = alpha;
sp.beta = beta;
sp.nodeType = nodeType;
sp.bestValue = bestValue;
sp.mp = mp;
sp.moveCount = moveCount;
sp.pos = &pos;
sp.nodes = 0;
sp.ss = ss;
assert(master->is_searching);
master->curSplitPoint = &sp;
int slavesCnt = 0;
// Try to allocate available threads and ask them to start searching setting
// is_searching flag. This must be done under lock protection to avoid concurrent
// allocation of the same slave by another master.
sp.mutex.lock();
mutex.lock();
for (size_t i = 0; i < threads.size() && !Fake; ++i)
if (threads[i]->is_available_to(master))
{
sp.slavesMask |= 1ULL << i;
threads[i]->curSplitPoint = &sp;
threads[i]->is_searching = true; // Slave leaves idle_loop()
if (useSleepingThreads)
threads[i]->wake_up();
if (++slavesCnt + 1 >= maxThreadsPerSplitPoint) // Master is always included
break;
}
master->splitPointsCnt++;
mutex.unlock();
sp.mutex.unlock();
// Everything is set up. The master thread enters the idle loop, from which
// it will instantly launch a search, because its is_searching flag is set.
// The thread will return from the idle loop when all slaves have finished
// their work at this split point.
if (slavesCnt || Fake)
{
master->idle_loop();
// In helpful master concept a master can help only a sub-tree of its split
// point, and because here is all finished is not possible master is booked.
assert(!master->is_searching);
}
// We have returned from the idle loop, which means that all threads are
// finished. Note that setting is_searching and decreasing splitPointsCnt is
// done under lock protection to avoid a race with Thread::is_available_to().
sp.mutex.lock(); // To protect sp.nodes
mutex.lock();
master->is_searching = true;
master->splitPointsCnt--;
master->curSplitPoint = sp.parent;
pos.set_nodes_searched(pos.nodes_searched() + sp.nodes);
*bestMove = sp.bestMove;
mutex.unlock();
sp.mutex.unlock();
return sp.bestValue;
}
// Explicit template instantiations
template Value ThreadPool::split<false>(Position&, Stack*, Value, Value, Value, Move*, Depth, Move, int, MovePicker*, int);
template Value ThreadPool::split<true>(Position&, Stack*, Value, Value, Value, Move*, Depth, Move, int, MovePicker*, int);
// set_timer() is used to set the timer to trigger after msec milliseconds.
// If msec is 0 then timer is stopped.
void ThreadPool::set_timer(int msec) {
timer->mutex.lock();
timer->maxPly = msec;
timer->sleepCondition.notify_one(); // Wake up and restart the timer
timer->mutex.unlock();
}
// wait_for_search_finished() waits for main thread to go to sleep, this means
// search is finished. Then returns.
void ThreadPool::wait_for_search_finished() {
Thread* t = main_thread();
t->mutex.lock();
t->sleepCondition.notify_one(); // In case is waiting for stop or ponderhit
while (!t->do_sleep) sleepCondition.wait(t->mutex);
t->mutex.unlock();
}
// start_searching() wakes up the main thread sleeping in main_loop() so to start
// a new search, then returns immediately.
void ThreadPool::start_searching(const Position& pos, const LimitsType& limits,
const std::vector<Move>& searchMoves, StateStackPtr& states) {
wait_for_search_finished();
SearchTime = Time::now(); // As early as possible SearchTime = Time::now(); // As early as possible
Signals.stopOnPonderhit = Signals.firstRootMove = false; Signals.stopOnPonderhit = Signals.firstRootMove = false;
Signals.stop = Signals.failedLowAtRoot = false; Signals.stop = Signals.failedLowAtRoot = false;
RootPosition = pos;
Limits = limits;
SetupStates = states; // Ownership transfer here
RootMoves.clear(); RootMoves.clear();
RootPos = pos;
Limits = limits;
if (states.get()) // If we don't set a new position, preserve current state
{
SetupStates = states; // Ownership transfer here
assert(!states.get());
}
for (MoveList<LEGAL> ml(pos); !ml.end(); ++ml) for (MoveList<LEGAL> it(pos); *it; ++it)
if (searchMoves.empty() || count(searchMoves.begin(), searchMoves.end(), ml.move())) if ( limits.searchmoves.empty()
RootMoves.push_back(RootMove(ml.move())); || std::count(limits.searchmoves.begin(), limits.searchmoves.end(), *it))
RootMoves.push_back(RootMove(*it));
main_thread()->do_sleep = false; main()->thinking = true;
main_thread()->wake_up(); main()->notify_one(); // Starts main thread
} }
+85 -67
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-2012 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, 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
@@ -17,9 +17,10 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#if !defined(THREAD_H_INCLUDED) #ifndef THREAD_H_INCLUDED
#define THREAD_H_INCLUDED #define THREAD_H_INCLUDED
#include <bitset>
#include <vector> #include <vector>
#include "material.h" #include "material.h"
@@ -28,9 +29,14 @@
#include "position.h" #include "position.h"
#include "search.h" #include "search.h"
const int MAX_THREADS = 32; struct Thread;
const int MAX_THREADS = 128;
const int MAX_SPLITPOINTS_PER_THREAD = 8; const int MAX_SPLITPOINTS_PER_THREAD = 8;
/// Mutex and ConditionVariable struct are wrappers of the low level locking
/// machinery and are modeled after the corresponding C++11 classes.
struct Mutex { struct Mutex {
Mutex() { lock_init(l); } Mutex() { lock_init(l); }
~Mutex() { lock_destroy(l); } ~Mutex() { lock_destroy(l); }
@@ -56,27 +62,30 @@ private:
WaitCondition c; WaitCondition c;
}; };
class Thread;
/// SplitPoint struct stores information shared by the threads searching in
/// parallel below the same split point. It is populated at splitting time.
struct SplitPoint { struct SplitPoint {
// Const data after split point has been setup // Const data after split point has been setup
const Position* pos; const Position* pos;
const Search::Stack* ss; Search::Stack* ss;
Thread* masterThread;
Depth depth; Depth depth;
Value beta; Value beta;
int nodeType; int nodeType;
Thread* master; bool cutNode;
Move threatMove;
// Const pointers to shared data // Const pointers to shared data
MovePicker* mp; MovePicker* movePicker;
SplitPoint* parent; SplitPoint* parentSplitPoint;
// Shared data // Shared variable data
Mutex mutex; Mutex mutex;
volatile uint64_t slavesMask; std::bitset<MAX_THREADS> slavesMask;
volatile int64_t nodes; volatile bool allSlavesSearching;
volatile uint64_t nodes;
volatile Value alpha; volatile Value alpha;
volatile Value bestValue; volatile Value bestValue;
volatile Move bestMove; volatile Move bestMove;
@@ -85,84 +94,93 @@ struct SplitPoint {
}; };
/// ThreadBase struct is the base of the hierarchy from where we derive all the
/// specialized thread classes.
struct ThreadBase {
ThreadBase() : handle(NativeHandle()), exit(false) {}
virtual ~ThreadBase() {}
virtual void idle_loop() = 0;
void notify_one();
void wait_for(volatile const bool& b);
Mutex mutex;
ConditionVariable sleepCondition;
NativeHandle handle;
volatile bool exit;
};
/// Thread struct keeps together all the thread related stuff like locks, state /// Thread struct keeps together all the thread related stuff like locks, state
/// and especially split points. We also use per-thread pawn and material hash /// and especially split points. We also use per-thread pawn and material hash
/// tables so that once we get a pointer to an entry its life time is unlimited /// tables so that once we get a pointer to an entry its life time is unlimited
/// and we don't have to care about someone changing the entry under our feet. /// and we don't have to care about someone changing the entry under our feet.
class Thread { struct Thread : public ThreadBase {
typedef void (Thread::* Fn) (); // Pointer to member function Thread();
virtual void idle_loop();
public:
Thread(Fn fn);
~Thread();
void wake_up();
bool cutoff_occurred() const; bool cutoff_occurred() const;
bool is_available_to(Thread* master) const; bool available_to(const Thread* master) const;
void idle_loop();
void main_loop(); void split(Position& pos, Search::Stack* ss, Value alpha, Value beta, Value* bestValue, Move* bestMove,
void timer_loop(); Depth depth, int moveCount, MovePicker* movePicker, int nodeType, bool cutNode);
void wait_for_stop_or_ponderhit();
SplitPoint splitPoints[MAX_SPLITPOINTS_PER_THREAD]; SplitPoint splitPoints[MAX_SPLITPOINTS_PER_THREAD];
MaterialTable materialTable; Pawns::Table pawnsTable;
PawnTable pawnTable; Material::Table materialTable;
Endgames endgames;
Position* activePosition;
size_t idx; size_t idx;
int maxPly; int maxPly;
Mutex mutex; SplitPoint* volatile activeSplitPoint;
ConditionVariable sleepCondition; volatile int splitPointsSize;
NativeHandle handle; volatile bool searching;
Fn start_fn;
SplitPoint* volatile curSplitPoint;
volatile int splitPointsCnt;
volatile bool is_searching;
volatile bool do_sleep;
volatile bool do_exit;
}; };
/// ThreadPool class handles all the threads related stuff like init, starting, /// MainThread and TimerThread are derived classes used to characterize the two
/// parking and, the most important, launching a slave thread at a split point. /// special threads: the main one and the recurring timer.
struct MainThread : public Thread {
MainThread() : thinking(true) {} // Avoid a race with start_thinking()
virtual void idle_loop();
volatile bool thinking;
};
struct TimerThread : public ThreadBase {
static const int Resolution = 5; // Millisec between two check_time() calls
TimerThread() : run(false) {}
virtual void idle_loop();
bool run;
};
/// ThreadPool struct handles all the threads related stuff like init, starting,
/// parking and, most importantly, launching a slave thread at a split point.
/// All the access to shared thread data is done through this class. /// All the access to shared thread data is done through this class.
class ThreadPool { struct ThreadPool : public std::vector<Thread*> {
public: void init(); // No c'tor and d'tor, threads rely on globals that should be
void init(); // No c'tor and d'tor, threads rely on globals that should void exit(); // initialized and are valid during the whole thread lifetime.
void exit(); // be initialized and valid during the whole thread lifetime.
Thread& operator[](size_t id) { return *threads[id]; } MainThread* main() { return static_cast<MainThread*>(at(0)); }
bool use_sleeping_threads() const { return useSleepingThreads; }
int min_split_depth() const { return minimumSplitDepth; }
size_t size() const { return threads.size(); }
Thread* main_thread() { return threads[0]; }
void wake_up() const;
void sleep() const;
void read_uci_options(); void read_uci_options();
bool available_slave_exists(Thread* master) const; Thread* available_slave(const Thread* master) const;
void set_timer(int msec); void wait_for_think_finished();
void wait_for_search_finished(); void start_thinking(const Position&, const Search::LimitsType&, Search::StateStackPtr&);
void start_searching(const Position&, const Search::LimitsType&,
const std::vector<Move>&, Search::StateStackPtr&);
template <bool Fake> Depth minimumSplitDepth;
Value split(Position& pos, Search::Stack* ss, Value alpha, Value beta, Value bestValue, Move* bestMove,
Depth depth, Move threatMove, int moveCount, MovePicker* mp, int nodeType);
private:
friend class Thread;
std::vector<Thread*> threads;
Thread* timer;
Mutex mutex; Mutex mutex;
ConditionVariable sleepCondition; ConditionVariable sleepCondition;
Depth minimumSplitDepth; TimerThread* timer;
int maxThreadsPerSplitPoint;
bool useSleepingThreads;
}; };
extern ThreadPool Threads; extern ThreadPool Threads;
#endif // !defined(THREAD_H_INCLUDED) #endif // #ifndef THREAD_H_INCLUDED
+71 -117
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-2012 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, 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
@@ -17,146 +17,100 @@
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 <cmath>
#include <algorithm> #include <algorithm>
#include <cfloat>
#include <cmath>
#include "search.h" #include "search.h"
#include "timeman.h" #include "timeman.h"
#include "ucioption.h" #include "uci.h"
namespace { namespace {
/// Constants
const int MoveHorizon = 50; // Plan time management at most this many moves ahead
const float MaxRatio = 3.0f; // When in trouble, we can step over reserved time with this ratio
const float StealRatio = 0.33f; // However we must not steal time from remaining moves over this ratio
// MoveImportance[] is based on naive statistical analysis of "how many games are still undecided
// after n half-moves". Game is considered "undecided" as long as neither side has >275cp advantage.
// Data was extracted from CCRL game database with some simple filtering criteria.
const int MoveImportance[512] = {
7780, 7780, 7780, 7780, 7780, 7780, 7780, 7780, 7780, 7780, 7780, 7780, 7780, 7780, 7780, 7780,
7780, 7780, 7780, 7780, 7778, 7778, 7776, 7776, 7776, 7773, 7770, 7768, 7766, 7763, 7757, 7751,
7743, 7735, 7724, 7713, 7696, 7689, 7670, 7656, 7627, 7605, 7571, 7549, 7522, 7493, 7462, 7425,
7385, 7350, 7308, 7272, 7230, 7180, 7139, 7094, 7055, 7010, 6959, 6902, 6841, 6778, 6705, 6651,
6569, 6508, 6435, 6378, 6323, 6253, 6152, 6085, 5995, 5931, 5859, 5794, 5717, 5646, 5544, 5462,
5364, 5282, 5172, 5078, 4988, 4901, 4831, 4764, 4688, 4609, 4536, 4443, 4365, 4293, 4225, 4155,
4085, 4005, 3927, 3844, 3765, 3693, 3634, 3560, 3479, 3404, 3331, 3268, 3207, 3146, 3077, 3011,
2947, 2894, 2828, 2776, 2727, 2676, 2626, 2589, 2538, 2490, 2442, 2394, 2345, 2302, 2243, 2192,
2156, 2115, 2078, 2043, 2004, 1967, 1922, 1893, 1845, 1809, 1772, 1736, 1702, 1674, 1640, 1605,
1566, 1536, 1509, 1479, 1452, 1423, 1388, 1362, 1332, 1304, 1289, 1266, 1250, 1228, 1206, 1180,
1160, 1134, 1118, 1100, 1080, 1068, 1051, 1034, 1012, 1001, 980, 960, 945, 934, 916, 900, 888,
878, 865, 852, 828, 807, 787, 770, 753, 744, 731, 722, 706, 700, 683, 676, 671, 664, 652, 641,
634, 627, 613, 604, 591, 582, 568, 560, 552, 540, 534, 529, 519, 509, 495, 484, 474, 467, 460,
450, 438, 427, 419, 410, 406, 399, 394, 387, 382, 377, 372, 366, 359, 353, 348, 343, 337, 333,
328, 321, 315, 309, 303, 298, 293, 287, 284, 281, 277, 273, 265, 261, 255, 251, 247, 241, 240,
235, 229, 218, 217, 213, 212, 208, 206, 197, 193, 191, 189, 185, 184, 180, 177, 172, 170, 170,
170, 166, 163, 159, 158, 156, 155, 151, 146, 141, 138, 136, 132, 130, 128, 125, 123, 122, 118,
118, 118, 117, 115, 114, 108, 107, 105, 105, 105, 102, 97, 97, 95, 94, 93, 91, 88, 86, 83, 80,
80, 79, 79, 79, 78, 76, 75, 72, 72, 71, 70, 68, 65, 63, 61, 61, 59, 59, 59, 58, 56, 55, 54, 54,
52, 49, 48, 48, 48, 48, 45, 45, 45, 44, 43, 41, 41, 41, 41, 40, 40, 38, 37, 36, 34, 34, 34, 33,
31, 29, 29, 29, 28, 28, 28, 28, 28, 28, 28, 27, 27, 27, 27, 27, 24, 24, 23, 23, 22, 21, 20, 20,
19, 19, 19, 19, 19, 18, 18, 18, 18, 17, 17, 17, 17, 17, 16, 16, 15, 15, 14, 14, 14, 12, 12, 11,
9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 2, 2, 2, 2,
2, 1, 1, 1, 1, 1, 1, 1 };
int move_importance(int ply) { return MoveImportance[std::min(ply, 511)]; }
/// Function Prototypes
enum TimeType { OptimumTime, MaxTime }; enum TimeType { OptimumTime, MaxTime };
template<TimeType> const int MoveHorizon = 50; // Plan time management at most this many moves ahead
int remaining(int myTime, int movesToGo, int fullMoveNumber, int slowMover); const double MaxRatio = 7.0; // When in trouble, we can step over reserved time with this ratio
} const double StealRatio = 0.33; // However we must not steal time from remaining moves over this ratio
void TimeManager::pv_instability(int curChanges, int prevChanges) { // move_importance() is a skew-logistic function based on naive statistical
// analysis of "how many games are still undecided after n half-moves". Game
// is considered "undecided" as long as neither side has >275cp advantage.
// Data was extracted from CCRL game database with some simple filtering criteria.
unstablePVExtraTime = curChanges * (optimumSearchTime / 2) double move_importance(int ply) {
+ prevChanges * (optimumSearchTime / 3);
}
const double XScale = 9.3;
const double XShift = 59.8;
const double Skew = 0.172;
void TimeManager::init(const Search::LimitsType& limits, int currentPly, Color us) return pow((1 + exp((ply - XShift) / XScale)), -Skew) + DBL_MIN; // Ensure non-zero
{ }
/* We support four different kind of time controls:
increment == 0 && movesToGo == 0 means: x basetime [sudden death!] template<TimeType T>
increment == 0 && movesToGo != 0 means: x moves in y minutes int remaining(int myTime, int movesToGo, int ply, int slowMover)
increment > 0 && movesToGo == 0 means: x basetime + z increment
increment > 0 && movesToGo != 0 means: x moves in y minutes + z increment
Time management is adjusted by following UCI parameters:
emergencyMoveHorizon: Be prepared to always play at least this many moves
emergencyBaseTime : Always attempt to keep at least this much time (in ms) at clock
emergencyMoveTime : Plus attempt to keep at least this much time for each remaining emergency move
minThinkingTime : No matter what, use at least this much thinking before doing the move
*/
int hypMTG, hypMyTime, t1, t2;
// Read uci parameters
int emergencyMoveHorizon = Options["Emergency Move Horizon"];
int emergencyBaseTime = Options["Emergency Base Time"];
int emergencyMoveTime = Options["Emergency Move Time"];
int minThinkingTime = Options["Minimum Thinking Time"];
int slowMover = Options["Slow Mover"];
// Initialize to maximum values but unstablePVExtraTime that is reset
unstablePVExtraTime = 0;
optimumSearchTime = maximumSearchTime = limits.time[us];
// We calculate optimum time usage for different hypothetic "moves to go"-values and choose the
// minimum of calculated search time values. Usually the greatest hypMTG gives the minimum values.
for (hypMTG = 1; hypMTG <= (limits.movestogo ? std::min(limits.movestogo, MoveHorizon) : MoveHorizon); hypMTG++)
{ {
// Calculate thinking time for hypothetic "moves to go"-value const double TMaxRatio = (T == OptimumTime ? 1 : MaxRatio);
hypMyTime = limits.time[us] const double TStealRatio = (T == OptimumTime ? 0 : StealRatio);
+ limits.inc[us] * (hypMTG - 1)
- emergencyBaseTime double moveImportance = (move_importance(ply) * slowMover) / 100;
- emergencyMoveTime * std::min(hypMTG, emergencyMoveHorizon); double otherMovesImportance = 0;
for (int i = 1; i < movesToGo; ++i)
otherMovesImportance += move_importance(ply + 2 * i);
double ratio1 = (TMaxRatio * moveImportance) / (TMaxRatio * moveImportance + otherMovesImportance);
double ratio2 = (moveImportance + TStealRatio * otherMovesImportance) / (moveImportance + otherMovesImportance);
return int(myTime * std::min(ratio1, ratio2)); // Intel C++ asks an explicit cast
}
} // namespace
/// init() is called at the beginning of the search and calculates the allowed
/// thinking time out of the time control and current game ply. We support four
/// different kinds of time controls, passed in 'limits':
///
/// inc == 0 && movestogo == 0 means: x basetime [sudden death!]
/// inc == 0 && movestogo != 0 means: x moves in y minutes
/// inc > 0 && movestogo == 0 means: x basetime + z increment
/// inc > 0 && movestogo != 0 means: x moves in y minutes + z increment
void TimeManager::init(const Search::LimitsType& limits, Color us, int ply)
{
int minThinkingTime = Options["Minimum Thinking Time"];
int moveOverhead = Options["Move Overhead"];
int slowMover = Options["Slow Mover"];
// Initialize unstablePvFactor to 1 and search times to maximum values
unstablePvFactor = 1;
optimumSearchTime = maximumSearchTime = std::max(limits.time[us], minThinkingTime);
const int MaxMTG = limits.movestogo ? std::min(limits.movestogo, MoveHorizon) : MoveHorizon;
// We calculate optimum time usage for different hypothetical "moves to go"-values
// and choose the minimum of calculated search time values. Usually the greatest
// hypMTG gives the minimum values.
for (int hypMTG = 1; hypMTG <= MaxMTG; ++hypMTG)
{
// Calculate thinking time for hypothetical "moves to go"-value
int hypMyTime = limits.time[us]
+ limits.inc[us] * (hypMTG - 1)
- moveOverhead * (2 + std::min(hypMTG, 40));
hypMyTime = std::max(hypMyTime, 0); hypMyTime = std::max(hypMyTime, 0);
t1 = minThinkingTime + remaining<OptimumTime>(hypMyTime, hypMTG, currentPly, slowMover); int t1 = minThinkingTime + remaining<OptimumTime>(hypMyTime, hypMTG, ply, slowMover);
t2 = minThinkingTime + remaining<MaxTime>(hypMyTime, hypMTG, currentPly, slowMover); int t2 = minThinkingTime + remaining<MaxTime >(hypMyTime, hypMTG, ply, slowMover);
optimumSearchTime = std::min(optimumSearchTime, t1); optimumSearchTime = std::min(t1, optimumSearchTime);
maximumSearchTime = std::min(maximumSearchTime, t2); maximumSearchTime = std::min(t2, maximumSearchTime);
} }
if (Options["Ponder"]) if (Options["Ponder"])
optimumSearchTime += optimumSearchTime / 4; optimumSearchTime += optimumSearchTime / 4;
// Make sure that maxSearchTime is not over absoluteMaxSearchTime
optimumSearchTime = std::min(optimumSearchTime, maximumSearchTime); optimumSearchTime = std::min(optimumSearchTime, maximumSearchTime);
} }
namespace {
template<TimeType T>
int remaining(int myTime, int movesToGo, int currentPly, int slowMover)
{
const float TMaxRatio = (T == OptimumTime ? 1 : MaxRatio);
const float TStealRatio = (T == OptimumTime ? 0 : StealRatio);
int thisMoveImportance = move_importance(currentPly) * slowMover / 100;
int otherMovesImportance = 0;
for (int i = 1; i < movesToGo; i++)
otherMovesImportance += move_importance(currentPly + 2 * i);
float ratio1 = (TMaxRatio * thisMoveImportance) / float(TMaxRatio * thisMoveImportance + otherMovesImportance);
float ratio2 = (thisMoveImportance + TStealRatio * otherMovesImportance) / float(thisMoveImportance + otherMovesImportance);
return int(floor(myTime * std::min(ratio1, ratio2)));
}
}
+8 -8
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-2012 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, 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
@@ -17,23 +17,23 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#if !defined(TIMEMAN_H_INCLUDED) #ifndef TIMEMAN_H_INCLUDED
#define TIMEMAN_H_INCLUDED #define TIMEMAN_H_INCLUDED
/// The TimeManager class computes the optimal time to think depending on the /// The TimeManager class computes the optimal time to think depending on the
/// maximum available time, the move game number and other parameters. /// maximum available time, the game move number and other parameters.
class TimeManager { class TimeManager {
public: public:
void init(const Search::LimitsType& limits, int currentPly, Color us); void init(const Search::LimitsType& limits, Color us, int ply);
void pv_instability(int curChanges, int prevChanges); void pv_instability(double bestMoveChanges) { unstablePvFactor = 1 + bestMoveChanges; }
int available_time() const { return optimumSearchTime + unstablePVExtraTime; } int available_time() const { return int(optimumSearchTime * unstablePvFactor * 0.71); }
int maximum_time() const { return maximumSearchTime; } int maximum_time() const { return maximumSearchTime; }
private: private:
int optimumSearchTime; int optimumSearchTime;
int maximumSearchTime; int maximumSearchTime;
int unstablePVExtraTime; double unstablePvFactor;
}; };
#endif // !defined(TIMEMAN_H_INCLUDED) #endif // #ifndef TIMEMAN_H_INCLUDED
+39 -82
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-2012 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, 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
@@ -17,7 +17,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 <cstring> #include <cstring> // For std::memset
#include <iostream> #include <iostream>
#include "bitboard.h" #include "bitboard.h"
@@ -25,117 +25,74 @@
TranspositionTable TT; // Our global transposition table TranspositionTable TT; // Our global transposition table
TranspositionTable::TranspositionTable() {
size = generation = 0; /// TranspositionTable::resize() sets the size of the transposition table,
entries = NULL; /// measured in megabytes. Transposition table consists of a power of 2 number
} /// of clusters and each cluster consists of ClusterSize number of TTEntry.
TranspositionTable::~TranspositionTable() { void TranspositionTable::resize(size_t mbSize) {
delete [] entries; assert(sizeof(Cluster) == CacheLineSize / 2);
}
size_t newClusterCount = size_t(1) << msb((mbSize * 1024 * 1024) / sizeof(Cluster));
/// TranspositionTable::set_size() sets the size of the transposition table, if (newClusterCount == clusterCount)
/// measured in megabytes. Transposition table consists of a power of 2 number of
/// TTCluster and each cluster consists of ClusterSize number of TTEntries. Each
/// non-empty entry contains information of exactly one position.
void TranspositionTable::set_size(size_t mbSize) {
size_t newSize = 1ULL << msb((mbSize << 20) / sizeof(TTCluster));
if (newSize == size)
return; return;
size = newSize; clusterCount = newClusterCount;
delete [] entries;
entries = new (std::nothrow) TTCluster[size];
if (!entries) free(mem);
mem = calloc(clusterCount * sizeof(Cluster) + CacheLineSize - 1, 1);
if (!mem)
{ {
std::cerr << "Failed to allocate " << mbSize std::cerr << "Failed to allocate " << mbSize
<< "MB for transposition table." << std::endl; << "MB for transposition table." << std::endl;
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
clear(); // Operator new is not guaranteed to initialize memory to zero table = (Cluster*)((uintptr_t(mem) + CacheLineSize - 1) & ~(CacheLineSize - 1));
} }
/// TranspositionTable::clear() overwrites the entire transposition table /// TranspositionTable::clear() overwrites the entire transposition table
/// with zeroes. It is called whenever the table is resized, or when the /// with zeros. It is called whenever the table is resized, or when the
/// user asks the program to clear the table (from the UCI interface). /// user asks the program to clear the table (from the UCI interface).
void TranspositionTable::clear() { void TranspositionTable::clear() {
memset(entries, 0, size * sizeof(TTCluster)); std::memset(table, 0, clusterCount * sizeof(Cluster));
} }
/// TranspositionTable::store() writes a new entry containing position key and /// TranspositionTable::probe() looks up the current position in the transposition
/// valuable information of current position. The lowest order bits of position /// table. It returns true and a pointer to the TTEntry if the position is found.
/// key are used to decide on which cluster the position will be placed. /// Otherwise, it returns false and a pointer to an empty or least valuable TTEntry
/// When a new entry is written and there are no empty entries available in cluster, /// to be replaced later. A TTEntry t1 is considered to be more valuable than a
/// it replaces the least valuable of entries. A TTEntry t1 is considered to be /// TTEntry t2 if t1 is from the current search and t2 is from a previous search,
/// more valuable than a TTEntry t2 if t1 is from the current search and t2 is from /// or if the depth of t1 is bigger than the depth of t2.
/// a previous search, or if the depth of t1 is bigger than the depth of t2.
void TranspositionTable::store(const Key posKey, Value v, Bound t, Depth d, Move m, Value statV, Value kingD) { TTEntry* TranspositionTable::probe(const Key key, bool& found) const {
int c1, c2, c3; TTEntry* const tte = first_entry(key);
TTEntry *tte, *replace; const uint16_t key16 = key >> 48; // Use the high 16 bits as key inside the cluster
uint32_t posKey32 = posKey >> 32; // Use the high 32 bits as key inside the cluster
tte = replace = first_entry(posKey); for (int i = 0; i < ClusterSize; ++i)
if (!tte[i].key16 || tte[i].key16 == key16)
for (int i = 0; i < ClusterSize; i++, tte++)
{
if (!tte->key() || tte->key() == posKey32) // Empty or overwrite old
{ {
// Preserve any existing ttMove if (tte[i].key16)
if (m == MOVE_NONE) tte[i].genBound8 = uint8_t(generation8 | tte[i].bound()); // Refresh
m = tte->move();
tte->save(posKey32, v, t, d, m, generation, statV, kingD); return found = (bool)tte[i].key16, &tte[i];
return;
} }
// Implement replace strategy // Find an entry to be replaced according to the replacement strategy
c1 = (replace->generation() == generation ? 2 : 0); TTEntry* replace = tte;
c2 = (tte->generation() == generation || tte->type() == BOUND_EXACT ? -2 : 0); for (int i = 1; i < ClusterSize; ++i)
c3 = (tte->depth() < replace->depth() ? 1 : 0); if ( (( tte[i].genBound8 & 0xFC) == generation8 || tte[i].bound() == BOUND_EXACT)
- ((replace->genBound8 & 0xFC) == generation8)
- (tte[i].depth8 < replace->depth8) < 0)
replace = &tte[i];
if (c1 + c2 + c3 > 0) return found = false, replace;
replace = tte;
}
replace->save(posKey32, v, t, d, m, generation, statV, kingD);
}
/// TranspositionTable::probe() looks up the current position in the
/// transposition table. Returns a pointer to the TTEntry or NULL if
/// position is not found.
TTEntry* TranspositionTable::probe(const Key posKey) const {
uint32_t posKey32 = posKey >> 32;
TTEntry* tte = first_entry(posKey);
for (int i = 0; i < ClusterSize; i++, tte++)
if (tte->key() == posKey32)
return tte;
return NULL;
}
/// TranspositionTable::new_search() is called at the beginning of every new
/// search. It increments the "generation" variable, which is used to
/// distinguish transposition table entries from previous searches from
/// entries from the current search.
void TranspositionTable::new_search() {
generation++;
} }
+60 -90
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2012 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, 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
@@ -17,120 +17,90 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#if !defined(TT_H_INCLUDED) #ifndef TT_H_INCLUDED
#define TT_H_INCLUDED #define TT_H_INCLUDED
#include "misc.h" #include "misc.h"
#include "types.h" #include "types.h"
/// The TTEntry is the class of transposition table entries /// TTEntry struct is the 10 bytes transposition table entry, defined as below:
/// ///
/// A TTEntry needs 128 bits to be stored /// key 16 bit
/// /// move 16 bit
/// bit 0-31: key /// value 16 bit
/// bit 32-63: data /// eval value 16 bit
/// bit 64-79: value /// generation 6 bit
/// bit 80-95: depth /// bound type 2 bit
/// bit 96-111: static value /// depth 8 bit
/// bit 112-127: margin of static value
///
/// the 32 bits of the data field are so defined
///
/// bit 0-15: move
/// bit 16-20: not used
/// bit 21-22: value type
/// bit 23-31: generation
class TTEntry { struct TTEntry {
public: Move move() const { return (Move )move16; }
void save(uint32_t k, Value v, Bound b, Depth d, Move m, int g, Value statV, Value statM) { Value value() const { return (Value)value16; }
Value eval() const { return (Value)eval16; }
Depth depth() const { return (Depth)depth8; }
Bound bound() const { return (Bound)(genBound8 & 0x3); }
key32 = (uint32_t)k; void save(Key k, Value v, Bound b, Depth d, Move m, Value ev, uint8_t g) {
move16 = (uint16_t)m;
bound = (uint8_t)b; if (m || (k >> 48) != key16) // Preserve any existing move for the same position
generation8 = (uint8_t)g; move16 = (uint16_t)m;
value16 = (int16_t)v;
depth16 = (int16_t)d; key16 = (uint16_t)(k >> 48);
staticValue = (int16_t)statV; value16 = (int16_t)v;
staticMargin = (int16_t)statM; eval16 = (int16_t)ev;
genBound8 = (uint8_t)(g | b);
depth8 = (int8_t)d;
} }
void set_generation(int g) { generation8 = (uint8_t)g; }
uint32_t key() const { return key32; }
Depth depth() const { return (Depth)depth16; }
Move move() const { return (Move)move16; }
Value value() const { return (Value)value16; }
Bound type() const { return (Bound)bound; }
int generation() const { return (int)generation8; }
Value static_value() const { return (Value)staticValue; }
Value static_value_margin() const { return (Value)staticMargin; }
private: private:
uint32_t key32; friend class TranspositionTable;
uint16_t key16;
uint16_t move16; uint16_t move16;
uint8_t bound, generation8; int16_t value16;
int16_t value16, depth16, staticValue, staticMargin; int16_t eval16;
uint8_t genBound8;
int8_t depth8;
}; };
/// This is the number of TTEntry slots for each cluster /// A TranspositionTable consists of a power of 2 number of clusters and each
const int ClusterSize = 4; /// cluster consists of ClusterSize number of TTEntry. Each non-empty entry
/// contains information of exactly one position. The size of a cluster should
/// not be bigger than a cache line size. In case it is less, it should be padded
/// TTCluster consists of ClusterSize number of TTEntries. Size of TTCluster /// to guarantee always aligned accesses.
/// must not be bigger than a cache line size. In case it is less, it should
/// be padded to guarantee always aligned accesses.
struct TTCluster {
TTEntry data[ClusterSize];
};
/// The transposition table class. This is basically just a huge array containing
/// TTCluster objects, and a few methods for writing and reading entries.
class TranspositionTable { class TranspositionTable {
TranspositionTable(const TranspositionTable&); static const int CacheLineSize = 64;
TranspositionTable& operator=(const TranspositionTable&); static const int ClusterSize = 3;
struct Cluster {
TTEntry entry[ClusterSize];
char padding[2]; // Align to the cache line size
};
public: public:
TranspositionTable(); ~TranspositionTable() { free(mem); }
~TranspositionTable(); void new_search() { generation8 += 4; } // Lower 2 bits are used by Bound
void set_size(size_t mbSize); uint8_t generation() const { return generation8; }
TTEntry* probe(const Key key, bool& found) const;
void resize(size_t mbSize);
void clear(); void clear();
void store(const Key posKey, Value v, Bound type, Depth d, Move m, Value statV, Value kingD);
TTEntry* probe(const Key posKey) const; // The lowest order bits of the key are used to get the index of the cluster
void new_search(); TTEntry* first_entry(const Key key) const {
TTEntry* first_entry(const Key posKey) const; return &table[(size_t)key & (clusterCount - 1)].entry[0];
void refresh(const TTEntry* tte) const; }
private: private:
size_t size; size_t clusterCount;
TTCluster* entries; Cluster* table;
uint8_t generation; // Size must be not bigger then TTEntry::generation8 void* mem;
uint8_t generation8; // Size must be not bigger than TTEntry::genBound8
}; };
extern TranspositionTable TT; extern TranspositionTable TT;
#endif // #ifndef TT_H_INCLUDED
/// TranspositionTable::first_entry() returns a pointer to the first entry of
/// a cluster given a position. The lowest order bits of the key are used to
/// get the index of the cluster.
inline TTEntry* TranspositionTable::first_entry(const Key posKey) const {
return entries[((uint32_t)posKey) & (size - 1)].data;
}
/// TranspositionTable::refresh() updates the 'generation' value of the TTEntry
/// to avoid aging. Normally called after a TT hit.
inline void TranspositionTable::refresh(const TTEntry* tte) const {
const_cast<TTEntry*>(tte)->set_generation(generation);
}
#endif // !defined(TT_H_INCLUDED)
+177 -234
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-2012 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, 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
@@ -17,47 +17,60 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#if !defined(TYPES_H_INCLUDED) #ifndef TYPES_H_INCLUDED
#define TYPES_H_INCLUDED #define TYPES_H_INCLUDED
/// For Linux and OSX configuration is done automatically using Makefile. To get /// When compiling with provided Makefile (e.g. for Linux and OSX), configuration
/// started type 'make help'. /// is done automatically. To get started type 'make help'.
/// ///
/// For Windows, part of the configuration is detected automatically, but some /// When Makefile is not used (e.g. with Microsoft Visual Studio) some switches
/// switches need to be set manually: /// need to be set manually:
/// ///
/// -DNDEBUG | Disable debugging mode. Use always. /// -DNDEBUG | Disable debugging mode. Always use this for release.
/// ///
/// -DNO_PREFETCH | Disable use of prefetch asm-instruction. A must if you want /// -DNO_PREFETCH | Disable use of prefetch asm-instruction. You may need this to
/// | the executable to run on some very old machines. /// | run on some very old machines.
/// ///
/// -DUSE_POPCNT | Add runtime support for use of popcnt asm-instruction. Works /// -DUSE_POPCNT | Add runtime support for use of popcnt asm-instruction. Works
/// | only in 64-bit mode. For compiling requires hardware with /// | only in 64-bit mode and requires hardware with popcnt support.
/// | popcnt support.
#include <cassert>
#include <cctype> #include <cctype>
#include <climits> #include <climits>
#include <cstdlib> #include <cstdlib>
#include "platform.h" #include "platform.h"
#if defined(_WIN64) /// Predefined macros hell:
///
/// __GNUC__ Compiler is gcc, Clang or Intel on Linux
/// __INTEL_COMPILER Compiler is Intel
/// _MSC_VER Compiler is MSVC or Intel on Windows
/// _WIN32 Building on Windows (any)
/// _WIN64 Building on Windows 64 bit
#if defined(_WIN64) && !defined(IS_64BIT) // Last condition means Makefile is not used
# include <intrin.h> // MSVC popcnt and bsfq instrinsics # include <intrin.h> // MSVC popcnt and bsfq instrinsics
# define IS_64BIT # define IS_64BIT
# define USE_BSFQ # define USE_BSFQ
#endif #endif
#if defined(USE_POPCNT) && defined(_MSC_VER) && defined(__INTEL_COMPILER) #if defined(USE_POPCNT) && defined(__INTEL_COMPILER) && defined(_MSC_VER)
# include <nmmintrin.h> // Intel header for _mm_popcnt_u64() intrinsic # include <nmmintrin.h> // Intel header for _mm_popcnt_u64() intrinsic
#endif #endif
#if defined(_MSC_VER) || defined(__INTEL_COMPILER) #if !defined(NO_PREFETCH) && (defined(__INTEL_COMPILER) || defined(_MSC_VER))
# define CACHE_LINE_ALIGNMENT __declspec(align(64)) # include <xmmintrin.h> // Intel and Microsoft header for _mm_prefetch()
#else
# define CACHE_LINE_ALIGNMENT __attribute__ ((aligned(64)))
#endif #endif
#if defined(_MSC_VER) #if defined(USE_PEXT)
# include <immintrin.h> // Header for _pext_u64() intrinsic
# define pext(b, m) _pext_u64(b, m)
#else
# define pext(b, m) (0)
#endif
#ifdef _MSC_VER
# define FORCE_INLINE __forceinline # define FORCE_INLINE __forceinline
#elif defined(__GNUC__) #elif defined(__GNUC__)
# define FORCE_INLINE inline __attribute__((always_inline)) # define FORCE_INLINE inline __attribute__((always_inline))
@@ -65,13 +78,19 @@
# define FORCE_INLINE inline # define FORCE_INLINE inline
#endif #endif
#if defined(USE_POPCNT) #ifdef USE_POPCNT
const bool HasPopCnt = true; const bool HasPopCnt = true;
#else #else
const bool HasPopCnt = false; const bool HasPopCnt = false;
#endif #endif
#if defined(IS_64BIT) #ifdef USE_PEXT
const bool HasPext = true;
#else
const bool HasPext = false;
#endif
#ifdef IS_64BIT
const bool Is64Bit = true; const bool Is64Bit = true;
#else #else
const bool Is64Bit = false; const bool Is64Bit = false;
@@ -80,128 +99,125 @@ const bool Is64Bit = false;
typedef uint64_t Key; typedef uint64_t Key;
typedef uint64_t Bitboard; typedef uint64_t Bitboard;
const int MAX_MOVES = 192; const int MAX_MOVES = 256;
const int MAX_PLY = 100; const int MAX_PLY = 128;
const int MAX_PLY_PLUS_2 = MAX_PLY + 2;
const Bitboard FileABB = 0x0101010101010101ULL;
const Bitboard FileBBB = FileABB << 1;
const Bitboard FileCBB = FileABB << 2;
const Bitboard FileDBB = FileABB << 3;
const Bitboard FileEBB = FileABB << 4;
const Bitboard FileFBB = FileABB << 5;
const Bitboard FileGBB = FileABB << 6;
const Bitboard FileHBB = FileABB << 7;
const Bitboard Rank1BB = 0xFF;
const Bitboard Rank2BB = Rank1BB << (8 * 1);
const Bitboard Rank3BB = Rank1BB << (8 * 2);
const Bitboard Rank4BB = Rank1BB << (8 * 3);
const Bitboard Rank5BB = Rank1BB << (8 * 4);
const Bitboard Rank6BB = Rank1BB << (8 * 5);
const Bitboard Rank7BB = Rank1BB << (8 * 6);
const Bitboard Rank8BB = Rank1BB << (8 * 7);
/// A move needs 16 bits to be stored /// A move needs 16 bits to be stored
/// ///
/// bit 0- 5: destination square (from 0 to 63) /// bit 0- 5: destination square (from 0 to 63)
/// bit 6-11: origin square (from 0 to 63) /// bit 6-11: origin square (from 0 to 63)
/// bit 12-13: promotion piece type - 2 (from KNIGHT-2 to QUEEN-2) /// bit 12-13: promotion piece type - 2 (from KNIGHT-2 to QUEEN-2)
/// bit 14-15: special move flag: promotion (1), en passant (2), castle (3) /// bit 14-15: special move flag: promotion (1), en passant (2), castling (3)
/// NOTE: EN-PASSANT bit is set only when a pawn can be captured
/// ///
/// Special cases are MOVE_NONE and MOVE_NULL. We can sneak these in because in /// Special cases are MOVE_NONE and MOVE_NULL. We can sneak these in because in
/// any normal move destination square is always different from origin square /// any normal move destination square is always different from origin square
/// while MOVE_NONE and MOVE_NULL have the same origin and destination square. /// while MOVE_NONE and MOVE_NULL have the same origin and destination square.
enum Move { enum Move {
MOVE_NONE = 0, MOVE_NONE,
MOVE_NULL = 65 MOVE_NULL = 65
}; };
enum MoveType { enum MoveType {
NORMAL = 0, NORMAL,
PROMOTION = 1 << 14, PROMOTION = 1 << 14,
ENPASSANT = 2 << 14, ENPASSANT = 2 << 14,
CASTLE = 3 << 14 CASTLING = 3 << 14
}; };
enum CastleRight { // Defined as in PolyGlot book hash key enum Color {
CASTLES_NONE = 0, WHITE, BLACK, NO_COLOR, COLOR_NB = 2
WHITE_OO = 1,
WHITE_OOO = 2,
BLACK_OO = 4,
BLACK_OOO = 8,
ALL_CASTLES = 15
}; };
enum CastlingSide { enum CastlingSide {
KING_SIDE, KING_SIDE, QUEEN_SIDE, CASTLING_SIDE_NB = 2
QUEEN_SIDE };
enum CastlingRight {
NO_CASTLING,
WHITE_OO,
WHITE_OOO = WHITE_OO << 1,
BLACK_OO = WHITE_OO << 2,
BLACK_OOO = WHITE_OO << 3,
ANY_CASTLING = WHITE_OO | WHITE_OOO | BLACK_OO | BLACK_OOO,
CASTLING_RIGHT_NB = 16
};
template<Color C, CastlingSide S> struct MakeCastling {
static const CastlingRight
right = C == WHITE ? S == QUEEN_SIDE ? WHITE_OOO : WHITE_OO
: S == QUEEN_SIDE ? BLACK_OOO : BLACK_OO;
};
enum Phase {
PHASE_ENDGAME,
PHASE_MIDGAME = 128,
MG = 0, EG = 1, PHASE_NB = 2
}; };
enum ScaleFactor { enum ScaleFactor {
SCALE_FACTOR_DRAW = 0, SCALE_FACTOR_DRAW = 0,
SCALE_FACTOR_NORMAL = 64, SCALE_FACTOR_ONEPAWN = 48,
SCALE_FACTOR_MAX = 128, SCALE_FACTOR_NORMAL = 64,
SCALE_FACTOR_NONE = 255 SCALE_FACTOR_MAX = 128,
SCALE_FACTOR_NONE = 255
}; };
enum Bound { enum Bound {
BOUND_NONE = 0, BOUND_NONE,
BOUND_UPPER = 1, BOUND_UPPER,
BOUND_LOWER = 2, BOUND_LOWER,
BOUND_EXACT = BOUND_UPPER | BOUND_LOWER BOUND_EXACT = BOUND_UPPER | BOUND_LOWER
}; };
enum Value { enum Value {
VALUE_ZERO = 0, VALUE_ZERO = 0,
VALUE_DRAW = 0, VALUE_DRAW = 0,
VALUE_KNOWN_WIN = 15000, VALUE_KNOWN_WIN = 10000,
VALUE_MATE = 30000, VALUE_MATE = 32000,
VALUE_INFINITE = 30001, VALUE_INFINITE = 32001,
VALUE_NONE = 30002, VALUE_NONE = 32002,
VALUE_MATE_IN_MAX_PLY = VALUE_MATE - MAX_PLY, VALUE_MATE_IN_MAX_PLY = VALUE_MATE - 2 * MAX_PLY,
VALUE_MATED_IN_MAX_PLY = -VALUE_MATE + MAX_PLY, VALUE_MATED_IN_MAX_PLY = -VALUE_MATE + 2 * MAX_PLY,
VALUE_ENSURE_INTEGER_SIZE_P = INT_MAX, VALUE_ENSURE_INTEGER_SIZE_P = INT_MAX,
VALUE_ENSURE_INTEGER_SIZE_N = INT_MIN, VALUE_ENSURE_INTEGER_SIZE_N = INT_MIN,
Mg = 0, Eg = 1,
PawnValueMg = 198, PawnValueEg = 258, PawnValueMg = 198, PawnValueEg = 258,
KnightValueMg = 817, KnightValueEg = 846, KnightValueMg = 817, KnightValueEg = 846,
BishopValueMg = 836, BishopValueEg = 857, BishopValueMg = 836, BishopValueEg = 857,
RookValueMg = 1270, RookValueEg = 1278, RookValueMg = 1270, RookValueEg = 1278,
QueenValueMg = 2521, QueenValueEg = 2558 QueenValueMg = 2521, QueenValueEg = 2558,
MidgameLimit = 15581, EndgameLimit = 3998
}; };
enum PieceType { enum PieceType {
NO_PIECE_TYPE = 0, ALL_PIECES = 0, NO_PIECE_TYPE, PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING,
PAWN = 1, KNIGHT = 2, BISHOP = 3, ROOK = 4, QUEEN = 5, KING = 6 ALL_PIECES = 0,
PIECE_TYPE_NB = 8
}; };
enum Piece { enum Piece {
NO_PIECE = 16, // color_of(NO_PIECE) == NO_COLOR NO_PIECE,
W_PAWN = 1, W_KNIGHT = 2, W_BISHOP = 3, W_ROOK = 4, W_QUEEN = 5, W_KING = 6, W_PAWN = 1, W_KNIGHT, W_BISHOP, W_ROOK, W_QUEEN, W_KING,
B_PAWN = 9, B_KNIGHT = 10, B_BISHOP = 11, B_ROOK = 12, B_QUEEN = 13, B_KING = 14 B_PAWN = 9, B_KNIGHT, B_BISHOP, B_ROOK, B_QUEEN, B_KING,
}; PIECE_NB = 16
enum Color {
WHITE, BLACK, NO_COLOR
}; };
enum Depth { enum Depth {
ONE_PLY = 2, ONE_PLY = 1,
DEPTH_ZERO = 0 * ONE_PLY, DEPTH_ZERO = 0,
DEPTH_QS_CHECKS = -1 * ONE_PLY, DEPTH_QS_CHECKS = 0,
DEPTH_QS_NO_CHECKS = -2 * ONE_PLY, DEPTH_QS_NO_CHECKS = -1,
DEPTH_QS_RECAPTURES = -5 * ONE_PLY, DEPTH_QS_RECAPTURES = -5,
DEPTH_NONE = -127 * ONE_PLY DEPTH_NONE = -6,
DEPTH_MAX = MAX_PLY
}; };
enum Square { enum Square {
@@ -215,6 +231,8 @@ 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,
DELTA_N = 8, DELTA_N = 8,
DELTA_E = 1, DELTA_E = 1,
DELTA_S = -8, DELTA_S = -8,
@@ -229,76 +247,81 @@ enum Square {
}; };
enum File { enum File {
FILE_A, FILE_B, FILE_C, FILE_D, FILE_E, FILE_F, FILE_G, FILE_H FILE_A, FILE_B, FILE_C, FILE_D, FILE_E, FILE_F, FILE_G, FILE_H, FILE_NB
}; };
enum Rank { enum Rank {
RANK_1, RANK_2, RANK_3, RANK_4, RANK_5, RANK_6, RANK_7, RANK_8 RANK_1, RANK_2, RANK_3, RANK_4, RANK_5, RANK_6, RANK_7, RANK_8, RANK_NB
}; };
/// Score enum keeps a midgame and an endgame value in a single integer (enum), /// Score enum stores a middlegame and an endgame value in a single integer.
/// first LSB 16 bits are used to store endgame value, while upper bits are used /// The least significant 16 bits are used to store the endgame value and
/// for midgame value. Compiler is free to choose the enum type as long as can /// the upper 16 bits are used to store the middlegame value. The compiler
/// keep its data, so ensure Score to be an integer type. /// is free to choose the enum type as long as it can store the data, so we
/// ensure that Score is an integer type by assigning some big int values.
enum Score { enum Score {
SCORE_ZERO = 0, SCORE_ZERO,
SCORE_ENSURE_INTEGER_SIZE_P = INT_MAX, SCORE_ENSURE_INTEGER_SIZE_P = INT_MAX,
SCORE_ENSURE_INTEGER_SIZE_N = INT_MIN SCORE_ENSURE_INTEGER_SIZE_N = INT_MIN
}; };
inline Score make_score(int mg, int eg) { return Score((mg << 16) + eg); } inline Score make_score(int mg, int eg) {
return Score((mg << 16) + eg);
/// Extracting the signed lower and upper 16 bits it not so trivial because
/// according to the standard a simple cast to short is implementation defined
/// and so is a right shift of a signed integer.
inline Value mg_value(Score s) { return Value(((s + 32768) & ~0xffff) / 0x10000); }
/// On Intel 64 bit we have a small speed regression with the standard conforming
/// version, so use a faster code in this case that, although not 100% standard
/// compliant it seems to work for Intel and MSVC.
#if defined(IS_64BIT) && (!defined(__GNUC__) || defined(__INTEL_COMPILER))
inline Value eg_value(Score s) { return Value(int16_t(s & 0xffff)); }
#else
inline Value eg_value(Score s) {
return Value((int)(unsigned(s) & 0x7fffu) - (int)(unsigned(s) & 0x8000u));
} }
#endif /// Extracting the signed lower and upper 16 bits is not so trivial because
/// according to the standard a simple cast to short is implementation defined
/// and so is a right shift of a signed integer.
inline Value mg_value(Score s) {
#define ENABLE_SAFE_OPERATORS_ON(T) \ union { uint16_t u; int16_t s; } mg = { uint16_t(unsigned(s + 0x8000) >> 16) };
inline T operator+(const T d1, const T d2) { return T(int(d1) + int(d2)); } \ return Value(mg.s);
inline T operator-(const T d1, const T d2) { return T(int(d1) - int(d2)); } \ }
inline T operator*(int i, const T d) { return T(i * int(d)); } \
inline T operator*(const T d, int i) { return T(int(d) * i); } \
inline T operator-(const T d) { return T(-int(d)); } \
inline T& operator+=(T& d1, const T d2) { d1 = d1 + d2; return d1; } \
inline T& operator-=(T& d1, const T d2) { d1 = d1 - d2; return d1; } \
inline T& operator*=(T& d, int i) { d = T(int(d) * i); return d; }
#define ENABLE_OPERATORS_ON(T) ENABLE_SAFE_OPERATORS_ON(T) \ inline Value eg_value(Score s) {
inline T operator++(T& d, int) { d = T(int(d) + 1); return d; } \
inline T operator--(T& d, int) { d = T(int(d) - 1); return d; } \
inline T operator/(const T d, int i) { return T(int(d) / i); } \
inline T& operator/=(T& d, int i) { d = T(int(d) / i); return d; }
ENABLE_OPERATORS_ON(Value) union { uint16_t u; int16_t s; } eg = { uint16_t(unsigned(s)) };
ENABLE_OPERATORS_ON(PieceType) return Value(eg.s);
ENABLE_OPERATORS_ON(Piece) }
ENABLE_OPERATORS_ON(Color)
ENABLE_OPERATORS_ON(Depth)
ENABLE_OPERATORS_ON(Square)
ENABLE_OPERATORS_ON(File)
ENABLE_OPERATORS_ON(Rank)
/// Added operators for adding integers to a Value #define ENABLE_BASE_OPERATORS_ON(T) \
inline 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)); } \
inline T operator*(int i, T d) { return T(i * int(d)); } \
inline T operator*(T d, int i) { return T(int(d) * i); } \
inline T operator-(T d) { return T(-int(d)); } \
inline T& operator+=(T& d1, T d2) { return d1 = d1 + d2; } \
inline T& operator-=(T& d1, T d2) { return d1 = d1 - d2; } \
inline T& operator*=(T& d, int i) { return d = T(int(d) * i); }
#define ENABLE_FULL_OPERATORS_ON(T) \
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, int i) { return T(int(d) / i); } \
inline int operator/(T d1, T d2) { return int(d1) / int(d2); } \
inline T& operator/=(T& d, int i) { return d = T(int(d) / i); }
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(Square)
ENABLE_FULL_OPERATORS_ON(File)
ENABLE_FULL_OPERATORS_ON(Rank)
ENABLE_BASE_OPERATORS_ON(Score)
#undef ENABLE_FULL_OPERATORS_ON
#undef ENABLE_BASE_OPERATORS_ON
/// Additional operators to add integers to a Value
inline Value operator+(Value v, int i) { return Value(int(v) + i); } inline Value operator+(Value v, int i) { return Value(int(v) + i); }
inline Value operator-(Value v, int i) { return Value(int(v) - i); } inline Value operator-(Value v, int i) { return Value(int(v) - i); }
inline Value& operator+=(Value& v, int i) { return v = v + i; }
ENABLE_SAFE_OPERATORS_ON(Score) inline Value& operator-=(Value& v, int i) { return v = v - i; }
/// 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.
@@ -309,51 +332,18 @@ 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);
} }
/// Weight score v by score w trying to prevent overflow extern Value PieceValue[PHASE_NB][PIECE_NB];
inline Score apply_weight(Score v, Score w) {
return make_score((int(mg_value(v)) * mg_value(w)) / 0x100,
(int(eg_value(v)) * eg_value(w)) / 0x100);
}
#undef ENABLE_OPERATORS_ON
#undef ENABLE_SAFE_OPERATORS_ON
namespace Zobrist {
extern Key psq[2][8][64]; // [color][pieceType][square / piece count]
extern Key enpassant[8]; // [file]
extern Key castle[16]; // [castleRight]
extern Key side;
extern Key exclusion;
void init();
}
CACHE_LINE_ALIGNMENT
extern Score pieceSquareTable[16][64]; // [piece][square]
extern Value PieceValue[2][18]; // [Mg / Eg][piece / pieceType]
extern int SquareDistance[64][64]; // [square][square]
struct MoveStack {
Move move;
int score;
};
inline bool operator<(const MoveStack& f, const MoveStack& s) {
return f.score < s.score;
}
inline Color operator~(Color c) { inline Color operator~(Color c) {
return Color(c ^ 1); return Color(c ^ BLACK);
} }
inline Square operator~(Square s) { inline Square operator~(Square s) {
return Square(s ^ 56); // Vertical flip SQ_A1 -> SQ_A8 return Square(s ^ SQ_A8); // Vertical flip SQ_A1 -> SQ_A8
} }
inline Square operator|(File f, Rank r) { inline CastlingRight operator|(Color c, CastlingSide s) {
return Square((r << 3) | f); return CastlingRight(WHITE_OO << ((s == QUEEN_SIDE) + 2 * c));
} }
inline Value mate_in(int ply) { inline Value mate_in(int ply) {
@@ -364,20 +354,21 @@ inline Value mated_in(int ply) {
return -VALUE_MATE + ply; return -VALUE_MATE + ply;
} }
inline Square make_square(File f, Rank r) {
return Square((r << 3) | f);
}
inline Piece make_piece(Color c, PieceType pt) { inline Piece make_piece(Color c, PieceType pt) {
return Piece((c << 3) | pt); return Piece((c << 3) | pt);
} }
inline CastleRight make_castle_right(Color c, CastlingSide s) { inline PieceType type_of(Piece pc) {
return CastleRight(WHITE_OO << ((s == QUEEN_SIDE) + 2 * c)); return PieceType(pc & 7);
} }
inline PieceType type_of(Piece p) { inline Color color_of(Piece pc) {
return PieceType(p & 7); assert(pc != NO_PIECE);
} return Color(pc >> 3);
inline Color color_of(Piece p) {
return Color(p >> 3);
} }
inline bool is_ok(Square s) { inline bool is_ok(Square s) {
@@ -392,10 +383,6 @@ inline Rank rank_of(Square s) {
return Rank(s >> 3); return Rank(s >> 3);
} }
inline Square mirror(Square s) {
return Square(s ^ 7); // Horizontal flip SQ_A1 -> SQ_H1
}
inline Square relative_square(Color c, Square s) { inline Square relative_square(Color c, Square s) {
return Square(s ^ (c * 56)); return Square(s ^ (c * 56));
} }
@@ -413,26 +400,6 @@ inline bool opposite_colors(Square s1, Square s2) {
return ((s >> 3) ^ s) & 1; return ((s >> 3) ^ s) & 1;
} }
inline int file_distance(Square s1, Square s2) {
return abs(file_of(s1) - file_of(s2));
}
inline int rank_distance(Square s1, Square s2) {
return abs(rank_of(s1) - rank_of(s2));
}
inline int square_distance(Square s1, Square s2) {
return SquareDistance[s1][s2];
}
inline char file_to_char(File f) {
return char(f - FILE_A + int('a'));
}
inline char rank_to_char(Rank r) {
return char(r - RANK_1 + int('1'));
}
inline Square pawn_push(Color c) { inline Square pawn_push(Color c) {
return c == WHITE ? DELTA_N : DELTA_S; return c == WHITE ? DELTA_N : DELTA_S;
} }
@@ -459,35 +426,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) { inline Move make(Square from, Square to, PieceType pt = KNIGHT) {
return Move(to | (from << 6) | T | ((pt - KNIGHT) << 12)) ; return Move(to | (from << 6) | T | ((pt - KNIGHT) << 12));
} }
inline bool is_ok(Move m) { inline bool is_ok(Move m) {
return from_sq(m) != to_sq(m); // Catches also MOVE_NULL and MOVE_NONE return from_sq(m) != to_sq(m); // Catch MOVE_NULL and MOVE_NONE
} }
#include <string> #endif // #ifndef TYPES_H_INCLUDED
inline const std::string square_to_string(Square s) {
char ch[] = { file_to_char(file_of(s)), rank_to_char(rank_of(s)), 0 };
return ch;
}
/// Our insertion sort implementation, works with pointers and iterators and is
/// guaranteed to be stable, as is needed.
template<typename T, typename K>
void sort(K first, K last)
{
T tmp;
K p, q;
for (p = first + 1; p < last; p++)
{
tmp = *p;
for (q = p; q != first && *(q-1) < tmp; --q)
*q = *(q-1);
*q = tmp;
}
}
#endif // !defined(TYPES_H_INCLUDED)
+179 -148
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-2012 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, 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,11 +22,12 @@
#include <string> #include <string>
#include "evaluate.h" #include "evaluate.h"
#include "notation.h" #include "movegen.h"
#include "position.h" #include "position.h"
#include "search.h" #include "search.h"
#include "thread.h" #include "thread.h"
#include "ucioption.h" #include "tt.h"
#include "uci.h"
using namespace std; using namespace std;
@@ -37,125 +38,18 @@ 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";
// Keep track of position keys along the setup moves (from start position to the // Stack to keep track of the position states along the setup moves (from the
// position just before to start searching). Needed by repetition draw detection. // start position to the position just before the search starts). Needed by
// 'draw by repetition' detection.
Search::StateStackPtr SetupStates; Search::StateStackPtr SetupStates;
void set_option(istringstream& up);
void set_position(Position& pos, istringstream& up);
void go(Position& pos, istringstream& up);
}
// position() is called when engine receives the "position" UCI command.
/// Wait for a command from the user, parse this text string as an UCI command, // The function sets up the position described in the given FEN string ("fen")
/// and call the appropriate functions. Also intercepts EOF from stdin to ensure
/// that we exit gracefully if the GUI dies unexpectedly. In addition to the UCI
/// commands, the function also supports a few debug commands.
void UCI::loop(const string& args) {
Position pos(StartFEN, false, Threads.main_thread()); // The root position
string cmd, token;
while (token != "quit")
{
if (!args.empty())
cmd = args;
else if (!getline(cin, cmd)) // Block here waiting for input
cmd = "quit";
istringstream is(cmd);
is >> skipws >> token;
if (token == "quit" || token == "stop")
{
Search::Signals.stop = true;
Threads.wait_for_search_finished(); // Cannot quit while threads are running
}
else if (token == "ponderhit")
{
// The opponent has played the expected move. GUI sends "ponderhit" if
// we were told to ponder on the same move the opponent has played. We
// should continue searching but switching from pondering to normal search.
Search::Limits.ponder = false;
if (Search::Signals.stopOnPonderhit)
{
Search::Signals.stop = true;
Threads.main_thread()->wake_up(); // Could be sleeping
}
}
else if (token == "go")
go(pos, is);
else if (token == "ucinewgame")
{ /* Avoid returning "Unknown command" */ }
else if (token == "isready")
sync_cout << "readyok" << sync_endl;
else if (token == "position")
set_position(pos, is);
else if (token == "setoption")
set_option(is);
else if (token == "d")
pos.print();
else if (token == "flip")
pos.flip();
else if (token == "eval")
sync_cout << Eval::trace(pos) << sync_endl;
else if (token == "bench")
benchmark(pos, is);
else if (token == "key")
sync_cout << "key: " << hex << pos.key()
<< "\nmaterial key: " << pos.material_key()
<< "\npawn key: " << pos.pawn_key() << sync_endl;
else if (token == "uci")
sync_cout << "id name " << engine_info(true)
<< "\n" << Options
<< "\nuciok" << sync_endl;
else if (token == "perft" && (is >> token)) // Read depth
{
stringstream ss;
ss << Options["Hash"] << " "
<< Options["Threads"] << " " << token << " current perft";
benchmark(pos, ss);
}
else
sync_cout << "Unknown command: " << cmd << sync_endl;
if (!args.empty()) // Command line arguments have one-shot behaviour
{
Threads.wait_for_search_finished();
break;
}
}
}
namespace {
// set_position() is called when engine receives the "position" UCI command.
// 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 set_position(Position& pos, istringstream& is) { void position(Position& pos, istringstream& is) {
Move m; Move m;
string token, fen; string token, fen;
@@ -173,11 +67,11 @@ namespace {
else else
return; return;
pos.from_fen(fen, Options["UCI_Chess960"], Threads.main_thread()); pos.set(fen, Options["UCI_Chess960"], Threads.main());
SetupStates = Search::StateStackPtr(new std::stack<StateInfo>()); SetupStates = Search::StateStackPtr(new std::stack<StateInfo>());
// Parse move list (if any) // Parse move list (if any)
while (is >> token && (m = move_from_uci(pos, token)) != MOVE_NONE) while (is >> token && (m = UCI::to_move(pos, token)) != MOVE_NONE)
{ {
SetupStates->push(StateInfo()); SetupStates->push(StateInfo());
pos.do_move(m, SetupStates->top()); pos.do_move(m, SetupStates->top());
@@ -185,10 +79,10 @@ namespace {
} }
// set_option() is called when engine receives the "setoption" UCI command. The // setoption() is called when engine receives the "setoption" UCI command. The
// function updates the UCI option ("name") to the given value ("value"). // function updates the UCI option ("name") to the given value ("value").
void set_option(istringstream& is) { void setoption(istringstream& is) {
string token, name, value; string token, name, value;
@@ -210,42 +104,179 @@ namespace {
// go() is called when engine receives the "go" UCI command. The function sets // go() is called when engine receives the "go" UCI command. The function sets
// the thinking time and other parameters from the input string, and 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(const Position& pos, istringstream& is) {
Search::LimitsType limits; Search::LimitsType limits;
vector<Move> searchMoves;
string token; string token;
while (is >> token) while (is >> token)
{ if (token == "searchmoves")
if (token == "wtime")
is >> limits.time[WHITE];
else if (token == "btime")
is >> limits.time[BLACK];
else if (token == "winc")
is >> limits.inc[WHITE];
else if (token == "binc")
is >> limits.inc[BLACK];
else if (token == "movestogo")
is >> limits.movestogo;
else if (token == "depth")
is >> limits.depth;
else if (token == "nodes")
is >> limits.nodes;
else if (token == "movetime")
is >> limits.movetime;
else if (token == "infinite")
limits.infinite = true;
else if (token == "ponder")
limits.ponder = true;
else if (token == "searchmoves")
while (is >> token) while (is >> token)
searchMoves.push_back(move_from_uci(pos, token)); limits.searchmoves.push_back(UCI::to_move(pos, token));
}
Threads.start_searching(pos, limits, searchMoves, SetupStates); else if (token == "wtime") is >> limits.time[WHITE];
else if (token == "btime") is >> limits.time[BLACK];
else if (token == "winc") is >> limits.inc[WHITE];
else if (token == "binc") is >> limits.inc[BLACK];
else if (token == "movestogo") is >> limits.movestogo;
else if (token == "depth") is >> limits.depth;
else if (token == "nodes") is >> limits.nodes;
else if (token == "movetime") is >> limits.movetime;
else if (token == "mate") is >> limits.mate;
else if (token == "infinite") limits.infinite = true;
else if (token == "ponder") limits.ponder = true;
Threads.start_thinking(pos, limits, SetupStates);
} }
} // namespace
/// UCI::loop() waits for a command from stdin, parses it and calls the appropriate
/// function. Also intercepts EOF from stdin to ensure gracefully exiting if the
/// GUI dies unexpectedly. When called with some command line arguments, e.g. to
/// run 'bench', once the command is executed the function returns immediately.
/// In addition to the UCI ones, also some additional debug commands are supported.
void UCI::loop(int argc, char* argv[]) {
Position pos(StartFEN, false, Threads.main()); // The root position
string token, cmd;
for (int i = 1; i < argc; ++i)
cmd += std::string(argv[i]) + " ";
do {
if (argc == 1 && !getline(cin, cmd)) // Block here waiting for input or EOF
cmd = "quit";
istringstream is(cmd);
token.clear(); // getline() could return empty or blank line
is >> skipws >> token;
// The GUI sends 'ponderhit' to tell us to ponder on the same move the
// opponent has played. In case Signals.stopOnPonderhit is set we are
// waiting for 'ponderhit' to stop the search (for instance because we
// already ran out of time), otherwise we should continue searching but
// switching from pondering to normal search.
if ( token == "quit"
|| token == "stop"
|| (token == "ponderhit" && Search::Signals.stopOnPonderhit))
{
Search::Signals.stop = true;
Threads.main()->notify_one(); // Could be sleeping
}
else if (token == "ponderhit")
Search::Limits.ponder = false; // Switch to normal search
else if (token == "uci")
sync_cout << "id name " << engine_info(true)
<< "\n" << Options
<< "\nuciok" << sync_endl;
else if (token == "isready") sync_cout << "readyok" << sync_endl;
else if (token == "ucinewgame") TT.clear();
else if (token == "go") go(pos, is);
else if (token == "position") position(pos, is);
else if (token == "setoption") setoption(is);
// Additional custom non-UCI commands, useful for debugging
else if (token == "flip") pos.flip();
else if (token == "bench") benchmark(pos, is);
else if (token == "d") sync_cout << 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
sync_cout << "Unknown command: " << cmd << sync_endl;
} while (token != "quit" && argc == 1); // Passed args have one-shot behaviour
Threads.wait_for_think_finished(); // Cannot quit whilst the search is running
}
/// UCI::value() converts a Value to a string suitable for use with the UCI
/// protocol specification:
///
/// cp <x> The score from the engine's point of view in centipawns.
/// mate <y> Mate in y moves, not plies. If the engine is getting mated
/// use negative values for y.
string UCI::value(Value v) {
stringstream ss;
if (abs(v) < VALUE_MATE - MAX_PLY)
ss << "cp " << v * 100 / PawnValueEg;
else
ss << "mate " << (v > 0 ? VALUE_MATE - v + 1 : -VALUE_MATE - v) / 2;
return ss.str();
}
/// UCI::square() converts a Square to a string in algebraic notation (g1, a7, etc.)
std::string UCI::square(Square s) {
char sq[] = { char('a' + file_of(s)), char('1' + rank_of(s)), 0 }; // NULL terminated
return sq;
}
/// UCI::move() converts a Move to a string in coordinate notation (g1f3, a7a8q).
/// The only special case is castling, where we print in the e1g1 notation in
/// normal chess mode, and in e1h1 notation in chess960 mode. Internally all
/// castling moves are always encoded as 'king captures rook'.
string UCI::move(Move m, bool chess960) {
Square from = from_sq(m);
Square to = to_sq(m);
if (m == MOVE_NONE)
return "(none)";
if (m == MOVE_NULL)
return "0000";
if (type_of(m) == CASTLING && !chess960)
to = make_square(to > from ? FILE_G : FILE_C, rank_of(from));
string move = UCI::square(from) + UCI::square(to);
if (type_of(m) == PROMOTION)
move += " pnbrqk"[promotion_type(m)];
return move;
}
/// UCI::to_move() converts a string representing a move in coordinate notation
/// (g1f3, a7a8q) to the corresponding legal Move, if any.
Move UCI::to_move(const Position& pos, string& str) {
if (str.length() == 5) // Junior could send promotion piece in uppercase
str[4] = char(tolower(str[4]));
for (MoveList<LEGAL> it(pos); *it; ++it)
if (str == UCI::move(*it, pos.is_chess960()))
return *it;
return MOVE_NONE;
} }
+20 -11
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-2012 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, 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
@@ -17,12 +17,16 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#if !defined(UCIOPTION_H_INCLUDED) #ifndef UCIOPTION_H_INCLUDED
#define UCIOPTION_H_INCLUDED #define UCIOPTION_H_INCLUDED
#include <map> #include <map>
#include <string> #include <string>
#include "types.h"
class Position;
namespace UCI { namespace UCI {
class Option; class Option;
@@ -38,15 +42,16 @@ typedef std::map<std::string, Option, CaseInsensitiveLess> OptionsMap;
/// Option class implements an option as defined by UCI protocol /// Option class implements an option as defined by UCI protocol
class Option { class Option {
typedef void (Fn)(const Option&); typedef void (*OnChange)(const Option&);
public: public:
Option(Fn* = NULL); Option(OnChange = NULL);
Option(bool v, Fn* = NULL); Option(bool v, OnChange = NULL);
Option(const char* v, Fn* = NULL); Option(const char* v, OnChange = NULL);
Option(int v, int min, int max, Fn* = NULL); Option(int v, int min, int max, OnChange = NULL);
Option& operator=(const std::string& v); Option& operator=(const std::string&);
void operator<<(const Option&);
operator int() const; operator int() const;
operator std::string() const; operator std::string() const;
@@ -56,14 +61,18 @@ private:
std::string defaultValue, currentValue, type; std::string defaultValue, currentValue, type;
int min, max; int min, max;
size_t idx; size_t idx;
Fn* on_change; OnChange on_change;
}; };
void init(OptionsMap&); void init(OptionsMap&);
void loop(const std::string&); void loop(int argc, char* argv[]);
std::string value(Value v);
std::string square(Square s);
std::string move(Move m, bool chess960);
Move to_move(const Position& pos, std::string& str);
} // namespace UCI } // namespace UCI
extern UCI::OptionsMap Options; extern UCI::OptionsMap Options;
#endif // !defined(UCIOPTION_H_INCLUDED) #endif // #ifndef UCIOPTION_H_INCLUDED
+44 -48
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-2012 Marco Costalba, Joona Kiiski, Tord Romstad Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, 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,11 +22,11 @@
#include <cstdlib> #include <cstdlib>
#include <sstream> #include <sstream>
#include "evaluate.h"
#include "misc.h" #include "misc.h"
#include "thread.h" #include "thread.h"
#include "tt.h" #include "tt.h"
#include "ucioption.h" #include "uci.h"
#include "syzygy/tbprobe.h"
using std::string; using std::string;
@@ -35,11 +35,11 @@ UCI::OptionsMap Options; // Global object
namespace UCI { namespace UCI {
/// 'On change' actions, triggered by an option's value change /// 'On change' actions, triggered by an option's value change
void on_logger(const Option& o) { start_logger(o); }
void on_eval(const Option&) { Eval::init(); }
void on_threads(const Option&) { Threads.read_uci_options(); }
void on_hash_size(const Option& o) { TT.set_size(o); }
void on_clear_hash(const Option&) { TT.clear(); } void on_clear_hash(const Option&) { TT.clear(); }
void on_hash_size(const Option& o) { TT.resize(o); }
void on_logger(const Option& o) { start_logger(o); }
void on_threads(const Option&) { Threads.read_uci_options(); }
void on_tb_path(const Option& o) { Tablebases::init(o); }
/// Our case insensitive less() function as required by UCI protocol /// Our case insensitive less() function as required by UCI protocol
@@ -50,44 +50,29 @@ bool CaseInsensitiveLess::operator() (const string& s1, const string& s2) const
} }
/// init() initializes the UCI options to their hard coded default values /// init() initializes the UCI options to their hard-coded default values
/// and initializes the default value of "Threads" and "Min Split Depth"
/// parameters according to the number of CPU cores detected.
void init(OptionsMap& o) { void init(OptionsMap& o) {
int cpus = std::min(cpu_count(), MAX_THREADS); const int MaxHashMB = Is64Bit ? 1024 * 1024 : 2048;
int msd = cpus < 8 ? 4 : 7;
o["Use Debug Log"] = Option(false, on_logger); o["Write Debug Log"] << Option(false, on_logger);
o["Use Search Log"] = Option(false); o["Contempt"] << Option(0, -100, 100);
o["Search Log Filename"] = Option("SearchLog.txt"); o["Min Split Depth"] << Option(0, 0, 12, on_threads);
o["Book File"] = Option("book.bin"); o["Threads"] << Option(1, 1, MAX_THREADS, on_threads);
o["Best Book Move"] = Option(false); o["Hash"] << Option(16, 1, MaxHashMB, on_hash_size);
o["Mobility (Middle Game)"] = Option(100, 0, 200, on_eval); o["Clear Hash"] << Option(on_clear_hash);
o["Mobility (Endgame)"] = Option(100, 0, 200, on_eval); o["Ponder"] << Option(true);
o["Passed Pawns (Middle Game)"] = Option(100, 0, 200, on_eval); o["MultiPV"] << Option(1, 1, 500);
o["Passed Pawns (Endgame)"] = Option(100, 0, 200, on_eval); o["Skill Level"] << Option(20, 0, 20);
o["Space"] = Option(100, 0, 200, on_eval); o["Move Overhead"] << Option(30, 0, 5000);
o["Aggressiveness"] = Option(100, 0, 200, on_eval); o["Minimum Thinking Time"] << Option(20, 0, 5000);
o["Cowardice"] = Option(100, 0, 200, on_eval); o["Slow Mover"] << Option(80, 10, 1000);
o["Min Split Depth"] = Option(msd, 4, 7, on_threads); o["UCI_Chess960"] << Option(false);
o["Max Threads per Split Point"] = Option(5, 4, 8, on_threads); o["SyzygyPath"] << Option("<empty>", on_tb_path);
o["Threads"] = Option(cpus, 1, MAX_THREADS, on_threads); o["SyzygyProbeDepth"] << Option(1, 1, 100);
o["Use Sleeping Threads"] = Option(false, on_threads); o["Syzygy50MoveRule"] << Option(true);
o["Hash"] = Option(32, 4, 8192, on_hash_size); o["SyzygyProbeLimit"] << Option(6, 0, 6);
o["Clear Hash"] = Option(on_clear_hash);
o["Ponder"] = Option(true);
o["OwnBook"] = Option(false);
o["MultiPV"] = Option(1, 1, 500);
o["Skill Level"] = Option(20, 0, 20);
o["Emergency Move Horizon"] = Option(40, 0, 50);
o["Emergency Base Time"] = Option(200, 0, 30000);
o["Emergency Move Time"] = Option(70, 0, 5000);
o["Minimum Thinking Time"] = Option(20, 0, 5000);
o["Slow Mover"] = Option(100, 10, 1000);
o["UCI_Chess960"] = Option(false);
o["UCI_AnalyseMode"] = Option(false, on_eval);
} }
@@ -96,7 +81,7 @@ void init(OptionsMap& o) {
std::ostream& operator<<(std::ostream& os, const OptionsMap& om) { std::ostream& operator<<(std::ostream& os, const OptionsMap& om) {
for (size_t idx = 0; idx < om.size(); idx++) for (size_t idx = 0; idx < om.size(); ++idx)
for (OptionsMap::const_iterator it = om.begin(); it != om.end(); ++it) for (OptionsMap::const_iterator it = om.begin(); it != om.end(); ++it)
if (it->second.idx == idx) if (it->second.idx == idx)
{ {
@@ -115,18 +100,18 @@ std::ostream& operator<<(std::ostream& os, const OptionsMap& om) {
} }
/// Option c'tors and conversion operators /// Option class constructors and conversion operators
Option::Option(const char* v, Fn* f) : type("string"), min(0), max(0), idx(Options.size()), on_change(f) Option::Option(const char* v, OnChange f) : type("string"), min(0), max(0), on_change(f)
{ defaultValue = currentValue = v; } { defaultValue = currentValue = v; }
Option::Option(bool v, Fn* f) : type("check"), min(0), max(0), idx(Options.size()), on_change(f) Option::Option(bool v, OnChange f) : type("check"), min(0), max(0), on_change(f)
{ defaultValue = currentValue = (v ? "true" : "false"); } { defaultValue = currentValue = (v ? "true" : "false"); }
Option::Option(Fn* f) : type("button"), min(0), max(0), idx(Options.size()), on_change(f) Option::Option(OnChange f) : type("button"), min(0), max(0), on_change(f)
{} {}
Option::Option(int v, int minv, int maxv, Fn* f) : type("spin"), min(minv), max(maxv), idx(Options.size()), on_change(f) Option::Option(int v, int minv, int maxv, OnChange f) : type("spin"), min(minv), max(maxv), on_change(f)
{ std::ostringstream ss; ss << v; defaultValue = currentValue = ss.str(); } { std::ostringstream ss; ss << v; defaultValue = currentValue = ss.str(); }
@@ -141,6 +126,17 @@ Option::operator std::string() const {
} }
/// operator<<() inits options and assigns idx in the correct printing order
void Option::operator<<(const Option& o) {
static size_t insert_order = 0;
*this = o;
idx = insert_order++;
}
/// operator=() updates currentValue and triggers on_change() action. It's up to /// operator=() updates currentValue and triggers on_change() action. It's up to
/// the GUI to check for option's limits, but we could receive the new value from /// the GUI to check for option's limits, but we could receive the new value from
/// the user by console window, so let's check the bounds anyway. /// the user by console window, so let's check the bounds anyway.
@@ -158,7 +154,7 @@ Option& Option::operator=(const string& v) {
currentValue = v; currentValue = v;
if (on_change) if (on_change)
(*on_change)(*this); on_change(*this);
return *this; return *this;
} }