Compare commits

..

320 Commits

Author SHA1 Message Date
Marco Costalba
71e14bb67b Stockfish 1.9.1
Fix release to workaround chess960 on some GUIs

Signature is:

stockfish bench 128 1 12 default depth

Node counts: 10914593

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-05 12:00:24 +01:00
Marco Costalba
66a64406ca Fix broken chess960 under Shredder GUI
We need to add a dummy option anyway to make GUIs happy.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-05 12:00:16 +01:00
Marco Costalba
d4876dc963 Rewrite bit counting functions
Get rid of macros and use templates instead,
this is safer and allows us fix the warning:

ISO C++ forbids braced-groups within expressions

That broke compilation with -pedantic flag under
gcc and POPCNT enabled.

No functional and no performance change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-04 18:40:44 +01:00
Marco Costalba
3249777cdb Remove -pedantic option
Breaks current POPCNT code.

Perhaps we will readd with a proper fix...

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-03 14:43:17 +01:00
Marco Costalba
544adf7e41 Use special handling for promotions in move_is_legal()
Simplifies a bit the code and the common case too.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-03 11:15:53 +01:00
Marco Costalba
98b09b4038 Fix an obsoleted NO_PIECE_TYPE in a comment
Spotted by Ralph Stoesser.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-02 18:57:46 +01:00
Marco Costalba
0aeba002c8 Restore development version
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-02 14:36:43 +01:00
Marco Costalba
247c2cd207 Increase warning level
Both under gcc and icc: sf compiles with no warnings !

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-02 14:32:43 +01:00
Marco Costalba
46c16ab783 Stockfish 1.9
Signature is:

stockfish bench 128 1 12 default depth

Node counts: 10914593

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-02 09:55:10 +01:00
Joona Kiiski
3fd0079807 Less aggressive move count based futility pruning
This patch from Joona greatly reduces move count pruning,
below is the old and new move count limits starting from
ONE_PLY with half-play increment:

Old: 4,5,5,5, 7, 7,11,11,11,19,19,19,35,35
New: 4,5,7,9,12,15,19,23,28,33,39,45,52,59

Surprisingly results are even a bit better at a quite
fast time control.

After 5260 games at 30"+0.1
Mod - Orig:  864 - 806 - 3590  ELO +3 (+- 3.8)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-09-26 10:27:15 +01:00
Marco Costalba
a28f4a56d3 Fix handling of 50 move rule and remove a fixme
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-09-25 11:24:20 +01:00
Marco Costalba
7305b56957 Shrink OutpostBonus[] definition
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-09-25 11:12:55 +01:00
Marco Costalba
045beac156 Simplify scale factors implementation
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-09-24 12:56:45 +01:00
Marco Costalba
0e3535ea23 Rename no_mob_area in mobilityArea
It is the correct name.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-09-24 12:56:38 +01:00
Marco Costalba
c254861ee6 Small code style in qsearch
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-09-21 20:04:15 +01:00
Marco Costalba
c1558dde12 Do not update killers in qsearch
It seems totally unuseful because killers are not
used to order the moves in qsearch. Although there
is some functionality change, probably just a small
side effect.

After 5656 games on rc
Mod vs Orig: 1007 - 980 - 3669  ELO +1 (+- 3.7)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-09-21 06:25:47 +01:00
Marco Costalba
9d1522b24f A king move can never have negative SEE
So there is no need to explicitly check for king moves
when detecting prunable evasions.

Perhaps teoretically a very bit slower (I didn't test),
but it is more clear now what evasions we consider prunable.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-09-19 13:56:50 +01:00
Marco Costalba
23fd379694 Simplify SEE
Greatly cleanup SEE code and now it is also a bit
faster on gcc, about +0.6%.

Thanks to Mike Whiteley new SEE code that gave me
fresh ideas on how to cleanup this old stuff.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-09-19 13:41:54 +01:00
Marco Costalba
9ab0e1bb13 Retire NullMoveMargin
A code semplification that could even be a slight increase,
anyhow is a reducing pruning patch, so it is good even
at equal strenght.

After 6342 games
Mod - Orig:  1040 - 974 - 4328  ELO +3 (+- 3.5)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-09-16 08:22:39 +01:00
Marco Costalba
debc815352 We need just one eval margin in search
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-09-14 18:06:10 +01:00
Marco Costalba
dd8a076128 Reintroduce rook contact checks
Were removed when merged from Glaurung 2.2, but without
any test.

Note that weight has been increased from original 2 to 4 and
has been also fixed a bug where in the original version were
considered also diagonal sqaures for the rook, that are
contact squares but not checks.

After 4449 games at 30"+0.1
Mod - Orig:  717 - 649 - 3083  ELO +5 (+- 4.1)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-09-14 13:48:26 +01:00
Marco Costalba
4350d9e8a6 Fix a warning under icc
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-09-14 07:56:02 +01:00
Marco Costalba
42ed488987 Retire badCaptures[] array in MovePicker
Use the tail of moves[] array to store bad captures.

No functional change but some move reorder. Verified with old perft.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-09-13 13:22:00 +01:00
Marco Costalba
4143d00011 Increase QueenContactCheckBonus
And also other check bonuses.

After 4272 games on russian cluster at 30"+0.1
Mod - Orig:  711 - 612 - 2949  ELO +8 (+- 4.2)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-09-13 00:10:48 +01:00
Marco Costalba
1a2768705a Do not update king tables when we skip king safety
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-09-12 14:28:07 +01:00
Joona Kiiski
fa2478a81f Retire pawn storm evaluation
More then 100 lines of almost useless evaluations. Prefer
code semplification to a very small and dubious advantage.

After 7457 games on russian cluster:
Mod - Orig: 1285 - 1334 - 4838  ELO -2 (+- 3.2)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-09-11 09:46:00 +01:00
Marco Costalba
5b5b496a6d Array FutilityMarginsMatrix stores Values
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-09-04 14:10:48 +01:00
Marco Costalba
6096ca7a95 Remove get_* prefix from RootMoveList API
And small additional cleanup in RootMoveList.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-30 12:56:12 +01:00
Marco Costalba
427dc2a82c Use only cumulativeNodes in RootMoveList
And rename in nodes now that we have only one.

After the beta-cut off counters removing we can
get rid also of this one.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-30 12:56:04 +01:00
Marco Costalba
b177e6dd91 Use evaluation margins also in main search
For now keep FutilityMarginsMatrix[] unchanged, in
future we are going to reduce to compensate for extra
margin.

At this moment it is enough we don't have regressions.

After 9694 games on russian cluster
Mod - Orig 1608 - 1578 - 6508  ELO +1 (+- 2.8)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-28 12:07:15 +01:00
Marco Costalba
d9dc9dbd65 Split branches in generate_piece_moves()
Instead of one comparison in while() condition use two,
the first to check if the piece is exsistant and the second
to loop across pieces of that type.

This should help branch prediction in cases we have only
one piece of the same type, for instance for queens, the
first branch is always true and the second is almost always
false.

Increased speed of 0.3-0.5 % on Gcc pgo compiles.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-27 13:28:07 +01:00
Marco Costalba
2a2353aac6 Speed up updateShelter()
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-26 18:52:53 +02:00
Marco Costalba
1b4084b4a5 Assorted code style in evaluation.cpp
Renaming, cleanu up, etc.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-26 13:47:38 +01:00
Marco Costalba
c7dd9b8d0c Finally remove value from EvalInfo
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-26 13:47:29 +01:00
Marco Costalba
9ee42d83b6 Remove dependency from ei.value in evaluate functions
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-26 13:41:28 +01:00
Marco Costalba
3107e68c03 Remove margin[] from EvalInfo
Directly pass arguments to king evaluation.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-26 13:41:28 +01:00
Marco Costalba
d4250c52f0 Remove MaterialInfo* from EvalInfo
Use a local variable instead.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-26 13:41:27 +01:00
Marco Costalba
15d265cc66 Change evaluate() signature
Hide EvalInfo and return just the score and the margin.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-26 13:41:26 +01:00
Marco Costalba
fff59319b0 Retire attackedBy[] access functions
Currently are used by evaluation itself and the
whole EvalInfo will be removed from global visibility
by next patch, so no reason to use them.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-26 13:41:26 +01:00
Marco Costalba
b196af4dcd Decrypt some magics in bitboards definitions
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-26 13:41:25 +01:00
Marco Costalba
eb4858256b We don't need EvalInfo c'tor anymore
We know always get complete info from TT, so this
code is obsolete.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-25 00:20:53 +01:00
Marco Costalba
c7a932bc74 Rename ei.kingDanger in ei.margin
It will be more clear when we will go to add stuff
apart from king danger itself.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-24 19:16:03 +01:00
Marco Costalba
00469d1798 Call apply_weight() only once in passed pawns evaluation
First accumulate the bonus for each pawn, then call the
not very fast apply_weight().

Should be no functional change apart from rounding issues.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-24 19:13:13 +01:00
Marco Costalba
17d820e248 Don't need to memset() EvalInfo
Set manually to zero the few fields that are
optionally populated and that's enough.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-24 18:58:51 +01:00
Marco Costalba
d73eea3f71 There is no need of storing mobility in EvalInfo
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-24 18:55:40 +01:00
Marco Costalba
74033b004e Refresh comments in evaluate.cpp
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-24 18:55:31 +01:00
Marco Costalba
6125966da0 Unify single MobilityBonus[] tables in a big single one
Avoid one address lookup in a very critical time path.

Unified also outpost bonus tables for knights and bishops.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-24 13:34:41 +01:00
Marco Costalba
421867ea2d Retire trapped bishop evaluation
Another 100 lines of dubious and ad-hoc code.

After 7644 games on russian cluster:
Mod - Orig 1285 - 1249 - 5110  ELO +1 (+- 3.2)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-24 13:13:20 +01:00
Marco Costalba
e17fa64aec Retire UCI_Chess960 option
We don't need that !

We can infere from starting fen string if we are in
a Chess960 game or not. And note that this is a per-position
property, not an application wide one.

A nice trick is to use a custom manipulator (that is an
enum actually) to keep using the handy operator<<() on the
move when sending to std::cout, yes, I have indulged a
bit here ;-)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-22 16:51:20 +01:00
Marco Costalba
7b721b3663 Prefetch pawn hash key
Plus a bunch of other minor optimizations.

With this power pack we have an increase
of a whopping 1.4%  :-)

...and it took 3 good hours of profiling + hacking to get it out !

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-22 14:04:06 +01:00
Marco Costalba
b6ba5f7fe4 Retire unstoppable pawns evaluation
One hundred lines of code should be compensated by an
important ELO increase, otherwise are candidate for removal...

...and is not the case. We are well within error margin, so
remove the code even if we lose a couple of elo points, but
semplification is huge.

After 6494 games on russian cluster
Orig vs Mod 1145 - 1107 - 4242 (-2 ELO)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-22 01:39:31 +01:00
Marco Costalba
73f1179d39 Remove my address from README
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-21 17:21:44 +01:00
Marco Costalba
0363b54358 Retire beta counters stuff
Is now obsoleted by previous patch.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-20 18:33:19 +01:00
Joona Kiiski
a44f79141e Use MovePicker's move ordering also at root
After testing on our russian cluster: +3 elo after 4200 games

So keep it becuase it allows a good semplification.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-20 18:04:02 +01:00
Marco Costalba
79a28841f9 Move StartPositionFEN out of the header
It is not needed to have global visibility.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-19 18:22:48 +01:00
Marco Costalba
df4b106716 Move piece values in piece.h / piece.cpp
Where they belong.

Note that array PieceValueMidgame[] and PieceValueEndgame[]
are now declared extern in the header and moved in piece.cpp
so to avoid allocate the array each time the header is
included !

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-19 18:22:48 +01:00
Marco Costalba
a952c6bc6d Retire is_upper_bound() and friend
Directly expand in the few places where is called.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-19 18:22:47 +01:00
Marco Costalba
391e176274 Retire useless piece_value_midgame() overloads
Directly access the table in the few call places.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-19 18:22:46 +01:00
Marco Costalba
5bed82cd4e Introduce and use SCORE_ZERO
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-19 18:22:46 +01:00
Marco Costalba
4419924fcf Do not score PH_QCHECKS
They are picked unsorted anyway, so score is unuseful.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-19 14:50:02 +01:00
Marco Costalba
a5ae7fe260 Disable templetized operators by default
To avoid nasty bugs due to silently overriding of
common operator we enable the templates on a type
by type base using partial template specialization.

No functional change, zero overhead at runtime.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-19 13:48:41 +01:00
Marco Costalba
94b9c65e09 Introduce enum VALUE_ZERO instead of Value(0)
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-19 13:48:38 +01:00
Marco Costalba
0e800c527a Use Use templetized operations for Score and Value
Note that in value we leave two specialized functions
to allow adding an integer, we don't want to add this
as a template becasue we want to control implicit
conversions to integer of an enum.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-19 13:48:37 +01:00
Marco Costalba
13bd0cff0d Use templetized operations for Piece
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-19 13:48:35 +01:00
Marco Costalba
8e31764c49 Use templetized operations for Square
This is tricky because there are some special
binary fnctions with SquareDelta that we should
leave as they are.

Also note that we needed to add Unary minus template
to fix a comile error in SERIALIZE_MOVES_D macro that was
triggered because now we don't allow conversion to int.

No fuctional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-19 13:48:33 +01:00
Marco Costalba
4ce08482c3 Use templetized operations for File and Rank
Doing the conversion the compiler is now able to
spot two possible ambiguity calls that now we can
easily fix.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-19 13:48:30 +01:00
Marco Costalba
80bee85d5f Use templetize enum operations for Depth
Instead of hardcoded ones.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-19 13:48:28 +01:00
Marco Costalba
4f96f420a3 Store in TT with depth == -OnePly instead of -1
When depth < DEPTH_ZERO we store with the same depth all
the positions, use -OnePly instead of -1 for consistency
with depth arithmetic.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-19 13:48:26 +01:00
Marco Costalba
4f28e19fc0 (Re)introduce DEPTH_ZERO to replace Depth(0)
No functional changes.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-19 13:48:24 +01:00
Marco Costalba
ea2b8a93eb Retire some unused Depth operator() functions
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-19 13:48:23 +01:00
Marco Costalba
4aeffc8c9a Rename OnePly in ONE_PLY
Use enum values standard naming policy also for this one.

No fuctional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-19 13:48:20 +01:00
Marco Costalba
cfb52fcd5d Define OnePly as a Depth enum costant
There is no reason to use a variable for this.

Also remove unused DEPTH_ZERO and DEPTH_MAX.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-19 13:48:11 +01:00
Marco Costalba
cf4c28ff86 Revert F_90 and F_92
Regression test found the patches to be harmless,
so revert to keep code simpler.

Test1 at 20+0.1: (2500 - 3000) +0 ELO
Test2 at 1+0: (~1000) +2 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-18 10:07:28 +01:00
Marco Costalba
252537fd9c Cleanup and optimize Position::has_mate_threat()
There is a functional change because we now skip
more moves and because do_move() / undo_move() is
well known to be not reversible we end up with a
change in node count, although there is actually
no change but a bit speed up.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-09 12:30:33 +01:00
Marco Costalba
f26e0fec64 Usual material.cpp small touches
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-08 13:14:18 +01:00
Marco Costalba
e6376d9b8d Rename constants to use *_NONE scheme
To be uniform across the sources. As a nice side effect
I quickly spotted a couple of needed renames:

captured_piece() -> captured_piece_type()
st->capture      -> st->capturedType

Proposed by Ralph and done with QtCreator

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-07 18:56:24 +01:00
Marco Costalba
2170fa18bf Move depth computation out of fail low loop
In root_search() we can compute depth at the beginning
once and for all.

Spotted by Ralph Stoesser.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-06 22:30:50 +01:00
Marco Costalba
be540b6dd7 Another push to perft speed
We don't need to generate captures and non
captures in a separate step. This gives another
7% push to perft speed.

yes, I know, it is totally useless :-)

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-06 12:10:07 +01:00
Marco Costalba
3a2cd37080 Faster perft
Skip moves scoring and sorting: this more then
doubles the speed !

Verified is correct.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-06 11:15:41 +01:00
Marco Costalba
d6904157aa Rename TM in ThreadsMgr
This avoid misunderstandings with new TimeManager
object called TimeMgr.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-03 13:06:56 +01:00
Marco Costalba
5fc98745c3 TimeManager API rename
We can now set member data as private because is no more
directly accessed.

Should be more clear now.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-03 11:49:28 +01:00
Marco Costalba
c295599e4a Move time related global variables under TimeManager
Move OptimumSearchTime, MaximumSearchTime and
ExtraSearchTime in TimeManager.

Note that we remove an useless initialization to 0 because
these variables are used only with time management.

Also introduce and use TimeManager::available_time()

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-03 11:47:52 +01:00
Marco Costalba
dda53e831d Introduce TimeManager class
Firt step in unifying all time management under
a single umbrella. Just introduced the class without
even member data.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-03 11:39:42 +01:00
Marco Costalba
977f6349a9 Small cleanup in search Step.5
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-02 22:09:20 +01:00
Marco Costalba
5aef9186ac Reset bestMove before entering main moves loop
After razoring, IID, null verification and singular
extension searches we have could have a dirty ss->bestMove,
restore to MOVE_NONE before to enter moves loop.

This should avoid to store in TT a stale move when
we fail low.

Tested together with previous patch that is the
one that gives ELO.

After 1152 games at 1+0 on my QUAD
Mod vs Orig +233 =716 -203 (+9 ELO)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-02 22:02:59 +01:00
Marco Costalba
cbcc581a86 Use past SE information also for success cases
If singular extension search was succesful in the past then
skip another the SE search and extend of one ply.

Another way to mitigate the cost of SE at the price of
some more spurious extension, but on 90% of cases info
is correct.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-02 18:47:27 +01:00
Marco Costalba
fe23c70cf1 Rename MaxSearchTime and AbsoluteMaxSearchTime
Renamed in OptimumSearchTime and MaximumSearchTime,
should be more clear now.

Suggested by Joona.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-02 18:41:55 +01:00
Marco Costalba
cf0295f1ad Templetize xxx_time_for_MTG()
Also fixed some warnings under MSVC.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-02 11:55:45 +01:00
Marco Costalba
391cd57b52 Little timeman.cpp massage
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-02 11:49:49 +01:00
Joona Kiiski
f40e481fd6 Tweak default values for ucioptions
I created three different systems, tested them all separately and
attached one did best:

1/40: Orig - Mod: 841 - 850 (+2 elo)
1+1 : Orig - Mod: 474 - 498 (+9 elo)
1+0 : Orig - Mod: 455 - 495 (+15 elo)

Because such testing system is not statistically reliable, I made a
confirmation test:

1/40: Orig - Mod: 502 - 543 (+14 elo)
1+1: Orig - Mod: 447 - 489 (+16 elo)
1+0: Orig - Mod: 641 - 656 (+4 elo)

All tests show positive score :-)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-02 11:49:31 +01:00
Joona Kiiski
c0616d773d New Time management system
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-08-02 11:48:03 +01:00
Marco Costalba
87139d018c Always use ss->bestMove to store ply best move
Instead of ss->currentMove. It is more consistent and
clear to understand.

Remark by Ralph Stoesser.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-31 07:29:29 +01:00
Marco Costalba
9645e8e4e7 Lower SingularExtensionDepth to 7 plies for non-pv
To compensate for the extra work skip singular
searches deemed to fail because excluded node
failed high already in the past.

After 1200 games at 1+0
Mod vs Orig +387 =1274 -339  (+8 ELO)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-30 22:50:03 +01:00
Marco Costalba
935fc09fd4 Two small fixes in passed pawns evaluation
The one in evaluate_passed_pawns() is just a micro
optimization, the other in evaluate_unstoppable_pawns()
is indeed a fix, although almost unmeasurable in real
games.

Bugs report and fixes by Marek Kwiatkowski

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-26 06:10:01 +01:00
Marco Costalba
5ee7dfebf7 Fix KBNK endgame
Broken by recent patch. Also better document what's
happening there.

Verified to restore original behaviour.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-25 21:58:09 +01:00
Marco Costalba
6b6f3c4ca4 Rename EMPTY in NO_PIECE
It is more correct and more in line with enum PieceType

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-25 12:10:22 +01:00
Marco Costalba
14f059072a Introduce enum SquareColor
Square and piece colors are two different things,
so use different types to avoid misunderstandings.

Suggested by Tord.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-25 11:49:58 +01:00
Marco Costalba
9b1d5bd534 Introduce and use same_color_squares()
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-25 11:49:32 +01:00
Marco Costalba
a84e4b2049 Cleanup Position::print()
And remove not used OUTSIDE enum Piece.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-25 09:57:57 +01:00
Joona Kiiski
4d438fae9e Fix build failure on GCC
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-25 08:57:23 +01:00
Marco Costalba
02882dfe81 Cleanup Position::to_fen()
Less invasive then previous patches, but still a good
enhancement.

Also some indulge on STL algorithms :-)

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-24 18:56:07 +01:00
Marco Costalba
c2048136ec Last touches to from_fen()
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-24 16:31:12 +01:00
Marco Costalba
839088205e Rewrite Position::from_fen()
Complete rewrite the function and extend compatibility
also to X-FEN notation for Chess960.

We are now able to read standard FEN, Shredder-FEN and X-FEN.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-24 09:43:01 +01:00
Joona Kiiski
098ac5e44e Don't initialize psqt-tables when 'ucinewgame' is received
After 'Randomness' is retired, this is no longer necessary.

NOTE: Possibly some extra care is needed when tuning branch is synced

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-23 12:21:54 +01:00
Joona Kiiski
d3260ce70f Retire 'Randomness' ucioption
Using multiple threads and good opening book is
much better and more reliable source of randomness than
spoiling psqt-tables

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-23 12:21:46 +01:00
Joona Kiiski
71ba48c4ff Always init pthread locks to NULL
This is the only way to keep Windows and POSIX behaviour in sync,
so better hardcode it.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-23 07:03:39 +01:00
Joona Kiiski
65f8b6dbc0 Remove other locking options
Currently broken and we use pthreads in search.cpp
anyway, so I see no reason to keep these around

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-23 07:03:32 +01:00
Marco Costalba
d5520977b9 Retire SearchStack init() and initKillers()
Let be explicit about what this functions do, and
we save some code lines too.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-23 02:42:27 +01:00
Marco Costalba
d004ec924d Fix errouneus reset of ss->threatMove
After we set ss->threatMove we could go under a IID step that
resets SearchStack ss and so also ss->threatMove.

When later we use that field in futility pruning we have this
set to MOVE_NONE !

The fix is to use a local variable and add threatMove to SplitPoint
to pass this move to slaves.

Spotted by Ralph Stoesser, fix suggested by Richard Vida.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-23 02:26:57 +01:00
Marco Costalba
5c3aeae566 Revert previous patch
Improvement is easily in error bar and there is
some added complexity making future changes more
difficult.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-22 18:30:18 +01:00
Marco Costalba
26a8b84417 Weight backward-ness of a pawn
Because not all backward pawns are the same ;-) if the
blocking enemy pawn is near then our pawn is more backward
than another whose enemy pawn is far away so that can advance
for some sqaures.

After 2925 games at 30"+0 on my QUAD
Mod vs Orig +602 =1745 -578 +3 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-22 18:15:16 +01:00
Joona Kiiski
6aef4429fd ValueType needs only 2 bits to be stored in TT
Also update some more TT documentation

No functional change

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-22 17:51:33 +01:00
Joona Kiiski
23db43e698 Update TT documentation
Update outdated and even misleading documentation.

Also check #include-directives

No functional change

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-22 17:51:26 +01:00
Marco Costalba
6f6f59ea6a Move insert_pv() and extract_pv() out of TT class
These functions have little to do with TranspositionTable
class and more with the search and in particular with the PV
handling. So move them where they belong.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-21 12:09:09 +01:00
Marco Costalba
e2c0b5f995 Store position static score in TT as soon as possible
So to maximize the possibility to avoid to recalculate it
in the future. A small speed-up of 0.8%

Idea by Ralph Stoesser.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-21 12:08:45 +01:00
Marco Costalba
02f96fcf5e Introduce DEPTH_NONE and use it
Also better fix previous patch.

Suggestions by Joona and Ralph.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-20 19:06:09 +01:00
Joona Kiiski
28feb2c6b0 Remove pointless tte->static_value() != VALUE_NONE checks
Now in non-check nodes we are guaranteed to always have static value
in TT Entry.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-20 19:01:10 +01:00
Joona Kiiski
ba1a44f216 Store static value and king danger in TT also in TT.insert_pv() method
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-20 19:01:01 +01:00
Marco Costalba
0fb5d7a737 Fix "pass ss->eval to qsearch()" condition
The seocond check is no more needed now and
anyhow is wrong to overwrite a TT entry if
present.

Spotted by Ralph Stoesser.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-19 12:28:33 +01:00
Marco Costalba
201f924d53 Triviality in material.cpp
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-19 12:01:36 +01:00
Marco Costalba
95388a952b Small rewrite of backward pawn test
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-19 07:13:50 +01:00
Joona Kiiski
b5178597bd Initialize SearchStack only once at RootMoveList c'tor
Just fix current ugly behaviour :-)

No functional change

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-19 03:53:37 +01:00
Joona Kiiski
b75e68860c Every node is responsible for initializing its own SearchStack entry
More logical than doing partly initialization at init_ss_array()

No functional change

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-19 03:52:21 +01:00
Joona Kiiski
66c5835080 Drop KILLER_MAX. Hardcode to 2 instead.
KILLER_MAX in search.h is quite pointless, because
we already hardcode this to 2 in MovePicker anyway.

By hard-coding this to 2 we can keep code simpler.

No functional change

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-19 03:51:25 +01:00
Joona Kiiski
a6d13428f6 Do not initialize ss->reduction to zero in the beginning of node
It must already be zero because zeroed in SearchStack initialization

No functional change

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-19 03:48:51 +01:00
Joona Kiiski
1322ab97c7 Do not reset ss->eval in the beginning of the node
This avoids problems with IID clearing ss->eval and
eval not being available when we return

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-19 03:43:58 +01:00
Marco Costalba
6e06db93fd Fix isolated and backward pawns scoring
It is more clear and also more correct because we
consider enemy pawns only in fornt of us and not just
on our file.

Very small functional change, almost not measurable, but
keep the patch for documenting purposes.

Spotted by Marek Kwiatkowski.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-17 17:32:54 +01:00
Marco Costalba
53bbcb78d5 Triviality in endgame.cpp
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-17 14:00:25 +01:00
Joona Kiiski
a6dcaa575f Update Makefile
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-16 12:04:02 +01:00
Joona Kiiski
05c5442633 Find balance between 1.7 and 1.8 reductions
Almost no change so commit because is a pruning
reduction patch.

After 1088 games at 1'+0 with QUAD
Mod vs Orig +178 =727 -183  (-2 ELO)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-15 20:53:16 +01:00
Marco Costalba
b6ab610e2f Remove redundant argument in think()
We don't need to pass side_to_move because we can get
it directly from the position object.

Note that in benchmark we always used to pass '0' and
it was a bug, but with no effect because was used only
in time[] and increment[], set always to 0 for both
colors.

Also additional small cleanup while there.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-15 17:14:30 +01:00
Marco Costalba
a98dee7835 Retire apply_scale_factor() and scale.h
Directly inline in the only occurence.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-15 17:05:23 +01:00
Marco Costalba
3e38e61565 Inline history and gain getters
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-15 16:55:35 +01:00
Marco Costalba
bc0c1c8d7b Retire value.cpp
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-15 12:16:36 +01:00
Marco Costalba
605b3aedd5 Retire LSN machinery
Now that we use cutechess-cli we can set the auto-resign
parameter that makes LSN less effective.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-14 17:29:36 +01:00
Marco Costalba
8547798345 Triviality in ucioption.cpp
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-14 17:29:34 +01:00
Marco Costalba
3703d12eb9 Add moves from failed high nodes in PV
Considering only VALUE_TYPE_EXACT nodes is too
restrictive and has a number of side-effects, most
notably the truncation of PV line after a fail high
at root.

Note that in this way we are no more guaranteed that
PV line is built up with PV nodes only, because
it could happen that a side search overwrites with a
cut-off move a PV node and this cut-off move ends up
in PV.

Change should be almost not measurable, perhaps with
ponder on we could have some beneficial effect.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-12 21:06:40 +01:00
Marco Costalba
a47a7dadeb Fix (zugzwang) verification to be shallower then null search
Currently starting from depth 12*OnePly on we have a verification
search deeper then the null search.

Note that, although reduction is R we start from one ply less then
null search, so actually we reach a depth that is OnePly shallower
then null search.

After 1130 games at 1'+0 on QUAD
Mod vs Orig +202 =756 -172  +9 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-12 21:03:30 +01:00
Joona Kiiski
00e86078a5 Remove TranspositionTable::overwrites variable
Doesn't provide useful information and
can cause slowdown with many Threads.

No functional change

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-11 22:25:02 +01:00
Marco Costalba
2adbb80b8b Space inflate bitbase.cpp
Also heavy cleanup while there.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-11 12:05:06 +01:00
Marco Costalba
ee8cdb1721 There is no need to clear TT at allocation time
Operator new() already returns a zeroed memory.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-11 09:42:04 +01:00
Marco Costalba
82bd61a8fa Revert previous patch
After the previous patch, it's impossible to build
anything else than x86 32-bit binary!

So revert.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-10 16:43:05 +01:00
Marco Costalba
87502c0fcb Makefile: default on gcc 32 bits when type 'make'
From Vratko Polak

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-10 12:16:43 +01:00
Marco Costalba
aa172032c4 Reword singular extension comments
Should be more stick to original definition (Hsu, Campbell)

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-06 17:56:04 +01:00
Joona Kiiski
8689ff7d03 Tweak Makefile a bit
To fix some build problems on debian's
automatic building system.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-06 06:24:58 +01:00
Marco Costalba
04e1ba8aa2 Move SplitPoint array under its thread
And cleanup / rename that part of code.

No functional change also with faked split.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-05 20:55:01 +01:00
Marco Costalba
2dfec0f614 Tweak non-captures scoring
Tested with Orig set at f5ef5632f so to evaluate
direct gain against 1.8

After 3239 games at 10"+0.1
Mod vs Orig +701 =1906 -632 +7 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-04 21:49:23 +01:00
Joona Kiiski
e0056c3851 Fix TT documentation
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-04 20:15:09 +01:00
Marco Costalba
a5c85d3cfc Reintroduce GCC/ICC rounding hack
Unfortunatly the source of this issue is not in the
different handling of log(0) illegal value.

No functional change on MSVC.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-03 19:05:04 +01:00
Joona Kiiski
d0fdc20231 Fix Makefile for HPUX
On hpux there is no prefetch.

Reported by Richard Lloyd

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-03 18:54:34 +01:00
Marco Costalba
1d4e7bbdf5 Fix DIVIDE BY ZERO exception in init_search()
It happens that when d == 0 we calculate:

log(double(0 * 0) / 2)

Unfortunately, log(0) is "illegal" and can generate either a
floating point exception or return a nonsense "huge" value
depending on the platform.

This fixs in the proper way the GCC/ICC rounding difference,
bug was from our side, not in the intel compiler.

Also fixed some few other warnings.

Bug spotted by Richard Lloyd.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-03 16:12:20 +01:00
Marco Costalba
3578207974 PSQT access functions can be static
Also renamed history access value in something more
in line with the meaning.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-03 05:49:13 +01:00
Marco Costalba
40ad5194aa Use only history to score non-captures
It seems there is absolutely no difference in using gains.

After 7025 games at 5"+0
Mod vs Orig +1903 =3236 -1886 (+1 ELO)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-03 05:36:53 +01:00
Marco Costalba
f5ef5632ff Restore development version
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-03 05:34:57 +01:00
Marco Costalba
21de03fad7 Revert "Another PSQT tuning round"
At longer TC of 1'+0" patch fails:
Orig - Mod: 841 - 819 (-6 elo!)

Just before the release ;-)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-02 06:55:03 +01:00
Marco Costalba
2d635f7b74 Stockfish 1.8
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-02 06:23:15 +01:00
Marco Costalba
b50dc1647f Mark CheckInfo c'tor as explicit
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-01 22:21:09 +01:00
Marco Costalba
971c591be7 Move singleEvasion assignment out of move's loop
We don't need to recheck after every move.

Spotted by Ralph Stoesser.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-07-01 22:18:53 +01:00
Joona Kiiski
b24a2dfc72 Another PSQT tuning round
This time with a new algorithm by Joona.

It works basically like this:

repeat
{
   1) pick 8000 random positions from qsearch
   2) "go depth 8" to get the true evaluation.
   3) "eval" to get the stand pat score
   4) Adjusting parameters one by one to minimize deltasum between
true evaluation and stand  pat scores.
}

* Good news: method seems to converge
* Bad news: Point where it converges is not optimum.

So it's more or less trial and error... sometimes works, sometimes
doesn't. It can give you the right direction, but if you let it run
too long, it fails. Far from scientific ;)

After 14800 games with 5s/game
Orig - Mod: 3318 - 3570 - 7626 (+6 elo)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-29 18:52:51 +01:00
Marco Costalba
4d170725ab Remove a redundant check in passed pawn eval
When first condition is met then second one is
always true.

Spotted by Ralph Stoesser.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-29 18:35:54 +01:00
Marco Costalba
aad8c82cf6 Code style triviality in san.cpp
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-29 18:33:43 +01:00
Marco Costalba
6c0a37bbf2 Rename TranspositionTable 'writes' in 'overwrites'
Better documents what that variable means.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-29 18:23:45 +01:00
Marco Costalba
5c3ebd1fbf Extract only exact scores to get the PV
This should allow to skip overwritten nodes because
only in PV we store in TT with VALUE_TYPE_EXACT flag.

Test result for the whole series is:

