Compare commits

..

556 Commits

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

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

Verified 100% functional equivalent to 1.7

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

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

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

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

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

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

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

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

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

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

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

No functional change.

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

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

Spotted by Richard Lloyd.

No functional change.

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

./stockfish bench 128 1 12 default depth
8299338

./stockfish bench 128 1 13 default depth
15694903

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

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

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

No functional change.

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

A very small increase, if any.

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

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

No functional change.

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

No functional change.

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

This fixes a couple of warnings under MSVC.

No functional change.

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

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

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

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

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

Also small comments tweaks.

No functional change.

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

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

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

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

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

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

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

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

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

No functional change.

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

No functional change.

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

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

No functional change.

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

No functional change.

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

No functional change.

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

No functional change.

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

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

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

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

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

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

No functional change.

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

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

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

No functional change.

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

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

Strangely no functional change, but should be.

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

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

Remaining stuff is triviality and documentation tweaks.

No functional change.

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

No functional change.

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

No functional change.

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

No functional change.

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

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

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

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

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

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

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

No functional change.

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

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

No functional change.

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

No functional change

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

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

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

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

No functional change

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

No functional change

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

No functional change

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

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

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

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

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

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

Also add one FIXME for illogical behaviour

No functional change

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

No functional change

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

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

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

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

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

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

No functional change.

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

No functional change.

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

No functional change.

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

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

No functional change.

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

So revert the patch and come back to single lock.

No functional change.

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

No functional change.

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

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

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

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

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

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

No functional change.

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

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

No functional change and a good semplification.

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

No functional change.

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

No functional change.

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

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

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

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

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

No functional change.

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

It is important the name reflects this.

No functional change.

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

No functional change.

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

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

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

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

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

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

No functional change.

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

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

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

No functional change.

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

No functional change.

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

No functional change.

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

No functional change.

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

- Renamed Idle in AllThreadsShouldSleep

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

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

No functional change.

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

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

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

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

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

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

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

No functional change.

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

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

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

No functional change.

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

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

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

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

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

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

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

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

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

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

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

No functional change.

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

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

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

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

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

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

No real change, just move reordering.

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

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

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

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

This patch restores proper ordering.

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

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

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

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

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

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

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

No functional change.

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

No functional change.

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

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

Bug introduced by 30e8f0c9ad6a473 of 13/02/2009

No functional change.

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

No functional change.

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

No functional change.

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

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

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

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

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

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

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

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

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

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

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

Idea suggested by Richard Vida.

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

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

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

No functional change.

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

No functional change.

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

No functional change.

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

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

No functional change

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

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

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

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

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

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

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

Testing result is very positive.

1CPU:
953-1149

4CPU:
545 - 656

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

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

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

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

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

No functional change.

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

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

in search(), line 1615.

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

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

No functional change.

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

No functional change and big code remove.

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

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

Test results for the whole futility pruning series:

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

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

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

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

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

So remove old dated hack

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

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

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

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

No functional change.

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

Bug spotted by Bruno Causse.

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

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

After 998 games at 1+0

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

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

No functional change.

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

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

Rearrange the last loop to fix this race.

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

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

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

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

No functional change.

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

No functional change.

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

No functional change.

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

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

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

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

No functional change.

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

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

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

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

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

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

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

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

No functional change.

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

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

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

No functional change.

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

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

No functional change.

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

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

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

No functional change.

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

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

No functional change.

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

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

Bug spotted by Bruno Causse.

No functional change (for single CPU case)

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

No functional change

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

No functional change.

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

No functional change.

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

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

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

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

Joona's test results are positive:

32-bit 1CPU:

Mod - Orig: 1073 - 993

64-bit 4CPU:

Mod - Orig: 759 - 721

Functionality Signature: 11448962

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

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

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

No functional change.

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

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

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

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

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

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

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

Bug found by Pascal Georges.

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

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

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

Here are testing results:

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

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

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

This is a 2.0 type change!

After 977 games at 1+0

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

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

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

Functionality Signature: 12581900

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

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

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

Bug fixed by Justin Blanchard

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

No functional change.

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

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

Bug reported and fixed by Justin Blanchard.

No functional change.

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

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

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

Functionality Signature: 16627355

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

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

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

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

Functionality Signature: 17655312

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

No functional change.

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

No functional change.

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

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

No functional change.

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

No functional change.

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

No functional change.

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

No functional change.

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

No functional change.

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

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

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

After 967 games at 1+0

Mod vs Orig 240 529 198 +15 ELO

Functionality Signature: 21222553

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

No functional change.

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

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

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

Verified it works on all compilers and with equivalent
functionality.

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

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

No functional change.

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

No functional change.

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

So remove it.

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

No functional change.

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

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

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

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

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

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

No functional change.

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

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

Spotted by Justin Blanchard

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

Bug reported and fixed by Justin Blanchard (Arch Linux)

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

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

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

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

Mod - Orig: 365 - 351

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

After 999 games at 1+0

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

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

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

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

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

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

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

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

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

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

After 786 games

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

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

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

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

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

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

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

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

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

Bug reported by xiaozhi

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

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

Also small indentation fix.

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

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

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

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

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

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

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

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

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

No functional change.

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

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

No functional change. Apart from possible crash fix.

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

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

Mod - Orig: 361 - 404

Master is now verified to be functional equivalent with F_63

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

We have two advantages

1) We don't need to sort zero scores

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

Speed up is of about 2%

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

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

No functional change.

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

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

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

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

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

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

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

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

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

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

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

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

After 965 games

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

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

After 1019 games on Joona's QUAD

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

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

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

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

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

No functional change.

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

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

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

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

No functional change.

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

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

No functional change.

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

No functional change.

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

No functional change.

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

No functional change.

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

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

A small increase as expected.

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

No functional change.

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

No functional change.

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

Idea of pointer is of Eric Mullins.

No functional change.

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

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

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

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

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

No functional change.

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

No functional change.

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

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

Optimization is really a black art.

No functional change.

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

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

No functional change.

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

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

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

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

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

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

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

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

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

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

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

No functional change.

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

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

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

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

No functional change.

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

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

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

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

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

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

Updated documentation too.

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

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

Of curse no functional change.

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

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

No functional change.

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

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

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

No functional change.

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

No functional change.

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

No functional change.

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

Verified against perft: no functional change.

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

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

Verified with perft no functional change.

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

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

Verified with perft no functional change.

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

No functional change.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

After 100 games at 1+0 on Joona QUAD

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

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

No functional change.

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

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

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

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

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

No functional change.

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

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

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

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

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

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

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

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

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

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

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

Patch suggested by Joona.

No functional search.

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

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

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

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

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

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

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

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

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

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

Idea and patch by Joona

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

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

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

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

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

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

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

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

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

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

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

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

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

After 999 games at 1+0

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

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

No functional change.

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

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

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

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

No functional change.

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

Speed up on pgo compile is of 1.3%

No functional change.

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

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

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

So we _really_ need two counters.

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

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

pv[PLY_MAX] = MOVE_NONE;

And because SearchStack is defined as:

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

We end up with the unwanted assignment

SearchStack.currentMove = MOVE_NONE;

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

Thanks to Uri Blass for spotting out this.

No functional change.

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

No functional change.

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

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

Idea from Joona.

After 999 games at 1+0

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

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

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

No functional change.

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

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

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

The killer moves cleared correspond to ply+2.

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

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

Bug spotted by Valgrind.

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

No functional change.

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

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

Fix suggested by Joona.

No functional change.

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

