Compare commits

...

441 Commits

Author SHA1 Message Date
Marco Costalba 369eff437c Stockfish 8
Bench: 5926706

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

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

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

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

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

With this patch gcc --sanitize builds cleanly.

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

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

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

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

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

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

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

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

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

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

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

Thanks to Werner Bergmans for reporting
the regression.

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

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

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

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

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

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

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

Results for 12 tests for each version:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Currently just compile builds, wthouth benching
the resulting executable.

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

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

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

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

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

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

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

Speed test by Stephane Nicolet

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

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

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

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

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

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

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

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

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

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

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

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

While there fix some small code style issues.

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

abs(ttValue) < VALUE_KNOWN_WIN

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

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

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

with 1 sec time:

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

Verified for no regression:

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

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

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

Spotted and reported by Dann Corbit.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

So, summarizing:

GOOD:

Measured big improvement in high core scenario

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

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

Non functional change for the common case of a single core

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

BAD:

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

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

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

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

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

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

The Movepick SEE is now dead code, retire it.

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

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

Test result is positive, master is weaker.

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

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

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

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

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

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

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

This correctly handles the majority of cases with absolute pins.

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

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

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

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

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

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

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

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

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

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

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

Credits: Leonardo Ljubičić for the strategic idea, Alain Savard for the
implementation of the open files calculation, "CrunchyNYC" for the
compensation of the numerator.

STC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 49112 W: 9239 L: 8900 D: 30973

LTC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 89415 W: 12014 L: 11601 D: 65800

Bench: 7591630
2016-09-03 00:04:20 +02:00
lucasart 13b4444d9e Change exclusion key setup
Should depend on which move is excluded. This
allow us to remove the dedicated Position::exclusion_key().

STC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 59814 W: 11136 L: 11083 D: 37595

LTC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 31023 W: 4187 L: 4080 D: 22756

bench 7553379
2016-09-02 08:37:01 +02:00
Stefano80 7f2eb10e93 Retire linear imbalance
Retire linear imbalance and compensate
in piece values enumeration.

STC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 43596 W: 8105 L: 8023 D: 27468

LTC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 24482 W: 3352 L: 3237 D: 17893

Bench: 7777707
2016-09-02 08:25:17 +02:00
ajithcj 5cffc032da Optimize order of a few conditions in search
Also fix size of KingDanger array to reduce memory footprint.

Small speed up of around 0.5%

No functional change.
2016-08-31 13:47:45 +02:00
VoyagerOne 2731bbaf6b Remove condition on killers in history pruning
Now allows main killer to be history prune.

STC:
LLR: 2.94 (-2.94,2.94) [-3.00,1.00]
Total: 15852 W: 2910 L: 2781 D: 10161

LTC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 56428 W: 7610 L: 7537 D: 41281

Bench: 8032058
2016-08-30 09:09:55 +02:00
Stefan Geschwentner 6aa9308f08 Tweak probcut threshold
Use better threshold for capture move generation.

STC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 23265 W: 4415 L: 4188 D: 14662

LTC:
LLR: 2.95 (-2.94,2.94) [0.00,4.00]
Total: 36618 W: 5083 L: 4836 D: 26699

bench: 7030088
2016-08-29 22:15:03 +02:00
Andrew Grant b4f6728e61 Removed an extra space
No functional change.
2016-08-28 09:47:30 +02:00
Alain SAVARD 2b57b61cb1 Move king tropism to evaluate_king
No functional change.
2016-08-28 08:49:40 +02:00
Marco Costalba 1ee2838214 Retire CheckInfo
Move its content directly under StateInfo.

Verified for no speed regression.

No functional change.
2016-08-28 08:08:13 +02:00
Marco Costalba 0b944c7186 Silence some warnings with MSVC 2013
No functional change.
2016-08-27 12:16:13 +02:00
Stéphane Nicolet 805afcbf3d Move CheckInfo under StateInfo
This greately simplifies usage because hides to the
search the implementation specific CheckInfo.

This is based on the work done by Marco in pull request #716,
implementing on top of it the ideas in the discussion: caching
the calls to slider_blockers() in the CheckInfo structure,
and simplifying the slider_blockers() function by removing its
first parameter.

Compared to master, bench is identical but the number of calls
to slider_blockers() during bench goes down from 22461515 to 18853422,
hopefully being a little bit faster overall.

archlinux, gcc-6
make profile-build ARCH=x86-64-bmi2
50 runs each

bench:
base = 2356320 +/- 981
test = 2403811 +/- 981
diff = 47490 +/- 1828

speedup = 0.0202
P(speedup > 0) = 1.0000

perft 6:
base = 175498484 +/- 429925
test = 183997959 +/- 429925
diff = 8499474 +/- 469401

speedup = 0.0484
P(speedup > 0) = 1.0000

perft 7 (but only 10 runs):
base = 185403228 +/- 468705
test = 188777591 +/- 468705
diff = 3374363 +/- 476687

speedup = 0.0182
P(speedup > 0) = 1.0000

$ ./pyshbench ../Stockfish/master ../Stockfish/test 20
run base     test     diff
...

base = 2501728 +/- 182034
test = 2532997 +/- 182034
diff = 31268 +/- 5116

speedup = 0.0125
P(speedup > 0) = 1.0000

No functional change.
2016-08-27 09:53:26 +02:00
Marco Costalba 4c5cbb1b14 Make engine ONE_PLY value independent
This non-functional change patch is a deep work to allow SF to be independent
from the actual value of ONE_PLY (currently set to 1). I have verified SF is
now independent for ONE_PLY values 1, 2, 4, 8, 16, 32 and 256.

This patch gives consistency to search code and enables future work, opening
the door to safely tweaking the ONE_PLY value for any reason.

Verified for no speed regression at STC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 95643 W: 17728 L: 17737 D: 60178

No functional change.
2016-08-27 09:12:25 +02:00
gamander 133808851d Fixed wrong definition of WhiteCamp and BlackCamp
No functional change.
2016-08-27 08:48:07 +02:00
hxim 9bd856e28e Simplify stats update
Simplify code by moving countermove and follow-up move
history update into procedure.

No functional change.
2016-08-27 08:39:32 +02:00
Marco Costalba 3e739f883f Reformat stats update
Rewritten in a way to have explicit in the search
the bonus/penalty we apply: hopefully this will lead
to further simplification/fix of current rather messy
stats update code.

No functional change.
2016-08-25 09:51:50 +02:00
VoyagerOne 0b4f6e562b Refutation penalty on captures
Apply refutation penalty for prior PV quiet move on captures

LTC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 8208 W: 1153 L: 1008 D: 6047
http://tests.stockfishchess.org/tests/view/57bc5a9f0ebc59030fbe47b5

Only LTC because a very similar patch already passed STC + LTC

bench: 7038730
2016-08-24 08:26:32 +02:00
VoyagerOne 5596492f6e Simplify IID
STC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 30468 W: 5687 L: 5582 D: 19199
http://tests.stockfishchess.org/tests/view/57b1ddd80ebc591c761f63e2

LTC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 87406 W: 11756 L: 11725 D: 63925
http://tests.stockfishchess.org/tests/view/57b212590ebc591c761f63f9

bench: 6554900
2016-08-19 08:59:18 +02:00
VoyagerOne 8493c8c6b8 Do LMR on captures
STC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 5361 W: 1086 L: 936 D: 3339
http://tests.stockfishchess.org/tests/view/57b31b0f0ebc591c761f643d

LTC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 54694 W: 7591 L: 7287 D: 39816
http://tests.stockfishchess.org/tests/view/57b3442b0ebc591c761f6450

bench: 6881120
2016-08-19 08:50:14 +02:00
Marco Costalba e3af492142 Remove a stale assignment
No more used after previous patch.

Spotted by Jekaa .

No functional change.
2016-08-18 10:40:56 +02:00
Stefano80 9585f8ef58 Retire pawn span
Retire pawn span and replace with pawn count in evaluate_scale_factor.

STC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 26482 W: 4929 L: 4818 D: 16735

LTC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 61938 W: 8400 L: 8335 D: 45203

Bench: 7662861
2016-08-18 10:16:56 +02:00
VoyagerOne 7396c08b79 Use predicted depth for history pruning
STC: (Yellow)
LLR: -2.96 (-2.94,2.94) [0.00,4.00]
Total: 69115 W: 12880 L: 12797 D: 43438

LTC:
LLR: 2.96 (-2.94,2.94) [0.00,4.00]
Total: 124163 W: 16923 L: 16442 D: 90798

Note: Note based off past experiments / patches... history pruning
is quite TC sensitive. I believe the reason for this TC dependency
is that the CMH/FMH is a very large table that takes time to fill
up with. In addition having more time for will increase the accuracy
of the stats' value.

Bench: 7351698
2016-08-15 14:45:40 +02:00
Luca Brivio 3d10cfcdd2 Cap space evaluation bonus
When computing space evaluation, limit the bonus square count to 16.

STC @ 10+0.1 th 1:
LLR: 2.97 (-2.94,2.94) [0.00,5.00]
Total: 30793 W: 5910 L: 5648 D: 19235

LTC @ 60+0.6 th 1:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 31361 W: 4410 L: 4184 D: 22767

Bench: 7165385
2016-08-13 10:12:09 +02:00
Alain SAVARD 8abb98455f Simplify space formula
STC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 16868 W: 3260 L: 3132 D: 10476

LTC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 16910 W: 2381 L: 2255 D: 12274

bench: 6663531
2016-08-10 12:49:24 +02:00
VoyagerOne b3525fa9ea Use Color-From-To history stats to help sort moves
STC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 33502 W: 6498 L: 6223 D: 20781
http://tests.stockfishchess.org/tests/view/578abb940ebc5972faa169e2

LTC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 50782 W: 7124 L: 6832 D: 36826
http://tests.stockfishchess.org/tests/view/578b8e5d0ebc5972faa169fd

LTC: (Sanity test against latest master)
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 32759 W: 4600 L: 4370 D: 23789
http://tests.stockfishchess.org/tests/view/5798b7d30ebc591c761f5b72

bench: 6985912

P.S. Thanks @mstembera for rewriting my code to make it smp compatible. A BIG thank you!
2016-08-02 09:17:14 +02:00
VoyagerOne 85924db496 Futility tweak
Use a different margin for pruning child nodes.

STC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 16692 W: 3251 L: 3051 D: 10390
http://tests.stockfishchess.org/tests/view/579b95d10ebc591c761f5c03

LTC:
LLR: 2.97 (-2.94,2.94) [0.00,5.00]
Total: 24140 W: 3501 L: 3297 D: 17342
http://tests.stockfishchess.org/tests/view/579bb15d0ebc591c761f5c0b

Bench: 7927017
2016-08-01 21:47:42 +02:00
ajithcj f2f3a06a1a Allow null pruning at depth 1
This removes a check that prevents null pruning at depth 1 PLY.

STC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 23445 W: 4638 L: 4521 D: 14286

LTC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 61416 W: 8627 L: 8563 D: 44226

bench: 8145304
2016-07-24 09:54:07 +02:00
Stefano80 714329dbdc See prune at higher depth
Allow SEE pruning at higher depths in shallow depth
pruning using a threshold increasing with depth.

STC
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 35366 W: 7011 L: 6724 D: 21631

LTC
LLR: 2.97 (-2.94,2.94) [0.00,5.00]
Total: 15578 W: 2243 L: 2070 D: 11265

Bench: 8417887
2016-07-24 08:55:58 +02:00
ajithcj 76971d8acb Gradually relax the NMP staticEval check
Gradually relax the NMP staticEval check as we go to
higher depths.

Use tuned values.

STC
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 16745 W: 3371 L: 3168 D: 10206

LTC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 5906 W: 875 L: 736 D: 4295

bench: 8548212
2016-07-16 07:35:31 +02:00
Lyudmil Antonov f619f1d38c Workaround gcc stack alignment bug
GCC uses SSE instructions to move data but in 32-bit gcc version used
by abrok the stack is not 16-byte aligned due to a bug.

This patch workaround teh bug by not using the stack
to store KingFlank[]

Fixes issue #721.

No functional change.
2016-07-16 07:06:13 +02:00
joergoster 82d02a3133 Fix extract_ponder_from_tt()
Checking for legality of a possible ponder move
must be done before we undo the first pv move,
of course. (spotted by mohammed li.)

This obviously only has any effect when playing in ponder mode.

No functional change.
2016-07-12 08:47:21 +02:00
Stéphane Nicolet 1d09ee70f7 King tropism
Bonus for each square that we attack in the flank where the opponent
king is. Squares that we attack twice and are not protected by an enemy
pawn count double.

Passed STC:
http://tests.stockfishchess.org/tests/view/577dfca60ebc5972faa166b8
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 48373 W: 9832 L: 9481 D: 29060

And LTC:
http://tests.stockfishchess.org/tests/view/577e77870ebc5972faa166df
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 8881 W: 1408 L: 1255 D: 6218

Bench: 7577046
2016-07-08 09:35:22 +02:00
Alain SAVARD eb20a87c67 More safe checks
Consider a check given by a rook or a minor to be a "safe check"
also in the case where supported by another piece,
and given on a square only defended by a queen

Was yellow STC
http://tests.stockfishchess.org/tests/view/576fcbc80ebc5972faa163e8
LLR: -2.96 (-2.94,2.94) [0.00,5.00]
Total: 55453 W: 10431 L: 10315 D: 34707

Passed LTC
http://tests.stockfishchess.org/tests/view/57733a0b0ebc5972faa164b7
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 54550 W: 7671 L: 7365 D: 39514

bench: 7398346
2016-07-07 08:39:58 +02:00
ajithcj ade3bb9a4e Use staticEval in null prune condition
Don't null prune at depth < 12 if staticEval < beta

STC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 62858 W: 12035 L: 11632 D: 39191

LTC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 49784 W: 7009 L: 6720 D: 36055

bench: 8054611
2016-07-02 16:43:49 +02:00
loco-loco 716a145a6c Removing inCheck condition for counter move bonus
STC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 20206 W: 3946 L: 3823 D:

LTC:
LLR: 3.10 (-2.94,2.94) [-3.00,1.00]
Total: 25004 W: 3512 L: 3390 D: 18102

Bench: 8172428
2016-06-26 10:25:05 +02:00
Marco Costalba 190d2ea4bc Restore standard passed pawn definition
Use the usual and accepted passed pawn semantic
instead of a non-standard one and remove a FIXME.

STC (http://tests.stockfishchess.org/tests/view/576401350ebc5972faa1608d):
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 29646 W: 5663 L: 5557 D: 18426

LTC (http://tests.stockfishchess.org/tests/view/5764e4e90ebc5972faa160c3):
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 40224 W: 5578 L: 5484 D: 29162

bench: 7543902
2016-06-25 11:46:17 +02:00
ElbertoOne c2c0e6b07d Remove redundant PvNode condition
After commit 6d58bf777c we always call PvNodes
with cutNode set to false.

No functional change.
2016-06-24 08:46:36 +02:00
VoyagerOne c94145b65c Comment out a redundant condition
Take advantage that VALUE_NONE = 32002 to remove
the condition.

Commented out and not removed becuase it is tricky
to rely on the hidden value of VALUE_NONE and code
can break in case we change VALUE_NONE in the future.

No functional change.
2016-06-24 08:26:39 +02:00
Jonathan Calovski 09efbf915e Remove scalefactor dependency
STC
http://tests.stockfishchess.org/tests/view/5764539e0ebc5972faa160a4
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 43878 W: 8289 L: 8208 D: 27381

LTC
http://tests.stockfishchess.org/tests/view/5764f0130ebc5972faa160c9
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 39338 W: 5408 L: 5313 D: 28617

bench: 7977279
2016-06-21 09:01:39 +02:00
ElbertoOne 6d58bf777c On IID do not always search with cutNode = true
On IID now search with cutNode value instead of fixed value true.

STC (http://tests.stockfishchess.org/tests/view/575fa3860ebc5972faa15f67):
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 163974 W: 30744 L: 30874 D: 102356

LTC (http://tests.stockfishchess.org/tests/view/5763b0640ebc5972faa16075):
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 48363 W: 6611 L: 6528 D: 35224

Bench: 7806393
2016-06-19 18:04:22 +02:00
VoyagerOne 1c0c4db677 Simplify Check Extension
STC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 32704 W: 6146 L: 6045 D: 20513

LTC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 146622 W: 19967 L: 20017 D: 106638

Bench: 8245662
2016-06-18 08:32:25 +02:00
ajithcj 8e45e70e55 Don't insert pv back into tt
This code was added before the accurate pv patch, when
we retrieved PV directly from TT.

It's not required for correct (and long) PVs any more and
should be safe to remove it.

Also, allowing helper threads to repeatedly over-write
TT doesn't seem to make sense(that was probably an un-intended
side-effect of lazy smp). Before Lazy SMP only Main Thread used
to run ID loop and insert PV into TT.

STC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 74346 W: 13946 L: 13918 D: 46482

LTC
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 47265 W: 6531 L: 6447 D: 34287

bench: 8819179
2016-06-15 08:55:40 +02:00
lucasart 126036abb0 Do not hardcode Debug Log File
Allow to specifiy the log file name, this comes
handy in case of self-matches so that each SF
instance writes into a different log file.

No functional change.
2016-06-15 08:47:08 +02:00
Marco Costalba ca14345ba2 Filter root moves filter before copy to threads
Currently root moves are copied to all teh threads
but are DTZ filtered only in main thread at the
beginning of teh search.

This patch moves the TB filtering before the
copy of root moves fixing issue #679

https://github.com/official-stockfish/Stockfish/issues/679

No bench change.
2016-06-11 09:24:40 +02:00
VoyagerOne 7d2a79f037 Stat Formula Tweak
bonus = d * d + 2 * d - 2

STC:
LLR: 2.94 (-2.94,2.94) [0.00,4.00]
Total: 99444 W: 18274 L: 17778 D: 63392

LTC:
LLR: 2.95 (-2.94,2.94) [0.00,4.00]
Total: 89757 W: 12285 L: 11896 D: 65576

bench: 8276130
2016-06-10 07:27:47 +02:00
VoyagerOne 7c5d724724 Tweak check extension condition
There are two concepts with this patch:

Limit check extensions by using move count.
The idea is to limit search explosion.

Always extend check if the first move gives check.
The idea is to save expensive SEE calls, since the vast
majority of first move will have SEE value >= 0, also
first move may still be strong even if the SEE is negative.

STC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 16503 W: 3068 L: 2873 D: 10562

LTC:
LLR: 2.97 (-2.94,2.94) [0.00,5.00]
Total: 37202 W: 5261 L: 5014 D: 26927

bench: 8543366
2016-06-10 07:15:56 +02:00
Alain SAVARD 6fed8ff22a Small Queen simplification
Moving a few lines from evaluate_threats to evaluate_pieces allows to
a) Remove a condition pos.count<QUEEN>(Them) == 1
b) use precalculated s instead of pos.square(Them)
c) do not check the condition at all in queenless endings

Passed STC
http://tests.stockfishchess.org/tests/view/5752e0410ebc59029919b1f4
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 67175 W: 12194 L: 12152 D: 42829

and LTC
http://tests.stockfishchess.org/tests/view/57587b140ebc59029919b2f4
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 20276 W: 2774 L: 2653 D: 14849

bench: 7907962
2016-06-10 06:53:07 +02:00
mstembera 0c076f1136 Avoid some redundant scaling function calls
Posted by Mohammed Li here:
https://groups.google.com/forum/?fromgroups=#!topic/fishcooking/N-PHfN0O79o

No functional change.
2016-06-10 06:43:37 +02:00
ElbertoOne e48c7547c5 LMR reduction parameter tweak
More reduction for cut nodes, less for moves that escape a capture:

STC (http://tests.stockfishchess.org/tests/view/57548c1e0ebc59029919b247):
LLR: 2.96 (-2.94,2.94) [0.00,4.00]
Total: 60165 W: 11519 L: 11149 D: 37497

LTC (http://tests.stockfishchess.org/tests/view/57555b570ebc59029919b260):
LLR: 2.95 (-2.94,2.94) [0.00,4.00]
Total: 10353 W: 1493 L: 1317 D: 7543

Bench: 8902859
2016-06-07 15:15:49 +02:00
Marco Costalba 6e2ca97d93 Fix syzygy DTZ bug
In this position: 3K4/8/3k4/8/4p3/4B3/5P2/8 w - - 0 5

Current DTZ probe returns 1 instead of 15

What happens is that the double push f4 is erroneously detected as a win move.

After the push we have:

[D]3K4/8/3k4/8/4pP2/4B3/8/8 b - f3 0 5

And here the code misses the possible ep capture exf3.

The bug is in probe_dtz_no_ep() where is used probe_ab() that is
blind to ep captures so it returns v == 2 (win) for position

3K4/8/3k4/8/4pP2/4B3/8/8 b - f3 0 5

Note that at the caller site the original position did not have any
possible ep capture, so probe_dtz() returns immediately after calling
probe_dtz_no_ep().

The fix is to call the ep-aware probe_wdl() instead of probe_ab()

I have verified that DTZ is correct now and also there are no more
mistmatches compared to the new 'syzygy' branch. Tested on a set of
more than 600 endgame positions, included some tricky ones.

For people interested to redo the test or doing additional tests
please pull branch tb_dbg from https://github.com/mcostalba/Stockfish repo.

bench: 8450534 (bench unaffected because syzygy is not exercized during bench)
2016-06-07 15:06:26 +02:00
VoyagerOne 5f096e9bef Simplify Futility Pruning
Don't update bestValue when futility pruning.

STC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 21933 W: 4031 L: 3912 D: 13990

LTC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 46225 W: 6115 L: 6028 D: 34082

Bench: 8450534
2016-06-03 19:58:42 +02:00
ElbertoOne 20023ac9b8 LMR Simplification
LMR simplification that also gives a slight ELO gain, especially at LTC:

STC (http://tests.stockfishchess.org/tests/view/574ec8e20ebc59029919b147):
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 32402 W: 5967 L: 5866 D: 20569

LTC (http://tests.stockfishchess.org/tests/view/574fbebf0ebc59029919b16d):
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 15103 W: 2103 L: 1975 D: 11025

Bench: 8248133
2016-06-03 19:53:04 +02:00
joergoster 3549d98d07 Tuned values for piece check and attack unit factors
A middle ground patch of two successful tuning patches,
one at STC, the other at LTC, which now passed both.

LLR: 2.95 (-2.94,2.94) [0.00,4.00]
Total: 67893 W: 12777 L: 12384 D: 42732

LLR: 2.95 (-2.94,2.94) [0.00,4.00]
Total: 30165 W: 4189 L: 3960 D: 22016

bench: 9209507
2016-06-03 07:39:27 +02:00
Stéphane Nicolet 07b247f943 Pins or discovered attacks on the opponent's queen
Bonus for pins or discovered attacks on the opponent's queen

STC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 32020 W: 5914 L: 5652 D: 20454

LTC:
LLR: 2.97 (-2.94,2.94) [0.00,5.00]
Total: 10946 W: 1530 L: 1375 D: 8041

Bench: 7031649
2016-05-28 14:57:58 +02:00
Stéphane Nicolet abac509ccb Teach check_blockers to check also non-king pieces
This is a prerequisite for next patch

No functional change.
2016-05-28 14:52:21 +02:00
Stéphane Nicolet ab0f4c0353 Simplify doubled pawn
Only use doubled pawn malus when the doubled pawns are on consecutive squares.

Passed STC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 7678 W: 1469 L: 1325 D: 4884

And LTC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 26739 W: 3562 L: 3449 D: 19728

Bench: 8211685
2016-05-26 12:33:44 +02:00
Leonid Pechenik 71bfbb22fc More detailed dependence of time allocation on the magnitude of score change
10+0.1:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 5657 W: 1130 L: 979 D: 3548

60+0.6:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 36884 W: 5002 L: 4762 D: 27120

bench: 8428997
2016-05-20 19:44:50 +02:00
loco-loco 7cb8cbb403 Assorted pruning tweaks
LTC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 38257 W: 5206 L: 4961 D: 28090

STC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 16550 W: 3110 L: 2914 D: 10526

Bench: 8428997
2016-05-20 19:34:49 +02:00
mstembera 0784bd542b Fix a multiPV bug in lazy SMP
Where the helper threads were not doing multiPV at all.

Regression tested sprt @ 5+0.05 th 7

LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 73918 W: 11891 L: 11853 D: 50174

bench: 8716243
2016-05-14 21:34:55 +02:00
Stéphane Nicolet 16c603ce9b Double pawn simplification
Try doubled pawn simplification, with psq
table compensation.

STC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 36094 W: 6558 L: 6463 D: 23073

LTC:
LLR: 2.94 (-2.94,2.94) [-3.00,1.00]
Total: 102352 W: 13417 L: 13404 D: 75531

Bench: 8716243
2016-05-13 13:01:59 +02:00
loco-loco 969982406c Merge good and bad quiets
STC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 58613 W: 10779 L: 10723 D: 37111

LTC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 33608 W: 4539 L: 4436 D: 24633

Bench: 9441294
2016-05-10 18:15:16 +02:00
Alain SAVARD 4b9ed6566a Unsafe checks
Introducing a new multi-purpose penalty related to King safety, which
includes all kind of potential checks (from unsafe or unavailable
squares currently occupied by some other piece)

This will indirectly detect and reward some pins, discovered checks, and
motifs such as square vacation, or rook behind its pawn and aligned with
King (example Black Rg8, g7 against Kg1),
and penalize some pawn blockers (if they move, it allows a discovered
check by the pawn).

And since it looks also at protected squares, it detects some potential
defense overloading.

Finally, the rook contact checks had been removed some time ago. This
test will give a small bonus for them, as well as for bishop contact
checks.

Passed STC
http://tests.stockfishchess.org/tests/view/5729ec740ebc59301a354b36
LLR: 2.94 (-2.94,2.94) [0.00,5.00]
Total: 13306 W: 2477 L: 2296 D: 8533

and LTC
http://tests.stockfishchess.org/tests/view/572a5be00ebc59301a354b65
LLR: 2.97 (-2.94,2.94) [0.00,5.00]
Total: 20369 W: 2750 L: 2565 D: 15054

bench: 9298175
2016-05-06 20:04:57 +02:00
Marco Costalba 5e4cd3fc0d Retire __popcnt64 intrinsic
Just use _mm_popcnt_u64() that is available
both for MSVC abd Intel compiler.

Verified on MSVC that the produced assembly
has the hardware 'popcnt' instruction.

No functional change.
2016-05-05 09:09:07 +02:00
VoyagerOne 5486911e01 Simplify History LMR Formula
STC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 41713 W: 7589 L: 7504 D: 26620

LTC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 41353 W: 5484 L: 5391 D: 30478

Bench: 8946983
2016-05-05 08:53:50 +02:00
Marco Costalba 3487eb9f9e Fix a warning with MSVC
Introduced by 2dd24dc4e6 ("Use popcount intrinsic with Intel")

No functional change.
2016-05-01 15:10:33 +02:00
joergoster dc0030de4f Fix LazySMP when searching to a fixed depth.
Currently, helper threads will only search up to the
specified depth limit. Now let them search until the
main thread has finished the specified depth.

On the other hand, we don't want to pick a thread with
a higher search depth.

This may be considered cheating. ;-)

No functional change.
2016-05-01 14:30:50 +02:00
erbsenzaehler 2dd24dc4e6 Use popcount intrinsic with Interl compiler
It seems that icc used our fallback version of popcount.
Now use intrinsics.

icc version 16.0.2 (gcc version 5.3.0 compatibility)
bmi2 compile
uname -r 4.5.1-1-ARCH

20xbench gives a nice speedup
./stockfish-icc-master 2161515 +- 34462
./stockfish-icc-sse42 2260857 +- 50349
2016-05-01 14:18:16 +02:00
Krgp 8f934dff9a Remove useless -mbmi flag in Makefile
I could not find anything documented that is necessary that prepending -mbmi to -mbmi2 gives some benefit.
Instead at
https://gcc.gnu.org/onlinedocs/gcc/x86-Built-in-Functions.html#x86-Built-in-Functions

The following built-in functions are available when -mbmi is used. All of them generate the machine instruction that is part of the name.
unsigned int __builtin_ia32_bextr_u32(unsigned int, unsigned int);
unsigned long long __builtin_ia32_bextr_u64 (unsigned long long, unsigned long long);

The following built-in functions are available when -mbmi2 is used. All of them generate the machine instruction that is part of the name.
unsigned int _bzhi_u32 (unsigned int, unsigned int)
unsigned int _pdep_u32 (unsigned int, unsigned int)
unsigned int _pext_u32 (unsigned int, unsigned int)
unsigned long long _bzhi_u64 (unsigned long long, unsigned long long)
unsigned long long _pdep_u64 (unsigned long long, unsigned long long)
unsigned long long _pext_u64 (unsigned long long, unsigned long long)

and at
https://gcc.gnu.org/ml/gcc/2014-02/msg00204.html

( "... The real optimization comes from being able to use pext
(parallel bit extract), which can implement several bextr expressions in
parallel.")

Apart from that we don't use all -msse -msse2 -msse3 -msse4.2 etc. but just -msse3 (or -msse4.2) only.

As regards to the speedup within noise level - this pull request is actually reversal of mcostalba#198 wherein prepending -mbmi to -mbmi2 was claimed to be 0.3% faster and here (removing -mbmi) gives 0.4% speed gain.
2016-05-01 14:11:28 +02:00
Stéphane Nicolet 2694ef23c3 Isolated pawn simplification
STC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 117822 W: 21697 L: 21744 D: 74381

LTC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 92307 W: 12330 L: 12305 D: 67672

Bench: 8813983

Resolves #659
2016-04-30 22:23:22 +01:00
VoyagerOne e082112cfe Use FMHs to assist with LMR formula.
STC:
LLR: 2.99 (-2.94,2.94) [0.00,5.00]
Total: 52232 W: 9654 L: 9304 D: 33274

LTC:
LLR: 2.97 (-2.94,2.94) [0.00,5.00]
Total: 115988 W: 15550 L: 15049 D: 85389

Bench: 7890808

Resolves #651
2016-04-24 01:00:58 +01:00
erbsenzaehler 4048bae47b Use -O3 for all compilers (including ICC)
There seems to be no benefit from using -fast over -O3 with icc.
So use -O3 everywhere.

No functional change

Resolves #652
2016-04-24 00:55:56 +01:00
DU-jdto c737062436 Remove some pointless micro-optimizations
Seems to give around 1% speed-up for CPUs with popcnt support.
Seems to give a very minor speed-up for CPUs without popcnt.

No functional change

Resolves #646
2016-04-23 02:04:28 +01:00
Marco Costalba 94e41274bb Fix incorrect draw detection
In this position we should have draw for repetition:

position fen rnbqkbnr/2pppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1 moves g1f3 g8f6 f3g1
go infinite

But latest patch broke it.

Actually we had two(!) very subtle bugs, the first is that Position::set()
clears the passed state and in particular 'previous' member, so
that on passing setupStates, 'previous' pointer was reset.

Second bug is even more subtle: SetupStates was based on std::vector
as container, but when vector grows, std::vector copies all its contents
to a new location invalidating all references to its entries. Because
all StateInfo records are linked by 'previous' pointer, this made pointers
go stale upon adding more element to setupStates. So revert to use a
std::deque that ensures references are preserved when pushing back new
elements.

No functional change.
2016-04-18 00:13:16 +02:00
loco-loco ec6aab0136 Add a second level of follow-up moves
STC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 6438 W: 1229 L: 1077 D: 4132

LTC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 4000 W: 605 L: 473 D: 2922

bench: 7378965

Resolves #636
2016-04-17 15:19:20 +01:00
Marco Costalba 7eaea3848c StateInfo is usually allocated on the stack by search()
And passed in do_move(), this ensures maximum efficiency and
speed and at the same time unlimited move numbers.

The draw back is that to handle Position init we need to
reserve a StateInfo inside Position itself and use at
init time and when copying from another Position.

After lazy SMP we don't need anymore this gimmick and we can
get rid of this special case and always pass an external
StateInfo to Position object.

Also rewritten and simplified Position constructors.

Verified it does not regress with a 3 threads SMP test:
ELO: -0.00 +-12.7 (95%) LOS: 50.0%
Total: 1000 W: 173 L: 173 D: 654

No functional change.
2016-04-17 08:29:33 +02:00
Niklas Fiekas ee7a68ea5f Fix last search info carried over to mate position
When starting search in a mate or stalemate position, Stockfish does not
even care to reinitialize and start worker threads. However after search
all threads are checked for the best move.

This can lead to bestmove and info beeing carried over from the last
search.

Example session:

    setoption name threads value 7
    go movetime 4000
    position startpos moves f2f3 e7e5 g2g4 d8h4
    go movetime 4000

Actual output is like (almost always):

    [...]
    bestmove e2e4
    info depth 0 score mate 0
    info depth 20 seldepth 29 multipv 1 score cp 28 [...] pv e2e4
    bestmove e2e4

Expected output / output after fix:

    [...]
    bestmove e2e4 ponder e7e6
    info depth 0 score mate 0
    bestmove (none)

Resolves #623
2016-04-16 10:22:36 +01:00
Marco Costalba d30994ecd5 Hide global visibility when not needed
Also move PieceValue definition in psqt.cpp,
where it is initialized.

Fix a warning in popcount16() with Intel compiler

No functional change.
2016-04-09 10:42:04 +02:00
Marco Costalba bd04f9a0f1 Fix Travis Cl
Broken after "32-bit/64-bit Makefile fix" commit.

Ubuntu "Precise" 12.04.5 supports multilib only until
g++ 4.6 that is not enough to compile Stockfish.

So move to Ubuntu 14.04.4 LTS (Trusty Tahr)

No functional change.
2016-04-09 09:35:19 +02:00
DU-jdto 1cbba8d6fa Small passed pawn simplification
STC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 21993 W: 4197 L: 4078 D: 13718

LTC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 67213 W: 9135 L: 9077 D: 49001

Bench: 7482426

Resolves #622
2016-04-08 19:48:03 +01:00
Alain SAVARD e9e5f72c74 Undefended King Ring
There was already a penalty for squares only defended by King (undefended)

This test records a penalty for completely undefended squares in the so called extended king-ring
(so if we exclude squares defended by a Kg8 for example, we only look at h6 g6 and f6)

We also exclude squares occupied by opponent pieces in this computation,
based on the following results

Was yellow at STC
LLR: -2.97 (-2.94,2.94) [0.00,5.00]
Total: 112499 W: 20649 L: 20293 D: 71557

and passed LTC
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 36805 W: 5100 L: 4857 D: 26848

Bench: 8430233

Resolves: #619
2016-04-08 19:22:33 +01:00
Alain SAVARD 29b5842da8 Backward simplication
On top of the usual conditions
a) some opponent in front (but no lever)
b) some neighbours (in front) (but no neighbour behind or same rank)
c) < rank_5

to find out if a pawn is backward we look at the squares in front of this pawn to reach the same rank as the next neighbour.

In current master, a pawn is backward if any of those squares is controlled by an enemy pawn on an adjacent file

In this version, a pawn is ALSO backward if any of those squares is occupied by an enemy pawn.

STC:
http://tests.stockfishchess.org/tests/view/56fe7efd0ebc59301a3541f1
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 19051 W: 3557 L: 3433 D: 12061

LTC:
http://tests.stockfishchess.org/tests/view/56febc2d0ebc59301a354209
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 40810 W: 5619 L: 5526 D: 29665

Bench: 7525245

Resolves #614
2016-04-08 19:12:55 +01:00
mstembera 8fb45caade Simplify popcnt
Also a speedup(about 1%) on 64-bit w/o hardware popcnt

Retire Max15 and Full template parameters
(Contributed by Marco Costalba)

Now that we have just SW and HW versions, use
template default parameter to get rid of explicit
template parameters.

Retire bitcount.h and move the only defined
function to bitboard.h

No functional change

Resolves #620
2016-04-08 18:52:15 +01:00
lucasart 900279a06f 32-bit/64-bit Makefile fix
Counter intuitively, make build ARCH=x86-32 does NOT produce a 32-bit compile
when running a 64-bit OS. Nor would ARCH=x86-64 produce a 64-bit compile when
running a 32-bit OS (assuming it compiled w/o errors).

No functional change

Resolves #621
2016-04-08 18:47:31 +01:00
NicklasPersson d5b24ad77b A combo patch of two tuning patches
STC:
LLR: 2.96 (-2.94,2.94) [0.00,4.00]
Total: 14223 W: 2700 L: 2494 D: 9029

LTC:
LLR: 2.96 (-2.94,2.94) [0.00,4.00]
Total: 66294 W: 9065 L: 8739 D: 48490

Bench: 7607385

Resolves #612
2016-03-31 13:26:00 +01:00
lucasart f256388e08 Guard against UB in lsb/msb
lsb(b) and msb(b) are undefined when b == 0. This can lead to subtle bugs, where
the resulting code behaves differently on different configurations:
- It can be the home grown software LSB/MSB
- It can be the compiler generated software LSB/MSB (when using compiler
  intrinsics without the right compiler flags to allow compiler to use hardware
  LSB/MSB). Which of course depends on the compiler.
- It can be hardware LSB/MSB generated by the compiler.
- Not to mention that hardware LSB/MSB can return different value on different
  hardware when b == 0.

No functional change

Resolves #610
2016-03-31 13:22:37 +01:00
Marco Costalba db4b0d8b7d Rewrite bsfq management
Use compiler intrinsics when possible to
avoid writing platform specific asm code.

Tested on Windows 7 with MSVC 2013 and mingw 4.8.3 (32 and 64 bit)
and on Linux Mint with g++ 4.8.4 and clang 3.4 (32 and 64 bit).

No functional change

Resolves #609
2016-03-28 15:46:55 +01:00
snicolet 24dac5ccd3 Bonus for loose enemies
STC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 30504 W: 5743 L: 5485 D: 19276

LTC:
LLR: 2.97 (-2.94,2.94) [0.00,5.00]
Total: 11936 W: 1651 L: 1493 D: 8792

Bench: 8880041

Resolves #606
2016-03-27 20:56:54 +01:00
mbootsector 8788612828 Raise endgame passed pawn and material values
STC:
LLR: 2.95 (-2.94,2.94) [0.00,4.00]
Total: 136149 W: 25213 L: 24588 D: 86348

LTC:
LLR: 2.95 (-2.94,2.94) [0.00,4.00]
Total: 54637 W: 7533 L: 7238 D: 39866

Bench: 8546808

Resolves #608
2016-03-27 20:22:48 +01:00
fanon 5d1644ba69 Simplify pawns King Safety calculation
STC
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 130209 W: 23516 L: 23581 D: 83112

LTC
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 33541 W: 4563 L: 4460 D: 24518

Bench: 8644370

Resolves #604
2016-03-27 20:08:56 +01:00
VoyagerOne 60590577f2 A small simplification in movepick.h
No functional change

Resolves #597
2016-03-14 20:54:49 -07:00
mstembera 04be84e0e2 Simplify Safe Checks
STC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 11796 W: 2211 L: 2074 D: 7511

LTC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 14324 W: 1935 L: 1806 D: 10583

Bench: 8075202

Resolves #600
2016-03-14 20:51:16 -07:00
Marco Costalba 647402ff79 Assorted cleanup of latest commits
No functional change.

Resolves #601
2016-03-14 20:42:44 -07:00
Stefan Geschwentner a273b6ef8c Add followup moves history for move ordering
STC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 7955 W: 1538 L: 1378 D: 5039

LTC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 5323 W: 778 L: 642 D: 3903

Bench: 8261839

Resolves #599
2016-03-10 14:26:06 -08:00
mbootsector e1a7d135b2 Passed pawn bonus simplification
STC: (yellow)

LLR: -2.96 (-2.94,2.94) [0.00,4.00]
Total: 86114 W: 16063 L: 15921 D: 54130

LTC:

LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 14347 W: 2025 L: 1896 D: 10426

Bench: 8576437

Resolves #595
2016-03-02 19:10:56 +00:00
snicolet c1be0c68c7 Tweak initiative formula
Give more weight to the pawns number and
the vertical king distance in evaluate_initiative()

Passed STC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 26729 W: 5067 L: 4825 D: 16837

and LTC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 60480 W: 8338 L: 8016 D: 44126

Bench: 8295162

Resolves #594
2016-03-02 00:02:03 +00:00
ElbertoOne c13052f344 Clean up depth reduction calculation
Might also be a slight speed up

No functional change

Resolves #593
2016-02-28 13:40:47 +00:00
joergoster 8de29390f2 Pass endgame value to evaluate_scale_factor()
No functional change

Resolves #592
2016-02-28 13:35:34 +00:00
VoyagerOne 45a309d92e Simplify Reduction Formula
Formula now only contains one coefficient. Making it much easier to tune.

STC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 187443 W: 34858 L: 35028 D: 117557

LTC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 88329 W: 11982 L: 11953 D: 64394

Bench: 7521394

Resolves #591
2016-02-28 13:31:25 +00:00
Leonid Pechenik d5ba8e827d Revert "Remove slowMover"
This reverts commit 77fa960f89.

Resolves #590
2016-02-28 13:25:05 +00:00
IIvec 77fa960f89 Remove slowMover
Removes a slowMover and one paramater from move_importance function.

STC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 77023 W: 14456 L: 14433 D: 48134

LTC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 37175 W: 5190 L: 5092 D: 26893

Resolves #589
2016-02-21 20:16:28 +00:00
VoyagerOne bfe9044ad9 History Stat Formula Simplification
STC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 67476 W: 12561 L: 12521 D: 42394

LTC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 111923 W: 15147 L: 15149 D: 81627

Bench: 8430465

Resolves #588
2016-02-21 20:12:33 +00:00
VoyagerOne 744ed85a4d Fix futility pruning bug
PredictedDepth can be negative, causing the futility_margin to be negative.
It will be very difficult to tweak moveCount pruning and reduction formula, as they are tuned to prevent this behavior.

No functional change

Resolves #587
2016-02-14 19:48:46 +00:00
hxim 56dd58e6f9 Remove Weights
Removed remaining redundant weights for pawn structure,
passed pawns, space and king safety by redistributing them
into individual evaluation terms.

STC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 15173 W: 2790 L: 2659 D: 9724

LTC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 43433 W: 5936 L: 5846 D: 31651

Bench: 7156237

Resolves #586
2016-02-07 21:00:24 +00:00
Marco Costalba 4f6aa15228 Document HalfDensityMap
No functional change.

Resolves #584
2016-02-07 20:54:25 +00:00
Leonid Pechenik aedebe35cf Time management simplification
10+0.1:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 41963 W: 7967 L: 7883 D: 26113

60+0.6:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 132314 W: 17939 L: 17969 D: 96406

Resolves #580
2016-01-29 00:47:07 +00:00
Guenther Demetz 9a10313a9d rotating symmetric patterns with increasing skipsize
STC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00] sprt @ 5+0.1 th 21
Total: 7068 W: 1121 L: 975 D: 4972

LTC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00] sprt @ 12+0.12 th 21
Total: 26691 W: 3594 L: 3481 D: 19616

No functional change with a single thread

Resolves #574
2016-01-24 14:08:01 +00:00
Joona Kiiski 8c3a5bbc52 Do not probe syzygy bases when castling is possible
Almost no functional change. Bench is unchanged.

Resolves #230
Resolves #573
2016-01-20 15:24:21 +00:00
lucasart 28933a580e Retire RootNode template
There is no reason to compile 3 different copies of search(). PV nodes are on
the cold path, and PvNode is a template parameter, so there is no cost in
computing:

const bool RootNode = PvNode && (ss-1)->ply == 0;

And this simplifies code a tiny bit as well.

Speed impact is negligible on my machine (i7-3770k, linux 4.2, gcc 5.2):

            nps   +/-
test    2378605  3118
master  2383128  2793
diff      -4523  2746

Bench: 7751425

No functional change.

Resolves #568
2016-01-18 22:21:42 +00:00
Guenther Demetz 12eb345ebd Depth margin parameter-tweak in TT-save
Verified that is improvement with multiple threads:

LLR: 2.95 (-2.94,2.94) [0.00,4.00] sprt @ 30+0.3 th 3
Total: 14817 W: 2103 L: 1915 D: 10799

LLR: 2.96 (-2.94,2.94) [0.00,4.00] sprt @ 15+0.15 th 7
Total: 10264 W: 1498 L: 1321 D: 7445

Verified that is not a significant regression with a single thread:

LLR: 2.96 (-2.94,2.94) [-4.00,0.00] sprt @ 60+0.6 th 1
Total: 23975 W: 3294 L: 3210 D: 17471

Resolves #575
2016-01-18 22:04:38 +00:00
Joona Kiiski ebec2fa48e Remove redundant -std=c++0x flag
This flag is functionally identical to '-std=c++11' flag which
is part of standard flags.

No functional change

Resolves #571
2016-01-18 21:54:40 +00:00
Joona Kiiski 552b3ccb66 Makefile: Allow specifying compiler executable
No functional change

Resolves #570
2016-01-18 21:47:52 +00:00
Marco Costalba 356147d99a Rewrite time formula
Time management is really too complex, our aim is
to simplify it, but for time being at least rewrite
in an understandable way.

No functional change.
2016-01-18 17:12:18 +01:00
Lyudmil Antonov 89723339d9 Assorted English grammar changes
No functional change

Resolves #567
2016-01-16 21:34:29 +00:00
Stefano80 74e2fa97b7 Adjust reductions based on history and cmh tables
STC:
LLR: 4.06 (-2.94,2.94) [0.00,5.00]
Total: 149395 W: 28029 L: 27208 D: 94158

LTC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 9628 W: 1368 L: 1217 D: 7043

bench: 8076724

Resolves #565
2016-01-13 16:18:35 +00:00
Stefano80 dcd8ce7094 Update comments in LMR step
No functional change

Resolves #564
2016-01-13 16:03:53 +00:00
Leonid Pechenik 4d1220d672 Tune time management for LTC
60+0.6:
LLR: 2.96 (-2.94,2.94) [0.00,4.00]
Total: 102533 W: 14270 L: 13842 D: 74421

Resolves #558
2016-01-09 09:21:52 +00:00
lucasart aa31f7f096 Retire CenterBind
And compensate in the PSQT.

STC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 27714 W: 5161 L: 5052 D: 17501

LTC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 36354 W: 5008 L: 4909 D: 26437

Bench: 8603285

Resolves #556
2016-01-03 17:33:36 +00:00
Alain SAVARD 1de97337c2 Fine tuning of unsupported pawn penalty
Adjust the unsupported pawn penalty when the pawn is supporting 2 pawns
(for example g7 in f6-g7-h6)

Passed STC
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 23833 W: 4384 L: 4158 D: 15291

Passed LTC
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 42711 W: 5918 L: 5655 D: 31138

Bench: 8390233

Resolves #549
2016-01-03 14:15:29 +00:00
Leonid Pechenik 9eceb894ac Adjust time used for move based on previous score
Use less time if evaluation is not worse than for previous move and even less time if in addition no fail low encountered for current iteration.

STC: 10+0.1
ELO: 5.37 +-2.9 (95%) LOS: 100.0%
Total: 20000 W: 3832 L: 3523 D: 12645

STC: 10+0.1
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 17527 W: 3334 L: 3132 D: 11061

LTC: 60+0.6
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 28233 W: 3939 L: 3725 D: 20569

LTC: 60+0.6
ELO: 2.43 +-1.4 (95%) LOS: 100.0%
Total: 60000 W: 8266 L: 7847 D: 43887

LTC: 60+0.06
LLR: 2.95 (-2.94,2.94) [-1.00,3.00]
Total: 38932 W: 5408 L: 5207 D: 28317

Resolves #547
2016-01-03 14:01:15 +00:00
Joona Kiiski 5972c4a678 Restore development version 2016-01-03 13:52:01 +00:00
Joona Kiiski dd9cf30581 Stockfish 7
Bench: 8355485

No functional change
2016-01-02 20:26:02 +00:00
ppigazzini d4af15f682 Update AUTHORS and copyright notice
No functional change

Resolves #555
2016-01-02 09:43:51 +00:00
Marco Costalba 9742fb10fd Update Copyright year
No functional change.

Resolves #554
2016-01-01 10:17:36 +00:00
Joona Kiiski 7cafbab529 Stockfish 7 Beta 2
Bench: 8355485

No functional change
2015-12-30 11:32:45 +00:00
Alain SAVARD 6a79d5d10e Correct Pawn Trace Score + Code Clean up
No functional change

Resolves #542
2015-12-30 11:30:28 +00:00
Marco Costalba 3e4fed3a91 Fix assert with very high score position
In case of a very high material score, we can
overflow VALUE_INFINITE.

This patch fixes an assert with:

position fen 7k/QQQQR3/2B5/4KN1Q/3QQ3/8/8/4R3 b - - 0 1
go depth 1

No functional change.

Resolves #546
2015-12-30 11:16:48 +00:00
Joona Kiiski a5c76d69c3 Stockfish 7 Beta 1
Bench: 8355485

No functional change
2015-12-27 19:36:56 +00:00
Marco Costalba 1b5b900a29 Move some globals into main thread scope
Make it explicit that those variables are not globals, but
are used only by main thread. I think it is a sensible
clarification because easy move is already tricky enough
and current patch makes the involved actors explicit.

No functional change.

Resolves #537
2015-12-27 19:29:16 +00:00
Marco Costalba 90f5937373 Revert "Fix compiling of 32 bit binary on 64-bit Windows"
This reverts commit 1e8836d921

Broken compile on mingw under Windows:

Config:
debug: 'yes'
optimize: 'yes'
arch: 'i386'
bits: '32'
prefetch: 'yes'
bsfq: 'no'
popcnt: 'no'
sse: 'yes'
pext: 'no'

Flags:
CXX: i686-w64-mingw32-c++
CXXFLAGS: -Wall -Wcast-qual -fno-exceptions -fno-rtti -std=c++11  -Wextra -Wshadow -g -O3 -msse
LDFLAGS:  -static

Testing config sanity. If this fails, try 'make help' ...

mingw32-make[1]: Leaving directory 'C:/stockfish/src'
c:/MinGw/bin/mingw32-make ARCH=x86-32 COMP=mingw all
mingw32-make[1]: Entering directory 'C:/stockfish/src'
sh: C:\Program: No such file or directory
i686-w64-mingw32-c++ -Wall -Wcast-qual -fno-exceptions -fno-rtti -std=c++11  -Wextra -Wshadow -g -O3 -msse   -c -o benchmark.o benchmark.cpp
<builtin>: recipe for target 'benchmark.o' failed
process_begin: CreateProcess(NULL, i686-w64-mingw32-c++ -Wall -Wcast-qual -fno-exceptions -fno-rtti -std=c++11 -Wextra -Wshadow -g -O3 -msse -c -o benchmark.o benchmark.cpp, ...) failed.
make (e=2): Impossibile trovare il file specificato.

mingw32-make[1]: *** [benchmark.o] Error 2
mingw32-make[1]: Leaving directory 'C:/stockfish/src'
makefile:401: recipe for target 'build' failed
mingw32-make: *** [build] Error 2

No functional change.
2015-12-23 09:41:56 +01:00
braich 1e8836d921 Fix compiling of 32 bit binary on 64-bit Windows
Two versions of mingw-w64 (targeting Win64 and Win32)
can be installed on Windows too.

No functional change

Resolves #532
2015-12-22 19:07:10 +00:00
DU-jdto e3c85c314d Remove another unnecessary Search::Stack field
No functional change

Resolves #535
2015-12-22 17:16:15 +00:00
Alain SAVARD da34023cfc New mobility bonus
Tuned the global mobility factor for each piece, as well as some +- delta,

The master mobility factor was {266,334} and tuning gave
{267, 362} +S(-2,-2) for the Knight
{249, 328} +S( 0,-2) for the Bishop
{298, 353} +S(1,1) for the Rook
{265, 358} +S(2,-1) for the Queen

Passed STC
LLR: 2.95 (-2.94,2.94) [0.00,4.00]
Total: 49402 W: 9367 L: 9037 D: 30998

and LTC
LLR: 2.97 (-2.94,2.94) [0.00,5.00]
Total: 26831 W: 3871 L: 3658 D: 19302

Bench: 8355485

Resolves #536
2015-12-22 10:02:37 +00:00
VoyagerOne ed72a1e9ba Remove killer move conditions from LMR
STC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 8459 W: 1619 L: 1477 D: 5363

LTC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 32239 W: 4404 L: 4299 D: 23536

Bench: 7597031

Resolves #534
2015-12-20 20:41:17 +00:00
loco-loco 5bbd944099 Remove unused field SearchStack::ttMove
No functional change

Resolves #533
2015-12-20 20:37:18 +00:00
Guenther Demetz 38adb487ca Distinct iteration paths for Lazy SMP threads
STC 5+0.1, threads 7
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 6026 W: 1047 L: 901 D: 4078

LTC: 20+0.2, threads 7
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 19739 W: 2910 L: 2721 D: 14108

STC 5+0.1, threads 20
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 2493 W: 462 L: 331 D: 1700

LTC 30+0.3, threads 20
ELO: 8.86 +-3.7 (95%) LOS: 100.0%
Total: 8000 W: 1076 L: 872 D: 6052

Bench: 8012530

Resolves #525
2015-12-18 21:59:09 +00:00
mstembera 2c1797ab81 Fix easy move bug in SMP mode
Fix a bug where we could stop the search after only 10% of time used due to a matching easy move but later switch to a different move that was never pre-screened as easy due to SMP thread select.

STC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 27227 W: 4910 L: 4800 D: 17517

LTC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 40368 W: 5826 L: 5733 D: 28809

Resolves #521
2015-12-14 18:47:12 +00:00
Alain SAVARD 9fac5774f4 Threats retuned
STC:

LLR: 2.96 (-2.94,2.94) [0.00,4.00]
Total: 45239 W: 8913 L: 8591 D: 27735

LTC:

LLR: 2.95 (-2.94,2.94) [0.00,4.00]
Total: 21046 W: 3200 L: 2989 D: 14857

Bench: 8012530

Resolves #526
2015-12-14 18:11:13 +00:00
Leonid Pechenik 69240a982d Simplify time management and fix 'ponder on' bug
Simplify time management code by removing hard stops for unchanging first root moves.
Search is now stopped earlier at the end iteration if it did not have fail-lows at root.

This simplification also fixes pondering bug. Ponder flag was true by default
and cutechess-cli doesn't change it to false even though no pondering is possible.
Fix the issue by setting the default value of 'Ponder' flag to false.

10+0.1:
ELO: 3.51 +-3.0 (95%) LOS: 99.0%
Total: 20000 W: 3898 L: 3696 D: 12406

40+0.4:
ELO: 1.39 +-2.7 (95%) LOS: 84.7%
Total: 20000 W: 3104 L: 3024 D: 13872

60+0.06:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 37231 W: 5333 L: 5236 D: 26662

Stopped run at 100+1:
LLR: 1.09 (-2.94,2.94) [-3.00,1.00]
Total: 37253 W: 4862 L: 4856 D: 27535

Resolves #523
Fixes #510
2015-12-14 18:00:52 +00:00
mstembera 7904a7d930 Fix MultiPv and Skill in SMP.
7 threads, 5+0.1:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 55460 W: 9665 L: 9601 D: 36194

No functional change in normal playing mode
2015-12-12 10:32:28 +00:00
absimaldata 8315620522 New Tuned Weights
More accurate evaluation weights

Performed better at STC

LLR: 1.32 (-2.94,2.94) [0.00,4.00]
Total: 190043 W: 37433 L: 36675 D: 115935

Passed LTC

LLR: 2.95 (-2.94,2.94) [0.00,4.00]
Total: 30157 W: 4540 L: 4303 D: 21314

Bench: 9264977

Resolves #515
2015-12-05 10:31:00 +00:00
Marco Costalba 52eac1e535 Simplify outpost code
Also inline defintions of SpaceMask and CenterBindMask.

Verified from assembly that compiler computes the values
at compile time, so it is also theoretical faster.

While there factor out scale factor evaluation.

No functional change.
2015-12-05 11:16:19 +01:00
mstembera 5d077bb482 Proper Makefile for cross compiling 64 or 32 bit PGO + LTO + static Windows binaries under Linux.
No functional change

Resolves #511
2015-12-03 14:01:38 +00:00
Stéphane Nicolet 5a42427cb8 Introduce new Threats weights = {350, 256}
Raise the midgame threats weight by 37%.

Passed STC:
LLR: 2.95 (-2.94,2.94) [0.00,4.00]
Total: 8165 W: 1675 L: 1487 D: 5003

and LTC:
LLR: 2.95 (-2.94,2.94) [0.00,4.00]
Total: 28181 W: 4141 L: 3912 D: 20128

Bench: 7824961

Resolves #512
2015-12-02 11:18:26 +00:00
Joona Kiiski 5339ab57d8 Revert "Allow cross compilation of Windows binaries on a Linux system"
This reverts commit 388630ae28.

Confuses fishtest build system
2015-11-24 17:24:45 -08:00
mstembera 388630ae28 Allow cross compilation of Windows binaries on a Linux system
that are PGO, LTO, and statically linked.
Credit: pasquale....@gmail.com

No functional change

Resolves #505
2015-11-23 17:06:14 -08:00
mstembera 79f393084a Clean up RootMove less operator
This is used by std::stable_sort() to sort moves from highest score to lowest score.

1) The comment is incorrect since highest to lowest means descending.
2) It's more natural to implement a less operator using another less operator rather than a greater operator.

No functional change.

Resolves #504
2015-11-20 23:30:07 -08:00
lucasart 328098d027 Fix TT comment and static_assert()
Comment is based on a misunderstanding of what unaligned memory access is. Here
is an article that explains it very clearly:
https://www.kernel.org/doc/Documentation/unaligned-memory-access.txt

No matter how we define TTEntry or TTCluster, there will never be any unaligned
memory access. This is because the complier knows the alignment rules, and does
the necessary adjustments to make sure unaligned memory access does not occur.

The issue being adressed here has nothing to do with unaligned memory access. It
is about cache performance. In order to achieve best cache performance:
- we prefetch the cacheline as soon as possible.
- we ensure that TT clusters do not spread across two cachelines. If they did,
  we would need to prefetch 2 cachelines, which could hurt cache performance.

Therefore the true conditions to achieve this are:
1/ start adress of TT is cache line aligned. void TranspositionTable::resize()
enforces this.
2/ TT cluster size should *divide* the cache line size. Currently, we pack 2
clusters per cache lines. It used to be 1 before "TT sardines". Does not matter
what the ratio is, all we want is to fit an integer number of clusters per cache
line.

No functional change.

Resolves #506
2015-11-20 23:23:53 -08:00
Marco Costalba 93195555ed Rewrite how threads are spawned
Instead of creating a running std::thread and
returning, wait in Thread c'tor that the native
thread of execution goes to sleep in idle_loop().

In this way we can simplify how search is started,
because when main thread is idle we are sure also
all other threads will be idle, in any case, even
at thread creation and startup.

After lazy smp went in, we can simpify and rewrite
a lot of logic that is now no more needed. This is
hopefully the final big cleanup.

Tested for no regression at 5+0.1 with 3 threads:
LLR: 2.95 (-2.94,2.94) [-5.00,0.00]
Total: 17411 W: 3248 L: 3198 D: 10965

No functional change.
2015-11-21 07:48:50 +01:00
VoyagerOne 07e0741dfb History Pruning: Don't prune the main killer move.
Also increased pruned depth to 4.

STC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 23380 W: 4581 L: 4350 D: 14449

LTC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 28934 W: 4329 L: 4105 D: 20500

Bench: 8369743

Resolves #498
2015-11-15 20:40:09 -08:00
Ken T Takusagawa 27ca89d479 Do not conceal the invocation of the benchmark program
It is better to be able to see what arguments it is being called with.

No functional change

Resolves #497
2015-11-15 20:34:37 -08:00
Stefan Geschwentner cccf3c815c Bonus for reachable outpost
Give a bonus for outpost squares which in reach of a bishop or knight.

STC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 22725 W: 4570 L: 4339 D: 13816

LTC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 15019 W: 2333 L: 2157 D: 10529

Bench: 8503181

Resolves #495
2015-11-14 06:31:45 -08:00
Marco Costalba 76ed0ab501 Retire ThreadBase
Now that we don't have anymore TimerThread, there is
no need of this long class hierarchy.

Also assorted reformatting while there.

To verify no regression, passed at STC with 7 threads:
LLR: 2.97 (-2.94,2.94) [-5.00,0.00]
Total: 30990 W: 4945 L: 4942 D: 21103

No functional change.
2015-11-13 08:22:44 +01:00
Marco Costalba ce84ab6e9d Fix broken UCI 'wait for stop'
When we reach the maximum depth, we can finish the
search without a raise of Signals.stop. However, if
we are pondering or in an infinite search, the UCI
protocol states that we shouldn't print the best move
before the GUI sends a "stop" or "ponderhit" command.

It was broken by lazy smp. Fix it by moving the stopping
of the threads after waiting for GUI.

No functional change.
2015-11-13 08:13:59 +01:00
lucasart fca8dbc029 Avoid friend
operator<<(os, pos) does not need to access any private members of pos.

No functional change.

Resolves #492
2015-11-10 21:46:02 +00:00
lucasart e6eeb17aa6 Ensure that rootDepth < DEPTH_MAX
Indeed, if we use a depth >= DEPTH_MAX, we start having negative depth in the
TT (due to int8_t cast).

No functional change in single thread mode

Resolves #490
2015-11-10 21:41:42 +00:00
Marco Costalba 9c9205860c Get rid of timer thread
Unfortunately std::condition_variable::wait_for()
is not accurate in general case and the timer thread
can wake up also after tens or even hundreds of
millisecs after time has elapsded. CPU load, process
priorities, number of concurrent threads, even from
other processes, will have effect upon it.

Even official documentation says: "This function may
block for longer than timeout_duration due to scheduling
or resource contention delays."

So retire timer and use a polling scheme based on a
local thread counter that counts search() calls and
a small trick to keep polling frequency constant,
independently from the number of threads.

Tested for no regression at very fast TC 2+0.05 th 7:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 32969 W: 6720 L: 6620 D: 19629

TC 2+0.05 th 1:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 7765 W: 1917 L: 1765 D: 4083

And at STC TC, both single thread
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 15587 W: 3036 L: 2905 D: 9646

And with 7 threads
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 8149 W: 1367 L: 1227 D: 5555

bench: 8639247
2015-11-03 11:27:00 +01:00
mbootsector 27c5cb5912 Pick bestmove from the deepest thread.
STC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 26930 W: 4441 L: 4214 D: 18275

LTC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 7783 W: 1017 L: 876 D: 5890

No functional change in single thread mode

Resolves #485
2015-11-02 10:05:43 +00:00
Marco Costalba 86f04dbcc0 Assorted trivia in search.cpp
The only interesting change is the moving of
stack[MAX_PLY+4] back to its original position
in id_loop (now renamed Thread::search).

No functional change.
2015-10-31 19:26:35 +01:00
VoyagerOne aa242d2f84 New History Bonus Formula
bonus = d^2 + d - 1

Bench: 8639247

Resolves #484
2015-10-31 18:17:00 +00:00
Ajith 8d858783e1 Reduce variation in rootDepth between different threads
Reduce the variation in Root Depth between different threads. This
prevents threads from searching at a depth much higher than Main Thread.

Performed well at STC 24 Threads:
ELO: 3.44 +-3.8 (95%) LOS: 96.1%
Total: 10000 W: 1627 L: 1528 D: 6845

And LTC 24 Threads
LLR: 1.43 (-2.94,2.94) [0.00,4.00]
Total: 3804 W: 500 L: 420 D: 2884
ELO : +7.31
p-value: 73.16%

Passed no regression at STC 3 Threads:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 40457 W: 7148 L: 7060 D: 26249

And LTC 3 Threads:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 17704 W: 2489 L: 2364 D: 12851

Raising a pull request early as 24 Thread tests are very expensive and
this is clearly a positive gain at high thread counts and high time
controls. The change is a small parameter tweak with no additional
logic.

No functional change for single thread mode.

Resolves #481
2015-10-29 17:06:13 -07:00
Stéphane Nicolet 80d7556af7 Some code and comment cleanup
- Remove all references to split points
- Some grammar and spelling fixes

No Functional change

Resolves #478
2015-10-29 15:28:59 +00:00
lucasart 00d9e9fd28 Use atomics instead of volatile
Rely on well defined behaviour for message passing, instead of volatile. Three
versions have been tested, to make sure this wouldn't cause a slowdown on any
platform.

v1: Sequentially consistent atomics

No mesurable regression, despite the extra memory barriers on x86. Even with 15
threads and extreme time pressure, both acting as a magnifying glass:

threads=15, tc=2+0.02
ELO: 2.59 +-3.4 (95%) LOS: 93.3%
Total: 18132 W: 4113 L: 3978 D: 10041

threads=7, tc=2+0.02
ELO: -1.64 +-3.6 (95%) LOS: 18.8%
Total: 16914 W: 4053 L: 4133 D: 8728

v2: Acquire/Release semantics

This version generates no extra barriers for x86 (on the hot path). As expected,
no regression either, under the same conditions:

threads=15, tc=2+0.02
ELO: 2.85 +-3.3 (95%) LOS: 95.4%
Total: 19661 W: 4640 L: 4479 D: 10542

threads=7, tc=2+0.02
ELO: 0.23 +-3.5 (95%) LOS: 55.1%
Total: 18108 W: 4326 L: 4314 D: 9468

As suggested by Joona, another test at LTC:

threads=15, tc=20+0.05
ELO: 0.64 +-2.6 (95%) LOS: 68.3%
Total: 20000 W: 3053 L: 3016 D: 13931

v3: Final version: SeqCst/Relaxed

threads=15, tc=10+0.1
ELO: 0.87 +-3.9 (95%) LOS: 67.1%
Total: 9541 W: 1478 L: 1454 D: 6609

Resolves #474
2015-10-25 09:15:45 +00:00
Stefano80 3428a28751 KRPPKRP endgame: Simplify ugly switch statement
No functional change

Resolves #470
2015-10-24 23:17:08 +01:00
Marco Costalba 307a5a4f63 Cleanup history stats
And other assorted trivia.

No functional change.
2015-10-24 17:29:12 +02:00
Alain SAVARD 55758344d3 Simplify threats
Using less parameters and code to compute Threats
Includes also a few spacing edits.

Run as a simplification.

Passed STC 10+0.1
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 18879 W: 3725 L: 3600 D: 11554

Passed LTC 60+0.4
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 74116 W: 11001 L: 10958 D: 52157

bench: 8004751
2015-10-24 10:08:26 +02:00
VoyagerOne 4eca981e55 History pruning
Prune moves with negative History
and CMH scores at low depth.

STC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 24182 W: 4672 L: 4439 D: 15071

LTC:
LLR: 2.97 (-2.94,2.94) [0.00,5.00]
Total: 12579 W: 1959 L: 1792 D: 8828

bench: 8907701
2015-10-24 09:30:31 +02:00
Marco Costalba 5066e17eba Update authors
Fishtest is a key factor of SF success.

Thanks to Fishtest we have not only greately
improved ELO but, even more important, we
have enabled a kind of joint development and
testing that it is the herat of on open
source project like SF.

Open sourcing is not just about open code, it is
about commuity development. In case of a chess engine
this has never been possible before due to missing
a strong and strict testing environment that allows
many people to contribute in a safe and coordinate way.

Fishtest is a new way of developing chess engines,
something that has never exsisted before.

No functional change.
2015-10-22 07:03:03 +02:00
Stefano80 328d314f2f Almost passed tuning attempts
Collect and give a second try to some almost passed tuning attempts and
one-line tweaks from the last month.

Passed STC

LLR: 3.07 (-2.94,2.94) [0.00,4.00]
Total: 15124 W: 2974 L: 2756 D: 9394

And LTC

LLR: 2.95 (-2.94,2.94) [0.00,4.00]
Total: 21577 W: 3507 L: 3289 D: 14781

Bench: 8855226

Resolves #464
2015-10-20 19:49:01 -07:00
mbootsector ecc5ff6693 Lazy SMP
Start all threads searching on root position and
use only the shared TT table as synching scheme.

It seems this scheme scales better than YBWC for
high number of threads.

Verified for nor regression at STC 3 threads
LLR: -2.95 (-2.94,2.94) [-3.00,1.00]
Total: 40232 W: 6908 L: 7130 D: 26194

Verified for nor regression at LTC 3 threads
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 28186 W: 3908 L: 3798 D: 20480

Verified for nor regression at STC 7 threads
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 3607 W: 674 L: 526 D: 2407

Verified for nor regression at LTC 7 threads
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 4235 W: 671 L: 528 D: 3036

Tested with fixed games at LTC with 20 threads
ELO: 44.75 +-7.6 (95%) LOS: 100.0%
Total: 2069 W: 407 L: 142 D: 1520

Tested with fixed games at XLTC (120secs) with 20 threads
ELO: 28.01 +-6.7 (95%) LOS: 100.0%
Total: 2275 W: 349 L: 166 D: 1760

Original patch of mbootsector, with additional work
from Ivan Ivec (log formula), Joerg Oster (id loop
simplification) and Marco Costalba (assorted formatting
and rework).

Bench: 8116244
2015-10-20 06:58:08 +02:00
Stéphane Nicolet 7ea5659c5f Asymmetry bonus for the attacking side
Use asymmetry in the position (king separation, pawn structure) to
compute an "initiative bonus" for the attacking side.

Passed STC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 14563 W: 2826 L: 2636 D: 9101

And LTC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 14363 W: 2317 L: 2141 D: 9905

Bench: 8116244

Resolves #462
2015-10-15 21:27:52 -07:00
VoyagerOne 8fd34d7763 Combination of two ideas:
Apply bonus for the prior CMH that caused a fail low.

Balance Stats: CMH and History bonuses are updated differently.
This eliminates the "fudge" factor weight when scoring moves. Also
eliminated discontinuity in the gravity history stat formula. (i.e. stat
scores will no longer inverse when depth exceeds 22)

STC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 21802 W: 4107 L: 3887 D: 13808

LTC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 46036 W: 7046 L: 6756 D: 32234

Bench: 7677367
2015-10-12 14:00:54 -07:00
Jonathan Calovski 55b46ffa90 Retire rook contact checks
STC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 34114 W: 6363 L: 6265 D: 21486

LTC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 61776 W: 9349 L: 9289 D: 43138

LTC (after rebasing):
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 15261 W: 2343 L: 2214 D: 10704

Bench: 7523382

Resolves #442
2015-10-07 19:43:20 +01:00
Marco Costalba 08d6465d90 Travis CI: add gcc 4.8 for osx
This setup was still missing.

Suggested by Stéphane Nicolet.

No functional change.
2015-10-07 20:33:37 +02:00
Marco Costalba 5f4d9309c8 Travis CI: add clang and osx
Extend builds to clang and osx platforms.

And check bench numbers.

No functional change.
2015-10-06 12:35:42 +02:00
Stefano80 436c303731 Tuning of assorted values
Passed STC

LLR: 2.96 (-2.94,2.94) [0.00,4.00]
Total: 45401 W: 8590 L: 8274 D: 28537

Passed LTC

LLR: 2.96 (-2.94,2.94) [0.00,4.00]
Total: 36089 W: 5589 L: 5331 D: 25169

Bench: 8397672

Resolves #445
2015-10-05 19:49:52 -07:00
Alain SAVARD 540b49a152 Remove queen threat evaluation
Threats by queen seem to be worthless.

STC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 13627 W: 2607 L: 2473 D: 8547

LTC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 19146 W: 2950 L: 2827 D: 13369

Bench: 8222484

Resolves #439
2015-10-06 03:35:17 +01:00
Marco Costalba 2e45447957 Add Trevis CI support
Add Travis CI support to GitHub repo.

After every push to master, Travis will build
the sources directly from GitHub repo according
to .travis.yml and verify everything is ok.

No functional change.
2015-10-05 12:39:34 +02:00
Marco Costalba dc3508d157 Fix a comment in TTEntry::save
Comment was slightly incorrect.

No functional change.
2015-10-05 09:16:16 +02:00
Marco Costalba ca38358574 Run PVS-STUDIO analyzer
Fix issues after a run of PVS-STUDIO analyzer.
Mainly false positives but warnings are anyhow
useful to point out not very readable code.

Noteworthy is the memset() one, where PVS prefers ss-2
instead of stack. This is because memeset() could
be optimized away by the compiler when using 'stack',
due to stack being a local variable no more used after
memset. This should normally not happen, but when
it happens it leads to very sublte and difficult
to find bug, so better to be safe than sorry.

No functional change.
2015-10-05 09:13:33 +02:00
Stefan Geschwentner 83e19fbed5 File based passed pawn bonus
Add file based bonus for passed pawns. Values tuned by SPSA.

STC:
LLR: 3.33 (-2.94,2.94) [0.00,5.00]
Total: 36889 W: 6805 L: 6507 D: 23577

LTC:
LLR: 2.97 (-2.94,2.94) [0.00,5.00]
Total: 32301 W: 5101 L: 4858 D: 22342

Bench: 8073614

Resolves #436
2015-10-03 03:50:06 -07:00
Jonathan Calovski 9f5b31c21d Bonus for checking moves
STC:
LLR: 2.97 (-2.94,2.94) [0.00,5.00]
Total: 14531 W: 2765 L: 2576 D: 9190

LTC:
LLR: 3.20 (-2.94,2.94) [0.00,5.00]
Total: 52518 W: 8107 L: 7782 D: 36629

Bench: 7556477

Resolves #435
2015-10-03 03:39:21 -07:00
Marco Costalba 3c0fe1d9b2 Rework lock protecting
When changing 'search' and 'splitPointsSize' we have to
use thread locks, not split point ones, because can_join()
is called under the formers.

Verified succesfully with 24 hours toruture tests with 20
cores machine by Louis Zulli: it does not hangs.

Verifyed for no regressions with STC, 7 threads:
LLR: 2.94 (-2.94,2.94) [-3.00,1.00]
Total: 52804 W: 8159 L: 8087 D: 36558

No functional change.
2015-09-30 10:47:20 +02:00
Jonathan Calovski 77b4f4c2e7 Refine ranks and increase resulting bonus.
STC:
LLR: 2.94 (-2.94,2.94) [0.00,4.00]
Total: 272379 W: 51773 L: 50658 D: 169948

LTC:
LLR: 3.06 (-2.94,2.94) [0.00,4.00]
Total: 41504 W: 6555 L: 6273 D: 28676

bench: 7658406

Resolves #430
2015-09-19 09:14:35 -07:00
mstembera 68fbb1e052 Reduce writes in TT::probe().
Only refresh TT entry when it's really necessary.
This should give a small speed boost for some machines.
And it's a risk-free change.

No functional change.

Resolves #429
2015-09-17 17:33:40 -07:00
mstembera 01fab4d432 Remove unnecessary generation check in TT save
Checking for generation is unnecessary because if the key matches then the entry was probed and refreshed earlier.

STC 2MB
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 57391 W: 10671 L: 10613 D: 36107
http://tests.stockfishchess.org/tests/view/55ef59fa0ebc5976a2d6da5d

LTC 8MB
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 60732 W: 9260 L: 9199 D: 42273
http://tests.stockfishchess.org/tests/view/55ef8fe60ebc5976a2d6da6b

STC 16MB
LLR: 2.95 (-2.94,2.94) [-4.00,0.00]
Total: 23443 W: 4369 L: 4293 D: 14781
http://tests.stockfishchess.org/tests/view/55ef8fe60ebc5976a2d6da6b

No functional change

Resolves #427
2015-09-17 17:13:45 -07:00
Stefan Geschwentner 660c38f781 Scales the endgame score by the number of pawns.
Credits goes also to Stephane Nicolet for his great idea of scaling by pawns.

STC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 9994 W: 1929 L: 1760 D: 6305

LTC:
LLR: 2.96 (-2.94,2.94) [0.00,5.00]
Total: 11240 W: 1789 L: 1626 D: 7825

bench 7298564

Resolves #423
2015-09-15 05:55:09 -07:00
Joona Kiiski 613dc66c12 Careful SMP locking - Fix very occasional hangs
Louis Zulli reported that Stockfish suffers from very occasional hangs with his 20 cores machine.

Careful SMP debugging revealed that this was caused by "a ghost split point slave", where thread
was marked as a split point slave, but wasn't actually working on it.

The only logical explanation for this was double booking, where due to SMP race, the same thread
is booked for two different split points simultaneously.

Due to very intermittent nature of the problem, we can't say exactly how this happens.

The current handling of Thread specific variables is risky though. Volatile variables are in some
cases changed without spinlock being hold. In this case standard doesn't give us any kind of
guarantees about how the updated values are propagated to other threads.

We resolve the situation by enforcing very strict locking rules:
- Values for key thread variables (splitPointsSize, activeSplitPoint, searching)
can only be changed when the thread specific spinlock is held.
- Structural changes for splitPoints[] are only allowed when the thread specific spinlock is held.
- Thread booking decisions (per split point) can only be done when the thread specific spinlock is held.

With these changes hangs didn't occur anymore during 2 days torture testing on Zulli's machine.

We probably have a slight performance penalty in SMP mode due to more locking.

STC (7 threads):
ELO: -1.00 +-2.2 (95%) LOS: 18.4%
Total: 30000 W: 4538 L: 4624 D: 20838

However stability is worth more than 1-2 ELO points in this case.

No functional change

Resolves #422
2015-09-10 19:15:43 +01:00
mstembera 3e2591d83c Minor clean up of some function parameters
No function change

Resolves #416
2015-09-07 20:17:39 +01:00
mstembera 46b5a5f0db Fix syzygy en passant issue
v = value without ep capture being considered
v1 = value of the ep capture

The correct logic is:
if without e.p. capture we are losing, and the value of e.p is either draw, or win or "loss, but 50 move rule saves us", then we should use the value of ep capture.

Credit and thanks to syzygy1 and lantonov !

No functional change (except with syzygy bases)

Resolves #415
Resolves #394
2015-09-06 22:19:33 +01:00
gguliash 84a641b8bb A small code simplification
No functional change

Resolves #411
2015-08-30 19:58:32 +01:00
Joona Kiiski 7f300a7698 History gravity
Instead of using hard coded Min and Max values for history,
always adjust the old value slightly downwards before adding a new value.

The adjustment acts like gravity that prevents the value escaping too
far from zero.

Bench: 8020484

Resolves #407
2015-08-29 15:09:00 +01:00
Marco Costalba 087b638f6c Reformat trace code
Apart from usual renaiming, take advantage of
C++11 function template default parmeter to
get rid of Eval trampoline functions.

Some triviality fixes while there.

No functional change.
2015-08-29 08:28:01 +02:00
lucasart 7ad85fca6d Prune castling moves
Align the behaviour with reductions. Initially castling moves had to be
treated differently, because the SEE did not handle them correctly. But now it
does.

STC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 83750 W: 15722 L: 15711 D: 52317

LTC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 97183 W: 15120 L: 15115 D: 66948

bench 7759837

Resolves #403
2015-08-28 20:33:12 +01:00
mstembera bf6bc1b37b Better document entry age calculation used in TT replace.
No functional change.

Resolves #401
Resolves #400
2015-08-20 20:27:06 +01:00
lucasart c052e03426 Retire dangerous flag
Replace by its value where it is used. Code is more clear that
way.

No functional change.

Resolves #402
2015-08-20 20:18:23 +01:00
Alain SAVARD 69a1a808c8 Retire PawnSafePush bonus
PawnSafePush, with the value S(5,5) proved not "necessary"
possibly due to recent changes to MobilityArea and other changes to Connected bonus.

STC:
LLR: 3.22 (-2.94,2.94) [-3.00,1.00]
Total: 98528 W: 18757 L: 18759 D: 61012

LTC:
LLR: 5.30 (-2.94,2.94) [-3.00,1.00]
Total: 204194 W: 31698 L: 31734 D: 140762

Bench: 7620871

Resolves #396
2015-08-17 19:32:43 +01:00
Marco Costalba 600234f2e2 Reformat PassedPawnsBonus
Align to SF coding standards.

No functional change.
2015-08-15 16:04:16 +02:00
mstembera 9dbb3ae8b2 TT entry value based on depth and relative age
Calculate TT replace value as depth minus eight times relative age.

STC 2MB
LLR: 2.96 (-2.94,2.94) [0.00,4.00]
Total: 45258 W: 8595 L: 8279 D: 28384

LTC 8MB
LLR: 2.95 (-2.94,2.94) [0.00,4.00]
Total: 56401 W: 8809 L: 8489 D: 39103

STC 16MB
LLR: 2.96 (-2.94,2.94) [-4.00,0.00]
Total: 34764 W: 6565 L: 6529 D: 21670

Bench: 9069474

Resolves #395
2015-08-15 12:24:48 +01:00
DiscanX f4ace94f91 Tuned values for mid and end game passed pawns.
STC :
LLR: 2.96 (-2.94,2.94) [0.00,4.00]
Total: 22691 W: 4468 L: 4228 D: 13995

LTC :
LLR: 2.95 (-2.94,2.94) [0.00,4.00]
Total: 13620 W: 2216 L: 2023 D: 9381

Bench: 8384669

Resolves #391
2015-08-10 01:26:59 +08:00
mstembera 1aae35b8b7 Revert TT replacement strategy changes (#380)
It could cause problems with high depths and long time controls

Bench: 8626315

Resolves #390
2015-08-08 17:49:53 +01:00
Marco Costalba e6310b3469 Rename Position::list
Use Position::square and Position::squares instead.

This allow us to remove king_square(), simplify
endgames and to have more naming uniformity.

Moreover, this is a prerequisite step in case
in the future we decide to retire piece lists
altoghter and use pop_lsb() to loop across
pieces and serialize the moves. In this way
we just need to change definition of Position::square
to something like:

template<PieceType Pt> inline
Square Position::square(Color c) const {
  return lsb(byColorBB[c]);
}

No functional change.
2015-08-04 09:51:06 +02:00
Marco Costalba 68d61b80c6 Simplify IID depth formula
Restore original formula messed up during
half-ply removal.

STC
LLR: 4.11 (-2.94,2.94) [-3.00,1.00]
Total: 21349 W: 4091 L: 3909 D: 13349

LTC
LLR: 5.42 (-2.94,2.94) [-3.00,1.00]
Total: 52819 W: 8321 L: 8122 D: 36376

bench: 8040572
2015-07-30 09:54:25 +02:00
VoyagerOne a2410227cc PV refutation penalty
Extra penalty for PV move in previous ply when it gets refuted.

STC:
LLR: 4.49 (-2.94,2.94) [-1.50,4.50]
Total: 41094 W: 7889 L: 7620 D: 25585

LTC:
LLR: 2.95 (-2.94,2.94) [0.00,6.00]
Total: 12304 W: 1967 L: 1811 D: 8526

Bench: 8373608

Resolves #386
2015-07-30 00:51:49 +08:00
Alain SAVARD 4a6d59c6c7 MobilityArea (simplified)
Based off of Pull request #383:

Include squares occupied by some pawns in the MobilityArea
a) not blocked
b) on rank 4 and above
c) or captures

Passed STC
LLR: 2.95 (-2.94,2.94) [-1.50,4.50]
Total: 8157 W: 1644 L: 1516 D: 4997

And LTC
LLR: 2.97 (-2.94,2.94) [0.00,6.00]
Total: 26086 W: 4274 L: 4051 D: 17761

-----------

Then, a simplification test failed, trying to remove b and c)
LLR: -2.95 (-2.94,2.94) [-3.00,1.00]
Total: 6048 W: 1117 L: 1288 D: 3643

Another simplification test, was run to remove just (c)
Passed STC
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 28073 W: 5364 L: 5255 D: 17454

And LTC
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 34652 W: 5448 L: 5348 D: 23856

A parameter tweak test showed that changing b) for "on rank 3 and above"
does not work
LLR: -2.95 (-2.94,2.94) [0.00,4.00]
Total: 5233 W: 937 L: 1077 D: 3219

Finally, a small rewrite, and we have this version

Include squares occupied by some pawns in the MobilityArea which are
a) not blocked
b) on rank 4 and above

Bench: 8977899

Resolves #385
2015-07-30 00:47:51 +08:00
mstembera 51330414c4 Tuned version of TT replacement policy
If the used multiplier of 8 was any number larger than DEPTH_MAX
this would be a non functional patch.

STC 2MB
LLR: 2.96 (-2.94,2.94) [-1.50,4.50]
Total: 16353 W: 3216 L: 3066 D: 10071
http://tests.stockfishchess.org/tests/view/55a6d0630ebc590abbe1babd

LTC 8MB
LLR: 2.95 (-2.94,2.94) [0.00,4.00]
Total: 134618 W: 21276 L: 20716 D: 92626
http://tests.stockfishchess.org/tests/view/55a74d760ebc590abbe1bad6

STC 16MB
LLR: 2.96 (-2.94,2.94) [-4.00,0.00]
Total: 22549 W: 4257 L: 4178 D: 14114
http://tests.stockfishchess.org/tests/view/55a9a2f90ebc590abbe1bb16

Bench: 7372460

Resolves #380
2015-07-25 00:33:53 +08:00
Marco Costalba 42b77ea7ee Tidy up in movepick.cpp
Some formattng after recent changes.

No functional change.
2015-07-19 12:38:33 +02:00
Marco Costalba 4095ff0ee5 Fix formatting of previous patch
No functional change.
2015-07-16 08:17:40 +02:00
VoyagerOne 1d977aa79e LMR Simplification: Remove countermove condition
Removed countermove condition for decreasing reduction.

LTC:
LLR: 3.01 (-2.94,2.94) [-3.00,1.00]
Total: 32410 W: 5092 L: 4986 D: 22332

STC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 24450 W: 4632 L: 4517 D: 15301

Bench: 6943812

Resolves #378
2015-07-15 20:21:14 +01:00
mstembera d8aeaab79c Consistent TT replace policy
This fixes an inconsistency bug where TT entries were valued differently
depending on which pointer they were accessed through.

STC 2MB
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 11301 W: 2176 L: 2038 D: 7087

LTC 8MB
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 17732 W: 2870 L: 2745 D: 12117

STC 16MB
LLR: 2.96 (-2.94,2.94) [-4.00,0.00]
Total: 17401 W: 3324 L: 3227 D: 10850

Bench: 8248164

Resolves #377
2015-07-15 20:17:16 +01:00
joergoster 3054db989d Use distance<file>() function in endgame.cpp
This one occurance of distance function was most likely overlooked.

No functional change.

Resolves #376
2015-07-12 20:48:50 +01:00
Marco Costalba b2edac7075 Remove useless razoring condition
STC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 20626 W: 3977 L: 3855 D: 12794

LTC:
LLR: 3.10 (-2.94,2.94) [-3.00,1.00]
Total: 87334 W: 13675 L: 13648 D: 60011

Retire also the now unused pawn_on_7th() helper.

bench: 8248166
2015-07-09 08:13:30 +02:00
VoyagerOne aa0dc16b75 CMH Fix: Exclude captures for TT move refutation penalty
This will make sure we store only quiet moves for TT Penalty.

STC:
LLR: 2.96 (-2.94,2.94) [-1.50,4.50]
Total: 34748 W: 6617 L: 6420 D: 21711

LTC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 19975 W: 3259 L: 3137 D: 13579

Bench: 8063826

Resolves #373
2015-07-04 14:22:41 +01:00
Marco Costalba 112607bf49 Correctly check for no-makefile compile
Under Windows with MSVC we use the IDE to compile,
in this case we infer some compiler flags usually
set by Makefile.

The condition to check this was wrong, namely when compiling
with mingw under Windows 64 bit we always set IS_64BIT and
USE_BSFQ even if compiled with ARCH=x86-32 (this is how I
found it).

Small code style touches while there.

No functional change.
2015-06-28 10:56:42 +02:00
VoyagerOne 7e9f776fca LMR Tweak: Decrease reduction if cmh>0 && history>0.
STC:
LLR: 2.96 (-2.94,2.94) [-1.50,4.50]
Total: 9627 W: 1879 L: 1748 D: 6000

LTC:
LLR: 2.97 (-2.94,2.94) [0.00,6.00]
Total: 21543 W: 3433 L: 3234 D: 14876

Bench: 8646407

Resolves #370 #371
2015-06-27 09:45:59 +01:00
Marco Costalba 3f1bc9e013 Fix compile on icc
Error is:

  a value of type "int" cannot be assigned to an entity of type "Value"

Also retire the now unused squares_of_color() function.

No functional change.
2015-06-25 05:29:56 +02:00
joergoster e8cc5c9968 Small coding style fix for Outpost array
No functional change

Resolves #367
2015-06-17 15:02:57 +01:00
lucasart 00563be5cc Retire -Wno-long-long
long long is part of the C++11 standard.

No functional change.

Resolves #364
2015-06-13 16:59:50 +01:00
lucasart ad87d707ff Simplify outpost evaluation
STC

LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 114149 W: 21986 L: 22032 D: 70131

LTC

LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 52232 W: 8468 L: 8396 D: 35368

Bench: 6716940

No functional change

Resolves #363
2015-06-07 09:49:01 +01:00
Vince Negri 7b8ffe0f5d Remove intermediate re-search in LMR
STC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 20149 W: 3830 L: 3707 D: 12612

LTC:
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 45384 W: 7089 L: 7006 D: 31289

Bench: 8110365

Resolves #361
2015-06-05 21:03:10 +01:00
Marco Costalba c1d3bd2dba Rename stages
Hopefully more clear.

No functional change.
2015-06-04 15:51:45 +02:00
lucasart 5ebdf2f8c8 Tune pawn shelter/storm
STC
LLR: 2.95 (-2.94,2.94) [0.00,4.00]
Total: 31679 W: 6183 L: 5912 D: 19584

LTC
LLR: 2.95 (-2.94,2.94) [0.00,4.00]
Total: 43550 W: 6885 L: 6602 D: 30063

Bench: 9219343

Resolves #360
2015-06-02 12:09:19 -07:00
Stéphane Nicolet 4502a1934f Tweak backward pawns definition
Advanced pawns cannot be backward. Also lower the backward penalty in
endgame.

Passed STC:
LLR: 2.96 (-2.94,2.94) [-1.50,4.50]
Total: 18534 W: 3588 L: 3433 D: 11513

and LTC:
LLR: 2.96 (-2.94,2.94) [0.00,6.00]
Total: 21319 W: 3415 L: 3217 D: 14687

Bench: 7271152

Resolves #359
2015-06-02 12:07:02 -07:00
Marco Costalba 2795aedbc3 Checking for rook color when setting castling
In Chess960 we can have legal positions with
opponent rook in A or H file and with castling
available, for instance:

4k3/pppppppp/8/8/8/8/PPPPPPPP/rR2K3 w Q - 0 1

In those cases we pick up the wrong rook when
setting castling.

Fix it by checking the color of the rook.

Bug reported by Matthew Lai.

No functional change.
2015-05-29 05:38:40 +02:00
lucasart 8e95c39bfa Simplify backward pawn scoring
STC

LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 52322 W: 10011 L: 9945 D: 32366

LTC

LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 14143 W: 2334 L: 2203 D: 9606

Bench: 7976423

Resolves #354
2015-05-27 20:05:20 +01:00
Joona Kiiski 80a759d544 Resolve build failure for Mac
Remove '-Wl' switch from gcc arguments when compiling for Mac

No functional change

Resolves #353
2015-05-24 13:07:15 +01:00
lucasart 2e0ec4ad6f Fix merge error for Tuned PSQT
Fall-out from 411e704f

Bench: 7907776

Resolves #352
2015-05-21 19:56:01 +01:00
Stefan Geschwentner e14046517e Remove Gain Stats
Additionally in futility pruning the margin is raised for compensation.

STC
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 48481 W: 9229 L: 9156 D: 30096

LTC
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 32058 W: 5134 L: 5031 D: 21893

Bench: 8098149

Resolves #350
2015-05-18 13:59:30 -07:00
lucasart 411e704fdf Tuned PSQT
STC:
LLR: 3.11 (-2.94,2.94) [-0.50,4.50]
Total: 58764 W: 11530 L: 11185 D: 36049

LTC:
LLR: 2.96 (-2.94,2.94) [0.00,4.50]
Total: 282710 W: 46339 L: 45209 D: 191162

Bench: 8512947

Resolves #349
2015-05-18 13:54:45 -07:00
Marco Costalba ee0371f86e Cleanup work in misc.cpp
Also some code style tidy up of latest patches.

Also renamed checkSq -> checkSquares because it
is a bitboard and not a square.

No functional change.
2015-05-10 09:42:26 +02:00
mstembera eaeb63f1d0 Smart TT save
Don't overwrite more valuable data with less valuable data

STC 2MB
LLR: 2.96 (-2.94,2.94) [-1.50,4.50]
Total: 21132 W: 4108 L: 3946 D: 13078
http://tests.stockfishchess.org/tests/view/5547d59f0ebc5940ca5d6883

LTC 8MB
LLR: 2.97 (-2.94,2.94) [0.00,6.00]
Total: 13381 W: 2149 L: 1987 D: 9245
http://tests.stockfishchess.org/tests/view/5549b5a80ebc5940ca5d68b9

STC 16MB regression w/ zero effective hash pressure
LLR: 2.96 (-2.94,2.94) [-5.00,0.00]
Total: 18944 W: 3607 L: 3564 D: 11773
http://tests.stockfishchess.org/tests/view/554b0fda0ebc5940ca5d68ea

Bench: 8787152

Resolves #347
2015-05-09 17:43:57 +01:00
lucasart 92dbee7875 Edge distance
Instead of crafting a clever formula to calculate the array offset, simply use a
3 dimensional array. Remove the comment while at it, because now the code is
self-documenting.

No functional change.

Resolves #344
2015-05-09 14:06:19 +01:00
lucasart 2e86d1febc Restore deterministic search state
Introduce helper function Search::reset() which clears all kind of search
memory, in order to restore a deterministic search state.

Generalize TT.clear() into Search::reset() for the following use cases:
- bench: needed to guarantee deterministic bench (ie. if you call bench from
interactive command line twice in a row you get the same value).
- Clear Hash: restore clean search state, which is the purpose of this button.
- ucinewgame: ditto.

No functional change.

Resolves #346
2015-05-07 14:20:32 -07:00
lucasart 946fa47625 Never clear stats
Based on an idea and patch by VoyagerOne.

Small simplification, but was tedted for an ELO gain anyway.

STC:
LLR: 2.95 (-2.94,2.94) [-1.00,4.00]
Total: 5375 W: 1119 L: 977 D: 3279

LTC:
LLR: 2.95 (-2.94,2.94) [0.00,5.00]
Total: 17893 W: 2984 L: 2792 D: 12117

bench 8322847
2015-05-06 19:17:33 +08:00
Marco Costalba 7231b18af1 Halve PSQT row data
Use symmetry along vertical middle axis of the board
to reduce the number of parameters.

For instance psqt value of SQ_A5 == SQ_A4 and value of
SQ_F8 == SQ_F1.

This is always true, at least until now nobody came in
with an asymmetric psqt table that worked.

Original patch by Lucas.

No functional change.
2015-05-03 20:07:52 +02:00
Marco Costalba 578b21bbee Split PSQT init from Position init
Easier for tuning psq tables:

TUNE(myParameters, PSQT::init);

Also move PSQT code in a new *.cpp file, and retire the
old and hacky psqtab.h that required to be included only
once to work correctly, this is not idiomatic for a header
file.

Give wide visibility to psq tables (previously visible only
in position.cpp), this will easy the use of psq tables outside
Position, for instance in move ordering.

Finally trivial code style fixes of the latest patches.

Original patch of Lucas Braesch.

No functional change.
2015-05-03 20:07:15 +02:00
Stefano80 59f64fda4f Improve ordering of good captures using rank term
Rank based term improved approximation of pos.see() for scoring good
captures.

STC
LLR: 2.95 (-2.94,2.94) [-1.50,4.50]
Total: 4632 W: 945 L: 827 D: 2860

LTC
LLR: 2.95 (-2.94,2.94) [0.00,6.00]
Total: 25770 W: 4184 L: 3964 D: 17622

Bench: 7593704

Resolves #342
2015-05-03 10:19:34 -07:00
Stefano80 cc54a91ca5 Replace MVV/LVA by MVV for good captures
Passed STC

LLR: 3.71 (-2.94,2.94) [-3.00,1.00]
Total: 64363 W: 12299 L: 12214 D: 39850

and LTC

LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 69976 W: 11056 L: 11011 D: 47909

Bench: 8012532

Resolves #340
2015-04-28 22:07:48 +01:00
VoyagerOne b7063ef65b Change extra ply LMR condition to: cmh <= 0 && hist < 0
Extra ply LMR condition is now cmh <= 0 && h < 0
Instead of cmh + h < 0

STC:
LLR: 2.96 (-2.94,2.94) [-1.50,4.50]
Total: 55210 W: 10812 L: 10557 D: 33841

LTC:
LLR: 2.95 (-2.94,2.94) [0.00,4.00]
Total: 13212 W: 2239 L: 2045 D: 8928

Bench: 8420865

Resolves #339
2015-04-26 20:12:25 +01:00
Alain SAVARD 078625e333 Exclude queen from Rook Contact Check computation
In ei.attackedBy, Queen does not x-ray through Rook, but the Rook does
X-ray through the Queen.

So most of the rook contact checks supported by queen are, in fact,
Queen Contact Checks and they are already scored separately.

Bench: 7762189

Resolves #338
2015-04-18 22:17:46 +01:00
lucasart 6c040c821a Retire FORCE_INLINE
No speed regression on my machine (i7-3770k, gcc 4.9.1, linux 3.16):

        stat        test     master   diff
        mean   2,482,415  2,474,987  7,906
        stdev      4,603      5,644  2,497

        speedup        0.32%
        P(speedup>0)  100.0%

Fishtest 9+0.03:

ELO: 0.26 +-1.8 (95%) LOS: 61.2%
Total: 60000 W: 12437 L: 12392 D: 35171

No functional change.

Resolves #334
2015-04-15 21:21:45 +01:00
VoyagerOne 20e92895af Removed extra condition (history < 0) in LMR to help sync up with move ordering.
LMR condition is now cmh+history<0
Instead of history<0 OR cmh+history<0

STC:
LLR: 2.96 (-2.94,2.94) [-3.00, 1.00]
Total: 26446 W: 5092 L: 4980 D: 16374

LTC:
LLR: 2.96 (-2.94,2.94) [-3.00, 1.00]
Total: 14129 W: 2340 L: 2209 D: 9580

Bench: 7815183

Resolves #331
2015-04-12 20:05:59 +01:00
Marco Costalba fb03188fc7 Assorted cleanup of last patches
No functional change.
2015-04-11 23:24:43 +02:00
Marco Costalba a66c73deef Allow Position::init() to be called more than once
Currently Zobrist::castling[] are not properly zeroed
and rely on the compiler to do this at startup, but this
makes Position::init() to set different values every time
it is called!

This is a bit odd, and although not impacting normal usage,
can yield to subtle misbehaviour, very difficult to track
down, in case we happen to call it more than once for some
reason. I found this while developing tuning support and
it took me a while to track it down.

So properly init Zobrist::castling[]

No functional change.

Resolves #329
2015-04-10 20:39:15 +01:00
Stefan Geschwentner 27efc5ac99 Update stats at pv nodes
If a quiet best move is found at a pv node then always update stats.

STC:
LLR: 2.96 (-2.94,2.94) [-1.50,4.50]
Total: 41485 W: 8047 L: 7830 D: 25608

LTC:
LLR: 2.96 (-2.94,2.94) [0.00,6.00]
Total: 14351 W: 2420 L: 2250 D: 9681

Bench: 6985247

Resolves #330
2015-04-10 20:34:55 +01:00
mstembera 36f2133df3 New formula for quiet move scoring: 3 * cmh + 1 * hist
STC

LLR: 2.97 (-2.94,2.94) [-1.50,4.50]
Total: 45363 W: 8759 L: 8532 D: 28072

LTC

LLR: 3.51 (-2.94,2.94) [0.00,4.00]
Total: 125092 W: 20032 L: 19468 D: 85592

Bench: 7058819

Resolves #328
2015-04-10 20:14:11 +01:00
Stefan Geschwentner ef4d89c9bd update stats also in check
Update stats also if in check (drop condition).

STC:
LLR: 3.22 (-2.94,2.94) [-3.00,1.00]
Total: 87472 W: 16929 L: 16913 D: 53630

LTC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 39971 W: 6436 L: 6345 D: 27190

Bench: 7086031

Resolves #327
2015-04-09 20:41:08 +01:00
lucasart aaf17326e2 Prune evasions when we can castle
A minor simplification.

STC:

LLR: 2.95 (-2.94,2.94) [-3.50,0.50]
Total: 67877 W: 12882 L: 12904 D: 42091

STC:

LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 20677 W: 4023 L: 3901 D: 12753

LTC:

LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 12221 W: 2022 L: 1888 D: 8311

Bench: 7911336

Resolves #326
2015-04-09 20:34:06 +01:00
Stéphane Nicolet 2ca142a5b4 Use minimumSplitDepth = 5
Using minimumSplitDepth = 5 seems to be the best compromise in the
current SMP implementation

STC, 11 threads:

ELO: 14.87 +-4.1 (95%) LOS: 100.0%
Total: 8509 W: 1497 L: 1133 D: 5879

STC, 4 threads:

ELO: 0.30 +-2.8 (95%) LOS: 58.2%
Total: 20000 W: 3365 L: 3348 D: 13287

STC, 2 threads:

ELO: -1.02 +-2.0 (95%) LOS: 16.4%
Total: 40000 W: 7087 L: 7204 D: 25709

Resolves #324
2015-04-09 20:32:36 +01:00
Marco Costalba ffbaa1c5a8 Fix MSVC warning from previous patch
No functional change.
2015-04-03 19:29:29 +02:00
Marco Costalba 57dfe41ddb Fix elapsed()
Messed up during merge.

No functional change.
2015-04-03 04:53:53 +02:00
Marco Costalba 926f215061 Add support for playing in 'nodes as time' mode
When running more games in parallel, or simply when running a game
with a background process, due to how OS scheduling works, there is no
guarantee that the CPU resources allocated evenly between the two
players. This introduces noise in the result that leads to unreliable
result and in the worst cases can even invalidate the result. For
instance in SF test framework we avoid running from clouds virtual
machines because are a known source of very unstable CPU speed.

To overcome this issue, without requiring changes to the GUI, the idea
is to use searched nodes instead of time, and to convert time to
available nodes upfront, at the beginning of the game.

When nodestime UCI option is set at a given nodes per milliseconds
(npmsec), at the beginning of the game (and only once), the engine
reads the available time to think, sent by the GUI with 'go wtime x'
UCI command. Then it translates time in available nodes (nodes =
npmsec * x), then feeds available nodes instead of time to the time
management logic and starts the search. During the search the engine
checks the searched nodes against the available ones in such a way
that all the time management logic still fully applies, and the game
mimics a real one played on real time. When the search finishes,
before returning best move, the total available nodes are updated,
subtracting the real searched nodes. After the first move, the time
information sent by the GUI is ignored, and the engine fully relies on
the updated total available nodes to feed time management.

To avoid time losses, the speed of the engine (npms) must be set to a
value lower than real speed so that if the real TC is for instance 30
secs, and npms is half of the real speed, the game will last on
average 15 secs, so much less than the TC limit, providing for a
safety 'time buffer'.

There are 2 main limitations with this mode.

1. Engine speed should be the same for both players, and this limits
the approach to mainly parameter tuning patches.

2. Because npms is fixed while, in real engines, the speed increases
toward endgame, this introduces an artifact that is equivalent to an
altered time management. Namely it is like the time management gives
less available time than what should be in standard case.

May be the second limitation could be mitigated in a future with a
smarter 'dynamic npms' approach.

Tests shows that the standard deviation of the results with 'nodestime'
is lower than in standard TC, as is expected because now all the introduced
noise due the random speed variability of the engines during the game is
fully removed.

Original NIT idea by Michael Hoffman that shows how to play in NIT mode
without requiring changes to the GUI. This implementation goes a bit
further, the key difference is that we read TC from GUI only once upfront
instead of re-reading after every move as in Michael's implementation.

No functional change.
2015-04-03 04:40:55 +02:00
Marco Costalba df722521ba Rename of TimeMgr and friends
More natural naming IMO.

No functional change.
2015-04-03 04:19:29 +02:00
Marco Costalba 5d1b92e8f9 Introduce elapsed_time()
And reformat a bit time manager code.

Note that now we set starting search time in think() and
no more in ThreadPool::start_thinking(), the added delay
is less than 1 msec, so below timer resolution (5msec) and
should not affect time lossses ratio.

No functional change.
2015-04-03 04:19:26 +02:00
mstembera 6661a31541 Simplification to use only one counter move.
STC http://tests.stockfishchess.org/tests/view/5518dca30ebc5902160ec5d0
LLR: 2.95 (-2.94,2.94) [-3.50,0.50]
Total: 18868 W: 3638 L: 3530 D: 11700

LTC http://tests.stockfishchess.org/tests/view/5518f7ed0ebc5902160ec5d4
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 69767 W: 11019 L: 10973 D: 47775

Extracted from http://tests.stockfishchess.org/tests/view/5511028a0ebc5902160ec40b

Original patch by hxim.  All credit goes to him.

Bench: 7664249

Resolves #320
2015-04-03 01:16:15 +08:00
Marco Costalba 6c42575208 Assorted code style of latest commits
No functional chnage.
2015-03-29 10:16:10 +02:00
Joona Kiiski 61a6e46664 Fix indentations for hanging pawns code
No functional change
2015-03-29 08:54:25 +01:00
lucasart 60beb18efc Remove some difficult to understand C++11 constructs
Code like this is more a case of showing off one's C++ knowledge, rather than
using it adequately, IMHO.

**First loop (std::generate)**

Iterators are inadequate here, because they lose the key information which is
idx. As a result, we need to carry a redundant idx variable, and increment it
along the way. Very clumsy.
Usage of std::generate and a lambda function only obfuscate the code, which is
merely a simple and stupid loop over the elements of a vector.

**Second loop (std::accumulate)**

This code is thoroughlly incomprehensible. Restore the original, which was much
simpler to understand.

**Third loop (range based loop)**

Again, a range based loop is inadequate, because we lose idx! To resolve this
artificially created problem, the data model was made redundant (idx is a data
member of db[] elements!?), which is ugly and unjustified. A simple and stupid
for loop with idx does the job much better.

No functional change.

Resolves #313
2015-03-29 08:40:24 +01:00
Alain SAVARD 8463fa479e PSV3_1
Small speed-up in pawn.cpp
Results for 10 tests for each version:

Base      Test      Diff
Mean    1435636   1445238   -9602
StDev   22576     23189     1848

p-value: 1
speedup: 0.007

No functional change

Resolves #295
2015-03-29 07:30:46 +08:00
Ajith 63500274db Give a reduced bonus for threats by hanging pawns
Passed STC:
LLR: 2.96 (-2.94,2.94) [-1.50,4.50]
Total: 105539 W: 20389 L: 20001 D: 65149

and LTC:
LLR: 2.95 (-2.94,2.94) [0.00,6.00]
Total: 9629 W: 1577 L: 1432 D: 6620

Bench: 7658627

Resolves #317
2015-03-29 07:28:47 +08:00
mbootsector 1d5eaba573 Retire follow-up move heuristic
STC: http://tests.stockfishchess.org/tests/view/5501d0f30ebc5902160ec0fd
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 34891 W: 6904 L: 6808 D: 21179

LTC: http://tests.stockfishchess.org/tests/view/550328540ebc5902160ec133
LLR: 3.10 (-2.94,2.94) [-3.00,1.00]
Total: 182653 W: 29866 L: 29993 D: 122794

Bench: 8396161

Resolves #310
2015-03-28 22:12:06 +00:00
VoyagerOne ac8e6ff000 Use CounterMoveHistory when calculating LMR for cut nodes
If the sum of CounterMoveHistory heuristic and History heuristic is below zero,
then reduce an extra ply in cut nodes

LTC:
LLR: 2.96 (-2.94,2.94) [0.00,6.00]
Total: 6479 W: 1099 L: 967 D: 4413

Bench: 7773299

Resolves #315
2015-03-28 21:15:49 +00:00
Marco Costalba 3a6753328c Clean up previous patch
No functional change.
2015-03-25 07:05:27 +01:00
joergoster 50182f1100 Tuned values for the pawn piece square table
Quick measure at very fast tc:
ELO: 4.77 +-2.2 (95%) LOS: 100.0%
Total: 40124 W: 8711 L: 8160 D: 23253

LTC:
LLR: 2.95 (-2.94,2.94) [0.00,4.00]
Total: 52284 W: 8880 L: 8559 D: 34845

Bench: 8865736

Resolves #311
2015-03-25 07:39:44 +08:00
VoyagerOne e51965aa57 Introduce a new counter move history penalty
Extra penalty for TT move in previous ply when it gets refuted

STC:

LLR: 2.94 (-2.94,2.94) [-1.50,4.50]
Total: 31303 W: 6216 L: 6025 D: 19062

LTC:

LLR: 2.97 (-2.94,2.94) [0.00,6.00]
Total: 6950 W: 1189 L: 1054 D: 4707

Bench: 8191926

Resolves #309
2015-03-24 23:04:08 +00:00
Joona Kiiski a7381d5e81 Fully yielding locks, no spinning
7 threads:

ELO: 2.00 +-2.7 (95%) LOS: 92.4%
Total: 20000 W: 3276 L: 3161 D: 13563

There is no functional change in single thread mode

Resolves #304
2015-03-24 21:34:19 +00:00
Marco Costalba dc3a5f791e Allow Bitbases::init() to be called more than once
Currently if we call it more than once, we crash.

This is not a real problem, because this function is
indeed called just once. Nevertheless with this small fix,
that gets rid of a hidden 'static' variable, we cleanly
resolve the issue.

While there, fix also ThreadPool::exit to return in a
consistent state. Now all the init() functions but
UCI::init() are reentrant and can be called multiple
times.

No functional change.
2015-03-23 17:14:31 +01:00
Marco Costalba 35a082064f Double magics generation speed
Profiling shows that resetting attacks table after
a failed candidate magic attempt is the biggest
time consumer, so rewrite the logic avoiding the
memset()

Magics init for rook+bishop goes from 200msecs to
under 100msec.

No functional change.
2015-03-23 17:10:38 +01:00
Marco Costalba be77406a55 Get rid of nativeThread
No functional change.
2015-03-23 09:02:52 +01:00
Marco Costalba 26dabb1e6b Use only one ConditionVariable to sync UI
To sync UI with main thread it is enough a single
condition variable because here we have a single
producer / single consumer design pattern.

Two condition variables are strictly needed just for
many producers / many consumers case.

Note that this is possible because now we don't send to
sleep idle threads anymore while searching, so that now
only UI can wake up the main thread and we can use the
same ConditionVariable for both threads.

The natural consequence is to retire wait_for_think_finished()
and move all the logic under MainThread class, yielding the
rename of teh function to join()

No functional change.
2015-03-21 07:55:33 +01:00
lucasart 35b6079852 Fix comment
We always probe, but we do not prune at PV nodes.

No functional change.

Resolves #300
2015-03-20 22:40:03 +00:00
Marco Costalba ebf3735754 Retire ConditionVariable
Now that we use spinlocks everywhere and don't put
threads to sleep while idle, we can use the slower
(but no more in hot path) std::condition_variable_any
instead of our homwgrown ConditionVariable struct.

Verified fo rno regression at STC with 7 threads:
ELO: -0.66 +-2.7 (95%) LOS: 31.8%
Total: 20000 W: 3210 L: 3248 D: 13542

No functional change
2015-03-20 03:05:25 +01:00
joergoster 966bc477af Tuned mobility with another SPSA run
Further improved mobility values after another SPSA session, 50k
iterations.

Elo measure at very fast 9+0.05":
ELO: 3.40 +-2.2 (95%) LOS: 99.9%
Total: 40000 W: 8434 L: 8042 D: 23524

and LTC SPRT[0, 4]:
LLR: 2.95 (-2.94,2.94) [0.00,4.00]
Total: 11052 W: 1874 L: 1687 D: 7491

Bench: 8226843

Resolves #301
2015-03-20 08:08:21 +08:00
joergoster c6f987d1ad Fix the comment for Position::is_draw()
We no longer check for insufficient material.

No functional change

Resolves #299
2015-03-18 20:30:50 +00:00
lucasart d477a0d611 connected should be bool, not Bitboard
There's no reason to define it as a Bitboard, so for consistency, use bool.

This is even a speedup on my machine: i7-3770k, using gcc 4.9.1 (linux):

    stat        test     master    diff
    mean   2,341,338  2,327,998  13,134
    stdev     15,765     14,717   5,405

    speedup       0.56%
    P(speedup>0) 100.0%

No functional change.

Resolves #298
2015-03-18 20:21:41 +00:00
Marco Costalba 54889618c2 Reformat FastMove
Align to SF coding style.

Verified no regression:

LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 55938 W: 10893 L: 10835 D: 34210

No functional change.
2015-03-18 08:12:59 +01:00
Marco Costalba 9a6cfee73b Simplify nosleep logic
Avoid redundant 'while' conditions. It is enough to
check them in the outer loop.

Quick tested for no regression 10K games at 4 threads
ELO: -1.32 +-3.9 (95%) LOS: 25.6%
Total: 10000 W: 1653 L: 1691 D: 6656

No functional change.
2015-03-18 08:01:50 +01:00
Marco Costalba 2e8552db76 Fix a bogus use of mutex
Spinlock must be used instead.

Tested for no regression at 15+0.05 th 4:

LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 25928 W: 4303 L: 4190 D: 17435

No functional change.

Resolves #297
2015-03-17 08:19:29 +00:00
Marco Costalba a4b2eeea75 Re-arrange history update code
Unify the quites moves loop for both cases,
the compiler optimizes away the

 if (is_ok((ss-1)->currentMove))

inside loop, so that the result is same
speed as original.

No functional change.
2015-03-16 15:14:09 +01:00
Marco Costalba 13d4df95cd Use acquire() and release() for spinlocks
It is more idiomatick than lock() and unlock()

No functional change.
2015-03-16 08:14:08 +01:00
Vince Negri bae4679de2 Fix dependency generation for MacOSX
No functional change

Resolves #290
2015-03-15 20:31:43 +00:00
Joona Kiiski a3943b2aa7 Fix dependency generation for C++11
No functional change

Resolves #291
2015-03-15 20:26:08 +00:00
Joona Kiiski f04f50b368 Do not sleep, but yield
During the search, do not block on condition variable, but instead use std::this_thread::yield().

Clear gain with 16 threads. Again results vary highly depending on hardware, but on average it's a clear gain.

ELO: 12.17 +-4.3 (95%) LOS: 100.0%
Total: 7998 W: 1407 L: 1127 D: 5464

There is no functional change in single thread mode

Resolves #294
2015-03-15 19:45:30 +00:00
joergoster a4b98a052e New values for Mobility and Outposts.
Both are the result of a SPSA tuning session with a custom book, 50k iterations each.

After an additional tuning session of the mobility values, tuning the delta values, with following result.

40k games at 9+0.05:
ELO: 4.13 +-2.2 (95%) LOS: 100.0%
Total: 40000 W: 8581 L: 8106 D: 23313

and LTC
LLR: 2.95 (-2.94,2.94) [0.00,4.00]
Total: 36518 W: 6049 L: 5782 D: 24687

Bench: 8567402

Resolves #284
2015-03-14 21:35:52 +00:00
Marco Costalba e5da0e4b79 Link with -static in mingw
Fixes reported startup error about missing libwinpthread-1.dll
when the dll is not in the path.

The current -static-xxxx flags, introduced with:

https://github.com/official-stockfish/Stockfish/commit/373503f4a9a990054b5

Only take in account standard libraries, but not thread
library.

No functional change.

Resolves #289
2015-03-14 19:23:54 +00:00
Joona Kiiski d71f707040 Introduce yielding spin locks
Idea and original implementation by Stephane Nicolet

7 threads 15+0.05
ELO: 3.54 +-2.9 (95%) LOS: 99.2%
Total: 17971 W: 2976 L: 2793 D: 12202

There is no functional change in single thread mode
2015-03-14 19:14:52 +00:00
Joona Kiiski 558b0c848c Remove check for gcc version from Makefile.
This check is obsolete.
very old gcc versions can't compile c++11 code.

No functional change

Resolves #285
2015-03-13 20:29:28 +00:00
mstembera 062ca91db5 New easy move implementation
Spend much less time in positions where one move is much better than all other alternatives.
We carry forward pv stability information from the previous search to identify such positions.
It's based on my old InstaMove idea but with two significant improvements.

1) Much better instability detection inside the search itself.
2) When it's time to make a FastMove we no longer make it instantly but still spend at least 10% of normal time verifying it.

Credit to Gull for the inspiration.
BIG thanks to Gary because this would not work without accurate PV!

20K
ELO: 8.22 +-3.0 (95%) LOS: 100.0%
Total: 20000 W: 4203 L: 3730 D: 12067

STC
LLR: 2.96 (-2.94,2.94) [-1.50,4.50]
Total: 23266 W: 4662 L: 4492 D: 14112

LTC
LLR: 2.95 (-2.94,2.94) [0.00,6.00]
Total: 12470 W: 2091 L: 1931 D: 8448

Resolves #283
2015-03-12 19:49:30 +00:00
Stefan Geschwentner 13c11f4048 Introduce Counter Move History tables
Introduce a counter move history table which additionally is indexed by the last move's piece and target square.
For quiet move ordering use now the sum of standard and counter move history table.

STC:
LLR: 2.96 (-2.94,2.94) [-1.50,4.50]
Total: 4747 W: 1005 L: 885 D: 2857

LTC:
LLR: 2.95 (-2.94,2.94) [0.00,6.00]
Total: 5726 W: 1001 L: 872 D: 3853

Because of reported low NPS on multi core test
STC (7 threads):
ELO: 7.26 +-3.3 (95%) LOS: 100.0%
Total: 14937 W: 2710 L: 2398 D: 9829

Bench: 7725341

Resolves #282
2015-03-12 07:29:57 +00:00
Joona Kiiski 81c7975dcd Use thread specific mutexes instead of a global one.
This is necessary to improve the scalability with high number of cores.

There is no functional change in a single thread mode.

Resolves #281
2015-03-11 21:59:34 +00:00
Marco Costalba 4b59347194 Retire spinlocks
Use Mutex instead.

This is in preparaation for merging with master branch,
where we stilll don't have spinlocks.

Eventually spinlocks will be readded in some future
patch, once c++11 has been merged.

No functional change.
2015-03-11 21:20:47 +01:00
Marco Costalba 6027652773 Cleanup thread_win.h
No functional change.
2015-03-10 17:13:52 +01:00
Marco Costalba 04372316b3 Disable spinlocks
To allow testing on fishtest.

No functional change.
2015-03-10 12:47:49 +01:00
Marco Costalba 8725494966 Add thread_win32.h header
Workaround slow std::thread implementation in mingw
and gcc for Windows with our own old low level thread
functions.

No functional change.
2015-03-10 12:42:40 +01:00
Marco Costalba be50952533 Sync with master
bench: 8285241
2015-03-07 10:56:01 +01:00
Marco Costalba e53774bc49 Sync with master
No functional change.
2015-03-07 10:45:58 +01:00
hxim 3017e8c604 Transform minKingPawnDistance into a local variable
minKingPawnDistance is used only as local variable in one place so we don't need it to be part of "Pawns::Entry" structure.

No functional change.

Resolves #277
2015-03-07 09:03:19 +00:00
Stéphane Nicolet 8fcaa78a04 Update Makefile for Mac OS X compilation
This change in the Makefile restores the possibility to compile
Stockfish on Mac OS X 10.9 and 10.10 after the C++11 has been merged.

To use the default (fastest) settings, compile with:

make build ARCH=x86-64-modern

To test the clang settings, compile with

make build ARCH=x86-64-modern COMP=clang

Beware that the clang settings may provide a slightly slower (6%)
executable.

Backported from master.

No functional change

Resolves #275
2015-03-07 08:39:21 +01:00
Marco Costalba a590d1d52d Re-enable spinlocks
For branch C++11, that doe snot run on fishtest,
there is no need of this kludge, let only master
have it.

No functional change.
2015-03-07 08:38:26 +01:00
Joona Kiiski 856a5f3aaa Revert C++11 merge
Restore the state of repo back to commit 'Simplify pawn code a bit' (1e6d21dbb6)

No functional change
2015-03-07 07:38:22 +00:00
Stéphane Nicolet 6fa6da3ee1 Update Makefile for Mac OS X compilation
This change in the Makefile restores the possibility to compile
Stockfish on Mac OS X 10.9 and 10.10 after the C++11 has been merged.

To use the default (fastest) settings, compile with:

make build ARCH=x86-64-modern

To test the clang settings, compile with

make build ARCH=x86-64-modern COMP=clang

Beware that the clang settings may provide a slightly slower (6%)
executable.

No functional change

Resolves #275
2015-03-05 04:18:59 +00:00
Marco Costalba cb2111f0b6 Disable spinlocks
Now that c++11 branch has been merged in master,
disable unconditionally the spinlocks and use mutex
instead. This will allow to run fishtest even on HT
machines withouth changes.

In the future we will reintorduce spinlocks, once
we will have took care of fishtest.

No functional change.
2015-03-02 08:11:39 +01:00
Marco Costalba 6645115377 Allow to disable spinlocks
And use mutex instead. You may never want to do this.
It is a workaround to run c++11 on fishtest where many
machiens have HTenabled and this can be a problem when
number of cores set is higher than number of physical cores.

To disable spinlocks, just compile with -DNO_SPINLOCK flag

No functional change.
2015-03-01 17:16:05 +01:00
Marco Costalba 63a5fc2366 Rename available_to()
Change this API to be more natural and simple.

Inspired by a patch by Joona.

No functional change.
2015-03-01 12:33:05 +01:00
Marco Costalba 0da7295795 Sync with master
bench: 8285241
2015-02-28 20:22:28 +01:00
Stéphane Nicolet 1e6d21dbb6 Simplify pawn code a bit
Simplify a bit the number of bitwise operators used to calculate the
pawn evaluation in pawns.cpp

No functional change.

Resolves #269
2015-03-01 01:01:37 +08:00
Stéphane Nicolet 9369f4963d Raise penalty for knight attacked by pawn
Raise a bit the penalty for knight attacked by pawn.

STC:
LLR: 2.97 (-2.94,2.94) [-1.50,4.50]
Total: 27744 W: 5563 L: 5380 D: 16801

LTC:
LLR: 2.96 (-2.94,2.94) [0.00,4.00]
Total: 87571 W: 14747 L: 14314 D: 58510

Bench: 8285241

Resolves #270
2015-03-01 00:58:32 +08:00
Marco Costalba a459709fcc Retire apply_weight()
Use the more natural operator*() instead.

No functional change.
2015-02-27 10:38:12 +01:00
Marco Costalba 2dbb1adf2a Sync with master
bench: 8069601
2015-02-26 20:50:39 +01:00
Marco Costalba 8a2c4134a6 Normalize twice supported pawns
Align codying style to current conventions and move
formula for twice supported pawns to Pawns::init()
where it should be.

No functional change.
2015-02-27 01:56:16 +08:00
Alain SAVARD fce799294c Apex Pawns
Pawns which are supported already have a bonus. Apex are pawns which are
supported twice.
This patch gives an additional 50% bonus for them.

STC
LLR: 2.96 (-2.94,2.94) [-1.50,4.50]
Total: 6549 W: 1333 L: 1209 D: 4007

LTC
LLR: 2.95 (-2.94,2.94) [0.00,6.00]
Total: 18002 W: 3037 L: 2850 D: 12115

Bench: 8069601

Resolves #267
2015-02-27 01:52:23 +08:00
Marco Costalba 0b36ba74fc Don't assume the type of Time::point
But instead use the proper definition. Also
rewrite chrono functions while there.

No functional change.
2015-02-24 14:08:14 +01:00
Marco Costalba 153fb216a1 Small tweaks in pawns.cpp
No functional change.
2015-02-24 11:45:29 +01:00
Marco Costalba d3d26a94b3 Improve spinlock implementation
Calling lock.test_and_set() in a tight loop creates expensive
memory synchronizations among processors and penalize other
running threads. So syncronize only only once at the beginning
with fetch_sub() and then loop on a simple load() that puts much
less pressure on the system.

Reported about 2-3% speed up on various systems.

Patch by Ronald de Man.

No functional change.
2015-02-23 19:48:46 +01:00
Marco Costalba 38112060dc Use spinlock instead of mutex for Threads and SplitPoint
It is reported to be defenitly faster with increasing
number of threads, we go from a +3.5% with 4 threads
to a +15% with 16 threads.

The only drawback is that now when testing with more
threads than physical available cores, the speed slows
down to a crawl. This is expected and was similar at what
we had setting the old sleepingThreads to false.

No functional change.
2015-02-23 13:47:07 +01:00
Marco Costalba 775f8239d3 Introduce Spinlock class
Initialization is more complex than what I'd like due
to MSVC compatibility that for some reason does not like:

std::atomic_flag lock = ATOMIC_FLAG_INIT;

No functional change.
2015-02-23 13:37:46 +01:00
Marco Costalba 098f645d26 Sync with master
bench: 8253813
2015-02-23 13:36:15 +01:00
Marco Costalba 29ff925fd8 Fix build under OS X
Reported by Vince Negri

No functional change.
2015-02-22 16:33:24 +01:00
Marco Costalba 8d16111ffd Sync with master
bench: 8253813
2015-02-22 14:20:23 +01:00
Marco Costalba e2226cbb20 Use only 'level' as late join metric
It seems other metric are useless, this allow us
to simplify the code and to prune useless stuff.

STC 20K games 4 threads
ELO: -0.76 +-2.8 (95%) LOS: 29.9%
Total: 20000 W: 3477 L: 3521 D: 13002

STC 10K games 16 threads
ELO: 1.36 +-3.9 (95%) LOS: 75.0%
Total: 10000 W: 1690 L: 1651 D: 6659

bench: 8253813
2015-02-22 12:59:34 +01:00
Marco Costalba 5fd5453e59 Further refine SMP code
Backported from C++11 branch:

https://github.com/official-stockfish/Stockfish/commit/7ff965eebfbc17d2b
https://github.com/official-stockfish/Stockfish/commit/e74c2df907d5336d3d2b

Fully verified it is equivalent to master (see log msg
of individual commits for details).

No functional change.
2015-02-21 11:33:03 +01:00
Marco Costalba e74c2df907 Use sp->master instead of bestThread
Verified with:

dbg_hit_on(th != sp->master);

It is 100% equivalent on more than 200K hits.

No functional change.
2015-02-21 10:40:59 +01:00
Stéphane Nicolet 41ccc885ec Fix comment for kingAdjacentZoneAttacksCount
The comment for kingAdjacentZoneAttacksCount[] was bogus, using
reversed semantics for color.

No functional change

Resolves #262
2015-02-20 19:59:26 +00:00
snicolet 2f46592736 Mobile phalanxes
Try to create mobile phalanxes

STC:
LLR: 2.97 (-2.94,2.94) [-1.50,4.50]
Total: 52393 W: 10912 L: 10656 D: 30825

LTC:
LLR: 2.96 (-2.94,2.94) [0.00,6.00]
Total: 30398 W: 5315 L: 5063 D: 20020

Bench: 8253813

Resolves #261
2015-02-20 19:56:57 +00:00
Marco Costalba 7ff965eebf Improve comments in SMP code
No functional change.
2015-02-20 12:38:54 +01:00
Marco Costalba a6f873cd8d Use range-based-for in late join
No functional change.
2015-02-20 10:50:47 +01:00
Marco Costalba 40548c9153 Sync with master
bench: 7911944
2015-02-20 10:37:29 +01:00
Marco Costalba 667f350737 Clarify we don't late join with only 2 threads
Thanks to Gary for pointing this out.

No functional change.
2015-02-19 23:12:59 +01:00
Marco Costalba 950c8436ed Use size_t consistently across thread code
No functional change.
2015-02-19 10:43:28 +01:00
Marco Costalba 8d47caa16e Retire redundant sp->slavesCount field
It should be used slavesMask.count() instead.

Verified 100% equivalent when sp->allSlavesSearching:

dbg_hit_on(sp->allSlavesSearching, sp->slavesCount != sp->slavesMask.count());

No functional change.
2015-02-19 10:36:15 +01:00
Marco Costalba b9d4e6f7fd Fix a warning under MSVC
Assignment of size_t to int.

No functional change.
2015-02-19 10:18:24 +01:00
Marco Costalba 193a7ae35b Add a couple of asserts to late join
Document and clarify that we cannot rejoin on ourselves
and that we never late join if we are master and all
slaves have finished, inded in this case we exit idle_loop.

No functional change.
2015-02-19 10:08:29 +01:00
Marco Costalba 4f906a2589 Remove useless condition in late join
In case of Threads.size() == 2 we have that sp->allSlavesSearching
is always false (because we have finished our search), bestSp is
always NULL and we never late join, so there is no need to special
case here.

Tested with dbg_hit_on(sp && sp->allSlavesSearching) and
verified it never fires.

No functional change.
2015-02-19 09:53:39 +01:00
Marco Costalba dccaa145d2 Compute SplitPoint::spLevel on the fly
And retire a redundant field. This is important also
from a concept point of view becuase we want to keep
SMP structures as simple as possible with the only
strictly necessary data.

Verified with

dbg_hit_on(sp->spLevel != level)

that the values are 100% the same out of more 50K samples.

No functional change.
2015-02-18 21:50:35 +01:00
Marco Costalba 6656ed8904 Simplify attackUnits formula
Use '/ 8' instead of '* 31 / 256'

Passed STC
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 55077 W: 10999 L: 10940 D: 33138

And LTC
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 14751 W: 2530 L: 2400 D: 9821

bench: 7911944
2015-02-17 08:23:35 +01:00
Joona Kiiski d65f75c153 Improve smp performance for high number of threads
Balance threads between split points.

There are huge differences between different machines and autopurging makes it very difficult to measure the improvement in fishtest, but the following was recorded for 16 threads at 15+0.05:

    For Bravone (1000 games): 0 ELO
    For Glinscott (1000 games): +20 ELO
    For bKingUs (1000 games): +50 ELO
    For fastGM (1500 games): +50 ELO

The change was regression for no one, and a big improvement for some, so it should be fine to commit it.
Also for 8 threads at 15+0.05 we measured a statistically significant improvement:
ELO: 6.19 +-3.9 (95%) LOS: 99.9%
Total: 10325 W: 1824 L: 1640 D: 6861

Finally it was verified that there was no (significant) regression for

4 threads:
ELO: 0.09 +-2.8 (95%) LOS: 52.4%
Total: 19908 W: 3422 L: 3417 D: 13069

2 threads:
ELO: 0.38 +-3.0 (95%) LOS: 60.0%
Total: 19044 W: 3480 L: 3459 D: 12105

1 thread:
ELO: -1.27 +-2.1 (95%) LOS: 12.3%
Total: 40000 W: 7829 L: 7975 D: 24196

Resolves #258
2015-02-16 20:36:13 +00:00
lucasart f8f5dcbb68 Compute checkers from scratch
This micro-optimization only complicates the code and provides no benefit.
Removing it is even a speedup on my machine (i7-3770k, linux, gcc 4.9.1):

stat        test     master    diff
mean   2,403,118  2,390,904  12,214
stdev     12,043     10,620   3,677

speedup       0.51%
P(speedup>0) 100.0%

No functional change.
2015-02-16 09:34:26 +08:00
Marco Costalba 686b45e121 Retire one do_move() overload
After Lucas patch it is almost useless.

No functional change.
2015-02-15 12:23:03 +01:00
lucasart dc13004283 Compute checkers from scratch
This micro-optimization only complicates the code and provides no benefit.
Removing it is even a speedup on my machine (i7-3770k, linux, gcc 4.9.1):

stat        test     master    diff
mean   2,403,118  2,390,904  12,214
stdev     12,043     10,620   3,677

speedup       0.51%
P(speedup>0) 100.0%

No functional change.
2015-02-15 12:11:05 +01:00
Marco Costalba 901bfb1f55 Revert "Delayed killers checking"
It seems a slowdown when run with fishbench.

No functional change.
2015-02-15 11:32:53 +01:00
Marco Costalba 20a5c07472 Further simplify KingDanger init
And remove a tale whitespace while there.

No functional change.
2015-02-14 15:56:54 +01:00
Marco Costalba e38eb2302d Further simplify KingDanger init
And remove a tale whitespace while there.

No functional change.
2015-02-14 15:55:11 +01:00
Marco Costalba 0af24a1445 Sync with master
Bench: 7369224
2015-02-14 15:30:16 +01:00
snicolet a8f9c7a790 Small bonus for all safe pawn pushes
Pawn flexibility: add a small bonus for all safe pawn pushes

STC:
LLR: 2.70 (-2.94,2.94) [-1.50,4.50]
Total: 18233 W: 3705 L: 3557 D: 10971

LTC:
LLR: 2.97 (-2.94,2.94) [0.00,6.00]
Total: 17684 W: 3042 L: 2854 D: 11788

Bench: 7369224

Resolves #253
2015-02-13 21:33:00 +00:00
Marco Costalba c0a80afe89 Reformat tracing functions
No functional change.
2015-02-13 11:54:46 +01:00
hxim 44a571c1c7 Fix KingDanger[] array initialization
Use integer arithmetic instead of floating point arithmetic.
Floating point arithmetic was causing different results for some 32-bit compiles

No functional change

Resolves #249
Resolves #250
2015-02-09 22:02:35 +00:00
Marco Costalba ce8ac7997c Sync with master
bench: 7699138
2015-02-08 21:32:14 +01:00
Joona Kiiski e118570038 Pawn Center Bind Bonus
Bonus for two pawns controlling the same central square

STC:

LLR: 3.14 (-2.94,2.94) [-1.50,4.50]
Total: 15974 W: 3291 L: 3133 D: 9550

LTC:

LLR: 3.24 (-2.94,2.94) [0.00,6.00]
Total: 10449 W: 1837 L: 1674 D: 6938

Idea from Lyudmil Tsvetkov.

Bench: 7699138

Resolves #248
2015-02-08 19:28:01 +00:00
Marco Costalba 8f10f6c9cd Shuffle put_piece() and friends signatures
It is more consistent with the others member functions.

No functional change.
2015-02-08 18:17:08 +01:00
Marco Costalba 3184852bdc Small tweaks in do_move and friends
Also remove useless StateCopySize64 optimization:
compiler uses SSE movups instruction anyhow and
does not need this trick (verified with fishbench).

No functional change.
2015-02-08 13:09:29 +01:00
Marco Costalba 99c9cae586 Avoid casting to char* in prefetch()
Funny enough, gcc __builtin_prefetch() expects
already a void*, instead Windows's _mm_prefetch()
requires a char*.

The patch allows to remove ugly casts from caller
sites.

No functional change.
2015-02-07 19:13:41 +01:00
Marco Costalba 152a4dc5cd Rewrite pos_is_ok()
No functional change.
2015-02-07 15:02:28 +01:00
Marco Costalba 47a0768102 Micro-optimize SEE
Results for 10 tests for each version (gcc 4.8.3 on mingw):

            Base      Test      Diff
    Mean    1502447   1507917   -5470
    StDev   3119      1364      4153

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

Results for 10 tests for each version (MSVC 2013):

            Base      Test      Diff
    Mean    1400899   1403713   -2814
    StDev   1273      2804      2700

p-value: 0,851
speedup: 0,002

No functional change.
2015-02-07 12:21:39 +01:00
Marco Costalba 170bdf40cd Rename dbg_hit_on_c() to dbg_hit_on()
Use an overload instead of a new named function.

I have found this handier and easier when adding
some quick debug code.

No functional change.
2015-02-07 11:18:06 +01:00
Marco Costalba 8b0fee9998 Rename dbg_hit_on_c() to dbg_hit_on()
Use an overload instead of a new named function.

I have found this handier and easier when adding
some quick debug code.

No functional change.
2015-02-07 11:15:38 +01:00
Marco Costalba 1277a42823 Sync with master
bench: 7696257
2015-02-07 10:32:28 +01:00
lucasart 35aa21c1fe Removes useless templates, some of which lead to code duplication: is_K*() functions.
No functional change

Resolves #245
2015-02-07 09:12:04 +00:00
Stefan Geschwentner 18b0809639 Add bonus for pawn attack threats
Latent pawn attacks: Add a bonus to safe pawn pushes which attacks an
enemy piece.  Based on an idea of Lyudmil Tsvetkov.

STC:
LLR: 2.95 (-2.94,2.94) [-1.50,4.50]
Total: 7925 W: 1666 L: 1537 D: 4722

LTC:
LLR: 2.95 (-2.94,2.94) [0.00,6.00]
Total: 40109 W: 6841 L: 6546 D: 26722

Bench: 7696257

Resolves #240
2015-02-03 11:19:33 +08:00
mstembera f4136c5434 Profile build options
I went through all the individual compile options that differ between
-fprofile-generate/-fprofile-use  and  -fprofile-arcs/-fbranch-probabilities
and distilled the speed difference down to only turning off
-fno-peel-loops and -fno-tracer.  Using this we still get the full speedup
(maybe a bit more because other optimizations stay on) and it's also much cleaner
because we can get rid of the "@rm -f ucioption.gc*" hack for all versions of gcc.

No functional change.

Resolves #237
2015-02-03 11:09:37 +08:00
NicklasPersson ddccb5355c Improved King Safety values
From an SPSA-session on king safety.

STC:
ELO: 3.21 +-2.1 (95%) LOS: 99.8%
Total: 40000 W: 8181 L: 7812 D: 24007

LTC:
LLR: 2.95 (-2.94,2.94) [0.00,4.00]
Total: 47765 W: 8091 L: 7785 D: 31889

Bench: 8589262

Resolves #241
2015-02-03 04:00:52 +08:00
Marco Costalba 1c7a727795 Use move assignment in movegen.h
No functional change and same speed (tested with perft)
2015-02-01 16:42:31 +01:00
Marco Costalba e56e5045dd Allow to assign a Move to an ExtMove
After defining ExtMove::operator Move(), this is a
natural extension.

No fnctional change.
2015-02-01 13:31:49 +01:00
Marco Costalba 20d6a8e57f Delay checking for duplicated killer moves
Follow the usual approach to delay computation
as far as possible, in case an earlier killer
cut-offs we avoid to do useless work.

This also greatly simplifies the code.

No functional change.
2015-02-01 13:17:42 +01:00
Marco Costalba 0dc6f16992 Small tweaks in movepick.cpp
No functional change.
2015-02-01 12:01:35 +01:00
Marco Costalba 21120288a3 Silence a warning under MSVC
warning C4100: 'ci' : unreferenced formal parameter

It is a silly and wrong one, but just silent it.

No functional change.
2015-02-01 10:40:22 +01:00
Marco Costalba 519b2fe849 More readable score<CAPTURES>()
No functional change.
2015-01-31 20:13:38 +01:00
Marco Costalba f3189bdc9a Use C++11 loops in MovePicker
No functional change.
2015-01-31 20:02:08 +01:00
Marco Costalba 65f46794af Implicit conversion from ExtMove to Move
Verified with perft there is no speed regression,
and code is simpler. It is also conceptually correct
becuase an extended move is just a move that happens
to have also a score.

No functional change.
2015-01-31 19:22:07 +01:00
Marco Costalba 81d6c4a0d6 Another small tweak to skills
No functional change.
2015-01-31 18:24:39 +01:00
Marco Costalba 60c121f3b1 Sync with master
bench: 7374604
2015-01-31 13:05:51 +01:00
Marco Costalba 45eac9507c Use C++ loops in insert_pv_in_tt
Also small tweak to extract_ponder_from_tt

No functional change.
2015-01-31 12:57:52 +01:00
Marco Costalba bfd0f95f06 Move uci_pv under UCI namespace
That's the correct place.

No functional change.
2015-01-31 12:18:24 +01:00
Marco Costalba 1b947aafbf Convert Reductions[] from int8_t to Depth
This is the type anyhow. Assorted cleanup while there.

No functional change.
2015-01-31 11:44:35 +01:00
Marco Costalba a7592e69d7 Fix a MSVC warning
warning C4805: '|' : unsafe mix of type 'Bitboard' and type 'bool' in operation

No functional change.
2015-01-31 10:19:00 +01:00
Jean-Francois Romang a3b4e9e23c Ressurrect hashfull patch
This is an old patch from Jean-Francois Romang to send
UCI hashfull info to the GUI:
https://github.com/mcostalba/Stockfish/pull/60/files

It was wrongly judged as a slowdown, but it takes much
less than 1 ms to run, indeed on my core i5 2.6Ghz it
takes about 2 microsecs to run!

Regression test is good:

STC
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 7352 W: 1548 L: 1401 D: 4403

LTC
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 61432 W: 10307 L: 10251 D: 40874

I have set the name of the author to the original
one.

No functional change.
2015-01-30 18:07:20 +01:00
Marco Costalba f6f1d24223 Sync with master
bench: 7374604
2015-01-30 17:58:18 +01:00
Marco Costalba ce0a95c2c0 Simplify skill level and reduce ELO
This patch has two positive effects:

- Retire a hackish formula and leave
  just a natural, simple and plain one.

- Reduce strenght at very low level, but
  don't impact medium/high levels.

Actually even at level 0, SF is still too
strong for many beginners (this was reported
many times for instance on Droidfish user
comments on Google Play).

Test on fishtest shows that ELO drop is around
170 ELO at level 0 (good!), 130 ELO at level 1
and smoothly reduces (as expected) until level
10 where the drop is just of 8 ELO.

No functional change.
2015-01-29 22:35:24 +01:00
Alain SAVARD 8aa8608c2a Simplify backward pawn definition
Make use of 'lever' attribute

No functional change

Resolves #234
2015-01-28 21:29:04 +00:00
NicklasPersson 7837fb2aca King safety tuning with values obtained by SPSA.
Part I:

LTC:

LLR: 2.96 (-2.94,2.94) [0.00,4.00]
Total: 11529 W: 2075 L: 1882 D: 7572

Part II:

LTC:

ELO: 2.07 +-2.1 (95%) LOS: 97.3%
Total: 34859 W: 5967 L: 5759 D: 23133

Bench: 7374604

Resolves #228
2015-01-28 21:05:21 +00:00
Joona Kiiski 9f0d5241bf Restore development version
No functional change
2015-01-28 20:53:50 +00:00
Marco Costalba 14f7d9a629 Re-arrange Skill struct
Instead of swapping sub-optimal move in Skill
d'tor, make it explicitly at the end of the search.

Also streamline and clarify relation with multiPV
and pass it directly instead of relying on the hacky
'candidates' member.

No functional change.
2015-01-25 11:16:54 +01:00
Marco Costalba 69407ae9b8 Additional work in bitbases
Verified the generated bitbases are unchanged.

No functional change.
2015-01-24 09:29:35 +01:00
Marco Costalba 18375e3bfb Rearrange bitbases C++11 way
No functional change.
2015-01-22 11:05:31 +01:00
Marco Costalba 6390a3da94 Document how to enable PEXT with MSVC
When not using Makefile, e.g. with MSVC, if hardware
supports BMI2 instructions, then USE_PEXT should be
added in project configuration to enable pext support.

No functional change.
2015-01-21 19:54:15 +01:00
Marco Costalba 36f8814aa6 Rearrange Endgames
Remove references to EndgameBase and use instead
Value and ScaleFactor as template parameters of
the endgames maps.

No functional change.
2015-01-21 17:35:53 +01:00
Marco Costalba 96e36a7897 Explicitly defaulted and deleted members
Better than a bit obscure implicit ones.

No functional change.
2015-01-21 13:18:19 +01:00
Marco Costalba 2ca2c3f35b Fun with lambdas
Use lambda functions instead of has_positive_value()
and toggle_case()

No functional change.
2015-01-21 11:33:53 +01:00
Marco Costalba f54c44e6be 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.
2015-01-20 22:17:22 +01:00
Marco Costalba ca3622f8e8 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.

No functional change.
2015-01-19 08:11:43 +01:00
Marco Costalba 712bbb052e Fix compile error with MSVC 2013
Without this std::min chokes with windows 'min' macro.

No functional change.
2015-01-18 15:14:05 +01:00
Marco Costalba fe4fda474f Fun with initializer lists in UCI::square
No functional change.
2015-01-18 11:04:51 +01:00
Marco Costalba f7d8ea3866 Fix a coverity scan warning
Coverity scan warns about uninitialized 'sf' argument when
calling probe(). Actually it is a false positive because
argument is passed by reference and assigned inside
probe(). Nevertheless it is a hint that fucntion signature
is a bit tricky, so rewrite it in a more conventional way,
assigning 'sf' from probe() return value.

No functional change.
2015-01-18 10:41:56 +01:00
Marco Costalba f53aea45e3 Add syzygy support
bench: 8080602
2015-01-18 08:27:46 +01:00
Marco Costalba 3c07603dac Import C++11 branch
Import C++11 branch from:

https://github.com/mcostalba/Stockfish/tree/c++11

The version imported is teh last one as of today:
https://github.com/mcostalba/Stockfish/commit/6670e93e50a7a4e739ac2ac8b6026ffa3a12150a

Branch is fully equivalent with master but syzygy
tablebases that are missing (but will be added with
next commit).

bench: 8080602
2015-01-18 08:00:50 +01:00
46 changed files with 3516 additions and 3832 deletions
+55
View File
@@ -0,0 +1,55 @@
language: cpp
sudo: required
dist: trusty
matrix:
include:
- os: linux
compiler: gcc
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-6', 'g++-6-multilib', 'g++-multilib', 'valgrind']
env:
- COMPILER=g++-6
- COMP=gcc
- os: linux
compiler: clang
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['clang', 'g++-multilib', 'valgrind']
env:
- COMPILER=clang++
- COMP=clang
- os: osx
compiler: gcc
env:
- COMPILER=g++
- COMP=gcc
- os: osx
compiler: clang
env:
- COMPILER=clang++ V='Apple LLVM 6.0' # Apple LLVM version 6.0 (clang-600.0.54) (based on LLVM 3.5svn)
- COMP=clang
branches:
only:
- master
before_script:
- cd src
script:
- make clean && make build ARCH=x86-64 && ./stockfish bench 2>&1 >/dev/null | grep 'Nodes searched' | tee bench1
- make clean && make build ARCH=x86-32 && ./stockfish bench 2>&1 >/dev/null | grep 'Nodes searched' | tee bench2
- echo "Checking for same bench numbers..."
- diff bench1 bench2 > result
- test ! -s result
# if valgrind is available check the build is without error, reduce depth to speedup testing, but not too shallow to catch more cases.
- if [ -x "$(command -v valgrind )" ] ; then make clean && make ARCH=x86-64 debug=yes build && valgrind --error-exitcode=42 ./stockfish bench 128 1 10 default depth 1>/dev/null ; fi
# use g++-6 as a proxy for having sanitizers ... might need revision as they become available for more recent versions of clang/gcc than trusty provides
- if [[ "$COMPILER" == "g++-6" ]]; then make clean && make ARCH=x86-64 sanitize=yes build && ! ./stockfish bench 2>&1 | grep "runtime error:" ; fi
+48 -14
View File
@@ -1,64 +1,98 @@
# Generated with git shortlog -sn | cut -c8-', which sorts by commits (manually moved Tord to top)
# Generated with git shortlog -sn | cut -c8-', which sorts by commits (manually ordered the first four authors)
Tord Romstad
Marco Costalba
Joona Kiiski
Gary Linscott
lucasart
mstembera
Lucas Braesch
Stefan Geschwentner
Reuven Peleg
Chris Caino
homoSapiensSapiens
joergoster
VoyagerOne
Jean-Francois Romang
jundery
homoSapiensSapiens
Alain SAVARD
Arjun Temurnikar
Stéphane Nicolet
Uri Blass
jundery
Ralph Stößer
Stefan Geschwentner
Ajith
Leonid Pechenik
Stefano80
Tom Vijlbrief
hxim
snicolet
Daylen Yang
Henri Wiechers
Leonid Pechenik
mstembera
Jonathan Calovski
mbootsector
David Zar
Eelco de Groot
Jerry Donald
Joerg Oster
Jörg Oster
Ryan Schmitt
mcostalba
Alexander Kure
Dan Schmidt
H. Felix Wittmann
Joseph R. Prostko
Justin Blanchard
Linus Arver
NicklasPersson
Rodrigo Exterckötter Tjäder
Ron Britvich
Ronald de Man
RyanTaker
Vince Negri
ceebo
Joseph H Ellis
Stephane Nicolet
Ajith
jhellis3
ppigazzini
shane31
Andy Duplain
Auguste Pop
Balint Pfliegel
Chris Cain
DU-jdto
Dariusz Orzechowski
DiscanX
Ernesto Gatti
Gregor Cramer
Guenther Demetz
Hiraoka Takuya
Hongzhi Cheng
Jonathan Calovski
Joseph R. Prostko
Joseph Hellis
Kelly Wilson
Ken T Takusagawa
Kojirion
Luca Brivio
Matt Sullivan
Matthew Lai
Matthew Sullivan
Michel Van den Bergh
Mysseno
Oskar Werkelin Ahlin
Pablo Vazquez
Pascal Romaret
Ralph Stoesser
Ralph Stößer
Raminder Singh
Richard Lloyd
Ron Britvich
Ronald de Man
Ryan Takker
Stephane Nicolet
Thanar2
absimaldata
braich
gguliash
kinderchocolate
loco-loco
pellanda
renouve
shane31
sf-x
thaspel
unknown
uriblass
+5 -2
View File
@@ -1,5 +1,8 @@
### Overview
[![Build Status](https://travis-ci.org/official-stockfish/Stockfish.svg?branch=master)](https://travis-ci.org/official-stockfish/Stockfish)
[![Build Status](https://ci.appveyor.com/api/projects/status/github/official-stockfish/Stockfish?svg=true)](https://ci.appveyor.com/project/mcostalba/stockfish)
Stockfish is a free UCI chess engine derived from Glaurung 2.1. It is
not a complete chess program and requires some UCI-compatible GUI
(e.g. XBoard with PolyGlot, eboard, Arena, Sigma Chess, Shredder, Chess
@@ -54,7 +57,7 @@ for correspondence games (because of tablebase adjudication).
The "SyzygyProbeLimit" option should normally be left at its default value.
**What to expect**
**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
@@ -109,4 +112,4 @@ to where the source code can be found. If you make any changes to the
source code, these changes must also be made available under the GPL.
For full details, read the copy of the GPL found in the file named
*Copying.txt*
*Copying.txt*.
+45
View File
@@ -0,0 +1,45 @@
version: 1.0.{build}
clone_depth: 5
branches:
only:
- master
- appveyor
# Operating system (build VM template)
os: Visual Studio 2015
# Build platform, i.e. x86, x64, AnyCPU. This setting is optional.
platform:
- x86
- x64
- Any CPU
# build Configuration, i.e. Debug, Release, etc.
configuration: Debug
matrix:
# The build fail immediately once one of the job fails
fast_finish: true
# Scripts that are called at very beginning, before repo cloning
init:
- cmake --version
- msbuild /version
before_build:
- cd src
- echo project (Stockfish) >> CMakeLists.txt
- echo add_executable(stockfish benchmark.cpp bitbase.cpp bitboard.cpp endgame.cpp evaluate.cpp >> CMakeLists.txt
- echo main.cpp material.cpp misc.cpp movegen.cpp movepick.cpp pawns.cpp position.cpp psqt.cpp >> CMakeLists.txt
- echo search.cpp thread.cpp timeman.cpp tt.cpp uci.cpp ucioption.cpp syzygy/tbprobe.cpp) >> CMakeLists.txt
- echo set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/src) >> CMakeLists.txt
# - echo target_compile_options(stockfish PUBLIC "/Ox") >> CMakeLists.txt
build_script:
- cmake -G "Visual Studio 14 2015 Win64" .
- cmake --build .
before_test:
- cd Debug
- stockfish.exe bench > null
+126 -68
View File
@@ -1,6 +1,7 @@
# Stockfish, a UCI chess playing engine derived from Glaurung 2.1
# Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
# Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
# Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
#
# Stockfish is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -21,7 +22,10 @@
### ==========================================================================
### Establish the operating system name
UNAME = $(shell uname)
KERNEL = $(shell uname -s)
ifeq ($(KERNEL),Linux)
OS = $(shell uname -o)
endif
### Executable name
EXE = stockfish
@@ -31,11 +35,11 @@ PREFIX = /usr/local
BINDIR = $(PREFIX)/bin
### Built-in benchmark for pgo-builds
PGOBENCH = ./$(EXE) bench 16 1 1000 default time
PGOBENCH = ./$(EXE) bench
### Object files
OBJS = benchmark.o bitbase.o bitboard.o endgame.o evaluate.o main.o \
material.o misc.o movegen.o movepick.o pawns.o position.o \
material.o misc.o movegen.o movepick.o pawns.o position.o psqt.o \
search.o thread.o timeman.o tt.o uci.o ucioption.o syzygy/tbprobe.o
### ==========================================================================
@@ -46,13 +50,12 @@ OBJS = benchmark.o bitbase.o bitboard.o endgame.o evaluate.o main.o \
# ----------------------------------------------------------------------------
#
# debug = yes/no --- -DNDEBUG --- Enable/Disable debug mode
# sanitize = yes/no --- (-fsanitize ) --- enable undefined behavior checks
# optimize = yes/no --- (-O3/-fast etc.) --- Enable/Disable optimizations
# arch = (name) --- (-arch) --- Target architecture
# bits = 64/32 --- -DIS_64BIT --- 64-/32-bit operating system
# prefetch = yes/no --- -DUSE_PREFETCH --- Use prefetch x86 asm-instruction
# bsfq = yes/no --- -DUSE_BSFQ --- Use bsfq x86_64 asm-instruction (only
# with GCC and ICC 64-bit)
# popcnt = yes/no --- -DUSE_POPCNT --- Use popcnt x86_64 asm-instruction
# prefetch = yes/no --- -DUSE_PREFETCH --- Use prefetch asm-instruction
# popcnt = yes/no --- -DUSE_POPCNT --- Use popcnt asm-instruction
# sse = yes/no --- -msse --- Use Intel Streaming SIMD Extensions
# pext = yes/no --- -DUSE_PEXT --- Use pext x86_64 asm-instruction
#
@@ -63,9 +66,9 @@ OBJS = benchmark.o bitbase.o bitboard.o endgame.o evaluate.o main.o \
### 2.1. General and architecture defaults
optimize = yes
debug = no
sanitize = no
bits = 32
prefetch = no
bsfq = no
popcnt = no
sse = no
pext = no
@@ -95,7 +98,6 @@ ifeq ($(ARCH),x86-64)
arch = x86_64
bits = 64
prefetch = yes
bsfq = yes
sse = yes
endif
@@ -103,7 +105,6 @@ ifeq ($(ARCH),x86-64-modern)
arch = x86_64
bits = 64
prefetch = yes
bsfq = yes
popcnt = yes
sse = yes
endif
@@ -112,7 +113,6 @@ ifeq ($(ARCH),x86-64-bmi2)
arch = x86_64
bits = 64
prefetch = yes
bsfq = yes
popcnt = yes
sse = yes
pext = yes
@@ -121,7 +121,6 @@ endif
ifeq ($(ARCH),armv7)
arch = armv7
prefetch = yes
bsfq = yes
endif
ifeq ($(ARCH),ppc-32)
@@ -140,7 +139,8 @@ endif
### 3.1 Selecting compiler (default = gcc)
CXXFLAGS += -Wall -Wcast-qual -fno-exceptions -fno-rtti $(EXTRACXXFLAGS)
CXXFLAGS += -Wall -Wcast-qual -fno-exceptions -fno-rtti -std=c++11 $(EXTRACXXFLAGS)
DEPENDFLAGS += -std=c++11
LDFLAGS += $(EXTRALDFLAGS)
ifeq ($(COMP),)
@@ -150,14 +150,44 @@ endif
ifeq ($(COMP),gcc)
comp=gcc
CXX=g++
CXXFLAGS += -ansi -pedantic -Wno-long-long -Wextra -Wshadow
CXXFLAGS += -pedantic -Wextra -Wshadow
ifeq ($(ARCH),armv7)
ifeq ($(OS),Android)
CXXFLAGS += -m$(bits)
endif
else
CXXFLAGS += -m$(bits)
endif
ifneq ($(KERNEL),Darwin)
LDFLAGS += -Wl,--no-as-needed
endif
endif
ifeq ($(COMP),mingw)
comp=mingw
CXX=g++
ifeq ($(KERNEL),Linux)
ifeq ($(bits),64)
ifeq ($(shell which x86_64-w64-mingw32-c++-posix),)
CXX=x86_64-w64-mingw32-c++
else
CXX=x86_64-w64-mingw32-c++-posix
endif
else
ifeq ($(shell which i686-w64-mingw32-c++-posix),)
CXX=i686-w64-mingw32-c++
else
CXX=i686-w64-mingw32-c++-posix
endif
endif
else
CXX=g++
endif
CXXFLAGS += -Wextra -Wshadow
LDFLAGS += -static-libstdc++ -static-libgcc
LDFLAGS += -static
endif
ifeq ($(COMP),icc)
@@ -169,7 +199,22 @@ endif
ifeq ($(COMP),clang)
comp=clang
CXX=clang++
CXXFLAGS += -pedantic -Wno-long-long -Wextra -Wshadow
CXXFLAGS += -pedantic -Wextra -Wshadow
ifeq ($(ARCH),armv7)
ifeq ($(OS),Android)
CXXFLAGS += -m$(bits)
LDFLAGS += -m$(bits)
endif
else
CXXFLAGS += -m$(bits)
LDFLAGS += -m$(bits)
endif
ifeq ($(KERNEL),Darwin)
CXXFLAGS += -stdlib=libc++
DEPENDFLAGS += -stdlib=libc++
endif
endif
ifeq ($(comp),icc)
@@ -184,36 +229,52 @@ else
profile_clean = gcc-profile-clean
endif
ifeq ($(UNAME),Darwin)
CXXFLAGS += -arch $(arch) -mmacosx-version-min=10.6
LDFLAGS += -arch $(arch) -mmacosx-version-min=10.6
ifeq ($(KERNEL),Darwin)
CXXFLAGS += -arch $(arch) -mmacosx-version-min=10.9
LDFLAGS += -arch $(arch) -mmacosx-version-min=10.9
endif
### Travis CI script uses COMPILER to overwrite CXX
ifdef COMPILER
COMPCXX=$(COMPILER)
endif
### Allow overwriting CXX from command line
ifdef COMPCXX
CXX=$(COMPCXX)
endif
### On mingw use Windows threads, otherwise POSIX
ifneq ($(comp),mingw)
# On Android Bionic's C library comes with its own pthread implementation bundled in
ifneq ($(arch),armv7)
ifneq ($(OS),Android)
# Haiku has pthreads in its libroot, so only link it in on other platforms
ifneq ($(UNAME),Haiku)
ifneq ($(KERNEL),Haiku)
LDFLAGS += -lpthread
endif
endif
endif
### 3.4 Debugging
### 3.2.1 Debugging
ifeq ($(debug),no)
CXXFLAGS += -DNDEBUG
else
CXXFLAGS += -g
endif
### 3.5 Optimization
### 3.2.2 Debugging with undefined behavior sanitizers
ifeq ($(sanitize),yes)
CXXFLAGS += -g3 -fsanitize=undefined
endif
### 3.3 Optimization
ifeq ($(optimize),yes)
ifeq ($(comp),gcc)
CXXFLAGS += -O3
CXXFLAGS += -O3
ifeq ($(UNAME),Darwin)
ifeq ($(comp),gcc)
ifeq ($(KERNEL),Darwin)
ifeq ($(arch),i386)
CXXFLAGS += -mdynamic-no-pic
endif
@@ -222,27 +283,19 @@ ifeq ($(optimize),yes)
endif
endif
ifeq ($(arch),armv7)
ifeq ($(OS), Android)
CXXFLAGS += -fno-gcse -mthumb -march=armv7-a -mfloat-abi=softfp
endif
endif
ifeq ($(comp),mingw)
CXXFLAGS += -O3
endif
ifeq ($(comp),icc)
ifeq ($(UNAME),Darwin)
CXXFLAGS += -fast -mdynamic-no-pic
else
CXXFLAGS += -fast
ifeq ($(KERNEL),Darwin)
CXXFLAGS += -mdynamic-no-pic
endif
endif
ifeq ($(comp),clang)
CXXFLAGS += -O3
ifeq ($(UNAME),Darwin)
ifeq ($(KERNEL),Darwin)
ifeq ($(pext),no)
CXXFLAGS += -flto
LDFLAGS += $(CXXFLAGS)
@@ -257,12 +310,12 @@ ifeq ($(optimize),yes)
endif
endif
### 3.6. Bits
### 3.4 Bits
ifeq ($(bits),64)
CXXFLAGS += -DIS_64BIT
endif
### 3.7 prefetch
### 3.5 prefetch
ifeq ($(prefetch),yes)
ifeq ($(sse),yes)
CXXFLAGS += -msse
@@ -272,12 +325,7 @@ else
CXXFLAGS += -DNO_PREFETCH
endif
### 3.8 bsfq
ifeq ($(bsfq),yes)
CXXFLAGS += -DUSE_BSFQ
endif
### 3.9 popcnt
### 3.6 popcnt
ifeq ($(popcnt),yes)
ifeq ($(comp),icc)
CXXFLAGS += -msse3 -DUSE_POPCNT
@@ -286,33 +334,40 @@ ifeq ($(popcnt),yes)
endif
endif
### 3.10 pext
### 3.7 pext
ifeq ($(pext),yes)
CXXFLAGS += -DUSE_PEXT
ifeq ($(comp),$(filter $(comp),gcc clang mingw))
CXXFLAGS += -mbmi -mbmi2
CXXFLAGS += -mbmi2
endif
endif
### 3.11 Link Time Optimization, it works since gcc 4.5 but not on mingw.
### 3.8 Link Time Optimization, it works since gcc 4.5 but not on mingw under Windows.
### This is a mix of compile and link time options because the lto link phase
### needs access to the optimization flags.
ifeq ($(comp),gcc)
ifeq ($(optimize),yes)
ifeq ($(debug),no)
GCC_MAJOR := `$(CXX) -dumpversion | cut -f1 -d.`
GCC_MINOR := `$(CXX) -dumpversion | cut -f2 -d.`
ifeq (1,$(shell expr \( $(GCC_MAJOR) \> 4 \) \| \( $(GCC_MAJOR) \= 4 \& $(GCC_MINOR) \>= 5 \)))
CXXFLAGS += -flto
LDFLAGS += $(CXXFLAGS)
endif
CXXFLAGS += -flto
LDFLAGS += $(CXXFLAGS)
endif
endif
endif
### 3.12 Android 5 can only run position independent executables. Note that this
ifeq ($(comp),mingw)
ifeq ($(KERNEL),Linux)
ifeq ($(optimize),yes)
ifeq ($(debug),no)
CXXFLAGS += -flto
LDFLAGS += $(CXXFLAGS)
endif
endif
endif
endif
### 3.9 Android 5 can only run position independent executables. Note that this
### breaks Android 4.0 and earlier.
ifeq ($(arch),armv7)
ifeq ($(OS), Android)
CXXFLAGS += -fPIE
LDFLAGS += -fPIE -pie
endif
@@ -326,7 +381,7 @@ help:
@echo ""
@echo "To compile stockfish, type: "
@echo ""
@echo "make target ARCH=arch [COMP=comp]"
@echo "make target ARCH=arch [COMP=compiler] [COMPCXX=cxx]"
@echo ""
@echo "Supported targets:"
@echo ""
@@ -356,11 +411,17 @@ help:
@echo "clang > LLVM Clang compiler"
@echo "icc > Intel compiler"
@echo ""
@echo "Examples. If you don't know what to do, you likely want to run: "
@echo "Simple examples. If you don't know what to do, you likely want to run: "
@echo ""
@echo "make build ARCH=x86-64 (This is for 64-bit systems)"
@echo "make build ARCH=x86-32 (This is for 32-bit systems)"
@echo ""
@echo "Advanced examples, for experienced users: "
@echo ""
@echo "make build ARCH=x86-64 COMP=clang"
@echo "make profile-build ARCH=x86-64-modern COMP=gcc COMPCXX=g++-4.8"
@echo ""
.PHONY: build profile-build
build:
@@ -378,7 +439,7 @@ profile-build:
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_make)
@echo ""
@echo "Step 2/4. Running benchmark for pgo-build ..."
@$(PGOBENCH) > /dev/null
$(PGOBENCH) > /dev/null
@echo ""
@echo "Step 3/4. Building final executable ..."
@touch *.cpp *.h syzygy/*.cpp syzygy/*.h
@@ -414,8 +475,9 @@ config-sanity:
@echo "optimize: '$(optimize)'"
@echo "arch: '$(arch)'"
@echo "bits: '$(bits)'"
@echo "kernel: '$(KERNEL)'"
@echo "os: '$(OS)'"
@echo "prefetch: '$(prefetch)'"
@echo "bsfq: '$(bsfq)'"
@echo "popcnt: '$(popcnt)'"
@echo "sse: '$(sse)'"
@echo "pext: '$(pext)'"
@@ -433,7 +495,6 @@ config-sanity:
test "$(arch)" = "ppc64" || test "$(arch)" = "ppc" || test "$(arch)" = "armv7"
@test "$(bits)" = "32" || test "$(bits)" = "64"
@test "$(prefetch)" = "yes" || test "$(prefetch)" = "no"
@test "$(bsfq)" = "yes" || test "$(bsfq)" = "no"
@test "$(popcnt)" = "yes" || test "$(popcnt)" = "no"
@test "$(sse)" = "yes" || test "$(sse)" = "no"
@test "$(pext)" = "yes" || test "$(pext)" = "no"
@@ -447,16 +508,13 @@ gcc-profile-prepare:
gcc-profile-make:
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
EXTRACXXFLAGS='-fprofile-arcs' \
EXTRACXXFLAGS='-fprofile-generate' \
EXTRALDFLAGS='-lgcov' \
all
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) \
EXTRACXXFLAGS='-fbranch-probabilities' \
EXTRACXXFLAGS='-fprofile-use -fno-peel-loops -fno-tracer' \
EXTRALDFLAGS='-lgcov' \
all
+28 -20
View File
@@ -2,6 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +18,6 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <algorithm>
#include <fstream>
#include <iostream>
#include <istream>
@@ -27,14 +27,13 @@
#include "position.h"
#include "search.h"
#include "thread.h"
#include "tt.h"
#include "uci.h"
using namespace std;
namespace {
const char* Defaults[] = {
const vector<string> Defaults = {
"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1",
"r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 10",
"8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - - 0 11",
@@ -78,6 +77,13 @@ const char* Defaults[] = {
// 7-man positions
"8/R7/2q5/8/6k1/8/1P5p/K6R w - - 0 124", // Draw
// Mate and stalemate positions
"8/8/8/8/8/6k1/6p1/6K1 w - -",
"5k2/5P2/5K2/8/8/8/8/8 b - -",
"8/8/8/8/8/4k3/4p3/4K3 w - -",
"8/8/8/8/8/5K2/8/3Q1k2 b - -",
"7k/7P/6K1/8/3B4/8/8/8 b - -"
};
} // namespace
@@ -93,8 +99,8 @@ const char* Defaults[] = {
void benchmark(const Position& current, istream& is) {
string token;
Search::LimitsType limits;
vector<string> fens;
Search::LimitsType limits;
// Assign default values to missing arguments
string ttSize = (is >> token) ? token : "16";
@@ -105,22 +111,22 @@ void benchmark(const Position& current, istream& is) {
Options["Hash"] = ttSize;
Options["Threads"] = threads;
TT.clear();
Search::clear();
if (limitType == "time")
limits.movetime = atoi(limit.c_str()); // movetime is in ms
limits.movetime = stoi(limit); // movetime is in millisecs
else if (limitType == "nodes")
limits.nodes = atoi(limit.c_str());
limits.nodes = stoi(limit);
else if (limitType == "mate")
limits.mate = atoi(limit.c_str());
limits.mate = stoi(limit);
else
limits.depth = atoi(limit.c_str());
limits.depth = stoi(limit);
if (fenFile == "default")
fens.assign(Defaults, Defaults + 37);
fens = Defaults;
else if (fenFile == "current")
fens.push_back(current.fen());
@@ -128,7 +134,7 @@ void benchmark(const Position& current, istream& is) {
else
{
string fen;
ifstream file(fenFile.c_str());
ifstream file(fenFile);
if (!file.is_open())
{
@@ -144,29 +150,31 @@ void benchmark(const Position& current, istream& is) {
}
uint64_t nodes = 0;
Search::StateStackPtr st;
Time::point elapsed = Time::now();
TimePoint elapsed = now();
Position pos;
for (size_t i = 0; i < fens.size(); ++i)
{
Position pos(fens[i], Options["UCI_Chess960"], Threads.main());
StateListPtr states(new std::deque<StateInfo>(1));
pos.set(fens[i], Options["UCI_Chess960"], &states->back(), Threads.main());
cerr << "\nPosition: " << i + 1 << '/' << fens.size() << endl;
if (limitType == "perft")
nodes += Search::perft<true>(pos, limits.depth * ONE_PLY);
nodes += Search::perft(pos, limits.depth * ONE_PLY);
else
{
Threads.start_thinking(pos, limits, st);
Threads.wait_for_think_finished();
nodes += Search::RootPos.nodes_searched();
limits.startTime = now();
Threads.start_thinking(pos, states, limits);
Threads.main()->wait_for_search_finished();
nodes += Threads.nodes_searched();
}
}
elapsed = std::max(Time::now() - elapsed, Time::point(1)); // Avoid a 'divide by zero'
elapsed = now() - elapsed + 1; // Ensure positivity to avoid a 'divide by zero'
dbg_print(); // Just before to exit
dbg_print(); // Just before exiting
cerr << "\n==========================="
<< "\nTotal time (ms) : " << elapsed
+51 -46
View File
@@ -2,6 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +18,9 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <algorithm>
#include <cassert>
#include <numeric>
#include <vector>
#include "bitboard.h"
@@ -51,20 +54,19 @@ namespace {
WIN = 4
};
inline Result& operator|=(Result& r, Result v) { return r = Result(r | v); }
Result& operator|=(Result& r, Result v) { return r = Result(r | v); }
struct KPKPosition {
KPKPosition(unsigned idx);
KPKPosition() = default;
explicit KPKPosition(unsigned idx);
operator Result() const { return result; }
Result classify(const std::vector<KPKPosition>& db)
{ return us == WHITE ? classify<WHITE>(db) : classify<BLACK>(db); }
private:
template<Color Us> Result classify(const std::vector<KPKPosition>& db);
Color us;
Square bksq, wksq, psq;
Square ksq[COLOR_NB], psq;
Result result;
};
@@ -82,13 +84,12 @@ bool Bitbases::probe(Square wksq, Square wpsq, Square bksq, Color us) {
void Bitbases::init() {
std::vector<KPKPosition> db(MAX_INDEX);
unsigned idx, repeat = 1;
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));
db[idx] = KPKPosition(idx);
// Iterate through the positions until none of the unknown positions can be
// changed to either wins or draws (15 cycles needed).
@@ -107,69 +108,73 @@ namespace {
KPKPosition::KPKPosition(unsigned idx) {
wksq = Square((idx >> 0) & 0x3F);
bksq = Square((idx >> 6) & 0x3F);
us = Color ((idx >> 12) & 0x01);
psq = make_square(File((idx >> 13) & 0x3), RANK_7 - Rank((idx >> 15) & 0x7));
result = UNKNOWN;
ksq[WHITE] = Square((idx >> 0) & 0x3F);
ksq[BLACK] = Square((idx >> 6) & 0x3F);
us = Color ((idx >> 12) & 0x01);
psq = make_square(File((idx >> 13) & 0x3), RANK_7 - Rank((idx >> 15) & 0x7));
// Check if two pieces are on the same square or if a king can be captured
if ( distance(wksq, bksq) <= 1
|| wksq == psq
|| bksq == psq
|| (us == WHITE && (StepAttacksBB[PAWN][psq] & bksq)))
if ( distance(ksq[WHITE], ksq[BLACK]) <= 1
|| ksq[WHITE] == psq
|| ksq[BLACK] == psq
|| (us == WHITE && (StepAttacksBB[PAWN][psq] & ksq[BLACK])))
result = INVALID;
else if (us == WHITE)
{
// Immediate win if a pawn can be promoted without getting captured
if ( rank_of(psq) == RANK_7
&& wksq != psq + DELTA_N
&& ( distance(bksq, psq + DELTA_N) > 1
||(StepAttacksBB[KING][wksq] & (psq + DELTA_N))))
result = WIN;
}
// Immediate win if a pawn can be promoted without getting captured
else if ( us == WHITE
&& rank_of(psq) == RANK_7
&& ksq[us] != psq + NORTH
&& ( distance(ksq[~us], psq + NORTH) > 1
|| (StepAttacksBB[KING][ksq[us]] & (psq + NORTH))))
result = WIN;
// Immediate draw if it is a stalemate or a king captures undefended pawn
else if ( !(StepAttacksBB[KING][bksq] & ~(StepAttacksBB[KING][wksq] | StepAttacksBB[PAWN][psq]))
|| (StepAttacksBB[KING][bksq] & psq & ~StepAttacksBB[KING][wksq]))
else if ( us == BLACK
&& ( !(StepAttacksBB[KING][ksq[us]] & ~(StepAttacksBB[KING][ksq[~us]] | StepAttacksBB[PAWN][psq]))
|| (StepAttacksBB[KING][ksq[us]] & psq & ~StepAttacksBB[KING][ksq[~us]])))
result = DRAW;
// Position will be classified later
else
result = UNKNOWN;
}
template<Color Us>
Result KPKPosition::classify(const std::vector<KPKPosition>& db) {
// White to Move: If one move leads to a position classified as WIN, the result
// White to move: If one move leads to a position classified as WIN, the result
// of the current position is WIN. If all moves lead to positions classified
// as DRAW, the current position is classified as DRAW, otherwise the current
// position is classified as UNKNOWN.
//
// Black to Move: If one move leads to a position classified as DRAW, the result
// Black to move: If one move leads to a position classified as DRAW, the result
// of the current position is DRAW. If all moves lead to positions classified
// as WIN, the position is classified as WIN, otherwise the current position is
// classified as UNKNOWN.
const Color Them = (Us == WHITE ? BLACK : WHITE);
const Color Them = (Us == WHITE ? BLACK : WHITE);
const Result Good = (Us == WHITE ? WIN : DRAW);
const Result Bad = (Us == WHITE ? DRAW : WIN);
Result r = INVALID;
Bitboard b = StepAttacksBB[KING][Us == WHITE ? wksq : bksq];
Bitboard b = StepAttacksBB[KING][ksq[Us]];
while (b)
r |= Us == WHITE ? db[index(Them, bksq, pop_lsb(&b), psq)]
: db[index(Them, pop_lsb(&b), wksq, psq)];
if (Us == WHITE && rank_of(psq) < RANK_7)
{
Square s = psq + DELTA_N;
r |= db[index(BLACK, bksq, wksq, s)]; // Single push
if (rank_of(psq) == RANK_2 && s != wksq && s != bksq)
r |= db[index(BLACK, bksq, wksq, s + DELTA_N)]; // Double push
}
r |= Us == WHITE ? db[index(Them, ksq[Them] , pop_lsb(&b), psq)]
: db[index(Them, pop_lsb(&b), ksq[Them] , psq)];
if (Us == WHITE)
return result = r & WIN ? WIN : r & UNKNOWN ? UNKNOWN : DRAW;
else
return result = r & DRAW ? DRAW : r & UNKNOWN ? UNKNOWN : WIN;
{
if (rank_of(psq) < RANK_7) // Single push
r |= db[index(Them, ksq[Them], ksq[Us], psq + NORTH)];
if ( rank_of(psq) == RANK_2 // Double push
&& psq + NORTH != ksq[Us]
&& psq + NORTH != ksq[Them])
r |= db[index(Them, ksq[Them], ksq[Us], psq + NORTH + NORTH)];
}
return result = r & Good ? Good : r & UNKNOWN ? UNKNOWN : Bad;
}
} // namespace
+47 -35
View File
@@ -2,6 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,12 +19,11 @@
*/
#include <algorithm>
#include <cstring> // For std::memset
#include "bitboard.h"
#include "bitcount.h"
#include "misc.h"
uint8_t PopCnt16[1 << 16];
int SquareDistance[SQUARE_NB][SQUARE_NB];
Bitboard RookMasks [SQUARE_NB];
@@ -56,7 +56,7 @@ namespace {
const uint64_t DeBruijn64 = 0x3F79D71B4CB0A89ULL;
const uint32_t DeBruijn32 = 0x783A9B23;
int MS1BTable[256]; // To implement software msb()
int MSBTable[256]; // To implement software msb()
Square BSFTable[SQUARE_NB]; // To implement software bitscan
Bitboard RookTable[0x19000]; // To store rook attacks
Bitboard BishopTable[0x1480]; // To store bishop attacks
@@ -69,23 +69,35 @@ namespace {
// 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) {
unsigned bsf_index(Bitboard b) {
b ^= b - 1;
return Is64Bit ? (b * DeBruijn64) >> 58
: ((unsigned(b) ^ unsigned(b >> 32)) * DeBruijn32) >> 26;
}
// popcount16() counts the non-zero bits using SWAR-Popcount algorithm
unsigned popcount16(unsigned u) {
u -= (u >> 1) & 0x5555U;
u = ((u >> 2) & 0x3333U) + (u & 0x3333U);
u = ((u >> 4) + u) & 0x0F0FU;
return (u * 0x0101U) >> 8;
}
}
#ifndef USE_BSFQ
#ifdef NO_BSF
/// Software fall-back of lsb() and msb() for CPU lacking hardware support
Square lsb(Bitboard b) {
assert(b);
return BSFTable[bsf_index(b)];
}
Square msb(Bitboard b) {
assert(b);
unsigned b32;
int result = 0;
@@ -109,10 +121,10 @@ Square msb(Bitboard b) {
result += 8;
}
return Square(result + MS1BTable[b32]);
return Square(result + MSBTable[b32]);
}
#endif // ifndef USE_BSFQ
#endif // ifdef NO_BSF
/// Bitboards::pretty() returns an ASCII representation of a bitboard suitable
@@ -125,9 +137,9 @@ const std::string Bitboards::pretty(Bitboard b) {
for (Rank r = RANK_8; r >= RANK_1; --r)
{
for (File f = FILE_A; f <= FILE_H; ++f)
s.append(b & make_square(f, r) ? "| X " : "| ");
s += b & make_square(f, r) ? "| X " : "| ";
s.append("|\n+---+---+---+---+---+---+---+---+\n");
s += "|\n+---+---+---+---+---+---+---+---+\n";
}
return s;
@@ -139,14 +151,17 @@ const std::string Bitboards::pretty(Bitboard b) {
void Bitboards::init() {
for (unsigned i = 0; i < (1 << 16); ++i)
PopCnt16[i] = (uint8_t) popcount16(i);
for (Square s = SQ_A1; s <= SQ_H8; ++s)
{
SquareBB[s] = 1ULL << s;
BSFTable[bsf_index(SquareBB[s])] = s;
}
for (Bitboard b = 1; b < 256; ++b)
MS1BTable[b] = more_than_one(b) ? MS1BTable[b - 1] : lsb(b);
for (Bitboard b = 2; b < 256; ++b)
MSBTable[b] = MSBTable[b - 1] + !more_than_one(b);
for (File f = FILE_A; f <= FILE_H; ++f)
FileBB[f] = f > FILE_A ? FileBB[f - 1] << 1 : FileABB;
@@ -190,8 +205,8 @@ void Bitboards::init() {
StepAttacksBB[make_piece(c, pt)][s] |= to;
}
Square RookDeltas[] = { DELTA_N, DELTA_E, DELTA_S, DELTA_W };
Square BishopDeltas[] = { DELTA_NE, DELTA_SE, DELTA_SW, DELTA_NW };
Square RookDeltas[] = { NORTH, EAST, SOUTH, WEST };
Square BishopDeltas[] = { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST };
init_magics(RookTable, RookAttacks, RookMagics, RookMasks, RookShifts, RookDeltas, magic_index<ROOK>);
init_magics(BishopTable, BishopAttacks, BishopMagics, BishopMasks, BishopShifts, BishopDeltas, magic_index<BISHOP>);
@@ -201,17 +216,15 @@ void Bitboards::init() {
PseudoAttacks[QUEEN][s1] = PseudoAttacks[BISHOP][s1] = attacks_bb<BISHOP>(s1, 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;
for (Piece pc = W_BISHOP; pc <= W_ROOK; ++pc)
for (Square s2 = SQ_A1; s2 <= SQ_H8; ++s2)
{
if (!(PseudoAttacks[pc][s1] & s2))
continue;
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]);
}
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]);
}
}
}
@@ -249,7 +262,7 @@ namespace {
{ 728, 10316, 55013, 32803, 12281, 15100, 16645, 255 } };
Bitboard occupancy[4096], reference[4096], edges, b;
int i, size;
int age[4096] = {0}, current = 0, i, size;
// attacks[s] is a pointer to the beginning of the attacks table for square 's'
attacks[SQ_A1] = table;
@@ -265,7 +278,7 @@ namespace {
// the number of 1s of the mask. Hence we deduce the size of the shift to
// apply to the 64 or 32 bits word to get the index.
masks[s] = sliding_attack(deltas, s, 0) & ~edges;
shifts[s] = (Is64Bit ? 64 : 32) - popcount<Max15>(masks[s]);
shifts[s] = (Is64Bit ? 64 : 32) - popcount(masks[s]);
// Use Carry-Rippler trick to enumerate all subsets of masks[s] and
// store the corresponding sliding attack bitboard in reference[].
@@ -296,24 +309,23 @@ namespace {
do {
do
magics[s] = rng.sparse_rand<Bitboard>();
while (popcount<Max15>((magics[s] * masks[s]) >> 56) < 6);
std::memset(attacks[s], 0, size * sizeof(Bitboard));
while (popcount((magics[s] * masks[s]) >> 56) < 6);
// A good magic must map every possible occupancy to an index that
// looks up the correct sliding attack in the attacks[s] database.
// Note that we build up the database for square 's' as a side
// effect of verifying the magic.
for (i = 0; i < size; ++i)
for (++current, i = 0; i < size; ++i)
{
Bitboard& attack = attacks[s][index(s, occupancy[i])];
unsigned idx = index(s, occupancy[i]);
if (attack && attack != reference[i])
if (age[idx] < current)
{
age[idx] = current;
attacks[s][idx] = reference[i];
}
else if (attacks[s][idx] != reference[i])
break;
assert(reference[i]);
attack = reference[i];
}
} while (i < size);
}
+60 -62
View File
@@ -2,13 +2,13 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Stockfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -61,16 +61,6 @@ const Bitboard Rank8BB = Rank1BB << (8 * 7);
extern int SquareDistance[SQUARE_NB][SQUARE_NB];
extern Bitboard RookMasks [SQUARE_NB];
extern Bitboard RookMagics [SQUARE_NB];
extern Bitboard* RookAttacks[SQUARE_NB];
extern unsigned RookShifts [SQUARE_NB];
extern Bitboard BishopMasks [SQUARE_NB];
extern Bitboard BishopMagics [SQUARE_NB];
extern Bitboard* BishopAttacks[SQUARE_NB];
extern unsigned BishopShifts [SQUARE_NB];
extern Bitboard SquareBB[SQUARE_NB];
extern Bitboard FileBB[FILE_NB];
extern Bitboard RankBB[RANK_NB];
@@ -134,13 +124,13 @@ inline Bitboard file_bb(Square s) {
}
/// shift_bb() moves a bitboard one step along direction Delta. Mainly for pawns
/// shift() moves a bitboard one step along direction D. Mainly for pawns
template<Square Delta>
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
template<Square D>
inline Bitboard shift(Bitboard b) {
return D == NORTH ? b << 8 : D == SOUTH ? b >> 8
: D == NORTH_EAST ? (b & ~FileHBB) << 9 : D == SOUTH_EAST ? (b & ~FileHBB) >> 7
: D == NORTH_WEST ? (b & ~FileABB) << 7 : D == SOUTH_WEST ? (b & ~FileABB) >> 9
: 0;
}
@@ -200,14 +190,6 @@ inline Bitboard passed_pawn_mask(Color c, Square s) {
}
/// squares_of_color() returns a bitboard representing all the squares of the
/// same color of the given one.
inline Bitboard squares_of_color(Square s) {
return DarkSquares & s ? DarkSquares : ~DarkSquares;
}
/// aligned() returns true if the squares s1, s2 and s3 are aligned either on a
/// straight or on a diagonal line.
@@ -231,7 +213,14 @@ template<> inline int distance<Rank>(Square x, Square y) { return distance(rank_
/// piece of type Pt (bishop or rook) placed on 's'. The helper magic_index()
/// looks up the index using the 'magic bitboards' approach.
template<PieceType Pt>
FORCE_INLINE unsigned magic_index(Square s, Bitboard occupied) {
inline unsigned magic_index(Square s, Bitboard occupied) {
extern Bitboard RookMasks[SQUARE_NB];
extern Bitboard RookMagics[SQUARE_NB];
extern unsigned RookShifts[SQUARE_NB];
extern Bitboard BishopMasks[SQUARE_NB];
extern Bitboard BishopMagics[SQUARE_NB];
extern unsigned BishopShifts[SQUARE_NB];
Bitboard* const Masks = Pt == ROOK ? RookMasks : BishopMasks;
Bitboard* const Magics = Pt == ROOK ? RookMagics : BishopMagics;
@@ -250,6 +239,10 @@ FORCE_INLINE unsigned magic_index(Square s, Bitboard occupied) {
template<PieceType Pt>
inline Bitboard attacks_bb(Square s, Bitboard occupied) {
extern Bitboard* RookAttacks[SQUARE_NB];
extern Bitboard* BishopAttacks[SQUARE_NB];
return (Pt == ROOK ? RookAttacks : BishopAttacks)[s][magic_index<Pt>(s, occupied)];
}
@@ -265,56 +258,61 @@ inline Bitboard attacks_bb(Piece pc, Square s, Bitboard occupied) {
}
/// popcount() counts the number of non-zero bits in a bitboard
inline int popcount(Bitboard b) {
#ifndef USE_POPCNT
extern uint8_t PopCnt16[1 << 16];
union { Bitboard bb; uint16_t u[4]; } v = { b };
return PopCnt16[v.u[0]] + PopCnt16[v.u[1]] + PopCnt16[v.u[2]] + PopCnt16[v.u[3]];
#elif defined(_MSC_VER) || defined(__INTEL_COMPILER)
return (int)_mm_popcnt_u64(b);
#else // Assumed gcc or compatible compiler
return __builtin_popcountll(b);
#endif
}
/// lsb() and msb() return the least/most significant bit in a non-zero bitboard
#ifdef USE_BSFQ
#if defined(__GNUC__)
# if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
inline Square lsb(Bitboard b) {
assert(b);
return Square(__builtin_ctzll(b));
}
FORCE_INLINE Square lsb(Bitboard b) {
inline Square msb(Bitboard b) {
assert(b);
return Square(63 - __builtin_clzll(b));
}
#elif defined(_WIN64) && defined(_MSC_VER)
inline Square lsb(Bitboard b) {
assert(b);
unsigned long idx;
_BitScanForward64(&idx, b);
return (Square) idx;
}
FORCE_INLINE Square msb(Bitboard b) {
inline Square msb(Bitboard b) {
assert(b);
unsigned long idx;
_BitScanReverse64(&idx, b);
return (Square) idx;
}
# elif defined(__arm__)
#else
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
Bitboard idx;
__asm__("bsfq %1, %0": "=r"(idx): "rm"(b) );
return (Square) idx;
}
FORCE_INLINE Square msb(Bitboard b) {
Bitboard idx;
__asm__("bsrq %1, %0": "=r"(idx): "rm"(b) );
return (Square) idx;
}
# endif
#else // ifdef(USE_BSFQ)
#define NO_BSF // Fallback on software implementation for other cases
Square lsb(Bitboard b);
Square msb(Bitboard b);
@@ -324,7 +322,7 @@ Square msb(Bitboard b);
/// pop_lsb() finds and clears the least significant bit in a non-zero bitboard
FORCE_INLINE Square pop_lsb(Bitboard* b) {
inline Square pop_lsb(Bitboard* b) {
const Square s = lsb(*b);
*b &= *b - 1;
return s;
-105
View File
@@ -1,105 +0,0 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Stockfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef BITCOUNT_H_INCLUDED
#define BITCOUNT_H_INCLUDED
#include <cassert>
#include "types.h"
enum BitCountType {
CNT_64,
CNT_64_MAX15,
CNT_32,
CNT_32_MAX15,
CNT_HW_POPCNT
};
/// Determine at compile time the best popcount<> specialization according to
/// whether the platform is 32 or 64 bit, the maximum number of non-zero
/// bits to count and if the hardware popcnt instruction is available.
const BitCountType Full = HasPopCnt ? CNT_HW_POPCNT : Is64Bit ? CNT_64 : CNT_32;
const BitCountType Max15 = HasPopCnt ? CNT_HW_POPCNT : Is64Bit ? CNT_64_MAX15 : CNT_32_MAX15;
/// popcount() counts the number of non-zero bits in a bitboard
template<BitCountType> inline int popcount(Bitboard);
template<>
inline int popcount<CNT_64>(Bitboard b) {
b -= (b >> 1) & 0x5555555555555555ULL;
b = ((b >> 2) & 0x3333333333333333ULL) + (b & 0x3333333333333333ULL);
b = ((b >> 4) + b) & 0x0F0F0F0F0F0F0F0FULL;
return (b * 0x0101010101010101ULL) >> 56;
}
template<>
inline int popcount<CNT_64_MAX15>(Bitboard b) {
b -= (b >> 1) & 0x5555555555555555ULL;
b = ((b >> 2) & 0x3333333333333333ULL) + (b & 0x3333333333333333ULL);
return (b * 0x1111111111111111ULL) >> 60;
}
template<>
inline int popcount<CNT_32>(Bitboard b) {
unsigned w = unsigned(b >> 32), v = unsigned(b);
v -= (v >> 1) & 0x55555555; // 0-2 in 2 bits
w -= (w >> 1) & 0x55555555;
v = ((v >> 2) & 0x33333333) + (v & 0x33333333); // 0-4 in 4 bits
w = ((w >> 2) & 0x33333333) + (w & 0x33333333);
v = ((v >> 4) + v + (w >> 4) + w) & 0x0F0F0F0F;
return (v * 0x01010101) >> 24;
}
template<>
inline int popcount<CNT_32_MAX15>(Bitboard b) {
unsigned w = unsigned(b >> 32), v = unsigned(b);
v -= (v >> 1) & 0x55555555; // 0-2 in 2 bits
w -= (w >> 1) & 0x55555555;
v = ((v >> 2) & 0x33333333) + (v & 0x33333333); // 0-4 in 4 bits
w = ((w >> 2) & 0x33333333) + (w & 0x33333333);
return ((v + w) * 0x11111111) >> 28;
}
template<>
inline int popcount<CNT_HW_POPCNT>(Bitboard b) {
#ifndef USE_POPCNT
assert(false);
return b != 0; // Avoid 'b not used' warning
#elif defined(_MSC_VER) && defined(__INTEL_COMPILER)
return _mm_popcnt_u64(b);
#elif defined(_MSC_VER)
return (int)__popcnt64(b);
#else // Assumed gcc or compatible compiler
return __builtin_popcountll(b);
#endif
}
#endif // #ifndef BITCOUNT_H_INCLUDED
+91 -103
View File
@@ -2,6 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -21,7 +22,6 @@
#include <cassert>
#include "bitboard.h"
#include "bitcount.h"
#include "endgame.h"
#include "movegen.h"
@@ -39,7 +39,7 @@ namespace {
70, 50, 30, 20, 20, 30, 50, 70,
80, 60, 40, 30, 30, 40, 60, 80,
90, 70, 60, 50, 50, 60, 70, 90,
100, 90, 80, 70, 70, 80, 90, 100,
100, 90, 80, 70, 70, 80, 90, 100
};
// Table used to drive the king towards a corner square of the
@@ -59,6 +59,9 @@ namespace {
const int PushClose[8] = { 0, 0, 100, 80, 60, 40, 20, 10 };
const int PushAway [8] = { 0, 5, 20, 40, 60, 80, 90, 100 };
// Pawn Rank based scaling factors used in KRPPKRP endgame
const int KRPPKRPScaleFactors[RANK_NB] = { 0, 9, 10, 14, 21, 44, 0, 0 };
#ifndef NDEBUG
bool verify_material(const Position& pos, Color c, Value npm, int pawnsCnt) {
return pos.non_pawn_material(c) == npm && pos.count<PAWN>(c) == pawnsCnt;
@@ -71,7 +74,7 @@ namespace {
assert(pos.count<PAWN>(strongSide) == 1);
if (file_of(pos.list<PAWN>(strongSide)[0]) >= FILE_E)
if (file_of(pos.square<PAWN>(strongSide)) >= FILE_E)
sq = Square(sq ^ 7); // Mirror SQ_H1 -> SQ_A1
if (strongSide == BLACK)
@@ -96,12 +99,10 @@ namespace {
string fen = sides[0] + char(8 - sides[0].length() + '0') + "/8/8/8/8/8/8/"
+ sides[1] + char(8 - sides[1].length() + '0') + " w - - 0 10";
return Position(fen, false, NULL).material_key();
StateInfo st;
return Position().set(fen, false, &st, nullptr).material_key();
}
template<typename M>
void delete_endgame(const typename M::value_type& p) { delete p.second; }
} // namespace
@@ -128,17 +129,11 @@ Endgames::Endgames() {
add<KRPPKRP>("KRPPKRP");
}
Endgames::~Endgames() {
for_each(m1.begin(), m1.end(), delete_endgame<M1>);
for_each(m2.begin(), m2.end(), delete_endgame<M2>);
}
template<EndgameType E>
template<EndgameType E, typename T>
void Endgames::add(const string& code) {
map((Endgame<E>*)0)[key(code, WHITE)] = new Endgame<E>(WHITE);
map((Endgame<E>*)0)[key(code, BLACK)] = new Endgame<E>(BLACK);
map<T>()[key(code, WHITE)] = std::unique_ptr<EndgameBase<T>>(new Endgame<E>(WHITE));
map<T>()[key(code, BLACK)] = std::unique_ptr<EndgameBase<T>>(new Endgame<E>(BLACK));
}
@@ -156,8 +151,8 @@ Value Endgame<KXK>::operator()(const Position& pos) const {
if (pos.side_to_move() == weakSide && !MoveList<LEGAL>(pos).size())
return VALUE_DRAW;
Square winnerKSq = pos.king_square(strongSide);
Square loserKSq = pos.king_square(weakSide);
Square winnerKSq = pos.square<KING>(strongSide);
Square loserKSq = pos.square<KING>(weakSide);
Value result = pos.non_pawn_material(strongSide)
+ pos.count<PAWN>(strongSide) * PawnValueEg
@@ -167,9 +162,9 @@ Value Endgame<KXK>::operator()(const Position& pos) const {
if ( pos.count<QUEEN>(strongSide)
|| pos.count<ROOK>(strongSide)
||(pos.count<BISHOP>(strongSide) && pos.count<KNIGHT>(strongSide))
||(pos.count<BISHOP>(strongSide) > 1 && opposite_colors(pos.list<BISHOP>(strongSide)[0],
pos.list<BISHOP>(strongSide)[1])))
result += VALUE_KNOWN_WIN;
||(pos.count<BISHOP>(strongSide) > 1 && opposite_colors(pos.squares<BISHOP>(strongSide)[0],
pos.squares<BISHOP>(strongSide)[1])))
result = std::min(result + VALUE_KNOWN_WIN, VALUE_MATE_IN_MAX_PLY - 1);
return strongSide == pos.side_to_move() ? result : -result;
}
@@ -183,9 +178,9 @@ Value Endgame<KBNK>::operator()(const Position& pos) const {
assert(verify_material(pos, strongSide, KnightValueMg + BishopValueMg, 0));
assert(verify_material(pos, weakSide, VALUE_ZERO, 0));
Square winnerKSq = pos.king_square(strongSide);
Square loserKSq = pos.king_square(weakSide);
Square bishopSq = pos.list<BISHOP>(strongSide)[0];
Square winnerKSq = pos.square<KING>(strongSide);
Square loserKSq = pos.square<KING>(weakSide);
Square bishopSq = pos.square<BISHOP>(strongSide);
// kbnk_mate_table() tries to drive toward corners A1 or H8. If we have a
// bishop that cannot reach the above squares, we flip the kings in order
@@ -212,9 +207,9 @@ Value Endgame<KPK>::operator()(const Position& pos) const {
assert(verify_material(pos, weakSide, VALUE_ZERO, 0));
// Assume strongSide is white and the pawn is on files A-D
Square wksq = normalize(pos, strongSide, pos.king_square(strongSide));
Square bksq = normalize(pos, strongSide, pos.king_square(weakSide));
Square psq = normalize(pos, strongSide, pos.list<PAWN>(strongSide)[0]);
Square wksq = normalize(pos, strongSide, pos.square<KING>(strongSide));
Square bksq = normalize(pos, strongSide, pos.square<KING>(weakSide));
Square psq = normalize(pos, strongSide, pos.square<PAWN>(strongSide));
Color us = strongSide == pos.side_to_move() ? WHITE : BLACK;
@@ -237,10 +232,10 @@ Value Endgame<KRKP>::operator()(const Position& pos) const {
assert(verify_material(pos, strongSide, RookValueMg, 0));
assert(verify_material(pos, weakSide, VALUE_ZERO, 1));
Square wksq = relative_square(strongSide, pos.king_square(strongSide));
Square bksq = relative_square(strongSide, pos.king_square(weakSide));
Square rsq = relative_square(strongSide, pos.list<ROOK>(strongSide)[0]);
Square psq = relative_square(strongSide, pos.list<PAWN>(weakSide)[0]);
Square wksq = relative_square(strongSide, pos.square<KING>(strongSide));
Square bksq = relative_square(strongSide, pos.square<KING>(weakSide));
Square rsq = relative_square(strongSide, pos.square<ROOK>(strongSide));
Square psq = relative_square(strongSide, pos.square<PAWN>(weakSide));
Square queeningSq = make_square(file_of(psq), RANK_1);
Value result;
@@ -264,8 +259,8 @@ Value Endgame<KRKP>::operator()(const Position& pos) const {
result = Value(80) - 8 * distance(wksq, psq);
else
result = Value(200) - 8 * ( distance(wksq, psq + DELTA_S)
- distance(bksq, psq + DELTA_S)
result = Value(200) - 8 * ( distance(wksq, psq + SOUTH)
- distance(bksq, psq + SOUTH)
- distance(psq, queeningSq));
return strongSide == pos.side_to_move() ? result : -result;
@@ -280,7 +275,7 @@ Value Endgame<KRKB>::operator()(const Position& pos) const {
assert(verify_material(pos, strongSide, RookValueMg, 0));
assert(verify_material(pos, weakSide, BishopValueMg, 0));
Value result = Value(PushToEdges[pos.king_square(weakSide)]);
Value result = Value(PushToEdges[pos.square<KING>(weakSide)]);
return strongSide == pos.side_to_move() ? result : -result;
}
@@ -293,8 +288,8 @@ Value Endgame<KRKN>::operator()(const Position& pos) const {
assert(verify_material(pos, strongSide, RookValueMg, 0));
assert(verify_material(pos, weakSide, KnightValueMg, 0));
Square bksq = pos.king_square(weakSide);
Square bnsq = pos.list<KNIGHT>(weakSide)[0];
Square bksq = pos.square<KING>(weakSide);
Square bnsq = pos.square<KNIGHT>(weakSide);
Value result = Value(PushToEdges[bksq] + PushAway[distance(bksq, bnsq)]);
return strongSide == pos.side_to_move() ? result : -result;
}
@@ -310,9 +305,9 @@ Value Endgame<KQKP>::operator()(const Position& pos) const {
assert(verify_material(pos, strongSide, QueenValueMg, 0));
assert(verify_material(pos, weakSide, VALUE_ZERO, 1));
Square winnerKSq = pos.king_square(strongSide);
Square loserKSq = pos.king_square(weakSide);
Square pawnSq = pos.list<PAWN>(weakSide)[0];
Square winnerKSq = pos.square<KING>(strongSide);
Square loserKSq = pos.square<KING>(weakSide);
Square pawnSq = pos.square<PAWN>(weakSide);
Value result = Value(PushClose[distance(winnerKSq, loserKSq)]);
@@ -335,8 +330,8 @@ Value Endgame<KQKR>::operator()(const Position& pos) const {
assert(verify_material(pos, strongSide, QueenValueMg, 0));
assert(verify_material(pos, weakSide, RookValueMg, 0));
Square winnerKSq = pos.king_square(strongSide);
Square loserKSq = pos.king_square(weakSide);
Square winnerKSq = pos.square<KING>(strongSide);
Square loserKSq = pos.square<KING>(weakSide);
Value result = QueenValueEg
- RookValueEg
@@ -365,15 +360,15 @@ ScaleFactor Endgame<KBPsK>::operator()(const Position& pos) const {
// be detected even when the weaker side has some pawns.
Bitboard pawns = pos.pieces(strongSide, PAWN);
File pawnFile = file_of(pos.list<PAWN>(strongSide)[0]);
File pawnsFile = file_of(lsb(pawns));
// All pawns are on a single rook file ?
if ( (pawnFile == FILE_A || pawnFile == FILE_H)
&& !(pawns & ~file_bb(pawnFile)))
// All pawns are on a single rook file?
if ( (pawnsFile == FILE_A || pawnsFile == FILE_H)
&& !(pawns & ~file_bb(pawnsFile)))
{
Square bishopSq = pos.list<BISHOP>(strongSide)[0];
Square queeningSq = relative_square(strongSide, make_square(pawnFile, RANK_8));
Square kingSq = pos.king_square(weakSide);
Square bishopSq = pos.square<BISHOP>(strongSide);
Square queeningSq = relative_square(strongSide, make_square(pawnsFile, RANK_8));
Square kingSq = pos.square<KING>(weakSide);
if ( opposite_colors(queeningSq, bishopSq)
&& distance(queeningSq, kingSq) <= 1)
@@ -381,17 +376,17 @@ ScaleFactor Endgame<KBPsK>::operator()(const Position& pos) const {
}
// If all the pawns are on the same B or G file, then it's potentially a draw
if ( (pawnFile == FILE_B || pawnFile == FILE_G)
&& !(pos.pieces(PAWN) & ~file_bb(pawnFile))
if ( (pawnsFile == FILE_B || pawnsFile == FILE_G)
&& !(pos.pieces(PAWN) & ~file_bb(pawnsFile))
&& pos.non_pawn_material(weakSide) == 0
&& pos.count<PAWN>(weakSide) >= 1)
{
// Get weakSide pawn that is closest to the home rank
Square weakPawnSq = backmost_sq(weakSide, pos.pieces(weakSide, PAWN));
Square strongKingSq = pos.king_square(strongSide);
Square weakKingSq = pos.king_square(weakSide);
Square bishopSq = pos.list<BISHOP>(strongSide)[0];
Square strongKingSq = pos.square<KING>(strongSide);
Square weakKingSq = pos.square<KING>(weakSide);
Square bishopSq = pos.square<BISHOP>(strongSide);
// There's potential for a draw if our pawn is blocked on the 7th rank,
// the bishop cannot attack it or they only have one pawn left
@@ -428,11 +423,11 @@ ScaleFactor Endgame<KQKRPs>::operator()(const Position& pos) const {
assert(pos.count<ROOK>(weakSide) == 1);
assert(pos.count<PAWN>(weakSide) >= 1);
Square kingSq = pos.king_square(weakSide);
Square rsq = pos.list<ROOK>(weakSide)[0];
Square kingSq = pos.square<KING>(weakSide);
Square rsq = pos.square<ROOK>(weakSide);
if ( relative_rank(weakSide, kingSq) <= RANK_2
&& relative_rank(weakSide, pos.king_square(strongSide)) >= RANK_4
&& relative_rank(weakSide, pos.square<KING>(strongSide)) >= RANK_4
&& relative_rank(weakSide, rsq) == RANK_3
&& ( pos.pieces(weakSide, PAWN)
& pos.attacks_from<KING>(kingSq)
@@ -456,11 +451,11 @@ ScaleFactor Endgame<KRPKR>::operator()(const Position& pos) const {
assert(verify_material(pos, weakSide, RookValueMg, 0));
// Assume strongSide is white and the pawn is on files A-D
Square wksq = normalize(pos, strongSide, pos.king_square(strongSide));
Square bksq = normalize(pos, strongSide, pos.king_square(weakSide));
Square wrsq = normalize(pos, strongSide, pos.list<ROOK>(strongSide)[0]);
Square wpsq = normalize(pos, strongSide, pos.list<PAWN>(strongSide)[0]);
Square brsq = normalize(pos, strongSide, pos.list<ROOK>(weakSide)[0]);
Square wksq = normalize(pos, strongSide, pos.square<KING>(strongSide));
Square bksq = normalize(pos, strongSide, pos.square<KING>(weakSide));
Square wrsq = normalize(pos, strongSide, pos.square<ROOK>(strongSide));
Square wpsq = normalize(pos, strongSide, pos.square<PAWN>(strongSide));
Square brsq = normalize(pos, strongSide, pos.square<ROOK>(weakSide));
File f = file_of(wpsq);
Rank r = rank_of(wpsq);
@@ -480,7 +475,7 @@ ScaleFactor Endgame<KRPKR>::operator()(const Position& pos) const {
if ( r == RANK_6
&& distance(bksq, queeningSq) <= 1
&& rank_of(wksq) + tempo <= RANK_6
&& (rank_of(brsq) == RANK_1 || (!tempo && distance(file_of(brsq), f) >= 3)))
&& (rank_of(brsq) == RANK_1 || (!tempo && distance<File>(brsq, wpsq) >= 3)))
return SCALE_FACTOR_DRAW;
if ( r >= RANK_6
@@ -501,7 +496,7 @@ ScaleFactor Endgame<KRPKR>::operator()(const Position& pos) const {
// If the defending king blocks the pawn and the attacking king is too far
// away, it's a draw.
if ( r <= RANK_5
&& bksq == wpsq + DELTA_N
&& bksq == wpsq + NORTH
&& distance(wksq, wpsq) - tempo >= 2
&& distance(wksq, brsq) - tempo >= 2)
return SCALE_FACTOR_DRAW;
@@ -522,10 +517,10 @@ ScaleFactor Endgame<KRPKR>::operator()(const Position& pos) const {
&& file_of(wrsq) == f
&& wrsq < wpsq
&& (distance(wksq, queeningSq) < distance(bksq, queeningSq) - 2 + tempo)
&& (distance(wksq, wpsq + DELTA_N) < distance(bksq, wpsq + DELTA_N) - 2 + tempo)
&& (distance(wksq, wpsq + NORTH) < distance(bksq, wpsq + NORTH) - 2 + tempo)
&& ( distance(bksq, wrsq) + tempo >= 3
|| ( distance(wksq, queeningSq) < distance(bksq, wrsq) + tempo
&& (distance(wksq, wpsq + DELTA_N) < distance(bksq, wrsq) + tempo))))
&& (distance(wksq, wpsq + NORTH) < distance(bksq, wrsq) + tempo))))
return ScaleFactor( SCALE_FACTOR_MAX
- 8 * distance(wpsq, queeningSq)
- 2 * distance(wksq, queeningSq));
@@ -552,9 +547,9 @@ ScaleFactor Endgame<KRPKB>::operator()(const Position& pos) const {
// Test for a rook pawn
if (pos.pieces(PAWN) & (FileABB | FileHBB))
{
Square ksq = pos.king_square(weakSide);
Square bsq = pos.list<BISHOP>(weakSide)[0];
Square psq = pos.list<PAWN>(strongSide)[0];
Square ksq = pos.square<KING>(weakSide);
Square bsq = pos.square<BISHOP>(weakSide);
Square psq = pos.square<PAWN>(strongSide);
Rank rk = relative_rank(strongSide, psq);
Square push = pawn_push(strongSide);
@@ -567,7 +562,7 @@ ScaleFactor Endgame<KRPKB>::operator()(const Position& pos) const {
{
int d = distance(psq + 3 * push, ksq);
if (d <= 2 && !(d == 0 && ksq == pos.king_square(strongSide) + 2 * push))
if (d <= 2 && !(d == 0 && ksq == pos.square<KING>(strongSide) + 2 * push))
return ScaleFactor(24);
else
return ScaleFactor(48);
@@ -595,9 +590,9 @@ ScaleFactor Endgame<KRPPKRP>::operator()(const Position& pos) const {
assert(verify_material(pos, strongSide, RookValueMg, 2));
assert(verify_material(pos, weakSide, RookValueMg, 1));
Square wpsq1 = pos.list<PAWN>(strongSide)[0];
Square wpsq2 = pos.list<PAWN>(strongSide)[1];
Square bksq = pos.king_square(weakSide);
Square wpsq1 = pos.squares<PAWN>(strongSide)[0];
Square wpsq2 = pos.squares<PAWN>(strongSide)[1];
Square bksq = pos.square<KING>(weakSide);
// Does the stronger side have a passed pawn?
if (pos.pawn_passed(strongSide, wpsq1) || pos.pawn_passed(strongSide, wpsq2))
@@ -609,14 +604,8 @@ ScaleFactor Endgame<KRPPKRP>::operator()(const Position& pos) const {
&& distance<File>(bksq, wpsq2) <= 1
&& relative_rank(strongSide, bksq) > r)
{
switch (r) {
case RANK_2: return ScaleFactor(10);
case RANK_3: return ScaleFactor(10);
case RANK_4: return ScaleFactor(15);
case RANK_5: return ScaleFactor(20);
case RANK_6: return ScaleFactor(40);
default: assert(false);
}
assert(r > RANK_1 && r < RANK_7);
return ScaleFactor(KRPPKRPScaleFactors[r]);
}
return SCALE_FACTOR_NONE;
}
@@ -631,15 +620,14 @@ ScaleFactor Endgame<KPsK>::operator()(const Position& pos) const {
assert(pos.count<PAWN>(strongSide) >= 2);
assert(verify_material(pos, weakSide, VALUE_ZERO, 0));
Square ksq = pos.king_square(weakSide);
Square ksq = pos.square<KING>(weakSide);
Bitboard pawns = pos.pieces(strongSide, PAWN);
Square psq = pos.list<PAWN>(strongSide)[0];
// If all pawns are ahead of the king, on a single rook file and
// the king is within one file of the pawns, it's a draw.
if ( !(pawns & ~in_front_bb(weakSide, rank_of(ksq)))
&& !((pawns & ~FileABB) && (pawns & ~FileHBB))
&& distance<File>(ksq, psq) <= 1)
&& distance<File>(ksq, lsb(pawns)) <= 1)
return SCALE_FACTOR_DRAW;
return SCALE_FACTOR_NONE;
@@ -656,10 +644,10 @@ ScaleFactor Endgame<KBPKB>::operator()(const Position& pos) const {
assert(verify_material(pos, strongSide, BishopValueMg, 1));
assert(verify_material(pos, weakSide, BishopValueMg, 0));
Square pawnSq = pos.list<PAWN>(strongSide)[0];
Square strongBishopSq = pos.list<BISHOP>(strongSide)[0];
Square weakBishopSq = pos.list<BISHOP>(weakSide)[0];
Square weakKingSq = pos.king_square(weakSide);
Square pawnSq = pos.square<PAWN>(strongSide);
Square strongBishopSq = pos.square<BISHOP>(strongSide);
Square weakBishopSq = pos.square<BISHOP>(weakSide);
Square weakKingSq = pos.square<KING>(weakSide);
// Case 1: Defending king blocks the pawn, and cannot be driven away
if ( file_of(weakKingSq) == file_of(pawnSq)
@@ -706,15 +694,15 @@ ScaleFactor Endgame<KBPPKB>::operator()(const Position& pos) const {
assert(verify_material(pos, strongSide, BishopValueMg, 2));
assert(verify_material(pos, weakSide, BishopValueMg, 0));
Square wbsq = pos.list<BISHOP>(strongSide)[0];
Square bbsq = pos.list<BISHOP>(weakSide)[0];
Square wbsq = pos.square<BISHOP>(strongSide);
Square bbsq = pos.square<BISHOP>(weakSide);
if (!opposite_colors(wbsq, bbsq))
return SCALE_FACTOR_NONE;
Square ksq = pos.king_square(weakSide);
Square psq1 = pos.list<PAWN>(strongSide)[0];
Square psq2 = pos.list<PAWN>(strongSide)[1];
Square ksq = pos.square<KING>(weakSide);
Square psq1 = pos.squares<PAWN>(strongSide)[0];
Square psq2 = pos.squares<PAWN>(strongSide)[1];
Rank r1 = rank_of(psq1);
Rank r2 = rank_of(psq2);
Square blockSq1, blockSq2;
@@ -777,9 +765,9 @@ ScaleFactor Endgame<KBPKN>::operator()(const Position& pos) const {
assert(verify_material(pos, strongSide, BishopValueMg, 1));
assert(verify_material(pos, weakSide, KnightValueMg, 0));
Square pawnSq = pos.list<PAWN>(strongSide)[0];
Square strongBishopSq = pos.list<BISHOP>(strongSide)[0];
Square weakKingSq = pos.king_square(weakSide);
Square pawnSq = pos.square<PAWN>(strongSide);
Square strongBishopSq = pos.square<BISHOP>(strongSide);
Square weakKingSq = pos.square<KING>(weakSide);
if ( file_of(weakKingSq) == file_of(pawnSq)
&& relative_rank(strongSide, pawnSq) < relative_rank(strongSide, weakKingSq)
@@ -800,8 +788,8 @@ ScaleFactor Endgame<KNPK>::operator()(const Position& pos) const {
assert(verify_material(pos, weakSide, VALUE_ZERO, 0));
// Assume strongSide is white and the pawn is on files A-D
Square pawnSq = normalize(pos, strongSide, pos.list<PAWN>(strongSide)[0]);
Square weakKingSq = normalize(pos, strongSide, pos.king_square(weakSide));
Square pawnSq = normalize(pos, strongSide, pos.square<PAWN>(strongSide));
Square weakKingSq = normalize(pos, strongSide, pos.square<KING>(weakSide));
if (pawnSq == SQ_A7 && distance(SQ_A8, weakKingSq) <= 1)
return SCALE_FACTOR_DRAW;
@@ -815,9 +803,9 @@ ScaleFactor Endgame<KNPK>::operator()(const Position& pos) const {
template<>
ScaleFactor Endgame<KNPKB>::operator()(const Position& pos) const {
Square pawnSq = pos.list<PAWN>(strongSide)[0];
Square bishopSq = pos.list<BISHOP>(weakSide)[0];
Square weakKingSq = pos.king_square(weakSide);
Square pawnSq = pos.square<PAWN>(strongSide);
Square bishopSq = pos.square<BISHOP>(weakSide);
Square weakKingSq = pos.square<KING>(weakSide);
// King needs to get close to promoting pawn to prevent knight from blocking.
// Rules for this are very tricky, so just approximate.
@@ -840,9 +828,9 @@ ScaleFactor Endgame<KPKP>::operator()(const Position& pos) const {
assert(verify_material(pos, weakSide, VALUE_ZERO, 1));
// Assume strongSide is white and the pawn is on files A-D
Square wksq = normalize(pos, strongSide, pos.king_square(strongSide));
Square bksq = normalize(pos, strongSide, pos.king_square(weakSide));
Square psq = normalize(pos, strongSide, pos.list<PAWN>(strongSide)[0]);
Square wksq = normalize(pos, strongSide, pos.square<KING>(strongSide));
Square bksq = normalize(pos, strongSide, pos.square<KING>(weakSide));
Square psq = normalize(pos, strongSide, pos.square<PAWN>(strongSide));
Color us = strongSide == pos.side_to_move() ? WHITE : BLACK;
+20 -17
View File
@@ -2,6 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -21,7 +22,10 @@
#define ENDGAME_H_INCLUDED
#include <map>
#include <memory>
#include <string>
#include <type_traits>
#include <utility>
#include "position.h"
#include "types.h"
@@ -63,11 +67,9 @@ enum EndgameType {
/// Endgame functions can be of two types depending on whether they return a
/// Value or a ScaleFactor. Type eg_fun<int>::type returns either ScaleFactor
/// or Value depending on whether the template parameter is 0 or 1.
template<int> struct eg_fun { typedef Value type; };
template<> struct eg_fun<1> { typedef ScaleFactor type; };
/// Value or a ScaleFactor.
template<EndgameType E> using
eg_type = typename std::conditional<(E < SCALING_FUNCTIONS), Value, ScaleFactor>::type;
/// Base and derived templates for endgame evaluation and scaling functions
@@ -75,13 +77,13 @@ template<> struct eg_fun<1> { typedef ScaleFactor type; };
template<typename T>
struct EndgameBase {
virtual ~EndgameBase() {}
virtual ~EndgameBase() = default;
virtual Color strong_side() const = 0;
virtual T operator()(const Position&) const = 0;
};
template<EndgameType E, typename T = typename eg_fun<(E > SCALING_FUNCTIONS)>::type>
template<EndgameType E, typename T = eg_type<E>>
struct Endgame : public EndgameBase<T> {
explicit Endgame(Color c) : strongSide(c), weakSide(~c) {}
@@ -99,23 +101,24 @@ private:
class Endgames {
typedef std::map<Key, EndgameBase<eg_fun<0>::type>*> M1;
typedef std::map<Key, EndgameBase<eg_fun<1>::type>*> M2;
template<typename T> using Map = std::map<Key, std::unique_ptr<EndgameBase<T>>>;
M1 m1;
M2 m2;
template<EndgameType E, typename T = eg_type<E>>
void add(const std::string& code);
M1& map(M1::mapped_type) { return m1; }
M2& map(M2::mapped_type) { return m2; }
template<typename T>
Map<T>& map() {
return std::get<std::is_same<T, ScaleFactor>::value>(maps);
}
template<EndgameType E> void add(const std::string& code);
std::pair<Map<Value>, Map<ScaleFactor>> maps;
public:
Endgames();
~Endgames();
template<typename T> T probe(Key key, T& eg) {
return eg = map(eg).count(key) ? map(eg)[key] : NULL;
template<typename T>
EndgameBase<T>* probe(Key key) {
return map<T>().count(key) ? map<T>()[key].get() : nullptr;
}
};
+528 -506
View File
File diff suppressed because it is too large Load Diff
+4 -3
View File
@@ -2,6 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -28,12 +29,12 @@ class Position;
namespace Eval {
const Value Tempo = Value(17); // Must be visible to search
const Value Tempo = Value(20); // Must be visible to search
void init();
Value evaluate(const Position& pos);
std::string trace(const Position& pos);
template<bool DoTrace = false>
Value evaluate(const Position& pos);
}
#endif // #ifndef EVALUATE_H_INCLUDED
+7 -2
View File
@@ -2,6 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,7 +21,6 @@
#include <iostream>
#include "bitboard.h"
#include "evaluate.h"
#include "position.h"
#include "search.h"
#include "thread.h"
@@ -28,16 +28,20 @@
#include "uci.h"
#include "syzygy/tbprobe.h"
namespace PSQT {
void init();
}
int main(int argc, char* argv[]) {
std::cout << engine_info() << std::endl;
UCI::init(Options);
PSQT::init();
Bitboards::init();
Position::init();
Bitbases::init();
Search::init();
Eval::init();
Pawns::init();
Threads.init();
Tablebases::init(Options["SyzygyPath"]);
@@ -46,4 +50,5 @@ int main(int argc, char* argv[]) {
UCI::loop(argc, argv);
Threads.exit();
return 0;
}
+44 -57
View File
@@ -2,6 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -30,29 +31,26 @@ namespace {
// Polynomial material imbalance parameters
// pair pawn knight bishop rook queen
const int Linear[6] = { 1852, -162, -1122, -183, 249, -154 };
const int QuadraticOurs[][PIECE_TYPE_NB] = {
// OUR PIECES
// 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
{1667 }, // Bishop pair
{ 40, 2 }, // Pawn
{ 32, 255, -3 }, // Knight OUR PIECES
{ 0, 104, 4, 0 }, // Bishop
{ -26, -2, 47, 105, -149 }, // Rook
{-185, 24, 122, 137, -134, 0 } // Queen
};
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
{ 36, 0 }, // Pawn
{ 9, 63, 0 }, // Knight OUR PIECES
{ 59, 65, 42, 0 }, // Bishop
{ 46, 39, 24, -24, 0 }, // Rook
{ 101, 100, -37, 141, 268, 0 } // Queen
};
// Endgame evaluation and scaling functions are accessed directly and not through
@@ -64,31 +62,28 @@ namespace {
Endgame<KPsK> ScaleKPsK[] = { Endgame<KPsK>(WHITE), Endgame<KPsK>(BLACK) };
Endgame<KPKP> ScaleKPKP[] = { Endgame<KPKP>(WHITE), Endgame<KPKP>(BLACK) };
// Helper templates used to detect a given material distribution
template<Color Us> bool is_KXK(const Position& pos) {
const Color Them = (Us == WHITE ? BLACK : WHITE);
return !more_than_one(pos.pieces(Them))
&& pos.non_pawn_material(Us) >= RookValueMg;
// Helper used to detect a given material distribution
bool is_KXK(const Position& pos, Color us) {
return !more_than_one(pos.pieces(~us))
&& pos.non_pawn_material(us) >= RookValueMg;
}
template<Color Us> bool is_KBPsKs(const Position& pos) {
return pos.non_pawn_material(Us) == BishopValueMg
&& pos.count<BISHOP>(Us) == 1
&& pos.count<PAWN >(Us) >= 1;
bool is_KBPsKs(const Position& pos, Color us) {
return pos.non_pawn_material(us) == BishopValueMg
&& pos.count<BISHOP>(us) == 1
&& pos.count<PAWN >(us) >= 1;
}
template<Color Us> bool is_KQKRPs(const Position& pos) {
const Color Them = (Us == WHITE ? BLACK : WHITE);
return !pos.count<PAWN>(Us)
&& pos.non_pawn_material(Us) == QueenValueMg
&& pos.count<QUEEN>(Us) == 1
&& pos.count<ROOK>(Them) == 1
&& pos.count<PAWN>(Them) >= 1;
bool is_KQKRPs(const Position& pos, Color us) {
return !pos.count<PAWN>(us)
&& pos.non_pawn_material(us) == QueenValueMg
&& pos.count<QUEEN>(us) == 1
&& pos.count<ROOK>(~us) == 1
&& pos.count<PAWN>(~us) >= 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]) {
@@ -102,7 +97,7 @@ namespace {
if (!pieceCount[Us][pt1])
continue;
int v = Linear[pt1];
int v = 0;
for (int pt2 = NO_PIECE_TYPE; pt2 <= pt1; ++pt2)
v += QuadraticOurs[pt1][pt2] * pieceCount[Us][pt2]
@@ -139,26 +134,21 @@ Entry* probe(const Position& pos) {
// Let's look if we have a specialized evaluation function for this particular
// material configuration. Firstly we look for a fixed configuration one, then
// for a generic one if the previous search failed.
if (pos.this_thread()->endgames.probe(key, e->evaluationFunction))
if ((e->evaluationFunction = pos.this_thread()->endgames.probe<Value>(key)) != nullptr)
return e;
if (is_KXK<WHITE>(pos))
{
e->evaluationFunction = &EvaluateKXK[WHITE];
return e;
}
if (is_KXK<BLACK>(pos))
{
e->evaluationFunction = &EvaluateKXK[BLACK];
return e;
}
for (Color c = WHITE; c <= BLACK; ++c)
if (is_KXK(pos, c))
{
e->evaluationFunction = &EvaluateKXK[c];
return e;
}
// OK, we didn't find any special evaluation function for the current material
// configuration. Is there a suitable specialized scaling function?
EndgameBase<ScaleFactor>* sf;
if (pos.this_thread()->endgames.probe(key, sf))
if ((sf = pos.this_thread()->endgames.probe<ScaleFactor>(key)) != nullptr)
{
e->scalingFunction[sf->strong_side()] = sf; // Only strong color assigned
return e;
@@ -167,17 +157,14 @@ Entry* probe(const Position& pos) {
// We didn't find any specialized scaling function, so fall back on generic
// ones that refer to more than one material distribution. Note that in this
// case we don't return after setting the function.
if (is_KBPsKs<WHITE>(pos))
e->scalingFunction[WHITE] = &ScaleKBPsK[WHITE];
for (Color c = WHITE; c <= BLACK; ++c)
{
if (is_KBPsKs(pos, c))
e->scalingFunction[c] = &ScaleKBPsK[c];
if (is_KBPsKs<BLACK>(pos))
e->scalingFunction[BLACK] = &ScaleKBPsK[BLACK];
if (is_KQKRPs<WHITE>(pos))
e->scalingFunction[WHITE] = &ScaleKQKRPs[WHITE];
else if (is_KQKRPs<BLACK>(pos))
e->scalingFunction[BLACK] = &ScaleKQKRPs[BLACK];
else if (is_KQKRPs(pos, c))
e->scalingFunction[c] = &ScaleKQKRPs[c];
}
Value npm_w = pos.non_pawn_material(WHITE);
Value npm_b = pos.non_pawn_material(BLACK);
@@ -210,11 +197,11 @@ Entry* probe(const Position& pos) {
// drawish scale factor for cases such as KRKBP and KmmKm (except for KBBKN).
if (!pos.count<PAWN>(WHITE) && npm_w - npm_b <= BishopValueMg)
e->factor[WHITE] = uint8_t(npm_w < RookValueMg ? SCALE_FACTOR_DRAW :
npm_b <= BishopValueMg ? 4 : 12);
npm_b <= BishopValueMg ? 4 : 14);
if (!pos.count<PAWN>(BLACK) && npm_b - npm_w <= BishopValueMg)
e->factor[BLACK] = uint8_t(npm_b < RookValueMg ? SCALE_FACTOR_DRAW :
npm_w <= BishopValueMg ? 4 : 12);
npm_w <= BishopValueMg ? 4 : 14);
if (pos.count<PAWN>(WHITE) == 1 && npm_w - npm_b <= BishopValueMg)
e->factor[WHITE] = (uint8_t) SCALE_FACTOR_ONEPAWN;
+5 -4
View File
@@ -2,6 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -40,7 +41,7 @@ struct Entry {
Score imbalance() const { return make_score(value, value); }
Phase game_phase() const { return gamePhase; }
bool specialized_eval_exists() const { return evaluationFunction != NULL; }
bool specialized_eval_exists() const { return evaluationFunction != nullptr; }
Value evaluate(const Position& pos) const { return (*evaluationFunction)(pos); }
// scale_factor takes a position and a color as input and returns a scale factor
@@ -49,9 +50,9 @@ struct Entry {
// the position. For instance, in KBP vs K endgames, the scaling function looks
// for rook pawns and wrong-colored bishops.
ScaleFactor scale_factor(const Position& pos, Color c) const {
return !scalingFunction[c]
|| (*scalingFunction[c])(pos) == SCALE_FACTOR_NONE ? ScaleFactor(factor[c])
: (*scalingFunction[c])(pos);
ScaleFactor sf = scalingFunction[c] ? (*scalingFunction[c])(pos)
: SCALE_FACTOR_NONE;
return sf != SCALE_FACTOR_NONE ? sf : ScaleFactor(factor[c]);
}
Key key;
+23 -44
View File
@@ -2,6 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -31,60 +32,56 @@ namespace {
/// Version number. If Version is left empty, then compile date in the format
/// DD-MM-YY and show in engine_info.
const string Version = "6";
/// Debug counters
int64_t hits[2], means[2];
const string Version = "8";
/// 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
/// can toggle the logging of std::cout and std:cin at runtime whilst preserving
/// usual i/o functionality, all 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
struct Tie: public streambuf { // MSVC requires splitted streambuf for cin and cout
struct Tie: public streambuf { // MSVC requires split streambuf for cin and cout
Tie(streambuf* b, ofstream* f) : buf(b), file(f) {}
Tie(streambuf* b, streambuf* l) : buf(b), logBuf(l) {}
int sync() { return file->rdbuf()->pubsync(), buf->pubsync(); }
int sync() { return logBuf->pubsync(), buf->pubsync(); }
int overflow(int c) { return log(buf->sputc((char)c), "<< "); }
int underflow() { return buf->sgetc(); }
int uflow() { return log(buf->sbumpc(), ">> "); }
streambuf* buf;
ofstream* file;
streambuf *buf, *logBuf;
int log(int c, const char* prefix) {
static int last = '\n';
static int last = '\n'; // Single log file
if (last == '\n')
file->rdbuf()->sputn(prefix, 3);
logBuf->sputn(prefix, 3);
return last = file->rdbuf()->sputc((char)c);
return last = logBuf->sputc((char)c);
}
};
class Logger {
Logger() : in(cin.rdbuf(), &file), out(cout.rdbuf(), &file) {}
~Logger() { start(false); }
Logger() : in(cin.rdbuf(), file.rdbuf()), out(cout.rdbuf(), file.rdbuf()) {}
~Logger() { start(""); }
ofstream file;
Tie in, out;
public:
static void start(bool b) {
static void start(const std::string& fname) {
static Logger l;
if (b && !l.file.is_open())
if (!fname.empty() && !l.file.is_open())
{
l.file.open("io_log.txt", ifstream::out | ifstream::app);
l.file.open(fname, ifstream::out);
cin.rdbuf(&l.in);
cout.rdbuf(&l.out);
}
else if (!b && l.file.is_open())
else if (fname.empty() && l.file.is_open())
{
cout.rdbuf(l.out.buf);
cin.rdbuf(l.in.buf);
@@ -117,16 +114,17 @@ const string engine_info(bool to_uci) {
ss << (Is64Bit ? " 64" : "")
<< (HasPext ? " BMI2" : (HasPopCnt ? " POPCNT" : ""))
<< (to_uci ? "\nid author ": " by ")
<< "Tord Romstad, Marco Costalba and Joona Kiiski";
<< "T. Romstad, M. Costalba, J. Kiiski, G. Linscott";
return ss.str();
}
/// Debug functions used mainly to collect run-time statistics
static int64_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_hit_on(bool c, bool b) { if (c) dbg_hit_on(b); }
void dbg_mean_of(int v) { ++means[0]; means[1] += v; }
void dbg_print() {
@@ -159,26 +157,7 @@ std::ostream& operator<<(std::ostream& os, SyncCout sc) {
/// Trampoline helper to avoid moving Logger to misc.h
void start_logger(bool b) { Logger::start(b); }
/// timed_wait() waits for msec milliseconds. It is mainly a helper to wrap
/// the conversion from milliseconds to struct timespec, as used by pthreads.
void timed_wait(WaitCondition& sleepCond, Lock& sleepLock, int msec) {
#ifdef _WIN32
int tm = msec;
#else
timespec ts, *tm = &ts;
uint64_t ms = Time::now() + msec;
ts.tv_sec = ms / 1000;
ts.tv_nsec = (ms % 1000) * 1000000LL;
#endif
cond_timedwait(sleepCond, sleepLock, tm);
}
void start_logger(const std::string& fname) { Logger::start(fname); }
/// prefetch() preloads the given address in L1/L2 cache. This is a non-blocking
@@ -186,11 +165,11 @@ void timed_wait(WaitCondition& sleepCond, Lock& sleepLock, int msec) {
/// which can be quite slow.
#ifdef NO_PREFETCH
void prefetch(char*) {}
void prefetch(void*) {}
#else
void prefetch(char* addr) {
void prefetch(void* addr) {
# if defined(__INTEL_COMPILER)
// This hack prevents prefetches from being optimized away by
@@ -199,7 +178,7 @@ void prefetch(char* addr) {
# endif
# if defined(__INTEL_COMPILER) || defined(_MSC_VER)
_mm_prefetch(addr, _MM_HINT_T0);
_mm_prefetch((char*)addr, _MM_HINT_T0);
# else
__builtin_prefetch(addr);
# endif
+10 -10
View File
@@ -2,6 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -21,6 +22,7 @@
#define MISC_H_INCLUDED
#include <cassert>
#include <chrono>
#include <ostream>
#include <string>
#include <vector>
@@ -28,29 +30,27 @@
#include "types.h"
const std::string engine_info(bool to_uci = false);
void timed_wait(WaitCondition&, Lock&, int);
void prefetch(char* addr);
void start_logger(bool b);
void prefetch(void* addr);
void start_logger(const std::string& fname);
void dbg_hit_on(bool b);
void dbg_hit_on_c(bool c, bool b);
void dbg_hit_on(bool c, bool b);
void dbg_mean_of(int v);
void dbg_print();
typedef std::chrono::milliseconds::rep TimePoint; // A value in milliseconds
namespace Time {
typedef int64_t point;
inline point now() { return system_time_to_msec(); }
inline TimePoint now() {
return std::chrono::duration_cast<std::chrono::milliseconds>
(std::chrono::steady_clock::now().time_since_epoch()).count();
}
template<class Entry, int Size>
struct HashTable {
HashTable() : table(Size, Entry()) {}
Entry* operator[](Key key) { return &table[(uint32_t)key & (Size - 1)]; }
private:
std::vector<Entry> table;
std::vector<Entry> table = std::vector<Entry>(Size);
};
+80 -78
View File
@@ -2,6 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -25,7 +26,7 @@
namespace {
template<CastlingRight Cr, bool Checks, bool Chess960>
ExtMove* generate_castling(const Position& pos, ExtMove* moveList, Color us, const CheckInfo* ci) {
ExtMove* generate_castling(const Position& pos, ExtMove* moveList, Color us) {
static const bool KingSide = (Cr == WHITE_OO || Cr == BLACK_OO);
@@ -34,15 +35,15 @@ namespace {
// After castling, the rook and king final positions are the same in Chess960
// as they would be in standard chess.
Square kfrom = pos.king_square(us);
Square kfrom = pos.square<KING>(us);
Square rfrom = pos.castling_rook_square(Cr);
Square kto = relative_square(us, KingSide ? SQ_G1 : SQ_C1);
Bitboard enemies = pos.pieces(~us);
assert(!pos.checkers());
const Square K = Chess960 ? kto > kfrom ? DELTA_W : DELTA_E
: KingSide ? DELTA_W : DELTA_E;
const Square K = Chess960 ? kto > kfrom ? WEST : EAST
: KingSide ? WEST : EAST;
for (Square s = kto; s != kfrom; s += K)
if (pos.attackers_to(s) & enemies)
@@ -56,52 +57,50 @@ namespace {
Move m = make<CASTLING>(kfrom, rfrom);
if (Checks && !pos.gives_check(m, *ci))
if (Checks && !pos.gives_check(m))
return moveList;
(moveList++)->move = m;
*moveList++ = m;
return moveList;
}
template<GenType Type, Square Delta>
inline ExtMove* make_promotions(ExtMove* moveList, Square to, const CheckInfo* ci) {
template<GenType Type, Square D>
ExtMove* make_promotions(ExtMove* moveList, Square to, Square ksq) {
if (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS)
(moveList++)->move = make<PROMOTION>(to - Delta, to, QUEEN);
*moveList++ = make<PROMOTION>(to - D, to, QUEEN);
if (Type == QUIETS || Type == EVASIONS || Type == NON_EVASIONS)
{
(moveList++)->move = make<PROMOTION>(to - Delta, to, ROOK);
(moveList++)->move = make<PROMOTION>(to - Delta, to, BISHOP);
(moveList++)->move = make<PROMOTION>(to - Delta, to, KNIGHT);
*moveList++ = make<PROMOTION>(to - D, to, ROOK);
*moveList++ = make<PROMOTION>(to - D, to, BISHOP);
*moveList++ = make<PROMOTION>(to - D, to, KNIGHT);
}
// 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);
if (Type == QUIET_CHECKS && (StepAttacksBB[W_KNIGHT][to] & ksq))
*moveList++ = make<PROMOTION>(to - D, to, KNIGHT);
else
(void)ci; // Silence a warning under MSVC
(void)ksq; // Silence a warning under MSVC
return moveList;
}
template<Color Us, GenType Type>
ExtMove* generate_pawn_moves(const Position& pos, ExtMove* moveList,
Bitboard target, const CheckInfo* ci) {
ExtMove* generate_pawn_moves(const Position& pos, ExtMove* moveList, Bitboard target) {
// Compute our parametrized parameters at compile time, named according to
// the point of view of white side.
const Color Them = (Us == WHITE ? BLACK : WHITE);
const Bitboard TRank8BB = (Us == WHITE ? Rank8BB : Rank1BB);
const Bitboard TRank7BB = (Us == WHITE ? Rank7BB : Rank2BB);
const Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB);
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);
const Color Them = (Us == WHITE ? BLACK : WHITE);
const Bitboard TRank8BB = (Us == WHITE ? Rank8BB : Rank1BB);
const Bitboard TRank7BB = (Us == WHITE ? Rank7BB : Rank2BB);
const Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB);
const Square Up = (Us == WHITE ? NORTH : SOUTH);
const Square Right = (Us == WHITE ? NORTH_EAST : SOUTH_WEST);
const Square Left = (Us == WHITE ? NORTH_WEST : SOUTH_EAST);
Bitboard emptySquares;
@@ -116,8 +115,8 @@ namespace {
{
emptySquares = (Type == QUIETS || Type == QUIET_CHECKS ? target : ~pos.pieces());
Bitboard b1 = shift_bb<Up>(pawnsNotOn7) & emptySquares;
Bitboard b2 = shift_bb<Up>(b1 & TRank3BB) & emptySquares;
Bitboard b1 = shift<Up>(pawnsNotOn7) & emptySquares;
Bitboard b2 = shift<Up>(b1 & TRank3BB) & emptySquares;
if (Type == EVASIONS) // Consider only blocking squares
{
@@ -127,17 +126,20 @@ namespace {
if (Type == QUIET_CHECKS)
{
b1 &= pos.attacks_from<PAWN>(ci->ksq, Them);
b2 &= pos.attacks_from<PAWN>(ci->ksq, Them);
Square ksq = pos.square<KING>(Them);
b1 &= pos.attacks_from<PAWN>(ksq, Them);
b2 &= pos.attacks_from<PAWN>(ksq, Them);
// Add pawn pushes which give discovered check. This is possible only
// 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
// promotion has been already generated amongst the captures.
if (pawnsNotOn7 & ci->dcCandidates)
Bitboard dcCandidates = pos.discovered_check_candidates();
if (pawnsNotOn7 & dcCandidates)
{
Bitboard dc1 = shift_bb<Up>(pawnsNotOn7 & ci->dcCandidates) & emptySquares & ~file_bb(ci->ksq);
Bitboard dc2 = shift_bb<Up>(dc1 & TRank3BB) & emptySquares;
Bitboard dc1 = shift<Up>(pawnsNotOn7 & dcCandidates) & emptySquares & ~file_bb(ksq);
Bitboard dc2 = shift<Up>(dc1 & TRank3BB) & emptySquares;
b1 |= dc1;
b2 |= dc2;
@@ -147,13 +149,13 @@ namespace {
while (b1)
{
Square to = pop_lsb(&b1);
(moveList++)->move = make_move(to - Up, to);
*moveList++ = make_move(to - Up, to);
}
while (b2)
{
Square to = pop_lsb(&b2);
(moveList++)->move = make_move(to - Up - Up, to);
*moveList++ = make_move(to - Up - Up, to);
}
}
@@ -166,36 +168,38 @@ namespace {
if (Type == EVASIONS)
emptySquares &= target;
Bitboard b1 = shift_bb<Right>(pawnsOn7) & enemies;
Bitboard b2 = shift_bb<Left >(pawnsOn7) & enemies;
Bitboard b3 = shift_bb<Up >(pawnsOn7) & emptySquares;
Bitboard b1 = shift<Right>(pawnsOn7) & enemies;
Bitboard b2 = shift<Left >(pawnsOn7) & enemies;
Bitboard b3 = shift<Up >(pawnsOn7) & emptySquares;
Square ksq = pos.square<KING>(Them);
while (b1)
moveList = make_promotions<Type, Right>(moveList, pop_lsb(&b1), ci);
moveList = make_promotions<Type, Right>(moveList, pop_lsb(&b1), ksq);
while (b2)
moveList = make_promotions<Type, Left >(moveList, pop_lsb(&b2), ci);
moveList = make_promotions<Type, Left >(moveList, pop_lsb(&b2), ksq);
while (b3)
moveList = make_promotions<Type, Up >(moveList, pop_lsb(&b3), ci);
moveList = make_promotions<Type, Up >(moveList, pop_lsb(&b3), ksq);
}
// Standard and en-passant captures
if (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS)
{
Bitboard b1 = shift_bb<Right>(pawnsNotOn7) & enemies;
Bitboard b2 = shift_bb<Left >(pawnsNotOn7) & enemies;
Bitboard b1 = shift<Right>(pawnsNotOn7) & enemies;
Bitboard b2 = shift<Left >(pawnsNotOn7) & enemies;
while (b1)
{
Square to = pop_lsb(&b1);
(moveList++)->move = make_move(to - Right, to);
*moveList++ = make_move(to - Right, to);
}
while (b2)
{
Square to = pop_lsb(&b2);
(moveList++)->move = make_move(to - Left, to);
*moveList++ = make_move(to - Left, to);
}
if (pos.ep_square() != SQ_NONE)
@@ -213,7 +217,7 @@ namespace {
assert(b1);
while (b1)
(moveList++)->move = make<ENPASSANT>(pop_lsb(&b1), pos.ep_square());
*moveList++ = make<ENPASSANT>(pop_lsb(&b1), pos.ep_square());
}
}
@@ -221,70 +225,69 @@ namespace {
}
template<PieceType Pt, bool Checks> FORCE_INLINE
template<PieceType Pt, bool Checks>
ExtMove* generate_moves(const Position& pos, ExtMove* moveList, Color us,
Bitboard target, const CheckInfo* ci) {
Bitboard target) {
assert(Pt != KING && Pt != PAWN);
const Square* pl = pos.list<Pt>(us);
const Square* pl = pos.squares<Pt>(us);
for (Square from = *pl; from != SQ_NONE; from = *++pl)
{
if (Checks)
{
if ( (Pt == BISHOP || Pt == ROOK || Pt == QUEEN)
&& !(PseudoAttacks[Pt][from] & target & ci->checkSq[Pt]))
&& !(PseudoAttacks[Pt][from] & target & pos.check_squares(Pt)))
continue;
if (ci->dcCandidates && (ci->dcCandidates & from))
if (pos.discovered_check_candidates() & from)
continue;
}
Bitboard b = pos.attacks_from<Pt>(from) & target;
if (Checks)
b &= ci->checkSq[Pt];
b &= pos.check_squares(Pt);
while (b)
(moveList++)->move = make_move(from, pop_lsb(&b));
*moveList++ = make_move(from, pop_lsb(&b));
}
return moveList;
}
template<Color Us, GenType Type> FORCE_INLINE
ExtMove* generate_all(const Position& pos, ExtMove* moveList, Bitboard target,
const CheckInfo* ci = NULL) {
template<Color Us, GenType Type>
ExtMove* generate_all(const Position& pos, ExtMove* moveList, Bitboard target) {
const bool Checks = Type == QUIET_CHECKS;
moveList = generate_pawn_moves<Us, Type>(pos, moveList, target, ci);
moveList = generate_moves<KNIGHT, Checks>(pos, moveList, Us, target, ci);
moveList = generate_moves<BISHOP, Checks>(pos, moveList, Us, target, ci);
moveList = generate_moves< ROOK, Checks>(pos, moveList, Us, target, ci);
moveList = generate_moves< QUEEN, Checks>(pos, moveList, Us, target, ci);
moveList = generate_pawn_moves<Us, Type>(pos, moveList, target);
moveList = generate_moves<KNIGHT, Checks>(pos, moveList, Us, target);
moveList = generate_moves<BISHOP, Checks>(pos, moveList, Us, target);
moveList = generate_moves< ROOK, Checks>(pos, moveList, Us, target);
moveList = generate_moves< QUEEN, Checks>(pos, moveList, Us, target);
if (Type != QUIET_CHECKS && Type != EVASIONS)
{
Square ksq = pos.king_square(Us);
Square ksq = pos.square<KING>(Us);
Bitboard b = pos.attacks_from<KING>(ksq) & target;
while (b)
(moveList++)->move = make_move(ksq, pop_lsb(&b));
*moveList++ = make_move(ksq, pop_lsb(&b));
}
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);
moveList = generate_castling<MakeCastling<Us, KING_SIDE>::right, Checks, true>(pos, moveList, Us);
moveList = generate_castling<MakeCastling<Us, QUEEN_SIDE>::right, Checks, true>(pos, moveList, Us);
}
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);
moveList = generate_castling<MakeCastling<Us, KING_SIDE>::right, Checks, false>(pos, moveList, Us);
moveList = generate_castling<MakeCastling<Us, QUEEN_SIDE>::right, Checks, false>(pos, moveList, Us);
}
}
@@ -333,8 +336,7 @@ ExtMove* generate<QUIET_CHECKS>(const Position& pos, ExtMove* moveList) {
assert(!pos.checkers());
Color us = pos.side_to_move();
CheckInfo ci(pos);
Bitboard dc = ci.dcCandidates;
Bitboard dc = pos.discovered_check_candidates();
while (dc)
{
@@ -347,14 +349,14 @@ ExtMove* generate<QUIET_CHECKS>(const Position& pos, ExtMove* moveList) {
Bitboard b = pos.attacks_from(Piece(pt), from) & ~pos.pieces();
if (pt == KING)
b &= ~PseudoAttacks[QUEEN][ci.ksq];
b &= ~PseudoAttacks[QUEEN][pos.square<KING>(~us)];
while (b)
(moveList++)->move = make_move(from, pop_lsb(&b));
*moveList++ = make_move(from, pop_lsb(&b));
}
return us == WHITE ? generate_all<WHITE, QUIET_CHECKS>(pos, moveList, ~pos.pieces(), &ci)
: generate_all<BLACK, QUIET_CHECKS>(pos, moveList, ~pos.pieces(), &ci);
return us == WHITE ? generate_all<WHITE, QUIET_CHECKS>(pos, moveList, ~pos.pieces())
: generate_all<BLACK, QUIET_CHECKS>(pos, moveList, ~pos.pieces());
}
@@ -366,7 +368,7 @@ ExtMove* generate<EVASIONS>(const Position& pos, ExtMove* moveList) {
assert(pos.checkers());
Color us = pos.side_to_move();
Square ksq = pos.king_square(us);
Square ksq = pos.square<KING>(us);
Bitboard sliderAttacks = 0;
Bitboard sliders = pos.checkers() & ~pos.pieces(KNIGHT, PAWN);
@@ -382,7 +384,7 @@ ExtMove* generate<EVASIONS>(const Position& pos, ExtMove* moveList) {
// Generate evasions for king, capture and non capture moves
Bitboard b = pos.attacks_from<KING>(ksq) & ~pos.pieces(us) & ~sliderAttacks;
while (b)
(moveList++)->move = make_move(ksq, pop_lsb(&b));
*moveList++ = make_move(ksq, pop_lsb(&b));
if (more_than_one(pos.checkers()))
return moveList; // Double check, only a king move can save the day
@@ -402,15 +404,15 @@ template<>
ExtMove* generate<LEGAL>(const Position& pos, ExtMove* moveList) {
Bitboard pinned = pos.pinned_pieces(pos.side_to_move());
Square ksq = pos.king_square(pos.side_to_move());
Square ksq = pos.square<KING>(pos.side_to_move());
ExtMove* cur = moveList;
moveList = pos.checkers() ? generate<EVASIONS >(pos, moveList)
: generate<NON_EVASIONS>(pos, moveList);
while (cur != moveList)
if ( (pinned || from_sq(cur->move) == ksq || type_of(cur->move) == ENPASSANT)
&& !pos.legal(cur->move, pinned))
cur->move = (--moveList)->move;
if ( (pinned || from_sq(*cur) == ksq || type_of(*cur) == ENPASSANT)
&& !pos.legal(*cur))
*cur = (--moveList)->move;
else
++cur;
+10 -7
View File
@@ -2,6 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -36,6 +37,9 @@ enum GenType {
struct ExtMove {
Move move;
Value value;
operator Move() const { return move; }
void operator=(Move m) { move = m; }
};
inline bool operator<(const ExtMove& f, const ExtMove& s) {
@@ -50,18 +54,17 @@ ExtMove* generate(const Position& pos, ExtMove* moveList);
template<GenType T>
struct MoveList {
explicit MoveList(const Position& pos) : cur(moveList), last(generate<T>(pos, moveList)) { last->move = MOVE_NONE; }
void operator++() { ++cur; }
Move operator*() const { return cur->move; }
explicit MoveList(const Position& pos) : last(generate<T>(pos, moveList)) {}
const ExtMove* begin() const { return moveList; }
const ExtMove* end() const { return last; }
size_t size() const { return last - moveList; }
bool contains(Move m) const {
for (const ExtMove* it(moveList); it != last; ++it) if (it->move == m) return true;
bool contains(Move move) const {
for (const auto& m : *this) if (m == move) return true;
return false;
}
private:
ExtMove moveList[MAX_MOVES];
ExtMove *cur, *last;
ExtMove moveList[MAX_MOVES], *last;
};
#endif // #ifndef MOVEGEN_H_INCLUDED
+215 -250
View File
@@ -2,13 +2,13 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Stockfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -26,16 +26,15 @@
namespace {
enum Stages {
MAIN_SEARCH, CAPTURES_S1, KILLERS_S1, QUIETS_1_S1, QUIETS_2_S1, BAD_CAPTURES_S1,
EVASION, EVASIONS_S2,
QSEARCH_0, CAPTURES_S3, QUIET_CHECKS_S3,
QSEARCH_1, CAPTURES_S4,
PROBCUT, CAPTURES_S5,
RECAPTURE, CAPTURES_S6,
STOP
MAIN_SEARCH, CAPTURES_INIT, GOOD_CAPTURES, KILLERS, COUNTERMOVE, QUIET_INIT, QUIET, BAD_CAPTURES,
EVASION, EVASIONS_INIT, ALL_EVASIONS,
PROBCUT, PROBCUT_INIT, PROBCUT_CAPTURES,
QSEARCH_WITH_CHECKS, QCAPTURES_1_INIT, QCAPTURES_1, QCHECKS,
QSEARCH_NO_CHECKS, QCAPTURES_2_INIT, QCAPTURES_2,
QSEARCH_RECAPTURES, QRECAPTURES
};
// Our insertion sort, which is guaranteed (and also needed) to be stable
// Our insertion sort, which is guaranteed to be stable, as it should be
void insertion_sort(ExtMove* begin, ExtMove* end)
{
ExtMove tmp, *p, *q;
@@ -49,50 +48,39 @@ namespace {
}
}
// 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)
// pick_best() finds the best move in the range (begin, end) and moves it to
// the front. It's faster than sorting all the moves in advance when there
// are few moves, e.g., the possible captures.
Move pick_best(ExtMove* begin, ExtMove* end)
{
std::swap(*begin, *std::max_element(begin, end));
return begin;
return *begin;
}
} // namespace
/// Constructors of the MovePicker class. As arguments we pass information
/// 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
/// search captures, promotions and some checks) and how important good move
/// search captures, promotions, and some checks) and how important good move
/// ordering is at the current node.
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const HistoryStats& h,
Move* cm, Move* fm, Search::Stack* s) : pos(p), history(h), depth(d) {
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, Search::Stack* s)
: pos(p), ss(s), depth(d) {
assert(d > DEPTH_ZERO);
cur = end = moves;
endBadCaptures = moves + MAX_MOVES - 1;
countermoves = cm;
followupmoves = fm;
ss = s;
Square prevSq = to_sq((ss-1)->currentMove);
countermove = pos.this_thread()->counterMoves[pos.piece_on(prevSq)][prevSq];
if (pos.checkers())
stage = EVASION;
else
stage = MAIN_SEARCH;
ttMove = (ttm && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE);
end += (ttMove != MOVE_NONE);
stage = pos.checkers() ? EVASION : MAIN_SEARCH;
ttMove = ttm && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE;
stage += (ttMove == MOVE_NONE);
}
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const HistoryStats& h,
Square s) : pos(p), history(h), cur(moves), end(moves) {
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, Square s)
: pos(p) {
assert(d <= DEPTH_ZERO);
@@ -100,191 +88,88 @@ MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const HistoryStats&
stage = EVASION;
else if (d > DEPTH_QS_NO_CHECKS)
stage = QSEARCH_0;
stage = QSEARCH_WITH_CHECKS;
else if (d > DEPTH_QS_RECAPTURES)
stage = QSEARCH_1;
stage = QSEARCH_NO_CHECKS;
else
{
stage = RECAPTURE;
stage = QSEARCH_RECAPTURES;
recaptureSquare = s;
ttm = MOVE_NONE;
return;
}
ttMove = (ttm && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE);
end += (ttMove != MOVE_NONE);
ttMove = ttm && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE;
stage += (ttMove == MOVE_NONE);
}
MovePicker::MovePicker(const Position& p, Move ttm, const HistoryStats& h, PieceType pt)
: pos(p), history(h), cur(moves), end(moves) {
MovePicker::MovePicker(const Position& p, Move ttm, Value th)
: pos(p), threshold(th) {
assert(!pos.checkers());
stage = PROBCUT;
// In ProbCut we generate only captures that are better than the parent's
// captured piece.
captureThreshold = PieceValue[MG][pt];
ttMove = (ttm && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE);
// In ProbCut we generate captures with SEE higher than the given threshold
ttMove = ttm
&& pos.pseudo_legal(ttm)
&& pos.capture(ttm)
&& pos.see_ge(ttm, threshold + 1)? ttm : MOVE_NONE;
if (ttMove && (!pos.capture(ttMove) || pos.see(ttMove) <= captureThreshold))
ttMove = MOVE_NONE;
end += (ttMove != MOVE_NONE);
stage += (ttMove == MOVE_NONE);
}
/// score() assign a numerical value to each move in a move list. The moves with
/// score() assigns a numerical value to each move in a move list. The moves with
/// highest values will be picked first.
template<>
void MovePicker::score<CAPTURES>() {
// Winning and equal captures in the main search are ordered by MVV/LVA.
// Suprisingly, this appears to perform slightly better than SEE based
// move ordering. The reason is probably that in a position with a winning
// capture, capturing a more valuable (but sufficiently defended) piece
// first usually doesn't hurt. The opponent will have to recapture, and
// the hanging piece will still be hanging (except in the unusual cases
// where it is possible to recapture with the hanging piece). Exchanging
// big pieces before capturing a hanging piece probably helps to reduce
// the subtree size.
// In main search we want to push captures with negative SEE values to the
// Winning and equal captures in the main search are ordered by MVV, preferring
// captures near our home rank. Surprisingly, this appears to perform slightly
// better than SEE-based move ordering: exchanging big pieces before capturing
// a hanging piece probably helps to reduce the subtree size.
// In the main search we want to push captures with negative SEE values to the
// badCaptures[] array, but instead of doing it now we delay until the move
// has been picked up in pick_move_from_list(). This way we save some SEE
// calls in case we get a cutoff.
Move m;
for (ExtMove* it = moves; it != end; ++it)
{
m = it->move;
it->value = PieceValue[MG][pos.piece_on(to_sq(m))]
- Value(type_of(pos.moved_piece(m)));
if (type_of(m) == ENPASSANT)
it->value += PieceValue[MG][PAWN];
else if (type_of(m) == PROMOTION)
it->value += PieceValue[MG][promotion_type(m)] - PieceValue[MG][PAWN];
}
// has been picked up, saving some SEE calls in case we get a cutoff.
for (auto& m : *this)
m.value = PieceValue[MG][pos.piece_on(to_sq(m))]
- Value(200 * relative_rank(pos.side_to_move(), to_sq(m)));
}
template<>
void MovePicker::score<QUIETS>() {
Move m;
const HistoryStats& history = pos.this_thread()->history;
const FromToStats& fromTo = pos.this_thread()->fromTo;
for (ExtMove* it = moves; it != end; ++it)
{
m = it->move;
it->value = history[pos.moved_piece(m)][to_sq(m)];
}
const CounterMoveStats* cm = (ss-1)->counterMoves;
const CounterMoveStats* fm = (ss-2)->counterMoves;
const CounterMoveStats* f2 = (ss-4)->counterMoves;
Color c = pos.side_to_move();
for (auto& m : *this)
m.value = history[pos.moved_piece(m)][to_sq(m)]
+ (cm ? (*cm)[pos.moved_piece(m)][to_sq(m)] : VALUE_ZERO)
+ (fm ? (*fm)[pos.moved_piece(m)][to_sq(m)] : VALUE_ZERO)
+ (f2 ? (*f2)[pos.moved_piece(m)][to_sq(m)] : VALUE_ZERO)
+ fromTo.get(c, m);
}
template<>
void MovePicker::score<EVASIONS>() {
// Try 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
// moves with a negative SEE. This last group is ordered by the SEE value.
Move m;
Value see;
// Try captures ordered by MVV/LVA, then non-captures ordered by history value
const HistoryStats& history = pos.this_thread()->history;
const FromToStats& fromTo = pos.this_thread()->fromTo;
Color c = pos.side_to_move();
for (ExtMove* it = moves; it != end; ++it)
{
m = it->move;
if ((see = pos.see_sign(m)) < VALUE_ZERO)
it->value = see - HistoryStats::Max; // At the bottom
else if (pos.capture(m))
it->value = PieceValue[MG][pos.piece_on(to_sq(m))]
- Value(type_of(pos.moved_piece(m))) + HistoryStats::Max;
for (auto& m : *this)
if (pos.capture(m))
m.value = PieceValue[MG][pos.piece_on(to_sq(m))]
- Value(type_of(pos.moved_piece(m))) + HistoryStats::Max;
else
it->value = history[pos.moved_piece(m)][to_sq(m)];
}
}
/// generate_next_stage() generates, scores and sorts the next bunch of moves,
/// when there are no more moves to try for the current stage.
void MovePicker::generate_next_stage() {
cur = moves;
switch (++stage) {
case CAPTURES_S1: case CAPTURES_S3: case CAPTURES_S4: case CAPTURES_S5: case CAPTURES_S6:
end = generate<CAPTURES>(pos, moves);
score<CAPTURES>();
return;
case KILLERS_S1:
cur = killers;
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;
case QUIETS_1_S1:
endQuiets = end = generate<QUIETS>(pos, moves);
score<QUIETS>();
end = std::partition(cur, end, has_positive_value);
insertion_sort(cur, end);
return;
case QUIETS_2_S1:
cur = end;
end = endQuiets;
if (depth >= 3 * ONE_PLY)
insertion_sort(cur, end);
return;
case BAD_CAPTURES_S1:
// Just pick them in reverse order to get MVV/LVA ordering
cur = moves + MAX_MOVES - 1;
end = endBadCaptures;
return;
case EVASIONS_S2:
end = generate<EVASIONS>(pos, moves);
if (end > moves + 1)
score<EVASIONS>();
return;
case QUIET_CHECKS_S3:
end = generate<QUIET_CHECKS>(pos, moves);
return;
case EVASION: case QSEARCH_0: case QSEARCH_1: case PROBCUT: case RECAPTURE:
stage = STOP;
/* Fall through */
case STOP:
end = cur + 1; // Avoid another next_phase() call
return;
default:
assert(false);
}
m.value = history[pos.moved_piece(m)][to_sq(m)] + fromTo.get(c, m);
}
@@ -292,94 +177,174 @@ void MovePicker::generate_next_stage() {
/// a new pseudo legal move every time it is called, until there are no more moves
/// left. It picks the move with the biggest value from a list of generated moves
/// taking care not to return the ttMove if it has already been searched.
template<>
Move MovePicker::next_move<false>() {
Move MovePicker::next_move() {
Move move;
while (true)
{
while (cur == end)
generate_next_stage();
switch (stage) {
switch (stage) {
case MAIN_SEARCH: case EVASION: case QSEARCH_WITH_CHECKS:
case QSEARCH_NO_CHECKS: case PROBCUT:
++stage;
return ttMove;
case MAIN_SEARCH: case EVASION: case QSEARCH_0: case QSEARCH_1: case PROBCUT:
++cur;
return ttMove;
case CAPTURES_INIT:
endBadCaptures = cur = moves;
endMoves = generate<CAPTURES>(pos, cur);
score<CAPTURES>();
++stage;
case CAPTURES_S1:
move = pick_best(cur++, end)->move;
case GOOD_CAPTURES:
while (cur < endMoves)
{
move = pick_best(cur++, endMoves);
if (move != ttMove)
{
if (pos.see_sign(move) >= VALUE_ZERO)
if (pos.see_ge(move, VALUE_ZERO))
return move;
// Losing capture, move it to the tail of the array
(endBadCaptures--)->move = move;
// Losing capture, move it to the beginning of the array
*endBadCaptures++ = move;
}
break;
}
case KILLERS_S1:
move = (cur++)->move;
if ( move != MOVE_NONE
&& move != ttMove
&& pos.pseudo_legal(move)
&& !pos.capture(move))
return move;
break;
++stage;
move = ss->killers[0]; // First killer move
if ( move != MOVE_NONE
&& move != ttMove
&& pos.pseudo_legal(move)
&& !pos.capture(move))
return move;
case QUIETS_1_S1: case QUIETS_2_S1:
move = (cur++)->move;
case KILLERS:
++stage;
move = ss->killers[1]; // Second killer move
if ( move != MOVE_NONE
&& move != ttMove
&& pos.pseudo_legal(move)
&& !pos.capture(move))
return move;
case COUNTERMOVE:
++stage;
move = countermove;
if ( move != MOVE_NONE
&& move != ttMove
&& move != ss->killers[0]
&& move != ss->killers[1]
&& pos.pseudo_legal(move)
&& !pos.capture(move))
return move;
case QUIET_INIT:
cur = endBadCaptures;
endMoves = generate<QUIETS>(pos, cur);
score<QUIETS>();
if (depth < 3 * ONE_PLY)
{
ExtMove* goodQuiet = std::partition(cur, endMoves, [](const ExtMove& m)
{ return m.value > VALUE_ZERO; });
insertion_sort(cur, goodQuiet);
} else
insertion_sort(cur, endMoves);
++stage;
case QUIET:
while (cur < endMoves)
{
move = *cur++;
if ( move != ttMove
&& move != killers[0].move
&& move != killers[1].move
&& move != killers[2].move
&& move != killers[3].move
&& move != killers[4].move
&& move != killers[5].move)
&& move != ss->killers[0]
&& move != ss->killers[1]
&& move != countermove)
return move;
break;
}
++stage;
cur = moves; // Point to beginning of bad captures
case BAD_CAPTURES_S1:
return (cur--)->move;
case BAD_CAPTURES:
if (cur < endBadCaptures)
return *cur++;
break;
case EVASIONS_S2: case CAPTURES_S3: case CAPTURES_S4:
move = pick_best(cur++, end)->move;
case EVASIONS_INIT:
cur = moves;
endMoves = generate<EVASIONS>(pos, cur);
score<EVASIONS>();
++stage;
case ALL_EVASIONS:
while (cur < endMoves)
{
move = pick_best(cur++, endMoves);
if (move != ttMove)
return move;
}
break;
case PROBCUT_INIT:
cur = moves;
endMoves = generate<CAPTURES>(pos, cur);
score<CAPTURES>();
++stage;
case PROBCUT_CAPTURES:
while (cur < endMoves)
{
move = pick_best(cur++, endMoves);
if ( move != ttMove
&& pos.see_ge(move, threshold + 1))
return move;
}
break;
case QCAPTURES_1_INIT: case QCAPTURES_2_INIT:
cur = moves;
endMoves = generate<CAPTURES>(pos, cur);
score<CAPTURES>();
++stage;
case QCAPTURES_1: case QCAPTURES_2:
while (cur < endMoves)
{
move = pick_best(cur++, endMoves);
if (move != ttMove)
return move;
}
if (stage == QCAPTURES_2)
break;
cur = moves;
endMoves = generate<QUIET_CHECKS>(pos, cur);
++stage;
case CAPTURES_S5:
move = pick_best(cur++, end)->move;
if (move != ttMove && pos.see(move) > captureThreshold)
return move;
break;
case QCHECKS:
while (cur < endMoves)
{
move = cur++->move;
if (move != ttMove)
return move;
}
break;
case CAPTURES_S6:
move = pick_best(cur++, end)->move;
case QSEARCH_RECAPTURES:
cur = moves;
endMoves = generate<CAPTURES>(pos, cur);
score<CAPTURES>();
++stage;
case QRECAPTURES:
while (cur < endMoves)
{
move = pick_best(cur++, endMoves);
if (to_sq(move) == recaptureSquare)
return move;
break;
case QUIET_CHECKS_S3:
move = (cur++)->move;
if (move != ttMove)
return move;
break;
case STOP:
return MOVE_NONE;
default:
assert(false);
}
break;
default:
assert(false);
}
return MOVE_NONE;
}
/// 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
/// safe so must be lock protected by the caller.
template<>
Move MovePicker::next_move<true>() { return ss->splitPoint->movePicker->next_move<false>(); }
+49 -38
View File
@@ -2,6 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -25,51 +26,62 @@
#include "movegen.h"
#include "position.h"
#include "search.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
/// the class can store History 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.
/// and is used for reduction and move ordering decisions.
/// Countermoves store the move that refute a previous one. Entries are stored
/// using only the moving piece and destination square, hence two moves with
/// different origin but same destination and piece will be considered identical.
template<bool Gain, typename T>
template<typename T, bool CM = false>
struct Stats {
static const Value Max = Value(250);
static const Value Max = Value(1 << 28);
const T* operator[](Piece pc) const { return table[pc]; }
T* operator[](Piece pc) { return table[pc]; }
void clear() { std::memset(table, 0, sizeof(table)); }
void update(Piece pc, Square to, Move m) {
if (m == table[pc][to].first)
return;
table[pc][to].second = table[pc][to].first;
table[pc][to].first = m;
}
void update(Piece pc, Square to, Move m) { table[pc][to] = m; }
void update(Piece pc, Square to, Value v) {
if (Gain)
table[pc][to] = std::max(v, table[pc][to] - 1);
if (abs(int(v)) >= 324)
return;
else if (abs(table[pc][to] + v) < Max)
table[pc][to] += v;
table[pc][to] -= table[pc][to] * abs(int(v)) / (CM ? 936 : 324);
table[pc][to] += int(v) * 32;
}
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;
typedef Stats<Move> MoveStats;
typedef Stats<Value, false> HistoryStats;
typedef Stats<Value, true> CounterMoveStats;
typedef Stats<CounterMoveStats> CounterMoveHistoryStats;
struct FromToStats {
Value get(Color c, Move m) const { return table[c][from_sq(m)][to_sq(m)]; }
void clear() { std::memset(table, 0, sizeof(table)); }
void update(Color c, Move m, Value v) {
if (abs(int(v)) >= 324)
return;
Square from = from_sq(m);
Square to = to_sq(m);
table[c][from][to] -= table[c][from][to] * abs(int(v)) / 324;
table[c][from][to] += int(v) * 32;
}
private:
Value table[COLOR_NB][SQUARE_NB][SQUARE_NB];
};
/// MovePicker class is used to pick one pseudo legal move at a time from the
@@ -78,34 +90,33 @@ typedef Stats<false, std::pair<Move, Move> > MovesStats;
/// when MOVE_NONE is returned. In order to improve the efficiency of the alpha
/// beta algorithm, MovePicker attempts to return the moves which are most likely
/// to get a cut-off first.
namespace Search { struct Stack; }
class MovePicker {
MovePicker& operator=(const MovePicker&); // Silence a warning under MSVC
public:
MovePicker(const Position&, Move, Depth, const HistoryStats&, Square);
MovePicker(const Position&, Move, const HistoryStats&, PieceType);
MovePicker(const Position&, Move, Depth, const HistoryStats&, Move*, Move*, Search::Stack*);
MovePicker(const MovePicker&) = delete;
MovePicker& operator=(const MovePicker&) = delete;
template<bool SpNode> Move next_move();
MovePicker(const Position&, Move, Value);
MovePicker(const Position&, Move, Depth, Square);
MovePicker(const Position&, Move, Depth, Search::Stack*);
Move next_move();
private:
template<GenType> void score();
void generate_next_stage();
ExtMove* begin() { return cur; }
ExtMove* end() { return endMoves; }
const Position& pos;
const HistoryStats& history;
Search::Stack* ss;
Move* countermoves;
Move* followupmoves;
const Search::Stack* ss;
Move countermove;
Depth depth;
Move ttMove;
ExtMove killers[6];
Square recaptureSquare;
Value captureThreshold;
Value threshold;
int stage;
ExtMove *cur, *end, *endQuiets, *endBadCaptures;
ExtMove *cur, *endMoves, *endBadCaptures;
ExtMove moves[MAX_MOVES];
};
+99 -120
View File
@@ -2,6 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -21,7 +22,6 @@
#include <cassert>
#include "bitboard.h"
#include "bitcount.h"
#include "pawns.h"
#include "position.h"
#include "thread.h"
@@ -31,65 +31,58 @@ namespace {
#define V Value
#define S(mg, eg) make_score(mg, eg)
// Doubled pawn penalty by file
const Score Doubled[FILE_NB] = {
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
const Score Isolated[2] = { S(45, 40), S(30, 27) };
// Isolated pawn penalty by opposed flag and file
const Score Isolated[2][FILE_NB] = {
{ S(37, 45), S(54, 52), S(60, 52), S(60, 52),
S(60, 52), S(60, 52), S(54, 52), S(37, 45) },
{ S(25, 30), S(36, 35), S(40, 35), S(40, 35),
S(40, 35), S(40, 35), S(36, 35), S(25, 30) } };
// Backward pawn penalty by opposed flag
const Score Backward[2] = { S(56, 33), S(41, 19) };
// Backward pawn penalty by opposed flag and file
const Score Backward[2][FILE_NB] = {
{ 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(20, 28), S(29, 31), S(33, 31), S(33, 31),
S(33, 31), S(33, 31), S(29, 31), S(20, 28) } };
// Unsupported pawn penalty for pawns which are neither isolated or backward
const Score Unsupported = S(17, 8);
// Connected pawn bonus by opposed, phalanx flags and rank
Score Connected[2][2][RANK_NB];
// Connected pawn bonus by opposed, phalanx, twice supported and rank
Score Connected[2][2][2][RANK_NB];
// Levers bonus by rank
// Doubled pawn penalty
const Score Doubled = S(18,38);
// Lever bonus by rank
const Score Lever[RANK_NB] = {
S( 0, 0), S( 0, 0), S(0, 0), S(0, 0),
S(20,20), S(40,40), S(0, 0), S(0, 0) };
// Unsupported pawn penalty
const Score UnsupportedPawnPenalty = S(20, 10);
S( 0, 0), S( 0, 0), S(0, 0), S(0, 0),
S(17, 16), S(33, 32), S(0, 0), S(0, 0)
};
// Weakness of our pawn shelter in front of the king by [distance from edge][rank]
const Value ShelterWeakness[][RANK_NB] = {
{ V(100), V(13), V(24), V(64), V(89), V( 93), V(104) },
{ 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) } };
{ V( 97), V(21), V(26), V(51), V(87), V( 89), V( 99) },
{ V(120), V( 0), V(28), V(76), V(88), V(103), V(104) },
{ V(101), V( 7), V(54), V(78), V(77), V( 92), V(101) },
{ V( 80), V(11), V(44), V(68), V(87), V( 90), V(119) }
};
// Danger of enemy pawns moving toward our king by [type][distance from edge][rank]
const Value StormDanger[][4][RANK_NB] = {
{ { V( 0), V( 63), V( 128), V(43), V(27) },
{ 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) } } };
{ { V( 0), V( 67), V( 134), V(38), V(32) },
{ V( 0), V( 57), V( 139), V(37), V(22) },
{ V( 0), V( 43), V( 115), V(43), V(27) },
{ V( 0), V( 68), V( 124), V(57), V(32) } },
{ { V(20), V( 43), V( 100), V(56), V(20) },
{ V(23), V( 20), V( 98), V(40), V(15) },
{ V(23), V( 39), V( 103), V(36), V(18) },
{ V(28), V( 19), V( 108), V(42), V(26) } },
{ { V( 0), V( 0), V( 75), V(14), V( 2) },
{ V( 0), V( 0), V( 150), V(30), V( 4) },
{ V( 0), V( 0), V( 160), V(22), V( 5) },
{ V( 0), V( 0), V( 166), V(24), V(13) } },
{ { V( 0), V(-283), V(-281), V(57), V(31) },
{ V( 0), V( 58), V( 141), V(39), V(18) },
{ V( 0), V( 65), V( 142), V(48), V(32) },
{ V( 0), V( 60), V( 126), V(51), V(19) } }
};
// Max bonus for king safety. Corresponds to start position with all the pawns
// in front of the king and no enemy pawn on the horizon.
const Value MaxSafetyBonus = V(257);
const Value MaxSafetyBonus = V(258);
#undef S
#undef V
@@ -97,26 +90,26 @@ namespace {
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);
const Color Them = (Us == WHITE ? BLACK : WHITE);
const Square Up = (Us == WHITE ? NORTH : SOUTH);
const Square Right = (Us == WHITE ? NORTH_EAST : SOUTH_WEST);
const Square Left = (Us == WHITE ? NORTH_WEST : SOUTH_EAST);
Bitboard b, p, doubled, connected;
Bitboard b, neighbours, stoppers, doubled, supported, phalanx;
Square s;
bool passed, isolated, opposed, phalanx, backward, unsupported, lever;
bool opposed, lever, connected, backward;
Score score = SCORE_ZERO;
const Square* pl = pos.list<PAWN>(Us);
const Square* pl = pos.squares<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->passedPawns[Us] = e->pawnAttacksSpan[Us] = 0;
e->semiopenFiles[Us] = 0xFF;
e->pawnAttacks[Us] = shift_bb<Right>(ourPawns) | shift_bb<Left>(ourPawns);
e->pawnsOnSquares[Us][BLACK] = popcount<Max15>(ourPawns & DarkSquares);
e->kingSquares[Us] = SQ_NONE;
e->pawnAttacks[Us] = shift<Right>(ourPawns) | shift<Left>(ourPawns);
e->pawnsOnSquares[Us][BLACK] = popcount(ourPawns & DarkSquares);
e->pawnsOnSquares[Us][WHITE] = pos.count<PAWN>(Us) - e->pawnsOnSquares[Us][BLACK];
// Loop through all pawns of the current color and score each pawn
@@ -126,76 +119,61 @@ namespace {
File f = file_of(s);
// This file cannot be semi-open
e->semiopenFiles[Us] &= ~(1 << f);
e->semiopenFiles[Us] &= ~(1 << f);
e->pawnAttacksSpan[Us] |= pawn_attack_span(Us, s);
// Previous rank
p = rank_bb(s - pawn_push(Us));
// Flag the pawn
opposed = theirPawns & forward_bb(Us, s);
stoppers = theirPawns & passed_pawn_mask(Us, s);
lever = theirPawns & pawnAttacksBB[s];
doubled = ourPawns & (s + Up);
neighbours = ourPawns & adjacent_files_bb(f);
phalanx = neighbours & rank_bb(s);
supported = neighbours & rank_bb(s - Up);
connected = supported | phalanx;
// 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))
// A pawn is backward when it is behind all pawns of the same color on the
// adjacent files and cannot be safely advanced.
if (!neighbours || lever || relative_rank(Us, s) >= RANK_5)
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));
// Find the backmost rank with neighbours or stoppers
b = rank_bb(backmost_sq(Us, neighbours | stoppers));
// 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;
// The pawn is backward when it cannot safely progress to that rank:
// either there is a stopper in the way on this rank, or there is a
// stopper on adjacent file which controls the way to that rank.
backward = (b | shift<Up>(b & adjacent_files_bb(f))) & stoppers;
assert(!backward || !(pawn_attack_span(Them, s + Up) & neighbours));
}
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)
// full attack info to evaluate them.
if (!stoppers && !(ourPawns & forward_bb(Us, s)))
e->passedPawns[Us] |= s;
// Score this pawn
if (isolated)
score -= Isolated[opposed][f];
if (!neighbours)
score -= Isolated[opposed];
if (unsupported && !isolated)
score -= UnsupportedPawnPenalty;
else if (backward)
score -= Backward[opposed];
if (doubled)
score -= Doubled[f] / distance<Rank>(s, frontmost_sq(Us, doubled));
if (backward)
score -= Backward[opposed][f];
else if (!supported)
score -= Unsupported;
if (connected)
score += Connected[opposed][phalanx][relative_rank(Us, s)];
score += Connected[opposed][!!phalanx][more_than_one(supported)][relative_rank(Us, s)];
if (doubled)
score -= Doubled;
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;
}
@@ -207,17 +185,19 @@ namespace Pawns {
/// 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 };
void init() {
static const int Seed[RANK_NB] = { 0, 8, 19, 13, 71, 94, 169, 324 };
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);
}
for (int apex = 0; apex <= 1; ++apex)
for (Rank r = RANK_2; r < RANK_8; ++r)
{
int v = (Seed[r] + (phalanx ? (Seed[r + 1] - Seed[r]) / 2 : 0)) >> opposed;
v += (apex ? v / 2 : 0);
Connected[opposed][phalanx][apex][r] = make_score(v, v * 5 / 8);
}
}
@@ -236,6 +216,8 @@ Entry* probe(const Position& pos) {
e->key = key;
e->score = evaluate<WHITE>(pos, e) - evaluate<BLACK>(pos, e);
e->asymmetry = popcount(e->semiopenFiles[WHITE] ^ e->semiopenFiles[BLACK]);
e->openFiles = popcount(e->semiopenFiles[WHITE] & e->semiopenFiles[BLACK]);
return e;
}
@@ -284,14 +266,11 @@ Score Entry::do_king_safety(const Position& pos, Square ksq) {
kingSquares[Us] = ksq;
castlingRights[Us] = pos.can_castle(Us);
minKingPawnDistance[Us] = 0;
int minKingPawnDistance = 0;
Bitboard pawns = pos.pieces(Us, PAWN);
if (pawns)
while (!(DistanceRingBB[ksq][minKingPawnDistance[Us]++] & pawns)) {}
if (relative_rank(Us, ksq) > RANK_4)
return make_score(0, -16 * minKingPawnDistance[Us]);
while (!(DistanceRingBB[ksq][minKingPawnDistance++] & pawns)) {}
Value bonus = shelter_storm<Us>(pos, ksq);
@@ -302,7 +281,7 @@ Score Entry::do_king_safety(const Position& pos, Square ksq) {
if (pos.can_castle(MakeCastling<Us, QUEEN_SIDE>::right))
bonus = std::max(bonus, shelter_storm<Us>(pos, relative_square(Us, SQ_C1)));
return make_score(bonus, -16 * minKingPawnDistance[Us]);
return make_score(bonus, -16 * minKingPawnDistance);
}
// Explicit template instantiation
+8 -4
View File
@@ -2,6 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -35,7 +36,9 @@ struct Entry {
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]; }
Bitboard pawn_attacks_span(Color c) const { return pawnAttacksSpan[c]; }
int pawn_asymmetry() const { return asymmetry; }
int open_files() const { return openFiles; }
int semiopen_file(Color c, File f) const {
return semiopenFiles[c] & (1 << f);
@@ -50,7 +53,7 @@ struct Entry {
}
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));
}
@@ -65,13 +68,14 @@ struct Entry {
Score score;
Bitboard passedPawns[COLOR_NB];
Bitboard pawnAttacks[COLOR_NB];
Bitboard pawnAttacksSpan[COLOR_NB];
Square kingSquares[COLOR_NB];
Score kingSafety[COLOR_NB];
int minKingPawnDistance[COLOR_NB];
int castlingRights[COLOR_NB];
int semiopenFiles[COLOR_NB];
int pawnSpan[COLOR_NB];
int pawnsOnSquares[COLOR_NB][COLOR_NB]; // [color][light/dark squares]
int asymmetry;
int openFiles;
};
typedef HashTable<Entry, 16384> Table;
-116
View File
@@ -1,116 +0,0 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Stockfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PLATFORM_H_INCLUDED
#define PLATFORM_H_INCLUDED
#ifdef _MSC_VER
// Disable some silly and noisy warnings from MSVC compiler
#pragma warning(disable: 4127) // Conditional expression is constant
#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: 4996) // Function _ftime() may be unsafe
// MSVC does not support <inttypes.h>
typedef signed __int8 int8_t;
typedef unsigned __int8 uint8_t;
typedef signed __int16 int16_t;
typedef unsigned __int16 uint16_t;
typedef signed __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef signed __int64 int64_t;
typedef unsigned __int64 uint64_t;
#else
# include <inttypes.h>
#endif
#ifndef _WIN32 // Linux - Unix
# include <sys/time.h>
inline int64_t system_time_to_msec() {
timeval t;
gettimeofday(&t, NULL);
return t.tv_sec * 1000LL + t.tv_usec / 1000;
}
# include <pthread.h>
typedef pthread_mutex_t Lock;
typedef pthread_cond_t WaitCondition;
typedef pthread_t NativeHandle;
typedef void*(*pt_start_fn)(void*);
# define lock_init(x) pthread_mutex_init(&(x), NULL)
# define lock_grab(x) pthread_mutex_lock(&(x))
# define lock_release(x) pthread_mutex_unlock(&(x))
# define lock_destroy(x) pthread_mutex_destroy(&(x))
# define cond_destroy(x) pthread_cond_destroy(&(x))
# define cond_init(x) pthread_cond_init(&(x), NULL)
# define cond_signal(x) pthread_cond_signal(&(x))
# define cond_wait(x,y) pthread_cond_wait(&(x),&(y))
# 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_join(x) pthread_join(x, NULL)
#else // Windows and MinGW
# include <sys/timeb.h>
inline int64_t system_time_to_msec() {
_timeb t;
_ftime(&t);
return t.time * 1000LL + t.millitm;
}
#ifndef NOMINMAX
# define NOMINMAX // disable macros min() and max()
#endif
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#undef WIN32_LEAN_AND_MEAN
#undef NOMINMAX
// We use critical sections on Windows to support Windows XP and older versions.
// Unfortunately, cond_wait() is racy between lock_release() and WaitForSingleObject()
// but apart from this they have the same speed performance of SRW locks.
typedef CRITICAL_SECTION Lock;
typedef HANDLE WaitCondition;
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_grab(x) EnterCriticalSection(&(x))
# define lock_release(x) LeaveCriticalSection(&(x))
# define lock_destroy(x) DeleteCriticalSection(&(x))
# define cond_init(x) { x = CreateEvent(0, FALSE, FALSE, 0); }
# define cond_destroy(x) CloseHandle(x)
# define cond_signal(x) SetEvent(x)
# 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 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); }
#endif
#endif // #ifndef PLATFORM_H_INCLUDED
+295 -407
View File
File diff suppressed because it is too large Load Diff
+82 -108
View File
@@ -2,6 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -21,28 +22,13 @@
#define POSITION_H_INCLUDED
#include <cassert>
#include <cstddef> // For offsetof()
#include <deque>
#include <memory> // For std::unique_ptr
#include <string>
#include "bitboard.h"
#include "types.h"
class Position;
struct Thread;
/// CheckInfo struct is initialized at c'tor time and keeps info used to detect
/// if a move gives check.
struct CheckInfo {
explicit CheckInfo(const Position&);
Bitboard dcCandidates;
Bitboard pinned;
Bitboard checkSq[PIECE_TYPE_NB];
Square ksq;
};
/// StateInfo struct stores information needed to restore a Position object to
/// its previous state when we retract a move. Whenever a move is made on the
@@ -60,40 +46,36 @@ struct StateInfo {
Score psq;
Square epSquare;
// Not copied when making a move
// Not copied when making a move (will be recomputed anyhow)
Key key;
Bitboard checkersBB;
PieceType capturedType;
Piece capturedPiece;
StateInfo* previous;
Bitboard blockersForKing[COLOR_NB];
Bitboard pinnersForKing[COLOR_NB];
Bitboard checkSquares[PIECE_TYPE_NB];
};
/// When making a move the current StateInfo up to 'key' excluded is copied to
/// the new one. Here we calculate the quad words (64 bit) needed to be copied.
const size_t StateCopySize64 = offsetof(StateInfo, key) / sizeof(uint64_t) + 1;
// In a std::deque references to elements are unaffected upon resizing
typedef std::unique_ptr<std::deque<StateInfo>> StateListPtr;
/// Position class stores information regarding the board representation as
/// pieces, side to move, hash keys, castling info, etc. Important methods are
/// do_move() and undo_move(), used by the search to update node info when
/// traversing the search tree.
class Thread;
class Position {
friend std::ostream& operator<<(std::ostream&, const Position&);
Position(const Position&); // Disable the default copy constructor
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
Position() = default;
Position(const Position&) = delete;
Position& operator=(const Position&) = delete;
// FEN string input/output
void set(const std::string& fenStr, bool isChess960, Thread* th);
Position& set(const std::string& fenStr, bool isChess960, StateInfo* si, Thread* th);
const std::string fen() const;
// Position representation
@@ -104,11 +86,11 @@ public:
Bitboard pieces(Color c, PieceType pt) const;
Bitboard pieces(Color c, PieceType pt1, PieceType pt2) const;
Piece piece_on(Square s) const;
Square king_square(Color c) const;
Square ep_square() const;
bool empty(Square s) const;
template<PieceType Pt> int count(Color c) const;
template<PieceType Pt> const Square* list(Color c) const;
template<PieceType Pt> const Square* squares(Color c) const;
template<PieceType Pt> Square square(Color c) const;
// Castling
int can_castle(Color c) const;
@@ -120,6 +102,7 @@ public:
Bitboard checkers() const;
Bitboard discovered_check_candidates() const;
Bitboard pinned_pieces(Color c) const;
Bitboard check_squares(PieceType pt) const;
// Attacks to/from a given square
Bitboard attackers_to(Square s) const;
@@ -127,37 +110,34 @@ public:
Bitboard attacks_from(Piece pc, Square s) const;
template<PieceType> Bitboard attacks_from(Square s) const;
template<PieceType> Bitboard attacks_from(Square s, Color c) const;
Bitboard slider_blockers(Bitboard sliders, Square s, Bitboard& pinners) const;
// Properties of moves
bool legal(Move m, Bitboard pinned) const;
bool legal(Move m) const;
bool pseudo_legal(const Move m) const;
bool capture(Move m) const;
bool capture_or_promotion(Move m) const;
bool gives_check(Move m, const CheckInfo& ci) const;
bool gives_check(Move m) const;
bool advanced_pawn_push(Move m) const;
Piece moved_piece(Move m) const;
PieceType captured_piece_type() const;
Piece captured_piece() const;
// Piece specific
bool pawn_passed(Color c, Square s) const;
bool pawn_on_7th(Color c) const;
bool opposite_bishops() const;
// Doing and undoing moves
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, bool givesCheck);
void undo_move(Move m);
void do_null_move(StateInfo& st);
void undo_null_move();
// Static exchange evaluation
Value see(Move m) const;
Value see_sign(Move m) const;
// Static Exchange Evaluation
bool see_ge(Move m, Value value) const;
// Accessing hash keys
Key key() const;
Key key_after(Move m) const;
Key exclusion_key() const;
Key material_key() const;
Key pawn_key() const;
@@ -168,41 +148,38 @@ public:
bool is_chess960() const;
Thread* this_thread() const;
uint64_t nodes_searched() const;
void set_nodes_searched(uint64_t n);
bool is_draw() const;
int rule50_count() const;
Score psq_score() const;
Value non_pawn_material(Color c) const;
// Position consistency check, for debugging
bool pos_is_ok(int* step = NULL) const;
bool pos_is_ok(int* failedStep = nullptr) const;
void flip();
private:
// Initialization helpers (used while setting up a position)
void clear();
void set_castling_right(Color c, Square rfrom);
void set_state(StateInfo* si) const;
void set_check_info(StateInfo* si) const;
// Other helpers
Bitboard check_blockers(Color c, Color kingColor) 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);
void put_piece(Piece pc, Square s);
void remove_piece(Piece pc, Square s);
void move_piece(Piece pc, Square from, Square to);
template<bool Do>
void do_castling(Square from, Square& to, Square& rfrom, Square& rto);
void do_castling(Color us, Square from, Square& to, Square& rfrom, Square& rto);
// Data members
Piece board[SQUARE_NB];
Bitboard byTypeBB[PIECE_TYPE_NB];
Bitboard byColorBB[COLOR_NB];
int pieceCount[COLOR_NB][PIECE_TYPE_NB];
Square pieceList[COLOR_NB][PIECE_TYPE_NB][16];
int pieceCount[PIECE_NB];
Square pieceList[PIECE_NB][16];
int index[SQUARE_NB];
int castlingRightsMask[SQUARE_NB];
Square castlingRookSquare[CASTLING_RIGHT_NB];
Bitboard castlingPath[CASTLING_RIGHT_NB];
StateInfo startState;
uint64_t nodes;
int gamePly;
Color sideToMove;
@@ -211,6 +188,8 @@ private:
bool chess960;
};
extern std::ostream& operator<<(std::ostream& os, const Position& pos);
inline Color Position::side_to_move() const {
return sideToMove;
}
@@ -252,15 +231,16 @@ inline Bitboard Position::pieces(Color c, PieceType pt1, PieceType pt2) const {
}
template<PieceType Pt> inline int Position::count(Color c) const {
return pieceCount[c][Pt];
return pieceCount[make_piece(c, Pt)];
}
template<PieceType Pt> inline const Square* Position::list(Color c) const {
return pieceList[c][Pt];
template<PieceType Pt> inline const Square* Position::squares(Color c) const {
return pieceList[make_piece(c, Pt)];
}
inline Square Position::king_square(Color c) const {
return pieceList[c][KING][0];
template<PieceType Pt> inline Square Position::square(Color c) const {
assert(pieceCount[make_piece(c, Pt)] == 1);
return pieceList[make_piece(c, Pt)][0];
}
inline Square Position::ep_square() const {
@@ -308,11 +288,15 @@ inline Bitboard Position::checkers() const {
}
inline Bitboard Position::discovered_check_candidates() const {
return check_blockers(sideToMove, ~sideToMove);
return st->blockersForKing[~sideToMove] & pieces(sideToMove);
}
inline Bitboard Position::pinned_pieces(Color c) const {
return check_blockers(c, c);
return st->blockersForKing[c] & pieces(c);
}
inline Bitboard Position::check_squares(PieceType pt) const {
return st->checkSquares[pt];
}
inline bool Position::pawn_passed(Color c, Square s) const {
@@ -356,18 +340,10 @@ 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 {
return pieceCount[WHITE][BISHOP] == 1
&& pieceCount[BLACK][BISHOP] == 1
&& opposite_colors(pieceList[WHITE][BISHOP][0], pieceList[BLACK][BISHOP][0]);
}
inline bool Position::pawn_on_7th(Color c) const {
return pieces(c, PAWN) & rank_bb(relative_rank(c, RANK_7));
return pieceCount[W_BISHOP] == 1
&& pieceCount[B_BISHOP] == 1
&& opposite_colors(square<BISHOP>(WHITE), square<BISHOP>(BLACK));
}
inline bool Position::is_chess960() const {
@@ -375,66 +351,64 @@ inline bool Position::is_chess960() const {
}
inline bool Position::capture_or_promotion(Move m) const {
assert(is_ok(m));
return type_of(m) != NORMAL ? type_of(m) != CASTLING : !empty(to_sq(m));
}
inline bool Position::capture(Move m) const {
// Castling is encoded as "king captures the rook"
assert(is_ok(m));
// Castling is encoded as "king captures rook"
return (!empty(to_sq(m)) && type_of(m) != CASTLING) || type_of(m) == ENPASSANT;
}
inline PieceType Position::captured_piece_type() const {
return st->capturedType;
inline Piece Position::captured_piece() const {
return st->capturedPiece;
}
inline Thread* Position::this_thread() const {
return thisThread;
}
inline void Position::put_piece(Square s, Color c, PieceType pt) {
inline void Position::put_piece(Piece pc, Square s) {
board[s] = make_piece(c, pt);
board[s] = pc;
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]++;
byTypeBB[type_of(pc)] |= s;
byColorBB[color_of(pc)] |= s;
index[s] = pieceCount[pc]++;
pieceList[pc][index[s]] = s;
pieceCount[make_piece(color_of(pc), ALL_PIECES)]++;
}
inline void Position::move_piece(Square from, Square to, Color c, PieceType pt) {
inline void Position::remove_piece(Piece pc, Square s) {
// 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 invariant to a do_move() + undo_move() sequence.
byTypeBB[ALL_PIECES] ^= s;
byTypeBB[type_of(pc)] ^= s;
byColorBB[color_of(pc)] ^= s;
/* board[s] = NO_PIECE; Not needed, overwritten by the capturing one */
Square lastSquare = pieceList[pc][--pieceCount[pc]];
index[lastSquare] = index[s];
pieceList[pc][index[lastSquare]] = lastSquare;
pieceList[pc][pieceCount[pc]] = SQ_NONE;
pieceCount[make_piece(color_of(pc), ALL_PIECES)]--;
}
inline void Position::move_piece(Piece pc, Square from, Square to) {
// index[from] is not updated and becomes stale. This works as long as index[]
// 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;
byTypeBB[type_of(pc)] ^= from_to_bb;
byColorBB[color_of(pc)] ^= from_to_bb;
board[from] = NO_PIECE;
board[to] = make_piece(c, pt);
board[to] = pc;
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]--;
pieceList[pc][index[to]] = to;
}
#endif // #ifndef POSITION_H_INCLUDED
+126
View File
@@ -0,0 +1,126 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Stockfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <algorithm>
#include "types.h"
Value PieceValue[PHASE_NB][PIECE_NB] = {
{ VALUE_ZERO, PawnValueMg, KnightValueMg, BishopValueMg, RookValueMg, QueenValueMg },
{ VALUE_ZERO, PawnValueEg, KnightValueEg, BishopValueEg, RookValueEg, QueenValueEg }
};
namespace PSQT {
#define S(mg, eg) make_score(mg, eg)
// Bonus[PieceType][Square / 2] contains Piece-Square scores. For each piece
// type on a given square a (middlegame, endgame) score pair is assigned. Table
// is defined for files A..D and white side: it is symmetric for black side and
// second half of the files.
const Score Bonus[][RANK_NB][int(FILE_NB) / 2] = {
{ },
{ // Pawn
{ S( 0, 0), S( 0, 0), S( 0, 0), S( 0, 0) },
{ S(-16, 7), S( 1,-4), S( 7, 8), S( 3,-2) },
{ S(-23,-4), S( -7,-5), S( 19, 5), S(24, 4) },
{ S(-22, 3), S(-14, 3), S( 20,-8), S(35,-3) },
{ S(-11, 8), S( 0, 9), S( 3, 7), S(21,-6) },
{ S(-11, 8), S(-13,-5), S( -6, 2), S(-2, 4) },
{ S( -9, 3), S( 15,-9), S( -8, 1), S(-4,18) }
},
{ // Knight
{ S(-143, -97), S(-96,-82), S(-80,-46), S(-73,-14) },
{ S( -83, -69), S(-43,-55), S(-21,-17), S(-10, 9) },
{ S( -71, -50), S(-22,-39), S( 0, -8), S( 9, 28) },
{ S( -25, -41), S( 18,-25), S( 43, 7), S( 47, 38) },
{ S( -26, -46), S( 16,-25), S( 38, 2), S( 50, 41) },
{ S( -11, -55), S( 37,-38), S( 56, -8), S( 71, 27) },
{ S( -62, -64), S(-17,-50), S( 5,-24), S( 14, 13) },
{ S(-195,-110), S(-66,-90), S(-42,-50), S(-29,-13) }
},
{ // Bishop
{ S(-54,-68), S(-23,-40), S(-35,-46), S(-44,-28) },
{ S(-30,-43), S( 10,-17), S( 2,-23), S( -9, -5) },
{ S(-19,-32), S( 17, -9), S( 11,-13), S( 1, 8) },
{ S(-21,-36), S( 18,-13), S( 11,-15), S( 0, 7) },
{ S(-21,-36), S( 14,-14), S( 6,-17), S( -1, 3) },
{ S(-27,-35), S( 6,-13), S( 2,-10), S( -8, 1) },
{ S(-33,-44), S( 7,-21), S( -4,-22), S(-12, -4) },
{ S(-45,-65), S(-21,-42), S(-29,-46), S(-39,-27) }
},
{ // Rook
{ S(-25, 0), S(-16, 0), S(-16, 0), S(-9, 0) },
{ S(-21, 0), S( -8, 0), S( -3, 0), S( 0, 0) },
{ S(-21, 0), S( -9, 0), S( -4, 0), S( 2, 0) },
{ S(-22, 0), S( -6, 0), S( -1, 0), S( 2, 0) },
{ S(-22, 0), S( -7, 0), S( 0, 0), S( 1, 0) },
{ S(-21, 0), S( -7, 0), S( 0, 0), S( 2, 0) },
{ S(-12, 0), S( 4, 0), S( 8, 0), S(12, 0) },
{ S(-23, 0), S(-15, 0), S(-11, 0), S(-5, 0) }
},
{ // Queen
{ S( 0,-70), S(-3,-57), S(-4,-41), S(-1,-29) },
{ S(-4,-58), S( 6,-30), S( 9,-21), S( 8, -4) },
{ S(-2,-39), S( 6,-17), S( 9, -7), S( 9, 5) },
{ S(-1,-29), S( 8, -5), S(10, 9), S( 7, 17) },
{ S(-3,-27), S( 9, -5), S( 8, 10), S( 7, 23) },
{ S(-2,-40), S( 6,-16), S( 8,-11), S(10, 3) },
{ S(-2,-54), S( 7,-30), S( 7,-21), S( 6, -7) },
{ S(-1,-75), S(-4,-54), S(-1,-44), S( 0,-30) }
},
{ // King
{ S(291, 28), S(344, 76), S(294,103), S(219,112) },
{ S(289, 70), S(329,119), S(263,170), S(205,159) },
{ S(226,109), S(271,164), S(202,195), S(136,191) },
{ S(204,131), S(212,194), S(175,194), S(137,204) },
{ S(177,132), S(205,187), S(143,224), S( 94,227) },
{ S(147,118), S(188,178), S(113,199), S( 70,197) },
{ S(116, 72), S(158,121), S( 93,142), S( 48,161) },
{ S( 94, 30), S(120, 76), S( 78,101), S( 31,111) }
}
};
#undef S
Score psq[PIECE_NB][SQUARE_NB];
// init() initializes piece-square tables: the white halves of the tables are
// copied from Bonus[] adding the piece value, then the black halves of the
// tables are initialized by flipping and changing the sign of the white scores.
void init() {
for (Piece pc = W_PAWN; pc <= W_KING; ++pc)
{
PieceValue[MG][~pc] = PieceValue[MG][pc];
PieceValue[EG][~pc] = PieceValue[EG][pc];
Score v = make_score(PieceValue[MG][pc], PieceValue[EG][pc]);
for (Square s = SQ_A1; s <= SQ_H8; ++s)
{
File f = std::min(file_of(s), FILE_H - file_of(s));
psq[ pc][ s] = v + Bonus[pc][rank_of(s)][f];
psq[~pc][~s] = -psq[pc][s];
}
}
}
} // namespace PSQT
-98
View File
@@ -1,98 +0,0 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Stockfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PSQTAB_H_INCLUDED
#define PSQTAB_H_INCLUDED
#include "types.h"
#define S(mg, eg) make_score(mg, eg)
/// PSQT[PieceType][Square] contains Piece-Square scores. For each piece type on
/// a given square a (middlegame, endgame) score pair is assigned. PSQT is defined
/// for the white side and the tables are symmetric for the black side.
static const Score PSQT[][SQUARE_NB] = {
{ },
{ // 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(-20, 0), S( 0, 0), S( 0, 0), S( 0, 0), S(0, 0), S( 0, 0), S( 0, 0), S(-20, 0),
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(-20, 0), S( 0, 0), S(20, 0), S(40, 0), S(40, 0), S(20, 0), S( 0, 0), S(-20, 0),
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(-20, 0), S( 0, 0), S( 0, 0), S( 0, 0), S(0, 0), S( 0, 0), S( 0, 0), S(-20, 0),
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)
},
{ // Knight
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( -88,-68), S( -43,-53), S(-19,-21), S( -7, 14), S( -7, 14), S(-19,-21), S( -43,-53), S( -88,-68),
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( -28,-42), S( 17,-27), S( 41, 5), S( 53, 40), S( 53, 40), S( 41, 5), S( 17,-27), S( -28,-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( -10,-53), S( 35,-38), S( 59, -6), S( 71, 29), S( 71, 29), S( 59, -6), S( 35,-38), S( -10,-53),
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(-200,-98), S( -65,-83), S(-41,-51), S(-29,-16), S(-29,-16), S(-41,-51), S( -65,-83), S(-200,-98)
},
{ // Bishop
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(-29,-43), S( 8,-20), S( 1,-22), S( -8, -4), S( -8, -4), S( 1,-22), S( 8,-20), S(-29,-43),
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(-19,-35), S( 18,-12), S( 11,-14), S( 2, 4), S( 2, 4), S( 11,-14), S( 18,-12), S(-19,-35),
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(-28,-33), S( 9,-10), S( 2,-12), S( -7, 6), S( -7, 6), S( 2,-12), S( 9,-10), S(-28,-33),
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(-49,-65), S(-22,-42), S(-29,-44), S(-38,-26), S(-38,-26), S(-29,-44), S(-22,-42), S(-49,-65)
},
{ // Rook
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(-22, 3), S( -7, 3), S( -2, 3), S( 2, 3), S( 2, 3), S( -2, 3), S( -7, 3), S(-22, 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(-22, 3), S( -7, 3), S( -2, 3), S( 2, 3), S( 2, 3), S( -2, 3), S( -7, 3), S(-22, 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(-22, 3), S( -7, 3), S( -2, 3), S( 2, 3), S( 2, 3), S( -2, 3), S( -7, 3), S(-22, 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(-22, 3), S(-17, 3), S(-12, 3), S(-8, 3), S(-8, 3), S(-12, 3), S(-17, 3), S(-22, 3)
},
{ // Queen
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(-2,-54), S( 8,-30), S( 8,-18), S( 8, -6), S( 8, -6), S( 8,-18), S( 8,-30), S(-2,-54),
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(-2,-30), S( 8, -6), S( 8, 6), S( 8, 18), S( 8, 18), S( 8, 6), S( 8, -6), S(-2,-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(-2,-42), S( 8,-18), S( 8, -6), S( 8, 6), S( 8, 6), S( 8, -6), S( 8,-18), S(-2,-42),
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(-2,-80), S(-2,-54), S(-2,-42), S(-2,-30), S(-2,-30), S(-2,-42), S(-2,-54), S(-2,-80)
},
{ // King
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(287, 74), S(321,128), S(262,155), S(214,163), S(214,163), S(262,155), S(321,128), S(287, 74),
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(196,135), S(230,189), S(171,216), S(123,224), S(123,224), S(171,216), S(230,189), S(196,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(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, 74), S(153,128), S( 94,155), S( 46,163), S( 46,163), S( 94,155), S(153,128), S(119, 74),
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
#endif // #ifndef PSQTAB_H_INCLUDED
+824 -869
View File
File diff suppressed because it is too large Load Diff
+26 -29
View File
@@ -2,6 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,15 +21,14 @@
#ifndef SEARCH_H_INCLUDED
#define SEARCH_H_INCLUDED
#include <memory> // For std::auto_ptr
#include <stack>
#include <atomic>
#include <vector>
#include "misc.h"
#include "position.h"
#include "movepick.h"
#include "types.h"
struct SplitPoint;
class Position;
namespace Search {
@@ -37,37 +37,38 @@ namespace Search {
/// its own array of Stack objects, indexed by the current ply.
struct Stack {
SplitPoint* splitPoint;
Move* pv;
int ply;
Move currentMove;
Move ttMove;
Move excludedMove;
Move killers[2];
Depth reduction;
Value staticEval;
Value history;
bool skipEarlyPruning;
int moveCount;
CounterMoveStats* counterMoves;
};
/// 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.
struct RootMove {
RootMove(Move m) : score(-VALUE_INFINITE), previousScore(-VALUE_INFINITE), pv(1, m) {}
explicit RootMove(Move m) : pv(1, m) {}
bool operator<(const RootMove& m) const { return score > m.score; } // Ascending sort
bool operator<(const RootMove& m) const { return m.score < score; } // Descending sort
bool operator==(const Move& m) const { return pv[0] == m; }
void insert_pv_in_tt(Position& pos);
Move extract_ponder_from_tt(Position& pos);
bool extract_ponder_from_tt(Position& pos);
Value score;
Value previousScore;
Value score = -VALUE_INFINITE;
Value previousScore = -VALUE_INFINITE;
std::vector<Move> pv;
};
typedef std::vector<RootMove> RootMoveVector;
typedef std::vector<RootMove> RootMoves;
/// LimitsType struct stores information sent by GUI about available time to
/// search the current move, maximum depth/time, if we are in analysis mode or
@@ -76,8 +77,8 @@ typedef std::vector<RootMove> RootMoveVector;
struct LimitsType {
LimitsType() { // Init explicitly due to broken value-initialization of non POD in MSVC
nodes = time[WHITE] = time[BLACK] = inc[WHITE] = inc[BLACK] = movestogo =
depth = movetime = mate = infinite = ponder = 0;
nodes = time[WHITE] = time[BLACK] = inc[WHITE] = inc[BLACK] =
npmsec = movestogo = depth = movetime = mate = infinite = ponder = 0;
}
bool use_time_management() const {
@@ -85,29 +86,25 @@ struct LimitsType {
}
std::vector<Move> searchmoves;
int time[COLOR_NB], inc[COLOR_NB], movestogo, depth, movetime, mate, infinite, ponder;
int time[COLOR_NB], inc[COLOR_NB], npmsec, movestogo, depth, movetime, mate, infinite, ponder;
int64_t nodes;
TimePoint startTime;
};
/// The SignalsType struct stores volatile flags updated during the search
/// typically in an async fashion e.g. to stop the search by the GUI.
/// SignalsType struct stores atomic flags updated during the search, typically
/// in an async fashion e.g. to stop the search by the GUI.
struct SignalsType {
bool stop, stopOnPonderhit, firstRootMove, failedLowAtRoot;
std::atomic_bool stop, stopOnPonderhit;
};
typedef std::auto_ptr<std::stack<StateInfo> > StateStackPtr;
extern volatile SignalsType Signals;
extern SignalsType Signals;
extern LimitsType Limits;
extern RootMoveVector RootMoves;
extern Position RootPos;
extern Time::point SearchTime;
extern StateStackPtr SetupStates;
void init();
void think();
template<bool Root> uint64_t perft(Position& pos, Depth depth);
void clear();
template<bool Root = true> uint64_t perft(Position& pos, Depth depth);
} // namespace Search
+1 -1
View File
@@ -3,7 +3,7 @@
This file may be redistributed and/or modified without restrictions.
tbcore.c contains engine-independent routines of the tablebase probing code.
This file should not need to much adaptation to add tablebase probing to
This file should not need too much adaptation to add tablebase probing to
a particular engine, provided the engine is written in C or C++.
*/
+34 -41
View File
@@ -7,13 +7,14 @@
this code to other chess engines.
*/
#define NOMINMAX
#include <algorithm>
#include "../position.h"
#include "../movegen.h"
#include "../bitboard.h"
#include "../search.h"
#include "../bitcount.h"
#include "tbprobe.h"
#include "tbcore.h"
@@ -21,7 +22,7 @@
#include "tbcore.cpp"
namespace Zobrist {
extern Key psq[COLOR_NB][PIECE_TYPE_NB][SQUARE_NB];
extern Key psq[PIECE_NB][SQUARE_NB];
}
int Tablebases::MaxCardinality = 0;
@@ -37,12 +38,12 @@ static void prt_str(Position& pos, char *str, int mirror)
color = !mirror ? WHITE : BLACK;
for (pt = KING; pt >= PAWN; --pt)
for (i = popcount<Max15>(pos.pieces(color, pt)); i > 0; i--)
for (i = popcount(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--)
for (i = popcount(pos.pieces(color, pt)); i > 0; i--)
*str++ = pchr[6 - pt];
*str++ = 0;
}
@@ -58,12 +59,12 @@ static uint64 calc_key(Position& pos, int mirror)
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];
for (i = popcount(pos.pieces(color, pt)); i > 0; i--)
key ^= Zobrist::psq[make_piece(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];
for (i = popcount(pos.pieces(color, pt)); i > 0; i--)
key ^= Zobrist::psq[make_piece(BLACK, pt)][i - 1];
return key;
}
@@ -82,11 +83,11 @@ static uint64 calc_key_from_pcs(int *pcs, int mirror)
color = !mirror ? 0 : 8;
for (pt = PAWN; pt <= KING; ++pt)
for (i = 0; i < pcs[color + pt]; i++)
key ^= Zobrist::psq[WHITE][pt][i];
key ^= Zobrist::psq[make_piece(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];
key ^= Zobrist::psq[make_piece(BLACK, pt)][i];
return key;
}
@@ -122,7 +123,7 @@ static int probe_wdl_table(Position& pos, int *success)
key = pos.material_key();
// Test for KvK.
if (key == (Zobrist::psq[WHITE][KING][0] ^ Zobrist::psq[BLACK][KING][0]))
if (key == (Zobrist::psq[W_KING][0] ^ Zobrist::psq[B_KING][0]))
return 0;
ptr2 = TB_hash[key >> (64 - TBHASHBITS)];
@@ -360,14 +361,12 @@ static int probe_ab(Position& pos, int alpha, int beta, int *success)
} 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))
|| !pos.legal(capture))
continue;
pos.do_move(capture, st, ci, pos.gives_check(capture, ci));
pos.do_move(capture, st, pos.gives_check(capture));
v = -probe_ab(pos, -beta, -alpha, success);
pos.undo_move(capture);
if (*success == 0) return 0;
@@ -423,14 +422,12 @@ int Tablebases::probe_wdl(Position& pos, int *success)
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))
|| !pos.legal(capture))
continue;
pos.do_move(capture, st, ci, pos.gives_check(capture, ci));
pos.do_move(capture, st, pos.gives_check(capture));
int v0 = -probe_ab(pos, -2, 2, success);
pos.undo_move(capture);
if (*success == 0) return 0;
@@ -443,13 +440,13 @@ int Tablebases::probe_wdl(Position& pos, int *success)
for (moves = stack; moves < end; moves++) {
Move capture = moves->move;
if (type_of(capture) == ENPASSANT) continue;
if (pos.legal(capture, ci.pinned)) break;
if (pos.legal(capture)) 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))
if (pos.legal(move))
break;
}
}
@@ -478,7 +475,6 @@ static int probe_dtz_no_ep(Position& pos, int *success)
ExtMove stack[192];
ExtMove *moves, *end = NULL;
StateInfo st;
CheckInfo ci(pos);
if (wdl > 0) {
// Generate at least all legal non-capturing pawn moves
@@ -491,10 +487,10 @@ static int probe_dtz_no_ep(Position& pos, int *success)
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))
|| !pos.legal(move))
continue;
pos.do_move(move, st, ci, pos.gives_check(move, ci));
int v = -probe_ab(pos, -2, -wdl + 1, success);
pos.do_move(move, st, pos.gives_check(move));
int v = -Tablebases::probe_wdl(pos, success);
pos.undo_move(move);
if (*success == 0) return 0;
if (v == wdl)
@@ -513,9 +509,9 @@ static int probe_dtz_no_ep(Position& pos, int *success)
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))
|| !pos.legal(move))
continue;
pos.do_move(move, st, ci, pos.gives_check(move, ci));
pos.do_move(move, st, pos.gives_check(move));
int v = -Tablebases::probe_dtz(pos, success);
pos.undo_move(move);
if (*success == 0) return 0;
@@ -532,9 +528,9 @@ static int probe_dtz_no_ep(Position& pos, int *success)
for (moves = stack; moves < end; moves++) {
int v;
Move move = moves->move;
if (!pos.legal(move, ci.pinned))
if (!pos.legal(move))
continue;
pos.do_move(move, st, ci, pos.gives_check(move, ci));
pos.do_move(move, st, pos.gives_check(move));
if (st.rule50 == 0) {
if (wdl == -2) v = -1;
else {
@@ -603,14 +599,13 @@ int Tablebases::probe_dtz(Position& pos, int *success)
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))
|| !pos.legal(capture))
continue;
pos.do_move(capture, st, ci, pos.gives_check(capture, ci));
pos.do_move(capture, st, pos.gives_check(capture));
int v0 = -probe_ab(pos, -2, 2, success);
pos.undo_move(capture);
if (*success == 0) return 0;
@@ -622,7 +617,7 @@ int Tablebases::probe_dtz(Position& pos, int *success)
if (v1 >= 0)
v = v1;
} else if (v < 0) {
if (v1 >= 0 || v1 < 100)
if (v1 >= 0 || v1 < -100)
v = v1;
} else if (v > 100) {
if (v1 > 0)
@@ -636,13 +631,13 @@ int Tablebases::probe_dtz(Position& pos, int *success)
for (moves = stack; moves < end; moves++) {
Move move = moves->move;
if (type_of(move) == ENPASSANT) continue;
if (pos.legal(move, ci.pinned)) break;
if (pos.legal(move)) 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))
if (pos.legal(move))
break;
}
}
@@ -687,7 +682,7 @@ static Value wdl_to_Value[5] = {
//
// 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)
bool Tablebases::root_probe(Position& pos, Search::RootMoves& rootMoves, Value& score)
{
int success;
@@ -695,12 +690,11 @@ bool Tablebases::root_probe(Position& pos, Search::RootMoveVector& rootMoves, Va
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));
pos.do_move(move, st, pos.gives_check(move));
int v = 0;
if (pos.checkers() && dtz > 0) {
ExtMove s[192];
@@ -794,7 +788,7 @@ bool Tablebases::root_probe(Position& pos, Search::RootMoveVector& rootMoves, Va
//
// 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)
bool Tablebases::root_probe_wdl(Position& pos, Search::RootMoves& rootMoves, Value& score)
{
int success;
@@ -803,14 +797,13 @@ bool Tablebases::root_probe_wdl(Position& pos, Search::RootMoveVector& rootMoves
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));
pos.do_move(move, st, pos.gives_check(move));
int v = -Tablebases::probe_wdl(pos, &success);
pos.undo_move(move);
if (!success) return false;
+3 -2
View File
@@ -10,8 +10,9 @@ 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);
bool root_probe(Position& pos, Search::RootMoves& rootMoves, Value& score);
bool root_probe_wdl(Position& pos, Search::RootMoves& rootMoves, Value& score);
void filter_root_moves(Position& pos, Search::RootMoves& rootMoves);
}
+112 -274
View File
@@ -2,6 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -24,362 +25,199 @@
#include "search.h"
#include "thread.h"
#include "uci.h"
using namespace Search;
#include "syzygy/tbprobe.h"
ThreadPool Threads; // Global object
extern void check_time();
/// Thread constructor launches the thread and then waits until it goes to sleep
/// in idle_loop().
namespace {
Thread::Thread() {
// 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;
}
resetCalls = exit = false;
maxPly = callsCnt = 0;
tbHits = 0;
history.clear();
counterMoves.clear();
idx = Threads.size(); // Start from 0
std::unique_lock<Mutex> lk(mutex);
searching = true;
nativeThread = std::thread(&Thread::idle_loop, this);
sleepCondition.wait(lk, [&]{ return !searching; });
}
// ThreadBase::notify_one() wakes up the thread when there is some work to do
/// Thread destructor waits for thread termination before returning
void ThreadBase::notify_one() {
Thread::~Thread() {
mutex.lock();
exit = true;
sleepCondition.notify_one();
mutex.unlock();
nativeThread.join();
}
// ThreadBase::wait_for() set the thread to sleep until 'condition' turns true
/// Thread::wait_for_search_finished() waits on sleep condition
/// until not searching
void ThreadBase::wait_for(volatile const bool& condition) {
void Thread::wait_for_search_finished() {
mutex.lock();
while (!condition) sleepCondition.wait(mutex);
mutex.unlock();
std::unique_lock<Mutex> lk(mutex);
sleepCondition.wait(lk, [&]{ return !searching; });
}
// Thread c'tor makes some init but does not launch any execution thread that
// will be started only when c'tor returns.
/// Thread::wait() waits on sleep condition until condition is true
Thread::Thread() /* : splitPoints() */ { // Initialization of non POD broken in MSVC
void Thread::wait(std::atomic_bool& condition) {
searching = false;
maxPly = splitPointsSize = 0;
activeSplitPoint = NULL;
activePosition = NULL;
idx = Threads.size(); // Starts from 0
std::unique_lock<Mutex> lk(mutex);
sleepCondition.wait(lk, [&]{ return bool(condition); });
}
// Thread::cutoff_occurred() checks whether a beta cutoff has occurred in the
// current active split point, or in some ancestor of the split point.
/// Thread::start_searching() wakes up the thread that will start the search
bool Thread::cutoff_occurred() const {
void Thread::start_searching(bool resume) {
for (SplitPoint* sp = activeSplitPoint; sp; sp = sp->parentSplitPoint)
if (sp->cutoff)
return true;
std::unique_lock<Mutex> lk(mutex);
return false;
if (!resume)
searching = true;
sleepCondition.notify_one();
}
// 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
// be idle. With more than two threads, this is not sufficient: If the thread is
// the master of some split point, it is only available as a slave to the slaves
// which are busy searching the split point at the top of slave's split point
// stack (the "helpful master concept" in YBWC terminology).
/// Thread::idle_loop() is where the thread is parked when it has no work to do
bool Thread::available_to(const Thread* master) const {
if (searching)
return false;
// 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 bounds access.
const int size = splitPointsSize;
// No split points means that the thread is available as a slave for any
// other thread otherwise apply the "helpful master" concept if possible.
return !size || splitPoints[size - 1].slavesMask.test(master->idx);
}
// Thread::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), 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
// 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() {
void Thread::idle_loop() {
while (!exit)
{
mutex.lock();
std::unique_lock<Mutex> lk(mutex);
searching = false;
while (!searching && !exit)
{
sleepCondition.notify_one(); // Wake up any waiting thread
sleepCondition.wait(lk);
}
lk.unlock();
if (!exit)
sleepCondition.wait_for(mutex, run ? Resolution : INT_MAX);
mutex.unlock();
if (run)
check_time();
search();
}
}
// 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.
/// ThreadPool::init() creates and launches requested threads that will go
/// immediately to sleep. We cannot use a constructor because Threads is a
/// static object and we need a fully initialized engine at this point due to
/// allocation of Endgames in the Thread constructor.
void ThreadPool::init() {
timer = new_thread<TimerThread>();
push_back(new_thread<MainThread>());
push_back(new MainThread);
read_uci_options();
}
// ThreadPool::exit() terminates the threads before the program exits. Cannot be
// done in d'tor because threads must be terminated before freeing us.
/// ThreadPool::exit() terminates threads before the program exits. Cannot be
/// done in destructor because threads must be terminated before deleting any
/// static objects while still in main().
void ThreadPool::exit() {
delete_thread(timer); // As first because check_time() accesses threads data
for (iterator it = begin(); it != end(); ++it)
delete_thread(*it);
while (size())
delete back(), pop_back();
}
// ThreadPool::read_uci_options() updates internal threads parameters from the
// corresponding UCI options and creates/destroys threads to match the requested
// number. Thread objects are dynamically allocated to avoid creating all possible
// threads in advance (which include pawns and material tables), even if only a
// few are to be used.
/// ThreadPool::read_uci_options() updates internal threads parameters from the
/// corresponding UCI options and creates/destroys threads to match requested
/// number. Thread objects are dynamically allocated.
void ThreadPool::read_uci_options() {
minimumSplitDepth = Options["Min Split Depth"] * ONE_PLY;
size_t requested = Options["Threads"];
size_t requested = Options["Threads"];
assert(requested > 0);
// If zero (default) then set best minimum split depth automatically
if (!minimumSplitDepth)
minimumSplitDepth = requested < 8 ? 4 * ONE_PLY : 7 * ONE_PLY;
while (size() < requested)
push_back(new_thread<Thread>());
push_back(new Thread);
while (size() > requested)
{
delete_thread(back());
pop_back();
}
delete back(), pop_back();
}
// ThreadPool::available_slave() tries to find an idle thread which is available
// as a slave for the thread 'master'.
/// ThreadPool::nodes_searched() returns the number of nodes searched
Thread* ThreadPool::available_slave(const Thread* master) const {
uint64_t ThreadPool::nodes_searched() const {
for (const_iterator it = begin(); it != end(); ++it)
if ((*it)->available_to(master))
return *it;
return NULL;
uint64_t nodes = 0;
for (Thread* th : *this)
nodes += th->rootPos.nodes_searched();
return nodes;
}
// ThreadPool::wait_for_think_finished() waits for main thread to finish the search
/// ThreadPool::tb_hits() returns the number of TB hits
void ThreadPool::wait_for_think_finished() {
uint64_t ThreadPool::tb_hits() const {
MainThread* th = main();
th->mutex.lock();
while (th->thinking) sleepCondition.wait(th->mutex);
th->mutex.unlock();
uint64_t hits = 0;
for (Thread* th : *this)
hits += th->tbHits;
return hits;
}
// ThreadPool::start_thinking() wakes up the main thread sleeping in
// MainThread::idle_loop() and starts a new search, then returns immediately.
/// ThreadPool::start_thinking() wakes up the main thread sleeping in idle_loop()
/// and starts a new search, then returns immediately.
void ThreadPool::start_thinking(const Position& pos, const LimitsType& limits,
StateStackPtr& states) {
wait_for_think_finished();
void ThreadPool::start_thinking(Position& pos, StateListPtr& states,
const Search::LimitsType& limits) {
SearchTime = Time::now(); // As early as possible
main()->wait_for_search_finished();
Signals.stopOnPonderhit = Signals.firstRootMove = false;
Signals.stop = Signals.failedLowAtRoot = false;
Search::Signals.stopOnPonderhit = Search::Signals.stop = false;
Search::Limits = limits;
Search::RootMoves rootMoves;
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> it(pos); *it; ++it)
for (const auto& m : MoveList<LEGAL>(pos))
if ( limits.searchmoves.empty()
|| std::count(limits.searchmoves.begin(), limits.searchmoves.end(), *it))
RootMoves.push_back(RootMove(*it));
|| std::count(limits.searchmoves.begin(), limits.searchmoves.end(), m))
rootMoves.push_back(Search::RootMove(m));
main()->thinking = true;
main()->notify_one(); // Starts main thread
if (!rootMoves.empty())
Tablebases::filter_root_moves(pos, rootMoves);
// After ownership transfer 'states' becomes empty, so if we stop the search
// and call 'go' again without setting a new position states.get() == NULL.
assert(states.get() || setupStates.get());
if (states.get())
setupStates = std::move(states); // Ownership transfer, states is now empty
StateInfo tmp = setupStates->back();
for (Thread* th : Threads)
{
th->maxPly = 0;
th->tbHits = 0;
th->rootDepth = DEPTH_ZERO;
th->rootMoves = rootMoves;
th->rootPos.set(pos.fen(), pos.is_chess960(), &setupStates->back(), th);
}
setupStates->back() = tmp; // Restore st->previous, cleared by Position::set()
main()->start_searching();
}
+48 -123
View File
@@ -2,6 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,7 +21,11 @@
#ifndef THREAD_H_INCLUDED
#define THREAD_H_INCLUDED
#include <atomic>
#include <bitset>
#include <condition_variable>
#include <mutex>
#include <thread>
#include <vector>
#include "material.h"
@@ -28,157 +33,77 @@
#include "pawns.h"
#include "position.h"
#include "search.h"
struct Thread;
const int MAX_THREADS = 128;
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 {
Mutex() { lock_init(l); }
~Mutex() { lock_destroy(l); }
void lock() { lock_grab(l); }
void unlock() { lock_release(l); }
private:
friend struct ConditionVariable;
Lock l;
};
struct ConditionVariable {
ConditionVariable() { cond_init(c); }
~ConditionVariable() { cond_destroy(c); }
void wait(Mutex& m) { cond_wait(c, m.l); }
void wait_for(Mutex& m, int ms) { timed_wait(c, m.l, ms); }
void notify_one() { cond_signal(c); }
private:
WaitCondition c;
};
#include "thread_win32.h"
/// SplitPoint struct stores information shared by the threads searching in
/// parallel below the same split point. It is populated at splitting time.
/// Thread struct keeps together all the thread-related stuff. 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 and we don't have to care about someone
/// changing the entry under our feet.
struct SplitPoint {
// Const data after split point has been setup
const Position* pos;
Search::Stack* ss;
Thread* masterThread;
Depth depth;
Value beta;
int nodeType;
bool cutNode;
// Const pointers to shared data
MovePicker* movePicker;
SplitPoint* parentSplitPoint;
// Shared variable data
Mutex mutex;
std::bitset<MAX_THREADS> slavesMask;
volatile bool allSlavesSearching;
volatile uint64_t nodes;
volatile Value alpha;
volatile Value bestValue;
volatile Move bestMove;
volatile int moveCount;
volatile bool cutoff;
};
/// 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);
class Thread {
std::thread nativeThread;
Mutex mutex;
ConditionVariable sleepCondition;
NativeHandle handle;
volatile bool exit;
};
/// 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
/// 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.
struct Thread : public ThreadBase {
bool exit, searching;
public:
Thread();
virtual void idle_loop();
bool cutoff_occurred() const;
bool available_to(const Thread* master) const;
virtual ~Thread();
virtual void search();
void idle_loop();
void start_searching(bool resume = false);
void wait_for_search_finished();
void wait(std::atomic_bool& b);
void split(Position& pos, Search::Stack* ss, Value alpha, Value beta, Value* bestValue, Move* bestMove,
Depth depth, int moveCount, MovePicker* movePicker, int nodeType, bool cutNode);
SplitPoint splitPoints[MAX_SPLITPOINTS_PER_THREAD];
Pawns::Table pawnsTable;
Material::Table materialTable;
Endgames endgames;
Position* activePosition;
size_t idx;
int maxPly;
SplitPoint* volatile activeSplitPoint;
volatile int splitPointsSize;
volatile bool searching;
size_t idx, PVIdx;
int maxPly, callsCnt;
uint64_t tbHits;
Position rootPos;
Search::RootMoves rootMoves;
Depth rootDepth;
Depth completedDepth;
std::atomic_bool resetCalls;
HistoryStats history;
MoveStats counterMoves;
FromToStats fromTo;
CounterMoveHistoryStats counterMoveHistory;
};
/// MainThread and TimerThread are derived classes used to characterize the two
/// special threads: the main one and the recurring timer.
/// MainThread is a derived class with a specific overload for the main thread
struct MainThread : public Thread {
MainThread() : thinking(true) {} // Avoid a race with start_thinking()
virtual void idle_loop();
volatile bool thinking;
};
virtual void search();
struct TimerThread : public ThreadBase {
static const int Resolution = 5; // Millisec between two check_time() calls
TimerThread() : run(false) {}
virtual void idle_loop();
bool run;
bool easyMovePlayed, failedLow;
double bestMoveChanges;
Value previousScore;
};
/// 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.
/// ThreadPool struct handles all the threads-related stuff like init, starting,
/// parking and, most importantly, launching a thread. All the access to threads
/// data is done through this class.
struct ThreadPool : public std::vector<Thread*> {
void init(); // No c'tor and d'tor, threads rely on globals that should be
void exit(); // initialized and are valid during the whole thread lifetime.
void init(); // No constructor and destructor, threads rely on globals that should
void exit(); // be initialized and valid during the whole thread lifetime.
MainThread* main() { return static_cast<MainThread*>(at(0)); }
void start_thinking(Position&, StateListPtr&, const Search::LimitsType&);
void read_uci_options();
Thread* available_slave(const Thread* master) const;
void wait_for_think_finished();
void start_thinking(const Position&, const Search::LimitsType&, Search::StateStackPtr&);
uint64_t nodes_searched() const;
uint64_t tb_hits() const;
Depth minimumSplitDepth;
Mutex mutex;
ConditionVariable sleepCondition;
TimerThread* timer;
private:
StateListPtr setupStates;
};
extern ThreadPool Threads;
+70
View File
@@ -0,0 +1,70 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Stockfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef THREAD_WIN32_H_INCLUDED
#define THREAD_WIN32_H_INCLUDED
/// STL thread library used by mingw and gcc when cross compiling for Windows
/// relies on libwinpthread. Currently libwinpthread implements mutexes directly
/// on top of Windows semaphores. Semaphores, being kernel objects, require kernel
/// mode transition in order to lock or unlock, which is very slow compared to
/// interlocked operations (about 30% slower on bench test). To work around this
/// issue, we define our wrappers to the low level Win32 calls. We use critical
/// sections to support Windows XP and older versions. Unfortunately, cond_wait()
/// is racy between unlock() and WaitForSingleObject() but they have the same
/// speed performance as the SRW locks.
#include <condition_variable>
#include <mutex>
#if defined(_WIN32) && !defined(_MSC_VER)
#ifndef NOMINMAX
# define NOMINMAX // Disable macros min() and max()
#endif
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#undef WIN32_LEAN_AND_MEAN
#undef NOMINMAX
/// Mutex and ConditionVariable struct are wrappers of the low level locking
/// machinery and are modeled after the corresponding C++11 classes.
struct Mutex {
Mutex() { InitializeCriticalSection(&cs); }
~Mutex() { DeleteCriticalSection(&cs); }
void lock() { EnterCriticalSection(&cs); }
void unlock() { LeaveCriticalSection(&cs); }
private:
CRITICAL_SECTION cs;
};
typedef std::condition_variable_any ConditionVariable;
#else // Default case: use STL classes
typedef std::mutex Mutex;
typedef std::condition_variable ConditionVariable;
#endif
#endif // #ifndef THREAD_WIN32_H_INCLUDED
+35 -19
View File
@@ -2,6 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -25,32 +26,34 @@
#include "timeman.h"
#include "uci.h"
TimeManagement Time; // Our global time management object
namespace {
enum TimeType { OptimumTime, MaxTime };
const int MoveHorizon = 50; // Plan time management at most this many moves ahead
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
const double MaxRatio = 7.09; // When in trouble, we can step over reserved time with this ratio
const double StealRatio = 0.35; // However we must not steal time from remaining moves over this ratio
// move_importance() is a skew-logistic function based on naive statistical
// 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.
// Data was extracted from the CCRL game database with some simple filtering criteria.
double move_importance(int ply) {
const double XScale = 9.3;
const double XShift = 59.8;
const double Skew = 0.172;
const double XScale = 7.64;
const double XShift = 58.4;
const double Skew = 0.183;
return pow((1 + exp((ply - XShift) / XScale)), -Skew) + DBL_MIN; // Ensure non-zero
}
template<TimeType T>
int remaining(int myTime, int movesToGo, int ply, int slowMover)
{
int remaining(int myTime, int movesToGo, int ply, int slowMover) {
const double TMaxRatio = (T == OptimumTime ? 1 : MaxRatio);
const double TStealRatio = (T == OptimumTime ? 0 : StealRatio);
@@ -63,7 +66,7 @@ namespace {
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
return int(myTime * std::min(ratio1, ratio2)); // Intel C++ asks for an explicit cast
}
} // namespace
@@ -78,15 +81,30 @@ namespace {
/// 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)
{
void TimeManagement::init(Search::LimitsType& limits, Color us, int ply) {
int minThinkingTime = Options["Minimum Thinking Time"];
int moveOverhead = Options["Move Overhead"];
int slowMover = Options["Slow Mover"];
int npmsec = Options["nodestime"];
// Initialize unstablePvFactor to 1 and search times to maximum values
unstablePvFactor = 1;
optimumSearchTime = maximumSearchTime = std::max(limits.time[us], minThinkingTime);
// If we have to play in 'nodes as time' mode, then convert from time
// to nodes, and use resulting values in time management formulas.
// WARNING: Given npms (nodes per millisecond) must be much lower then
// the real engine speed to avoid time losses.
if (npmsec)
{
if (!availableNodes) // Only once at game start
availableNodes = npmsec * limits.time[us]; // Time is in msec
// Convert from millisecs to nodes
limits.time[us] = (int)availableNodes;
limits.inc[us] *= npmsec;
limits.npmsec = npmsec;
}
startTime = limits.startTime;
optimumTime = maximumTime = std::max(limits.time[us], minThinkingTime);
const int MaxMTG = limits.movestogo ? std::min(limits.movestogo, MoveHorizon) : MoveHorizon;
@@ -105,12 +123,10 @@ void TimeManager::init(const Search::LimitsType& limits, Color us, int ply)
int t1 = minThinkingTime + remaining<OptimumTime>(hypMyTime, hypMTG, ply, slowMover);
int t2 = minThinkingTime + remaining<MaxTime >(hypMyTime, hypMTG, ply, slowMover);
optimumSearchTime = std::min(t1, optimumSearchTime);
maximumSearchTime = std::min(t2, maximumSearchTime);
optimumTime = std::min(t1, optimumTime);
maximumTime = std::min(t2, maximumTime);
}
if (Options["Ponder"])
optimumSearchTime += optimumSearchTime / 4;
optimumSearchTime = std::min(optimumSearchTime, maximumSearchTime);
optimumTime += optimumTime / 4;
}
+19 -10
View File
@@ -2,6 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,20 +21,28 @@
#ifndef TIMEMAN_H_INCLUDED
#define TIMEMAN_H_INCLUDED
/// The TimeManager class computes the optimal time to think depending on the
/// maximum available time, the game move number and other parameters.
#include "misc.h"
#include "search.h"
#include "thread.h"
class TimeManager {
/// The TimeManagement class computes the optimal time to think depending on
/// the maximum available time, the game move number and other parameters.
class TimeManagement {
public:
void init(const Search::LimitsType& limits, Color us, int ply);
void pv_instability(double bestMoveChanges) { unstablePvFactor = 1 + bestMoveChanges; }
int available_time() const { return int(optimumSearchTime * unstablePvFactor * 0.71); }
int maximum_time() const { return maximumSearchTime; }
void init(Search::LimitsType& limits, Color us, int ply);
int optimum() const { return optimumTime; }
int maximum() const { return maximumTime; }
int elapsed() const { return int(Search::Limits.npmsec ? Threads.nodes_searched() : now() - startTime); }
int64_t availableNodes; // When in 'nodes as time' mode
private:
int optimumSearchTime;
int maximumSearchTime;
double unstablePvFactor;
TimePoint startTime;
int optimumTime;
int maximumTime;
};
extern TimeManagement Time;
#endif // #ifndef TIMEMAN_H_INCLUDED
+28 -9
View File
@@ -2,6 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -32,8 +33,6 @@ TranspositionTable TT; // Our global transposition table
void TranspositionTable::resize(size_t mbSize) {
assert(sizeof(Cluster) == CacheLineSize / 2);
size_t newClusterCount = size_t(1) << msb((mbSize * 1024 * 1024) / sizeof(Cluster));
if (newClusterCount == clusterCount)
@@ -68,9 +67,9 @@ void TranspositionTable::clear() {
/// TranspositionTable::probe() looks up the current position in the transposition
/// table. It returns true and a pointer to the TTEntry if the position is found.
/// Otherwise, it returns false and a pointer to an empty or least valuable TTEntry
/// to be replaced later. A TTEntry t1 is considered to be more valuable than a
/// TTEntry t2 if t1 is from the current search and t2 is from a previous search,
/// or if the depth of t1 is bigger than the depth of t2.
/// to be replaced later. The replace value of an entry is calculated as its depth
/// minus 8 times its relative age. TTEntry t1 is considered more valuable than
/// TTEntry t2 if its replace value is greater than that of t2.
TTEntry* TranspositionTable::probe(const Key key, bool& found) const {
@@ -80,7 +79,7 @@ TTEntry* TranspositionTable::probe(const Key key, bool& found) const {
for (int i = 0; i < ClusterSize; ++i)
if (!tte[i].key16 || tte[i].key16 == key16)
{
if (tte[i].key16)
if ((tte[i].genBound8 & 0xFC) != generation8 && tte[i].key16)
tte[i].genBound8 = uint8_t(generation8 | tte[i].bound()); // Refresh
return found = (bool)tte[i].key16, &tte[i];
@@ -89,10 +88,30 @@ TTEntry* TranspositionTable::probe(const Key key, bool& found) const {
// Find an entry to be replaced according to the replacement strategy
TTEntry* replace = tte;
for (int i = 1; i < ClusterSize; ++i)
if ( (( tte[i].genBound8 & 0xFC) == generation8 || tte[i].bound() == BOUND_EXACT)
- ((replace->genBound8 & 0xFC) == generation8)
- (tte[i].depth8 < replace->depth8) < 0)
// Due to our packed storage format for generation and its cyclic
// nature we add 259 (256 is the modulus plus 3 to keep the lowest
// two bound bits from affecting the result) to calculate the entry
// age correctly even after generation8 overflows into the next cycle.
if ( replace->depth8 - ((259 + generation8 - replace->genBound8) & 0xFC) * 2
> tte[i].depth8 - ((259 + generation8 - tte[i].genBound8) & 0xFC) * 2)
replace = &tte[i];
return found = false, replace;
}
/// TranspositionTable::hashfull() returns an approximation of the hashtable
/// occupation during a search. The hash is x permill full, as per UCI protocol.
int TranspositionTable::hashfull() const {
int cnt = 0;
for (int i = 0; i < 1000 / ClusterSize; i++)
{
const TTEntry* tte = &table[i].entry[0];
for (int j = 0; j < ClusterSize; j++)
if ((tte[j].genBound8 & 0xFC) == generation8)
cnt++;
}
return cnt;
}
+25 -10
View File
@@ -2,6 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -38,19 +39,29 @@ struct TTEntry {
Move move() const { return (Move )move16; }
Value value() const { return (Value)value16; }
Value eval() const { return (Value)eval16; }
Depth depth() const { return (Depth)depth8; }
Depth depth() const { return (Depth)(depth8 * int(ONE_PLY)); }
Bound bound() const { return (Bound)(genBound8 & 0x3); }
void save(Key k, Value v, Bound b, Depth d, Move m, Value ev, uint8_t g) {
if (m || (k >> 48) != key16) // Preserve any existing move for the same position
assert(d / ONE_PLY * ONE_PLY == d);
// Preserve any existing move for the same position
if (m || (k >> 48) != key16)
move16 = (uint16_t)m;
key16 = (uint16_t)(k >> 48);
value16 = (int16_t)v;
eval16 = (int16_t)ev;
genBound8 = (uint8_t)(g | b);
depth8 = (int8_t)d;
// Don't overwrite more valuable entries
if ( (k >> 48) != key16
|| d / ONE_PLY > depth8 - 4
/* || g != (genBound8 & 0xFC) // Matching non-zero keys are already refreshed by probe() */
|| b == BOUND_EXACT)
{
key16 = (uint16_t)(k >> 48);
value16 = (int16_t)v;
eval16 = (int16_t)ev;
genBound8 = (uint8_t)(g | b);
depth8 = (int8_t)(d / ONE_PLY);
}
}
private:
@@ -68,8 +79,9 @@ private:
/// A TranspositionTable consists of a power of 2 number of clusters and each
/// 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
/// to guarantee always aligned accesses.
/// divide the size of a cache line size, to ensure that clusters never cross
/// cache lines. This ensures best cache performance, as the cacheline is
/// prefetched, as soon as possible.
class TranspositionTable {
@@ -78,14 +90,17 @@ class TranspositionTable {
struct Cluster {
TTEntry entry[ClusterSize];
char padding[2]; // Align to the cache line size
char padding[2]; // Align to a divisor of the cache line size
};
static_assert(CacheLineSize % sizeof(Cluster) == 0, "Cluster size incorrect");
public:
~TranspositionTable() { free(mem); }
void new_search() { generation8 += 4; } // Lower 2 bits are used by Bound
uint8_t generation() const { return generation8; }
TTEntry* probe(const Key key, bool& found) const;
int hashfull() const;
void resize(size_t mbSize);
void clear();
+70 -71
View File
@@ -2,6 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -33,13 +34,22 @@
///
/// -DUSE_POPCNT | Add runtime support for use of popcnt asm-instruction. Works
/// | only in 64-bit mode and requires hardware with popcnt support.
///
/// -DUSE_PEXT | Add runtime support for use of pext asm-instruction. Works
/// | only in 64-bit mode and requires hardware with pext support.
#include <cassert>
#include <cctype>
#include <climits>
#include <cstdint>
#include <cstdlib>
#include "platform.h"
#if defined(_MSC_VER)
// Disable some silly and noisy warning from MSVC compiler
#pragma warning(disable: 4127) // Conditional expression is constant
#pragma warning(disable: 4146) // Unary minus operator applied to unsigned type
#pragma warning(disable: 4800) // Forcing value to bool 'true' or 'false'
#endif
/// Predefined macros hell:
///
@@ -49,14 +59,13 @@
/// _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
#if defined(_WIN64) && defined(_MSC_VER) // No Makefile used
# include <intrin.h> // Microsoft header for _BitScanForward64()
# define IS_64BIT
# define USE_BSFQ
#endif
#if defined(USE_POPCNT) && defined(__INTEL_COMPILER) && defined(_MSC_VER)
# include <nmmintrin.h> // Intel header for _mm_popcnt_u64() intrinsic
#if defined(USE_POPCNT) && (defined(__INTEL_COMPILER) || defined(_MSC_VER))
# include <nmmintrin.h> // Intel and Microsoft header for _mm_popcnt_u64()
#endif
#if !defined(NO_PREFETCH) && (defined(__INTEL_COMPILER) || defined(_MSC_VER))
@@ -70,14 +79,6 @@
# define pext(b, m) (0)
#endif
#ifdef _MSC_VER
# define FORCE_INLINE __forceinline
#elif defined(__GNUC__)
# define FORCE_INLINE inline __attribute__((always_inline))
#else
# define FORCE_INLINE inline
#endif
#ifdef USE_POPCNT
const bool HasPopCnt = true;
#else
@@ -114,7 +115,7 @@ const int MAX_PLY = 128;
/// any normal move destination square is always different from origin square
/// while MOVE_NONE and MOVE_NULL have the same origin and destination square.
enum Move {
enum Move : int {
MOVE_NONE,
MOVE_NULL = 65
};
@@ -171,7 +172,7 @@ enum Bound {
BOUND_EXACT = BOUND_UPPER | BOUND_LOWER
};
enum Value {
enum Value : int {
VALUE_ZERO = 0,
VALUE_DRAW = 0,
VALUE_KNOWN_WIN = 10000,
@@ -182,16 +183,13 @@ enum Value {
VALUE_MATE_IN_MAX_PLY = VALUE_MATE - 2 * MAX_PLY,
VALUE_MATED_IN_MAX_PLY = -VALUE_MATE + 2 * MAX_PLY,
VALUE_ENSURE_INTEGER_SIZE_P = INT_MAX,
VALUE_ENSURE_INTEGER_SIZE_N = INT_MIN,
PawnValueMg = 188, PawnValueEg = 248,
KnightValueMg = 753, KnightValueEg = 832,
BishopValueMg = 826, BishopValueEg = 897,
RookValueMg = 1285, RookValueEg = 1371,
QueenValueMg = 2513, QueenValueEg = 2650,
PawnValueMg = 198, PawnValueEg = 258,
KnightValueMg = 817, KnightValueEg = 846,
BishopValueMg = 836, BishopValueEg = 857,
RookValueMg = 1270, RookValueEg = 1278,
QueenValueMg = 2521, QueenValueEg = 2558,
MidgameLimit = 15581, EndgameLimit = 3998
MidgameLimit = 15258, EndgameLimit = 3915
};
enum PieceType {
@@ -207,19 +205,25 @@ enum Piece {
PIECE_NB = 16
};
const Piece Pieces[] = { W_PAWN, W_KNIGHT, W_BISHOP, W_ROOK, W_QUEEN, W_KING,
B_PAWN, B_KNIGHT, B_BISHOP, B_ROOK, B_QUEEN, B_KING };
extern Value PieceValue[PHASE_NB][PIECE_NB];
enum Depth {
ONE_PLY = 1,
DEPTH_ZERO = 0,
DEPTH_QS_CHECKS = 0,
DEPTH_QS_NO_CHECKS = -1,
DEPTH_QS_RECAPTURES = -5,
DEPTH_ZERO = 0 * ONE_PLY,
DEPTH_QS_CHECKS = 0 * ONE_PLY,
DEPTH_QS_NO_CHECKS = -1 * ONE_PLY,
DEPTH_QS_RECAPTURES = -5 * ONE_PLY,
DEPTH_NONE = -6,
DEPTH_MAX = MAX_PLY
DEPTH_NONE = -6 * ONE_PLY,
DEPTH_MAX = MAX_PLY * ONE_PLY
};
static_assert(!(ONE_PLY & (ONE_PLY - 1)), "ONE_PLY is not a power of 2");
enum Square {
SQ_A1, SQ_B1, SQ_C1, SQ_D1, SQ_E1, SQ_F1, SQ_G1, SQ_H1,
SQ_A2, SQ_B2, SQ_C2, SQ_D2, SQ_E2, SQ_F2, SQ_G2, SQ_H2,
@@ -233,58 +237,51 @@ enum Square {
SQUARE_NB = 64,
DELTA_N = 8,
DELTA_E = 1,
DELTA_S = -8,
DELTA_W = -1,
NORTH = 8,
EAST = 1,
SOUTH = -8,
WEST = -1,
DELTA_NN = DELTA_N + DELTA_N,
DELTA_NE = DELTA_N + DELTA_E,
DELTA_SE = DELTA_S + DELTA_E,
DELTA_SS = DELTA_S + DELTA_S,
DELTA_SW = DELTA_S + DELTA_W,
DELTA_NW = DELTA_N + DELTA_W
NORTH_EAST = NORTH + EAST,
SOUTH_EAST = SOUTH + EAST,
SOUTH_WEST = SOUTH + WEST,
NORTH_WEST = NORTH + WEST
};
enum File {
enum File : int {
FILE_A, FILE_B, FILE_C, FILE_D, FILE_E, FILE_F, FILE_G, FILE_H, FILE_NB
};
enum Rank {
enum Rank : int {
RANK_1, RANK_2, RANK_3, RANK_4, RANK_5, RANK_6, RANK_7, RANK_8, RANK_NB
};
/// Score enum stores a middlegame and an endgame value in a single integer.
/// The least significant 16 bits are used to store the endgame value and
/// the upper 16 bits are used to store the middlegame value. The compiler
/// 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 {
SCORE_ZERO,
SCORE_ENSURE_INTEGER_SIZE_P = INT_MAX,
SCORE_ENSURE_INTEGER_SIZE_N = INT_MIN
};
/// Score enum stores a middlegame and an endgame value in a single integer
/// (enum). The least significant 16 bits are used to store the endgame value
/// and the upper 16 bits are used to store the middlegame value. Take some
/// care to avoid left-shifting a signed int to avoid undefined behavior.
enum Score : int { SCORE_ZERO };
inline Score make_score(int mg, int eg) {
return Score((mg << 16) + eg);
return Score((int)((unsigned int)eg << 16) + mg);
}
/// Extracting the signed lower and upper 16 bits is not so trivial because
/// 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) {
union { uint16_t u; int16_t s; } mg = { uint16_t(unsigned(s + 0x8000) >> 16) };
return Value(mg.s);
}
inline Value eg_value(Score s) {
union { uint16_t u; int16_t s; } eg = { uint16_t(unsigned(s)) };
union { uint16_t u; int16_t s; } eg = { uint16_t(unsigned(s + 0x8000) >> 16) };
return Value(eg.s);
}
inline Value mg_value(Score s) {
union { uint16_t u; int16_t s; } mg = { uint16_t(unsigned(s)) };
return Value(mg.s);
}
#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)); } \
@@ -332,16 +329,18 @@ inline Score operator/(Score s, int i) {
return make_score(mg_value(s) / i, eg_value(s) / i);
}
extern Value PieceValue[PHASE_NB][PIECE_NB];
inline Color operator~(Color c) {
return Color(c ^ BLACK);
return Color(c ^ BLACK); // Toggle color
}
inline Square operator~(Square s) {
return Square(s ^ SQ_A8); // Vertical flip SQ_A1 -> SQ_A8
}
inline Piece operator~(Piece pc) {
return Piece(pc ^ 8); // Swap color of piece B_KNIGHT -> W_KNIGHT
}
inline CastlingRight operator|(Color c, CastlingSide s) {
return CastlingRight(WHITE_OO << ((s == QUEEN_SIDE) + 2 * c));
}
@@ -355,14 +354,14 @@ inline Value mated_in(int ply) {
}
inline Square make_square(File f, Rank r) {
return Square((r << 3) | f);
return Square((r << 3) + f);
}
inline Piece make_piece(Color c, PieceType pt) {
return Piece((c << 3) | pt);
return Piece((c << 3) + pt);
}
inline PieceType type_of(Piece pc) {
inline PieceType type_of(Piece pc) {
return PieceType(pc & 7);
}
@@ -401,7 +400,7 @@ inline bool opposite_colors(Square s1, Square s2) {
}
inline Square pawn_push(Color c) {
return c == WHITE ? DELTA_N : DELTA_S;
return c == WHITE ? NORTH : SOUTH;
}
inline Square from_sq(Move m) {
@@ -417,16 +416,16 @@ inline MoveType type_of(Move m) {
}
inline PieceType promotion_type(Move m) {
return PieceType(((m >> 12) & 3) + 2);
return PieceType(((m >> 12) & 3) + KNIGHT);
}
inline Move make_move(Square from, Square to) {
return Move(to | (from << 6));
return Move((from << 6) + to);
}
template<MoveType T>
inline Move make(Square from, Square to, PieceType pt = KNIGHT) {
return Move(to | (from << 6) | T | ((pt - KNIGHT) << 12));
return Move(T + ((pt - KNIGHT) << 12) + (from << 6) + to);
}
inline bool is_ok(Move m) {
+31 -24
View File
@@ -2,6 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -26,7 +27,7 @@
#include "position.h"
#include "search.h"
#include "thread.h"
#include "tt.h"
#include "timeman.h"
#include "uci.h"
using namespace std;
@@ -38,10 +39,10 @@ namespace {
// FEN string of the initial position, normal chess
const char* StartFEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
// Stack to keep track of the position states along the setup moves (from the
// A list to keep track of the position states along the setup moves (from the
// start position to the position just before the search starts). Needed by
// 'draw by repetition' detection.
Search::StateStackPtr SetupStates;
StateListPtr States(new std::deque<StateInfo>(1));
// position() is called when engine receives the "position" UCI command.
@@ -67,14 +68,14 @@ namespace {
else
return;
pos.set(fen, Options["UCI_Chess960"], Threads.main());
SetupStates = Search::StateStackPtr(new std::stack<StateInfo>());
States = StateListPtr(new std::deque<StateInfo>(1));
pos.set(fen, Options["UCI_Chess960"], &States->back(), Threads.main());
// Parse move list (if any)
while (is >> token && (m = UCI::to_move(pos, token)) != MOVE_NONE)
{
SetupStates->push(StateInfo());
pos.do_move(m, SetupStates->top());
States->push_back(StateInfo());
pos.do_move(m, States->back(), pos.gives_check(m));
}
}
@@ -90,11 +91,11 @@ namespace {
// Read option name (can contain spaces)
while (is >> token && token != "value")
name += string(" ", !name.empty()) + token;
name += string(" ", name.empty() ? 0 : 1) + token;
// Read option value (can contain spaces)
while (is >> token)
value += string(" ", !value.empty()) + token;
value += string(" ", value.empty() ? 0 : 1) + token;
if (Options.count(name))
Options[name] = value;
@@ -107,11 +108,13 @@ namespace {
// the thinking time and other parameters from the input string, then starts
// the search.
void go(const Position& pos, istringstream& is) {
void go(Position& pos, istringstream& is) {
Search::LimitsType limits;
string token;
limits.startTime = now(); // As early as possible!
while (is >> token)
if (token == "searchmoves")
while (is >> token)
@@ -126,10 +129,10 @@ namespace {
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;
else if (token == "infinite") limits.infinite = 1;
else if (token == "ponder") limits.ponder = 1;
Threads.start_thinking(pos, limits, SetupStates);
Threads.start_thinking(pos, States, limits);
}
} // namespace
@@ -143,9 +146,11 @@ namespace {
void UCI::loop(int argc, char* argv[]) {
Position pos(StartFEN, false, Threads.main()); // The root position
Position pos;
string token, cmd;
pos.set(StartFEN, false, &States->back(), Threads.main());
for (int i = 1; i < argc; ++i)
cmd += std::string(argv[i]) + " ";
@@ -168,18 +173,22 @@ void UCI::loop(int argc, char* argv[]) {
|| (token == "ponderhit" && Search::Signals.stopOnPonderhit))
{
Search::Signals.stop = true;
Threads.main()->notify_one(); // Could be sleeping
Threads.main()->start_searching(true); // Could be sleeping
}
else if (token == "ponderhit")
Search::Limits.ponder = false; // Switch to normal search
Search::Limits.ponder = 0; // Switch to normal search
else if (token == "uci")
sync_cout << "id name " << engine_info(true)
<< "\n" << Options
<< "\nuciok" << sync_endl;
else if (token == "ucinewgame")
{
Search::clear();
Time.availableNodes = 0;
}
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);
@@ -205,7 +214,7 @@ void UCI::loop(int argc, char* argv[]) {
} while (token != "quit" && argc == 1); // Passed args have one-shot behaviour
Threads.wait_for_think_finished(); // Cannot quit whilst the search is running
Threads.main()->wait_for_search_finished();
}
@@ -232,9 +241,7 @@ string UCI::value(Value v) {
/// 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;
return std::string{ char('a' + file_of(s)), char('1' + rank_of(s)) };
}
@@ -274,9 +281,9 @@ 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;
for (const auto& m : MoveList<LEGAL>(pos))
if (str == UCI::move(m, pos.is_chess960()))
return m;
return MOVE_NONE;
}
+9 -7
View File
@@ -2,6 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,8 +18,8 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef UCIOPTION_H_INCLUDED
#define UCIOPTION_H_INCLUDED
#ifndef UCI_H_INCLUDED
#define UCI_H_INCLUDED
#include <map>
#include <string>
@@ -45,10 +46,10 @@ class Option {
typedef void (*OnChange)(const Option&);
public:
Option(OnChange = NULL);
Option(bool v, OnChange = NULL);
Option(const char* v, OnChange = NULL);
Option(int v, int min, int max, OnChange = NULL);
Option(OnChange = nullptr);
Option(bool v, OnChange = nullptr);
Option(const char* v, OnChange = nullptr);
Option(int v, int min, int max, OnChange = nullptr);
Option& operator=(const std::string&);
void operator<<(const Option&);
@@ -69,10 +70,11 @@ void loop(int argc, char* argv[]);
std::string value(Value v);
std::string square(Square s);
std::string move(Move m, bool chess960);
std::string pv(const Position& pos, Depth depth, Value alpha, Value beta);
Move to_move(const Position& pos, std::string& str);
} // namespace UCI
extern UCI::OptionsMap Options;
#endif // #ifndef UCIOPTION_H_INCLUDED
#endif // #ifndef UCI_H_INCLUDED
+20 -19
View File
@@ -2,6 +2,7 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,10 +20,10 @@
#include <algorithm>
#include <cassert>
#include <cstdlib>
#include <sstream>
#include <ostream>
#include "misc.h"
#include "search.h"
#include "thread.h"
#include "tt.h"
#include "uci.h"
@@ -35,7 +36,7 @@ UCI::OptionsMap Options; // Global object
namespace UCI {
/// 'On change' actions, triggered by an option's value change
void on_clear_hash(const Option&) { TT.clear(); }
void on_clear_hash(const Option&) { Search::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(); }
@@ -43,10 +44,10 @@ void on_tb_path(const Option& o) { Tablebases::init(o); }
/// Our case insensitive less() function as required by UCI protocol
bool ci_less(char c1, char c2) { return tolower(c1) < tolower(c2); }
bool CaseInsensitiveLess::operator() (const string& s1, const string& s2) const {
return std::lexicographical_compare(s1.begin(), s1.end(), s2.begin(), s2.end(), ci_less);
return std::lexicographical_compare(s1.begin(), s1.end(), s2.begin(), s2.end(),
[](char c1, char c2) { return tolower(c1) < tolower(c2); });
}
@@ -56,18 +57,18 @@ void init(OptionsMap& o) {
const int MaxHashMB = Is64Bit ? 1024 * 1024 : 2048;
o["Write Debug Log"] << Option(false, on_logger);
o["Debug Log File"] << Option("", on_logger);
o["Contempt"] << Option(0, -100, 100);
o["Min Split Depth"] << Option(0, 0, 12, on_threads);
o["Threads"] << Option(1, 1, MAX_THREADS, on_threads);
o["Threads"] << Option(1, 1, 128, on_threads);
o["Hash"] << Option(16, 1, MaxHashMB, on_hash_size);
o["Clear Hash"] << Option(on_clear_hash);
o["Ponder"] << Option(true);
o["Ponder"] << Option(false);
o["MultiPV"] << Option(1, 1, 500);
o["Skill Level"] << Option(20, 0, 20);
o["Move Overhead"] << Option(30, 0, 5000);
o["Minimum Thinking Time"] << Option(20, 0, 5000);
o["Slow Mover"] << Option(80, 10, 1000);
o["Slow Mover"] << Option(89, 10, 1000);
o["nodestime"] << Option(0, 0, 10000);
o["UCI_Chess960"] << Option(false);
o["SyzygyPath"] << Option("<empty>", on_tb_path);
o["SyzygyProbeDepth"] << Option(1, 1, 100);
@@ -82,11 +83,11 @@ void init(OptionsMap& o) {
std::ostream& operator<<(std::ostream& os, const OptionsMap& om) {
for (size_t idx = 0; idx < om.size(); ++idx)
for (OptionsMap::const_iterator it = om.begin(); it != om.end(); ++it)
if (it->second.idx == idx)
for (const auto& it : om)
if (it.second.idx == idx)
{
const Option& o = it->second;
os << "\noption name " << it->first << " type " << o.type;
const Option& o = it.second;
os << "\noption name " << it.first << " type " << o.type;
if (o.type != "button")
os << " default " << o.defaultValue;
@@ -96,6 +97,7 @@ std::ostream& operator<<(std::ostream& os, const OptionsMap& om) {
break;
}
return os;
}
@@ -112,12 +114,11 @@ Option::Option(OnChange f) : type("button"), min(0), max(0), 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(); }
{ defaultValue = currentValue = std::to_string(v); }
Option::operator int() const {
assert(type == "check" || type == "spin");
return (type == "spin" ? atoi(currentValue.c_str()) : currentValue == "true");
return (type == "spin" ? stoi(currentValue) : currentValue == "true");
}
Option::operator std::string() const {
@@ -147,7 +148,7 @@ Option& Option::operator=(const string& v) {
if ( (type != "button" && v.empty())
|| (type == "check" && v != "true" && v != "false")
|| (type == "spin" && (atoi(v.c_str()) < min || atoi(v.c_str()) > max)))
|| (type == "spin" && (stoi(v) < min || stoi(v) > max)))
return *this;
if (type != "button")