After 3627 games at 5"
Mod vs Orig +1037 =1605 -985 +5 ELO

After 1311 games at 1'+0"
Mod vs Orig +234 =850 -227 +2 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-29 18:23:28 +01:00
Marco Costalba
62c68c2d21 Retire update_pv() and sp_update_pv()
Expand inline instead.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-26 15:43:54 +01:00
Marco Costalba
adb43cc0cc Retire pv[] from SearchStack
Extract PV info from TT instead of using
a set of arrays. This is almost equivalent
except for cases when TT is full and the PV entry
is overwritten, but this is very rare.

(Almost) No functional change

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-26 15:13:39 +01:00
Marco Costalba
0a687b2cf0 Introduce bestMove to store PV move
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-26 14:42:44 +01:00
Marco Costalba
eb48c54687 Cleanup code that stores score in TT
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-26 11:01:43 +01:00
Joona Kiiski
3c3b129e7b Fix some wrong documentation
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-26 10:23:31 +01:00
Joona Kiiski
918533dc06 Remove unused constant
Fixes warning on ICC

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-26 10:22:26 +01:00
Marco Costalba
0ac44b40c9 Stockfish 1.8 beta 2
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-25 18:56:42 +01:00
Joona Kiiski
b839ea6c0c Hack to fix GCC/ICC rounding difference
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-25 18:54:33 +01:00
Marco Costalba
726df58131 Stockfish 1.8 beta 1
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-24 18:00:14 +01:00
Marco Costalba
d9a8dd0f7a Revert "Do IID also when we already have a ttMove"
Joona's testing reports very bad results at 5s, 30s and
even 1 minute TC, so revert.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-24 18:00:03 +01:00
Marco Costalba
6776f76d20 Call apply_weight() for both colors in one go
Due to rounding errors in apply_weight() where we divide
by 0x100 it is not possible to keep some functionality.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-24 17:53:01 +01:00
Marco Costalba
74db0f0f40 Tweak unstoppable pawns detection
A pawn is unstoppable also if enemy king can reach it
but path to queening is protected.

Original idea by Ralph Stoesser fixed by me.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-24 17:52:56 +01:00
Marco Costalba
a010d438a2 Merge branch 'master' of free2.projectlocker.com:sf 2010-06-21 20:50:20 +01:00
Tord Romstad
a4988fecee Moved a misplaced #endif in misc.cpp, which broke compilation in
Mac OS X.

No functional change.
2010-06-21 11:25:06 +02:00
Marco Costalba
dc5caff638 Test killer for legality earlier
Many killers moves, around 40%, are not legal, so
skip earlier in this case.

Some Movepicker c'tor cleanup while there.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-19 17:27:10 +01:00
Marco Costalba
4e7a898d7e Optimize for king moves in see_sign()
Because we only test legal moves, a king move
cannot have negative SEE.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-19 15:58:14 +01:00
Marco Costalba
47ee6d9fa4 Move prefetch() out of TT
This code is platform specific and has nothing to
do with TT class, so move to misc.cpp

This patch is a prerequisite to use extend prefetch use
also to other hash tables apart from Transposition Table.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-19 11:10:54 +01:00
Marco Costalba
221f41c2df Extend checks only if SEE is non-negative
Idea from Dr. Hyatt

After 10k games at 5"+0 on my QUAD
Mod vs Orig +2750 =4601 -2649 +4 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-15 07:02:09 +01:00
Marco Costalba
a8b9c11f56 Revert "Use ply counter in Position object"
Search ply and game ply are rwo different things !

Revert bogus commit.

No functional change on bench, but it changes in real games
when engine sends all the moves up to current one.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-13 02:38:16 +01:00
Marco Costalba
e9eea87341 Set LSNTime to 100 ms
This is a timeout compatible with very short TC of 5 sec/game.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-12 10:29:50 +01:00
Marco Costalba
a128faf0b0 Remove a wrong FIXME
If we are there it means we already had that info stored in TT,
so we don't need to overwrite with the same content !

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-06 00:17:33 +01:00
Marco Costalba
ed2754227a Avoid a double copy when saving a TTEntry
In statement:

*tte = TTEntry(posKey32, v, t, d, m, generation, statV, kingD);

We first create a TTEntry, then we copy the temporary entry to
its final destination in *tte then we discard the TTEntry.

Instead of this assign the fields directly to the destination TTEntry.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-05 12:35:44 +01:00
Marco Costalba
287b46aa63 Avoid calling evaluate() while razoring
Micro optimization that gives a 0.5% speed improvment

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-05 09:42:16 +02:00
Marco Costalba
a04dcce628 Offset pv[] always from 0
We don't need to offset from current ply.

Also rewritten a bit update_pv()

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-04 19:41:41 +01:00
Marco Costalba
452f0d1696 Big qsearch() cleanup
It is more clear and should be a bit faster too.

Reverted also previous optimization patch because
seems do not increase actual speed.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-03 19:15:44 +01:00
Marco Costalba
9337c6da46 Extend intermediate LMR to root search
Almost no change, but it is in sync with what we do in search
and in any case the ELO difference is very small (because the
events when the intermediate research triggers are very rare),
too small to be measured, we just verify we don't have any
unexpected regressions.

After 802 games at 1+0 full QUAD
Mod vs Orig +114 =581 -107 +3 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-03 12:17:05 +01:00
Marco Costalba
5f3c660d5d Shortcut futility pruning in qsearch
If we have pruned one capture due to its final value
we can prune also following ones because captures are
MVV ordered.

Also avoid a compare when not in PV because in that
case is always false.

No functional change.
2010-06-03 12:10:57 +01:00
Marco Costalba
ab127028ed Do not pass threadID as argument of search() and evaluate()
Get it from the position instead.

A good semplification of function calling and a speedup too.

No functional change also with faked split.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-02 20:48:40 +01:00
Marco Costalba
2f6927ac08 Save threadID info in Position
This is the best place because when we split we do a
copy of the position and also threadID, once set in a
given position, never changes anymore.

Forbid use of Position's default and copy c'tor to avoid
nasty bugs in case a position is created without explicitly
setting the threadID.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-02 20:19:43 +01:00
Marco Costalba
f148a8f6cc Don't initialize excludedMove and skipNullMove at each node
Do it once at the beginning becuase they are always reset
after use in the calling place where are set.

No functional change also with faked split.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-02 19:41:45 +01:00
Marco Costalba
c51e12200a Use SearchStack to pass allowNullmove
Also renamed allowNullmove in skipNullMove to reverse
the logic so that the field is initialized to 0 (false)
instead of 1 (true).

No functional change also with faked split.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-02 13:49:48 +01:00
Marco Costalba
5804bef824 Use SearchStack to pass excludedMove
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-02 13:22:48 +01:00
Marco Costalba
2572055c87 Fix white space breakage
No functional change with faked split.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-02 11:25:02 +01:00
Marco Costalba
c6ba14b7c9 Sync sp_search() with main search()
And fix qserahc() dispatch also there.

No functional change tested wit Faked Split.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-02 10:49:34 +01:00
Marco Costalba
5212995563 Retire bitScanReverse32()
Use log() instead because we are not in speed
critical paths.

Also a bit of renaming and code shuffle while there.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-01 21:58:54 +01:00
Marco Costalba
50e094ef8d Retire ok_to_do_nullmove()
Has been remained the same from ages also with the FIXME.

Retire for now and rearrange the conditions order for
maximum performance.

Also a small touch at null zugzwang verification.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-01 20:50:08 +01:00
Marco Costalba
7903495b0a Move invariant of singular ext. check out of loop
It is almost always false.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-01 15:47:28 +01:00
Marco Costalba
a3819188de Rename ok_to_prune() in connected_threat()
It is more up to the point. Also small speedup
due to checking for threat move before calling
the function. This saves more then 90% of function calls.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-01 15:12:31 +01:00
Marco Costalba
c0136fb728 Avoid double function dispatch
In 44% of cases we call search() just to call
qsearch() one moment later, avoid this double dispatch.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-01 14:47:55 +01:00
Marco Costalba
9b17083912 Retire init_node()
Also don't poll in qsearch()

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-01 12:34:49 +01:00
Marco Costalba
05c5f08372 Don't init SplitPointStack[i][j].parent
It is already set to zero because is allocated in
the global storage area.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-06-01 07:36:30 +01:00
Marco Costalba
6716337f40 Use ply counter in Position object
And avoid a redundant one passed as argument in
search calls.

Also renamed gamePly in ply to better clarify this
is used as search ply and is set to zero at the
beginning of the search.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-31 22:03:22 +01:00
Marco Costalba
ee8ccac622 Fix SearchStack and ply misalignment in RootMoveList
In RootMoveList c'tor we call qsearch() with
ply == 1 but SearchStack at 0.

We never noticed before because in qsearch we don't access
previous's ply SearchStack, otherwise we would have got
a nice crash ;-)

This bug is a fall down of previous patch.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-31 18:33:43 +01:00
Marco Costalba
e4e12ed595 Convert SearchStack ss[] to SearchStack*
Use a pointer to current SearchStack to avoid ss[ply]
address calculation.

Gives 1% speedup on Intel compiler

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-31 17:36:16 +01:00
Marco Costalba
d81def4fa9 Add function to get ply from position
It will be used by future patches.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-31 12:10:39 +01:00
Marco Costalba
9446dd6da3 Move gamePly among the StateInfo data
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-31 12:09:18 +01:00
Marco Costalba
b7bc0d4c57 Move promotion and ep under pawn handling
And remove from main do_move() flow. Just a small speedup
because we avoid two branches in the common case.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-31 12:08:34 +01:00
Marco Costalba
c35c18a705 Thread::splitPoint is a volatile pointer
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-31 06:16:50 +01:00
Marco Costalba
2ea323aec6 Do IID also when we already have a ttMove
In case tte->depth() is far lower the current depth
and we are in a PV node.

Almost 45% of researches give a different ttMove !

After 999 games at 1+0
Mod vs Orig +174 =694 -131 +15 ELO !!!!!!!

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-31 06:15:39 +01:00
Marco Costalba
ec0f0eba6b If LMR search fails high research at intemediate depth
Do not search immediately at full depth, but try a second
chance at lower depth. This is a feature that should scale
well because become important at high depths where we have
big reductions and also big savings in avoiding a costly
full depth search.

After 942 games at 1+0
Mod vs Orig +158 =645 -139  +7 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-29 23:35:12 +01:00
Marco Costalba
0719470e50 Fix IIDMargin description
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-29 11:19:53 +01:00
Marco Costalba
3ccdb57d6f Retire zobMaterial[]
Use zobrist[] array to compute material key.

Space save of 2KB in L1 cache.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-29 08:54:15 +01:00
Marco Costalba
03cfd94414 Change zobMaterial[] index 0 definition
The index at 0 was reserved for no-pieces
information. But we don't need that.

This is a prerequisite for next patch.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-29 08:49:16 +01:00
Marco Costalba
8c32878701 Use Key type instead of Bitboard
They are both 64 bits unsigned integer, but it
is correct to use the proper type.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-29 08:11:36 +01:00
Marco Costalba
0c5e89e3e1 Revert non-linear threats evaluation
After 999 games at 1+0
Mod vs Orig +148 =712 -139 +3 ELO

The added complexity doesn't seems to pay off and could
even scale worst with longer TC. So revert.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-23 14:53:04 +01:00
Marco Costalba
4a081280ed Remove an useless assert in evaluate_passed_pawns()
The tested square comes from a bitboard anded with
pos.pieces_of_color(Us), so assert is useless.

Another nitpick report by Marek Kwiatkowski  ;-)

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-22 19:14:19 +01:00
Marco Costalba
ee9e162dd5 Account for double pawn push in evaluate_unstoppable_pawns()
One of the most nitpicking patches I have ever seen.

Of course almost no functional change, but added just
becasue we are very pedantic ;-)

Spotted by Marek Kwiatkowski

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-22 18:42:00 +01:00
Marco Costalba
7e82f793b8 Fix StormOpenFileBonus[] bug
It was erroneusly reversed. Bug from Glaurung times.
Probably a full re-tuning is needed anyhow.

Spotted and fixed by Ralph Stoesser.

After 999 games almost no change, but modified anyway
for documentation reasons.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-22 18:35:00 +01:00
Marco Costalba
a7bfaede91 Fix a warning on array of size 0 under Windows
And better document new reality.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-22 12:45:05 +01:00
Joona Kiiski
1afbe1a1d7 Drop completely illogical ei.kingDanger == 0 requirement
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-22 12:37:19 +01:00
Joona Kiiski
226bd54064 Always save static value and kingDanger to TT
Around 5% speed-up

No functional change

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-22 12:37:11 +01:00
Joona Kiiski
de0c9e84ca Drop TTClusterSize from 5 to 4
Very small obvious functional change

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-22 12:37:02 +01:00
Marco Costalba
66b751713e Add non-linear threats evaluation
Increase threats score according to the number of
threats and to the side to move.

Constants have been balanced after ~34k iterations.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-22 12:01:51 +01:00
Marco Costalba
ecc100d1bb Revert "Simple implementation of strong YBWC"
It does not seem to increase anything even with a QUAD,
so revert.

After 1000 games with a QUAD
Mod - Orig: 500 - 497 (+1 elo)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-22 11:36:51 +01:00
Joona Kiiski
85559cc597 Add some automatic detection for Windows
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-21 23:09:53 +01:00
Joona Kiiski
187451294f Documentation fix
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-21 06:56:57 +01:00
Joona Kiiski
ac4c971e06 Correct 'prefetch' handling for Makefile
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-21 06:56:48 +01:00
Marco Costalba
cab8b78846 Let prefetch to be enabled by default on Windows
When compiling with MSVC we don't use the Makefile
so tweak a bit the Makefile to allow to let prefetch
in by default so that it works under Windows.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-20 21:37:37 +01:00
Joona Kiiski
efdd1e697a Small tweaks to install gcc-profile-clean targets
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-20 21:23:00 +01:00
Joona Kiiski
09884756d8 Modify source to follow new Makefile
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-20 21:22:51 +01:00
Joona Kiiski
32590884df Rewrite Makefile
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-20 21:22:42 +01:00
Marco Costalba
977cd9520a Simple implementation of strong YBWC
No gain in the worst case of 2 threads, but also no
loss and good potential for QUAD or OCTAL machines.

After 922 games at 1+0 with 2 threads

Mod vs Orig +143 =533 -143 +0 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-20 21:17:47 +01:00
Marco Costalba
471e745a91 Remove an assert in evaluate_passed_pawns()
We already tested few lines before with:

assert(pos.pawn_is_passed(Us, s));

Spotted by Marek Kwiatkowski.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-20 17:48:55 +01:00
Marco Costalba
8dc4396477 Indentation fix in middle-game evaluation
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-17 17:32:31 +01:00
Marco Costalba
6181e01c2a Introduce init_attack_tables() in evaluate()
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-17 06:45:59 +01:00
Marco Costalba
0d207ec2c6 Do not consider discovered checks in king safety
Does not help and it slows downs a bit because it
is not cheap to get the possible discovered checks
out of a position.

After 997 games at 1+0
Mod vs orig +153 =692 -152  +0 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-16 15:37:42 +01:00
Marco Costalba
93f64577c3 Fix RootMove::operator<() description
Reported by Melvin Sprague.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-16 08:56:58 +01:00
Marco Costalba
8b6bcd9731 Remove an useless Max() in passed pawns evaluation
There is no reason for that since tr cannot become negative.

Spotted by Ralph Stoesser.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-16 00:56:05 +01:00
Marco Costalba
6c0b2f5003 Threath tuning results
Final values for threath tuning (after ~30k iterations)

Verified to be equivalent with tuning branch.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-15 21:44:57 +01:00
Marco Costalba
52fd1a3d37 Add support for gcc-profile
It's now possible to build PGO builds with GCC

Patch from Oystein Johansen

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-15 07:51:46 +02:00
Marco Costalba
0c9c5032e8 Rename OutpostMask[] in AttackSpanMask[]
This is a more standard naming (see chessprogramming wiki)
and is more stick to what table is and not what is used for.

Code in pawns.cpp is a bit more readable now, at least for me ;-)

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-14 16:55:35 +01:00
Marco Costalba
9079bab84c Micro optimization in evaluate_pawns()
Avoid a double bitcount in test for candidate passed
pawn when we don't have any supporting pawn.

Also use outpost_mask() instead of build it up on
the fly.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-14 12:59:03 +01:00
Marco Costalba
ea5af9b8c0 Introduce evaluate_pawn_storm() to unify redundant code
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-14 12:08:48 +01:00
Marco Costalba
0b49ec9822 Code style tweaks to pawns.cpp
Also a small speedup.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-14 12:05:17 +01:00
Marco Costalba
6c27bf1880 Change color argument of square_is_weak()
Pass the color for which the square is to be
considered weak, not the opposite.

It is more natural and intuitive in this way.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-14 11:59:25 +01:00
Marco Costalba
da1165ae5d Space inflate marsenne
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-13 21:53:56 +01:00
Marco Costalba
6e5bb3279f Another split() tweak session
Function split() doesn't need to return a value, also
remove useless 'master' field.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-13 21:53:55 +01:00
Joona Kiiski
e63ab4bd03 Document old test result
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-12 17:33:56 +01:00
Joona Kiiski
d72e862a5b Remove one hack caused by misunderstanding
No functional change

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-12 17:33:42 +01:00
Marco Costalba
02fe05cd0d Fix a possible out of range access in previous patch
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-12 12:30:00 +01:00
Marco Costalba
16d6faf479 Retire splitPoint->cpus field
It is redundant with splitPoint->slaves[].

Also move slaves[MAX_THREADS] among the shared data in
SplitPoint definition as it should have been already.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-12 12:17:01 +01:00
Marco Costalba
2cec7347db Syncing sp_search() and search()
Small twekas to make the two searches as similar as
possible.

Also removed an useless setting of mateKiller in sp_search()

No functional change (tested with FakeSplit)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-12 07:01:50 +01:00
Marco Costalba
1288a5a10a Simplify init_safety()
In this for is also ready to be tuned....to be continued ;-)

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-11 12:03:32 +01:00
Marco Costalba
7f095b0a36 Greatly simplify weight_option()
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-11 11:59:50 +01:00
Marco Costalba
2aa455ce95 Small evaluate_passed_pawns() cleanup
Mainly renamed local variables with sensible names.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-11 07:06:48 +01:00
Marco Costalba
c053f0b838 Better integration of faked split
We don't need to comment/uncomment code, just
set FakeSplit bool to true to enable faked split.

Also reintroduced some asserts and cleaned up a bit.

Tested that with FakeSplit = true we have reproducible
finger printing even in SMP.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-11 07:05:31 +01:00
Joona Kiiski
7abe5f12ef Disable fake-mode
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-11 07:05:30 +01:00
Joona Kiiski
253428bb3f Unite sp_search() and sp_search_pv()
Also introduce a new rule:
In sp_search() always must hold: sp->alpha < sp->beta
Should fix some rear but very nasty races

To keep everything in sync, search() is also modified to
obey this rule. Because this affects only PV-nodes, should
have zero meaning to speed.

No functional change in fake mode

Regression test after 854 games
Mod vs Orig 433 - 421, no crashes.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-11 07:05:17 +01:00
Joona Kiiski
36f4fe52f0 Introduce fake-mode for split
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-09 23:06:13 +01:00
Marco Costalba
e4ad6a38ee Revert to old prefetch detection logic
It was broken on Windows 64bit with MSVC and possibly
on other platforms, so revert to old proven one.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-09 13:05:21 +01:00
Marco Costalba
6c6b6cd1a4 Fix an off-by-one bug in ThreatBonus[] table
We need a retuning anyhow.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-09 11:30:50 +02:00
Joona Kiiski
c20a41c9cf Templatize qsearch
No functional change and 2% speed-up on GCC.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-08 23:32:31 +01:00
Marco Costalba
e0e4bdc991 Retire mate threat detection from evaluation
Remove a lot of complex, obscure and useless code.

After 999 games at 1+0
Mod vs Orig +162 =673 -164 -1 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-08 23:09:40 +01:00
Marco Costalba
35e39a196d Add a comment and a FIXME
And fix indentation too.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-08 13:36:44 +01:00
Marco Costalba
276513c19f Lookup TT for eval also in PV nodes
We don't need to evaluate the position if it
is already cached in TT. We already do this
in non-PV case.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-08 13:12:46 +01:00
Marco Costalba
9643d7524e Fix an obsoleted descrption comment
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-08 13:06:55 +01:00
Marco Costalba
b763b40101 Unify Internal iterative deepening
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-08 13:00:07 +01:00
Marco Costalba
b4870595a5 Templetize extension() function
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-08 12:41:36 +01:00
Marco Costalba
f010685136 Templetize reduction() functions
No functional or speed change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-08 12:26:34 +01:00
Marco Costalba
91ce930b28 Use enum NodeType instead of opaque true/false
Increase readibility.

No functional and speed change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-08 11:49:55 +01:00
Joona Kiiski
b075d8ca53 Unite search_pv() and search()
A lot of redundant code removed: -182 lines of code

No functional and speed change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-08 11:48:45 +01:00
Marco Costalba
c0334c7bac Rename AttackWeight[] in KingAttackWeights[]
Also simplify a bit the code removing useless
named constants.

No functional change.
2010-05-07 12:04:23 +01:00
Marco Costalba
0f712ad4fd Array ThreatBonus[] is initialized at zero by compiler
We don't need to do the job.

No functional change.
2010-05-07 12:04:23 +01:00
Marco Costalba
7488d216fd Properly indent evaluate_king()
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-07 12:04:22 +01:00
Marco Costalba
b95b1a9705 Rename futilityMargin in kingDanger in EvalInfo
This is what actually is.

A standard naming convention suggests to name a variable
with someting resembling _what_ the variable is and not
_how_ the variable is used. This normally results
in easier to read code.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-07 12:04:22 +01:00
Marco Costalba
b14846b6d7 Simplify some obsolete code in king safety
Now that QueenCheckBonus and friends are always > 0
we can remove a bunch of useless 'if' statements.

No functional change.
2010-05-07 12:04:21 +01:00
Marco Costalba
921bd87280 Rename king "safety" to king "danger"
A bigger "safety" value is actually a bigger
threat for the king, so it is a bigger "danger"

With this renaming "Cowardice" and "Aggressiveness"
UCI parameters become easier to understand.

It is also easier to understand why the once "safety"
value (that is a "danger") is subtracted from evaluation
instead of being added.

No functional change.
2010-05-07 12:04:21 +01:00
Marco Costalba
569bc75eb8 Evaluation weights cleanup
Use a Weights[] array instead of named variables to
store evaluation weights.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-07 12:04:20 +01:00
Marco Costalba
0544d6c8f7 Set Mate Threat Extension to OnePly
For both PV and non-PV nodes.

After 981 games at 1+0
Mod vs Orig +153 =686 -142 +4 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-07 12:04:08 +01:00
Marco Costalba
fe76787a77 Avoid a call to apply_weight() in evaluate_king()
Precompute scores in SafetyTable[] instead of calculate
them on the fly.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-05 13:56:54 +02:00
Joona Kiiski
8e269d781a Further push the LMR pedal
More aggressive LMR reductions.

Tested at different time controls:

- Tested with 1CPU 1+0, after 3000 games, result was +12 ELO

- Tested this with 4CPU 1+0 and got sth around 5-10 ELO increase

- Last one at long time control,after ~1000 games with 10+0 result is:

Orig - Mod: 491 - 520 (+10 elo)

A testing marathon by Joona for this important change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-05 12:20:39 +01:00
Marco Costalba
df7cd94aee A promotion piece cannot be a king or a pawn
Or any other garbage value bigger then QUEEN.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-05 12:16:16 +01:00
Marco Costalba
f16c231bc9 Do not return from idle_loop() with lock held
Master thread returns from idle_loop() when sp->cpus == 0,
but cpus is decremented by slave threads under sp->lock,
so it could happen that we return in split(), where we release
the split point, with sp->lock still held.

This patch guarantees that sp->lock is released when returning
to split().

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-05 12:16:12 +01:00
Marco Costalba
b89733b46c Reverse the logic used to detect prefetch
Explicitly search for x86 architecture instead of
excluding the others.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-05 12:16:10 +01:00
Marco Costalba
67f611f3eb Allow a static evaluation to overwrite an exsisting entry
The idea here is that if we cut-off after a stand pat the
already exsisting TT entry was not usable with current
beta, so overwrite anyway.

After 999 games at 1+0
Mod vs Orig +173 =665 -161  + 4 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-05 12:15:40 +01:00
Marco Costalba
80f5ca88f6 Do not refresh TT in qsearch
Almost no change and simplifies a bit the code.

After 961 games at 1+0
Mod vs Orig +156 =650 -146  +4 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-02 07:50:19 +01:00
Marco Costalba
8425b2b499 Refresh TT entry after a cut-off to avoid aging
Re-save the same TT entry if value is usable and allow
us to cut-off, it means that entry is valuable and
we want to keep it fresh updating the 'generation'
parameter up to the current value.

Patch suggested by J. Wesley Cleveland and better
clarified by Miguel A. Ballicora.

After 999 games at 1+0 64MB hash size
Mod vs Orig +167 =677 -155 +4 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-05-01 05:09:55 +01:00
Joona Kiiski
a086f34f36 Fix compile error on GCC
Add missing prototype.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-04-28 12:01:00 +02:00
Marco Costalba
83631c89ce Endgame's apply() method can be 'const'
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-04-27 06:17:32 +01:00
Marco Costalba
bedf80a4c0 Remove an obsolete comment
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-04-27 06:09:04 +01:00
Marco Costalba
cb9399445f Another small material tweak
In this case we avoid to name the 'black' version of the
endgame function but use a vector indexed by color instead.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-04-26 18:45:28 +01:00
Marco Costalba
fe7e0a425e Cleanup material distribution detectors
No functional change (verified each function)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-04-26 12:21:22 +01:00
Marco Costalba
fb0e19dc8b Do not call exit_threads() in Application d'tor
Because exit_threads() references the global object TM, we
need to call the function when still inside main(), otherwise,
due to undefined global object initialization and destruction
we could end up with referencing an already destroyed object.

Actually this should not happen because Application singleton
is initialized _only_ after all the other globals due to how
Application::initialize() is defined, but this is very tricky
C++ and not easy to follow, even for me ;-)

Also rearranged a bit main() code flow.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-04-25 10:35:55 +01:00
Marco Costalba
e6b5d03cc4 Small passed pawns evaluation cleanup
Moved evaluation of unstoppable pawns out of
evauation of passed pawns because event frequency is
much lower. Added evaluate_unstoppable_pawns() that
is called very seldom and contains all the unstoppable
pawn logic.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-04-25 09:50:27 +01:00
Marco Costalba
b2c1e15698 Simplify a bit futility marging formula
Should be a very minor change, but there is a small
functional change because futility_margin() is used in more
places then in the pruning formula.

After 999 games at 1+0
Mod vs Orig +167 =678 -154  +5 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-04-23 18:52:22 +01:00
Marco Costalba
11207f7c1f Revert scale factor in pawn evaluation
It simply doesn't seems to work both in direct matches
and in balance tuning.

So revert the idea.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-04-21 20:35:47 +01:00
Marco Costalba
97f5d19bdc Introduce PawnsQtyTable[] to refine pawn's drawish calculation
Also fix dimension of UnpairedPawnsTable[] to accomodate the
case in which we have 8 unpaired pawns, i.e. only one side has
pawns, the other side has no pawns.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-04-19 12:24:26 +01:00
Marco Costalba
fc89dbcab2 First attempt at tweaking UnpairedPawnsTable[] values
Values by Joona.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-04-19 06:37:07 +01:00
Marco Costalba
6b7efa0cd1 Introduce scale factor in pawn evaluation
The idea is to reduce the score if we have many
pawns opposing an enemy pawn so that the draw
possibility increases.

Just introduced the logic, but no functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-04-19 06:21:13 +01:00
Marco Costalba
c23cd4d90a Fix candidate passed pawn definition
A pawn is candidate to be passed if doesn't have enemy pawns
in just front of him, not also behind !

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-04-18 10:09:12 +01:00
Marco Costalba
a9fa1fc7f7 Retire Position::pawn_is_passed() and friends
Absolutely no useful at all, just code obfuscation so
use real definition instead.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-04-18 09:58:57 +01:00
Marco Costalba
1f1ef0897c Introduce table SquaresInFrontMask[2][64]
It will be used to lookup squares in front of
a given square. Same concept of PassedPawnMask[]
and OutpostMask[].

Also small tweaks in bitboard.h

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-04-18 09:47:31 +01:00
Marco Costalba
a49e4fac98 Better perft integration in benchmark
Now with:

   stockfish bench 128 1 5 default perft

it is possible to get perft 5 results of each position and
the first 3 positions correspond to the well known test
position in:

http://chessprogramming.wikispaces.com/Perft+Results

This allow to quickly check for perft consistency running
the 'bench' command.

No functional change but signature has changed because
bench default positions 2 and 3 have changed.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-04-18 09:18:49 +01:00
Marco Costalba
87379c2929 Space inflate bitboard.cpp
This file, somehow, avoided the "space inflate" treatment...until now ;-)

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-04-18 08:58:26 +01:00
Marco Costalba
53b522d95d Convert polyglot.ini to use Linux line ending
Instead of Windows cr/lf

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-04-17 11:24:25 +01:00
Marco Costalba
ef0bbe6e18 Teach polyglot the new "Best Book Move" UCI option
Also turn off log by default as is in UCI case.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-04-17 11:22:40 +01:00
Marco Costalba
65c2715d9a Revert saving of null search value in TT
Revert all the patches that introduced the change and
more or less fixed the zugzwang issue.

There is a gain against last current version and we
can remove a lot of code.

After 979 games at 1+0 on my QUAD
Mod vs Orig +152 =688 -139 +5 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-04-17 10:57:37 +01:00
Marco Costalba
ec0a650dff Don't overwrite exsisting TT with null search value
Real search is considered of higher quality then null
search one.

This allows to fix the zugzwang issue with a minimal
impact on ELO.

Zugzwang verified on position:

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

After 999 games at 1+0 on my QUAD
Mod vs Orig(94bb196) +168 =657 -174  -2 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-04-16 05:52:18 +01:00
Joona Kiiski
abae3c5678 Prevent the use of nullmove TT value only at verification search
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-04-16 05:47:31 +01:00
Joona Kiiski
f3809f2a18 Introduce NullStatus enum
No functional change

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-04-16 05:47:29 +01:00
Joona Kiiski
81ae7cad2d Revert "Introduce "Zugzwang detection" temporary hack for 1.7.1"
This reverts commit f9d3b48ad0.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-04-16 05:47:28 +01:00
Marco Costalba
94bb1964f6 Add "Best Book Move" UCI option
Is a boolean option that when set allows Stockfish
to select the best book move across the possible ones.

Feature requested by Salvo Spitaleri.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-04-16 05:45:30 +01:00
Joona Kiiski
13431922a3 Fix overflow in init_safety
Also write the code in more clean way

No functional change

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-04-14 19:19:11 +01:00
Joona Kiiski
9a3fc4d3fb Fix evasion pruning condition
Avoid incorrect mate scores in positions like

BK5/1R4b1/2k1Np2/3p3b/2p3pq/p1rB4/n2n1p2/8 w - -

Thanks for Jouni Uski for reporting the problem

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-04-13 20:28:49 +01:00
Marco Costalba
a4a0ffce71 Fix some warnings under +w1 HP-UX compile
This is the world's fussiest compiler with +w1

Warnings reported by Richard Lloyd.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-04-11 17:03:03 +01:00
Marco Costalba
e81108a855 Restore development version
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-04-10 20:42:31 +01:00
Marco Costalba
f967f1a25e Update polyglot.ini
Remove obsolete options and add a few ones.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-04-10 20:41:10 +01:00
55 changed files with 3884 additions and 4619 deletions

View File