No functional change in normal chess.
2009-10-05 16:46:18 +02:00
Marco Costalba 3701a8e57d Restore development version
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-10-05 07:15:13 +01:00
61 changed files with 5120 additions and 4891 deletions
+4 -5
View File
@@ -52,14 +52,13 @@ UCI parameter "Book File".
On Unix-like systems, it should usually be possible to compile On Unix-like systems, it should usually be possible to compile
Stockfish directly from the source code with the included Makefile. Stockfish directly from the source code with the included Makefile.
The exception is computer with big-endian CPUs, like PowerPC
Macintoshes. Some of the bitboard routines in the current version of For big-endian machines like Power PC you need to enable the proper
Stockfish are endianness-sensitive, and won't work on a big-endian CPU. flag changing from -DNBIGENDIAN to -DBIGENDIAN in the Makefile.
Stockfish has POPCNT instruction runtime detection and support. This can Stockfish has POPCNT instruction runtime detection and support. This can
give an extra speed on Core i7 or similar systems. To enable this feature give an extra speed on Core i7 or similar systems. To enable this feature
(disabled by default) simply uncomment #define USE_POPCNT in bitcount.h compile with 'make icc-profile-popcnt'
before to compile.
On 64 bit Unix-like systems the 'bsfq' assembly instruction will be used On 64 bit Unix-like systems the 'bsfq' assembly instruction will be used
for bit counting. Detection is automatic at compile time, but in case you for bit counting. Detection is automatic at compile time, but in case you
+4 -19
View File
@@ -7,7 +7,7 @@ EngineCommand = ./stockfish
Book = false Book = false
BookFile = book.bin BookFile = book.bin
Log = true Log = false
LogFile = stockfish.log LogFile = stockfish.log
Resign = true Resign = true
@@ -19,28 +19,18 @@ Hash = 128
Threads = 1 Threads = 1
OwnBook = false OwnBook = false
Book File = book.bin Book File = book.bin
Best Book Move = false
Use Search Log = false Use Search Log = false
Search Log Filename = SearchLog.txt
Mobility (Middle Game) = 100 Mobility (Middle Game) = 100
Mobility (Endgame) = 100 Mobility (Endgame) = 100
Pawn Structure (Middle Game) = 100 Pawn Structure (Middle Game) = 100
Pawn Structure (Endgame) = 100 Pawn Structure (Endgame) = 100
Passed Pawns (Middle Game) = 100 Passed Pawns (Middle Game) = 100
Passed Pawns (Endgame) = 100 Passed Pawns (Endgame) = 100
Space = 100
Aggressiveness = 100 Aggressiveness = 100
Cowardice = 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 (PV nodes) = 2
Check Extension (non-PV nodes) = 1 Check Extension (non-PV nodes) = 1
Single Reply Extension (PV nodes) = 2 Single Reply Extension (PV nodes) = 2
@@ -53,11 +43,6 @@ Passed Pawn Extension (PV nodes) = 1
Passed Pawn Extension (non-PV nodes) = 0 Passed Pawn Extension (non-PV nodes) = 0
Pawn Endgame Extension (PV nodes) = 2 Pawn Endgame Extension (PV nodes) = 2
Pawn Endgame Extension (non-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 Randomness = 0
Minimum Split Depth = 4 Minimum Split Depth = 4
Maximum Number of Threads per Split Point = 5 Maximum Number of Threads per Split Point = 5
+449 -205
View File
@@ -1,7 +1,7 @@
# Stockfish, a UCI chess playing engine derived from Glaurung 2.1 # Stockfish, a UCI chess playing engine derived from Glaurung 2.1
# Copyright (C) 2004-2007 Tord Romstad # Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
# Copyright (C) 2008 Marco Costalba # Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
#
# This file is part of Stockfish. # This file is part of Stockfish.
# #
# Stockfish is free software: you can redistribute it and/or modify # Stockfish is free software: you can redistribute it and/or modify
@@ -18,246 +18,490 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # 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 EXE = stockfish
### Installation dir definitions
PREFIX = /usr/local
BINDIR = $(PREFIX)/bin
### ========================================================================== ### Built-in benchmark for pgo-builds
### 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
### ==========================================================================
### Run built-in benchmark for pgo-builds with: 32MB hash 1 thread 10 depth
### These settings are generally fast, but may be changed experimentally
### ==========================================================================
PGOBENCH = ./$(EXE) bench 32 1 10 default depth PGOBENCH = ./$(EXE) bench 32 1 10 default depth
### Object files
### General compiler settings. Do not change
GCCFLAGS += -g -Wall -fno-exceptions -fno-rtti -fno-strict-aliasing
ICCFLAGS += -g -Wall -fno-exceptions -fno-rtti -fno-strict-aliasing -wd383,869,981,10187,10188,11505,11503
ICCFLAGS-OSX += -g -Wall -fno-exceptions -fno-rtti -fno-strict-aliasing -wd383,869,981,10187,10188,11505,11503
### General linker settings. Do not change
LDFLAGS = -lpthread
### Object files. Do not change
OBJS = application.o bitboard.o pawns.o material.o endgame.o evaluate.o main.o \ 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 \ 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 \ position.o direction.o tt.o value.o uci.o ucioption.o \
mersenne.o book.o bitbase.o san.o benchmark.o mersenne.o book.o bitbase.o san.o benchmark.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 -fno-exceptions -fno-rtti $(EXTRACXXFLAGS)
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: default:
$(MAKE) gcc $(MAKE) ARCH=$(ARCH) COMP=$(COMP) build
help: help:
@echo "" @echo ""
@echo "Makefile options:" @echo "To compile stockfish, type: "
@echo "" @echo ""
@echo "make > Default: Compiler = g++" @echo "make target ARCH=arch [COMP=comp]"
@echo "make icc > Compiler = icpc" @echo ""
@echo "make icc-profile > Compiler = icpc + automatic pgo-build" @echo "Supported targets:"
@echo "make osx-ppc32 > PPC-Mac OS X 32 bit. Compiler = g++" @echo ""
@echo "make osx-ppc64 > PPC-Mac OS X 64 bit. Compiler = g++" @echo "build > Build unoptimized version"
@echo "make osx-x86 > x86-Mac OS X 32 bit. Compiler = g++" @echo "profile-build > Build PGO-optimized version"
@echo "make osx-x86_64 > x86-Mac OS X 64 bit. Compiler = g++" @echo "popcnt-profile-build > Build PGO-optimized version with optional popcnt-support"
@echo "make osx-icc32 > x86-Mac OS X 32 bit. Compiler = icpc" @echo "strip > Strip executable"
@echo "make osx-icc64 > x86-Mac OS X 64 bit. Compiler = icpc" @echo "install > Install executable"
@echo "make osx-icc32-profile > OSX 32 bit. Compiler = icpc + automatic pgo-build" @echo "clean > Clean up"
@echo "make osx-icc64-profile > OSX 64 bit. Compiler = icpc + automatic pgo-build" @echo "testrun > Make sample run"
@echo "make strip > Strip executable" @echo ""
@echo "make clean > Clean up" @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 "" @echo ""
all: $(EXE) .depend build:
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) config-sanity
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) all
clean: profile-build:
$(RM) *.o .depend *~ $(EXE) $(MAKE) ARCH=$(ARCH) COMP=$(COMP) config-sanity
@echo ""
@echo "Step 0/4. Preparing for profile build."
### Possible targets. You may add your own ones here $(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_prepare)
gcc: @echo ""
$(MAKE) \ @echo "Step 1/4. Building executable for benchmark ..."
CXX='g++' \
CXXFLAGS="$(GCCFLAGS)" \
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
@touch *.cpp *.h @touch *.cpp *.h
$(MAKE) icc-profile-make $(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_make)
@echo "" @echo ""
@echo "Running benchmark for pgo-build ..." @echo "Step 2/4. Running benchmark for pgo-build ..."
@$(PGOBENCH) > /dev/null @$(PGOBENCH) > /dev/null
@echo "Benchmark finished. Build final executable now ..."
@echo "" @echo ""
@touch *.cpp *.h @echo "Step 3/4. Building final executable ..."
$(MAKE) icc-profile-use @touch *.cpp
@rm -rf profdir bench.txt $(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_use)
osx-ppc32:
$(MAKE) \
CXX='g++' \
CXXFLAGS="$(GCCFLAGS)" \
CXXFLAGS+='-arch ppc' \
LDFLAGS+='-arch ppc' \
all
osx-ppc64:
$(MAKE) \
CXX='g++' \
CXXFLAGS="$(GCCFLAGS)" \
CXXFLAGS+='-arch ppc64' \
LDFLAGS+='-arch ppc64' \
all
osx-x86:
$(MAKE) \
CXX='g++' \
CXXFLAGS="$(GCCFLAGS)" \
CXXFLAGS+='-arch i386' \
LDFLAGS+='-arch i386' \
all
osx-x86_64:
$(MAKE) \
CXX='g++' \
CXXFLAGS="$(GCCFLAGS)" \
CXXFLAGS+='-arch x86_64' \
LDFLAGS+='-arch x86_64' \
all
osx-icc32:
$(MAKE) \
CXX='icpc' \
CXXFLAGS="$(ICCFLAGS-OSX)" \
CXXFLAGS+='-arch i386' \
LDFLAGS+='-arch i386' \
all
osx-icc64:
$(MAKE) \
CXX='icpc' \
CXXFLAGS="$(ICCFLAGS-OSX)" \
CXXFLAGS+='-arch x86_64' \
LDFLAGS+='-arch x86_64' \
all
osx-icc32-profile-make:
$(MAKE) \
CXX='icpc' \
CXXFLAGS="$(ICCFLAGS-OSX)" \
CXXFLAGS+='-arch i386' \
CXXFLAGS+='-prof_gen -prof_dir ./profdir' \
LDFLAGS+='-arch i386' \
all
osx-icc32-profile-use:
$(MAKE) \
CXX='icpc' \
CXXFLAGS="$(ICCFLAGS-OSX)" \
CXXFLAGS+='-arch i386' \
CXXFLAGS+='-prof_use -prof_dir ./profdir' \
LDFLAGS+='-arch i386' \
all
osx-icc32-profile:
@rm -rf profdir
@mkdir profdir
@touch *.cpp *.h
$(MAKE) osx-icc32-profile-make
@echo "" @echo ""
@echo "Running benchmark for pgo-build ..." @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 @$(PGOBENCH) > /dev/null
@echo "Benchmark finished. Build final executable now ..."
@echo "" @echo ""
@echo "Step 3/6. Building executable for benchmark (popcnt enabled)..."
@touch *.cpp *.h @touch *.cpp *.h
$(MAKE) osx-icc32-profile-use $(MAKE) ARCH=x86-64-modern COMP=$(COMP) $(profile_make)
@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 ""
@echo "Running benchmark for pgo-build ..." @echo "Step 4/6. Running benchmark for pgo-build (popcnt enabled)..."
@$(PGOBENCH) > /dev/null @$(PGOBENCH) > /dev/null
@echo "Benchmark finished. Build final executable now ..."
@echo "" @echo ""
@echo "Step 5/6. Building final executable ..."
@touch *.cpp *.h @touch *.cpp *.h
$(MAKE) osx-icc64-profile-use $(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_use)
@rm -rf profdir bench.txt @echo ""
@echo "Step 6/6. Deleting profile data ..."
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_clean)
@echo ""
strip: strip:
strip $(EXE) strip $(EXE)
install:
-mkdir -p -m 755 $(BINDIR)
-cp $(EXE) $(BINDIR)
-strip $(BINDIR)/$(EXE)
clean:
$(RM) $(EXE) *.o .depend *~ core bench.txt
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"
### Compilation. Do not change
$(EXE): $(OBJS) $(EXE): $(OBJS)
$(CXX) $(LDFLAGS) -o $@ $(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
### Dependencies. Do not change
.depend: .depend:
$(CXX) -msse -MM $(OBJS:.o=.cpp) > $@ -@$(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' \
CXXFLAGS="" \
LDFLAGS="" \
all
include .depend
+11 -8
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -49,6 +49,7 @@ Application::Application() {
Position::init_piece_square_tables(); Position::init_piece_square_tables();
init_eval(1); init_eval(1);
init_bitbases(); init_bitbases();
init_search();
init_threads(); init_threads();
// Make random number generation less deterministic, for book moves // Make random number generation less deterministic, for book moves
@@ -56,12 +57,6 @@ Application::Application() {
genrand_int32(); genrand_int32();
} }
Application::~Application() {
stop_threads();
quit_eval();
}
void Application::initialize() { void Application::initialize() {
// A static Application object is allocated // A static Application object is allocated
@@ -69,7 +64,15 @@ void Application::initialize() {
static Application singleton; 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() { void Application::exit_with_failure() {
exit(EXIT_FAILURE); // d'tor will be called automatically exit(EXIT_FAILURE);
} }
+2 -2
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -29,10 +29,10 @@ class Application {
Application(); Application();
Application(const Application&); Application(const Application&);
~Application();
public: public:
static void initialize(); static void initialize();
static void free_resources();
static void exit_with_failure(); static void exit_with_failure();
}; };
+17 -10
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -38,8 +38,8 @@ using namespace std;
const string BenchmarkPositions[] = { const string BenchmarkPositions[] = {
"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1", "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1",
"r4rk1/1b2qppp/p1n1p3/1p6/1b1PN3/3BRN2/PP3PPP/R2Q2K1 b - - 7 16", "r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq -",
"4r1k1/ppq3pp/3b4/2pP4/2Q1p3/4B1P1/PP5P/R5K1 b - - 0 20", "8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - -",
"4rrk1/pp1n3p/3q2pQ/2p1pb2/2PP4/2P3N1/P2B2PP/4RRK1 b - - 7 19", "4rrk1/pp1n3p/3q2pQ/2p1pb2/2PP4/2P3N1/P2B2PP/4RRK1 b - - 7 19",
"rq3rk1/ppp2ppp/1bnpb3/3N2B1/3NP3/7P/PPPQ1PP1/2KR3R w - - 7 14", "rq3rk1/ppp2ppp/1bnpb3/3N2B1/3NP3/7P/PPPQ1PP1/2KR3R w - - 7 14",
"r1bq1r1k/1pp1n1pp/1p1p4/4p2Q/4Pp2/1BNP4/PPP2PPP/3R1RK1 w - - 2 14", "r1bq1r1k/1pp1n1pp/1p1p4/4p2Q/4Pp2/1BNP4/PPP2PPP/3R1RK1 w - - 2 14",
@@ -84,9 +84,9 @@ void benchmark(const string& commandLine) {
} }
csStr >> threads; csStr >> threads;
csVal >> val; csVal >> val;
if (val < 1 || val > THREAD_MAX) if (val < 1 || val > MAX_THREADS)
{ {
cerr << "The number of threads must be between 1 and " << THREAD_MAX << endl; cerr << "The number of threads must be between 1 and " << MAX_THREADS << endl;
Application::exit_with_failure(); Application::exit_with_failure();
} }
set_option_value("Hash", ttSize); set_option_value("Hash", ttSize);
@@ -104,7 +104,7 @@ void benchmark(const string& commandLine) {
if (limitType == "time") if (limitType == "time")
secsPerPos = val * 1000; secsPerPos = val * 1000;
else if (limitType == "depth") else if (limitType == "depth" || limitType == "perft")
maxDepth = val; maxDepth = val;
else else
maxNodes = val; maxNodes = val;
@@ -151,11 +151,18 @@ void benchmark(const string& commandLine) {
{ {
Move moves[1] = {MOVE_NONE}; Move moves[1] = {MOVE_NONE};
int dummy[2] = {0, 0}; int dummy[2] = {0, 0};
Position pos(*it); Position pos(*it, 0);
cerr << "\nBench position: " << cnt << '/' << positions.size() << endl << endl; cerr << "\nBench position: " << cnt << '/' << positions.size() << endl << endl;
if (!think(pos, true, false, 0, dummy, dummy, 0, maxDepth, maxNodes, secsPerPos, moves)) if (limitType == "perft")
break; {
totalNodes += nodes_searched(); int64_t perftCnt = perft(pos, maxDepth * OnePly);
cerr << "\nPerft " << maxDepth << " result (nodes searched): " << perftCnt << endl << endl;
totalNodes += perftCnt;
} else {
if (!think(pos, false, false, 0, dummy, dummy, 0, maxDepth, maxNodes, secsPerPos, moves))
break;
totalNodes += nodes_searched();
}
} }
cnt = get_system_time() - startTime; cnt = get_system_time() - startTime;
+1 -1
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
+144 -113
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -226,8 +226,9 @@ Bitboard StepAttackBB[16][64];
Bitboard RayBB[64][8]; Bitboard RayBB[64][8];
Bitboard BetweenBB[64][64]; Bitboard BetweenBB[64][64];
Bitboard SquaresInFrontMask[2][64];
Bitboard PassedPawnMask[2][64]; Bitboard PassedPawnMask[2][64];
Bitboard OutpostMask[2][64]; Bitboard AttackSpanMask[2][64];
Bitboard BishopPseudoAttacks[64]; Bitboard BishopPseudoAttacks[64];
Bitboard RookPseudoAttacks[64]; Bitboard RookPseudoAttacks[64];
@@ -246,14 +247,12 @@ namespace {
void init_ray_bitboards(); void init_ray_bitboards();
void init_attacks(); void init_attacks();
void init_between_bitboards(); 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], Bitboard sliding_attacks(int sq, Bitboard block, int dirs, int deltas[][2],
int fmin, int fmax, int rmin, int rmax); 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[],
void init_sliding_attacks(Bitboard attacks[], const int shift[], const Bitboard mult[], int deltas[][2]);
int attackIndex[], Bitboard mask[],
const int shift[2], const Bitboard mult[],
int deltas[][2]);
void init_pseudo_attacks();
} }
@@ -265,11 +264,14 @@ namespace {
/// standard output. This is sometimes useful for debugging. /// standard output. This is sometimes useful for debugging.
void print_bitboard(Bitboard b) { void print_bitboard(Bitboard b) {
for(Rank r = RANK_8; r >= RANK_1; r--) {
std::cout << "+---+---+---+---+---+---+---+---+" << std::endl; for (Rank r = RANK_8; r >= RANK_1; r--)
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; 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; std::cout << "+---+---+---+---+---+---+---+---+" << std::endl;
} }
@@ -279,8 +281,10 @@ void print_bitboard(Bitboard b) {
/// program initialization. /// program initialization.
void init_bitboards() { void init_bitboards() {
int rookDeltas[4][2] = {{0,1},{0,-1},{1,0},{-1,0}}; int rookDeltas[4][2] = {{0,1},{0,-1},{1,0},{-1,0}};
int bishopDeltas[4][2] = {{1,1},{-1,1},{1,-1},{-1,-1}}; int bishopDeltas[4][2] = {{1,1},{-1,1},{1,-1},{-1,-1}};
init_masks(); init_masks();
init_ray_bitboards(); init_ray_bitboards();
init_attacks(); init_attacks();
@@ -297,8 +301,8 @@ void init_bitboards() {
#if defined(IS_64BIT) && !defined(USE_BSFQ) #if defined(IS_64BIT) && !defined(USE_BSFQ)
CACHE_LINE_ALIGNMENT static CACHE_LINE_ALIGNMENT
static const int BitTable[64] = { const int BitTable[64] = {
0, 1, 2, 7, 3, 13, 8, 19, 4, 25, 14, 28, 9, 34, 20, 40, 5, 17, 26, 38, 15, 0, 1, 2, 7, 3, 13, 8, 19, 4, 25, 14, 28, 9, 34, 20, 40, 5, 17, 26, 38, 15,
46, 29, 48, 10, 31, 35, 54, 21, 50, 41, 57, 63, 6, 12, 18, 24, 27, 33, 39, 46, 29, 48, 10, 31, 35, 54, 21, 50, 41, 57, 63, 6, 12, 18, 24, 27, 33, 39,
16, 37, 45, 47, 30, 53, 49, 56, 62, 11, 23, 32, 36, 44, 52, 55, 61, 22, 43, 16, 37, 45, 47, 30, 53, 49, 56, 62, 11, 23, 32, 36, 44, 52, 55, 61, 22, 43,
@@ -317,8 +321,8 @@ Square pop_1st_bit(Bitboard* b) {
#elif !defined(USE_BSFQ) #elif !defined(USE_BSFQ)
CACHE_LINE_ALIGNMENT static CACHE_LINE_ALIGNMENT
static const int BitTable[64] = { const int BitTable[64] = {
63, 30, 3, 32, 25, 41, 22, 33, 15, 50, 42, 13, 11, 53, 19, 34, 61, 29, 2, 63, 30, 3, 32, 25, 41, 22, 33, 15, 50, 42, 13, 11, 53, 19, 34, 61, 29, 2,
51, 21, 43, 45, 10, 18, 47, 1, 54, 9, 57, 0, 35, 62, 31, 40, 4, 49, 5, 52, 51, 21, 43, 45, 10, 18, 47, 1, 54, 9, 57, 0, 35, 62, 31, 40, 4, 49, 5, 52,
26, 60, 6, 23, 44, 46, 27, 56, 16, 7, 39, 48, 24, 59, 14, 12, 55, 38, 28, 26, 60, 6, 23, 44, 46, 27, 56, 16, 7, 39, 48, 24, 59, 14, 12, 55, 38, 28,
@@ -326,6 +330,7 @@ static const int BitTable[64] = {
}; };
Square first_1(Bitboard b) { Square first_1(Bitboard b) {
b ^= (b - 1); b ^= (b - 1);
uint32_t fold = int(b) ^ int(b >> 32); uint32_t fold = int(b) ^ int(b >> 32);
return Square(BitTable[(fold * 0x783a9b23) >> 26]); return Square(BitTable[(fold * 0x783a9b23) >> 26]);
@@ -336,30 +341,39 @@ union b_union {
Bitboard b; Bitboard b;
struct { struct {
#if defined (BIGENDIAN)
uint32_t h;
uint32_t l;
#else
uint32_t l; uint32_t l;
uint32_t h; uint32_t h;
#endif
} dw; } dw;
}; };
// WARNING: Needs -fno-strict-aliasing compiler option
Square pop_1st_bit(Bitboard* bb) { Square pop_1st_bit(Bitboard* bb) {
b_union u; b_union u;
Square ret;
u.b = *bb; u.b = *bb;
if (u.dw.l) if (u.dw.l)
{ {
*((uint32_t*)bb) = u.dw.l & (u.dw.l - 1); ret = Square(BitTable[((u.dw.l ^ (u.dw.l - 1)) * 0x783a9b23) >> 26]);
return Square(BitTable[((u.dw.l ^ (u.dw.l - 1)) * 0x783a9b23) >> 26]); u.dw.l &= (u.dw.l - 1);
} *bb = u.b;
return ret;
*((uint32_t*)bb+1) = u.dw.h & (u.dw.h - 1); // Little endian only? }
return Square(BitTable[((~(u.dw.h ^ (u.dw.h - 1))) * 0x783a9b23) >> 26]); ret = Square(BitTable[((~(u.dw.h ^ (u.dw.h - 1))) * 0x783a9b23) >> 26]);
u.dw.h &= (u.dw.h - 1);
*bb = u.b;
return ret;
} }
#endif #endif
namespace { namespace {
// All functions below are used to precompute various bitboards during // All functions below are used to precompute various bitboards during
@@ -368,39 +382,46 @@ namespace {
// be necessary to touch any of them. // be necessary to touch any of them.
void init_masks() { void init_masks() {
SetMaskBB[SQ_NONE] = 0ULL; SetMaskBB[SQ_NONE] = 0ULL;
ClearMaskBB[SQ_NONE] = ~SetMaskBB[SQ_NONE]; ClearMaskBB[SQ_NONE] = ~SetMaskBB[SQ_NONE];
for(Square s = SQ_A1; s <= SQ_H8; s++) {
SetMaskBB[s] = (1ULL << s); for (Square s = SQ_A1; s <= SQ_H8; s++)
ClearMaskBB[s] = ~SetMaskBB[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++) { for (Color c = WHITE; c <= BLACK; c++)
PassedPawnMask[c][s] = for (Square s = SQ_A1; s <= SQ_H8; s++)
in_front_bb(c, s) & this_and_neighboring_files_bb(s); {
OutpostMask[c][s] = in_front_bb(c, s) & neighboring_files_bb(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++) for (Bitboard b = 0ULL; b < 256ULL; b++)
BitCount8Bit[b] = (uint8_t)count_1s(b); BitCount8Bit[b] = (uint8_t)count_1s(b);
} }
int remove_bit_8(int i) { return ((i & ~15) >> 1) | (i & 7); }
void init_ray_bitboards() { void init_ray_bitboards() {
int d[8] = {1, -1, 16, -16, 17, -17, 15, -15}; 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++) { for (int i = 0; i < 128; i = (i + 9) & ~8)
RayBB[(i&7)|((i>>4)<<3)][j] = EmptyBoardBB; for (int j = 0; j < 8; j++)
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))); 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() { void init_attacks() {
int i, j, k, l;
int step[16][8] = { const int step[16][8] = {
{0}, {0},
{7,9,0}, {17,15,10,6,-6,-10,-15,-17}, {9,7,-7,-9,0}, {8,1,-1,-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}, {9,7,-7,-9,8,1,-1,-8}, {9,7,-7,-9,8,1,-1,-8}, {0}, {0},
@@ -408,105 +429,115 @@ namespace {
{9,7,-7,-9,8,1,-1,-8}, {9,7,-7,-9,8,1,-1,-8} {9,7,-7,-9,8,1,-1,-8}, {9,7,-7,-9,8,1,-1,-8}
}; };
for(i = 0; i < 64; i++) { for (int i = 0; i < 64; i++)
for(j = 0; j <= int(BK); j++) { for (int j = 0; j <= int(BK); j++)
StepAttackBB[j][i] = EmptyBoardBB; {
for(k = 0; k < 8 && step[j][k] != 0; k++) { StepAttackBB[j][i] = EmptyBoardBB;
l = i + step[j][k]; for (int k = 0; k < 8 && step[j][k] != 0; k++)
if(l >= 0 && l < 64 && abs((i&7) - (l&7)) < 3) {
StepAttackBB[j][i] |= (1ULL << l); 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], Bitboard sliding_attacks(int sq, Bitboard block, int dirs, int deltas[][2],
int fmin=0, int fmax=7, int rmin=0, int rmax=7) { int fmin=0, int fmax=7, int rmin=0, int rmax=7) {
Bitboard result = 0ULL; Bitboard result = 0ULL;
int rk = sq / 8, fl = sq % 8, r, f, i; int rk = sq / 8;
for(i = 0; i < dirs; i++) { int fl = sq % 8;
int dx = deltas[i][0], dy = deltas[i][1];
for(f = fl+dx, r = rk+dy; for (int i = 0; i < dirs; i++)
(dx==0 || (f>=fmin && f<=fmax)) && (dy==0 || (r>=rmin && r<=rmax)); {
f += dx, r += dy) { int dx = deltas[i][0];
result |= (1ULL << (f + r*8)); int dy = deltas[i][1];
if(block & (1ULL << (f + r*8))) break; 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; return result;
} }
void init_between_bitboards() { void init_between_bitboards() {
SquareDelta step[8] = {
DELTA_E, DELTA_W, DELTA_N, DELTA_S, DELTA_NE, DELTA_SW, DELTA_NW, DELTA_SE const 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 s1 = SQ_A1; s1 <= SQ_H8; s1++)
for(Square s2 = SQ_A1; s2 <= SQ_H8; s2++) { for (Square s2 = SQ_A1; s2 <= SQ_H8; s2++)
BetweenBB[s1][s2] = EmptyBoardBB; {
d = signed_direction_between_squares(s1, s2); BetweenBB[s1][s2] = EmptyBoardBB;
if(d != SIGNED_DIR_NONE) SignedDirection d = signed_direction_between_squares(s1, s2);
for(Square s3 = s1 + step[d]; s3 != s2; s3 += step[d])
set_bit(&(BetweenBB[s1][s2]), s3); 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) { Bitboard index_to_bitboard(int index, Bitboard mask) {
int i, j, bits = count_1s(mask);
Bitboard result = 0ULL; Bitboard result = 0ULL;
for(i = 0; i < bits; i++) { int bits = count_1s(mask);
j = pop_1st_bit(&mask);
if(index & (1 << i)) result |= (1ULL << j); for (int i = 0; i < bits; i++)
{
int j = pop_1st_bit(&mask);
if (index & (1 << i))
result |= (1ULL << j);
} }
return result; 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[], for (int i = 0, index = 0; i < 64; i++)
int attackIndex[], Bitboard mask[], {
const int shift[2], const Bitboard mult[], attackIndex[i] = index;
int deltas[][2]) { mask[i] = sliding_attacks(i, 0ULL, 4, deltas, 1, 6, 1, 6);
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);
#if defined(IS_64BIT) #if defined(IS_64BIT)
j = (1 << (64 - shift[i])); int j = (1 << (64 - shift[i]));
#else #else
j = (1 << (32 - shift[i])); int j = (1 << (32 - shift[i]));
#endif #endif
for(k = 0; k < j; k++) { for (int k = 0; k < j; k++)
{
#if defined(IS_64BIT) #if defined(IS_64BIT)
b = index_to_bitboard(k, mask[i]); Bitboard b = index_to_bitboard(k, mask[i]);
attacks[index + ((b * mult[i]) >> shift[i])] = attacks[index + ((b * mult[i]) >> shift[i])] = sliding_attacks(i, b, 4, deltas);
sliding_attacks(i, b, 4, deltas);
#else #else
b = index_to_bitboard(k, mask[i]); Bitboard b = index_to_bitboard(k, mask[i]);
attacks[index + unsigned v = int(b) * int(mult[i]) ^ int(b >> 32) * int(mult[i] >> 32);
(unsigned(int(b) * int(mult[i]) ^ attacks[index + (v >> shift[i])] = sliding_attacks(i, b, 4, deltas);
int(b >> 32) * int(mult[i] >> 32))
>> shift[i])] =
sliding_attacks(i, b, 4, deltas);
#endif #endif
} }
index += j; index += j;
} }
} }
void init_pseudo_attacks() { void init_pseudo_attacks() {
Square s;
for(s = SQ_A1; s <= SQ_H8; s++) { for (Square s = SQ_A1; s <= SQ_H8; s++)
BishopPseudoAttacks[s] = bishop_attacks_bb(s, EmptyBoardBB); {
RookPseudoAttacks[s] = rook_attacks_bb(s, EmptyBoardBB); BishopPseudoAttacks[s] = bishop_attacks_bb(s, EmptyBoardBB);
QueenPseudoAttacks[s] = queen_attacks_bb(s, EmptyBoardBB); RookPseudoAttacks[s] = rook_attacks_bb(s, EmptyBoardBB);
QueenPseudoAttacks[s] = queen_attacks_bb(s, EmptyBoardBB);
} }
} }
+21 -28
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -74,8 +74,9 @@ extern Bitboard StepAttackBB[16][64];
extern Bitboard RayBB[64][8]; extern Bitboard RayBB[64][8];
extern Bitboard BetweenBB[64][64]; extern Bitboard BetweenBB[64][64];
extern Bitboard SquaresInFrontMask[2][64];
extern Bitboard PassedPawnMask[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 uint64_t RMult[64];
extern const int RShift[64]; extern const int RShift[64];
@@ -127,9 +128,8 @@ inline void do_move_bb(Bitboard *b, Bitboard move_bb) {
*b ^= move_bb; *b ^= move_bb;
} }
/// rank_bb() and file_bb() gives a bitboard containing all squares on a given /// rank_bb() and file_bb() take a file or a square as input, and return
/// file or rank. It is also possible to pass a square as input to these /// a bitboard representing all squares on the given file or rank.
/// functions.
inline Bitboard rank_bb(Rank r) { inline Bitboard rank_bb(Rank r) {
return RankBB[r]; return RankBB[r];
@@ -156,7 +156,7 @@ inline Bitboard neighboring_files_bb(File f) {
} }
inline Bitboard neighboring_files_bb(Square s) { inline Bitboard neighboring_files_bb(Square s) {
return neighboring_files_bb(square_file(s)); return NeighboringFilesBB[square_file(s)];
} }
@@ -169,7 +169,7 @@ inline Bitboard this_and_neighboring_files_bb(File f) {
} }
inline Bitboard this_and_neighboring_files_bb(Square s) { 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 +195,7 @@ inline Bitboard in_front_bb(Color c, Rank r) {
} }
inline Bitboard in_front_bb(Color c, Square s) { 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 +208,7 @@ inline Bitboard behind_bb(Color c, Rank r) {
} }
inline Bitboard behind_bb(Color c, Square s) { 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 +274,11 @@ inline Bitboard squares_between(Square s1, Square s2) {
/// squares_in_front_of takes a color and a square as input, and returns a /// 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, /// bitboard representing all squares along the line in front of the square,
/// from the point of view of the given color. For instance, /// from the point of view of the given color. Definition of the table is:
/// squares_in_front_of(BLACK, SQ_E4) returns a bitboard with the squares /// SquaresInFrontOf[c][s] = in_front_bb(c, s) & file_bb(s)
/// e3, e2 and e1 set.
inline Bitboard squares_in_front_of(Color c, Square 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 +286,27 @@ inline Bitboard squares_in_front_of(Color c, Square s) {
/// behind the square instead of in front of the square. /// behind the square instead of in front of the square.
inline Bitboard squares_behind(Color c, Square s) { 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 /// 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 /// 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) { inline Bitboard passed_pawn_mask(Color c, Square s) {
return PassedPawnMask[c][s]; return PassedPawnMask[c][s];
} }
/// outpost_mask takes a color and a square as input, and returns a bitboard /// attack_span_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 /// representing all squares that can be attacked by a pawn of the given color
/// be driven away by an enemy pawn. /// 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) { inline Bitboard attack_span_mask(Color c, Square s) {
return OutpostMask[c][s]; return AttackSpanMask[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);
} }
+26 -53
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -22,62 +22,22 @@
#if !defined(BITCOUNT_H_INCLUDED) #if !defined(BITCOUNT_H_INCLUDED)
#define BITCOUNT_H_INCLUDED #define BITCOUNT_H_INCLUDED
// To enable POPCNT support uncomment USE_POPCNT define. For PGO compile on a Core i7
// you may want to collect profile data first with USE_POPCNT disabled and then, in a
// second profiling session, with USE_POPCNT enabled so to exercise both paths. Don't
// forget to leave USE_POPCNT enabled for the final optimized compile though ;-)
//#define USE_POPCNT
#include "types.h" #include "types.h"
// Select type of intrinsic bit count instruction to use // Select type of intrinsic bit count instruction to use, see
// README.txt on how to pgo compile with POPCNT support.
#if defined(__INTEL_COMPILER) && defined(IS_64BIT) && defined(USE_POPCNT) // Intel compiler #if !defined(USE_POPCNT)
#include <nmmintrin.h>
inline bool cpu_has_popcnt() {
int CPUInfo[4] = {-1};
__cpuid(CPUInfo, 0x00000001);
return (CPUInfo[2] >> 23) & 1;
}
// Define a dummy template to workaround a compile error if _mm_popcnt_u64() is not defined.
//
// If _mm_popcnt_u64() is defined in <nmmintrin.h> it will be choosen first due to
// C++ overload rules that always prefer a function to a template with the same name.
// If not, we avoid a compile error and because cpu_has_popcnt() should return false,
// our templetized _mm_popcnt_u64() is never called anyway.
template<typename T> inline unsigned _mm_popcnt_u64(T) { return 0; } // Is never called
#define POPCNT_INTRINSIC(x) _mm_popcnt_u64(x)
#elif defined(_MSC_VER) && defined(IS_64BIT) && defined(USE_POPCNT) // Microsoft compiler
#include <intrin.h>
inline bool cpu_has_popcnt() {
int CPUInfo[4] = {-1};
__cpuid(CPUInfo, 0x00000001);
return (CPUInfo[2] >> 23) & 1;
}
// See comment of _mm_popcnt_u64<>() few lines above for an explanation.
template<typename T> inline unsigned __popcnt64(T) { return 0; } // Is never called
#define POPCNT_INTRINSIC(x) __popcnt64(x)
#else // Safe fallback for unsupported compilers or when USE_POPCNT is disabled
inline bool cpu_has_popcnt() { return false; }
#define POPCNT_INTRINSIC(x) 0 #define POPCNT_INTRINSIC(x) 0
#elif defined(_MSC_VER)
#define POPCNT_INTRINSIC(x) (int)__popcnt64(x)
#elif defined(__GNUC__)
#endif // cpu_has_popcnt() and POPCNT_INTRINSIC() definitions #define POPCNT_INTRINSIC(x) ({ \
unsigned long __ret; \
__asm__("popcnt %1, %0" : "=r" (__ret) : "r" (x)); \
__ret; })
#endif
/// Software implementation of bit count functions /// Software implementation of bit count functions
@@ -144,10 +104,23 @@ inline int count_1s_max_15(Bitboard b) {
} }
// Detect hardware POPCNT support
inline bool cpu_has_popcnt() {
int CPUInfo[4] = {-1};
__cpuid(CPUInfo, 0x00000001);
return (CPUInfo[2] >> 23) & 1;
}
// Global constant initialized at startup that is set to true if // Global constant initialized at startup that is set to true if
// CPU on which application runs supports POPCNT intrinsic. Unless // CPU on which application runs supports POPCNT intrinsic. Unless
// USE_POPCNT is not defined. // USE_POPCNT is not defined.
#if defined(USE_POPCNT)
const bool CpuHasPOPCNT = cpu_has_popcnt(); const bool CpuHasPOPCNT = cpu_has_popcnt();
#else
const bool CpuHasPOPCNT = false;
#endif
// Global constant used to print info about the use of 64 optimized // Global constant used to print info about the use of 64 optimized
+17 -5
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -390,7 +390,7 @@ void Book::close() {
/// Book::file_name() returns the file name of the currently active book, /// Book::file_name() returns the file name of the currently active book,
/// or the empty string if no book is open. /// or the empty string if no book is open.
const string Book::file_name() const { const string Book::file_name() { // Not const to compile on HP-UX 11.X
return is_open() ? fileName : ""; return is_open() ? fileName : "";
} }
@@ -399,14 +399,15 @@ const string Book::file_name() const {
/// Book::get_move() gets a book move for a given position. Returns /// Book::get_move() gets a book move for a given position. Returns
/// MOVE_NONE if no book move is found. /// MOVE_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) if (!is_open() || bookSize == 0)
return MOVE_NONE; return MOVE_NONE;
int bookMove = 0, scoresSum = 0;
uint64_t key = book_key(pos);
BookEntry entry; 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 // Choose a book move among the possible moves for the given position
for (int idx = find_key(key); idx < bookSize; idx++) for (int idx = find_key(key); idx < bookSize; idx++)
@@ -419,6 +420,17 @@ Move Book::get_move(const Position& pos) {
assert(score > 0); 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 // 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 // high score it has more probability to be choosen then a one with
// lower score. Note that first entry is always chosen. // lower score. Note that first entry is always chosen.
+6 -3
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -53,12 +53,15 @@ struct BookEntry {
}; };
class Book : private std::ifstream { class Book : private std::ifstream {
Book(const Book&); // just decleared..
Book& operator=(const Book&); // ..to avoid a warning
public: public:
Book() {}
~Book(); ~Book();
void open(const std::string& fName); void open(const std::string& fName);
void close(); void close();
const std::string file_name() const; const std::string file_name();
Move get_move(const Position& pos); Move get_move(const Position& pos, bool findBestMove);
private: private:
Book& operator>>(uint64_t& n) { n = read_integer(8); return *this; } Book& operator>>(uint64_t& n) { n = read_integer(8); return *this; }
+1 -1
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
+5 -3
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -27,7 +27,8 @@
enum Depth { enum Depth {
DEPTH_ZERO = 0, DEPTH_ZERO = 0,
DEPTH_MAX = 200 // 100 * OnePly; DEPTH_MAX = 200, // 100 * OnePly;
DEPTH_ENSURE_SIGNED = -1
}; };
@@ -48,7 +49,8 @@ inline void operator+= (Depth &d, int i) { d = Depth(int(d) + i); }
inline void operator+= (Depth &d1, Depth d2) { d1 += int(d2); } inline 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 d, int i) { return Depth(int(d) - i); }
inline Depth operator- (Depth d1, Depth d2) { return Depth(int(d1) - int(d2)); } inline Depth operator- (Depth d1, Depth d2) { return Depth(int(d1) - int(d2)); }
inline void operator-= (Depth & d, int i) { d = Depth(int(d) - i); } inline void operator-= (Depth &d, int i) { d = Depth(int(d) - i); }
inline void operator-= (Depth &d1, Depth d2) { d1 -= int(d2); }
inline Depth operator* (Depth d, int i) { return Depth(int(d) * i); } inline Depth operator* (Depth d, int i) { return Depth(int(d) * i); }
inline Depth operator* (int i, Depth d) { 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 void operator*= (Depth &d, int i) { d = Depth(int(d) * i); }
+1 -1
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
+21 -21
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -104,7 +104,7 @@ namespace {
/// attacking side a bonus for driving the defending king towards the edge /// 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. /// of the board, and for keeping the distance between the two kings small.
template<> 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.non_pawn_material(weakerSide) == Value(0));
assert(pos.piece_count(weakerSide, PAWN) == Value(0)); assert(pos.piece_count(weakerSide, PAWN) == Value(0));
@@ -130,7 +130,7 @@ Value EvaluationFunction<KXK>::apply(const Position& pos) {
/// Mate with KBN vs K. This is similar to KX vs K, but we have to drive the /// 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. /// defending king towards a corner square of the right color.
template<> 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.non_pawn_material(weakerSide) == Value(0));
assert(pos.piece_count(weakerSide, PAWN) == Value(0)); assert(pos.piece_count(weakerSide, PAWN) == Value(0));
@@ -159,7 +159,7 @@ Value EvaluationFunction<KBNK>::apply(const Position& pos) {
/// KP vs K. This endgame is evaluated with the help of a bitbase. /// KP vs K. This endgame is evaluated with the help of a bitbase.
template<> 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(strongerSide) == Value(0));
assert(pos.non_pawn_material(weakerSide) == Value(0)); assert(pos.non_pawn_material(weakerSide) == Value(0));
@@ -207,7 +207,7 @@ Value EvaluationFunction<KPK>::apply(const Position& pos) {
/// far advanced with support of the king, while the attacking king is far /// far advanced with support of the king, while the attacking king is far
/// away. /// away.
template<> 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.non_pawn_material(strongerSide) == RookValueMidgame);
assert(pos.piece_count(strongerSide, PAWN) == 0); assert(pos.piece_count(strongerSide, PAWN) == 0);
@@ -264,7 +264,7 @@ Value EvaluationFunction<KRKP>::apply(const Position& pos) {
/// KR vs KB. This is very simple, and always returns drawish scores. The /// 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. /// score is slightly bigger when the defending king is close to the edge.
template<> 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.non_pawn_material(strongerSide) == RookValueMidgame);
assert(pos.piece_count(strongerSide, PAWN) == 0); assert(pos.piece_count(strongerSide, PAWN) == 0);
@@ -280,7 +280,7 @@ Value EvaluationFunction<KRKB>::apply(const Position& pos) {
/// KR vs KN. The attacking side has slightly better winning chances than /// 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. /// in KR vs KB, particularly if the king and the knight are far apart.
template<> 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.non_pawn_material(strongerSide) == RookValueMidgame);
assert(pos.piece_count(strongerSide, PAWN) == 0); assert(pos.piece_count(strongerSide, PAWN) == 0);
@@ -304,7 +304,7 @@ Value EvaluationFunction<KRKN>::apply(const Position& pos) {
/// for the defending side in the search, this is usually sufficient to be /// for the defending side in the search, this is usually sufficient to be
/// able to win KQ vs KR. /// able to win KQ vs KR.
template<> 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.non_pawn_material(strongerSide) == QueenValueMidgame);
assert(pos.piece_count(strongerSide, PAWN) == 0); assert(pos.piece_count(strongerSide, PAWN) == 0);
@@ -323,7 +323,7 @@ Value EvaluationFunction<KQKR>::apply(const Position& pos) {
} }
template<> 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.piece_count(strongerSide, BISHOP) == 2);
assert(pos.non_pawn_material(strongerSide) == 2*BishopValueMidgame); assert(pos.non_pawn_material(strongerSide) == 2*BishopValueMidgame);
@@ -352,12 +352,12 @@ Value EvaluationFunction<KBBKN>::apply(const Position& pos) {
/// K and two minors vs K and one or two minors or K and two knights against /// K and two minors vs K and one or two minors or K and two knights against
/// king alone are always draw. /// king alone are always draw.
template<> template<>
Value EvaluationFunction<KmmKm>::apply(const Position&) { Value EvaluationFunction<KmmKm>::apply(const Position&) const {
return Value(0); return Value(0);
} }
template<> template<>
Value EvaluationFunction<KNNK>::apply(const Position&) { Value EvaluationFunction<KNNK>::apply(const Position&) const {
return Value(0); return Value(0);
} }
@@ -367,7 +367,7 @@ Value EvaluationFunction<KNNK>::apply(const Position&) {
/// returned. If not, the return value is SCALE_FACTOR_NONE, i.e. no scaling /// returned. If not, the return value is SCALE_FACTOR_NONE, i.e. no scaling
/// will be used. /// will be used.
template<> 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.non_pawn_material(strongerSide) == BishopValueMidgame);
assert(pos.piece_count(strongerSide, BISHOP) == 1); assert(pos.piece_count(strongerSide, BISHOP) == 1);
@@ -421,7 +421,7 @@ ScaleFactor ScalingFunction<KBPsK>::apply(const Position& pos) {
/// It tests for fortress draws with a rook on the third rank defended by /// It tests for fortress draws with a rook on the third rank defended by
/// a pawn. /// a pawn.
template<> 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.non_pawn_material(strongerSide) == QueenValueMidgame);
assert(pos.piece_count(strongerSide, QUEEN) == 1); assert(pos.piece_count(strongerSide, QUEEN) == 1);
@@ -452,7 +452,7 @@ ScaleFactor ScalingFunction<KQKRPs>::apply(const Position& pos) {
/// It would also be nice to rewrite the actual code for this function, /// 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. /// which is mostly copied from Glaurung 1.x, and not very pretty.
template<> 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.non_pawn_material(strongerSide) == RookValueMidgame);
assert(pos.piece_count(strongerSide, PAWN) == 1); assert(pos.piece_count(strongerSide, PAWN) == 1);
@@ -570,7 +570,7 @@ ScaleFactor ScalingFunction<KRPKR>::apply(const Position &pos) {
/// single pattern: If the stronger side has no pawns and the defending king /// single pattern: If the stronger side has no pawns and the defending king
/// is actively placed, the position is drawish. /// is actively placed, the position is drawish.
template<> 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.non_pawn_material(strongerSide) == RookValueMidgame);
assert(pos.piece_count(strongerSide, PAWN) == 2); assert(pos.piece_count(strongerSide, PAWN) == 2);
@@ -609,7 +609,7 @@ ScaleFactor ScalingFunction<KRPPKRP>::apply(const Position &pos) {
/// against king. There is just a single rule here: If all pawns are on /// 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. /// the same rook file and are blocked by the defending king, it's a draw.
template<> 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(0));
assert(pos.piece_count(strongerSide, PAWN) >= 2); assert(pos.piece_count(strongerSide, PAWN) >= 2);
@@ -655,7 +655,7 @@ ScaleFactor ScalingFunction<KPsK>::apply(const Position &pos) {
/// it's a draw. If the two bishops have opposite color, it's almost always /// it's a draw. If the two bishops have opposite color, it's almost always
/// a draw. /// a draw.
template<> 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.non_pawn_material(strongerSide) == BishopValueMidgame);
assert(pos.piece_count(strongerSide, BISHOP) == 1); assert(pos.piece_count(strongerSide, BISHOP) == 1);
@@ -708,7 +708,7 @@ ScaleFactor ScalingFunction<KBPKB>::apply(const Position &pos) {
/// KBPPKBScalingFunction scales KBPP vs KB endgames. It detects a few basic /// KBPPKBScalingFunction scales KBPP vs KB endgames. It detects a few basic
/// draws with opposite-colored bishops. /// draws with opposite-colored bishops.
template<> 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.non_pawn_material(strongerSide) == BishopValueMidgame);
assert(pos.piece_count(strongerSide, BISHOP) == 1); assert(pos.piece_count(strongerSide, BISHOP) == 1);
@@ -784,7 +784,7 @@ ScaleFactor ScalingFunction<KBPPKB>::apply(const Position& pos) {
/// square of the king is not of the same color as the stronger side's bishop, /// square of the king is not of the same color as the stronger side's bishop,
/// it's a draw. /// it's a draw.
template<> 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.non_pawn_material(strongerSide) == BishopValueMidgame);
assert(pos.piece_count(strongerSide, BISHOP) == 1); assert(pos.piece_count(strongerSide, BISHOP) == 1);
@@ -811,7 +811,7 @@ ScaleFactor ScalingFunction<KBPKN>::apply(const Position &pos) {
/// If the pawn is a rook pawn on the 7th rank and the defending king prevents /// If the pawn is a rook pawn on the 7th rank and the defending king prevents
/// the pawn from advancing, the position is drawn. /// the pawn from advancing, the position is drawn.
template<> 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.non_pawn_material(strongerSide) == KnightValueMidgame);
assert(pos.piece_count(strongerSide, KNIGHT) == 1); assert(pos.piece_count(strongerSide, KNIGHT) == 1);
@@ -841,7 +841,7 @@ ScaleFactor ScalingFunction<KNPK>::apply(const Position &pos) {
/// advanced and not on a rook file; in this case it is often possible to win /// 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). /// (e.g. 8/4k3/3p4/3P4/6K1/8/8/8 w - - 0 1).
template<> 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(strongerSide) == Value(0));
assert(pos.non_pawn_material(weakerSide) == Value(0)); assert(pos.non_pawn_material(weakerSide) == Value(0));
+4 -4
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -68,7 +68,7 @@ class EndgameFunctionBase {
public: public:
EndgameFunctionBase(Color c) : strongerSide(c), weakerSide(opposite_color(c)) {} EndgameFunctionBase(Color c) : strongerSide(c), weakerSide(opposite_color(c)) {}
virtual ~EndgameFunctionBase() {} virtual ~EndgameFunctionBase() {}
virtual T apply(const Position&) = 0; virtual T apply(const Position&) const = 0;
Color color() const { return strongerSide; } Color color() const { return strongerSide; }
protected: protected:
@@ -85,14 +85,14 @@ template<EndgameType>
struct EvaluationFunction : public EndgameEvaluationFunctionBase { struct EvaluationFunction : public EndgameEvaluationFunctionBase {
typedef EndgameEvaluationFunctionBase Base; typedef EndgameEvaluationFunctionBase Base;
explicit EvaluationFunction(Color c): EndgameEvaluationFunctionBase(c) {} explicit EvaluationFunction(Color c): EndgameEvaluationFunctionBase(c) {}
Value apply(const Position&); Value apply(const Position&) const;
}; };
template<EndgameType> template<EndgameType>
struct ScalingFunction : public EndgameScalingFunctionBase { struct ScalingFunction : public EndgameScalingFunctionBase {
typedef EndgameScalingFunctionBase Base; typedef EndgameScalingFunctionBase Base;
explicit ScalingFunction(Color c) : EndgameScalingFunctionBase(c) {} explicit ScalingFunction(Color c) : EndgameScalingFunctionBase(c) {}
ScaleFactor apply(const Position&); ScaleFactor apply(const Position&) const;
}; };
+511 -611
View File
File diff suppressed because it is too large Load Diff
+11 -12
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -25,6 +25,8 @@
//// Includes //// Includes
//// ////
#include <iostream>
#include "material.h" #include "material.h"
#include "pawns.h" #include "pawns.h"
@@ -45,8 +47,10 @@ class Position;
struct EvalInfo { struct EvalInfo {
EvalInfo() { kingDanger[0] = kingDanger[1] = Value(0); }
// Middle game and endgame evaluations // Middle game and endgame evaluations
Value mgValue, egValue; Score value;
// Pointers to material and pawn hash table entries // Pointers to material and pawn hash table entries
MaterialInfo* mi; MaterialInfo* mi;
@@ -85,15 +89,11 @@ struct EvalInfo {
// 2 to kingAdjacentZoneAttacksCount[BLACK]. // 2 to kingAdjacentZoneAttacksCount[BLACK].
int kingAdjacentZoneAttacksCount[2]; int kingAdjacentZoneAttacksCount[2];
// mateThreat[color] is a move for the given side which gives a direct mate. // Middle game and endgame mobility scores
Move mateThreat[2]; Score mobility;
// Middle game and endgame mobility scores. // Value of the danger for the king of the given color
Value mgMobility, egMobility; Value kingDanger[2];
// Extra futility margin. This is added to the standard futility margin
// in the quiescence search.
Value futilityMargin;
}; };
@@ -101,8 +101,7 @@ struct EvalInfo {
//// Prototypes //// Prototypes
//// ////
extern Value evaluate(const Position& pos, EvalInfo& ei, int threadID); extern Value evaluate(const Position& pos, EvalInfo& ei);
extern Value quick_evaluate(const Position& pos);
extern void init_eval(int threads); extern void init_eval(int threads);
extern void quit_eval(); extern void quit_eval();
extern void read_weights(Color sideToMove); extern void read_weights(Color sideToMove);
+25 -15
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -42,8 +42,7 @@ History::History() { clear(); }
void History::clear() { void History::clear() {
memset(history, 0, 2 * 8 * 64 * sizeof(int)); memset(history, 0, 2 * 8 * 64 * sizeof(int));
memset(successCount, 0, 2 * 8 * 64 * sizeof(int)); memset(maxStaticValueDelta, 0, 2 * 8 * 64 * sizeof(int));
memset(failureCount, 0, 2 * 8 * 64 * sizeof(int));
} }
@@ -58,13 +57,12 @@ void History::success(Piece p, Square to, Depth d) {
assert(square_is_ok(to)); assert(square_is_ok(to));
history[p][to] += int(d) * int(d); history[p][to] += int(d) * int(d);
successCount[p][to]++;
// Prevent history overflow // Prevent history overflow
if (history[p][to] >= HistoryMax) if (history[p][to] >= HistoryMax)
for (int i = 0; i < 16; i++) for (int i = 0; i < 16; i++)
for (int j = 0; j < 64; j++) for (int j = 0; j < 64; j++)
history[i][j] /= 4; history[i][j] /= 2;
} }
@@ -72,12 +70,18 @@ void History::success(Piece p, Square to, Depth d) {
/// called for each non-capturing move which failed to produce a beta cutoff /// called for each non-capturing move which failed to produce a beta cutoff
/// at a node where a beta cutoff was finally found. /// at a node where a beta cutoff was finally found.
void History::failure(Piece p, Square to) { void History::failure(Piece p, Square to, Depth d) {
assert(piece_is_ok(p)); assert(piece_is_ok(p));
assert(square_is_ok(to)); assert(square_is_ok(to));
failureCount[p][to]++; history[p][to] -= int(d) * int(d);
// Prevent history underflow
if (history[p][to] <= -HistoryMax)
for (int i = 0; i < 16; i++)
for (int j = 0; j < 64; j++)
history[i][j] /= 2;
} }
@@ -93,13 +97,19 @@ int History::move_ordering_score(Piece p, Square to) const {
} }
/// History::ok_to_prune() decides whether a move has been sufficiently /// History::set_gain() and History::gain() store and retrieve the
/// unsuccessful that it makes sense to prune it entirely. /// gain of a move given the delta of the static position evaluations
/// before and after the move.
bool History::ok_to_prune(Piece p, Square to, Depth d) const { void History::set_gain(Piece p, Square to, Value delta)
{
assert(piece_is_ok(p)); if (delta >= maxStaticValueDelta[p][to])
assert(square_is_ok(to)); maxStaticValueDelta[p][to] = delta;
else
return (int(d) * successCount[p][to] < failureCount[p][to]); maxStaticValueDelta[p][to]--;
}
Value History::gain(Piece p, Square to) const
{
return Value(maxStaticValueDelta[p][to]);
} }
+7 -6
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -28,6 +28,7 @@
#include "depth.h" #include "depth.h"
#include "move.h" #include "move.h"
#include "piece.h" #include "piece.h"
#include "value.h"
//// ////
@@ -47,14 +48,14 @@ public:
History(); History();
void clear(); void clear();
void success(Piece p, Square to, Depth d); void success(Piece p, Square to, Depth d);
void failure(Piece p, Square to); void failure(Piece p, Square to, Depth d);
int move_ordering_score(Piece p, Square to) const; int move_ordering_score(Piece p, Square to) const;
bool ok_to_prune(Piece p, Square to, Depth d) const; void set_gain(Piece p, Square to, Value delta);
Value gain(Piece p, Square to) const;
private: private:
int history[16][64]; // [piece][square] int history[16][64]; // [piece][square]
int successCount[16][64]; int maxStaticValueDelta[16][64]; // [piece][from_square][to_square]
int failureCount[16][64];
}; };
@@ -70,7 +71,7 @@ private:
/// recently have a bigger importance for move ordering than the moves which /// recently have a bigger importance for move ordering than the moves which
/// have been searched a long time ago. /// have been searched a long time ago.
const int HistoryMax = 25000 * OnePly; const int HistoryMax = 50000 * OnePly;
#endif // !defined(HISTORY_H_INCLUDED) #endif // !defined(HISTORY_H_INCLUDED)
+1 -2
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -99,5 +99,4 @@ typedef CRITICAL_SECTION Lock;
#endif #endif
#endif // !defined(LOCK_H_INCLUDED) #endif // !defined(LOCK_H_INCLUDED)
+19 -17
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -57,33 +57,35 @@ int main(int argc, char *argv[]) {
CALLGRIND_START_INSTRUMENTATION; CALLGRIND_START_INSTRUMENTATION;
#endif #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) if (string(argv[1]) != "bench" || argc < 4 || argc > 8)
cout << "Usage: stockfish bench <hash size> <threads> " cout << "Usage: stockfish bench <hash size> <threads> "
<< "[time = 60s] [fen positions file = default] " << "[time = 60s] [fen positions file = default] "
<< "[time, depth or node limited = time] " << "[time, depth, perft or node limited = time] "
<< "[timing file name = none]" << endl; << "[timing file name = none]" << endl;
else else
{ {
string time = argc > 4 ? argv[4] : "60"; string time = argc > 4 ? argv[4] : "60";
string fen = argc > 5 ? argv[5] : "default"; string fen = argc > 5 ? argv[5] : "default";
string lim = argc > 6 ? argv[6] : "time"; string lim = argc > 6 ? argv[6] : "time";
string tim = argc > 7 ? argv[7] : ""; string tim = argc > 7 ? argv[7] : "";
benchmark(string(argv[2]) + " " + string(argv[3]) + " " + time + " " + fen + " " + lim + " " + tim); benchmark(string(argv[2]) + " " + string(argv[3]) + " " + time + " " + fen + " " + lim + " " + tim);
} }
return 0;
} }
// Print copyright notice Application::free_resources();
cout << engine_name()
<< ". By Tord Romstad, Marco Costalba, Joona Kiiski." << endl;
if (CpuHasPOPCNT)
cout << "Good! CPU has hardware POPCNT. We will use it." << endl;
// Enter UCI mode
uci_main_loop();
return 0; return 0;
} }
+91 -66
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -37,10 +37,15 @@ using namespace std;
namespace { namespace {
// Values modified by Joona Kiiski
const Value MidgameLimit = Value(15581);
const Value EndgameLimit = Value(3998);
// Polynomial material balance parameters // Polynomial material balance parameters
const Value RedundantQueenPenalty = Value(320); const Value RedundantQueenPenalty = Value(320);
const Value RedundantRookPenalty = Value(554); const Value RedundantRookPenalty = Value(554);
const int LinearCoefficients[6] = { 1617, -162, -1172, -190, 105, 26 };
const int LinearCoefficients[6] = { 1617, -162, -1172, -190, 105, 26 };
const int QuadraticCoefficientsSameColor[][6] = { const int QuadraticCoefficientsSameColor[][6] = {
{ 7, 7, 7, 7, 7, 7 }, { 39, 2, 7, 7, 7, 7 }, { 35, 271, -4, 7, 7, 7 }, { 7, 7, 7, 7, 7, 7 }, { 39, 2, 7, 7, 7, 7 }, { 35, 271, -4, 7, 7, 7 },
@@ -50,17 +55,40 @@ namespace {
{ 41, 41, 41, 41, 41, 41 }, { 37, 41, 41, 41, 41, 41 }, { 10, 62, 41, 41, 41, 41 }, { 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 } }; { 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 EndgameEvaluationFunctionBase EF;
typedef EndgameScalingFunctionBase SF; typedef EndgameScalingFunctionBase SF;
// 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(0)
&& 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;
}
} }
@@ -129,6 +157,22 @@ MaterialInfoTable::~MaterialInfoTable() {
} }
/// MaterialInfoTable::game_phase() calculates the phase given the current
/// position. Because the phase is strictly a function of the material, it
/// is stored in MaterialInfo.
Phase MaterialInfoTable::game_phase(const Position& pos) {
Value npm = pos.non_pawn_material(WHITE) + pos.non_pawn_material(BLACK);
if (npm >= MidgameLimit)
return PHASE_MIDGAME;
else if (npm <= EndgameLimit)
return PHASE_ENDGAME;
return Phase(((npm - EndgameLimit) * 128) / (MidgameLimit - EndgameLimit));
}
/// MaterialInfoTable::get_material_info() takes a position object as input, /// MaterialInfoTable::get_material_info() takes a position object as input,
/// computes or looks up a MaterialInfo object, and returns a pointer to it. /// computes or looks up a MaterialInfo object, and returns a pointer to it.
/// If the material configuration is not already present in the table, it /// If the material configuration is not already present in the table, it
@@ -151,28 +195,22 @@ MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) {
mi->clear(); mi->clear();
mi->key = key; mi->key = key;
// Store game phase
mi->gamePhase = MaterialInfoTable::game_phase(pos);
// Let's look if we have a specialized evaluation function for this // Let's look if we have a specialized evaluation function for this
// particular material configuration. First we look for a fixed // particular material configuration. First we look for a fixed
// configuration one, then a generic one if previous search failed. // configuration one, then a generic one if previous search failed.
if ((mi->evaluationFunction = funcs->get<EF>(key)) != NULL) if ((mi->evaluationFunction = funcs->get<EF>(key)) != NULL)
return mi; return mi;
else if ( pos.non_pawn_material(BLACK) == Value(0) else if (is_KXK<WHITE>(pos) || is_KXK<BLACK>(pos))
&& pos.piece_count(BLACK, PAWN) == 0
&& pos.non_pawn_material(WHITE) >= RookValueMidgame)
{ {
mi->evaluationFunction = &EvaluateKXK; mi->evaluationFunction = is_KXK<WHITE>(pos) ? &EvaluateKXK[WHITE] : &EvaluateKXK[BLACK];
return mi; return mi;
} }
else if ( pos.non_pawn_material(WHITE) == Value(0) else if ( pos.pieces(PAWN) == EmptyBoardBB
&& pos.piece_count(WHITE, PAWN) == 0 && pos.pieces(ROOK) == EmptyBoardBB
&& 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) && pos.pieces(QUEEN) == EmptyBoardBB)
{ {
// Minor piece endgame with at least one minor piece per side and // Minor piece endgame with at least one minor piece per side and
@@ -183,7 +221,7 @@ MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) {
if ( pos.piece_count(WHITE, BISHOP) + pos.piece_count(WHITE, KNIGHT) <= 2 if ( pos.piece_count(WHITE, BISHOP) + pos.piece_count(WHITE, KNIGHT) <= 2
&& pos.piece_count(BLACK, BISHOP) + pos.piece_count(BLACK, KNIGHT) <= 2) && pos.piece_count(BLACK, BISHOP) + pos.piece_count(BLACK, KNIGHT) <= 2)
{ {
mi->evaluationFunction = &EvaluateKmmKm; mi->evaluationFunction = &EvaluateKmmKm[WHITE];
return mi; return mi;
} }
} }
@@ -191,10 +229,8 @@ MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) {
// OK, we didn't find any special evaluation function for the current // OK, we didn't find any special evaluation function for the current
// material configuration. Is there a suitable scaling function? // material configuration. Is there a suitable scaling function?
// //
// The code below is rather messy, and it could easily get worse later, // We face problems when there are several conflicting applicable
// if we decide to add more special cases. We face problems when there // scaling functions and we need to decide which one to use.
// are several conflicting applicable scaling functions and we need to
// decide which one to use.
SF* sf; SF* sf;
if ((sf = funcs->get<SF>(key)) != NULL) if ((sf = funcs->get<SF>(key)) != NULL)
@@ -206,48 +242,36 @@ MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) {
// Generic scaling functions that refer to more then one material // Generic scaling functions that refer to more then one material
// distribution. Should be probed after the specialized ones. // distribution. Should be probed after the specialized ones.
// Note that these ones don't return after setting the function. // Note that these ones don't return after setting the function.
if ( pos.non_pawn_material(WHITE) == BishopValueMidgame if (is_KBPsK<WHITE>(pos))
&& pos.piece_count(WHITE, BISHOP) == 1 mi->scalingFunction[WHITE] = &ScaleKBPsK[WHITE];
&& pos.piece_count(WHITE, PAWN) >= 1)
mi->scalingFunction[WHITE] = &ScaleKBPsK;
if ( pos.non_pawn_material(BLACK) == BishopValueMidgame if (is_KBPsK<BLACK>(pos))
&& pos.piece_count(BLACK, BISHOP) == 1 mi->scalingFunction[BLACK] = &ScaleKBPsK[BLACK];
&& pos.piece_count(BLACK, PAWN) >= 1)
mi->scalingFunction[BLACK] = &ScaleKKBPs;
if ( pos.piece_count(WHITE, PAWN) == 0 if (is_KQKRPs<WHITE>(pos))
&& pos.non_pawn_material(WHITE) == QueenValueMidgame mi->scalingFunction[WHITE] = &ScaleKQKRPs[WHITE];
&& pos.piece_count(WHITE, QUEEN) == 1
&& pos.piece_count(BLACK, ROOK) == 1
&& pos.piece_count(BLACK, PAWN) >= 1)
mi->scalingFunction[WHITE] = &ScaleKQKRPs;
else if ( pos.piece_count(BLACK, PAWN) == 0 else if (is_KQKRPs<BLACK>(pos))
&& pos.non_pawn_material(BLACK) == QueenValueMidgame mi->scalingFunction[BLACK] = &ScaleKQKRPs[BLACK];
&& pos.piece_count(BLACK, QUEEN) == 1
&& pos.piece_count(WHITE, ROOK) == 1
&& pos.piece_count(WHITE, PAWN) >= 1)
mi->scalingFunction[BLACK] = &ScaleKRPsKQ;
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(0))
{ {
if (pos.piece_count(BLACK, PAWN) == 0) if (pos.piece_count(BLACK, PAWN) == 0)
{ {
assert(pos.piece_count(WHITE, PAWN) >= 2); assert(pos.piece_count(WHITE, PAWN) >= 2);
mi->scalingFunction[WHITE] = &ScaleKPsK; mi->scalingFunction[WHITE] = &ScaleKPsK[WHITE];
} }
else if (pos.piece_count(WHITE, PAWN) == 0) else if (pos.piece_count(WHITE, PAWN) == 0)
{ {
assert(pos.piece_count(BLACK, PAWN) >= 2); 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) else if (pos.piece_count(WHITE, PAWN) == 1 && pos.piece_count(BLACK, PAWN) == 1)
{ {
// This is a special case because we set scaling functions // This is a special case because we set scaling functions
// for both colors instead of only one. // for both colors instead of only one.
mi->scalingFunction[WHITE] = &ScaleKPKPw; mi->scalingFunction[WHITE] = &ScaleKPKP[WHITE];
mi->scalingFunction[BLACK] = &ScaleKPKPb; mi->scalingFunction[BLACK] = &ScaleKPKP[BLACK];
} }
} }
@@ -269,8 +293,8 @@ MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) {
{ pos.piece_count(BLACK, BISHOP) > 1, pos.piece_count(BLACK, PAWN), pos.piece_count(BLACK, KNIGHT), { pos.piece_count(BLACK, BISHOP) > 1, pos.piece_count(BLACK, PAWN), pos.piece_count(BLACK, KNIGHT),
pos.piece_count(BLACK, BISHOP), pos.piece_count(BLACK, ROOK), pos.piece_count(BLACK, QUEEN) } }; pos.piece_count(BLACK, BISHOP), pos.piece_count(BLACK, ROOK), pos.piece_count(BLACK, QUEEN) } };
Color c, them; Color c, them;
int sign; int sign, pt1, pt2, pc;
int matValue = 0; int v, vv, matValue = 0;
for (c = WHITE, sign = 1; c <= BLACK; c++, sign = -sign) for (c = WHITE, sign = 1; c <= BLACK; c++, sign = -sign)
{ {
@@ -304,25 +328,27 @@ MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) {
matValue -= sign * ((pieceCount[c][ROOK] - 1) * RedundantRookPenalty + pieceCount[c][QUEEN] * RedundantQueenPenalty); matValue -= sign * ((pieceCount[c][ROOK] - 1) * RedundantRookPenalty + pieceCount[c][QUEEN] * RedundantQueenPenalty);
them = opposite_color(c); them = opposite_color(c);
v = 0;
// Second-degree polynomial material imbalance by Tord Romstad // 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 NO_PIECE_TYPE as a place holder for the bishop pair "extended piece",
// this allow us to be more flexible in defining bishop pair bonuses. // this allow us to be more flexible in defining bishop pair bonuses.
for (int pt1 = NO_PIECE_TYPE; pt1 <= QUEEN; pt1++) for (pt1 = NO_PIECE_TYPE; pt1 <= QUEEN; pt1++)
{ {
int c1 = sign * pieceCount[c][pt1]; pc = pieceCount[c][pt1];
if (!c1) if (!pc)
continue; continue;
matValue += c1 * LinearCoefficients[pt1]; vv = LinearCoefficients[pt1];
for (int pt2 = NO_PIECE_TYPE; pt2 <= pt1; pt2++) for (pt2 = NO_PIECE_TYPE; pt2 <= pt1; pt2++)
{ vv += pieceCount[c][pt2] * QuadraticCoefficientsSameColor[pt1][pt2]
matValue += c1 * pieceCount[c][pt2] * QuadraticCoefficientsSameColor[pt1][pt2]; + pieceCount[them][pt2] * QuadraticCoefficientsOppositeColor[pt1][pt2];
matValue += c1 * pieceCount[them][pt2] * QuadraticCoefficientsOppositeColor[pt1][pt2];
} v += pc * vv;
} }
matValue += sign * v;
} }
mi->value = int16_t(matValue / 16); mi->value = int16_t(matValue / 16);
return mi; return mi;
@@ -348,7 +374,6 @@ EndgameFunctions::EndgameFunctions() {
add<ScalingFunction<KBPPKB> >("KBPPKB"); add<ScalingFunction<KBPPKB> >("KBPPKB");
add<ScalingFunction<KBPKN> >("KBPKN"); add<ScalingFunction<KBPKN> >("KBPKN");
add<ScalingFunction<KRPPKRP> >("KRPPKRP"); add<ScalingFunction<KRPPKRP> >("KRPPKRP");
add<ScalingFunction<KRPPKRP> >("KRPPKRP");
} }
EndgameFunctions::~EndgameFunctions() { EndgameFunctions::~EndgameFunctions() {
@@ -378,7 +403,7 @@ Key EndgameFunctions::buildKey(const string& keyCode) {
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 -"; s << 8 - keyCode.length() << "/8/8/8/8/8/8/8 w -";
return Position(s.str()).get_material_key(); return Position(s.str(), 0).get_material_key();
} }
const string EndgameFunctions::swapColors(const string& keyCode) { const string EndgameFunctions::swapColors(const string& keyCode) {
+17 -4
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -51,9 +51,10 @@ class MaterialInfo {
public: public:
MaterialInfo() : key(0) { clear(); } MaterialInfo() : key(0) { clear(); }
Value material_value() const; Score material_value() const;
ScaleFactor scale_factor(const Position& pos, Color c) const; ScaleFactor scale_factor(const Position& pos, Color c) const;
int space_weight() const; int space_weight() const;
Phase game_phase() const;
bool specialized_eval_exists() const; bool specialized_eval_exists() const;
Value evaluate(const Position& pos) const; Value evaluate(const Position& pos) const;
@@ -66,6 +67,7 @@ private:
EndgameEvaluationFunctionBase* evaluationFunction; EndgameEvaluationFunctionBase* evaluationFunction;
EndgameScalingFunctionBase* scalingFunction[2]; EndgameScalingFunctionBase* scalingFunction[2];
int spaceWeight; int spaceWeight;
Phase gamePhase;
}; };
/// The MaterialInfoTable class represents a pawn hash table. It is basically /// The MaterialInfoTable class represents a pawn hash table. It is basically
@@ -81,6 +83,8 @@ public:
~MaterialInfoTable(); ~MaterialInfoTable();
MaterialInfo* get_material_info(const Position& pos); MaterialInfo* get_material_info(const Position& pos);
static Phase game_phase(const Position& pos);
private: private:
unsigned size; unsigned size;
MaterialInfo* entries; MaterialInfo* entries;
@@ -92,12 +96,13 @@ private:
//// Inline functions //// Inline functions
//// ////
/// MaterialInfo::material_value simply returns the material balance /// MaterialInfo::material_value simply returns the material balance
/// evaluation that is independent from game phase. /// evaluation that is independent from game phase.
inline Value MaterialInfo::material_value() const { inline Score MaterialInfo::material_value() const {
return Value(value); return make_score(value, value);
} }
@@ -141,6 +146,14 @@ inline int MaterialInfo::space_weight() const {
return spaceWeight; return spaceWeight;
} }
/// MaterialInfo::game_phase() returns the game phase according
/// to this material configuration.
inline Phase MaterialInfo::game_phase() const {
return gamePhase;
}
/// MaterialInfo::specialized_eval_exists decides whether there is a /// MaterialInfo::specialized_eval_exists decides whether there is a
/// specialized evaluation function for the current material configuration, /// specialized evaluation function for the current material configuration,
+99 -77
View File
@@ -41,109 +41,131 @@
email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space) email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space)
*/ */
#include "types.h"
#include "mersenne.h" #include "mersenne.h"
/* Period parameters */ namespace {
#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 */
static unsigned long mt[N]; /* the array for the state vector */ // Period parameters
static int mti=N+1; /* mti==N+1 means mt[N] is not initialized */ 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 */ unsigned long mt[N]; // The array for the state vector
static void init_genrand(unsigned long s) int mti = N + 1; // mti == N+1 means mt[N] is not initialized
{
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 */
}
}
/* initialize by an array with array-length */ // Initializes mt[N] with a seed
/* init_key is the array for initializing keys */ void init_genrand(unsigned long s) {
/* 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; }
}
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; 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 */ /* mag01[x] = x * MATRIX_A for x=0,1 */
if (mti >= N) { /* generate N words at one time */ // Generate N words at one time
int kk; if (mti >= N)
{
int kk;
if (mti == N+1) /* if init_genrand() has not been called, */ if (mti == N+1) // If init_genrand() has not been called,
init_genrand(5489UL); /* a default initial seed is used */ init_genrand(5489UL); // a default initial seed is used.
for (kk=0;kk<N-M;kk++) { 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]; 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); for ( ; kk < N-1; kk++)
mt[kk] = mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1UL]; {
} y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK); mt[kk] = mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1UL];
mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1UL]; }
y = (mt[N-1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
mti = 0; mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1UL];
mti = 0;
} }
y = mt[mti++]; y = mt[mti++];
/* Tempering */ // Tempering
y ^= (y >> 11); y ^= (y >> 11);
y ^= (y << 7) & 0x9d2c5680UL; y ^= (y << 7) & 0x9d2c5680UL;
y ^= (y << 15) & 0xefc60000UL; y ^= (y << 15) & 0xefc60000UL;
y ^= (y >> 18); y ^= (y >> 18);
return y; return y;
} }
uint64_t genrand_int64(void) { uint64_t genrand_int64() {
uint64_t x, y; uint64_t x, y;
x = genrand_int32(); y = genrand_int32(); x = genrand_int32();
return (x<<32)|y; y = genrand_int32();
return (x << 32) | y;
} }
void init_mersenne(void) { void init_mersenne() {
unsigned long init[4]={0x123, 0x234, 0x345, 0x456}, length=4;
unsigned long init[4] = {0x123, 0x234, 0x345, 0x456};
unsigned long length = 4;
init_by_array(init, length); init_by_array(init, length);
} }
+4 -4
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -32,9 +32,9 @@
//// Prototypes //// Prototypes
//// ////
extern uint32_t genrand_int32(void); extern uint32_t genrand_int32();
extern uint64_t genrand_int64(void); extern uint64_t genrand_int64();
extern void init_mersenne(void); extern void init_mersenne();
#endif // !defined(MERSENNE_H_INCLUDED) #endif // !defined(MERSENNE_H_INCLUDED)
+44 -5
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -27,6 +27,9 @@
# include <sys/time.h> # include <sys/time.h>
# include <sys/types.h> # include <sys/types.h>
# include <unistd.h> # include <unistd.h>
# if defined(__hpux)
# include <sys/pstat.h>
# endif
#else #else
@@ -36,6 +39,10 @@
#endif #endif
#if !defined(NO_PREFETCH)
# include <xmmintrin.h>
#endif
#include <cassert> #include <cassert>
#include <cstdio> #include <cstdio>
#include <iomanip> #include <iomanip>
@@ -44,13 +51,14 @@
#include "bitcount.h" #include "bitcount.h"
#include "misc.h" #include "misc.h"
#include "thread.h"
using namespace std; using namespace std;
/// Version number. If this is left empty, the current date (in the format /// Version number. If this is left empty, the current date (in the format
/// YYMMDD) is used as a version number. /// YYMMDD) is used as a version number.
static const string EngineVersion = "1.5"; static const string EngineVersion = "1.8";
static const string AppName = "Stockfish"; static const string AppName = "Stockfish";
static const string AppTag = ""; static const string AppTag = "";
@@ -143,7 +151,7 @@ const string engine_name() {
const string cpu64(CpuHas64BitPath ? " 64bit" : ""); const string cpu64(CpuHas64BitPath ? " 64bit" : "");
if (!EngineVersion.empty()) if (!EngineVersion.empty())
return AppName+ " " + EngineVersion + cpu64; return AppName + " " + EngineVersion + cpu64;
string date(__DATE__); // From compiler, format is "Sep 21 2008" string date(__DATE__); // From compiler, format is "Sep 21 2008"
string months("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec"); string months("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec");
@@ -185,7 +193,15 @@ int get_system_time() {
# if defined(_SC_NPROCESSORS_ONLN) # if defined(_SC_NPROCESSORS_ONLN)
int cpu_count() { int cpu_count() {
return Min(sysconf(_SC_NPROCESSORS_ONLN), 8); return Min(sysconf(_SC_NPROCESSORS_ONLN), MAX_THREADS);
}
# elif defined(__hpux)
int cpu_count() {
struct pst_dynamic psd;
if (pstat_getdynamic(&psd, sizeof(psd), (size_t)1, 0) == -1)
return 1;
return Min(psd.psd_proc_cnt, MAX_THREADS);
} }
# else # else
int cpu_count() { int cpu_count() {
@@ -198,7 +214,7 @@ int cpu_count() {
int cpu_count() { int cpu_count() {
SYSTEM_INFO s; SYSTEM_INFO s;
GetSystemInfo(&s); GetSystemInfo(&s);
return Min(s.dwNumberOfProcessors, 8); return Min(s.dwNumberOfProcessors, MAX_THREADS);
} }
#endif #endif
@@ -275,4 +291,27 @@ int Bioskey()
return 0; return 0;
} }
} }
#endif #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
+2 -1
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -55,6 +55,7 @@ extern const std::string engine_name();
extern int get_system_time(); extern int get_system_time();
extern int cpu_count(); extern int cpu_count();
extern int Bioskey(); extern int Bioskey();
extern void prefetch(char* addr);
//// ////
+1 -1
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
+80 -2
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -62,9 +62,83 @@ struct MoveStack {
int score; int score;
}; };
// Note that operator< is set up such that std::sort() will sort in descending order // Note that operator< is set up such that sorting will be in descending order
inline bool operator<(const MoveStack& f, const MoveStack& s) { return s.score < f.score; } inline bool operator<(const MoveStack& f, const MoveStack& s) { return s.score < f.score; }
// An helper insertion sort implementation
template<typename T>
inline void insertion_sort(T* firstMove, T* lastMove)
{
T value;
T *cur, *p, *d;
if (firstMove != lastMove)
for (cur = firstMove + 1; cur != lastMove; cur++)
{
p = d = cur;
value = *p--;
if (value < *p)
{
do *d = *p;
while (--d != firstMove && value < *--p);
*d = value;
}
}
}
// Our dedicated sort in range [firstMove, lastMove), first splits
// positive scores from ramining then order seaprately the two sets.
template<typename T>
inline void sort_moves(T* firstMove, T* lastMove, T** lastPositive)
{
T tmp;
T *p, *d;
d = lastMove;
p = firstMove - 1;
d->score = -1; // right guard
// Split positives vs non-positives
do {
while ((++p)->score > 0) {}
if (p != d)
{
while (--d != p && d->score <= 0) {}
tmp = *p;
*p = *d;
*d = tmp;
}
} while (p != d);
// Sort just positive scored moves, remaining only when we get there
insertion_sort<T>(firstMove, p);
*lastPositive = p;
}
// Picks up the best move in range [curMove, lastMove), one per cycle.
// It is faster then sorting all the moves in advance when moves are few,
// as normally are the possible captures. Note that is not a stable alghoritm.
template<typename T>
inline T pick_best(T* curMove, T* lastMove)
{
T bestMove, tmp;
bestMove = *curMove;
while (++curMove != lastMove)
{
if (*curMove < bestMove)
{
tmp = *curMove;
*curMove = bestMove;
bestMove = tmp;
}
}
return bestMove;
}
//// ////
//// Inline functions //// Inline functions
@@ -82,6 +156,10 @@ inline PieceType move_promotion_piece(Move m) {
return PieceType((int(m) >> 12) & 7); return PieceType((int(m) >> 12) & 7);
} }
inline int move_is_special(Move m) {
return m & (0x1F << 12);
}
inline int move_is_promotion(Move m) { inline int move_is_promotion(Move m) {
return m & (7 << 12); return m & (7 << 12);
} }
+238 -319
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -52,16 +52,12 @@ namespace {
EVASION EVASION
}; };
// Functions
bool castling_is_check(const Position&, CastlingSide);
// Helper templates // Helper templates
template<CastlingSide Side> template<CastlingSide Side>
MoveStack* generate_castle_moves(const Position&, MoveStack*); MoveStack* generate_castle_moves(const Position&, MoveStack*);
template<Color Us, MoveType Type> template<Color Us, MoveType Type>
MoveStack* generate_pawn_moves(const Position&, MoveStack*, Bitboard = EmptyBoardBB, MoveStack* generate_pawn_moves(const Position&, MoveStack*, Bitboard, Square);
Square = SQ_NONE, Bitboard = EmptyBoardBB);
// Template generate_piece_moves (captures and non-captures) with specializations and overloads // Template generate_piece_moves (captures and non-captures) with specializations and overloads
template<PieceType> template<PieceType>
@@ -71,37 +67,29 @@ namespace {
MoveStack* generate_piece_moves<KING>(const Position&, MoveStack*, Color, Bitboard); MoveStack* generate_piece_moves<KING>(const Position&, MoveStack*, Color, Bitboard);
template<PieceType Piece, MoveType Type> template<PieceType Piece, MoveType Type>
inline MoveStack* generate_piece_moves(const Position& p, MoveStack* m, Color us) { inline MoveStack* generate_piece_moves(const Position& p, MoveStack* m, Color us, Bitboard t) {
assert(Piece == PAWN); assert(Piece == PAWN);
assert(Type == CAPTURE || Type == NON_CAPTURE); assert(Type == CAPTURE || Type == NON_CAPTURE || Type == EVASION);
return (us == WHITE ? generate_pawn_moves<WHITE, Type>(p, m) return (us == WHITE ? generate_pawn_moves<WHITE, Type>(p, m, t, SQ_NONE)
: generate_pawn_moves<BLACK, Type>(p, m)); : generate_pawn_moves<BLACK, Type>(p, m, t, SQ_NONE));
} }
// Template generate_piece_checks with specializations // Templates for non-capture checks generation
template<PieceType Piece>
MoveStack* generate_discovered_checks(const Position&, MoveStack*, Square);
template<PieceType> template<PieceType>
MoveStack* generate_piece_checks(const Position&, MoveStack*, Color, Bitboard, Square); MoveStack* generate_direct_checks(const Position&, MoveStack*, Color, Bitboard, Square);
template<> template<>
inline MoveStack* generate_piece_checks<PAWN>(const Position& p, MoveStack* m, Color us, Bitboard dc, Square ksq) { inline MoveStack* generate_direct_checks<PAWN>(const Position& p, MoveStack* m, Color us, Bitboard dc, Square ksq) {
return (us == WHITE ? generate_pawn_moves<WHITE, CHECK>(p, m, dc, ksq) return (us == WHITE ? generate_pawn_moves<WHITE, CHECK>(p, m, dc, ksq)
: generate_pawn_moves<BLACK, CHECK>(p, m, dc, ksq)); : generate_pawn_moves<BLACK, CHECK>(p, m, dc, ksq));
} }
// Template generate_piece_evasions with specializations
template<PieceType>
MoveStack* generate_piece_evasions(const Position&, MoveStack*, Color, Bitboard, Bitboard);
template<>
inline MoveStack* generate_piece_evasions<PAWN>(const Position& p, MoveStack* m,
Color us, Bitboard t, Bitboard pnd) {
return (us == WHITE ? generate_pawn_moves<WHITE, EVASION>(p, m, pnd, SQ_NONE, t)
: generate_pawn_moves<BLACK, EVASION>(p, m, pnd, SQ_NONE, t));
}
} }
@@ -125,7 +113,7 @@ MoveStack* generate_captures(const Position& pos, MoveStack* mlist) {
mlist = generate_piece_moves<ROOK>(pos, mlist, us, target); mlist = generate_piece_moves<ROOK>(pos, mlist, us, target);
mlist = generate_piece_moves<BISHOP>(pos, mlist, us, target); mlist = generate_piece_moves<BISHOP>(pos, mlist, us, target);
mlist = generate_piece_moves<KNIGHT>(pos, mlist, us, target); mlist = generate_piece_moves<KNIGHT>(pos, mlist, us, target);
mlist = generate_piece_moves<PAWN, CAPTURE>(pos, mlist, us); mlist = generate_piece_moves<PAWN, CAPTURE>(pos, mlist, us, target);
return generate_piece_moves<KING>(pos, mlist, us, target); return generate_piece_moves<KING>(pos, mlist, us, target);
} }
@@ -141,7 +129,7 @@ MoveStack* generate_noncaptures(const Position& pos, MoveStack* mlist) {
Color us = pos.side_to_move(); Color us = pos.side_to_move();
Bitboard target = pos.empty_squares(); Bitboard target = pos.empty_squares();
mlist = generate_piece_moves<PAWN, NON_CAPTURE>(pos, mlist, us); mlist = generate_piece_moves<PAWN, NON_CAPTURE>(pos, mlist, us, target);
mlist = generate_piece_moves<KNIGHT>(pos, mlist, us, target); mlist = generate_piece_moves<KNIGHT>(pos, mlist, us, target);
mlist = generate_piece_moves<BISHOP>(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<ROOK>(pos, mlist, us, target);
@@ -152,175 +140,111 @@ MoveStack* generate_noncaptures(const Position& pos, MoveStack* mlist) {
} }
/// generate_non_capture_checks() generates all pseudo-legal non-captures and /// 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. /// underpromotions that give check. Returns a pointer to the end of the move list.
MoveStack* generate_non_capture_checks(const Position& pos, MoveStack* mlist, Bitboard dc) { MoveStack* generate_non_capture_checks(const Position& pos, MoveStack* mlist) {
assert(pos.is_ok()); assert(pos.is_ok());
assert(!pos.is_check()); assert(!pos.is_check());
Bitboard b, dc;
Square from;
Color us = pos.side_to_move(); Color us = pos.side_to_move();
Square ksq = pos.king_square(opposite_color(us)); Square ksq = pos.king_square(opposite_color(us));
assert(pos.piece_on(ksq) == piece_of_color_and_type(opposite_color(us), KING)); assert(pos.piece_on(ksq) == piece_of_color_and_type(opposite_color(us), KING));
// Pieces moves // Discovered non-capture checks
mlist = generate_piece_checks<PAWN>(pos, mlist, us, dc, ksq); b = dc = pos.discovered_check_candidates(us);
mlist = generate_piece_checks<KNIGHT>(pos, mlist, us, dc, ksq);
mlist = generate_piece_checks<BISHOP>(pos, mlist, us, dc, ksq);
mlist = generate_piece_checks<ROOK>(pos, mlist, us, dc, ksq);
mlist = generate_piece_checks<QUEEN>(pos, mlist, us, dc, ksq);
mlist = generate_piece_checks<KING>(pos, mlist, us, dc, ksq);
// Castling moves that give check. Very rare but nice to have! while (b)
if ( pos.can_castle_queenside(us) {
&& (square_rank(ksq) == square_rank(pos.king_square(us)) || square_file(ksq) == FILE_D) from = pop_1st_bit(&b);
&& castling_is_check(pos, QUEEN_SIDE)) switch (pos.type_of_piece_on(from))
mlist = generate_castle_moves<QUEEN_SIDE>(pos, mlist); {
case PAWN: /* Will be generated togheter with pawns direct checks */ break;
case KNIGHT: mlist = generate_discovered_checks<KNIGHT>(pos, mlist, from); break;
case BISHOP: mlist = generate_discovered_checks<BISHOP>(pos, mlist, from); break;
case ROOK: mlist = generate_discovered_checks<ROOK>(pos, mlist, from); break;
case KING: mlist = generate_discovered_checks<KING>(pos, mlist, from); break;
default: assert(false); break;
}
}
if ( pos.can_castle_kingside(us) // Direct non-capture checks
&& (square_rank(ksq) == square_rank(pos.king_square(us)) || square_file(ksq) == FILE_F) mlist = generate_direct_checks<PAWN>(pos, mlist, us, dc, ksq);
&& castling_is_check(pos, KING_SIDE)) mlist = generate_direct_checks<KNIGHT>(pos, mlist, us, dc, ksq);
mlist = generate_castle_moves<KING_SIDE>(pos, mlist); mlist = generate_direct_checks<BISHOP>(pos, mlist, us, dc, ksq);
mlist = generate_direct_checks<ROOK>(pos, mlist, us, dc, ksq);
return mlist; return generate_direct_checks<QUEEN>(pos, mlist, us, dc, ksq);
} }
/// generate_evasions() generates all check evasions when the side to move is /// generate_evasions() generates all pseudo-legal check evasions when
/// in check. Unlike the other move generation functions, this one generates /// the side to move is in check. Returns a pointer to the end of the move list.
/// only legal moves. Returns a pointer to the end of the move list.
MoveStack* generate_evasions(const Position& pos, MoveStack* mlist, Bitboard pinned) { MoveStack* generate_evasions(const Position& pos, MoveStack* mlist) {
assert(pos.is_ok()); assert(pos.is_ok());
assert(pos.is_check()); assert(pos.is_check());
Square from, to; Bitboard b, target;
Square from, checksq;
int checkersCnt = 0;
Color us = pos.side_to_move(); Color us = pos.side_to_move();
Color them = opposite_color(us);
Square ksq = pos.king_square(us); Square ksq = pos.king_square(us);
Bitboard sliderAttacks = EmptyBoardBB;
Bitboard checkers = pos.checkers(); Bitboard checkers = pos.checkers();
Bitboard sliderAttacks = EmptyBoardBB;
assert(pos.piece_on(ksq) == piece_of_color_and_type(us, KING)); assert(pos.piece_on(ksq) == piece_of_color_and_type(us, KING));
assert(checkers);
// The bitboard of occupied pieces without our king
Bitboard b_noKing = pos.occupied_squares();
clear_bit(&b_noKing, ksq);
// Find squares attacked by slider checkers, we will remove // Find squares attacked by slider checkers, we will remove
// them from the king evasions set so to avoid a couple // them from the king evasions set so to early skip known
// of cycles in the slow king evasions legality check loop // illegal moves and avoid an useless legality check later.
// and to be able to use attackers_to(). b = checkers;
Bitboard b = checkers & pos.pieces(BISHOP, QUEEN); do
while (b)
{ {
from = pop_1st_bit(&b); checkersCnt++;
sliderAttacks |= bishop_attacks_bb(from, b_noKing); checksq = pop_1st_bit(&b);
}
b = checkers & pos.pieces(ROOK, QUEEN); assert(pos.color_of_piece_on(checksq) == opposite_color(us));
while (b)
{ switch (pos.type_of_piece_on(checksq))
from = pop_1st_bit(&b); {
sliderAttacks |= rook_attacks_bb(from, b_noKing); case BISHOP: sliderAttacks |= BishopPseudoAttacks[checksq]; break;
} case ROOK: sliderAttacks |= RookPseudoAttacks[checksq]; break;
case QUEEN:
// In case of a queen remove also squares attacked in the other direction to
// avoid possible illegal moves when queen and king are on adjacent squares.
if (direction_is_straight(checksq, ksq))
sliderAttacks |= RookPseudoAttacks[checksq] | pos.attacks_from<BISHOP>(checksq);
else
sliderAttacks |= BishopPseudoAttacks[checksq] | pos.attacks_from<ROOK>(checksq);
default:
break;
}
} while (b);
// Generate evasions for king, capture and non capture moves // Generate evasions for king, capture and non capture moves
Bitboard enemy = pos.pieces_of_color(them); b = pos.attacks_from<KING>(ksq) & ~pos.pieces_of_color(us) & ~sliderAttacks;
Bitboard b1 = pos.attacks_from<KING>(ksq) & ~pos.pieces_of_color(us) & ~sliderAttacks; from = ksq;
while (b1) SERIALIZE_MOVES(b);
{
// Note that we can use attackers_to() only because we have already
// removed from b1 the squares attacked by slider checkers.
to = pop_1st_bit(&b1);
if (!(pos.attackers_to(to) & enemy))
(*mlist++).move = make_move(ksq, to);
}
// Generate evasions for other pieces only if not double check. We use a // Generate evasions for other pieces only if not double check
// simple bit twiddling hack here rather than calling count_1s in order to if (checkersCnt > 1)
// save some time (we know that pos.checkers() has at most two nonzero bits). return mlist;
if (!(checkers & (checkers - 1))) // Only one bit set?
{
Square checksq = first_1(checkers);
assert(pos.color_of_piece_on(checksq) == them); // Find squares where a blocking evasion or a capture of the
// checker piece is possible.
target = squares_between(checksq, ksq) | checkers;
// Generate captures of the checking piece mlist = generate_piece_moves<PAWN, EVASION>(pos, mlist, us, target);
mlist = generate_piece_moves<KNIGHT>(pos, mlist, us, target);
// Pawn captures mlist = generate_piece_moves<BISHOP>(pos, mlist, us, target);
b1 = pos.attacks_from<PAWN>(checksq, them) & pos.pieces(PAWN, us) & ~pinned; mlist = generate_piece_moves<ROOK>(pos, mlist, us, target);
while (b1) return generate_piece_moves<QUEEN>(pos, mlist, us, target);
{
from = pop_1st_bit(&b1);
if (relative_rank(us, checksq) == RANK_8)
{
(*mlist++).move = make_promotion_move(from, checksq, QUEEN);
(*mlist++).move = make_promotion_move(from, checksq, ROOK);
(*mlist++).move = make_promotion_move(from, checksq, BISHOP);
(*mlist++).move = make_promotion_move(from, checksq, KNIGHT);
} else
(*mlist++).move = make_move(from, checksq);
}
// Pieces captures
b1 = ( (pos.attacks_from<KNIGHT>(checksq) & pos.pieces(KNIGHT, us))
| (pos.attacks_from<BISHOP>(checksq) & pos.pieces(BISHOP, QUEEN, us))
| (pos.attacks_from<ROOK>(checksq) & pos.pieces(ROOK, QUEEN, us)) ) & ~pinned;
while (b1)
{
from = pop_1st_bit(&b1);
(*mlist++).move = make_move(from, checksq);
}
// Blocking check evasions are possible only if the checking piece is a slider
if (sliderAttacks)
{
Bitboard blockSquares = squares_between(checksq, ksq);
assert((pos.occupied_squares() & blockSquares) == EmptyBoardBB);
if (blockSquares)
{
mlist = generate_piece_evasions<PAWN>(pos, mlist, us, blockSquares, pinned);
mlist = generate_piece_evasions<KNIGHT>(pos, mlist, us, blockSquares, pinned);
mlist = generate_piece_evasions<BISHOP>(pos, mlist, us, blockSquares, pinned);
mlist = generate_piece_evasions<ROOK>(pos, mlist, us, blockSquares, pinned);
mlist = generate_piece_evasions<QUEEN>(pos, mlist, us, blockSquares, pinned);
}
}
// Finally, the special case of en passant captures. An en passant
// capture can only be a check evasion if the check is not a discovered
// check. If pos.ep_square() is set, the last move made must have been
// a double pawn push. If, furthermore, the checking piece is a pawn,
// an en passant check evasion may be possible.
if (pos.ep_square() != SQ_NONE && (checkers & pos.pieces(PAWN, them)))
{
to = pos.ep_square();
b1 = pos.attacks_from<PAWN>(to, them) & pos.pieces(PAWN, us);
// The checking pawn cannot be a discovered (bishop) check candidate
// otherwise we were in check also before last double push move.
assert(!bit_is_set(pos.discovered_check_candidates(them), checksq));
assert(count_1s(b1) == 1 || count_1s(b1) == 2);
b1 &= ~pinned;
while (b1)
{
from = pop_1st_bit(&b1);
// Move is always legal because checking pawn is not a discovered
// check candidate and our capturing pawn has been already tested
// against pinned pieces.
(*mlist++).move = make_ep_move(from, to);
}
}
}
return mlist;
} }
@@ -332,24 +256,25 @@ MoveStack* generate_moves(const Position& pos, MoveStack* mlist, bool pseudoLega
assert(pos.is_ok()); assert(pos.is_ok());
MoveStack *last, *cur = mlist;
Bitboard pinned = pos.pinned_pieces(pos.side_to_move()); Bitboard pinned = pos.pinned_pieces(pos.side_to_move());
if (pos.is_check())
return generate_evasions(pos, mlist, pinned);
// Generate pseudo-legal moves // Generate pseudo-legal moves
MoveStack* last = generate_captures(pos, mlist); if (pos.is_check())
last = generate_noncaptures(pos, last); last = generate_evasions(pos, mlist);
else
last = generate_noncaptures(pos, generate_captures(pos, mlist));
if (pseudoLegal) if (pseudoLegal)
return last; return last;
// Remove illegal moves from the list // Remove illegal moves from the list
for (MoveStack* cur = mlist; cur != last; cur++) while (cur != last)
if (!pos.pl_move_is_legal(cur->move, pinned)) if (pos.pl_move_is_legal(cur->move, pinned))
{ cur++;
else
cur->move = (--last)->move; cur->move = (--last)->move;
cur--;
}
return last; return last;
} }
@@ -361,10 +286,11 @@ MoveStack* generate_moves(const Position& pos, MoveStack* mlist, bool pseudoLega
bool move_is_legal(const Position& pos, const Move m) { bool move_is_legal(const Position& pos, const Move m) {
MoveStack mlist[256]; MoveStack mlist[256];
MoveStack* last = generate_moves(pos, mlist, true); MoveStack *cur, *last = generate_moves(pos, mlist, true);
for (MoveStack* cur = mlist; cur != last; cur++)
for (cur = mlist; cur != last; cur++)
if (cur->move == m) if (cur->move == m)
return pos.pl_move_is_legal(m); return pos.pl_move_is_legal(m, pos.pinned_pieces(pos.side_to_move()));
return false; return false;
} }
@@ -372,25 +298,23 @@ bool move_is_legal(const Position& pos, const Move m) {
/// Fast version of move_is_legal() that takes a position a move and a /// Fast version of move_is_legal() that takes a position a move and a
/// bitboard of pinned pieces as input, and tests whether the move is legal. /// bitboard of pinned pieces as input, and tests whether the move is legal.
/// This version must only be used when the side to move is not in check.
bool move_is_legal(const Position& pos, const Move m, Bitboard pinned) { bool move_is_legal(const Position& pos, const Move m, Bitboard pinned) {
assert(pos.is_ok()); assert(pos.is_ok());
assert(!pos.is_check());
assert(move_is_ok(m)); assert(move_is_ok(m));
assert(pinned == pos.pinned_pieces(pos.side_to_move())); assert(pinned == pos.pinned_pieces(pos.side_to_move()));
// Use a slower but simpler function for uncommon cases
if (move_is_ep(m) || move_is_castle(m))
return move_is_legal(pos, m);
Color us = pos.side_to_move(); Color us = pos.side_to_move();
Color them = opposite_color(us); Color them = opposite_color(us);
Square from = move_from(m); Square from = move_from(m);
Square to = move_to(m); Square to = move_to(m);
Piece pc = pos.piece_on(from); Piece pc = pos.piece_on(from);
// Use a slower but simpler function for uncommon cases
if (move_is_ep(m) || move_is_castle(m))
return move_is_legal(pos, m);
// If the from square is not occupied by a piece belonging to the side to // If the from square is not occupied by a piece belonging to the side to
// move, the move is obviously not legal. // move, the move is obviously not legal.
if (color_of_piece(pc) != us) if (color_of_piece(pc) != us)
@@ -414,6 +338,10 @@ bool move_is_legal(const Position& pos, const Move m, Bitboard pinned) {
||(square_rank(to) == RANK_1 && us != WHITE)) != bool(move_is_promotion(m))) ||(square_rank(to) == RANK_1 && us != WHITE)) != bool(move_is_promotion(m)))
return false; return false;
// The promotion piece, if any, must be valid
if (move_promotion_piece(m) > QUEEN || move_promotion_piece(m) == PAWN)
return false;
// Proceed according to the square delta between the origin and // Proceed according to the square delta between the origin and
// destination squares. // destination squares.
switch (direction) switch (direction)
@@ -459,13 +387,13 @@ bool move_is_legal(const Position& pos, const Move m, Bitboard pinned) {
return false; return false;
} }
// The move is pseudo-legal, check if it is also legal // The move is pseudo-legal, check if it is also legal
return pos.pl_move_is_legal(m, pinned); return pos.is_check() ? pos.pl_move_is_evasion(m, pinned) : pos.pl_move_is_legal(m, pinned);
} }
// Luckly we can handle all the other pieces in one go // Luckly we can handle all the other pieces in one go
return ( bit_is_set(pos.attacks_from(pc, from), to) return bit_is_set(pos.attacks_from(pc, from), to)
&& pos.pl_move_is_legal(m, pinned) && (pos.is_check() ? pos.pl_move_is_evasion(m, pinned) : pos.pl_move_is_legal(m, pinned))
&& !move_is_promotion(m)); && !move_is_promotion(m);
} }
@@ -474,8 +402,8 @@ namespace {
template<PieceType Piece> template<PieceType Piece>
MoveStack* generate_piece_moves(const Position& pos, MoveStack* mlist, Color us, Bitboard target) { MoveStack* generate_piece_moves(const Position& pos, MoveStack* mlist, Color us, Bitboard target) {
Square from;
Bitboard b; Bitboard b;
Square from;
const Square* ptr = pos.piece_list_begin(us, Piece); const Square* ptr = pos.piece_list_begin(us, Piece);
while ((from = *ptr++) != SQ_NONE) while ((from = *ptr++) != SQ_NONE)
@@ -497,24 +425,6 @@ namespace {
return mlist; return mlist;
} }
template<PieceType Piece>
MoveStack* generate_piece_evasions(const Position& pos, MoveStack* mlist,
Color us, Bitboard target, Bitboard pinned) {
Square from;
Bitboard b;
const Square* ptr = pos.piece_list_begin(us, Piece);
while ((from = *ptr++) != SQ_NONE)
{
if (pinned && bit_is_set(pinned, from))
continue;
b = pos.attacks_from<Piece>(from) & target;
SERIALIZE_MOVES(b);
}
return mlist;
}
template<Color Us, SquareDelta Direction> template<Color Us, SquareDelta Direction>
inline Bitboard move_pawns(Bitboard p) { inline Bitboard move_pawns(Bitboard p) {
@@ -528,8 +438,8 @@ namespace {
return p; return p;
} }
template<Color Us, SquareDelta Diagonal> template<Color Us, MoveType Type, SquareDelta Diagonal>
MoveStack* generate_pawn_diagonal_captures(MoveStack* mlist, Bitboard pawns, Bitboard enemyPieces, bool promotion) { inline MoveStack* generate_pawn_captures(MoveStack* mlist, Bitboard pawns, Bitboard enemyPieces) {
// Calculate our parametrized parameters at compile time // Calculate our parametrized parameters at compile time
const Bitboard TRank8BB = (Us == WHITE ? Rank8BB : Rank1BB); const Bitboard TRank8BB = (Us == WHITE ? Rank8BB : Rank1BB);
@@ -538,136 +448,152 @@ namespace {
const SquareDelta TDELTA_NW = (Us == WHITE ? DELTA_NW : DELTA_SW); const SquareDelta TDELTA_NW = (Us == WHITE ? DELTA_NW : DELTA_SW);
const SquareDelta TTDELTA_NE = (Diagonal == DELTA_NE ? TDELTA_NE : TDELTA_NW); const SquareDelta TTDELTA_NE = (Diagonal == DELTA_NE ? TDELTA_NE : TDELTA_NW);
Bitboard b1, b2;
Square to; Square to;
// Captures in the a1-h8 (a8-h1 for black) diagonal or in the h1-a8 (h8-a1 for black) // Captures in the a1-h8 (a8-h1 for black) diagonal or in the h1-a8 (h8-a1 for black)
Bitboard b1 = move_pawns<Us, Diagonal>(pawns) & ~TFileABB & enemyPieces; b1 = move_pawns<Us, Diagonal>(pawns) & ~TFileABB & enemyPieces;
// Capturing promotions // Capturing promotions and under-promotions
if (promotion) if (b1 & TRank8BB)
{ {
Bitboard b2 = b1 & TRank8BB; b2 = b1 & TRank8BB;
b1 &= ~TRank8BB; b1 &= ~TRank8BB;
while (b2) while (b2)
{ {
to = pop_1st_bit(&b2); to = pop_1st_bit(&b2);
(*mlist++).move = make_promotion_move(to - TTDELTA_NE, to, QUEEN);
if (Type == CAPTURE || Type == EVASION)
(*mlist++).move = make_promotion_move(to - TTDELTA_NE, to, QUEEN);
if (Type == NON_CAPTURE || Type == EVASION)
{
(*mlist++).move = make_promotion_move(to - TTDELTA_NE, to, ROOK);
(*mlist++).move = make_promotion_move(to - TTDELTA_NE, to, BISHOP);
(*mlist++).move = make_promotion_move(to - TTDELTA_NE, to, KNIGHT);
}
// This is the only possible under promotion that can give a check
// not already included in the queen-promotion. It is not sure that
// the promoted knight will give check, but it doesn't worth to verify.
if (Type == CHECK)
(*mlist++).move = make_promotion_move(to - TTDELTA_NE, to, KNIGHT);
} }
} }
// Capturing non-promotions // Serialize standard captures
SERIALIZE_MOVES_D(b1, -TTDELTA_NE); if (Type == CAPTURE || Type == EVASION)
SERIALIZE_MOVES_D(b1, -TTDELTA_NE);
return mlist; return mlist;
} }
template<Color Us, MoveType Type> template<Color Us, MoveType Type>
MoveStack* generate_pawn_moves(const Position& pos, MoveStack* mlist, Bitboard dcp, MoveStack* generate_pawn_moves(const Position& pos, MoveStack* mlist, Bitboard target, Square ksq) {
Square ksq, Bitboard blockSquares) {
// Calculate our parametrized parameters at compile time // Calculate our parametrized parameters at compile time
const Color Them = (Us == WHITE ? BLACK : WHITE); const Color Them = (Us == WHITE ? BLACK : WHITE);
const Bitboard TRank8BB = (Us == WHITE ? Rank8BB : Rank1BB); const Bitboard TRank8BB = (Us == WHITE ? Rank8BB : Rank1BB);
const Bitboard TRank7BB = (Us == WHITE ? Rank7BB : Rank2BB); const Bitboard TRank7BB = (Us == WHITE ? Rank7BB : Rank2BB);
const Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB); const Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB);
const SquareDelta TDELTA_NE = (Us == WHITE ? DELTA_NE : DELTA_SE);
const SquareDelta TDELTA_NW = (Us == WHITE ? DELTA_NW : DELTA_SW);
const SquareDelta TDELTA_N = (Us == WHITE ? DELTA_N : DELTA_S); const SquareDelta TDELTA_N = (Us == WHITE ? DELTA_N : DELTA_S);
Bitboard b1, b2, dcPawns1, dcPawns2;
Square to; Square to;
Bitboard pawns = (Type == EVASION ? pos.pieces(PAWN, Us) & ~dcp : pos.pieces(PAWN, Us)); Bitboard b1, b2, enemyPieces, emptySquares;
bool possiblePromotion = pawns & TRank7BB; Bitboard pawns = pos.pieces(PAWN, Us);
if (Type == CAPTURE) // Standard captures and capturing promotions and underpromotions
if (Type == CAPTURE || Type == EVASION || (pawns & TRank7BB))
{ {
// Standard captures and capturing promotions in both directions enemyPieces = (Type == CAPTURE ? target : pos.pieces_of_color(opposite_color(Us)));
Bitboard enemyPieces = pos.pieces_of_color(opposite_color(Us));
mlist = generate_pawn_diagonal_captures<Us, DELTA_NE>(mlist, pawns, enemyPieces, possiblePromotion); if (Type == EVASION)
mlist = generate_pawn_diagonal_captures<Us, DELTA_NW>(mlist, pawns, enemyPieces, possiblePromotion); enemyPieces &= target; // Capture only the checker piece
mlist = generate_pawn_captures<Us, Type, DELTA_NE>(mlist, pawns, enemyPieces);
mlist = generate_pawn_captures<Us, Type, DELTA_NW>(mlist, pawns, enemyPieces);
} }
if (possiblePromotion) // Non-capturing promotions and underpromotions
if (pawns & TRank7BB)
{ {
// When generating checks consider under-promotion moves (both captures b1 = move_pawns<Us, DELTA_N>(pawns) & TRank8BB & pos.empty_squares();
// and non captures) only if can give a discovery check. Note that dcp
// is dc bitboard or pinned bitboard when Type == EVASION.
Bitboard pp = (Type == CHECK ? pawns & dcp : pawns);
if (Type != EVASION && Type != CAPTURE) if (Type == EVASION)
{ b1 &= target; // Only blocking promotion pushes
Bitboard enemyPieces = pos.pieces_of_color(opposite_color(Us));
// Underpromotion captures in the a1-h8 (a8-h1 for black) direction
b1 = move_pawns<Us, DELTA_NE>(pp) & ~FileABB & enemyPieces & TRank8BB;
while (b1)
{
to = pop_1st_bit(&b1);
(*mlist++).move = make_promotion_move(to - TDELTA_NE, to, ROOK);
(*mlist++).move = make_promotion_move(to - TDELTA_NE, to, BISHOP);
(*mlist++).move = make_promotion_move(to - TDELTA_NE, to, KNIGHT);
}
// Underpromotion captures in the h1-a8 (h8-a1 for black) direction
b1 = move_pawns<Us, DELTA_NW>(pp) & ~FileHBB & enemyPieces & TRank8BB;
while (b1)
{
to = pop_1st_bit(&b1);
(*mlist++).move = make_promotion_move(to - TDELTA_NW, to, ROOK);
(*mlist++).move = make_promotion_move(to - TDELTA_NW, to, BISHOP);
(*mlist++).move = make_promotion_move(to - TDELTA_NW, to, KNIGHT);
}
}
// Underpromotion pawn pushes. Also queen promotions for evasions and captures.
b1 = move_pawns<Us, DELTA_N>(pp) & TRank8BB;
b1 &= (Type == EVASION ? blockSquares : pos.empty_squares());
while (b1) while (b1)
{ {
to = pop_1st_bit(&b1); to = pop_1st_bit(&b1);
if (Type == EVASION || Type == CAPTURE)
if (Type == CAPTURE || Type == EVASION)
(*mlist++).move = make_promotion_move(to - TDELTA_N, to, QUEEN); (*mlist++).move = make_promotion_move(to - TDELTA_N, to, QUEEN);
if (Type != CAPTURE) if (Type == NON_CAPTURE || Type == EVASION)
{ {
(*mlist++).move = make_promotion_move(to - TDELTA_N, to, ROOK); (*mlist++).move = make_promotion_move(to - TDELTA_N, to, ROOK);
(*mlist++).move = make_promotion_move(to - TDELTA_N, to, BISHOP); (*mlist++).move = make_promotion_move(to - TDELTA_N, to, BISHOP);
(*mlist++).move = make_promotion_move(to - TDELTA_N, to, KNIGHT); (*mlist++).move = make_promotion_move(to - TDELTA_N, to, KNIGHT);
} }
// This is the only possible under promotion that can give a check
// not already included in the queen-promotion.
if (Type == CHECK && bit_is_set(pos.attacks_from<KNIGHT>(to), pos.king_square(Them)))
(*mlist++).move = make_promotion_move(to - TDELTA_N, to, KNIGHT);
} }
} }
// Standard pawn pushes and double pushes
if (Type != CAPTURE) if (Type != CAPTURE)
{ {
Bitboard emptySquares = pos.empty_squares(); emptySquares = (Type == NON_CAPTURE ? target : pos.empty_squares());
dcPawns1 = dcPawns2 = EmptyBoardBB;
if (Type == CHECK && (pawns & dcp))
{
// Pawn moves which gives discovered check. This is possible only if the
// pawn is not on the same file as the enemy king, because we don't
// generate captures.
dcPawns1 = move_pawns<Us, DELTA_N>(pawns & dcp & ~file_bb(ksq)) & emptySquares & ~TRank8BB;
dcPawns2 = move_pawns<Us, DELTA_N>(dcPawns1 & TRank3BB) & emptySquares;
}
// Single pawn pushes // Single and double pawn pushes
b1 = move_pawns<Us, DELTA_N>(pawns) & emptySquares & ~TRank8BB; b1 = move_pawns<Us, DELTA_N>(pawns) & emptySquares & ~TRank8BB;
b2 = (Type == CHECK ? (b1 & pos.attacks_from<PAWN>(ksq, Them)) | dcPawns1 : b2 = move_pawns<Us, DELTA_N>(b1 & TRank3BB) & emptySquares;
(Type == EVASION ? b1 & blockSquares : b1));
SERIALIZE_MOVES_D(b2, -TDELTA_N);
// Double pawn pushes // Filter out unwanted pushes according to the move type
b1 = move_pawns<Us, DELTA_N>(b1 & TRank3BB) & emptySquares; if (Type == EVASION)
b2 = (Type == CHECK ? (b1 & pos.attacks_from<PAWN>(ksq, Them)) | dcPawns2 : {
(Type == EVASION ? b1 & blockSquares : b1)); b1 &= target;
b2 &= target;
}
else if (Type == CHECK)
{
// Pawn moves which give direct cheks
b1 &= pos.attacks_from<PAWN>(ksq, Them);
b2 &= pos.attacks_from<PAWN>(ksq, Them);
// Pawn moves which gives discovered check. This is possible only if
// the pawn is not on the same file as the enemy king, because we
// don't generate captures.
if (pawns & target) // For CHECK type target is dc bitboard
{
Bitboard dc1 = move_pawns<Us, DELTA_N>(pawns & target & ~file_bb(ksq)) & emptySquares & ~TRank8BB;
Bitboard dc2 = move_pawns<Us, DELTA_N>(dc1 & TRank3BB) & emptySquares;
b1 |= dc1;
b2 |= dc2;
}
}
SERIALIZE_MOVES_D(b1, -TDELTA_N);
SERIALIZE_MOVES_D(b2, -TDELTA_N -TDELTA_N); SERIALIZE_MOVES_D(b2, -TDELTA_N -TDELTA_N);
} }
else if (pos.ep_square() != SQ_NONE) // En passant captures
// En passant captures
if ((Type == CAPTURE || Type == EVASION) && pos.ep_square() != SQ_NONE)
{ {
assert(Us != WHITE || square_rank(pos.ep_square()) == RANK_6); assert(Us != WHITE || square_rank(pos.ep_square()) == RANK_6);
assert(Us != BLACK || square_rank(pos.ep_square()) == RANK_3); assert(Us != BLACK || square_rank(pos.ep_square()) == RANK_3);
// An en passant capture can be an evasion only if the checking piece
// is the double pushed pawn and so is in the target. Otherwise this
// is a discovery check and we are forced to do otherwise.
if (Type == EVASION && !bit_is_set(target, pos.ep_square() - TDELTA_N))
return mlist;
b1 = pawns & pos.attacks_from<PAWN>(pos.ep_square(), Them); b1 = pawns & pos.attacks_from<PAWN>(pos.ep_square(), Them);
assert(b1 != EmptyBoardBB); assert(b1 != EmptyBoardBB);
while (b1) while (b1)
@@ -680,43 +606,49 @@ namespace {
} }
template<PieceType Piece> template<PieceType Piece>
MoveStack* generate_piece_checks(const Position& pos, MoveStack* mlist, Color us, MoveStack* generate_discovered_checks(const Position& pos, MoveStack* mlist, Square from) {
assert(Piece != QUEEN);
Bitboard b = pos.attacks_from<Piece>(from) & pos.empty_squares();
if (Piece == KING)
{
Square ksq = pos.king_square(opposite_color(pos.side_to_move()));
b &= ~QueenPseudoAttacks[ksq];
}
SERIALIZE_MOVES(b);
return mlist;
}
template<PieceType Piece>
MoveStack* generate_direct_checks(const Position& pos, MoveStack* mlist, Color us,
Bitboard dc, Square ksq) { Bitboard dc, Square ksq) {
assert(Piece != KING);
Bitboard target = pos.pieces(Piece, us); Bitboard checkSqs, b;
Square from;
const Square* ptr = pos.piece_list_begin(us, Piece);
// Discovered non-capture checks if ((from = *ptr++) == SQ_NONE)
Bitboard b = target & dc; return mlist;
assert(Piece != QUEEN || !b); checkSqs = pos.attacks_from<Piece>(ksq) & pos.empty_squares();
while (b) do
{ {
Square from = pop_1st_bit(&b); if ( (Piece == QUEEN && !(QueenPseudoAttacks[from] & checkSqs))
Bitboard bb = pos.attacks_from<Piece>(from) & pos.empty_squares(); || (Piece == ROOK && !(RookPseudoAttacks[from] & checkSqs))
if (Piece == KING) || (Piece == BISHOP && !(BishopPseudoAttacks[from] & checkSqs)))
bb &= ~QueenPseudoAttacks[ksq]; continue;
SERIALIZE_MOVES(bb); if (dc && bit_is_set(dc, from))
} continue;
// Direct non-capture checks b = pos.attacks_from<Piece>(from) & checkSqs;
b = target & ~dc; SERIALIZE_MOVES(b);
Bitboard checkSqs = pos.attacks_from<Piece>(ksq) & pos.empty_squares();
if (Piece != KING && checkSqs) } while ((from = *ptr++) != SQ_NONE);
{
while (b)
{
Square from = pop_1st_bit(&b);
if ( (Piece == QUEEN && !(QueenPseudoAttacks[from] & checkSqs))
|| (Piece == ROOK && !(RookPseudoAttacks[from] & checkSqs))
|| (Piece == BISHOP && !(BishopPseudoAttacks[from] & checkSqs)))
continue;
Bitboard bb = pos.attacks_from<Piece>(from) & checkSqs;
SERIALIZE_MOVES(bb);
}
}
return mlist; return mlist;
} }
@@ -762,17 +694,4 @@ namespace {
} }
return mlist; return mlist;
} }
bool castling_is_check(const Position& pos, CastlingSide side) {
// After castling opponent king is attacked by the castled rook?
File rookFile = (side == QUEEN_SIDE ? FILE_D : FILE_F);
Color us = pos.side_to_move();
Square ksq = pos.king_square(us);
Bitboard occ = pos.occupied_squares();
clear_bit(&occ, ksq); // Remove our king from the board
Square rsq = make_square(rookFile, square_rank(ksq));
return bit_is_set(rook_attacks_bb(rsq, occ), pos.king_square(opposite_color(us)));
}
} }
+3 -3
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -34,8 +34,8 @@
extern MoveStack* generate_captures(const Position& pos, MoveStack* mlist); extern MoveStack* generate_captures(const Position& pos, MoveStack* mlist);
extern MoveStack* generate_noncaptures(const Position& pos, MoveStack* mlist); extern MoveStack* generate_noncaptures(const Position& pos, MoveStack* mlist);
extern MoveStack* generate_non_capture_checks(const Position& pos, MoveStack* mlist, Bitboard dc); extern MoveStack* generate_non_capture_checks(const Position& pos, MoveStack* mlist);
extern MoveStack* generate_evasions(const Position& pos, MoveStack* mlist, Bitboard pinned); extern MoveStack* generate_evasions(const Position& pos, MoveStack* mlist);
extern MoveStack* generate_moves(const Position& pos, MoveStack* mlist, bool pseudoLegal = false); 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, Bitboard pinned);
extern bool move_is_legal(const Position& pos, const Move m); extern bool move_is_legal(const Position& pos, const Move m);
+80 -71
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -23,7 +23,6 @@
//// Includes //// Includes
//// ////
#include <algorithm>
#include <cassert> #include <cassert>
#include "history.h" #include "history.h"
@@ -53,7 +52,7 @@ namespace {
CACHE_LINE_ALIGNMENT CACHE_LINE_ALIGNMENT
const uint8_t MainSearchPhaseTable[] = { PH_TT_MOVES, PH_GOOD_CAPTURES, PH_KILLERS, PH_NONCAPTURES, PH_BAD_CAPTURES, PH_STOP}; const uint8_t MainSearchPhaseTable[] = { PH_TT_MOVES, PH_GOOD_CAPTURES, PH_KILLERS, PH_NONCAPTURES, PH_BAD_CAPTURES, PH_STOP};
const uint8_t EvasionsPhaseTable[] = { PH_EVASIONS, PH_STOP}; const uint8_t EvasionsPhaseTable[] = { PH_TT_MOVES, PH_EVASIONS, PH_STOP};
const uint8_t QsearchWithChecksPhaseTable[] = { PH_TT_MOVES, PH_QCAPTURES, PH_QCHECKS, PH_STOP}; const uint8_t QsearchWithChecksPhaseTable[] = { PH_TT_MOVES, PH_QCAPTURES, PH_QCHECKS, PH_STOP};
const uint8_t QsearchWithoutChecksPhaseTable[] = { PH_TT_MOVES, PH_QCAPTURES, PH_STOP}; const uint8_t QsearchWithoutChecksPhaseTable[] = { PH_TT_MOVES, PH_QCAPTURES, PH_STOP};
} }
@@ -71,37 +70,49 @@ namespace {
/// search captures, promotions and some checks) and about how important good /// search captures, promotions and some checks) and about how important good
/// move ordering is at the current node. /// move ordering is at the current node.
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const History& h,
const History& h, SearchStack* ss) : pos(p), H(h) { SearchStack* ss, Value beta) : pos(p), H(h) {
int searchTT = ttm; int searchTT = ttm;
ttMoves[0].move = ttm; ttMoves[0].move = ttm;
finished = false; badCaptureThreshold = 0;
lastBadCapture = badCaptures; lastBadCapture = badCaptures;
if (ss) 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; searchTT |= ttMoves[1].move;
killers[0].move = ss->killers[0]; killers[0].move = ss->killers[0];
killers[1].move = ss->killers[1]; killers[1].move = ss->killers[1];
} else } else
ttMoves[1].move = killers[0].move = killers[1].move = MOVE_NONE; ttMoves[1].move = killers[0].move = killers[1].move = MOVE_NONE;
Color us = pos.side_to_move();
dc = p.discovered_check_candidates(us);
pinned = p.pinned_pieces(us);
if (p.is_check()) if (p.is_check())
phasePtr = EvasionsPhaseTable; phasePtr = EvasionsPhaseTable;
else if (d > Depth(0)) else if (d > Depth(0))
phasePtr = MainSearchPhaseTable + !searchTT; {
else if (d == Depth(0)) // Consider sligtly negative captures as good if at low
phasePtr = QsearchWithChecksPhaseTable + !searchTT; // depth and far from beta.
else if (ss && ss->eval < beta - PawnValueMidgame && d < 3 * OnePly)
phasePtr = QsearchWithoutChecksPhaseTable + !searchTT; badCaptureThreshold = -PawnValueMidgame;
phasePtr--; phasePtr = MainSearchPhaseTable;
}
else if (d == Depth(0))
phasePtr = QsearchWithChecksPhaseTable;
else
{
phasePtr = QsearchWithoutChecksPhaseTable;
// Skip TT move if is not a capture or a promotion, this avoids
// qsearch tree explosion due to a possible perpetual check or
// similar rare cases when TT table is full.
if (ttm != MOVE_NONE && !pos.move_is_capture_or_promotion(ttm))
searchTT = ttMoves[0].move = MOVE_NONE;
}
phasePtr += int(!searchTT) - 1;
go_next_phase(); go_next_phase();
} }
@@ -123,7 +134,6 @@ void MovePicker::go_next_phase() {
case PH_GOOD_CAPTURES: case PH_GOOD_CAPTURES:
lastMove = generate_captures(pos, moves); lastMove = generate_captures(pos, moves);
score_captures(); score_captures();
std::sort(moves, lastMove);
return; return;
case PH_KILLERS: case PH_KILLERS:
@@ -134,7 +144,7 @@ void MovePicker::go_next_phase() {
case PH_NONCAPTURES: case PH_NONCAPTURES:
lastMove = generate_noncaptures(pos, moves); lastMove = generate_noncaptures(pos, moves);
score_noncaptures(); score_noncaptures();
std::sort(moves, lastMove); sort_moves(moves, lastMove, &lastGoodNonCapture);
return; return;
case PH_BAD_CAPTURES: case PH_BAD_CAPTURES:
@@ -142,29 +152,26 @@ void MovePicker::go_next_phase() {
// to get SEE move ordering. // to get SEE move ordering.
curMove = badCaptures; curMove = badCaptures;
lastMove = lastBadCapture; lastMove = lastBadCapture;
std::sort(badCaptures, lastMove);
return; return;
case PH_EVASIONS: case PH_EVASIONS:
assert(pos.is_check()); assert(pos.is_check());
lastMove = generate_evasions(pos, moves, pinned); lastMove = generate_evasions(pos, moves);
score_evasions(); score_evasions_or_checks();
std::sort(moves, lastMove);
return; return;
case PH_QCAPTURES: case PH_QCAPTURES:
lastMove = generate_captures(pos, moves); lastMove = generate_captures(pos, moves);
score_captures(); score_captures();
std::sort(moves, lastMove);
return; return;
case PH_QCHECKS: case PH_QCHECKS:
// Perhaps we should order moves move here? FIXME lastMove = generate_non_capture_checks(pos, moves);
lastMove = generate_non_capture_checks(pos, moves, dc); score_evasions_or_checks();
return; return;
case PH_STOP: case PH_STOP:
lastMove = curMove + 1; // hack to be friendly for get_next_move() lastMove = curMove + 1; // Avoids another go_next_phase() call
return; return;
default: default:
@@ -202,8 +209,8 @@ void MovePicker::score_captures() {
if (move_is_promotion(m)) if (move_is_promotion(m))
cur->score = QueenValueMidgame; cur->score = QueenValueMidgame;
else else
cur->score = int(pos.midgame_value_of_piece_on(move_to(m))) cur->score = pos.midgame_value_of_piece_on(move_to(m))
-int(pos.type_of_piece_on(move_from(m))); - pos.type_of_piece_on(move_from(m));
} }
} }
@@ -224,29 +231,36 @@ void MovePicker::score_noncaptures() {
piece = pos.piece_on(from); piece = pos.piece_on(from);
hs = H.move_ordering_score(piece, to); hs = H.move_ordering_score(piece, to);
// Ensure history is always preferred to pst // Ensure history has always highest priority
if (hs > 0) if (hs > 0)
hs += 1000; hs += 10000;
// pst based scoring // Gain table based scoring
cur->score = hs + pos.pst_delta<Position::MidGame>(piece, from, to); cur->score = hs + 16 * H.gain(piece, to);
} }
} }
void MovePicker::score_evasions() { void MovePicker::score_evasions_or_checks() {
// Try good captures ordered by MVV/LVA, then non-captures if
// destination square is not under attack, ordered by history
// value, and at the end bad-captures and non-captures with a
// negative SEE. This last group is ordered by the SEE score.
Move m; Move m;
int seeScore;
// Skip if we don't have at least two moves to order
if (lastMove < moves + 2)
return;
for (MoveStack* cur = moves; cur != lastMove; cur++) for (MoveStack* cur = moves; cur != lastMove; cur++)
{ {
m = cur->move; m = cur->move;
if (m == ttMoves[0].move) if ((seeScore = pos.see_sign(m)) < 0)
cur->score = 2 * HistoryMax; cur->score = seeScore - HistoryMax; // Be sure are at the bottom
else if (!pos.square_is_empty(move_to(m))) else if (pos.move_is_capture(m))
{ cur->score = pos.midgame_value_of_piece_on(move_to(m))
int seeScore = pos.see(m); - pos.type_of_piece_on(move_from(m)) + HistoryMax;
cur->score = seeScore + (seeScore >= 0 ? HistoryMax : 0); else
} else
cur->score = H.move_ordering_score(pos.piece_on(move_from(m)), move_to(m)); cur->score = H.move_ordering_score(pos.piece_on(move_from(m)), move_to(m));
} }
} }
@@ -256,36 +270,35 @@ void MovePicker::score_evasions() {
/// are no more moves left. /// are no more moves left.
/// It picks the move with the biggest score from a list of generated moves taking /// It picks the move with the biggest score from a list of generated moves taking
/// care not to return the tt move if has already been searched previously. /// care not to return the tt move if has already been searched previously.
/// Note that this function is not thread safe so should be lock protected by
/// caller when accessed through a shared MovePicker object.
Move MovePicker::get_next_move() { Move MovePicker::get_next_move() {
assert(!pos.is_check() || *phasePtr == PH_EVASIONS || *phasePtr == PH_STOP);
assert( pos.is_check() || *phasePtr != PH_EVASIONS);
Move move; Move move;
while (true) while (true)
{ {
while (curMove != lastMove) while (curMove != lastMove)
{ {
move = (curMove++)->move;
switch (phase) { switch (phase) {
case PH_TT_MOVES: case PH_TT_MOVES:
move = (curMove++)->move;
if ( move != MOVE_NONE if ( move != MOVE_NONE
&& move_is_legal(pos, move, pinned)) && move_is_legal(pos, move, pinned))
return move; return move;
break; break;
case PH_GOOD_CAPTURES: case PH_GOOD_CAPTURES:
move = pick_best(curMove++, lastMove).move;
if ( move != ttMoves[0].move if ( move != ttMoves[0].move
&& move != ttMoves[1].move && move != ttMoves[1].move
&& pos.pl_move_is_legal(move, pinned)) && pos.pl_move_is_legal(move, pinned))
{ {
// Check for a non negative SEE now // Check for a non negative SEE now
int seeValue = pos.see_sign(move); int seeValue = pos.see_sign(move);
if (seeValue >= 0) if (seeValue >= badCaptureThreshold)
return move; return move;
// Losing capture, move it to the badCaptures[] array, note // Losing capture, move it to the badCaptures[] array, note
@@ -298,15 +311,22 @@ Move MovePicker::get_next_move() {
break; break;
case PH_KILLERS: case PH_KILLERS:
move = (curMove++)->move;
if ( move != MOVE_NONE if ( move != MOVE_NONE
&& move_is_legal(pos, move, pinned)
&& move != ttMoves[0].move && move != ttMoves[0].move
&& move != ttMoves[1].move && move != ttMoves[1].move
&& move_is_legal(pos, move, pinned)
&& !pos.move_is_capture(move)) && !pos.move_is_capture(move))
return move; return move;
break; break;
case PH_NONCAPTURES: case PH_NONCAPTURES:
// Sort negative scored moves only when we get there
if (curMove == lastGoodNonCapture)
insertion_sort(lastGoodNonCapture, lastMove);
move = (curMove++)->move;
if ( move != ttMoves[0].move if ( move != ttMoves[0].move
&& move != ttMoves[1].move && move != ttMoves[1].move
&& move != killers[0].move && move != killers[0].move
@@ -315,13 +335,20 @@ Move MovePicker::get_next_move() {
return move; return move;
break; break;
case PH_EVASIONS:
case PH_BAD_CAPTURES: case PH_BAD_CAPTURES:
move = pick_best(curMove++, lastMove).move;
return move; return move;
case PH_EVASIONS:
case PH_QCAPTURES: case PH_QCAPTURES:
move = pick_best(curMove++, lastMove).move;
if ( move != ttMoves[0].move
&& pos.pl_move_is_legal(move, pinned))
return move;
break;
case PH_QCHECKS: case PH_QCHECKS:
// Maybe postpone the legality check until after futility pruning? move = (curMove++)->move;
if ( move != ttMoves[0].move if ( move != ttMoves[0].move
&& pos.pl_move_is_legal(move, pinned)) && pos.pl_move_is_legal(move, pinned))
return move; return move;
@@ -339,21 +366,3 @@ Move MovePicker::get_next_move() {
} }
} }
/// A variant of get_next_move() which takes a lock as a parameter, used to
/// prevent multiple threads from picking the same move at a split point.
Move MovePicker::get_next_move(Lock &lock) {
lock_grab(&lock);
if (finished)
{
lock_release(&lock);
return MOVE_NONE;
}
Move m = get_next_move();
if (m == MOVE_NONE)
finished = true;
lock_release(&lock);
return m;
}
+6 -18
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -27,7 +27,6 @@
#include "depth.h" #include "depth.h"
#include "history.h" #include "history.h"
#include "lock.h"
#include "position.h" #include "position.h"
@@ -50,26 +49,23 @@ class MovePicker {
MovePicker& operator=(const MovePicker&); // silence a warning under MSVC MovePicker& operator=(const MovePicker&); // silence a warning under MSVC
public: public:
MovePicker(const Position& p, Move ttm, Depth d, const History& h, SearchStack* ss = NULL); MovePicker(const Position& p, Move ttm, Depth d, const History& h, SearchStack* ss = NULL, Value beta = -VALUE_INFINITE);
Move get_next_move(); Move get_next_move();
Move get_next_move(Lock& lock);
int number_of_evasions() const; int number_of_evasions() const;
Bitboard discovered_check_candidates() const;
private: private:
void score_captures(); void score_captures();
void score_noncaptures(); void score_noncaptures();
void score_evasions(); void score_evasions_or_checks();
void go_next_phase(); void go_next_phase();
const Position& pos; const Position& pos;
const History& H; const History& H;
Bitboard pinned;
MoveStack ttMoves[2], killers[2]; MoveStack ttMoves[2], killers[2];
bool finished; int badCaptureThreshold, phase;
int phase;
const uint8_t* phasePtr; const uint8_t* phasePtr;
MoveStack *curMove, *lastMove, *lastBadCapture; MoveStack *curMove, *lastMove, *lastGoodNonCapture, *lastBadCapture;
Bitboard dc, pinned;
MoveStack moves[256], badCaptures[64]; MoveStack moves[256], badCaptures[64];
}; };
@@ -88,12 +84,4 @@ inline int MovePicker::number_of_evasions() const {
return int(lastMove - moves); return int(lastMove - moves);
} }
/// MovePicker::discovered_check_candidates() returns a bitboard containing
/// all pieces which can possibly give discovered check. This bitboard is
/// computed by the constructor function.
inline Bitboard MovePicker::discovered_check_candidates() const {
return dc;
}
#endif // !defined(MOVEPICK_H_INCLUDED) #endif // !defined(MOVEPICK_H_INCLUDED)
+198 -258
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -38,64 +38,36 @@ namespace {
/// Constants and variables /// Constants and variables
// Doubled pawn penalty by file, middle game #define S(mg, eg) make_score(mg, eg)
const Value DoubledPawnMidgamePenalty[8] = {
Value(13), Value(20), Value(23), Value(23), // Doubled pawn penalty by file
Value(23), Value(23), Value(20), Value(13) const Score DoubledPawnPenalty[8] = {
S(13, 43), S(20, 48), S(23, 48), S(23, 48),
S(23, 48), S(23, 48), S(20, 48), S(13, 43)
}; };
// Doubled pawn penalty by file, endgame // Isolated pawn penalty by file
const Value DoubledPawnEndgamePenalty[8] = { const Score IsolatedPawnPenalty[8] = {
Value(43), Value(48), Value(48), Value(48), S(25, 30), S(36, 35), S(40, 35), S(40, 35),
Value(48), Value(48), Value(48), Value(43) S(40, 35), S(40, 35), S(36, 35), S(25, 30)
}; };
// Isolated pawn penalty by file, middle game // Backward pawn penalty by file
const Value IsolatedPawnMidgamePenalty[8] = { const Score BackwardPawnPenalty[8] = {
Value(25), Value(36), Value(40), Value(40), S(20, 28), S(29, 31), S(33, 31), S(33, 31),
Value(40), Value(40), Value(36), Value(25) S(33, 31), S(33, 31), S(29, 31), S(20, 28)
}; };
// Isolated pawn penalty by file, endgame // Pawn chain membership bonus by file
const Value IsolatedPawnEndgamePenalty[8] = { const Score ChainBonus[8] = {
Value(30), Value(35), Value(35), Value(35), S(11,-1), S(13,-1), S(13,-1), S(14,-1),
Value(35), Value(35), Value(35), Value(30) S(14,-1), S(13,-1), S(13,-1), S(11,-1)
}; };
// Backward pawn penalty by file, middle game // Candidate passed pawn bonus by rank
const Value BackwardPawnMidgamePenalty[8] = { const Score CandidateBonus[8] = {
Value(20), Value(29), Value(33), Value(33), S( 0, 0), S( 6, 13), S(6,13), S(14,29),
Value(33), Value(33), Value(29), Value(20) S(34,68), S(83,166), S(0, 0), S( 0, 0)
};
// Backward pawn penalty by file, endgame
const Value BackwardPawnEndgamePenalty[8] = {
Value(28), Value(31), Value(31), Value(31),
Value(31), Value(31), Value(31), Value(28)
};
// Pawn chain membership bonus by file, middle game
const Value ChainMidgameBonus[8] = {
Value(11), Value(13), Value(13), Value(14),
Value(14), Value(13), Value(13), Value(11)
};
// Pawn chain membership bonus by file, endgame
const Value ChainEndgameBonus[8] = {
Value(-1), Value(-1), Value(-1), Value(-1),
Value(-1), Value(-1), Value(-1), Value(-1)
};
// Candidate passed pawn bonus by rank, middle game
const Value CandidateMidgameBonus[8] = {
Value( 0), Value( 6), Value(6), Value(14),
Value(34), Value(83), Value(0), Value( 0)
};
// Candidate passed pawn bonus by rank, endgame
const Value CandidateEndgameBonus[8] = {
Value( 0), Value( 13), Value(13), Value(29),
Value(68), Value(166), Value( 0), Value( 0)
}; };
// Pawn storm tables for positions with opposite castling // Pawn storm tables for positions with opposite castling
@@ -122,12 +94,13 @@ namespace {
}; };
// Pawn storm open file bonuses by file // 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] = { 31, 31, 18, 0, 0, 0, 0, 0 };
const int16_t QStormOpenFileBonus[8] = { 0, 0, 0, 0, 0, 26, 42, 26 }; const int16_t KStormOpenFileBonus[8] = { 0, 0, 0, 0, 0, 26, 42, 26 };
// Pawn storm lever bonuses by file // Pawn storm lever bonuses by file
const int StormLeverBonus[8] = { -8, -8, -13, 0, 0, -13, -8, -8 }; const int StormLeverBonus[8] = { -8, -8, -13, 0, 0, -13, -8, -8 };
#undef S
} }
@@ -135,11 +108,10 @@ namespace {
//// Functions //// Functions
//// ////
/// Constructor /// PawnInfoTable c'tor and d'tor instantiated one each thread
PawnInfoTable::PawnInfoTable(unsigned numOfEntries) { PawnInfoTable::PawnInfoTable(unsigned numOfEntries) : size(numOfEntries) {
size = numOfEntries;
entries = new PawnInfo[size]; entries = new PawnInfo[size];
if (!entries) if (!entries)
{ {
@@ -150,9 +122,8 @@ PawnInfoTable::PawnInfoTable(unsigned numOfEntries) {
} }
/// Destructor
PawnInfoTable::~PawnInfoTable() { PawnInfoTable::~PawnInfoTable() {
delete [] entries; delete [] entries;
} }
@@ -168,11 +139,11 @@ void PawnInfo::clear() {
/// PawnInfoTable::get_pawn_info() takes a position object as input, computes /// PawnInfoTable::get_pawn_info() takes a position object as input, computes
/// a PawnInfo object, and returns a pointer to it. The result is also /// a PawnInfo object, and returns a pointer to it. The result is also stored
/// stored in a hash table, so we don't have to recompute everything when /// in a hash table, so we don't have to recompute everything when the same
/// the same pawn structure occurs again. /// 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()); assert(pos.is_ok());
@@ -190,214 +161,183 @@ PawnInfo* PawnInfoTable::get_pawn_info(const Position& pos) {
pi->clear(); pi->clear();
pi->key = key; pi->key = key;
Value mgValue[2] = {Value(0), Value(0)};
Value egValue[2] = {Value(0), Value(0)};
// Calculate pawn attacks // Calculate pawn attacks
pi->pawnAttacks[WHITE] = ((pos.pieces(PAWN, WHITE) << 9) & ~FileABB) | ((pos.pieces(PAWN, WHITE) << 7) & ~FileHBB); Bitboard whitePawns = pos.pieces(PAWN, WHITE);
pi->pawnAttacks[BLACK] = ((pos.pieces(PAWN, BLACK) >> 7) & ~FileABB) | ((pos.pieces(PAWN, BLACK) >> 9) & ~FileHBB); Bitboard blackPawns = pos.pieces(PAWN, BLACK);
pi->pawnAttacks[WHITE] = ((whitePawns << 9) & ~FileABB) | ((whitePawns << 7) & ~FileHBB);
pi->pawnAttacks[BLACK] = ((blackPawns >> 7) & ~FileABB) | ((blackPawns >> 9) & ~FileHBB);
// Loop through the pawns for both colors // Evaluate pawns for both colors
for (Color us = WHITE; us <= BLACK; us++) pi->value = evaluate_pawns<WHITE>(pos, whitePawns, blackPawns, pi)
{ - evaluate_pawns<BLACK>(pos, blackPawns, whitePawns, pi);
Color them = opposite_color(us);
Bitboard ourPawns = pos.pieces(PAWN, us);
Bitboard theirPawns = pos.pieces(PAWN, them);
Bitboard pawns = ourPawns;
// Initialize pawn storm scores by giving bonuses for open files
for (File f = FILE_A; f <= FILE_H; f++)
if (!(pawns & 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 (pawns)
{
Square s = pop_1st_bit(&pawns);
File f = square_file(s);
Rank r = square_rank(s);
assert(pos.piece_on(s) == piece_of_color_and_type(us, PAWN));
// Passed, isolated or doubled pawn?
bool passed = Position::pawn_is_passed(theirPawns, us, s);
bool isolated = Position::pawn_is_isolated(ourPawns, s);
bool 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
int bonus = KStormTable[relative_square(us, s)];
if (f >= FILE_F)
{
Bitboard b = outpost_mask(us, s) & theirPawns & (FileFBB | FileGBB | FileHBB);
while (b)
{
Square s2 = pop_1st_bit(&b);
if (!(theirPawns & neighboring_files_bb(s2) & rank_bb(s2)))
{
// The enemy pawn has no pawn beside itself, which makes it
// particularly vulnerable. Big bonus, especially against a
// weakness on the rook file.
if (square_file(s2) == FILE_H)
bonus += 4*StormLeverBonus[f] - 8*square_distance(s, s2);
else
bonus += 2*StormLeverBonus[f] - 4*square_distance(s, s2);
} else
// There is at least one enemy pawn beside the enemy pawn we look
// at, which means that the pawn has somewhat better chances of
// defending itself by advancing. Smaller bonus.
bonus += StormLeverBonus[f] - 2*square_distance(s, s2);
}
}
pi->ksStormValue[us] += bonus;
// Queenside pawn storms
bonus = QStormTable[relative_square(us, s)];
if (f <= FILE_C)
{
Bitboard b = outpost_mask(us, s) & theirPawns & (FileABB | FileBBB | FileCBB);
while (b)
{
Square s2 = pop_1st_bit(&b);
if (!(theirPawns & neighboring_files_bb(s2) & rank_bb(s2)))
{
// The enemy pawn has no pawn beside itself, which makes it
// particularly vulnerable. Big bonus, especially against a
// weakness on the rook file.
if (square_file(s2) == FILE_A)
bonus += 4*StormLeverBonus[f] - 16*square_distance(s, s2);
else
bonus += 2*StormLeverBonus[f] - 8*square_distance(s, s2);
} else
// There is at least one enemy pawn beside the enemy pawn we look
// at, which means that the pawn has somewhat better chances of
// defending itself by advancing. Smaller bonus.
bonus += StormLeverBonus[f] - 4*square_distance(s, s2);
}
}
pi->qsStormValue[us] += bonus;
// Member of a pawn chain (but not the backward one)? We could speed up
// the test a little by introducing an array of masks indexed by color
// and square for doing the test, but because everything is hashed,
// it probably won't make any noticable difference.
bool chain = ourPawns
& neighboring_files_bb(f)
& (rank_bb(r) | rank_bb(r - (us == WHITE ? 1 : -1)));
// Test for backward pawn
//
// If the pawn is passed, isolated, or member of a pawn chain
// it cannot be backward. If can capture an enemy pawn or if
// there are friendly pawns behind on neighboring files it cannot
// be backward either.
bool backward;
if ( passed
|| isolated
|| chain
|| (pos.attacks_from<PAWN>(s, us) & theirPawns)
|| (ourPawns & behind_bb(us, r) & neighboring_files_bb(f)))
backward = false;
else
{
// We now know that there are no friendly pawns beside or behind this
// pawn on neighboring files. We now check whether the pawn is
// backward by looking in the forward direction on the neighboring
// files, and seeing whether we meet a friendly or an enemy pawn first.
Bitboard b = pos.attacks_from<PAWN>(s, us);
if (us == WHITE)
{
for ( ; !(b & (ourPawns | theirPawns)); b <<= 8);
backward = (b | (b << 8)) & theirPawns;
}
else
{
for ( ; !(b & (ourPawns | theirPawns)); b >>= 8);
backward = (b | (b >> 8)) & theirPawns;
}
}
// Test for candidate passed pawn
bool candidate;
candidate = !passed
&& !(theirPawns & file_bb(f))
&& ( count_1s_max_15(neighboring_files_bb(f) & (behind_bb(us, r) | rank_bb(r)) & ourPawns)
- count_1s_max_15(neighboring_files_bb(f) & in_front_bb(us, r) & theirPawns)
>= 0);
// In order to prevent doubled passed pawns from receiving a too big
// bonus, only the frontmost passed pawn on each file is considered as
// a true passed pawn.
if (passed && (ourPawns & squares_in_front_of(us, s)))
passed = false;
// Score this pawn
if (passed)
set_bit(&(pi->passedPawns), s);
if (isolated)
{
mgValue[us] -= IsolatedPawnMidgamePenalty[f];
egValue[us] -= IsolatedPawnEndgamePenalty[f];
if (!(theirPawns & file_bb(f)))
{
mgValue[us] -= IsolatedPawnMidgamePenalty[f] / 2;
egValue[us] -= IsolatedPawnEndgamePenalty[f] / 2;
}
}
if (doubled)
{
mgValue[us] -= DoubledPawnMidgamePenalty[f];
egValue[us] -= DoubledPawnEndgamePenalty[f];
}
if (backward)
{
mgValue[us] -= BackwardPawnMidgamePenalty[f];
egValue[us] -= BackwardPawnEndgamePenalty[f];
if (!(theirPawns & file_bb(f)))
{
mgValue[us] -= BackwardPawnMidgamePenalty[f] / 2;
egValue[us] -= BackwardPawnEndgamePenalty[f] / 2;
}
}
if (chain)
{
mgValue[us] += ChainMidgameBonus[f];
egValue[us] += ChainEndgameBonus[f];
}
if (candidate)
{
mgValue[us] += CandidateMidgameBonus[relative_rank(us, s)];
egValue[us] += CandidateEndgameBonus[relative_rank(us, s)];
}
} // while(pawns)
} // for(colors)
pi->mgValue = int16_t(mgValue[WHITE] - mgValue[BLACK]);
pi->egValue = int16_t(egValue[WHITE] - egValue[BLACK]);
return pi; return pi;
} }
/// PawnInfoTable::evaluate_pawns() evaluates each pawn of the given color
template<Color Us>
Score PawnInfoTable::evaluate_pawns(const Position& pos, Bitboard ourPawns,
Bitboard theirPawns, PawnInfo* pi) const {
Bitboard b;
Square s;
File f;
Rank r;
int bonus;
bool passed, isolated, doubled, opposed, chain, backward, candidate;
Score value = make_score(0, 0);
const Square* ptr = pos.piece_list_begin(Us, PAWN);
// Initialize pawn storm scores by giving bonuses for open files
for (f = FILE_A; f <= FILE_H; f++)
if (!(ourPawns & file_bb(f)))
{
pi->ksStormValue[Us] += KStormOpenFileBonus[f];
pi->qsStormValue[Us] += QStormOpenFileBonus[f];
pi->halfOpenFiles[Us] |= (1 << f);
}
// Loop through all pawns of the current color and score each pawn
while ((s = *ptr++) != SQ_NONE)
{
f = square_file(s);
r = square_rank(s);
assert(pos.piece_on(s) == piece_of_color_and_type(Us, PAWN));
// Calculate kingside and queenside pawn storm scores for both colors to be
// used when evaluating middle game positions with opposite side castling.
bonus = (f >= FILE_F ? evaluate_pawn_storm<Us, KingSide>(s, r, f, theirPawns) : 0);
pi->ksStormValue[Us] += KStormTable[relative_square(Us, s)] + bonus;
bonus = (f <= FILE_C ? evaluate_pawn_storm<Us, QueenSide>(s, r, f, theirPawns) : 0);
pi->qsStormValue[Us] += QStormTable[relative_square(Us, s)] + bonus;
// Our rank plus previous one. Used for chain detection.
b = 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
//
// 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 & attack_span_mask(opposite_color(Us), s))
|| (pos.attacks_from<PAWN>(s, Us) & theirPawns))
backward = false;
else
{
// We now know that there are no friendly pawns beside or behind this
// pawn on 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.
b = pos.attacks_from<PAWN>(s, Us);
// Note that we are sure to find something because pawn is not passed
// nor isolated, so loop is potentially infinite, but it isn't.
while (!(b & (ourPawns | theirPawns)))
Us == WHITE ? b <<= 8 : b >>= 8;
// The friendly pawn needs to be at least two ranks closer than the enemy
// pawn in order to help the potentially backward pawn advance.
backward = (b | (Us == WHITE ? b << 8 : b >> 8)) & theirPawns;
}
assert(passed | opposed | (attack_span_mask(Us, s) & theirPawns));
// Test for candidate passed pawn
candidate = !(opposed | passed)
&& (b = attack_span_mask(opposite_color(Us), s + pawn_push(Us)) & ourPawns) != EmptyBoardBB
&& count_1s_max_15(b) >= count_1s_max_15(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
// a true passed pawn.
if (passed && (ourPawns & squares_in_front_of(Us, s)))
passed = false;
// 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);
// Score this pawn
if (isolated)
{
value -= IsolatedPawnPenalty[f];
if (!(theirPawns & file_bb(f)))
value -= IsolatedPawnPenalty[f] / 2;
}
if (doubled)
value -= DoubledPawnPenalty[f];
if (backward)
{
value -= BackwardPawnPenalty[f];
if (!(theirPawns & file_bb(f)))
value -= BackwardPawnPenalty[f] / 2;
}
if (chain)
value += ChainBonus[f];
if (candidate)
value += CandidateBonus[relative_rank(Us, s)];
}
return value;
}
/// PawnInfoTable::evaluate_pawn_storm() evaluates each pawn which seems
/// to have good chances of creating an open file by exchanging itself
/// against an enemy pawn on an adjacent file.
template<Color Us, PawnInfoTable::SideType Side>
int PawnInfoTable::evaluate_pawn_storm(Square s, Rank r, File f, Bitboard theirPawns) const {
const Bitboard StormFilesBB = (Side == KingSide ? FileFBB | FileGBB | FileHBB
: FileABB | FileBBB | FileCBB);
const int K = (Side == KingSide ? 2 : 4);
const File RookFile = (Side == KingSide ? FILE_H : FILE_A);
Bitboard b = attack_span_mask(Us, s) & theirPawns & StormFilesBB;
int bonus = 0;
while (b)
{
// Give a bonus according to the distance of the nearest enemy pawn
Square s2 = pop_1st_bit(&b);
Rank r2 = square_rank(s2);
int v = StormLeverBonus[f] - K * rank_distance(r, r2);
// 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) == RookFile ? 4 : 2);
bonus += v;
}
return bonus;
}
/// PawnInfo::updateShelter calculates and caches king shelter. It is called /// PawnInfo::updateShelter calculates and caches king shelter. It is called
/// only when king square changes, about 20% of total get_king_shelter() calls. /// only when king square changes, about 20% of total get_king_shelter() calls.
int PawnInfo::updateShelter(const Position& pos, Color c, Square ksq) { 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); Bitboard pawns = pos.pieces(PAWN, c) & this_and_neighboring_files_bb(ksq);
unsigned shelter = 0;
unsigned r = ksq & (7 << 3); unsigned r = ksq & (7 << 3);
for (int i = 1, k = (c ? -8 : 8); i < 4; i++) for (int i = 1, k = (c ? -8 : 8); i < 4; i++)
{ {
r += k; r += k;
+16 -13
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -45,10 +45,9 @@ class PawnInfo {
friend class PawnInfoTable; friend class PawnInfoTable;
public: public:
PawnInfo() : key(0) { clear(); } PawnInfo() { clear(); }
Value mg_value() const; Score pawns_value() const;
Value eg_value() const;
Value kingside_storm_value(Color c) const; Value kingside_storm_value(Color c) const;
Value queenside_storm_value(Color c) const; Value queenside_storm_value(Color c) const;
Bitboard pawn_attacks(Color c) const; Bitboard pawn_attacks(Color c) const;
@@ -65,10 +64,10 @@ private:
Key key; Key key;
Bitboard passedPawns; Bitboard passedPawns;
Bitboard pawnAttacks[2]; Bitboard pawnAttacks[2];
int16_t mgValue, egValue; Square kingSquares[2];
Score value;
int16_t ksStormValue[2], qsStormValue[2]; int16_t ksStormValue[2], qsStormValue[2];
uint8_t halfOpenFiles[2]; uint8_t halfOpenFiles[2];
Square kingSquares[2];
uint8_t kingShelters[2]; uint8_t kingShelters[2];
}; };
@@ -79,12 +78,20 @@ private:
class PawnInfoTable { class PawnInfoTable {
enum SideType { KingSide, QueenSide };
public: public:
PawnInfoTable(unsigned numOfEntries); PawnInfoTable(unsigned numOfEntries);
~PawnInfoTable(); ~PawnInfoTable();
PawnInfo* get_pawn_info(const Position& pos); PawnInfo* get_pawn_info(const Position& pos) const;
private: private:
template<Color Us>
Score evaluate_pawns(const Position& pos, Bitboard ourPawns, Bitboard theirPawns, PawnInfo* pi) const;
template<Color Us, SideType Side>
int evaluate_pawn_storm(Square s, Rank r, File f, Bitboard theirPawns) const;
unsigned size; unsigned size;
PawnInfo* entries; PawnInfo* entries;
}; };
@@ -94,12 +101,8 @@ private:
//// Inline functions //// Inline functions
//// ////
inline Value PawnInfo::mg_value() const { inline Score PawnInfo::pawns_value() const {
return Value(mgValue); return value;
}
inline Value PawnInfo::eg_value() const {
return Value(egValue);
} }
inline Bitboard PawnInfo::passed_pawns() const { inline Bitboard PawnInfo::passed_pawns() const {
+2 -2
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -38,7 +38,7 @@ static const string PieceChars(" pnbrqk PNBRQK");
char piece_type_to_char(PieceType pt, bool upcase) { 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) { PieceType piece_type_from_char(char c) {
+1 -1
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
+434 -438
View File
File diff suppressed because it is too large Load Diff
+72 -77
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -63,6 +63,18 @@ const int MaxGameLength = 220;
//// Types //// Types
//// ////
/// struct checkInfo is initialized at c'tor time and keeps
/// info used to detect if a move gives check.
struct CheckInfo {
explicit CheckInfo(const Position&);
Bitboard dcCandidates;
Bitboard checkSq[8];
Square ksq;
};
/// Castle rights, encoded as bit fields /// Castle rights, encoded as bit fields
enum CastleRights { enum CastleRights {
@@ -87,13 +99,14 @@ enum Phase {
/// must be passed as a parameter. /// must be passed as a parameter.
struct StateInfo { struct StateInfo {
Key key, pawnKey, materialKey; Key pawnKey, materialKey;
int castleRights, rule50; int castleRights, rule50, gamePly, pliesFromNull;
Square epSquare; Square epSquare;
Value mgValue, egValue; Score value;
Value npMaterial[2]; Value npMaterial[2];
PieceType capture; PieceType capture;
Key key;
Bitboard checkersBB; Bitboard checkersBB;
StateInfo* previous; StateInfo* previous;
}; };
@@ -126,6 +139,9 @@ class Position {
friend class MaterialInfo; friend class MaterialInfo;
friend class EndgameFunctions; friend class EndgameFunctions;
Position(); // No default or copy c'tor allowed
Position(const Position& pos);
public: public:
enum GamePhase { enum GamePhase {
MidGame, MidGame,
@@ -133,9 +149,9 @@ public:
}; };
// Constructors // Constructors
Position() {} explicit Position(int threadID);
Position(const Position& pos); Position(const Position& pos, int threadID);
Position(const std::string& fen); Position(const std::string& fen, int threadID);
// Text input/output // Text input/output
void from_fen(const std::string& fen); void from_fen(const std::string& fen);
@@ -143,7 +159,6 @@ public:
void print(Move m = MOVE_NONE) const; void print(Move m = MOVE_NONE) const;
// Copying // Copying
void copy(const Position& pos);
void flipped_copy(const Position& pos); void flipped_copy(const Position& pos);
// The piece on a given square // The piece on a given square
@@ -202,27 +217,28 @@ public:
template<PieceType> Bitboard attacks_from(Square s, Color c) const; template<PieceType> Bitboard attacks_from(Square s, Color c) const;
// Properties of moves // Properties of moves
bool pl_move_is_legal(Move m) const;
bool pl_move_is_legal(Move m, Bitboard pinned) const; bool pl_move_is_legal(Move m, Bitboard pinned) const;
bool pl_move_is_evasion(Move m, Bitboard pinned) const;
bool move_is_check(Move m) const; bool move_is_check(Move m) const;
bool move_is_check(Move m, Bitboard dcCandidates) const; bool move_is_check(Move m, const CheckInfo& ci) const;
bool move_is_capture(Move m) const; bool move_is_capture(Move m) const;
bool move_is_capture_or_promotion(Move m) const;
bool move_is_passed_pawn_push(Move m) const; bool move_is_passed_pawn_push(Move m) const;
bool move_attacks_square(Move m, Square s) const; bool move_attacks_square(Move m, Square s) const;
// Piece captured with previous moves
PieceType captured_piece() const;
// Information about pawns // Information about pawns
bool pawn_is_passed(Color c, Square s) const; 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 // Weak squares
bool square_is_weak(Square s, Color c) const; bool square_is_weak(Square s, Color c) const;
// Doing and undoing moves // Doing and undoing moves
void saveState(); void detach();
void do_move(Move m, StateInfo& st); void do_move(Move m, StateInfo& st);
void do_move(Move m, StateInfo& st, Bitboard dcCandidates); void do_move(Move m, StateInfo& st, const CheckInfo& ci, bool moveIsCheck);
void undo_move(Move m); void undo_move(Move m);
void do_null_move(StateInfo& st); void do_null_move(StateInfo& st);
void undo_null_move(); void undo_null_move();
@@ -235,15 +251,14 @@ public:
// Accessing hash keys // Accessing hash keys
Key get_key() const; Key get_key() const;
Key get_exclusion_key() const;
Key get_pawn_key() const; Key get_pawn_key() const;
Key get_material_key() const; Key get_material_key() const;
// Incremental evaluation // Incremental evaluation
Value mg_value() const; Score value() const;
Value eg_value() const;
Value non_pawn_material(Color c) const; Value non_pawn_material(Color c) const;
Phase game_phase() const; Score pst_delta(Piece piece, Square from, Square to) const;
template<GamePhase> Value pst_delta(Piece piece, Square from, Square to) const;
// Game termination checks // Game termination checks
bool is_mate() const; bool is_mate() const;
@@ -259,6 +274,9 @@ public:
bool opposite_colored_bishops() const; bool opposite_colored_bishops() const;
bool has_pawn_on_7th(Color c) const; bool has_pawn_on_7th(Color c) const;
// Current thread ID searching on the position
int thread() const;
// Reset the gamePly variable to 0 // Reset the gamePly variable to 0
void reset_game_ply(); void reset_game_ply();
@@ -278,14 +296,11 @@ private:
void allow_ooo(Color c); void allow_ooo(Color c);
// Helper functions for doing and undoing moves // 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 do_castle_move(Move m);
void undo_castle_move(Move m); void undo_castle_move(Move m);
void find_checkers(); void find_checkers();
template<PieceType Piece>
void update_checkers(Bitboard* pCheckersBB, Square ksq, Square from, Square to, Bitboard dcCandidates);
template<bool FindPinned> template<bool FindPinned>
Bitboard hidden_checkers(Color c) const; Bitboard hidden_checkers(Color c) const;
@@ -295,8 +310,8 @@ private:
Key compute_material_key() const; Key compute_material_key() const;
// Computing incremental evaluation scores and material counts // Computing incremental evaluation scores and material counts
template<GamePhase> Value pst(Color c, PieceType pt, Square s) const; Score pst(Color c, PieceType pt, Square s) const;
template<GamePhase> Value compute_value() const; Score compute_value() const;
Value compute_non_pawn_material(Color c) const; Value compute_non_pawn_material(Color c) const;
// Board // Board
@@ -314,21 +329,20 @@ private:
// Other info // Other info
Color sideToMove; Color sideToMove;
int gamePly;
Key history[MaxGameLength]; Key history[MaxGameLength];
File initialKFile, initialKRFile, initialQRFile; int castleRightsMask[64];
StateInfo startState; StateInfo startState;
File initialKFile, initialKRFile, initialQRFile;
int threadID;
StateInfo* st; StateInfo* st;
// Static variables // Static variables
static int castleRightsMask[64];
static Key zobrist[2][8][64]; static Key zobrist[2][8][64];
static Key zobEp[64]; static Key zobEp[64];
static Key zobCastle[16]; static Key zobCastle[16];
static Key zobMaterial[2][8][16];
static Key zobSideToMove; static Key zobSideToMove;
static Value MgPieceSquareTable[16][64]; static Score PieceSquareTable[16][64];
static Value EgPieceSquareTable[16][64]; static Key zobExclusion;
}; };
@@ -400,8 +414,8 @@ inline int Position::piece_count(Color c, PieceType pt) const {
return pieceCount[c][pt]; return pieceCount[c][pt];
} }
inline Square Position::piece_list(Color c, PieceType pt, int index) const { inline Square Position::piece_list(Color c, PieceType pt, int idx) const {
return pieceList[c][pt][index]; return pieceList[c][pt][idx];
} }
inline const Square* Position::piece_list_begin(Color c, PieceType pt) const { inline const Square* Position::piece_list_begin(Color c, PieceType pt) const {
@@ -473,26 +487,18 @@ inline bool Position::pawn_is_passed(Color c, Square s) const {
return !(pieces(PAWN, opposite_color(c)) & passed_pawn_mask(c, s)); 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 { 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 { inline Key Position::get_key() const {
return st->key; return st->key;
} }
inline Key Position::get_exclusion_key() const {
return st->key ^ zobExclusion;
}
inline Key Position::get_pawn_key() const { inline Key Position::get_pawn_key() const {
return st->pawnKey; return st->pawnKey;
} }
@@ -501,46 +507,22 @@ inline Key Position::get_material_key() const {
return st->materialKey; return st->materialKey;
} }
template<Position::GamePhase Ph> inline Score Position::pst(Color c, PieceType pt, Square s) const {
inline Value Position::pst(Color c, PieceType pt, Square s) const { return PieceSquareTable[piece_of_color_and_type(c, pt)][s];
return (Ph == MidGame ? MgPieceSquareTable[piece_of_color_and_type(c, pt)][s]
: EgPieceSquareTable[piece_of_color_and_type(c, pt)][s]);
} }
template<Position::GamePhase Ph> inline Score Position::pst_delta(Piece piece, Square from, Square to) const {
inline Value Position::pst_delta(Piece piece, Square from, Square to) const { return PieceSquareTable[piece][to] - PieceSquareTable[piece][from];
return (Ph == MidGame ? MgPieceSquareTable[piece][to] - MgPieceSquareTable[piece][from]
: EgPieceSquareTable[piece][to] - EgPieceSquareTable[piece][from]);
} }
inline Value Position::mg_value() const { inline Score Position::value() const {
return st->mgValue; return st->value;
}
inline Value Position::eg_value() const {
return st->egValue;
} }
inline Value Position::non_pawn_material(Color c) const { inline Value Position::non_pawn_material(Color c) const {
return st->npMaterial[c]; return st->npMaterial[c];
} }
inline Phase Position::game_phase() const {
// Values modified by Joona Kiiski
static const Value MidgameLimit = Value(15581);
static const Value EndgameLimit = Value(3998);
Value npm = non_pawn_material(WHITE) + non_pawn_material(BLACK);
if (npm >= MidgameLimit)
return PHASE_MIDGAME;
else if(npm <= EndgameLimit)
return PHASE_ENDGAME;
else
return Phase(((npm - EndgameLimit) * 128) / (MidgameLimit - EndgameLimit));
}
inline bool Position::move_is_passed_pawn_push(Move m) const { inline bool Position::move_is_passed_pawn_push(Move m) const {
Color c = side_to_move(); Color c = side_to_move();
@@ -568,8 +550,21 @@ inline bool Position::has_pawn_on_7th(Color c) const {
inline bool Position::move_is_capture(Move m) const { inline bool Position::move_is_capture(Move m) const {
// Move must not be MOVE_NONE ! // Move must not be MOVE_NONE !
return (m & (3 << 15)) ? !move_is_castle(m) : !square_is_empty(move_to(m));
}
return (!square_is_empty(move_to(m)) && !move_is_castle(m)) || move_is_ep(m); inline bool Position::move_is_capture_or_promotion(Move m) const {
// Move must not be MOVE_NONE !
return (m & (0x1F << 12)) ? !move_is_castle(m) : !square_is_empty(move_to(m));
}
inline PieceType Position::captured_piece() const {
return st->capture;
}
inline int Position::thread() const {
return threadID;
} }
#endif // !defined(POSITION_H_INCLUDED) #endif // !defined(POSITION_H_INCLUDED)
+1 -1
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
+50 -43
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -47,7 +47,7 @@ namespace {
AMBIGUITY_BOTH 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); Ambiguity move_ambiguity(const Position& pos, Move m);
const string time_string(int milliseconds); const string time_string(int milliseconds);
@@ -63,33 +63,30 @@ namespace {
/// that the move is a legal move from the position. The return value is /// that the move is a legal move from the position. The return value is
/// a string containing the move in short algebraic notation. /// a string containing the move in short algebraic notation.
const string move_to_san(const Position& pos, Move m) { const string move_to_san(Position& pos, Move m) {
assert(pos.is_ok()); assert(pos.is_ok());
assert(move_is_ok(m)); assert(move_is_ok(m));
Square from, to; string san;
PieceType pt; Square from = move_from(m);
Square to = move_to(m);
from = move_from(m); PieceType pt = type_of_piece(pos.piece_on(move_from(m)));
to = move_to(m);
pt = type_of_piece(pos.piece_on(move_from(m)));
string san = "";
if (m == MOVE_NONE) if (m == MOVE_NONE)
return "(none)"; return "(none)";
else if (m == MOVE_NULL) else if (m == MOVE_NULL)
return "(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"; 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"; san = "O-O";
else else
{ {
if (pt != PAWN) if (pt != PAWN)
{ {
san += piece_type_to_char(pt, true); san += piece_type_to_char(pt, true);
switch (move_ambiguity(pos, m)) { switch (move_ambiguity(pos, m)) {
case AMBIGUITY_NONE: case AMBIGUITY_NONE:
break; break;
@@ -115,18 +112,18 @@ const string move_to_san(const Position& pos, Move m) {
san += square_to_string(move_to(m)); san += square_to_string(move_to(m));
if (move_is_promotion(m)) if (move_is_promotion(m))
{ {
san += '='; san += "=";
san += piece_type_to_char(move_promotion_piece(m), true); san += piece_type_to_char(move_promotion_piece(m), true);
} }
} }
// Is the move check? We don't use pos.move_is_check(m) here, because
// Position::move_is_check doesn't detect all checks (not castling moves, // The move gives check ? We don't use pos.move_is_check() here
// promotions and en passant captures). // because we need to test for mate after the move is done.
StateInfo st; StateInfo st;
Position p(pos); pos.do_move(m, st);
p.do_move(m, st); if (pos.is_check())
if (p.is_check()) san += pos.is_mate() ? "#" : "+";
san += p.is_mate()? "#" : "+"; pos.undo_move(m);
return san; return san;
} }
@@ -142,13 +139,14 @@ Move move_from_san(const Position& pos, const string& movestr) {
assert(pos.is_ok()); assert(pos.is_ok());
MovePicker mp = MovePicker(pos, MOVE_NONE, OnePly, H); MovePicker mp = MovePicker(pos, MOVE_NONE, OnePly, H);
Bitboard pinned = pos.pinned_pieces(pos.side_to_move());
// Castling moves // Castling moves
if (movestr == "O-O-O" || movestr == "O-O-O+") if (movestr == "O-O-O" || movestr == "O-O-O+")
{ {
Move m; Move m;
while ((m = mp.get_next_move()) != MOVE_NONE) while ((m = mp.get_next_move()) != MOVE_NONE)
if (move_is_long_castle(m) && pos.pl_move_is_legal(m)) if (move_is_long_castle(m) && pos.pl_move_is_legal(m, pinned))
return m; return m;
return MOVE_NONE; return MOVE_NONE;
@@ -157,7 +155,7 @@ Move move_from_san(const Position& pos, const string& movestr) {
{ {
Move m; Move m;
while ((m = mp.get_next_move()) != MOVE_NONE) while ((m = mp.get_next_move()) != MOVE_NONE)
if (move_is_short_castle(m) && pos.pl_move_is_legal(m)) if (move_is_short_castle(m) && pos.pl_move_is_legal(m, pinned))
return m; return m;
return MOVE_NONE; return MOVE_NONE;
@@ -298,23 +296,23 @@ const string line_to_san(const Position& pos, Move line[], int startColumn, bool
string moveStr; string moveStr;
size_t length = 0; size_t length = 0;
size_t maxLength = 80 - startColumn; 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; length += moveStr.length() + 1;
if (breakLines && length > maxLength) if (breakLines && length > maxLength)
{ {
s << '\n' << std::setw(startColumn) << ' '; s << "\n" << std::setw(startColumn) << " ";
length = moveStr.length() + 1; length = moveStr.length() + 1;
} }
s << moveStr << ' '; s << moveStr << ' ';
if (line[i] == MOVE_NULL) if (*m == MOVE_NULL)
p.do_null_move(st); p.do_null_move(st);
else else
p.do_move(line[i], st); p.do_move(*m, st);
} }
return s.str(); return s.str();
} }
@@ -324,26 +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 /// It is used to write search information to the log file (which is created
/// when the UCI parameter "Use Search Log" is "true"). /// when the UCI parameter "Use Search Log" is "true").
const string pretty_pv(const Position& pos, int time, int depth, const string pretty_pv(const Position& pos, int time, int depth, uint64_t nodes,
uint64_t nodes, Value score, Move pv[]) { Value score, ValueType type, Move pv[]) {
const uint64_t K = 1000;
const uint64_t M = 1000000;
std::stringstream s; std::stringstream s;
// Depth // Depth
s << std::setw(2) << depth << " "; s << std::setw(2) << depth << " ";
// Score // Score
s << std::setw(8) << score_string(score); s << (type == VALUE_TYPE_LOWER ? ">" : type == VALUE_TYPE_UPPER ? "<" : " ")
<< std::setw(7) << score_string(score);
// Time // Time
s << std::setw(8) << time_string(time) << " "; s << std::setw(8) << time_string(time) << " ";
// Nodes // Nodes
if (nodes < 1000000ULL) if (nodes < M)
s << std::setw(8) << nodes << " "; s << std::setw(8) << nodes / 1 << " ";
else if (nodes < 1000000000ULL) else if (nodes < K * M)
s << std::setw(7) << nodes/1000ULL << 'k' << " "; s << std::setw(7) << nodes / K << "K ";
else else
s << std::setw(7) << nodes/1000000ULL << 'M' << " "; s << std::setw(7) << nodes / M << "M ";
// PV // PV
s << line_to_san(pos, pv, 30, true); s << line_to_san(pos, pv, 30, true);
@@ -366,11 +369,12 @@ namespace {
return AMBIGUITY_NONE; return AMBIGUITY_NONE;
MovePicker mp = MovePicker(pos, MOVE_NONE, OnePly, H); MovePicker mp = MovePicker(pos, MOVE_NONE, OnePly, H);
Bitboard pinned = pos.pinned_pieces(pos.side_to_move());
Move mv, moveList[8]; Move mv, moveList[8];
int n = 0; int n = 0;
while ((mv = mp.get_next_move()) != MOVE_NONE) while ((mv = mp.get_next_move()) != MOVE_NONE)
if (move_to(mv) == to && pos.piece_on(move_from(mv)) == pc && pos.pl_move_is_legal(mv)) if (move_to(mv) == to && pos.piece_on(move_from(mv)) == pc && pos.pl_move_is_legal(mv, pinned))
moveList[n++] = mv; moveList[n++] = mv;
if (n == 1) if (n == 1)
@@ -395,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; std::stringstream s;
s << std::setfill('0'); s << std::setfill('0');
int hours = milliseconds / (1000*60*60); int hours = millisecs / MSecHour;
int minutes = (milliseconds - hours*1000*60*60) / (1000*60); int minutes = (millisecs - hours * MSecHour) / MSecMinute;
int seconds = (milliseconds - hours*1000*60*60 - minutes*1000*60) / 1000; int seconds = (millisecs - hours * MSecHour - minutes * MSecMinute) / 1000;
if (hours) if (hours)
s << hours << ':'; s << hours << ':';
@@ -418,7 +425,7 @@ namespace {
if (v >= VALUE_MATE - 200) if (v >= VALUE_MATE - 200)
s << "#" << (VALUE_MATE - v + 1) / 2; s << "#" << (VALUE_MATE - v + 1) / 2;
else if(v <= -VALUE_MATE + 200) else if (v <= -VALUE_MATE + 200)
s << "-#" << (VALUE_MATE + v) / 2; s << "-#" << (VALUE_MATE + v) / 2;
else else
{ {
+3 -3
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -36,9 +36,9 @@
//// Prototypes //// Prototypes
//// ////
extern const std::string move_to_san(const Position& pos, Move m); extern const std::string move_to_san(Position& pos, Move m);
extern Move move_from_san(const Position& pos, const std::string& str); extern Move move_from_san(const Position& pos, const std::string& str);
extern const std::string line_to_san(const Position& pos, Move line[], int startColumn, bool breakLines); extern const std::string line_to_san(const Position& pos, Move line[], int startColumn, bool breakLines);
extern const std::string pretty_pv(const Position& pos, int time, int depth, uint64_t nodes, Value score, Move pv[]); extern const std::string pretty_pv(const Position& pos, int time, int depth, uint64_t nodes, Value score, ValueType type, Move pv[]);
#endif // !defined(SAN_H_INCLUDED) #endif // !defined(SAN_H_INCLUDED)
+1 -1
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
+1908 -1975
View File
File diff suppressed because it is too large Load Diff
+11 -4
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -27,6 +27,7 @@
#include "depth.h" #include "depth.h"
#include "move.h" #include "move.h"
#include "value.h"
//// ////
@@ -46,16 +47,20 @@ const int KILLER_MAX = 2;
/// from nodes shallower and deeper in the tree during the search. Each /// from nodes shallower and deeper in the tree during the search. Each
/// search thread has its own array of SearchStack objects, indexed by the /// search thread has its own array of SearchStack objects, indexed by the
/// current ply. /// current ply.
struct EvalInfo;
struct SearchStack { struct SearchStack {
Move pv[PLY_MAX];
Move currentMove; Move currentMove;
Move mateKiller; Move mateKiller;
Move threatMove; Move threatMove;
Move excludedMove;
Move bestMove;
Move killers[KILLER_MAX]; Move killers[KILLER_MAX];
Depth reduction; Depth reduction;
Value eval;
bool skipNullMove;
void init(int ply); void init();
void initKillers(); void initKillers();
}; };
@@ -64,11 +69,13 @@ struct SearchStack {
//// Prototypes //// Prototypes
//// ////
extern void init_search();
extern void init_threads(); extern void init_threads();
extern void stop_threads(); extern void exit_threads();
extern bool think(const Position &pos, bool infinite, bool ponder, int side_to_move, extern bool think(const Position &pos, bool infinite, bool ponder, int side_to_move,
int time[], int increment[], int movesToGo, int maxDepth, int time[], int increment[], int movesToGo, int maxDepth,
int maxNodes, int maxTime, Move searchMoves[]); int maxNodes, int maxTime, Move searchMoves[]);
extern int perft(Position &pos, Depth depth);
extern int64_t nodes_searched(); extern int64_t nodes_searched();
+1 -1
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
+38 -23
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -26,6 +26,8 @@
//// Includes //// Includes
//// ////
#include <cstring>
#include "lock.h" #include "lock.h"
#include "movepick.h" #include "movepick.h"
#include "position.h" #include "position.h"
@@ -36,7 +38,8 @@
//// Constants and variables //// Constants and variables
//// ////
const int THREAD_MAX = 8; const int MAX_THREADS = 8;
const int ACTIVE_SPLIT_POINTS_MAX = 8;
//// ////
@@ -44,35 +47,47 @@ const int THREAD_MAX = 8;
//// ////
struct SplitPoint { struct SplitPoint {
SplitPoint *parent;
Position pos; // Const data after splitPoint has been setup
SearchStack sstack[THREAD_MAX][PLY_MAX]; SplitPoint* parent;
SearchStack *parentSstack; const Position* pos;
int ply;
Depth depth; Depth depth;
volatile Value alpha, beta, bestValue; bool pvNode, mateThreat;
bool pvNode; Value beta;
Bitboard dcCandidates; int ply;
int master, slaves[THREAD_MAX]; SearchStack sstack[MAX_THREADS][PLY_MAX_PLUS_2];
// Const pointers to shared data
MovePicker* mp;
SearchStack* parentSstack;
// Shared data
Lock lock; Lock lock;
MovePicker *mp; volatile Value alpha;
volatile int moves; volatile Value bestValue;
volatile int cpus; volatile int moveCount;
bool finished; volatile bool stopRequest;
volatile int slaves[MAX_THREADS];
}; };
// ThreadState type is used to represent thread's current state
enum ThreadState
{
THREAD_SEARCHING, // thread is performing work
THREAD_AVAILABLE, // thread is polling for work
THREAD_SLEEPING, // we are not thinking, so thread is sleeping
THREAD_BOOKED, // other thread (master) has booked us as a slave
THREAD_WORKISWAITING, // master has ordered us to start
THREAD_TERMINATED // we are quitting and thread is terminated
};
struct Thread { struct Thread {
SplitPoint *splitPoint; SplitPoint* volatile splitPoint;
int activeSplitPoints; volatile int activeSplitPoints;
uint64_t nodes; uint64_t nodes;
uint64_t betaCutOffs[2]; uint64_t betaCutOffs[2];
bool failHighPly1; volatile ThreadState state;
volatile bool stop;
volatile bool running;
volatile bool idle;
volatile bool workIsWaiting;
volatile bool printCurrentLine;
unsigned char pad[64]; // set some distance among local data for each thread unsigned char pad[64]; // set some distance among local data for each thread
}; };
+41 -72
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -25,7 +25,6 @@
#include <cassert> #include <cassert>
#include <cmath> #include <cmath>
#include <cstring> #include <cstring>
#include <xmmintrin.h>
#include "movegen.h" #include "movegen.h"
#include "tt.h" #include "tt.h"
@@ -39,7 +38,7 @@ TranspositionTable TT;
TranspositionTable::TranspositionTable() { TranspositionTable::TranspositionTable() {
size = writes = 0; size = overwrites = 0;
entries = 0; entries = 0;
generation = 0; generation = 0;
} }
@@ -53,11 +52,9 @@ TranspositionTable::~TranspositionTable() {
/// TranspositionTable::set_size sets the size of the transposition table, /// TranspositionTable::set_size sets the size of the transposition table,
/// measured in megabytes. /// measured in megabytes.
void TranspositionTable::set_size(unsigned mbSize) { void TranspositionTable::set_size(size_t mbSize) {
assert(mbSize >= 4 && mbSize <= 4096); size_t newSize = 1024;
unsigned newSize = 1024;
// We store a cluster of ClusterSize number of TTEntry for each position // We store a cluster of ClusterSize number of TTEntry for each position
// and newSize is the maximum number of storable positions. // and newSize is the maximum number of storable positions.
@@ -91,16 +88,6 @@ 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, /// TranspositionTable::store writes a new entry containing a position,
/// a value, a value type, a search depth, and a best move to the /// a value, a value type, a search depth, and a best move to the
/// transposition table. Transposition table is organized in clusters of /// transposition table. Transposition table is organized in clusters of
@@ -111,8 +98,9 @@ inline TTEntry* TranspositionTable::first_entry(const Key posKey) const {
/// is bigger than the depth of t2. A TTEntry of type VALUE_TYPE_EVAL /// is bigger than the depth of t2. A TTEntry of type VALUE_TYPE_EVAL
/// never replaces another entry for the same position. /// never replaces another entry for the same position.
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; TTEntry *tte, *replace;
uint32_t posKey32 = posKey >> 32; // Use the high 32 bits as key uint32_t posKey32 = posKey >> 32; // Use the high 32 bits as key
@@ -121,28 +109,26 @@ void TranspositionTable::store(const Key posKey, Value v, ValueType t, Depth d,
{ {
if (!tte->key() || tte->key() == posKey32) // empty or overwrite old if (!tte->key() || tte->key() == posKey32) // empty or overwrite old
{ {
// Do not overwrite when new type is VALUE_TYPE_EV_LO // Preserve any exsisting ttMove
if (tte->key() && t == VALUE_TYPE_EV_LO)
return;
if (m == MOVE_NONE) if (m == MOVE_NONE)
m = tte->move(); m = tte->move();
*tte = TTEntry(posKey32, v, t, d, m, generation); tte->save(posKey32, v, t, d, m, generation, statV, kingD);
return; return;
} }
else if (i == 0) // replace would be a no-op in this common case
if (i == 0) // replace would be a no-op in this common case
continue; continue;
int c1 = (replace->generation() == generation ? 2 : 0); c1 = (replace->generation() == generation ? 2 : 0);
int c2 = (tte->generation() == generation ? -2 : 0); c2 = (tte->generation() == generation ? -2 : 0);
int c3 = (tte->depth() < replace->depth() ? 1 : 0); c3 = (tte->depth() < replace->depth() ? 1 : 0);
if (c1 + c2 + c3 > 0) if (c1 + c2 + c3 > 0)
replace = tte; replace = tte;
} }
*replace = TTEntry(posKey32, v, t, d, m, generation); replace->save(posKey32, v, t, d, m, generation, statV, kingD);
writes++; overwrites++;
} }
@@ -163,27 +149,6 @@ 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.
void TranspositionTable::prefetch(const Key posKey) const {
#if defined(__INTEL_COMPILER) || defined(__ICL)
// This hack prevents prefetches to be optimized away by the
// 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
}
/// TranspositionTable::new_search() is called at the beginning of every new /// TranspositionTable::new_search() is called at the beginning of every new
/// search. It increments the "generation" variable, which is used to /// search. It increments the "generation" variable, which is used to
/// distinguish transposition table entries from previous searches from /// distinguish transposition table entries from previous searches from
@@ -192,7 +157,7 @@ void TranspositionTable::prefetch(const Key posKey) const {
void TranspositionTable::new_search() { void TranspositionTable::new_search() {
generation++; generation++;
writes = 0; overwrites = 0;
} }
@@ -204,11 +169,13 @@ void TranspositionTable::new_search() {
void TranspositionTable::insert_pv(const Position& pos, Move pv[]) { void TranspositionTable::insert_pv(const Position& pos, Move pv[]) {
StateInfo st; StateInfo st;
Position p(pos); Position p(pos, pos.thread());
for (int i = 0; pv[i] != MOVE_NONE; i++) for (int i = 0; pv[i] != MOVE_NONE; i++)
{ {
store(p.get_key(), VALUE_NONE, VALUE_TYPE_NONE, Depth(-127*OnePly), pv[i]); TTEntry *tte = retrieve(p.get_key());
if (!tte || tte->move() != pv[i])
store(p.get_key(), VALUE_NONE, VALUE_TYPE_NONE, Depth(-127*OnePly), pv[i], VALUE_NONE, VALUE_NONE);
p.do_move(pv[i], st); p.do_move(pv[i], st);
} }
} }
@@ -220,38 +187,40 @@ void TranspositionTable::insert_pv(const Position& pos, Move pv[]) {
/// will often get single-move PVs when the search stops while failing high, /// 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. /// and a single-move PV means that we don't have a ponder move.
void TranspositionTable::extract_pv(const Position& pos, Move pv[]) { void TranspositionTable::extract_pv(const Position& pos, Move bestMove, Move pv[], const int PLY_MAX) {
int ply;
Position p(pos);
StateInfo st[100];
for (ply = 0; pv[ply] != MOVE_NONE; ply++)
p.do_move(pv[ply], st[ply]);
bool stop;
const TTEntry* tte; const TTEntry* tte;
for (stop = false, tte = retrieve(p.get_key()); StateInfo st;
tte && tte->move() != MOVE_NONE && !stop; Position p(pos, pos.thread());
tte = retrieve(p.get_key()), ply++) int ply = 0;
assert(bestMove != MOVE_NONE);
pv[ply] = bestMove;
p.do_move(pv[ply++], st);
// Extract moves from TT when possible. We try hard to always
// get a ponder move, that's the reason of ply < 2 conditions.
while ( (tte = retrieve(p.get_key())) != NULL
&& tte->move() != MOVE_NONE
&& (tte->type() == VALUE_TYPE_EXACT || ply < 2)
&& move_is_legal(p, tte->move())
&& (!p.is_draw() || ply < 2)
&& ply < PLY_MAX)
{ {
if (!move_is_legal(p, tte->move()))
break;
pv[ply] = tte->move(); pv[ply] = tte->move();
p.do_move(pv[ply], st[ply]); p.do_move(pv[ply++], st);
for (int j = 0; j < ply; j++)
if (st[j].key == p.get_key()) stop = true;
} }
pv[ply] = MOVE_NONE; pv[ply] = MOVE_NONE;
} }
/// TranspositionTable::full() returns the permill of all transposition table /// TranspositionTable::full() returns the permill of all transposition table
/// entries which have received at least one write during the current search. /// entries which have received at least one overwrite during the current search.
/// It is used to display the "info hashfull ..." information in UCI. /// It is used to display the "info hashfull ..." information in UCI.
int TranspositionTable::full() const { int TranspositionTable::full() const {
double N = double(size) * ClusterSize; double N = double(size) * ClusterSize;
return int(1000 * (1 - exp(writes * log(1.0 - 1.0/N)))); return int(1000 * (1 - exp(overwrites * log(1.0 - 1.0/N))));
} }
+42 -25
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -53,36 +53,45 @@
class TTEntry { class TTEntry {
public: public:
TTEntry() {} void save(uint32_t k, Value v, ValueType t, Depth d, Move m, int g, Value statV, Value kd) {
TTEntry(uint32_t k, Value v, ValueType t, Depth d, Move m, int generation)
: key_ (k), data((m & 0x1FFFF) | (t << 20) | (generation << 23)),
value_(int16_t(v)), depth_(int16_t(d)) {}
uint32_t key() const { return key_; } key32 = k;
Depth depth() const { return Depth(depth_); } data = (m & 0x1FFFF) | (t << 20) | (g << 23);
value16 = int16_t(v);
depth16 = int16_t(d);
staticValue = int16_t(statV);
kingDanger = int16_t(kd);
}
uint32_t key() const { return key32; }
Depth depth() const { return Depth(depth16); }
Move move() const { return Move(data & 0x1FFFF); } Move move() const { return Move(data & 0x1FFFF); }
Value value() const { return Value(value_); } Value value() const { return Value(value16); }
ValueType type() const { return ValueType((data >> 20) & 7); } ValueType type() const { return ValueType((data >> 20) & 7); }
int generation() const { return (data >> 23); } int generation() const { return data >> 23; }
Value static_value() const { return Value(staticValue); }
Value king_danger() const { return Value(kingDanger); }
private: private:
uint32_t key_; uint32_t key32;
uint32_t data; uint32_t data;
int16_t value_; int16_t value16;
int16_t depth_; int16_t depth16;
int16_t staticValue;
int16_t kingDanger;
}; };
/// This is the number of TTEntry slots for each position /// This is the number of TTEntry slots for each position
const int ClusterSize = 5; const int ClusterSize = 4;
/// Each group of ClusterSize number of TTEntry form a TTCluster /// Each group of ClusterSize number of TTEntry form a TTCluster
/// that is indexed by a single position key. Cluster is padded /// that is indexed by a single position key. TTCluster size must
/// to a cache line size so to guarantee always aligned accesses. /// be not bigger then a cache line size, in case it is less then
/// it should be padded to guarantee always aligned accesses.
struct TTCluster { struct TTCluster {
TTEntry data[ClusterSize]; TTEntry data[ClusterSize];
char cache_line_padding[64 - sizeof(TTEntry[ClusterSize])];
}; };
@@ -95,30 +104,38 @@ class TranspositionTable {
public: public:
TranspositionTable(); TranspositionTable();
~TranspositionTable(); ~TranspositionTable();
void set_size(unsigned mbSize); void set_size(size_t mbSize);
void clear(); 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; TTEntry* retrieve(const Key posKey) const;
void prefetch(const Key posKey) const;
void new_search(); void new_search();
void insert_pv(const Position& pos, Move pv[]); void insert_pv(const Position& pos, Move pv[]);
void extract_pv(const Position& pos, Move pv[]); void extract_pv(const Position& pos, Move bestMove, Move pv[], const int PLY_MAX);
int full() const; int full() const;
TTEntry* first_entry(const Key posKey) const;
private: private:
inline TTEntry* first_entry(const Key posKey) const; // Be sure 'overwrites' is at least one cache line away
// Be sure 'writes' is at least one cache line away
// from read only variables. // from read only variables.
unsigned char pad_before[64 - sizeof(unsigned)]; unsigned char pad_before[64 - sizeof(unsigned)];
unsigned writes; // heavy SMP read/write access here unsigned overwrites; // heavy SMP read/write access here
unsigned char pad_after[64]; unsigned char pad_after[64];
unsigned size; size_t size;
TTCluster* entries; TTCluster* entries;
uint8_t generation; uint8_t generation;
}; };
extern TranspositionTable TT; extern TranspositionTable TT;
/// 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;
}
#endif // !defined(TT_H_INCLUDED) #endif // !defined(TT_H_INCLUDED)
+46 -10
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -33,7 +33,7 @@ typedef __int16 int16;
typedef unsigned __int16 uint16_t; typedef unsigned __int16 uint16_t;
typedef __int32 int32_t; typedef __int32 int32_t;
typedef unsigned __int32 uint32_t; typedef unsigned __int32 uint32_t;
typedef __int64 int64; typedef __int64 int64_t;
typedef unsigned __int64 uint64_t; typedef unsigned __int64 uint64_t;
typedef __int16 int16_t; typedef __int16 int16_t;
@@ -49,20 +49,32 @@ typedef uint64_t Bitboard;
//// ////
//// Compiler specific defines //// Configuration
//// ////
// Quiet a warning on Intel compiler //// For Linux and OSX configuration is done automatically using Makefile.
#if !defined(__SIZEOF_INT__ ) //// To get started type "make help".
#define __SIZEOF_INT__ 0 ////
#endif //// 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 // Automatic detection for 64-bit under Windows
#if defined(__x86_64) || defined(_M_X64) || defined(_WIN64) || (__SIZEOF_INT__ > 4) #if defined(_WIN64)
#define IS_64BIT #define IS_64BIT
#endif #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 #define USE_BSFQ
#endif #endif
@@ -73,4 +85,28 @@ typedef uint64_t Bitboard;
#define CACHE_LINE_ALIGNMENT __attribute__ ((aligned(64))) #define CACHE_LINE_ALIGNMENT __attribute__ ((aligned(64)))
#endif #endif
// Define a __cpuid() function for gcc compilers, for Intel and MSVC
// is already available as an intrinsic.
#if defined(_MSC_VER)
#include <intrin.h>
#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
inline void __cpuid(int CPUInfo[4], int InfoType)
{
int* eax = CPUInfo + 0;
int* ebx = CPUInfo + 1;
int* ecx = CPUInfo + 2;
int* edx = CPUInfo + 3;
*eax = InfoType;
*ecx = 0;
__asm__("cpuid" : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx)
: "0" (*eax), "2" (*ecx));
}
#else
inline void __cpuid(int CPUInfo[4], int)
{
CPUInfo[0] = CPUInfo[1] = CPUInfo[2] = CPUInfo[3] = 0;
}
#endif
#endif // !defined(TYPES_H_INCLUDED) #endif // !defined(TYPES_H_INCLUDED)
+53 -49
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -54,13 +54,14 @@ namespace {
// The root position. This is set up when the user (or in practice, the GUI) // 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() // sends the "position" UCI command. The root position is sent to the think()
// function when the program receives the "go" command. // function when the program receives the "go" command.
Position RootPosition; Position RootPosition(0);
// Local functions // Local functions
bool handle_command(const string& command); bool handle_command(const string& command);
void set_option(UCIInputParser& uip); void set_option(UCIInputParser& uip);
void set_position(UCIInputParser& uip); void set_position(UCIInputParser& uip);
bool go(UCIInputParser& uip); bool go(UCIInputParser& uip);
void perft(UCIInputParser& uip);
} }
@@ -106,7 +107,8 @@ namespace {
UCIInputParser uip(command); UCIInputParser uip(command);
string token; string token;
uip >> token; // operator>>() skips any whitespace if (!(uip >> token)) // operator>>() skips any whitespace
return true;
if (token == "quit") if (token == "quit")
return false; return false;
@@ -123,7 +125,7 @@ namespace {
} }
else if (token == "ucinewgame") else if (token == "ucinewgame")
{ {
push_button("Clear Hash"); push_button("New Game");
Position::init_piece_square_tables(); Position::init_piece_square_tables();
RootPosition.from_fen(StartPosition); RootPosition.from_fen(StartPosition);
} }
@@ -141,29 +143,25 @@ namespace {
RootPosition.print(); RootPosition.print();
else if (token == "flip") else if (token == "flip")
{ {
Position p(RootPosition); Position p(RootPosition, RootPosition.thread());
RootPosition.flipped_copy(p); RootPosition.flipped_copy(p);
} }
else if (token == "eval") else if (token == "eval")
{ {
EvalInfo ei; EvalInfo ei;
cout << "Incremental mg: " << RootPosition.mg_value() cout << "Incremental mg: " << mg_value(RootPosition.value())
<< "\nIncremental eg: " << RootPosition.eg_value() << "\nIncremental eg: " << eg_value(RootPosition.value())
<< "\nFull eval: " << evaluate(RootPosition, ei, 0) << endl; << "\nFull eval: " << evaluate(RootPosition, ei) << endl;
} }
else if (token == "key") else if (token == "key")
cout << "key: " << hex << RootPosition.get_key() cout << "key: " << hex << RootPosition.get_key()
<< "\nmaterial key: " << RootPosition.get_material_key() << "\nmaterial key: " << RootPosition.get_material_key()
<< "\npawn key: " << RootPosition.get_pawn_key() << endl; << "\npawn key: " << RootPosition.get_pawn_key() << endl;
else if (token == "perft")
perft(uip);
else else
{
cout << "Unknown command: " << command << endl; cout << "Unknown command: " << command << endl;
while (!uip.eof())
{
uip >> token;
cout << token << endl;
}
}
return true; return true;
} }
@@ -178,33 +176,33 @@ namespace {
string token; string token;
uip >> token; // operator>>() skips any whitespace if (!(uip >> token)) // operator>>() skips any whitespace
return;
if (token == "startpos") if (token == "startpos")
RootPosition.from_fen(StartPosition); RootPosition.from_fen(StartPosition);
else if (token == "fen") else if (token == "fen")
{ {
string fen; string fen;
while (token != "moves" && !uip.eof()) while (uip >> token && token != "moves")
{ {
uip >> token;
fen += token; fen += token;
fen += ' '; fen += ' ';
} }
RootPosition.from_fen(fen); RootPosition.from_fen(fen);
} }
if (!uip.eof()) if (uip.good())
{ {
if (token != "moves") if (token != "moves")
uip >> token; uip >> token;
if (token == "moves") if (token == "moves")
{ {
Move move; Move move;
StateInfo st; StateInfo st;
while (!uip.eof()) while (uip >> token)
{ {
uip >> token;
move = move_from_string(RootPosition, token); move = move_from_string(RootPosition, token);
RootPosition.do_move(move, st); RootPosition.do_move(move, st);
if (RootPosition.rule_50_counter() == 0) if (RootPosition.rule_50_counter() == 0)
@@ -212,7 +210,7 @@ namespace {
} }
// Our StateInfo st is about going out of scope so copy // Our StateInfo st is about going out of scope so copy
// its content inside RootPosition before they disappear. // its content inside RootPosition before they disappear.
RootPosition.saveState(); RootPosition.detach();
} }
} }
} }
@@ -226,27 +224,22 @@ namespace {
void set_option(UCIInputParser& uip) { void set_option(UCIInputParser& uip) {
string token, name; string token, name, value;
uip >> token; if (!(uip >> token)) // operator>>() skips any whitespace
if (token == "name") return;
if (token == "name" && uip >> name)
{ {
uip >> name; while (uip >> token && token != "value")
while (!uip.eof())
{
uip >> token;
if (token == "value")
break;
name += (" " + token); name += (" " + token);
}
if (token == "value")
{
// Reads until end of line and left trim white space
getline(uip, token);
token.erase(0, token.find_first_not_of(" \n\r\t"));
set_option_value(name, token); if (token == "value" && uip >> value)
{
while (uip >> token)
value += (" " + token);
set_option_value(name, value);
} else } else
push_button(name); push_button(name);
} }
@@ -273,10 +266,8 @@ namespace {
searchMoves[0] = MOVE_NONE; searchMoves[0] = MOVE_NONE;
while (!uip.eof()) while (uip >> token)
{ {
uip >> token;
if (token == "infinite") if (token == "infinite")
infinite = true; infinite = true;
else if (token == "ponder") else if (token == "ponder")
@@ -300,22 +291,35 @@ namespace {
else if (token == "searchmoves") else if (token == "searchmoves")
{ {
int numOfMoves = 0; int numOfMoves = 0;
while (!uip.eof()) while (uip >> token)
{
uip >> token;
searchMoves[numOfMoves++] = move_from_string(RootPosition, token); searchMoves[numOfMoves++] = move_from_string(RootPosition, token);
}
searchMoves[numOfMoves] = MOVE_NONE; searchMoves[numOfMoves] = MOVE_NONE;
} }
} }
if (moveTime)
infinite = true; // HACK
assert(RootPosition.is_ok()); assert(RootPosition.is_ok());
return think(RootPosition, infinite, ponder, RootPosition.side_to_move(), return think(RootPosition, infinite, ponder, RootPosition.side_to_move(),
time, inc, movesToGo, depth, nodes, moveTime, searchMoves); time, inc, movesToGo, depth, nodes, moveTime, searchMoves);
} }
void perft(UCIInputParser& uip) {
string token;
int depth, tm, n;
Position pos(RootPosition, RootPosition.thread());
if (!(uip >> depth))
return;
tm = get_system_time();
n = perft(pos, depth * OnePly);
tm = get_system_time() - tm;
std::cout << "\nNodes " << n
<< "\nTime (ms) " << tm
<< "\nNodes/second " << (int)(n/(tm/1000.0)) << std::endl;
}
} }
+1 -1
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
+52 -37
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -79,6 +79,7 @@ namespace {
o["Use Search Log"] = Option(false); o["Use Search Log"] = Option(false);
o["Search Log Filename"] = Option("SearchLog.txt"); o["Search Log Filename"] = Option("SearchLog.txt");
o["Book File"] = Option("book.bin"); o["Book File"] = Option("book.bin");
o["Best Book Move"] = Option(false);
o["Mobility (Middle Game)"] = Option(100, 0, 200); o["Mobility (Middle Game)"] = Option(100, 0, 200);
o["Mobility (Endgame)"] = Option(100, 0, 200); o["Mobility (Endgame)"] = Option(100, 0, 200);
o["Pawn Structure (Middle Game)"] = Option(100, 0, 200); o["Pawn Structure (Middle Game)"] = Option(100, 0, 200);
@@ -88,47 +89,28 @@ namespace {
o["Space"] = Option(100, 0, 200); o["Space"] = Option(100, 0, 200);
o["Aggressiveness"] = Option(100, 0, 200); o["Aggressiveness"] = Option(100, 0, 200);
o["Cowardice"] = Option(100, 0, 200); o["Cowardice"] = Option(100, 0, 200);
o["King Safety Curve"] = Option("Quadratic", COMBO);
o["King Safety Curve"].comboValues.push_back("Quadratic");
o["King Safety Curve"].comboValues.push_back("Linear"); /*, "From File"*/
o["King Safety Coefficient"] = Option(40, 1, 100);
o["King Safety X Intercept"] = Option(0, 0, 20);
o["King Safety Max Slope"] = Option(30, 10, 100);
o["King Safety Max Value"] = Option(500, 100, 1000);
o["Queen Contact Check Bonus"] = Option(3, 0, 8);
o["Queen Check Bonus"] = Option(2, 0, 4);
o["Rook Check Bonus"] = Option(1, 0, 4);
o["Bishop Check Bonus"] = Option(1, 0, 4);
o["Knight Check Bonus"] = Option(1, 0, 4);
o["Discovered Check Bonus"] = Option(3, 0, 8);
o["Mate Threat Bonus"] = Option(3, 0, 8);
o["Check Extension (PV nodes)"] = Option(2, 0, 2); o["Check Extension (PV nodes)"] = Option(2, 0, 2);
o["Check Extension (non-PV nodes)"] = Option(1, 0, 2); o["Check Extension (non-PV nodes)"] = Option(1, 0, 2);
o["Single Reply Extension (PV nodes)"] = Option(2, 0, 2); o["Single Evasion Extension (PV nodes)"] = Option(2, 0, 2);
o["Single Reply Extension (non-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 (PV nodes)"] = Option(2, 0, 2);
o["Mate Threat Extension (non-PV nodes)"] = Option(0, 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 (PV nodes)"] = Option(1, 0, 2);
o["Pawn Push to 7th Extension (non-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 (PV nodes)"] = Option(1, 0, 2);
o["Passed Pawn Extension (non-PV nodes)"] = Option(0, 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 (PV nodes)"] = Option(2, 0, 2);
o["Pawn Endgame Extension (non-PV nodes)"] = Option(2, 0, 2); o["Pawn Endgame Extension (non-PV nodes)"] = Option(2, 0, 2);
o["Full Depth Moves (PV nodes)"] = Option(10, 1, 100);
o["Full Depth Moves (non-PV nodes)"] = Option(3, 1, 100);
o["Threat Depth"] = Option(5, 0, 100);
o["Randomness"] = Option(0, 0, 10); o["Randomness"] = Option(0, 0, 10);
o["Minimum Split Depth"] = Option(4, 4, 7); o["Minimum Split Depth"] = Option(4, 4, 7);
o["Maximum Number of Threads per Split Point"] = Option(5, 4, 8); o["Maximum Number of Threads per Split Point"] = Option(5, 4, 8);
o["Threads"] = Option(1, 1, 8); o["Threads"] = Option(1, 1, MAX_THREADS);
o["Hash"] = Option(32, 4, 4096); o["Hash"] = Option(32, 4, 8192);
o["Clear Hash"] = Option(false, BUTTON); o["Clear Hash"] = Option(false, BUTTON);
o["New Game"] = Option(false, BUTTON);
o["Ponder"] = Option(true); o["Ponder"] = Option(true);
o["OwnBook"] = Option(true); o["OwnBook"] = Option(true);
o["MultiPV"] = Option(1, 1, 500); o["MultiPV"] = Option(1, 1, 500);
o["UCI_ShowCurrLine"] = Option(false);
o["UCI_Chess960"] = Option(false); o["UCI_Chess960"] = Option(false);
o["UCI_AnalyseMode"] = Option(false); o["UCI_AnalyseMode"] = Option(false);
@@ -169,6 +151,18 @@ namespace {
return ret; return ret;
} }
// Specialization for std::string where instruction 'ss >> ret;'
// would erroneusly tokenize a string with spaces.
template<>
string get_option_value<string>(const string& optionName) {
if (options.find(optionName) == options.end())
return string();
return options[optionName].currentValue;
}
} }
//// ////
@@ -183,15 +177,18 @@ void init_uci_options() {
load_defaults(options); load_defaults(options);
// Limit the default value of "Threads" to 7 even if we have 8 CPU cores. // Set optimal value for parameter "Minimum Split Depth"
// According to Ken Dail's tests, Glaurung plays much better with 7 than // according to number of available cores.
// with 8 threads. This is weird, but it is probably difficult to find out
// why before I have a 8-core computer to experiment with myself.
assert(options.find("Threads") != options.end()); assert(options.find("Threads") != options.end());
assert(options.find("Minimum Split Depth") != options.end()); assert(options.find("Minimum Split Depth") != options.end());
options["Threads"].defaultValue = stringify(Min(cpu_count(), 7)); Option& thr = options["Threads"];
options["Threads"].currentValue = stringify(Min(cpu_count(), 7)); Option& msd = options["Minimum Split Depth"];
thr.defaultValue = thr.currentValue = stringify(cpu_count());
if (cpu_count() >= 8)
msd.defaultValue = msd.currentValue = stringify(7);
} }
@@ -279,10 +276,28 @@ void set_option_value(const string& name, const string& value) {
else if (v == "false") else if (v == "false")
v = "0"; v = "0";
if (options.find(name) != options.end()) if (options.find(name) == options.end())
options[name].currentValue = v; {
else
std::cout << "No such option: " << name << std::endl; std::cout << "No such option: " << name << std::endl;
return;
}
// Normally it's up to the GUI to check for option's limits,
// but we could receive the new value directly from the user
// by teminal window. So let's check the bounds anyway.
Option& opt = options[name];
if (opt.type == CHECK && v != "0" && v != "1")
return;
else if (opt.type == SPIN)
{
int val = atoi(v.c_str());
if (val < opt.minValue || val > opt.maxValue)
return;
}
opt.currentValue = v;
} }
@@ -302,7 +317,7 @@ void push_button(const string& buttonName) {
bool button_was_pressed(const string& buttonName) { bool button_was_pressed(const string& buttonName) {
if (!get_option_value<bool>(buttonName)) if (!get_option_value<bool>(buttonName))
return false; return false;
set_option_value(buttonName, "false"); set_option_value(buttonName, "false");
return true; return true;
+1 -1
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
+44 -9
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -33,13 +33,10 @@
//// ////
enum ValueType { enum ValueType {
VALUE_TYPE_NONE = 0, VALUE_TYPE_NONE = 0,
VALUE_TYPE_UPPER = 1, // Upper bound VALUE_TYPE_UPPER = 1, // Upper bound
VALUE_TYPE_LOWER = 2, // Lower bound VALUE_TYPE_LOWER = 2, // Lower bound
VALUE_TYPE_EXACT = 3, // Exact score VALUE_TYPE_EXACT = VALUE_TYPE_UPPER | VALUE_TYPE_LOWER
VALUE_TYPE_EVAL = 4, // Evaluation cache
VALUE_TYPE_EV_UP = 5, // Evaluation cache for upper bound
VALUE_TYPE_EV_LO = 6 // Evaluation cache for lower bound
}; };
@@ -48,10 +45,49 @@ enum Value {
VALUE_KNOWN_WIN = 15000, VALUE_KNOWN_WIN = 15000,
VALUE_MATE = 30000, VALUE_MATE = 30000,
VALUE_INFINITE = 30001, VALUE_INFINITE = 30001,
VALUE_NONE = 30002 VALUE_NONE = 30002,
VALUE_ENSURE_SIGNED = -1
}; };
/// Score enum keeps a midgame and an endgame value in a single
/// integer (enum), first LSB 16 bits are used to store endgame
/// value, while upper bits are used for midgame value.
// Compiler is free to choose the enum type as long as can keep
// its data, so ensure Score to be an integer type.
enum Score { ENSURE_32_BITS_SIZE_P = (1 << 16), ENSURE_32_BITS_SIZE_N = -(1 << 16)};
// Extracting the _signed_ lower and upper 16 bits it not so trivial
// because according to the standard a simple cast to short is
// implementation defined and so is a right shift of a signed integer.
inline Value mg_value(Score s) { return Value(((int(s) + 32768) & ~0xffff) / 0x10000); }
// Unfortunatly on Intel 64 bit we have a small speed regression, so use a faster code in
// this case, although not 100% standard compliant it seems to work for Intel and MSVC.
#if defined(IS_64BIT) && (!defined(__GNUC__) || defined(__INTEL_COMPILER))
inline Value eg_value(Score s) { return Value(int16_t(s & 0xffff)); }
#else
inline Value eg_value(Score s) { return Value((int)(unsigned(s) & 0x7fffu) - (int)(unsigned(s) & 0x8000u)); }
#endif
inline Score make_score(int mg, int eg) { return Score((mg << 16) + eg); }
inline Score operator-(Score s) { return Score(-int(s)); }
inline Score operator+(Score s1, Score s2) { return Score(int(s1) + int(s2)); }
inline Score operator-(Score s1, Score s2) { return Score(int(s1) - int(s2)); }
inline void operator+=(Score& s1, Score s2) { s1 = Score(int(s1) + int(s2)); }
inline void operator-=(Score& s1, Score s2) { s1 = Score(int(s1) - int(s2)); }
inline Score operator*(int i, Score s) { return Score(i * int(s)); }
// Division must be handled separately for each term
inline Score operator/(Score s, int i) { return make_score(mg_value(s) / i, eg_value(s) / i); }
// Only declared but not defined. We don't want to multiply two scores due to
// a very high risk of overflow. So user should explicitly convert to integer.
inline Score operator*(Score s1, Score s2);
//// ////
//// Constants and variables //// Constants and variables
//// ////
@@ -97,8 +133,7 @@ const Value PieceValueEndgame[17] = {
/// Bonus for having the side to move (modified by Joona Kiiski) /// Bonus for having the side to move (modified by Joona Kiiski)
const Value TempoValueMidgame = Value(48); const Score TempoValue = make_score(48, 22);
const Value TempoValueEndgame = Value(22);
//// ////