Compare commits

..

645 Commits

Author SHA1 Message Date
Marco Costalba
86c2d2fc3b Stockfish 1.7.1
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-04-10 16:48:25 +01:00
Marco Costalba
f9d3b48ad0 Introduce "Zugzwang detection" temporary hack for 1.7.1
Add an UCI option "Zugzwang detection" OFF by default that
enables correct detection of zugzwang.

This is just to let 1.7.1 be 100% compatible with 1.7 and
should be removed after release.

Verified 100% functional equivalent to 1.7

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-04-10 16:41:40 +01:00
Marco Costalba
d720778b2b Revert HT detection
Fall back on 1.6.3 behaviour.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-04-10 11:35:30 +01:00
Marco Costalba
e2880f9b8e Revert last patch
It fails in test position:

8/7P/8/8/K2b4/p7/1k6/1B6 b - -

Not clear why but we revert because it fixes the issue.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-04-10 11:16:55 +01:00
Marco Costalba
909e3adede Relax TT condition for zugzwang verified null values
In this case use a normal VALUE_TYPE_LOWER TT type instead of
VALUE_TYPE_NS_LO. This allow us to TT cut-off in a bit more nodes.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-04-10 10:48:08 +01:00
Marco Costalba
626b1f8c6a Avoid TT cutoffs at root of null zugzwang verification
This patch fixes an issue with zugzwang well explained by Tord:

"Assume that a zugzwang position occurs at iteration N,
at a search depth d, with d < 6*OnePly. The null move search
fails high, and no verification search is done, because the
depth is too small. The position gets stored in the transposition
table with a good score and a depth of d.

Now, consider what happens when the same position occurs at iteration
N+1, this time with a depth of d+OnePly (i.e. one ply deeper than at
the previous iteration). Once again, the null move search fails
high. The point is that the verification search will also fail high,
because of an instant transposition table cutoff caused by the value
stored in the TT during the previous iteration."

With this patch we simply do not allow TT cutoffs at the root node
of a null move verification search if the TT value was found by a
null search.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-04-10 10:35:29 +01:00
Marco Costalba
06a350f1ae Use a flag in TT to track null search values
Add VALUE_TYPE_NS_LO to enum ValueType and use it when
saving in TT a value from a null search.

Currently no action is performed, the next patch will enable
the new type.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-04-10 10:07:53 +01:00
Marco Costalba
a9e9746495 Fix a warning under HP-UX ANSI C++
Reported warning is:

warning #2514-D: pointless comparison of unsigned
                 integer with a negative constant

Spotted by Richard Lloyd.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-04-09 07:54:00 +01:00
Marco Costalba
a7fcdfd6bf Stockfish 1.7
Signatures are:

./stockfish bench 128 1 12 default depth
8299338

./stockfish bench 128 1 13 default depth
15694903

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-04-07 13:08:50 +02:00
Tord Romstad
41816b7ced Fix PowerPC and ARM compatibility. 2010-04-06 10:19:09 +02:00
Tord Romstad
13224e1d9d Add -mdynamic-no-pic to CFLAGS when compiling with GCC under OS X.
Without this flag, the __cpuid() function doesn't compile correctly
in 32-bit mode.
2010-04-05 21:47:28 +02:00
Marco Costalba
10c1ae8da0 Fix one gcc 4.4 warning
Properly fix previous warning. Patch from Joona.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-04-05 20:11:41 +01:00
Marco Costalba
3a62738174 Fix a warning in HT_enabled()
Under gcc we have:

warning: dereferencing type-punned pointer will break
strict-aliasing rules

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-04-05 15:36:06 +01:00
Marco Costalba
84451191f3 Store score in TT when null search fails high
Use full depth, not reduced one. This allows
to avoid to do a null search when in the same
position and at the same or bigger depth the
null search failed high.

A very small increase, if any.

After 963 games at 1+0
Mod vs Orig: +158 =657 -147  +4 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-04-04 11:23:18 +01:00
Marco Costalba
2ed3358faf Cleanup pawn storm code
In this form it is even more evident we have some
issue there to be fixed sooner then later....

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-04-02 11:51:39 +01:00
Marco Costalba
08634b06a3 Fix a comment in evaluate.cpp
Function name is wrong.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-04-02 11:45:12 +01:00
Marco Costalba
0e33fc6fd4 Change poll() signature
After previous patch we don't need any more the call parameters.

This fixes a couple of warnings under MSVC.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-03-31 06:43:12 +01:00
Tord Romstad
a5a8830e97 Remove several unnecessary UCI options: All king safety options
except "Aggressiveness" and "Cowardice", and "UCI_ShowCurrLine".
No functional change compared to the previous version with the
default settings.
2010-03-30 15:15:01 +02:00
Marco Costalba
2a14123550 Revert LMR reduction based on thinking time
After 500 games at 5+0 on my QUAD (3 days) there
is no difference with old version, so probably it
is a feature that doesn't scale with search depth.

So revert for now, perhaps we should readd under a
different form.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-03-28 12:04:41 +01:00
Marco Costalba
8fabd69d4a Small comments tweaks in search.cpp
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-03-28 11:53:30 +01:00
Marco Costalba
1fc88071d1 Sync static null conditions with real one
Almost no functional change, but it seems more
in line with the meaning of static null pruning.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-03-28 11:53:16 +01:00
Marco Costalba
7dca461927 Silence a couple of warnings
MSVC complains about an implicit conversion from double to int.

Also small comments tweaks.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-03-23 23:34:31 +01:00
Joona Kiiski
7618ee2df1 Vary reduction aggressiveness as a function of thinking time
In the beginning use milder reduction and at the end be
more aggressive.

After 1500 games on Joona's QUAD
Mod - Orig: 791 - 720 +16 elo

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-03-23 23:29:23 +01:00
Joona Kiiski
661d48c27b Base work for different reduction schemes
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-03-23 23:25:58 +01:00
Joona Kiiski
42de93ac15 Do not return unproven mate scores from null move search
Causes very small functional change which is not observable with
our usual set of test positions.

However change is observable fx. with following position:
4k3/3r4/5Q2/6K1/8/8/8/8 w - - 0 1
go depth 24

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-03-22 07:27:05 +01:00
Marco Costalba
426f55b78d Use fail soft in null search
If null search fails high return null value instead of beta.

With TT hash there may be a small advantage for fail-soft since
storing slightly better bounds may cause slightly more hash hits.

After 990 games at 1+0
Mod vs Orig +171 =665 -154  +6 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-03-21 15:12:44 +01:00
Marco Costalba
b638f6b035 Remove castleRightsMask[] hack
Array castleRightsMask[] is not static because it can
be different for different positions, so let it be
a Position member data. This allows to remove tricky
hacks to take in account that although it was defined
static it could change.

Theoretically now copying a position is a bit slower because
we need to copy also an array of 64 integers, but because in
split() we don't copy the position anymore, but just keep the
pointer, the added burden is not mesurable even in MP case.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-03-20 11:59:22 +01:00
Marco Costalba
3de0bc43a2 Retire Position::fast_copy()
It is never used and could be tricky, so remove it.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-03-20 11:45:04 +01:00
Marco Costalba
9fc602bae7 Updated copyright year to 2010
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-03-20 11:27:07 +01:00
Marco Costalba
49c50399fe Fix POPCNT detection gcc compile error
Also don't use __cpuid() intrinsic for Intel under
Linux because gives wrong results when detecting HT,
use the gcc version instead. Finally clean up the code.

Error was due to changed __cpuid() signature for
gcc compiler.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-03-17 21:04:56 +01:00
Marco Costalba
a4551c59e0 Fix __cpuid() compile error with gcc
Use same __cpuid() signature used under Windows.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-03-17 13:22:28 +01:00
Marco Costalba
c853b87c08 Add hyper-threading detection
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-03-14 12:52:58 +01:00
Marco Costalba
92bada1a32 Move __cpuid() definition for gcc in types.h
This will allow to use the function also for other
purposes then detecting POPCNT.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-03-14 12:52:56 +01:00
Marco Costalba
eaed535c5f Introduce captured_piece()
It will be used by future patches and also rearranges some
half cooked code that mistakenly ended up in master in the
past.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-03-13 11:07:10 +01:00
Marco Costalba
49dfc50b12 Reduce increase progression of aspiration window
Currently, in case of fail high/low we research with
a window increased by 2*AspirationDelta at first
attempt, this patch instead makes the research be
done with an increase of just AspirationDelta size,
in case of a consecutive fail we will widen to
2*AspirationDelta and so on.

After Joona's test:
Orig - Mod: 850 - 890

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-03-13 11:05:27 +01:00
Marco Costalba
c835ee8853 Use separated research counters in root_search()
One for failing highs and one for failing lows, this
should reduce average window size in case of positions
that fail first high and then low (or the contrary).

After ~2000 games on Joona's quad we have:

Mod - Orig: 1012- 975 (+6 elo)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-03-13 11:00:12 +01:00
Marco Costalba
7ff9678651 Group time management globals initialization
Instead to leave uninitialized or scattered in the code
as is the case for ExtraSearchTime.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-03-13 10:59:03 +01:00
Marco Costalba
4ef068a506 Highlight that alpha and beta could change in root_search()
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-03-06 18:17:04 +01:00
Marco Costalba
f23a9e8f88 Fix a comment and add an assert in root_search()
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-03-06 17:51:56 +01:00
Marco Costalba
cc2a249952 Retire RootMoveNumber and use FirstRootMove instead
It is more clear why we use that global flag.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-03-06 17:34:36 +01:00
Joona Kiiski
55f0d6377f Save mateThreat flag in splitPoint and make use of it
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-03-06 12:18:03 +01:00
Joona Kiiski
aeb664e0ea Document one test result
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-03-06 12:17:41 +01:00
Joona Kiiski
8abdb131c8 Synchronize root_search() with other search routines
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-03-06 12:14:46 +01:00
Joona Kiiski
43c93cb151 Remove obsolete code snippet from root_search
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-03-06 12:07:37 +01:00
Marco Costalba
8d1d9f7181 Sort again root moves after a fail low
Currently we use original sorting after a fail low to
research at wider window. This patch instead sorts the
moves according to the last available move's scores.

Strangely no functional change, but should be.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-03-06 11:43:31 +01:00
Marco Costalba
a303bde26c Additional search.cpp cleanup
Changed FutilityMarginsMatrix dimensions to be a power of two
so that compiler can produce a faster accessing code.

Introduced print_pv_info() to remove some redundant code in
root_search()

Remaining stuff is triviality and documentation tweaks.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-03-06 11:14:38 +01:00
Marco Costalba
0f50f10327 Destroy all locks before to exit
And use platform-independent functions
where possible.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-28 23:36:02 +01:00
Marco Costalba
8286e6ded2 We don't need lpThreadId parameter in CreateThread()
Under Windows we use CreateThread() to setup threads and
we pass a pointer to a variable that receives the thread
identifier, but this parameter is optional and we don't
use it, so remove it.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-28 23:36:01 +01:00
Marco Costalba
3a558a3d8b Function init_thread() should return an integer under Windows
It happens that NULL is 0, but the conventional meaning is of
a zero pointer, so repleace with an explicit 0 integer value.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-28 23:36:01 +01:00
Marco Costalba
14dbeb22dd Try bad captures before non-captures
Consider sligtly negative captures as good if at low
depth and far from beta.

After 999 games at 1+0
Mod vs Orig +169 =694 -136  +11 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-28 23:35:51 +01:00
Marco Costalba
68eb7e77f1 Revert previous patch
It raises an assert under Windows, it is not clear why but it
happens that idle_loop() is called with incorrect threadID and
the assert triggered is:

assert(threadID >= 0 && threadID < MAX_THREADS);

So revert the patch for now, but we should understand why it
fails.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-27 17:24:58 +01:00
Marco Costalba
57340c109b Do not wait for sleeping in init_threads()
We can't do it with full guarantee anyway because
there is always a possible race between the setting of
state to THREAD_SLEEPING and actual sleeping.

So just remove the not perfect code to avoid misunderstandings.
This reflects what we have done in wake_sleeping_threads() in
the previous patch.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-27 13:26:04 +01:00
Marco Costalba
111aa44662 Remove an incorrect assert in wake_sleeping_threads()
Currently there is no guarantee that threads are sleeping
when calling wake_sleeping_threads() because put_threads_to_sleep()
returns without waiting for threads to actually sleep.

Assert can be easily triggered calling put_threads_to_sleep() and
wake_sleeping_threads() in a tight loop.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-27 12:01:07 +01:00
Joona Kiiski
29fb389760 Add some commentary
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-26 00:43:19 +01:00
Joona Kiiski
0d292d1a2d Clean up common adjustments
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-26 00:41:40 +01:00
Joona Kiiski
5bb9da9287 Remove "Threat Depth" ucioption
This option likely has very low meaning for playing strength and style,
so I see no need to keep this configurable

No functional change

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-26 00:41:31 +01:00
Joona Kiiski
34c7f1387d Cleanup steps 12, 14
No functional change

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-26 00:39:08 +01:00
Joona Kiiski
fc23466236 Clean up step 11
No functional change

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-26 00:38:34 +01:00
Joona Kiiski
01b228b5e1 Clean steps 8 and 9.
No functional change

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-26 00:37:56 +01:00
Joona Kiiski
2142be7d7f Clean razoring code (step 6)
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-26 00:37:09 +01:00
Joona Kiiski
3888d14bd4 Synchronize variable listing of 4 different search routines
search() is used as a "leading star" and other routines
are modified according to it.

No functional change

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-26 00:36:29 +01:00
Joona Kiiski
7bcd97933a Remove current line printing in SMP mode
Was broken and fixing would be too messy.
Now this option is only activated in single thread mode

No functional change

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-26 00:35:35 +01:00
Joona Kiiski
9d4abbc6eb Synchronize sp_search() with search() part I
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-25 07:30:19 +01:00
Joona Kiiski
c3b3dcc31a Rename staticValue to refinedValue
Just to avoid misunderstandings.
True staticValue is available through search stack

No functional change

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-25 07:30:09 +01:00
Joona Kiiski
e6f2d43b8a Fix repetition detection bug
Bug spotted by Jouni Uski and fix suggested by Pablo Vazquez

Also add note that we are not always handling fifty move rule correctly

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-24 19:56:48 +01:00
Joona Kiiski
1a03f0b0d3 Synchronize sp_search_pv() with search_pv()
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-24 19:42:24 +01:00
Joona Kiiski
62f6d39204 Synchronize sp_search() with search() part II
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-24 19:41:51 +01:00
Joona Kiiski
936cd5b83d Simplify locking in splitpoint search
One rule: Always lock before picking up a move.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-24 19:37:05 +01:00
Joona Kiiski
3c31776a20 Synchronize search_pv() with search take II
No functional change

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-24 19:36:21 +01:00
Joona Kiiski
0980f43ab0 Synchronize search_pv() with search take I
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-24 19:34:55 +01:00
Joona Kiiski
9eedc0a463 Search code documentation, take III
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-24 19:30:02 +01:00
Joona Kiiski
195b54c312 Search code documentation take II
No functional change

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-24 19:26:05 +01:00
Joona Kiiski
89b4ad6433 Separate razoring from null move
I cannot see connection between the two.

Also add one FIXME for illogical behaviour

No functional change

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-24 19:24:10 +01:00
Joona Kiiski
77bb9a94ae Split search() in independent sections
I don't know if enumerating sections is a good idea,
but for me code is more readable this way

No functional change

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-24 19:20:26 +01:00
Joona Kiiski
8a78ac84f3 Avoid research in case thread has already been asked to stop
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-24 19:19:52 +01:00
Joona Kiiski
5c944fb3b4 Add one assert
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-24 07:28:50 +01:00
Joona Kiiski
c974d9ef33 Do not wait for threads falling asleep
I cannot see any reason to do this. Even this is not enough to fix
theoretical race case on Windows which doesn't seem to cause any
problems in practice anyhow

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-24 07:27:45 +01:00
Joona Kiiski
12feb5866f Remove unnecessary conditions from if-clauses and replace them with asserts
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-24 07:26:28 +01:00
Joona Kiiski
80810e4951 Fix crash in debug mode
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-23 07:23:03 +01:00
Joona Kiiski
c67b9916f1 Fix some races
Resurrect extra check for sleeping in POSIX code.
This necessary to prevent ugly races between
thread_broadcast and thread_cond_wait.

After thread has woken up, it marks itself as available.
Another thread must not do this, because of possible race.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-23 07:22:56 +01:00
Joona Kiiski
78c6bb1079 Fix one assert
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-23 07:22:49 +01:00
Joona Kiiski
85e60bfc8e Fix compile errors in debug mode
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-23 07:22:42 +01:00
Marco Costalba
79b57dd4ca Document struct SplitPoint fields constness
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-21 16:10:19 +01:00
Marco Costalba
b9537edbb0 Beta is never changed after an sp_search()
So we can use a const value instead of a pointer in
split().

Also pass NULL instead of a faked address of alpha in
case split is called from a non-PV node.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-21 15:32:39 +01:00
Marco Costalba
d38f4f61e7 Supress make warning on missing .depend file
This is generated by make itself, so the warning
is useless.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-21 15:18:35 +01:00
Marco Costalba
27c74c5245 Fix an icc warning
remark #1599: declaration hides variable "i" (declared at line 2651)

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-21 15:07:53 +01:00
Marco Costalba
2f2e8a68d8 Code style triviality in split()
No functional change

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-21 14:05:38 +01:00
Marco Costalba
1ea70dd9dd Fix a warning with POPCNT and MSVC
Intrinsic __popcnt64() returns an unsigned __int64, cast
to an integer and silence the warning.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-21 13:44:36 +01:00
Marco Costalba
13c096f839 Revert "Recursive lock"
Joona says that sp_update_pv() does not pass the split point
boundaries, so there is no risk to corrupt data from another
split point. Also the race on thread_should_stop() is harmless
because of this.

So revert the patch and come back to single lock.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-20 23:59:47 +01:00
Marco Costalba
2de2b76896 Remove a couple of useless thread_should_stop() calls
We test for it anyway few lines below and even under lock
protection.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-20 23:48:54 +01:00
Marco Costalba
8b99e94562 Revert small state change optimization in idle_loop()
Joona says:

1. We should not be afraid of "AllThreadsShouldExit" flag.
Because when this is set to true we _must_not_ be searching (= All
splits must have been undone).
And if we are not searching it's impossible that some other thread
could give us work to do. So setting state to THREAD_AVAILABLE
doesn't do any harm. If you want to add check for this, you could do
it like this:

 if (threads[threadID].state == THREAD_WORKISWAITING)
 {
+    assert(!AllThreadsShouldExit)
     threads[threadID].state = THREAD_SEARCHING;

2a. If waitSp->cpus == 0, setting state to THREAD_AVAILABLE makes
no harm either, because helpful master concept dictates that _only_
our own slave can book us. If we don't have any slaves, noone has the
right to book us.

2b. If point (2a) is not correct then your extra check only adds extra race:
In smp code checking for waitSp->cpus > 0 is not enough. It's possible that
our slave immediately exits and another thread
books us as a slave when our state is still
THREAD_AVAILABLE. So instead of adding extra level of security we have
just introduced extra race.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-20 18:36:07 +01:00
Marco Costalba
512a4e4ff0 Recursive lock all split point's chain
When we found a cut-off then lock all the split point chain,
not only current one to avoid races in case two threads running
on different split points where one is ancestor then the other,
find a beta cut-off at the same time, in this case we want only
one to call sp_update_pv().

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-20 18:29:53 +01:00
Marco Costalba
2da290d72b Retire per-thread stopRequest flag
This is a per split-point request, not per-thread. When we find
a beta cut-off in current thread's split point or in or in some
ancestor of the current split point then threads should stop
immediately the search and return to idle_loop().

The check is done by thread_should_stop() that now looks only
at split point's chain.

No functional change and a good semplification.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-20 17:52:09 +01:00
Marco Costalba
b39a24ecca Use state instead of flags to track threads
This is easier to follow and also reduces the points
where state changes to mainly idle_loop() and split().

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-20 16:57:24 +01:00
Marco Costalba
189a005a0b Rename THREAD_MAX in MAX_THREADS
Also rename idle_thread_exists() in available_thread_exists()

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-20 13:38:04 +01:00
Joona Kiiski
7c61b8ad2a Search negative SEE moves in qsearch in PV
After 2704 games on slow single core
mod - orig: 1381 - 1323

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-15 19:15:44 +01:00
Joona Kiiski
a093f33154 Use zero null move margin when depth < 4 * OnePly
This is because when we are below 4 * OnePly, the null move
will directly jump to qsearch and if we are below beta,
our opponent is above beta and will get immediate
stand pat cut off.

So basically this patch is just optimizing away useless
evaluation calls. dbg_hit_on() runs show that this heuristic
is correct >99% of cases. Transposition table probably causes
some inaccurary?

After 1148 games on QUAD
mod-orig: 583 - 565 +5 elo

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-15 19:14:41 +01:00
Marco Costalba
0895f1ac71 Fix another setting of a flag out of lock protection
In this case is dangerous because in split() we reset the flag to
false, but if it was set due to a cut-off higher in the tree we
completely miss that and go on with the full search.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-14 16:31:30 +01:00
Marco Costalba
b29198354c Rename flag 'stop' in 'stopRequest'
Instead of other flags this is not a state flag, i.e. does
not defines a state for the thread, but a request because
after we raise 'stopRequest' flag the corresponding thread is
not stopped, but continues to run for a while until it returns
from sp_search() in idle_loop.

It is important the name reflects this.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-14 16:04:53 +01:00
Marco Costalba
40a7ffd53f Reset thread flags to a known state before to exit think()
Among them 'stop' and 'printCurrentLineRequest' could have
random value, so reset to a known state before to leave the
search.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-14 15:59:12 +01:00
Marco Costalba
8eae6a95fb Fix 'stop' flag changed out of lock protection
This is the first nice effect of previous patch !

Because thread_should_stop() should be declared 'const' we
need to remove the setting of 'stop' flag to true that
turns out to be a bug because thread_should_stop() is called
outside from lock protection while 'stop' flag is a volatile
shared variable so cannot be changed when not in lock.

Note that this bugs fires ONLY when we use more then 2 threads,
so commonly only in a QUAD or OCTAL machine.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-14 13:43:26 +01:00
Marco Costalba
2b740f5495 Introduce ThreadsManager class
Main aim of this patch is to consolidate all the thread related stuff
behind a single class interface so to avoid messing with global flags
and having thread code scattered among non-thread related stuff.

Another advantage is that now access to thread's variables is
more controlled, in particular we can differentiate between
read and write accesses by the mean of different interfaces, it
is so simpler to understand how a function is related to threads.

Lastly this rewrite is the base for future code consolidations and
semplifications that are easier now that we have only one thread's
access point.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-14 12:53:27 +01:00
Marco Costalba
fb5ba1d329 Fix compile error under gcc
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-13 13:40:23 +01:00
Marco Costalba
78e494fcbc Ensure function boundaries for threads state changes
Ensure threads are sleeping when leaving init_threads() and
the newly introduced put_threads_to_sleep().

Also ensure threads are not sleeping when leaving
wake_sleeping_threads().

As a side effect we now leave think() with all the threads
(but the main one) guaranteed to sleep. So when we enter
again in think(), after the opponent next move, we know
threads must be sleeping.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-13 12:40:29 +01:00
Marco Costalba
a16415f44d Rename stop_threads() to exit_threads()
More stick to what actually happens.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-13 12:07:13 +01:00
Marco Costalba
8a504d36f9 Be sure threads are woken in wake_sleeping_threads()
Wait inside wake_sleeping_threads() for the threads to be
effectively and reliably woken up.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-13 12:02:34 +01:00
Marco Costalba
093dd8fe88 Use Thread c'tor to properly init the struct
This is what c'tors are for.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-13 11:41:34 +01:00
Marco Costalba
6382324afd Add 'sleeping' flag to struct Thread
Will be used by future patches. Also:

- Renamed Idle in AllThreadsShouldSleep

- Explicitly inited AllThreadsShouldExit and AllThreadsShouldSleep
  in init_thread() instead of use an anonymous global initialization.

- Rewritten idle_loop() while condition to avoid a 'break' statement

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-13 11:28:33 +01:00
Marco Costalba
cb08413dc4 Allow build on HP-UX 11.X
Patch from Richard Lloyd (slightly edited from me), following the list
of changes as described by the author:

src/Makefile:
- Added PREFIX and BINDIR for the install: rule.
- Added a "make hpux" line to the help: rule.
- Added "make test"/"make check" rule that runs the $(PGOBENCH) command.
- "make clean" now additionally removes core and bench.txt.
- Added an hpux: rule.
- Added an install: rule to mkdir $(BINDIR), copy $(EXE) to $(BINDIR) and
 then strip it.
- "make strip" now ensures that $(EXE) is built first before trying to
 strip it.
- Hide errors and output from the g++ command used by the .depend: rule and
 then touch .depend in case g++ isn't available.
- Hide errors from the "include .depend" in case .depend doesn't exist
 (e.g. directly after a "make clean").

src/book.cpp and src/book.h:
- HP-UX's aCC really didn't like the const keywords used for the
 Book::file_name() definitions, so they were removed. I checked that this
 didn't affect a Linux build and it was still fine.

src/misc.cpp:
- HP-UX uses <sys/pstat.h> and pstat_getdynamic() to determine the number of
 CPU cores, so added conditional code for that (if pstat_getdynamic() fails,
 set the number of cores to 1).

src/tt.cpp:
- <xmmintrin.h> and _mm_prefetch() seem highly specific to the Intel x86(_64)
 and gcc platforms - neither exist in HP-UX, so conditionally avoid that
 code in HP-UX's case. Perhaps some sort of define is needed here
 such as -DHAS_MM_PREFETCH that could be #ifdef'ed for instead?

Even after these changes, it's more convenient for HP-UX users to edit the
default: rule in the Makefile to run "$(MAKE) hpux" before they build
stockfish, but that's not a big deal if they're warned about that first (the
same applies to all other builds other than the standard "$(MAKE) gcc" one).

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-12 06:49:16 +01:00
Marco Costalba
711ef615c7 Fix a couple of new MSVC 2010 warnings
Compiler complains because in Book we have a d'tor but not
copy c'tor and assignement operator (warning C4511 and C4512),
note that after adding them (just declared) you now need also
default c'tor !

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-10 21:27:44 +01:00
Marco Costalba
74203e181d Retire EvalInfo* in SearchStack
It is an hidden bug waiting to fire. The main problem is
that ss[ply] is overwritten by search() and qsearch() called
from IID and razoring, so that we cannot hold a pointer to a
local EvalInfo variable.

For instance if we go razoring then we overwrite the pointer
with the address of a variable local to qsearch(), when we return
from qsearch() variable goes out of scope and now ss[ply].evalInfo
holds a stale pointer !

Because we are not looking for troubles we go through the
safe route and we remove it entirely.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-08 10:50:17 +01:00
Marco Costalba
97fe0ac777 Small code style triviality
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-07 13:23:00 +01:00
Joona Kiiski
7ae16a193b Implement init_search()
No functional change

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-07 13:09:03 +01:00
Joona Kiiski
8261f61964 Document lookup tables
No functional change

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-07 13:08:56 +01:00
Joona Kiiski
6e1cb6e45b Implement futility move count array
No functional change

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-07 13:08:48 +01:00
Joona Kiiski
4bfa0c429e Implement futility margins matrix
No functinal change

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-07 13:08:40 +01:00
Marco Costalba
2e70a2873f Use gain table to order non-captures
Gain value is multiplied by 16 to be of comparable magnitudo
of negative history, on average.

This patch shows very good results in tactical tests, but
started very bad in real games, so I have run two test matches.

After 896 games at 1+0
Mod vs Orig +187 =525 -184 +1 ELO

After 999 games at 1+0
Mod vs Orig +223 =590 -186 +13 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-07 08:55:51 +01:00
Joona Kiiski
9429d2d028 Use posKey instead of pos.get_key() after NonPVIID
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-06 17:40:01 +01:00
Joona Kiiski
d44fa46082 Use opening book when pondering
Otherwise we will not use move given by opening book
when we receive 'ponderhit'-command.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-06 17:39:53 +01:00
Marco Costalba
c7866a4215 Delay sorting of negative scored non-captures
We can do this only when needed, if we get a cut-off
before we skip sorting entirely. This reduces sorting
time of about 20%.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-05 18:31:09 +01:00
Joona Kiiski
69644d3f73 Copy 4 SearchStack items in split()
In search routines we use information from previous ply
and init killers two plies ahead.

So for me it seems correct to copy 4 searchstack items
in split:

ply - 1, ply, ply + 1, ply + 2

Because
a) we do not split at root (ply == 0)
b) ply < PLY_MAX and SearchStack size is PLY_MAX_PLUS_2
there should be no risk of underflows or overflows

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-05 18:06:41 +01:00
Marco Costalba
b0858877ae Remove sorting optimization for many zeroes
With negative history we don't have anymore a
lot of zeroes to score, so just split moves in
positives and non-positives sets.

Speed up is almost zero, we cannot test speed directly
because node count changed due to reorder, but I have
verified sorting is correct. With a profiler I have
seen we gain a little in sort_moves() and lose a little
in insertion_sort(), so the net effect is almost zero,
but code is simpler.

No real change, just move reordering.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-05 18:04:08 +01:00
Joona Kiiski
321f6d1d19 Give FailLow flag more descriptive name
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-05 15:21:21 +01:00
Joona Kiiski
e738fa7d10 Remove Problem variable
It was only used to control StopOnPonderHit variable.
Now use FailLow variable instead.

Patch has a minor effect on time management when ponder is on.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-05 15:21:12 +01:00
Joona Kiiski
c5d546e18e Remove unused failHighPly1 flag
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-05 15:21:05 +01:00
Joona Kiiski
8d65fcc0f3 Remove unused FailHigh flag
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-05 15:20:57 +01:00
Joona Kiiski
d8e5b8c133 Simplify time management
noProblemFound condition is never true.
This was verified by running 800 games 1+0 match in 1 CPU computer.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-05 15:20:47 +01:00
Marco Costalba
6fe36d13de Be sure negative see evasions are at the bottom
Because H.move_ordering_score() can return negative values
some negative see moves could be searched before non-negative
see moves with negative history.

This patch restores proper ordering.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-05 08:19:39 +01:00
Marco Costalba
337ec0f3d0 Score non-captures only by history
Now that history can go negative and is almost alwyas
non zero we have no more reasons to use also psqt term.

After 994 games at 1+0
Mod vs Orig +204 =597 -193 +4 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-05 00:34:17 +01:00
Joona Kiiski
5b1043ee11 Reduction lookup table
No functional change

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-04 19:09:51 +01:00
Marco Costalba
439aea9ab7 Convert gains to use a piece-to mapping
Instead of piece-from-to, in this way it is similar
to what we already do for history.

Almost no change, but seems a bit simpler in this way.

After 995 games at 1+0
Mod vs Orig +207 =596 -192 +5 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-03 19:33:59 +01:00
Marco Costalba
770db27164 Fix a compile error from previous patch
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-02 19:01:24 +01:00
Joona Kiiski
21d32aa7fe Fix indentations
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-02 18:58:00 +01:00
Joona Kiiski
95d33aef9f Retire outdated aspiration search code
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-02 18:57:50 +01:00
Marco Costalba
b5a4edd86f Renamed stand pat as 'static null move pruning'
It seems more standard conformant. Also added a bit of
description directly from Tord.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-02 08:51:54 +01:00
Marco Costalba
35ada63174 Save futilityMargin for both colors
It will be needed by future patches.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-01 20:06:56 +01:00
Marco Costalba
06a695d5b8 Fix duplicated scaling function
We erroneusly added two times the same scaling function
to endgame's map.

Fix detected by valgrind becasue resulted in a memleak
of the first added scaling function.

Bug introduced by 30e8f0c9ad6a473 of 13/02/2009

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-01 19:33:02 +01:00
Marco Costalba
4b55d3d883 Increase TT size limit to 8 GB
We had an overflow due to use an integer for hash size,
now we use a size_t as we should, so we can increase to
an higher limit.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-01 16:53:10 +01:00
Marco Costalba
8008f78415 Check bounds in set_option_value()
Normally it's up to the GUI to check for option's limits,
but we could receive the new value directly from the user
by teminal window. So let's check the bounds anyway.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-01 14:17:37 +01:00
Marco Costalba
3941e4bdb3 Some code style triviality in root search
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-31 11:14:42 +01:00
Marco Costalba
d7d2c1b7e3 Add hardware POPCNT support for gcc
With new target 'make gcc-popcnt' it is now
possible to compile with enabled hardware POPCNT
support also with gcc. Until now was possible only
for Intel and MSVC compilers.

When this instruction is supported by CPU, for instance
on Intel i7 or i5 family, produced binary is a bit faster.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-31 09:39:32 +01:00
Marco Costalba
17502a5659 Revert "Remove pointless gcc flag when generating dependencies"
This reverts commit c43c5fe9e0.

Produces following build error after 'make clean', 'make icc' under Mandriva
with icc version 11.0

Makefile:306: .depend: No such file or directory
In file included from tt.cpp:28:
/usr/lib/gcc/i586-manbo-linux-gnu/4.3.2/include/xmmintrin.h:35:3: error: #error "SSE instruction set not enabled"

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-30 10:37:03 +01:00
Marco Costalba
e84488ed6b Retire captures pruning
Futility captures alone does not seem an improvment.

Perhaps is a combination of stand pat + futility that is winning,
so revert for now and continue testing starting from a standard
base until we find the correct receipe.

After 999 games at 1+0
Mod vs Orig +231 0506 -201  +10 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-30 09:59:28 +01:00
Marco Costalba
252844e899 Avoid search tree explosion in qsearch
Under some rare cases we can have a search tree explosion
due to a perpetual check or to a very long non-capture TT
sequence.

This avoids the tree explosion not following TT moves that
are not captures or promotions when we are below the
'generate checks' depth.

Idea suggested by Richard Vida.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-29 16:47:04 +01:00
Joona Kiiski
b651e5334b Correct qsearch() TT save
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-29 11:03:06 +01:00
Marco Costalba
bd358533a4 Stricter conditions in main search stand pat
Not a biggie but is a reduced pruned patch that doesn't
seems to hurt, so it is welcomed ;-)

After 999 games at 1+0
Mod vs Orig +207 =601 -191  +6 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-29 00:12:03 +01:00
Marco Costalba
e4d3a15656 Use float instead of double in reduction parameters
This is faster on 32 bit CPU and precision is enough.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-28 12:47:48 +01:00
Marco Costalba
1d7a3f26e0 Micro optimize reduction_parameters()
At ply == OnePly (common case) we avoid some useless
floating point computation.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-28 12:39:15 +01:00
Marco Costalba
a0005ba45f Avoid to calculate reduction for each move
This is slow because some floating point operation is
involved.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-28 12:34:28 +01:00
Joona Kiiski
bdd61b1744 Remove useless variable 'PostFutilityValueMargin'
No functional change

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-28 11:17:59 +01:00
Joona Kiiski
973e574e1f Precalculate FutilityMargins
This way we don't need to copy+paste formula everywhere

No functional change

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-28 11:16:56 +01:00
Joona Kiiski
27393ebae2 Use calculate_reduction() function to simplify code
No functional change

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-28 11:15:41 +01:00
Joona Kiiski
3c7eebb48d Bugfix: reduction was not set to zero in full depth search
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-28 11:15:18 +01:00
Joona Kiiski
548bae80bd Implement calculate_reduction function
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-28 11:14:43 +01:00
Joona Kiiski
2360c8aa2f Standardize set_option function
Previously input like "setoption name Use Search Log value true "
(note space at the end of the line) didn't work.

Now parse value same way as option name. This way we implicitly
left- and right-trim value.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-27 20:03:44 +01:00
Joona Kiiski
32bd6e44f0 Do not initialize RootPosition at startup
Initializing high-level object at startup is very dangerous,
because low-level snippets are not yet initialized.

For example Position's constructor calls find_checkers() which
calls attackers_to() which depends on various global bitboard arrays
which are not yet initialized. I think we are lucky not to crash.

RootPosition.from_fen(StartPosition); is called immediately after
all initializations are made at uci_main_loop() which is the
correct behaviour

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-27 20:00:28 +01:00
Marco Costalba
c83fd08fd4 Aspiration window rewrite
Joona new aspiration window. Main idea is to always
research aspiration fail highs/low at the same
ply and use much smaller aspiration window than previously.

Testing result is very positive.

1CPU:
953-1149

4CPU:
545 - 656

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-27 19:59:34 +01:00
Marco Costalba
62b43130e2 Be sure we exit while loop with lock held
This fixes an hang introduced by recent locking
rewrite patch.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-27 19:23:16 +01:00
Joona Kiiski
cd112ee8eb Fix capture pruning
We forgot to update bestValue previously

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-27 18:58:42 +01:00
Marco Costalba
bb968fd42a Simplify locking in sp_search and sp_search_pv
Avoid to take the lock two times in a tight sequence, the first
in get_next_move() and the second to update sp->moves.

Do all with one lock and so retire the now useless locked version
of get_next_move().

Also fix some theorical race due to comparison sp->bestValue < sp->beta
is done out of lock protection. Finally fix another (harmless but time
waster) race that coudl occur because thread_should_stop() is also
called outside of lock protection.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-27 17:58:04 +01:00
Marco Costalba
307909bed8 Temporary revert "captures pruning" due to an assert
In debug run with 2 threads it happens to be following
assert after some minutes:

assert(value > -VALUE_INFINITE && value < VALUE_INFINITE);

in search(), line 1615.

I am not able to understand why, anyhow reverted for the moment.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-27 17:57:04 +01:00
Marco Costalba
b95ba7b37e Added some FIXME to track needed tests
This avoid us to forget some very needed tests now that
futility has changed in a whole big chunk we need to fine
tuning every splitted change.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-27 11:49:03 +01:00
Marco Costalba
f37741cc83 Integrate gains table in History
This will be useful to use gains table in move
ordering along with history table.

No functional change and big code remove.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-27 11:22:38 +01:00
Marco Costalba
54b3d44194 Introduce update_gains() and refactor some code
No functional change

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-27 11:09:07 +01:00
Joona Kiiski
ea53006a9d Fix some silly bugs
SelectiveDepth was ignored

Test results for the whole futility pruning series:

4CPU:
Orig - Mod: 959 - 1027 (+12 elo)

1CPU:
Orig - Mod: 763 - 830 (+15 elo)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-27 10:14:20 +01:00
Joona Kiiski
6247f27a05 MaxGain based futility pruning for captures
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-27 09:57:51 +01:00
Joona Kiiski
5b2fc1e1c0 MaxGain based pruning
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-27 09:57:41 +01:00
Joona Kiiski
05a8c318b8 Implement post futility pruning
and prevent futility pruning from pruning
castling moves

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-27 09:57:31 +01:00
Joona Kiiski
22b8dc8c98 Collect MaxGain statistics
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-27 09:57:24 +01:00
Joona Kiiski
cfe59de27d Implement MaxGain table
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-27 09:57:14 +01:00
Joona Kiiski
c43c5fe9e0 Remove pointless gcc flag when generating dependencies
When generating dependencies there is absolutely no point
to pass -msse flag to gcc, so remove it.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-27 09:53:30 +01:00
Joona Kiiski
d0daa16769 Remove InfiniteSearch hack
With current search control system, I can see absolutely no
reason to classify fixed time search as infinite search.

So remove old dated hack

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-27 09:52:47 +01:00
Joona Kiiski
87303d7ed3 Remove last use of uip.eof()
Value of uip.eof() should not be trusted.
input like "go infinite searchmoves " (note space in the end of line)
causes problems.

Check the return value of (uip >> token) instead

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-27 09:52:15 +01:00
Marco Costalba
cf9bf4e58f Reduce lock contention in sp_search_pv()
In less then 1% of cases value > sp->bestValue, so avoid
an useless lock in the common case. This is the same change
already applied to sp_search().

Also SplitPoint futilityValue is not volatile because
never changes after has been assigned in split()

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-26 12:12:11 +01:00
Marco Costalba
5ca4284027 Fix a possible crash in thread_is_available()
When we have more then 2 threads then we do an array
access with index 'Threads[slave].activeSplitPoints - 1'
This should be >= 0 because we tested the variable just
few statements before, but because is a shared variable
it could be that the 'slave' thread set the value to zero
just after we test it, so that when we use the decremented
variable for array access we crash.

Bug spotted by Bruno Causse.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-25 23:34:21 +01:00
Marco Costalba
dac1bcab90 Small split() cleanup
Unify start loop for master and slave threads. Also guarantee
that all the 'stop' flags are set to false before first slave
is started, should be no harm because only master thread can
reset 'stop' flag of slaves to true, so should be no race but
better safe then sorry.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-25 19:59:33 +01:00
Marco Costalba
81cfd81366 Prune evasions with negative SEE in qsearch
Only pure blocking evasions are candidate
for pruning.

After 998 games at 1+0

Mod vs Orig +215 =596 -187  +10 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-25 16:31:56 +01:00
Marco Costalba
d844a75d2c Avoid copy a Position to get a move's san notation
In move_to_san() we create by copy a new position just
to detect if move gives check. This could be very costly in
line_to_san() that calls move_to_san() for every move, so
create the position only once and pass a reference to move_to_san()

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-25 16:22:50 +01:00
Marco Costalba
c5e71f5150 Fix a race in idle_loop() exiting
When pondering threads are put to sleep, but when thinking
the threads are parked in idle_loop in a tight polling loop
checking for workIsWaiting falg.

So before we set the slave's flag workIsWaiting we have to
guarantee that all the slave data is already setup because
slave can start in any moment from there.

Rearrange the last loop to fix this race.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-25 15:02:06 +01:00
Marco Costalba
c5858ff9ae In split() release the lock before slow search stack copy
Once we have allocated our slave threads and we have removed
master from available threads we can safely remove the lock
so that the lenghty search stack copy operation will not
impact lock contention.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-25 14:12:30 +01:00
Marco Costalba
0ff91e16da Do not copy master position in split()
A pointer is enough because after a split point has been
setup master and slaves thread end up calling sp_search() or
sp_search_pv() and here a full copy of split point position is
done again, note that even master does another copy (of itself)
and this is done before any do_move() call so that master Position
is never updated between split() and sp_search().

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-25 12:46:08 +01:00
Marco Costalba
c2df60048e Use fast_copy() instead of full copy in sp_search
And detach splitPoint Position from the master one.

So we duplicate StateInfo only once in split() instead
of one for each thread in sp_search

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-25 12:13:16 +01:00
Marco Costalba
84ec1f7331 Better document how Position c'tor works
Renamed a bit the functions to be more clear what
we actually are doing when we craete a Position object
and explained how StateInfo works.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-25 12:04:00 +01:00
Marco Costalba
b1ac6c69a0 Fix a couple of MSVC casting warnings
Also removed some trailing whitespaces and aligned
indentation to current standard.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-25 11:27:32 +01:00
Marco Costalba
56e09b4cc8 Copy only the search stack tail in split()
Only the previous, the current and the next ply SearchStack
are copied.

This reduces split overhead especially at low depth (high ply)
and with many threads.

Possibly no functional change (it is not easy to prove in SMP)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-25 11:11:22 +01:00
Tord Romstad
5ed0a60203 Merge branch 'master' of ssh://free2.projectlocker.com/sf 2010-01-24 16:09:54 +01:00
Tord Romstad
1588a4e846 Fixes a Chess960 bug when playing with more than one search thread.
The init_eval() function corrupted the static array castleRightsMask[]
in the Position class, resulting in instant crashes in most Chess960
games. Fixed by repairing the damage directly after the function is
called. Also modified the Position::to_fen() function to display
castle rights correctly for Chess960 positions, and added sanity checks
for uncastled rook files in Position::is_ok().
2010-01-24 16:09:32 +01:00
Marco Costalba
5894c759cd Check for thread creation successful completion
It is a good programming practice to verify a system
call has indeed succeed.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-24 14:33:51 +01:00
Marco Costalba
3975a2b94f Fix some races in SMP code
When a search fails high then sp->alpha is increased and
slave threads are requested to stop.

So we have to check for a stop request before to start a search
otherwise we could end up with sp->alpha >= sp->beta
leading to an assert in debug run in search_pv().

This patch fixes the assert and get rid of some of possible races.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-24 14:30:09 +01:00
Tord Romstad
eb6ddd54f1 Make sure we make a move at the end of the search when reaching
maximum depth during a "go movetime ..." search. This prevents
Stockfish from hanging forever after finding a mate in two or
three while running a test suite at a level of a few seconds
per move.

No functional change when playing games at normal time controls.
2010-01-22 13:42:33 +01:00
Marco Costalba
01ebb3d996 If near beta generate checks at -OnePly
In qsearch() try to get a cutoff with the help of an
extra check if we are already very near.

Small increase in actual games but a good result in tactical
test sets where this patch makes SF more tactical.

Mod vs Orig +197 =620 -181 +6 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-21 00:31:01 +01:00
Marco Costalba
285df57a9a Retire LMRPVMoves and LMRNonPVMoves
Are no used anymore.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-20 18:43:29 +01:00
Marco Costalba
806c1d8723 Fix enum Value issue with gcc 4.4
Louis Zulli reports a miscompile with g++-4.4 from MacPorts.

Namely enum Value is compiled as unsigned instead of signed integer
and this yields an issue in score_string() where float(v) is incorrectly
casted when Value v is negative.

This patch ensure that compiler choses a signed variable to store a Value.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-19 23:30:23 +01:00
Marco Costalba
a1b8c8109b Small lnArray[] cleanup
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-19 11:52:13 +01:00
Marco Costalba
c01af56769 Silence some silly MSVC warnings
Value is never used un-initialized, but MSVC is not
smart enough to detect itself :-(

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-19 11:23:00 +01:00
Marco Costalba
66d5c13a88 Order check moves used in qsearch
Use the same scoring system used for evasions. Small if any
increase, but should be in at least for completeness.

After 999 games at 1+0
Mod vs Orig +208 =601 -190 +6 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-19 11:22:49 +01:00
Marco Costalba
0edad63b44 Avoid an useless evaluate() call
Now that we have position static score we don't
need to call evaluate() a second time.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-18 15:47:43 +01:00
Marco Costalba
b833c8247a Allow SearchStack to link an EvalInfo object
This will allow to have wider access to attack
information, for instance from MovePicker.

Note that 'eval' field become obsolete, it is kept
just becasue when we get a position score from TT
we update 'eval' even without an EvalInfo object.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-18 10:03:09 +01:00
Joona Kiiski
419c5b69ca Make reduction search code SMP-friendly
In sp_search_pv() we do a LMR search using sp->alpha, at the end
we detect a fail high with condition (value > sp->alpha), but if
another thread has increased sp->alpha during our LMR search we
could miss to detect a fail high event becasue value will be equal
to old alpha and so smaller then new one.

This patch fixes this SMP-bug and changes also the non SMP versions
of the search to keep code style in sync.

Bug spotted by Bruno Causse.

No functional change (for single CPU case)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-18 09:11:58 +01:00
Joona Kiiski
72e1e9b986 Small cleanup of unused code in sp_search
futilityValue is now calculated immediately after
staticValue, so remove small bunch of unused code

No functional change

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-17 14:21:14 +01:00
Marco Costalba
1062459029 Fix silly MSVC warning
MSVC raises an "use of partially uninitialized variable" for futilityValue
and staticValue but this is not rue becasue when !isCheck variables
are never used, anyhow silence the warning.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-17 13:54:52 +01:00
Marco Costalba
b5d38ad1e5 Initialize futilityMargin in EvalInfo c'tor
This is less prone to bugs because now it's up to the
compiler don't forget this important initialization.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-17 13:24:40 +01:00
Joona Kiiski
000a975eaf Retire quick_evaluate()
No change in functionality signature

The only functional change is that when we reach PLY_MAX,
we now return VALUE_DRAW instead of evaluating position.

But we reach PLY_MAX only when position is dead drawn and
transposition table is filled with draw scores, so this
shouldn't matter at all.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-17 13:15:44 +01:00
Joona Kiiski
d457594197 Razor at depth one, but do razoring only when not in check
This way razoring is always based on exact evaluation and
follows simple formula.

Joona's test results are positive:

32-bit 1CPU:

Mod - Orig: 1073 - 993

64-bit 4CPU:

Mod - Orig: 759 - 721

Functionality Signature: 11448962

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-17 11:46:40 +01:00
Marco Costalba
942c18ef66 Allow negative history values
Don't clamp to zero if a move continues to fail.

After 946 games at 1+0
Mod vs Orig +208 =562 -176 +12 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-13 22:10:43 +01:00
Marco Costalba
007285be2d Store node evaluation in SearchStack
This info will be used by future patches.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-11 21:18:30 +01:00
Marco Costalba
e817a55bc6 Decrease NullMoveMargin and adjust razoring
Also retire razoring margins vector and use
a simpler formula instead.

Now that we use a more accurate static evaluation
try to avoid useless null searches when we are well
below beta. And for teh same reason increase a bit
the razoring.

After 972 games at 1+0
Mod vs Orig +224 =558 -190 +12 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-11 21:17:02 +01:00
Marco Costalba
638f3d31cc Do not wait when AbortSearch is set
It means we have already received "stop" or "quit" commands.

This fixes an hang in tactical test in Fritz GUI. Bug
introduced by previous bug fix :-(

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-11 11:19:12 +01:00
Marco Costalba
55745f4105 Fix sending of best move during an infinite search
According to UCI standard once engine receives 'go infinite'
command it should search until the "stop" command and do not exit
the search without being told so, even if PLY_MAX has been reached.

Patch is quite invasive because it cleanups some hacks used
by fixed depth and fixed nodes modes, mainly during benchmarks.

Bug found by Pascal Georges.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-10 13:18:43 +01:00
Marco Costalba
968c3de8e0 Fix threads count setting
Was broken after "Optimal tune for 8 cores" patch.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-09 16:49:54 +01:00
Marco Costalba
6a6facc058 Optimal tune for 8 cores
After deep tests Louis Zulli found on his OCTAL machine that
best setup for an 8 core CPU is as following

"Threads" = 8
"Minimum Split Depth" = 6 or 7 (mSD)
"Maximum Number of Threads per Split Point" = not important (MNTpSP)

Here are testing results:

mSD7 (8 threads) vs mSD4 (8 threads): 291 - 120 - 589
mSD6 vs mSD7: 168 - 188 - 644
mSD6-MNTpSP5 vs mSD6-MNTpSP6: 172 - 172 - 656
SF-7threads vs SF-8threads: 179 - 204 - 617

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-08 12:58:51 +01:00
Marco Costalba
5b21c10afb Sync qsearch with search
So to have the same layout and be as much similar as
possible. The only functional change is that now we
try ttMove as first also in PV nodes and at the end
we save the ttMove, as it happens in search. This
should have almost zero impact on ELO but it seems
the correct thing to do.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-08 12:03:47 +01:00
Marco Costalba
dba072c449 Use full evaluation in null search
This is an important design change because we know
compute evaluation in each node.

This is a 2.0 type change!

After 977 games at 1+0

Mod vs Orig +236 =538 -202 51.74%  +12 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-08 10:20:35 +01:00
Joona Kiiski
e2e360fcbc Slow down reductions
After testing on Joona QUAD the whole LMR series:

Orig - Mod: 335 - 405 (+33 elo)

Functionality Signature: 12581900

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-07 15:49:48 +01:00
Joona Kiiski
49b1c5dccd Use logarithmic LMR also at root
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-07 15:40:04 +01:00
Joona Kiiski
c99d963fa5 Logarithmic LMR
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-07 15:35:57 +01:00
Marco Costalba
7c0679ad61 Fix 'position ..... moves ' parsing bug
If after 'moves' there is a space then we crash.

The problem is that operator>>() trims whitespaces so that
after 'moves' has been extract we are still not at eof()
but remaining string contains only spaces. So that the next
extarction operation uip >> token ends up with unchanged token
value that remains 'moves', this garbage value is then feeded
to RootPosition.do_move() through move_from_string() that does
not detect the invalid move value leading to a crash.

This bug is triggered by Shredder 12 interface under Mac that
puts a space after 'moves' without any actual move list.

Bug fixed by Justin Blanchard

After reviewing UCI parsing code I spotted other possible weak
points due to the fact that we don't test if the last extract
operation has been succesful. So I have extended Justing patch
to fix the remaining possible holes in uci.cpp

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-07 11:59:32 +01:00
Marco Costalba
cc974fa7a4 Fix en-passant parsing from fen string
According to standard en-passant is recorded in fen string regardless
of whether there is a pawn in position to make an en passant capture.

Instead internally we set ep square only if the pawn can be captured.
So teach from_fen() to correctly handle this difference.

Bug reported and fixed by Justin Blanchard.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-06 10:07:07 +01:00
Marco Costalba
807844eab1 Introduce refine_eval()
Try to get a position evaluation better then
the quick one with the help of the TT table.

This allows the null search conditions and
chosen reductions to be more accurate.

After 908 games at 1+0
Mod vs Orig +209 =526 -173 +14 ELO

Functionality Signature: 16627355

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-05 14:57:59 +01:00
Marco Costalba
860260c3b1 Increase null reduction at high depths
Linear rule, less aggressive then Dann's one.

It seems it scales well with depth. We will need to
verify against weaker engine if it keeps the score.

After 999 games at 1+0 on my Dual Core
Mod vs Orig +232 =534 -207  +9 ELO

After 1000 games by Martin Thoresen on his QUAD at 1+0
Mod vs Orig 521/479 52.10%

Functionality Signature: 17655312

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-05 08:09:09 +01:00
Marco Costalba
d11af1de11 Fix a compile error under gcc
And some warnings on the picky icc.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-04 17:19:42 +01:00
Marco Costalba
721d557681 Last round of search.cpp cleanup
The most interesting thing is a bit of rewrite
and semplification in connected_moves()

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-04 12:39:13 +01:00
Marco Costalba
0e15b0f1d3 Space inflate bottom part of search.cpp
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-03 21:30:46 +01:00
Marco Costalba
9e6d38d224 Rename MaxActiveSplitPoints
And move in thread.h togheter with THREAD_MAX

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-03 15:37:23 +01:00
Marco Costalba
c8af7a867e Retire 'finished' from MovePicker
It is not useful becasue it is safe to call
get_next_move() multiple times when phase == PH_STOP

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-03 15:37:17 +01:00
Marco Costalba
5c8f571459 Rename SingleReplyExtension in SingleEvasionExtension
Because that's the correct meaning. Note that also the
corresponding UCI option has been renamed.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-03 15:37:03 +01:00
Marco Costalba
0256db2a11 Small cleanup in search.cpp
Also clarify some comments.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-03 15:36:40 +01:00
Marco Costalba
12d8f74242 Retire approximateEval field from SplitPoint
It is not used anymore after the futility pruning
rewrite in a66f31f12.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-01-02 10:30:05 +01:00
Marco Costalba
7824603549 Double HistoryMax and reduce aging
After history accounting rewrite in 1.6, a small
tweak of history parameters seems positive.

Note that these are not to be considered the optimal
values, just a wild guess that proved good.

Finding the optimal values would require a much longer
testing time.

After 967 games at 1+0

Mod vs Orig 240 529 198 +15 ELO

Functionality Signature: 21222553

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-12-31 13:45:57 +01:00
Marco Costalba
0f39e5c4ff Fix a little warning under gcc compiler
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-12-30 13:25:22 +01:00
Marco Costalba
990d83a72d Optimized bitScanReverse32()
Should be a bit faster then previous one.
Hacked by Pascal Georges.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-12-30 13:25:21 +01:00
Marco Costalba
cf486cf229 Restore development version
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-12-30 13:25:21 +01:00
Marco Costalba
e0a8b36436 Stockfish 1.6.2
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-12-30 13:25:20 +01:00
Marco Costalba
8d724220a7 Better fix for gcc optimization issue
According to the standard, compiler is free to choose
the enum type as long as can keep its data.
Also cast to short and right shift are implementation
defined in case of a signed integer.

Normally all the compilers implement this stuff in
the "usual" way, but gcc with -O3 and -O2 pushes
aggressively the language to its limits to squeeze
even the last bit of speed. And this broke our
not 100% standard conforming code.

The fix is to rewrite the Score enum and the 16 bits
word extracting functions in a way that is 100% standard
compliant and with no speed regression on gcc and also on
the other compilers.

Verified it works on all compilers and with equivalent
functionality.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-12-30 13:25:02 +01:00
Marco Costalba
0973cc2ef6 Score enum should be at least 32 bits
The compiler is allowed to chose the size of an enum variable
based on the values it is expected to store. So force the compiler
to use at least a 32 bit integer type for the Score.

MSVC and Intel do not change, while gcc under -O3 is affected
by this change.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-12-27 19:45:19 +01:00
Marco Costalba
3f14f9a478 Revert small pop_1st_bit() optimization
We cannot cast a pointer type to an unrelated pointer type.
This is a violation of the strict aliasing rules.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-12-27 14:07:08 +01:00
Marco Costalba
aa86d81f79 Remove a bogus assert
It is not clear why is not true, even in single thread
case, but as a matter of fact it is not!

So remove it.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-12-27 13:54:46 +01:00
Marco Costalba
b884351cc7 Use THREAD_MAX instead of hardcoded 8
This will allow to change THREAD_MAX value in the future.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-12-27 13:52:29 +01:00
Marco Costalba
4d9e9ac3d4 Restore development version
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-12-27 08:35:44 +01:00
Marco Costalba
3dc9f95225 Set maximum hash table size to 2GB
We cannot allocate more then 2 GB, so let the limit
reflect this.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-12-27 00:44:08 +01:00
Marco Costalba
bc0871acbc Stockfish 1.6.1
Workaround a gcc optimization bug.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-12-26 19:39:22 +01:00
Marco Costalba
2643f1552f Workaround optimization bug in gcc
Unfortunatly we need to slow down to -O1 to be sure
it works always.

Note that sometime it works also with -O2 or even -O3,
but user has to try himself.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-12-26 19:39:13 +01:00
Marco Costalba
ba07b95ee0 Fix description of Score enum
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-12-26 19:39:04 +01:00
Marco Costalba
ef58551a2d Fix a typo in ReducedStateInfo
It happened to work by accident because Score and
Value are both integer.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-12-26 19:38:53 +01:00
Marco Costalba
7d34e7bf84 Stockfish 1.6
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-12-22 22:11:10 +01:00
Marco Costalba
12aeac5e14 Score definition gives a compile error under gcc
For enum definitions a parenthesis is required.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-12-21 11:44:11 +01:00
Marco Costalba
734fb9a13b Setup Release Candidate 1
To be used by Jim for testing different compiles settings.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-12-19 17:00:33 +01:00
Marco Costalba
c12364bb67 Fix a comment in HistoryMax description
Was obsoleted out some time ago.

Spotted by Justin Blanchard

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-12-19 10:43:12 +01:00
Marco Costalba
ad5b5cef4a Fix book name is hard coded as book.bin
Instead should be read by the corresponding UCI
option "Book File".

Bug reported and fixed by Justin Blanchard (Arch Linux)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-12-18 10:11:50 +01:00
Marco Costalba
0d88b832e3 In non-PV IID don't call evaluate when in check
Was a long standing hidden bug from Glaurung times,
triggered only now that we enable IID at non PV nodes.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-12-15 12:07:23 +01:00
Marco Costalba
14c3da5cad Fix a compile error in debug mode
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-12-15 11:52:57 +01:00
Marco Costalba
0b9b34655f Enable IID at non-PV nodes
We want to increrase the opportunities
of doing an exclusion search.

After 999 games at 1+0
Mod vs Orig +216 =574 -209 50.35%  503.0/999  +2 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-12-14 11:44:37 +01:00
Joona Kiiski
a66f31f129 Synchronize pruning rules in search and sp_search
Regression test passed:

Mod - Orig: 365 - 351

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-12-13 10:03:46 +01:00
Marco Costalba
2161d8b0b3 Remove history counters
Instead decrement history value on failure.

After 999 games at 1+0

Mod vs Orig  +236 =558 -204 51.60% +11 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-12-12 19:23:10 +01:00
Joona Kiiski
7bc72d092f Fix overflow risk in split point
Sizeof of search stack should be PLY_MAX+2 instead of PLY_MAX.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-12-10 19:00:19 +01:00
Joona Kiiski
b056e5d40a Re-enable TT.insert_pv()
This time make sure that valuable TTentries are not overwritten.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-12-09 19:43:12 +01:00
Joona Kiiski
d0b8bc5fdf Disable insert_pv
This way we avoid overwriting valuable TT entries which
are needed to calculate exclusion search extension for pv.

Mod - Orig: 483 - 410 (+28 elo!)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-12-08 18:13:38 +01:00
Marco Costalba
9a46ac6b2c Set IncrementalFutilityMargin to 8
After 999 games we are almost equal (+2 ELO),
but we have a good result against Rybka

Rybka 2.3.2a mp 32-bit vs Mod  254.5 - 242.5 +152/-140/=205 51.21%
Rybka 2.3.2a mp 32-bit vs Orig 259.5 - 236.5 +151/-128/=217 52.32%

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-12-08 11:16:14 +01:00
Joona Kiiski
0fc9d9ef61 Replace 100 with PLY_MAX in ok_to_use_TT
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-12-03 15:12:50 +01:00
Joona Kiiski
bd618941ce Adjust SingleReplyMargin 0x64 -> 0x20
Mod - Orig: 920 - 890 (+6 elo)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-12-02 19:49:50 +01:00
Marco Costalba
403db5a6e9 Don't clear hash at the beginning of a new game
After 900 games at 1+0
Mod vs Orig +217 =480 -196 +8 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-12-02 15:13:13 +01:00
Marco Costalba
3f3365221b Try to prune also when approximateEval < beta
Now we always try to filter out moves, we will have
more wasted evaluation calls, but also more pruned
nodes.

After 786 games

Mod vs Orig +196 =413 -177 +8 ELO

Verified also against Rybka it increases score to 50-51%

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-12-01 11:49:33 +01:00
Joona Kiiski
ae0b965711 Do not crash if we are asked to search mate or stalemate position.
We might be asked to ponder mate or stalemate position.
This being the case, simply wait for stop or ponderhit.
Currently we crash.

UCI specs aren't clear on the issue, but it cost nothing to
add little check.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-28 21:41:57 +01:00
Marco Costalba
455993b289 Fix get_option_value() for strings with spaces
Problem is that

istream& operator>> (istream& is, char* str );

according to C++ documentation "Ends extraction when the
next character is either a valid whitespace or a null character,
or if the End-Of-File is reached."

So if the parameter value is a string with spaces the currently
used instruction 'ss >> ret;' copies the chars only up to the first
white space and not the whole string.

Use a specialization of get_option_value() to fix this corner case.

Bug reported by xiaozhi

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-28 17:31:56 +01:00
Marco Costalba
c7a77dd3c0 Retire FutilityMargins[] array
Now we use a formula to calculate margins on the fly.

Node count has changed because we fixed a leftover when
we still where using FutilityMargins to calculate futilityValue
in the case that we had the evaluation score in TT.

Also small indentation fix.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-28 11:56:08 +01:00
Marco Costalba
af3dd21e90 IncrementalFutilityMargin to 4 and increased pruning
Increase pruning at low depths while tone downa bit at
higher depths (linearize a bit the logaritmic behaviour)

This goes togheter with IncrementalFutilityMargin decreased
to 4 compensate the bigger pruning effect.

Total pruned nodes are more or less the same. We go from 36%
of nodes after prune to 37% with this patch.

After 999 games at 1+0
Mod vs Orig +250 =526 -223 +9 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-27 21:17:34 +01:00
Joona Kiiski
1a7047f544 Drop OnlyMoveExt PV-condition from 8 plies to 6 plies
Orig - Mod: 731 - 750

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-27 15:56:26 +01:00
Marco Costalba
25c22ffe7a Use move not ttMove in exclude search
If we arrive until the exclusion search call then
we know that move == ttMove == tte->move()

But using ttMove in search call while, during excluded search
conditions we have used tte->Move()could be a little bit suboptimal.
On the other side using tte->move() also in search call is a bit ugly
so opt for the third choice that is the most clean becasue from the
conditions the reader easily understands that we are talking of ttMove
and that we ant to exclude the move we are evaluating in that moment.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-27 15:38:51 +01:00
Marco Costalba
ae6157fcf3 Better document previous patch
If tte->move() != MOVE_NONE then tte->move() == ttMove

What could happen is that we have a ttMove without a tte, or,
we have a tte but tte->move() == MOVE_NONE

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-27 11:54:07 +01:00
Marco Costalba
5bec768d42 Fix a possible crash in excluded search condition
Due to IID we could have a ttMove and not a tte, or,
even if we have a tte they could belong to different
searches so that the depth and type of tte don't
have the same origin of the ttMove.

To fix this we always use tte entry in excluded search
condition and, after an IID, we reprobe the TT table.

No functional change. Apart from possible crash fix.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-26 13:58:55 +01:00
Marco Costalba
6ae30e7cb1 Document why we don't use TT to prune in search_pv()
From a Joona' s post on talkchess.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-25 17:42:52 +01:00
Joona Kiiski
5ea8167921 Revert last Only move extensions tweaks
They gave bad results:

Mod - Orig: 361 - 404

Master is now verified to be functional equivalent with F_63

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-25 17:42:51 +01:00
Marco Costalba
55b5b03273 Speed up sorting of non-captures
Becasue we have a lot of zero scores (around 30% of moves)
it is a good idea to do a couple a presorting loops across
the move list and shuffle the moves a bit so that with a
small effort we end up with 3 groups of moves: positives
scores, zero scores and negative scores.

We have two advantages

1) We don't need to sort zero scores

2) Sort two small groups is faster then sort a single big one

Speed up is of about 2%

Because equal scored moves could be reordered in a different way
this is not a "no functional change" although I have verified
the output list is always correctly sorted.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-25 17:42:41 +01:00
Marco Costalba
850c021f86 Rewrite messy LSN-code take 2
We already reset loseOnTime flag at the beginning of
a new game, so we can simplify a bit the ligic there.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-25 14:35:32 +01:00
Joona Kiiski
cd0c7373cd Rewrite messy LSN-code
* New version is documented and logic should be easier to follow
* Add extra check to not use LSN with x moves / y seconds time control
* New code fixes some rear cases where old code (still) causes program to lose on time at move 1.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-25 12:10:47 +01:00
Joona Kiiski
9a59535962 Remove RootMoveList::scan_for_easy_move()
* The function is called only in one place
* It must not be called elsewhere
* The function call easily replaced with simple one line condition

No functional change (tested with usual set + 2000 random positions)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-25 11:57:20 +01:00
Joona Kiiski
48246468f2 Remove 2 FIXMEs from search.cpp
* First one is without any documentation, code is working just fine,
  so there seems to be nothing that really should be fixed.

* Second one requesting emergency measures on aspiration fail low
  when we are running out of time and we are without good move.
  After very long time, I've come to conclusion that this is
  impossible to fix, so remove request.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-25 11:52:09 +01:00
Marco Costalba
2b6bc70f7b Document and cleanup new effective-single-reply code
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-23 21:12:49 +01:00
Joona Kiiski
8b3fdec7ec Always extend full ply in PV
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-23 21:02:34 +01:00
Joona Kiiski
58452de86d Add mild extension in low depths
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-23 21:02:27 +01:00
Joona Kiiski
93c9f342ca Fix currentMove bug
Orig vs Master: +15 elo 887.5 - 812.5 (1700 games, finished) [4CPU]

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-23 21:01:05 +01:00
Joona Kiiski
16acf57773 Only move extension based on exclusion search
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-23 21:00:13 +01:00
Joona Kiiski
77eec9f9cb Base work for exclusion search
No functional change

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-23 21:00:05 +01:00
Marco Costalba
bc35f4c42d Tone down a bit futility parameters
After 999 games at 1+0

Mod vs Orig +239 =542 -218  +7 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-23 20:59:27 +01:00
Marco Costalba
889c8538a8 Remove 4*IncrementalFutilityMargin from futilityValue
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-23 20:59:26 +01:00
Marco Costalba
c52da3b806 Logaritmic futility margins
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-23 20:59:24 +01:00
Marco Costalba
b599da01fa Exponential futility margins
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-23 20:59:23 +01:00
Marco Costalba
52bca81dcb History pruning exponential limit
Use an exponenital law instead of a linear one for
history pruning.

This should prune more at low depths and a bit less
at high depths.

After 965 games

Mod vs Orig +233 =504 -228 +2 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-23 20:59:21 +01:00
Marco Costalba
0eedf47661 Incremental Futility Margin
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-23 20:59:20 +01:00
Marco Costalba
989833205f In razor qsearch use corrected beta
Correct beta by razor margin when callin qsearch

After 1019 games on Joona's QUAD

Mod - Orig: 524 - 495 (+10 elo)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-22 21:15:13 +01:00
Marco Costalba
87507121d5 Code style triviality
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-22 21:12:33 +01:00
Marco Costalba
89fe8bc0a6 Micro-optimize get_material_info()
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-15 09:35:22 +01:00
Marco Costalba
4c58db0dab Convert pawns evaluation to Score
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-14 17:57:50 +01:00
Marco Costalba
71e852ea81 Move game phase computation to MaterialInfo
Game phase is a strictly function of the material
combination so its natural place is MaterialInfo,
not position.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-14 17:57:49 +01:00
Marco Costalba
314faa905a Null move dynamic reduction based on value
After 994 games at 1+0

Mod vs Orig +244 =521 -229 50.75%  504.5/994 +5 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-14 17:57:34 +01:00
Marco Costalba
a530fc2b60 Use a more standard perft UCI interface
Call directly 'perft 6' to search up to depth 6*OnePly
instead of the old 'perft depth 6'.

It is more in line to what other engines do. Also a bit
of cleanup while there.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-13 10:35:56 +01:00
Marco Costalba
7d0e0ff95e Better document king safety evaluation
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-13 10:10:22 +01:00
Marco Costalba
764229a2e2 Rearrange table layout in evaluate.cpp
A bit more cache friendly.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-13 10:10:21 +01:00
Marco Costalba
5e340346db Remove dcCandidates data member from SplitPoint
It is no more used now that we have CheckInfo.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-13 10:10:21 +01:00
Marco Costalba
bf395c6be1 Remove update_checkers()
Now that we have CheckInfo we don't need it anymore.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-11 22:26:29 +01:00
Marco Costalba
ad44ff2bca Retire evaluate_mobility()
Move the code to the caller and also move mob_area
computation out of evaluate_pieces(). It is more clear
the code flow and it is also faster.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-11 22:25:08 +01:00
Marco Costalba
8e96149c8c Small sort_moves() deobfuscation
Write the for loop in a more idiomatic way, no assembly
change and of course no functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-11 22:25:07 +01:00
Marco Costalba
3c085775d7 Don't futility-prune ttMove
After 933 games
Mod vs Orig +219 =505 -208 +4 ELO

A small increase as expected.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-11 22:24:30 +01:00
Marco Costalba
dd5a3ae4a6 Propagate "move is check" info to do_move()
When false (common case) we avoid to update checkers
bitboard that although not so costly slows down a bit
this very hot and critical path.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-10 18:12:19 +01:00
Marco Costalba
f7f09b91ea Small update_checkers() cleanup
And is a bit faster too.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-10 17:18:00 +01:00
Marco Costalba
8a116ce691 Small update to pop_1st_bit()
Avoid a 64 bit load using a pointer. It saves a couple of push/pop
instructions so advantage is only theorical, but anyway we use
pop_1st_bit() as a reference implementation for 32 bit systems so
we keep it more for documentation purposes then for other reasons.

Idea of pointer is of Eric Mullins.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-10 17:18:00 +01:00
Marco Costalba
16626dd655 Small CheckInfo fallout
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-09 21:48:02 +01:00
Marco Costalba
2f01d67a92 Fully convert move_is_check() internally
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-09 21:38:39 +01:00
Marco Costalba
975d5e9c64 Convert move_is_check() to take a CheckInfo reference
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-09 21:02:07 +01:00
Marco Costalba
30075e4abc Use CheckInfo to compute dcCandidates
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-09 20:54:45 +01:00
Marco Costalba
37398d9456 Introduce CheckInfo struct
Keeps info used to speed-up move_is_check()

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-09 20:50:02 +01:00
Marco Costalba
e05039156c Fix operator/(Score s, int i)
And remove some useless declarations

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-09 09:00:24 +01:00
Marco Costalba
f35ddb04af Don't copy the key in do_move
It will be overwritten anyway.

Also other little small touches that seem to increase
speed more then the whole enum Score patch series :-(

Optimization is really a black art.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-09 08:45:30 +01:00
Marco Costalba
ef6fca98a0 Define Score as an enum
Increases performance because now we use one integer
for both midgame and endgame scores.

Unfortunatly the latest patches seem to have reduced a bit
the speed so at the end we are more or less at the same
performance level of the beginning. But this patch series
introduced also some code cleanup so it is the main reason
we commit anyway.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-09 08:43:34 +01:00
Marco Costalba
fea46a8212 Change Score definition to avoid the union
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-07 21:10:49 +01:00
Marco Costalba
776c7df30c Revert "Do not extend at low depths if not in PV"
On Joona's QUAD:
Orig - Mod: 414 - 373

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-07 19:47:48 +01:00
Marco Costalba
5e112f16da Revert "IID in pv also when TT move depth is too small"
After almost 900 games we are at -2 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-07 19:46:36 +01:00
Marco Costalba
15ec3e911e Last conversions to Score in evaluate.cpp
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-07 17:08:28 +01:00
Marco Costalba
1ecd8e13ee Convert ThreatBonus to Score
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-07 15:45:49 +01:00
Marco Costalba
444c7c5183 Convert RookOn7thBonus and QueenOn7thBonus to be Score
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-07 15:35:11 +01:00
Marco Costalba
e9757f7610 Convert mobility bonus tables to Score
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-07 15:28:02 +01:00
Marco Costalba
1ab01f1c14 Convert apply_weight() to handle Score
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-07 14:33:40 +01:00
Marco Costalba
4626ec2890 Convert MaterialInfo and PawnInfo to use Score
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-07 14:17:10 +01:00
Marco Costalba
dda7e4639a Introduce PieceSquareTable[16][64]
Instead of MgPieceSquareTable[16][64] and EgPieceSquareTable[16][64]

This allows to fetch mg and eg values from adjacent words in memory.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-07 13:14:24 +01:00
Marco Costalba
1ae8c59c0b Convert Position to use Score struct
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-07 12:40:48 +01:00
Marco Costalba
06f06a9be8 Introduce Score struct
Save mid and end game scores in an union so to
operate on both values in one instruction.

This patch just introduces the infrastructure and changes
EvalInfo to use a single Score value instead of mgValue
and egValue.

Speed is more or less the same because we still don't use
unified midgame-endgame tables where the single assignment
optimization can prove effective.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-07 12:35:04 +01:00
Marco Costalba
2f5ee9e4e8 Fix correct name of int64_t type
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-07 10:08:28 +01:00
Marco Costalba
dd884b65b7 Do not extend at low depths if not in PV
Only check extensions are allowed.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-06 17:52:12 +01:00
Marco Costalba
0fdc75c0bd IID in pv also when TT move depth is too small
Try an internal iterative deepening not only when we don't
have a TT move but also if search depth is more then 4*OnePly
higher then TT move depth.

On some tests it seems that in around 20% of cases ttMove changes !

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-06 17:52:04 +01:00
Marco Costalba
dae7cacd3b Better big-endian support wording in Makefile
Suggested by Joona.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-06 17:50:38 +01:00
Marco Costalba
7c0cb8e73d Enable POPCNT only through Makefile
Also remove some fallback templates that prevent a
compile error in case the user runs 'make icc-profile-popcnt'
from a non supported machine.

We want to loudly fail in that case instead of silently
fallback in a non-popcount compilation.

Updated documentation too.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-06 17:50:24 +01:00
Joona Kiiski
53ce6ce49c Add popcnt-support in Makefile
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-06 17:50:15 +01:00
Marco Costalba
7a68916ff9 Small code-style touches in movegen.cpp
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-06 14:42:48 +01:00
Marco Costalba
82a1e2d5fc Fix a small warning under icc
Variable 'f' in 'for' loop scope hides same named
one in outer scope.

Of curse no functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-06 10:39:33 +01:00
Marco Costalba
dc286d2673 Big-endian compatible pop_1st_bit()
Thanks to Eric Mullins we have now endian friendly
pop_1st_bit() and also is removed the need to use
-fno-strict-aliasing compiler option with GCC.

Speed is almost as fast, very small difference if any in
perft test, so I assume almost no difference in real games.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-06 10:21:15 +01:00
Marco Costalba
a9e536a7eb Fix a compile error in debug mode
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-06 09:23:47 +01:00
Marco Costalba
e59d053984 Enable PH_TT_MOVES during evasion generation
This allow us to avoid the generation of the
evasion moves if we already have a TT move, and
in case we have a cut-off we skip evasion generation
altoghter.

Node count is changed because now we try TT move _before_
to generate evasions. The search on the TT move alters the
piece lists so that when we come back to generate evasions
we build the move list with a diferent order and this alters
the node count.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-05 19:14:17 +01:00
Marco Costalba
1c73c1c150 Extend move_is_legal() to work also when in check
This patch is a prerequisite to use TT phase
during evasions.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-05 14:58:57 +01:00
Marco Costalba
423b8b9ded Move locals definitions at the function start
It seems to me function are easier to read now.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-05 14:58:57 +01:00
Marco Costalba
94dcac1fee Retire MovePicker::discovered_check_candidates()
It is now no more needed to know dc candidates
inside MovePicker, so avoid calculating there.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-05 07:03:48 +01:00
Marco Costalba
0855d93de8 Rewrite generate_pawn_moves() and simplify evasions
Big cleanup and semplification of pawns evasions that
now are pseudo-legal as the remaining moves. This
allow us to remove a lot of tricky code.

Verified against perft: no functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-05 07:03:47 +01:00
Marco Costalba
deecb3757c Generate pseudo-legal moves in generate_evasions()
This allow a big semplification in move generation
that will be committed with the next patch. And makes
handling of evasions similar to the other type of moves.

This patch plus the next seem to improve also on
the performance side because after 640 games to
verify there are no hidden regressions we are at +9 ELO

Verified with perft no functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-05 07:03:36 +01:00
Marco Costalba
53c2bf0697 Optimize generate_evasions()
Generate captures of checking piece and blocking
evasions in one go.

Also reduce of one indentation level early returning
when we have a double check.

Verified with perft no functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-04 11:18:43 +01:00
Marco Costalba
483a257618 Speed up perft
There is no need to do / undo the move at the last ply

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-04 11:18:05 +01:00
Marco Costalba
12461996a5 Remove SEE optimizations
Don't seem to help, perhaps because we
return an approximate SEE score instead of the
real negative score so that we have some bad capture
or evasion sub-optimal ordering that compensates
the speed up.

Anyhow after 999 games at 1+0
Mod vs Orig +240 =514 -245 -2 ELO

So almost no harm to remove and make the code simpler.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-04 11:17:42 +01:00
Marco Costalba
70b7404a63 Reorder evasions
Always try ttMove as first. Then try good captures ordered
by MVV/LVA, then non-captures if destination square is not
under attack, ordered by history value, and at the end
bad-captures and non-captures with a negative SEE. This
last group is ordered by the SEE score.

After 999 games at 1+0
Mod vs Orig +254 =546 -199 +19 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-01 21:08:30 +01:00
Marco Costalba
dddaeff7d8 Another see() shortcut
Because we only generate legal moves we can assume
a king cannot be recaptured, so we can safely return
immediately with the captured piece score. If the move
turns out to be illegal it will be pruned anyhow,
independently from SEE value. This gives a good speed up
especially now that we SEE-test all the evasions that
are always legal and very often are king moves.

Another optimization catches almost 15% of cases, unfortunatly
we have already calculated the very expensive attacks, so
benefits are not so big anyway.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-01 21:06:26 +01:00
Marco Costalba
941d923bf8 Shortcut see_sign() when SEE is known negative
This patch cuts 30% of SEE calculations, as a drawback
a returned negative value is no more always correct if
a shortcut is found.

This could impact move order when based on negative see
score as example bad captures and evasions.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-01 21:06:14 +01:00
Marco Costalba
23de3e16f1 Remove castling moves in check generation
Check generation is used only in qsearch and
only at Depth(0), castling moves that give check
are very rare overall and even almost not exsistent
at Depth(0).

So retire this almost never used code that adds
a small but consistent slow down in the normal path.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-01 17:19:04 +01:00
Marco Costalba
8ebe5075eb Optimize check generation
Because discovery checks are very rare it is better to handle
them all in one go and strip from usual check generation
function.

Also rewrite direct checks generation to use piece lists instead
of pop_1st_bit()

On perft test we have a +6% of speed up and is verified we
generate the same moves, although in a different order.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-01 17:13:01 +01:00
Joona Kiiski
fa49311b36 Implemented perft
Patch from Joona with extension to benchmark and inclusion
of Depth(0) moves generation by me.

Note that to test also qsearch and in particulary checks
generations a change in the end condition is needed.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-11-01 17:05:00 +01:00
Marco Costalba
d9b920acfb Evaluation threat values after 39089 games
Verified against tuning branch.

After 100 games at 1+0 on Joona QUAD

Mod - Orig: 527.5 - 471.5 (+20 elo)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-10-31 09:42:59 +01:00
Marco Costalba
12b0517d1b Fix build under gcc
Also some warnings squashed.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-10-25 10:22:03 +01:00
Marco Costalba
b38685625a Add threat evaluation
Give a bonus for each kind of attacked piece. Bonus
value is based on the type of attacked piece and the
type of attacking one.

Penalize pieces attacked by enemy pawns, also in
this case penality value depends on the type of
attacked piece.

This patch oboletes as redundant the increased mobility
count of the attcked squares that is then removed.

After 956 games at 1+0
Mod vs Orig  +262 =462 -232 51.57%  493.0/956 +11 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-10-25 08:21:35 +01:00
Marco Costalba
73da3a431c Micro optimize mobility calculation
Take out of mobility loop a constant expression.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-10-23 11:24:53 +01:00
Marco Costalba
b50921fd5c Unify capture and promotion tests
Small code cleanup and a bit faster too.

The only functional change is that in extension
in pv node we extend promotions and not only captures
when condition met.

This is practically an undetectable change and has
no impact on strenght.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-10-22 07:22:54 +01:00
Marco Costalba
a72c55283d Don't prune TT move in qsearch even if SEE < 0
Even if SEE is negative there is always a good possibility
that TT move is a cut move anyway. For instance a lot of
BXN exchanges that have negative SEE can very easily be
good exchanges.

A nice side effect is a bit reduced frequency of
see_sign() calls.

After 643 games at 1+0
Mod vs Orig +174 =327 -142 52.49%  337.5/643 +17 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-10-22 07:22:44 +01:00
Marco Costalba
cf4df0327a Pick best moves one per cycle instead of sorting
When the move list is very small, like captures normally
are, it is faster to pick the best move with a linear
scan, one per cycle.

This has the added advantage that the picked capture move is
very possibly a cut-off move, so that other searches are
avoided. For non-captures it is still faster to sort in
advance.

Because scan-and-pick alghortim is not stable, node count
has changed.

After 885 games at 1+0
Mod vs Orig +196 =510 -179 50.96%  451.0/885

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-10-22 07:18:41 +01:00
Marco Costalba
51c3af9dd0 Avoid a needless locking in sp_search()
Only in less then 2% of cases we have a new sp->bestValue,
so check before to lock and save a costly locking
most of the times.

Patch suggested by Joona.

No functional search.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-10-19 07:47:18 +01:00
Joona Kiiski
f0b0a3b135 Similarize pruning code in search() and sp_search()
Use futility pruning also in split points.
Do not use history pruning in split points when
getting mated.

After 1000 games on Joona QUAD
Orig - Mod: 496 - 504

Added an optimization to avoid a costly lock in the
very common case that sp->futilityValue <= sp->bestValue.
A test on a dual CPU shows only 114 hits on 23196 events,
so avoid a lock in all the other cases.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-10-18 21:31:19 +01:00
Marco Costalba
4dd7fccfd1 Use an homegrown insertion sort instead of std::sort()
It is stable and it is also a bit faster then std::sort()
on the tipical small move lists that we need to handle.

Verified to have same functionality of std::stable_sort()

After 999 games at 1+0
Mod vs Orig +240 =534 -225 50.75%  507.0/999  +5 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-10-17 09:24:58 +01:00
Marco Costalba
c1ea5ed6f7 Do not prune the move if we are still under mate
If after the first tried 2 + int(depth) moves we still
have no any move that takes us out of a mate then do
not prune the following move, it is more important to
escape mate then speed up search.

This fixes an odd behaviour regarding mates, as example
the following diagram is a mate in 4, not in 3 as bogusly
reported before this patch.

1B2n3/8/2R5/5p2/3kp1n1/4p3/B3K3/8 w - - bm #4;

The performance impact should be minimal, the increment
in searched nodes is less then 0.1 %%

Idea and patch by Joona

After 999 games at 1+0
Mod vs Orig +193 =604 -202  -3 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-10-15 18:52:21 +01:00
Tord Romstad
53f882ff1a Minor improvement in eval of unstoppable pawns promoting one ply apart.
Marco's new code for evaluating two unstoppable passed pawns where
one pawn promotes a single ply before the other tried to detect
cases where the pawn that promotes first could immediately capture
the pawn that promotes a ply later, but didn't work in cases where
the two pawns are on the same file. An example of this is the
following position:

8/8/3K4/2P5/2p5/3k4/8/8 w - -

With the new code, such positions are handled correctly.
2009-10-15 12:39:55 +02:00
Marco Costalba
d8e7ce1863 Fix a crash when reaching PLY_MAX in a check position
In this case we call evaluate() being in check and this
is not allowed.

Bug found testing with reduced PLY_MAX value as suggested
by Miguel A. Ballicora on talkchess.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-10-12 15:32:50 +01:00
Marco Costalba
181d34e5a0 Add a new rule on promoting pawns in evaluate_passed_pawns()
Add a rule about the situation when one side queens exactly
one ply before the other. To avoid difficult (but luckly rare)
cases we only handle the case of free paths to queen for
both sides.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-10-12 10:09:06 +02:00
Marco Costalba
2655f93c32 Fix x-ray attack from behind in evaluate_passed_pawns()
Fix a condition for x-ray attack of a queen or
a rook behind a pawn of us. Previous condition does
not check if the enemy slider behind our pawn is
really attacking the pawn.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-10-12 09:36:35 +02:00
Marco Costalba
ab4d26f9bd Small cleanup and in evaluate_passed_pawns()
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-10-12 09:36:30 +02:00
Marco Costalba
d6b04c2798 Revert "Use std::stable_sort() instead of std::sort()"
Unfortunatly std::stable_sort() implementation in gcc is
horrendously slow. We have a big performance regression on
Linux systems (-20% !)

So revert the commit and wait to fix the issue in a different
way, perhaps with an our home grown sorting, that should be
comparable in speed with std::sort()

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-10-12 09:36:23 +02:00
Marco Costalba
e2e249eabd Use std::stable_sort() instead of std::sort()
Standard does not mandate std::sort() to be stable, so we
can have, and actually do have different node count on
different platforms.

So use the platform independent std::stable_sort() and gain
same functionality on any platform (Windows, Unix, Mac OS)
and with any compiler (MSVC, gcc or Intel C++).

This sort is teoretically slower, but profiling shows only a very
minimal drop in performance, probably due to the fact that
the set to sort is very small, mainly only captures and with
less frequency non-captures, anyhow we are talking of 30-40 moves
in the worst average case. Sorting alghortims are build to work on
thousands or even milions of elements. With such small sets
performance difference seems not noticable.

After 999 games at 1+0

Mod vs Orig +234 =523 -242 -3 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-10-10 15:45:46 +01:00
Marco Costalba
ed19a9f909 Unroll color loops in evaluate_passed_pawns()
Speed increase is on 1.5% on Intel pgo build.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-10-10 14:56:56 +01:00
Marco Costalba
eddfd46a10 Use piece_list to scan the pawns in evaluate_pawns()
No functional change and small speed increase.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-10-10 14:56:10 +01:00
Marco Costalba
a806d7c3d6 Fix pieceList initialization in Position::clear()
We want piece list to be terminated with SQ_NONE.

This happens with all the pieces but the pawns that
being 8 make the inner loop exit just before writing
the SQ_NONE value at the tail of the list.

This bug was hidden because currently we don't use
piece list to scan pawns, but this will change in the
future and in any case an initialization should be done
correctly for the whole array to avoid subtle bugs in
the future.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-10-10 09:49:41 +01:00
Marco Costalba
ccdb634b77 Unroll color loops in get_pawn_info
This allow to resolve a lot of addresses at compile time
instead of an indirect access at runtime.

Speed up on pgo compile is of 1.3%

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-10-09 16:48:45 +01:00
Marco Costalba
564ed5b38c Small micro-optimization in get_pawn_info()
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-10-09 11:29:11 +01:00
Marco Costalba
f05d059b17 Restore pliesFromNull counter
It is not equivalent because the check for the
50 moves rule get badly affected.

// Draw by the 50 moves rule?
if (st->rule50 > 100 || (st->rule50 == 100 && !is_check()))
    return true;

So we _really_ need two counters.

Thanks to Joona and Tord to be patience with a silly guy ;-)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-10-09 10:11:43 +01:00
Marco Costalba
06a5b602dc Fix an off-by-one bug in extract_pv()
In case we reach ply == PLY_MAX we exit the function
writing

pv[PLY_MAX] = MOVE_NONE;

And because SearchStack is defined as:

struct SearchStack {
  Move pv[PLY_MAX];
  Move currentMove;
  .....

We end up with the unwanted assignment

SearchStack.currentMove = MOVE_NONE;

Fortunatly this is harmless because currentMove is not used where
extarct_pv() is called. But neverthless this is a bug that
needs to be fixed.

Thanks to Uri Blass for spotting out this.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-10-09 10:04:55 +01:00
Marco Costalba
d892063cd3 Rewrite previous patch using only one counter
Use only rule50 and retire pliesFromNull.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-10-09 04:35:11 +01:00
Marco Costalba
64d6ba2e98 Do not claim repetition after null move
Null moves can artificially create a repetition
draw where instead there is no one.

So use a second counter to reset history after
a null move.

Idea from Joona.

After 999 games at 1+0

Mod vs Orig +238 =553 -208 51.50%  514.5/999  +10 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-10-09 03:55:10 +01:00
Marco Costalba
5a5dc6fa10 Restore development version
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-10-08 15:16:47 +01:00
Marco Costalba
8ee0842c81 Stockfish 1.5.1
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-10-08 15:16:34 +01:00
Marco Costalba
e59ff49a55 Fix the polling frequency when pondering
When pondering InfiniteSearch == false but myTime == 0 so that
NodesBetweenPolls = 1000 instead of the standard.

The patch fixes the bug and is more robust because checks
directly myTime for a non-zero value, without relying on
an indirect test (InfiniteSearch in this case).

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-10-08 09:09:19 +01:00
Tord Romstad
225dcfeeb7 Use slightly lower polling frequency in the last few seconds.
Instead of checking the time every 100 nodes in the last second,
and every 1000 nodes in the last five seconds, Stockfish now checks
every 1000 nodes in the last second and every 5000 nodes in the last
five seconds.  This was tested in 1036 games at a time control of
40 moves/10 seconds, and no losses on time occured.

Also fixed a bug pointed out by Marco:  In infinite mode, myTime
is actually 0, but of course we still don't want to check the time
more frequently than the standard once per 30000 nodes in this
case.
2009-10-08 08:55:25 +02:00
Tord Romstad
8dd01fda12 Minor change to time management code, to make sure we don't lose on
time at the last move before the time control when there is very
little time left.
2009-10-07 18:27:00 +02:00
Tord Romstad
18cd83a380 Display fail high/fail low in search log file. 2009-10-06 12:51:15 +02:00
Marco Costalba
fd2b3df770 Fix bogus comment in extract_pv()
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-10-06 11:15:05 +01:00
Marco Costalba
da948cc94e Fix use of an initialized SearchStack
In RootMoveList c'tor we allocate a search stack and then
call directly qsearch.

There is called init_node() that clears all the fields of the search
stack array that refers to current ply but not the the killer moves.

The killer moves cleared correspond to ply+2.

In id_loop() this is not a problem because killer moves of
corresponding ply are cleared anyway few instructions later,
but in RootMoveList c'tor we leave them uninitialized.

This patch fixes this very old bug. It comes direclty
from Glaurung age.

Bug spotted by Valgrind.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-10-06 11:12:41 +01:00
Marco Costalba
e49b21eacb Remove a redundant assignment in PawnInfo c'tor
We don't need to set key to 0 because clear() already
takes care of that.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-10-06 09:18:15 +01:00
Marco Costalba
60bc30275d Small code reformat in TranspositionTable::extract_pv()
In particular don't use an array of StateInfo, this
avoids a possible overflow and is in any case redundant.

Also pass as argument the pv[] array size to avoid a second
possible overflow on this one.

Fix suggested by Joona.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-10-06 07:14:12 +01:00
Tord Romstad
32dfaa56b0 Fixed an embarassing Chess960 bug found by Alexander Schmidt.
It turned out that we used do_move_bb to update the king and rook
bitboards when making and unmaking castling moves, which obviously
doesn't work in Chess960, where the source and destination squares
for the king or rook could be identical.

No functional change in normal chess.
2009-10-05 16:46:18 +02:00
Marco Costalba
3701a8e57d Restore development version
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-10-05 07:15:13 +01:00
Marco Costalba
aaa07fb161 Stockfish 1.5
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-10-04 07:09:12 +01:00
Marco Costalba
1361ba75cb Small touches to increased mobility patch
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-10-04 06:59:06 +01:00
Marco Costalba
da9c423989 Move a comment where it belongs in SEE
No functional change of course.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-10-03 10:48:20 +01:00
Marco Costalba
3713bb26ef Don't increase mobility if attacked piece is defended by a pawn
If an enemy piece is defended by a pawn don't give the
extra mobility bonus in case we attack it.

Joona says that "Paralyzing pawn" is usually worth of nothing.

On Joona QUAD after 964 games:
Orig - Patch_2: 191 - 218 - 555 (+ 10 elo)

On my PC after 999 games at 1+0:
Mod vs Orig +227 =550 -222 50.25%  502.0/999  +2 ELO

In both cases we tested against the original version (without
increased mobility), not against the previous patch that instead
seems to fail on Joona QUAD:
Orig vs. Prev.Patch: 237 - 217 - 627 (-6 elo)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-10-03 10:48:07 +01:00
Marco Costalba
cff9ff2198 Count two times number of attacked pieces in mobility
Now in mobility we count enemy attacked pieces as
empty squares.

With this patch we try to give an higher score to positions
where the number of attacked pieces is higher.

After 999 games at 1+0

Mod vs Orig +262 =517 -219 52.15% 520.5/998 +15 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-09-30 16:11:45 +01:00
Marco Costalba
a6c6037813 Optimize futilityValue calculation
Avoid calling evaluate() if we already have the score in TT

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-09-30 16:11:41 +01:00
Marco Costalba
e677185567 Store pawn attacks in PawnInfo
They are pawn structure invariant so has a sense to
store togheter with pawn info instead of recalculating
them each time evaluate() is called.

Speed up is around 1%

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-09-30 16:11:37 +01:00
Tord Romstad
237dd331d5 Fixed a couple of typos in a comment.
No functional change, of course.
2009-09-30 09:53:29 +02:00
Marco Costalba
98c8a83bb8 Fix a MSVC warning in search.cpp
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-09-29 16:48:50 +01:00
Tord Romstad
73be819426 Temporarily removed the unfinished UCI_Elo code in preparation for
the release of the public Stockfish 1.5.
2009-09-29 13:40:00 +02:00
Marco Costalba
2940abdac8 Print RootMoveList startup scoring
This satisfies a specific user request of 28/8/2009

"The only issue I have is that during multiPV analysis, the depth 1
best move score is not reported by the engine (reporting for the best
move begins at depth 2).  I need it at depth 1 also. Would it be
possible to make this modification in future versions? This would be
of great help as otherwise I will have to use a lesser engine.

The goal of my project is to calculate the ELO performance in a game
and also the ELO rating of individual moves. For this I need depth 1
scores for lower rated performances. I intend to distribute the program
for free upon completion.

Thanks, Jack Welbourne"

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-09-29 10:14:43 +01:00
Marco Costalba
fa0bffeafa Retire compute_weight() in evaluation.cpp
Is used only in weight_option() so inline there.
Unroll color loop also for evaluate_space() and
finally also some assorted code style fixes.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-09-28 17:56:04 +01:00
Marco Costalba
d56345c9ae Unroll color loops in evaluate
Use templates to manually unroll the loops so that
many values could be calculated at compile time or at
runtime but with a fast direct memory access instead of
an indirect one.

This change gives a speed up of 3.5 % on pgo build !!!  :-)

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-09-28 11:44:12 +01:00
Marco Costalba
60e23693f0 Change back file mode of misc.cpp
It was erroneusly changed by 6bf22f35 from
mode 100644 to 100755.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-09-27 07:58:28 +01:00
Marco Costalba
91f0c08789 Update piece list iteration also in evaluate_pieces()
Move to what we already do in generate_piece_moves()

This simple patch gives a spped up of 1.4% !!

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-09-26 15:49:04 +02:00
Marco Costalba
6bf22f354f Retire faked Windows version of gettimeofday()
Use equivalent Windows function _ftime() instead.

This patch also removes two long standing warnings
under MSVC.

No functional change and no change for non-Windows systems.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-09-26 15:48:58 +02:00
Marco Costalba
48b74142ef Micro optimization of generate_piece_moves()
This patch make the piece list always terminated by SQ_NONE,
so that we can use a simpler and faster loop in move
generation.

Speedup is about 0.6%.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-09-24 07:11:39 +01:00
Marco Costalba
dcb323bf0d Retire kingSquare[] array
It is redundant. Use pieceList[c][KING][0] instead.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-09-23 17:47:03 +01:00
Marco Costalba
44cb792c76 Reorder data layout and optimize access patern
With this very simple patch we get a speed boost
of 0.8% on my PC !

Sometime we find the most complex tricks to increase speed
when instead the best results come from the simplest solutions.

No functional change of course ;-)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-09-23 17:33:24 +01:00
Marco Costalba
e68e135771 Fix a couple of Intel compiler warnings
And avoid calculating emptySquares for pawns captures
case.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-09-23 17:01:59 +01:00
Marco Costalba
46141b078c Fix a piece_of_color_and_type() / pieceS_of_color_and_type() typo
Bug introduced in 17c51192

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-09-23 17:01:30 +01:00
Marco Costalba
02fd34a5e8 Rename generate_piece_moves() in generate_piece_evasions()
A better and more specific name. Also a bit of code reshuffle.

Verified No functional change and No performance change
for the whole series.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-09-23 14:23:07 +01:00
Marco Costalba
20cac227bb Retire generate_pawn_captures()
And unify in generate_pawn_noncaptures() renamed
generate_pawn_moves()

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-09-23 11:18:55 +01:00
Marco Costalba
4346445be3 Retire generate_pawn_blocking_evasions()
And unify in generate_pawn_noncaptures()

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-09-23 10:47:11 +01:00
Marco Costalba
21850536d5 Standardize generate_pawn_blocking_evasions()
Rewrite in the form normally used in other similar
functions like generate_pawn_noncaptures()

This allow an easier reading of the pawn moves generators
and simplify a bit the code.

No functional change (tested on more then 100M nodes).

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-09-23 10:06:32 +01:00
Marco Costalba
0179a32cf5 Code style and subtle fix in move_is_legal()
A bunch of trivial code style and comment fixes.

Among them there is a real fix for a subtle case
involving promotion moves.

We currently check that a pawn push to 8/1th rank
must be a promotion, but we don't check the contary,
i.e. that a pawn push on a different rank must NOT be
a promotion. Note that, funny enough, we perform this
control for all the other pieces, but not for the pawns!

This patch fixes this really corner case.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-09-22 07:07:19 +01:00
Marco Costalba
8487069058 Simplify move legality check for uncommon cases
Remove a bunch of difficult and tricky code to test
legality of castle and ep moves and instead use a slower
but simpler check against the list of generated legal moves.

Because these moves are very rare the performance impact
is small but code semplification is ver big: almost 100 lines
of difficult code removed !

No functionality change. No performance change (strangely enough
there is no even minimal performance regression in pgo builds but
instead a slightly and unexpected increase).

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-09-22 07:07:18 +01:00
Marco Costalba
43ca5c926d Enable functionality of previous patch
Now under-promotion checks are generated.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-09-22 07:07:18 +01:00
Marco Costalba
aed542d74c When generating checks add possibly under-promotions
In qsearch at depth 0 we generate only captures and checks.
Queen promotion moves are generated among the captures, but
under-promotion moves (both captures and non-captures) are
never generated even if they could give a discovery check.

This patch fixes this limitation extending generate_pawn_noncaptures()
to generate also check moves when required.

Apart for adding the (rare) case of an under-promotion that gives
discovery check, the patch is also a good cleanup because removes
generate_pawn_checks() altoghter.

This patch does the code clean-up but not enables the functional
change so to allow an easier debug.

No functional change and no performance change (actually a very
very small speed increase).

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-09-22 07:07:17 +01:00
Marco Costalba
aaffcf973e Fix a bug in generate_piece_checks()
We are generating also king moves that give check !

Of course these moves are illegal so are in any case
filtered out in MovePicker. Neverthless we should avoid
to generate them.

Also simplify a bit the code.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-09-22 07:07:16 +01:00
Marco Costalba
746bcb348f Small micro optimization in generate_evasions()
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-09-22 07:07:16 +01:00
Marco Costalba
a7cb05b1eb Change evaluation GrainSize from 4 to 8
Idea from Joona.

After 999 games at 1+0 on my Intel Core 2 Duo
Orig - Mod: +215 =538 -226 (+11 ELO)

On Joona QUAD after 845 games at 1+0
Orig - Mod: 151 - 181 - 513 (+13 elo)

So it seems a good change !

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-09-22 07:06:52 +01:00
Marco Costalba
9741694fca Save static evaluation also for failed low nodes
When a node fails low and bestValue is still equal to
the original static node evaluation, then save this
in TT along with usual info.

This will allow us to avoid a future costly evaluation() call.

This patch extends to failed low nodes what we already do
for failed high ones.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-09-20 20:05:40 +01:00
Marco Costalba
e145c0d3e2 Revert evaluation drift
Still not clear if it helps and, especially, how it
helps. So revert for now to avoid any influence on
future feature now under test.

With this patch we come back to be functional
equivalent to patch e33c94883 F_53.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-09-20 19:39:54 +01:00
Marco Costalba
24cc3a97a4 Evaluation drift: add always 7 instead of ply
After 828 games at 1+0

Mod vs Orig +191 =447 -190 50.06%  414.5/828

So almost no difference. Patch is committed more for
documentation purposes then for other reasons.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-09-20 19:32:53 +01:00
Marco Costalba
e4277c06bf Rename piece_attacks_from() in attacks_from()
It is in line with attackers_to() and is shorter and
piece is already redundant because is passed as template
parameter anyway.

Integrate also pawn_attacks_from() in the attacks_from()
family so to have an uniform attack info API.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-09-20 14:55:28 +01:00
Marco Costalba
dd80b9abaf Remove undefined pinned_pieces(Color c, Bitboard& p)
It was added in revision 5f142ec2 but never used.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-09-20 11:01:56 +01:00
Marco Costalba
84d6fe0f31 Retire attackers_to(Square s, Color c)
Use the definition in the few places where is needed.

As a nice side effect there is also an optimization in
generate_evasions() where the bitboard of enemy pieces
is computed only once and out of a tight loop.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-09-20 10:47:59 +01:00
Marco Costalba
6845397c5c Rename piece_attacks() in piece_attacks_from()
It is a bit longer but much easier to understand especially
for people new to the sources. I remember it was not trivial
for me to understand the returned attack bitboard refers to
attacks launched from the given square and not attacking the
given square.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-09-20 10:26:54 +01:00
Marco Costalba
f74f42b298 Cleanup piece_attacks_square() functions
Most of them are not required to be public and are
used in one place only so remove them and use its
definitions.

Also rename piece_attacks_square() in piece_attacks()
to be aligned to the current naming policy.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-09-20 10:12:56 +01:00
Marco Costalba
0e0adfe2e1 Rename attacks_to() in attackers_to()
These functions return bitboard of attacking pieces,
not the attacks themselfs so reflect this in the name.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-09-20 09:31:48 +01:00
Marco Costalba
049139d025 Change pawn_attacks() API
Instead of pawn_attacks(Color c, Square s) define as
pawn_attacks(Square s, Color c) to be more aligned to
the others attack info functions.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-09-20 09:09:27 +01:00
Marco Costalba
62a8f393f1 Clean up API for attack information
Remove undefined functions sliding_attacks() and ray_attacks()
and retire square_is_attacked(), use the corresponding definition
instead. It is more clear that we are computing full attack
info for the given square.

Alos fix some obsolete comments in move generation functions.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-09-20 08:48:10 +01:00
Marco Costalba
c5f44ef45b Move kingSquare[] array to StateInfo
This avoids to reverting back when undoing the move.

No functional change. No performance change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-09-20 07:32:00 +01:00
Marco Costalba
7c55b0e880 Don't compensate TT for evaluation drift
It seems that it works better without compensation
of drifted value when saving static evaluation in TT.

After 818 games at 1+0

Mod vs Orig +217 =429 -172 52.75%  431.5/818  +19 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-09-19 12:52:57 +01:00
Marco Costalba
77ac1e7953 Use WIN32_LEAN_AND_MEAN in lock.h
This avoids inclusion of a bunch of not very commonly
used headers from windows.h

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-09-17 14:18:44 +01:00
Joona Kiiski
cddda7cd19 Make static value saved in TT independent from ply
After 963 games at 1+0

Mod vs Orig +246 =511 -206 52.08%  501.0/962  +14 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-09-17 14:16:16 +01:00
Marco Costalba
c81010a878 Evaluation drift
Increase evaluation score with ply.

After 940 games at 1+0

Mod vs Orig +247 =487 -206  +15 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-09-15 09:04:16 +01:00
Marco Costalba
6709b01903 Fix semantic of piece_attacks<PAWN>
Return the bitboard with the pawn attacks for both colors
so to be aligned to the meaning of the others piece_attacks<Piece>
templates.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-09-13 16:13:49 +01:00
Marco Costalba
3863cd191c Indirectly prefetch board[from]
One of the most time critical functions is move_is_check()
and in particular the call to type_of_piece_on(from) in the
switch statement.

This call lookups in board[] array and can be slow if board[from]
is not already cached. Few instructions before in the execution stream,
we check the move for legality with pl_move_is_legal().

This patch changes pl_move_is_legal() to use type_of_piece_on(from)
for checking for a king move so that board[from] is automatically
cached in L1 and ready to be used by the near follower move_is_check()

Another advantage is that the call to king_square(us) in pl_move_is_legal()
is avoided most of the times.

Speed up of this nice and tricky patch is 0.7% !

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-09-13 11:35:48 +01:00
Marco Costalba
f205fe1fe5 Retire piece_is_slider(PieceType pt)
Is not used in any part of the sources.

No functional change, of course ;-)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-09-04 08:21:07 +01:00
Marco Costalba
9f28d8a854 Second take at unifying bitboard representation access
This patch is built on Tord idea to use functions instead of
templates to access position's bitboards. This has the added advantage
that we don't need fallback functions for cases where the piece
type or the color is a variable and not a constant.

Also added Joona suggestion to workaround request for two types
of pieces like bishop_and_queens() and rook_and_queens().

No functionality or performance change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-09-04 08:21:06 +01:00
Marco Costalba
76bed11f7b Templetize functions to get pieces by type
Use a single template to get bitboard representation of
the position given the type of piece as a constant.

This removes almost 80 lines of code and introduces an
uniform notation to be used for querying for piece type.

No functional change and no performance change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-09-04 08:21:05 +01:00
Marco Costalba
e33c94883f Set LMRPVMoves to 10 instead of 14
After 934 games at 1+0

Mod vs Orig +228 =493 -213 50.80%  474.5/934   +6 ELO

So it seems not negative and there is also the added
benefit to unify LMRPVMoves use in search_pv() and in
root list.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-09-04 08:21:04 +01:00
Marco Costalba
46ffea46ea Fix poly values mismerge
I managed to completely mismerge correct values
for QuadraticCoefficientsOppositeColor table :-(

Now it correspond to tuning branch for real.

After 999 games at 1+0

Mod vs Orig +247 =512 -240 50.35%  503.0/999  +2 ELO

So almost no change, but the new values comes from the
same tuning session of the others, so has more sense to
use these ones.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-09-04 08:21:02 +01:00
Tord Romstad
03d6a86900 Bug fix for discovered checks in connected_moves().
Because of a hard-to-spot single-character bug in connected_moves(),
the discovered check code had no effect whatsoever. The condition
in the if (...) statement at the beginning of the code would always
return false.

Thanks to Edsel Apostol for pointing out this bug!
2009-09-02 09:58:15 +02:00
Marco Costalba
17c5119222 Retire pieces_of_color_and_type()
It is used mainly in a bunch of inline oneliners
just below its definition. So substitute it with
the explicit definition and avoid information hiding.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-08-31 16:23:04 +02:00
Marco Costalba
cf71efc34b MovePicker: rename number_of_moves() in number_of_evasions()
It is more clear that only in that case the move number is
correct, otherwise is only a partial quantity: the number of
moves of that phase.

In case of PH_EVASIONS instead we have only one phase.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-08-31 15:32:31 +02:00
Marco Costalba
c9d364f9ca Use pointers instead of array indices also for badCaptures
To have uniformity with moves array handling.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-08-31 12:33:44 +02:00
Marco Costalba
97dd7568ed Document index[] and pieceList[] are not invariants
Array index[] and pieceList[] are not guaranteed to be
invariant to a do_move() + undo_move() sequence when a
capture move is involved.

The reason is that the captured piece is removed form
the list and substituted with the last one in do_move()
while in undo_move() is added again but at the end of
the list.

Because index[] and pieceList[] are used in move generation
to scan the pieces it means that moves will be generated
in a different order before and after a do_move() + undo_move()
sequence as, for instance, the one in Position::has_mate_threat()

After latest patches, move generation could now be invoked
also by MovePicker c'tor and this explains why order of
picked moves is different if MovePicker object is istantiated
before or after a Position::has_mate_threat() call.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-08-31 11:02:28 +02:00
Marco Costalba
af220cfd52 Workaround a bug in Position::has_mate_threat()
It seems that pos.has_mate_threat() changes the position !

So that calling MovePicker c'tor before or after the
has_mate_threat() call changes the things !

Bug was unhidden by previous patch that makes MovePicker c'tor
to generate, score and sort good captures under some circumstances.

Because scoring the captures is position dependent it seems that
the moves returned by MovePicker are different when c'tor is
called before has_mate_threat()

Of course this is only a workaround because the real bug is still
hidden :-(

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-08-30 20:10:09 +01:00
Marco Costalba
1130c8d815 Skip TT_MOVES phase when possible
If we don't have tt moves to search skip the
useless loop associated with TT_MOVES phase.

Another 1% speed boost that brings this series
to a +6.2% against original revision 595a90df

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-08-30 20:10:09 +01:00
Marco Costalba
607ac0687a Movepicker: take move's loop out of switch statement
This not only cleans up the code but gives another
speed boost of 1.8%

From revision 595a90dfd0 we have increased pgo compiled binary
speed of a whopping +5.2% without any functional change !!

This is really awsome considering that we have also
cut line count by 25 lines.

Sometime we spend days for getting an extra 1% from move
generation while instead the biggest optimizations come
from anonymous and apparently dull parts of the code.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-08-30 20:10:08 +01:00
Marco Costalba
e9de96f0e4 Revert "null move reorder" series
Does not seem to improve on the standard, latest results
from Joona after 2040 games are negative:

Orig - Mod: 454 - 424 - 1162

And is more or less the same I got few days ago.

So revert for now.

Verified same functionality of 595a90dfd

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-08-30 20:09:58 +01:00
Marco Costalba
9ab84a8165 Convert handling of tt moves and killers to standard form
Use the same way of loop along the move list used for
the others move kinds so to be consistent in get_next_move()

And a bit of the usual clean up too, but just a bit.

It is even a bit (+0.3%) faster now. ;-)

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-08-29 19:51:00 +01:00
Marco Costalba
ac65b14d30 Try null move before captures
Always after TT move but before captures.

This seems a better setup against version before this
patch.

After 999 games at 1+0

Mod - Orig +252 =527 -220 +11 ELO

Unfortunatly it does not seems to improve on the standard
version, with null move outside of movepicker (595a90df) with
the latest speed-up patches added in.

After 999 games at 1+0

Mod - Standard +244 =506 -249 -2 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-08-29 07:17:09 +01:00
Marco Costalba
9e4befe3f1 Use pointers instead of array indices in MovePicker
This avoids calculating the array entry position
at each access and gives another boost of almost 1%.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-08-29 06:48:31 +01:00
Marco Costalba
6cf28d4aa7 Change the flow in wich moves are generated and picked
In MovePicker we get the next move with pick_move_from_list(),
then check if the return value is equal to MOVE_NONE and
in this case we update the state to the new phase.

This patch reorders the flow so that now from pick_move_from_list()
renamed get_next_move() we directly call go_next_phase() to
generate and sort the next bunch of moves when there are no more
move to try. This avoids to always check for pick_move_from_list()
returned value and the flow is more linear and natural.

Also use a local variable instead of a pointer dereferencing in a
time critical switch statement in get_next_move()

With this patch alone we have an incredible speed up of 3.2% !!!

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-08-27 19:56:26 +01:00
Marco Costalba
129cde008c Disable again null move at depth == OnePly
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-08-26 16:59:58 +01:00
Joona Kiiski
b088f0aefd Use special null move technique in low depth.
Try good captures before null move when depth < 3 * OnePly.
Use this kind of null move also in Depth == OnePly.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-08-26 16:30:39 +01:00
Joona Kiiski
a5d699d62f Use nullMove only through MovePicker.
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-08-26 16:30:35 +01:00
Joona Kiiski
f6d2452916 Add Null move support to MovePicker.
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-08-26 16:29:18 +01:00
Joona Kiiski
268c53ac51 Create useNullMove local variable
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-08-26 15:42:58 +01:00
Marco Costalba
595a90dfd0 Clean killers handling in movepicker
Original patch from Joona with added optimizations
by me.

Great cleanup of MovePicker with speed improvment of 1%

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-08-26 15:38:47 +01:00
Marco Costalba
e217407450 Micro-optimze extension()
Explicitly write the conditions for pawn to 7th
and passed pawn instead of wrapping in redundant
helpers.

Also retire the now unused move_is_pawn_push_to_7th()
and the never used move_was_passed_pawn_push() and
move_is_deep_pawn_push()

Function extension() is so time critical that this
simple patch speeds up the pgo compile of 0.5% and
it is also more clear what actually happens there.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-08-25 15:11:05 +01:00
Marco Costalba
2078878376 Merge branch 'master' of git-Stockfish@free2.projectlocker.com:sf 2009-08-23 18:57:11 +01:00
Marco Costalba
d1d4437699 Remove a local variable from pop_1st_bit()
Remove the 'b' uint32_t local variable.
Optimized assembly is more or less the same
(one 'mov' instruction less), but now it is
written in a way more similar to the final assembly
flow so it should be easier for compiler to optimize.

Also guarantee that BitTable[] is always aligned.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-08-23 18:55:07 +01:00
Marco Costalba
ba04eb0446 Poly ampli+bias values after 73831 games
Verified correct against tuning branch.

After 999 games at 1+0

Mod vs Orig +257 =510 -232 51.20%  +9 ELO

Very small increase but an increase anyway !

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-08-23 18:51:01 +01:00
Tord Romstad
ed347e7cbd Added a few new targets to the Makefile for OS X with icpc.
The following new targets were added:
   * osx-icc32: 32-bit x86 compiled with icpc.
   * osx-icc64: 64-bit x86 compiled with icpc.
   * osx-icc32-profile: 32-bit x86 compiled with icpc and pgo.
   * osx-icc64-profile: 64-bit x86 compiled with icpc and pgo.
2009-08-21 10:50:34 +02:00
Marco Costalba
95af1e28be Fix some asserts raised by is_ok()
There were two asserts.

The first was raised because is_ok() was called at the
beginning of do_castle_move() and this is wrong after
the last code reformatting because at that point the state
is already modified by the caller do_move().

The second, raised by debugIncrementalEval, was due to a
rounding error in compute_value() that occurs because
TempoValueEndgame was updated in an odd number by patch

"Merge Joona Kiiski evaluation tweaks" (3ed603cd) of 13/3/2009

This line in compute_value() is the guilty one:

result += (side_to_move() == WHITE)? TempoValue / 2 : -TempoValue / 2;

The fix is to increment TempoValueEndgame so to be even.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-08-20 17:48:52 +01:00
Tord Romstad
e9aa20ad13 Fixed incorrect material key update when making promotion moves. 2009-08-20 16:54:20 +02:00
Marco Costalba
e01fefbbaf More use of memset() in Position::clear()
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-08-18 21:21:28 +01:00
Marco Costalba
e4fc957898 Little do_move() micro optimizations
Also a few remaining style touches.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-08-18 08:58:19 +01:00
Marco Costalba
693b38a5e7 Better clarify how pieceList[] and index[] work
Rearrange the code a bit to be more self-documenting.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-08-17 23:15:35 +01:00
Marco Costalba
fbec55e52e Unify patch series summary
This patch seems bigger then what actually is.

It just moves some code around and adds a bit of coding style fixes
to do_move() and undo_move() so to have uniformity of naming in both
functions.

The diffstat for the whole patch series is

239 insertions(+), 426 deletions(-)

And final MSVC pgo build is even a bit faster:

Before 448.051 nodes/sec

After 453.810  nodes/sec (+1.3%)

No functional change (tested on more then 100M of nodes)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-08-17 15:09:20 +01:00
Marco Costalba
05e70d6740 Unify undo_ep_move(m)
Integrate undo_ep_move in undo_move() this reduces line count
and code readibility.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-08-17 14:48:45 +01:00
Marco Costalba
b4cb1a3a9e Unify undo_promotion_move()
Integrate do_ep_move in undo_move() this reduces line count
and code readibility.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-08-17 14:48:33 +01:00
Marco Costalba
ec14fb1b33 Unify do_promotion_move()
Integrate do_promotion_move() in do_move() this reduces line count
and code readibility.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-08-17 14:48:20 +01:00
Marco Costalba
cb506d3b16 Unify do_ep_move()
Integrate do_ep_move in do_move() this reduces line count
and code readibility.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-08-17 14:47:12 +01:00
Marco Costalba
e0c47a6ceb L1/L2 friendly PhaseTable[]
In Movepicker c'tor we access during initialization one of
MainSearchPhaseIndex..QsearchWithoutChecksPhaseIndex globals.

Postpone definition of PhaseTable[] just after them so that
when PhaseTable[] will be accessed later in get_next_move()
it will be already present in L1/L2.

It works like an implicit prefetching of PhaseTable[].

Also shrink PhaseTable[] to fit an L1 cache line of 16 bytes
using uint8_t instead of int.

This apparentely innocuous patch gives an astonish speed
up of 1.6% under MSVC 2010 beta, pgo optimized !

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-08-15 16:09:10 +01:00
Marco Costalba
f3d0b76feb Use optimized pop_1st_bit() under Windows 64 with icc
Intel compiler can handle this code even under Windows.

So lift the costrain.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-08-14 12:47:49 +01:00
Marco Costalba
bfd4421f49 Better naming and document some endgame functions
In particular the generic scaling functions.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-08-14 08:19:55 +01:00
Marco Costalba
fd12e8cb23 Finally fix prefetch on Linux
It was due to a missing -msse compiler option !

Without this option the CPU silently discards
prefetcht2 instructions during execution.

Also added a (gcc documented) hack to prevent Intel
compiler to optimize away the prefetches.

Special thanks to Heinz for testing and suggesting
improvments. And for Jim for testing icc on Windows.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-08-14 08:13:42 +01:00
Marco Costalba
166c09a7a0 Reuse 5 slots instead of 4
But this time with the guarantee of an always aligned
access so that prefetching is not adversely impacted.

On Joona PC
1+0, 64Mb hash:

Orig - Mod: 174 - 237 - 359

Instead after 1000 games at 1+0 with 128MB hash size
we are at + 1 ELO (just 4 games of difference).

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-08-14 08:13:13 +01:00
Marco Costalba
8d369600ec Double prefetch on Windows
After fixing the cpu frequency with RightMark tool I was
able to test speed all the different prefetch combinations.

Here the results:

OS Windows Vista 32bit, MSVC compile
CPU Intecl Core 2 Duo T5220 1.55 GHz
bench on depth 12, 1 thread, 26552844 nodes searched
results in nodes/sec

no-prefetch
402486, 402005, 402767, 401439, 403060

single prefetch (aligned 64)
410145, 409159, 408078, 410443, 409652

double prefetch (aligned 64) 0+32
414739, 411238, 413937, 414641, 413834

double prefetch (aligned 64) 0+64
413537, 414337, 413537, 414842, 414240

And now also some crazy stuff:

single prefetch (aligned 128)
410145, 407395, 406230, 410050, 409949

double prefetch (aligned 64) 0+0
409753, 410044, 409456

single prefetch (aligned 64) +32
408379, 408272, 406809

single prefetch (aligned 64) +64
408279, 409059, 407395

So it seems the best is a double prefetch at the addres + 32 or +64,
I will choose the second one because it seems more natural to me.

It is still a mystery why it doesn't work under Linux :-(

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-08-10 22:35:08 +01:00
Marco Costalba
f4140ecc0c Avoid Intel compiler optimizes away prefetching
Without this hack Intel compiler happily optimizes
away the gcc builtin call.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-08-10 13:49:12 +01:00
Marco Costalba
60b5da4cc8 Use aligned prefetch address
Prefetch always form a chache line boundary. It seems
that if prefetch address is not cache line aligned then
performance is adversely impacted.

Hopefully we will resuse that 32 bits of padding for something
useful in the future.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-08-10 13:49:00 +01:00
Marco Costalba
55c46b2399 Remove old BishopPairBonus constants
Now that we have poly imbalance these ones
are no more used.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-08-10 13:47:39 +01:00
Marco Costalba
76ae0e36be Enable prefetch also for gcc
This fix a compile error under Linux with gcc when
there aren't the intel dev libraries.

Also simplify the previous patch moving TT definition
from search.cpp to tt.cpp so to avoid using passing a
pointer to TT to the current position.

Finally simplify do_move(), now we miss a prefetch in the
rare case of setting an en-passant square but code is
much cleaner and performance penalty is almost zero.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-08-10 01:42:35 +01:00
Marco Costalba
4251eac860 Try to prefetch as soon as position key is ready
Move prefetching code inside do_move() so to allow a
very early prefetching and to put as many instructions
as possible between prefetching and following retrieve().

With this patch retrieve() times are cutted of another 25%

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-08-09 16:45:37 +01:00
Marco Costalba
cd4604b05c Add TT prefetching support
TT.retrieve() is the most time consuming function
because almost always involves a very slow RAM access.

TT table is so big that is never cached. This patch
prefetches TT data just after a move is done, so that
subsequent TT.retrieve will be very  fast.

Profiling with VTune shows that TT:retrieve() times are
almost cutted in half !

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-08-09 14:18:15 +01:00
Marco Costalba
e6863f46de Use 5 TTEntry slots instead of 4
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-08-09 04:42:26 +01:00
Marco Costalba
6f1475b6fc Use 32 bit key in TT
Shrink key to 32 bits instead of 64. To still avoid
collisions use the high 32 bits of position key as the
TT key and the low 32 bits to retrieve the correct
cluster index in the table.

With this patch size og TTentry shrinks to 96 bits instead
of 128 and the cluster of 4 TTEntry sums to 48 bytes instead
of 64.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-08-09 04:42:07 +01:00
Marco Costalba
4a777954e1 Makefile: added 'make strip' target
Binaries are always built with symbol table in to easy
debugging and profiling.

It is now possible to run:

make strip

To remove symbol table from the compiled binary. This
could be useful to prepare the release version.

Patch by Heinz van Saanen.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-08-08 17:37:13 +01:00
Marco Costalba
54382f8b07 Let LMR at root be independent of MultiPV value
Current formula enable LMR when

i + MultiPV >= LMRPVMoves

It means that, for instance, if MultiPV == 1 then LMR
will be started to be considered at move i = LMRPVMoves - 1,
while if MultiPV == 3 then it will start before,
at move i = LMRPVMoves - 3.

With this patch the formula becomes

i >= MultiPV + LMRPVMoves - 2

So that LMR will always start after LMRPVMoves - 1 moves
from the last PV move.

No functional change when MultiPV == 1

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-08-08 17:30:46 +01:00
Marco Costalba
339bb8a524 Speed up polynomial material imbalance loop
Access pos.piece_count() only once and avoid some
branches in the inner loop.

Profiling with VTune shows a 20% speed improvement in
get_material_info(), and it is also a bit more cleaned
up this way ;-)

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-08-08 14:12:04 +01:00
Marco Costalba
aa925a0e29 There is no need to special case KNNK ending
It is always draw, so use the corresponding proper
evaluation function.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-08-08 13:10:10 +01:00
Marco Costalba
23ceb66950 Move halfOpenFiles[] calculation out of a loop
And put it in an already existing one so to
optimze a bit.

Also additional cleanups and code shuffles
all around the place.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-08-08 09:21:42 +01:00
Marco Costalba
565d12bf42 Compile without DEBUG flag by default
And build also symbol table. It can easily stripped
after .exe is done and it is necessary for profiling.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-08-08 09:21:29 +01:00
Marco Costalba
00eab73399 Revert material balance values after 100000 games
After Joona's direct testing with ~2000 games it seems
values after 100.000 games does not give any advantage,
so revert for now.

Score of Stockfish_0 vs Stockfish_15: 491 - 392 - 1102
Score of Stockfish_0 vs Stockfish_40: 461 - 439 - 1076
Score of Stockfish_0 vs Stockfish_65: 442 - 518 - 1018 (13 elo)
Score of Stockfish_0 vs Stockfish_100: 504 - 502 - 984

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-08-08 03:49:49 +01:00
Joona Kiiski
5be3d98d17 Do not adjust Minimum Split Depth automatically
Currently minimum split depth is set automatically to 6
when number of CPUs is more than 4. I believe this is a bad
idea since for example my quad (4CPU with hyperthreading) is
detected as 8CPU computer. I've manually lowered down the number
of Threads, but so far I have played all games with Minimum
Split Depth set to 6!

Since 4CPU computers with hyperthreading are quite common and
8 CPU computers extremely rear (I expect we can get a direct
jump to 16 or 32 cores), this automatic adjusting is likely
to do more harm than good. Add a note in Readme.txt, so that
those rear 8CPU owners can manually tweak the "Minimum Split
Depth" parameter

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-08-08 03:36:20 +01:00
Marco Costalba
5b3fcab1ad Polished Makefile for *nix
Greately improved Makefile from Heinz van Saanen

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-08-08 03:30:27 +01:00
Tord Romstad
977ca40d6d Supply the "upperbound" and "lowerbound" parameters in UCI search
output when the score is outside the root window.
2009-08-07 16:26:24 +02:00
Tord Romstad
ae49677446 Fixed a bug in PV extraction from the transposition table: The
previous used move_is_legal to verify that the move from the TT
was legal, and the old version of move_is_legal only works when
the side to move is not in check. Fixed this by adding a separate,
slower version of move_is_legal which works even when the side to
move is in check.
2009-08-06 18:07:32 +02:00
Tord Romstad
2fff532f4e Moved the code for extracting the PV from the TT to tt.cpp, where
it belongs.
2009-08-06 14:02:53 +02:00
Tord Romstad
da854fe83a Added a new function build_pv(), which extends a PV by walking
down the transposition table.

When the search was stopped before a fail high at the root was
resolved, Stockfish would often print a very short PV, sometimes
consisting of just a single move. This was not only a little
user-unfriendly, but also harmed the strength a little in
ponder-on games: Single-move PVs mean that there is no ponder
move to search.

It is perhaps worth considering to remove the pv[][] array
entirely, and always build the entire PV from the transposition
table. This would simplify the source code somewhat and probably
make the program infinitesimally faster, at the expense of
sometimes getting shorter PVs or PVs with rubbish moves near
the end.
2009-08-06 13:27:49 +02:00
Tord Romstad
a1096e55cf Initial work towards adjustable playing strength.
Added the UCI_LimitStrength and the UCI_Elo options, with an Elo
range of 2100-2900. When UCI_LimitStrength is enabled, the number
of threads is set to 1, and the search speed is slowed down according
to the chosen Elo level.

Todo:

1. Implement Elo levels below 2100 by blundering on purpose and/or
   crippling the evaluation.
2. Automatically calibrate the maximum Elo by measuring the CPU speed
   during program initialization, perhaps by doing some bitboard
   computations and measuring the time taken.

No functional change when UCI_LimitStrength is false (the default).
2009-08-04 11:31:25 +02:00
Tord Romstad
dad632ce5b Added LMR at the root.
After 2000 games at 1+0

Mod vs Orig +534 =1033 -433 52.525%  1050.5/2000  +18 ELO
2009-08-03 09:08:59 +02:00
Joona Kiiski
2f7723fd44 Remove useless mate value special handling in null search
After 1200 games (1CPU), time control 1+0:

Mod vs Orig: +331 =564 -277  +16 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-26 18:55:17 +01:00
Marco Costalba
152f3b13b7 Yet another small touch to endgame functions handling
It is like a never finished painting. Everyday a little touch
more.

But this time it is very little ;-)

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-26 17:42:48 +01:00
Marco Costalba
bb1b049b83 Remove unused members in Application class
Also rearrange a bit the remining methods.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-26 16:11:20 +01:00
Marco Costalba
50f92bed06 Fix a spurious extra space
This morning it seems there is nothing better to do...

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-26 09:07:42 +01:00
Marco Costalba
bdb586ac2b Micro optimize extension() in search.cpp
Small micro-optimization in this very
time critical function.

Use bitwise 'or' instead of logic 'or' to avoid branches
in the assembly and use the result to skip an handful of checks.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-25 16:48:28 +01:00
Marco Costalba
1b0303b6e9 Polynomial material balance after 100.000 games
Verified it is equivalent to the tuning branch results
with parameter values sampled after 100.000 games.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-24 14:26:49 +01:00
Marco Costalba
5f232e0667 Revert Makefile changes
Some unwanted changes to Makefile slept in in patch
"Introduced the UCI_AnalyseMode option".

Revert them. No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-24 14:18:03 +01:00
Marco Costalba
080a4995a3 Simplify king shelter cache handling
This is more similar to how get_material_info() and
get_pawn_info() work and also removes some clutter from
evaluate_king().

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-24 14:13:13 +01:00
Marco Costalba
20224a5bbf Delay costly SEE call during captures ordering in MovePicker
When ordering moves we push all captures with negative SEE values
to badCaptures[] array during the scoring phase.

This patch delays the costly SEE call up to when the move has been
picked up in pick_move_from_list(), this way we save some SEE calls
in case we get a cutoff.

It seems we have a speed gain of about 1-1.5 % in terms of nodes/sec
and profiling seems to confirm the small but real speed increase.

Idea from Pablo Vazquez on talkchess.com
http://www.talkchess.com/forum/viewtopic.php?t=29018&start=20

It would be a no functional change but actually it is not because
now sorting set is different and so std::sort(), that is not a
stable sort, does not guarantees the order of same scored moves to
remain the same as before.

After 952 games at 1+0 we are below error bar, almost equal just
6 games of difference (+2 ELO)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-24 14:12:33 +01:00
Marco Costalba
8654fee18c Microptimization in do_evaluate()
Do not call count_1s_max_15() if not necessary, as is
not in the common case (>95%).

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-23 22:01:42 +01:00
Marco Costalba
8b45b60327 Use do_move_bb() helpers when doing a castle
Small cleanup.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-23 10:43:58 +01:00
Marco Costalba
044ad593b3 Add Tord's polynomial material balance
Use a polynomial weighted evaluation to calculate
material value.

This is far more flexible and elegant then applying
a series of single euristic rules as before.

Also correct a design issue in which we returned two
values, one for middle game and one for endgame, while
instead, because game phase is a function of board
material itself, only one value should be calculated and
used both for mid and end game.

Verified it is equivalent to the tuning branch results with
parameter values sampled after 40.000 games.

After 999 games at 1+0

Mod vs Orig +277 =482 -240 51.85%  518.0/999  +13 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-23 00:03:30 +01:00
Marco Costalba
5600d91cff Rename int32 in int32_t
To use the same naming rule of the other types and
to be compatible with inttypes.h, used under Linux.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-20 10:53:41 +01:00
Marco Costalba
1cc44bcaae Correctly set mateThreat in search()
We do not accept null search returned mate values,
but we always do a full search in those cases.

So the variable mateThreat that is set only if null move
search returns a mate value is always false.

Restore the functionality of mateThreat moving the
assignement where it can be triggered.

After 999 games at 1+0

Mod vs Orig +253 =517 -229 51.20%  +8 ELO

Bug reported by xiaozhi

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-20 08:05:48 +01:00
Marco Costalba
15eb59683e Use increased LMR horizont also in PV search
Tord says that using a lower horizon at PV nodes
looks strange and inconsistent with the general
philosophy of our search (i.e. always being more
conservative at PV nodes). So set LMR at 3 also
on search_pv().

Test result after 601 games seems to confirm this.

Mod vs Orig +156 =318 -127 52.41%  315.0/601  +17 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-18 12:47:37 +02:00
Marco Costalba
620cfbb676 Reintroduce null move dynamic reduction
Test extension of LMR horizon to 3 plies alone, without
touching null move search. To keep the patch minimal we still
don't change LMR horizon in PV search. This will be the object
of the next patch.

Result seems good after 998 games:

Mod vs Orig  +252/=518/-228 51.20%  511.0/998 +8 ELO

So dynamic null move reduction seems a bit stronger then
fixed reduction even with LMR horizon set to 3.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-18 06:08:06 +01:00
Marco Costalba
fe523b2d18 Use increased LMR horizont only after a null move
Revert to LMR horizont of 2 plies. Only if parent move
is a null move increase to 3 so to avoid the bad combination
of null move reduction + LMR reduction. This is a more
aggressive patch then previous one, but it seems we are
going in the wromg direction.

After 531 games result is not good:

Mod vs Orig  +123/=265/-143 48.12%  255.5/531  -13 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-18 06:08:02 +01:00
Marco Costalba
2a203d8d6f Combine increased LMR horizont and fixed null move reduction
Set null move reduction to R=4, but increase the LMR horizon
to 3 plies. The two tweaks are related and should compensate
the combined effect of null move + LMR reduction at shallow
depths.

Idea from Tord.

After 999 games at 1+0

Mod vs Orig  +251 =522 -225 51.30% + 9 ELO

On Tord iMac Core 2 Duo 2.8 GHz, one thread,
Mac OS X 10.6, at 1+0 time control we have:

Mod vs Orig 994-1006  -1.4 ELO

But Orig version is pgo compiled and Mod is not.
The PGO compiled version is about 8% faster, which
corresponds to about 7 Elo points. This means that
results are reasonably consistent.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-18 06:07:58 +01:00
Tord Romstad
b8326edea3 Introduced the UCI_AnalyseMode option, and made the evaluation function
symmetrical in analyse mode.

No functional change when playing games.
2009-07-17 22:26:01 +02:00
Marco Costalba
20e8738901 Fix two compile errors in new endgame code
Code that compiles cleanly under MSVC triggers one
compile error (correct) under Intel C++ and two(!)
under gcc.

The first is the same complained by Intel, but the second
is an interesting corner case of C++ standard (there are many)
that is correctly spotted only by gcc.

Both MSVC and Intel pass this silently, probably to avoid
breaking people code.

Now we are fully C++ compliant ;-)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-17 19:29:25 +01:00
Marco Costalba
b3b1d3aaa7 Move constant bitboard arrays from header to cpp file
This avoid to duplicate storage allocation for every file
where they are used.

Note that simple numeric constant can remain in header because
are automatically folded by the compiler.

Patch suggested by Tord.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-17 16:25:53 +01:00
Marco Costalba
0d69ac33ff Remove even more redundancy in endgame functions handling
Push on the templatization even more to chip out some code
and take the opportunity to show some neat template trick ;-)

Ok. I would say we can stop here now....it is quickly becoming
a style exercise but we are not boost developers so give it a stop.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-17 16:05:19 +01:00
Tord Romstad
342c8c883c Removed an incorrect assert() statement in search.cpp, which asserted that
a static eval cached in the transposition table would always equal the static
eval of the current position. This is in general not true, because the cached
value could be from a previous search with different evaluation parameter
settings, or from a search from the opposite side (Stockfish's evaluation
function is assymmetric by default).
2009-07-17 09:12:59 +02:00
Marco Costalba
297c12e595 Simplify endgame functions handling
We really don't need to have global endgame functions. We can
allocate them on the heap at initialization time and store the
corresponding pointer directly in the functions maps. To avoid
leaks we just need to remember to deallocate them in map d'tor.

These functions are always created in couple, one for each color,
so remove a lot of redundant hard coded info and just use the minimum
required: the type and the corresponding named string.

This greatly simplifies the code and also it is less error prone,
now is much simpler to add a new endgame specialized function: just
add the corresponding enum in endgame.h and the obvious add_xx()
call in EndgameFunctions c'tor, and of course, the most important part,
the EvaluationFunction<xxx>::apply() specialization in endgame.cpp

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-17 07:55:51 +01:00
Tord Romstad
5c20f59788 Renamed the variable 'looseOnTime' to 'loseOnTime', because I'm a pedant.
No functional change.
2009-07-15 11:01:49 +02:00
Marco Costalba
ea06200423 Remove "Last seconds noise" filtering UCI option
This feature makes sense during development, but
It doesn't seem to make sense for normal users.

Also fix a possible race where the GUI adjudicates
the game a fraction of second before the engine sets
looseOnTime flag so that it will bogusly waits until
it ran out of time at the beginning of the next new game.

The fix is to always reset looseOnTime at the beginning
of a new game.

Race condition spotted by Tord.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-15 08:35:00 +01:00
Marco Costalba
3849beb979 Introduce SERIALIZE_MOVES_D() macro and use it for pawn moves
This is another moves serialization macro but this time
focused on pawn moves where the 'from' square is given as
a delta from the 'to' square.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-14 10:28:41 +01:00
Marco Costalba
20ed03fc0b Micro optimize pawn moves generation
It is very rare we have pawns on 7(2) rank, so we
can skip the promotion handling stuff in most cases.

With this patch pawn moves generation is almost 20% faster.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-14 10:28:29 +01:00
Marco Costalba
2a461b4b74 Introduce see_sign() and use it to shortcut full see()
Mostly of times we are interested only in the sign of SEE,
namely if a capture is negative or not.

If the capturing piece is smaller then the captured one we
already know SEE cannot be negative and this information
is enough most of the times. And of course it is much
faster to detect then a full SEE.

Note that in case see_sign() is negative then the returned
value is exactly the see() value, this is very important,
especially for ordering capturing moves.

With this patch the calls to the costly see() are reduced
of almost 30%.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-12 08:37:43 +01:00
Marco Costalba
6f39a3fc80 Move some global variables to local scope in search.cpp
Some variables were global due to some old and now removed code,
but now can be moved in local scope.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-12 08:37:43 +01:00
Marco Costalba
7eefc1f6cc Joona tweaks of Weights and limits
Verification test give unusless result

After 999 games at 1+0
Mod vs Orig +250 =503 -246 50.20% +1 ELO

So we are well below our radar level. Neverthless
there are 100.000 games on Joona QUAD that we could
take in account and that shows that this tweak perhaps
has something good in it, altough very little.

Verification tests shows should not be a regression, at
least not a big one even in the worst case, so apply the
change anyway and keep the finger crossed ;-)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-12 08:37:28 +01:00
Marco Costalba
7622793080 Small tidy up of previous patch
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-10 18:50:43 +01:00
Tord Romstad
174b40c28d Strip whitespace from beginning of string sent to set_option_value().
It turned out that the input sent to set_option_value() when it is called by
set_option() in uci.cpp always started with at least one whitespace. In most
cases, this is not a problem, because the majority of UCI options have numeric
values. It did, however, cause a problem for UCI options with non-numerical
values, like options of type CHECK and COMBO. In particular, changing the
value of an option of type CHECK didn't work, because the comparisons with
"true" and "false" would always return false. This means that the "Ponder"
and "UCI_Chess960" options haven't been working for a while.
2009-07-10 18:34:56 +02:00
Marco Costalba
03f524c591 Revert last tweaks
Tests show no improvment, so revert for now.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-09 16:45:39 +01:00
Marco Costalba
3444b94735 Joona tweaks of tempos and misc parameters
Unfortunatly this tweak does not give good results.

After 894 games at 1+0 we have:

Mod vs Orig  +205/-236/=453 48.27%  -12 ELO !!

Perhaps we should test again, but in the mean time
we are going to revert this.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-09 16:45:17 +01:00
Marco Costalba
2693db616d Restore development versioning and LSN filtering
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-06 11:20:05 +01:00
Marco Costalba
a5fce1958b Fix generation of check blocking promotion
A promotion move is not considered a possible evasion as it could be.

Bug introduced by patch

Convert also generate_pawn_blocking_evasions() to new API (7/5/2009)

Bug spotted by Kenny Dail.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-06 09:41:22 +01:00
Marco Costalba
67ac358ef2 Stockfish 1.4
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-04 21:57:12 +01:00
Marco Costalba
341f42be8c Small Makefile tweaks
Set gcc as default compiler on Linux, also compile
with symbols stripped to shrink binary file.

Original patch by Heinz van Saanen.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-04 21:56:59 +01:00
Marco Costalba
72ab2cd3e9 Fix bitcount.h compile warnings under Intel compiler
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-04 18:10:39 +01:00
Marco Costalba
92b625d04f Check Intel compiler before MSVC in bitcount.h
Predefined macro __INTEL_COMPILER is defined only for Intel,
while _MSC_VER is defined for both Intel C++ and MSVC.

So rearrange ifdefs to take in account this and test __INTEL_COMPILER
first and only if not defined check _MSC_VER for MSVC.

Patch suggested by Joona.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-04 18:03:49 +01:00
Marco Costalba
2b32571de8 Add support for saving timing file during benchmark
Add a new argument to bench to specify the name of the
file where timing information will be saved for each
benchmark session.

This argument is optional, if not specified file will
not be created.

Original patch by Heinz van Saanen

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-04 10:32:51 +01:00
Marco Costalba
36437f14e8 Disable POPCNT support per default
This is mainly intended to allow 64 bit compiles on any
system and avoid to crash when the binary, compiled on a
box where POPCNT is not supported, is run on a Core i7
system or similar CPU.

What could happen is that when compiled in a standard 64 bit
system, because the correct headers for the POPCNT intrinsic
are not found, the compiler creates dummy bit count functions
instead, these are never called at runtime on the machine where
Stockfish has been compiled. But if we run the same binary on a
Core i7 system, because POPCNT is detected at run time, the dummy
bitcount functions will be called giving false results that will
crash the application.

Note that would be possible to fallback on software bit count in
these cases, but this is even more subtle because POPCNT path is not
optimized so that we have an application working but at sub-optimal
speed, so better to crash, at least user is loudly warned that there
is something wrong.

If, instead, Stockfish is compiled on a Core i7 system with POPCNT
enabled, then if the PGO compile has been done properly, the same binary
will run at optimal speed _both_ on the Core i7 machine and on any other
64 bit standard machine. This is the ideal mode for binary distribution.

Finally this patch disables bsfq support under Windows, because it seems
inline assembly is not supported both by MSVC and by Intel Windows version.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-04 09:20:28 +01:00
Marco Costalba
08f3aac97c Do not compile POPCNT if NO_POPCNT is defined
Also rename DISABLE_POPCNT_SUPPORT in NO_POPCNT and simplify a bit
the macro logic.

Always define a __popcnt64()or _mm_popcnt_u64() template, if the proper
function with the same name is defined in the intrinsics header, then it
will be choosen as first otherwise we fall back on the dummy template
that is never called at runtime anyway because cpu_has_popcnt() returns
false.

This fixes the compile error reported by Jim.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-04 09:18:17 +01:00
Marco Costalba
48b0d41220 Microptimize pawns info access
Avoid indirect calling of piece_of_color_and_type(c, PAWN) and its
alias pawns(c) in the pawn evaluation loop, but use the pawns
bitboards accessed only once before entering the loop.

Also explicitly mark functions as static to better self-document.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-03 13:11:32 +01:00
Marco Costalba
5d79af9e0d Restore correct 64 bit version of pop_1st_bit()
Was erroneusly changed with the 32bit in recent
patch "Retire USE_COMPACT_ROOK_ATTACKS...".

Also another clean up of define magics. Move compiler
specific definitions in types.h and remove redundant cruft.

Now this macro ugly mess seems more reasonable.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-03 10:18:20 +02:00
Marco Costalba
a87ea9846d Use bsfq asm instruction to count bits
On 64 bit systems we can use bsfq instruction to count
set bits in a bitboard.

This is a patch for GCC and Intel compilers to take advantage
of that and get a 2% speed up.

Original patch from Heinz van Saanen, adapted to current tree
by me.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-03 10:18:14 +02:00
Marco Costalba
063e2441b1 Retire USE_COMPACT_ROOK_ATTACKS and USE_FOLDED_BITSCAN defines
This greatly simplifies bitboard.cpp that now has only two setups,
respectively for 32 and 64 bits CPU according to IS_64BIT define
that is automatically set but can be tweaked manually in
bitboard.h

No functional change both in 32 and in 64 bits.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-03 07:52:10 +01:00
Marco Costalba
b45936a8c7 Revert per-thread history tables
Testing on Joona QUAD failed to give any
advantage. Actually we had a little loss:

Mod - Orig: 342.0 - 374.0

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-02 06:29:25 +01:00
Marco Costalba
d39ddb9077 Joona tweaks of piece values
This is the backport of tuned piece values.

We needed to change also the psqt tables so that their
values, that are relative to piece values, remain the same.

Amost no change after 999 games:

Mod vs Orig 594-495 + 2 ELO points so well within error bar

It was expected somehow given the very little change of the
parameters values.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-02 06:29:14 +01:00
Marco Costalba
bbb2462576 Explicitly use delta psqt values when possible
Instead of add and subtract pqst values corrisponding to
the move starting and destination squares, do it in one
go with the helper function pst_delta<>()

This simplifies the code and also better documents that what
we need is a delta value, not an absolute one.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-28 06:30:13 +02:00
Marco Costalba
d9e3be4790 Joona tweaks of pawns parameters
Test result after 999 games at 1+0

Mod vs Orig +278 =493 -228 52,50% +17 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-26 10:17:47 +02:00
Marco Costalba
36c0ab3a50 Fix compile errors in debug mode
Fall out of move_promotion() rename

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-20 19:18:00 +01:00
Marco Costalba
ad4eac376f Use POPCNT in evaluate_space() when available
This was forgotten by the POCNT patches.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-20 14:45:11 +01:00
Marco Costalba
657286b0e5 Fix a couple of warnings under Intel compiler
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-20 14:45:03 +01:00
Marco Costalba
3a4d6e2034 Micro optimize and rename move_promotion()
Rename to move_is_promotion() to be more clear, also add
a new function move_promotion_piece() to get the
promotion piece type in the few places where is needed.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-20 09:04:32 +01:00
Marco Costalba
b1e79fed99 Only on Windows do wait for input at the end of benchmark
Under MS Visual C++ debug window always unconditionally closes
when program exits, this is bad because we want to read results before.

So limit this kludge on Windows only.

Original patch by Heinz van Saanen.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-20 09:04:20 +01:00
Marco Costalba
190f88e532 Skip castle rights update when not needed
Micro optimization in do_move(), a quick check
avoid us to update castle rights in almost 90%
of cases.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-18 17:23:35 +01:00
Joona Kiiski
8acb1d7e4d Disable use of aspiration window in known win positions
When we are hunting for mate, transposition table is filled in
with mate scores. Current implemenatation of aspiration search
can't cope with this very well.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-18 07:35:24 +01:00
Joona Kiiski
46c0bdb74f Bugfix: KRK was not classified as KNOWN_WIN
Problem is that npMaterial is compared to _endgame_ value
of rook, although npMaterial is always (also in endgame!)
calculated using _middlegame_ values.

Bug was hidden as long as Rook middlegame
and endgame values were same.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-18 07:35:24 +01:00
Marco Costalba
8225fdd5bb Give proper credit to Joona
Stockfish would not be as where is now without his
contributions.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-18 07:35:23 +01:00
Marco Costalba
e3c02d231a Joona tweaks of mobility and outposts bonus
These are the tuned values of mobility and outposts
after 100.000 games on Joona QUAD.

After 999 games at 1+0
Mod vs Orig +248 =537 -214 51.70% +12 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-18 07:35:08 +01:00
Marco Costalba
9847adf19f Fix king value in SEE
When SEE piece values changed in aaad48464b
of 9/12/2008 we forgot to update the value assigned in
case of captured king.

In that patch we changed the SEE piece values but without
proper testing. Probably it is a good idea to make some
tests with the old Glaurung values.

Bug spotted by Joona.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-16 19:22:22 +01:00
Marco Costalba
630fda2e2c Reduce SMP contention on TT
Move TT object away from heavy write accessed NodesSincePoll
and also, inside TT isolate the heavy accessed writes variable.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-13 11:13:09 +01:00
Marco Costalba
8bec65029d Better clarify why recent generate_pawn_checks() works
We can have false positives, but these are filtered out
anyhow by following conditions so they are harmless.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-12 13:12:42 +02:00
Marco Costalba
b5685fc564 Code style triviality in search.cpp
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-12 13:12:23 +02:00
Marco Costalba
d2c2af9e1c Remove global variables from search.h
Globals are not really needed, so redefine as locals.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-12 13:10:40 +02:00
Marco Costalba
3e0753bef3 MovePicker doesn't need to know if called from a pv node
This was needed by an old optimization in sorting of
non-captures that is now obsoleted by new std::sort()
approach.

Remove also the unused depth member data. Interestingly
this has always been unused since the Glaurung days.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-12 13:10:02 +02:00
Marco Costalba
c7843f2f79 Joona tweaks of piece-square tables
These are the tuned psqt values after 100.000 games
on Joona QUAD. Results seem very good.

On PC 1 after 999 games
Mod vs Orig  +261 =511 -227 51.70 %  +12 ELO

On PC 2 after 913 games
Mod vs Orig  +254 =448 -211 52.35 %  +16 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-12 13:00:18 +02:00
Marco Costalba
9005ea6339 Move initialization of PawnInfo in its c'tor
Where it belongs.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-08 12:53:38 +01:00
Marco Costalba
6d117e4a23 Move initialization of MaterialInfo in its c'tor
Where it belongs.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-08 11:27:50 +01:00
Marco Costalba
b8ab5d533b Micro optimize pretty_pv
Creating an History object requires clearing the History tables,
although fast is an useless job in san.cpp where History is used
just as a dummy argument for MovePicker c'tor.

So use a file scoped constant instead of creating a new History()
object each time MovePicker c'tor is called as in move_ambiguity()

This optimizes pretty_pv() through the following calling chain:
pretty_pv() -> line_to_san() -> move_to_san() -> move_ambiguity()

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-08 10:52:03 +01:00
Marco Costalba
bbd3e30b4e Give credit to Joona for optimized parameters
This also allow us to better track what is already
optimized and what still needs optimization.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-05 15:07:36 +01:00
Marco Costalba
e41602b721 Use a specialized function for king evaluation
King evaluation is special in any case and as an added
benefit we can use the HasPopCnt optimization also for king.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-05 15:07:26 +01:00
Marco Costalba
48c95706c8 Split evaluate_outposts from evaluate_common
This is an old patch, was part of a series, but is
good also alone as a cleanup.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-03 17:38:42 +01:00
Marco Costalba
2f760cdf8d Document variables with heavy SMP read access
Also move NodesSincePoll away from the same cache line
of other heavy read accessed only variables.

Fortunatly we don't have anymore write access contention,
but still read access contention in some cases.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-03 17:36:50 +01:00
Marco Costalba
b58ecb85c7 Retire UseQSearchFutilityPruning and UseFutilityPruning
They are always true anyway and are heavy used file scope
variables where there could be SMP contention. Although read only.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-03 17:35:56 +01:00
Marco Costalba
b4a04d8038 Use one History table per thread
This reduces contention and reduce history trashing
effect especially at high search depths.

No functional change for single CPU case.

After 999 games at 1+0 on Dual Core Intel we have

Mod vs Orig  +233 =526 -240  -2 ELO

We need to test at longer time controls and possibly with
a QUAD where we could foreseen an improvment.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-03 17:34:35 +01:00
Marco Costalba
c1b60269a2 Convert History table H in a local variable
This is a first step for future patches and in
any case seems a nice thing to do.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-02 09:57:15 +01:00
Marco Costalba
e1ed67aacb Avoid using EmptySearchStack global
This reduces contention in SMP case and also
cleanups the code a bit.

No functional change

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-02 09:35:49 +01:00
Marco Costalba
5b1316f7bb Detach the state when copying a position
In Position we store a pointer to a StateInfo record
kept outside of the Position object.

When copying a position we copy also that pointer so
after the copy we have two Position objects pointing
to the same StateInfo record. This can be dangerous
so fix by copying also the StateInfo record inside
the new Position object and let the new st pointer
point to it. This completely detach the copied
Position from the original one.

Also rename setStartState() as saveState() and clean up
the API to state more clearly what the function does.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-29 17:23:21 +02:00
Marco Costalba
bafb9f1a25 Order bad captures by SEE value
We have already calculated it, so just sorting the
moves adds a very little overhead.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-29 08:31:13 +02:00
Marco Costalba
738bf66a2d Passed pawns evaluation tweak
Do not penalize if in our adavncing pawn's path there are
non-pawns enemy pieces. Especially if they can be attacked
by us.

Patch is mine, but original idea and also fixing of a first, wrong,
version of the patch is from Eelco de Groot.

Tests with Joona framework seems to confirm patch is good

Results for patch 'disabled'   based on 5776 games: Win percentage:
41.309  (+- 0.526)  [+- 1.053]
Results for patch 'enabled'  based on 6400 games: Win percentage:
42.422  (+- 0.500)  [+- 1.000]

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-29 08:30:58 +02:00
Marco Costalba
3d0b60b065 Merge hardware POPCNT detection and use
Tests on Joona luxury iCore7 QUAD show that speed increase
against standrd 64bit routine is between 3% and 4%.

So it seems a good thing to have. Also the user feedback at
startup regarding the compile and the hardware detection can
be an useful debug tool.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-25 07:56:26 +01:00
Marco Costalba
bdb1bfecfb Split killer moves from non-captures
In MovePicker consider killer moves as a separate
phase from non-capture picking.

Note that this change guarantees that killer1 is always
tried before killer2. Until now, because scoring difference
of the two moves was just 1 point, if psqt tables of killer1
gave a lower value then killer2, the latter was tried as first.

After 999 games at 1+0 we have
Mod vs Orig: +245 =527 -227 +6 ELO

Not a lot but patch is anyhow something worth to have.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-25 07:49:50 +01:00
Marco Costalba
f1591447cf Revert _BitScanForward64 support
It shows almost no improvment and adds a good
bunch of complexity.

So remove for now. No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-25 07:28:55 +01:00
Marco Costalba
d63ff85a43 Add a bit more pop_1st_bit<HasBSF> conversions
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-24 10:25:59 +01:00
Marco Costalba
76024ac40e Use compiler name lookup to simplify code
We don't need different names between a function and a
template. Compiler will know when use one or the other.

This let use restore original count_1s_xx() names instead of
sw_count_1s_xxx so to simplify a bit the code.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-24 10:18:31 +01:00
Marco Costalba
6c9a64124a Enable _BitScanForward64 in move generation
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-24 10:07:03 +01:00
Marco Costalba
f90f810ac4 Enable _BitScanForward64 at runtime
Only add infrastructure, still disabled.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-24 09:46:43 +01:00
Marco Costalba
ce5d9eb19d Print info about use of 64bit functions and hardware POPCNT
With this patch at the applications startup a line is printed
with info about use of optimized 64 bit routines and hardware
POPCNT.

Also allow the possibility to disable POPCNT support during
PGO compiles to exercise the fallback software only path.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-23 16:12:26 +01:00
Marco Costalba
628f844c11 Fix compile errors under MSVC
Fallback from previous patches.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-21 17:08:34 +01:00
Marco Costalba
c729e4e1ab Forgot two conversion to new POPCNT interface
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-21 16:50:19 +02:00
Marco Costalba
0228ff9ca0 Add temporary debug info on POPCNT support
To be removed before to release.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-21 16:42:07 +02:00
Marco Costalba
e7d3a006cd Enable POPCNT at runtime
Runtime detect POPCNT instruction support and
use it.

Also if POPCNT is not supported we don't add _any_ overhead so
that we don't lose any speed in standard case.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-21 16:41:31 +02:00
Marco Costalba
3376c68f4b Introduce bitcount.h
It will be used for POPCNT intrinsics.

For now no bianry and functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-21 16:19:20 +02:00
Marco Costalba
1b0888708d Unify piece_attacks<> for KNIGHT and KING
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-21 12:15:52 +02:00
Marco Costalba
229274546f Use do_move_bb() also for en passant moves
Unfortunatly, due to Chess960 compatibility we cannot
extend also to castling where the destinations squares
are not guaranteed to be empty.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-21 11:28:51 +02:00
Marco Costalba
3e40bd0648 Introduce do_move_bb() to update bitboards after a move
Avoid a clear_bit() + set_bit() sequence but update bitboards
with only one xor instructions.

This is faster and simplifies the code.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-21 10:55:23 +02:00
Marco Costalba
595c7d75a2 Backup some mor einfo in do_null_move()
Faster undo_null_move()

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-21 09:54:48 +02:00
Marco Costalba
5603e25a7f Move npMaterial[2] to StateInfo in Position
So to have a bit faster undo_move() and also
a code semplification.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-21 09:47:03 +02:00
Marco Costalba
20c2a31464 Retire lastMove from Position class
Is not used in any way so remove.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-20 15:46:16 +02:00
Marco Costalba
d3c4618b3a Small code style in headers
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-20 15:11:41 +02:00
Marco Costalba
b98bcf858b Directly relate HistoryMax to OnePly
This obsoletes some remainding comments.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-20 14:43:17 +02:00
Marco Costalba
3b1e64ab72 Small code style massage in uci.cpp
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-20 12:40:07 +02:00
Marco Costalba
72ecd9e20d Space inflate and cleanup direction.cpp
Hopefully it is now more clear what's happening here.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-20 12:02:39 +02:00
Marco Costalba
25286e9932 Reduce history 4 times instead of 2 when reach the maximum
This gives more weight to newer entries.

After 999 games at 1'+ 0" we have:

Mod vs Orig +233/-208/=558 51.25% +9 ELO

Confirmed by another session of 437 games:

Mod vs Orig +109/-92/=236 51.95% +14 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-20 09:03:15 +02:00
Marco Costalba
4f7ec4128f Retire count_1s_8bit()
Use the plain array lookup in the only place where it
is used. This remove an unecessary indirection and better
clarifies what code does.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-19 15:49:54 +01:00
Marco Costalba
1e4472b651 Small code style triviality in evaluation
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-19 15:41:45 +01:00
Marco Costalba
da579e46b7 Remove hardcode default values of UCI variables from evaluation
This is the same change we have already done in search.cpp,
this time for evaluation.cpp

If a variable will be populated reading an UCI option
then do not hard code its default values.

This avoids misleadings when reading the sources.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-19 15:35:12 +01:00
Marco Costalba
f83b899f39 Cache king shelter info in pawns structure
It does not change often and is not so fast
to calculate.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-17 10:23:24 +01:00
Marco Costalba
a75aa6035b Move beta counter variables to the per-thread data
This should reduce concurrent accessing in SMP case.

Suggestion by Tord Romstad.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-16 12:25:35 +01:00
Marco Costalba
436fa5c8fa Better document how history works
Both with added comment and changing the API to
reflect that only destination square and moved piece
is important for history.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-16 12:06:54 +01:00
Marco Costalba
8df816f869 Fix broken multi-pv with aspiration window search
Aspiration window search must be disabled for
multi-pv case.

We missed one point where aspiration window should
be disabled in this case.

Patch from Joona, with a little added edit by me.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-15 17:48:18 +01:00
Marco Costalba
9c428afb6d Fix a warning un using anonymous structs
No functional and no binary change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-12 12:10:40 +02:00
Marco Costalba
27619830d4 Use string instead of std::string
And others small code style touches.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-10 18:38:47 +01:00
Marco Costalba
78eecbf6d7 Use 64 bits for debug counters
Has happened 32 bits were not enough for
some test.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-10 17:42:04 +01:00
Marco Costalba
980124c609 Fix some Intel compilers warnings
Also a compile fix due to Makefile missing new
application.cpp file.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-09 12:09:25 +02:00
Marco Costalba
5f7d37273c Micro optimize generate_pawn_checks()
Use a better condition to find candidate direct check pawns.
In particular consider only pawns in the front ranks of the
enemy king, this greatly reduces pawns candidates bitboard
that now is empty more then 90% of the time so that we
can early skip further tests.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-08 10:56:59 +02:00
Marco Costalba
be4ee0729d Convert also generate_pawn_blocking_evasions() to new API
New compact parameter passing API.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-07 17:08:55 +02:00
Marco Costalba
9fbe9af0a0 Better dscovery check condition in generate_pawn_checks()
Be more strict, is not enough dc bitboard is not empty, but
needs to inclde also at least one pawn.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-07 17:01:52 +02:00
Marco Costalba
1d15b38cd8 Further parametrize generate_pawn_captures
We can parametrize for the capture direction too.

Also use a single template parameter and calculate (at
compile time) remainin parameters directly in the function.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-07 16:41:36 +02:00
Marco Costalba
5c81602d14 Update copyright year
We are well in 2009 already.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-07 14:54:40 +02:00
Marco Costalba
a88e762b4e Rewrite the way application exits
Centralize in a single object all the global resources
management and avoid a bunch of sparse exit() calls.

This is more reliable and clean and more stick to C++ coding
practices.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-07 12:59:19 +02:00
Marco Costalba
2155fb7825 Be sure book file is closed before we leave
Move closing of file in Book destructor. This
guarantees us against leaving the file open under
any case and simplifies also Book use.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-07 09:27:38 +02:00
Marco Costalba
a03b8074c8 Rewrite Book implementation
Let Book be derived directly from std::ifstream
and rewrite the functions accordingly.

Also simplify file reading by use of operator>>()

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-06 19:28:17 +01:00
Marco Costalba
afadc33fb4 Space inflate book.cpp
Also document most interesting parts.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-06 12:19:20 +02:00
Marco Costalba
92ca97d121 Fix a couple of MSVC warnings
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-06 09:50:49 +02:00
Marco Costalba
da91fab8cb Micro optimize move_is_ep() and move_is_castle()
Avoid a shift operation moving it at compile time.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-05 15:12:23 +02:00
Marco Costalba
6176357ac1 Faster Position::move_is_capture() condition
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-05 14:55:48 +02:00
Marco Costalba
46bb6c6dc3 Fix missing pawn color check in move_is_legal()
In case we have a correct white pawn move but pawn
is black (or the contrary) we fail to detect the
move as illegal.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-05 13:10:29 +02:00
Marco Costalba
5c703b7526 Update makefile to use PGO with Intel C++ v11.0
Update profiler guided optimization instructions in
Makefile to the latest Intel C++ compiler.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-04 11:58:26 +02:00
Marco Costalba
412d68fe4f Micro optimize SEE
Use pieces_of_type() instead of pieces_of_color_and_type()
in an hot loop and cut of almost 10% SEE execution time.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-04 11:18:24 +02:00
Marco Costalba
9144e48eb6 Avoid an usless check in pl_move_is_legal
Although very cheap this is a very hot path,
so avoid it.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-03 08:15:55 +01:00
Marco Costalba
aabd526f7c Change TT interface to ask directly for a position key
Instead of a position because the key is all that we
need.

Interface is more clear and also very very little bit faster.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-03 08:11:36 +01:00
Marco Costalba
fdb2242d34 Setup to use Callgrind profiler
Disabled by default.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-03 08:11:24 +01:00
Marco Costalba
991ab2bea8 Restore development versioning and LSN filtering
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-03 08:11:07 +01:00
59 changed files with 6652 additions and 6499 deletions

View File

@@ -1,99 +1,90 @@
1. Introduction
---------------
Stockfish is a free UCI chess engine derived from Glaurung 2.1. It is
not a complete chess program, but requires some UCI compatible GUI
(like XBoard with PolyGlot, eboard, Jos<6F>, Arena, Sigma Chess, Shredder,
Chess Partner, or Fritz) in order to be used comfortably. Read the
documentation for your GUI of choice for information about how to use
Stockfish with your GUI.
This version of Stockfish supports up to 8 CPUs, but has not been
tested thoroughly with more than 2. The program tries to detect the
number of CPUs on your computer and set the number of search threads
accordingly, but please be aware that the detection is not always
correct. It is therefore recommended to inspect the value of the
"Threads" UCI parameter, and to make sure it equals the number of CPU
cores on your computer.
2. Files
--------
This distribution of Stockfish consists of the following files:
* Readme.txt, the file you are currently reading.
* Copying.txt, a text file containing the GNU General Public
License.
* src/, a subdirectory containing the full source code, including a
Makefile that can be used to compile Stockfish on Unix-like
systems. For further information about how to compile Stockfish
yourself, read section 4 below.
* polyglot.ini, for using Stockfish with Fabien Letouzey's PolyGlot
adapter.
3. Opening books
----------------
This version of Stockfish has experimental support for PolyGlot opening
books. For information about how to create such books, consult the
PolyGlot documentation. The book file can be selected by setting the
UCI parameter "Book File".
4. Compiling it yourself
------------------------
On Unix-like systems, it should usually be possible to compile
Stockfish directly from the source code with the included Makefile.
The exception is computer with big-endian CPUs, like PowerPC
Macintoshes. Some of the bitboard routines in the current version of
Stockfish are endianness-sensitive, and won't work on a big-endian CPU.
Ensuring that the line with #define USE_32BIT_ATTACKS" near the top
of bitboard.h is commented out should solve this problem.
Commenting out the line with "#define USE_32BIT_ATTACKS" near the
There is also a problem with compiling Stockfish on certain 64-bit
systems, regardless of the endianness. If Stockfish segfaults
immediately after startup, try to comment out the line with
"#define USE_FOLDED_BITSCAN" near the beginning of bitboard.h and
recompile.
Finally, even if Stockfish does work without any changes on your
computer, it might be possible to improve the performance by changing
some of the #define directives in bitboard.h. The default settings
are optimized for 64-bit CPUs. On 32-bit CPUs, it is probably better
to switch on USE_32BIT_ATTACKS, and to use BITCOUNT_SWAR_32 instead of
BITCOUNT_SWAR_64. For computers with very little memory (like
handheld devices), it is possible to conserve memory by defining
USE_COMPACT_ROOK_ATTACKS.
6. Terms of use
---------------
Stockfish is free, and distributed under the GNU General Public License
(GPL). Essentially, this means that you are free to do almost exactly
what you want with the program, including distributing it among your
friends, making it available for download from your web site, selling
it (either by itself or as part of some bigger software package), or
using it as the starting point for a software project of your own.
The only real limitation is that whenever you distribute Stockfish in
some way, you must always include the full source code, or a pointer
to where the source code can be found. If you make any changes to the
source code, these changes must also be made available under the GPL.
For full details, read the copy of the GPL found in the file named
Copying.txt.
7. Feedback
-----------
The author's e-mail address is mcostalba@gmail.com
1. Introduction
---------------
Stockfish is a free UCI chess engine derived from Glaurung 2.1. It is
not a complete chess program, but requires some UCI compatible GUI
(like XBoard with PolyGlot, eboard, Jos<6F>, Arena, Sigma Chess, Shredder,
Chess Partner, or Fritz) in order to be used comfortably. Read the
documentation for your GUI of choice for information about how to use
Stockfish with your GUI.
This version of Stockfish supports up to 8 CPUs, but has not been
tested thoroughly with more than 2. The program tries to detect the
number of CPUs on your computer and set the number of search threads
accordingly, but please be aware that the detection is not always
correct. It is therefore recommended to inspect the value of the
"Threads" UCI parameter, and to make sure it equals the number of CPU
cores on your computer. If you are using more than four threads, it
is recommended to raise the value of "Minimum Split Depth" UCI parameter
to 6.
2. Files
--------
This distribution of Stockfish consists of the following files:
* Readme.txt, the file you are currently reading.
* Copying.txt, a text file containing the GNU General Public
License.
* src/, a subdirectory containing the full source code, including a
Makefile that can be used to compile Stockfish on Unix-like
systems. For further information about how to compile Stockfish
yourself, read section 4 below.
* polyglot.ini, for using Stockfish with Fabien Letouzey's PolyGlot
adapter.
3. Opening books
----------------
This version of Stockfish has experimental support for PolyGlot opening
books. For information about how to create such books, consult the
PolyGlot documentation. The book file can be selected by setting the
UCI parameter "Book File".
4. Compiling it yourself
------------------------
On Unix-like systems, it should usually be possible to compile
Stockfish directly from the source code with the included Makefile.
For big-endian machines like Power PC you need to enable the proper
flag changing from -DNBIGENDIAN to -DBIGENDIAN in the Makefile.
Stockfish has POPCNT instruction runtime detection and support. This can
give an extra speed on Core i7 or similar systems. To enable this feature
compile with 'make icc-profile-popcnt'
On 64 bit Unix-like systems the 'bsfq' assembly instruction will be used
for bit counting. Detection is automatic at compile time, but in case you
experience compile problems you can comment out #define USE_BSFQ line in types.h
5. Terms of use
---------------
Stockfish is free, and distributed under the GNU General Public License
(GPL). Essentially, this means that you are free to do almost exactly
what you want with the program, including distributing it among your
friends, making it available for download from your web site, selling
it (either by itself or as part of some bigger software package), or
using it as the starting point for a software project of your own.
The only real limitation is that whenever you distribute Stockfish in
some way, you must always include the full source code, or a pointer
to where the source code can be found. If you make any changes to the
source code, these changes must also be made available under the GPL.
For full details, read the copy of the GPL found in the file named
Copying.txt.
6. Feedback
-----------
The author's e-mail address is mcostalba@gmail.com

View File

@@ -18,133 +18,318 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
###
### Files
###
### Executable name. Do not change
EXE = stockfish
OBJS = bitboard.o pawns.o material.o endgame.o evaluate.o main.o \
### Installation dir definitions
PREFIX = /usr/local
BINDIR = $(PREFIX)/bin
### ==========================================================================
### Compiler speed switches for both GCC and ICC. These settings are generally
### fast on a broad range of systems, but may be changed experimentally
### ==========================================================================
GCCFLAGS = -O3 -msse
ICCFLAGS = -fast -msse
ICCFLAGS-OSX = -fast -mdynamic-no-pic
### ==========================================================================
### Enable/disable debugging, disabled by default
### ==========================================================================
GCCFLAGS += -DNDEBUG
ICCFLAGS += -DNDEBUG
ICCFLAGS-OSX += -DNDEBUG
### ==========================================================================
### Remove below comments to compile for a big-endian machine
### ==========================================================================
#GCCFLAGS += -DBIGENDIAN
#ICCFLAGS += -DBIGENDIAN
#ICCFLAGS-OSX += -DBIGENDIAN
### ==========================================================================
### Run built-in benchmark for pgo-builds with: 32MB hash 1 thread 10 depth
### These settings are generally fast, but may be changed experimentally
### ==========================================================================
PGOBENCH = ./$(EXE) bench 32 1 10 default depth
### General compiler settings. Do not change
GCCFLAGS += -g -Wall -fno-exceptions -fno-rtti
ICCFLAGS += -g -Wall -fno-exceptions -fno-rtti -wd383,869,981,10187,10188,11505,11503
ICCFLAGS-OSX += -g -Wall -fno-exceptions -fno-rtti -wd383,869,981,10187,10188,11505,11503
### General linker settings. Do not change
LDFLAGS = -lpthread
### Object files. Do not change
OBJS = application.o bitboard.o pawns.o material.o endgame.o evaluate.o main.o \
misc.o move.o movegen.o history.o movepick.o search.o piece.o \
position.o direction.o tt.o value.o uci.o ucioption.o \
mersenne.o book.o bitbase.o san.o benchmark.o
###
### Rules
###
### General rules. Do not change
default:
$(MAKE) gcc
help:
@echo ""
@echo "Makefile options:"
@echo ""
@echo "make > Default: Compiler = g++"
@echo "make gcc-popcnt > Compiler = g++ + popcnt-support"
@echo "make icc > Compiler = icpc"
@echo "make icc-profile > Compiler = icpc + automatic pgo-build"
@echo "make icc-profile-popcnt > Compiler = icpc + automatic pgo-build + popcnt-support"
@echo "make osx-ppc32 > PPC-Mac OS X 32 bit. Compiler = g++"
@echo "make osx-ppc64 > PPC-Mac OS X 64 bit. Compiler = g++"
@echo "make osx-x86 > x86-Mac OS X 32 bit. Compiler = g++"
@echo "make osx-x86_64 > x86-Mac OS X 64 bit. Compiler = g++"
@echo "make osx-icc32 > x86-Mac OS X 32 bit. Compiler = icpc"
@echo "make osx-icc64 > x86-Mac OS X 64 bit. Compiler = icpc"
@echo "make osx-icc32-profile > OSX 32 bit. Compiler = icpc + automatic pgo-build"
@echo "make osx-icc64-profile > OSX 64 bit. Compiler = icpc + automatic pgo-build"
@echo "make hpux > HP-UX. Compiler = aCC"
@echo "make strip > Strip executable"
@echo "make clean > Clean up"
@echo ""
all: $(EXE) .depend
test check: default
@$(PGOBENCH)
clean:
$(RM) *.o .depend stockfish
$(RM) *.o .depend *~ $(EXE) core bench.txt
###
### Compiler:
###
### Possible targets. You may add your own ones here
gcc:
$(MAKE) \
CXX='g++' \
CXXFLAGS="$(GCCFLAGS)" \
all
# CXX = g++
# CXX = g++-4.2
CXX = icpc
gcc-popcnt:
$(MAKE) \
CXX='g++' \
CXXFLAGS="$(GCCFLAGS) -DUSE_POPCNT" \
all
###
### Dependencies
###
icc:
$(MAKE) \
CXX='icpc' \
CXXFLAGS="$(ICCFLAGS)" \
all
icc-profile-make:
$(MAKE) \
CXX='icpc' \
CXXFLAGS="$(ICCFLAGS)" \
CXXFLAGS+='-prof-gen=srcpos -prof_dir ./profdir' \
all
icc-profile-use:
$(MAKE) \
CXX='icpc' \
CXXFLAGS="$(ICCFLAGS)" \
CXXFLAGS+='-prof_use -prof_dir ./profdir' \
all
icc-profile:
@rm -rf profdir
@mkdir profdir
@touch *.cpp *.h
$(MAKE) icc-profile-make
@echo ""
@echo "Running benchmark for pgo-build ..."
@$(PGOBENCH) > /dev/null
@echo "Benchmark finished. Build final executable now ..."
@echo ""
@touch *.cpp *.h
$(MAKE) icc-profile-use
@rm -rf profdir bench.txt
icc-profile-make-with-popcnt:
$(MAKE) \
CXX='icpc' \
CXXFLAGS="$(ICCFLAGS) -DUSE_POPCNT" \
CXXFLAGS+='-prof-gen=srcpos -prof_dir ./profdir' \
all
icc-profile-use-with-popcnt:
$(MAKE) \
CXX='icpc' \
CXXFLAGS="$(ICCFLAGS) -DUSE_POPCNT" \
CXXFLAGS+='-prof_use -prof_dir ./profdir' \
all
icc-profile-popcnt:
@rm -rf profdir
@mkdir profdir
@touch *.cpp *.h
$(MAKE) icc-profile-make
@echo ""
@echo "Running benchmark for pgo-build (popcnt disabled)..."
@$(PGOBENCH) > /dev/null
@touch *.cpp *.h
$(MAKE) icc-profile-make-with-popcnt
@echo ""
@echo "Running benchmark for pgo-build (popcnt enabled)..."
@$(PGOBENCH) > /dev/null
@echo "Benchmarks finished. Build final executable now ..."
@echo ""
@touch *.cpp *.h
$(MAKE) icc-profile-use-with-popcnt
@rm -rf profdir bench.txt
osx-ppc32:
$(MAKE) \
CXX='g++' \
CXXFLAGS="$(GCCFLAGS)" \
CXXFLAGS+='-arch ppc' \
CXXFLAGS+='-DBIGENDIAN' \
LDFLAGS+='-arch ppc' \
all
osx-ppc64:
$(MAKE) \
CXX='g++' \
CXXFLAGS="$(GCCFLAGS)" \
CXXFLAGS+='-arch ppc64' \
CXXFLAGS+='-DBIGENDIAN' \
LDFLAGS+='-arch ppc64' \
all
osx-x86:
$(MAKE) \
CXX='g++' \
CXXFLAGS="$(GCCFLAGS)" \
CXXFLAGS+='-arch i386 -mdynamic-no-pic' \
LDFLAGS+='-arch i386 -mdynamic-no-pic' \
all
osx-x86_64:
$(MAKE) \
CXX='g++' \
CXXFLAGS="$(GCCFLAGS)" \
CXXFLAGS+='-arch x86_64 -mdynamic-no-pic' \
LDFLAGS+='-arch x86_64 -mdynamic-no-pic' \
all
osx-icc32:
$(MAKE) \
CXX='icpc' \
CXXFLAGS="$(ICCFLAGS-OSX)" \
CXXFLAGS+='-arch i386' \
LDFLAGS+='-arch i386' \
all
osx-icc64:
$(MAKE) \
CXX='icpc' \
CXXFLAGS="$(ICCFLAGS-OSX)" \
CXXFLAGS+='-arch x86_64' \
LDFLAGS+='-arch x86_64' \
all
osx-icc32-profile-make:
$(MAKE) \
CXX='icpc' \
CXXFLAGS="$(ICCFLAGS-OSX)" \
CXXFLAGS+='-arch i386' \
CXXFLAGS+='-prof_gen -prof_dir ./profdir' \
LDFLAGS+='-arch i386' \
all
osx-icc32-profile-use:
$(MAKE) \
CXX='icpc' \
CXXFLAGS="$(ICCFLAGS-OSX)" \
CXXFLAGS+='-arch i386' \
CXXFLAGS+='-prof_use -prof_dir ./profdir' \
LDFLAGS+='-arch i386' \
all
osx-icc32-profile:
@rm -rf profdir
@mkdir profdir
@touch *.cpp *.h
$(MAKE) osx-icc32-profile-make
@echo ""
@echo "Running benchmark for pgo-build ..."
@$(PGOBENCH) > /dev/null
@echo "Benchmark finished. Build final executable now ..."
@echo ""
@touch *.cpp *.h
$(MAKE) osx-icc32-profile-use
@rm -rf profdir bench.txt
osx-icc64-profile-make:
$(MAKE) \
CXX='icpc' \
CXXFLAGS="$(ICCFLAGS-OSX)" \
CXXFLAGS+='-arch x86_64' \
CXXFLAGS+='-prof_gen -prof_dir ./profdir' \
LDFLAGS+='-arch x86_64' \
all
osx-icc64-profile-use:
$(MAKE) \
CXX='icpc' \
CXXFLAGS="$(ICCFLAGS-OSX)" \
CXXFLAGS+='-arch x86_64' \
CXXFLAGS+='-prof_use -prof_dir ./profdir' \
LDFLAGS+='-arch x86_64' \
all
osx-icc64-profile:
@rm -rf profdir
@mkdir profdir
@touch *.cpp *.h
$(MAKE) osx-icc64-profile-make
@echo ""
@echo "Running benchmark for pgo-build ..."
@$(PGOBENCH) > /dev/null
@echo "Benchmark finished. Build final executable now ..."
@echo ""
@touch *.cpp *.h
$(MAKE) osx-icc64-profile-use
@rm -rf profdir bench.txt
hpux:
$(MAKE) \
CXX='/opt/aCC/bin/aCC -AA +hpxstd98 -DBIGENDIAN -mt +O3 -DNDEBUG' \
CXXFLAGS="" \
LDFLAGS="" \
all
strip:
strip $(EXE)
### Compilation. Do not change
$(EXE): $(OBJS)
$(CXX) $(LDFLAGS) -o $@ $(OBJS)
### Installation
install: default
-mkdir -p -m 755 $(BINDIR)
-cp $(EXE) $(BINDIR)
-strip $(BINDIR)/$(EXE)
### Dependencies. Do not change
.depend:
$(CXX) -MM $(OBJS:.o=.cpp) > $@
-@$(CXX) -msse -MM $(OBJS:.o=.cpp) > $@ 2> /dev/null
include .depend
###
### Compiler and linker switches
###
# Enable/disable debugging:
CXXFLAGS += -DNDEBUG
# Compile with full warnings, and symbol names
CXXFLAGS += -Wall -g
# General optimization flags. Note that -O2 might be faster than -O3 on some
# systems; this requires testing.
CXXFLAGS += -O3 -fno-exceptions -fomit-frame-pointer -fno-rtti -fno-strict-aliasing
# Disable most annoying warnings for the Intel C++ compiler
CXXFLAGS += -wd383,869,981
# Compiler optimization flags for the Intel C++ compiler in Mac OS X:
# CXXFLAGS += -mdynamic-no-pic -no-prec-div -ipo -static -xP
# Profiler guided optimization with the Intel C++ compiler. To use it, first
# create the directory ./profdata if it does not already exist, and delete its
# contents if it does exist. Then compile with -prof_gen, and run the
# resulting binary for a while (for instance, do ./stockfish bench 128 1, and
# wait 15 minutes for the benchmark to complete). Then do a 'make clean', and
# recompile with -prof_use.
# CXXFLAGS += -prof_gen -prof_dir profdata
# CXXFLAGS += -prof_use -prof_dir ./profdata
# Profiler guided optimization with GCC. I've never been able to make this
# work.
# CXXFLAGS += -fprofile-generate
# LDFLAGS += -fprofile-generate
# CXXFLAGS += -fprofile-use
# CXXFLAGS += -fprofile-use
# General linker flags
LDFLAGS += -lm -lpthread
# Compiler switches for generating binaries for various CPUs in Mac OS X.
# Note that 'arch ppc' and 'arch ppc64' only works with g++, and not with
# the intel compiler.
# CXXFLAGS += -arch ppc
# CXXFLAGS += -arch ppc64
# CXXFLAGS += -arch i386
# CXXFLAGS += -arch x86_64
# LDFLAGS += -arch ppc
# LDFLAGS += -arch ppc64
# LDFLAGS += -arch i386
# LDFLAGS += -arch x86_64
# Backwards compatibility with Mac OS X 10.4 when compiling under 10.5 with
# GCC 4.0. I haven't found a way to make it work with GCC 4.2.
# CXXFLAGS += -isysroot /Developer/SDKs/MacOSX10.4u.sdk
# CXXFLAGS += -mmacosx-version-min=10.4
# LDFLAGS += -isysroot /Developer/SDKs/MacOSX10.4u.sdk
# LDFLAGS += -Wl,-syslibroot /Developer/SDKs/MacOSX10.4u.sdk
# LDFLAGS += -mmacosx-version-min=10.4
# Backwards compatibility with Mac OS X 10.4 when compiling with ICC. Doesn't
# work yet. :-(
# CXXFLAGS += -DMAC_OS_X_VERSION_MIN_REQUIRED=1040
# CXXFLAGS += -DMAC_OS_X_VERSION_MAX_ALLOWED=1040
# CXXFLAGS += -D__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__=1040
# CXXFLAGS += -F/Developer/SDKs/MacOSX10.4u.sdk/
# LDFLAGS += -Wl,-syslibroot -Wl,/Developer/SDKs/MacOSX10.4u.sdk
-include .depend

76
src/application.cpp Normal file
View File

@@ -0,0 +1,76 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 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/>.
*/
////
//// Includes
////
#include "bitboard.h"
#include "direction.h"
#include "endgame.h"
#include "evaluate.h"
#include "material.h"
#include "mersenne.h"
#include "misc.h"
#include "movepick.h"
#include "position.h"
#include "search.h"
#include "thread.h"
#include "ucioption.h"
/// Application class is in charge of initializing global resources
/// at startup and cleanly releases them when program terminates.
Application::Application() {
init_mersenne();
init_direction_table();
init_bitboards();
init_uci_options();
Position::init_zobrist();
Position::init_piece_square_tables();
init_eval(1);
init_bitbases();
init_search();
init_threads();
// Make random number generation less deterministic, for book moves
for (int i = abs(get_system_time() % 10000); i > 0; i--)
genrand_int32();
}
Application::~Application() {
exit_threads();
quit_eval();
}
void Application::initialize() {
// A static Application object is allocated
// once only when this function is called.
static Application singleton;
}
void Application::exit_with_failure() {
exit(EXIT_FAILURE); // d'tor will be called automatically
}

39
src/application.h Normal file
View File

@@ -0,0 +1,39 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Stockfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined(APPLICATION_H_INCLUDED)
#define APPLICATION_H_INCLUDED
/// Singleton class used to housekeep memory and global resources
/// so to be sure we always leave in a clean state.
class Application {
Application();
Application(const Application&);
~Application();
public:
static void initialize();
static void exit_with_failure();
};
#endif // !defined(APPLICATION_H_INCLUDED)

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2010 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
@@ -30,12 +30,13 @@
#include "thread.h"
#include "ucioption.h"
using namespace std;
////
//// Variables
////
const std::string BenchmarkPositions[] = {
const string BenchmarkPositions[] = {
"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1",
"r4rk1/1b2qppp/p1n1p3/1p6/1b1PN3/3BRN2/PP3PPP/R2Q2K1 b - - 7 16",
"4r1k1/ppq3pp/3b4/2pP4/2Q1p3/4B1P1/PP5P/R5K1 b - - 0 20",
@@ -67,27 +68,26 @@ const std::string BenchmarkPositions[] = {
/// format (default are the BenchmarkPositions defined above).
/// The analysis is written to a file named bench.txt.
void benchmark(const std::string& commandLine) {
void benchmark(const string& commandLine) {
std::istringstream csVal(commandLine);
std::istringstream csStr(commandLine);
std::string ttSize, threads, fileName, limitType;
istringstream csVal(commandLine);
istringstream csStr(commandLine);
string ttSize, threads, fileName, limitType, timFile;
int val, secsPerPos, maxDepth, maxNodes;
csStr >> ttSize;
csVal >> val;
if (val < 4 || val > 1024)
{
std::cerr << "The hash table size must be between 4 and 1024" << std::endl;
exit(EXIT_FAILURE);
cerr << "The hash table size must be between 4 and 1024" << endl;
Application::exit_with_failure();
}
csStr >> threads;
csVal >> val;
if (val < 1 || val > THREAD_MAX)
if (val < 1 || val > MAX_THREADS)
{
std::cerr << "The number of threads must be between 1 and " << THREAD_MAX
<< std::endl;
exit(EXIT_FAILURE);
cerr << "The number of threads must be between 1 and " << MAX_THREADS << endl;
Application::exit_with_failure();
}
set_option_value("Hash", ttSize);
set_option_value("Threads", threads);
@@ -98,54 +98,84 @@ void benchmark(const std::string& commandLine) {
csVal >> val;
csVal >> fileName;
csVal >> limitType;
csVal >> timFile;
secsPerPos = maxDepth = maxNodes = 0;
if (limitType == "time")
secsPerPos = val * 1000;
else if (limitType == "depth")
else if (limitType == "depth" || limitType == "perft")
maxDepth = val;
else
maxNodes = val;
std::vector<std::string> positions;
vector<string> positions;
if (fileName != "default")
{
std::ifstream fenFile(fileName.c_str());
ifstream fenFile(fileName.c_str());
if (!fenFile.is_open())
{
std::cerr << "Unable to open positions file " << fileName
<< std::endl;
exit(EXIT_FAILURE);
cerr << "Unable to open positions file " << fileName << endl;
Application::exit_with_failure();
}
std::string pos;
string pos;
while (fenFile.good())
{
std::getline(fenFile, pos);
getline(fenFile, pos);
if (!pos.empty())
positions.push_back(pos);
}
fenFile.close();
} else
for (int i = 0; i < 16; i++)
positions.push_back(std::string(BenchmarkPositions[i]));
positions.push_back(string(BenchmarkPositions[i]));
int startTime = get_system_time();
std::vector<std::string>::iterator it;
ofstream timingFile;
if (!timFile.empty())
{
timingFile.open(timFile.c_str(), ios::out | ios::app);
if (!timingFile.is_open())
{
cerr << "Unable to open timing file " << timFile << endl;
Application::exit_with_failure();
}
}
vector<string>::iterator it;
int cnt = 1;
int64_t totalNodes = 0;
int startTime = get_system_time();
for (it = positions.begin(); it != positions.end(); ++it, ++cnt)
{
Move moves[1] = {MOVE_NONE};
int dummy[2] = {0, 0};
Position pos(*it);
std::cout << "\nProcessing position " << cnt << '/' << positions.size() << std::endl << std::endl;
think(pos, true, false, 0, dummy, dummy, 0, maxDepth, maxNodes, secsPerPos, moves);
cerr << "\nBench position: " << cnt << '/' << positions.size() << endl << endl;
if (limitType == "perft")
totalNodes += perft(pos, maxDepth * OnePly);
else if (!think(pos, false, false, 0, dummy, dummy, 0, maxDepth, maxNodes, secsPerPos, moves))
break;
totalNodes += nodes_searched();
}
std::cout << "\nProcessing time (ms) " << get_system_time() - startTime << std::endl
<< "Nodes searched " << totalNodes << std::endl
<< "Press any key to exit" << std::endl;
std::cin >> fileName;
cnt = get_system_time() - startTime;
cerr << "==============================="
<< "\nTotal time (ms) : " << cnt
<< "\nNodes searched : " << totalNodes
<< "\nNodes/second : " << (int)(totalNodes/(cnt/1000.0)) << endl << endl;
if (!timFile.empty())
{
timingFile << cnt << endl << endl;
timingFile.close();
}
// Under MS Visual C++ debug window always unconditionally closes
// when program exits, this is bad because we want to read results before.
#if (defined(WINDOWS) || defined(WIN32) || defined(WIN64))
cerr << "Press any key to exit" << endl;
cin >> fileName;
#endif
}

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2010 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

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2010 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

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2010 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

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2010 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
@@ -22,137 +22,14 @@
//// Includes
////
#ifdef _MSC_VER
#include <intrin.h>
#ifdef _WIN64
#pragma intrinsic(_BitScanForward64)
#else
#pragma intrinsic(_BitScanForward)
#endif
#define USING_INTRINSICS
#endif
#include <iostream>
#include "bitboard.h"
#include "bitcount.h"
#include "direction.h"
#if defined(USE_COMPACT_ROOK_ATTACKS)
Bitboard RankAttacks[8][64], FileAttacks[8][64];
#elif defined(USE_32BIT_ATTACKS)
const uint64_t RMult[64] = {
0xd7445cdec88002c0ULL, 0xd0a505c1f2001722ULL, 0xe065d1c896002182ULL,
0x9a8c41e75a000892ULL, 0x8900b10c89002aa8ULL, 0x9b28d1c1d60005a2ULL,
0x15d6c88de002d9aULL, 0xb1dbfc802e8016a9ULL, 0x149a1042d9d60029ULL,
0xb9c08050599e002fULL, 0x132208c3af300403ULL, 0xc1000ce2e9c50070ULL,
0x9d9aa13c99020012ULL, 0xb6b078daf71e0046ULL, 0x9d880182fb6e002eULL,
0x52889f467e850037ULL, 0xda6dc008d19a8480ULL, 0x468286034f902420ULL,
0x7140ac09dc54c020ULL, 0xd76ffffa39548808ULL, 0xea901c4141500808ULL,
0xc91004093f953a02ULL, 0x2882afa8f6bb402ULL, 0xaebe335692442c01ULL,
0xe904a22079fb91eULL, 0x13a514851055f606ULL, 0x76c782018c8fe632ULL,
0x1dc012a9d116da06ULL, 0x3c9e0037264fffa6ULL, 0x2036002853c6e4a2ULL,
0xe3fe08500afb47d4ULL, 0xf38af25c86b025c2ULL, 0xc0800e2182cf9a40ULL,
0x72002480d1f60673ULL, 0x2500200bae6e9b53ULL, 0xc60018c1eefca252ULL,
0x600590473e3608aULL, 0x46002c4ab3fe51b2ULL, 0xa200011486bcc8d2ULL,
0xb680078095784c63ULL, 0x2742002639bf11aeULL, 0xc7d60021a5bdb142ULL,
0xc8c04016bb83d820ULL, 0xbd520028123b4842ULL, 0x9d1600344ac2a832ULL,
0x6a808005631c8a05ULL, 0x604600a148d5389aULL, 0xe2e40103d40dea65ULL,
0x945b5a0087c62a81ULL, 0x12dc200cd82d28eULL, 0x2431c600b5f9ef76ULL,
0xfb142a006a9b314aULL, 0x6870e00a1c97d62ULL, 0x2a9db2004a2689a2ULL,
0xd3594600caf5d1a2ULL, 0xee0e4900439344a7ULL, 0x89c4d266ca25007aULL,
0x3e0013a2743f97e3ULL, 0x180e31a0431378aULL, 0x3a9e465a4d42a512ULL,
0x98d0a11a0c0d9cc2ULL, 0x8e711c1aba19b01eULL, 0x8dcdc836dd201142ULL,
0x5ac08a4735370479ULL,
};
const int RShift[64] = {
20, 21, 21, 21, 21, 21, 21, 20, 21, 22, 22, 22, 22, 22, 22, 21,
21, 22, 22, 22, 22, 22, 22, 21, 21, 22, 22, 22, 22, 22, 22, 21,
21, 22, 22, 22, 22, 22, 22, 21, 21, 22, 22, 22, 22, 22, 22, 21,
21, 22, 22, 22, 22, 22, 22, 21, 20, 21, 21, 21, 21, 21, 21, 20
};
#else // if defined(USE_32BIT_ATTACKS)
const uint64_t RMult[64] = {
0xa8002c000108020ULL, 0x4440200140003000ULL, 0x8080200010011880ULL,
0x380180080141000ULL, 0x1a00060008211044ULL, 0x410001000a0c0008ULL,
0x9500060004008100ULL, 0x100024284a20700ULL, 0x802140008000ULL,
0x80c01002a00840ULL, 0x402004282011020ULL, 0x9862000820420050ULL,
0x1001448011100ULL, 0x6432800200800400ULL, 0x40100010002000cULL,
0x2800d0010c080ULL, 0x90c0008000803042ULL, 0x4010004000200041ULL,
0x3010010200040ULL, 0xa40828028001000ULL, 0x123010008000430ULL,
0x24008004020080ULL, 0x60040001104802ULL, 0x582200028400d1ULL,
0x4000802080044000ULL, 0x408208200420308ULL, 0x610038080102000ULL,
0x3601000900100020ULL, 0x80080040180ULL, 0xc2020080040080ULL,
0x80084400100102ULL, 0x4022408200014401ULL, 0x40052040800082ULL,
0xb08200280804000ULL, 0x8a80a008801000ULL, 0x4000480080801000ULL,
0x911808800801401ULL, 0x822a003002001894ULL, 0x401068091400108aULL,
0x4a10a00004cULL, 0x2000800640008024ULL, 0x1486408102020020ULL,
0x100a000d50041ULL, 0x810050020b0020ULL, 0x204000800808004ULL,
0x20048100a000cULL, 0x112000831020004ULL, 0x9000040810002ULL,
0x440490200208200ULL, 0x8910401000200040ULL, 0x6404200050008480ULL,
0x4b824a2010010100ULL, 0x4080801810c0080ULL, 0x400802a0080ULL,
0x8224080110026400ULL, 0x40002c4104088200ULL, 0x1002100104a0282ULL,
0x1208400811048021ULL, 0x3201014a40d02001ULL, 0x5100019200501ULL,
0x101000208001005ULL, 0x2008450080702ULL, 0x1002080301d00cULL,
0x410201ce5c030092ULL
};
const int RShift[64] = {
52, 53, 53, 53, 53, 53, 53, 52, 53, 54, 54, 54, 54, 54, 54, 53,
53, 54, 54, 54, 54, 54, 54, 53, 53, 54, 54, 54, 54, 54, 54, 53,
53, 54, 54, 54, 54, 54, 54, 53, 53, 54, 54, 54, 54, 54, 54, 53,
53, 54, 54, 54, 54, 54, 54, 53, 52, 53, 53, 53, 53, 53, 53, 52
};
#endif // defined(USE_32BIT_ATTACKS)
#if !defined(USE_COMPACT_ROOK_ATTACKS)
Bitboard RMask[64];
int RAttackIndex[64];
Bitboard RAttacks[0x19000];
#endif
#if defined(USE_32BIT_ATTACKS)
const uint64_t BMult[64] = {
0x54142844c6a22981ULL, 0x710358a6ea25c19eULL, 0x704f746d63a4a8dcULL,
0xbfed1a0b80f838c5ULL, 0x90561d5631e62110ULL, 0x2804260376e60944ULL,
0x84a656409aa76871ULL, 0xf0267f64c28b6197ULL, 0x70764ebb762f0585ULL,
0x92aa09e0cfe161deULL, 0x41ee1f6bb266f60eULL, 0xddcbf04f6039c444ULL,
0x5a3fab7bac0d988aULL, 0xd3727877fa4eaa03ULL, 0xd988402d868ddaaeULL,
0x812b291afa075c7cULL, 0x94faf987b685a932ULL, 0x3ed867d8470d08dbULL,
0x92517660b8901de8ULL, 0x2d97e43e058814b4ULL, 0x880a10c220b25582ULL,
0xc7c6520d1f1a0477ULL, 0xdbfc7fbcd7656aa6ULL, 0x78b1b9bfb1a2b84fULL,
0x2f20037f112a0bc1ULL, 0x657171ea2269a916ULL, 0xc08302b07142210eULL,
0x880a4403064080bULL, 0x3602420842208c00ULL, 0x852800dc7e0b6602ULL,
0x595a3fbbaa0f03b2ULL, 0x9f01411558159d5eULL, 0x2b4a4a5f88b394f2ULL,
0x4afcbffc292dd03aULL, 0x4a4094a3b3f10522ULL, 0xb06f00b491f30048ULL,
0xd5b3820280d77004ULL, 0x8b2e01e7c8e57a75ULL, 0x2d342794e886c2e6ULL,
0xc302c410cde21461ULL, 0x111f426f1379c274ULL, 0xe0569220abb31588ULL,
0x5026d3064d453324ULL, 0xe2076040c343cd8aULL, 0x93efd1e1738021eeULL,
0xb680804bed143132ULL, 0x44e361b21986944cULL, 0x44c60170ef5c598cULL,
0xf4da475c195c9c94ULL, 0xa3afbb5f72060b1dULL, 0xbc75f410e41c4ffcULL,
0xb51c099390520922ULL, 0x902c011f8f8ec368ULL, 0x950b56b3d6f5490aULL,
0x3909e0635bf202d0ULL, 0x5744f90206ec10ccULL, 0xdc59fd76317abbc1ULL,
0x881c7c67fcbfc4f6ULL, 0x47ca41e7e440d423ULL, 0xeb0c88112048d004ULL,
0x51c60e04359aef1aULL, 0x1aa1fe0e957a5554ULL, 0xdd9448db4f5e3104ULL,
0xdc01f6dca4bebbdcULL,
};
const int BShift[64] = {
26, 27, 27, 27, 27, 27, 27, 26, 27, 27, 27, 27, 27, 27, 27, 27,
27, 27, 25, 25, 25, 25, 27, 27, 27, 27, 25, 23, 23, 25, 27, 27,
27, 27, 25, 23, 23, 25, 27, 27, 27, 27, 25, 25, 25, 25, 27, 27,
27, 27, 27, 27, 27, 27, 27, 27, 26, 27, 27, 27, 27, 27, 27, 26
};
#else // if defined(USE_32BIT_ATTACKS)
#if defined(IS_64BIT)
const uint64_t BMult[64] = {
0x440049104032280ULL, 0x1021023c82008040ULL, 0x404040082000048ULL,
@@ -179,6 +56,31 @@ const uint64_t BMult[64] = {
0xa08520292120600ULL
};
const uint64_t RMult[64] = {
0xa8002c000108020ULL, 0x4440200140003000ULL, 0x8080200010011880ULL,
0x380180080141000ULL, 0x1a00060008211044ULL, 0x410001000a0c0008ULL,
0x9500060004008100ULL, 0x100024284a20700ULL, 0x802140008000ULL,
0x80c01002a00840ULL, 0x402004282011020ULL, 0x9862000820420050ULL,
0x1001448011100ULL, 0x6432800200800400ULL, 0x40100010002000cULL,
0x2800d0010c080ULL, 0x90c0008000803042ULL, 0x4010004000200041ULL,
0x3010010200040ULL, 0xa40828028001000ULL, 0x123010008000430ULL,
0x24008004020080ULL, 0x60040001104802ULL, 0x582200028400d1ULL,
0x4000802080044000ULL, 0x408208200420308ULL, 0x610038080102000ULL,
0x3601000900100020ULL, 0x80080040180ULL, 0xc2020080040080ULL,
0x80084400100102ULL, 0x4022408200014401ULL, 0x40052040800082ULL,
0xb08200280804000ULL, 0x8a80a008801000ULL, 0x4000480080801000ULL,
0x911808800801401ULL, 0x822a003002001894ULL, 0x401068091400108aULL,
0x4a10a00004cULL, 0x2000800640008024ULL, 0x1486408102020020ULL,
0x100a000d50041ULL, 0x810050020b0020ULL, 0x204000800808004ULL,
0x20048100a000cULL, 0x112000831020004ULL, 0x9000040810002ULL,
0x440490200208200ULL, 0x8910401000200040ULL, 0x6404200050008480ULL,
0x4b824a2010010100ULL, 0x4080801810c0080ULL, 0x400802a0080ULL,
0x8224080110026400ULL, 0x40002c4104088200ULL, 0x1002100104a0282ULL,
0x1208400811048021ULL, 0x3201014a40d02001ULL, 0x5100019200501ULL,
0x101000208001005ULL, 0x2008450080702ULL, 0x1002080301d00cULL,
0x410201ce5c030092ULL
};
const int BShift[64] = {
58, 59, 59, 59, 59, 59, 59, 58, 59, 59, 59, 59, 59, 59, 59, 59,
59, 59, 57, 57, 57, 57, 59, 59, 59, 59, 57, 55, 55, 57, 59, 59,
@@ -186,7 +88,132 @@ const int BShift[64] = {
59, 59, 59, 59, 59, 59, 59, 59, 58, 59, 59, 59, 59, 59, 59, 58
};
#endif // defined(USE_32BIT_ATTACKS)
const int RShift[64] = {
52, 53, 53, 53, 53, 53, 53, 52, 53, 54, 54, 54, 54, 54, 54, 53,
53, 54, 54, 54, 54, 54, 54, 53, 53, 54, 54, 54, 54, 54, 54, 53,
53, 54, 54, 54, 54, 54, 54, 53, 53, 54, 54, 54, 54, 54, 54, 53,
53, 54, 54, 54, 54, 54, 54, 53, 52, 53, 53, 53, 53, 53, 53, 52
};
#else // if !defined(IS_64BIT)
const uint64_t BMult[64] = {
0x54142844c6a22981ULL, 0x710358a6ea25c19eULL, 0x704f746d63a4a8dcULL,
0xbfed1a0b80f838c5ULL, 0x90561d5631e62110ULL, 0x2804260376e60944ULL,
0x84a656409aa76871ULL, 0xf0267f64c28b6197ULL, 0x70764ebb762f0585ULL,
0x92aa09e0cfe161deULL, 0x41ee1f6bb266f60eULL, 0xddcbf04f6039c444ULL,
0x5a3fab7bac0d988aULL, 0xd3727877fa4eaa03ULL, 0xd988402d868ddaaeULL,
0x812b291afa075c7cULL, 0x94faf987b685a932ULL, 0x3ed867d8470d08dbULL,
0x92517660b8901de8ULL, 0x2d97e43e058814b4ULL, 0x880a10c220b25582ULL,
0xc7c6520d1f1a0477ULL, 0xdbfc7fbcd7656aa6ULL, 0x78b1b9bfb1a2b84fULL,
0x2f20037f112a0bc1ULL, 0x657171ea2269a916ULL, 0xc08302b07142210eULL,
0x880a4403064080bULL, 0x3602420842208c00ULL, 0x852800dc7e0b6602ULL,
0x595a3fbbaa0f03b2ULL, 0x9f01411558159d5eULL, 0x2b4a4a5f88b394f2ULL,
0x4afcbffc292dd03aULL, 0x4a4094a3b3f10522ULL, 0xb06f00b491f30048ULL,
0xd5b3820280d77004ULL, 0x8b2e01e7c8e57a75ULL, 0x2d342794e886c2e6ULL,
0xc302c410cde21461ULL, 0x111f426f1379c274ULL, 0xe0569220abb31588ULL,
0x5026d3064d453324ULL, 0xe2076040c343cd8aULL, 0x93efd1e1738021eeULL,
0xb680804bed143132ULL, 0x44e361b21986944cULL, 0x44c60170ef5c598cULL,
0xf4da475c195c9c94ULL, 0xa3afbb5f72060b1dULL, 0xbc75f410e41c4ffcULL,
0xb51c099390520922ULL, 0x902c011f8f8ec368ULL, 0x950b56b3d6f5490aULL,
0x3909e0635bf202d0ULL, 0x5744f90206ec10ccULL, 0xdc59fd76317abbc1ULL,
0x881c7c67fcbfc4f6ULL, 0x47ca41e7e440d423ULL, 0xeb0c88112048d004ULL,
0x51c60e04359aef1aULL, 0x1aa1fe0e957a5554ULL, 0xdd9448db4f5e3104ULL,
0xdc01f6dca4bebbdcULL,
};
const uint64_t RMult[64] = {
0xd7445cdec88002c0ULL, 0xd0a505c1f2001722ULL, 0xe065d1c896002182ULL,
0x9a8c41e75a000892ULL, 0x8900b10c89002aa8ULL, 0x9b28d1c1d60005a2ULL,
0x15d6c88de002d9aULL, 0xb1dbfc802e8016a9ULL, 0x149a1042d9d60029ULL,
0xb9c08050599e002fULL, 0x132208c3af300403ULL, 0xc1000ce2e9c50070ULL,
0x9d9aa13c99020012ULL, 0xb6b078daf71e0046ULL, 0x9d880182fb6e002eULL,
0x52889f467e850037ULL, 0xda6dc008d19a8480ULL, 0x468286034f902420ULL,
0x7140ac09dc54c020ULL, 0xd76ffffa39548808ULL, 0xea901c4141500808ULL,
0xc91004093f953a02ULL, 0x2882afa8f6bb402ULL, 0xaebe335692442c01ULL,
0xe904a22079fb91eULL, 0x13a514851055f606ULL, 0x76c782018c8fe632ULL,
0x1dc012a9d116da06ULL, 0x3c9e0037264fffa6ULL, 0x2036002853c6e4a2ULL,
0xe3fe08500afb47d4ULL, 0xf38af25c86b025c2ULL, 0xc0800e2182cf9a40ULL,
0x72002480d1f60673ULL, 0x2500200bae6e9b53ULL, 0xc60018c1eefca252ULL,
0x600590473e3608aULL, 0x46002c4ab3fe51b2ULL, 0xa200011486bcc8d2ULL,
0xb680078095784c63ULL, 0x2742002639bf11aeULL, 0xc7d60021a5bdb142ULL,
0xc8c04016bb83d820ULL, 0xbd520028123b4842ULL, 0x9d1600344ac2a832ULL,
0x6a808005631c8a05ULL, 0x604600a148d5389aULL, 0xe2e40103d40dea65ULL,
0x945b5a0087c62a81ULL, 0x12dc200cd82d28eULL, 0x2431c600b5f9ef76ULL,
0xfb142a006a9b314aULL, 0x6870e00a1c97d62ULL, 0x2a9db2004a2689a2ULL,
0xd3594600caf5d1a2ULL, 0xee0e4900439344a7ULL, 0x89c4d266ca25007aULL,
0x3e0013a2743f97e3ULL, 0x180e31a0431378aULL, 0x3a9e465a4d42a512ULL,
0x98d0a11a0c0d9cc2ULL, 0x8e711c1aba19b01eULL, 0x8dcdc836dd201142ULL,
0x5ac08a4735370479ULL,
};
const int BShift[64] = {
26, 27, 27, 27, 27, 27, 27, 26, 27, 27, 27, 27, 27, 27, 27, 27,
27, 27, 25, 25, 25, 25, 27, 27, 27, 27, 25, 23, 23, 25, 27, 27,
27, 27, 25, 23, 23, 25, 27, 27, 27, 27, 25, 25, 25, 25, 27, 27,
27, 27, 27, 27, 27, 27, 27, 27, 26, 27, 27, 27, 27, 27, 27, 26
};
const int RShift[64] = {
20, 21, 21, 21, 21, 21, 21, 20, 21, 22, 22, 22, 22, 22, 22, 21,
21, 22, 22, 22, 22, 22, 22, 21, 21, 22, 22, 22, 22, 22, 22, 21,
21, 22, 22, 22, 22, 22, 22, 21, 21, 22, 22, 22, 22, 22, 22, 21,
21, 22, 22, 22, 22, 22, 22, 21, 20, 21, 21, 21, 21, 21, 21, 20
};
#endif // defined(IS_64BIT)
const Bitboard SquaresByColorBB[2] = { BlackSquaresBB, WhiteSquaresBB };
const Bitboard FileBB[8] = {
FileABB, FileBBB, FileCBB, FileDBB, FileEBB, FileFBB, FileGBB, FileHBB
};
const Bitboard NeighboringFilesBB[8] = {
FileBBB, FileABB|FileCBB, FileBBB|FileDBB, FileCBB|FileEBB,
FileDBB|FileFBB, FileEBB|FileGBB, FileFBB|FileHBB, FileGBB
};
const Bitboard ThisAndNeighboringFilesBB[8] = {
FileABB|FileBBB, FileABB|FileBBB|FileCBB,
FileBBB|FileCBB|FileDBB, FileCBB|FileDBB|FileEBB,
FileDBB|FileEBB|FileFBB, FileEBB|FileFBB|FileGBB,
FileFBB|FileGBB|FileHBB, FileGBB|FileHBB
};
const Bitboard RankBB[8] = {
Rank1BB, Rank2BB, Rank3BB, Rank4BB, Rank5BB, Rank6BB, Rank7BB, Rank8BB
};
const Bitboard RelativeRankBB[2][8] = {
{ Rank1BB, Rank2BB, Rank3BB, Rank4BB, Rank5BB, Rank6BB, Rank7BB, Rank8BB },
{ Rank8BB, Rank7BB, Rank6BB, Rank5BB, Rank4BB, Rank3BB, Rank2BB, Rank1BB }
};
const Bitboard InFrontBB[2][8] = {
{ Rank2BB | Rank3BB | Rank4BB | Rank5BB | Rank6BB | Rank7BB | Rank8BB,
Rank3BB | Rank4BB | Rank5BB | Rank6BB | Rank7BB | Rank8BB,
Rank4BB | Rank5BB | Rank6BB | Rank7BB | Rank8BB,
Rank5BB | Rank6BB | Rank7BB | Rank8BB,
Rank6BB | Rank7BB | Rank8BB,
Rank7BB | Rank8BB,
Rank8BB,
EmptyBoardBB
},
{ EmptyBoardBB,
Rank1BB,
Rank2BB | Rank1BB,
Rank3BB | Rank2BB | Rank1BB,
Rank4BB | Rank3BB | Rank2BB | Rank1BB,
Rank5BB | Rank4BB | Rank3BB | Rank2BB | Rank1BB,
Rank6BB | Rank5BB | Rank4BB | Rank3BB | Rank2BB | Rank1BB,
Rank7BB | Rank6BB | Rank5BB | Rank4BB | Rank3BB | Rank2BB | Rank1BB
}
};
Bitboard RMask[64];
int RAttackIndex[64];
Bitboard RAttacks[0x19000];
Bitboard BMask[64];
int BAttackIndex[64];
@@ -206,6 +233,8 @@ Bitboard BishopPseudoAttacks[64];
Bitboard RookPseudoAttacks[64];
Bitboard QueenPseudoAttacks[64];
uint8_t BitCount8Bit[256];
////
//// Local definitions
@@ -225,9 +254,6 @@ namespace {
const int shift[2], const Bitboard mult[],
int deltas[][2]);
void init_pseudo_attacks();
#if defined(USE_COMPACT_ROOK_ATTACKS)
void init_file_and_rank_attacks();
#endif
}
@@ -259,115 +285,123 @@ void init_bitboards() {
init_ray_bitboards();
init_attacks();
init_between_bitboards();
#if defined(USE_COMPACT_ROOK_ATTACKS)
init_file_and_rank_attacks();
#else
init_sliding_attacks(RAttacks, RAttackIndex, RMask, RShift,
RMult, rookDeltas);
#endif
init_sliding_attacks(BAttacks, BAttackIndex, BMask, BShift,
BMult, bishopDeltas);
init_sliding_attacks(RAttacks, RAttackIndex, RMask, RShift, RMult, rookDeltas);
init_sliding_attacks(BAttacks, BAttackIndex, BMask, BShift, BMult, bishopDeltas);
init_pseudo_attacks();
}
#if defined(USE_FOLDED_BITSCAN)
/// first_1() finds the least significant nonzero bit in a nonzero bitboard.
/// pop_1st_bit() finds and clears the least significant nonzero bit in a
/// nonzero bitboard.
static const int BitTable[64] = {
#if defined(IS_64BIT) && !defined(USE_BSFQ)
static CACHE_LINE_ALIGNMENT
const int BitTable[64] = {
0, 1, 2, 7, 3, 13, 8, 19, 4, 25, 14, 28, 9, 34, 20, 40, 5, 17, 26, 38, 15,
46, 29, 48, 10, 31, 35, 54, 21, 50, 41, 57, 63, 6, 12, 18, 24, 27, 33, 39,
16, 37, 45, 47, 30, 53, 49, 56, 62, 11, 23, 32, 36, 44, 52, 55, 61, 22, 43,
51, 60, 42, 59, 58
};
Square first_1(Bitboard b) {
return Square(BitTable[((b & -b) * 0x218a392cd3d5dbfULL) >> 58]);
}
Square pop_1st_bit(Bitboard* b) {
Bitboard bb = *b;
*b &= (*b - 1);
return Square(BitTable[((bb & -bb) * 0x218a392cd3d5dbfULL) >> 58]);
}
#elif !defined(USE_BSFQ)
static CACHE_LINE_ALIGNMENT
const int BitTable[64] = {
63, 30, 3, 32, 25, 41, 22, 33, 15, 50, 42, 13, 11, 53, 19, 34, 61, 29, 2,
51, 21, 43, 45, 10, 18, 47, 1, 54, 9, 57, 0, 35, 62, 31, 40, 4, 49, 5, 52,
26, 60, 6, 23, 44, 46, 27, 56, 16, 7, 39, 48, 24, 59, 14, 12, 55, 38, 28,
58, 20, 37, 17, 36, 8
};
/// first_1() finds the least significant nonzero bit in a nonzero bitboard.
Square first_1(Bitboard b) {
b ^= (b - 1);
uint32_t fold = int(b) ^ int(b >> 32);
return Square(BitTable[(fold * 0x783a9b23) >> 26]);
}
/// pop_1st_bit() finds and clears the least significant nonzero bit in a
/// nonzero bitboard.
#if defined(USE_32BIT_ATTACKS)
// Use type-punning
union b_union {
Bitboard b;
struct {
#if defined (BIGENDIAN)
uint32_t h;
uint32_t l;
#else
uint32_t l;
uint32_t h;
};
#endif
} dw;
};
// WARNING: Needs -fno-strict-aliasing compiler option
Square pop_1st_bit(Bitboard *bb) {
Square pop_1st_bit(Bitboard* bb) {
b_union u;
uint32_t b;
b_union u;
Square ret;
u.b = *bb;
u.b = *bb;
if (u.l)
{
b = u.l;
*((uint32_t*)bb) = b & (b - 1);
b ^= (b - 1);
}
else
{
b = u.h;
*((uint32_t*)bb+1) = b & (b - 1); // Little endian only?
b = ~(b ^ (b - 1));
}
return Square(BitTable[(b * 0x783a9b23) >> 26]);
}
#else
Square pop_1st_bit(Bitboard *b) {
Bitboard bb = *b ^ (*b - 1);
uint32_t fold = int(bb) ^ int(bb >> 32);
*b &= (*b - 1);
return Square(BitTable[(fold * 0x783a9b23) >> 26]);
if (u.dw.l)
{
ret = Square(BitTable[((u.dw.l ^ (u.dw.l - 1)) * 0x783a9b23) >> 26]);
u.dw.l &= (u.dw.l - 1);
*bb = u.b;
return ret;
}
ret = Square(BitTable[((~(u.dw.h ^ (u.dw.h - 1))) * 0x783a9b23) >> 26]);
u.dw.h &= (u.dw.h - 1);
*bb = u.b;
return ret;
}
#endif
#else
static const int BitTable[64] = {
0, 1, 2, 7, 3, 13, 8, 19, 4, 25, 14, 28, 9, 34, 20, 40, 5, 17, 26, 38, 15,
46, 29, 48, 10, 31, 35, 54, 21, 50, 41, 57, 63, 6, 12, 18, 24, 27, 33, 39,
16, 37, 45, 47, 30, 53, 49, 56, 62, 11, 23, 32, 36, 44, 52, 55, 61, 22, 43,
51, 60, 42, 59, 58
// Optimized bitScanReverse32() implementation by Pascal Georges. Note
// that first bit is 1, this allow to differentiate between 0 and 1.
static CACHE_LINE_ALIGNMENT
const char MsbTable[256] = {
0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8
};
int bitScanReverse32(uint32_t b)
{
int result = 0;
/// first_1() finds the least significant nonzero bit in a nonzero bitboard.
Square first_1(Bitboard b) {
return Square(BitTable[((b & -b) * 0x218a392cd3d5dbfULL) >> 58]);
if (b > 0xFFFF)
{
b >>= 16;
result += 16;
}
if (b > 0xFF)
{
b >>= 8;
result += 8;
}
return result + MsbTable[b];
}
/// pop_1st_bit() finds and clears the least significant nonzero bit in a
/// nonzero bitboard.
Square pop_1st_bit(Bitboard *b) {
Bitboard bb = *b;
*b &= (*b - 1);
return Square(BitTable[((bb & -bb) * 0x218a392cd3d5dbfULL) >> 58]);
}
#endif // defined(USE_FOLDED_BITSCAN)
namespace {
// All functions below are used to precompute various bitboards during
@@ -388,6 +422,9 @@ namespace {
in_front_bb(c, s) & this_and_neighboring_files_bb(s);
OutpostMask[c][s] = in_front_bb(c, s) & neighboring_files_bb(s);
}
for (Bitboard b = 0ULL; b < 256ULL; b++)
BitCount8Bit[b] = (uint8_t)count_1s(b);
}
@@ -480,25 +517,25 @@ namespace {
attackIndex[i] = index;
mask[i] = sliding_attacks(i, 0ULL, 4, deltas, 1, 6, 1, 6);
#if defined(USE_32BIT_ATTACKS)
j = (1 << (32 - shift[i]));
#else
#if defined(IS_64BIT)
j = (1 << (64 - shift[i]));
#else
j = (1 << (32 - shift[i]));
#endif
for(k = 0; k < j; k++) {
#if defined(USE_32BIT_ATTACKS)
#if defined(IS_64BIT)
b = index_to_bitboard(k, mask[i]);
attacks[index + ((b * mult[i]) >> shift[i])] =
sliding_attacks(i, b, 4, deltas);
#else
b = index_to_bitboard(k, mask[i]);
attacks[index +
(unsigned(int(b) * int(mult[i]) ^
int(b >> 32) * int(mult[i] >> 32))
>> shift[i])] =
sliding_attacks(i, b, 4, deltas);
#else
b = index_to_bitboard(k, mask[i]);
attacks[index + ((b * mult[i]) >> shift[i])] =
sliding_attacks(i, b, 4, deltas);
#endif
}
index += j;
@@ -515,29 +552,4 @@ namespace {
}
}
#if defined(USE_COMPACT_ROOK_ATTACKS)
void init_file_and_rank_attacks() {
int i, j, k, l, m, s;
Bitboard b1, b2;
for(i = 0; i < 64; i++) {
for(m = 0; m <= 1; m++) {
b1 = 0ULL;
for(j = 0; j < 6; j++) if(i & (1<<j)) b1 |= (1ULL << ((j+1)*(1+m*7)));
for(j = 0; j < 8; j++) {
b2 = 0ULL;
for(k = 0, s = 1; k < 2; k++, s *= -1) {
for(l = j+s; l >= 0 && l <= 7; l += s) {
b2 |= (m? RankBB[l] : FileBB[l]);
if(b1 & (1ULL << (l*(1+m*7)))) break;
}
}
if(m) FileAttacks[j][(b1*0xd6e8802041d0c441ULL) >> 58] = b2;
else RankAttacks[j][i] = b2;
}
}
}
}
#endif // defined(USE_COMPACT_ROOK_ATTACKS)
}

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2010 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
@@ -22,43 +22,6 @@
#if !defined(BITBOARD_H_INCLUDED)
#define BITBOARD_H_INCLUDED
////
//// Defines
////
// Comment following define if you prefer manually adjust
// platform macros defined below
#define AUTO_CONFIGURATION
// Quiet a warning on Intel compiler
#if !defined(__SIZEOF_INT__ )
#define __SIZEOF_INT__ 0
#endif
// Check for 64 bits for different compilers: Intel, MSVC and gcc
#if defined(__x86_64) || defined(_WIN64) || (__SIZEOF_INT__ > 4)
#define IS_64BIT
#endif
#if !defined(AUTO_CONFIGURATION) || defined(IS_64BIT)
//#define USE_COMPACT_ROOK_ATTACKS
//#define USE_32BIT_ATTACKS
#define USE_FOLDED_BITSCAN
#define BITCOUNT_SWAR_64
//#define BITCOUNT_SWAR_32
//#define BITCOUNT_LOOP
#else
#define USE_32BIT_ATTACKS
#define USE_FOLDED_BITSCAN
#define BITCOUNT_SWAR_32
#endif
////
//// Includes
////
@@ -69,13 +32,6 @@
#include "types.h"
////
//// Types
////
typedef uint64_t Bitboard;
////
//// Constants and variables
////
@@ -84,7 +40,6 @@ const Bitboard EmptyBoardBB = 0ULL;
const Bitboard WhiteSquaresBB = 0x55AA55AA55AA55AAULL;
const Bitboard BlackSquaresBB = 0xAA55AA55AA55AA55ULL;
const Bitboard SquaresByColorBB[2] = { BlackSquaresBB, WhiteSquaresBB };
const Bitboard FileABB = 0x0101010101010101ULL;
const Bitboard FileBBB = 0x0202020202020202ULL;
@@ -95,22 +50,6 @@ const Bitboard FileFBB = 0x2020202020202020ULL;
const Bitboard FileGBB = 0x4040404040404040ULL;
const Bitboard FileHBB = 0x8080808080808080ULL;
const Bitboard FileBB[8] = {
FileABB, FileBBB, FileCBB, FileDBB, FileEBB, FileFBB, FileGBB, FileHBB
};
const Bitboard NeighboringFilesBB[8] = {
FileBBB, FileABB|FileCBB, FileBBB|FileDBB, FileCBB|FileEBB,
FileDBB|FileFBB, FileEBB|FileGBB, FileFBB|FileHBB, FileGBB
};
const Bitboard ThisAndNeighboringFilesBB[8] = {
FileABB|FileBBB, FileABB|FileBBB|FileCBB,
FileBBB|FileCBB|FileDBB, FileCBB|FileDBB|FileEBB,
FileDBB|FileEBB|FileFBB, FileEBB|FileFBB|FileGBB,
FileFBB|FileGBB|FileHBB, FileGBB|FileHBB
};
const Bitboard Rank1BB = 0xFFULL;
const Bitboard Rank2BB = 0xFF00ULL;
const Bitboard Rank3BB = 0xFF0000ULL;
@@ -120,35 +59,13 @@ const Bitboard Rank6BB = 0xFF0000000000ULL;
const Bitboard Rank7BB = 0xFF000000000000ULL;
const Bitboard Rank8BB = 0xFF00000000000000ULL;
const Bitboard RankBB[8] = {
Rank1BB, Rank2BB, Rank3BB, Rank4BB, Rank5BB, Rank6BB, Rank7BB, Rank8BB
};
const Bitboard RelativeRankBB[2][8] = {
{ Rank1BB, Rank2BB, Rank3BB, Rank4BB, Rank5BB, Rank6BB, Rank7BB, Rank8BB },
{ Rank8BB, Rank7BB, Rank6BB, Rank5BB, Rank4BB, Rank3BB, Rank2BB, Rank1BB }
};
const Bitboard InFrontBB[2][8] = {
{ Rank2BB | Rank3BB | Rank4BB | Rank5BB | Rank6BB | Rank7BB | Rank8BB,
Rank3BB | Rank4BB | Rank5BB | Rank6BB | Rank7BB | Rank8BB,
Rank4BB | Rank5BB | Rank6BB | Rank7BB | Rank8BB,
Rank5BB | Rank6BB | Rank7BB | Rank8BB,
Rank6BB | Rank7BB | Rank8BB,
Rank7BB | Rank8BB,
Rank8BB,
EmptyBoardBB
},
{ EmptyBoardBB,
Rank1BB,
Rank2BB | Rank1BB,
Rank3BB | Rank2BB | Rank1BB,
Rank4BB | Rank3BB | Rank2BB | Rank1BB,
Rank5BB | Rank4BB | Rank3BB | Rank2BB | Rank1BB,
Rank6BB | Rank5BB | Rank4BB | Rank3BB | Rank2BB | Rank1BB,
Rank7BB | Rank6BB | Rank5BB | Rank4BB | Rank3BB | Rank2BB | Rank1BB
}
};
extern const Bitboard SquaresByColorBB[2];
extern const Bitboard FileBB[8];
extern const Bitboard NeighboringFilesBB[8];
extern const Bitboard ThisAndNeighboringFilesBB[8];
extern const Bitboard RankBB[8];
extern const Bitboard RelativeRankBB[2][8];
extern const Bitboard InFrontBB[2][8];
extern Bitboard SetMaskBB[65];
extern Bitboard ClearMaskBB[65];
@@ -160,20 +77,12 @@ extern Bitboard BetweenBB[64][64];
extern Bitboard PassedPawnMask[2][64];
extern Bitboard OutpostMask[2][64];
#if defined(USE_COMPACT_ROOK_ATTACKS)
extern Bitboard RankAttacks[8][64], FileAttacks[8][64];
#else
extern const uint64_t RMult[64];
extern const int RShift[64];
extern Bitboard RMask[64];
extern int RAttackIndex[64];
extern Bitboard RAttacks[0x19000];
#endif // defined(USE_COMPACT_ROOK_ATTACKS)
extern const uint64_t BMult[64];
extern const int BShift[64];
extern Bitboard BMask[64];
@@ -184,6 +93,8 @@ extern Bitboard BishopPseudoAttacks[64];
extern Bitboard RookPseudoAttacks[64];
extern Bitboard QueenPseudoAttacks[64];
extern uint8_t BitCount8Bit[256];
////
//// Inline functions
@@ -205,6 +116,17 @@ inline void clear_bit(Bitboard *b, Square s) {
}
/// Functions used to update a bitboard after a move. This is faster
/// then calling a sequence of clear_bit() + set_bit()
inline Bitboard make_move_bb(Square from, Square to) {
return SetMaskBB[from] | SetMaskBB[to];
}
inline void do_move_bb(Bitboard *b, Bitboard move_bb) {
*b ^= move_bb;
}
/// rank_bb() and file_bb() gives a bitboard containing all squares on a given
/// file or rank. It is also possible to pass a square as input to these
/// functions.
@@ -298,29 +220,24 @@ inline Bitboard ray_bb(Square s, SignedDirection d) {
}
/// Functions for computing sliding attack bitboards. rook_attacks_bb(),
/// Functions for computing sliding attack bitboards. rook_attacks_bb(),
/// bishop_attacks_bb() and queen_attacks_bb() all take a square and a
/// bitboard of occupied squares as input, and return a bitboard representing
/// all squares attacked by a rook, bishop or queen on the given square.
#if defined(USE_COMPACT_ROOK_ATTACKS)
inline Bitboard file_attacks_bb(Square s, Bitboard blockers) {
Bitboard b = (blockers >> square_file(s)) & 0x01010101010100ULL;
return
FileAttacks[square_rank(s)][(b*0xd6e8802041d0c441ULL)>>58] & file_bb(s);
}
inline Bitboard rank_attacks_bb(Square s, Bitboard blockers) {
Bitboard b = (blockers >> ((s & 56) + 1)) & 63;
return RankAttacks[square_file(s)][b] & rank_bb(s);
}
#if defined(IS_64BIT)
inline Bitboard rook_attacks_bb(Square s, Bitboard blockers) {
return file_attacks_bb(s, blockers) | rank_attacks_bb(s, blockers);
Bitboard b = blockers & RMask[s];
return RAttacks[RAttackIndex[s] + ((b * RMult[s]) >> RShift[s])];
}
#elif defined(USE_32BIT_ATTACKS)
inline Bitboard bishop_attacks_bb(Square s, Bitboard blockers) {
Bitboard b = blockers & BMask[s];
return BAttacks[BAttackIndex[s] + ((b * BMult[s]) >> BShift[s])];
}
#else // if !defined(IS_64BIT)
inline Bitboard rook_attacks_bb(Square s, Bitboard blockers) {
Bitboard b = blockers & RMask[s];
@@ -330,17 +247,6 @@ inline Bitboard rook_attacks_bb(Square s, Bitboard blockers) {
>> RShift[s])];
}
#else
inline Bitboard rook_attacks_bb(Square s, Bitboard blockers) {
Bitboard b = blockers & RMask[s];
return RAttacks[RAttackIndex[s] + ((b * RMult[s]) >> RShift[s])];
}
#endif
#if defined(USE_32BIT_ATTACKS)
inline Bitboard bishop_attacks_bb(Square s, Bitboard blockers) {
Bitboard b = blockers & BMask[s];
return BAttacks[BAttackIndex[s] +
@@ -349,14 +255,7 @@ inline Bitboard bishop_attacks_bb(Square s, Bitboard blockers) {
>> BShift[s])];
}
#else // defined(USE_32BIT_ATTACKS)
inline Bitboard bishop_attacks_bb(Square s, Bitboard blockers) {
Bitboard b = blockers & BMask[s];
return BAttacks[BAttackIndex[s] + ((b * BMult[s]) >> BShift[s])];
}
#endif // defined(USE_32BIT_ATTACKS)
#endif
inline Bitboard queen_attacks_bb(Square s, Bitboard blockers) {
return rook_attacks_bb(s, blockers) | bishop_attacks_bb(s, blockers);
@@ -418,63 +317,30 @@ inline Bitboard isolated_pawn_mask(Square s) {
}
/// count_1s() counts the number of nonzero bits in a bitboard.
/// first_1() finds the least significant nonzero bit in a nonzero bitboard.
/// pop_1st_bit() finds and clears the least significant nonzero bit in a
/// nonzero bitboard.
#if defined(BITCOUNT_LOOP)
#if defined(USE_BSFQ) // Assembly code by Heinz van Saanen
inline int count_1s(Bitboard b) {
int r;
for(r = 0; b; r++, b &= b - 1);
return r;
inline Square first_1(Bitboard b) {
Bitboard dummy;
__asm__("bsfq %1, %0": "=r"(dummy): "rm"(b) );
return (Square)(dummy);
}
inline int count_1s_max_15(Bitboard b) {
return count_1s(b);
inline Square pop_1st_bit(Bitboard* b) {
const Square s = first_1(*b);
*b &= ~(1ULL<<s);
return s;
}
#elif defined(BITCOUNT_SWAR_32)
#else // if !defined(USE_BSFQ)
inline int count_1s(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) & 0x0F0F0F0F; // 0-8 in 8 bits
v += (((w >> 4) + w) & 0x0F0F0F0F); // 0-16 in 8 bits
v *= 0x01010101; // mul is fast on amd procs
return int(v >> 24);
}
extern Square first_1(Bitboard b);
extern Square pop_1st_bit(Bitboard* b);
inline int count_1s_max_15(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 += w; // 0-8 in 4 bits
v *= 0x11111111;
return int(v >> 28);
}
#elif defined(BITCOUNT_SWAR_64)
inline int count_1s(Bitboard b) {
b -= ((b>>1) & 0x5555555555555555ULL);
b = ((b>>2) & 0x3333333333333333ULL) + (b & 0x3333333333333333ULL);
b = ((b>>4) + b) & 0x0F0F0F0F0F0F0F0FULL;
b *= 0x0101010101010101ULL;
return int(b >> 56);
}
inline int count_1s_max_15(Bitboard b) {
b -= (b>>1) & 0x5555555555555555ULL;
b = ((b>>2) & 0x3333333333333333ULL) + (b & 0x3333333333333333ULL);
b *= 0x1111111111111111ULL;
return int(b >> 60);
}
#endif // BITCOUNT
#endif
////
@@ -483,8 +349,7 @@ inline int count_1s_max_15(Bitboard b) {
extern void print_bitboard(Bitboard b);
extern void init_bitboards();
extern Square first_1(Bitboard b);
extern Square pop_1st_bit(Bitboard *b);
extern int bitScanReverse32(uint32_t b);
#endif // !defined(BITBOARD_H_INCLUDED)

134
src/bitcount.h Normal file
View File

@@ -0,0 +1,134 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Stockfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined(BITCOUNT_H_INCLUDED)
#define BITCOUNT_H_INCLUDED
#include "types.h"
// Select type of intrinsic bit count instruction to use, see
// README.txt on how to pgo compile with POPCNT support.
#if !defined(USE_POPCNT)
#define POPCNT_INTRINSIC(x) 0
#elif defined(_MSC_VER)
#define POPCNT_INTRINSIC(x) (int)__popcnt64(x)
#elif defined(__GNUC__)
#define POPCNT_INTRINSIC(x) ({ \
unsigned long __ret; \
__asm__("popcnt %1, %0" : "=r" (__ret) : "r" (x)); \
__ret; })
#endif
/// Software implementation of bit count functions
#if defined(IS_64BIT)
inline int count_1s(Bitboard b) {
b -= ((b>>1) & 0x5555555555555555ULL);
b = ((b>>2) & 0x3333333333333333ULL) + (b & 0x3333333333333333ULL);
b = ((b>>4) + b) & 0x0F0F0F0F0F0F0F0FULL;
b *= 0x0101010101010101ULL;
return int(b >> 56);
}
inline int count_1s_max_15(Bitboard b) {
b -= (b>>1) & 0x5555555555555555ULL;
b = ((b>>2) & 0x3333333333333333ULL) + (b & 0x3333333333333333ULL);
b *= 0x1111111111111111ULL;
return int(b >> 60);
}
#else // if !defined(IS_64BIT)
inline int count_1s(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) & 0x0F0F0F0F; // 0-8 in 8 bits
v += (((w >> 4) + w) & 0x0F0F0F0F); // 0-16 in 8 bits
v *= 0x01010101; // mul is fast on amd procs
return int(v >> 24);
}
inline int count_1s_max_15(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 += w; // 0-8 in 4 bits
v *= 0x11111111;
return int(v >> 28);
}
#endif // BITCOUNT
/// count_1s() counts the number of nonzero bits in a bitboard.
/// If template parameter is true an intrinsic is called, otherwise
/// we fallback on a software implementation.
template<bool UseIntrinsic>
inline int count_1s(Bitboard b) {
return UseIntrinsic ? POPCNT_INTRINSIC(b) : count_1s(b);
}
template<bool UseIntrinsic>
inline int count_1s_max_15(Bitboard b) {
return UseIntrinsic ? POPCNT_INTRINSIC(b) : count_1s_max_15(b);
}
// Detect hardware POPCNT support
inline bool cpu_has_popcnt() {
int CPUInfo[4] = {-1};
__cpuid(CPUInfo, 0x00000001);
return (CPUInfo[2] >> 23) & 1;
}
// Global constant initialized at startup that is set to true if
// CPU on which application runs supports POPCNT intrinsic. Unless
// USE_POPCNT is not defined.
#if defined(USE_POPCNT)
const bool CpuHasPOPCNT = cpu_has_popcnt();
#else
const bool CpuHasPOPCNT = false;
#endif
// Global constant used to print info about the use of 64 optimized
// functions to verify that a 64 bit compile has been correctly built.
#if defined(IS_64BIT)
const bool CpuHas64BitPath = true;
#else
const bool CpuHas64BitPath = false;
#endif
#endif // !defined(BITCOUNT_H_INCLUDED)

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2010 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
@@ -35,6 +35,7 @@
#include "mersenne.h"
#include "movegen.h"
using namespace std;
////
//// Global variables
@@ -49,7 +50,11 @@ Book OpeningBook;
namespace {
/// Random numbers from PolyGlot, used to compute book hash keys.
/// Book entry size in bytes
const int EntrySize = 16;
/// Random numbers from PolyGlot, used to compute book hash keys
const uint64_t Random64[781] = {
0x9D39247E33776D41ULL, 0x2AF7398005AAA5C7ULL, 0x44DB015024623547ULL,
@@ -318,30 +323,19 @@ namespace {
/// Indices to the Random64[] array
const int RandomPiece = 0;
const int RandomCastle = 768;
const int RandomPiece = 0;
const int RandomCastle = 768;
const int RandomEnPassant = 772;
const int RandomTurn = 780;
/// Convert pieces to the range 0..1
const int PieceTo12[] = {
0, 0, 2, 4, 6, 8, 10, 0, 0, 1, 3, 5, 7, 9, 11
};
const int RandomTurn = 780;
/// Prototypes
uint64_t book_key(const Position &pos);
uint64_t book_key(const Position& pos);
uint64_t book_piece_key(Piece p, Square s);
uint64_t book_castle_key(const Position &pos);
uint64_t book_ep_key(const Position &pos);
uint64_t book_color_key(const Position &pos);
uint16_t read_integer16(std::ifstream& file);
uint64_t read_integer64(std::ifstream& file);
uint64_t read_integer(std::ifstream& file, int size);
uint64_t book_castle_key(const Position& pos);
uint64_t book_ep_key(const Position& pos);
uint64_t book_color_key(const Position& pos);
}
@@ -350,99 +344,108 @@ namespace {
////
/// Constructor
/// Destructor. Be sure file is closed before we leave.
Book::Book() : bookSize(0) {}
Book::~Book() {
close();
}
/// Book::open() opens a book file with a given file name.
/// Book::open() opens a book file with a given file name
void Book::open(const std::string &fName) {
void Book::open(const string& fName) {
// Close old file before opening the new
close();
fileName = fName;
bookFile.open(fileName.c_str(), std::ifstream::in | std::ifstream::binary);
if (!bookFile.is_open())
ifstream::open(fileName.c_str(), ifstream::in | ifstream::binary);
if (!is_open())
return;
bookFile.seekg(0, std::ios::end);
bookSize = bookFile.tellg() / 16;
bookFile.seekg(0, std::ios::beg);
// Get the book size in number of entries
seekg(0, ios::end);
bookSize = tellg() / EntrySize;
seekg(0, ios::beg);
if (!bookFile.good())
if (!good())
{
std::cerr << "Failed to open book file " << fileName << std::endl;
exit(EXIT_FAILURE);
cerr << "Failed to open book file " << fileName << endl;
Application::exit_with_failure();
}
}
/// Book::close() closes the currently open book file.
/// Book::close() closes the file only if it is open, otherwise
/// we can end up in a little mess due to how std::ifstream works.
void Book::close() {
if (bookFile.is_open())
bookFile.close();
}
/// Book::is_open() tests whether a book file has been opened.
bool Book::is_open() const {
return bookFile.is_open() && bookSize != 0;
if (is_open())
ifstream::close();
}
/// Book::file_name() returns the file name of the currently active book,
/// or the empty string if no book is open.
const std::string Book::file_name() const {
const string Book::file_name() { // Not const to compile on HP-UX 11.X
return bookFile.is_open() ? fileName : "";
return is_open() ? fileName : "";
}
/// Book::get_move() gets a book move for a given position. Returns
/// Book::get_move() gets a book move for a given position. Returns
/// MOVE_NONE if no book move is found.
Move Book::get_move(const Position &pos) const {
if(this->is_open()) {
int bestMove = 0, bestScore = 0, move, score;
uint64_t key = book_key(pos);
BookEntry entry;
Move Book::get_move(const Position& pos) {
if (!is_open() || bookSize == 0)
return MOVE_NONE;
int bookMove = 0, scoresSum = 0;
uint64_t key = book_key(pos);
BookEntry entry;
// Choose a book move among the possible moves for the given position
for (int idx = find_key(key); idx < bookSize; idx++)
{
read_entry(entry, idx);
if (entry.key != key)
break;
int score = entry.count;
for(int i = this->find_key(key); i < bookSize; i++) {
this->read_entry(entry, i);
if(entry.key != key)
break;
move = entry.move;
score = entry.count;
assert(score > 0);
bestScore += score;
if(int(genrand_int32() % bestScore) < score)
bestMove = move;
}
if(bestMove != 0) {
MoveStack moves[256];
int n, j;
n = generate_legal_moves(pos, moves);
for(j = 0; j < n; j++)
if((int(moves[j].move) & 07777) == bestMove)
return moves[j].move;
}
// Choose book move according to its score. If a move has a very
// high score it has more probability to be choosen then a one with
// lower score. Note that first entry is always chosen.
scoresSum += score;
if (int(genrand_int32() % scoresSum) < score)
bookMove = entry.move;
}
if (!bookMove)
return MOVE_NONE;
MoveStack mlist[256];
MoveStack* last = generate_moves(pos, mlist);
for (MoveStack* cur = mlist; cur != last; cur++)
if ((int(cur->move) & 07777) == bookMove)
return cur->move;
return MOVE_NONE;
}
/// Book::find_key() takes a book key as input, and does a binary search
/// through the book file for the given key. The index to the first book
/// entry with the same key as the input is returned. When the key is not
/// through the book file for the given key. The index to the first book
/// entry with the same key as the input is returned. When the key is not
/// found in the book file, bookSize is returned.
int Book::find_key(uint64_t key) const {
int Book::find_key(uint64_t key) {
int left, right, mid;
BookEntry entry;
@@ -452,46 +455,59 @@ int Book::find_key(uint64_t key) const {
assert(left <= right);
while(left < right) {
mid = (left + right) / 2;
assert(mid >= left && mid < right);
while (left < right)
{
mid = (left + right) / 2;
this->read_entry(entry, mid);
assert(mid >= left && mid < right);
if(key <= entry.key)
right = mid;
else
left = mid + 1;
read_entry(entry, mid);
if (key <= entry.key)
right = mid;
else
left = mid + 1;
}
assert(left == right);
this->read_entry(entry, left);
read_entry(entry, left);
return (entry.key == key)? left : bookSize;
}
/// Book::read_entry() takes a BookEntry reference and an integer index as
/// input, and looks up the opening book entry at the given index in the book
/// file. The book entry is copied to the first input parameter.
/// file. The book entry is copied to the first input parameter.
void Book::read_entry(BookEntry& entry, int n) const {
void Book::read_entry(BookEntry& entry, int idx) {
assert(n >= 0 && n < bookSize);
assert(bookFile.is_open());
assert(idx >= 0 && idx < bookSize);
assert(is_open());
bookFile.seekg(n*16, std::ios_base::beg);
if (!bookFile.good())
seekg(idx * EntrySize, ios_base::beg);
*this >> entry;
if (!good())
{
std::cerr << "Failed to read book entry at index " << n << std::endl;
exit(EXIT_FAILURE);
cerr << "Failed to read book entry at index " << idx << endl;
Application::exit_with_failure();
}
entry.key = read_integer64(bookFile);
entry.move = read_integer16(bookFile);
entry.count = read_integer16(bookFile);
entry.n = read_integer16(bookFile);
entry.sum = read_integer16(bookFile);
}
/// Book::read_integer() reads size chars from the file stream
/// and converts them in an integer number.
uint64_t Book::read_integer(int size) {
char buf[8];
read(buf, size);
// Numbers are stored on disk as a binary byte stream
uint64_t n = 0ULL;
for (int i = 0; i < size; i++)
n = (n << 8) + (unsigned char)buf[i];
return n;
}
@@ -501,92 +517,67 @@ void Book::read_entry(BookEntry& entry, int n) const {
namespace {
uint64_t book_key(const Position &pos) {
uint64_t book_key(const Position& pos) {
uint64_t result = 0ULL;
for(Color c = WHITE; c <= BLACK; c++) {
Bitboard b = pos.pieces_of_color(c);
Square s;
Piece p;
while(b != EmptyBoardBB) {
s = pop_1st_bit(&b);
p = pos.piece_on(s);
assert(piece_is_ok(p));
assert(color_of_piece(p) == c);
for (Color c = WHITE; c <= BLACK; c++)
{
Bitboard b = pos.pieces_of_color(c);
result ^= book_piece_key(p, s);
}
while (b)
{
Square s = pop_1st_bit(&b);
Piece p = pos.piece_on(s);
assert(piece_is_ok(p));
assert(color_of_piece(p) == c);
result ^= book_piece_key(p, s);
}
}
result ^= book_castle_key(pos);
result ^= book_ep_key(pos);
result ^= book_color_key(pos);
return result;
}
uint64_t book_piece_key(Piece p, Square s) {
return Random64[RandomPiece + (PieceTo12[int(p)]^1)*64 + int(s)];
/// Convert pieces to the range 0..11
static const int PieceTo12[] = { 0, 0, 2, 4, 6, 8, 10, 0, 0, 1, 3, 5, 7, 9, 11 };
return Random64[RandomPiece + (PieceTo12[int(p)]^1) * 64 + int(s)];
}
uint64_t book_castle_key(const Position &pos) {
uint64_t book_castle_key(const Position& pos) {
uint64_t result = 0ULL;
if(pos.can_castle_kingside(WHITE))
result ^= Random64[RandomCastle+0];
if(pos.can_castle_queenside(WHITE))
result ^= Random64[RandomCastle+1];
if(pos.can_castle_kingside(BLACK))
result ^= Random64[RandomCastle+2];
if(pos.can_castle_queenside(BLACK))
result ^= Random64[RandomCastle+3];
if (pos.can_castle_kingside(WHITE))
result ^= Random64[RandomCastle+0];
if (pos.can_castle_queenside(WHITE))
result ^= Random64[RandomCastle+1];
if (pos.can_castle_kingside(BLACK))
result ^= Random64[RandomCastle+2];
if (pos.can_castle_queenside(BLACK))
result ^= Random64[RandomCastle+3];
return result;
}
uint64_t book_ep_key(const Position &pos) {
return (pos.ep_square() == SQ_NONE)?
0ULL : Random64[RandomEnPassant + square_file(pos.ep_square())];
uint64_t book_ep_key(const Position& pos) {
return (pos.ep_square() == SQ_NONE ? 0ULL : Random64[RandomEnPassant + square_file(pos.ep_square())]);
}
uint64_t book_color_key(const Position &pos) {
return (pos.side_to_move() == WHITE)? Random64[RandomTurn] : 0ULL;
}
uint16_t read_integer16(std::ifstream& file) {
uint64_t n = read_integer(file, 2);
assert(n == (uint16_t)n);
return (uint16_t)n;
}
uint64_t read_integer64(std::ifstream& file) {
return read_integer(file, 8);
}
uint64_t read_integer(std::ifstream& file, int size) {
char buf[8];
file.read(buf, size);
if (!file.good())
{
std::cerr << "Failed to read " << size << " bytes from book file"
<< std::endl;
exit(EXIT_FAILURE);
}
// Numbers are stored in little endian format
uint64_t n = 0ULL;
for (int i = 0; i < size; i++)
n = (n << 8) + (unsigned char)buf[i];
return n;
uint64_t book_color_key(const Position& pos) {
return (pos.side_to_move() == WHITE ? Random64[RandomTurn] : 0ULL);
}
}

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2010 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
@@ -52,31 +52,27 @@ struct BookEntry {
uint16_t sum;
};
class Book {
class Book : private std::ifstream {
Book(const Book&); // just decleared..
Book& operator=(const Book&); // ..to avoid a warning
public:
// Constructors
Book();
// Open and close book files
void open(const std::string &fName);
Book() {}
~Book();
void open(const std::string& fName);
void close();
// Testing if a book is opened
bool is_open() const;
// The file name of the currently active book
const std::string file_name() const;
// Get a book move for a given position
Move get_move(const Position &pos) const;
const std::string file_name();
Move get_move(const Position& pos);
private:
int find_key(uint64_t key) const;
void read_entry(BookEntry &entry, int n) const;
Book& operator>>(uint64_t& n) { n = read_integer(8); return *this; }
Book& operator>>(uint16_t& n) { n = (uint16_t)read_integer(2); return *this; }
void operator>>(BookEntry& e) { *this >> e.key >> e.move >> e.count >> e.n >> e.sum; }
uint64_t read_integer(int size);
void read_entry(BookEntry& e, int n);
int find_key(uint64_t key);
std::string fileName;
mutable std::ifstream bookFile;
int bookSize;
};

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2010 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
@@ -37,7 +37,6 @@ enum Color {
//// Inline functions
////
inline Color operator+ (Color c, int i) { return Color(int(c) + i); }
inline void operator++ (Color &c, int) { c = Color(int(c) + 1); }
inline Color opposite_color(Color c) {

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2010 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
@@ -27,7 +27,8 @@
enum Depth {
DEPTH_ZERO = 0,
DEPTH_MAX = 200 // 100 * OnePly;
DEPTH_MAX = 200, // 100 * OnePly;
DEPTH_ENSURE_SIGNED = -1
};
@@ -35,9 +36,6 @@ enum Depth {
//// Constants
////
/// Note: If OnePly is changed, the constant HistoryMax in history.h should
/// probably also be changed.
const Depth OnePly = Depth(2);
@@ -51,7 +49,8 @@ inline void operator+= (Depth &d, int i) { d = Depth(int(d) + i); }
inline void operator+= (Depth &d1, Depth d2) { d1 += int(d2); }
inline Depth operator- (Depth d, int i) { return Depth(int(d) - i); }
inline Depth operator- (Depth d1, Depth d2) { return Depth(int(d1) - int(d2)); }
inline void operator-= (Depth & d, int i) { d = Depth(int(d) - i); }
inline void operator-= (Depth &d, int i) { d = Depth(int(d) - i); }
inline void operator-= (Depth &d1, Depth d2) { d1 -= int(d2); }
inline Depth operator* (Depth d, int i) { return Depth(int(d) * i); }
inline Depth operator* (int i, Depth d) { return Depth(int(d) * i); }
inline void operator*= (Depth &d, int i) { d = Depth(int(d) * i); }

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2010 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
@@ -26,6 +26,32 @@
#include "square.h"
////
//// Local definitions
////
namespace {
const SquareDelta directionToDelta[] = {
DELTA_E, DELTA_W, DELTA_N, DELTA_S, DELTA_NE, DELTA_SW, DELTA_NW, DELTA_SE
};
bool reachable(Square orig, Square dest, SignedDirection dir) {
SquareDelta delta = directionToDelta[dir];
Square from = orig;
Square to = from + delta;
while (to != dest && square_distance(to, from) == 1 && square_is_ok(to))
{
from = to;
to += delta;
}
return (to == dest && square_distance(from, to) == 1);
}
}
////
//// Variables
////
@@ -39,25 +65,23 @@ uint8_t SignedDirectionTable[64][64];
////
void init_direction_table() {
SquareDelta deltas[8] = {
DELTA_E, DELTA_W, DELTA_N, DELTA_S, DELTA_NE, DELTA_SW, DELTA_NW, DELTA_SE
};
for(Square s1 = SQ_A1; s1 <= SQ_H8; s1++)
for(Square s2 = SQ_A1; s2 <= SQ_H8; s2++) {
DirectionTable[s1][s2] = uint8_t(DIR_NONE);
SignedDirectionTable[s1][s2] = uint8_t(SIGNED_DIR_NONE);
if(s1 == s2) continue;
for(SignedDirection d = SIGNED_DIR_E; d <= SIGNED_DIR_SE; d++) {
SquareDelta delta = deltas[d];
Square s3, s4;
for(s4 = s1 + delta, s3 = s1;
square_distance(s4, s3) == 1 && s4 != s2 && square_is_ok(s4);
s3 = s4, s4 += delta);
if(s4 == s2 && square_distance(s4, s3) == 1) {
SignedDirectionTable[s1][s2] = uint8_t(d);
DirectionTable[s1][s2] = uint8_t(d/2);
break;
}
for (Square s1 = SQ_A1; s1 <= SQ_H8; s1++)
for (Square s2 = SQ_A1; s2 <= SQ_H8; s2++)
{
DirectionTable[s1][s2] = uint8_t(DIR_NONE);
SignedDirectionTable[s1][s2] = uint8_t(SIGNED_DIR_NONE);
if (s1 == s2)
continue;
for (SignedDirection d = SIGNED_DIR_E; d != SIGNED_DIR_NONE; d++)
{
if (reachable(s1, s2, d))
{
SignedDirectionTable[s1][s2] = uint8_t(d);
DirectionTable[s1][s2] = uint8_t(d / 2);
break;
}
}
}
}
}

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2010 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

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2010 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
@@ -25,44 +25,10 @@
#include <cassert>
#include "bitbase.h"
#include "bitcount.h"
#include "endgame.h"
////
//// Constants and variables
////
/// Evaluation functions
// Generic "mate lone king" eval
EvaluationFunction<KXK> EvaluateKXK(WHITE), EvaluateKKX(BLACK);
// K and two minors vs K and one or two minors
EvaluationFunction<KmmKm> EvaluateKmmKm(WHITE);
EvaluationFunction<KBNK> EvaluateKBNK(WHITE), EvaluateKKBN(BLACK); // KBN vs K
EvaluationFunction<KPK> EvaluateKPK(WHITE), EvaluateKKP(BLACK); // KP vs K
EvaluationFunction<KRKP> EvaluateKRKP(WHITE), EvaluateKPKR(BLACK); // KR vs KP
EvaluationFunction<KRKB> EvaluateKRKB(WHITE), EvaluateKBKR(BLACK); // KR vs KB
EvaluationFunction<KRKN> EvaluateKRKN(WHITE), EvaluateKNKR(BLACK); // KR vs KN
EvaluationFunction<KQKR> EvaluateKQKR(WHITE), EvaluateKRKQ(BLACK); // KQ vs KR
EvaluationFunction<KBBKN> EvaluateKBBKN(WHITE), EvaluateKNKBB(BLACK); // KBB vs KN
/// Scaling functions
ScalingFunction<KBPK> ScaleKBPK(WHITE), ScaleKKBP(BLACK); // KBP vs K
ScalingFunction<KQKRP> ScaleKQKRP(WHITE), ScaleKRPKQ(BLACK); // KQ vs KRP
ScalingFunction<KRPKR> ScaleKRPKR(WHITE), ScaleKRKRP(BLACK); // KRP vs KR
ScalingFunction<KRPPKRP> ScaleKRPPKRP(WHITE), ScaleKRPKRPP(BLACK); // KRPP vs KRP
ScalingFunction<KPsK> ScaleKPsK(WHITE), ScaleKKPs(BLACK); // King and pawns vs king
ScalingFunction<KBPKB> ScaleKBPKB(WHITE), ScaleKBKBP(BLACK); // KBP vs KB
ScalingFunction<KBPPKB> ScaleKBPPKB(WHITE), ScaleKBKBPP(BLACK); // KBPP vs KB
ScalingFunction<KBPKN> ScaleKBPKN(WHITE), ScaleKNKBP(BLACK); // KBP vs KN
ScalingFunction<KNPK> ScaleKNPK(WHITE), ScaleKKNP(BLACK); // KNP vs K
ScalingFunction<KPKP> ScaleKPKPw(WHITE), ScaleKPKPb(BLACK); // KPKP
////
//// Local definitions
////
@@ -363,7 +329,7 @@ Value EvaluationFunction<KBBKN>::apply(const Position& pos) {
assert(pos.non_pawn_material(strongerSide) == 2*BishopValueMidgame);
assert(pos.piece_count(weakerSide, KNIGHT) == 1);
assert(pos.non_pawn_material(weakerSide) == KnightValueMidgame);
assert(pos.pawns() == EmptyBoardBB);
assert(pos.pieces(PAWN) == EmptyBoardBB);
Value result = BishopValueEndgame;
Square wksq = pos.king_square(strongerSide);
@@ -377,16 +343,23 @@ Value EvaluationFunction<KBBKN>::apply(const Position& pos) {
result += Value(square_distance(bksq, nsq) * 32);
// Bonus for restricting the knight's mobility
result += Value((8 - count_1s_max_15(pos.piece_attacks<KNIGHT>(nsq))) * 8);
result += Value((8 - count_1s_max_15(pos.attacks_from<KNIGHT>(nsq))) * 8);
return (strongerSide == pos.side_to_move() ? result : -result);
}
/// K and two minors vs K and one or two minors or K and two knights against
/// king alone are always draw.
template<>
Value EvaluationFunction<KmmKm>::apply(const Position&) {
return Value(0);
}
template<>
Value EvaluationFunction<KNNK>::apply(const Position&) {
return Value(0);
}
/// KBPKScalingFunction scales endgames where the stronger side has king,
/// bishop and one or more pawns. It checks for draws with rook pawns and a
@@ -394,7 +367,7 @@ Value EvaluationFunction<KmmKm>::apply(const Position&) {
/// returned. If not, the return value is SCALE_FACTOR_NONE, i.e. no scaling
/// will be used.
template<>
ScaleFactor ScalingFunction<KBPK>::apply(const Position& pos) {
ScaleFactor ScalingFunction<KBPsK>::apply(const Position& pos) {
assert(pos.non_pawn_material(strongerSide) == BishopValueMidgame);
assert(pos.piece_count(strongerSide, BISHOP) == 1);
@@ -403,7 +376,7 @@ ScaleFactor ScalingFunction<KBPK>::apply(const Position& pos) {
// No assertions about the material of weakerSide, because we want draws to
// be detected even when the weaker side has some pawns.
Bitboard pawns = pos.pawns(strongerSide);
Bitboard pawns = pos.pieces(PAWN, strongerSide);
File pawnFile = square_file(pos.piece_list(strongerSide, PAWN, 0));
// All pawns are on a single rook file ?
@@ -420,7 +393,6 @@ ScaleFactor ScalingFunction<KBPK>::apply(const Position& pos) {
// The bishop has the wrong color, and the defending king is on the
// file of the pawn(s) or the neighboring file. Find the rank of the
// frontmost pawn.
Rank rank;
if (strongerSide == WHITE)
{
@@ -449,7 +421,7 @@ ScaleFactor ScalingFunction<KBPK>::apply(const Position& pos) {
/// It tests for fortress draws with a rook on the third rank defended by
/// a pawn.
template<>
ScaleFactor ScalingFunction<KQKRP>::apply(const Position& pos) {
ScaleFactor ScalingFunction<KQKRPs>::apply(const Position& pos) {
assert(pos.non_pawn_material(strongerSide) == QueenValueMidgame);
assert(pos.piece_count(strongerSide, QUEEN) == 1);
@@ -460,12 +432,12 @@ ScaleFactor ScalingFunction<KQKRP>::apply(const Position& pos) {
Square kingSq = pos.king_square(weakerSide);
if ( relative_rank(weakerSide, kingSq) <= RANK_2
&& relative_rank(weakerSide, pos.king_square(strongerSide)) >= RANK_4
&& (pos.rooks(weakerSide) & relative_rank_bb(weakerSide, RANK_3))
&& (pos.pawns(weakerSide) & relative_rank_bb(weakerSide, RANK_2))
&& (pos.piece_attacks<KING>(kingSq) & pos.pawns(weakerSide)))
&& (pos.pieces(ROOK, weakerSide) & relative_rank_bb(weakerSide, RANK_3))
&& (pos.pieces(PAWN, weakerSide) & relative_rank_bb(weakerSide, RANK_2))
&& (pos.attacks_from<KING>(kingSq) & pos.pieces(PAWN, weakerSide)))
{
Square rsq = pos.piece_list(weakerSide, ROOK, 0);
if (pos.pawn_attacks(strongerSide, rsq) & pos.pawns(weakerSide))
if (pos.attacks_from<PAWN>(rsq, strongerSide) & pos.pieces(PAWN, weakerSide))
return ScaleFactor(0);
}
return SCALE_FACTOR_NONE;
@@ -644,7 +616,7 @@ ScaleFactor ScalingFunction<KPsK>::apply(const Position &pos) {
assert(pos.non_pawn_material(weakerSide) == Value(0));
assert(pos.piece_count(weakerSide, PAWN) == 0);
Bitboard pawns = pos.pawns(strongerSide);
Bitboard pawns = pos.pieces(PAWN, strongerSide);
// Are all pawns on the 'a' file?
if ((pawns & ~FileABB) == EmptyBoardBB)
@@ -722,9 +694,9 @@ ScaleFactor ScalingFunction<KBPKB>::apply(const Position &pos) {
else
{
Bitboard ray = ray_bb(pawnSq, (strongerSide == WHITE)? SIGNED_DIR_N : SIGNED_DIR_S);
if (ray & pos.kings(weakerSide))
if (ray & pos.pieces(KING, weakerSide))
return ScaleFactor(0);
if( (pos.piece_attacks<BISHOP>(weakerBishopSq) & ray)
if( (pos.attacks_from<BISHOP>(weakerBishopSq) & ray)
&& square_distance(weakerBishopSq, pawnSq) >= 3)
return ScaleFactor(0);
}
@@ -789,13 +761,13 @@ ScaleFactor ScalingFunction<KBPPKB>::apply(const Position& pos) {
if ( ksq == blockSq1
&& square_color(ksq) != square_color(wbsq)
&& ( bbsq == blockSq2
|| (pos.piece_attacks<BISHOP>(blockSq2) & pos.bishops(weakerSide))
|| (pos.attacks_from<BISHOP>(blockSq2) & pos.pieces(BISHOP, weakerSide))
|| rank_distance(r1, r2) >= 2))
return ScaleFactor(0);
else if ( ksq == blockSq2
&& square_color(ksq) != square_color(wbsq)
&& ( bbsq == blockSq1
|| (pos.piece_attacks<BISHOP>(blockSq1) & pos.bishops(weakerSide))))
|| (pos.attacks_from<BISHOP>(blockSq1) & pos.pieces(BISHOP, weakerSide))))
return ScaleFactor(0);
else
return SCALE_FACTOR_NONE;

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2010 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
@@ -45,11 +45,12 @@ enum EndgameType {
KRKN, // KR vs KN
KQKR, // KQ vs KR
KBBKN, // KBB vs KN
KNNK, // KNN vs K
KmmKm, // K and two minors vs K and one or two minors
// Scaling functions
KBPK, // KBP vs K
KQKRP, // KQ vs KRP
KBPsK, // KB+pawns vs K
KQKRPs, // KQ vs KR+pawns
KRPKR, // KRP vs KR
KRPPKRP, // KRPP vs KRP
KPsK, // King and pawns vs king
@@ -65,9 +66,10 @@ enum EndgameType {
template<typename T>
class EndgameFunctionBase {
public:
EndgameFunctionBase(Color c) : strongerSide(c) { weakerSide = opposite_color(strongerSide); }
EndgameFunctionBase(Color c) : strongerSide(c), weakerSide(opposite_color(c)) {}
virtual ~EndgameFunctionBase() {}
virtual T apply(const Position&) = 0;
Color color() const { return strongerSide; }
protected:
Color strongerSide, weakerSide;
@@ -81,42 +83,19 @@ typedef EndgameFunctionBase<ScaleFactor> EndgameScalingFunctionBase;
template<EndgameType>
struct EvaluationFunction : public EndgameEvaluationFunctionBase {
typedef EndgameEvaluationFunctionBase Base;
explicit EvaluationFunction(Color c): EndgameEvaluationFunctionBase(c) {}
Value apply(const Position&);
};
template<EndgameType>
struct ScalingFunction : public EndgameScalingFunctionBase {
typedef EndgameScalingFunctionBase Base;
explicit ScalingFunction(Color c) : EndgameScalingFunctionBase(c) {}
ScaleFactor apply(const Position&);
};
////
//// Constants and variables
////
extern EvaluationFunction<KXK> EvaluateKXK, EvaluateKKX; // Generic "mate lone king" eval
extern EvaluationFunction<KBNK> EvaluateKBNK, EvaluateKKBN; // KBN vs K
extern EvaluationFunction<KPK> EvaluateKPK, EvaluateKKP; // KP vs K
extern EvaluationFunction<KRKP> EvaluateKRKP, EvaluateKPKR; // KR vs KP
extern EvaluationFunction<KRKB> EvaluateKRKB, EvaluateKBKR; // KR vs KB
extern EvaluationFunction<KRKN> EvaluateKRKN, EvaluateKNKR; // KR vs KN
extern EvaluationFunction<KQKR> EvaluateKQKR, EvaluateKRKQ; // KQ vs KR
extern EvaluationFunction<KBBKN> EvaluateKBBKN, EvaluateKNKBB; // KBB vs KN
extern EvaluationFunction<KmmKm> EvaluateKmmKm; // K and two minors vs K and one or two minors:
extern ScalingFunction<KBPK> ScaleKBPK, ScaleKKBP; // KBP vs K
extern ScalingFunction<KQKRP> ScaleKQKRP, ScaleKRPKQ; // KQ vs KRP
extern ScalingFunction<KRPKR> ScaleKRPKR, ScaleKRKRP; // KRP vs KR
extern ScalingFunction<KRPPKRP> ScaleKRPPKRP, ScaleKRPKRPP; // KRPP vs KRP
extern ScalingFunction<KPsK> ScaleKPsK, ScaleKKPs; // King and pawns vs king
extern ScalingFunction<KBPKB> ScaleKBPKB, ScaleKBKBP; // KBP vs KB
extern ScalingFunction<KBPPKB> ScaleKBPPKB, ScaleKBKBPP; // KBPP vs KB
extern ScalingFunction<KBPKN> ScaleKBPKN, ScaleKNKBP; // KBP vs KN
extern ScalingFunction<KNPK> ScaleKNPK, ScaleKKNP; // KNP vs K
extern ScalingFunction<KPKP> ScaleKPKPw, ScaleKPKPb; // KP vs KP
////
//// Prototypes
////

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2010 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
@@ -25,6 +25,8 @@
//// Includes
////
#include <iostream>
#include "material.h"
#include "pawns.h"
@@ -39,30 +41,32 @@
/// arguments to the evaluation function, and the search can make use of its
/// contents to make intelligent search decisions.
///
/// At the moment, this is not utilized very much: The only part of the
/// At the moment, this is not utilized very much: The only part of the
/// EvalInfo object which is used by the search is futilityMargin.
class Position;
struct EvalInfo {
EvalInfo() { futilityMargin[0] = futilityMargin[1] = Value(0); }
// Middle game and endgame evaluations
Value mgValue, egValue;
Score value;
// Pointers to material and pawn hash table entries
MaterialInfo* mi;
PawnInfo* pi;
// attackedBy[color][piece type] is a bitboard representing all squares
// attacked by a given color and piece type. attackedBy[color][0] contains
// attacked by a given color and piece type, attackedBy[color][0] contains
// all squares attacked by the given color.
Bitboard attackedBy[2][8];
Bitboard attacked_by(Color c) const { return attackedBy[c][0]; }
Bitboard attacked_by(Color c, PieceType pt) const { return attackedBy[c][pt]; }
// kingZone[color] is the zone around the enemy king which is considered
// by the king safety evaluation. This consists of the squares directly
// by the king safety evaluation. This consists of the squares directly
// adjacent to the king, and the three (or two, for a king on an edge file)
// squares two ranks in front of the king. For instance, if black's king
// squares two ranks in front of the king. For instance, if black's king
// is on g8, kingZone[WHITE] is a bitboard containing the squares f8, h8,
// f7, g7, h7, f6, g6 and h6.
Bitboard kingZone[2];
@@ -89,11 +93,11 @@ struct EvalInfo {
Move mateThreat[2];
// Middle game and endgame mobility scores.
Value mgMobility, egMobility;
Score mobility;
// Extra futility margin. This is added to the standard futility margin
// in the quiescence search.
Value futilityMargin;
// Extra futility margin. This is added to the standard futility margin
// in the quiescence search. One for each color.
Value futilityMargin[2];
};
@@ -102,7 +106,6 @@ struct EvalInfo {
////
extern Value evaluate(const Position& pos, EvalInfo& ei, int threadID);
extern Value quick_evaluate(const Position& pos);
extern void init_eval(int threads);
extern void quit_eval();
extern void read_weights(Color sideToMove);

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2010 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
@@ -32,71 +32,84 @@
//// Functions
////
/// Constructor
History::History() {
this->clear();
}
History::History() { clear(); }
/// History::clear() clears the history tables.
/// History::clear() clears the history tables
void History::clear() {
memset(history, 0, 2 * 8 * 64 * sizeof(int));
memset(successCount, 0, 2 * 8 * 64 * sizeof(int));
memset(failureCount, 0, 2 * 8 * 64 * sizeof(int));
memset(maxStaticValueDelta, 0, 2 * 8 * 64 * sizeof(int));
}
/// History::success() registers a move as being successful. This is done
/// History::success() registers a move as being successful. This is done
/// whenever a non-capturing move causes a beta cutoff in the main search.
/// The three parameters are the moving piece, the move itself, and the
/// search depth.
/// The three parameters are the moving piece, the destination square, and
/// the search depth.
void History::success(Piece p, Square to, Depth d) {
void History::success(Piece p, Move m, Depth d) {
assert(piece_is_ok(p));
assert(move_is_ok(m));
assert(square_is_ok(to));
history[p][move_to(m)] += int(d) * int(d);
successCount[p][move_to(m)]++;
history[p][to] += int(d) * int(d);
// Prevent history overflow:
if(history[p][move_to(m)] >= HistoryMax)
for(int i = 0; i < 16; i++)
for(int j = 0; j < 64; j++)
history[i][j] /= 2;
// Prevent history overflow
if (history[p][to] >= HistoryMax)
for (int i = 0; i < 16; i++)
for (int j = 0; j < 64; j++)
history[i][j] /= 2;
}
/// History::failure() registers a move as being unsuccessful. The function is
/// History::failure() registers a move as being unsuccessful. The function is
/// called for each non-capturing move which failed to produce a beta cutoff
/// at a node where a beta cutoff was finally found.
void History::failure(Piece p, Move m) {
assert(piece_is_ok(p));
assert(move_is_ok(m));
void History::failure(Piece p, Square to, Depth d) {
failureCount[p][move_to(m)]++;
assert(piece_is_ok(p));
assert(square_is_ok(to));
history[p][to] -= int(d) * int(d);
// Prevent history underflow
if (history[p][to] <= -HistoryMax)
for (int i = 0; i < 16; i++)
for (int j = 0; j < 64; j++)
history[i][j] /= 2;
}
/// History::move_ordering_score() returns an integer value used to order the
/// non-capturing moves in the MovePicker class.
int History::move_ordering_score(Piece p, Move m) const {
assert(piece_is_ok(p));
assert(move_is_ok(m));
int History::move_ordering_score(Piece p, Square to) const {
return history[p][move_to(m)];
assert(piece_is_ok(p));
assert(square_is_ok(to));
return history[p][to];
}
/// History::ok_to_prune() decides whether a move has been sufficiently
/// unsuccessful that it makes sense to prune it entirely.
/// History::set_gain() and History::gain() store and retrieve the
/// gain of a move given the delta of the static position evaluations
/// before and after the move.
bool History::ok_to_prune(Piece p, Move m, Depth d) const {
assert(piece_is_ok(p));
assert(move_is_ok(m));
return (int(d) * successCount[p][move_to(m)] < failureCount[p][move_to(m)]);
void History::set_gain(Piece p, Square to, Value delta)
{
if (delta >= maxStaticValueDelta[p][to])
maxStaticValueDelta[p][to] = delta;
else
maxStaticValueDelta[p][to]--;
}
Value History::gain(Piece p, Square to) const
{
return Value(maxStaticValueDelta[p][to]);
}

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2010 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
@@ -28,30 +28,34 @@
#include "depth.h"
#include "move.h"
#include "piece.h"
#include "value.h"
////
//// Types
////
/// The History class stores statistics about how often different moves have
/// been successful or unsuccessful during the current search. These
/// statistics are used for reduction and move ordering decisions.
/// The History class stores statistics about how often different moves
/// have been successful or unsuccessful during the current search. These
/// statistics are used for reduction and move ordering decisions. History
/// entries are stored according only to moving piece and destination square,
/// in particular two moves with different origin but same destination and
/// same piece will be considered identical.
class History {
public:
History();
void clear();
void success(Piece p, Move m, Depth d);
void failure(Piece p, Move m);
int move_ordering_score(Piece p, Move m) const;
bool ok_to_prune(Piece p, Move m, Depth d) const;
void success(Piece p, Square to, Depth d);
void failure(Piece p, Square to, Depth d);
int move_ordering_score(Piece p, Square to) const;
void set_gain(Piece p, Square to, Value delta);
Value gain(Piece p, Square to) const;
private:
int history[16][64]; // [piece][square]
int successCount[16][64];
int failureCount[16][64];
int maxStaticValueDelta[16][64]; // [piece][from_square][to_square]
};
@@ -61,17 +65,13 @@ private:
/// HistoryMax controls how often the history counters will be scaled down:
/// When the history score for a move gets bigger than HistoryMax, all
/// entries in the table are divided by 2. It is difficult to guess what
/// the ideal value of this constant is. Scaling down the scores often has
/// entries in the table are divided by 2. It is difficult to guess what
/// the ideal value of this constant is. Scaling down the scores often has
/// the effect that parts of the search tree which have been searched
/// recently have a bigger importance for move ordering than the moves which
/// have been searched a long time ago.
///
/// Note that HistoryMax should probably be changed whenever the constant
/// OnePly in depth.h is changed. This is somewhat annoying. Perhaps it
/// would be better to scale down the history table at regular intervals?
const int HistoryMax = 50000;
const int HistoryMax = 50000 * OnePly;
#endif // !defined(HISTORY_H_INCLUDED)

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2010 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
@@ -23,7 +23,7 @@
// x86 assembly language locks or OS spin locks may perform faster than
// mutex locks on some platforms. On my machine, mutexes seem to be the
// mutex locks on some platforms. On my machine, mutexes seem to be the
// best.
//#define ASM_LOCK
@@ -86,8 +86,9 @@ typedef pthread_mutex_t Lock;
#else
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#undef WIN32_LEAN_AND_MEAN
typedef CRITICAL_SECTION Lock;
# define lock_init(x, y) InitializeCriticalSection(x)
@@ -98,5 +99,4 @@ typedef CRITICAL_SECTION Lock;
#endif
#endif // !defined(LOCK_H_INCLUDED)

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2010 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
@@ -17,29 +17,28 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// To profile with callgrind uncomment following line
//#define USE_CALLGRIND
////
//// Includes
////
#include <iostream>
#include <string>
#include "benchmark.h"
#include "bitboard.h"
#include "direction.h"
#include "endgame.h"
#include "evaluate.h"
#include "material.h"
#include "mersenne.h"
#include "bitcount.h"
#include "misc.h"
#include "movepick.h"
#include "position.h"
#include "search.h"
#include "thread.h"
#include "uci.h"
#include "ucioption.h"
using std::string;
#ifdef USE_CALLGRIND
#include <valgrind/callgrind.h>
#endif
using namespace std;
////
//// Functions
@@ -48,50 +47,43 @@ using std::string;
int main(int argc, char *argv[]) {
// Disable IO buffering
std::cout.rdbuf()->pubsetbuf(NULL, 0);
std::cin.rdbuf()->pubsetbuf(NULL, 0);
cout.rdbuf()->pubsetbuf(NULL, 0);
cin.rdbuf()->pubsetbuf(NULL, 0);
// Initialization
init_mersenne();
init_direction_table();
init_bitboards();
init_uci_options();
Position::init_zobrist();
Position::init_piece_square_tables();
MovePicker::init_phase_table();
init_eval(1);
init_bitbases();
init_threads();
// Initialization through global resources manager
Application::initialize();
// Make random number generation less deterministic, for book moves
for (int i = abs(get_system_time() % 10000); i > 0; i--)
genrand_int32();
#ifdef USE_CALLGRIND
CALLGRIND_START_INSTRUMENTATION;
#endif
// Process command line arguments
if (argc >= 2 && string(argv[1]) == "bench")
// Process command line arguments if any
if (argc > 1)
{
if (argc < 4 || argc > 7)
if (string(argv[1]) != "bench" || argc < 4 || argc > 8)
cout << "Usage: stockfish bench <hash size> <threads> "
<< "[time = 60s] [fen positions file = default] "
<< "[time, depth, perft or node limited = time] "
<< "[timing file name = none]" << endl;
else
{
std::cout << "Usage: stockfish bench <hash size> <threads> "
<< "[time = 60s] [fen positions file = default] "
<< "[time, depth or node limited = time]"
<< std::endl;
exit(0);
string time = argc > 4 ? argv[4] : "60";
string fen = argc > 5 ? argv[5] : "default";
string lim = argc > 6 ? argv[6] : "time";
string tim = argc > 7 ? argv[7] : "";
benchmark(string(argv[2]) + " " + string(argv[3]) + " " + time + " " + fen + " " + lim + " " + tim);
}
string time = argc > 4 ? argv[4] : "60";
string fen = argc > 5 ? argv[5] : "default";
string lim = argc > 6 ? argv[6] : "time";
benchmark(string(argv[2]) + " " + string(argv[3]) + " " + time + " " + fen + " " + lim);
return 0;
}
// Print copyright notice
std::cout << engine_name() << ". Copyright (C) "
<< "2004-2008 Tord Romstad, Marco Costalba. "
<< std::endl;
cout << engine_name()
<< ". By Tord Romstad, Marco Costalba, Joona Kiiski." << endl;
if (CpuHasPOPCNT)
cout << "Good! CPU has hardware POPCNT. We will use it." << endl;
// Enter UCI mode
uci_main_loop();
return 0;
}

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2010 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
@@ -23,12 +23,13 @@
////
#include <cassert>
#include <cstring>
#include <sstream>
#include <map>
#include "material.h"
using namespace std;
////
//// Local definitions
@@ -36,84 +37,119 @@
namespace {
const Value BishopPairMidgameBonus = Value(109);
const Value BishopPairEndgameBonus = Value(97);
// Values modified by Joona Kiiski
const Value MidgameLimit = Value(15581);
const Value EndgameLimit = Value(3998);
Key KNNKMaterialKey, KKNNMaterialKey;
// Polynomial material balance parameters
const Value RedundantQueenPenalty = Value(320);
const Value RedundantRookPenalty = Value(554);
const int LinearCoefficients[6] = { 1617, -162, -1172, -190, 105, 26 };
const int QuadraticCoefficientsSameColor[][6] = {
{ 7, 7, 7, 7, 7, 7 }, { 39, 2, 7, 7, 7, 7 }, { 35, 271, -4, 7, 7, 7 },
{ 7, 25, 4, 7, 7, 7 }, { -27, -2, 46, 100, 56, 7 }, { 58, 29, 83, 148, -3, -25 } };
const int QuadraticCoefficientsOppositeColor[][6] = {
{ 41, 41, 41, 41, 41, 41 }, { 37, 41, 41, 41, 41, 41 }, { 10, 62, 41, 41, 41, 41 },
{ 57, 64, 39, 41, 41, 41 }, { 50, 40, 23, -22, 41, 41 }, { 106, 101, 3, 151, 171, 41 } };
// Named endgame evaluation and scaling functions, these
// are accessed direcly and not through the function maps.
EvaluationFunction<KmmKm> EvaluateKmmKm(WHITE);
EvaluationFunction<KXK> EvaluateKXK(WHITE), EvaluateKKX(BLACK);
ScalingFunction<KBPsK> ScaleKBPsK(WHITE), ScaleKKBPs(BLACK);
ScalingFunction<KQKRPs> ScaleKQKRPs(WHITE), ScaleKRPsKQ(BLACK);
ScalingFunction<KPsK> ScaleKPsK(WHITE), ScaleKKPs(BLACK);
ScalingFunction<KPKP> ScaleKPKPw(WHITE), ScaleKPKPb(BLACK);
typedef EndgameEvaluationFunctionBase EF;
typedef EndgameScalingFunctionBase SF;
}
////
//// Classes
////
/// See header for a class description. It is declared here to avoid
/// to include <map> in the header file.
/// EndgameFunctions class stores endgame evaluation and scaling functions
/// in two std::map. Because STL library is not guaranteed to be thread
/// safe even for read access, the maps, although with identical content,
/// are replicated for each thread. This is faster then using locks.
class EndgameFunctions {
public:
EndgameFunctions();
EndgameEvaluationFunctionBase* getEEF(Key key) const;
EndgameScalingFunctionBase* getESF(Key key, Color* c) const;
~EndgameFunctions();
template<class T> T* get(Key key) const;
private:
void add(const std::string& keyCode, EndgameEvaluationFunctionBase* f);
void add(const std::string& keyCode, Color c, EndgameScalingFunctionBase* f);
Key buildKey(const std::string& keyCode);
template<class T> void add(const string& keyCode);
struct ScalingInfo
{
Color col;
EndgameScalingFunctionBase* fun;
};
static Key buildKey(const string& keyCode);
static const string swapColors(const string& keyCode);
std::map<Key, EndgameEvaluationFunctionBase*> EEFmap;
std::map<Key, ScalingInfo> ESFmap;
// Here we store two maps, for evaluate and scaling functions
pair<map<Key, EF*>, map<Key, SF*> > maps;
// Maps accessing functions returning const and non-const references
template<typename T> const map<Key, T*>& get() const { return maps.first; }
template<typename T> map<Key, T*>& get() { return maps.first; }
};
// Explicit specializations of a member function shall be declared in
// the namespace of which the class template is a member.
template<> const map<Key, SF*>&
EndgameFunctions::get<SF>() const { return maps.second; }
template<> map<Key, SF*>&
EndgameFunctions::get<SF>() { return maps.second; }
////
//// Functions
////
/// Constructor for the MaterialInfoTable class
/// MaterialInfoTable c'tor and d'tor, called once by each thread
MaterialInfoTable::MaterialInfoTable(unsigned int numOfEntries) {
size = numOfEntries;
entries = new MaterialInfo[size];
funcs = new EndgameFunctions();
if (!entries || !funcs)
{
std::cerr << "Failed to allocate " << (numOfEntries * sizeof(MaterialInfo))
<< " bytes for material hash table." << std::endl;
exit(EXIT_FAILURE);
cerr << "Failed to allocate " << numOfEntries * sizeof(MaterialInfo)
<< " bytes for material hash table." << endl;
Application::exit_with_failure();
}
clear();
}
/// Destructor for the MaterialInfoTable class
MaterialInfoTable::~MaterialInfoTable() {
delete [] entries;
delete funcs;
delete [] entries;
}
/// MaterialInfoTable::clear() clears a material hash table by setting
/// all entries to 0.
/// MaterialInfoTable::game_phase() calculates the phase given the current
/// position. Because the phase is strictly a function of the material, it
/// is stored in MaterialInfo.
void MaterialInfoTable::clear() {
Phase MaterialInfoTable::game_phase(const Position& pos) {
memset(entries, 0, size * sizeof(MaterialInfo));
Value npm = pos.non_pawn_material(WHITE) + pos.non_pawn_material(BLACK);
if (npm >= MidgameLimit)
return PHASE_MIDGAME;
else if (npm <= EndgameLimit)
return PHASE_ENDGAME;
return Phase(((npm - EndgameLimit) * 128) / (MidgameLimit - EndgameLimit));
}
/// MaterialInfoTable::get_material_info() takes a position object as input,
/// computes or looks up a MaterialInfo object, and returns a pointer to it.
/// If the material configuration is not already present in the table, it
@@ -136,42 +172,37 @@ MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) {
mi->clear();
mi->key = key;
// A special case before looking for a specialized evaluation function
// KNN vs K is a draw.
if (key == KNNKMaterialKey || key == KKNNMaterialKey)
{
mi->factor[WHITE] = mi->factor[BLACK] = 0;
return mi;
}
// Store game phase
mi->gamePhase = MaterialInfoTable::game_phase(pos);
// Let's look if we have a specialized evaluation function for this
// particular material configuration. First we look for a fixed
// configuration one, then a generic one if previous search failed.
if ((mi->evaluationFunction = funcs->getEEF(key)) != NULL)
if ((mi->evaluationFunction = funcs->get<EF>(key)) != NULL)
return mi;
else if ( pos.non_pawn_material(BLACK) == Value(0)
&& pos.piece_count(BLACK, PAWN) == 0
&& pos.non_pawn_material(WHITE) >= RookValueEndgame)
&& pos.non_pawn_material(WHITE) >= RookValueMidgame)
{
mi->evaluationFunction = &EvaluateKXK;
return mi;
}
else if ( pos.non_pawn_material(WHITE) == Value(0)
&& pos.piece_count(WHITE, PAWN) == 0
&& pos.non_pawn_material(BLACK) >= RookValueEndgame)
&& pos.non_pawn_material(BLACK) >= RookValueMidgame)
{
mi->evaluationFunction = &EvaluateKKX;
return mi;
}
else if ( pos.pawns() == EmptyBoardBB
&& pos.rooks() == EmptyBoardBB
&& pos.queens() == EmptyBoardBB)
else if ( pos.pieces(PAWN) == EmptyBoardBB
&& pos.pieces(ROOK) == EmptyBoardBB
&& pos.pieces(QUEEN) == EmptyBoardBB)
{
// Minor piece endgame with at least one minor piece per side,
// and no pawns.
assert(pos.knights(WHITE) | pos.bishops(WHITE));
assert(pos.knights(BLACK) | pos.bishops(BLACK));
// Minor piece endgame with at least one minor piece per side and
// no pawns. Note that the case KmmK is already handled by KXK.
assert((pos.pieces(KNIGHT, WHITE) | pos.pieces(BISHOP, WHITE)));
assert((pos.pieces(KNIGHT, BLACK) | pos.pieces(BISHOP, BLACK)));
if ( pos.piece_count(WHITE, BISHOP) + pos.piece_count(WHITE, KNIGHT) <= 2
&& pos.piece_count(BLACK, BISHOP) + pos.piece_count(BLACK, KNIGHT) <= 2)
@@ -185,41 +216,43 @@ MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) {
// material configuration. Is there a suitable scaling function?
//
// The code below is rather messy, and it could easily get worse later,
// if we decide to add more special cases. We face problems when there
// if we decide to add more special cases. We face problems when there
// are several conflicting applicable scaling functions and we need to
// decide which one to use.
Color c;
EndgameScalingFunctionBase* sf;
SF* sf;
if ((sf = funcs->getESF(key, &c)) != NULL)
if ((sf = funcs->get<SF>(key)) != NULL)
{
mi->scalingFunction[c] = sf;
mi->scalingFunction[sf->color()] = sf;
return mi;
}
// Generic scaling functions that refer to more then one material
// distribution. Should be probed after the specialized ones.
// Note that these ones don't return after setting the function.
if ( pos.non_pawn_material(WHITE) == BishopValueMidgame
&& pos.piece_count(WHITE, BISHOP) == 1
&& pos.piece_count(WHITE, PAWN) >= 1)
mi->scalingFunction[WHITE] = &ScaleKBPK;
mi->scalingFunction[WHITE] = &ScaleKBPsK;
if ( pos.non_pawn_material(BLACK) == BishopValueMidgame
&& pos.piece_count(BLACK, BISHOP) == 1
&& pos.piece_count(BLACK, PAWN) >= 1)
mi->scalingFunction[BLACK] = &ScaleKKBP;
mi->scalingFunction[BLACK] = &ScaleKKBPs;
if ( pos.piece_count(WHITE, PAWN) == 0
&& pos.non_pawn_material(WHITE) == QueenValueMidgame
&& pos.piece_count(WHITE, QUEEN) == 1
&& pos.piece_count(BLACK, ROOK) == 1
&& pos.piece_count(BLACK, PAWN) >= 1)
mi->scalingFunction[WHITE] = &ScaleKQKRP;
mi->scalingFunction[WHITE] = &ScaleKQKRPs;
else if ( pos.piece_count(BLACK, PAWN) == 0
&& pos.non_pawn_material(BLACK) == QueenValueMidgame
&& pos.piece_count(BLACK, QUEEN) == 1
&& pos.piece_count(WHITE, ROOK) == 1
&& pos.piece_count(WHITE, PAWN) >= 1)
mi->scalingFunction[BLACK] = &ScaleKRPKQ;
mi->scalingFunction[BLACK] = &ScaleKRPsKQ;
if (pos.non_pawn_material(WHITE) + pos.non_pawn_material(BLACK) == Value(0))
{
@@ -235,6 +268,8 @@ MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) {
}
else if (pos.piece_count(WHITE, PAWN) == 1 && pos.piece_count(BLACK, PAWN) == 1)
{
// This is a special case because we set scaling functions
// for both colors instead of only one.
mi->scalingFunction[WHITE] = &ScaleKPKPw;
mi->scalingFunction[BLACK] = &ScaleKPKPb;
}
@@ -253,10 +288,13 @@ MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) {
}
// Evaluate the material balance
int sign;
Value egValue = Value(0);
Value mgValue = Value(0);
const int pieceCount[2][6] = { { pos.piece_count(WHITE, BISHOP) > 1, pos.piece_count(WHITE, PAWN), pos.piece_count(WHITE, KNIGHT),
pos.piece_count(WHITE, BISHOP), pos.piece_count(WHITE, ROOK), pos.piece_count(WHITE, QUEEN) },
{ pos.piece_count(BLACK, BISHOP) > 1, pos.piece_count(BLACK, PAWN), pos.piece_count(BLACK, KNIGHT),
pos.piece_count(BLACK, BISHOP), pos.piece_count(BLACK, ROOK), pos.piece_count(BLACK, QUEEN) } };
Color c, them;
int sign, pt1, pt2, pc;
int v, vv, matValue = 0;
for (c = WHITE, sign = 1; c <= BLACK; c++, sign = -sign)
{
@@ -283,85 +321,80 @@ MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) {
}
}
// Bishop pair
if (pos.piece_count(c, BISHOP) >= 2)
{
mgValue += sign * BishopPairMidgameBonus;
egValue += sign * BishopPairEndgameBonus;
}
// Knights are stronger when there are many pawns on the board. The
// formula is taken from Larry Kaufman's paper "The Evaluation of Material
// Imbalances in Chess":
// Redundancy of major pieces, formula based on Kaufman's paper
// "The Evaluation of Material Imbalances in Chess"
// http://mywebpages.comcast.net/danheisman/Articles/evaluation_of_material_imbalance.htm
mgValue += sign * Value(pos.piece_count(c, KNIGHT)*(pos.piece_count(c, PAWN)-5)*16);
egValue += sign * Value(pos.piece_count(c, KNIGHT)*(pos.piece_count(c, PAWN)-5)*16);
if (pieceCount[c][ROOK] >= 1)
matValue -= sign * ((pieceCount[c][ROOK] - 1) * RedundantRookPenalty + pieceCount[c][QUEEN] * RedundantQueenPenalty);
// Redundancy of major pieces, again based on Kaufman's paper:
if (pos.piece_count(c, ROOK) >= 1)
them = opposite_color(c);
v = 0;
// Second-degree polynomial material imbalance by Tord Romstad
//
// We use NO_PIECE_TYPE as a place holder for the bishop pair "extended piece",
// this allow us to be more flexible in defining bishop pair bonuses.
for (pt1 = NO_PIECE_TYPE; pt1 <= QUEEN; pt1++)
{
Value v = Value((pos.piece_count(c, ROOK) - 1) * 32 + pos.piece_count(c, QUEEN) * 16);
mgValue -= sign * v;
egValue -= sign * v;
pc = pieceCount[c][pt1];
if (!pc)
continue;
vv = LinearCoefficients[pt1];
for (pt2 = NO_PIECE_TYPE; pt2 <= pt1; pt2++)
vv += pieceCount[c][pt2] * QuadraticCoefficientsSameColor[pt1][pt2]
+ pieceCount[them][pt2] * QuadraticCoefficientsOppositeColor[pt1][pt2];
v += pc * vv;
}
matValue += sign * v;
}
mi->mgValue = int16_t(mgValue);
mi->egValue = int16_t(egValue);
mi->value = int16_t(matValue / 16);
return mi;
}
/// EndgameFunctions member definitions. This class is used to store the maps
/// of end game and scaling functions that MaterialInfoTable will query for
/// each key. The maps are constant and are populated only at construction,
/// but are per-thread instead of globals to avoid expensive locks.
/// EndgameFunctions member definitions.
EndgameFunctions::EndgameFunctions() {
KNNKMaterialKey = buildKey("KNNK");
KKNNMaterialKey = buildKey("KKNN");
add<EvaluationFunction<KNNK> >("KNNK");
add<EvaluationFunction<KPK> >("KPK");
add<EvaluationFunction<KBNK> >("KBNK");
add<EvaluationFunction<KRKP> >("KRKP");
add<EvaluationFunction<KRKB> >("KRKB");
add<EvaluationFunction<KRKN> >("KRKN");
add<EvaluationFunction<KQKR> >("KQKR");
add<EvaluationFunction<KBBKN> >("KBBKN");
add("KPK", &EvaluateKPK);
add("KKP", &EvaluateKKP);
add("KBNK", &EvaluateKBNK);
add("KKBN", &EvaluateKKBN);
add("KRKP", &EvaluateKRKP);
add("KPKR", &EvaluateKPKR);
add("KRKB", &EvaluateKRKB);
add("KBKR", &EvaluateKBKR);
add("KRKN", &EvaluateKRKN);
add("KNKR", &EvaluateKNKR);
add("KQKR", &EvaluateKQKR);
add("KRKQ", &EvaluateKRKQ);
add("KBBKN", &EvaluateKBBKN);
add("KNKBB", &EvaluateKNKBB);
add("KNPK", WHITE, &ScaleKNPK);
add("KKNP", BLACK, &ScaleKKNP);
add("KRPKR", WHITE, &ScaleKRPKR);
add("KRKRP", BLACK, &ScaleKRKRP);
add("KBPKB", WHITE, &ScaleKBPKB);
add("KBKBP", BLACK, &ScaleKBKBP);
add("KBPPKB", WHITE, &ScaleKBPPKB);
add("KBKBPP", BLACK, &ScaleKBKBPP);
add("KBPKN", WHITE, &ScaleKBPKN);
add("KNKBP", BLACK, &ScaleKNKBP);
add("KRPPKRP", WHITE, &ScaleKRPPKRP);
add("KRPKRPP", BLACK, &ScaleKRPKRPP);
add("KRPPKRP", WHITE, &ScaleKRPPKRP);
add("KRPKRPP", BLACK, &ScaleKRPKRPP);
add<ScalingFunction<KNPK> >("KNPK");
add<ScalingFunction<KRPKR> >("KRPKR");
add<ScalingFunction<KBPKB> >("KBPKB");
add<ScalingFunction<KBPPKB> >("KBPPKB");
add<ScalingFunction<KBPKN> >("KBPKN");
add<ScalingFunction<KRPPKRP> >("KRPPKRP");
}
Key EndgameFunctions::buildKey(const std::string& keyCode) {
EndgameFunctions::~EndgameFunctions() {
for (map<Key, EF*>::iterator it = maps.first.begin(); it != maps.first.end(); ++it)
delete (*it).second;
for (map<Key, SF*>::iterator it = maps.second.begin(); it != maps.second.end(); ++it)
delete (*it).second;
}
Key EndgameFunctions::buildKey(const string& keyCode) {
assert(keyCode.length() > 0 && keyCode[0] == 'K');
assert(keyCode.length() < 8);
std::stringstream s;
stringstream s;
bool upcase = false;
// Build up a fen substring with the given pieces, note
// that the fen string could be of an illegal position.
// Build up a fen string with the given pieces, note that
// the fen string could be of an illegal position.
for (size_t i = 0; i < keyCode.length(); i++)
{
if (keyCode[i] == 'K')
@@ -373,29 +406,25 @@ Key EndgameFunctions::buildKey(const std::string& keyCode) {
return Position(s.str()).get_material_key();
}
void EndgameFunctions::add(const std::string& keyCode, EndgameEvaluationFunctionBase* f) {
const string EndgameFunctions::swapColors(const string& keyCode) {
EEFmap.insert(std::pair<Key, EndgameEvaluationFunctionBase*>(buildKey(keyCode), f));
// Build corresponding key for the opposite color: "KBPKN" -> "KNKBP"
size_t idx = keyCode.find("K", 1);
return keyCode.substr(idx) + keyCode.substr(0, idx);
}
void EndgameFunctions::add(const std::string& keyCode, Color c, EndgameScalingFunctionBase* f) {
template<class T>
void EndgameFunctions::add(const string& keyCode) {
ScalingInfo s = {c, f};
ESFmap.insert(std::pair<Key, ScalingInfo>(buildKey(keyCode), s));
typedef typename T::Base F;
get<F>().insert(pair<Key, F*>(buildKey(keyCode), new T(WHITE)));
get<F>().insert(pair<Key, F*>(buildKey(swapColors(keyCode)), new T(BLACK)));
}
EndgameEvaluationFunctionBase* EndgameFunctions::getEEF(Key key) const {
template<class T>
T* EndgameFunctions::get(Key key) const {
std::map<Key, EndgameEvaluationFunctionBase*>::const_iterator it(EEFmap.find(key));
return (it != EEFmap.end() ? it->second : NULL);
}
EndgameScalingFunctionBase* EndgameFunctions::getESF(Key key, Color* c) const {
std::map<Key, ScalingInfo>::const_iterator it(ESFmap.find(key));
if (it == ESFmap.end())
return NULL;
*c = it->second.col;
return it->second.fun;
typename map<Key, T*>::const_iterator it(get<T>().find(key));
return (it != get<T>().end() ? it->second : NULL);
}

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2010 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
@@ -49,47 +49,42 @@ class MaterialInfo {
friend class MaterialInfoTable;
public:
Value mg_value() const;
Value eg_value() const;
MaterialInfo() : key(0) { clear(); }
Score material_value() const;
ScaleFactor scale_factor(const Position& pos, Color c) const;
int space_weight() const;
Phase game_phase() const;
bool specialized_eval_exists() const;
Value evaluate(const Position& pos) const;
private:
void clear();
inline void clear();
Key key;
int16_t mgValue;
int16_t egValue;
int16_t value;
uint8_t factor[2];
EndgameEvaluationFunctionBase* evaluationFunction;
EndgameScalingFunctionBase* scalingFunction[2];
int spaceWeight;
Phase gamePhase;
};
/// EndgameFunctions class stores the endgame evaluation functions std::map.
/// Because STL library is not thread safe even for read access, the maps,
/// although with identical content, are replicated for each thread. This
/// is faster then using locks with an unique set of global maps.
class EndgameFunctions;
/// The MaterialInfoTable class represents a pawn hash table. It is basically
/// just an array of MaterialInfo objects and a few methods for accessing these
/// objects. The most important method is get_material_info, which looks up a
/// position in the table and returns a pointer to a MaterialInfo object.
class EndgameFunctions;
class MaterialInfoTable {
public:
MaterialInfoTable(unsigned numOfEntries);
~MaterialInfoTable();
void clear();
MaterialInfo* get_material_info(const Position& pos);
static Phase game_phase(const Position& pos);
private:
unsigned size;
MaterialInfo* entries;
@@ -101,35 +96,31 @@ private:
//// Inline functions
////
/// MaterialInfo::mg_value and MaterialInfo::eg_value simply returns the
/// material balance evaluation for the middle game and the endgame.
inline Value MaterialInfo::mg_value() const {
/// MaterialInfo::material_value simply returns the material balance
/// evaluation that is independent from game phase.
return Value(mgValue);
}
inline Score MaterialInfo::material_value() const {
inline Value MaterialInfo::eg_value() const {
return Value(egValue);
return make_score(value, value);
}
/// MaterialInfo::clear() resets a MaterialInfo object to an empty state,
/// with all slots at their default values.
/// with all slots at their default values but the key.
inline void MaterialInfo::clear() {
mgValue = egValue = 0;
value = 0;
factor[WHITE] = factor[BLACK] = uint8_t(SCALE_FACTOR_NORMAL);
spaceWeight = 0;
evaluationFunction = NULL;
scalingFunction[WHITE] = scalingFunction[BLACK] = NULL;
spaceWeight = 0;
}
/// MaterialInfo::scale_factor takes a position and a color as input, and
/// returns a scale factor for the given color. We have to provide the
/// returns a scale factor for the given color. We have to provide the
/// position in addition to the color, because the scale factor need not
/// to be a constant: It can also be a function which should be applied to
/// the position. For instance, in KBP vs K endgames, a scaling function
@@ -155,6 +146,14 @@ inline int MaterialInfo::space_weight() const {
return spaceWeight;
}
/// MaterialInfo::game_phase() returns the game phase according
/// to this material configuration.
inline Phase MaterialInfo::game_phase() const {
return gamePhase;
}
/// MaterialInfo::specialized_eval_exists decides whether there is a
/// specialized evaluation function for the current material configuration,
@@ -167,7 +166,7 @@ inline bool MaterialInfo::specialized_eval_exists() const {
/// MaterialInfo::evaluate applies a specialized evaluation function
/// to a given position object. It should only be called when
/// to a given position object. It should only be called when
/// specialized_eval_exists() returns 'true'.
inline Value MaterialInfo::evaluate(const Position& pos) const {

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2010 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

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2010 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
@@ -27,34 +27,15 @@
# include <sys/time.h>
# include <sys/types.h>
# include <unistd.h>
# if defined(__hpux)
# include <sys/pstat.h>
# endif
#else
/*
(c) Copyright 1992 Eric Backus
This software may be used freely so long as this copyright notice is
left intact. There is no warrantee on this software.
*/
# include <windows.h>
# include <time.h>
# include "dos.h"
static int gettimeofday(struct timeval* tp, struct timezone*)
{
SYSTEMTIME systime;
if (tp)
{
struct tm tmrec;
time_t theTime = time(NULL);
tmrec = *localtime(&theTime);
tp->tv_sec = mktime(&tmrec);
GetLocalTime(&systime); /* system time */
tp->tv_usec = systime.wMilliseconds * 1000;
}
return 0;
}
#define _CRT_SECURE_NO_DEPRECATE
#include <windows.h>
#include <sys/timeb.h>
#endif
@@ -64,14 +45,16 @@ static int gettimeofday(struct timeval* tp, struct timezone*)
#include <iostream>
#include <sstream>
#include "bitcount.h"
#include "misc.h"
#include "thread.h"
using namespace std;
/// Version number. If this is left empty, the current date (in the format
/// YYMMDD) is used as a version number.
static const string EngineVersion = "1.3.1";
static const string EngineVersion = "1.7.1";
static const string AppName = "Stockfish";
static const string AppTag = "";
@@ -80,8 +63,10 @@ static const string AppTag = "";
//// Variables
////
long dbg_cnt0 = 0;
long dbg_cnt1 = 0;
bool Chess960;
uint64_t dbg_cnt0 = 0;
uint64_t dbg_cnt1 = 0;
bool dbg_show_mean = false;
bool dbg_show_hit_rate = false;
@@ -159,8 +144,10 @@ void dbg_print_mean(ofstream& logFile) {
const string engine_name() {
const string cpu64(CpuHas64BitPath ? " 64bit" : "");
if (!EngineVersion.empty())
return "Stockfish " + EngineVersion;
return AppName+ " " + EngineVersion + cpu64;
string date(__DATE__); // From compiler, format is "Sep 21 2008"
string months("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec");
@@ -173,7 +160,7 @@ const string engine_name() {
string name = AppName + " " + AppTag + " ";
s << name << date.substr(date.length() - 2) << setfill('0')
<< setw(2) << mon << setw(2) << day;
<< setw(2) << mon << setw(2) << day << cpu64;
return s.str();
}
@@ -183,9 +170,16 @@ const string engine_name() {
/// milliseconds.
int get_system_time() {
struct timeval t;
gettimeofday(&t, NULL);
return t.tv_sec*1000 + t.tv_usec/1000;
#if defined(_MSC_VER)
struct _timeb t;
_ftime(&t);
return int(t.time*1000 + t.millitm);
#else
struct timeval t;
gettimeofday(&t, NULL);
return t.tv_sec*1000 + t.tv_usec/1000;
#endif
}
@@ -195,7 +189,15 @@ int get_system_time() {
# if defined(_SC_NPROCESSORS_ONLN)
int cpu_count() {
return Min(sysconf(_SC_NPROCESSORS_ONLN), 8);
return Min(sysconf(_SC_NPROCESSORS_ONLN), MAX_THREADS);
}
# elif defined(__hpux)
int cpu_count() {
struct pst_dynamic psd;
if (pstat_getdynamic(&psd, sizeof(psd), (size_t)1, 0) == -1)
return 1;
return Min(psd.psd_proc_cnt, MAX_THREADS);
}
# else
int cpu_count() {
@@ -208,7 +210,7 @@ int cpu_count() {
int cpu_count() {
SYSTEM_INFO s;
GetSystemInfo(&s);
return Min(s.dwNumberOfProcessors, 8);
return Min(s.dwNumberOfProcessors, MAX_THREADS);
}
#endif

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2010 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
@@ -29,6 +29,8 @@
#include <fstream>
#include <string>
#include "application.h"
#include "types.h"
////
//// Macros
@@ -38,6 +40,13 @@
#define Max(x, y) (((x) < (y))? (y) : (x))
////
//// Variables
////
extern bool Chess960;
////
//// Prototypes
////
@@ -47,6 +56,7 @@ extern int get_system_time();
extern int cpu_count();
extern int Bioskey();
////
//// Debug
////
@@ -54,8 +64,8 @@ extern int Bioskey();
extern bool dbg_show_mean;
extern bool dbg_show_hit_rate;
extern long dbg_cnt0;
extern long dbg_cnt1;
extern uint64_t dbg_cnt0;
extern uint64_t dbg_cnt1;
extern void dbg_hit_on(bool b);
extern void dbg_hit_on_c(bool c, bool b);

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2010 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
@@ -27,7 +27,6 @@
#include "move.h"
#include "piece.h"
#include "position.h"
#include "ucioption.h"
////
@@ -130,8 +129,8 @@ const std::string move_to_string(Move move) {
return (from == SQ_E1 ? "e1c1" : "e8c8");
}
str = square_to_string(from) + square_to_string(to);
if (move_promotion(move))
str += piece_type_to_char(move_promotion(move), false);
if (move_is_promotion(move))
str += piece_type_to_char(move_promotion_piece(move), false);
}
return str;
}

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2010 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
@@ -62,9 +62,83 @@ struct MoveStack {
int score;
};
// Note that operator< is set up such that std::sort() will sort in descending order
// Note that operator< is set up such that sorting will be in descending order
inline bool operator<(const MoveStack& f, const MoveStack& s) { return s.score < f.score; }
// An helper insertion sort implementation
template<typename T>
inline void insertion_sort(T* firstMove, T* lastMove)
{
T value;
T *cur, *p, *d;
if (firstMove != lastMove)
for (cur = firstMove + 1; cur != lastMove; cur++)
{
p = d = cur;
value = *p--;
if (value < *p)
{
do *d = *p;
while (--d != firstMove && value < *--p);
*d = value;
}
}
}
// Our dedicated sort in range [firstMove, lastMove), first splits
// positive scores from ramining then order seaprately the two sets.
template<typename T>
inline void sort_moves(T* firstMove, T* lastMove, T** lastPositive)
{
T tmp;
T *p, *d;
d = lastMove;
p = firstMove - 1;
d->score = -1; // right guard
// Split positives vs non-positives
do {
while ((++p)->score > 0);
if (p != d)
{
while (--d != p && d->score <= 0);
tmp = *p;
*p = *d;
*d = tmp;
}
} while (p != d);
// Sort just positive scored moves, remaining only when we get there
insertion_sort<T>(firstMove, p);
*lastPositive = p;
}
// Picks up the best move in range [curMove, lastMove), one per cycle.
// It is faster then sorting all the moves in advance when moves are few,
// as normally are the possible captures. Note that is not a stable alghoritm.
template<typename T>
inline T pick_best(T* curMove, T* lastMove)
{
T bestMove, tmp;
bestMove = *curMove;
while (++curMove != lastMove)
{
if (*curMove < bestMove)
{
tmp = *curMove;
*curMove = bestMove;
bestMove = tmp;
}
}
return bestMove;
}
////
//// Inline functions
@@ -78,16 +152,24 @@ inline Square move_to(Move m) {
return Square(m & 0x3F);
}
inline PieceType move_promotion(Move m) {
inline PieceType move_promotion_piece(Move m) {
return PieceType((int(m) >> 12) & 7);
}
inline bool move_is_ep(Move m) {
return bool((int(m) >> 15) & 1);
inline int move_is_special(Move m) {
return m & (0x1F << 12);
}
inline bool move_is_castle(Move m) {
return bool((int(m) >> 16) & 1);
inline int move_is_promotion(Move m) {
return m & (7 << 12);
}
inline int move_is_ep(Move m) {
return m & (1 << 15);
}
inline int move_is_castle(Move m) {
return m & (1 << 16);
}
inline bool move_is_short_castle(Move m) {
@@ -119,7 +201,7 @@ inline Move make_ep_move(Square from, Square to) {
//// Prototypes
////
extern std::ostream &operator << (std::ostream &os, Move m);
extern std::ostream& operator<<(std::ostream &os, Move m);
extern Move move_from_string(const Position &pos, const std::string &str);
extern const std::string move_to_string(Move m);
extern bool move_is_ok(Move m);

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2010 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
@@ -32,12 +32,13 @@
//// Prototypes
////
extern int generate_captures(const Position& pos, MoveStack* mlist);
extern int generate_noncaptures(const Position& pos, MoveStack* mlist);
extern int generate_non_capture_checks(const Position& pos, MoveStack* mlist, Bitboard dc);
extern int generate_evasions(const Position& pos, MoveStack* mlist, Bitboard pinned);
extern int generate_legal_moves(const Position& pos, MoveStack* mlist);
extern MoveStack* generate_captures(const Position& pos, MoveStack* mlist);
extern MoveStack* generate_noncaptures(const Position& pos, MoveStack* mlist);
extern MoveStack* generate_non_capture_checks(const Position& pos, MoveStack* mlist);
extern MoveStack* generate_evasions(const Position& pos, MoveStack* mlist);
extern MoveStack* generate_moves(const Position& pos, MoveStack* mlist, bool pseudoLegal = false);
extern bool move_is_legal(const Position& pos, const Move m, Bitboard pinned);
extern bool move_is_legal(const Position& pos, const Move m);
#endif // !defined(MOVEGEN_H_INCLUDED)

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2010 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
@@ -23,11 +23,9 @@
//// Includes
////
#include <algorithm>
#include <cassert>
#include "history.h"
#include "evaluate.h"
#include "movegen.h"
#include "movepick.h"
#include "search.h"
@@ -40,14 +38,23 @@
namespace {
/// Variables
MovePicker::MovegenPhase PhaseTable[32];
int MainSearchPhaseIndex;
int EvasionsPhaseIndex;
int QsearchWithChecksPhaseIndex;
int QsearchWithoutChecksPhaseIndex;
enum MovegenPhase {
PH_TT_MOVES, // Transposition table move and mate killer
PH_GOOD_CAPTURES, // Queen promotions and captures with SEE values >= 0
PH_KILLERS, // Killer moves from the current ply
PH_NONCAPTURES, // Non-captures and underpromotions
PH_BAD_CAPTURES, // Queen promotions and captures with SEE values < 0
PH_EVASIONS, // Check evasions
PH_QCAPTURES, // Captures in quiescence search
PH_QCHECKS, // Non-capture checks in quiescence search
PH_STOP
};
CACHE_LINE_ALIGNMENT
const uint8_t MainSearchPhaseTable[] = { PH_TT_MOVES, PH_GOOD_CAPTURES, PH_KILLERS, PH_NONCAPTURES, PH_BAD_CAPTURES, PH_STOP};
const uint8_t EvasionsPhaseTable[] = { PH_TT_MOVES, PH_EVASIONS, PH_STOP};
const uint8_t QsearchWithChecksPhaseTable[] = { PH_TT_MOVES, PH_QCAPTURES, PH_QCHECKS, PH_STOP};
const uint8_t QsearchWithoutChecksPhaseTable[] = { PH_TT_MOVES, PH_QCAPTURES, PH_STOP};
}
@@ -56,195 +63,153 @@ namespace {
////
/// Constructor for the MovePicker class. Apart from the position for which
/// Constructor for the MovePicker class. Apart from the position for which
/// it is asked to pick legal moves, MovePicker also wants some 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 about how important good
/// move ordering is at the current node.
MovePicker::MovePicker(const Position& p, bool pv, Move ttm,
const SearchStack& ss, Depth d) : pos(p) {
pvNode = pv;
ttMove = ttm;
mateKiller = (ss.mateKiller == ttm)? MOVE_NONE : ss.mateKiller;
killer1 = ss.killers[0];
killer2 = ss.killers[1];
depth = d;
movesPicked = 0;
numOfMoves = 0;
numOfBadCaptures = 0;
MovePicker::MovePicker(const Position& p, Move ttm, Depth d,
const History& h, SearchStack* ss, Value beta) : pos(p), H(h) {
int searchTT = ttm;
ttMoves[0].move = ttm;
lastBadCapture = badCaptures;
badCaptureThreshold = 0;
pinned = p.pinned_pieces(pos.side_to_move());
if (ss && !p.is_check())
{
ttMoves[1].move = (ss->mateKiller == ttm)? MOVE_NONE : ss->mateKiller;
searchTT |= ttMoves[1].move;
killers[0].move = ss->killers[0];
killers[1].move = ss->killers[1];
} else
ttMoves[1].move = killers[0].move = killers[1].move = MOVE_NONE;
if (p.is_check())
phaseIndex = EvasionsPhaseIndex;
else if (depth > Depth(0))
phaseIndex = MainSearchPhaseIndex;
else if (depth == Depth(0))
phaseIndex = QsearchWithChecksPhaseIndex;
phasePtr = EvasionsPhaseTable;
else if (d > Depth(0))
{
// Consider sligtly negative captures as good if at low
// depth and far from beta.
if (ss && ss->eval < beta - PawnValueMidgame && d < 3 * OnePly)
badCaptureThreshold = -PawnValueMidgame;
phasePtr = MainSearchPhaseTable;
} else if (d == Depth(0))
phasePtr = QsearchWithChecksPhaseTable;
else
phaseIndex = QsearchWithoutChecksPhaseIndex;
{
phasePtr = QsearchWithoutChecksPhaseTable;
Color us = pos.side_to_move();
// Skip TT move if is not a capture or a promotion, this avoids
// qsearch tree explosion due to a possible perpetual check or
// similar rare cases when TT table is full.
if (ttm != MOVE_NONE && !pos.move_is_capture_or_promotion(ttm))
searchTT = ttMoves[0].move = MOVE_NONE;
}
dc = p.discovered_check_candidates(us);
pinned = p.pinned_pieces(us);
finished = false;
phasePtr += !searchTT - 1;
go_next_phase();
}
/// MovePicker::get_next_move() is the most important method of the MovePicker
/// class. It returns a new legal move every time it is called, until there
/// are no more moves left of the types we are interested in.
/// MovePicker::go_next_phase() generates, scores and sorts the next bunch
/// of moves when there are no more moves to try for the current phase.
Move MovePicker::get_next_move() {
void MovePicker::go_next_phase() {
Move move;
curMove = moves;
phase = *(++phasePtr);
switch (phase) {
while (true)
{
// If we already have a list of generated moves, pick the best move from
// the list, and return it.
move = pick_move_from_list();
if (move != MOVE_NONE)
{
assert(move_is_ok(move));
return move;
}
case PH_TT_MOVES:
curMove = ttMoves;
lastMove = curMove + 2;
return;
// Next phase
phaseIndex++;
switch (PhaseTable[phaseIndex]) {
case PH_GOOD_CAPTURES:
lastMove = generate_captures(pos, moves);
score_captures();
return;
case PH_TT_MOVE:
if (ttMove != MOVE_NONE)
{
assert(move_is_ok(ttMove));
if (move_is_legal(pos, ttMove, pinned))
return ttMove;
}
break;
case PH_KILLERS:
curMove = killers;
lastMove = curMove + 2;
return;
case PH_MATE_KILLER:
if (mateKiller != MOVE_NONE)
{
assert(move_is_ok(mateKiller));
if (move_is_legal(pos, mateKiller, pinned))
return mateKiller;
}
break;
case PH_NONCAPTURES:
lastMove = generate_noncaptures(pos, moves);
score_noncaptures();
sort_moves(moves, lastMove, &lastGoodNonCapture);
return;
case PH_GOOD_CAPTURES:
numOfMoves = generate_captures(pos, moves);
score_captures();
std::sort(moves, moves + numOfMoves);
movesPicked = 0;
break;
case PH_BAD_CAPTURES:
// Bad captures SEE value is already calculated so just sort them
// to get SEE move ordering.
curMove = badCaptures;
lastMove = lastBadCapture;
return;
case PH_BAD_CAPTURES:
// It's probably a good idea to use SEE move ordering here. FIXME
movesPicked = 0;
break;
case PH_EVASIONS:
assert(pos.is_check());
lastMove = generate_evasions(pos, moves);
score_evasions_or_checks();
return;
case PH_NONCAPTURES:
numOfMoves = generate_noncaptures(pos, moves);
score_noncaptures();
std::sort(moves, moves + numOfMoves);
movesPicked = 0;
break;
case PH_QCAPTURES:
lastMove = generate_captures(pos, moves);
score_captures();
return;
case PH_EVASIONS:
assert(pos.is_check());
numOfMoves = generate_evasions(pos, moves, pinned);
score_evasions();
std::sort(moves, moves + numOfMoves);
movesPicked = 0;
break;
case PH_QCHECKS:
lastMove = generate_non_capture_checks(pos, moves);
score_evasions_or_checks();
return;
case PH_QCAPTURES:
numOfMoves = generate_captures(pos, moves);
score_qcaptures();
std::sort(moves, moves + numOfMoves);
movesPicked = 0;
break;
case PH_STOP:
lastMove = curMove + 1; // Avoids another go_next_phase() call
return;
case PH_QCHECKS:
// Perhaps we should order moves move here? FIXME
numOfMoves = generate_non_capture_checks(pos, moves, dc);
movesPicked = 0;
break;
case PH_STOP:
return MOVE_NONE;
default:
assert(false);
return MOVE_NONE;
}
default:
assert(false);
return;
}
}
/// A variant of get_next_move() which takes a lock as a parameter, used to
/// prevent multiple threads from picking the same move at a split point.
Move MovePicker::get_next_move(Lock &lock) {
lock_grab(&lock);
if (finished)
{
lock_release(&lock);
return MOVE_NONE;
}
Move m = get_next_move();
if (m == MOVE_NONE)
finished = true;
lock_release(&lock);
return m;
}
/// MovePicker::score_captures(), MovePicker::score_noncaptures(),
/// MovePicker::score_evasions() and MovePicker::score_qcaptures() assign a
/// numerical move ordering score to each move in a move list. The moves
/// with highest scores will be picked first by pick_move_from_list().
/// MovePicker::score_captures(), MovePicker::score_noncaptures() and
/// MovePicker::score_evasions() assign a numerical move ordering score
/// to each move in a move list. The moves with highest scores will be
/// picked first by get_next_move().
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
// 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
// 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.
// While scoring captures it moves all captures with negative SEE values
// to the badCaptures[] array.
// In main search we want to push captures with negative SEE values to
// badCaptures[] array, but instead of doing it now we delay till when
// the move has been picked up in pick_move_from_list(), this way we save
// some SEE calls in case we get a cutoff (idea from Pablo Vazquez).
Move m;
int seeValue;
for (int i = 0; i < numOfMoves; i++)
// Use MVV/LVA ordering
for (MoveStack* cur = moves; cur != lastMove; cur++)
{
m = moves[i].move;
seeValue = pos.see(m);
if (seeValue >= 0)
{
if (move_promotion(m))
moves[i].score = QueenValueMidgame;
else
moves[i].score = int(pos.midgame_value_of_piece_on(move_to(m)))
-int(pos.type_of_piece_on(move_from(m)));
}
m = cur->move;
if (move_is_promotion(m))
cur->score = QueenValueMidgame;
else
{
// Losing capture, move it to the badCaptures[] array
assert(numOfBadCaptures < 63);
moves[i].score = seeValue;
badCaptures[numOfBadCaptures++] = moves[i];
moves[i--] = moves[--numOfMoves];
}
cur->score = pos.midgame_value_of_piece_on(move_to(m))
- pos.type_of_piece_on(move_from(m));
}
}
@@ -253,156 +218,150 @@ void MovePicker::score_noncaptures() {
// piece/square tables values. This seems to be better then a
// random choice when we don't have an history for any move.
Move m;
Piece piece;
Square from, to;
int hs;
for (int i = 0; i < numOfMoves; i++)
for (MoveStack* cur = moves; cur != lastMove; cur++)
{
m = moves[i].move;
m = cur->move;
from = move_from(m);
to = move_to(m);
piece = pos.piece_on(from);
hs = H.move_ordering_score(piece, to);
if (m == killer1)
hs = HistoryMax + 2;
else if (m == killer2)
hs = HistoryMax + 1;
else
hs = H.move_ordering_score(pos.piece_on(move_from(m)), m);
// Ensure history is always preferred to pst
// Ensure history has always highest priority
if (hs > 0)
hs += 1000;
hs += 10000;
// pst based scoring
moves[i].score = hs + pos.mg_pst_delta(m);
// Gain table based scoring
cur->score = hs + 16 * H.gain(piece, to);
}
}
void MovePicker::score_evasions() {
void MovePicker::score_evasions_or_checks() {
// Try good captures ordered by MVV/LVA, then non-captures if
// destination square is not under attack, ordered by history
// value, and at the end bad-captures and non-captures with a
// negative SEE. This last group is ordered by the SEE score.
Move m;
int seeScore;
for (int i = 0; i < numOfMoves; i++)
// Skip if we don't have at least two moves to order
if (lastMove < moves + 2)
return;
for (MoveStack* cur = moves; cur != lastMove; cur++)
{
Move m = moves[i].move;
if (m == ttMove)
moves[i].score = 2*HistoryMax;
else if (!pos.square_is_empty(move_to(m)))
{
int seeScore = pos.see(m);
moves[i].score = (seeScore >= 0)? seeScore + HistoryMax : seeScore;
} else
moves[i].score = H.move_ordering_score(pos.piece_on(move_from(m)), m);
}
}
void MovePicker::score_qcaptures() {
// Use MVV/LVA ordering
for (int i = 0; i < numOfMoves; i++)
{
Move m = moves[i].move;
if (move_promotion(m))
moves[i].score = QueenValueMidgame;
m = cur->move;
if ((seeScore = pos.see_sign(m)) < 0)
cur->score = seeScore - HistoryMax; // Be sure are at the bottom
else if (pos.move_is_capture(m))
cur->score = pos.midgame_value_of_piece_on(move_to(m))
- pos.type_of_piece_on(move_from(m)) + HistoryMax;
else
moves[i].score = int(pos.midgame_value_of_piece_on(move_to(m)))
-int(pos.type_of_piece_on(move_from(m)));
cur->score = H.move_ordering_score(pos.piece_on(move_from(m)), move_to(m));
}
}
/// MovePicker::get_next_move() is the most important method of the MovePicker
/// class. It returns a new legal move every time it is called, until there
/// are no more moves left.
/// It picks the move with the biggest score from a list of generated moves taking
/// care not to return the tt move if has already been searched previously.
/// Note that this function is not thread safe so should be lock protected by
/// caller when accessed through a shared MovePicker object.
/// MovePicker::pick_move_from_list() picks the move with the biggest score
/// from a list of generated moves (moves[] or badCaptures[], depending on
/// the current move generation phase). It takes care not to return the
/// transposition table move if that has already been serched previously.
Move MovePicker::get_next_move() {
Move MovePicker::pick_move_from_list() {
Move move;
assert(movesPicked >= 0);
assert(!pos.is_check() || PhaseTable[phaseIndex] == PH_EVASIONS || PhaseTable[phaseIndex] == PH_STOP);
assert( pos.is_check() || PhaseTable[phaseIndex] != PH_EVASIONS);
switch (PhaseTable[phaseIndex]) {
case PH_GOOD_CAPTURES:
case PH_NONCAPTURES:
while (movesPicked < numOfMoves)
while (true)
{
while (curMove != lastMove)
{
Move move = moves[movesPicked++].move;
if ( move != ttMove
&& move != mateKiller
&& pos.pl_move_is_legal(move, pinned))
switch (phase) {
case PH_TT_MOVES:
move = (curMove++)->move;
if ( move != MOVE_NONE
&& move_is_legal(pos, move, pinned))
return move;
break;
case PH_GOOD_CAPTURES:
move = pick_best(curMove++, lastMove).move;
if ( move != ttMoves[0].move
&& move != ttMoves[1].move
&& pos.pl_move_is_legal(move, pinned))
{
// Check for a non negative SEE now
int seeValue = pos.see_sign(move);
if (seeValue >= badCaptureThreshold)
return move;
// Losing capture, move it to the badCaptures[] array, note
// that move has now been already checked for legality.
assert(int(lastBadCapture - badCaptures) < 63);
lastBadCapture->move = move;
lastBadCapture->score = seeValue;
lastBadCapture++;
}
break;
case PH_KILLERS:
move = (curMove++)->move;
if ( move != MOVE_NONE
&& move != ttMoves[0].move
&& move != ttMoves[1].move
&& move_is_legal(pos, move, pinned)
&& !pos.move_is_capture(move))
return move;
break;
case PH_NONCAPTURES:
// Sort negative scored moves only when we get there
if (curMove == lastGoodNonCapture)
insertion_sort(lastGoodNonCapture, lastMove);
move = (curMove++)->move;
if ( move != ttMoves[0].move
&& move != ttMoves[1].move
&& move != killers[0].move
&& move != killers[1].move
&& pos.pl_move_is_legal(move, pinned))
return move;
break;
case PH_BAD_CAPTURES:
move = pick_best(curMove++, lastMove).move;
return move;
case PH_EVASIONS:
case PH_QCAPTURES:
move = pick_best(curMove++, lastMove).move;
if ( move != ttMoves[0].move
&& pos.pl_move_is_legal(move, pinned))
return move;
break;
case PH_QCHECKS:
move = (curMove++)->move;
if ( move != ttMoves[0].move
&& pos.pl_move_is_legal(move, pinned))
return move;
break;
case PH_STOP:
return MOVE_NONE;
default:
assert(false);
break;
}
}
break;
case PH_EVASIONS:
if (movesPicked < numOfMoves)
return moves[movesPicked++].move;
break;
case PH_BAD_CAPTURES:
while (movesPicked < numOfBadCaptures)
{
Move move = badCaptures[movesPicked++].move;
if ( move != ttMove
&& move != mateKiller
&& pos.pl_move_is_legal(move, pinned))
return move;
}
break;
case PH_QCAPTURES:
case PH_QCHECKS:
while (movesPicked < numOfMoves)
{
Move move = moves[movesPicked++].move;
// Maybe postpone the legality check until after futility pruning?
if ( move != ttMove
&& pos.pl_move_is_legal(move, pinned))
return move;
}
break;
default:
break;
go_next_phase();
}
return MOVE_NONE;
}
/// MovePicker::init_phase_table() initializes the PhaseTable[],
/// MainSearchPhaseIndex, EvasionPhaseIndex, QsearchWithChecksPhaseIndex
/// and QsearchWithoutChecksPhaseIndex. It is only called once during
/// program startup, and never again while the program is running.
void MovePicker::init_phase_table() {
int i = 0;
// Main search
MainSearchPhaseIndex = i - 1;
PhaseTable[i++] = PH_TT_MOVE;
PhaseTable[i++] = PH_MATE_KILLER;
PhaseTable[i++] = PH_GOOD_CAPTURES;
// PH_KILLER_1 and PH_KILLER_2 are not yet used.
// PhaseTable[i++] = PH_KILLER_1;
// PhaseTable[i++] = PH_KILLER_2;
PhaseTable[i++] = PH_NONCAPTURES;
PhaseTable[i++] = PH_BAD_CAPTURES;
PhaseTable[i++] = PH_STOP;
// Check evasions
EvasionsPhaseIndex = i - 1;
PhaseTable[i++] = PH_EVASIONS;
PhaseTable[i++] = PH_STOP;
// Quiescence search with checks
QsearchWithChecksPhaseIndex = i - 1;
PhaseTable[i++] = PH_TT_MOVE;
PhaseTable[i++] = PH_QCAPTURES;
PhaseTable[i++] = PH_QCHECKS;
PhaseTable[i++] = PH_STOP;
// Quiescence search without checks
QsearchWithoutChecksPhaseIndex = i - 1;
PhaseTable[i++] = PH_TT_MOVE;
PhaseTable[i++] = PH_QCAPTURES;
PhaseTable[i++] = PH_STOP;
}

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2010 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
@@ -26,7 +26,7 @@
////
#include "depth.h"
#include "lock.h"
#include "history.h"
#include "position.h"
@@ -34,12 +34,11 @@
//// Types
////
struct EvalInfo;
struct SearchStack;
/// MovePicker is a class which is used to pick one legal move at a time from
/// the current position. It is initialized with a Position object and a few
/// moves we have reason to believe are good. The most important method is
/// the current position. It is initialized with a Position object and a few
/// moves we have reason to believe are good. The most important method is
/// MovePicker::pick_next_move(), which returns a new legal move each time it
/// is called, until there are no legal moves left, when MOVE_NONE is returned.
/// In order to improve the efficiency of the alpha beta algorithm, MovePicker
@@ -47,50 +46,27 @@ struct SearchStack;
class MovePicker {
MovePicker& operator=(const MovePicker&); // Silence a warning under MSVC
MovePicker& operator=(const MovePicker&); // silence a warning under MSVC
public:
enum MovegenPhase {
PH_TT_MOVE, // Transposition table move
PH_MATE_KILLER, // Mate killer from the current ply
PH_GOOD_CAPTURES, // Queen promotions and captures with SEE values >= 0
PH_BAD_CAPTURES, // Queen promotions and captures with SEE values < 0
PH_KILLER_1, // Killer move 1 from the current ply (not used yet).
PH_KILLER_2, // Killer move 2 from the current ply (not used yet).
PH_NONCAPTURES, // Non-captures and underpromotions
PH_EVASIONS, // Check evasions
PH_QCAPTURES, // Captures in quiescence search
PH_QCHECKS, // Checks in quiescence search
PH_STOP
};
MovePicker(const Position& p, bool pvnode, Move ttm, const SearchStack& ss, Depth d);
MovePicker(const Position& p, Move ttm, Depth d, const History& h, SearchStack* ss = NULL, Value beta = -VALUE_INFINITE);
Move get_next_move();
Move get_next_move(Lock &lock);
int number_of_moves() const;
int current_move_score() const;
Bitboard discovered_check_candidates() const;
static void init_phase_table();
int number_of_evasions() const;
private:
void score_captures();
void score_noncaptures();
void score_evasions();
void score_qcaptures();
Move pick_move_from_list();
void score_evasions_or_checks();
void go_next_phase();
const Position& pos;
Move ttMove, mateKiller, killer1, killer2;
Bitboard pinned, dc;
const History& H;
MoveStack ttMoves[2], killers[2];
int badCaptureThreshold, phase;
const uint8_t* phasePtr;
MoveStack *curMove, *lastMove, *lastGoodNonCapture, *lastBadCapture;
Bitboard pinned;
MoveStack moves[256], badCaptures[64];
bool pvNode;
Depth depth;
int phaseIndex;
int numOfMoves, numOfBadCaptures;
int movesPicked;
bool finished;
};
@@ -98,21 +74,14 @@ private:
//// Inline functions
////
/// MovePicker::number_of_moves() simply returns the numOfMoves member
/// variable. It is intended to be used in positions where the side to move
/// is in check, for detecting checkmates or situations where there is only
/// a single reply to check.
/// MovePicker::number_of_evasions() simply returns the number of moves in
/// evasions phase. It is intended to be used in positions where the side to
/// move is in check, for detecting checkmates or situations where there is
/// only a single reply to check.
/// WARNING: It works as long as PH_EVASIONS is the _only_ phase for evasions.
inline int MovePicker::number_of_moves() const {
return numOfMoves;
}
/// MovePicker::discovered_check_candidates() returns a bitboard containing
/// all pieces which can possibly give discovered check. This bitboard is
/// computed by the constructor function.
inline Bitboard MovePicker::discovered_check_candidates() const {
return dc;
inline int MovePicker::number_of_evasions() const {
return int(lastMove - moves);
}
#endif // !defined(MOVEPICK_H_INCLUDED)

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2010 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
@@ -25,6 +25,7 @@
#include <cassert>
#include <cstring>
#include "bitcount.h"
#include "pawns.h"
#include "position.h"
@@ -37,95 +38,67 @@ namespace {
/// Constants and variables
// Doubled pawn penalty by file, middle game.
const Value DoubledPawnMidgamePenalty[8] = {
Value(20), Value(30), Value(34), Value(34),
Value(34), Value(34), Value(30), Value(20)
#define S(mg, eg) make_score(mg, eg)
// Doubled pawn penalty by file
const Score DoubledPawnPenalty[8] = {
S(13, 43), S(20, 48), S(23, 48), S(23, 48),
S(23, 48), S(23, 48), S(20, 48), S(13, 43)
};
// Doubled pawn penalty by file, endgame.
const Value DoubledPawnEndgamePenalty[8] = {
Value(35), Value(40), Value(40), Value(40),
Value(40), Value(40), Value(40), Value(35)
// Isolated pawn penalty by file
const Score IsolatedPawnPenalty[8] = {
S(25, 30), S(36, 35), S(40, 35), S(40, 35),
S(40, 35), S(40, 35), S(36, 35), S(25, 30)
};
// Isolated pawn penalty by file, middle game.
const Value IsolatedPawnMidgamePenalty[8] = {
Value(20), Value(30), Value(34), Value(34),
Value(34), Value(34), Value(30), Value(20)
// Backward pawn penalty by file
const Score BackwardPawnPenalty[8] = {
S(20, 28), S(29, 31), S(33, 31), S(33, 31),
S(33, 31), S(33, 31), S(29, 31), S(20, 28)
};
// Isolated pawn penalty by file, endgame.
const Value IsolatedPawnEndgamePenalty[8] = {
Value(35), Value(40), Value(40), Value(40),
Value(40), Value(40), Value(40), Value(35)
// Pawn chain membership bonus by file
const Score ChainBonus[8] = {
S(11,-1), S(13,-1), S(13,-1), S(14,-1),
S(14,-1), S(13,-1), S(13,-1), S(11,-1)
};
// Backward pawn penalty by file, middle game.
const Value BackwardPawnMidgamePenalty[8] = {
Value(16), Value(24), Value(27), Value(27),
Value(27), Value(27), Value(24), Value(16)
// Candidate passed pawn bonus by rank
const Score CandidateBonus[8] = {
S( 0, 0), S( 6, 13), S(6,13), S(14,29),
S(34,68), S(83,166), S(0, 0), S( 0, 0)
};
// Backward pawn penalty by file, endgame.
const Value BackwardPawnEndgamePenalty[8] = {
Value(28), Value(32), Value(32), Value(32),
Value(32), Value(32), Value(32), Value(28)
};
// Pawn chain membership bonus by file, middle game.
const Value ChainMidgameBonus[8] = {
Value(14), Value(16), Value(17), Value(18),
Value(18), Value(17), Value(16), Value(14)
};
// Pawn chain membership bonus by file, endgame.
const Value ChainEndgameBonus[8] = {
Value(16), Value(16), Value(16), Value(16),
Value(16), Value(16), Value(16), Value(16)
};
// Candidate passed pawn bonus by rank, middle game.
const Value CandidateMidgameBonus[8] = {
Value( 0), Value(12), Value(12), Value(20),
Value(40), Value(90), Value( 0), Value( 0)
};
// Candidate passed pawn bonus by rank, endgame.
const Value CandidateEndgameBonus[8] = {
Value( 0), Value(24), Value(24), Value(40),
Value(80), Value(180), Value(0), Value( 0)
};
// Pawn storm tables for positions with opposite castling:
// Pawn storm tables for positions with opposite castling
const int QStormTable[64] = {
0, 0, 0, 0, 0, 0, 0, 0,
-22,-22,-22,-13,-4, 0, 0, 0,
-4, -9, -9, -9,-4, 0, 0, 0,
9, 18, 22, 18, 9, 0, 0, 0,
22, 31, 31, 22, 0, 0, 0, 0,
31, 40, 40, 31, 0, 0, 0, 0,
31, 40, 40, 31, 0, 0, 0, 0,
-22,-22,-22,-14,-6, 0, 0, 0,
-6,-10,-10,-10,-6, 0, 0, 0,
4, 12, 16, 12, 4, 0, 0, 0,
16, 23, 23, 16, 0, 0, 0, 0,
23, 31, 31, 23, 0, 0, 0, 0,
23, 31, 31, 23, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
};
const int KStormTable[64] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0,-4,-13,-22,-27,-27,
0, 0, 0,-4, -9,-13,-18,-18,
0, 0, 0, 0, 9, 9, 9, 9,
0, 0, 0, 0, 9, 18, 27, 27,
0, 0, 0, 0, 9, 27, 40, 36,
0, 0, 0, 0, 0, 31, 40, 31,
0, 0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0,-10,-19,-28,-33,-33,
0, 0, 0,-10,-15,-19,-24,-24,
0, 0, 0, 0, 1, 1, 1, 1,
0, 0, 0, 0, 1, 10, 19, 19,
0, 0, 0, 0, 1, 19, 31, 27,
0, 0, 0, 0, 0, 22, 31, 22,
0, 0, 0, 0, 0, 0, 0, 0
};
// Pawn storm open file bonuses by file
const int16_t KStormOpenFileBonus[8] = { 45, 45, 30, 0, 0, 0, 0, 0 };
const int16_t QStormOpenFileBonus[8] = { 0, 0, 0, 0, 0, 30, 45, 30 };
const int16_t KStormOpenFileBonus[8] = { 31, 31, 18, 0, 0, 0, 0, 0 };
const int16_t QStormOpenFileBonus[8] = { 0, 0, 0, 0, 0, 26, 42, 26 };
// Pawn storm lever bonuses by file
const int StormLeverBonus[8] = { 20, 20, 10, 0, 0, 10, 20, 20 };
const int StormLeverBonus[8] = { -8, -8, -13, 0, 0, -13, -8, -8 };
}
@@ -140,13 +113,12 @@ PawnInfoTable::PawnInfoTable(unsigned numOfEntries) {
size = numOfEntries;
entries = new PawnInfo[size];
if (entries == NULL)
if (!entries)
{
std::cerr << "Failed to allocate " << (numOfEntries * sizeof(PawnInfo))
<< " bytes for pawn hash table." << std::endl;
exit(EXIT_FAILURE);
Application::exit_with_failure();
}
clear();
}
@@ -157,11 +129,13 @@ PawnInfoTable::~PawnInfoTable() {
}
/// PawnInfoTable::clear() clears the pawn hash table by setting all
/// entries to 0.
/// PawnInfo::clear() resets to zero the PawnInfo entry. Note that
/// kingSquares[] is initialized to SQ_NONE instead.
void PawnInfoTable::clear() {
memset(entries, 0, size * sizeof(PawnInfo));
void PawnInfo::clear() {
memset(this, 0, sizeof(PawnInfo));
kingSquares[WHITE] = kingSquares[BLACK] = SQ_NONE;
}
@@ -170,17 +144,17 @@ void PawnInfoTable::clear() {
/// stored in a hash table, so we don't have to recompute everything when
/// the same pawn structure occurs again.
PawnInfo *PawnInfoTable::get_pawn_info(const Position &pos) {
PawnInfo* PawnInfoTable::get_pawn_info(const Position& pos) {
assert(pos.is_ok());
Key key = pos.get_pawn_key();
int index = int(key & (size - 1));
PawnInfo *pi = entries + index;
PawnInfo* pi = entries + index;
// If pi->key matches the position's pawn hash key, it means that we
// have analysed this pawn structure before, and we can simply return the
// information we found the last time instead of recomputing it
// have analysed this pawn structure before, and we can simply return
// the information we found the last time instead of recomputing it.
if (pi->key == key)
return pi;
@@ -188,209 +162,197 @@ PawnInfo *PawnInfoTable::get_pawn_info(const Position &pos) {
pi->clear();
pi->key = key;
Value mgValue[2] = {Value(0), Value(0)};
Value egValue[2] = {Value(0), Value(0)};
// Calculate pawn attacks
Bitboard whitePawns = pos.pieces(PAWN, WHITE);
Bitboard blackPawns = pos.pieces(PAWN, BLACK);
pi->pawnAttacks[WHITE] = ((whitePawns << 9) & ~FileABB) | ((whitePawns << 7) & ~FileHBB);
pi->pawnAttacks[BLACK] = ((blackPawns >> 7) & ~FileABB) | ((blackPawns >> 9) & ~FileHBB);
// Loop through the pawns for both colors
for (Color us = WHITE; us <= BLACK; us++)
{
Color them = opposite_color(us);
Bitboard ourPawns = pos.pawns(us);
Bitboard theirPawns = pos.pawns(them);
Bitboard pawns = ourPawns;
int bonus;
// Initialize pawn storm scores by giving bonuses for open files
for (File f = FILE_A; f <= FILE_H; f++)
if (pos.file_is_half_open(us, f))
{
pi->ksStormValue[us] += KStormOpenFileBonus[f];
pi->qsStormValue[us] += QStormOpenFileBonus[f];
}
// Loop through all pawns of the current color and score each pawn
while (pawns)
{
bool passed, doubled, isolated, backward, chain, candidate;
Square s = pop_1st_bit(&pawns);
File f = square_file(s);
Rank r = square_rank(s);
assert(pos.piece_on(s) == piece_of_color_and_type(us, PAWN));
// The file containing the pawn is not half open
pi->halfOpenFiles[us] &= ~(1 << f);
// Passed, isolated or doubled pawn?
passed = pos.pawn_is_passed(us, s);
isolated = pos.pawn_is_isolated(us, s);
doubled = pos.pawn_is_doubled(us, s);
// We calculate kingside and queenside pawn storm
// scores for both colors. These are used when evaluating
// middle game positions with opposite side castling.
//
// Each pawn is given a base score given by a piece square table
// (KStormTable[] or QStormTable[]). Pawns which seem to have good
// chances of creating an open file by exchanging itself against an
// enemy pawn on an adjacent file gets an additional bonus.
// Kingside pawn storms
bonus = KStormTable[relative_square(us, s)];
if (f >= FILE_F)
{
Bitboard b = outpost_mask(us, s) & theirPawns & (FileFBB | FileGBB | FileHBB);
while (b)
{
Square s2 = pop_1st_bit(&b);
if (!(theirPawns & neighboring_files_bb(s2) & rank_bb(s2)))
{
// The enemy pawn has no pawn beside itself, which makes it
// particularly vulnerable. Big bonus, especially against a
// weakness on the rook file.
if (square_file(s2) == FILE_H)
bonus += 4*StormLeverBonus[f] - 8*square_distance(s, s2);
else
bonus += 2*StormLeverBonus[f] - 4*square_distance(s, s2);
} else
// There is at least one enemy pawn beside the enemy pawn we look
// at, which means that the pawn has somewhat better chances of
// defending itself by advancing. Smaller bonus.
bonus += StormLeverBonus[f] - 2*square_distance(s, s2);
}
}
pi->ksStormValue[us] += bonus;
// Queenside pawn storms
bonus = QStormTable[relative_square(us, s)];
if (f <= FILE_C)
{
Bitboard b = outpost_mask(us, s) & theirPawns & (FileABB | FileBBB | FileCBB);
while (b)
{
Square s2 = pop_1st_bit(&b);
if (!(theirPawns & neighboring_files_bb(s2) & rank_bb(s2)))
{
// The enemy pawn has no pawn beside itself, which makes it
// particularly vulnerable. Big bonus, especially against a
// weakness on the rook file.
if (square_file(s2) == FILE_A)
bonus += 4*StormLeverBonus[f] - 16*square_distance(s, s2);
else
bonus += 2*StormLeverBonus[f] - 8*square_distance(s, s2);
} else
// There is at least one enemy pawn beside the enemy pawn we look
// at, which means that the pawn has somewhat better chances of
// defending itself by advancing. Smaller bonus.
bonus += StormLeverBonus[f] - 4*square_distance(s, s2);
}
}
pi->qsStormValue[us] += bonus;
// Member of a pawn chain (but not the backward one)? We could speed up
// the test a little by introducing an array of masks indexed by color
// and square for doing the test, but because everything is hashed,
// it probably won't make any noticable difference.
chain = ourPawns
& neighboring_files_bb(f)
& (rank_bb(r) | rank_bb(r - (us == WHITE ? 1 : -1)));
// Test for backward pawn
//
// If the pawn is passed, isolated, or member of a pawn chain
// it cannot be backward. If can capture an enemy pawn or if
// there are friendly pawns behind on neighboring files it cannot
// be backward either.
if ( passed
|| isolated
|| chain
|| (pos.pawn_attacks(us, s) & theirPawns)
|| (ourPawns & behind_bb(us, r) & neighboring_files_bb(f)))
backward = false;
else
{
// We now know that there are no friendly pawns beside or behind this
// pawn on neighboring files. We now check whether the pawn is
// backward by looking in the forward direction on the neighboring
// files, and seeing whether we meet a friendly or an enemy pawn first.
Bitboard b;
if (us == WHITE)
{
for (b = pos.pawn_attacks(us, s); !(b & (ourPawns | theirPawns)); b <<= 8);
backward = (b | (b << 8)) & theirPawns;
}
else
{
for (b = pos.pawn_attacks(us, s); !(b & (ourPawns | theirPawns)); b >>= 8);
backward = (b | (b >> 8)) & theirPawns;
}
}
// Test for candidate passed pawn
candidate = !passed
&& pos.file_is_half_open(them, f)
&& ( count_1s_max_15(neighboring_files_bb(f) & (behind_bb(us, r) | rank_bb(r)) & ourPawns)
- count_1s_max_15(neighboring_files_bb(f) & in_front_bb(us, r) & theirPawns)
>= 0);
// In order to prevent doubled passed pawns from receiving a too big
// bonus, only the frontmost passed pawn on each file is considered as
// a true passed pawn.
if (passed && (ourPawns & squares_in_front_of(us, s)))
{
// candidate = true;
passed = false;
}
// Score this pawn
Value mv = Value(0), ev = Value(0);
if (isolated)
{
mv -= IsolatedPawnMidgamePenalty[f];
ev -= IsolatedPawnEndgamePenalty[f];
if (pos.file_is_half_open(them, f))
{
mv -= IsolatedPawnMidgamePenalty[f] / 2;
ev -= IsolatedPawnEndgamePenalty[f] / 2;
}
}
if (doubled)
{
mv -= DoubledPawnMidgamePenalty[f];
ev -= DoubledPawnEndgamePenalty[f];
}
if (backward)
{
mv -= BackwardPawnMidgamePenalty[f];
ev -= BackwardPawnEndgamePenalty[f];
if (pos.file_is_half_open(them, f))
{
mv -= BackwardPawnMidgamePenalty[f] / 2;
ev -= BackwardPawnEndgamePenalty[f] / 2;
}
}
if (chain)
{
mv += ChainMidgameBonus[f];
ev += ChainEndgameBonus[f];
}
if (candidate)
{
mv += CandidateMidgameBonus[relative_rank(us, s)];
ev += CandidateEndgameBonus[relative_rank(us, s)];
}
mgValue[us] += mv;
egValue[us] += ev;
// If the pawn is passed, set the square of the pawn in the passedPawns
// bitboard
if (passed)
set_bit(&(pi->passedPawns), s);
} // while(pawns)
} // for(colors)
pi->mgValue = int16_t(mgValue[WHITE] - mgValue[BLACK]);
pi->egValue = int16_t(egValue[WHITE] - egValue[BLACK]);
// Evaluate pawns for both colors
pi->value = evaluate_pawns<WHITE>(pos, whitePawns, blackPawns, pi)
- evaluate_pawns<BLACK>(pos, blackPawns, whitePawns, pi);
return pi;
}
/// PawnInfoTable::evaluate_pawns() evaluates each pawn of the given color
template<Color Us>
Score PawnInfoTable::evaluate_pawns(const Position& pos, Bitboard ourPawns,
Bitboard theirPawns, PawnInfo* pi) {
Square s;
File f;
Rank r;
bool passed, isolated, doubled, chain, backward, candidate;
int bonus;
Score value = make_score(0, 0);
const Square* ptr = pos.piece_list_begin(Us, PAWN);
// Initialize pawn storm scores by giving bonuses for open files
for (f = FILE_A; f <= FILE_H; f++)
if (!(ourPawns & file_bb(f)))
{
pi->ksStormValue[Us] += KStormOpenFileBonus[f];
pi->qsStormValue[Us] += QStormOpenFileBonus[f];
pi->halfOpenFiles[Us] |= (1 << f);
}
// Loop through all pawns of the current color and score each pawn
while ((s = *ptr++) != SQ_NONE)
{
f = square_file(s);
r = square_rank(s);
assert(pos.piece_on(s) == piece_of_color_and_type(Us, PAWN));
// Passed, isolated or doubled pawn?
passed = Position::pawn_is_passed(theirPawns, Us, s);
isolated = Position::pawn_is_isolated(ourPawns, s);
doubled = Position::pawn_is_doubled(ourPawns, Us, s);
// We calculate kingside and queenside pawn storm
// scores for both colors. These are used when evaluating
// middle game positions with opposite side castling.
//
// Each pawn is given a base score given by a piece square table
// (KStormTable[] or QStormTable[]). Pawns which seem to have good
// chances of creating an open file by exchanging itself against an
// enemy pawn on an adjacent file gets an additional bonus.
// Kingside pawn storms
bonus = KStormTable[relative_square(Us, s)];
if (f >= FILE_F)
{
Bitboard b = outpost_mask(Us, s) & theirPawns & (FileFBB | FileGBB | FileHBB);
while (b)
{
// Give a bonus according to the distance of the nearest enemy pawn
Square s2 = pop_1st_bit(&b);
int v = StormLeverBonus[f] - 2 * square_distance(s, s2);
// If enemy pawn has no pawn beside itself is particularly vulnerable.
// Big bonus, especially against a weakness on the rook file
if (!(theirPawns & neighboring_files_bb(s2) & rank_bb(s2)))
v *= (square_file(s2) == FILE_H ? 4 : 2);
bonus += v;
}
}
pi->ksStormValue[Us] += bonus;
// Queenside pawn storms
bonus = QStormTable[relative_square(Us, s)];
if (f <= FILE_C)
{
Bitboard b = outpost_mask(Us, s) & theirPawns & (FileABB | FileBBB | FileCBB);
while (b)
{
// Give a bonus according to the distance of the nearest enemy pawn
Square s2 = pop_1st_bit(&b);
int v = StormLeverBonus[f] - 4 * square_distance(s, s2);
// If enemy pawn has no pawn beside itself is particularly vulnerable.
// Big bonus, especially against a weakness on the rook file
if (!(theirPawns & neighboring_files_bb(s2) & rank_bb(s2)))
v *= (square_file(s2) == FILE_A ? 4 : 2);
bonus += v;
}
}
pi->qsStormValue[Us] += bonus;
// Member of a pawn chain (but not the backward one)? We could speed up
// the test a little by introducing an array of masks indexed by color
// and square for doing the test, but because everything is hashed,
// it probably won't make any noticable difference.
chain = ourPawns
& neighboring_files_bb(f)
& (rank_bb(r) | rank_bb(r - (Us == WHITE ? 1 : -1)));
// Test for backward pawn
//
// If the pawn is passed, isolated, or member of a pawn chain
// it cannot be backward. If can capture an enemy pawn or if
// there are friendly pawns behind on neighboring files it cannot
// be backward either.
if ( (passed | isolated | chain)
|| (ourPawns & behind_bb(Us, r) & neighboring_files_bb(f))
|| (pos.attacks_from<PAWN>(s, Us) & theirPawns))
backward = false;
else
{
// We now know that there are no friendly pawns beside or behind this
// pawn on neighboring files. We now check whether the pawn is
// backward by looking in the forward direction on the neighboring
// files, and seeing whether we meet a friendly or an enemy pawn first.
Bitboard b = pos.attacks_from<PAWN>(s, Us);
// Note that we are sure to find something because pawn is not passed
// nor isolated, so loop is potentially infinite, but it isn't.
while (!(b & (ourPawns | theirPawns)))
Us == WHITE ? b <<= 8 : b >>= 8;
// The friendly pawn needs to be at least two ranks closer than the enemy
// pawn in order to help the potentially backward pawn advance.
backward = (b | (Us == WHITE ? b << 8 : b >> 8)) & theirPawns;
}
// Test for candidate passed pawn
candidate = !passed
&& !(theirPawns & file_bb(f))
&& ( count_1s_max_15(neighboring_files_bb(f) & (behind_bb(Us, r) | rank_bb(r)) & ourPawns)
- count_1s_max_15(neighboring_files_bb(f) & in_front_bb(Us, r) & theirPawns)
>= 0);
// In order to prevent doubled passed pawns from receiving a too big
// bonus, only the frontmost passed pawn on each file is considered as
// a true passed pawn.
if (passed && (ourPawns & squares_in_front_of(Us, s)))
passed = false;
// Score this pawn
if (passed)
set_bit(&(pi->passedPawns), s);
if (isolated)
{
value -= IsolatedPawnPenalty[f];
if (!(theirPawns & file_bb(f)))
value -= IsolatedPawnPenalty[f] / 2;
}
if (doubled)
value -= DoubledPawnPenalty[f];
if (backward)
{
value -= BackwardPawnPenalty[f];
if (!(theirPawns & file_bb(f)))
value -= BackwardPawnPenalty[f] / 2;
}
if (chain)
value += ChainBonus[f];
if (candidate)
value += CandidateBonus[relative_rank(Us, s)];
}
return value;
}
/// PawnInfo::updateShelter calculates and caches king shelter. It is called
/// only when king square changes, about 20% of total get_king_shelter() calls.
int PawnInfo::updateShelter(const Position& pos, Color c, Square ksq) {
unsigned shelter = 0;
Bitboard pawns = pos.pieces(PAWN, c) & this_and_neighboring_files_bb(ksq);
unsigned r = ksq & (7 << 3);
for (int i = 1, k = (c ? -8 : 8); i < 4; i++)
{
r += k;
shelter += BitCount8Bit[(pawns >> r) & 0xFF] * (128 >> i);
}
kingSquares[c] = ksq;
kingShelters[c] = shelter;
return shelter;
}

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2010 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
@@ -33,9 +33,9 @@
////
/// PawnInfo is a class which contains various information about a pawn
/// structure. Currently, it only includes a middle game and an end game
/// pawn structure evaluation, and a bitboard of passed pawns. We may want
/// to add further information in the future. A lookup to the pawn hash table
/// structure. Currently, it only includes a middle game and an end game
/// pawn structure evaluation, and a bitboard of passed pawns. We may want
/// to add further information in the future. A lookup to the pawn hash table
/// (performed by calling the get_pawn_info method in a PawnInfoTable object)
/// returns a pointer to a PawnInfo object.
class Position;
@@ -45,26 +45,32 @@ class PawnInfo {
friend class PawnInfoTable;
public:
Value mg_value() const;
Value eg_value() const;
PawnInfo() { clear(); }
Score pawns_value() const;
Value kingside_storm_value(Color c) const;
Value queenside_storm_value(Color c) const;
Bitboard pawn_attacks(Color c) const;
Bitboard passed_pawns() const;
int file_is_half_open(Color c, File f) const;
int has_open_file_to_left(Color c, File f) const;
int has_open_file_to_right(Color c, File f) const;
int get_king_shelter(const Position& pos, Color c, Square ksq);
private:
void clear();
int updateShelter(const Position& pos, Color c, Square ksq);
Key key;
Bitboard passedPawns;
int16_t mgValue, egValue;
Bitboard pawnAttacks[2];
Score value;
int16_t ksStormValue[2], qsStormValue[2];
uint8_t halfOpenFiles[2];
Square kingSquares[2];
uint8_t kingShelters[2];
};
/// The PawnInfoTable class represents a pawn hash table. It is basically
/// just an array of PawnInfo objects and a few methods for accessing these
/// objects. The most important method is get_pawn_info, which looks up a
@@ -75,10 +81,12 @@ class PawnInfoTable {
public:
PawnInfoTable(unsigned numOfEntries);
~PawnInfoTable();
void clear();
PawnInfo* get_pawn_info(const Position& pos);
private:
template<Color Us>
Score evaluate_pawns(const Position& pos, Bitboard ourPawns, Bitboard theirPawns, PawnInfo* pi);
unsigned size;
PawnInfo* entries;
};
@@ -88,18 +96,18 @@ private:
//// Inline functions
////
inline Value PawnInfo::mg_value() const {
return Value(mgValue);
}
inline Value PawnInfo::eg_value() const {
return Value(egValue);
inline Score PawnInfo::pawns_value() const {
return value;
}
inline Bitboard PawnInfo::passed_pawns() const {
return passedPawns;
}
inline Bitboard PawnInfo::pawn_attacks(Color c) const {
return pawnAttacks[c];
}
inline Value PawnInfo::kingside_storm_value(Color c) const {
return Value(ksStormValue[c]);
}
@@ -120,14 +128,8 @@ inline int PawnInfo::has_open_file_to_right(Color c, File f) const {
return halfOpenFiles[c] & ~((1 << int(f+1)) - 1);
}
inline void PawnInfo::clear() {
passedPawns = EmptyBoardBB;
mgValue = egValue = 0;
ksStormValue[WHITE] = ksStormValue[BLACK] = 0;
qsStormValue[WHITE] = qsStormValue[BLACK] = 0;
halfOpenFiles[WHITE] = halfOpenFiles[BLACK] = 0xFF;
inline int PawnInfo::get_king_shelter(const Position& pos, Color c, Square ksq) {
return (kingSquares[c] == ksq ? kingShelters[c] : updateShelter(pos, c, ksq));
}
#endif // !defined(PAWNS_H_INCLUDED)

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2010 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

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2010 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
@@ -83,10 +83,6 @@ inline int piece_is_slider(Piece p) {
return SlidingArray[int(p)];
}
inline int piece_is_slider(PieceType pt) {
return SlidingArray[int(pt)];
}
inline SquareDelta pawn_push(Color c) {
return (c == WHITE ? DELTA_N : DELTA_S);
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2010 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
@@ -21,7 +21,7 @@
#if !defined(POSITION_H_INCLUDED)
#define POSITION_H_INCLUDED
// Disable a silly and noisy warning from MSVC compiler
// Disable some silly and noisy warning from MSVC compiler
#if defined(_MSC_VER)
// Forcing value to bool 'true' or 'false' (performance warning)
@@ -50,13 +50,12 @@
//// Constants
////
/// FEN string for the initial position:
const std::string StartPosition =
"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
/// FEN string for the initial position
const std::string StartPosition = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
/// Maximum number of plies per game (220 should be enough, because the
/// maximum search depth is 100, and during position setup we reset the
/// move counter for every non-reversible move):
/// move counter for every non-reversible move).
const int MaxGameLength = 220;
@@ -64,14 +63,26 @@ const int MaxGameLength = 220;
//// Types
////
/// struct checkInfo is initialized at c'tor time and keeps
/// info used to detect if a move gives check.
struct CheckInfo {
CheckInfo(const Position&);
Square ksq;
Bitboard dcCandidates;
Bitboard checkSq[8];
};
/// Castle rights, encoded as bit fields
enum CastleRights {
NO_CASTLES = 0,
WHITE_OO = 1,
BLACK_OO = 2,
WHITE_OOO = 4,
BLACK_OOO = 8,
NO_CASTLES = 0,
WHITE_OO = 1,
BLACK_OO = 2,
WHITE_OOO = 4,
BLACK_OOO = 8,
ALL_CASTLES = 15
};
@@ -88,38 +99,38 @@ enum Phase {
/// must be passed as a parameter.
struct StateInfo {
Key key, pawnKey, materialKey;
int castleRights, rule50;
Key pawnKey, materialKey;
int castleRights, rule50, pliesFromNull;
Square epSquare;
Value mgValue, egValue;
Score value;
Value npMaterial[2];
Key key;
PieceType capture;
Bitboard checkersBB;
Move lastMove;
StateInfo* previous;
};
/// The position data structure. A position consists of the following data:
/// The position data structure. A position consists of the following data:
///
/// * For each piece type, a bitboard representing the squares occupied
/// by pieces of that type.
/// * For each color, a bitboard representing the squares occupiecd by
/// * For each color, a bitboard representing the squares occupied by
/// pieces of that color.
/// * A bitboard of all occupied squares.
/// * A bitboard of all checking pieces.
/// * A 64-entry array of pieces, indexed by the squares of the board.
/// * The current side to move.
/// * Information about the castling rights for both sides.
/// * The initial files of the kings and both pairs of rooks. This is
/// * The initial files of the kings and both pairs of rooks. This is
/// used to implement the Chess960 castling rules.
/// * The en passant square (which is SQ_NONE if no en passant capture is
/// possible).
/// * The squares of the kings for both sides.
/// * The last move played.
/// * Hash keys for the position itself, the current pawn structure, and
/// the current material situation.
/// * Hash keys for all previous positions in the game (for detecting
/// * Hash keys for all previous positions in the game for detecting
/// repetition draws.
/// * A counter for detecting 50 move rule draws.
@@ -129,10 +140,15 @@ class Position {
friend class EndgameFunctions;
public:
enum GamePhase {
MidGame,
EndGame
};
// Constructors
Position() {};
Position(const Position& pos);
Position(const std::string& fen);
Position();
explicit Position(const Position& pos);
explicit Position(const std::string& fen);
// Text input/output
void from_fen(const std::string& fen);
@@ -140,8 +156,7 @@ public:
void print(Move m = MOVE_NONE) const;
// Copying
void copy(const Position &pos);
void flipped_copy(const Position &pos);
void flipped_copy(const Position& pos);
// The piece on a given square
Piece piece_on(Square s) const;
@@ -159,26 +174,10 @@ public:
Bitboard empty_squares() const;
Bitboard occupied_squares() const;
Bitboard pieces_of_color(Color c) const;
Bitboard pieces_of_type(PieceType pt) const;
Bitboard pieces_of_color_and_type(Color c, PieceType pt) const;
Bitboard pawns() const;
Bitboard knights() const;
Bitboard bishops() const;
Bitboard rooks() const;
Bitboard queens() const;
Bitboard kings() const;
Bitboard rooks_and_queens() const;
Bitboard bishops_and_queens() const;
Bitboard sliders() const;
Bitboard pawns(Color c) const;
Bitboard knights(Color c) const;
Bitboard bishops(Color c) const;
Bitboard rooks(Color c) const;
Bitboard queens(Color c) const;
Bitboard kings(Color c) const;
Bitboard rooks_and_queens(Color c) const;
Bitboard bishops_and_queens(Color c) const;
Bitboard sliders_of_color(Color c) const;
Bitboard pieces(PieceType pt) const;
Bitboard pieces(PieceType pt, Color c) const;
Bitboard pieces(PieceType pt1, PieceType pt2) const;
Bitboard pieces(PieceType pt1, PieceType pt2, Color c) const;
// Number of pieces of each color and type
int piece_count(Color c, PieceType pt) const;
@@ -196,65 +195,50 @@ public:
Square initial_kr_square(Color c) const;
Square initial_qr_square(Color c) const;
// Attack bitboards
Bitboard sliding_attacks(Square s, Direction d) const;
Bitboard ray_attacks(Square s, SignedDirection d) const;
Bitboard pawn_attacks(Color c, Square s) const;
template<PieceType>
Bitboard piece_attacks(Square s) const;
// Bitboards for pinned pieces and discovered check candidates
Bitboard discovered_check_candidates(Color c) const;
Bitboard pinned_pieces(Color c, Bitboard& p) const;
Bitboard pinned_pieces(Color c) const;
// Checking pieces
// Checking pieces and under check information
Bitboard checkers() const;
bool is_check() const;
// Piece lists
Square piece_list(Color c, PieceType pt, int index) const;
const Square* piece_list_begin(Color c, PieceType pt) const;
// Attack information for a given square
bool square_is_attacked(Square s, Color c) const;
Bitboard attacks_to(Square s) const;
Bitboard attacks_to(Square s, Color c) const;
bool is_check() const;
bool pawn_attacks_square(Color c, Square f, Square t) const;
template<PieceType>
Bitboard piece_attacks_square(Square f, Square t) const; // Dispatch at compile-time
bool piece_attacks_square(Piece p, Square f, Square t) const; // Dispatch at run-time
// Information about attacks to or from a given square
Bitboard attackers_to(Square s) const;
Bitboard attacks_from(Piece p, Square s) const;
template<PieceType> Bitboard attacks_from(Square s) const;
template<PieceType> Bitboard attacks_from(Square s, Color c) const;
// Properties of moves
bool pl_move_is_legal(Move m) const;
bool pl_move_is_legal(Move m, Bitboard pinned) const;
bool pl_move_is_evasion(Move m, Bitboard pinned) const;
bool move_is_check(Move m) const;
bool move_is_check(Move m, Bitboard dcCandidates) const;
bool move_is_check(Move m, const CheckInfo& ci) const;
bool move_is_capture(Move m) const;
bool move_is_deep_pawn_push(Move m) const;
bool move_is_pawn_push_to_7th(Move m) const;
bool move_is_capture_or_promotion(Move m) const;
bool move_is_passed_pawn_push(Move m) const;
bool move_was_passed_pawn_push(Move m) const;
bool move_attacks_square(Move m, Square s) const;
// Piece captured with previous moves
PieceType captured_piece() const;
// Information about pawns
bool pawn_is_passed(Color c, Square s) const;
bool pawn_is_isolated(Color c, Square s) const;
bool pawn_is_doubled(Color c, Square s) const;
// Open and half-open files
bool file_is_open(File f) const;
bool file_is_half_open(Color c, File f) const;
static bool pawn_is_passed(Bitboard theirPawns, Color c, Square s);
static bool pawn_is_isolated(Bitboard ourPawns, Square s);
static bool pawn_is_doubled(Bitboard ourPawns, Color c, Square s);
// Weak squares
bool square_is_weak(Square s, Color c) const;
// Doing and undoing moves
void setStartState(const StateInfo& st);
void detach();
void do_move(Move m, StateInfo& st);
void do_move(Move m, StateInfo& st, Bitboard dcCandidates);
void do_move(Move m, StateInfo& st, const CheckInfo& ci, bool moveIsCheck);
void undo_move(Move m);
void do_null_move(StateInfo& st);
void undo_null_move();
@@ -263,18 +247,18 @@ public:
int see(Square from, Square to) const;
int see(Move m) const;
int see(Square to) const;
int see_sign(Move m) const;
// Accessing hash keys
Key get_key() const;
Key get_exclusion_key() const;
Key get_pawn_key() const;
Key get_material_key() const;
// Incremental evaluation
Value mg_value() const;
Value eg_value() const;
Score value() const;
Value non_pawn_material(Color c) const;
Phase game_phase() const;
Value mg_pst_delta(Move m) const;
Score pst_delta(Piece piece, Square from, Square to) const;
// Game termination checks
bool is_mate() const;
@@ -296,7 +280,7 @@ public:
// Position consistency check, for debugging
bool is_ok(int* failedStep = NULL) const;
// Static member functions:
// Static member functions
static void init_zobrist();
static void init_piece_square_tables();
@@ -309,18 +293,11 @@ private:
void allow_ooo(Color c);
// Helper functions for doing and undoing moves
void do_capture_move(PieceType capture, Color them, Square to);
void do_capture_move(Bitboard& key, PieceType capture, Color them, Square to, bool ep);
void do_castle_move(Move m);
void do_promotion_move(Move m);
void do_ep_move(Move m);
void undo_castle_move(Move m);
void undo_promotion_move(Move m);
void undo_ep_move(Move m);
void find_checkers();
template<PieceType Piece>
void update_checkers(Bitboard* pCheckersBB, Square ksq, Square from, Square to, Bitboard dcCandidates);
template<bool FindPinned>
Bitboard hidden_checkers(Color c) const;
@@ -330,46 +307,40 @@ private:
Key compute_material_key() const;
// Computing incremental evaluation scores and material counts
enum GamePhase {
MidGame,
EndGame
};
template<GamePhase> Value pst(Color c, PieceType pt, Square s) const;
template<GamePhase> Value compute_value() const;
Score pst(Color c, PieceType pt, Square s) const;
Score compute_value() const;
Value compute_non_pawn_material(Color c) const;
// Bitboards
Bitboard byColorBB[2], byTypeBB[8];
// Board
Piece board[64];
// Bitboards
Bitboard byTypeBB[8], byColorBB[2];
// Piece counts
int pieceCount[2][8]; // [color][pieceType]
// Piece lists
Square pieceList[2][8][16]; // [color][pieceType][index]
int index[64];
int index[64]; // [square]
// Other info
Square kingSquare[2];
Color sideToMove;
int gamePly;
Key history[MaxGameLength];
Value npMaterial[2];
int castleRightsMask[64];
File initialKFile, initialKRFile, initialQRFile;
StateInfo startState;
StateInfo* st;
// Static variables
static int castleRightsMask[64];
static Key zobrist[2][8][64];
static Key zobEp[64];
static Key zobCastle[16];
static Key zobMaterial[2][8][16];
static Key zobSideToMove;
static Value MgPieceSquareTable[16][64];
static Value EgPieceSquareTable[16][64];
static Score PieceSquareTable[16][64];
static Key zobExclusion;
};
@@ -421,84 +392,20 @@ inline Bitboard Position::pieces_of_color(Color c) const {
return byColorBB[c];
}
inline Bitboard Position::pieces_of_type(PieceType pt) const {
inline Bitboard Position::pieces(PieceType pt) const {
return byTypeBB[pt];
}
inline Bitboard Position::pieces_of_color_and_type(Color c, PieceType pt) const {
return pieces_of_color(c) & pieces_of_type(pt);
inline Bitboard Position::pieces(PieceType pt, Color c) const {
return byTypeBB[pt] & byColorBB[c];
}
inline Bitboard Position::pawns() const {
return pieces_of_type(PAWN);
inline Bitboard Position::pieces(PieceType pt1, PieceType pt2) const {
return byTypeBB[pt1] | byTypeBB[pt2];
}
inline Bitboard Position::knights() const {
return pieces_of_type(KNIGHT);
}
inline Bitboard Position::bishops() const {
return pieces_of_type(BISHOP);
}
inline Bitboard Position::rooks() const {
return pieces_of_type(ROOK);
}
inline Bitboard Position::queens() const {
return pieces_of_type(QUEEN);
}
inline Bitboard Position::kings() const {
return pieces_of_type(KING);
}
inline Bitboard Position::rooks_and_queens() const {
return rooks() | queens();
}
inline Bitboard Position::bishops_and_queens() const {
return bishops() | queens();
}
inline Bitboard Position::sliders() const {
return bishops() | queens() | rooks();
}
inline Bitboard Position::pawns(Color c) const {
return pieces_of_color_and_type(c, PAWN);
}
inline Bitboard Position::knights(Color c) const {
return pieces_of_color_and_type(c, KNIGHT);
}
inline Bitboard Position::bishops(Color c) const {
return pieces_of_color_and_type(c, BISHOP);
}
inline Bitboard Position::rooks(Color c) const {
return pieces_of_color_and_type(c, ROOK);
}
inline Bitboard Position::queens(Color c) const {
return pieces_of_color_and_type(c, QUEEN);
}
inline Bitboard Position::kings(Color c) const {
return pieces_of_color_and_type(c, KING);
}
inline Bitboard Position::rooks_and_queens(Color c) const {
return rooks_and_queens() & pieces_of_color(c);
}
inline Bitboard Position::bishops_and_queens(Color c) const {
return bishops_and_queens() & pieces_of_color(c);
}
inline Bitboard Position::sliders_of_color(Color c) const {
return sliders() & pieces_of_color(c);
inline Bitboard Position::pieces(PieceType pt1, PieceType pt2, Color c) const {
return (byTypeBB[pt1] | byTypeBB[pt2]) & byColorBB[c];
}
inline int Position::piece_count(Color c, PieceType pt) const {
@@ -509,12 +416,16 @@ inline Square Position::piece_list(Color c, PieceType pt, int index) const {
return pieceList[c][pt][index];
}
inline const Square* Position::piece_list_begin(Color c, PieceType pt) const {
return pieceList[c][pt];
}
inline Square Position::ep_square() const {
return st->epSquare;
}
inline Square Position::king_square(Color c) const {
return kingSquare[c];
return pieceList[c][KING][0];
}
inline bool Position::can_castle_kingside(Color side) const {
@@ -537,38 +448,29 @@ inline Square Position::initial_qr_square(Color c) const {
return relative_square(c, make_square(initialQRFile, RANK_1));
}
inline Bitboard Position::pawn_attacks(Color c, Square s) const {
template<>
inline Bitboard Position::attacks_from<PAWN>(Square s, Color c) const {
return StepAttackBB[piece_of_color_and_type(c, PAWN)][s];
}
template<>
inline Bitboard Position::piece_attacks<PAWN>(Square s) const {
return StepAttackBB[piece_of_color_and_type(opposite_color(sideToMove), PAWN)][s];
template<PieceType Piece> // Knight and King and white pawns
inline Bitboard Position::attacks_from(Square s) const {
return StepAttackBB[Piece][s];
}
template<>
inline Bitboard Position::piece_attacks<KNIGHT>(Square s) const {
return StepAttackBB[KNIGHT][s];
}
template<>
inline Bitboard Position::piece_attacks<BISHOP>(Square s) const {
inline Bitboard Position::attacks_from<BISHOP>(Square s) const {
return bishop_attacks_bb(s, occupied_squares());
}
template<>
inline Bitboard Position::piece_attacks<ROOK>(Square s) const {
inline Bitboard Position::attacks_from<ROOK>(Square s) const {
return rook_attacks_bb(s, occupied_squares());
}
template<>
inline Bitboard Position::piece_attacks<QUEEN>(Square s) const {
return piece_attacks<ROOK>(s) | piece_attacks<BISHOP>(s);
}
template<>
inline Bitboard Position::piece_attacks<KING>(Square s) const {
return StepAttackBB[KING][s];
inline Bitboard Position::attacks_from<QUEEN>(Square s) const {
return attacks_from<ROOK>(s) | attacks_from<BISHOP>(s);
}
inline Bitboard Position::checkers() const {
@@ -579,53 +481,34 @@ inline bool Position::is_check() const {
return st->checkersBB != EmptyBoardBB;
}
inline bool Position::pawn_attacks_square(Color c, Square f, Square t) const {
return bit_is_set(pawn_attacks(c, f), t);
}
template<PieceType Piece>
Bitboard Position::piece_attacks_square(Square f, Square t) const {
return bit_is_set(piece_attacks<Piece>(f), t);
}
inline Bitboard Position::attacks_to(Square s, Color c) const {
return attacks_to(s) & pieces_of_color(c);
}
inline bool Position::square_is_attacked(Square s, Color c) const {
return attacks_to(s, c) != EmptyBoardBB;
}
inline bool Position::pawn_is_passed(Color c, Square s) const {
return !(pawns(opposite_color(c)) & passed_pawn_mask(c, s));
return !(pieces(PAWN, opposite_color(c)) & passed_pawn_mask(c, s));
}
inline bool Position::pawn_is_isolated(Color c, Square s) const {
return !(pawns(c) & neighboring_files_bb(s));
inline bool Position::pawn_is_passed(Bitboard theirPawns, Color c, Square s) {
return !(theirPawns & passed_pawn_mask(c, s));
}
inline bool Position::pawn_is_doubled(Color c, Square s) const {
return pawns(c) & squares_behind(c, s);
inline bool Position::pawn_is_isolated(Bitboard ourPawns, Square s) {
return !(ourPawns & neighboring_files_bb(s));
}
inline bool Position::file_is_open(File f) const {
return !(pawns() & file_bb(f));
}
inline bool Position::file_is_half_open(Color c, File f) const {
return !(pawns(c) & file_bb(f));
inline bool Position::pawn_is_doubled(Bitboard ourPawns, Color c, Square s) {
return ourPawns & squares_behind(c, s);
}
inline bool Position::square_is_weak(Square s, Color c) const {
return !(pawns(c) & outpost_mask(opposite_color(c), s));
return !(pieces(PAWN, c) & outpost_mask(opposite_color(c), s));
}
inline Key Position::get_key() const {
return st->key;
}
inline Key Position::get_exclusion_key() const {
return st->key ^ zobExclusion;
}
inline Key Position::get_pawn_key() const {
return st->pawnKey;
}
@@ -634,57 +517,20 @@ inline Key Position::get_material_key() const {
return st->materialKey;
}
template<Position::GamePhase Phase>
inline Value Position::pst(Color c, PieceType pt, Square s) const {
return (Phase == MidGame ? MgPieceSquareTable[piece_of_color_and_type(c, pt)][s]
: EgPieceSquareTable[piece_of_color_and_type(c, pt)][s]);
inline Score Position::pst(Color c, PieceType pt, Square s) const {
return PieceSquareTable[piece_of_color_and_type(c, pt)][s];
}
inline Value Position::mg_pst_delta(Move m) const {
return MgPieceSquareTable[piece_on(move_from(m))][move_to(m)]
-MgPieceSquareTable[piece_on(move_from(m))][move_from(m)];
inline Score Position::pst_delta(Piece piece, Square from, Square to) const {
return PieceSquareTable[piece][to] - PieceSquareTable[piece][from];
}
inline Value Position::mg_value() const {
return st->mgValue;
}
inline Value Position::eg_value() const {
return st->egValue;
inline Score Position::value() const {
return st->value;
}
inline Value Position::non_pawn_material(Color c) const {
return npMaterial[c];
}
inline Phase Position::game_phase() const {
// Values modified by Joona Kiiski
static const Value MidgameLimit = Value(15713);
static const Value EndgameLimit = Value(4428);
Value npm = non_pawn_material(WHITE) + non_pawn_material(BLACK);
if (npm >= MidgameLimit)
return PHASE_MIDGAME;
else if(npm <= EndgameLimit)
return PHASE_ENDGAME;
else
return Phase(((npm - EndgameLimit) * 128) / (MidgameLimit - EndgameLimit));
}
inline bool Position::move_is_deep_pawn_push(Move m) const {
Color c = side_to_move();
return piece_on(move_from(m)) == piece_of_color_and_type(c, PAWN)
&& relative_rank(c, move_to(m)) > RANK_4;
}
inline bool Position::move_is_pawn_push_to_7th(Move m) const {
Color c = side_to_move();
return piece_on(move_from(m)) == piece_of_color_and_type(c, PAWN)
&& relative_rank(c, move_to(m)) == RANK_7;
return st->npMaterial[c];
}
inline bool Position::move_is_passed_pawn_push(Move m) const {
@@ -694,13 +540,6 @@ inline bool Position::move_is_passed_pawn_push(Move m) const {
&& pawn_is_passed(c, move_to(m));
}
inline bool Position::move_was_passed_pawn_push(Move m) const {
Color c = opposite_color(side_to_move());
return piece_on(move_to(m)) == piece_of_color_and_type(c, PAWN)
&& pawn_is_passed(c, move_to(m));
}
inline int Position::rule_50_counter() const {
return st->rule50;
@@ -715,17 +554,23 @@ inline bool Position::opposite_colored_bishops() const {
inline bool Position::has_pawn_on_7th(Color c) const {
return pawns(c) & relative_rank_bb(c, RANK_7);
return pieces(PAWN, c) & relative_rank_bb(c, RANK_7);
}
inline bool Position::move_is_capture(Move m) const {
// Move must not be MOVE_NONE !
return (m & (3 << 15)) ? !move_is_castle(m) : !square_is_empty(move_to(m));
}
return ( !square_is_empty(move_to(m))
&& (color_of_piece_on(move_to(m)) != color_of_piece_on(move_from(m)))
)
|| move_is_ep(m);
inline bool Position::move_is_capture_or_promotion(Move m) const {
// Move must not be MOVE_NONE !
return (m & (0x1F << 12)) ? !move_is_castle(m) : !square_is_empty(move_to(m));
}
inline PieceType Position::captured_piece() const {
return st->capture;
}
#endif // !defined(POSITION_H_INCLUDED)

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2010 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
@@ -29,7 +29,7 @@
////
//// Variables
//// Constants modified by Joona Kiiski
////
static const Value MP = PawnValueMidgame;
@@ -41,70 +41,70 @@ static const Value MQ = QueenValueMidgame;
static const int MgPST[][64] = {
{ },
{// Pawn
// A B C D E F G H
0, 0, 0, 0, 0, 0, 0, 0,
MP-38, MP-12, MP- 0, MP+12, MP+12, MP- 0, MP-12, MP-38,
MP-38, MP-12, MP+ 6, MP+38, MP+38, MP+ 6, MP-12, MP-38,
MP-38, MP-12, MP+16, MP+64, MP+64, MP+16, MP-12, MP-38,
MP-38, MP-12, MP+16, MP+38, MP+38, MP+16, MP-12, MP-38,
MP-38, MP-12, MP+ 6, MP+12, MP+12, MP+ 6, MP-12, MP-38,
MP-38, MP-12, MP- 0, MP+12, MP+12, MP- 0, MP-12, MP-38,
0, 0, 0, 0, 0, 0, 0, 0
// A B C D E F G H
0, 0, 0, 0, 0, 0, 0, 0,
MP-28, MP-6, MP+ 4, MP+14, MP+14, MP+ 4, MP-6, MP-28,
MP-28, MP-6, MP+ 9, MP+36, MP+36, MP+ 9, MP-6, MP-28,
MP-28, MP-6, MP+17, MP+58, MP+58, MP+17, MP-6, MP-28,
MP-28, MP-6, MP+17, MP+36, MP+36, MP+17, MP-6, MP-28,
MP-28, MP-6, MP+ 9, MP+14, MP+14, MP+ 9, MP-6, MP-28,
MP-28, MP-6, MP+ 4, MP+14, MP+14, MP+ 4, MP-6, MP-28,
0, 0, 0, 0, 0, 0, 0, 0
},
{// Knight
// A B C D E F G H
MK-128, MK-102, MK-76, MK-64, MK-64, MK-76, MK-102, MK-128,
MK- 89, MK- 64, MK-38, MK-25, MK-25, MK-38, MK- 64, MK- 89,
MK- 51, MK- 25, MK- 0, MK+12, MK+12, MK- 0, MK- 25, MK- 51,
MK- 25, MK- 0, MK+25, MK+38, MK+38, MK+25, MK- 0, MK- 25,
MK- 12, MK+ 12, MK+38, MK+51, MK+51, MK+38, MK+ 12, MK- 12,
MK- 12, MK+ 12, MK+38, MK+51, MK+51, MK+38, MK+ 12, MK- 12,
MK- 51, MK- 25, MK- 0, MK+12, MK+12, MK- 0, MK- 25, MK- 51,
MK-182, MK- 64, MK-38, MK-25, MK-25, MK-38, MK- 64, MK-182
MK-135, MK-107, MK-80, MK-67, MK-67, MK-80, MK-107, MK-135,
MK- 93, MK- 67, MK-39, MK-25, MK-25, MK-39, MK- 67, MK- 93,
MK- 53, MK- 25, MK+ 1, MK+13, MK+13, MK+ 1, MK- 25, MK- 53,
MK- 25, MK+ 1, MK+27, MK+41, MK+41, MK+27, MK+ 1, MK- 25,
MK- 11, MK+ 13, MK+41, MK+55, MK+55, MK+41, MK+ 13, MK- 11,
MK- 11, MK+ 13, MK+41, MK+55, MK+55, MK+41, MK+ 13, MK- 11,
MK- 53, MK- 25, MK+ 1, MK+13, MK+13, MK+ 1, MK- 25, MK- 53,
MK-193, MK- 67, MK-39, MK-25, MK-25, MK-39, MK- 67, MK-193
},
{// Bishop
// A B C D E F G H
MB-46, MB-46, MB-40, MB-35, MB-35, MB-40, MB-46, MB-46,
MB-20, MB- 0, MB- 5, MB- 0, MB- 0, MB- 5, MB- 0, MB-20,
MB-15, MB- 5, MB+10, MB+ 5, MB+ 5, MB+10, MB- 5, MB-15,
MB-10, MB- 0, MB+ 5, MB+20, MB+20, MB+ 5, MB- 0, MB-10,
MB-10, MB- 0, MB+ 5, MB+20, MB+20, MB+ 5, MB- 0, MB-10,
MB-15, MB- 5, MB+10, MB+ 5, MB+ 5, MB+10, MB- 5, MB-15,
MB-20, MB- 0, MB- 5, MB- 0, MB- 0, MB- 5, MB- 0, MB-20,
MB-20, MB-20, MB-15, MB-10, MB-10, MB-15, MB-20, MB-20
MB-40, MB-40, MB-35, MB-30, MB-30, MB-35, MB-40, MB-40,
MB-17, MB+ 0, MB- 4, MB+ 0, MB+ 0, MB- 4, MB+ 0, MB-17,
MB-13, MB- 4, MB+ 8, MB+ 4, MB+ 4, MB+ 8, MB- 4, MB-13,
MB- 8, MB+ 0, MB+ 4, MB+17, MB+17, MB+ 4, MB+ 0, MB- 8,
MB- 8, MB+ 0, MB+ 4, MB+17, MB+17, MB+ 4, MB+ 0, MB- 8,
MB-13, MB- 4, MB+ 8, MB+ 4, MB+ 4, MB+ 8, MB- 4, MB-13,
MB-17, MB+ 0, MB- 4, MB+ 0, MB+ 0, MB- 4, MB+ 0, MB-17,
MB-17, MB-17, MB-13, MB- 8, MB- 8, MB-13, MB-17, MB-17
},
{// Rook
// A B C D E F G H
MR-18, MR-10, MR-3, MR+4, MR+4, MR-3, MR-10, MR-18,
MR-18, MR-10, MR-3, MR+4, MR+4, MR-3, MR-10, MR-18,
MR-18, MR-10, MR-3, MR+4, MR+4, MR-3, MR-10, MR-18,
MR-18, MR-10, MR-3, MR+4, MR+4, MR-3, MR-10, MR-18,
MR-18, MR-10, MR-3, MR+4, MR+4, MR-3, MR-10, MR-18,
MR-18, MR-10, MR-3, MR+4, MR+4, MR-3, MR-10, MR-18,
MR-18, MR-10, MR-3, MR+4, MR+4, MR-3, MR-10, MR-18,
MR-18, MR-10, MR-3, MR+4, MR+4, MR-3, MR-10, MR-18
// A B C D E F G H
MR-12, MR-7, MR-2, MR+2, MR+2, MR-2, MR-7, MR-12,
MR-12, MR-7, MR-2, MR+2, MR+2, MR-2, MR-7, MR-12,
MR-12, MR-7, MR-2, MR+2, MR+2, MR-2, MR-7, MR-12,
MR-12, MR-7, MR-2, MR+2, MR+2, MR-2, MR-7, MR-12,
MR-12, MR-7, MR-2, MR+2, MR+2, MR-2, MR-7, MR-12,
MR-12, MR-7, MR-2, MR+2, MR+2, MR-2, MR-7, MR-12,
MR-12, MR-7, MR-2, MR+2, MR+2, MR-2, MR-7, MR-12,
MR-12, MR-7, MR-2, MR+2, MR+2, MR-2, MR-7, MR-12
},
{// Queen
//A B C D E F G H
MQ, MQ, MQ, MQ, MQ, MQ, MQ, MQ,
MQ, MQ, MQ, MQ, MQ, MQ, MQ, MQ,
MQ, MQ, MQ, MQ, MQ, MQ, MQ, MQ,
MQ, MQ, MQ, MQ, MQ, MQ, MQ, MQ,
MQ, MQ, MQ, MQ, MQ, MQ, MQ, MQ,
MQ, MQ, MQ, MQ, MQ, MQ, MQ, MQ,
MQ, MQ, MQ, MQ, MQ, MQ, MQ, MQ,
MQ, MQ, MQ, MQ, MQ, MQ, MQ, MQ
// A B C D E F G H
MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8,
MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8,
MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8,
MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8,
MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8,
MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8,
MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8,
MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8
},
{// King
//A B C D E F G H
302, 328, 276, 225, 225, 276, 328, 302,
276, 302, 251, 200, 200, 251, 302, 276,
225, 251, 200, 149, 149, 200, 251, 225,
200, 225, 175, 124, 124, 175, 225, 200,
175, 200, 149, 98, 98, 149, 200, 175,
149, 175, 124, 72, 72, 124, 175, 149,
124, 149, 98, 47, 47, 98, 149, 124,
98, 124, 72, 21, 21, 72, 124, 98
287, 311, 262, 214, 214, 262, 311, 287,
262, 287, 238, 190, 190, 238, 287, 262,
214, 238, 190, 142, 142, 190, 238, 214,
190, 214, 167, 119, 119, 167, 214, 190,
167, 190, 142, 94, 94, 142, 190, 167,
142, 167, 119, 69, 69, 119, 167, 142,
119, 142, 94, 46, 46, 94, 142, 119,
94, 119, 69, 21, 21, 69, 119, 94
}
};
@@ -117,70 +117,70 @@ static const Value EQ = QueenValueEndgame;
static const int EgPST[][64] = {
{ },
{// Pawn
//A B C D E F G H
0, 0, 0, 0, 0, 0, 0, 0,
EP, EP, EP, EP, EP, EP, EP, EP,
EP, EP, EP, EP, EP, EP, EP, EP,
EP, EP, EP, EP, EP, EP, EP, EP,
EP, EP, EP, EP, EP, EP, EP, EP,
EP, EP, EP, EP, EP, EP, EP, EP,
EP, EP, EP, EP, EP, EP, EP, EP,
0, 0, 0, 0, 0, 0, 0, 0
// A B C D E F G H
0, 0, 0, 0, 0, 0, 0, 0,
EP-8, EP-8, EP-8, EP-8, EP-8, EP-8, EP-8, EP-8,
EP-8, EP-8, EP-8, EP-8, EP-8, EP-8, EP-8, EP-8,
EP-8, EP-8, EP-8, EP-8, EP-8, EP-8, EP-8, EP-8,
EP-8, EP-8, EP-8, EP-8, EP-8, EP-8, EP-8, EP-8,
EP-8, EP-8, EP-8, EP-8, EP-8, EP-8, EP-8, EP-8,
EP-8, EP-8, EP-8, EP-8, EP-8, EP-8, EP-8, EP-8,
0, 0, 0, 0, 0, 0, 0, 0
},
{// Knight
// A B C D E F G H
EK-102, EK-76, EK-51, EK-38, EK-38, EK-51, EK-76, EK-102,
EK- 76, EK-51, EK-25, EK-12, EK-12, EK-25, EK-51, EK-76,
EK- 51, EK-25, EK- 0, EK+12, EK+12, EK- 0, EK-25, EK-51,
EK- 38, EK-12, EK+12, EK+25, EK+25, EK+12, EK-12, EK-38,
EK- 38, EK-12, EK+12, EK+25, EK+25, EK+12, EK-12, EK-38,
EK- 51, EK-25, EK- 0, EK+12, EK+12, EK- 0, EK-25, EK-51,
EK- 76, EK-51, EK-25, EK-12, EK-12, EK-25, EK-51, EK-76,
EK-102, EK-76, EK-51, EK-38, EK-38, EK-51, EK-76, EK-102
EK-104, EK-79, EK-55, EK-42, EK-42, EK-55, EK-79, EK-104,
EK- 79, EK-55, EK-30, EK-17, EK-17, EK-30, EK-55, EK- 79,
EK- 55, EK-30, EK- 6, EK+ 5, EK+ 5, EK- 6, EK-30, EK- 55,
EK- 42, EK-17, EK+ 5, EK+18, EK+18, EK+ 5, EK-17, EK- 42,
EK- 42, EK-17, EK+ 5, EK+18, EK+18, EK+ 5, EK-17, EK- 42,
EK- 55, EK-30, EK- 6, EK+ 5, EK+ 5, EK- 6, EK-30, EK- 55,
EK- 79, EK-55, EK-30, EK-17, EK-17, EK-30, EK-55, EK- 79,
EK-104, EK-79, EK-55, EK-42, EK-42, EK-55, EK-79, EK-104
},
{// Bishop
// A B C D E F G H
EB-46, EB-30, EB-23, EB-15, EB-15, EB-23, EB-30, EB-46,
EB-30, EB-15, EB- 7, EB- 0, EB- 0, EB- 7, EB-15, EB-30,
EB-23, EB- 7, EB- 0, EB+ 7, EB+ 7, EB- 0, EB- 7, EB-23,
EB-15, EB- 0, EB+ 7, EB+15, EB+15, EB+ 7, EB- 0, EB-15,
EB-15, EB- 0, EB+ 7, EB+15, EB+15, EB+ 7, EB- 0, EB-15,
EB-23, EB- 7, EB- 0, EB+ 7, EB+ 7, EB- 0, EB- 7, EB-23,
EB-30, EB-15, EB- 7, EB- 0, EB- 0, EB- 7, EB-15, EB-30,
EB-46, EB-30, EB-23, EB-15, EB-15, EB-23, EB-30, EB-46
EB-59, EB-42, EB-35, EB-26, EB-26, EB-35, EB-42, EB-59,
EB-42, EB-26, EB-18, EB-11, EB-11, EB-18, EB-26, EB-42,
EB-35, EB-18, EB-11, EB- 4, EB- 4, EB-11, EB-18, EB-35,
EB-26, EB-11, EB- 4, EB+ 4, EB+ 4, EB- 4, EB-11, EB-26,
EB-26, EB-11, EB- 4, EB+ 4, EB+ 4, EB- 4, EB-11, EB-26,
EB-35, EB-18, EB-11, EB- 4, EB- 4, EB-11, EB-18, EB-35,
EB-42, EB-26, EB-18, EB-11, EB-11, EB-18, EB-26, EB-42,
EB-59, EB-42, EB-35, EB-26, EB-26, EB-35, EB-42, EB-59
},
{// Rook
// A B C D E F G H
ER-3, ER-3, ER-3, ER-3, ER-3, ER-3, ER-3, ER-3,
ER-3, ER-3, ER-3, ER-3, ER-3, ER-3, ER-3, ER-3,
ER-3, ER-3, ER-3, ER-3, ER-3, ER-3, ER-3, ER-3,
ER-3, ER-3, ER-3, ER-3, ER-3, ER-3, ER-3, ER-3,
ER-3, ER-3, ER-3, ER-3, ER-3, ER-3, ER-3, ER-3,
ER-3, ER-3, ER-3, ER-3, ER-3, ER-3, ER-3, ER-3,
ER-3, ER-3, ER-3, ER-3, ER-3, ER-3, ER-3, ER-3,
ER-3, ER-3, ER-3, ER-3, ER-3, ER-3, ER-3, ER-3
ER+3, ER+3, ER+3, ER+3, ER+3, ER+3, ER+3, ER+3,
ER+3, ER+3, ER+3, ER+3, ER+3, ER+3, ER+3, ER+3,
ER+3, ER+3, ER+3, ER+3, ER+3, ER+3, ER+3, ER+3,
ER+3, ER+3, ER+3, ER+3, ER+3, ER+3, ER+3, ER+3,
ER+3, ER+3, ER+3, ER+3, ER+3, ER+3, ER+3, ER+3,
ER+3, ER+3, ER+3, ER+3, ER+3, ER+3, ER+3, ER+3,
ER+3, ER+3, ER+3, ER+3, ER+3, ER+3, ER+3, ER+3,
ER+3, ER+3, ER+3, ER+3, ER+3, ER+3, ER+3, ER+3
},
{// Queen
// A B C D E F G H
EQ-61, EQ-40, EQ-30, EQ-20, EQ-20, EQ-30, EQ-40, EQ-61,
EQ-40, EQ-20, EQ-10, EQ- 0, EQ- 0, EQ-10, EQ-20, EQ-40,
EQ-30, EQ-10, EQ- 0, EQ+10, EQ+10, EQ- 0, EQ-10, EQ-30,
EQ-20, EQ- 0, EQ+10, EQ+20, EQ+20, EQ+10, EQ- 0, EQ-20,
EQ-20, EQ- 0, EQ+10, EQ+20, EQ+20, EQ+10, EQ- 0, EQ-20,
EQ-30, EQ-10, EQ- 0, EQ+10, EQ+10, EQ- 0, EQ-10, EQ-30,
EQ-40, EQ-20, EQ-10, EQ- 0, EQ- 0, EQ-10, EQ-20, EQ-40,
EQ-61, EQ-40, EQ-30, EQ-20, EQ-20, EQ-30, EQ-40, EQ-61
EQ-80, EQ-54, EQ-42, EQ-30, EQ-30, EQ-42, EQ-54, EQ-80,
EQ-54, EQ-30, EQ-18, EQ- 6, EQ- 6, EQ-18, EQ-30, EQ-54,
EQ-42, EQ-18, EQ- 6, EQ+ 6, EQ+ 6, EQ- 6, EQ-18, EQ-42,
EQ-30, EQ- 6, EQ+ 6, EQ+18, EQ+18, EQ+ 6, EQ- 6, EQ-30,
EQ-30, EQ- 6, EQ+ 6, EQ+18, EQ+18, EQ+ 6, EQ- 6, EQ-30,
EQ-42, EQ-18, EQ- 6, EQ+ 6, EQ+ 6, EQ- 6, EQ-18, EQ-42,
EQ-54, EQ-30, EQ-18, EQ- 6, EQ- 6, EQ-18, EQ-30, EQ-54,
EQ-80, EQ-54, EQ-42, EQ-30, EQ-30, EQ-42, EQ-54, EQ-80
},
{// King
//A B C D E F G H
16, 78, 108, 139, 139, 108, 78, 16,
78, 139, 170, 200, 200, 170, 139, 78,
108, 170, 200, 230, 230, 200, 170, 108,
139, 200, 230, 261, 261, 230, 200, 139,
139, 200, 230, 261, 261, 230, 200, 139,
108, 170, 200, 230, 230, 200, 170, 108,
78, 139, 170, 200, 200, 170, 139, 78,
16, 78, 108, 139, 139, 108, 78, 16
18, 77, 105, 135, 135, 105, 77, 18,
77, 135, 165, 193, 193, 165, 135, 77,
105, 165, 193, 222, 222, 193, 165, 105,
135, 193, 222, 251, 251, 222, 193, 135,
135, 193, 222, 251, 251, 222, 193, 135,
105, 165, 193, 222, 222, 193, 165, 105,
77, 135, 165, 193, 193, 165, 135, 77,
18, 77, 105, 135, 135, 105, 77, 18
}
};

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2010 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
@@ -28,10 +28,11 @@
#include <string>
#include <sstream>
#include "history.h"
#include "movepick.h"
#include "san.h"
extern SearchStack EmptySearchStack;
using std::string;
////
//// Local definitions
@@ -39,8 +40,6 @@ extern SearchStack EmptySearchStack;
namespace {
/// Types
enum Ambiguity {
AMBIGUITY_NONE,
AMBIGUITY_FILE,
@@ -48,12 +47,11 @@ namespace {
AMBIGUITY_BOTH
};
/// Functions
const History H; // used as dummy argument for MovePicker c'tor
Ambiguity move_ambiguity(const Position& pos, Move m);
const std::string time_string(int milliseconds);
const std::string score_string(Value v);
const string time_string(int milliseconds);
const string score_string(Value v);
}
@@ -65,7 +63,7 @@ namespace {
/// that the move is a legal move from the position. The return value is
/// a string containing the move in short algebraic notation.
const std::string move_to_san(const Position& pos, Move m) {
const string move_to_san(Position& pos, Move m) {
assert(pos.is_ok());
assert(move_is_ok(m));
@@ -77,7 +75,7 @@ const std::string move_to_san(const Position& pos, Move m) {
to = move_to(m);
pt = type_of_piece(pos.piece_on(move_from(m)));
std::string san = "";
string san = "";
if (m == MOVE_NONE)
return "(none)";
@@ -115,20 +113,20 @@ const std::string move_to_san(const Position& pos, Move m) {
san += "x";
}
san += square_to_string(move_to(m));
if (move_promotion(m))
if (move_is_promotion(m))
{
san += '=';
san += piece_type_to_char(move_promotion(m), true);
san += piece_type_to_char(move_promotion_piece(m), true);
}
}
// Is the move check? We don't use pos.move_is_check(m) here, because
// Position::move_is_check doesn't detect all checks (not castling moves,
// promotions and en passant captures).
StateInfo st;
Position p(pos);
p.do_move(m, st);
if (p.is_check())
san += p.is_mate()? "#" : "+";
pos.do_move(m, st);
if (pos.is_check())
san += pos.is_mate() ? "#" : "+";
pos.undo_move(m);
return san;
}
@@ -139,18 +137,19 @@ const std::string move_to_san(const Position& pos, Move m) {
/// the move is returned. On failure (i.e. if the string is unparsable, or
/// if the move is illegal or ambiguous), MOVE_NONE is returned.
Move move_from_san(const Position& pos, const std::string& movestr) {
Move move_from_san(const Position& pos, const string& movestr) {
assert(pos.is_ok());
MovePicker mp = MovePicker(pos, false, MOVE_NONE, EmptySearchStack, OnePly);
MovePicker mp = MovePicker(pos, MOVE_NONE, OnePly, H);
Bitboard pinned = pos.pinned_pieces(pos.side_to_move());
// Castling moves
if (movestr == "O-O-O" || movestr == "O-O-O+")
{
Move m;
while ((m = mp.get_next_move()) != MOVE_NONE)
if (move_is_long_castle(m) && pos.pl_move_is_legal(m))
if (move_is_long_castle(m) && pos.pl_move_is_legal(m, pinned))
return m;
return MOVE_NONE;
@@ -159,7 +158,7 @@ Move move_from_san(const Position& pos, const std::string& movestr) {
{
Move m;
while ((m = mp.get_next_move()) != MOVE_NONE)
if (move_is_short_castle(m) && pos.pl_move_is_legal(m))
if (move_is_short_castle(m) && pos.pl_move_is_legal(m, pinned))
return m;
return MOVE_NONE;
@@ -167,7 +166,7 @@ Move move_from_san(const Position& pos, const std::string& movestr) {
// Normal moves. We use a simple FSM to parse the san string.
enum { START, TO_FILE, TO_RANK, PROMOTION_OR_CHECK, PROMOTION, CHECK, END };
static const std::string pieceLetters = "KQRBN";
static const string pieceLetters = "KQRBN";
PieceType pt = NO_PIECE_TYPE, promotion = NO_PIECE_TYPE;
File fromFile = FILE_NONE, toFile = FILE_NONE;
Rank fromRank = RANK_NONE, toRank = RANK_NONE;
@@ -177,7 +176,7 @@ Move move_from_san(const Position& pos, const std::string& movestr) {
for (size_t i = 0; i < movestr.length(); i++)
{
char type, c = movestr[i];
if (pieceLetters.find(c) != std::string::npos)
if (pieceLetters.find(c) != string::npos)
type = 'P';
else if (c >= 'a' && c <= 'h')
type = 'F';
@@ -275,7 +274,7 @@ Move move_from_san(const Position& pos, const std::string& movestr) {
while ((m = mp.get_next_move()) != MOVE_NONE)
if ( pos.type_of_piece_on(move_from(m)) == pt
&& move_to(m) == to
&& move_promotion(m) == promotion
&& move_promotion_piece(m) == promotion
&& (fromFile == FILE_NONE || fromFile == square_file(move_from(m)))
&& (fromRank == RANK_NONE || fromRank == square_rank(move_from(m))))
{
@@ -293,11 +292,11 @@ Move move_from_san(const Position& pos, const std::string& movestr) {
/// length of 80 characters. After a line break, 'startColumn' spaces are
/// inserted at the beginning of the new line.
const std::string line_to_san(const Position& pos, Move line[], int startColumn, bool breakLines) {
const string line_to_san(const Position& pos, Move line[], int startColumn, bool breakLines) {
StateInfo st;
std::stringstream s;
std::string moveStr;
string moveStr;
size_t length = 0;
size_t maxLength = 80 - startColumn;
Position p(pos);
@@ -326,15 +325,16 @@ const std::string line_to_san(const Position& pos, Move line[], int startColumn,
/// It is used to write search information to the log file (which is created
/// when the UCI parameter "Use Search Log" is "true").
const std::string pretty_pv(const Position& pos, int time, int depth,
uint64_t nodes, Value score, Move pv[]) {
const string pretty_pv(const Position& pos, int time, int depth,
uint64_t nodes, Value score, ValueType type, Move pv[]) {
std::stringstream s;
// Depth
s << std::setw(2) << depth << " ";
// Score
s << std::setw(8) << score_string(score);
s << ((type == VALUE_TYPE_LOWER)? ">" : ((type == VALUE_TYPE_UPPER)? "<" : " "));
s << std::setw(7) << score_string(score);
// Time
s << std::setw(8) << time_string(time) << " ";
@@ -367,12 +367,13 @@ namespace {
if (type_of_piece(pc) == KING)
return AMBIGUITY_NONE;
MovePicker mp = MovePicker(pos, false, MOVE_NONE, EmptySearchStack, OnePly);
MovePicker mp = MovePicker(pos, MOVE_NONE, OnePly, H);
Bitboard pinned = pos.pinned_pieces(pos.side_to_move());
Move mv, moveList[8];
int n = 0;
while ((mv = mp.get_next_move()) != MOVE_NONE)
if (move_to(mv) == to && pos.piece_on(move_from(mv)) == pc && pos.pl_move_is_legal(mv))
if (move_to(mv) == to && pos.piece_on(move_from(mv)) == pc && pos.pl_move_is_legal(mv, pinned))
moveList[n++] = mv;
if (n == 1)
@@ -397,7 +398,7 @@ namespace {
}
const std::string time_string(int milliseconds) {
const string time_string(int milliseconds) {
std::stringstream s;
s << std::setfill('0');
@@ -414,7 +415,7 @@ namespace {
}
const std::string score_string(Value v) {
const string score_string(Value v) {
std::stringstream s;

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2010 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
@@ -36,9 +36,9 @@
//// Prototypes
////
extern const std::string move_to_san(const Position& pos, Move m);
extern const std::string move_to_san(Position& pos, Move m);
extern Move move_from_san(const Position& pos, const std::string& str);
extern const std::string line_to_san(const Position& pos, Move line[], int startColumn, bool breakLines);
extern const std::string pretty_pv(const Position& pos, int time, int depth, uint64_t nodes, Value score, Move pv[]);
extern const std::string pretty_pv(const Position& pos, int time, int depth, uint64_t nodes, Value score, ValueType type, Move pv[]);
#endif // !defined(SAN_H_INCLUDED)

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2010 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

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2010 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
@@ -26,11 +26,7 @@
////
#include "depth.h"
#include "history.h"
#include "lock.h"
#include "movegen.h"
#include "position.h"
#include "tt.h"
#include "move.h"
#include "value.h"
@@ -51,42 +47,33 @@ const int KILLER_MAX = 2;
/// from nodes shallower and deeper in the tree during the search. Each
/// search thread has its own array of SearchStack objects, indexed by the
/// current ply.
struct EvalInfo;
struct SearchStack {
Move pv[PLY_MAX];
Move pv[PLY_MAX_PLUS_2];
Move currentMove;
Move mateKiller;
Move threatMove;
Move killers[KILLER_MAX];
Depth reduction;
Value eval;
void init(int ply);
void initKillers();
};
////
//// Global variables
////
extern SearchStack EmptySearchStack;
extern TranspositionTable TT;
extern int ActiveThreads;
extern Lock SMPLock;
// Perhaps better to make H local, and pass as parameter to MovePicker?
extern History H;
////
//// Prototypes
////
extern void init_search();
extern void init_threads();
extern void stop_threads();
extern void think(const Position &pos, bool infinite, bool ponder, int side_to_move,
extern void exit_threads();
extern bool think(const Position &pos, bool infinite, bool ponder, int side_to_move,
int time[], int increment[], int movesToGo, int maxDepth,
int maxNodes, int maxTime, Move searchMoves[]);
extern int perft(Position &pos, Depth depth);
extern int64_t nodes_searched();

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2010 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

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2010 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
@@ -26,6 +26,8 @@
//// Includes
////
#include <cstring>
#include "lock.h"
#include "movepick.h"
#include "position.h"
@@ -36,7 +38,8 @@
//// Constants and variables
////
const int THREAD_MAX = 8;
const int MAX_THREADS = 8;
const int ACTIVE_SPLIT_POINTS_MAX = 8;
////
@@ -44,35 +47,49 @@ const int THREAD_MAX = 8;
////
struct SplitPoint {
SplitPoint *parent;
Position pos;
SearchStack sstack[THREAD_MAX][PLY_MAX];
SearchStack *parentSstack;
int ply;
Depth depth;
volatile Value alpha, beta, bestValue;
// Const data after splitPoint has been setup
SplitPoint* parent;
const Position* pos;
bool pvNode;
Bitboard dcCandidates;
int master, slaves[THREAD_MAX];
Depth depth;
bool mateThreat;
Value beta;
int ply, master, slaves[MAX_THREADS];
SearchStack sstack[MAX_THREADS][PLY_MAX_PLUS_2];
// Const pointers to shared data
MovePicker* mp;
SearchStack* parentSstack;
// Shared data
Lock lock;
MovePicker *mp;
volatile Value alpha;
volatile Value bestValue;
volatile int moves;
volatile int cpus;
bool finished;
volatile bool stopRequest;
};
// ThreadState type is used to represent thread's current state
enum ThreadState
{
THREAD_SEARCHING, // thread is performing work
THREAD_AVAILABLE, // thread is polling for work
THREAD_SLEEPING, // we are not thinking, so thread is sleeping
THREAD_BOOKED, // other thread (master) has booked us as a slave
THREAD_WORKISWAITING, // master has ordered us to start
THREAD_TERMINATED // we are quitting and thread is terminated
};
struct Thread {
SplitPoint *splitPoint;
int activeSplitPoints;
SplitPoint* splitPoint;
volatile int activeSplitPoints;
uint64_t nodes;
bool failHighPly1;
volatile bool stop;
volatile bool running;
volatile bool idle;
volatile bool workIsWaiting;
volatile bool printCurrentLine;
unsigned char pad[64];
uint64_t betaCutOffs[2];
volatile ThreadState state;
unsigned char pad[64]; // set some distance among local data for each thread
};

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2010 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
@@ -25,9 +25,15 @@
#include <cassert>
#include <cmath>
#include <cstring>
#if !(defined(__hpux) || defined(__ppc__) || defined(__ppc64__) || defined(__arm__))
# include <xmmintrin.h>
#endif
#include "movegen.h"
#include "tt.h"
// The main transposition table
TranspositionTable TT;
////
//// Functions
@@ -49,27 +55,25 @@ TranspositionTable::~TranspositionTable() {
/// TranspositionTable::set_size sets the size of the transposition table,
/// measured in megabytes.
void TranspositionTable::set_size(unsigned mbSize) {
void TranspositionTable::set_size(size_t mbSize) {
assert(mbSize >= 4 && mbSize <= 4096);
size_t newSize = 1024;
unsigned newSize = 1024;
// We store a cluster of 4 TTEntry for each position and newSize is
// the maximum number of storable positions
while ((2 * newSize) * 4 * (sizeof(TTEntry)) <= (mbSize << 20))
// We store a cluster of ClusterSize number of TTEntry for each position
// and newSize is the maximum number of storable positions.
while ((2 * newSize) * sizeof(TTCluster) <= (mbSize << 20))
newSize *= 2;
if (newSize != size)
{
size = newSize;
delete [] entries;
entries = new TTEntry[size * 4];
entries = new TTCluster[size];
if (!entries)
{
std::cerr << "Failed to allocate " << mbSize
<< " MB for transposition table." << std::endl;
exit(EXIT_FAILURE);
Application::exit_with_failure();
}
clear();
}
@@ -83,7 +87,17 @@ void TranspositionTable::set_size(unsigned mbSize) {
void TranspositionTable::clear() {
memset(entries, 0, size * 4 * sizeof(TTEntry));
memset(entries, 0, size * sizeof(TTCluster));
}
/// TranspositionTable::first_entry returns a pointer to the first
/// entry of a cluster given a position. The low 32 bits of the key
/// are used to get the index in the table.
inline TTEntry* TranspositionTable::first_entry(const Key posKey) const {
return entries[uint32_t(posKey) & (size - 1)].data;
}
@@ -97,23 +111,25 @@ void TranspositionTable::clear() {
/// is bigger than the depth of t2. A TTEntry of type VALUE_TYPE_EVAL
/// never replaces another entry for the same position.
void TranspositionTable::store(const Position& p, Value v, ValueType t, Depth d, Move m) {
void TranspositionTable::store(const Key posKey, Value v, ValueType t, Depth d, Move m) {
TTEntry *tte, *replace;
uint32_t posKey32 = posKey >> 32; // Use the high 32 bits as key
tte = replace = first_entry(p);
for (int i = 0; i < 4; i++, tte++)
tte = replace = first_entry(posKey);
for (int i = 0; i < ClusterSize; i++, tte++)
{
if (!tte->key() || tte->key() == p.get_key()) // empty or overwrite old
if (!tte->key() || tte->key() == posKey32) // empty or overwrite old
{
// Do not overwrite when new type is VALUE_TYPE_EVAL
if (tte->key() && t == VALUE_TYPE_EVAL)
// Do not overwrite when new type is VALUE_TYPE_EV_LO
if (tte->key() && t == VALUE_TYPE_EV_LO)
return;
// Preserve any exsisting ttMove
if (m == MOVE_NONE)
m = tte->move();
*tte = TTEntry(p.get_key(), v, t, d, m, generation);
*tte = TTEntry(posKey32, v, t, d, m, generation);
return;
}
else if (i == 0) // replace would be a no-op in this common case
@@ -126,7 +142,7 @@ void TranspositionTable::store(const Position& p, Value v, ValueType t, Depth d,
if (c1 + c2 + c3 > 0)
replace = tte;
}
*replace = TTEntry(p.get_key(), v, t, d, m, generation);
*replace = TTEntry(posKey32, v, t, d, m, generation);
writes++;
}
@@ -135,26 +151,44 @@ void TranspositionTable::store(const Position& p, Value v, ValueType t, Depth d,
/// transposition table. Returns a pointer to the TTEntry or NULL
/// if position is not found.
TTEntry* TranspositionTable::retrieve(const Position& pos) const {
TTEntry* TranspositionTable::retrieve(const Key posKey) const {
TTEntry *tte = first_entry(pos);
uint32_t posKey32 = posKey >> 32;
TTEntry* tte = first_entry(posKey);
for (int i = 0; i < 4; i++, tte++)
if (tte->key() == pos.get_key())
for (int i = 0; i < ClusterSize; i++, tte++)
if (tte->key() == posKey32)
return tte;
return NULL;
}
/// TranspositionTable::first_entry returns a pointer to the first
/// entry of a cluster given a position.
/// TranspositionTable::prefetch looks up the current position in the
/// transposition table and load it in L1/L2 cache. This is a non
/// blocking function and do not stalls the CPU waiting for data
/// to be loaded from RAM, that can be very slow. When we will
/// subsequently call retrieve() the TT data will be already
/// quickly accessible in L1/L2 CPU cache.
#if defined(__hpux) || defined(__ppc__) || defined(__ppc64__) || defined(__arm__)
void TranspositionTable::prefetch(const Key) const {} // Not supported on HP UX
#else
inline TTEntry* TranspositionTable::first_entry(const Position& pos) const {
void TranspositionTable::prefetch(const Key posKey) const {
return entries + (int(pos.get_key() & (size - 1)) << 2);
#if defined(__INTEL_COMPILER) || defined(__ICL)
// This hack prevents prefetches to be optimized away by
// Intel compiler. Both MSVC and gcc seems not affected.
__asm__ ("");
#endif
char const* addr = (char*)first_entry(posKey);
_mm_prefetch(addr, _MM_HINT_T2);
_mm_prefetch(addr+64, _MM_HINT_T2); // 64 bytes ahead
}
#endif
/// TranspositionTable::new_search() is called at the beginning of every new
/// search. It increments the "generation" variable, which is used to
/// distinguish transposition table entries from previous searches from
@@ -179,18 +213,51 @@ void TranspositionTable::insert_pv(const Position& pos, Move pv[]) {
for (int i = 0; pv[i] != MOVE_NONE; i++)
{
store(p, VALUE_NONE, VALUE_TYPE_NONE, Depth(-127*OnePly), pv[i]);
TTEntry *tte = retrieve(p.get_key());
if (!tte || tte->move() != pv[i])
store(p.get_key(), VALUE_NONE, VALUE_TYPE_NONE, Depth(-127*OnePly), pv[i]);
p.do_move(pv[i], st);
}
}
/// TranspositionTable::extract_pv() extends a PV by adding moves from the
/// transposition table at the end. This should ensure that the PV is almost
/// always at least two plies long, which is important, because otherwise we
/// will often get single-move PVs when the search stops while failing high,
/// and a single-move PV means that we don't have a ponder move.
void TranspositionTable::extract_pv(const Position& pos, Move pv[], const int PLY_MAX) {
const TTEntry* tte;
StateInfo st;
Position p(pos);
int ply = 0;
// Update position to the end of current PV
while (pv[ply] != MOVE_NONE)
p.do_move(pv[ply++], st);
// Try to add moves from TT while possible
while ( (tte = retrieve(p.get_key())) != NULL
&& tte->move() != MOVE_NONE
&& move_is_legal(p, tte->move())
&& (!p.is_draw() || ply < 2)
&& ply < PLY_MAX)
{
pv[ply] = tte->move();
p.do_move(pv[ply++], st);
}
pv[ply] = MOVE_NONE;
}
/// TranspositionTable::full() returns the permill of all transposition table
/// entries which have received at least one write during the current search.
/// It is used to display the "info hashfull ..." information in UCI.
int TranspositionTable::full() const {
double N = double(size) * 4.0;
double N = double(size) * ClusterSize;
return int(1000 * (1 - exp(writes * log(1.0 - 1.0/N))));
}

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2010 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
@@ -36,43 +36,57 @@
/// The TTEntry class is the class of transposition table entries
///
/// A TTEntry needs 128 bits to be stored
/// A TTEntry needs 96 bits to be stored
///
/// bit 0-63: key
/// bit 64-95: data
/// bit 96-111: value
/// bit 112-127: depth
/// bit 0-31: key
/// bit 32-63: data
/// bit 64-79: value
/// bit 80-95: depth
///
/// the 32 bits of the data field are so defined
///
/// bit 0-16: move
/// bit 17-19: not used
/// bit 20-22: value type
/// bit 17-18: not used
/// bit 19-22: value type
/// bit 23-31: generation
class TTEntry {
public:
TTEntry() {}
TTEntry(Key k, Value v, ValueType t, Depth d, Move m, int generation)
: key_ (k), data((m & 0x1FFFF) | (t << 20) | (generation << 23)),
TTEntry(uint32_t k, Value v, ValueType t, Depth d, Move m, int generation)
: key_ (k), data((m & 0x1FFFF) | (t << 19) | (generation << 23)),
value_(int16_t(v)), depth_(int16_t(d)) {}
Key key() const { return key_; }
uint32_t key() const { return key_; }
Depth depth() const { return Depth(depth_); }
Move move() const { return Move(data & 0x1FFFF); }
Value value() const { return Value(value_); }
ValueType type() const { return ValueType((data >> 20) & 7); }
ValueType type() const { return ValueType((data >> 19) & 0xF); }
int generation() const { return (data >> 23); }
private:
Key key_;
uint32_t key_;
uint32_t data;
int16_t value_;
int16_t depth_;
};
/// The transposition table class. This is basically just a huge array
/// This is the number of TTEntry slots for each position
const int ClusterSize = 5;
/// Each group of ClusterSize number of TTEntry form a TTCluster
/// that is indexed by a single position key. Cluster is padded
/// to a cache line size so to guarantee always aligned accesses.
struct TTCluster {
TTEntry data[ClusterSize];
char cache_line_padding[64 - sizeof(TTEntry[ClusterSize])];
};
/// The transposition table class. This is basically just a huge array
/// containing TTEntry objects, and a few methods for writing new entries
/// and reading new ones.
@@ -81,20 +95,30 @@ class TranspositionTable {
public:
TranspositionTable();
~TranspositionTable();
void set_size(unsigned mbSize);
void set_size(size_t mbSize);
void clear();
void store(const Position& pos, Value v, ValueType type, Depth d, Move m);
TTEntry* retrieve(const Position& pos) const;
void store(const Key posKey, Value v, ValueType type, Depth d, Move m);
TTEntry* retrieve(const Key posKey) const;
void prefetch(const Key posKey) const;
void new_search();
void insert_pv(const Position& pos, Move pv[]);
void extract_pv(const Position& pos, Move pv[], const int PLY_MAX);
int full() const;
private:
inline TTEntry* first_entry(const Position& pos) const;
inline TTEntry* first_entry(const Key posKey) const;
unsigned size, writes;
TTEntry* entries;
// Be sure 'writes' is at least one cache line away
// from read only variables.
unsigned char pad_before[64 - sizeof(unsigned)];
unsigned writes; // heavy SMP read/write access here
unsigned char pad_after[64];
size_t size;
TTCluster* entries;
uint8_t generation;
};
extern TranspositionTable TT;
#endif // !defined(TT_H_INCLUDED)

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2010 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
@@ -31,9 +31,9 @@ typedef __int8 int8_t;
typedef unsigned __int8 uint8_t;
typedef __int16 int16;
typedef unsigned __int16 uint16_t;
typedef __int32 int32;
typedef __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef __int64 int64;
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
typedef __int16 int16_t;
@@ -41,7 +41,60 @@ typedef __int64 int64_t;
#endif // !defined(_MSC_VER)
// Hash keys:
// Hash keys
typedef uint64_t Key;
// Bitboard type
typedef uint64_t Bitboard;
////
//// Compiler specific defines
////
// Quiet a warning on Intel compiler
#if !defined(__SIZEOF_INT__ )
#define __SIZEOF_INT__ 0
#endif
// Check for 64 bits for different compilers: Intel, MSVC and gcc
#if defined(__x86_64) || defined(_M_X64) || defined(_WIN64) || (__SIZEOF_INT__ > 4)
#define IS_64BIT
#endif
#if defined(IS_64BIT) && (defined(__GNUC__) || defined(__INTEL_COMPILER))
#define USE_BSFQ
#endif
// Cache line alignment specification
#if defined(_MSC_VER) || defined(__INTEL_COMPILER)
#define CACHE_LINE_ALIGNMENT __declspec(align(64))
#else
#define CACHE_LINE_ALIGNMENT __attribute__ ((aligned(64)))
#endif
// Define a __cpuid() function for gcc compilers, for Intel and MSVC
// is already available as an intrinsic.
#if defined(_MSC_VER)
#include <intrin.h>
#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
inline void __cpuid(int CPUInfo[4], int InfoType)
{
int* eax = CPUInfo + 0;
int* ebx = CPUInfo + 1;
int* ecx = CPUInfo + 2;
int* edx = CPUInfo + 3;
*eax = InfoType;
*ecx = 0;
__asm__("cpuid" : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx)
: "0" (*eax), "2" (*ecx));
}
#else
inline void __cpuid(int CPUInfo[4], int)
{
CPUInfo[0] = CPUInfo[1] = CPUInfo[2] = CPUInfo[3] = 0;
}
#endif
#endif // !defined(TYPES_H_INCLUDED)

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2010 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
@@ -38,6 +38,7 @@
#include "uci.h"
#include "ucioption.h"
using namespace std;
////
//// Local definitions:
@@ -45,22 +46,22 @@
namespace {
// UCIInputParser is a class for parsing UCI input. The class
// UCIInputParser is a class for parsing UCI input. The class
// is actually a string stream built on a given input string.
typedef std::istringstream UCIInputParser;
typedef istringstream UCIInputParser;
// The root position. This is set up when the user (or in practice, the GUI)
// sends the "position" UCI command. The root position is sent to the think()
// The root position. This is set up when the user (or in practice, the GUI)
// sends the "position" UCI command. The root position is sent to the think()
// function when the program receives the "go" command.
Position RootPosition;
// Local functions
void get_command();
void handle_command(const std::string &command);
void set_option(UCIInputParser &uip);
void set_position(UCIInputParser &uip);
void go(UCIInputParser &uip);
bool handle_command(const string& command);
void set_option(UCIInputParser& uip);
void set_position(UCIInputParser& uip);
bool go(UCIInputParser& uip);
void perft(UCIInputParser& uip);
}
@@ -68,17 +69,25 @@ namespace {
//// Functions
////
/// uci_main_loop() is the only global function in this file. It is
/// uci_main_loop() is the only global function in this file. It is
/// called immediately after the program has finished initializing.
/// The program remains in this loop until it receives the "quit" UCI
/// command.
/// command. It waits for a command from the user, and passes this
/// command to handle_command and also intercepts EOF from stdin,
/// by translating EOF to the "quit" command. This ensures that Stockfish
/// exits gracefully if the GUI dies unexpectedly.
void uci_main_loop() {
RootPosition.from_fen(StartPosition);
string command;
while (1)
get_command();
do {
// Wait for a command from stdin
if (!getline(cin, command))
command = "quit";
} while (handle_command(command));
}
@@ -88,64 +97,44 @@ void uci_main_loop() {
namespace {
// get_command() waits for a command from the user, and passes
// this command to handle_command. get_command also intercepts
// EOF from stdin, by translating EOF to the "quit" command. This
// ensures that Stockfish exits gracefully if the GUI dies
// unexpectedly.
void get_command() {
std::string command;
if (!std::getline(std::cin, command))
command = "quit";
handle_command(command);
}
// handle_command() takes a text string as input, uses a
// UCIInputParser object to parse this text string as a UCI command,
// and calls the appropriate functions. In addition to the UCI
// and calls the appropriate functions. In addition to the UCI
// commands, the function also supports a few debug commands.
void handle_command(const std::string &command) {
bool handle_command(const string& command) {
UCIInputParser uip(command);
std::string token;
string token;
uip >> token; // operator >> skips any whitespace
if (!(uip >> token)) // operator>>() skips any whitespace
return true;
if (token == "quit")
return false;
if (token == "go")
return go(uip);
if (token == "uci")
{
OpeningBook.close();
stop_threads();
quit_eval();
exit(0);
}
else if (token == "uci")
{
std::cout << "id name " << engine_name() << std::endl
<< "id author Tord Romstad, Marco Costalba"
<< std::endl;
cout << "id name " << engine_name()
<< "\nid author Tord Romstad, Marco Costalba, Joona Kiiski\n";
print_uci_options();
std::cout << "uciok" << std::endl;
cout << "uciok" << endl;
}
else if (token == "ucinewgame")
{
TT.clear();
push_button("New Game");
Position::init_piece_square_tables();
RootPosition.from_fen(StartPosition);
}
else if (token == "isready")
std::cout << "readyok" << std::endl;
cout << "readyok" << endl;
else if (token == "position")
set_position(uip);
else if (token == "setoption")
set_option(uip);
else if (token == "go")
go(uip);
// The remaining commands are for debugging purposes only.
// Perhaps they should be removed later in order to reduce the
@@ -160,126 +149,115 @@ namespace {
else if (token == "eval")
{
EvalInfo ei;
std::cout << "Incremental mg: " << RootPosition.mg_value()
<< std::endl;
std::cout << "Incremental eg: " << RootPosition.eg_value()
<< std::endl;
std::cout << "Full eval: "
<< evaluate(RootPosition, ei, 0)
<< std::endl;
cout << "Incremental mg: " << mg_value(RootPosition.value())
<< "\nIncremental eg: " << eg_value(RootPosition.value())
<< "\nFull eval: " << evaluate(RootPosition, ei, 0) << endl;
}
else if (token == "key")
{
std::cout << "key: " << std::hex << RootPosition.get_key()
<< " material key: " << RootPosition.get_material_key()
<< " pawn key: " << RootPosition.get_pawn_key()
<< std::endl;
}
cout << "key: " << hex << RootPosition.get_key()
<< "\nmaterial key: " << RootPosition.get_material_key()
<< "\npawn key: " << RootPosition.get_pawn_key() << endl;
else if (token == "perft")
perft(uip);
else
{
std::cout << "Unknown command: " << command << std::endl;
while (!uip.eof())
{
uip >> token;
std::cout << token << std::endl;
}
}
cout << "Unknown command: " << command << endl;
return true;
}
// set_position() is called when Stockfish receives the "position" UCI
// command. The input parameter is a UCIInputParser. It is assumed
// command. The input parameter is a UCIInputParser. It is assumed
// that this parser has consumed the first token of the UCI command
// ("position"), and is ready to read the second token ("startpos"
// or "fen", if the input is well-formed).
void set_position(UCIInputParser &uip) {
void set_position(UCIInputParser& uip) {
std::string token;
string token;
uip >> token; // operator >> skips any whitespace
if (!(uip >> token)) // operator>>() skips any whitespace
return;
if (token == "startpos")
RootPosition.from_fen(StartPosition);
else if (token == "fen")
{
std::string fen;
while (token != "moves" && !uip.eof())
string fen;
while (uip >> token && token != "moves")
{
uip >> token;
fen += token;
fen += ' ';
fen += token;
fen += ' ';
}
RootPosition.from_fen(fen);
}
if (!uip.eof())
if (uip.good())
{
if (token != "moves")
uip >> token;
if (token == "moves")
{
Move move;
StateInfo st;
while (!uip.eof())
while (uip >> token)
{
uip >> token;
move = move_from_string(RootPosition, token);
RootPosition.do_move(move, st);
if (RootPosition.rule_50_counter() == 0)
RootPosition.reset_game_ply();
}
// Our StateInfo st is about going out of scope,
// so save its content before they disappear.
RootPosition.setStartState(st);
// Our StateInfo st is about going out of scope so copy
// its content inside RootPosition before they disappear.
RootPosition.detach();
}
}
}
// set_option() is called when Stockfish receives the "setoption" UCI
// command. The input parameter is a UCIInputParser. It is assumed
// command. The input parameter is a UCIInputParser. It is assumed
// that this parser has consumed the first token of the UCI command
// ("setoption"), and is ready to read the second token ("name", if
// the input is well-formed).
void set_option(UCIInputParser &uip) {
void set_option(UCIInputParser& uip) {
std::string token, name;
string token, name, value;
uip >> token;
if (token == "name")
if (!(uip >> token)) // operator>>() skips any whitespace
return;
if (token == "name" && uip >> name)
{
uip >> name;
while (!uip.eof())
{
uip >> token;
if (token == "value")
break;
while (uip >> token && token != "value")
name += (" " + token);
}
if (token == "value")
if (token == "value" && uip >> value)
{
std::getline(uip, token); // reads until end of line
set_option_value(name, token);
while (uip >> token)
value += (" " + token);
set_option_value(name, value);
} else
push_button(name);
}
}
// go() is called when Stockfish receives the "go" UCI command. The
// input parameter is a UCIInputParser. It is assumed that this
// go() is called when Stockfish receives the "go" UCI command. The
// input parameter is a UCIInputParser. It is assumed that this
// parser has consumed the first token of the UCI command ("go"),
// and is ready to read the second token. The function sets the
// and is ready to read the second token. The function sets the
// thinking time and other parameters from the input string, and
// calls think() (defined in search.cpp) with the appropriate
// parameters.
// parameters. Returns false if a quit command is received while
// thinking, returns true otherwise.
void go(UCIInputParser &uip) {
bool go(UCIInputParser& uip) {
std::string token;
string token;
int time[2] = {0, 0}, inc[2] = {0, 0};
int movesToGo = 0, depth = 0, nodes = 0, moveTime = 0;
@@ -288,10 +266,8 @@ namespace {
searchMoves[0] = MOVE_NONE;
while (!uip.eof())
while (uip >> token)
{
uip >> token;
if (token == "infinite")
infinite = true;
else if (token == "ponder")
@@ -315,21 +291,35 @@ namespace {
else if (token == "searchmoves")
{
int numOfMoves = 0;
while (!uip.eof())
{
uip >> token;
while (uip >> token)
searchMoves[numOfMoves++] = move_from_string(RootPosition, token);
}
searchMoves[numOfMoves] = MOVE_NONE;
}
}
if (moveTime)
infinite = true; // HACK
assert(RootPosition.is_ok());
think(RootPosition, infinite, ponder, RootPosition.side_to_move(), time,
inc, movesToGo, depth, nodes, moveTime, searchMoves);
return think(RootPosition, infinite, ponder, RootPosition.side_to_move(),
time, inc, movesToGo, depth, nodes, moveTime, searchMoves);
}
void perft(UCIInputParser& uip) {
string token;
int depth, tm, n;
Position pos(RootPosition);
if (!(uip >> depth))
return;
tm = get_system_time();
n = perft(pos, depth * OnePly);
tm = get_system_time() - tm;
std::cout << "\nNodes " << n
<< "\nTime (ms) " << tm
<< "\nNodes/second " << (int)(n/(tm/1000.0)) << std::endl;
}
}

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2010 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

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2010 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
@@ -33,13 +33,7 @@
#include "thread.h"
#include "ucioption.h"
////
//// Variables
////
bool Chess960;
using std::string;
////
//// Local definitions
@@ -53,11 +47,11 @@ namespace {
enum OptionType { SPIN, COMBO, CHECK, STRING, BUTTON };
typedef std::vector<std::string> ComboValues;
typedef std::vector<string> ComboValues;
struct Option {
std::string name, defaultValue, currentValue;
string name, defaultValue, currentValue;
OptionType type;
size_t idx;
int minValue, maxValue;
@@ -71,7 +65,7 @@ namespace {
bool operator<(const Option& o) const { return this->idx < o.idx; }
};
typedef std::map<std::string, Option> Options;
typedef std::map<string, Option> Options;
///
/// Constants
@@ -94,26 +88,10 @@ namespace {
o["Space"] = Option(100, 0, 200);
o["Aggressiveness"] = Option(100, 0, 200);
o["Cowardice"] = Option(100, 0, 200);
o["King Safety Curve"] = Option("Quadratic", COMBO);
o["King Safety Curve"].comboValues.push_back("Quadratic");
o["King Safety Curve"].comboValues.push_back("Linear"); /*, "From File"*/
o["King Safety Coefficient"] = Option(40, 1, 100);
o["King Safety X Intercept"] = Option(0, 0, 20);
o["King Safety Max Slope"] = Option(30, 10, 100);
o["King Safety Max Value"] = Option(500, 100, 1000);
o["Queen Contact Check Bonus"] = Option(3, 0, 8);
o["Queen Check Bonus"] = Option(2, 0, 4);
o["Rook Check Bonus"] = Option(1, 0, 4);
o["Bishop Check Bonus"] = Option(1, 0, 4);
o["Knight Check Bonus"] = Option(1, 0, 4);
o["Discovered Check Bonus"] = Option(3, 0, 8);
o["Mate Threat Bonus"] = Option(3, 0, 8);
o["Check Extension (PV nodes)"] = Option(2, 0, 2);
o["Check Extension (non-PV nodes)"] = Option(1, 0, 2);
o["Single Reply Extension (PV nodes)"] = Option(2, 0, 2);
o["Single Reply Extension (non-PV nodes)"] = Option(2, 0, 2);
o["Single Evasion Extension (PV nodes)"] = Option(2, 0, 2);
o["Single Evasion Extension (non-PV nodes)"] = Option(2, 0, 2);
o["Mate Threat Extension (PV nodes)"] = Option(0, 0, 2);
o["Mate Threat Extension (non-PV nodes)"] = Option(0, 0, 2);
o["Pawn Push to 7th Extension (PV nodes)"] = Option(1, 0, 2);
@@ -122,25 +100,21 @@ namespace {
o["Passed Pawn Extension (non-PV nodes)"] = Option(0, 0, 2);
o["Pawn Endgame Extension (PV nodes)"] = Option(2, 0, 2);
o["Pawn Endgame Extension (non-PV nodes)"] = Option(2, 0, 2);
o["Full Depth Moves (PV nodes)"] = Option(14, 1, 100);
o["Full Depth Moves (non-PV nodes)"] = Option(3, 1, 100);
o["Threat Depth"] = Option(5, 0, 100);
o["Futility Pruning (Main Search)"] = Option(true);
o["Futility Pruning (Quiescence Search)"] = Option(true);
o["LSN filtering"] = Option(false);
o["LSN Time Margin (sec)"] = Option(4, 1, 10);
o["LSN Value Margin"] = Option(200, 100, 600);
o["Randomness"] = Option(0, 0, 10);
o["Minimum Split Depth"] = Option(4, 4, 7);
o["Maximum Number of Threads per Split Point"] = Option(5, 4, 8);
o["Threads"] = Option(1, 1, 8);
o["Hash"] = Option(32, 4, 4096);
o["Threads"] = Option(1, 1, MAX_THREADS);
o["Hash"] = Option(32, 4, 8192);
o["Clear Hash"] = Option(false, BUTTON);
o["New Game"] = Option(false, BUTTON);
o["Ponder"] = Option(true);
o["OwnBook"] = Option(true);
o["MultiPV"] = Option(1, 1, 500);
o["UCI_ShowCurrLine"] = Option(false);
o["UCI_Chess960"] = Option(false);
o["UCI_AnalyseMode"] = Option(false);
// Temporary hack for 1.7.1 to be removed in next release
o["Zugzwang detection"] = Option(false);
// Any option should know its name so to be easily printed
for (Options::iterator it = o.begin(); it != o.end(); ++it)
@@ -155,7 +129,7 @@ namespace {
// stringify converts a value of type T to a std::string
template<typename T>
std::string stringify(const T& v) {
string stringify(const T& v) {
std::ostringstream ss;
ss << v;
@@ -168,7 +142,7 @@ namespace {
// type changes a template seems a proper solution.
template<typename T>
T get_option_value(const std::string& optionName) {
T get_option_value(const string& optionName) {
T ret = T();
if (options.find(optionName) == options.end())
@@ -179,6 +153,18 @@ namespace {
return ret;
}
// Specialization for std::string where instruction 'ss >> ret;'
// would erroneusly tokenize a string with spaces.
template<>
string get_option_value<string>(const string& optionName) {
if (options.find(optionName) == options.end())
return string();
return options[optionName].currentValue;
}
}
////
@@ -193,24 +179,18 @@ void init_uci_options() {
load_defaults(options);
// Limit the default value of "Threads" to 7 even if we have 8 CPU cores.
// According to Ken Dail's tests, Glaurung plays much better with 7 than
// with 8 threads. This is weird, but it is probably difficult to find out
// why before I have a 8-core computer to experiment with myself.
// Set optimal value for parameter "Minimum Split Depth"
// according to number of available cores.
assert(options.find("Threads") != options.end());
assert(options.find("Minimum Split Depth") != options.end());
options["Threads"].defaultValue = stringify(Min(cpu_count(), 7));
options["Threads"].currentValue = stringify(Min(cpu_count(), 7));
Option& thr = options["Threads"];
Option& msd = options["Minimum Split Depth"];
// Increase the minimum split depth when the number of CPUs is big.
// It would probably be better to let this depend on the number of threads
// instead.
if (cpu_count() > 4)
{
options["Minimum Split Depth"].defaultValue = "6";
options["Minimum Split Depth"].currentValue = "6";
}
thr.defaultValue = thr.currentValue = stringify(cpu_count());
if (cpu_count() >= 8)
msd.defaultValue = msd.currentValue = stringify(7);
}
@@ -245,9 +225,7 @@ void print_uci_options() {
std::cout << " default " << it->defaultValue;
if (it->type == SPIN)
std::cout << " min " << it->minValue
<< " max " << it->maxValue;
std::cout << " min " << it->minValue << " max " << it->maxValue;
else if (it->type == COMBO)
for (ComboValues::const_iterator itc = it->comboValues.begin();
itc != it->comboValues.end(); ++itc)
@@ -260,7 +238,7 @@ void print_uci_options() {
/// get_option_value_bool() returns the current value of a UCI parameter of
/// type "check".
bool get_option_value_bool(const std::string& optionName) {
bool get_option_value_bool(const string& optionName) {
return get_option_value<bool>(optionName);
}
@@ -271,7 +249,7 @@ bool get_option_value_bool(const std::string& optionName) {
/// it could also be used with a "combo" parameter, where all the available
/// values are integers.
int get_option_value_int(const std::string& optionName) {
int get_option_value_int(const string& optionName) {
return get_option_value<int>(optionName);
}
@@ -280,9 +258,9 @@ int get_option_value_int(const std::string& optionName) {
/// get_option_value_string() returns the current value of a UCI parameter as
/// a string. It is used with parameters of type "combo" and "string".
const std::string get_option_value_string(const std::string& optionName) {
string get_option_value_string(const string& optionName) {
return get_option_value<std::string>(optionName);
return get_option_value<string>(optionName);
}
@@ -290,28 +268,45 @@ const std::string get_option_value_string(const std::string& optionName) {
/// the function does not check that the new value is legal for the given
/// parameter: This is assumed to be the responsibility of the GUI.
void set_option_value(const std::string& optionName,
const std::string& newValue) {
void set_option_value(const string& name, const string& value) {
// UCI protocol uses "true" and "false" instead of "1" and "0", so convert
// newValue according to standard C++ convention before to store it.
std::string v(newValue);
// value according to standard C++ convention before to store it.
string v(value);
if (v == "true")
v = "1";
else if (v == "false")
v = "0";
if (options.find(optionName) != options.end())
options[optionName].currentValue = v;
else
std::cout << "No such option: " << optionName << std::endl;
if (options.find(name) == options.end())
{
std::cout << "No such option: " << name << std::endl;
return;
}
// Normally it's up to the GUI to check for option's limits,
// but we could receive the new value directly from the user
// by teminal window. So let's check the bounds anyway.
Option& opt = options[name];
if (opt.type == CHECK && v != "0" && v != "1")
return;
else if (opt.type == SPIN)
{
int val = atoi(v.c_str());
if (val < opt.minValue || val > opt.maxValue)
return;
}
opt.currentValue = v;
}
/// push_button() is used to tell the engine that a UCI parameter of type
/// "button" has been selected:
void push_button(const std::string& buttonName) {
void push_button(const string& buttonName) {
set_option_value(buttonName, "true");
}
@@ -321,10 +316,10 @@ void push_button(const std::string& buttonName) {
/// been selected since the last time the function was called, in this case
/// it also resets the button.
bool button_was_pressed(const std::string& buttonName) {
bool button_was_pressed(const string& buttonName) {
if (!get_option_value<bool>(buttonName))
return false;
return false;
set_option_value(buttonName, "false");
return true;

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2010 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
@@ -27,27 +27,18 @@
#include <string>
////
//// Variables
////
extern bool Chess960;
////
//// Prototypes
////
extern void init_uci_options();
extern void print_uci_options();
extern bool get_option_value_bool(const std::string &optionName);
extern int get_option_value_int(const std::string &optionName);
extern const std::string get_option_value_string(const std::string &optionName);
extern bool button_was_pressed(const std::string &buttonName);
extern void set_option_value(const std::string &optionName,
const std::string &newValue);
extern void push_button(const std::string &buttonName);
extern bool get_option_value_bool(const std::string& optionName);
extern int get_option_value_int(const std::string& optionName);
extern std::string get_option_value_string(const std::string& optionName);
extern bool button_was_pressed(const std::string& buttonName);
extern void set_option_value(const std::string& optionName,const std::string& newValue);
extern void push_button(const std::string& buttonName);
#endif // !defined(UCIOPTION_H_INCLUDED)

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2010 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

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2010 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
@@ -33,11 +33,16 @@
////
enum ValueType {
VALUE_TYPE_NONE = 0,
VALUE_TYPE_NONE = 0,
VALUE_TYPE_UPPER = 1, // Upper bound
VALUE_TYPE_LOWER = 2, // Lower bound
VALUE_TYPE_EXACT = 3, // Exact score
VALUE_TYPE_EVAL = 4 // Evaluation cache
VALUE_TYPE_EVAL = 4, // Static evaluation value
VALUE_TYPE_NULL = 8, // Null search value
VALUE_TYPE_EV_UP = VALUE_TYPE_EVAL | VALUE_TYPE_UPPER,
VALUE_TYPE_EV_LO = VALUE_TYPE_EVAL | VALUE_TYPE_LOWER,
VALUE_TYPE_NS_LO = VALUE_TYPE_NULL | VALUE_TYPE_LOWER,
};
@@ -46,10 +51,49 @@ enum Value {
VALUE_KNOWN_WIN = 15000,
VALUE_MATE = 30000,
VALUE_INFINITE = 30001,
VALUE_NONE = 30002
VALUE_NONE = 30002,
VALUE_ENSURE_SIGNED = -1
};
/// Score enum keeps a midgame and an endgame value in a single
/// integer (enum), first LSB 16 bits are used to store endgame
/// value, while upper bits are used for midgame value.
// Compiler is free to choose the enum type as long as can keep
// its data, so ensure Score to be an integer type.
enum Score { ENSURE_32_BITS_SIZE_P = (1 << 16), ENSURE_32_BITS_SIZE_N = -(1 << 16)};
// Extracting the _signed_ lower and upper 16 bits it not so trivial
// because according to the standard a simple cast to short is
// implementation defined and so is a right shift of a signed integer.
inline Value mg_value(Score s) { return Value(((int(s) + 32768) & ~0xffff) / 0x10000); }
// Unfortunatly on Intel 64 bit we have a small speed regression, so use a faster code in
// this case, although not 100% standard compliant it seems to work for Intel and MSVC.
#if defined(IS_64BIT) && (!defined(__GNUC__) || defined(__INTEL_COMPILER))
inline Value eg_value(Score s) { return Value(int16_t(s & 0xffff)); }
#else
inline Value eg_value(Score s) { return Value((int)(unsigned(s) & 0x7fffu) - (int)(unsigned(s) & 0x8000u)); }
#endif
inline Score make_score(int mg, int eg) { return Score((mg << 16) + eg); }
inline Score operator-(Score s) { return Score(-int(s)); }
inline Score operator+(Score s1, Score s2) { return Score(int(s1) + int(s2)); }
inline Score operator-(Score s1, Score s2) { return Score(int(s1) - int(s2)); }
inline void operator+=(Score& s1, Score s2) { s1 = Score(int(s1) + int(s2)); }
inline void operator-=(Score& s1, Score s2) { s1 = Score(int(s1) - int(s2)); }
inline Score operator*(int i, Score s) { return Score(i * int(s)); }
// Division must be handled separately for each term
inline Score operator/(Score s, int i) { return make_score(mg_value(s) / i, eg_value(s) / i); }
// Only declared but not defined. We don't want to multiply two scores due to
// a very high risk of overflow. So user should explicitly convert to integer.
inline Score operator*(Score s1, Score s2);
////
//// Constants and variables
////
@@ -62,16 +106,16 @@ enum Value {
///
/// Values modified by Joona Kiiski
const Value PawnValueMidgame = Value(0x0CC);
const Value PawnValueEndgame = Value(0x101);
const Value KnightValueMidgame = Value(0x332);
const Value PawnValueMidgame = Value(0x0C6);
const Value PawnValueEndgame = Value(0x102);
const Value KnightValueMidgame = Value(0x331);
const Value KnightValueEndgame = Value(0x34E);
const Value BishopValueMidgame = Value(0x345);
const Value BishopValueEndgame = Value(0x356);
const Value RookValueMidgame = Value(0x4F8);
const Value RookValueEndgame = Value(0x500);
const Value QueenValueMidgame = Value(0x9D5);
const Value QueenValueEndgame = Value(0x9FB);
const Value BishopValueMidgame = Value(0x344);
const Value BishopValueEndgame = Value(0x359);
const Value RookValueMidgame = Value(0x4F6);
const Value RookValueEndgame = Value(0x4FE);
const Value QueenValueMidgame = Value(0x9D9);
const Value QueenValueEndgame = Value(0x9FE);
const Value PieceValueMidgame[17] = {
Value(0),
@@ -93,10 +137,9 @@ const Value PieceValueEndgame[17] = {
Value(0), Value(0), Value(0)
};
/// Bonus for having the side to move
/// Bonus for having the side to move (modified by Joona Kiiski)
const Value TempoValueMidgame = Value(48);
const Value TempoValueEndgame = Value(21);
const Score TempoValue = make_score(48, 22);
////