@@ -3,7 +3,7 @@
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<EFBFBD>, Arena, Sigma Chess, Shredder,
(like XBoard with PolyGlot, eboard, Josè, 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.
@@ -83,8 +83,3 @@ 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

@@ -1,63 +1,48 @@
[PolyGlot]
EngineDir = .
EngineCommand = ./stockfish
Book = false
BookFile = book.bin
Log = true
LogFile = stockfish.log
Resign = true
ResignScore = 600
[Engine]
Hash = 128
Threads = 1
OwnBook = false
Book File = book.bin
Use Search Log = false
Mobility (Middle Game) = 100
Mobility (Endgame) = 100
Pawn Structure (Middle Game) = 100
Pawn Structure (Endgame) = 100
Passed Pawns (Middle Game) = 100
Passed Pawns (Endgame) = 100
Aggressiveness = 100
Cowardice = 100
King Safety Curve = Quadratic
Quadratic = Linear
King Safety Coefficient = 40
King Safety X Intercept = 0
King Safety Max Slope = 30
King Safety Max Value = 500
Queen Contact Check Bonus = 3
Queen Check Bonus = 2
Rook Check Bonus = 1
Bishop Check Bonus = 1
Knight Check Bonus = 1
Discovered Check Bonus = 3
Mate Threat Bonus = 3
Check Extension (PV nodes) = 2
Check Extension (non-PV nodes) = 1
Single Reply Extension (PV nodes) = 2
Single Reply Extension (non-PV nodes) = 2
Mate Threat Extension (PV nodes) = 0
Mate Threat Extension (non-PV nodes) = 0
Pawn Push to 7th Extension (PV nodes) = 1
Pawn Push to 7th Extension (non-PV nodes) = 1
Passed Pawn Extension (PV nodes) = 1
Passed Pawn Extension (non-PV nodes) = 0
Pawn Endgame Extension (PV nodes) = 2
Pawn Endgame Extension (non-PV nodes) = 2
Full Depth Moves (PV nodes) = 14
Full Depth Moves (non-PV nodes) = 3
Threat Depth = 5
Futility Pruning (Main Search) = true
Futility Pruning (Quiescence Search) = true
Randomness = 0
Minimum Split Depth = 4
Maximum Number of Threads per Split Point = 5
[PolyGlot]
EngineDir = .
EngineCommand = ./stockfish
Book = false
BookFile = book.bin
Log = false
LogFile = stockfish.log
Resign = true
ResignScore = 600
[Engine]
Hash = 128
Threads = 1
OwnBook = false
Book File = book.bin
Best Book Move = false
Use Search Log = false
Search Log Filename = SearchLog.txt
Mobility (Middle Game) = 100
Mobility (Endgame) = 100
Pawn Structure (Middle Game) = 100
Pawn Structure (Endgame) = 100
Passed Pawns (Middle Game) = 100
Passed Pawns (Endgame) = 100
Space = 100
Aggressiveness = 100
Cowardice = 100
Check Extension (PV nodes) = 2
Check Extension (non-PV nodes) = 1
Single Reply Extension (PV nodes) = 2
Single Reply Extension (non-PV nodes) = 2
Mate Threat Extension (PV nodes) = 0
Mate Threat Extension (non-PV nodes) = 0
Pawn Push to 7th Extension (PV nodes) = 1
Pawn Push to 7th Extension (non-PV nodes) = 1
Passed Pawn Extension (PV nodes) = 1
Passed Pawn Extension (non-PV nodes) = 0
Pawn Endgame Extension (PV nodes) = 2
Pawn Endgame Extension (non-PV nodes) = 2
Randomness = 0
Minimum Split Depth = 4
Maximum Number of Threads per Split Point = 5

View File

@@ -1,7 +1,7 @@
# Stockfish, a UCI chess playing engine derived from Glaurung 2.1
# Copyright (C) 2004-2007 Tord Romstad
# Copyright (C) 2008 Marco Costalba
# Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
# Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
#
# This file is part of Stockfish.
#
# Stockfish is free software: you can redistribute it and/or modify
@@ -18,318 +18,494 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
### Executable name. Do not change
### ==========================================================================
### Section 1. General Configuration
### ==========================================================================
### Executable name
EXE = stockfish
### 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
### ==========================================================================
### Built-in benchmark for pgo-builds
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
### Object files
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
position.o direction.o tt.o uci.o ucioption.o \
mersenne.o book.o bitbase.o san.o benchmark.o timeman.o
### General rules. Do not change
### ==========================================================================
### Section 2. High-level Configuration
### ==========================================================================
#
# flag --- Comp switch --- Description
# ----------------------------------------------------------------------------
#
# debug = no/yes --- -DNDEBUG --- Enable/Disable debug mode
# optimize = yes/no --- (-O3/-fast etc.) --- Enable/Disable optimizations
# arch = (name) --- (-arch) --- Target architecture
# os = (name) --- --- Target operating system
# bits = 64/32 --- -DIS_64BIT --- 64-/32-bit operating system
# bigendian = no/yes --- -DBIGENDIAN --- big/little-endian byte order
# prefetch = no/yes --- -DUSE_PREFETCH --- Use prefetch x86 asm-instruction
# bsfq = no/yes --- -DUSE_BSFQ --- Use bsfq x86_64 asm-instruction
# --- (Works only with GCC and ICC 64-bit)
# popcnt = no/yes --- -DUSE_POPCNT --- Use popcnt x86_64 asm-instruction
#
# Note that Makefile is space sensitive, so when adding new architectures
# or modifying existing flags, you have to make sure there are no extra spaces
# at the end of the line for flag values.
### 2.1. General
debug = no
optimize = yes
### 2.2 Architecture specific
# General-section
ifeq ($(ARCH),general-64)
arch = any
os = any
bits = 64
bigendian = no
prefetch = no
bsfq = no
popcnt = no
endif
ifeq ($(ARCH),general-32)
arch = any
os = any
bits = 32
bigendian = no
prefetch = no
bsfq = no
popcnt = no
endif
ifeq ($(ARCH),bigendian-64)
arch = any
os = any
bits = 64
bigendian = yes
prefetch = no
bsfq = no
popcnt = no
endif
ifeq ($(ARCH),bigendian-32)
arch = any
os = any
bits = 32
bigendian = yes
prefetch = no
bsfq = no
popcnt = no
endif
# x86-section
ifeq ($(ARCH),x86-64)
arch = x86_64
os = any
bits = 64
bigendian = no
prefetch = yes
bsfq = yes
popcnt = no
endif
ifeq ($(ARCH),x86-64-modern)
arch = x86_64
os = any
bits = 64
bigendian = no
prefetch = yes
bsfq = yes
popcnt = yes
endif
ifeq ($(ARCH),x86-32)
arch = i386
os = any
bits = 32
bigendian = no
prefetch = yes
bsfq = no
popcnt = no
endif
ifeq ($(ARCH),x86-32-old)
arch = i386
os = any
bits = 32
bigendian = no
prefetch = no
bsfq = no
popcnt = no
endif
# osx-section
ifeq ($(ARCH),osx-ppc-64)
arch = ppc64
os = osx
bits = 64
bigendian = yes
prefetch = no
bsfq = no
popcnt = no
endif
ifeq ($(ARCH),osx-ppc-32)
arch = ppc
os = osx
bits = 32
bigendian = yes
prefetch = no
bsfq = no
popcnt = no
endif
ifeq ($(ARCH),osx-x86-64)
arch = x86_64
os = osx
bits = 64
bigendian = no
prefetch = yes
bsfq = yes
popcnt = no
endif
ifeq ($(ARCH),osx-x86-32)
arch = i386
os = osx
bits = 32
bigendian = no
prefetch = yes
bsfq = no
popcnt = no
endif
### ==========================================================================
### Section 3. Low-level configuration
### ==========================================================================
### 3.1 Selecting compiler (default = gcc)
ifeq ($(COMP),)
COMP=gcc
endif
ifeq ($(COMP),gcc)
comp=gcc
CXX=g++
profile_prepare = gcc-profile-prepare
profile_make = gcc-profile-make
profile_use = gcc-profile-use
profile_clean = gcc-profile-clean
endif
ifeq ($(COMP),icc)
comp=icc
CXX=icpc
profile_prepare = icc-profile-prepare
profile_make = icc-profile-make
profile_use = icc-profile-use
profile_clean = icc-profile-clean
endif
### 3.2 General compiler settings
CXXFLAGS = -g -Wall -Wcast-qual -ansi -fno-exceptions -fno-rtti $(EXTRACXXFLAGS)
ifeq ($(comp),gcc)
CXXFLAGS += -pedantic -Wno-long-long -Wextra
endif
ifeq ($(comp),icc)
CXXFLAGS += -wd383,869,981,10187,10188,11505,11503
endif
ifeq ($(os),osx)
CXXFLAGS += -arch $(arch)
endif
### 3.3 General linker settings
LDFLAGS = -lpthread $(EXTRALDFLAGS)
ifeq ($(os),osx)
LDFLAGS += -arch $(arch)
endif
### 3.4 Debugging
ifeq ($(debug),no)
CXXFLAGS += -DNDEBUG
endif
### 3.5 Optimization
ifeq ($(optimize),yes)
ifeq ($(comp),gcc)
CXXFLAGS += -O3
ifeq ($(os),osx)
ifeq ($(arch),i386)
CXXFLAGS += -mdynamic-no-pic
endif
ifeq ($(arch),x86_64)
CXXFLAGS += -mdynamic-no-pic
endif
endif
endif
ifeq ($(comp),icc)
CXXFLAGS += -fast
ifeq ($(os),osx)
CXXFLAGS += -mdynamic-no-pic
endif
endif
endif
### 3.6. Bits
ifeq ($(bits),64)
CXXFLAGS += -DIS_64BIT
endif
### 3.7 Endianess
ifeq ($(bigendian),yes)
CXXFLAGS += -DBIGENDIAN
endif
### 3.8 prefetch
ifeq ($(prefetch),yes)
CXXFLAGS += -msse
DEPENDFLAGS += -msse
else
CXXFLAGS += -DNO_PREFETCH
endif
### 3.9 bsfq
ifeq ($(bsfq),yes)
CXXFLAGS += -DUSE_BSFQ
endif
### 3.10 popcnt
ifeq ($(popcnt),yes)
CXXFLAGS += -DUSE_POPCNT
endif
### ==========================================================================
### Section 4. Public targets
### ==========================================================================
default:
$(MAKE) gcc
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) build
help:
@echo ""
@echo "Makefile options:"
@echo "To compile stockfish, type: "
@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 "make target ARCH=arch [COMP=comp]"
@echo ""
@echo "Supported targets:"
@echo ""
@echo "build > Build unoptimized version"
@echo "profile-build > Build PGO-optimized version"
@echo "popcnt-profile-build > Build PGO-optimized version with optional popcnt-support"
@echo "strip > Strip executable"
@echo "install > Install executable"
@echo "clean > Clean up"
@echo "testrun > Make sample run"
@echo ""
@echo "Supported archs:"
@echo ""
@echo "x86-64 > x86 64-bit"
@echo "x86-64-modern > x86 64-bit with runtime support for popcnt-instruction"
@echo "x86-32 > x86 32-bit excluding very old hardware without SSE-support"
@echo "x86-32-old > x86 32-bit including also very old hardware"
@echo "osx-ppc-64 > PPC-Mac OS X 64 bit"
@echo "osx-ppc-32 > PPC-Mac OS X 32 bit"
@echo "osx-x86-64 > x86-Mac OS X 64 bit"
@echo "osx-x86-32 > x86-Mac OS X 32 bit"
@echo "general-64 > unspecified 64-bit"
@echo "general-32 > unspecified 32-bit"
@echo "bigendian-64 > unspecified 64-bit with bigendian byte order"
@echo "bigendian-32 > unspecified 32-bit with bigendian byte order"
@echo ""
@echo "Supported comps:"
@echo ""
@echo "gcc > Gnu compiler (default)"
@echo "icc > Intel compiler"
@echo ""
@echo "Non-standard targets:"
@echo ""
@echo "make hpux > Compile for HP-UX. Compiler = aCC"
@echo ""
@echo "Examples. If you don't know what to do, you likely want to run: "
@echo ""
@echo "make profile-build ARCH=x86-64 (This is for 64-bit systems)"
@echo "make profile-build ARCH=x86-32 (This is for 32-bit systems)"
@echo ""
all: $(EXE) .depend
build:
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) config-sanity
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) all
test check: default
@$(PGOBENCH)
clean:
$(RM) *.o .depend *~ $(EXE) core bench.txt
### Possible targets. You may add your own ones here
gcc:
$(MAKE) \
CXX='g++' \
CXXFLAGS="$(GCCFLAGS)" \
all
gcc-popcnt:
$(MAKE) \
CXX='g++' \
CXXFLAGS="$(GCCFLAGS) -DUSE_POPCNT" \
all
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
profile-build:
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) config-sanity
@echo ""
@echo "Step 0/4. Preparing for profile build."
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_prepare)
@echo ""
@echo "Step 1/4. Building executable for benchmark ..."
@touch *.cpp *.h
$(MAKE) icc-profile-make
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_make)
@echo ""
@echo "Running benchmark for pgo-build ..."
@echo "Step 2/4. 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 "Step 3/4. Building final executable ..."
@touch *.cpp
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_use)
@echo ""
@echo "Running benchmark for pgo-build (popcnt disabled)..."
@echo "Step 4/4. Deleting profile data ..."
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_clean)
popcnt-profile-build:
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) config-sanity
@echo ""
@echo "Step 0/6. Preparing for profile build."
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_prepare)
@echo ""
@echo "Step 1/6. Building executable for benchmark (popcnt disabled)..."
@touch *.cpp *.h
$(MAKE) ARCH=x86-64 COMP=$(COMP) $(profile_make)
@echo ""
@echo "Step 2/6. 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)..."
@echo "Step 3/6. Building executable for benchmark (popcnt enabled)..."
@touch *.cpp *.h
$(MAKE) ARCH=x86-64-modern COMP=$(COMP) $(profile_make)
@echo ""
@echo "Step 4/6. Running benchmark for pgo-build (popcnt enabled)..."
@$(PGOBENCH) > /dev/null
@echo "Benchmarks finished. Build final executable now ..."
@echo ""
@echo "Step 5/6. Building final executable ..."
@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
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_use)
@echo ""
@echo "Running benchmark for pgo-build ..."
@$(PGOBENCH) > /dev/null
@echo "Benchmark finished. Build final executable now ..."
@echo "Step 6/6. Deleting profile data ..."
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_clean)
@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
install:
-mkdir -p -m 755 $(BINDIR)
-cp $(EXE) $(BINDIR)
-strip $(BINDIR)/$(EXE)
### Dependencies. Do not change
clean:
$(RM) $(EXE) *.o .depend *~ core bench.txt *.gcda
testrun:
@$(PGOBENCH)
### ==========================================================================
### Section 5. Private targets
### ==========================================================================
all: $(EXE) .depend
config-sanity:
@echo ""
@echo "Config:"
@echo "debug: '$(debug)'"
@echo "optimize: '$(optimize)'"
@echo "arch: '$(arch)'"
@echo "os: '$(os)'"
@echo "bits: '$(bits)'"
@echo "bigendian: '$(bigendian)'"
@echo "prefetch: '$(prefetch)'"
@echo "bsfq: '$(bsfq)'"
@echo "popcnt: '$(popcnt)'"
@echo ""
@echo "Flags:"
@echo "CXX: $(CXX)"
@echo "CXXFLAGS: $(CXXFLAGS)"
@echo "LDFLAGS: $(LDFLAGS)"
@echo ""
@echo "Testing config sanity. If this fails, try 'make help' ..."
@echo ""
@test "$(debug)" = "yes" || test "$(debug)" = "no"
@test "$(optimize)" = "yes" || test "$(optimize)" = "no"
@test "$(arch)" = "any" || test "$(arch)" = "x86_64" || test "$(arch)" = "i386" || \
test "$(arch)" = "ppc64" || test "$(arch)" = "ppc"
@test "$(os)" = "any" || test "$(os)" = "osx"
@test "$(bits)" = "32" || test "$(bits)" = "64"
@test "$(bigendian)" = "yes" || test "$(bigendian)" = "no"
@test "$(prefetch)" = "yes" || test "$(prefetch)" = "no"
@test "$(bsfq)" = "yes" || test "$(bsfq)" = "no"
@test "$(popcnt)" = "yes" || test "$(popcnt)" = "no"
@test "$(comp)" = "gcc" || test "$(comp)" = "icc"
$(EXE): $(OBJS)
$(CXX) -o $@ $(OBJS) $(LDFLAGS)
gcc-profile-prepare:
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) gcc-profile-clean
gcc-profile-make:
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
EXTRACXXFLAGS='-fprofile-generate' \
EXTRALDFLAGS='-lgcov' \
all
gcc-profile-use:
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
EXTRACXXFLAGS='-fprofile-use' \
all
gcc-profile-clean:
@rm -rf *.gcda *.gcno bench.txt
icc-profile-prepare:
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) icc-profile-clean
@mkdir profdir
icc-profile-make:
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
EXTRACXXFLAGS='-prof-gen=srcpos -prof_dir ./profdir' \
all
icc-profile-use:
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
EXTRACXXFLAGS='-prof_use -prof_dir ./profdir' \
all
icc-profile-clean:
@rm -rf profdir bench.txt
.depend:
-@$(CXX) -msse -MM $(OBJS:.o=.cpp) > $@ 2> /dev/null
-@$(CXX) $(DEPENDFLAGS) -MM $(OBJS:.o=.cpp) > $@ 2> /dev/null
-include .depend
### ==========================================================================
### Section 6. Non-standard targets
### ==========================================================================
hpux:
$(MAKE) \
CXX='/opt/aCC/bin/aCC -AA +hpxstd98 -DBIGENDIAN -mt +O3 -DNDEBUG -DNO_PREFETCH' \
CXXFLAGS="" \
LDFLAGS="" \
all

View File

@@ -57,12 +57,6 @@ Application::Application() {
genrand_int32();
}
Application::~Application() {
exit_threads();
quit_eval();
}
void Application::initialize() {
// A static Application object is allocated
@@ -70,7 +64,15 @@ void Application::initialize() {
static Application singleton;
}
void Application::free_resources() {
// Warning, following functions reference global objects that
// must be still alive when free_resources() is called.
exit_threads();
quit_eval();
}
void Application::exit_with_failure() {
exit(EXIT_FAILURE); // d'tor will be called automatically
exit(EXIT_FAILURE);
}

View File

@@ -29,10 +29,10 @@ class Application {
Application();
Application(const Application&);
~Application();
public:
static void initialize();
static void free_resources();
static void exit_with_failure();
};

View File

@@ -38,8 +38,8 @@ using namespace std;
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",
"r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq -",
"8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - -",
"4rrk1/pp1n3p/3q2pQ/2p1pb2/2PP4/2P3N1/P2B2PP/4RRK1 b - - 7 19",
"rq3rk1/ppp2ppp/1bnpb3/3N2B1/3NP3/7P/PPPQ1PP1/2KR3R w - - 7 14",
"r1bq1r1k/1pp1n1pp/1p1p4/4p2Q/4Pp2/1BNP4/PPP2PPP/3R1RK1 w - - 2 14",
@@ -51,7 +51,7 @@ const string BenchmarkPositions[] = {
"r1bq1r1k/b1p1npp1/p2p3p/1p6/3PP3/1B2NN2/PP3PPP/R2Q1RK1 w - - 1 16",
"3r1rk1/p5pp/bpp1pp2/8/q1PP1P2/b3P3/P2NQRPP/1R2B1K1 b - - 6 22",
"r1q2rk1/2p1bppp/2Pp4/p6b/Q1PNp3/4B3/PP1R1PPP/2K4R w - - 2 18",
"4k2r/1pb2ppp/1p2p3/1R1p4/3P4/2r1PN2/P4PPP/1R4K1 b - 3 22",
"4k2r/1pb2ppp/1p2p3/1R1p4/3P4/2r1PN2/P4PPP/1R4K1 b - - 3 22",
"3q2k1/pb3p1p/4pbp1/2r5/PpN2N2/1P2P2P/5PP1/Q2R2K1 b - - 4 26"
};
@@ -151,13 +151,18 @@ void benchmark(const string& commandLine) {
{
Move moves[1] = {MOVE_NONE};
int dummy[2] = {0, 0};
Position pos(*it);
Position pos(*it, 0);
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();
{
int64_t perftCnt = perft(pos, maxDepth * ONE_PLY);
cerr << "\nPerft " << maxDepth << " result (nodes searched): " << perftCnt << endl << endl;
totalNodes += perftCnt;
} else {
if (!think(pos, false, false, dummy, dummy, 0, maxDepth, maxNodes, secsPerPos, moves))
break;
totalNodes += nodes_searched();
}
}
cnt = get_system_time() - startTime;

View File

@@ -26,7 +26,6 @@
#include "bitbase.h"
#include "bitboard.h"
#include "move.h"
#include "square.h"
@@ -46,30 +45,22 @@ namespace {
struct KPKPosition {
void from_index(int index);
int to_index() const;
bool is_legal() const;
bool is_immediate_draw() const;
bool is_immediate_win() const;
Bitboard wk_attacks() const;
Bitboard bk_attacks() const;
Bitboard pawn_attacks() const;
Bitboard wk_attacks() const { return StepAttackBB[WK][whiteKingSquare]; }
Bitboard bk_attacks() const { return StepAttackBB[BK][blackKingSquare]; }
Bitboard pawn_attacks() const { return StepAttackBB[WP][pawnSquare]; }
Square whiteKingSquare, blackKingSquare, pawnSquare;
Color sideToMove;
};
const int IndexMax = 2 * 24 * 64 * 64;
Result *Bitbase;
const int IndexMax = 2*24*64*64;
int UnknownCount = 0;
void initialize();
bool next_iteration();
Result classify_wtm(const KPKPosition &p);
Result classify_btm(const KPKPosition &p);
Result classify_wtm(const KPKPosition& pos, const Result bb[]);
Result classify_btm(const KPKPosition& pos, const Result bb[]);
int compute_index(Square wksq, Square bksq, Square psq, Color stm);
int compress_result(Result r);
}
@@ -78,273 +69,252 @@ namespace {
////
void generate_kpk_bitbase(uint8_t bitbase[]) {
// Allocate array and initialize:
Bitbase = new Result[IndexMax];
initialize();
// Iterate until all positions are classified:
while(next_iteration());
// Compress bitbase into the supplied parameter:
bool repeat;
int i, j, b;
for(i = 0; i < 24576; i++) {
for(b = 0, j = 0; j < 8; b |= (compress_result(Bitbase[8*i+j]) << j), j++);
assert(b == int(uint8_t(b)));
bitbase[i] = (uint8_t)b;
KPKPosition pos;
Result bb[IndexMax];
// Initialize table
for (i = 0; i < IndexMax; i++)
{
pos.from_index(i);
bb[i] = !pos.is_legal() ? RESULT_INVALID
: pos.is_immediate_draw() ? RESULT_DRAW
: pos.is_immediate_win() ? RESULT_WIN : RESULT_UNKNOWN;
}
// Release allocated memory:
delete [] Bitbase;
// Iterate until all positions are classified (30 cycles needed)
do {
repeat = false;
for (i = 0; i < IndexMax; i++)
if (bb[i] == RESULT_UNKNOWN)
{
pos.from_index(i);
bb[i] = (pos.sideToMove == WHITE) ? classify_wtm(pos, bb)
: classify_btm(pos, bb);
if (bb[i] != RESULT_UNKNOWN)
repeat = true;
}
} while (repeat);
// Compress result and map into supplied bitbase parameter
for (i = 0; i < 24576; i++)
{
b = 0;
for (j = 0; j < 8; j++)
if (bb[8*i+j] == RESULT_WIN || bb[8*i+j] == RESULT_LOSS)
b |= (1 << j);
bitbase[i] = (uint8_t)b;
}
}
namespace {
int compute_index(Square wksq, Square bksq, Square psq, Color stm) {
int p = int(square_file(psq)) + (int(square_rank(psq)) - 1) * 4;
int r = int(stm) + 2 * int(bksq) + 128 * int(wksq) + 8192 * p;
assert(r >= 0 && r < IndexMax);
return r;
}
void KPKPosition::from_index(int index) {
int s;
int s = (index / 8192) % 24;
sideToMove = Color(index % 2);
blackKingSquare = Square((index / 2) % 64);
whiteKingSquare = Square((index / 128) % 64);
s = (index / 8192) % 24;
pawnSquare = make_square(File(s % 4), Rank(s / 4 + 1));
}
int KPKPosition::to_index() const {
return compute_index(whiteKingSquare, blackKingSquare, pawnSquare,
sideToMove);
}
bool KPKPosition::is_legal() const {
if(whiteKingSquare == pawnSquare || whiteKingSquare == blackKingSquare ||
pawnSquare == blackKingSquare)
return false;
if(sideToMove == WHITE) {
if(bit_is_set(this->wk_attacks(), blackKingSquare))
return false;
if(bit_is_set(this->pawn_attacks(), blackKingSquare))
if ( whiteKingSquare == pawnSquare
|| whiteKingSquare == blackKingSquare
|| pawnSquare == blackKingSquare)
return false;
if (sideToMove == WHITE)
{
if ( bit_is_set(wk_attacks(), blackKingSquare)
|| bit_is_set(pawn_attacks(), blackKingSquare))
return false;
}
else {
if(bit_is_set(this->bk_attacks(), whiteKingSquare))
else if (bit_is_set(bk_attacks(), whiteKingSquare))
return false;
}
return true;
}
bool KPKPosition::is_immediate_draw() const {
if(sideToMove == BLACK) {
Bitboard wka = this->wk_attacks();
Bitboard bka = this->bk_attacks();
// Case 1: Stalemate
if((bka & ~(wka | this->pawn_attacks())) == EmptyBoardBB)
return true;
if (sideToMove == BLACK)
{
Bitboard wka = wk_attacks();
Bitboard bka = bk_attacks();
// Case 2: King can capture pawn
if(bit_is_set(bka, pawnSquare) && !bit_is_set(wka, pawnSquare))
return true;
// Case 1: Stalemate
if ((bka & ~(wka | pawn_attacks())) == EmptyBoardBB)
return true;
// Case 2: King can capture pawn
if (bit_is_set(bka, pawnSquare) && !bit_is_set(wka, pawnSquare))
return true;
}
else {
// Case 1: Stalemate
if(whiteKingSquare == SQ_A8 && pawnSquare == SQ_A7 &&
(blackKingSquare == SQ_C7 || blackKingSquare == SQ_C8))
return true;
else
{
// Case 1: Stalemate
if ( whiteKingSquare == SQ_A8
&& pawnSquare == SQ_A7
&& (blackKingSquare == SQ_C7 || blackKingSquare == SQ_C8))
return true;
}
return false;
}
bool KPKPosition::is_immediate_win() const {
// The position is an immediate win if it is white to move and the white
// pawn can be promoted without getting captured:
return
sideToMove == WHITE &&
square_rank(pawnSquare) == RANK_7 &&
(square_distance(blackKingSquare, pawnSquare+DELTA_N) > 1 ||
bit_is_set(this->wk_attacks(), pawnSquare+DELTA_N));
// The position is an immediate win if it is white to move and the
// white pawn can be promoted without getting captured.
return sideToMove == WHITE
&& square_rank(pawnSquare) == RANK_7
&& ( square_distance(blackKingSquare, pawnSquare + DELTA_N) > 1
|| bit_is_set(wk_attacks(), pawnSquare + DELTA_N));
}
Bitboard KPKPosition::wk_attacks() const {
return StepAttackBB[WK][whiteKingSquare];
}
Bitboard KPKPosition::bk_attacks() const {
return StepAttackBB[BK][blackKingSquare];
}
Bitboard KPKPosition::pawn_attacks() const {
return StepAttackBB[WP][pawnSquare];
}
void initialize() {
KPKPosition p;
for(int i = 0; i < IndexMax; i++) {
p.from_index(i);
if(!p.is_legal())
Bitbase[i] = RESULT_INVALID;
else if(p.is_immediate_draw())
Bitbase[i] = RESULT_DRAW;
else if(p.is_immediate_win())
Bitbase[i] = RESULT_WIN;
else {
Bitbase[i] = RESULT_UNKNOWN;
UnknownCount++;
}
}
}
bool next_iteration() {
KPKPosition p;
int previousUnknownCount = UnknownCount;
for(int i = 0; i < IndexMax; i++)
if(Bitbase[i] == RESULT_UNKNOWN) {
p.from_index(i);
Bitbase[i] = (p.sideToMove == WHITE)? classify_wtm(p) : classify_btm(p);
if(Bitbase[i] == RESULT_WIN || Bitbase[i] == RESULT_LOSS ||
Bitbase[i] == RESULT_DRAW)
UnknownCount--;
}
return UnknownCount != previousUnknownCount;
}
Result classify_wtm(const KPKPosition &p) {
Result classify_wtm(const KPKPosition& pos, const Result bb[]) {
// If one move leads to a position classified as RESULT_LOSS, the result
// of the current position is RESULT_WIN. If all moves lead to positions
// classified as RESULT_DRAW, the current position is classified as
// RESULT_DRAW. Otherwise, the current position is classified as
// RESULT_UNKNOWN.
// of the current position is RESULT_WIN. If all moves lead to positions
// classified as RESULT_DRAW, the current position is classified RESULT_DRAW
// otherwise the current position is classified as RESULT_UNKNOWN.
bool unknownFound = false;
Bitboard b;
Square s;
int idx;
// King moves
b = p.wk_attacks();
while(b) {
s = pop_1st_bit(&b);
switch(Bitbase[compute_index(s, p.blackKingSquare, p.pawnSquare,
BLACK)]) {
case RESULT_LOSS:
return RESULT_WIN;
b = pos.wk_attacks();
while (b)
{
s = pop_1st_bit(&b);
idx = compute_index(s, pos.blackKingSquare, pos.pawnSquare, BLACK);
case RESULT_UNKNOWN:
unknownFound = true;
break;
switch (bb[idx]) {
case RESULT_DRAW: case RESULT_INVALID:
break;
case RESULT_LOSS:
return RESULT_WIN;
default:
assert(false);
}
case RESULT_UNKNOWN:
unknownFound = true;
case RESULT_DRAW:
case RESULT_INVALID:
break;
default:
assert(false);
}
}
// Pawn moves
if(square_rank(p.pawnSquare) < RANK_7) {
s = p.pawnSquare + DELTA_N;
switch(Bitbase[compute_index(p.whiteKingSquare, p.blackKingSquare, s,
BLACK)]) {
case RESULT_LOSS:
return RESULT_WIN;
if (square_rank(pos.pawnSquare) < RANK_7)
{
s = pos.pawnSquare + DELTA_N;
idx = compute_index(pos.whiteKingSquare, pos.blackKingSquare, s, BLACK);
case RESULT_UNKNOWN:
unknownFound = true;
break;
switch (bb[idx]) {
case RESULT_DRAW: case RESULT_INVALID:
break;
default:
assert(false);
}
if(square_rank(s) == RANK_3 &&
s != p.whiteKingSquare && s != p.blackKingSquare) {
s += DELTA_N;
switch(Bitbase[compute_index(p.whiteKingSquare, p.blackKingSquare, s,
BLACK)]) {
case RESULT_LOSS:
return RESULT_WIN;
return RESULT_WIN;
case RESULT_UNKNOWN:
unknownFound = true;
break;
unknownFound = true;
case RESULT_DRAW: case RESULT_INVALID:
break;
case RESULT_DRAW:
case RESULT_INVALID:
break;
default:
assert(false);
assert(false);
}
}
}
return unknownFound? RESULT_UNKNOWN : RESULT_DRAW;
// Double pawn push
if ( square_rank(s) == RANK_3
&& s != pos.whiteKingSquare
&& s != pos.blackKingSquare)
{
s += DELTA_N;
idx = compute_index(pos.whiteKingSquare, pos.blackKingSquare, s, BLACK);
switch (bb[idx]) {
case RESULT_LOSS:
return RESULT_WIN;
case RESULT_UNKNOWN:
unknownFound = true;
case RESULT_DRAW:
case RESULT_INVALID:
break;
default:
assert(false);
}
}
}
return unknownFound ? RESULT_UNKNOWN : RESULT_DRAW;
}
Result classify_btm(const KPKPosition &p) {
Result classify_btm(const KPKPosition& pos, const Result bb[]) {
// If one move leads to a position classified as RESULT_DRAW, the result
// of the current position is RESULT_DRAW. If all moves lead to positions
// of the current position is RESULT_DRAW. If all moves lead to positions
// classified as RESULT_WIN, the current position is classified as
// RESULT_LOSS. Otherwise, the current position is classified as
// RESULT_LOSS. Otherwise, the current position is classified as
// RESULT_UNKNOWN.
bool unknownFound = false;
Bitboard b;
Square s;
int idx;
// King moves
b = p.bk_attacks();
while(b) {
s = pop_1st_bit(&b);
switch(Bitbase[compute_index(p.whiteKingSquare, s, p.pawnSquare,
WHITE)]) {
case RESULT_DRAW:
return RESULT_DRAW;
b = pos.bk_attacks();
while (b)
{
s = pop_1st_bit(&b);
idx = compute_index(pos.whiteKingSquare, s, pos.pawnSquare, WHITE);
case RESULT_UNKNOWN:
unknownFound = true;
break;
switch (bb[idx]) {
case RESULT_WIN: case RESULT_INVALID:
break;
case RESULT_DRAW:
return RESULT_DRAW;
default:
assert(false);
}
case RESULT_UNKNOWN:
unknownFound = true;
case RESULT_WIN:
case RESULT_INVALID:
break;
default:
assert(false);
}
}
return unknownFound? RESULT_UNKNOWN : RESULT_LOSS;
}
int compute_index(Square wksq, Square bksq, Square psq, Color stm) {
int p = int(square_file(psq)) + (int(square_rank(psq)) - 1) * 4;
int result = int(stm) + 2*int(bksq) + 128*int(wksq) + 8192*p;
assert(result >= 0 && result < IndexMax);
return result;
}
int compress_result(Result r) {
return (r == RESULT_WIN || r == RESULT_LOSS)? 1 : 0;
return unknownFound ? RESULT_UNKNOWN : RESULT_LOSS;
}
}

View File

@@ -163,7 +163,10 @@ const int RShift[64] = {
#endif // defined(IS_64BIT)
const Bitboard SquaresByColorBB[2] = { BlackSquaresBB, WhiteSquaresBB };
const Bitboard LightSquaresBB = 0x55AA55AA55AA55AAULL;
const Bitboard DarkSquaresBB = 0xAA55AA55AA55AA55ULL;
const Bitboard SquaresByColorBB[2] = { DarkSquaresBB, LightSquaresBB };
const Bitboard FileBB[8] = {
FileABB, FileBBB, FileCBB, FileDBB, FileEBB, FileFBB, FileGBB, FileHBB
@@ -226,8 +229,9 @@ Bitboard StepAttackBB[16][64];
Bitboard RayBB[64][8];
Bitboard BetweenBB[64][64];
Bitboard SquaresInFrontMask[2][64];
Bitboard PassedPawnMask[2][64];
Bitboard OutpostMask[2][64];
Bitboard AttackSpanMask[2][64];
Bitboard BishopPseudoAttacks[64];
Bitboard RookPseudoAttacks[64];
@@ -246,14 +250,12 @@ namespace {
void init_ray_bitboards();
void init_attacks();
void init_between_bitboards();
void init_pseudo_attacks();
Bitboard index_to_bitboard(int index, Bitboard mask);
Bitboard sliding_attacks(int sq, Bitboard block, int dirs, int deltas[][2],
int fmin, int fmax, int rmin, int rmax);
Bitboard index_to_bitboard(int index, Bitboard mask);
void init_sliding_attacks(Bitboard attacks[],
int attackIndex[], Bitboard mask[],
const int shift[2], const Bitboard mult[],
int deltas[][2]);
void init_pseudo_attacks();
void init_sliding_attacks(Bitboard attacks[], int attackIndex[], Bitboard mask[],
const int shift[], const Bitboard mult[], int deltas[][2]);
}
@@ -265,11 +267,14 @@ namespace {
/// standard output. This is sometimes useful for debugging.
void print_bitboard(Bitboard b) {
for(Rank r = RANK_8; r >= RANK_1; r--) {
std::cout << "+---+---+---+---+---+---+---+---+" << std::endl;
for(File f = FILE_A; f <= FILE_H; f++)
std::cout << "| " << (bit_is_set(b, make_square(f, r))? 'X' : ' ') << ' ';
std::cout << "|" << std::endl;
for (Rank r = RANK_8; r >= RANK_1; r--)
{
std::cout << "+---+---+---+---+---+---+---+---+" << std::endl;
for (File f = FILE_A; f <= FILE_H; f++)
std::cout << "| " << (bit_is_set(b, make_square(f, r))? 'X' : ' ') << ' ';
std::cout << "|" << std::endl;
}
std::cout << "+---+---+---+---+---+---+---+---+" << std::endl;
}
@@ -279,8 +284,10 @@ void print_bitboard(Bitboard b) {
/// program initialization.
void init_bitboards() {
int rookDeltas[4][2] = {{0,1},{0,-1},{1,0},{-1,0}};
int bishopDeltas[4][2] = {{1,1},{-1,1},{1,-1},{-1,-1}};
init_masks();
init_ray_bitboards();
init_attacks();
@@ -326,6 +333,7 @@ const int BitTable[64] = {
};
Square first_1(Bitboard b) {
b ^= (b - 1);
uint32_t fold = int(b) ^ int(b >> 32);
return Square(BitTable[(fold * 0x783a9b23) >> 26]);
@@ -368,39 +376,6 @@ Square pop_1st_bit(Bitboard* bb) {
#endif
// 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;
if (b > 0xFFFF)
{
b >>= 16;
result += 16;
}
if (b > 0xFF)
{
b >>= 8;
result += 8;
}
return result + MsbTable[b];
}
namespace {
@@ -410,39 +385,46 @@ namespace {
// be necessary to touch any of them.
void init_masks() {
SetMaskBB[SQ_NONE] = 0ULL;
ClearMaskBB[SQ_NONE] = ~SetMaskBB[SQ_NONE];
for(Square s = SQ_A1; s <= SQ_H8; s++) {
SetMaskBB[s] = (1ULL << s);
ClearMaskBB[s] = ~SetMaskBB[s];
for (Square s = SQ_A1; s <= SQ_H8; s++)
{
SetMaskBB[s] = (1ULL << s);
ClearMaskBB[s] = ~SetMaskBB[s];
}
for(Color c = WHITE; c <= BLACK; c++)
for(Square s = SQ_A1; s <= SQ_H8; s++) {
PassedPawnMask[c][s] =
in_front_bb(c, s) & this_and_neighboring_files_bb(s);
OutpostMask[c][s] = in_front_bb(c, s) & neighboring_files_bb(s);
}
for (Color c = WHITE; c <= BLACK; c++)
for (Square s = SQ_A1; s <= SQ_H8; s++)
{
SquaresInFrontMask[c][s] = in_front_bb(c, s) & file_bb(s);
PassedPawnMask[c][s] = in_front_bb(c, s) & this_and_neighboring_files_bb(s);
AttackSpanMask[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);
BitCount8Bit[b] = (uint8_t)count_1s<CNT32>(b);
}
int remove_bit_8(int i) { return ((i & ~15) >> 1) | (i & 7); }
void init_ray_bitboards() {
int d[8] = {1, -1, 16, -16, 17, -17, 15, -15};
for(int i = 0; i < 128; i = (i + 9) & ~8) {
for(int j = 0; j < 8; j++) {
RayBB[(i&7)|((i>>4)<<3)][j] = EmptyBoardBB;
for(int k = i + d[j]; (k & 0x88) == 0; k += d[j])
set_bit(&(RayBB[(i&7)|((i>>4)<<3)][j]), Square((k&7)|((k>>4)<<3)));
}
}
for (int i = 0; i < 128; i = (i + 9) & ~8)
for (int j = 0; j < 8; j++)
{
RayBB[remove_bit_8(i)][j] = EmptyBoardBB;
for (int k = i + d[j]; (k & 0x88) == 0; k += d[j])
set_bit(&(RayBB[remove_bit_8(i)][j]), Square(remove_bit_8(k)));
}
}
void init_attacks() {
int i, j, k, l;
int step[16][8] = {
const int step[16][8] = {
{0},
{7,9,0}, {17,15,10,6,-6,-10,-15,-17}, {9,7,-7,-9,0}, {8,1,-1,-8,0},
{9,7,-7,-9,8,1,-1,-8}, {9,7,-7,-9,8,1,-1,-8}, {0}, {0},
@@ -450,105 +432,115 @@ namespace {
{9,7,-7,-9,8,1,-1,-8}, {9,7,-7,-9,8,1,-1,-8}
};
for(i = 0; i < 64; i++) {
for(j = 0; j <= int(BK); j++) {
StepAttackBB[j][i] = EmptyBoardBB;
for(k = 0; k < 8 && step[j][k] != 0; k++) {
l = i + step[j][k];
if(l >= 0 && l < 64 && abs((i&7) - (l&7)) < 3)
StepAttackBB[j][i] |= (1ULL << l);
for (int i = 0; i < 64; i++)
for (int j = 0; j <= int(BK); j++)
{
StepAttackBB[j][i] = EmptyBoardBB;
for (int k = 0; k < 8 && step[j][k] != 0; k++)
{
int l = i + step[j][k];
if (l >= 0 && l < 64 && abs((i & 7) - (l & 7)) < 3)
StepAttackBB[j][i] |= (1ULL << l);
}
}
}
}
}
Bitboard sliding_attacks(int sq, Bitboard block, int dirs, int deltas[][2],
int fmin=0, int fmax=7, int rmin=0, int rmax=7) {
Bitboard result = 0ULL;
int rk = sq / 8, fl = sq % 8, r, f, i;
for(i = 0; i < dirs; i++) {
int dx = deltas[i][0], dy = deltas[i][1];
for(f = fl+dx, r = rk+dy;
(dx==0 || (f>=fmin && f<=fmax)) && (dy==0 || (r>=rmin && r<=rmax));
f += dx, r += dy) {
result |= (1ULL << (f + r*8));
if(block & (1ULL << (f + r*8))) break;
}
int rk = sq / 8;
int fl = sq % 8;
for (int i = 0; i < dirs; i++)
{
int dx = deltas[i][0];
int dy = deltas[i][1];
int f = fl + dx;
int r = rk + dy;
while ( (dx == 0 || (f >= fmin && f <= fmax))
&& (dy == 0 || (r >= rmin && r <= rmax)))
{
result |= (1ULL << (f + r*8));
if (block & (1ULL << (f + r*8)))
break;
f += dx;
r += dy;
}
}
return result;
}
void init_between_bitboards() {
SquareDelta step[8] = {
DELTA_E, DELTA_W, DELTA_N, DELTA_S, DELTA_NE, DELTA_SW, DELTA_NW, DELTA_SE
};
SignedDirection d;
for(Square s1 = SQ_A1; s1 <= SQ_H8; s1++)
for(Square s2 = SQ_A1; s2 <= SQ_H8; s2++) {
BetweenBB[s1][s2] = EmptyBoardBB;
d = signed_direction_between_squares(s1, s2);
if(d != SIGNED_DIR_NONE)
for(Square s3 = s1 + step[d]; s3 != s2; s3 += step[d])
set_bit(&(BetweenBB[s1][s2]), s3);
const SquareDelta step[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++)
{
BetweenBB[s1][s2] = EmptyBoardBB;
SignedDirection d = signed_direction_between_squares(s1, s2);
if (d != SIGNED_DIR_NONE)
{
for (Square s3 = s1 + step[d]; s3 != s2; s3 += step[d])
set_bit(&(BetweenBB[s1][s2]), s3);
}
}
}
Bitboard index_to_bitboard(int index, Bitboard mask) {
int i, j, bits = count_1s(mask);
Bitboard result = 0ULL;
for(i = 0; i < bits; i++) {
j = pop_1st_bit(&mask);
if(index & (1 << i)) result |= (1ULL << j);
int bits = count_1s<CNT32>(mask);
for (int i = 0; i < bits; i++)
{
int j = pop_1st_bit(&mask);
if (index & (1 << i))
result |= (1ULL << j);
}
return result;
}
void init_sliding_attacks(Bitboard attacks[], int attackIndex[], Bitboard mask[],
const int shift[], const Bitboard mult[], int deltas[][2]) {
void init_sliding_attacks(Bitboard attacks[],
int attackIndex[], Bitboard mask[],
const int shift[2], const Bitboard mult[],
int deltas[][2]) {
int i, j, k, index = 0;
Bitboard b;
for(i = 0; i < 64; i++) {
attackIndex[i] = index;
mask[i] = sliding_attacks(i, 0ULL, 4, deltas, 1, 6, 1, 6);
for (int i = 0, index = 0; i < 64; i++)
{
attackIndex[i] = index;
mask[i] = sliding_attacks(i, 0ULL, 4, deltas, 1, 6, 1, 6);
#if defined(IS_64BIT)
j = (1 << (64 - shift[i]));
int j = (1 << (64 - shift[i]));
#else
j = (1 << (32 - shift[i]));
int j = (1 << (32 - shift[i]));
#endif
for(k = 0; k < j; k++) {
for (int k = 0; k < j; k++)
{
#if defined(IS_64BIT)
b = index_to_bitboard(k, mask[i]);
attacks[index + ((b * mult[i]) >> shift[i])] =
sliding_attacks(i, b, 4, deltas);
Bitboard 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);
Bitboard b = index_to_bitboard(k, mask[i]);
unsigned v = int(b) * int(mult[i]) ^ int(b >> 32) * int(mult[i] >> 32);
attacks[index + (v >> shift[i])] = sliding_attacks(i, b, 4, deltas);
#endif
}
index += j;
}
index += j;
}
}
void init_pseudo_attacks() {
Square s;
for(s = SQ_A1; s <= SQ_H8; s++) {
BishopPseudoAttacks[s] = bishop_attacks_bb(s, EmptyBoardBB);
RookPseudoAttacks[s] = rook_attacks_bb(s, EmptyBoardBB);
QueenPseudoAttacks[s] = queen_attacks_bb(s, EmptyBoardBB);
for (Square s = SQ_A1; s <= SQ_H8; s++)
{
BishopPseudoAttacks[s] = bishop_attacks_bb(s, EmptyBoardBB);
RookPseudoAttacks[s] = rook_attacks_bb(s, EmptyBoardBB);
QueenPseudoAttacks[s] = queen_attacks_bb(s, EmptyBoardBB);
}
}

View File

@@ -36,28 +36,25 @@
//// Constants and variables
////
const Bitboard EmptyBoardBB = 0ULL;
const Bitboard WhiteSquaresBB = 0x55AA55AA55AA55AAULL;
const Bitboard BlackSquaresBB = 0xAA55AA55AA55AA55ULL;
const Bitboard EmptyBoardBB = 0;
const Bitboard FileABB = 0x0101010101010101ULL;
const Bitboard FileBBB = 0x0202020202020202ULL;
const Bitboard FileCBB = 0x0404040404040404ULL;
const Bitboard FileDBB = 0x0808080808080808ULL;
const Bitboard FileEBB = 0x1010101010101010ULL;
const Bitboard FileFBB = 0x2020202020202020ULL;
const Bitboard FileGBB = 0x4040404040404040ULL;
const Bitboard FileHBB = 0x8080808080808080ULL;
const Bitboard FileBBB = FileABB << 1;
const Bitboard FileCBB = FileABB << 2;
const Bitboard FileDBB = FileABB << 3;
const Bitboard FileEBB = FileABB << 4;
const Bitboard FileFBB = FileABB << 5;
const Bitboard FileGBB = FileABB << 6;
const Bitboard FileHBB = FileABB << 7;
const Bitboard Rank1BB = 0xFFULL;
const Bitboard Rank2BB = 0xFF00ULL;
const Bitboard Rank3BB = 0xFF0000ULL;
const Bitboard Rank4BB = 0xFF000000ULL;
const Bitboard Rank5BB = 0xFF00000000ULL;
const Bitboard Rank6BB = 0xFF0000000000ULL;
const Bitboard Rank7BB = 0xFF000000000000ULL;
const Bitboard Rank8BB = 0xFF00000000000000ULL;
const Bitboard Rank1BB = 0xFF;
const Bitboard Rank2BB = Rank1BB << (8 * 1);
const Bitboard Rank3BB = Rank1BB << (8 * 2);
const Bitboard Rank4BB = Rank1BB << (8 * 3);
const Bitboard Rank5BB = Rank1BB << (8 * 4);
const Bitboard Rank6BB = Rank1BB << (8 * 5);
const Bitboard Rank7BB = Rank1BB << (8 * 6);
const Bitboard Rank8BB = Rank1BB << (8 * 7);
extern const Bitboard SquaresByColorBB[2];
extern const Bitboard FileBB[8];
@@ -74,8 +71,9 @@ extern Bitboard StepAttackBB[16][64];
extern Bitboard RayBB[64][8];
extern Bitboard BetweenBB[64][64];
extern Bitboard SquaresInFrontMask[2][64];
extern Bitboard PassedPawnMask[2][64];
extern Bitboard OutpostMask[2][64];
extern Bitboard AttackSpanMask[2][64];
extern const uint64_t RMult[64];
extern const int RShift[64];
@@ -127,9 +125,8 @@ 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.
/// rank_bb() and file_bb() take a file or a square as input, and return
/// a bitboard representing all squares on the given file or rank.
inline Bitboard rank_bb(Rank r) {
return RankBB[r];
@@ -156,7 +153,7 @@ inline Bitboard neighboring_files_bb(File f) {
}
inline Bitboard neighboring_files_bb(Square s) {
return neighboring_files_bb(square_file(s));
return NeighboringFilesBB[square_file(s)];
}
@@ -169,7 +166,7 @@ inline Bitboard this_and_neighboring_files_bb(File f) {
}
inline Bitboard this_and_neighboring_files_bb(Square s) {
return this_and_neighboring_files_bb(square_file(s));
return ThisAndNeighboringFilesBB[square_file(s)];
}
@@ -195,7 +192,7 @@ inline Bitboard in_front_bb(Color c, Rank r) {
}
inline Bitboard in_front_bb(Color c, Square s) {
return in_front_bb(c, square_rank(s));
return InFrontBB[c][square_rank(s)];
}
@@ -208,7 +205,7 @@ inline Bitboard behind_bb(Color c, Rank r) {
}
inline Bitboard behind_bb(Color c, Square s) {
return in_front_bb(opposite_color(c), square_rank(s));
return InFrontBB[opposite_color(c)][square_rank(s)];
}
@@ -274,12 +271,11 @@ inline Bitboard squares_between(Square s1, Square s2) {
/// squares_in_front_of takes a color and a square as input, and returns a
/// bitboard representing all squares along the line in front of the square,
/// from the point of view of the given color. For instance,
/// squares_in_front_of(BLACK, SQ_E4) returns a bitboard with the squares
/// e3, e2 and e1 set.
/// from the point of view of the given color. Definition of the table is:
/// SquaresInFrontOf[c][s] = in_front_bb(c, s) & file_bb(s)
inline Bitboard squares_in_front_of(Color c, Square s) {
return in_front_bb(c, s) & file_bb(s);
return SquaresInFrontMask[c][s];
}
@@ -287,33 +283,27 @@ inline Bitboard squares_in_front_of(Color c, Square s) {
/// behind the square instead of in front of the square.
inline Bitboard squares_behind(Color c, Square s) {
return in_front_bb(opposite_color(c), s) & file_bb(s);
return SquaresInFrontMask[opposite_color(c)][s];
}
/// passed_pawn_mask takes a color and a square as input, and returns a
/// bitboard mask which can be used to test if a pawn of the given color on
/// the given square is a passed pawn.
/// the given square is a passed pawn. Definition of the table is:
/// PassedPawnMask[c][s] = in_front_bb(c, s) & this_and_neighboring_files_bb(s)
inline Bitboard passed_pawn_mask(Color c, Square s) {
return PassedPawnMask[c][s];
}
/// outpost_mask takes a color and a square as input, and returns a bitboard
/// mask which can be used to test whether a piece on the square can possibly
/// be driven away by an enemy pawn.
/// attack_span_mask takes a color and a square as input, and returns a bitboard
/// representing all squares that can be attacked by a pawn of the given color
/// when it moves along its file starting from the given square. Definition is:
/// AttackSpanMask[c][s] = in_front_bb(c, s) & neighboring_files_bb(s);
inline Bitboard outpost_mask(Color c, Square s) {
return OutpostMask[c][s];
}
/// isolated_pawn_mask takes a square as input, and returns a bitboard mask
/// which can be used to test whether a pawn on the given square is isolated.
inline Bitboard isolated_pawn_mask(Square s) {
return neighboring_files_bb(s);
inline Bitboard attack_span_mask(Color c, Square s) {
return AttackSpanMask[c][s];
}
@@ -349,7 +339,6 @@ extern Square pop_1st_bit(Bitboard* b);
extern void print_bitboard(Bitboard b);
extern void init_bitboards();
extern int bitScanReverse32(uint32_t b);
#endif // !defined(BITBOARD_H_INCLUDED)

View File

@@ -24,27 +24,23 @@
#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__)
enum BitCountType {
CNT64,
CNT64_MAX15,
CNT32,
CNT32_MAX15,
CNT_POPCNT
};
#define POPCNT_INTRINSIC(x) ({ \
unsigned long __ret; \
__asm__("popcnt %1, %0" : "=r" (__ret) : "r" (x)); \
__ret; })
/// count_1s() counts the number of nonzero bits in a bitboard.
/// We have different optimized versions according if platform
/// is 32 or 64 bits, and to the maximum number of nonzero bits.
/// We also support hardware popcnt instruction. See Readme.txt
/// on how to pgo compile with popcnt support.
template<BitCountType> inline int count_1s(Bitboard);
#endif
/// Software implementation of bit count functions
#if defined(IS_64BIT)
inline int count_1s(Bitboard b) {
template<>
inline int count_1s<CNT64>(Bitboard b) {
b -= ((b>>1) & 0x5555555555555555ULL);
b = ((b>>2) & 0x3333333333333333ULL) + (b & 0x3333333333333333ULL);
b = ((b>>4) + b) & 0x0F0F0F0F0F0F0F0FULL;
@@ -52,16 +48,16 @@ inline int count_1s(Bitboard b) {
return int(b >> 56);
}
inline int count_1s_max_15(Bitboard b) {
template<>
inline int count_1s<CNT64_MAX15>(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) {
template<>
inline int count_1s<CNT32>(Bitboard b) {
unsigned w = unsigned(b >> 32), v = unsigned(b);
v -= (v >> 1) & 0x55555555; // 0-2 in 2 bits
w -= (w >> 1) & 0x55555555;
@@ -73,7 +69,8 @@ inline int count_1s(Bitboard b) {
return int(v >> 24);
}
inline int count_1s_max_15(Bitboard b) {
template<>
inline int count_1s<CNT32_MAX15>(Bitboard b) {
unsigned w = unsigned(b >> 32), v = unsigned(b);
v -= (v >> 1) & 0x55555555; // 0-2 in 2 bits
w -= (w >> 1) & 0x55555555;
@@ -84,27 +81,21 @@ inline int count_1s_max_15(Bitboard b) {
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);
template<>
inline int count_1s<CNT_POPCNT>(Bitboard b) {
#if !defined(USE_POPCNT)
return int(b != 0); // Avoid 'b not used' warning
#elif defined(_MSC_VER)
return __popcnt64(b);
#elif defined(__GNUC__)
unsigned long ret;
__asm__("popcnt %1, %0" : "=r" (ret) : "r" (b));
return ret;
#endif
}
// Detect hardware POPCNT support
/// cpu_has_popcnt() detects support for popcnt instruction at runtime
inline bool cpu_has_popcnt() {
int CPUInfo[4] = {-1};
@@ -113,9 +104,9 @@ inline bool cpu_has_popcnt() {
}
// 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.
/// CpuHasPOPCNT is a global constant initialized at startup that
/// is set to true if CPU on which application runs supports popcnt
/// hardware instruction. Unless USE_POPCNT is not defined.
#if defined(USE_POPCNT)
const bool CpuHasPOPCNT = cpu_has_popcnt();
#else
@@ -123,12 +114,12 @@ 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.
/// CpuIs64Bit is a global constant initialized at compile time that
/// is set to true if CPU on which application runs is a 64 bits.
#if defined(IS_64BIT)
const bool CpuHas64BitPath = true;
const bool CpuIs64Bit = true;
#else
const bool CpuHas64BitPath = false;
const bool CpuIs64Bit = false;
#endif
#endif // !defined(BITCOUNT_H_INCLUDED)

View File

@@ -366,7 +366,7 @@ void Book::open(const string& fName) {
// Get the book size in number of entries
seekg(0, ios::end);
bookSize = tellg() / EntrySize;
bookSize = long(tellg()) / EntrySize;
seekg(0, ios::beg);
if (!good())
@@ -399,14 +399,15 @@ const string Book::file_name() { // Not const to compile on HP-UX 11.X
/// 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) {
Move Book::get_move(const Position& pos, bool findBestMove) {
if (!is_open() || bookSize == 0)
return MOVE_NONE;
int bookMove = 0, scoresSum = 0;
uint64_t key = book_key(pos);
BookEntry entry;
int bookMove = MOVE_NONE;
int scoresSum = 0, bestScore = 0;
uint64_t key = book_key(pos);
// Choose a book move among the possible moves for the given position
for (int idx = find_key(key); idx < bookSize; idx++)
@@ -419,6 +420,17 @@ Move Book::get_move(const Position& pos) {
assert(score > 0);
// If findBestMove is true choose highest rated book move
if (findBestMove)
{
if (score > bestScore)
{
bestScore = score;
bookMove = entry.move;
}
continue;
}
// 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.

View File

@@ -61,7 +61,7 @@ public:
void open(const std::string& fName);
void close();
const std::string file_name();
Move get_move(const Position& pos);
Move get_move(const Position& pos, bool findBestMove);
private:
Book& operator>>(uint64_t& n) { n = read_integer(8); return *this; }

View File

@@ -21,6 +21,7 @@
#if !defined(COLOR_H_INCLUDED)
#define COLOR_H_INCLUDED
#include "types.h"
////
//// Types
@@ -32,13 +33,18 @@ enum Color {
COLOR_NONE
};
enum SquareColor {
DARK,
LIGHT
};
ENABLE_OPERATORS_ON(Color);
////
//// Inline functions
////
inline void operator++ (Color &c, int) { c = Color(int(c) + 1); }
inline Color opposite_color(Color c) {
return Color(int(c) ^ 1);
}

View File

@@ -21,41 +21,20 @@
#if !defined(DEPTH_H_INCLUDED)
#define DEPTH_H_INCLUDED
#include "types.h"
////
//// Types
////
enum Depth {
ONE_PLY = 2,
DEPTH_ZERO = 0,
DEPTH_MAX = 200, // 100 * OnePly;
DEPTH_ENSURE_SIGNED = -1
DEPTH_NONE = -127 * ONE_PLY
};
////
//// Constants
////
const Depth OnePly = Depth(2);
////
//// Inline functions
////
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 &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 &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); }
inline Depth operator/ (Depth d, int i) { return Depth(int(d) / i); }
inline void operator/= (Depth &d, int i) { d = Depth(int(d) / i); }
ENABLE_OPERATORS_ON(Depth);
#endif // !defined(DEPTH_H_INCLUDED)

View File

@@ -45,6 +45,8 @@ enum SignedDirection {
SIGNED_DIR_NONE = 8
};
ENABLE_OPERATORS_ON(SignedDirection);
////
//// Variables
@@ -58,14 +60,6 @@ extern uint8_t SignedDirectionTable[64][64];
//// Inline functions
////
inline void operator++ (Direction& d, int) {
d = Direction(int(d) + 1);
}
inline void operator++ (SignedDirection& d, int) {
d = SignedDirection(int(d) + 1);
}
inline Direction direction_between_squares(Square s1, Square s2) {
return Direction(DirectionTable[s1][s2]);
}

View File

@@ -65,13 +65,13 @@ namespace {
// the two kings in basic endgames.
const int DistanceBonus[8] = { 0, 0, 100, 80, 60, 40, 20, 10 };
// Bitbase for KP vs K
uint8_t KPKBitbase[24576];
// Penalty for big distance between king and knight for the defending king
// and knight in KR vs KN endgames.
const int KRKNKingKnightDistancePenalty[8] = { 0, 0, 4, 10, 20, 32, 48, 70 };
// Bitbase for KP vs K
uint8_t KPKBitbase[24576];
// Various inline functions for accessing the above arrays
inline Value mate_table(Square s) {
return Value(MateTable[s]);
@@ -99,15 +99,24 @@ namespace {
//// Functions
////
/// init_bitbases() is called during program initialization, and simply loads
/// bitbases from disk into memory. At the moment, there is only the bitbase
/// for KP vs K, but we may decide to add other bitbases later.
void init_bitbases() {
generate_kpk_bitbase(KPKBitbase);
}
/// Mate with KX vs K. This function is used to evaluate positions with
/// King and plenty of material vs a lone king. It simply gives the
/// attacking side a bonus for driving the defending king towards the edge
/// of the board, and for keeping the distance between the two kings small.
template<>
Value EvaluationFunction<KXK>::apply(const Position& pos) {
Value EvaluationFunction<KXK>::apply(const Position& pos) const {
assert(pos.non_pawn_material(weakerSide) == Value(0));
assert(pos.piece_count(weakerSide, PAWN) == Value(0));
assert(pos.non_pawn_material(weakerSide) == VALUE_ZERO);
assert(pos.piece_count(weakerSide, PAWN) == VALUE_ZERO);
Square winnerKSq = pos.king_square(strongerSide);
Square loserKSq = pos.king_square(weakerSide);
@@ -117,23 +126,23 @@ Value EvaluationFunction<KXK>::apply(const Position& pos) {
+ mate_table(loserKSq)
+ distance_bonus(square_distance(winnerKSq, loserKSq));
if ( pos.piece_count(strongerSide, QUEEN) > 0
|| pos.piece_count(strongerSide, ROOK) > 0
if ( pos.piece_count(strongerSide, QUEEN)
|| pos.piece_count(strongerSide, ROOK)
|| pos.piece_count(strongerSide, BISHOP) > 1)
// TODO: check for two equal-colored bishops!
result += VALUE_KNOWN_WIN;
return (strongerSide == pos.side_to_move() ? result : -result);
return strongerSide == pos.side_to_move() ? result : -result;
}
/// Mate with KBN vs K. This is similar to KX vs K, but we have to drive the
/// defending king towards a corner square of the right color.
template<>
Value EvaluationFunction<KBNK>::apply(const Position& pos) {
Value EvaluationFunction<KBNK>::apply(const Position& pos) const {
assert(pos.non_pawn_material(weakerSide) == Value(0));
assert(pos.piece_count(weakerSide, PAWN) == Value(0));
assert(pos.non_pawn_material(weakerSide) == VALUE_ZERO);
assert(pos.piece_count(weakerSide, PAWN) == VALUE_ZERO);
assert(pos.non_pawn_material(strongerSide) == KnightValueMidgame + BishopValueMidgame);
assert(pos.piece_count(strongerSide, BISHOP) == 1);
assert(pos.piece_count(strongerSide, KNIGHT) == 1);
@@ -143,7 +152,10 @@ Value EvaluationFunction<KBNK>::apply(const Position& pos) {
Square loserKSq = pos.king_square(weakerSide);
Square bishopSquare = pos.piece_list(strongerSide, BISHOP, 0);
if (square_color(bishopSquare) == BLACK)
// kbnk_mate_table() tries to drive toward corners A1 or H8,
// if we have a bishop that cannot reach the above squares we
// mirror the kings so to drive enemy toward corners A8 or H1.
if (!same_color_squares(bishopSquare, SQ_A1))
{
winnerKSq = flop_square(winnerKSq);
loserKSq = flop_square(loserKSq);
@@ -153,16 +165,16 @@ Value EvaluationFunction<KBNK>::apply(const Position& pos) {
+ distance_bonus(square_distance(winnerKSq, loserKSq))
+ kbnk_mate_table(loserKSq);
return (strongerSide == pos.side_to_move() ? result : -result);
return strongerSide == pos.side_to_move() ? result : -result;
}
/// KP vs K. This endgame is evaluated with the help of a bitbase.
template<>
Value EvaluationFunction<KPK>::apply(const Position& pos) {
Value EvaluationFunction<KPK>::apply(const Position& pos) const {
assert(pos.non_pawn_material(strongerSide) == Value(0));
assert(pos.non_pawn_material(weakerSide) == Value(0));
assert(pos.non_pawn_material(strongerSide) == VALUE_ZERO);
assert(pos.non_pawn_material(weakerSide) == VALUE_ZERO);
assert(pos.piece_count(strongerSide, PAWN) == 1);
assert(pos.piece_count(weakerSide, PAWN) == 0);
@@ -186,9 +198,9 @@ Value EvaluationFunction<KPK>::apply(const Position& pos) {
if (square_file(wpsq) >= FILE_E)
{
wksq = flop_square(wksq);
bksq = flop_square(bksq);
wpsq = flop_square(wpsq);
wksq = flop_square(wksq);
bksq = flop_square(bksq);
wpsq = flop_square(wpsq);
}
if (!probe_kpk(wksq, wpsq, bksq, stm))
@@ -198,7 +210,7 @@ Value EvaluationFunction<KPK>::apply(const Position& pos) {
+ PawnValueEndgame
+ Value(square_rank(wpsq));
return (strongerSide == pos.side_to_move() ? result : -result);
return strongerSide == pos.side_to_move() ? result : -result;
}
@@ -207,7 +219,7 @@ Value EvaluationFunction<KPK>::apply(const Position& pos) {
/// far advanced with support of the king, while the attacking king is far
/// away.
template<>
Value EvaluationFunction<KRKP>::apply(const Position& pos) {
Value EvaluationFunction<KRKP>::apply(const Position& pos) const {
assert(pos.non_pawn_material(strongerSide) == RookValueMidgame);
assert(pos.piece_count(strongerSide, PAWN) == 0);
@@ -239,7 +251,7 @@ Value EvaluationFunction<KRKP>::apply(const Position& pos) {
// If the weaker side's king is too far from the pawn and the rook,
// it's a win
else if ( square_distance(bksq, bpsq) - (tempo^1) >= 3
else if ( square_distance(bksq, bpsq) - (tempo ^ 1) >= 3
&& square_distance(bksq, wrsq) >= 3)
result = RookValueEndgame - Value(square_distance(wksq, bpsq));
@@ -257,14 +269,14 @@ Value EvaluationFunction<KRKP>::apply(const Position& pos) {
+ Value(square_distance(bksq, bpsq + DELTA_S) * 8)
+ Value(square_distance(bpsq, queeningSq) * 8);
return (strongerSide == pos.side_to_move() ? result : -result);
return strongerSide == pos.side_to_move() ? result : -result;
}
/// KR vs KB. This is very simple, and always returns drawish scores. The
/// score is slightly bigger when the defending king is close to the edge.
template<>
Value EvaluationFunction<KRKB>::apply(const Position& pos) {
Value EvaluationFunction<KRKB>::apply(const Position& pos) const {
assert(pos.non_pawn_material(strongerSide) == RookValueMidgame);
assert(pos.piece_count(strongerSide, PAWN) == 0);
@@ -273,14 +285,14 @@ Value EvaluationFunction<KRKB>::apply(const Position& pos) {
assert(pos.piece_count(weakerSide, BISHOP) == 1);
Value result = mate_table(pos.king_square(weakerSide));
return (pos.side_to_move() == strongerSide ? result : -result);
return strongerSide == pos.side_to_move() ? result : -result;
}
/// KR vs KN. The attacking side has slightly better winning chances than
/// in KR vs KB, particularly if the king and the knight are far apart.
template<>
Value EvaluationFunction<KRKN>::apply(const Position& pos) {
Value EvaluationFunction<KRKN>::apply(const Position& pos) const {
assert(pos.non_pawn_material(strongerSide) == RookValueMidgame);
assert(pos.piece_count(strongerSide, PAWN) == 0);
@@ -291,10 +303,12 @@ Value EvaluationFunction<KRKN>::apply(const Position& pos) {
Square defendingKSq = pos.king_square(weakerSide);
Square nSq = pos.piece_list(weakerSide, KNIGHT, 0);
Value result = Value(10) + mate_table(defendingKSq) +
krkn_king_knight_distance_penalty(square_distance(defendingKSq, nSq));
int d = square_distance(defendingKSq, nSq);
Value result = Value(10)
+ mate_table(defendingKSq)
+ krkn_king_knight_distance_penalty(d);
return (strongerSide == pos.side_to_move())? result : -result;
return strongerSide == pos.side_to_move() ? result : -result;
}
@@ -304,7 +318,7 @@ Value EvaluationFunction<KRKN>::apply(const Position& pos) {
/// for the defending side in the search, this is usually sufficient to be
/// able to win KQ vs KR.
template<>
Value EvaluationFunction<KQKR>::apply(const Position& pos) {
Value EvaluationFunction<KQKR>::apply(const Position& pos) const {
assert(pos.non_pawn_material(strongerSide) == QueenValueMidgame);
assert(pos.piece_count(strongerSide, PAWN) == 0);
@@ -319,11 +333,11 @@ Value EvaluationFunction<KQKR>::apply(const Position& pos) {
+ mate_table(loserKSq)
+ distance_bonus(square_distance(winnerKSq, loserKSq));
return (strongerSide == pos.side_to_move())? result : -result;
return strongerSide == pos.side_to_move() ? result : -result;
}
template<>
Value EvaluationFunction<KBBKN>::apply(const Position& pos) {
Value EvaluationFunction<KBBKN>::apply(const Position& pos) const {
assert(pos.piece_count(strongerSide, BISHOP) == 2);
assert(pos.non_pawn_material(strongerSide) == 2*BishopValueMidgame);
@@ -343,31 +357,31 @@ 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.attacks_from<KNIGHT>(nsq))) * 8);
result += Value((8 - count_1s<CNT32_MAX15>(pos.attacks_from<KNIGHT>(nsq))) * 8);
return (strongerSide == pos.side_to_move() ? result : -result);
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);
Value EvaluationFunction<KmmKm>::apply(const Position&) const {
return VALUE_ZERO;
}
template<>
Value EvaluationFunction<KNNK>::apply(const Position&) {
return Value(0);
Value EvaluationFunction<KNNK>::apply(const Position&) const {
return VALUE_ZERO;
}
/// KBPKScalingFunction scales endgames where the stronger side has king,
/// bishop and one or more pawns. It checks for draws with rook pawns and a
/// bishop of the wrong color. If such a draw is detected, ScaleFactor(0) is
/// bishop of the wrong color. If such a draw is detected, SCALE_FACTOR_ZERO is
/// returned. If not, the return value is SCALE_FACTOR_NONE, i.e. no scaling
/// will be used.
template<>
ScaleFactor ScalingFunction<KBPsK>::apply(const Position& pos) {
ScaleFactor ScalingFunction<KBPsK>::apply(const Position& pos) const {
assert(pos.non_pawn_material(strongerSide) == BishopValueMidgame);
assert(pos.piece_count(strongerSide, BISHOP) == 1);
@@ -387,7 +401,7 @@ ScaleFactor ScalingFunction<KBPsK>::apply(const Position& pos) {
Square queeningSq = relative_square(strongerSide, make_square(pawnFile, RANK_8));
Square kingSq = pos.king_square(weakerSide);
if ( square_color(queeningSq) != square_color(bishopSq)
if ( !same_color_squares(queeningSq, bishopSq)
&& file_distance(square_file(kingSq), pawnFile) <= 1)
{
// The bishop has the wrong color, and the defending king is on the
@@ -401,15 +415,15 @@ ScaleFactor ScalingFunction<KBPsK>::apply(const Position& pos) {
}
else
{
for(rank = RANK_2; (rank_bb(rank) & pawns) == EmptyBoardBB; rank++) {}
rank = Rank(rank^7); // HACK to get the relative rank
for (rank = RANK_2; (rank_bb(rank) & pawns) == EmptyBoardBB; rank++) {}
rank = Rank(rank ^ 7); // HACK to get the relative rank
assert(rank >= RANK_2 && rank <= RANK_7);
}
// If the defending king has distance 1 to the promotion square or
// is placed somewhere in front of the pawn, it's a draw.
if ( square_distance(kingSq, queeningSq) <= 1
|| relative_rank(strongerSide, kingSq) >= rank)
return ScaleFactor(0);
return SCALE_FACTOR_ZERO;
}
}
return SCALE_FACTOR_NONE;
@@ -421,7 +435,7 @@ ScaleFactor ScalingFunction<KBPsK>::apply(const Position& pos) {
/// It tests for fortress draws with a rook on the third rank defended by
/// a pawn.
template<>
ScaleFactor ScalingFunction<KQKRPs>::apply(const Position& pos) {
ScaleFactor ScalingFunction<KQKRPs>::apply(const Position& pos) const {
assert(pos.non_pawn_material(strongerSide) == QueenValueMidgame);
assert(pos.piece_count(strongerSide, QUEEN) == 1);
@@ -438,7 +452,7 @@ ScaleFactor ScalingFunction<KQKRPs>::apply(const Position& pos) {
{
Square rsq = pos.piece_list(weakerSide, ROOK, 0);
if (pos.attacks_from<PAWN>(rsq, strongerSide) & pos.pieces(PAWN, weakerSide))
return ScaleFactor(0);
return SCALE_FACTOR_ZERO;
}
return SCALE_FACTOR_NONE;
}
@@ -452,7 +466,7 @@ ScaleFactor ScalingFunction<KQKRPs>::apply(const Position& pos) {
/// It would also be nice to rewrite the actual code for this function,
/// which is mostly copied from Glaurung 1.x, and not very pretty.
template<>
ScaleFactor ScalingFunction<KRPKR>::apply(const Position &pos) {
ScaleFactor ScalingFunction<KRPKR>::apply(const Position& pos) const {
assert(pos.non_pawn_material(strongerSide) == RookValueMidgame);
assert(pos.piece_count(strongerSide, PAWN) == 1);
@@ -495,7 +509,7 @@ ScaleFactor ScalingFunction<KRPKR>::apply(const Position &pos) {
&& square_distance(bksq, queeningSq) <= 1
&& wksq <= SQ_H5
&& (square_rank(brsq) == RANK_6 || (r <= RANK_3 && square_rank(wrsq) != RANK_6)))
return ScaleFactor(0);
return SCALE_FACTOR_ZERO;
// The defending side saves a draw by checking from behind in case the pawn
// has advanced to the 6th rank with the king behind.
@@ -503,13 +517,13 @@ ScaleFactor ScalingFunction<KRPKR>::apply(const Position &pos) {
&& square_distance(bksq, queeningSq) <= 1
&& square_rank(wksq) + tempo <= RANK_6
&& (square_rank(brsq) == RANK_1 || (!tempo && abs(square_file(brsq) - f) >= 3)))
return ScaleFactor(0);
return SCALE_FACTOR_ZERO;
if ( r >= RANK_6
&& bksq == queeningSq
&& square_rank(brsq) == RANK_1
&& (!tempo || square_distance(wksq, wpsq) >= 2))
return ScaleFactor(0);
return SCALE_FACTOR_ZERO;
// White pawn on a7 and rook on a8 is a draw if black's king is on g7 or h7
// and the black rook is behind the pawn.
@@ -518,7 +532,7 @@ ScaleFactor ScalingFunction<KRPKR>::apply(const Position &pos) {
&& (bksq == SQ_H7 || bksq == SQ_G7)
&& square_file(brsq) == FILE_A
&& (square_rank(brsq) <= RANK_3 || square_file(wksq) >= FILE_D || square_rank(wksq) <= RANK_5))
return ScaleFactor(0);
return SCALE_FACTOR_ZERO;
// If the defending king blocks the pawn and the attacking king is too far
// away, it's a draw.
@@ -526,7 +540,7 @@ ScaleFactor ScalingFunction<KRPKR>::apply(const Position &pos) {
&& bksq == wpsq + DELTA_N
&& square_distance(wksq, wpsq) - tempo >= 2
&& square_distance(wksq, brsq) - tempo >= 2)
return ScaleFactor(0);
return SCALE_FACTOR_ZERO;
// Pawn on the 7th rank supported by the rook from behind usually wins if the
// attacking king is closer to the queening square than the defending king,
@@ -549,8 +563,8 @@ ScaleFactor ScalingFunction<KRPKR>::apply(const Position &pos) {
|| ( square_distance(wksq, queeningSq) < square_distance(bksq, wrsq) + tempo
&& (square_distance(wksq, wpsq + DELTA_N) < square_distance(bksq, wrsq) + tempo))))
return ScaleFactor( SCALE_FACTOR_MAX
- (8 * square_distance(wpsq, queeningSq)
+ 2 * square_distance(wksq, queeningSq)));
- 8 * square_distance(wpsq, queeningSq)
- 2 * square_distance(wksq, queeningSq));
// If the pawn is not far advanced, and the defending king is somewhere in
// the pawn's path, it's probably a draw.
@@ -570,7 +584,7 @@ ScaleFactor ScalingFunction<KRPKR>::apply(const Position &pos) {
/// single pattern: If the stronger side has no pawns and the defending king
/// is actively placed, the position is drawish.
template<>
ScaleFactor ScalingFunction<KRPPKRP>::apply(const Position &pos) {
ScaleFactor ScalingFunction<KRPPKRP>::apply(const Position& pos) const {
assert(pos.non_pawn_material(strongerSide) == RookValueMidgame);
assert(pos.piece_count(strongerSide, PAWN) == 2);
@@ -609,43 +623,35 @@ ScaleFactor ScalingFunction<KRPPKRP>::apply(const Position &pos) {
/// against king. There is just a single rule here: If all pawns are on
/// the same rook file and are blocked by the defending king, it's a draw.
template<>
ScaleFactor ScalingFunction<KPsK>::apply(const Position &pos) {
ScaleFactor ScalingFunction<KPsK>::apply(const Position& pos) const {
assert(pos.non_pawn_material(strongerSide) == Value(0));
assert(pos.non_pawn_material(strongerSide) == VALUE_ZERO);
assert(pos.piece_count(strongerSide, PAWN) >= 2);
assert(pos.non_pawn_material(weakerSide) == Value(0));
assert(pos.non_pawn_material(weakerSide) == VALUE_ZERO);
assert(pos.piece_count(weakerSide, PAWN) == 0);
Square ksq = pos.king_square(weakerSide);
Bitboard pawns = pos.pieces(PAWN, strongerSide);
// Are all pawns on the 'a' file?
if ((pawns & ~FileABB) == EmptyBoardBB)
{
// Does the defending king block the pawns?
Square ksq = pos.king_square(weakerSide);
if (square_distance(ksq, relative_square(strongerSide, SQ_A8)) <= 1)
return ScaleFactor(0);
else if( square_file(ksq) == FILE_A
&& (in_front_bb(strongerSide, ksq) & pawns) == EmptyBoardBB)
return ScaleFactor(0);
else
return SCALE_FACTOR_NONE;
if ( square_distance(ksq, relative_square(strongerSide, SQ_A8)) <= 1
|| ( square_file(ksq) == FILE_A
&& (in_front_bb(strongerSide, ksq) & pawns) == EmptyBoardBB))
return SCALE_FACTOR_ZERO;
}
// Are all pawns on the 'h' file?
else if ((pawns & ~FileHBB) == EmptyBoardBB)
{
// Does the defending king block the pawns?
Square ksq = pos.king_square(weakerSide);
if (square_distance(ksq, relative_square(strongerSide, SQ_H8)) <= 1)
return ScaleFactor(0);
else if ( square_file(ksq) == FILE_H
&& (in_front_bb(strongerSide, ksq) & pawns) == EmptyBoardBB)
return ScaleFactor(0);
else
return SCALE_FACTOR_NONE;
if ( square_distance(ksq, relative_square(strongerSide, SQ_H8)) <= 1
|| ( square_file(ksq) == FILE_H
&& (in_front_bb(strongerSide, ksq) & pawns) == EmptyBoardBB))
return SCALE_FACTOR_ZERO;
}
else
return SCALE_FACTOR_NONE;
return SCALE_FACTOR_NONE;
}
@@ -655,7 +661,7 @@ ScaleFactor ScalingFunction<KPsK>::apply(const Position &pos) {
/// it's a draw. If the two bishops have opposite color, it's almost always
/// a draw.
template<>
ScaleFactor ScalingFunction<KBPKB>::apply(const Position &pos) {
ScaleFactor ScalingFunction<KBPKB>::apply(const Position& pos) const {
assert(pos.non_pawn_material(strongerSide) == BishopValueMidgame);
assert(pos.piece_count(strongerSide, BISHOP) == 1);
@@ -672,12 +678,12 @@ ScaleFactor ScalingFunction<KBPKB>::apply(const Position &pos) {
// Case 1: Defending king blocks the pawn, and cannot be driven away
if ( square_file(weakerKingSq) == square_file(pawnSq)
&& relative_rank(strongerSide, pawnSq) < relative_rank(strongerSide, weakerKingSq)
&& ( square_color(weakerKingSq) != square_color(strongerBishopSq)
&& ( !same_color_squares(weakerKingSq, strongerBishopSq)
|| relative_rank(strongerSide, weakerKingSq) <= RANK_6))
return ScaleFactor(0);
return SCALE_FACTOR_ZERO;
// Case 2: Opposite colored bishops
if (square_color(strongerBishopSq) != square_color(weakerBishopSq))
if (!same_color_squares(strongerBishopSq, weakerBishopSq))
{
// We assume that the position is drawn in the following three situations:
//
@@ -690,15 +696,16 @@ ScaleFactor ScalingFunction<KBPKB>::apply(const Position &pos) {
// reasonably well.
if (relative_rank(strongerSide, pawnSq) <= RANK_5)
return ScaleFactor(0);
return SCALE_FACTOR_ZERO;
else
{
Bitboard ray = ray_bb(pawnSq, (strongerSide == WHITE)? SIGNED_DIR_N : SIGNED_DIR_S);
if (ray & pos.pieces(KING, weakerSide))
return ScaleFactor(0);
if( (pos.attacks_from<BISHOP>(weakerBishopSq) & ray)
&& square_distance(weakerBishopSq, pawnSq) >= 3)
return ScaleFactor(0);
return SCALE_FACTOR_ZERO;
if ( (pos.attacks_from<BISHOP>(weakerBishopSq) & ray)
&& square_distance(weakerBishopSq, pawnSq) >= 3)
return SCALE_FACTOR_ZERO;
}
}
return SCALE_FACTOR_NONE;
@@ -708,7 +715,7 @@ ScaleFactor ScalingFunction<KBPKB>::apply(const Position &pos) {
/// KBPPKBScalingFunction scales KBPP vs KB endgames. It detects a few basic
/// draws with opposite-colored bishops.
template<>
ScaleFactor ScalingFunction<KBPPKB>::apply(const Position& pos) {
ScaleFactor ScalingFunction<KBPPKB>::apply(const Position& pos) const {
assert(pos.non_pawn_material(strongerSide) == BishopValueMidgame);
assert(pos.piece_count(strongerSide, BISHOP) == 1);
@@ -720,7 +727,7 @@ ScaleFactor ScalingFunction<KBPPKB>::apply(const Position& pos) {
Square wbsq = pos.piece_list(strongerSide, BISHOP, 0);
Square bbsq = pos.piece_list(weakerSide, BISHOP, 0);
if (square_color(wbsq) == square_color(bbsq))
if (same_color_squares(wbsq, bbsq))
// Not opposite-colored bishops, no scaling
return SCALE_FACTOR_NONE;
@@ -749,8 +756,8 @@ ScaleFactor ScalingFunction<KBPPKB>::apply(const Position& pos) {
// some square in the frontmost pawn's path.
if ( square_file(ksq) == square_file(blockSq1)
&& relative_rank(strongerSide, ksq) >= relative_rank(strongerSide, blockSq1)
&& square_color(ksq) != square_color(wbsq))
return ScaleFactor(0);
&& !same_color_squares(ksq, wbsq))
return SCALE_FACTOR_ZERO;
else
return SCALE_FACTOR_NONE;
@@ -759,16 +766,17 @@ ScaleFactor ScalingFunction<KBPPKB>::apply(const Position& pos) {
// in front of the frontmost pawn's path, and the square diagonally behind
// this square on the file of the other pawn.
if ( ksq == blockSq1
&& square_color(ksq) != square_color(wbsq)
&& !same_color_squares(ksq, wbsq)
&& ( bbsq == blockSq2
|| (pos.attacks_from<BISHOP>(blockSq2) & pos.pieces(BISHOP, weakerSide))
|| rank_distance(r1, r2) >= 2))
return ScaleFactor(0);
return SCALE_FACTOR_ZERO;
else if ( ksq == blockSq2
&& square_color(ksq) != square_color(wbsq)
&& !same_color_squares(ksq, wbsq)
&& ( bbsq == blockSq1
|| (pos.attacks_from<BISHOP>(blockSq1) & pos.pieces(BISHOP, weakerSide))))
return ScaleFactor(0);
return SCALE_FACTOR_ZERO;
else
return SCALE_FACTOR_NONE;
@@ -784,7 +792,7 @@ ScaleFactor ScalingFunction<KBPPKB>::apply(const Position& pos) {
/// square of the king is not of the same color as the stronger side's bishop,
/// it's a draw.
template<>
ScaleFactor ScalingFunction<KBPKN>::apply(const Position &pos) {
ScaleFactor ScalingFunction<KBPKN>::apply(const Position& pos) const {
assert(pos.non_pawn_material(strongerSide) == BishopValueMidgame);
assert(pos.piece_count(strongerSide, BISHOP) == 1);
@@ -799,9 +807,9 @@ ScaleFactor ScalingFunction<KBPKN>::apply(const Position &pos) {
if ( square_file(weakerKingSq) == square_file(pawnSq)
&& relative_rank(strongerSide, pawnSq) < relative_rank(strongerSide, weakerKingSq)
&& ( square_color(weakerKingSq) != square_color(strongerBishopSq)
&& ( !same_color_squares(weakerKingSq, strongerBishopSq)
|| relative_rank(strongerSide, weakerKingSq) <= RANK_6))
return ScaleFactor(0);
return SCALE_FACTOR_ZERO;
return SCALE_FACTOR_NONE;
}
@@ -811,12 +819,12 @@ ScaleFactor ScalingFunction<KBPKN>::apply(const Position &pos) {
/// If the pawn is a rook pawn on the 7th rank and the defending king prevents
/// the pawn from advancing, the position is drawn.
template<>
ScaleFactor ScalingFunction<KNPK>::apply(const Position &pos) {
ScaleFactor ScalingFunction<KNPK>::apply(const Position& pos) const {
assert(pos.non_pawn_material(strongerSide) == KnightValueMidgame);
assert(pos.piece_count(strongerSide, KNIGHT) == 1);
assert(pos.piece_count(strongerSide, PAWN) == 1);
assert(pos.non_pawn_material(weakerSide) == Value(0));
assert(pos.non_pawn_material(weakerSide) == VALUE_ZERO);
assert(pos.piece_count(weakerSide, PAWN) == 0);
Square pawnSq = pos.piece_list(strongerSide, PAWN, 0);
@@ -824,11 +832,11 @@ ScaleFactor ScalingFunction<KNPK>::apply(const Position &pos) {
if ( pawnSq == relative_square(strongerSide, SQ_A7)
&& square_distance(weakerKingSq, relative_square(strongerSide, SQ_A8)) <= 1)
return ScaleFactor(0);
return SCALE_FACTOR_ZERO;
if ( pawnSq == relative_square(strongerSide, SQ_H7)
&& square_distance(weakerKingSq, relative_square(strongerSide, SQ_H8)) <= 1)
return ScaleFactor(0);
return SCALE_FACTOR_ZERO;
return SCALE_FACTOR_NONE;
}
@@ -841,10 +849,10 @@ ScaleFactor ScalingFunction<KNPK>::apply(const Position &pos) {
/// advanced and not on a rook file; in this case it is often possible to win
/// (e.g. 8/4k3/3p4/3P4/6K1/8/8/8 w - - 0 1).
template<>
ScaleFactor ScalingFunction<KPKP>::apply(const Position &pos) {
ScaleFactor ScalingFunction<KPKP>::apply(const Position& pos) const {
assert(pos.non_pawn_material(strongerSide) == Value(0));
assert(pos.non_pawn_material(weakerSide) == Value(0));
assert(pos.non_pawn_material(strongerSide) == VALUE_ZERO);
assert(pos.non_pawn_material(weakerSide) == VALUE_ZERO);
assert(pos.piece_count(WHITE, PAWN) == 1);
assert(pos.piece_count(BLACK, PAWN) == 1);
@@ -881,32 +889,21 @@ ScaleFactor ScalingFunction<KPKP>::apply(const Position &pos) {
// Probe the KPK bitbase with the weakest side's pawn removed. If it's a
// draw, it's probably at least a draw even with the pawn.
if (probe_kpk(wksq, wpsq, bksq, stm))
return SCALE_FACTOR_NONE;
else
return ScaleFactor(0);
}
/// init_bitbases() is called during program initialization, and simply loads
/// bitbases from disk into memory. At the moment, there is only the bitbase
/// for KP vs K, but we may decide to add other bitbases later.
void init_bitbases() {
generate_kpk_bitbase(KPKBitbase);
return probe_kpk(wksq, wpsq, bksq, stm) ? SCALE_FACTOR_NONE : SCALE_FACTOR_ZERO;
}
namespace {
// Probe the KP vs K bitbase:
// Probe the KP vs K bitbase
int probe_kpk(Square wksq, Square wpsq, Square bksq, Color stm) {
int wp = int(square_file(wpsq)) + (int(square_rank(wpsq)) - 1) * 4;
int index = int(stm) + 2*int(bksq) + 128*int(wksq) + 8192*wp;
int wp = square_file(wpsq) + 4 * (square_rank(wpsq) - 1);
int index = int(stm) + 2 * bksq + 128 * wksq + 8192 * wp;
assert(index >= 0 && index < 24576*8);
return KPKBitbase[index/8] & (1 << (index&7));
assert(index >= 0 && index < 24576 * 8);
return KPKBitbase[index / 8] & (1 << (index & 7));
}
}

View File

@@ -26,7 +26,6 @@
////
#include "position.h"
#include "scale.h"
#include "value.h"
@@ -68,7 +67,7 @@ class EndgameFunctionBase {
public:
EndgameFunctionBase(Color c) : strongerSide(c), weakerSide(opposite_color(c)) {}
virtual ~EndgameFunctionBase() {}
virtual T apply(const Position&) = 0;
virtual T apply(const Position&) const = 0;
Color color() const { return strongerSide; }
protected:
@@ -85,14 +84,14 @@ template<EndgameType>
struct EvaluationFunction : public EndgameEvaluationFunctionBase {
typedef EndgameEvaluationFunctionBase Base;
explicit EvaluationFunction(Color c): EndgameEvaluationFunctionBase(c) {}
Value apply(const Position&);
Value apply(const Position&) const;
};
template<EndgameType>
struct ScalingFunction : public EndgameScalingFunctionBase {
typedef EndgameScalingFunctionBase Base;
explicit ScalingFunction(Color c) : EndgameScalingFunctionBase(c) {}
ScaleFactor apply(const Position&);
ScaleFactor apply(const Position&) const;
};

File diff suppressed because it is too large Load Diff

View File

@@ -21,94 +21,14 @@
#if !defined(EVALUATE_H_INCLUDED)
#define EVALUATE_H_INCLUDED
////
//// Includes
////
#include "color.h"
#include "value.h"
#include <iostream>
#include "material.h"
#include "pawns.h"
////
//// Types
////
/// The EvalInfo struct contains various information computed and collected
/// by the evaluation function. An EvalInfo object is passed as one of the
/// 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
/// 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
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
// 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
// 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
// is on g8, kingZone[WHITE] is a bitboard containing the squares f8, h8,
// f7, g7, h7, f6, g6 and h6.
Bitboard kingZone[2];
// kingAttackersCount[color] is the number of pieces of the given color
// which attack a square in the kingZone of the enemy king.
int kingAttackersCount[2];
// kingAttackersWeight[color] is the sum of the "weight" of the pieces of the
// given color which attack a square in the kingZone of the enemy king. The
// weights of the individual piece types are given by the variables
// QueenAttackWeight, RookAttackWeight, BishopAttackWeight and
// KnightAttackWeight in evaluate.cpp
int kingAttackersWeight[2];
// kingAdjacentZoneAttacksCount[color] is the number of attacks to squares
// directly adjacent to the king of the given color. Pieces which attack
// more than one square are counted multiple times. For instance, if black's
// king is on g8 and there's a white knight on g5, this knight adds
// 2 to kingAdjacentZoneAttacksCount[BLACK].
int kingAdjacentZoneAttacksCount[2];
// mateThreat[color] is a move for the given side which gives a direct mate.
Move mateThreat[2];
// Middle game and endgame mobility scores.
Score mobility;
// Extra futility margin. This is added to the standard futility margin
// in the quiescence search. One for each color.
Value futilityMargin[2];
};
////
//// Prototypes
////
extern Value evaluate(const Position& pos, EvalInfo& ei, int threadID);
extern Value evaluate(const Position& pos, Value& margin);
extern void init_eval(int threads);
extern void quit_eval();
extern void read_weights(Color sideToMove);
#endif // !defined(EVALUATE_H_INCLUDED)

View File

@@ -41,8 +41,8 @@ History::History() { clear(); }
/// History::clear() clears the history tables
void History::clear() {
memset(history, 0, 2 * 8 * 64 * sizeof(int));
memset(maxStaticValueDelta, 0, 2 * 8 * 64 * sizeof(int));
memset(history, 0, 16 * 64 * sizeof(int));
memset(maxStaticValueDelta, 0, 16 * 64 * sizeof(int));
}
@@ -85,31 +85,14 @@ void History::failure(Piece p, Square to, Depth d) {
}
/// 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, Square to) const {
assert(piece_is_ok(p));
assert(square_is_ok(to));
return history[p][to];
}
/// 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.
void History::set_gain(Piece p, Square to, Value delta)
{
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

@@ -49,7 +49,7 @@ public:
void clear();
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;
int value(Piece p, Square to) const;
void set_gain(Piece p, Square to, Value delta);
Value gain(Piece p, Square to) const;
@@ -71,7 +71,19 @@ private:
/// recently have a bigger importance for move ordering than the moves which
/// have been searched a long time ago.
const int HistoryMax = 50000 * OnePly;
const int HistoryMax = 50000 * ONE_PLY;
////
//// Inline functions
////
inline int History::value(Piece p, Square to) const {
return history[p][to];
}
inline Value History::gain(Piece p, Square to) const {
return Value(maxStaticValueDelta[p][to]);
}
#endif // !defined(HISTORY_H_INCLUDED)

View File

@@ -22,63 +22,13 @@
#define LOCK_H_INCLUDED
// 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
// best.
//#define ASM_LOCK
//#define OS_SPIN_LOCK
#if defined(ASM_LOCK)
typedef volatile int Lock;
static inline void LockX86(Lock *lock) {
int dummy;
asm __volatile__("1: movl $1, %0" "\n\t"
" xchgl (%1), %0" "\n\t" " testl %0, %0" "\n\t"
" jz 3f" "\n\t" "2: pause" "\n\t"
" movl (%1), %0" "\n\t" " testl %0, %0" "\n\t"
" jnz 2b" "\n\t" " jmp 1b" "\n\t" "3:"
"\n\t":"=&q"(dummy)
:"q"(lock)
:"cc");
}
static inline void UnlockX86(Lock *lock) {
int dummy;
asm __volatile__("movl $0, (%1)":"=&q"(dummy)
:"q"(lock));
}
# define lock_init(x, y) (*(x) = 0)
# define lock_grab(x) LockX86(x)
# define lock_release(x) UnlockX86(x)
# define lock_destroy(x)
#elif defined(OS_SPIN_LOCK)
# include <libkern/OSAtomic.h>
typedef OSSpinLock Lock;
# define lock_init(x, y) (*(x) = 0)
# define lock_grab(x) OSSpinLockLock(x)
# define lock_release(x) OSSpinLockUnlock(x)
# define lock_destroy(x)
#elif !defined(_MSC_VER)
#if !defined(_MSC_VER)
# include <pthread.h>
typedef pthread_mutex_t Lock;
# define lock_init(x, y) pthread_mutex_init(x, y)
# define lock_init(x) pthread_mutex_init(x, NULL)
# define lock_grab(x) pthread_mutex_lock(x)
# define lock_release(x) pthread_mutex_unlock(x)
# define lock_destroy(x) pthread_mutex_destroy(x)
@@ -91,7 +41,7 @@ typedef pthread_mutex_t Lock;
#undef WIN32_LEAN_AND_MEAN
typedef CRITICAL_SECTION Lock;
# define lock_init(x, y) InitializeCriticalSection(x)
# define lock_init(x) InitializeCriticalSection(x)
# define lock_grab(x) EnterCriticalSection(x)
# define lock_release(x) LeaveCriticalSection(x)
# define lock_destroy(x) DeleteCriticalSection(x)

View File

@@ -57,8 +57,19 @@ int main(int argc, char *argv[]) {
CALLGRIND_START_INSTRUMENTATION;
#endif
// Process command line arguments if any
if (argc > 1)
if (argc <= 1)
{
// Print copyright notice
cout << engine_name()
<< " by Tord Romstad, Marco Costalba, Joona Kiiski" << endl;
if (CpuHasPOPCNT)
cout << "Good! CPU has hardware POPCNT." << endl;
// Enter UCI mode
uci_main_loop();
}
else // Process command line arguments
{
if (string(argv[1]) != "bench" || argc < 4 || argc > 8)
cout << "Usage: stockfish bench <hash size> <threads> "
@@ -68,22 +79,13 @@ int main(int argc, char *argv[]) {
else
{
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] : "";
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);
}
return 0;
}
// Print copyright notice
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();
Application::free_resources();
return 0;
}

View File

@@ -23,6 +23,7 @@
////
#include <cassert>
#include <cstring>
#include <sstream>
#include <map>
@@ -55,17 +56,42 @@ namespace {
{ 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;
typedef map<Key, EF*> EFMap;
typedef map<Key, SF*> SFMap;
// Endgame evaluation and scaling functions accessed direcly and not through
// the function maps because correspond to more then one material hash key.
EvaluationFunction<KmmKm> EvaluateKmmKm[] = { EvaluationFunction<KmmKm>(WHITE), EvaluationFunction<KmmKm>(BLACK) };
EvaluationFunction<KXK> EvaluateKXK[] = { EvaluationFunction<KXK>(WHITE), EvaluationFunction<KXK>(BLACK) };
ScalingFunction<KBPsK> ScaleKBPsK[] = { ScalingFunction<KBPsK>(WHITE), ScalingFunction<KBPsK>(BLACK) };
ScalingFunction<KQKRPs> ScaleKQKRPs[] = { ScalingFunction<KQKRPs>(WHITE), ScalingFunction<KQKRPs>(BLACK) };
ScalingFunction<KPsK> ScaleKPsK[] = { ScalingFunction<KPsK>(WHITE), ScalingFunction<KPsK>(BLACK) };
ScalingFunction<KPKP> ScaleKPKP[] = { ScalingFunction<KPKP>(WHITE), ScalingFunction<KPKP>(BLACK) };
// Helper templates used to detect a given material distribution
template<Color Us> bool is_KXK(const Position& pos) {
const Color Them = (Us == WHITE ? BLACK : WHITE);
return pos.non_pawn_material(Them) == VALUE_ZERO
&& pos.piece_count(Them, PAWN) == 0
&& pos.non_pawn_material(Us) >= RookValueMidgame;
}
template<Color Us> bool is_KBPsK(const Position& pos) {
return pos.non_pawn_material(Us) == BishopValueMidgame
&& pos.piece_count(Us, BISHOP) == 1
&& pos.piece_count(Us, PAWN) >= 1;
}
template<Color Us> bool is_KQKRPs(const Position& pos) {
const Color Them = (Us == WHITE ? BLACK : WHITE);
return pos.piece_count(Us, PAWN) == 0
&& pos.non_pawn_material(Us) == QueenValueMidgame
&& pos.piece_count(Us, QUEEN) == 1
&& pos.piece_count(Them, ROOK) == 1
&& pos.piece_count(Them, PAWN) >= 1;
}
}
@@ -90,21 +116,17 @@ private:
static Key buildKey(const string& keyCode);
static const string swapColors(const string& keyCode);
// Here we store two maps, for evaluate and scaling functions
pair<map<Key, EF*>, map<Key, SF*> > maps;
// Here we store two maps, for evaluate and scaling functions...
pair<EFMap, SFMap> 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; }
// ...and here is the accessing template function
template<typename T> const map<Key, T*>& get() const;
};
// 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; }
template<> const EFMap& EndgameFunctions::get<EF>() const { return maps.first; }
template<> const SFMap& EndgameFunctions::get<SF>() const { return maps.second; }
////
@@ -113,15 +135,14 @@ EndgameFunctions::get<SF>() { return maps.second; }
/// MaterialInfoTable c'tor and d'tor, called once by each thread
MaterialInfoTable::MaterialInfoTable(unsigned int numOfEntries) {
MaterialInfoTable::MaterialInfoTable() {
size = numOfEntries;
entries = new MaterialInfo[size];
entries = new MaterialInfo[MaterialTableSize];
funcs = new EndgameFunctions();
if (!entries || !funcs)
{
cerr << "Failed to allocate " << numOfEntries * sizeof(MaterialInfo)
cerr << "Failed to allocate " << MaterialTableSize * sizeof(MaterialInfo)
<< " bytes for material hash table." << endl;
Application::exit_with_failure();
}
@@ -144,7 +165,8 @@ Phase MaterialInfoTable::game_phase(const Position& pos) {
if (npm >= MidgameLimit)
return PHASE_MIDGAME;
else if (npm <= EndgameLimit)
if (npm <= EndgameLimit)
return PHASE_ENDGAME;
return Phase(((npm - EndgameLimit) * 128) / (MidgameLimit - EndgameLimit));
@@ -159,7 +181,7 @@ Phase MaterialInfoTable::game_phase(const Position& pos) {
MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) {
Key key = pos.get_material_key();
int index = key & (size - 1);
unsigned index = unsigned(key & (MaterialTableSize - 1));
MaterialInfo* mi = entries + index;
// If mi->key matches the position's material hash key, it means that we
@@ -169,7 +191,8 @@ MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) {
return mi;
// Clear the MaterialInfo object, and set its key
mi->clear();
memset(mi, 0, sizeof(MaterialInfo));
mi->factor[WHITE] = mi->factor[BLACK] = uint8_t(SCALE_FACTOR_NORMAL);
mi->key = key;
// Store game phase
@@ -181,23 +204,15 @@ MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) {
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) >= RookValueMidgame)
if (is_KXK<WHITE>(pos) || is_KXK<BLACK>(pos))
{
mi->evaluationFunction = &EvaluateKXK;
mi->evaluationFunction = is_KXK<WHITE>(pos) ? &EvaluateKXK[WHITE] : &EvaluateKXK[BLACK];
return mi;
}
else if ( pos.non_pawn_material(WHITE) == Value(0)
&& pos.piece_count(WHITE, PAWN) == 0
&& pos.non_pawn_material(BLACK) >= RookValueMidgame)
{
mi->evaluationFunction = &EvaluateKKX;
return mi;
}
else if ( pos.pieces(PAWN) == EmptyBoardBB
&& pos.pieces(ROOK) == EmptyBoardBB
&& pos.pieces(QUEEN) == EmptyBoardBB)
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. Note that the case KmmK is already handled by KXK.
@@ -207,7 +222,7 @@ MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) {
if ( pos.piece_count(WHITE, BISHOP) + pos.piece_count(WHITE, KNIGHT) <= 2
&& pos.piece_count(BLACK, BISHOP) + pos.piece_count(BLACK, KNIGHT) <= 2)
{
mi->evaluationFunction = &EvaluateKmmKm;
mi->evaluationFunction = &EvaluateKmmKm[WHITE];
return mi;
}
}
@@ -215,10 +230,8 @@ MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) {
// OK, we didn't find any special evaluation function for the current
// 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
// are several conflicting applicable scaling functions and we need to
// decide which one to use.
// We face problems when there are several conflicting applicable
// scaling functions and we need to decide which one to use.
SF* sf;
if ((sf = funcs->get<SF>(key)) != NULL)
@@ -230,48 +243,36 @@ MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) {
// 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] = &ScaleKBPsK;
if (is_KBPsK<WHITE>(pos))
mi->scalingFunction[WHITE] = &ScaleKBPsK[WHITE];
if ( pos.non_pawn_material(BLACK) == BishopValueMidgame
&& pos.piece_count(BLACK, BISHOP) == 1
&& pos.piece_count(BLACK, PAWN) >= 1)
mi->scalingFunction[BLACK] = &ScaleKKBPs;
if (is_KBPsK<BLACK>(pos))
mi->scalingFunction[BLACK] = &ScaleKBPsK[BLACK];
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] = &ScaleKQKRPs;
if (is_KQKRPs<WHITE>(pos))
mi->scalingFunction[WHITE] = &ScaleKQKRPs[WHITE];
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] = &ScaleKRPsKQ;
else if (is_KQKRPs<BLACK>(pos))
mi->scalingFunction[BLACK] = &ScaleKQKRPs[BLACK];
if (pos.non_pawn_material(WHITE) + pos.non_pawn_material(BLACK) == Value(0))
if (pos.non_pawn_material(WHITE) + pos.non_pawn_material(BLACK) == VALUE_ZERO)
{
if (pos.piece_count(BLACK, PAWN) == 0)
{
assert(pos.piece_count(WHITE, PAWN) >= 2);
mi->scalingFunction[WHITE] = &ScaleKPsK;
mi->scalingFunction[WHITE] = &ScaleKPsK[WHITE];
}
else if (pos.piece_count(WHITE, PAWN) == 0)
{
assert(pos.piece_count(BLACK, PAWN) >= 2);
mi->scalingFunction[BLACK] = &ScaleKKPs;
mi->scalingFunction[BLACK] = &ScaleKPsK[BLACK];
}
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;
mi->scalingFunction[WHITE] = &ScaleKPKP[WHITE];
mi->scalingFunction[BLACK] = &ScaleKPKP[BLACK];
}
}
@@ -332,9 +333,9 @@ MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) {
// Second-degree polynomial material imbalance by Tord Romstad
//
// We use NO_PIECE_TYPE as a place holder for the bishop pair "extended piece",
// We use PIECE_TYPE_NONE 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++)
for (pt1 = PIECE_TYPE_NONE; pt1 <= QUEEN; pt1++)
{
pc = pieceCount[c][pt1];
if (!pc)
@@ -342,7 +343,7 @@ MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) {
vv = LinearCoefficients[pt1];
for (pt2 = NO_PIECE_TYPE; pt2 <= pt1; pt2++)
for (pt2 = PIECE_TYPE_NONE; pt2 <= pt1; pt2++)
vv += pieceCount[c][pt2] * QuadraticCoefficientsSameColor[pt1][pt2]
+ pieceCount[them][pt2] * QuadraticCoefficientsOppositeColor[pt1][pt2];
@@ -378,11 +379,11 @@ EndgameFunctions::EndgameFunctions() {
EndgameFunctions::~EndgameFunctions() {
for (map<Key, EF*>::iterator it = maps.first.begin(); it != maps.first.end(); ++it)
delete (*it).second;
for (EFMap::const_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;
for (SFMap::const_iterator it = maps.second.begin(); it != maps.second.end(); ++it)
delete it->second;
}
Key EndgameFunctions::buildKey(const string& keyCode) {
@@ -400,10 +401,10 @@ Key EndgameFunctions::buildKey(const string& keyCode) {
if (keyCode[i] == 'K')
upcase = !upcase;
s << char(upcase? toupper(keyCode[i]) : tolower(keyCode[i]));
s << char(upcase ? toupper(keyCode[i]) : tolower(keyCode[i]));
}
s << 8 - keyCode.length() << "/8/8/8/8/8/8/8 w -";
return Position(s.str()).get_material_key();
s << 8 - keyCode.length() << "/8/8/8/8/8/8/8 w - -";
return Position(s.str(), 0).get_material_key();
}
const string EndgameFunctions::swapColors(const string& keyCode) {
@@ -417,14 +418,15 @@ template<class T>
void EndgameFunctions::add(const string& keyCode) {
typedef typename T::Base F;
typedef map<Key, F*> M;
get<F>().insert(pair<Key, F*>(buildKey(keyCode), new T(WHITE)));
get<F>().insert(pair<Key, F*>(buildKey(swapColors(keyCode)), new T(BLACK)));
const_cast<M&>(get<F>()).insert(pair<Key, F*>(buildKey(keyCode), new T(WHITE)));
const_cast<M&>(get<F>()).insert(pair<Key, F*>(buildKey(swapColors(keyCode)), new T(BLACK)));
}
template<class T>
T* EndgameFunctions::get(Key key) const {
typename map<Key, T*>::const_iterator it(get<T>().find(key));
return (it != get<T>().end() ? it->second : NULL);
typename map<Key, T*>::const_iterator it = get<T>().find(key);
return it != get<T>().end() ? it->second : NULL;
}

View File

@@ -27,13 +27,14 @@
#include "endgame.h"
#include "position.h"
#include "scale.h"
////
//// Types
////
const int MaterialTableSize = 1024;
/// MaterialInfo is a class which contains various information about a
/// material configuration. It contains a material balance evaluation,
/// a function pointer to a special endgame evaluation function (which in
@@ -49,8 +50,6 @@ class MaterialInfo {
friend class MaterialInfoTable;
public:
MaterialInfo() : key(0) { clear(); }
Score material_value() const;
ScaleFactor scale_factor(const Position& pos, Color c) const;
int space_weight() const;
@@ -59,8 +58,6 @@ public:
Value evaluate(const Position& pos) const;
private:
inline void clear();
Key key;
int16_t value;
uint8_t factor[2];
@@ -79,14 +76,13 @@ class EndgameFunctions;
class MaterialInfoTable {
public:
MaterialInfoTable(unsigned numOfEntries);
MaterialInfoTable();
~MaterialInfoTable();
MaterialInfo* get_material_info(const Position& pos);
static Phase game_phase(const Position& pos);
private:
unsigned size;
MaterialInfo* entries;
EndgameFunctions* funcs;
};
@@ -105,20 +101,6 @@ inline Score MaterialInfo::material_value() const {
return make_score(value, value);
}
/// MaterialInfo::clear() resets a MaterialInfo object to an empty state,
/// with all slots at their default values but the key.
inline void MaterialInfo::clear() {
value = 0;
factor[WHITE] = factor[BLACK] = uint8_t(SCALE_FACTOR_NORMAL);
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
/// position in addition to the color, because the scale factor need not

View File

@@ -41,109 +41,131 @@
email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space)
*/
#include "types.h"
#include "mersenne.h"
/* Period parameters */
#define N 624
#define M 397
#define MATRIX_A 0x9908b0dfUL /* constant vector a */
#define UPPER_MASK 0x80000000UL /* most significant w-r bits */
#define LOWER_MASK 0x7fffffffUL /* least significant r bits */
namespace {
static unsigned long mt[N]; /* the array for the state vector */
static int mti=N+1; /* mti==N+1 means mt[N] is not initialized */
// Period parameters
const int N = 624;
const int M = 397;
const unsigned long MATRIX_A = 0x9908b0dfUL; // Constant vector a
const unsigned long UPPER_MASK = 0x80000000UL; // Most significant w-r bits
const unsigned long LOWER_MASK = 0x7fffffffUL; // Least significant r bits
/* initializes mt[N] with a seed */
static void init_genrand(unsigned long s)
{
mt[0]= s & 0xffffffffUL;
for (mti=1; mti<N; mti++) {
mt[mti] =
(1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti);
/* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
/* In the previous versions, MSBs of the seed affect */
/* only MSBs of the array mt[]. */
/* 2002/01/09 modified by Makoto Matsumoto */
mt[mti] &= 0xffffffffUL;
/* for >32 bit machines */
}
}
unsigned long mt[N]; // The array for the state vector
int mti = N + 1; // mti == N+1 means mt[N] is not initialized
/* initialize by an array with array-length */
/* init_key is the array for initializing keys */
/* key_length is its length */
/* slight change for C++, 2004/2/26 */
static void init_by_array(unsigned long init_key[], int key_length)
{
int i, j, k;
init_genrand(19650218UL);
i=1; j=0;
k = (N>key_length ? N : key_length);
for (; k; k--) {
mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525UL))
+ init_key[j] + j; /* non linear */
mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
i++; j++;
if (i>=N) { mt[0] = mt[N-1]; i=1; }
if (j>=key_length) j=0;
}
for (k=N-1; k; k--) {
mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941UL))
- i; /* non linear */
mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
i++;
if (i>=N) { mt[0] = mt[N-1]; i=1; }
}
// Initializes mt[N] with a seed
void init_genrand(unsigned long s) {
mt[0] = 0x80000000UL; /* MSB is 1; assuring non-zero initial array */
}
mt[0]= s & 0xffffffffUL;
for (mti = 1; mti < N; mti++)
{
// See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier.
// In the previous versions, MSBs of the seed affect
// only MSBs of the array mt[].
// 2002/01/09 modified by Makoto Matsumoto
mt[mti] = 1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti;
mt[mti] &= 0xffffffffUL; // For > 32 bit machines
}
}
// Initialize by an array with array-length
// init_key is the array for initializing keys
// key_length is its length
// slight change for C++, 2004/2/26
void init_by_array(unsigned long init_key[], int key_length) {
int i = 1;
int j = 0;
int k = (N > key_length ? N : key_length);
init_genrand(19650218UL);
for ( ; k; k--)
{
mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525UL)) + init_key[j] + j; // Non linear
mt[i] &= 0xffffffffUL; // For WORDSIZE > 32 machines
i++; j++;
if (i >= N)
{
mt[0] = mt[N-1];
i = 1;
}
if (j >= key_length)
j = 0;
}
for (k = N-1; k; k--)
{
mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941UL)) - i; // Non linear
mt[i] &= 0xffffffffUL; // For WORDSIZE > 32 machines
i++;
if (i >= N)
{
mt[0] = mt[N-1];
i = 1;
}
}
mt[0] = 0x80000000UL; // MSB is 1; assuring non-zero initial array
}
} // namespace
// Generates a random number on [0,0xffffffff]-interval
uint32_t genrand_int32() {
/* generates a random number on [0,0xffffffff]-interval */
uint32_t genrand_int32(void) {
unsigned long y;
static unsigned long mag01[2]={0x0UL, MATRIX_A};
static unsigned long mag01[2] = {0x0UL, MATRIX_A};
/* mag01[x] = x * MATRIX_A for x=0,1 */
if (mti >= N) { /* generate N words at one time */
int kk;
// Generate N words at one time
if (mti >= N)
{
int kk;
if (mti == N+1) /* if init_genrand() has not been called, */
init_genrand(5489UL); /* a default initial seed is used */
if (mti == N+1) // If init_genrand() has not been called,
init_genrand(5489UL); // a default initial seed is used.
for (kk=0;kk<N-M;kk++) {
y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
mt[kk] = mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1UL];
}
for (;kk<N-1;kk++) {
y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
mt[kk] = mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1UL];
}
y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK);
mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1UL];
mti = 0;
for (kk = 0; kk < N-M; kk++)
{
y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
mt[kk] = mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1UL];
}
for ( ; kk < N-1; kk++)
{
y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
mt[kk] = mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1UL];
}
y = (mt[N-1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1UL];
mti = 0;
}
y = mt[mti++];
/* Tempering */
// Tempering
y ^= (y >> 11);
y ^= (y << 7) & 0x9d2c5680UL;
y ^= (y << 7) & 0x9d2c5680UL;
y ^= (y << 15) & 0xefc60000UL;
y ^= (y >> 18);
return y;
}
uint64_t genrand_int64(void) {
uint64_t genrand_int64() {
uint64_t x, y;
x = genrand_int32(); y = genrand_int32();
return (x<<32)|y;
x = genrand_int32();
y = genrand_int32();
return (x << 32) | y;
}
void init_mersenne(void) {
unsigned long init[4]={0x123, 0x234, 0x345, 0x456}, length=4;
void init_mersenne() {
unsigned long init[4] = {0x123, 0x234, 0x345, 0x456};
unsigned long length = 4;
init_by_array(init, length);
}

View File

@@ -32,9 +32,9 @@
//// Prototypes
////
extern uint32_t genrand_int32(void);
extern uint64_t genrand_int64(void);
extern void init_mersenne(void);
extern uint32_t genrand_int32();
extern uint64_t genrand_int64();
extern void init_mersenne();
#endif // !defined(MERSENNE_H_INCLUDED)

View File

@@ -39,6 +39,10 @@
#endif
#if !defined(NO_PREFETCH)
# include <xmmintrin.h>
#endif
#include <cassert>
#include <cstdio>
#include <iomanip>
@@ -54,7 +58,7 @@ 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.7.1";
static const string EngineVersion = "1.9.1";
static const string AppName = "Stockfish";
static const string AppTag = "";
@@ -63,8 +67,6 @@ static const string AppTag = "";
//// Variables
////
bool Chess960;
uint64_t dbg_cnt0 = 0;
uint64_t dbg_cnt1 = 0;
@@ -144,10 +146,10 @@ void dbg_print_mean(ofstream& logFile) {
const string engine_name() {
const string cpu64(CpuHas64BitPath ? " 64bit" : "");
const string cpu64(CpuIs64Bit ? " 64bit" : "");
if (!EngineVersion.empty())
return AppName+ " " + EngineVersion + cpu64;
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");
@@ -287,4 +289,27 @@ int Bioskey()
return 0;
}
}
#endif
/// prefetch() preloads the given address 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.
#if defined(NO_PREFETCH)
void prefetch(char*) {}
#else
void prefetch(char* addr) {
#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
_mm_prefetch(addr, _MM_HINT_T2);
_mm_prefetch(addr+64, _MM_HINT_T2); // 64 bytes ahead
}
#endif

View File

@@ -40,13 +40,6 @@
#define Max(x, y) (((x) < (y))? (y) : (x))
////
//// Variables
////
extern bool Chess960;
////
//// Prototypes
////
@@ -55,6 +48,8 @@ extern const std::string engine_name();
extern int get_system_time();
extern int cpu_count();
extern int Bioskey();
extern void prefetch(char* addr);
extern void prefetchPawn(Key, int);
////

View File

@@ -104,11 +104,11 @@ Move move_from_string(const Position& pos, const std::string& str) {
/// move_to_string() converts a move to a string in coordinate notation
/// (g1f3, a7a8q, etc.). The only special case is castling moves, where we
/// (g1f3, a7a8q, etc.). The only special case is castling moves, where we
/// print in the e1g1 notation in normal chess mode, and in e1h1 notation in
/// Chess960 mode.
const std::string move_to_string(Move move) {
const std::string move_to_string(Move move, bool chess960) {
std::string str;
Square from = move_from(move);
@@ -120,14 +120,12 @@ const std::string move_to_string(Move move) {
str = "0000";
else
{
if (!Chess960)
{
if (move_is_short_castle(move))
return (from == SQ_E1 ? "e1g1" : "e8g8");
if (move_is_short_castle(move) && !chess960)
return (from == SQ_E1 ? "e1g1" : "e8g8");
if (move_is_long_castle(move) && !chess960)
return (from == SQ_E1 ? "e1c1" : "e8c8");
if (move_is_long_castle(move))
return (from == SQ_E1 ? "e1c1" : "e8c8");
}
str = square_to_string(from) + square_to_string(to);
if (move_is_promotion(move))
str += piece_type_to_char(move_promotion_piece(move), false);
@@ -138,9 +136,10 @@ const std::string move_to_string(Move move) {
/// Overload the << operator, to make it easier to print moves.
std::ostream &operator << (std::ostream& os, Move m) {
std::ostream& operator << (std::ostream& os, Move m) {
return os << move_to_string(m);
bool chess960 = (os.iword(0) != 0); // See set960()
return os << move_to_string(m, chess960);
}

View File

@@ -101,11 +101,11 @@ inline void sort_moves(T* firstMove, T* lastMove, T** lastPositive)
// Split positives vs non-positives
do {
while ((++p)->score > 0);
while ((++p)->score > 0) {}
if (p != d)
{
while (--d != p && d->score <= 0);
while (--d != p && d->score <= 0) {}
tmp = *p;
*p = *d;
@@ -201,9 +201,9 @@ inline Move make_ep_move(Square from, Square to) {
//// Prototypes
////
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 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, bool chess960);
extern bool move_is_ok(Move m);

View File

@@ -140,6 +140,32 @@ MoveStack* generate_noncaptures(const Position& pos, MoveStack* mlist) {
}
/// generate_non_evasions() generates all pseudo-legal captures and
/// non-captures. Returns a pointer to the end of the move list.
MoveStack* generate_non_evasions(const Position& pos, MoveStack* mlist) {
assert(pos.is_ok());
assert(!pos.is_check());
Color us = pos.side_to_move();
Bitboard target = pos.pieces_of_color(opposite_color(us));
mlist = generate_piece_moves<PAWN, CAPTURE>(pos, mlist, us, target);
mlist = generate_piece_moves<PAWN, NON_CAPTURE>(pos, mlist, us, pos.empty_squares());
target |= pos.empty_squares();
mlist = generate_piece_moves<KNIGHT>(pos, mlist, us, target);
mlist = generate_piece_moves<BISHOP>(pos, mlist, us, target);
mlist = generate_piece_moves<ROOK>(pos, mlist, us, target);
mlist = generate_piece_moves<QUEEN>(pos, mlist, us, target);
mlist = generate_piece_moves<KING>(pos, mlist, us, target);
mlist = generate_castle_moves<KING_SIDE>(pos, mlist);
return generate_castle_moves<QUEEN_SIDE>(pos, mlist);
}
/// generate_non_capture_checks() generates all pseudo-legal non-captures and knight
/// underpromotions that give check. Returns a pointer to the end of the move list.
@@ -260,11 +286,8 @@ MoveStack* generate_moves(const Position& pos, MoveStack* mlist, bool pseudoLega
Bitboard pinned = pos.pinned_pieces(pos.side_to_move());
// Generate pseudo-legal moves
if (pos.is_check())
last = generate_evasions(pos, mlist);
else
last = generate_noncaptures(pos, generate_captures(pos, mlist));
last = pos.is_check() ? generate_evasions(pos, mlist)
: generate_non_evasions(pos, mlist);
if (pseudoLegal)
return last;
@@ -312,7 +335,7 @@ bool move_is_legal(const Position& pos, const Move m, Bitboard pinned) {
Piece pc = pos.piece_on(from);
// Use a slower but simpler function for uncommon cases
if (move_is_ep(m) || move_is_castle(m))
if (move_is_special(m))
return move_is_legal(pos, m);
// If the from square is not occupied by a piece belonging to the side to
@@ -332,10 +355,9 @@ bool move_is_legal(const Position& pos, const Move m, Bitboard pinned) {
if ((us == WHITE) != (direction > 0))
return false;
// A pawn move is a promotion iff the destination square is
// on the 8/1th rank.
if (( (square_rank(to) == RANK_8 && us == WHITE)
||(square_rank(to) == RANK_1 && us != WHITE)) != bool(move_is_promotion(m)))
// We have already handled promotion moves, so destination
// cannot be on the 8/1th rank.
if (square_rank(to) == RANK_8 || square_rank(to) == RANK_1)
return false;
// Proceed according to the square delta between the origin and
@@ -382,14 +404,12 @@ bool move_is_legal(const Position& pos, const Move m, Bitboard pinned) {
default:
return false;
}
// The move is pseudo-legal, check if it is also legal
return pos.is_check() ? pos.pl_move_is_evasion(m, pinned) : pos.pl_move_is_legal(m, pinned);
}
else if (!bit_is_set(pos.attacks_from(pc, from), to))
return false;
// Luckly we can handle all the other pieces in one go
return bit_is_set(pos.attacks_from(pc, from), to)
&& (pos.is_check() ? pos.pl_move_is_evasion(m, pinned) : pos.pl_move_is_legal(m, pinned))
&& !move_is_promotion(m);
// The move is pseudo-legal, check if it is also legal
return pos.is_check() ? pos.pl_move_is_evasion(m, pinned) : pos.pl_move_is_legal(m, pinned);
}
@@ -402,10 +422,13 @@ namespace {
Square from;
const Square* ptr = pos.piece_list_begin(us, Piece);
while ((from = *ptr++) != SQ_NONE)
if (*ptr != SQ_NONE)
{
b = pos.attacks_from<Piece>(from) & target;
SERIALIZE_MOVES(b);
do {
from = *ptr;
b = pos.attacks_from<Piece>(from) & target;
SERIALIZE_MOVES(b);
} while (*++ptr != SQ_NONE);
}
return mlist;
}

View File

@@ -36,6 +36,7 @@ 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_non_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);

View File

@@ -70,18 +70,18 @@ namespace {
/// search captures, promotions and some checks) and about how important good
/// move ordering is at the current node.
MovePicker::MovePicker(const Position& p, Move ttm, Depth d,
const History& h, SearchStack* ss, Value beta) : pos(p), H(h) {
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;
badCaptures = moves + 256;
pinned = p.pinned_pieces(pos.side_to_move());
if (ss && !p.is_check())
{
ttMoves[1].move = (ss->mateKiller == ttm)? MOVE_NONE : ss->mateKiller;
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];
@@ -90,15 +90,16 @@ MovePicker::MovePicker(const Position& p, Move ttm, Depth d,
if (p.is_check())
phasePtr = EvasionsPhaseTable;
else if (d > Depth(0))
else if (d > DEPTH_ZERO)
{
// Consider sligtly negative captures as good if at low
// depth and far from beta.
if (ss && ss->eval < beta - PawnValueMidgame && d < 3 * OnePly)
if (ss && ss->eval < beta - PawnValueMidgame && d < 3 * ONE_PLY)
badCaptureThreshold = -PawnValueMidgame;
phasePtr = MainSearchPhaseTable;
} else if (d == Depth(0))
}
else if (d == DEPTH_ZERO)
phasePtr = QsearchWithChecksPhaseTable;
else
{
@@ -111,7 +112,7 @@ MovePicker::MovePicker(const Position& p, Move ttm, Depth d,
searchTT = ttMoves[0].move = MOVE_NONE;
}
phasePtr += !searchTT - 1;
phasePtr += int(!searchTT) - 1;
go_next_phase();
}
@@ -147,16 +148,16 @@ void MovePicker::go_next_phase() {
return;
case PH_BAD_CAPTURES:
// Bad captures SEE value is already calculated so just sort them
// to get SEE move ordering.
// Bad captures SEE value is already calculated so just pick
// them in order to get SEE move ordering.
curMove = badCaptures;
lastMove = lastBadCapture;
lastMove = moves + 256;
return;
case PH_EVASIONS:
assert(pos.is_check());
lastMove = generate_evasions(pos, moves);
score_evasions_or_checks();
score_evasions();
return;
case PH_QCAPTURES:
@@ -166,7 +167,6 @@ void MovePicker::go_next_phase() {
case PH_QCHECKS:
lastMove = generate_non_capture_checks(pos, moves);
score_evasions_or_checks();
return;
case PH_STOP:
@@ -220,7 +220,6 @@ void MovePicker::score_noncaptures() {
Move m;
Piece piece;
Square from, to;
int hs;
for (MoveStack* cur = moves; cur != lastMove; cur++)
{
@@ -228,18 +227,11 @@ void MovePicker::score_noncaptures() {
from = move_from(m);
to = move_to(m);
piece = pos.piece_on(from);
hs = H.move_ordering_score(piece, to);
// Ensure history has always highest priority
if (hs > 0)
hs += 10000;
// Gain table based scoring
cur->score = hs + 16 * H.gain(piece, to);
cur->score = H.value(piece, to) + H.gain(piece, to);
}
}
void MovePicker::score_evasions_or_checks() {
void MovePicker::score_evasions() {
// Try good captures ordered by MVV/LVA, then non-captures if
// destination square is not under attack, ordered by history
// value, and at the end bad-captures and non-captures with a
@@ -260,7 +252,7 @@ void MovePicker::score_evasions_or_checks() {
cur->score = pos.midgame_value_of_piece_on(move_to(m))
- pos.type_of_piece_on(move_from(m)) + HistoryMax;
else
cur->score = H.move_ordering_score(pos.piece_on(move_from(m)), move_to(m));
cur->score = H.value(pos.piece_on(move_from(m)), move_to(m));
}
}
@@ -300,21 +292,19 @@ Move MovePicker::get_next_move() {
if (seeValue >= badCaptureThreshold)
return move;
// Losing capture, move it to the badCaptures[] array, note
// Losing capture, move it to the tail of the array, note
// that move has now been already checked for legality.
assert(int(lastBadCapture - badCaptures) < 63);
lastBadCapture->move = move;
lastBadCapture->score = seeValue;
lastBadCapture++;
(--badCaptures)->move = move;
badCaptures->score = seeValue;
}
break;
case PH_KILLERS:
move = (curMove++)->move;
if ( move != MOVE_NONE
&& move_is_legal(pos, move, pinned)
&& move != ttMoves[0].move
&& move != ttMoves[1].move
&& move_is_legal(pos, move, pinned)
&& !pos.move_is_capture(move))
return move;
break;

View File

@@ -56,17 +56,17 @@ public:
private:
void score_captures();
void score_noncaptures();
void score_evasions_or_checks();
void score_evasions();
void go_next_phase();
const Position& pos;
const History& H;
Bitboard pinned;
MoveStack ttMoves[2], killers[2];
int badCaptureThreshold, phase;
const uint8_t* phasePtr;
MoveStack *curMove, *lastMove, *lastGoodNonCapture, *lastBadCapture;
Bitboard pinned;
MoveStack moves[256], badCaptures[64];
MoveStack *curMove, *lastMove, *lastGoodNonCapture, *badCaptures;
MoveStack moves[256];
};

View File

@@ -70,36 +70,7 @@ namespace {
S(34,68), S(83,166), S(0, 0), S( 0, 0)
};
// Pawn storm tables for positions with opposite castling
const int QStormTable[64] = {
0, 0, 0, 0, 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,-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] = { 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] = { -8, -8, -13, 0, 0, -13, -8, -8 };
#undef S
}
@@ -107,49 +78,38 @@ namespace {
//// Functions
////
/// Constructor
/// PawnInfoTable c'tor and d'tor instantiated one each thread
PawnInfoTable::PawnInfoTable(unsigned numOfEntries) {
PawnInfoTable::PawnInfoTable() {
entries = new PawnInfo[PawnTableSize];
size = numOfEntries;
entries = new PawnInfo[size];
if (!entries)
{
std::cerr << "Failed to allocate " << (numOfEntries * sizeof(PawnInfo))
std::cerr << "Failed to allocate " << (PawnTableSize * sizeof(PawnInfo))
<< " bytes for pawn hash table." << std::endl;
Application::exit_with_failure();
}
}
/// Destructor
PawnInfoTable::~PawnInfoTable() {
delete [] entries;
}
/// PawnInfo::clear() resets to zero the PawnInfo entry. Note that
/// kingSquares[] is initialized to SQ_NONE instead.
void PawnInfo::clear() {
memset(this, 0, sizeof(PawnInfo));
kingSquares[WHITE] = kingSquares[BLACK] = SQ_NONE;
}
/// PawnInfoTable::get_pawn_info() takes a position object as input, computes
/// a PawnInfo object, and returns a pointer to it. The result is also
/// stored in a hash table, so we don't have to recompute everything when
/// the same pawn structure occurs again.
/// a PawnInfo object, and returns a pointer to it. The result is also 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) const {
assert(pos.is_ok());
Key key = pos.get_pawn_key();
int index = int(key & (size - 1));
unsigned index = unsigned(key & (PawnTableSize - 1));
PawnInfo* pi = entries + index;
// If pi->key matches the position's pawn hash key, it means that we
@@ -159,7 +119,8 @@ PawnInfo* PawnInfoTable::get_pawn_info(const Position& pos) {
return pi;
// Clear the PawnInfo object, and set the key
pi->clear();
memset(pi, 0, sizeof(PawnInfo));
pi->kingSquares[WHITE] = pi->kingSquares[BLACK] = SQ_NONE;
pi->key = key;
// Calculate pawn attacks
@@ -179,113 +140,57 @@ PawnInfo* PawnInfoTable::get_pawn_info(const Position& pos) {
template<Color Us>
Score PawnInfoTable::evaluate_pawns(const Position& pos, Bitboard ourPawns,
Bitboard theirPawns, PawnInfo* pi) {
Bitboard theirPawns, PawnInfo* pi) const {
Bitboard b;
Square s;
File f;
Rank r;
bool passed, isolated, doubled, chain, backward, candidate;
int bonus;
Score value = make_score(0, 0);
bool passed, isolated, doubled, opposed, chain, backward, candidate;
Score value = SCORE_ZERO;
const BitCountType Max15 = CpuIs64Bit ? CNT64_MAX15 : CNT32_MAX15;
const Square* ptr = pos.piece_list_begin(Us, PAWN);
// Initialize pawn storm scores by giving bonuses for open files
// Initialize halfOpenFiles[]
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)
{
assert(pos.piece_on(s) == piece_of_color_and_type(Us, PAWN));
f = square_file(s);
r = square_rank(s);
assert(pos.piece_on(s) == piece_of_color_and_type(Us, PAWN));
// Our rank plus previous one. Used for chain detection.
b = rank_bb(r) | rank_bb(Us == WHITE ? r - Rank(1) : r + Rank(1));
// 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)));
// Passed, isolated, doubled or member of a pawn
// chain (but not the backward one) ?
passed = !(theirPawns & passed_pawn_mask(Us, s));
doubled = ourPawns & squares_behind(Us, s);
opposed = theirPawns & squares_in_front_of(Us, s);
isolated = !(ourPawns & neighboring_files_bb(f));
chain = ourPawns & neighboring_files_bb(f) & b;
// Test for backward pawn
//
backward = false;
// 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
if ( !(passed | isolated | chain)
&& !(ourPawns & attack_span_mask(opposite_color(Us), s))
&& !(pos.attacks_from<PAWN>(s, Us) & theirPawns))
{
// 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);
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.
@@ -297,12 +202,12 @@ Score PawnInfoTable::evaluate_pawns(const Position& pos, Bitboard ourPawns,
backward = (b | (Us == WHITE ? b << 8 : b >> 8)) & theirPawns;
}
assert(passed | opposed | (attack_span_mask(Us, s) & 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);
candidate = !(opposed | passed)
&& (b = attack_span_mask(opposite_color(Us), s + pawn_push(Us)) & ourPawns) != EmptyBoardBB
&& count_1s<Max15>(b) >= count_1s<Max15>(attack_span_mask(Us, s) & theirPawns);
// In order to prevent doubled passed pawns from receiving a too big
// bonus, only the frontmost passed pawn on each file is considered as
@@ -310,14 +215,16 @@ Score PawnInfoTable::evaluate_pawns(const Position& pos, Bitboard ourPawns,
if (passed && (ourPawns & squares_in_front_of(Us, s)))
passed = false;
// Score this pawn
// Mark the pawn as passed. Pawn will be properly scored in evaluation
// because we need full attack info to evaluate passed pawns.
if (passed)
set_bit(&(pi->passedPawns), s);
set_bit(&(pi->passedPawns[Us]), s);
// Score this pawn
if (isolated)
{
value -= IsolatedPawnPenalty[f];
if (!(theirPawns & file_bb(f)))
if (!opposed)
value -= IsolatedPawnPenalty[f] / 2;
}
if (doubled)
@@ -326,7 +233,7 @@ Score PawnInfoTable::evaluate_pawns(const Position& pos, Bitboard ourPawns,
if (backward)
{
value -= BackwardPawnPenalty[f];
if (!(theirPawns & file_bb(f)))
if (!opposed)
value -= BackwardPawnPenalty[f] / 2;
}
if (chain)
@@ -339,20 +246,3 @@ Score PawnInfoTable::evaluate_pawns(const Position& pos, Bitboard ourPawns,
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

@@ -26,49 +26,47 @@
////
#include "bitboard.h"
#include "position.h"
#include "value.h"
////
//// Types
////
const int PawnTableSize = 16384;
/// 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
/// (performed by calling the get_pawn_info method in a PawnInfoTable object)
/// returns a pointer to a PawnInfo object.
class Position;
class PawnInfo {
friend class PawnInfoTable;
public:
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;
Bitboard passed_pawns(Color c) 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);
template<Color Us>
Score king_shelter(const Position& pos, Square ksq);
private:
void clear();
int updateShelter(const Position& pos, Color c, Square ksq);
template<Color Us>
Score updateShelter(const Position& pos, Square ksq);
Key key;
Bitboard passedPawns;
Bitboard passedPawns[2];
Bitboard pawnAttacks[2];
Score value;
int16_t ksStormValue[2], qsStormValue[2];
uint8_t halfOpenFiles[2];
Square kingSquares[2];
uint8_t kingShelters[2];
Score value;
int halfOpenFiles[2];
Score kingShelters[2];
};
/// The PawnInfoTable class represents a pawn hash table. It is basically
@@ -78,16 +76,18 @@ private:
class PawnInfoTable {
enum SideType { KingSide, QueenSide };
public:
PawnInfoTable(unsigned numOfEntries);
PawnInfoTable();
~PawnInfoTable();
PawnInfo* get_pawn_info(const Position& pos);
PawnInfo* get_pawn_info(const Position& pos) const;
void prefetch(Key key) const;
private:
template<Color Us>
Score evaluate_pawns(const Position& pos, Bitboard ourPawns, Bitboard theirPawns, PawnInfo* pi);
Score evaluate_pawns(const Position& pos, Bitboard ourPawns, Bitboard theirPawns, PawnInfo* pi) const;
unsigned size;
PawnInfo* entries;
};
@@ -96,24 +96,23 @@ private:
//// Inline functions
////
inline Score PawnInfo::pawns_value() const {
return value;
inline void PawnInfoTable::prefetch(Key key) const {
unsigned index = unsigned(key & (PawnTableSize - 1));
PawnInfo* pi = entries + index;
::prefetch((char*) pi);
}
inline Bitboard PawnInfo::passed_pawns() const {
return passedPawns;
inline Score PawnInfo::pawns_value() const {
return value;
}
inline Bitboard PawnInfo::pawn_attacks(Color c) const {
return pawnAttacks[c];
}
inline Value PawnInfo::kingside_storm_value(Color c) const {
return Value(ksStormValue[c]);
}
inline Value PawnInfo::queenside_storm_value(Color c) const {
return Value(qsStormValue[c]);
inline Bitboard PawnInfo::passed_pawns(Color c) const {
return passedPawns[c];
}
inline int PawnInfo::file_is_half_open(Color c, File f) const {
@@ -128,8 +127,34 @@ inline int PawnInfo::has_open_file_to_right(Color c, File f) const {
return halfOpenFiles[c] & ~((1 << int(f+1)) - 1);
}
inline int PawnInfo::get_king_shelter(const Position& pos, Color c, Square ksq) {
return (kingSquares[c] == ksq ? kingShelters[c] : updateShelter(pos, c, ksq));
/// PawnInfo::updateShelter() calculates and caches king shelter. It is called
/// only when king square changes, about 20% of total king_shelter() calls.
template<Color Us>
Score PawnInfo::updateShelter(const Position& pos, Square ksq) {
const int Shift = (Us == WHITE ? 8 : -8);
Bitboard pawns;
int r, shelter = 0;
if (relative_rank(Us, ksq) <= RANK_4)
{
pawns = pos.pieces(PAWN, Us) & this_and_neighboring_files_bb(ksq);
r = square_rank(ksq) * 8;
for (int i = 1; i < 4; i++)
{
r += Shift;
shelter += BitCount8Bit[(pawns >> r) & 0xFF] * (128 >> i);
}
}
kingSquares[Us] = ksq;
kingShelters[Us] = make_score(shelter, 0);
return kingShelters[Us];
}
template<Color Us>
inline Score PawnInfo::king_shelter(const Position& pos, Square ksq) {
return kingSquares[Us] == ksq ? kingShelters[Us] : updateShelter<Us>(pos, ksq);
}
#endif // !defined(PAWNS_H_INCLUDED)

View File

@@ -28,6 +28,33 @@
using namespace std;
// Tables indexed by Piece
const Value PieceValueMidgame[17] = {
VALUE_ZERO,
PawnValueMidgame, KnightValueMidgame, BishopValueMidgame,
RookValueMidgame, QueenValueMidgame,
VALUE_ZERO, VALUE_ZERO, VALUE_ZERO,
PawnValueMidgame, KnightValueMidgame, BishopValueMidgame,
RookValueMidgame, QueenValueMidgame,
VALUE_ZERO, VALUE_ZERO, VALUE_ZERO
};
const Value PieceValueEndgame[17] = {
VALUE_ZERO,
PawnValueEndgame, KnightValueEndgame, BishopValueEndgame,
RookValueEndgame, QueenValueEndgame,
VALUE_ZERO, VALUE_ZERO, VALUE_ZERO,
PawnValueEndgame, KnightValueEndgame, BishopValueEndgame,
RookValueEndgame, QueenValueEndgame,
VALUE_ZERO, VALUE_ZERO, VALUE_ZERO
};
const int SlidingArray[18] = {
0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0
};
////
//// Functions
////
@@ -38,12 +65,12 @@ static const string PieceChars(" pnbrqk PNBRQK");
char piece_type_to_char(PieceType pt, bool upcase) {
return PieceChars[pt + upcase * 7];
return PieceChars[pt + int(upcase) * 7];
}
PieceType piece_type_from_char(char c) {
size_t idx = PieceChars.find(c);
return idx != string::npos ? PieceType(idx % 7) : NO_PIECE_TYPE;
return idx != string::npos ? PieceType(idx % 7) : PIECE_TYPE_NONE;
}

View File

@@ -27,6 +27,7 @@
#include "color.h"
#include "square.h"
#include "value.h"
////
@@ -34,39 +35,49 @@
////
enum PieceType {
NO_PIECE_TYPE = 0,
PIECE_TYPE_NONE = 0,
PAWN = 1, KNIGHT = 2, BISHOP = 3, ROOK = 4, QUEEN = 5, KING = 6
};
enum Piece {
NO_PIECE = 0, WP = 1, WN = 2, WB = 3, WR = 4, WQ = 5, WK = 6,
BP = 9, BN = 10, BB = 11, BR = 12, BQ = 13, BK = 14,
EMPTY = 16, OUTSIDE = 17
PIECE_NONE_DARK_SQ = 0, WP = 1, WN = 2, WB = 3, WR = 4, WQ = 5, WK = 6,
BP = 9, BN = 10, BB = 11, BR = 12, BQ = 13, BK = 14, PIECE_NONE = 16
};
ENABLE_OPERATORS_ON(PieceType);
ENABLE_OPERATORS_ON(Piece);
////
//// Constants
////
const int SlidingArray[18] = {
0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0
};
/// Important: If the material values are changed, one must also
/// adjust the piece square tables, and the method game_phase() in the
/// Position class!
///
/// Values modified by Joona Kiiski
const Value PawnValueMidgame = Value(0x0C6);
const Value PawnValueEndgame = Value(0x102);
const Value KnightValueMidgame = Value(0x331);
const Value KnightValueEndgame = Value(0x34E);
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);
extern const Value PieceValueMidgame[17];
extern const Value PieceValueEndgame[17];
extern const int SlidingArray[18];
////
//// Inline functions
////
inline Piece operator+ (Piece p, int i) { return Piece(int(p) + i); }
inline void operator++ (Piece &p, int) { p = Piece(int(p) + 1); }
inline Piece operator- (Piece p, int i) { return Piece(int(p) - i); }
inline void operator-- (Piece &p, int) { p = Piece(int(p) - 1); }
inline PieceType operator+ (PieceType p, int i) {return PieceType(int(p) + i);}
inline void operator++ (PieceType &p, int) { p = PieceType(int(p) + 1); }
inline PieceType operator- (PieceType p, int i) {return PieceType(int(p) - i);}
inline void operator-- (PieceType &p, int) { p = PieceType(int(p) - 1); }
inline PieceType type_of_piece(Piece p) {
return PieceType(int(p) & 7);
}
@@ -80,7 +91,7 @@ inline Piece piece_of_color_and_type(Color c, PieceType pt) {
}
inline int piece_is_slider(Piece p) {
return SlidingArray[int(p)];
return SlidingArray[p];
}
inline SquareDelta pawn_push(Color c) {

File diff suppressed because it is too large Load Diff

View File

@@ -50,9 +50,6 @@
//// Constants
////
/// 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).
@@ -68,22 +65,22 @@ const int MaxGameLength = 220;
struct CheckInfo {
CheckInfo(const Position&);
explicit CheckInfo(const Position&);
Square ksq;
Bitboard dcCandidates;
Bitboard checkSq[8];
Square ksq;
};
/// Castle rights, encoded as bit fields
enum CastleRights {
NO_CASTLES = 0,
WHITE_OO = 1,
BLACK_OO = 2,
WHITE_OOO = 4,
BLACK_OOO = 8,
ALL_CASTLES = 15
CASTLES_NONE = 0,
WHITE_OO = 1,
BLACK_OO = 2,
WHITE_OOO = 4,
BLACK_OOO = 8,
ALL_CASTLES = 15
};
/// Game phase
@@ -100,13 +97,13 @@ enum Phase {
struct StateInfo {
Key pawnKey, materialKey;
int castleRights, rule50, pliesFromNull;
int castleRights, rule50, gamePly, pliesFromNull;
Square epSquare;
Score value;
Value npMaterial[2];
PieceType capturedType;
Key key;
PieceType capture;
Bitboard checkersBB;
StateInfo* previous;
};
@@ -139,6 +136,9 @@ class Position {
friend class MaterialInfo;
friend class EndgameFunctions;
Position(); // No default or copy c'tor allowed
Position(const Position& pos);
public:
enum GamePhase {
MidGame,
@@ -146,9 +146,9 @@ public:
};
// Constructors
Position();
explicit Position(const Position& pos);
explicit Position(const std::string& fen);
explicit Position(int threadID);
Position(const Position& pos, int threadID);
Position(const std::string& fen, int threadID);
// Text input/output
void from_fen(const std::string& fen);
@@ -224,13 +224,10 @@ public:
bool move_attacks_square(Move m, Square s) const;
// Piece captured with previous moves
PieceType captured_piece() const;
PieceType captured_piece_type() const;
// Information about pawns
bool pawn_is_passed(Color c, Square s) 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;
@@ -246,7 +243,6 @@ public:
// Static exchange evaluation
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
@@ -258,25 +254,33 @@ public:
// Incremental evaluation
Score value() const;
Value non_pawn_material(Color c) const;
Score pst_delta(Piece piece, Square from, Square to) const;
static Score pst_delta(Piece piece, Square from, Square to);
// Game termination checks
bool is_mate() const;
bool is_draw() const;
// Check if one side threatens a mate in one
bool has_mate_threat(Color c);
// Check if side to move could be mated in one
bool has_mate_threat();
// Number of plies since the last non-reversible move
int rule_50_counter() const;
int startpos_ply_counter() const;
// Other properties of the position
bool opposite_colored_bishops() const;
bool has_pawn_on_7th(Color c) const;
bool is_chess960() const;
// Current thread ID searching on the position
int thread() const;
// Reset the gamePly variable to 0
void reset_game_ply();
void inc_startpos_ply_counter();
// Position consistency check, for debugging
bool is_ok(int* failedStep = NULL) const;
@@ -291,9 +295,10 @@ private:
void put_piece(Piece p, Square s);
void allow_oo(Color c);
void allow_ooo(Color c);
bool set_castling_rights(char token);
// Helper functions for doing and undoing moves
void do_capture_move(Bitboard& key, PieceType capture, Color them, Square to, bool ep);
void do_capture_move(Key& key, PieceType capture, Color them, Square to, bool ep);
void do_castle_move(Move m);
void undo_castle_move(Move m);
void find_checkers();
@@ -307,7 +312,7 @@ private:
Key compute_material_key() const;
// Computing incremental evaluation scores and material counts
Score pst(Color c, PieceType pt, Square s) const;
static Score pst(Color c, PieceType pt, Square s);
Score compute_value() const;
Value compute_non_pawn_material(Color c) const;
@@ -326,21 +331,23 @@ private:
// Other info
Color sideToMove;
int gamePly;
Key history[MaxGameLength];
int castleRightsMask[64];
File initialKFile, initialKRFile, initialQRFile;
StateInfo startState;
File initialKFile, initialKRFile, initialQRFile;
bool isChess960;
int startPosPlyCounter;
int threadID;
StateInfo* st;
// Static variables
static Key zobrist[2][8][64];
static Key zobEp[64];
static Key zobCastle[16];
static Key zobMaterial[2][8][16];
static Key zobSideToMove;
static Score PieceSquareTable[16][64];
static Key zobExclusion;
static const Value seeValues[8];
};
@@ -361,7 +368,7 @@ inline PieceType Position::type_of_piece_on(Square s) const {
}
inline bool Position::square_is_empty(Square s) const {
return piece_on(s) == EMPTY;
return piece_on(s) == PIECE_NONE;
}
inline bool Position::square_is_occupied(Square s) const {
@@ -369,11 +376,11 @@ inline bool Position::square_is_occupied(Square s) const {
}
inline Value Position::midgame_value_of_piece_on(Square s) const {
return piece_value_midgame(piece_on(s));
return PieceValueMidgame[piece_on(s)];
}
inline Value Position::endgame_value_of_piece_on(Square s) const {
return piece_value_endgame(piece_on(s));
return PieceValueEndgame[piece_on(s)];
}
inline Color Position::side_to_move() const {
@@ -412,8 +419,8 @@ inline int Position::piece_count(Color c, PieceType pt) const {
return pieceCount[c][pt];
}
inline Square Position::piece_list(Color c, PieceType pt, int index) const {
return pieceList[c][pt][index];
inline Square Position::piece_list(Color c, PieceType pt, int idx) const {
return pieceList[c][pt][idx];
}
inline const Square* Position::piece_list_begin(Color c, PieceType pt) const {
@@ -485,20 +492,8 @@ inline bool Position::pawn_is_passed(Color c, Square s) const {
return !(pieces(PAWN, opposite_color(c)) & passed_pawn_mask(c, 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_isolated(Bitboard ourPawns, Square s) {
return !(ourPawns & neighboring_files_bb(s));
}
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 !(pieces(PAWN, c) & outpost_mask(opposite_color(c), s));
return !(pieces(PAWN, opposite_color(c)) & attack_span_mask(c, s));
}
inline Key Position::get_key() const {
@@ -517,11 +512,11 @@ inline Key Position::get_material_key() const {
return st->materialKey;
}
inline Score Position::pst(Color c, PieceType pt, Square s) const {
inline Score Position::pst(Color c, PieceType pt, Square s) {
return PieceSquareTable[piece_of_color_and_type(c, pt)][s];
}
inline Score Position::pst_delta(Piece piece, Square from, Square to) const {
inline Score Position::pst_delta(Piece piece, Square from, Square to) {
return PieceSquareTable[piece][to] - PieceSquareTable[piece][from];
}
@@ -545,11 +540,16 @@ inline int Position::rule_50_counter() const {
return st->rule50;
}
inline int Position::startpos_ply_counter() const {
return startPosPlyCounter;
}
inline bool Position::opposite_colored_bishops() const {
return piece_count(WHITE, BISHOP) == 1
&& piece_count(BLACK, BISHOP) == 1
&& square_color(piece_list(WHITE, BISHOP, 0)) != square_color(piece_list(BLACK, BISHOP, 0));
&& !same_color_squares(piece_list(WHITE, BISHOP, 0), piece_list(BLACK, BISHOP, 0));
}
inline bool Position::has_pawn_on_7th(Color c) const {
@@ -557,6 +557,11 @@ inline bool Position::has_pawn_on_7th(Color c) const {
return pieces(PAWN, c) & relative_rank_bb(c, RANK_7);
}
inline bool Position::is_chess960() const {
return isChess960;
}
inline bool Position::move_is_capture(Move m) const {
// Move must not be MOVE_NONE !
@@ -569,8 +574,12 @@ inline bool Position::move_is_capture_or_promotion(Move m) const {
return (m & (0x1F << 12)) ? !move_is_castle(m) : !square_is_empty(move_to(m));
}
inline PieceType Position::captured_piece() const {
return st->capture;
inline PieceType Position::captured_piece_type() const {
return st->capturedType;
}
inline int Position::thread() const {
return threadID;
}
#endif // !defined(POSITION_H_INCLUDED)

View File

@@ -47,7 +47,7 @@ namespace {
AMBIGUITY_BOTH
};
const History H; // used as dummy argument for MovePicker c'tor
const History H; // Used as dummy argument for MovePicker c'tor
Ambiguity move_ambiguity(const Position& pos, Move m);
const string time_string(int milliseconds);
@@ -68,28 +68,25 @@ const string move_to_san(Position& pos, Move m) {
assert(pos.is_ok());
assert(move_is_ok(m));
Square from, to;
PieceType pt;
from = move_from(m);
to = move_to(m);
pt = type_of_piece(pos.piece_on(move_from(m)));
string san = "";
string san;
Square from = move_from(m);
Square to = move_to(m);
PieceType pt = type_of_piece(pos.piece_on(move_from(m)));
if (m == MOVE_NONE)
return "(none)";
else if (m == MOVE_NULL)
return "(null)";
else if (move_is_long_castle(m) || (int(to - from) == -2 && pt == KING))
else if (move_is_long_castle(m) || (int(to - from) == -2 && pt == KING))
san = "O-O-O";
else if (move_is_short_castle(m) || (int(to - from) == 2 && pt == KING))
else if (move_is_short_castle(m) || (int(to - from) == 2 && pt == KING))
san = "O-O";
else
{
if (pt != PAWN)
{
san += piece_type_to_char(pt, true);
switch (move_ambiguity(pos, m)) {
case AMBIGUITY_NONE:
break;
@@ -115,13 +112,13 @@ const string move_to_san(Position& pos, Move m) {
san += square_to_string(move_to(m));
if (move_is_promotion(m))
{
san += '=';
san += "=";
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).
// The move gives check ? We don't use pos.move_is_check() here
// because we need to test for mate after the move is done.
StateInfo st;
pos.do_move(m, st);
if (pos.is_check())
@@ -141,7 +138,7 @@ Move move_from_san(const Position& pos, const string& movestr) {
assert(pos.is_ok());
MovePicker mp = MovePicker(pos, MOVE_NONE, OnePly, H);
MovePicker mp = MovePicker(pos, MOVE_NONE, ONE_PLY, H);
Bitboard pinned = pos.pinned_pieces(pos.side_to_move());
// Castling moves
@@ -167,7 +164,7 @@ Move move_from_san(const Position& pos, const 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 string pieceLetters = "KQRBN";
PieceType pt = NO_PIECE_TYPE, promotion = NO_PIECE_TYPE;
PieceType pt = PIECE_TYPE_NONE, promotion = PIECE_TYPE_NONE;
File fromFile = FILE_NONE, toFile = FILE_NONE;
Rank fromRank = RANK_NONE, toRank = RANK_NONE;
Square to;
@@ -299,23 +296,23 @@ const string line_to_san(const Position& pos, Move line[], int startColumn, bool
string moveStr;
size_t length = 0;
size_t maxLength = 80 - startColumn;
Position p(pos);
Position p(pos, pos.thread());
for (int i = 0; line[i] != MOVE_NONE; i++)
for (Move* m = line; *m != MOVE_NONE; m++)
{
moveStr = move_to_san(p, line[i]);
moveStr = move_to_san(p, *m);
length += moveStr.length() + 1;
if (breakLines && length > maxLength)
{
s << '\n' << std::setw(startColumn) << ' ';
s << "\n" << std::setw(startColumn) << " ";
length = moveStr.length() + 1;
}
s << moveStr << ' ';
if (line[i] == MOVE_NULL)
if (*m == MOVE_NULL)
p.do_null_move(st);
else
p.do_move(line[i], st);
p.do_move(*m, st);
}
return s.str();
}
@@ -325,27 +322,31 @@ const string line_to_san(const Position& pos, Move line[], int startColumn, bool
/// It is used to write search information to the log file (which is created
/// when the UCI parameter "Use Search Log" is "true").
const string pretty_pv(const Position& pos, int time, int depth,
uint64_t nodes, Value score, ValueType type, Move pv[]) {
const string pretty_pv(const Position& pos, int time, int depth, uint64_t nodes,
Value score, ValueType type, Move pv[]) {
const uint64_t K = 1000;
const uint64_t M = 1000000;
std::stringstream s;
// Depth
s << std::setw(2) << depth << " ";
// Score
s << ((type == VALUE_TYPE_LOWER)? ">" : ((type == VALUE_TYPE_UPPER)? "<" : " "));
s << std::setw(7) << score_string(score);
s << (type == VALUE_TYPE_LOWER ? ">" : type == VALUE_TYPE_UPPER ? "<" : " ")
<< std::setw(7) << score_string(score);
// Time
s << std::setw(8) << time_string(time) << " ";
// Nodes
if (nodes < 1000000ULL)
s << std::setw(8) << nodes << " ";
else if (nodes < 1000000000ULL)
s << std::setw(7) << nodes/1000ULL << 'k' << " ";
if (nodes < M)
s << std::setw(8) << nodes / 1 << " ";
else if (nodes < K * M)
s << std::setw(7) << nodes / K << "K ";
else
s << std::setw(7) << nodes/1000000ULL << 'M' << " ";
s << std::setw(7) << nodes / M << "M ";
// PV
s << line_to_san(pos, pv, 30, true);
@@ -367,7 +368,7 @@ namespace {
if (type_of_piece(pc) == KING)
return AMBIGUITY_NONE;
MovePicker mp = MovePicker(pos, MOVE_NONE, OnePly, H);
MovePicker mp = MovePicker(pos, MOVE_NONE, ONE_PLY, H);
Bitboard pinned = pos.pinned_pieces(pos.side_to_move());
Move mv, moveList[8];
@@ -398,14 +399,17 @@ namespace {
}
const string time_string(int milliseconds) {
const string time_string(int millisecs) {
const int MSecMinute = 1000 * 60;
const int MSecHour = 1000 * 60 * 60;
std::stringstream s;
s << std::setfill('0');
int hours = milliseconds / (1000*60*60);
int minutes = (milliseconds - hours*1000*60*60) / (1000*60);
int seconds = (milliseconds - hours*1000*60*60 - minutes*1000*60) / 1000;
int hours = millisecs / MSecHour;
int minutes = (millisecs - hours * MSecHour) / MSecMinute;
int seconds = (millisecs - hours * MSecHour - minutes * MSecMinute) / 1000;
if (hours)
s << hours << ':';
@@ -421,7 +425,7 @@ namespace {
if (v >= VALUE_MATE - 200)
s << "#" << (VALUE_MATE - v + 1) / 2;
else if(v <= -VALUE_MATE + 200)
else if (v <= -VALUE_MATE + 200)
s << "-#" << (VALUE_MATE + v) / 2;
else
{

File diff suppressed because it is too large Load Diff

View File

@@ -36,7 +36,6 @@
const int PLY_MAX = 100;
const int PLY_MAX_PLUS_2 = 102;
const int KILLER_MAX = 2;
////
@@ -50,16 +49,14 @@ const int KILLER_MAX = 2;
struct EvalInfo;
struct SearchStack {
Move pv[PLY_MAX_PLUS_2];
Move currentMove;
Move mateKiller;
Move threatMove;
Move killers[KILLER_MAX];
Move excludedMove;
Move bestMove;
Move killers[2];
Depth reduction;
Value eval;
void init(int ply);
void initKillers();
bool skipNullMove;
};
@@ -70,11 +67,9 @@ struct SearchStack {
extern void init_search();
extern void init_threads();
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 int perft(Position& pos, Depth depth);
extern int64_t nodes_searched();
extern bool think(const Position& pos, bool infinite, bool ponder, int time[], int increment[],
int movesToGo, int maxDepth, int maxNodes, int maxTime, Move searchMoves[]);
#endif // !defined(SEARCH_H_INCLUDED)

View File

@@ -64,6 +64,11 @@ enum SquareDelta {
DELTA_NN = 020, DELTA_NNE = 021
};
ENABLE_OPERATORS_ON(Square);
ENABLE_OPERATORS_ON(File);
ENABLE_OPERATORS_ON(Rank);
ENABLE_OPERATORS_ON(SquareDelta);
////
//// Constants
@@ -77,35 +82,10 @@ const int FlopMask = 07;
//// Inline functions
////
inline File operator+ (File x, int i) { return File(int(x) + i); }
inline File operator+ (File x, File y) { return x + int(y); }
inline void operator++ (File &x, int) { x = File(int(x) + 1); }
inline void operator+= (File &x, int i) { x = File(int(x) + i); }
inline File operator- (File x, int i) { return File(int(x) - i); }
inline void operator-- (File &x, int) { x = File(int(x) - 1); }
inline void operator-= (File &x, int i) { x = File(int(x) - i); }
inline Rank operator+ (Rank x, int i) { return Rank(int(x) + i); }
inline Rank operator+ (Rank x, Rank y) { return x + int(y); }
inline void operator++ (Rank &x, int) { x = Rank(int(x) + 1); }
inline void operator+= (Rank &x, int i) { x = Rank(int(x) + i); }
inline Rank operator- (Rank x, int i) { return Rank(int(x) - i); }
inline void operator-- (Rank &x, int) { x = Rank(int(x) - 1); }
inline void operator-= (Rank &x, int i) { x = Rank(int(x) - i); }
inline Square operator+ (Square x, int i) { return Square(int(x) + i); }
inline void operator++ (Square &x, int) { x = Square(int(x) + 1); }
inline void operator+= (Square &x, int i) { x = Square(int(x) + i); }
inline Square operator- (Square x, int i) { return Square(int(x) - i); }
inline void operator-- (Square &x, int) { x = Square(int(x) - 1); }
inline void operator-= (Square &x, int i) { x = Square(int(x) - i); }
inline Square operator+ (Square x, SquareDelta i) { return Square(int(x) + i); }
inline void operator+= (Square &x, SquareDelta i) { x = Square(int(x) + i); }
inline Square operator- (Square x, SquareDelta i) { return Square(int(x) - i); }
inline void operator-= (Square &x, SquareDelta i) { x = Square(int(x) - i); }
inline SquareDelta operator- (Square x, Square y) {
return SquareDelta(int(x) - int(y));
}
inline Square operator+ (Square x, SquareDelta i) { return x + Square(i); }
inline void operator+= (Square& x, SquareDelta i) { x = x + Square(i); }
inline Square operator- (Square x, SquareDelta i) { return x - Square(i); }
inline void operator-= (Square& x, SquareDelta i) { x = x - Square(i); }
inline Square make_square(File f, Rank r) {
return Square(int(f) | (int(r) << 3));
@@ -135,8 +115,13 @@ inline Rank relative_rank(Color c, Square s) {
return square_rank(relative_square(c, s));
}
inline Color square_color(Square s) {
return Color((int(square_file(s)) + int(square_rank(s))) & 1);
inline SquareColor square_color(Square s) {
return SquareColor((int(square_file(s)) + int(square_rank(s))) & 1);
}
inline bool same_color_squares(Square s1, Square s2) {
int s = int(s1) ^ int(s2);
return (((s >> 3) ^ s) & 1) == 0;
}
inline int file_distance(File f1, File f2) {
@@ -180,10 +165,8 @@ inline Square square_from_string(const std::string& str) {
}
inline const std::string square_to_string(Square s) {
std::string str;
str += file_to_char(square_file(s));
str += rank_to_char(square_rank(s));
return str;
return std::string(1, file_to_char(square_file(s)))
+ std::string(1, rank_to_char(square_rank(s)));
}
inline bool file_is_ok(File f) {

View File

@@ -39,7 +39,7 @@
////
const int MAX_THREADS = 8;
const int ACTIVE_SPLIT_POINTS_MAX = 8;
const int MAX_ACTIVE_SPLIT_POINTS = 8;
////
@@ -51,11 +51,11 @@ struct SplitPoint {
// Const data after splitPoint has been setup
SplitPoint* parent;
const Position* pos;
bool pvNode;
Depth depth;
bool mateThreat;
bool pvNode, mateThreat;
Value beta;
int ply, master, slaves[MAX_THREADS];
int ply;
Move threatMove;
SearchStack sstack[MAX_THREADS][PLY_MAX_PLUS_2];
// Const pointers to shared data
@@ -66,9 +66,9 @@ struct SplitPoint {
Lock lock;
volatile Value alpha;
volatile Value bestValue;
volatile int moves;
volatile int cpus;
volatile int moveCount;
volatile bool stopRequest;
volatile int slaves[MAX_THREADS];
};
// ThreadState type is used to represent thread's current state
@@ -84,12 +84,11 @@ enum ThreadState
};
struct Thread {
SplitPoint* splitPoint;
volatile int activeSplitPoints;
uint64_t nodes;
uint64_t betaCutOffs[2];
volatile ThreadState state;
unsigned char pad[64]; // set some distance among local data for each thread
SplitPoint* volatile splitPoint;
volatile int activeSplitPoints;
SplitPoint splitPoints[MAX_ACTIVE_SPLIT_POINTS];
};

170
src/timeman.cpp Normal file
View File

@@ -0,0 +1,170 @@
/*
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 <cmath>
#include "misc.h"
#include "timeman.h"
#include "ucioption.h"
////
//// Local definitions
////
namespace {
/// Constants
const int MoveHorizon = 50; // Plan time management at most this many moves ahead
const float MaxRatio = 3.0f; // When in trouble, we can step over reserved time with this ratio
const float StealRatio = 0.33f; // However we must not steal time from remaining moves over this ratio
// MoveImportance[] is based on naive statistical analysis of "how many games are still undecided
// after n half-moves". Game is considered "undecided" as long as neither side has >275cp advantage.
// Data was extracted from CCRL game database with some simple filtering criteria.
const int MoveImportance[512] = {
7780, 7780, 7780, 7780, 7780, 7780, 7780, 7780, 7780, 7780, 7780, 7780, 7780, 7780, 7780, 7780,
7780, 7780, 7780, 7780, 7778, 7778, 7776, 7776, 7776, 7773, 7770, 7768, 7766, 7763, 7757, 7751,
7743, 7735, 7724, 7713, 7696, 7689, 7670, 7656, 7627, 7605, 7571, 7549, 7522, 7493, 7462, 7425,
7385, 7350, 7308, 7272, 7230, 7180, 7139, 7094, 7055, 7010, 6959, 6902, 6841, 6778, 6705, 6651,
6569, 6508, 6435, 6378, 6323, 6253, 6152, 6085, 5995, 5931, 5859, 5794, 5717, 5646, 5544, 5462,
5364, 5282, 5172, 5078, 4988, 4901, 4831, 4764, 4688, 4609, 4536, 4443, 4365, 4293, 4225, 4155,
4085, 4005, 3927, 3844, 3765, 3693, 3634, 3560, 3479, 3404, 3331, 3268, 3207, 3146, 3077, 3011,
2947, 2894, 2828, 2776, 2727, 2676, 2626, 2589, 2538, 2490, 2442, 2394, 2345, 2302, 2243, 2192,
2156, 2115, 2078, 2043, 2004, 1967, 1922, 1893, 1845, 1809, 1772, 1736, 1702, 1674, 1640, 1605,
1566, 1536, 1509, 1479, 1452, 1423, 1388, 1362, 1332, 1304, 1289, 1266, 1250, 1228, 1206, 1180,
1160, 1134, 1118, 1100, 1080, 1068, 1051, 1034, 1012, 1001, 980, 960, 945, 934, 916, 900, 888,
878, 865, 852, 828, 807, 787, 770, 753, 744, 731, 722, 706, 700, 683, 676, 671, 664, 652, 641,
634, 627, 613, 604, 591, 582, 568, 560, 552, 540, 534, 529, 519, 509, 495, 484, 474, 467, 460,
450, 438, 427, 419, 410, 406, 399, 394, 387, 382, 377, 372, 366, 359, 353, 348, 343, 337, 333,
328, 321, 315, 309, 303, 298, 293, 287, 284, 281, 277, 273, 265, 261, 255, 251, 247, 241, 240,
235, 229, 218, 217, 213, 212, 208, 206, 197, 193, 191, 189, 185, 184, 180, 177, 172, 170, 170,
170, 166, 163, 159, 158, 156, 155, 151, 146, 141, 138, 136, 132, 130, 128, 125, 123, 122, 118,
118, 118, 117, 115, 114, 108, 107, 105, 105, 105, 102, 97, 97, 95, 94, 93, 91, 88, 86, 83, 80,
80, 79, 79, 79, 78, 76, 75, 72, 72, 71, 70, 68, 65, 63, 61, 61, 59, 59, 59, 58, 56, 55, 54, 54,
52, 49, 48, 48, 48, 48, 45, 45, 45, 44, 43, 41, 41, 41, 41, 40, 40, 38, 37, 36, 34, 34, 34, 33,
31, 29, 29, 29, 28, 28, 28, 28, 28, 28, 28, 27, 27, 27, 27, 27, 24, 24, 23, 23, 22, 21, 20, 20,
19, 19, 19, 19, 19, 18, 18, 18, 18, 17, 17, 17, 17, 17, 16, 16, 15, 15, 14, 14, 14, 12, 12, 11,
9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 2, 2, 2, 2,
2, 1, 1, 1, 1, 1, 1, 1 };
int move_importance(int ply) { return MoveImportance[Min(ply, 511)]; }
/// Function Prototypes
enum TimeType { OptimumTime, MaxTime };
template<TimeType>
int remaining(int myTime, int movesToGo, int currentPly);
}
////
//// Functions
////
void TimeManager::pv_unstability(int curChanges, int prevChanges) {
unstablePVExtraTime = curChanges * (optimumSearchTime / 2)
+ prevChanges * (optimumSearchTime / 3);
}
void TimeManager::init(int myTime, int myInc, int movesToGo, int currentPly)
{
/* We support four different kind of time controls:
Inc == 0 && movesToGo == 0 means: x basetime [sudden death!]
Inc == 0 && movesToGo != 0 means: (x moves) / (y minutes)
Inc > 0 && movesToGo == 0 means: x basetime + z inc.
Inc > 0 && movesToGo != 0 means: (x moves) / (y minutes) + z inc
Time management is adjusted by following UCI parameters:
emergencyMoveHorizon :Be prepared to always play at least this many moves
emergencyBaseTime :Always attempt to keep at least this much time (in ms) at clock
emergencyMoveTime :Plus attempt to keep at least this much time for each remaining emergency move
minThinkingTime :No matter what, use at least this much thinking before doing the move
*/
int hypMTG, hypMyTime, t1, t2;
// Read uci parameters
int emergencyMoveHorizon = get_option_value_int("Emergency Move Horizon");
int emergencyBaseTime = get_option_value_int("Emergency Base Time");
int emergencyMoveTime = get_option_value_int("Emergency Move Time");
int minThinkingTime = get_option_value_int("Minimum Thinking Time");
// Initialize to maximum values but unstablePVExtraTime that is reset
unstablePVExtraTime = 0;
optimumSearchTime = maximumSearchTime = myTime;
// We calculate optimum time usage for different hypothetic "moves to go"-values and choose the
// minimum of calculated search time values. Usually the greatest hypMTG gives the minimum values.
for (hypMTG = 1; hypMTG <= (movesToGo ? Min(movesToGo, MoveHorizon) : MoveHorizon); hypMTG++)
{
// Calculate thinking time for hypothetic "moves to go"-value
hypMyTime = Max(myTime + (hypMTG - 1) * myInc - emergencyBaseTime - Min(hypMTG, emergencyMoveHorizon) * emergencyMoveTime, 0);
t1 = minThinkingTime + remaining<OptimumTime>(hypMyTime, hypMTG, currentPly);
t2 = minThinkingTime + remaining<MaxTime>(hypMyTime, hypMTG, currentPly);
optimumSearchTime = Min(optimumSearchTime, t1);
maximumSearchTime = Min(maximumSearchTime, t2);
}
if (get_option_value_bool("Ponder"))
optimumSearchTime += optimumSearchTime / 4;
// Make sure that maxSearchTime is not over absoluteMaxSearchTime
optimumSearchTime = Min(optimumSearchTime, maximumSearchTime);
}
////
//// Local functions
////
namespace {
template<TimeType T>
int remaining(int myTime, int movesToGo, int currentPly)
{
const float TMaxRatio = (T == OptimumTime ? 1 : MaxRatio);
const float TStealRatio = (T == OptimumTime ? 0 : StealRatio);
int thisMoveImportance = move_importance(currentPly);
int otherMovesImportance = 0;
for (int i = 1; i < movesToGo; i++)
otherMovesImportance += move_importance(currentPly + 2 * i);
float ratio1 = (TMaxRatio * thisMoveImportance) / float(TMaxRatio * thisMoveImportance + otherMovesImportance);
float ratio2 = (thisMoveImportance + TStealRatio * otherMovesImportance) / float(thisMoveImportance + otherMovesImportance);
return int(floor(myTime * Min(ratio1, ratio2)));
}
}

View File

@@ -18,35 +18,25 @@
*/
#if !defined(SCALE_H_INCLUDED)
#define SCALE_H_INCLUDED
#if !defined(TIMEMAN_H_INCLUDED)
#define TIMEMAN_H_INCLUDED
////
//// Includes
//// Prototypes
////
#include "value.h"
class TimeManager {
public:
void init(int myTime, int myInc, int movesToGo, int currentPly);
void pv_unstability(int curChanges, int prevChanges);
int available_time() const { return optimumSearchTime + unstablePVExtraTime; }
int maximum_time() const { return maximumSearchTime; }
////
//// Types
////
enum ScaleFactor {
SCALE_FACTOR_ZERO = 0,
SCALE_FACTOR_NORMAL = 64,
SCALE_FACTOR_MAX = 128,
SCALE_FACTOR_NONE = 255
private:
int optimumSearchTime;
int maximumSearchTime;
int unstablePVExtraTime;
};
////
//// Inline functions
////
inline Value apply_scale_factor(Value v, ScaleFactor f) {
return Value((v * f) / int(SCALE_FACTOR_NORMAL));
}
#endif // !defined(SCALE_H_INCLUDED)
#endif // !defined(TIMEMAN_H_INCLUDED)

View File

@@ -23,13 +23,8 @@
////
#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
@@ -41,7 +36,7 @@ TranspositionTable TT;
TranspositionTable::TranspositionTable() {
size = writes = 0;
size = 0;
entries = 0;
generation = 0;
}
@@ -59,8 +54,10 @@ void TranspositionTable::set_size(size_t mbSize) {
size_t newSize = 1024;
// We store a cluster of ClusterSize number of TTEntry for each position
// and newSize is the maximum number of storable positions.
// Transposition table consists of clusters and
// each cluster consists of ClusterSize number of TTEntries.
// Each non-empty entry contains information of exactly one position.
// newSize is the number of clusters we are going to allocate.
while ((2 * newSize) * sizeof(TTCluster) <= (mbSize << 20))
newSize *= 2;
@@ -75,7 +72,6 @@ void TranspositionTable::set_size(size_t mbSize) {
<< " MB for transposition table." << std::endl;
Application::exit_with_failure();
}
clear();
}
}
@@ -83,7 +79,7 @@ void TranspositionTable::set_size(size_t mbSize) {
/// TranspositionTable::clear overwrites the entire transposition table
/// with zeroes. It is called whenever the table is resized, or when the
/// user asks the program to clear the table (from the UCI interface).
/// Perhaps we should also clear it when the "ucinewgame" command is recieved?
/// Perhaps we should also clear it when the "ucinewgame" command is received?
void TranspositionTable::clear() {
@@ -91,28 +87,19 @@ void TranspositionTable::clear() {
}
/// 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;
}
/// TranspositionTable::store writes a new entry containing a position,
/// a value, a value type, a search depth, and a best move to the
/// transposition table. Transposition table is organized in clusters of
/// four TTEntry objects, and when a new entry is written, it replaces
/// the least valuable of the four entries in a cluster. A TTEntry t1 is
/// considered to be more valuable than a TTEntry t2 if t1 is from the
/// TranspositionTable::store writes a new entry containing position key and
/// valuable information of current position.
/// The Lowest order bits of position key are used to decide on which cluster
/// the position will be placed.
/// When a new entry is written and there are no empty entries available in cluster,
/// it replaces the least valuable of entries.
/// A TTEntry t1 is considered to be more valuable than a TTEntry t2 if t1 is from the
/// current search and t2 is from a previous search, or if the depth of t1
/// is bigger than the depth of t2. A TTEntry of type VALUE_TYPE_EVAL
/// never replaces another entry for the same position.
/// is bigger than the depth of t2.
void TranspositionTable::store(const Key posKey, Value v, ValueType t, Depth d, Move m) {
void TranspositionTable::store(const Key posKey, Value v, ValueType t, Depth d, Move m, Value statV, Value kingD) {
int c1, c2, c3;
TTEntry *tte, *replace;
uint32_t posKey32 = posKey >> 32; // Use the high 32 bits as key
@@ -121,29 +108,25 @@ void TranspositionTable::store(const Key posKey, Value v, ValueType t, Depth d,
{
if (!tte->key() || tte->key() == posKey32) // empty or overwrite old
{
// Do not overwrite when new type is VALUE_TYPE_EV_LO
if (tte->key() && t == VALUE_TYPE_EV_LO)
return;
// Preserve any exsisting ttMove
// Preserve any existing ttMove
if (m == MOVE_NONE)
m = tte->move();
*tte = TTEntry(posKey32, v, t, d, m, generation);
tte->save(posKey32, v, t, d, m, generation, statV, kingD);
return;
}
else if (i == 0) // replace would be a no-op in this common case
if (i == 0) // Replacing first entry is default and already set before entering for-loop
continue;
int c1 = (replace->generation() == generation ? 2 : 0);
int c2 = (tte->generation() == generation ? -2 : 0);
int c3 = (tte->depth() < replace->depth() ? 1 : 0);
c1 = (replace->generation() == generation ? 2 : 0);
c2 = (tte->generation() == generation ? -2 : 0);
c3 = (tte->depth() < replace->depth() ? 1 : 0);
if (c1 + c2 + c3 > 0)
replace = tte;
}
*replace = TTEntry(posKey32, v, t, d, m, generation);
writes++;
replace->save(posKey32, v, t, d, m, generation, statV, kingD);
}
@@ -164,100 +147,11 @@ TTEntry* TranspositionTable::retrieve(const Key posKey) const {
}
/// 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
void TranspositionTable::prefetch(const Key posKey) const {
#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
/// entries from the current search.
void TranspositionTable::new_search() {
generation++;
writes = 0;
}
/// TranspositionTable::insert_pv() is called at the end of a search
/// iteration, and inserts the PV back into the PV. This makes sure
/// the old PV moves are searched first, even if the old TT entries
/// have been overwritten.
void TranspositionTable::insert_pv(const Position& pos, Move pv[]) {
StateInfo st;
Position p(pos);
for (int i = 0; pv[i] != MOVE_NONE; 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) * ClusterSize;
return int(1000 * (1 - exp(writes * log(1.0 - 1.0/N))));
}

View File

@@ -26,7 +26,7 @@
////
#include "depth.h"
#include "position.h"
#include "move.h"
#include "value.h"
@@ -36,58 +36,68 @@
/// The TTEntry class is the class of transposition table entries
///
/// A TTEntry needs 96 bits to be stored
/// A TTEntry needs 128 bits to be stored
///
/// bit 0-31: key
/// bit 32-63: data
/// bit 64-79: value
/// bit 80-95: depth
/// bit 96-111: static value
/// bit 112-127: margin of static value
///
/// the 32 bits of the data field are so defined
///
/// bit 0-16: move
/// bit 17-18: not used
/// bit 19-22: value type
/// bit 17-20: not used
/// bit 21-22: value type
/// bit 23-31: generation
class TTEntry {
public:
TTEntry() {}
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)) {}
void save(uint32_t k, Value v, ValueType t, Depth d, Move m, int g, Value statV, Value kd) {
uint32_t key() const { return key_; }
Depth depth() const { return Depth(depth_); }
key32 = k;
data = (m & 0x1FFFF) | (t << 21) | (g << 23);
value16 = int16_t(v);
depth16 = int16_t(d);
staticValue = int16_t(statV);
staticValueMargin = int16_t(kd);
}
uint32_t key() const { return key32; }
Depth depth() const { return Depth(depth16); }
Move move() const { return Move(data & 0x1FFFF); }
Value value() const { return Value(value_); }
ValueType type() const { return ValueType((data >> 19) & 0xF); }
int generation() const { return (data >> 23); }
Value value() const { return Value(value16); }
ValueType type() const { return ValueType((data >> 21) & 3); }
int generation() const { return data >> 23; }
Value static_value() const { return Value(staticValue); }
Value static_value_margin() const { return Value(staticValueMargin); }
private:
uint32_t key_;
uint32_t key32;
uint32_t data;
int16_t value_;
int16_t depth_;
int16_t value16;
int16_t depth16;
int16_t staticValue;
int16_t staticValueMargin;
};
/// This is the number of TTEntry slots for each position
const int ClusterSize = 5;
/// This is the number of TTEntry slots for each cluster
const int ClusterSize = 4;
/// 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.
/// TTCluster consists of ClusterSize number of TTEntries.
/// Size of TTCluster must not be bigger than a cache line size.
/// In case it is less, it should be padded to guarantee always aligned accesses.
struct TTCluster {
TTEntry data[ClusterSize];
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
/// containing TTCluster objects, and a few methods for writing new entries
/// and reading new ones.
class TranspositionTable {
@@ -97,23 +107,12 @@ public:
~TranspositionTable();
void set_size(size_t mbSize);
void clear();
void store(const Key posKey, Value v, ValueType type, Depth d, Move m);
void store(const Key posKey, Value v, ValueType type, Depth d, Move m, Value statV, Value kingD);
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;
TTEntry* first_entry(const Key posKey) const;
private:
inline TTEntry* first_entry(const Key posKey) const;
// 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;
@@ -121,4 +120,14 @@ private:
extern TranspositionTable TT;
/// TranspositionTable::first_entry returns a pointer to the first
/// entry of a cluster given a position. The lowest order bits of the key
/// are used to get the index of the cluster.
inline TTEntry* TranspositionTable::first_entry(const Key posKey) const {
return entries[uint32_t(posKey) & (size - 1)].data;
}
#endif // !defined(TT_H_INCLUDED)

View File

@@ -49,20 +49,32 @@ typedef uint64_t Bitboard;
////
//// Compiler specific defines
//// Configuration
////
// Quiet a warning on Intel compiler
#if !defined(__SIZEOF_INT__ )
#define __SIZEOF_INT__ 0
#endif
//// For Linux and OSX configuration is done automatically using Makefile.
//// To get started type "make help".
////
//// For windows part of the configuration is detected automatically, but
//// some switches need to be set manually:
////
//// -DNDEBUG | Disable debugging mode. Use always.
////
//// -DNO_PREFETCH | Disable use of prefetch asm-instruction. A must if you want the
//// | executable to run on some very old machines.
////
//// -DUSE_POPCNT | Add runtime support for use of popcnt asm-instruction.
//// | Works only in 64-bit mode. For compiling requires hardware
//// | with popcnt support. Around 4% speed-up.
// Check for 64 bits for different compilers: Intel, MSVC and gcc
#if defined(__x86_64) || defined(_M_X64) || defined(_WIN64) || (__SIZEOF_INT__ > 4)
// Automatic detection for 64-bit under Windows
#if defined(_WIN64)
#define IS_64BIT
#endif
#if defined(IS_64BIT) && (defined(__GNUC__) || defined(__INTEL_COMPILER))
// Automatic detection for use of bsfq asm-instruction under Windows.
// Works only in 64-bit mode. Does not work with MSVC.
#if defined(_WIN64) && defined(__INTEL_COMPILER)
#define USE_BSFQ
#endif
@@ -97,4 +109,64 @@ inline void __cpuid(int CPUInfo[4], int)
}
#endif
// Templetized operators used by enum types like Depth, Piece, Square and so on.
// We don't want to write the same inline for each different enum. Note that we
// pass by value to silence scaring warnings when using volatiles.
// Because these templates override common operators and are included in all the
// files, there is a possibility that the compiler silently performs some unwanted
// overrides. To avoid possible very nasty bugs the templates are disabled by default
// and must be enabled for each type on a case by case base. The enabling trick
// uses template specialization, namely we just declare following struct.
template<typename T> struct TempletizedOperator;
// Then to enable the enum type we use following macro that defines a specialization
// of TempletizedOperator for the given enum T. Here is defined typedef Not_Enabled.
// Name of typedef is chosen to produce somewhat informative compile error messages.
#define ENABLE_OPERATORS_ON(T) \
template<> struct TempletizedOperator<T> { typedef T Not_Enabled; }
// Finally we use macro OK(T) to check if type T is enabled. The macro simply
// tries to use Not_Enabled, if was not previously defined a compile error occurs.
// The check is done fully at compile time and there is zero overhead at runtime.
#define OK(T) typedef typename TempletizedOperator<T>::Not_Enabled Type
template<typename T>
inline T operator+ (const T d1, const T d2) { OK(T); return T(int(d1) + int(d2)); }
template<typename T>
inline T operator- (const T d1, const T d2) { OK(T); return T(int(d1) - int(d2)); }
template<typename T>
inline T operator* (int i, const T d) { OK(T); return T(i * int(d)); }
template<typename T>
inline T operator* (const T d, int i) { OK(T); return T(int(d) * i); }
template<typename T>
inline T operator/ (const T d, int i) { OK(T); return T(int(d) / i); }
template<typename T>
inline T operator- (const T d) { OK(T); return T(-int(d)); }
template<typename T>
inline void operator++ (T& d, int) { OK(T); d = T(int(d) + 1); }
template<typename T>
inline void operator-- (T& d, int) { OK(T); d = T(int(d) - 1); }
template<typename T>
inline void operator+= (T& d1, const T d2) { OK(T); d1 = d1 + d2; }
template<typename T>
inline void operator-= (T& d1, const T d2) { OK(T); d1 = d1 - d2; }
template<typename T>
inline void operator*= (T& d, int i) { OK(T); d = T(int(d) * i); }
template<typename T>
inline void operator/= (T& d, int i) { OK(T); d = T(int(d) / i); }
#undef OK
#endif // !defined(TYPES_H_INCLUDED)

View File

@@ -46,6 +46,9 @@ using namespace std;
namespace {
// FEN string for the initial position
const string StartPositionFEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
// UCIInputParser is a class for parsing UCI input. The class
// is actually a string stream built on a given input string.
@@ -54,7 +57,7 @@ namespace {
// 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;
Position RootPosition(0);
// Local functions
bool handle_command(const string& command);
@@ -79,7 +82,7 @@ namespace {
void uci_main_loop() {
RootPosition.from_fen(StartPosition);
RootPosition.from_fen(StartPositionFEN);
string command;
do {
@@ -126,8 +129,7 @@ namespace {
else if (token == "ucinewgame")
{
push_button("New Game");
Position::init_piece_square_tables();
RootPosition.from_fen(StartPosition);
RootPosition.from_fen(StartPositionFEN);
}
else if (token == "isready")
cout << "readyok" << endl;
@@ -143,15 +145,15 @@ namespace {
RootPosition.print();
else if (token == "flip")
{
Position p(RootPosition);
Position p(RootPosition, RootPosition.thread());
RootPosition.flipped_copy(p);
}
else if (token == "eval")
{
EvalInfo ei;
cout << "Incremental mg: " << mg_value(RootPosition.value())
Value evalMargin;
cout << "Incremental mg: " << mg_value(RootPosition.value())
<< "\nIncremental eg: " << eg_value(RootPosition.value())
<< "\nFull eval: " << evaluate(RootPosition, ei, 0) << endl;
<< "\nFull eval: " << evaluate(RootPosition, evalMargin) << endl;
}
else if (token == "key")
cout << "key: " << hex << RootPosition.get_key()
@@ -180,7 +182,7 @@ namespace {
return;
if (token == "startpos")
RootPosition.from_fen(StartPosition);
RootPosition.from_fen(StartPositionFEN);
else if (token == "fen")
{
string fen;
@@ -207,9 +209,11 @@ namespace {
RootPosition.do_move(move, st);
if (RootPosition.rule_50_counter() == 0)
RootPosition.reset_game_ply();
RootPosition.inc_startpos_ply_counter(); //FIXME: make from_fen to support this and rule50
}
// Our StateInfo st is about going out of scope so copy
// its content inside RootPosition before they disappear.
// its content inside RootPosition before it disappears.
RootPosition.detach();
}
}
@@ -300,22 +304,22 @@ namespace {
assert(RootPosition.is_ok());
return think(RootPosition, infinite, ponder, RootPosition.side_to_move(),
time, inc, movesToGo, depth, nodes, moveTime, searchMoves);
return think(RootPosition, infinite, ponder, time, inc, movesToGo,
depth, nodes, moveTime, searchMoves);
}
void perft(UCIInputParser& uip) {
string token;
int depth, tm, n;
Position pos(RootPosition);
Position pos(RootPosition, RootPosition.thread());
if (!(uip >> depth))
return;
tm = get_system_time();
n = perft(pos, depth * OnePly);
n = perft(pos, depth * ONE_PLY);
tm = get_system_time() - tm;
std::cout << "\nNodes " << n

View File

@@ -34,6 +34,8 @@
#include "ucioption.h"
using std::string;
using std::cout;
using std::endl;
////
//// Local definitions
@@ -41,13 +43,9 @@ using std::string;
namespace {
///
/// Types
///
enum OptionType { SPIN, COMBO, CHECK, STRING, BUTTON };
typedef std::vector<string> ComboValues;
typedef std::vector<string> StrVector;
struct Option {
@@ -55,23 +53,42 @@ namespace {
OptionType type;
size_t idx;
int minValue, maxValue;
ComboValues comboValues;
StrVector comboValues;
Option();
Option(const char* defaultValue, OptionType = STRING);
Option(bool defaultValue, OptionType = CHECK);
Option(int defaultValue, int minValue, int maxValue);
bool operator<(const Option& o) const { return this->idx < o.idx; }
bool operator<(const Option& o) const { return idx < o.idx; }
};
typedef std::vector<Option> OptionsVector;
typedef std::map<string, Option> Options;
///
/// Constants
///
Options options;
// load_defaults populates the options map with the hard
// stringify() converts a value of type T to a std::string
template<typename T>
string stringify(const T& v) {
std::ostringstream ss;
ss << v;
return ss.str();
}
Option::Option() {} // To allow insertion in a std::map
Option::Option(const char* def, OptionType t)
: defaultValue(def), currentValue(def), type(t), idx(options.size()), minValue(0), maxValue(0) {}
Option::Option(bool def, OptionType t)
: defaultValue(stringify(def)), currentValue(stringify(def)), type(t), idx(options.size()), minValue(0), maxValue(0) {}
Option::Option(int def, int minv, int maxv)
: defaultValue(stringify(def)), currentValue(stringify(def)), type(SPIN), idx(options.size()), minValue(minv), maxValue(maxv) {}
// load_defaults() populates the options map with the hard
// coded names and default values.
void load_defaults(Options& o) {
@@ -79,6 +96,7 @@ namespace {
o["Use Search Log"] = Option(false);
o["Search Log Filename"] = Option("SearchLog.txt");
o["Book File"] = Option("book.bin");
o["Best Book Move"] = Option(false);
o["Mobility (Middle Game)"] = Option(100, 0, 200);
o["Mobility (Endgame)"] = Option(100, 0, 200);
o["Pawn Structure (Middle Game)"] = Option(100, 0, 200);
@@ -92,15 +110,14 @@ namespace {
o["Check Extension (non-PV nodes)"] = Option(1, 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["Mate Threat Extension (PV nodes)"] = Option(2, 0, 2);
o["Mate Threat Extension (non-PV nodes)"] = Option(2, 0, 2);
o["Pawn Push to 7th Extension (PV nodes)"] = Option(1, 0, 2);
o["Pawn Push to 7th Extension (non-PV nodes)"] = Option(1, 0, 2);
o["Passed Pawn Extension (PV nodes)"] = Option(1, 0, 2);
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["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, MAX_THREADS);
@@ -110,36 +127,20 @@ namespace {
o["Ponder"] = Option(true);
o["OwnBook"] = Option(true);
o["MultiPV"] = Option(1, 1, 500);
o["UCI_Chess960"] = Option(false);
o["Emergency Move Horizon"] = Option(40, 0, 50);
o["Emergency Base Time"] = Option(200, 0, 60000);
o["Emergency Move Time"] = Option(70, 0, 5000);
o["Minimum Thinking Time"] = Option(20, 0, 5000);
o["UCI_Chess960"] = Option(false); // Just a dummy but needed by GUIs
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)
it->second.name = it->first;
}
///
/// Variables
///
Options options;
// stringify converts a value of type T to a std::string
template<typename T>
string stringify(const T& v) {
std::ostringstream ss;
ss << v;
return ss.str();
}
// get_option_value implements the various get_option_value_<type>
// functions defined later, because only the option value
// type changes a template seems a proper solution.
// get_option_value() implements the various get_option_value_<type>
// functions defined later.
template<typename T>
T get_option_value(const string& optionName) {
@@ -153,9 +154,8 @@ namespace {
return ret;
}
// Specialization for std::string where instruction 'ss >> 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) {
@@ -167,20 +167,15 @@ namespace {
}
////
//// Functions
////
/// init_uci_options() initializes the UCI options. Currently, the only
/// thing this function does is to initialize the default value of the
/// "Threads" parameter to the number of available CPU cores.
/// init_uci_options() initializes the UCI options. Currently, the only thing
/// this function does is to initialize the default value of "Threads" and
/// "Minimum Split Depth" parameters according to the number of CPU cores.
void init_uci_options() {
load_defaults(options);
// 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());
@@ -199,39 +194,40 @@ void init_uci_options() {
void print_uci_options() {
static const char optionTypeName[][16] = {
const char OptTypeName[][16] = {
"spin", "combo", "check", "string", "button"
};
// Build up a vector out of the options map and sort it according to idx
// field, that is the chronological insertion order in options map.
std::vector<Option> vec;
OptionsVector vec;
for (Options::const_iterator it = options.begin(); it != options.end(); ++it)
vec.push_back(it->second);
std::sort(vec.begin(), vec.end());
for (std::vector<Option>::const_iterator it = vec.begin(); it != vec.end(); ++it)
for (OptionsVector::const_iterator it = vec.begin(); it != vec.end(); ++it)
{
std::cout << "\noption name " << it->name
<< " type " << optionTypeName[it->type];
cout << "\noption name " << it->name << " type " << OptTypeName[it->type];
if (it->type == BUTTON)
continue;
if (it->type == CHECK)
std::cout << " default " << (it->defaultValue == "1" ? "true" : "false");
cout << " default " << (it->defaultValue == "1" ? "true" : "false");
else
std::cout << " default " << it->defaultValue;
cout << " default " << it->defaultValue;
if (it->type == SPIN)
std::cout << " min " << it->minValue << " max " << it->maxValue;
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)
std::cout << " var " << *itc;
{
StrVector::const_iterator itc;
for (itc = it->comboValues.begin(); itc != it->comboValues.end(); ++itc)
cout << " var " << *itc;
}
}
std::cout << std::endl;
cout << endl;
}
@@ -264,12 +260,16 @@ string get_option_value_string(const string& optionName) {
}
/// set_option_value() inserts a new value for a UCI parameter. Note that
/// 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.
/// set_option_value() inserts a new value for a UCI parameter
void set_option_value(const string& name, const string& value) {
if (options.find(name) == options.end())
{
cout << "No such option: " << name << endl;
return;
}
// UCI protocol uses "true" and "false" instead of "1" and "0", so convert
// value according to standard C++ convention before to store it.
string v(value);
@@ -278,12 +278,6 @@ void set_option_value(const string& name, const string& value) {
else if (v == "false")
v = "0";
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.
@@ -298,7 +292,6 @@ void set_option_value(const string& name, const string& value) {
if (val < opt.minValue || val > opt.maxValue)
return;
}
opt.currentValue = v;
}
@@ -324,21 +317,3 @@ bool button_was_pressed(const string& buttonName) {
set_option_value(buttonName, "false");
return true;
}
namespace {
// Define constructors of Option class.
Option::Option() {} // To allow insertion in a std::map
Option::Option(const char* def, OptionType t)
: defaultValue(def), currentValue(def), type(t), idx(options.size()), minValue(0), maxValue(0) {}
Option::Option(bool def, OptionType t)
: defaultValue(stringify(def)), currentValue(stringify(def)), type(t), idx(options.size()), minValue(0), maxValue(0) {}
Option::Option(int def, int minv, int maxv)
: defaultValue(stringify(def)), currentValue(stringify(def)), type(SPIN), idx(options.size()), minValue(minv), maxValue(maxv) {}
}

View File

@@ -1,96 +0,0 @@
/*
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 <sstream>
#include <string>
#include "value.h"
////
//// Functions
////
/// value_to_tt() adjusts a mate score from "plies to mate from the root" to
/// "plies to mate from the current ply". Non-mate scores are unchanged.
/// The function is called before storing a value to the transposition table.
Value value_to_tt(Value v, int ply) {
if(v >= value_mate_in(100))
return v + ply;
else if(v <= value_mated_in(100))
return v - ply;
else
return v;
}
/// value_from_tt() is the inverse of value_to_tt(): It adjusts a mate score
/// from the transposition table to a mate score corrected for the current
/// ply depth.
Value value_from_tt(Value v, int ply) {
if(v >= value_mate_in(100))
return v - ply;
else if(v <= value_mated_in(100))
return v + ply;
else
return v;
}
/// value_to_centipawns() converts a value from Stockfish's somewhat unusual
/// scale of pawn = 256 to the more conventional pawn = 100.
int value_to_centipawns(Value v) {
return (int(v) * 100) / int(PawnValueMidgame);
}
/// value_from_centipawns() converts a centipawn value to Stockfish's internal
/// evaluation scale. It's used when reading the values of UCI options
/// containing material values (e.g. futility pruning margins).
Value value_from_centipawns(int cp) {
return Value((cp * 256) / 100);
}
/// value_to_string() converts a value to a string suitable for use with the
/// UCI protocol.
const std::string value_to_string(Value v) {
std::stringstream s;
if(abs(v) < VALUE_MATE - 200)
s << "cp " << value_to_centipawns(v);
else {
s << "mate ";
if(v > 0)
s << (VALUE_MATE - v + 1) / 2;
else
s << -(VALUE_MATE + v) / 2;
}
return s.str();
}

View File

@@ -21,40 +21,38 @@
#if !defined(VALUE_H_INCLUDED)
#define VALUE_H_INCLUDED
////
//// Includes
////
#include "piece.h"
////
//// Types
////
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, // 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,
VALUE_TYPE_EXACT = VALUE_TYPE_UPPER | VALUE_TYPE_LOWER
};
enum Value {
VALUE_DRAW = 0,
VALUE_ZERO = 0,
VALUE_DRAW = 0,
VALUE_KNOWN_WIN = 15000,
VALUE_MATE = 30000,
VALUE_INFINITE = 30001,
VALUE_NONE = 30002,
VALUE_MATE = 30000,
VALUE_INFINITE = 30001,
VALUE_NONE = 30002,
VALUE_ENSURE_SIGNED = -1
};
ENABLE_OPERATORS_ON(Value);
enum ScaleFactor {
SCALE_FACTOR_ZERO = 0,
SCALE_FACTOR_NORMAL = 64,
SCALE_FACTOR_MAX = 128,
SCALE_FACTOR_NONE = 255
};
/// Score enum keeps a midgame and an endgame value in a single
/// integer (enum), first LSB 16 bits are used to store endgame
@@ -62,7 +60,14 @@ enum 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)};
enum Score {
SCORE_ZERO = 0,
SCORE_ENSURE_32_BITS_SIZE_P = (1 << 16),
SCORE_ENSURE_32_BITS_SIZE_N = -(1 << 16)
};
ENABLE_OPERATORS_ON(Score);
// Extracting the _signed_ lower and upper 16 bits it not so trivial
// because according to the standard a simple cast to short is
@@ -79,13 +84,6 @@ inline Value eg_value(Score s) { return Value((int)(unsigned(s) & 0x7fffu) - (in
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); }
@@ -94,118 +92,20 @@ inline Score operator/(Score s, int i) { return make_score(mg_value(s) / i, eg_v
inline Score operator*(Score s1, Score s2);
////
//// Constants and variables
////
/// Piece values, middle game and endgame
/// Important: If the material values are changed, one must also
/// adjust the piece square tables, and the method game_phase() in the
/// Position class!
///
/// Values modified by Joona Kiiski
const Value PawnValueMidgame = Value(0x0C6);
const Value PawnValueEndgame = Value(0x102);
const Value KnightValueMidgame = Value(0x331);
const Value KnightValueEndgame = Value(0x34E);
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),
PawnValueMidgame, KnightValueMidgame, BishopValueMidgame,
RookValueMidgame, QueenValueMidgame,
Value(0), Value(0), Value(0),
PawnValueMidgame, KnightValueMidgame, BishopValueMidgame,
RookValueMidgame, QueenValueMidgame,
Value(0), Value(0), Value(0)
};
const Value PieceValueEndgame[17] = {
Value(0),
PawnValueEndgame, KnightValueEndgame, BishopValueEndgame,
RookValueEndgame, QueenValueEndgame,
Value(0), Value(0), Value(0),
PawnValueEndgame, KnightValueEndgame, BishopValueEndgame,
RookValueEndgame, QueenValueEndgame,
Value(0), Value(0), Value(0)
};
/// Bonus for having the side to move (modified by Joona Kiiski)
const Score TempoValue = make_score(48, 22);
////
//// Inline functions
////
inline Value operator+ (Value v, int i) { return Value(int(v) + i); }
inline Value operator+ (Value v1, Value v2) { return Value(int(v1) + int(v2)); }
inline void operator+= (Value &v1, Value v2) {
v1 = Value(int(v1) + int(v2));
}
inline Value operator- (Value v, int i) { return Value(int(v) - i); }
inline Value operator- (Value v) { return Value(-int(v)); }
inline Value operator- (Value v1, Value v2) { return Value(int(v1) - int(v2)); }
inline void operator-= (Value &v1, Value v2) {
v1 = Value(int(v1) - int(v2));
}
inline Value operator* (Value v, int i) { return Value(int(v) * i); }
inline void operator*= (Value &v, int i) { v = Value(int(v) * i); }
inline Value operator* (int i, Value v) { return Value(int(v) * i); }
inline Value operator/ (Value v, int i) { return Value(int(v) / i); }
inline void operator/= (Value &v, int i) { v = Value(int(v) / i); }
inline Value value_mate_in(int ply) {
return Value(VALUE_MATE - Value(ply));
return VALUE_MATE - ply;
}
inline Value value_mated_in(int ply) {
return Value(-VALUE_MATE + Value(ply));
return -VALUE_MATE + ply;
}
inline bool is_upper_bound(ValueType vt) {
return (int(vt) & int(VALUE_TYPE_UPPER)) != 0;
}
inline bool is_lower_bound(ValueType vt) {
return (int(vt) & int(VALUE_TYPE_LOWER)) != 0;
}
inline Value piece_value_midgame(PieceType pt) {
return PieceValueMidgame[pt];
}
inline Value piece_value_endgame(PieceType pt) {
return PieceValueEndgame[pt];
}
inline Value piece_value_midgame(Piece p) {
return PieceValueMidgame[p];
}
inline Value piece_value_endgame(Piece p) {
return PieceValueEndgame[p];
}
////
//// Prototypes
////
extern Value value_to_tt(Value v, int ply);
extern Value value_from_tt(Value v, int ply);
extern int value_to_centipawns(Value v);
extern Value value_from_centipawns(int cp);
extern const std::string value_to_string(Value v);
#endif // !defined(VALUE_H_INCLUDED)