Compare commits

..

100 Commits

Author SHA1 Message Date
Marco Costalba
67ac358ef2 Stockfish 1.4
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-04 21:57:12 +01:00
Marco Costalba
341f42be8c Small Makefile tweaks
Set gcc as default compiler on Linux, also compile
with symbols stripped to shrink binary file.

Original patch by Heinz van Saanen.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-04 21:56:59 +01:00
Marco Costalba
72ab2cd3e9 Fix bitcount.h compile warnings under Intel compiler
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-04 18:10:39 +01:00
Marco Costalba
92b625d04f Check Intel compiler before MSVC in bitcount.h
Predefined macro __INTEL_COMPILER is defined only for Intel,
while _MSC_VER is defined for both Intel C++ and MSVC.

So rearrange ifdefs to take in account this and test __INTEL_COMPILER
first and only if not defined check _MSC_VER for MSVC.

Patch suggested by Joona.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-04 18:03:49 +01:00
Marco Costalba
2b32571de8 Add support for saving timing file during benchmark
Add a new argument to bench to specify the name of the
file where timing information will be saved for each
benchmark session.

This argument is optional, if not specified file will
not be created.

Original patch by Heinz van Saanen

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-04 10:32:51 +01:00
Marco Costalba
36437f14e8 Disable POPCNT support per default
This is mainly intended to allow 64 bit compiles on any
system and avoid to crash when the binary, compiled on a
box where POPCNT is not supported, is run on a Core i7
system or similar CPU.

What could happen is that when compiled in a standard 64 bit
system, because the correct headers for the POPCNT intrinsic
are not found, the compiler creates dummy bit count functions
instead, these are never called at runtime on the machine where
Stockfish has been compiled. But if we run the same binary on a
Core i7 system, because POPCNT is detected at run time, the dummy
bitcount functions will be called giving false results that will
crash the application.

Note that would be possible to fallback on software bit count in
these cases, but this is even more subtle because POPCNT path is not
optimized so that we have an application working but at sub-optimal
speed, so better to crash, at least user is loudly warned that there
is something wrong.

If, instead, Stockfish is compiled on a Core i7 system with POPCNT
enabled, then if the PGO compile has been done properly, the same binary
will run at optimal speed _both_ on the Core i7 machine and on any other
64 bit standard machine. This is the ideal mode for binary distribution.

Finally this patch disables bsfq support under Windows, because it seems
inline assembly is not supported both by MSVC and by Intel Windows version.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-04 09:20:28 +01:00
Marco Costalba
08f3aac97c Do not compile POPCNT if NO_POPCNT is defined
Also rename DISABLE_POPCNT_SUPPORT in NO_POPCNT and simplify a bit
the macro logic.

Always define a __popcnt64()or _mm_popcnt_u64() template, if the proper
function with the same name is defined in the intrinsics header, then it
will be choosen as first otherwise we fall back on the dummy template
that is never called at runtime anyway because cpu_has_popcnt() returns
false.

This fixes the compile error reported by Jim.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-04 09:18:17 +01:00
Marco Costalba
48b0d41220 Microptimize pawns info access
Avoid indirect calling of piece_of_color_and_type(c, PAWN) and its
alias pawns(c) in the pawn evaluation loop, but use the pawns
bitboards accessed only once before entering the loop.

Also explicitly mark functions as static to better self-document.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-03 13:11:32 +01:00
Marco Costalba
5d79af9e0d Restore correct 64 bit version of pop_1st_bit()
Was erroneusly changed with the 32bit in recent
patch "Retire USE_COMPACT_ROOK_ATTACKS...".

Also another clean up of define magics. Move compiler
specific definitions in types.h and remove redundant cruft.

Now this macro ugly mess seems more reasonable.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-03 10:18:20 +02:00
Marco Costalba
a87ea9846d Use bsfq asm instruction to count bits
On 64 bit systems we can use bsfq instruction to count
set bits in a bitboard.

This is a patch for GCC and Intel compilers to take advantage
of that and get a 2% speed up.

Original patch from Heinz van Saanen, adapted to current tree
by me.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-03 10:18:14 +02:00
Marco Costalba
063e2441b1 Retire USE_COMPACT_ROOK_ATTACKS and USE_FOLDED_BITSCAN defines
This greatly simplifies bitboard.cpp that now has only two setups,
respectively for 32 and 64 bits CPU according to IS_64BIT define
that is automatically set but can be tweaked manually in
bitboard.h

No functional change both in 32 and in 64 bits.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-03 07:52:10 +01:00
Marco Costalba
b45936a8c7 Revert per-thread history tables
Testing on Joona QUAD failed to give any
advantage. Actually we had a little loss:

Mod - Orig: 342.0 - 374.0

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-02 06:29:25 +01:00
Marco Costalba
d39ddb9077 Joona tweaks of piece values
This is the backport of tuned piece values.

We needed to change also the psqt tables so that their
values, that are relative to piece values, remain the same.

Amost no change after 999 games:

Mod vs Orig 594-495 + 2 ELO points so well within error bar

It was expected somehow given the very little change of the
parameters values.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-07-02 06:29:14 +01:00
Marco Costalba
bbb2462576 Explicitly use delta psqt values when possible
Instead of add and subtract pqst values corrisponding to
the move starting and destination squares, do it in one
go with the helper function pst_delta<>()

This simplifies the code and also better documents that what
we need is a delta value, not an absolute one.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-28 06:30:13 +02:00
Marco Costalba
d9e3be4790 Joona tweaks of pawns parameters
Test result after 999 games at 1+0

Mod vs Orig +278 =493 -228 52,50% +17 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-26 10:17:47 +02:00
Marco Costalba
36c0ab3a50 Fix compile errors in debug mode
Fall out of move_promotion() rename

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-20 19:18:00 +01:00
Marco Costalba
ad4eac376f Use POPCNT in evaluate_space() when available
This was forgotten by the POCNT patches.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-20 14:45:11 +01:00
Marco Costalba
657286b0e5 Fix a couple of warnings under Intel compiler
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-20 14:45:03 +01:00
Marco Costalba
3a4d6e2034 Micro optimize and rename move_promotion()
Rename to move_is_promotion() to be more clear, also add
a new function move_promotion_piece() to get the
promotion piece type in the few places where is needed.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-20 09:04:32 +01:00
Marco Costalba
b1e79fed99 Only on Windows do wait for input at the end of benchmark
Under MS Visual C++ debug window always unconditionally closes
when program exits, this is bad because we want to read results before.

So limit this kludge on Windows only.

Original patch by Heinz van Saanen.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-20 09:04:20 +01:00
Marco Costalba
190f88e532 Skip castle rights update when not needed
Micro optimization in do_move(), a quick check
avoid us to update castle rights in almost 90%
of cases.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-18 17:23:35 +01:00
Joona Kiiski
8acb1d7e4d Disable use of aspiration window in known win positions
When we are hunting for mate, transposition table is filled in
with mate scores. Current implemenatation of aspiration search
can't cope with this very well.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-18 07:35:24 +01:00
Joona Kiiski
46c0bdb74f Bugfix: KRK was not classified as KNOWN_WIN
Problem is that npMaterial is compared to _endgame_ value
of rook, although npMaterial is always (also in endgame!)
calculated using _middlegame_ values.

Bug was hidden as long as Rook middlegame
and endgame values were same.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-18 07:35:24 +01:00
Marco Costalba
8225fdd5bb Give proper credit to Joona
Stockfish would not be as where is now without his
contributions.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-18 07:35:23 +01:00
Marco Costalba
e3c02d231a Joona tweaks of mobility and outposts bonus
These are the tuned values of mobility and outposts
after 100.000 games on Joona QUAD.

After 999 games at 1+0
Mod vs Orig +248 =537 -214 51.70% +12 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-18 07:35:08 +01:00
Marco Costalba
9847adf19f Fix king value in SEE
When SEE piece values changed in aaad48464b
of 9/12/2008 we forgot to update the value assigned in
case of captured king.

In that patch we changed the SEE piece values but without
proper testing. Probably it is a good idea to make some
tests with the old Glaurung values.

Bug spotted by Joona.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-16 19:22:22 +01:00
Marco Costalba
630fda2e2c Reduce SMP contention on TT
Move TT object away from heavy write accessed NodesSincePoll
and also, inside TT isolate the heavy accessed writes variable.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-13 11:13:09 +01:00
Marco Costalba
8bec65029d Better clarify why recent generate_pawn_checks() works
We can have false positives, but these are filtered out
anyhow by following conditions so they are harmless.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-12 13:12:42 +02:00
Marco Costalba
b5685fc564 Code style triviality in search.cpp
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-12 13:12:23 +02:00
Marco Costalba
d2c2af9e1c Remove global variables from search.h
Globals are not really needed, so redefine as locals.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-12 13:10:40 +02:00
Marco Costalba
3e0753bef3 MovePicker doesn't need to know if called from a pv node
This was needed by an old optimization in sorting of
non-captures that is now obsoleted by new std::sort()
approach.

Remove also the unused depth member data. Interestingly
this has always been unused since the Glaurung days.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-12 13:10:02 +02:00
Marco Costalba
c7843f2f79 Joona tweaks of piece-square tables
These are the tuned psqt values after 100.000 games
on Joona QUAD. Results seem very good.

On PC 1 after 999 games
Mod vs Orig  +261 =511 -227 51.70 %  +12 ELO

On PC 2 after 913 games
Mod vs Orig  +254 =448 -211 52.35 %  +16 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-12 13:00:18 +02:00
Marco Costalba
9005ea6339 Move initialization of PawnInfo in its c'tor
Where it belongs.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-08 12:53:38 +01:00
Marco Costalba
6d117e4a23 Move initialization of MaterialInfo in its c'tor
Where it belongs.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-08 11:27:50 +01:00
Marco Costalba
b8ab5d533b Micro optimize pretty_pv
Creating an History object requires clearing the History tables,
although fast is an useless job in san.cpp where History is used
just as a dummy argument for MovePicker c'tor.

So use a file scoped constant instead of creating a new History()
object each time MovePicker c'tor is called as in move_ambiguity()

This optimizes pretty_pv() through the following calling chain:
pretty_pv() -> line_to_san() -> move_to_san() -> move_ambiguity()

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-08 10:52:03 +01:00
Marco Costalba
bbd3e30b4e Give credit to Joona for optimized parameters
This also allow us to better track what is already
optimized and what still needs optimization.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-05 15:07:36 +01:00
Marco Costalba
e41602b721 Use a specialized function for king evaluation
King evaluation is special in any case and as an added
benefit we can use the HasPopCnt optimization also for king.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-05 15:07:26 +01:00
Marco Costalba
48c95706c8 Split evaluate_outposts from evaluate_common
This is an old patch, was part of a series, but is
good also alone as a cleanup.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-03 17:38:42 +01:00
Marco Costalba
2f760cdf8d Document variables with heavy SMP read access
Also move NodesSincePoll away from the same cache line
of other heavy read accessed only variables.

Fortunatly we don't have anymore write access contention,
but still read access contention in some cases.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-03 17:36:50 +01:00
Marco Costalba
b58ecb85c7 Retire UseQSearchFutilityPruning and UseFutilityPruning
They are always true anyway and are heavy used file scope
variables where there could be SMP contention. Although read only.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-03 17:35:56 +01:00
Marco Costalba
b4a04d8038 Use one History table per thread
This reduces contention and reduce history trashing
effect especially at high search depths.

No functional change for single CPU case.

After 999 games at 1+0 on Dual Core Intel we have

Mod vs Orig  +233 =526 -240  -2 ELO

We need to test at longer time controls and possibly with
a QUAD where we could foreseen an improvment.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-03 17:34:35 +01:00
Marco Costalba
c1b60269a2 Convert History table H in a local variable
This is a first step for future patches and in
any case seems a nice thing to do.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-02 09:57:15 +01:00
Marco Costalba
e1ed67aacb Avoid using EmptySearchStack global
This reduces contention in SMP case and also
cleanups the code a bit.

No functional change

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-06-02 09:35:49 +01:00
Marco Costalba
5b1316f7bb Detach the state when copying a position
In Position we store a pointer to a StateInfo record
kept outside of the Position object.

When copying a position we copy also that pointer so
after the copy we have two Position objects pointing
to the same StateInfo record. This can be dangerous
so fix by copying also the StateInfo record inside
the new Position object and let the new st pointer
point to it. This completely detach the copied
Position from the original one.

Also rename setStartState() as saveState() and clean up
the API to state more clearly what the function does.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-29 17:23:21 +02:00
Marco Costalba
bafb9f1a25 Order bad captures by SEE value
We have already calculated it, so just sorting the
moves adds a very little overhead.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-29 08:31:13 +02:00
Marco Costalba
738bf66a2d Passed pawns evaluation tweak
Do not penalize if in our adavncing pawn's path there are
non-pawns enemy pieces. Especially if they can be attacked
by us.

Patch is mine, but original idea and also fixing of a first, wrong,
version of the patch is from Eelco de Groot.

Tests with Joona framework seems to confirm patch is good

Results for patch 'disabled'   based on 5776 games: Win percentage:
41.309  (+- 0.526)  [+- 1.053]
Results for patch 'enabled'  based on 6400 games: Win percentage:
42.422  (+- 0.500)  [+- 1.000]

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-29 08:30:58 +02:00
Marco Costalba
3d0b60b065 Merge hardware POPCNT detection and use
Tests on Joona luxury iCore7 QUAD show that speed increase
against standrd 64bit routine is between 3% and 4%.

So it seems a good thing to have. Also the user feedback at
startup regarding the compile and the hardware detection can
be an useful debug tool.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-25 07:56:26 +01:00
Marco Costalba
bdb1bfecfb Split killer moves from non-captures
In MovePicker consider killer moves as a separate
phase from non-capture picking.

Note that this change guarantees that killer1 is always
tried before killer2. Until now, because scoring difference
of the two moves was just 1 point, if psqt tables of killer1
gave a lower value then killer2, the latter was tried as first.

After 999 games at 1+0 we have
Mod vs Orig: +245 =527 -227 +6 ELO

Not a lot but patch is anyhow something worth to have.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-25 07:49:50 +01:00
Marco Costalba
f1591447cf Revert _BitScanForward64 support
It shows almost no improvment and adds a good
bunch of complexity.

So remove for now. No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-25 07:28:55 +01:00
Marco Costalba
d63ff85a43 Add a bit more pop_1st_bit<HasBSF> conversions
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-24 10:25:59 +01:00
Marco Costalba
76024ac40e Use compiler name lookup to simplify code
We don't need different names between a function and a
template. Compiler will know when use one or the other.

This let use restore original count_1s_xx() names instead of
sw_count_1s_xxx so to simplify a bit the code.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-24 10:18:31 +01:00
Marco Costalba
6c9a64124a Enable _BitScanForward64 in move generation
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-24 10:07:03 +01:00
Marco Costalba
f90f810ac4 Enable _BitScanForward64 at runtime
Only add infrastructure, still disabled.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-24 09:46:43 +01:00
Marco Costalba
ce5d9eb19d Print info about use of 64bit functions and hardware POPCNT
With this patch at the applications startup a line is printed
with info about use of optimized 64 bit routines and hardware
POPCNT.

Also allow the possibility to disable POPCNT support during
PGO compiles to exercise the fallback software only path.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-23 16:12:26 +01:00
Marco Costalba
628f844c11 Fix compile errors under MSVC
Fallback from previous patches.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-21 17:08:34 +01:00
Marco Costalba
c729e4e1ab Forgot two conversion to new POPCNT interface
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-21 16:50:19 +02:00
Marco Costalba
0228ff9ca0 Add temporary debug info on POPCNT support
To be removed before to release.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-21 16:42:07 +02:00
Marco Costalba
e7d3a006cd Enable POPCNT at runtime
Runtime detect POPCNT instruction support and
use it.

Also if POPCNT is not supported we don't add _any_ overhead so
that we don't lose any speed in standard case.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-21 16:41:31 +02:00
Marco Costalba
3376c68f4b Introduce bitcount.h
It will be used for POPCNT intrinsics.

For now no bianry and functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-21 16:19:20 +02:00
Marco Costalba
1b0888708d Unify piece_attacks<> for KNIGHT and KING
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-21 12:15:52 +02:00
Marco Costalba
229274546f Use do_move_bb() also for en passant moves
Unfortunatly, due to Chess960 compatibility we cannot
extend also to castling where the destinations squares
are not guaranteed to be empty.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-21 11:28:51 +02:00
Marco Costalba
3e40bd0648 Introduce do_move_bb() to update bitboards after a move
Avoid a clear_bit() + set_bit() sequence but update bitboards
with only one xor instructions.

This is faster and simplifies the code.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-21 10:55:23 +02:00
Marco Costalba
595c7d75a2 Backup some mor einfo in do_null_move()
Faster undo_null_move()

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-21 09:54:48 +02:00
Marco Costalba
5603e25a7f Move npMaterial[2] to StateInfo in Position
So to have a bit faster undo_move() and also
a code semplification.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-21 09:47:03 +02:00
Marco Costalba
20c2a31464 Retire lastMove from Position class
Is not used in any way so remove.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-20 15:46:16 +02:00
Marco Costalba
d3c4618b3a Small code style in headers
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-20 15:11:41 +02:00
Marco Costalba
b98bcf858b Directly relate HistoryMax to OnePly
This obsoletes some remainding comments.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-20 14:43:17 +02:00
Marco Costalba
3b1e64ab72 Small code style massage in uci.cpp
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-20 12:40:07 +02:00
Marco Costalba
72ecd9e20d Space inflate and cleanup direction.cpp
Hopefully it is now more clear what's happening here.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-20 12:02:39 +02:00
Marco Costalba
25286e9932 Reduce history 4 times instead of 2 when reach the maximum
This gives more weight to newer entries.

After 999 games at 1'+ 0" we have:

Mod vs Orig +233/-208/=558 51.25% +9 ELO

Confirmed by another session of 437 games:

Mod vs Orig +109/-92/=236 51.95% +14 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-20 09:03:15 +02:00
Marco Costalba
4f7ec4128f Retire count_1s_8bit()
Use the plain array lookup in the only place where it
is used. This remove an unecessary indirection and better
clarifies what code does.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-19 15:49:54 +01:00
Marco Costalba
1e4472b651 Small code style triviality in evaluation
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-19 15:41:45 +01:00
Marco Costalba
da579e46b7 Remove hardcode default values of UCI variables from evaluation
This is the same change we have already done in search.cpp,
this time for evaluation.cpp

If a variable will be populated reading an UCI option
then do not hard code its default values.

This avoids misleadings when reading the sources.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-19 15:35:12 +01:00
Marco Costalba
f83b899f39 Cache king shelter info in pawns structure
It does not change often and is not so fast
to calculate.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-17 10:23:24 +01:00
Marco Costalba
a75aa6035b Move beta counter variables to the per-thread data
This should reduce concurrent accessing in SMP case.

Suggestion by Tord Romstad.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-16 12:25:35 +01:00
Marco Costalba
436fa5c8fa Better document how history works
Both with added comment and changing the API to
reflect that only destination square and moved piece
is important for history.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-16 12:06:54 +01:00
Marco Costalba
8df816f869 Fix broken multi-pv with aspiration window search
Aspiration window search must be disabled for
multi-pv case.

We missed one point where aspiration window should
be disabled in this case.

Patch from Joona, with a little added edit by me.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-15 17:48:18 +01:00
Marco Costalba
9c428afb6d Fix a warning un using anonymous structs
No functional and no binary change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-12 12:10:40 +02:00
Marco Costalba
27619830d4 Use string instead of std::string
And others small code style touches.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-10 18:38:47 +01:00
Marco Costalba
78eecbf6d7 Use 64 bits for debug counters
Has happened 32 bits were not enough for
some test.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-10 17:42:04 +01:00
Marco Costalba
980124c609 Fix some Intel compilers warnings
Also a compile fix due to Makefile missing new
application.cpp file.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-09 12:09:25 +02:00
Marco Costalba
5f7d37273c Micro optimize generate_pawn_checks()
Use a better condition to find candidate direct check pawns.
In particular consider only pawns in the front ranks of the
enemy king, this greatly reduces pawns candidates bitboard
that now is empty more then 90% of the time so that we
can early skip further tests.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-08 10:56:59 +02:00
Marco Costalba
be4ee0729d Convert also generate_pawn_blocking_evasions() to new API
New compact parameter passing API.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-07 17:08:55 +02:00
Marco Costalba
9fbe9af0a0 Better dscovery check condition in generate_pawn_checks()
Be more strict, is not enough dc bitboard is not empty, but
needs to inclde also at least one pawn.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-07 17:01:52 +02:00
Marco Costalba
1d15b38cd8 Further parametrize generate_pawn_captures
We can parametrize for the capture direction too.

Also use a single template parameter and calculate (at
compile time) remainin parameters directly in the function.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-07 16:41:36 +02:00
Marco Costalba
5c81602d14 Update copyright year
We are well in 2009 already.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-07 14:54:40 +02:00
Marco Costalba
a88e762b4e Rewrite the way application exits
Centralize in a single object all the global resources
management and avoid a bunch of sparse exit() calls.

This is more reliable and clean and more stick to C++ coding
practices.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-07 12:59:19 +02:00
Marco Costalba
2155fb7825 Be sure book file is closed before we leave
Move closing of file in Book destructor. This
guarantees us against leaving the file open under
any case and simplifies also Book use.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-07 09:27:38 +02:00
Marco Costalba
a03b8074c8 Rewrite Book implementation
Let Book be derived directly from std::ifstream
and rewrite the functions accordingly.

Also simplify file reading by use of operator>>()

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-06 19:28:17 +01:00
Marco Costalba
afadc33fb4 Space inflate book.cpp
Also document most interesting parts.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-06 12:19:20 +02:00
Marco Costalba
92ca97d121 Fix a couple of MSVC warnings
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-06 09:50:49 +02:00
Marco Costalba
da91fab8cb Micro optimize move_is_ep() and move_is_castle()
Avoid a shift operation moving it at compile time.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-05 15:12:23 +02:00
Marco Costalba
6176357ac1 Faster Position::move_is_capture() condition
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-05 14:55:48 +02:00
Marco Costalba
46bb6c6dc3 Fix missing pawn color check in move_is_legal()
In case we have a correct white pawn move but pawn
is black (or the contrary) we fail to detect the
move as illegal.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-05 13:10:29 +02:00
Marco Costalba
5c703b7526 Update makefile to use PGO with Intel C++ v11.0
Update profiler guided optimization instructions in
Makefile to the latest Intel C++ compiler.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-04 11:58:26 +02:00
Marco Costalba
412d68fe4f Micro optimize SEE
Use pieces_of_type() instead of pieces_of_color_and_type()
in an hot loop and cut of almost 10% SEE execution time.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-04 11:18:24 +02:00
Marco Costalba
9144e48eb6 Avoid an usless check in pl_move_is_legal
Although very cheap this is a very hot path,
so avoid it.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-03 08:15:55 +01:00
Marco Costalba
aabd526f7c Change TT interface to ask directly for a position key
Instead of a position because the key is all that we
need.

Interface is more clear and also very very little bit faster.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-03 08:11:36 +01:00
Marco Costalba
fdb2242d34 Setup to use Callgrind profiler
Disabled by default.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-03 08:11:24 +01:00
Marco Costalba
991ab2bea8 Restore development versioning and LSN filtering
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-03 08:11:07 +01:00
59 changed files with 2087 additions and 1973 deletions

View File

@@ -45,7 +45,6 @@ PolyGlot documentation. The book file can be selected by setting the
UCI parameter "Book File".
4. Compiling it yourself
------------------------
@@ -54,27 +53,18 @@ Stockfish directly from the source code with the included Makefile.
The exception is computer with big-endian CPUs, like PowerPC
Macintoshes. Some of the bitboard routines in the current version of
Stockfish are endianness-sensitive, and won't work on a big-endian CPU.
Ensuring that the line with #define USE_32BIT_ATTACKS" near the top
of bitboard.h is commented out should solve this problem.
Commenting out the line with "#define USE_32BIT_ATTACKS" near the
There is also a problem with compiling Stockfish on certain 64-bit
systems, regardless of the endianness. If Stockfish segfaults
immediately after startup, try to comment out the line with
"#define USE_FOLDED_BITSCAN" near the beginning of bitboard.h and
recompile.
Stockfish has POPCNT instruction runtime detection and support. This can
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
before to compile.
Finally, even if Stockfish does work without any changes on your
computer, it might be possible to improve the performance by changing
some of the #define directives in bitboard.h. The default settings
are optimized for 64-bit CPUs. On 32-bit CPUs, it is probably better
to switch on USE_32BIT_ATTACKS, and to use BITCOUNT_SWAR_32 instead of
BITCOUNT_SWAR_64. For computers with very little memory (like
handheld devices), it is possible to conserve memory by defining
USE_COMPACT_ROOK_ATTACKS.
On 64 bit Unix-like systems the 'bsfq' assembly instruction will be used
for bit counting. Detection is automatic at compile time, but in case you
experience compile problems you can comment out #define USE_BSFQ line in types.h
6. Terms of use
5. Terms of use
---------------
Stockfish is free, and distributed under the GNU General Public License
@@ -93,7 +83,7 @@ For full details, read the copy of the GPL found in the file named
Copying.txt.
7. Feedback
6. Feedback
-----------
The author's e-mail address is mcostalba@gmail.com

View File

@@ -24,7 +24,7 @@
EXE = stockfish
OBJS = 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 \
position.o direction.o tt.o value.o uci.o ucioption.o \
mersenne.o book.o bitbase.o san.o benchmark.o
@@ -44,9 +44,8 @@ clean:
### Compiler:
###
# CXX = g++
# CXX = g++-4.2
CXX = icpc
CXX = g++
# CXX = icpc
###
@@ -66,24 +65,25 @@ include .depend
### Compiler and linker switches
###
# Enable/disable debugging:
# Enable/disable debugging, disabled by default
CXXFLAGS += -DNDEBUG
# Compile with full warnings, and symbol names
# Compile with full warnings, and symbol names stripped, you can use
# -g instead of -s to compile symbol's table in, useful for debugging.
CXXFLAGS += -Wall -g
CXXFLAGS += -Wall -s
# General optimization flags. Note that -O2 might be faster than -O3 on some
# General optimization flags. Note that -O2 might be faster than -O3 on some
# systems; this requires testing.
CXXFLAGS += -O3 -fno-exceptions -fomit-frame-pointer -fno-rtti -fno-strict-aliasing
CXXFLAGS += -O3 -fno-exceptions -fno-rtti -fno-strict-aliasing
# Disable most annoying warnings for the Intel C++ compiler
CXXFLAGS += -wd383,869,981
# CXXFLAGS += -wd383,869,981
# Compiler optimization flags for the Intel C++ compiler in Mac OS X:
@@ -91,15 +91,15 @@ CXXFLAGS += -wd383,869,981
# CXXFLAGS += -mdynamic-no-pic -no-prec-div -ipo -static -xP
# Profiler guided optimization with the Intel C++ compiler. To use it, first
# Profiler guided optimization with the Intel C++ compiler v11. To use it, first
# create the directory ./profdata if it does not already exist, and delete its
# contents if it does exist. Then compile with -prof_gen, and run the
# resulting binary for a while (for instance, do ./stockfish bench 128 1, and
# wait 15 minutes for the benchmark to complete). Then do a 'make clean', and
# recompile with -prof_use.
# CXXFLAGS += -prof_gen -prof_dir profdata
# CXXFLAGS += -prof_use -prof_dir ./profdata
# CXXFLAGS += -prof-gen -prof-dir./profdata
# CXXFLAGS += -prof-use -ipo -prof_dir./profdata
# Profiler guided optimization with GCC. I've never been able to make this

80
src/application.cpp Normal file
View File

@@ -0,0 +1,80 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Stockfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
////
//// Includes
////
#include "bitboard.h"
#include "direction.h"
#include "endgame.h"
#include "evaluate.h"
#include "material.h"
#include "mersenne.h"
#include "misc.h"
#include "movepick.h"
#include "position.h"
#include "search.h"
#include "thread.h"
#include "ucioption.h"
/// Application class is in charge of initializing global resources
/// at startup and cleanly releases them when program terminates.
Application::Application() {
init_mersenne();
init_direction_table();
init_bitboards();
init_uci_options();
Position::init_zobrist();
Position::init_piece_square_tables();
MovePicker::init_phase_table();
init_eval(1);
init_bitbases();
init_threads();
// Make random number generation less deterministic, for book moves
for (int i = abs(get_system_time() % 10000); i > 0; i--)
genrand_int32();
}
Application::~Application() {
stop_threads();
quit_eval();
}
void Application::initialize() {
instance();
}
Application& Application::instance() {
static Application singleton;
return singleton;
}
void Application::exit_with_failure() {
exit(EXIT_FAILURE); // d'tor will be called automatically
}

46
src/application.h Normal file
View File

@@ -0,0 +1,46 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Stockfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined(APPLICATION_H_INCLUDED)
#define APPLICATION_H_INCLUDED
/// Singleton class used to housekeep memory and global resources
/// so to be sure we always leave in a clean state.
class Application {
Application();
Application(const Application&);
public:
static void initialize();
static void exit_with_failure();
~Application();
private:
static Application& instance();
void init();
void deallocateAll();
};
#endif // !defined(APPLICATION_H_INCLUDED)

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -30,12 +30,13 @@
#include "thread.h"
#include "ucioption.h"
using namespace std;
////
//// Variables
////
const std::string BenchmarkPositions[] = {
const string BenchmarkPositions[] = {
"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1",
"r4rk1/1b2qppp/p1n1p3/1p6/1b1PN3/3BRN2/PP3PPP/R2Q2K1 b - - 7 16",
"4r1k1/ppq3pp/3b4/2pP4/2Q1p3/4B1P1/PP5P/R5K1 b - - 0 20",
@@ -67,27 +68,26 @@ const std::string BenchmarkPositions[] = {
/// format (default are the BenchmarkPositions defined above).
/// The analysis is written to a file named bench.txt.
void benchmark(const std::string& commandLine) {
void benchmark(const string& commandLine) {
std::istringstream csVal(commandLine);
std::istringstream csStr(commandLine);
std::string ttSize, threads, fileName, limitType;
istringstream csVal(commandLine);
istringstream csStr(commandLine);
string ttSize, threads, fileName, limitType, timFile;
int val, secsPerPos, maxDepth, maxNodes;
csStr >> ttSize;
csVal >> val;
if (val < 4 || val > 1024)
{
std::cerr << "The hash table size must be between 4 and 1024" << std::endl;
exit(EXIT_FAILURE);
cerr << "The hash table size must be between 4 and 1024" << endl;
Application::exit_with_failure();
}
csStr >> threads;
csVal >> val;
if (val < 1 || val > THREAD_MAX)
{
std::cerr << "The number of threads must be between 1 and " << THREAD_MAX
<< std::endl;
exit(EXIT_FAILURE);
cerr << "The number of threads must be between 1 and " << THREAD_MAX << endl;
Application::exit_with_failure();
}
set_option_value("Hash", ttSize);
set_option_value("Threads", threads);
@@ -98,6 +98,7 @@ void benchmark(const std::string& commandLine) {
csVal >> val;
csVal >> fileName;
csVal >> limitType;
csVal >> timFile;
secsPerPos = maxDepth = maxNodes = 0;
@@ -108,44 +109,71 @@ void benchmark(const std::string& commandLine) {
else
maxNodes = val;
std::vector<std::string> positions;
vector<string> positions;
if (fileName != "default")
{
std::ifstream fenFile(fileName.c_str());
ifstream fenFile(fileName.c_str());
if (!fenFile.is_open())
{
std::cerr << "Unable to open positions file " << fileName
<< std::endl;
exit(EXIT_FAILURE);
cerr << "Unable to open positions file " << fileName << endl;
Application::exit_with_failure();
}
std::string pos;
string pos;
while (fenFile.good())
{
std::getline(fenFile, pos);
getline(fenFile, pos);
if (!pos.empty())
positions.push_back(pos);
}
fenFile.close();
} else
for (int i = 0; i < 16; i++)
positions.push_back(std::string(BenchmarkPositions[i]));
positions.push_back(string(BenchmarkPositions[i]));
int startTime = get_system_time();
std::vector<std::string>::iterator it;
ofstream timingFile;
if (!timFile.empty())
{
timingFile.open(timFile.c_str(), ios::out | ios::app);
if (!timingFile.is_open())
{
cerr << "Unable to open timing file " << timFile << endl;
Application::exit_with_failure();
}
}
vector<string>::iterator it;
int cnt = 1;
int64_t totalNodes = 0;
int startTime = get_system_time();
for (it = positions.begin(); it != positions.end(); ++it, ++cnt)
{
Move moves[1] = {MOVE_NONE};
int dummy[2] = {0, 0};
Position pos(*it);
std::cout << "\nProcessing position " << cnt << '/' << positions.size() << std::endl << std::endl;
think(pos, true, false, 0, dummy, dummy, 0, maxDepth, maxNodes, secsPerPos, moves);
cerr << "\nBench position: " << cnt << '/' << positions.size() << endl << endl;
if (!think(pos, true, false, 0, dummy, dummy, 0, maxDepth, maxNodes, secsPerPos, moves))
break;
totalNodes += nodes_searched();
}
std::cout << "\nProcessing time (ms) " << get_system_time() - startTime << std::endl
<< "Nodes searched " << totalNodes << std::endl
<< "Press any key to exit" << std::endl;
std::cin >> fileName;
cnt = get_system_time() - startTime;
cerr << "==============================="
<< "\nTotal time (ms) : " << cnt
<< "\nNodes searched : " << totalNodes
<< "\nNodes/second : " << (int)(totalNodes/(cnt/1000.0)) << endl << endl;
if (!timFile.empty())
{
timingFile << cnt << endl << endl;
timingFile.close();
}
// Under MS Visual C++ debug window always unconditionally closes
// when program exits, this is bad because we want to read results before.
#if (defined(WINDOWS) || defined(WIN32) || defined(WIN64))
cerr << "Press any key to exit" << endl;
cin >> fileName;
#endif
}

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -22,137 +22,14 @@
//// Includes
////
#ifdef _MSC_VER
#include <intrin.h>
#ifdef _WIN64
#pragma intrinsic(_BitScanForward64)
#else
#pragma intrinsic(_BitScanForward)
#endif
#define USING_INTRINSICS
#endif
#include <iostream>
#include "bitboard.h"
#include "bitcount.h"
#include "direction.h"
#if defined(USE_COMPACT_ROOK_ATTACKS)
Bitboard RankAttacks[8][64], FileAttacks[8][64];
#elif defined(USE_32BIT_ATTACKS)
const uint64_t RMult[64] = {
0xd7445cdec88002c0ULL, 0xd0a505c1f2001722ULL, 0xe065d1c896002182ULL,
0x9a8c41e75a000892ULL, 0x8900b10c89002aa8ULL, 0x9b28d1c1d60005a2ULL,
0x15d6c88de002d9aULL, 0xb1dbfc802e8016a9ULL, 0x149a1042d9d60029ULL,
0xb9c08050599e002fULL, 0x132208c3af300403ULL, 0xc1000ce2e9c50070ULL,
0x9d9aa13c99020012ULL, 0xb6b078daf71e0046ULL, 0x9d880182fb6e002eULL,
0x52889f467e850037ULL, 0xda6dc008d19a8480ULL, 0x468286034f902420ULL,
0x7140ac09dc54c020ULL, 0xd76ffffa39548808ULL, 0xea901c4141500808ULL,
0xc91004093f953a02ULL, 0x2882afa8f6bb402ULL, 0xaebe335692442c01ULL,
0xe904a22079fb91eULL, 0x13a514851055f606ULL, 0x76c782018c8fe632ULL,
0x1dc012a9d116da06ULL, 0x3c9e0037264fffa6ULL, 0x2036002853c6e4a2ULL,
0xe3fe08500afb47d4ULL, 0xf38af25c86b025c2ULL, 0xc0800e2182cf9a40ULL,
0x72002480d1f60673ULL, 0x2500200bae6e9b53ULL, 0xc60018c1eefca252ULL,
0x600590473e3608aULL, 0x46002c4ab3fe51b2ULL, 0xa200011486bcc8d2ULL,
0xb680078095784c63ULL, 0x2742002639bf11aeULL, 0xc7d60021a5bdb142ULL,
0xc8c04016bb83d820ULL, 0xbd520028123b4842ULL, 0x9d1600344ac2a832ULL,
0x6a808005631c8a05ULL, 0x604600a148d5389aULL, 0xe2e40103d40dea65ULL,
0x945b5a0087c62a81ULL, 0x12dc200cd82d28eULL, 0x2431c600b5f9ef76ULL,
0xfb142a006a9b314aULL, 0x6870e00a1c97d62ULL, 0x2a9db2004a2689a2ULL,
0xd3594600caf5d1a2ULL, 0xee0e4900439344a7ULL, 0x89c4d266ca25007aULL,
0x3e0013a2743f97e3ULL, 0x180e31a0431378aULL, 0x3a9e465a4d42a512ULL,
0x98d0a11a0c0d9cc2ULL, 0x8e711c1aba19b01eULL, 0x8dcdc836dd201142ULL,
0x5ac08a4735370479ULL,
};
const int RShift[64] = {
20, 21, 21, 21, 21, 21, 21, 20, 21, 22, 22, 22, 22, 22, 22, 21,
21, 22, 22, 22, 22, 22, 22, 21, 21, 22, 22, 22, 22, 22, 22, 21,
21, 22, 22, 22, 22, 22, 22, 21, 21, 22, 22, 22, 22, 22, 22, 21,
21, 22, 22, 22, 22, 22, 22, 21, 20, 21, 21, 21, 21, 21, 21, 20
};
#else // if defined(USE_32BIT_ATTACKS)
const uint64_t RMult[64] = {
0xa8002c000108020ULL, 0x4440200140003000ULL, 0x8080200010011880ULL,
0x380180080141000ULL, 0x1a00060008211044ULL, 0x410001000a0c0008ULL,
0x9500060004008100ULL, 0x100024284a20700ULL, 0x802140008000ULL,
0x80c01002a00840ULL, 0x402004282011020ULL, 0x9862000820420050ULL,
0x1001448011100ULL, 0x6432800200800400ULL, 0x40100010002000cULL,
0x2800d0010c080ULL, 0x90c0008000803042ULL, 0x4010004000200041ULL,
0x3010010200040ULL, 0xa40828028001000ULL, 0x123010008000430ULL,
0x24008004020080ULL, 0x60040001104802ULL, 0x582200028400d1ULL,
0x4000802080044000ULL, 0x408208200420308ULL, 0x610038080102000ULL,
0x3601000900100020ULL, 0x80080040180ULL, 0xc2020080040080ULL,
0x80084400100102ULL, 0x4022408200014401ULL, 0x40052040800082ULL,
0xb08200280804000ULL, 0x8a80a008801000ULL, 0x4000480080801000ULL,
0x911808800801401ULL, 0x822a003002001894ULL, 0x401068091400108aULL,
0x4a10a00004cULL, 0x2000800640008024ULL, 0x1486408102020020ULL,
0x100a000d50041ULL, 0x810050020b0020ULL, 0x204000800808004ULL,
0x20048100a000cULL, 0x112000831020004ULL, 0x9000040810002ULL,
0x440490200208200ULL, 0x8910401000200040ULL, 0x6404200050008480ULL,
0x4b824a2010010100ULL, 0x4080801810c0080ULL, 0x400802a0080ULL,
0x8224080110026400ULL, 0x40002c4104088200ULL, 0x1002100104a0282ULL,
0x1208400811048021ULL, 0x3201014a40d02001ULL, 0x5100019200501ULL,
0x101000208001005ULL, 0x2008450080702ULL, 0x1002080301d00cULL,
0x410201ce5c030092ULL
};
const int RShift[64] = {
52, 53, 53, 53, 53, 53, 53, 52, 53, 54, 54, 54, 54, 54, 54, 53,
53, 54, 54, 54, 54, 54, 54, 53, 53, 54, 54, 54, 54, 54, 54, 53,
53, 54, 54, 54, 54, 54, 54, 53, 53, 54, 54, 54, 54, 54, 54, 53,
53, 54, 54, 54, 54, 54, 54, 53, 52, 53, 53, 53, 53, 53, 53, 52
};
#endif // defined(USE_32BIT_ATTACKS)
#if !defined(USE_COMPACT_ROOK_ATTACKS)
Bitboard RMask[64];
int RAttackIndex[64];
Bitboard RAttacks[0x19000];
#endif
#if defined(USE_32BIT_ATTACKS)
const uint64_t BMult[64] = {
0x54142844c6a22981ULL, 0x710358a6ea25c19eULL, 0x704f746d63a4a8dcULL,
0xbfed1a0b80f838c5ULL, 0x90561d5631e62110ULL, 0x2804260376e60944ULL,
0x84a656409aa76871ULL, 0xf0267f64c28b6197ULL, 0x70764ebb762f0585ULL,
0x92aa09e0cfe161deULL, 0x41ee1f6bb266f60eULL, 0xddcbf04f6039c444ULL,
0x5a3fab7bac0d988aULL, 0xd3727877fa4eaa03ULL, 0xd988402d868ddaaeULL,
0x812b291afa075c7cULL, 0x94faf987b685a932ULL, 0x3ed867d8470d08dbULL,
0x92517660b8901de8ULL, 0x2d97e43e058814b4ULL, 0x880a10c220b25582ULL,
0xc7c6520d1f1a0477ULL, 0xdbfc7fbcd7656aa6ULL, 0x78b1b9bfb1a2b84fULL,
0x2f20037f112a0bc1ULL, 0x657171ea2269a916ULL, 0xc08302b07142210eULL,
0x880a4403064080bULL, 0x3602420842208c00ULL, 0x852800dc7e0b6602ULL,
0x595a3fbbaa0f03b2ULL, 0x9f01411558159d5eULL, 0x2b4a4a5f88b394f2ULL,
0x4afcbffc292dd03aULL, 0x4a4094a3b3f10522ULL, 0xb06f00b491f30048ULL,
0xd5b3820280d77004ULL, 0x8b2e01e7c8e57a75ULL, 0x2d342794e886c2e6ULL,
0xc302c410cde21461ULL, 0x111f426f1379c274ULL, 0xe0569220abb31588ULL,
0x5026d3064d453324ULL, 0xe2076040c343cd8aULL, 0x93efd1e1738021eeULL,
0xb680804bed143132ULL, 0x44e361b21986944cULL, 0x44c60170ef5c598cULL,
0xf4da475c195c9c94ULL, 0xa3afbb5f72060b1dULL, 0xbc75f410e41c4ffcULL,
0xb51c099390520922ULL, 0x902c011f8f8ec368ULL, 0x950b56b3d6f5490aULL,
0x3909e0635bf202d0ULL, 0x5744f90206ec10ccULL, 0xdc59fd76317abbc1ULL,
0x881c7c67fcbfc4f6ULL, 0x47ca41e7e440d423ULL, 0xeb0c88112048d004ULL,
0x51c60e04359aef1aULL, 0x1aa1fe0e957a5554ULL, 0xdd9448db4f5e3104ULL,
0xdc01f6dca4bebbdcULL,
};
const int BShift[64] = {
26, 27, 27, 27, 27, 27, 27, 26, 27, 27, 27, 27, 27, 27, 27, 27,
27, 27, 25, 25, 25, 25, 27, 27, 27, 27, 25, 23, 23, 25, 27, 27,
27, 27, 25, 23, 23, 25, 27, 27, 27, 27, 25, 25, 25, 25, 27, 27,
27, 27, 27, 27, 27, 27, 27, 27, 26, 27, 27, 27, 27, 27, 27, 26
};
#else // if defined(USE_32BIT_ATTACKS)
#if defined(IS_64BIT)
const uint64_t BMult[64] = {
0x440049104032280ULL, 0x1021023c82008040ULL, 0x404040082000048ULL,
@@ -179,6 +56,31 @@ const uint64_t BMult[64] = {
0xa08520292120600ULL
};
const uint64_t RMult[64] = {
0xa8002c000108020ULL, 0x4440200140003000ULL, 0x8080200010011880ULL,
0x380180080141000ULL, 0x1a00060008211044ULL, 0x410001000a0c0008ULL,
0x9500060004008100ULL, 0x100024284a20700ULL, 0x802140008000ULL,
0x80c01002a00840ULL, 0x402004282011020ULL, 0x9862000820420050ULL,
0x1001448011100ULL, 0x6432800200800400ULL, 0x40100010002000cULL,
0x2800d0010c080ULL, 0x90c0008000803042ULL, 0x4010004000200041ULL,
0x3010010200040ULL, 0xa40828028001000ULL, 0x123010008000430ULL,
0x24008004020080ULL, 0x60040001104802ULL, 0x582200028400d1ULL,
0x4000802080044000ULL, 0x408208200420308ULL, 0x610038080102000ULL,
0x3601000900100020ULL, 0x80080040180ULL, 0xc2020080040080ULL,
0x80084400100102ULL, 0x4022408200014401ULL, 0x40052040800082ULL,
0xb08200280804000ULL, 0x8a80a008801000ULL, 0x4000480080801000ULL,
0x911808800801401ULL, 0x822a003002001894ULL, 0x401068091400108aULL,
0x4a10a00004cULL, 0x2000800640008024ULL, 0x1486408102020020ULL,
0x100a000d50041ULL, 0x810050020b0020ULL, 0x204000800808004ULL,
0x20048100a000cULL, 0x112000831020004ULL, 0x9000040810002ULL,
0x440490200208200ULL, 0x8910401000200040ULL, 0x6404200050008480ULL,
0x4b824a2010010100ULL, 0x4080801810c0080ULL, 0x400802a0080ULL,
0x8224080110026400ULL, 0x40002c4104088200ULL, 0x1002100104a0282ULL,
0x1208400811048021ULL, 0x3201014a40d02001ULL, 0x5100019200501ULL,
0x101000208001005ULL, 0x2008450080702ULL, 0x1002080301d00cULL,
0x410201ce5c030092ULL
};
const int BShift[64] = {
58, 59, 59, 59, 59, 59, 59, 58, 59, 59, 59, 59, 59, 59, 59, 59,
59, 59, 57, 57, 57, 57, 59, 59, 59, 59, 57, 55, 55, 57, 59, 59,
@@ -186,7 +88,85 @@ const int BShift[64] = {
59, 59, 59, 59, 59, 59, 59, 59, 58, 59, 59, 59, 59, 59, 59, 58
};
#endif // defined(USE_32BIT_ATTACKS)
const int RShift[64] = {
52, 53, 53, 53, 53, 53, 53, 52, 53, 54, 54, 54, 54, 54, 54, 53,
53, 54, 54, 54, 54, 54, 54, 53, 53, 54, 54, 54, 54, 54, 54, 53,
53, 54, 54, 54, 54, 54, 54, 53, 53, 54, 54, 54, 54, 54, 54, 53,
53, 54, 54, 54, 54, 54, 54, 53, 52, 53, 53, 53, 53, 53, 53, 52
};
#else // if !defined(IS_64BIT)
const uint64_t BMult[64] = {
0x54142844c6a22981ULL, 0x710358a6ea25c19eULL, 0x704f746d63a4a8dcULL,
0xbfed1a0b80f838c5ULL, 0x90561d5631e62110ULL, 0x2804260376e60944ULL,
0x84a656409aa76871ULL, 0xf0267f64c28b6197ULL, 0x70764ebb762f0585ULL,
0x92aa09e0cfe161deULL, 0x41ee1f6bb266f60eULL, 0xddcbf04f6039c444ULL,
0x5a3fab7bac0d988aULL, 0xd3727877fa4eaa03ULL, 0xd988402d868ddaaeULL,
0x812b291afa075c7cULL, 0x94faf987b685a932ULL, 0x3ed867d8470d08dbULL,
0x92517660b8901de8ULL, 0x2d97e43e058814b4ULL, 0x880a10c220b25582ULL,
0xc7c6520d1f1a0477ULL, 0xdbfc7fbcd7656aa6ULL, 0x78b1b9bfb1a2b84fULL,
0x2f20037f112a0bc1ULL, 0x657171ea2269a916ULL, 0xc08302b07142210eULL,
0x880a4403064080bULL, 0x3602420842208c00ULL, 0x852800dc7e0b6602ULL,
0x595a3fbbaa0f03b2ULL, 0x9f01411558159d5eULL, 0x2b4a4a5f88b394f2ULL,
0x4afcbffc292dd03aULL, 0x4a4094a3b3f10522ULL, 0xb06f00b491f30048ULL,
0xd5b3820280d77004ULL, 0x8b2e01e7c8e57a75ULL, 0x2d342794e886c2e6ULL,
0xc302c410cde21461ULL, 0x111f426f1379c274ULL, 0xe0569220abb31588ULL,
0x5026d3064d453324ULL, 0xe2076040c343cd8aULL, 0x93efd1e1738021eeULL,
0xb680804bed143132ULL, 0x44e361b21986944cULL, 0x44c60170ef5c598cULL,
0xf4da475c195c9c94ULL, 0xa3afbb5f72060b1dULL, 0xbc75f410e41c4ffcULL,
0xb51c099390520922ULL, 0x902c011f8f8ec368ULL, 0x950b56b3d6f5490aULL,
0x3909e0635bf202d0ULL, 0x5744f90206ec10ccULL, 0xdc59fd76317abbc1ULL,
0x881c7c67fcbfc4f6ULL, 0x47ca41e7e440d423ULL, 0xeb0c88112048d004ULL,
0x51c60e04359aef1aULL, 0x1aa1fe0e957a5554ULL, 0xdd9448db4f5e3104ULL,
0xdc01f6dca4bebbdcULL,
};
const uint64_t RMult[64] = {
0xd7445cdec88002c0ULL, 0xd0a505c1f2001722ULL, 0xe065d1c896002182ULL,
0x9a8c41e75a000892ULL, 0x8900b10c89002aa8ULL, 0x9b28d1c1d60005a2ULL,
0x15d6c88de002d9aULL, 0xb1dbfc802e8016a9ULL, 0x149a1042d9d60029ULL,
0xb9c08050599e002fULL, 0x132208c3af300403ULL, 0xc1000ce2e9c50070ULL,
0x9d9aa13c99020012ULL, 0xb6b078daf71e0046ULL, 0x9d880182fb6e002eULL,
0x52889f467e850037ULL, 0xda6dc008d19a8480ULL, 0x468286034f902420ULL,
0x7140ac09dc54c020ULL, 0xd76ffffa39548808ULL, 0xea901c4141500808ULL,
0xc91004093f953a02ULL, 0x2882afa8f6bb402ULL, 0xaebe335692442c01ULL,
0xe904a22079fb91eULL, 0x13a514851055f606ULL, 0x76c782018c8fe632ULL,
0x1dc012a9d116da06ULL, 0x3c9e0037264fffa6ULL, 0x2036002853c6e4a2ULL,
0xe3fe08500afb47d4ULL, 0xf38af25c86b025c2ULL, 0xc0800e2182cf9a40ULL,
0x72002480d1f60673ULL, 0x2500200bae6e9b53ULL, 0xc60018c1eefca252ULL,
0x600590473e3608aULL, 0x46002c4ab3fe51b2ULL, 0xa200011486bcc8d2ULL,
0xb680078095784c63ULL, 0x2742002639bf11aeULL, 0xc7d60021a5bdb142ULL,
0xc8c04016bb83d820ULL, 0xbd520028123b4842ULL, 0x9d1600344ac2a832ULL,
0x6a808005631c8a05ULL, 0x604600a148d5389aULL, 0xe2e40103d40dea65ULL,
0x945b5a0087c62a81ULL, 0x12dc200cd82d28eULL, 0x2431c600b5f9ef76ULL,
0xfb142a006a9b314aULL, 0x6870e00a1c97d62ULL, 0x2a9db2004a2689a2ULL,
0xd3594600caf5d1a2ULL, 0xee0e4900439344a7ULL, 0x89c4d266ca25007aULL,
0x3e0013a2743f97e3ULL, 0x180e31a0431378aULL, 0x3a9e465a4d42a512ULL,
0x98d0a11a0c0d9cc2ULL, 0x8e711c1aba19b01eULL, 0x8dcdc836dd201142ULL,
0x5ac08a4735370479ULL,
};
const int BShift[64] = {
26, 27, 27, 27, 27, 27, 27, 26, 27, 27, 27, 27, 27, 27, 27, 27,
27, 27, 25, 25, 25, 25, 27, 27, 27, 27, 25, 23, 23, 25, 27, 27,
27, 27, 25, 23, 23, 25, 27, 27, 27, 27, 25, 25, 25, 25, 27, 27,
27, 27, 27, 27, 27, 27, 27, 27, 26, 27, 27, 27, 27, 27, 27, 26
};
const int RShift[64] = {
20, 21, 21, 21, 21, 21, 21, 20, 21, 22, 22, 22, 22, 22, 22, 21,
21, 22, 22, 22, 22, 22, 22, 21, 21, 22, 22, 22, 22, 22, 22, 21,
21, 22, 22, 22, 22, 22, 22, 21, 21, 22, 22, 22, 22, 22, 22, 21,
21, 22, 22, 22, 22, 22, 22, 21, 20, 21, 21, 21, 21, 21, 21, 20
};
#endif // defined(IS_64BIT)
Bitboard RMask[64];
int RAttackIndex[64];
Bitboard RAttacks[0x19000];
Bitboard BMask[64];
int BAttackIndex[64];
@@ -225,9 +205,6 @@ namespace {
const int shift[2], const Bitboard mult[],
int deltas[][2]);
void init_pseudo_attacks();
#if defined(USE_COMPACT_ROOK_ATTACKS)
void init_file_and_rank_attacks();
#endif
}
@@ -259,87 +236,17 @@ void init_bitboards() {
init_ray_bitboards();
init_attacks();
init_between_bitboards();
#if defined(USE_COMPACT_ROOK_ATTACKS)
init_file_and_rank_attacks();
#else
init_sliding_attacks(RAttacks, RAttackIndex, RMask, RShift,
RMult, rookDeltas);
#endif
init_sliding_attacks(BAttacks, BAttackIndex, BMask, BShift,
BMult, bishopDeltas);
init_sliding_attacks(RAttacks, RAttackIndex, RMask, RShift, RMult, rookDeltas);
init_sliding_attacks(BAttacks, BAttackIndex, BMask, BShift, BMult, bishopDeltas);
init_pseudo_attacks();
}
#if defined(USE_FOLDED_BITSCAN)
static const int BitTable[64] = {
63, 30, 3, 32, 25, 41, 22, 33, 15, 50, 42, 13, 11, 53, 19, 34, 61, 29, 2,
51, 21, 43, 45, 10, 18, 47, 1, 54, 9, 57, 0, 35, 62, 31, 40, 4, 49, 5, 52,
26, 60, 6, 23, 44, 46, 27, 56, 16, 7, 39, 48, 24, 59, 14, 12, 55, 38, 28,
58, 20, 37, 17, 36, 8
};
/// first_1() finds the least significant nonzero bit in a nonzero bitboard.
Square first_1(Bitboard b) {
b ^= (b - 1);
uint32_t fold = int(b) ^ int(b >> 32);
return Square(BitTable[(fold * 0x783a9b23) >> 26]);
}
/// pop_1st_bit() finds and clears the least significant nonzero bit in a
/// nonzero bitboard.
#if defined(USE_32BIT_ATTACKS)
// Use type-punning
union b_union {
Bitboard b;
struct {
uint32_t l;
uint32_t h;
};
};
// WARNING: Needs -fno-strict-aliasing compiler option
Square pop_1st_bit(Bitboard *bb) {
b_union u;
uint32_t b;
u.b = *bb;
if (u.l)
{
b = u.l;
*((uint32_t*)bb) = b & (b - 1);
b ^= (b - 1);
}
else
{
b = u.h;
*((uint32_t*)bb+1) = b & (b - 1); // Little endian only?
b = ~(b ^ (b - 1));
}
return Square(BitTable[(b * 0x783a9b23) >> 26]);
}
#else
Square pop_1st_bit(Bitboard *b) {
Bitboard bb = *b ^ (*b - 1);
uint32_t fold = int(bb) ^ int(bb >> 32);
*b &= (*b - 1);
return Square(BitTable[(fold * 0x783a9b23) >> 26]);
}
#endif
#else
#if defined(IS_64BIT) && !defined(USE_BSFQ)
static const int BitTable[64] = {
0, 1, 2, 7, 3, 13, 8, 19, 4, 25, 14, 28, 9, 34, 20, 40, 5, 17, 26, 38, 15,
@@ -348,25 +255,65 @@ static const int BitTable[64] = {
51, 60, 42, 59, 58
};
/// first_1() finds the least significant nonzero bit in a nonzero bitboard.
Square first_1(Bitboard b) {
return Square(BitTable[((b & -b) * 0x218a392cd3d5dbfULL) >> 58]);
}
/// pop_1st_bit() finds and clears the least significant nonzero bit in a
/// nonzero bitboard.
Square pop_1st_bit(Bitboard *b) {
Square pop_1st_bit(Bitboard* b) {
Bitboard bb = *b;
*b &= (*b - 1);
return Square(BitTable[((bb & -bb) * 0x218a392cd3d5dbfULL) >> 58]);
}
#endif // defined(USE_FOLDED_BITSCAN)
#elif !defined(USE_BSFQ)
static const int BitTable[64] = {
63, 30, 3, 32, 25, 41, 22, 33, 15, 50, 42, 13, 11, 53, 19, 34, 61, 29, 2,
51, 21, 43, 45, 10, 18, 47, 1, 54, 9, 57, 0, 35, 62, 31, 40, 4, 49, 5, 52,
26, 60, 6, 23, 44, 46, 27, 56, 16, 7, 39, 48, 24, 59, 14, 12, 55, 38, 28,
58, 20, 37, 17, 36, 8
};
Square first_1(Bitboard b) {
b ^= (b - 1);
uint32_t fold = int(b) ^ int(b >> 32);
return Square(BitTable[(fold * 0x783a9b23) >> 26]);
}
// Use type-punning
union b_union {
Bitboard b;
struct {
uint32_t l;
uint32_t h;
} dw;
};
// WARNING: Needs -fno-strict-aliasing compiler option
Square pop_1st_bit(Bitboard* bb) {
b_union u;
uint32_t b;
u.b = *bb;
if (u.dw.l)
{
b = u.dw.l;
*((uint32_t*)bb) = b & (b - 1);
b ^= (b - 1);
}
else
{
b = u.dw.h;
*((uint32_t*)bb+1) = b & (b - 1); // Little endian only?
b = ~(b ^ (b - 1));
}
return Square(BitTable[(b * 0x783a9b23) >> 26]);
}
#endif
namespace {
@@ -480,25 +427,25 @@ namespace {
attackIndex[i] = index;
mask[i] = sliding_attacks(i, 0ULL, 4, deltas, 1, 6, 1, 6);
#if defined(USE_32BIT_ATTACKS)
j = (1 << (32 - shift[i]));
#else
#if defined(IS_64BIT)
j = (1 << (64 - shift[i]));
#else
j = (1 << (32 - shift[i]));
#endif
for(k = 0; k < j; k++) {
#if defined(USE_32BIT_ATTACKS)
#if defined(IS_64BIT)
b = index_to_bitboard(k, mask[i]);
attacks[index + ((b * mult[i]) >> shift[i])] =
sliding_attacks(i, b, 4, deltas);
#else
b = index_to_bitboard(k, mask[i]);
attacks[index +
(unsigned(int(b) * int(mult[i]) ^
int(b >> 32) * int(mult[i] >> 32))
>> shift[i])] =
sliding_attacks(i, b, 4, deltas);
#else
b = index_to_bitboard(k, mask[i]);
attacks[index + ((b * mult[i]) >> shift[i])] =
sliding_attacks(i, b, 4, deltas);
#endif
}
index += j;
@@ -515,29 +462,4 @@ namespace {
}
}
#if defined(USE_COMPACT_ROOK_ATTACKS)
void init_file_and_rank_attacks() {
int i, j, k, l, m, s;
Bitboard b1, b2;
for(i = 0; i < 64; i++) {
for(m = 0; m <= 1; m++) {
b1 = 0ULL;
for(j = 0; j < 6; j++) if(i & (1<<j)) b1 |= (1ULL << ((j+1)*(1+m*7)));
for(j = 0; j < 8; j++) {
b2 = 0ULL;
for(k = 0, s = 1; k < 2; k++, s *= -1) {
for(l = j+s; l >= 0 && l <= 7; l += s) {
b2 |= (m? RankBB[l] : FileBB[l]);
if(b1 & (1ULL << (l*(1+m*7)))) break;
}
}
if(m) FileAttacks[j][(b1*0xd6e8802041d0c441ULL) >> 58] = b2;
else RankAttacks[j][i] = b2;
}
}
}
}
#endif // defined(USE_COMPACT_ROOK_ATTACKS)
}

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -22,43 +22,6 @@
#if !defined(BITBOARD_H_INCLUDED)
#define BITBOARD_H_INCLUDED
////
//// Defines
////
// Comment following define if you prefer manually adjust
// platform macros defined below
#define AUTO_CONFIGURATION
// Quiet a warning on Intel compiler
#if !defined(__SIZEOF_INT__ )
#define __SIZEOF_INT__ 0
#endif
// Check for 64 bits for different compilers: Intel, MSVC and gcc
#if defined(__x86_64) || defined(_WIN64) || (__SIZEOF_INT__ > 4)
#define IS_64BIT
#endif
#if !defined(AUTO_CONFIGURATION) || defined(IS_64BIT)
//#define USE_COMPACT_ROOK_ATTACKS
//#define USE_32BIT_ATTACKS
#define USE_FOLDED_BITSCAN
#define BITCOUNT_SWAR_64
//#define BITCOUNT_SWAR_32
//#define BITCOUNT_LOOP
#else
#define USE_32BIT_ATTACKS
#define USE_FOLDED_BITSCAN
#define BITCOUNT_SWAR_32
#endif
////
//// Includes
////
@@ -69,13 +32,6 @@
#include "types.h"
////
//// Types
////
typedef uint64_t Bitboard;
////
//// Constants and variables
////
@@ -160,20 +116,12 @@ extern Bitboard BetweenBB[64][64];
extern Bitboard PassedPawnMask[2][64];
extern Bitboard OutpostMask[2][64];
#if defined(USE_COMPACT_ROOK_ATTACKS)
extern Bitboard RankAttacks[8][64], FileAttacks[8][64];
#else
extern const uint64_t RMult[64];
extern const int RShift[64];
extern Bitboard RMask[64];
extern int RAttackIndex[64];
extern Bitboard RAttacks[0x19000];
#endif // defined(USE_COMPACT_ROOK_ATTACKS)
extern const uint64_t BMult[64];
extern const int BShift[64];
extern Bitboard BMask[64];
@@ -205,6 +153,17 @@ inline void clear_bit(Bitboard *b, Square s) {
}
/// Functions used to update a bitboard after a move. This is faster
/// then calling a sequence of clear_bit() + set_bit()
inline Bitboard make_move_bb(Square from, Square to) {
return SetMaskBB[from] | SetMaskBB[to];
}
inline void do_move_bb(Bitboard *b, Bitboard move_bb) {
*b ^= move_bb;
}
/// rank_bb() and file_bb() gives a bitboard containing all squares on a given
/// file or rank. It is also possible to pass a square as input to these
/// functions.
@@ -298,29 +257,24 @@ inline Bitboard ray_bb(Square s, SignedDirection d) {
}
/// Functions for computing sliding attack bitboards. rook_attacks_bb(),
/// Functions for computing sliding attack bitboards. rook_attacks_bb(),
/// bishop_attacks_bb() and queen_attacks_bb() all take a square and a
/// bitboard of occupied squares as input, and return a bitboard representing
/// all squares attacked by a rook, bishop or queen on the given square.
#if defined(USE_COMPACT_ROOK_ATTACKS)
inline Bitboard file_attacks_bb(Square s, Bitboard blockers) {
Bitboard b = (blockers >> square_file(s)) & 0x01010101010100ULL;
return
FileAttacks[square_rank(s)][(b*0xd6e8802041d0c441ULL)>>58] & file_bb(s);
}
inline Bitboard rank_attacks_bb(Square s, Bitboard blockers) {
Bitboard b = (blockers >> ((s & 56) + 1)) & 63;
return RankAttacks[square_file(s)][b] & rank_bb(s);
}
#if defined(IS_64BIT)
inline Bitboard rook_attacks_bb(Square s, Bitboard blockers) {
return file_attacks_bb(s, blockers) | rank_attacks_bb(s, blockers);
Bitboard b = blockers & RMask[s];
return RAttacks[RAttackIndex[s] + ((b * RMult[s]) >> RShift[s])];
}
#elif defined(USE_32BIT_ATTACKS)
inline Bitboard bishop_attacks_bb(Square s, Bitboard blockers) {
Bitboard b = blockers & BMask[s];
return BAttacks[BAttackIndex[s] + ((b * BMult[s]) >> BShift[s])];
}
#else // if !defined(IS_64BIT)
inline Bitboard rook_attacks_bb(Square s, Bitboard blockers) {
Bitboard b = blockers & RMask[s];
@@ -330,17 +284,6 @@ inline Bitboard rook_attacks_bb(Square s, Bitboard blockers) {
>> RShift[s])];
}
#else
inline Bitboard rook_attacks_bb(Square s, Bitboard blockers) {
Bitboard b = blockers & RMask[s];
return RAttacks[RAttackIndex[s] + ((b * RMult[s]) >> RShift[s])];
}
#endif
#if defined(USE_32BIT_ATTACKS)
inline Bitboard bishop_attacks_bb(Square s, Bitboard blockers) {
Bitboard b = blockers & BMask[s];
return BAttacks[BAttackIndex[s] +
@@ -349,14 +292,7 @@ inline Bitboard bishop_attacks_bb(Square s, Bitboard blockers) {
>> BShift[s])];
}
#else // defined(USE_32BIT_ATTACKS)
inline Bitboard bishop_attacks_bb(Square s, Bitboard blockers) {
Bitboard b = blockers & BMask[s];
return BAttacks[BAttackIndex[s] + ((b * BMult[s]) >> BShift[s])];
}
#endif // defined(USE_32BIT_ATTACKS)
#endif
inline Bitboard queen_attacks_bb(Square s, Bitboard blockers) {
return rook_attacks_bb(s, blockers) | bishop_attacks_bb(s, blockers);
@@ -418,63 +354,30 @@ inline Bitboard isolated_pawn_mask(Square s) {
}
/// count_1s() counts the number of nonzero bits in a bitboard.
/// first_1() finds the least significant nonzero bit in a nonzero bitboard.
/// pop_1st_bit() finds and clears the least significant nonzero bit in a
/// nonzero bitboard.
#if defined(BITCOUNT_LOOP)
#if defined(USE_BSFQ) // Assembly code by Heinz van Saanen
inline int count_1s(Bitboard b) {
int r;
for(r = 0; b; r++, b &= b - 1);
return r;
inline Square __attribute__((always_inline)) first_1(Bitboard b) {
Bitboard dummy;
__asm__("bsfq %1, %0": "=r"(dummy): "rm"(b) );
return (Square)(dummy);
}
inline int count_1s_max_15(Bitboard b) {
return count_1s(b);
inline Square __attribute__((always_inline)) pop_1st_bit(Bitboard* b) {
const Square s = first_1(*b);
*b &= ~(1ULL<<s);
return s;
}
#elif defined(BITCOUNT_SWAR_32)
#else // if !defined(USE_BSFQ)
inline int count_1s(Bitboard b) {
unsigned w = unsigned(b >> 32), v = unsigned(b);
v -= (v >> 1) & 0x55555555; // 0-2 in 2 bits
w -= (w >> 1) & 0x55555555;
v = ((v >> 2) & 0x33333333) + (v & 0x33333333); // 0-4 in 4 bits
w = ((w >> 2) & 0x33333333) + (w & 0x33333333);
v = ((v >> 4) + v) & 0x0F0F0F0F; // 0-8 in 8 bits
v += (((w >> 4) + w) & 0x0F0F0F0F); // 0-16 in 8 bits
v *= 0x01010101; // mul is fast on amd procs
return int(v >> 24);
}
extern Square first_1(Bitboard b);
extern Square pop_1st_bit(Bitboard* b);
inline int count_1s_max_15(Bitboard b) {
unsigned w = unsigned(b >> 32), v = unsigned(b);
v -= (v >> 1) & 0x55555555; // 0-2 in 2 bits
w -= (w >> 1) & 0x55555555;
v = ((v >> 2) & 0x33333333) + (v & 0x33333333); // 0-4 in 4 bits
w = ((w >> 2) & 0x33333333) + (w & 0x33333333);
v += w; // 0-8 in 4 bits
v *= 0x11111111;
return int(v >> 28);
}
#elif defined(BITCOUNT_SWAR_64)
inline int count_1s(Bitboard b) {
b -= ((b>>1) & 0x5555555555555555ULL);
b = ((b>>2) & 0x3333333333333333ULL) + (b & 0x3333333333333333ULL);
b = ((b>>4) + b) & 0x0F0F0F0F0F0F0F0FULL;
b *= 0x0101010101010101ULL;
return int(b >> 56);
}
inline int count_1s_max_15(Bitboard b) {
b -= (b>>1) & 0x5555555555555555ULL;
b = ((b>>2) & 0x3333333333333333ULL) + (b & 0x3333333333333333ULL);
b *= 0x1111111111111111ULL;
return int(b >> 60);
}
#endif // BITCOUNT
#endif
////
@@ -483,8 +386,6 @@ inline int count_1s_max_15(Bitboard b) {
extern void print_bitboard(Bitboard b);
extern void init_bitboards();
extern Square first_1(Bitboard b);
extern Square pop_1st_bit(Bitboard *b);
#endif // !defined(BITBOARD_H_INCLUDED)

161
src/bitcount.h Normal file
View File

@@ -0,0 +1,161 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Stockfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined(BITCOUNT_H_INCLUDED)
#define BITCOUNT_H_INCLUDED
// 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"
// Select type of intrinsic bit count instruction to use
#if defined(__INTEL_COMPILER) && defined(IS_64BIT) && defined(USE_POPCNT) // Intel compiler
#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
#endif // cpu_has_popcnt() and POPCNT_INTRINSIC() definitions
/// Software implementation of bit count functions
#if defined(IS_64BIT)
inline int count_1s(Bitboard b) {
b -= ((b>>1) & 0x5555555555555555ULL);
b = ((b>>2) & 0x3333333333333333ULL) + (b & 0x3333333333333333ULL);
b = ((b>>4) + b) & 0x0F0F0F0F0F0F0F0FULL;
b *= 0x0101010101010101ULL;
return int(b >> 56);
}
inline int count_1s_max_15(Bitboard b) {
b -= (b>>1) & 0x5555555555555555ULL;
b = ((b>>2) & 0x3333333333333333ULL) + (b & 0x3333333333333333ULL);
b *= 0x1111111111111111ULL;
return int(b >> 60);
}
#else // if !defined(IS_64BIT)
inline int count_1s(Bitboard b) {
unsigned w = unsigned(b >> 32), v = unsigned(b);
v -= (v >> 1) & 0x55555555; // 0-2 in 2 bits
w -= (w >> 1) & 0x55555555;
v = ((v >> 2) & 0x33333333) + (v & 0x33333333); // 0-4 in 4 bits
w = ((w >> 2) & 0x33333333) + (w & 0x33333333);
v = ((v >> 4) + v) & 0x0F0F0F0F; // 0-8 in 8 bits
v += (((w >> 4) + w) & 0x0F0F0F0F); // 0-16 in 8 bits
v *= 0x01010101; // mul is fast on amd procs
return int(v >> 24);
}
inline int count_1s_max_15(Bitboard b) {
unsigned w = unsigned(b >> 32), v = unsigned(b);
v -= (v >> 1) & 0x55555555; // 0-2 in 2 bits
w -= (w >> 1) & 0x55555555;
v = ((v >> 2) & 0x33333333) + (v & 0x33333333); // 0-4 in 4 bits
w = ((w >> 2) & 0x33333333) + (w & 0x33333333);
v += w; // 0-8 in 4 bits
v *= 0x11111111;
return int(v >> 28);
}
#endif // BITCOUNT
/// count_1s() counts the number of nonzero bits in a bitboard.
/// If template parameter is true an intrinsic is called, otherwise
/// we fallback on a software implementation.
template<bool UseIntrinsic>
inline int count_1s(Bitboard b) {
return UseIntrinsic ? POPCNT_INTRINSIC(b) : count_1s(b);
}
template<bool UseIntrinsic>
inline int count_1s_max_15(Bitboard b) {
return UseIntrinsic ? POPCNT_INTRINSIC(b) : count_1s_max_15(b);
}
// Global constant initialized at startup that is set to true if
// CPU on which application runs supports POPCNT intrinsic. Unless
// USE_POPCNT is not defined.
const bool CpuHasPOPCNT = cpu_has_popcnt();
// Global constant used to print info about the use of 64 optimized
// functions to verify that a 64 bit compile has been correctly built.
#if defined(IS_64BIT)
const bool CpuHas64BitPath = true;
#else
const bool CpuHas64BitPath = false;
#endif
#endif // !defined(BITCOUNT_H_INCLUDED)

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -35,6 +35,7 @@
#include "mersenne.h"
#include "movegen.h"
using namespace std;
////
//// Global variables
@@ -49,7 +50,11 @@ Book OpeningBook;
namespace {
/// Random numbers from PolyGlot, used to compute book hash keys.
/// Book entry size in bytes
const int EntrySize = 16;
/// Random numbers from PolyGlot, used to compute book hash keys
const uint64_t Random64[781] = {
0x9D39247E33776D41ULL, 0x2AF7398005AAA5C7ULL, 0x44DB015024623547ULL,
@@ -318,30 +323,19 @@ namespace {
/// Indices to the Random64[] array
const int RandomPiece = 0;
const int RandomCastle = 768;
const int RandomPiece = 0;
const int RandomCastle = 768;
const int RandomEnPassant = 772;
const int RandomTurn = 780;
/// Convert pieces to the range 0..1
const int PieceTo12[] = {
0, 0, 2, 4, 6, 8, 10, 0, 0, 1, 3, 5, 7, 9, 11
};
const int RandomTurn = 780;
/// Prototypes
uint64_t book_key(const Position &pos);
uint64_t book_key(const Position& pos);
uint64_t book_piece_key(Piece p, Square s);
uint64_t book_castle_key(const Position &pos);
uint64_t book_ep_key(const Position &pos);
uint64_t book_color_key(const Position &pos);
uint16_t read_integer16(std::ifstream& file);
uint64_t read_integer64(std::ifstream& file);
uint64_t read_integer(std::ifstream& file, int size);
uint64_t book_castle_key(const Position& pos);
uint64_t book_ep_key(const Position& pos);
uint64_t book_color_key(const Position& pos);
}
@@ -350,99 +344,108 @@ namespace {
////
/// Constructor
/// Destructor. Be sure file is closed before we leave.
Book::Book() : bookSize(0) {}
Book::~Book() {
close();
}
/// Book::open() opens a book file with a given file name.
/// Book::open() opens a book file with a given file name
void Book::open(const std::string &fName) {
void Book::open(const string& fName) {
// Close old file before opening the new
close();
fileName = fName;
bookFile.open(fileName.c_str(), std::ifstream::in | std::ifstream::binary);
if (!bookFile.is_open())
ifstream::open(fileName.c_str(), ifstream::in | ifstream::binary);
if (!is_open())
return;
bookFile.seekg(0, std::ios::end);
bookSize = bookFile.tellg() / 16;
bookFile.seekg(0, std::ios::beg);
// Get the book size in number of entries
seekg(0, ios::end);
bookSize = tellg() / EntrySize;
seekg(0, ios::beg);
if (!bookFile.good())
if (!good())
{
std::cerr << "Failed to open book file " << fileName << std::endl;
exit(EXIT_FAILURE);
cerr << "Failed to open book file " << fileName << endl;
Application::exit_with_failure();
}
}
/// Book::close() closes the currently open book file.
/// Book::close() closes the file only if it is open, otherwise
/// we can end up in a little mess due to how std::ifstream works.
void Book::close() {
if (bookFile.is_open())
bookFile.close();
}
/// Book::is_open() tests whether a book file has been opened.
bool Book::is_open() const {
return bookFile.is_open() && bookSize != 0;
if (is_open())
ifstream::close();
}
/// Book::file_name() returns the file name of the currently active book,
/// or the empty string if no book is open.
const std::string Book::file_name() const {
const string Book::file_name() const {
return bookFile.is_open() ? fileName : "";
return is_open() ? fileName : "";
}
/// Book::get_move() gets a book move for a given position. Returns
/// Book::get_move() gets a book move for a given position. Returns
/// MOVE_NONE if no book move is found.
Move Book::get_move(const Position &pos) const {
if(this->is_open()) {
int bestMove = 0, bestScore = 0, move, score;
uint64_t key = book_key(pos);
BookEntry entry;
Move Book::get_move(const Position& pos) {
if (!is_open() || bookSize == 0)
return MOVE_NONE;
int bookMove = 0, scoresSum = 0;
uint64_t key = book_key(pos);
BookEntry entry;
// Choose a book move among the possible moves for the given position
for (int idx = find_key(key); idx < bookSize; idx++)
{
read_entry(entry, idx);
if (entry.key != key)
break;
int score = entry.count;
for(int i = this->find_key(key); i < bookSize; i++) {
this->read_entry(entry, i);
if(entry.key != key)
break;
move = entry.move;
score = entry.count;
assert(score > 0);
bestScore += score;
if(int(genrand_int32() % bestScore) < score)
bestMove = move;
}
if(bestMove != 0) {
MoveStack moves[256];
int n, j;
n = generate_legal_moves(pos, moves);
for(j = 0; j < n; j++)
if((int(moves[j].move) & 07777) == bestMove)
return moves[j].move;
}
// Choose book move according to its score. If a move has a very
// high score it has more probability to be choosen then a one with
// lower score. Note that first entry is always chosen.
scoresSum += score;
if (int(genrand_int32() % scoresSum) < score)
bookMove = entry.move;
}
if (!bookMove)
return MOVE_NONE;
MoveStack moves[256];
int n = generate_legal_moves(pos, moves);
for (int j = 0; j < n; j++)
if ((int(moves[j].move) & 07777) == bookMove)
return moves[j].move;
return MOVE_NONE;
}
/// Book::find_key() takes a book key as input, and does a binary search
/// through the book file for the given key. The index to the first book
/// entry with the same key as the input is returned. When the key is not
/// through the book file for the given key. The index to the first book
/// entry with the same key as the input is returned. When the key is not
/// found in the book file, bookSize is returned.
int Book::find_key(uint64_t key) const {
int Book::find_key(uint64_t key) {
int left, right, mid;
BookEntry entry;
@@ -452,46 +455,59 @@ int Book::find_key(uint64_t key) const {
assert(left <= right);
while(left < right) {
mid = (left + right) / 2;
assert(mid >= left && mid < right);
while (left < right)
{
mid = (left + right) / 2;
this->read_entry(entry, mid);
assert(mid >= left && mid < right);
if(key <= entry.key)
right = mid;
else
left = mid + 1;
read_entry(entry, mid);
if (key <= entry.key)
right = mid;
else
left = mid + 1;
}
assert(left == right);
this->read_entry(entry, left);
read_entry(entry, left);
return (entry.key == key)? left : bookSize;
}
/// Book::read_entry() takes a BookEntry reference and an integer index as
/// input, and looks up the opening book entry at the given index in the book
/// file. The book entry is copied to the first input parameter.
/// file. The book entry is copied to the first input parameter.
void Book::read_entry(BookEntry& entry, int n) const {
void Book::read_entry(BookEntry& entry, int idx) {
assert(n >= 0 && n < bookSize);
assert(bookFile.is_open());
assert(idx >= 0 && idx < bookSize);
assert(is_open());
bookFile.seekg(n*16, std::ios_base::beg);
if (!bookFile.good())
seekg(idx * EntrySize, ios_base::beg);
*this >> entry;
if (!good())
{
std::cerr << "Failed to read book entry at index " << n << std::endl;
exit(EXIT_FAILURE);
cerr << "Failed to read book entry at index " << idx << endl;
Application::exit_with_failure();
}
entry.key = read_integer64(bookFile);
entry.move = read_integer16(bookFile);
entry.count = read_integer16(bookFile);
entry.n = read_integer16(bookFile);
entry.sum = read_integer16(bookFile);
}
/// Book::read_integer() reads size chars from the file stream
/// and converts them in an integer number.
uint64_t Book::read_integer(int size) {
char buf[8];
read(buf, size);
// Numbers are stored on disk as a binary byte stream
uint64_t n = 0ULL;
for (int i = 0; i < size; i++)
n = (n << 8) + (unsigned char)buf[i];
return n;
}
@@ -501,92 +517,67 @@ void Book::read_entry(BookEntry& entry, int n) const {
namespace {
uint64_t book_key(const Position &pos) {
uint64_t book_key(const Position& pos) {
uint64_t result = 0ULL;
for(Color c = WHITE; c <= BLACK; c++) {
Bitboard b = pos.pieces_of_color(c);
Square s;
Piece p;
while(b != EmptyBoardBB) {
s = pop_1st_bit(&b);
p = pos.piece_on(s);
assert(piece_is_ok(p));
assert(color_of_piece(p) == c);
for (Color c = WHITE; c <= BLACK; c++)
{
Bitboard b = pos.pieces_of_color(c);
result ^= book_piece_key(p, s);
}
while (b)
{
Square s = pop_1st_bit(&b);
Piece p = pos.piece_on(s);
assert(piece_is_ok(p));
assert(color_of_piece(p) == c);
result ^= book_piece_key(p, s);
}
}
result ^= book_castle_key(pos);
result ^= book_ep_key(pos);
result ^= book_color_key(pos);
return result;
}
uint64_t book_piece_key(Piece p, Square s) {
return Random64[RandomPiece + (PieceTo12[int(p)]^1)*64 + int(s)];
/// Convert pieces to the range 0..11
static const int PieceTo12[] = { 0, 0, 2, 4, 6, 8, 10, 0, 0, 1, 3, 5, 7, 9, 11 };
return Random64[RandomPiece + (PieceTo12[int(p)]^1) * 64 + int(s)];
}
uint64_t book_castle_key(const Position &pos) {
uint64_t book_castle_key(const Position& pos) {
uint64_t result = 0ULL;
if(pos.can_castle_kingside(WHITE))
result ^= Random64[RandomCastle+0];
if(pos.can_castle_queenside(WHITE))
result ^= Random64[RandomCastle+1];
if(pos.can_castle_kingside(BLACK))
result ^= Random64[RandomCastle+2];
if(pos.can_castle_queenside(BLACK))
result ^= Random64[RandomCastle+3];
if (pos.can_castle_kingside(WHITE))
result ^= Random64[RandomCastle+0];
if (pos.can_castle_queenside(WHITE))
result ^= Random64[RandomCastle+1];
if (pos.can_castle_kingside(BLACK))
result ^= Random64[RandomCastle+2];
if (pos.can_castle_queenside(BLACK))
result ^= Random64[RandomCastle+3];
return result;
}
uint64_t book_ep_key(const Position &pos) {
return (pos.ep_square() == SQ_NONE)?
0ULL : Random64[RandomEnPassant + square_file(pos.ep_square())];
uint64_t book_ep_key(const Position& pos) {
return (pos.ep_square() == SQ_NONE ? 0ULL : Random64[RandomEnPassant + square_file(pos.ep_square())]);
}
uint64_t book_color_key(const Position &pos) {
return (pos.side_to_move() == WHITE)? Random64[RandomTurn] : 0ULL;
}
uint16_t read_integer16(std::ifstream& file) {
uint64_t n = read_integer(file, 2);
assert(n == (uint16_t)n);
return (uint16_t)n;
}
uint64_t read_integer64(std::ifstream& file) {
return read_integer(file, 8);
}
uint64_t read_integer(std::ifstream& file, int size) {
char buf[8];
file.read(buf, size);
if (!file.good())
{
std::cerr << "Failed to read " << size << " bytes from book file"
<< std::endl;
exit(EXIT_FAILURE);
}
// Numbers are stored in little endian format
uint64_t n = 0ULL;
for (int i = 0; i < size; i++)
n = (n << 8) + (unsigned char)buf[i];
return n;
uint64_t book_color_key(const Position& pos) {
return (pos.side_to_move() == WHITE ? Random64[RandomTurn] : 0ULL);
}
}

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -52,31 +52,24 @@ struct BookEntry {
uint16_t sum;
};
class Book {
class Book : private std::ifstream {
public:
// Constructors
Book();
// Open and close book files
void open(const std::string &fName);
~Book();
void open(const std::string& fName);
void close();
// Testing if a book is opened
bool is_open() const;
// The file name of the currently active book
const std::string file_name() const;
// Get a book move for a given position
Move get_move(const Position &pos) const;
Move get_move(const Position& pos);
private:
int find_key(uint64_t key) const;
void read_entry(BookEntry &entry, int n) const;
Book& operator>>(uint64_t& n) { n = read_integer(8); return *this; }
Book& operator>>(uint16_t& n) { n = (uint16_t)read_integer(2); return *this; }
void operator>>(BookEntry& e) { *this >> e.key >> e.move >> e.count >> e.n >> e.sum; }
uint64_t read_integer(int size);
void read_entry(BookEntry& e, int n);
int find_key(uint64_t key);
std::string fileName;
mutable std::ifstream bookFile;
int bookSize;
};

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -37,7 +37,6 @@ enum Color {
//// Inline functions
////
inline Color operator+ (Color c, int i) { return Color(int(c) + i); }
inline void operator++ (Color &c, int) { c = Color(int(c) + 1); }
inline Color opposite_color(Color c) {

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -35,9 +35,6 @@ enum Depth {
//// Constants
////
/// Note: If OnePly is changed, the constant HistoryMax in history.h should
/// probably also be changed.
const Depth OnePly = Depth(2);

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -26,6 +26,32 @@
#include "square.h"
////
//// Local definitions
////
namespace {
const SquareDelta directionToDelta[] = {
DELTA_E, DELTA_W, DELTA_N, DELTA_S, DELTA_NE, DELTA_SW, DELTA_NW, DELTA_SE
};
bool reachable(Square orig, Square dest, SignedDirection dir) {
SquareDelta delta = directionToDelta[dir];
Square from = orig;
Square to = from + delta;
while (to != dest && square_distance(to, from) == 1 && square_is_ok(to))
{
from = to;
to += delta;
}
return (to == dest && square_distance(from, to) == 1);
}
}
////
//// Variables
////
@@ -39,25 +65,23 @@ uint8_t SignedDirectionTable[64][64];
////
void init_direction_table() {
SquareDelta deltas[8] = {
DELTA_E, DELTA_W, DELTA_N, DELTA_S, DELTA_NE, DELTA_SW, DELTA_NW, DELTA_SE
};
for(Square s1 = SQ_A1; s1 <= SQ_H8; s1++)
for(Square s2 = SQ_A1; s2 <= SQ_H8; s2++) {
DirectionTable[s1][s2] = uint8_t(DIR_NONE);
SignedDirectionTable[s1][s2] = uint8_t(SIGNED_DIR_NONE);
if(s1 == s2) continue;
for(SignedDirection d = SIGNED_DIR_E; d <= SIGNED_DIR_SE; d++) {
SquareDelta delta = deltas[d];
Square s3, s4;
for(s4 = s1 + delta, s3 = s1;
square_distance(s4, s3) == 1 && s4 != s2 && square_is_ok(s4);
s3 = s4, s4 += delta);
if(s4 == s2 && square_distance(s4, s3) == 1) {
SignedDirectionTable[s1][s2] = uint8_t(d);
DirectionTable[s1][s2] = uint8_t(d/2);
break;
}
for (Square s1 = SQ_A1; s1 <= SQ_H8; s1++)
for (Square s2 = SQ_A1; s2 <= SQ_H8; s2++)
{
DirectionTable[s1][s2] = uint8_t(DIR_NONE);
SignedDirectionTable[s1][s2] = uint8_t(SIGNED_DIR_NONE);
if (s1 == s2)
continue;
for (SignedDirection d = SIGNED_DIR_E; d != SIGNED_DIR_NONE; d++)
{
if (reachable(s1, s2, d))
{
SignedDirectionTable[s1][s2] = uint8_t(d);
DirectionTable[s1][s2] = uint8_t(d / 2);
break;
}
}
}
}
}

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -25,6 +25,7 @@
#include <cassert>
#include "bitbase.h"
#include "bitcount.h"
#include "endgame.h"

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -65,7 +65,7 @@ enum EndgameType {
template<typename T>
class EndgameFunctionBase {
public:
EndgameFunctionBase(Color c) : strongerSide(c) { weakerSide = opposite_color(strongerSide); }
EndgameFunctionBase(Color c) : strongerSide(c), weakerSide(opposite_color(c)) {}
virtual ~EndgameFunctionBase() {}
virtual T apply(const Position&) = 0;

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -25,6 +25,7 @@
#include <cassert>
#include <cstring>
#include "bitcount.h"
#include "evaluate.h"
#include "material.h"
#include "pawns.h"
@@ -39,23 +40,20 @@
namespace {
const int Sign[2] = {1, -1};
const int Sign[2] = { 1, -1 };
// Evaluation grain size, must be a power of 2.
// Evaluation grain size, must be a power of 2
const int GrainSize = 4;
// Evaluation weights
int WeightMobilityMidgame = 0x100;
int WeightMobilityEndgame = 0x100;
int WeightPawnStructureMidgame = 0x100;
int WeightPawnStructureEndgame = 0x100;
int WeightPassedPawnsMidgame = 0x100;
int WeightPassedPawnsEndgame = 0x100;
int WeightKingSafety[2] = { 0x100, 0x100 };
// Evaluation weights, initialized from UCI options
int WeightMobilityMidgame, WeightMobilityEndgame;
int WeightPawnStructureMidgame, WeightPawnStructureEndgame;
int WeightPassedPawnsMidgame, WeightPassedPawnsEndgame;
int WeightKingSafety[2];
int WeightSpace;
// Internal evaluation weights. These are applied on top of the evaluation
// weights read from UCI parameters. The purpose is to be able to change
// Internal evaluation weights. These are applied on top of the evaluation
// weights read from UCI parameters. The purpose is to be able to change
// the evaluation weights while keeping the default values of the UCI
// parameters at 100, which looks prettier.
//
@@ -70,6 +68,8 @@ namespace {
const int WeightKingOppSafetyInternal = 0x101;
const int WeightSpaceInternal = 0x02F;
// Mobility and outposts bonus modified by Joona Kiiski
//
// Visually better to define tables constants
typedef Value V;
@@ -77,70 +77,70 @@ namespace {
// of attacked squares not occupied by friendly piecess.
const Value MidgameKnightMobilityBonus[] = {
// 0 1 2 3 4 5 6 7 8
V(-30), V(-20),V(-10), V(0), V(10), V(20), V(25), V(30), V(30)
V(-38), V(-25),V(-12), V(0), V(12), V(25), V(31), V(38), V(38)
};
const Value EndgameKnightMobilityBonus[] = {
// 0 1 2 3 4 5 6 7 8
V(-30), V(-20),V(-10), V(0), V(10), V(20), V(25), V(30), V(30)
V(-33), V(-23),V(-13), V(-3), V(7), V(17), V(22), V(27), V(27)
};
// Bishop mobility bonus in middle game and endgame, indexed by the number
// of attacked squares not occupied by friendly pieces. X-ray attacks through
// of attacked squares not occupied by friendly pieces. X-ray attacks through
// queens are also included.
const Value MidgameBishopMobilityBonus[] = {
// 0 1 2 3 4 5 6 7
V(-30), V(-15), V(0), V(15), V(30), V(45), V(58), V(66),
V(-25), V(-11), V(3), V(17), V(31), V(45), V(57), V(65),
// 8 9 10 11 12 13 14 15
V( 72), V( 76), V(78), V(80), V(81), V(82), V(83), V(83)
V( 71), V( 74), V(76), V(78), V(79), V(80), V(81), V(81)
};
const Value EndgameBishopMobilityBonus[] = {
// 0 1 2 3 4 5 6 7
V(-30), V(-15), V(0), V(15), V(30), V(45), V(58), V(66),
V(-30), V(-16), V(-2), V(12), V(26), V(40), V(52), V(60),
// 8 9 10 11 12 13 14 15
V( 72), V( 76), V(78), V(80), V(81), V(82), V(83), V(83)
V( 65), V( 69), V(71), V(73), V(74), V(75), V(76), V(76)
};
// Rook mobility bonus in middle game and endgame, indexed by the number
// of attacked squares not occupied by friendly pieces. X-ray attacks through
// of attacked squares not occupied by friendly pieces. X-ray attacks through
// queens and rooks are also included.
const Value MidgameRookMobilityBonus[] = {
// 0 1 2 3 4 5 6 7
V(-18), V(-12), V(-6), V(0), V(6), V(12), V(16), V(21),
V(-20), V(-14), V(-8), V(-2), V(4), V(10), V(14), V(19),
// 8 9 10 11 12 13 14 15
V( 24), V( 27), V(28), V(29), V(30), V(31), V(32), V(33)
V( 23), V( 26), V(27), V(28), V(29), V(30), V(31), V(32)
};
const Value EndgameRookMobilityBonus[] = {
// 0 1 2 3 4 5 6 7
V(-30), V(-18), V(-6), V(6), V(18), V(30), V(42), V(54),
V(-36), V(-19), V(-3), V(13), V(29), V(46), V(62), V(79),
// 8 9 10 11 12 13 14 15
V( 66), V( 74), V(78), V(80), V(81), V(82), V(83), V(83)
V( 95), V(106),V(111),V(114),V(116),V(117),V(118),V(118)
};
// Queen mobility bonus in middle game and endgame, indexed by the number
// of attacked squares not occupied by friendly pieces.
const Value MidgameQueenMobilityBonus[] = {
// 0 1 2 3 4 5 6 7
V(-10), V(-8), V(-6), V(-4), V(-2), V( 0), V( 2), V( 4),
V(-10), V(-8), V(-6), V(-3), V(-1), V( 1), V( 3), V( 5),
// 8 9 10 11 12 13 14 15
V( 6), V( 8), V(10), V(12), V(13), V(14), V(15), V(16),
V( 8), V(10), V(12), V(15), V(16), V(17), V(18), V(20),
// 16 17 18 19 20 21 22 23
V( 16), V(16), V(16), V(16), V(16), V(16), V(16), V(16),
V( 20), V(20), V(20), V(20), V(20), V(20), V(20), V(20),
// 24 25 26 27 28 29 30 31
V( 16), V(16), V(16), V(16), V(16), V(16), V(16), V(16)
V( 20), V(20), V(20), V(20), V(20), V(20), V(20), V(20)
};
const Value EndgameQueenMobilityBonus[] = {
// 0 1 2 3 4 5 6 7
V(-20),V(-15),V(-10), V(-5), V( 0), V( 5), V(10), V(15),
V(-18),V(-13), V(-7), V(-2), V( 3), V (8), V(13), V(19),
// 8 9 10 11 12 13 14 15
V( 19), V(23), V(27), V(29), V(30), V(30), V(30), V(30),
V( 23), V(27), V(32), V(34), V(35), V(35), V(35), V(35),
// 16 17 18 19 20 21 22 23
V( 30), V(30), V(30), V(30), V(30), V(30), V(30), V(30),
V( 35), V(35), V(35), V(35), V(35), V(35), V(35), V(35),
// 24 25 26 27 28 29 30 31
V( 30), V(30), V(30), V(30), V(30), V(30), V(30), V(30)
V( 35), V(35), V(35), V(35), V(35), V(35), V(35), V(35)
};
// Outpost bonuses for knights and bishops, indexed by square (from white's
@@ -149,10 +149,10 @@ namespace {
// A B C D E F G H
V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(0), // 1
V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(0), // 2
V(0), V(0), V(5),V(10),V(10), V(5), V(0), V(0), // 3
V(0), V(5),V(20),V(30),V(30),V(20), V(5), V(0), // 4
V(0),V(10),V(30),V(40),V(40),V(30),V(10), V(0), // 5
V(0), V(5),V(20),V(20),V(20),V(20), V(5), V(0), // 6
V(0), V(0), V(4), V(8), V(8), V(4), V(0), V(0), // 3
V(0), V(4),V(17),V(26),V(26),V(17), V(4), V(0), // 4
V(0), V(8),V(26),V(35),V(35),V(26), V(8), V(0), // 5
V(0), V(4),V(17),V(17),V(17),V(17), V(4), V(0), // 6
V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(0), // 7
V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(0) // 8
};
@@ -163,7 +163,7 @@ namespace {
V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(0), // 2
V(0), V(0), V(5), V(5), V(5), V(5), V(0), V(0), // 3
V(0), V(5),V(10),V(10),V(10),V(10), V(5), V(0), // 4
V(0),V(10),V(20),V(20),V(20),V(20),V(10), V(0), // 5
V(0),V(10),V(21),V(21),V(21),V(21),V(10), V(0), // 5
V(0), V(5), V(8), V(8), V(8), V(8), V(5), V(0), // 6
V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(0), // 7
V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(0) // 8
@@ -172,44 +172,43 @@ namespace {
// Bonus for unstoppable passed pawns
const Value UnstoppablePawnValue = Value(0x500);
// Rooks and queens on the 7th rank
// Rooks and queens on the 7th rank (modified by Joona Kiiski)
const Value MidgameRookOn7thBonus = Value(47);
const Value EndgameRookOn7thBonus = Value(98);
const Value MidgameQueenOn7thBonus = Value(27);
const Value EndgameQueenOn7thBonus = Value(54);
// Rooks on open files
// Rooks on open files (modified by Joona Kiiski)
const Value RookOpenFileBonus = Value(43);
const Value RookHalfOpenFileBonus = Value(19);
// Penalty for rooks trapped inside a friendly king which has lost the
// right to castle:
// right to castle.
const Value TrappedRookPenalty = Value(180);
// Penalty for a bishop on a7/h7 (a2/h2 for black) which is trapped by
// enemy pawns:
// enemy pawns.
const Value TrappedBishopA7H7Penalty = Value(300);
// Bitboard masks for detecting trapped bishops on a7/h7 (a2/h2 for black):
// Bitboard masks for detecting trapped bishops on a7/h7 (a2/h2 for black)
const Bitboard MaskA7H7[2] = {
((1ULL << SQ_A7) | (1ULL << SQ_H7)),
((1ULL << SQ_A2) | (1ULL << SQ_H2))
};
// Penalty for a bishop on a1/h1 (a8/h8 for black) which is trapped by
// a friendly pawn on b2/g2 (b7/g7 for black). This can obviously only
// a friendly pawn on b2/g2 (b7/g7 for black). This can obviously only
// happen in Chess960 games.
const Value TrappedBishopA1H1Penalty = Value(100);
// Bitboard masks for detecting trapped bishops on a1/h1 (a8/h8 for black):
// Bitboard masks for detecting trapped bishops on a1/h1 (a8/h8 for black)
const Bitboard MaskA1H1[2] = {
((1ULL << SQ_A1) | (1ULL << SQ_H1)),
((1ULL << SQ_A8) | (1ULL << SQ_H8))
};
// The SpaceMask[color] contains area of the board which is consdered by
// the space evaluation. In the middle game, each side is given a bonus
// the space evaluation. In the middle game, each side is given a bonus
// based on how many squares inside this area are safe and available for
// friendly minor pieces.
const Bitboard SpaceMask[2] = {
@@ -221,30 +220,26 @@ namespace {
(1ULL<<SQ_C5) | (1ULL<<SQ_D5) | (1ULL<<SQ_E5) | (1ULL<<SQ_F5)
};
/// King safety constants and variables. The king safety scores are taken
/// from the array SafetyTable[]. Various little "meta-bonuses" measuring
/// King safety constants and variables. The king safety scores are taken
/// from the array SafetyTable[]. Various little "meta-bonuses" measuring
/// the strength of the attack are added up into an integer, which is used
/// as an index to SafetyTable[].
// Attack weights for each piece type.
// Attack weights for each piece type
const int QueenAttackWeight = 5;
const int RookAttackWeight = 3;
const int BishopAttackWeight = 2;
const int KnightAttackWeight = 2;
// Bonuses for safe checks for each piece type.
int QueenContactCheckBonus = 3;
int QueenCheckBonus = 2;
int RookCheckBonus = 1;
int BishopCheckBonus = 1;
int KnightCheckBonus = 1;
int DiscoveredCheckBonus = 3;
// Bonuses for safe checks, initialized from UCI options
int QueenContactCheckBonus, DiscoveredCheckBonus;
int QueenCheckBonus, RookCheckBonus, BishopCheckBonus, KnightCheckBonus;
// Scan for queen contact mates?
const bool QueenContactMates = true;
// Bonus for having a mate threat.
int MateThreatBonus = 3;
// Bonus for having a mate threat, initialized from UCI options
int MateThreatBonus;
// InitKingDanger[] contains bonuses based on the position of the defending
// king.
@@ -259,40 +254,41 @@ namespace {
15, 15, 15, 15, 15, 15, 15, 15
};
// SafetyTable[] contains the actual king safety scores. It is initialized
// SafetyTable[] contains the actual king safety scores. It is initialized
// in init_safety().
Value SafetyTable[100];
// Pawn and material hash tables, indexed by the current thread id
PawnInfoTable *PawnTable[8] = {0, 0, 0, 0, 0, 0, 0, 0};
MaterialInfoTable *MaterialTable[8] = {0, 0, 0, 0, 0, 0, 0, 0};
PawnInfoTable* PawnTable[8] = {0, 0, 0, 0, 0, 0, 0, 0};
MaterialInfoTable* MaterialTable[8] = {0, 0, 0, 0, 0, 0, 0, 0};
// Sizes of pawn and material hash tables
const int PawnTableSize = 16384;
const int MaterialTableSize = 1024;
// Array which gives the number of nonzero bits in an 8-bit integer:
// Array which gives the number of nonzero bits in an 8-bit integer
uint8_t BitCount8Bit[256];
// Function prototypes
template<PieceType Piece>
template<bool HasPopCnt>
Value do_evaluate(const Position& pos, EvalInfo& ei, int threadID);
template<PieceType Piece, bool HasPopCnt>
void evaluate_pieces(const Position& p, Color us, EvalInfo& ei);
template<>
void evaluate_pieces<KING>(const Position& p, Color us, EvalInfo &ei);
template<bool HasPopCnt>
void evaluate_king(const Position& p, Color us, EvalInfo &ei);
void evaluate_passed_pawns(const Position &pos, EvalInfo &ei);
void evaluate_trapped_bishop_a7h7(const Position &pos, Square s, Color us,
EvalInfo &ei);
void evaluate_trapped_bishop_a1h1(const Position &pos, Square s, Color us,
EvalInfo &ei);
template<bool HasPopCnt>
void evaluate_space(const Position &p, Color us, EvalInfo &ei);
inline Value apply_weight(Value v, int w);
Value scale_by_game_phase(Value mv, Value ev, Phase ph, const ScaleFactor sf[]);
int count_1s_8bit(Bitboard b);
int compute_weight(int uciWeight, int internalWeight);
int weight_option(const std::string& opt, int weight);
void init_safety();
@@ -304,11 +300,19 @@ namespace {
//// Functions
////
/// evaluate() is the main evaluation function. It always computes two
/// evaluate() is the main evaluation function. It always computes two
/// values, an endgame score and a middle game score, and interpolates
/// between them based on the remaining material.
Value evaluate(const Position& pos, EvalInfo& ei, int threadID) {
Value evaluate(const Position &pos, EvalInfo &ei, int threadID) {
return CpuHasPOPCNT ? do_evaluate<true>(pos, ei, threadID)
: do_evaluate<false>(pos, ei, threadID);
}
namespace {
template<bool HasPopCnt>
Value do_evaluate(const Position& pos, EvalInfo& ei, int threadID) {
assert(pos.is_ok());
assert(threadID >= 0 && threadID < THREAD_MAX);
@@ -349,16 +353,16 @@ Value evaluate(const Position &pos, EvalInfo &ei, int threadID) {
// Initialize pawn attack bitboards for both sides
ei.attackedBy[WHITE][PAWN] = ((pos.pawns(WHITE) << 9) & ~FileABB) | ((pos.pawns(WHITE) << 7) & ~FileHBB);
ei.attackedBy[BLACK][PAWN] = ((pos.pawns(BLACK) >> 7) & ~FileABB) | ((pos.pawns(BLACK) >> 9) & ~FileHBB);
ei.kingAttackersCount[WHITE] = count_1s_max_15(ei.attackedBy[WHITE][PAWN] & ei.attackedBy[BLACK][KING])/2;
ei.kingAttackersCount[BLACK] = count_1s_max_15(ei.attackedBy[BLACK][PAWN] & ei.attackedBy[WHITE][KING])/2;
ei.kingAttackersCount[WHITE] = count_1s_max_15<HasPopCnt>(ei.attackedBy[WHITE][PAWN] & ei.attackedBy[BLACK][KING])/2;
ei.kingAttackersCount[BLACK] = count_1s_max_15<HasPopCnt>(ei.attackedBy[BLACK][PAWN] & ei.attackedBy[WHITE][KING])/2;
// Evaluate pieces
for (Color c = WHITE; c <= BLACK; c++)
{
evaluate_pieces<KNIGHT>(pos, c, ei);
evaluate_pieces<BISHOP>(pos, c, ei);
evaluate_pieces<ROOK>(pos, c, ei);
evaluate_pieces<QUEEN>(pos, c, ei);
evaluate_pieces<KNIGHT, HasPopCnt>(pos, c, ei);
evaluate_pieces<BISHOP, HasPopCnt>(pos, c, ei);
evaluate_pieces<ROOK, HasPopCnt>(pos, c, ei);
evaluate_pieces<QUEEN, HasPopCnt>(pos, c, ei);
// Sum up all attacked squares
ei.attackedBy[c][0] = ei.attackedBy[c][PAWN] | ei.attackedBy[c][KNIGHT]
@@ -366,11 +370,11 @@ Value evaluate(const Position &pos, EvalInfo &ei, int threadID) {
| ei.attackedBy[c][QUEEN] | ei.attackedBy[c][KING];
}
// Kings. Kings are evaluated after all other pieces for both sides,
// Kings. Kings are evaluated after all other pieces for both sides,
// because we need complete attack information for all pieces when computing
// the king safety evaluation.
for (Color c = WHITE; c <= BLACK; c++)
evaluate_pieces<KING>(pos, c, ei);
evaluate_king<HasPopCnt>(pos, c, ei);
// Evaluate passed pawns. We evaluate passed pawns for both sides at once,
// because we need to know which side promotes first in positions where
@@ -399,8 +403,8 @@ Value evaluate(const Position &pos, EvalInfo &ei, int threadID) {
// Evaluate space for both sides
if (ei.mi->space_weight() > 0)
{
evaluate_space(pos, WHITE, ei);
evaluate_space(pos, BLACK, ei);
evaluate_space<HasPopCnt>(pos, WHITE, ei);
evaluate_space<HasPopCnt>(pos, BLACK, ei);
}
}
@@ -446,6 +450,7 @@ Value evaluate(const Position &pos, EvalInfo &ei, int threadID) {
return (ei.mateThreat[stm] == MOVE_NONE ? v : 8 * QueenValueMidgame - v);
}
} // namespace
/// quick_evaluate() does a very approximate evaluation of the current position.
/// It currently considers only material and piece square table scores. Perhaps
@@ -505,6 +510,8 @@ void quit_eval() {
{
delete PawnTable[i];
delete MaterialTable[i];
PawnTable[i] = NULL;
MaterialTable[i] = NULL;
}
}
@@ -533,76 +540,76 @@ void read_weights(Color us) {
namespace {
// evaluate_common() computes terms common to all pieces attack
// evaluate_mobility() computes mobility and attacks for every piece
template<PieceType Piece>
int evaluate_common(const Position& p, const Bitboard& b, Color us, EvalInfo& ei, Square s = SQ_NONE) {
template<PieceType Piece, bool HasPopCnt>
int evaluate_mobility(const Position& p, const Bitboard& b, Color us, Color them, EvalInfo& ei) {
static const int AttackWeight[] = { 0, 0, KnightAttackWeight, BishopAttackWeight, RookAttackWeight, QueenAttackWeight };
static const Value* MgBonus[] = { 0, 0, MidgameKnightMobilityBonus, MidgameBishopMobilityBonus, MidgameRookMobilityBonus, MidgameQueenMobilityBonus };
static const Value* EgBonus[] = { 0, 0, EndgameKnightMobilityBonus, EndgameBishopMobilityBonus, EndgameRookMobilityBonus, EndgameQueenMobilityBonus };
static const Value* OutpostBonus[] = { 0, 0, KnightOutpostBonus, BishopOutpostBonus, 0, 0 };
Color them = opposite_color(us);
// Update attack info
ei.attackedBy[us][Piece] |= b;
// King attack
// King attacks
if (b & ei.kingZone[us])
{
ei.kingAttackersCount[us]++;
ei.kingAttackersWeight[us] += AttackWeight[Piece];
Bitboard bb = (b & ei.attackedBy[them][KING]);
if (bb)
ei.kingAdjacentZoneAttacksCount[us] += count_1s_max_15(bb);
ei.kingAdjacentZoneAttacksCount[us] += count_1s_max_15<HasPopCnt>(bb);
}
// Remove squares protected by enemy pawns
Bitboard bb = (b & ~ei.attackedBy[them][PAWN]);
// Mobility
int mob = (Piece != QUEEN ? count_1s_max_15(bb & ~p.pieces_of_color(us))
: count_1s(bb & ~p.pieces_of_color(us)));
int mob = (Piece != QUEEN ? count_1s_max_15<HasPopCnt>(bb & ~p.pieces_of_color(us))
: count_1s<HasPopCnt>(bb & ~p.pieces_of_color(us)));
ei.mgMobility += Sign[us] * MgBonus[Piece][mob];
ei.egMobility += Sign[us] * EgBonus[Piece][mob];
return mob;
}
// Bishop and Knight outposts
if ( (Piece != BISHOP && Piece != KNIGHT) // compile time condition
|| !p.square_is_weak(s, them))
return mob;
// evaluate_outposts() evaluates bishop and knight outposts squares
template<PieceType Piece>
void evaluate_outposts(const Position& p, Color us, Color them, EvalInfo& ei, Square s) {
// Initial bonus based on square
Value v, bonus;
v = bonus = OutpostBonus[Piece][relative_square(us, s)];
Value bonus = (Piece == BISHOP ? BishopOutpostBonus[relative_square(us, s)]
: KnightOutpostBonus[relative_square(us, s)]);
// Increase bonus if supported by pawn, especially if the opponent has
// no minor piece which can exchange the outpost piece
if (v && (p.pawn_attacks(them, s) & p.pawns(us)))
if (bonus && (p.pawn_attacks(them, s) & p.pawns(us)))
{
bonus += v / 2;
if ( p.piece_count(them, KNIGHT) == 0
if ( p.knights(them) == EmptyBoardBB
&& (SquaresByColorBB[square_color(s)] & p.bishops(them)) == EmptyBoardBB)
bonus += v;
bonus += bonus + bonus / 2;
else
bonus += bonus / 2;
}
ei.mgValue += Sign[us] * bonus;
ei.egValue += Sign[us] * bonus;
return mob;
}
// evaluate_pieces<>() assigns bonuses and penalties to the pieces of a given
// color.
template<PieceType Piece>
template<PieceType Piece, bool HasPopCnt>
void evaluate_pieces(const Position& pos, Color us, EvalInfo& ei) {
Bitboard b;
Square s, ksq;
Color them;
int mob;
File f;
Color them = opposite_color(us);
for (int i = 0, e = pos.piece_count(us, Piece); i < e; i++)
{
@@ -614,9 +621,15 @@ namespace {
b = bishop_attacks_bb(s, pos.occupied_squares() & ~pos.queens(us));
else if (Piece == ROOK)
b = rook_attacks_bb(s, pos.occupied_squares() & ~pos.rooks_and_queens(us));
else
assert(false);
// Attacks, mobility and outposts
mob = evaluate_common<Piece>(pos, b, us, ei, s);
// Attacks and mobility
mob = evaluate_mobility<Piece, HasPopCnt>(pos, b, us, them, ei);
// Bishop and knight outposts squares
if ((Piece == BISHOP || Piece == KNIGHT) && pos.square_is_weak(s, them))
evaluate_outposts<Piece>(pos, us, them, ei, s);
// Special patterns: trapped bishops on a7/h7/a2/h2
// and trapped bishops on a1/h1/a8/h8 in Chess960.
@@ -632,8 +645,6 @@ namespace {
if (Piece == ROOK || Piece == QUEEN)
{
// Queen or rook on 7th rank
them = opposite_color(us);
if ( relative_rank(us, s) == RANK_7
&& relative_rank(us, pos.king_square(them)) == RANK_8)
{
@@ -695,11 +706,10 @@ namespace {
return b >> (num << 3);
}
// evaluate_pieces<KING>() assigns bonuses and penalties to a king of a given
// color.
// evaluate_king<>() assigns bonuses and penalties to a king of a given color.
template<>
void evaluate_pieces<KING>(const Position& p, Color us, EvalInfo& ei) {
template<bool HasPopCnt>
void evaluate_king(const Position& p, Color us, EvalInfo& ei) {
int shelter = 0, sign = Sign[us];
Square s = p.king_square(us);
@@ -707,15 +717,23 @@ namespace {
// King shelter
if (relative_rank(us, s) <= RANK_4)
{
Bitboard pawns = p.pawns(us) & this_and_neighboring_files_bb(s);
Rank r = square_rank(s);
for (int i = 1; i < 4; i++)
shelter += count_1s_8bit(shiftRowsDown(pawns, r+i*sign)) * (128>>i);
// Shelter cache lookup
shelter = ei.pi->kingShelter(us, s);
if (shelter == -1)
{
shelter = 0;
Bitboard pawns = p.pawns(us) & this_and_neighboring_files_bb(s);
Rank r = square_rank(s);
for (int i = 1; i < 4; i++)
shelter += BitCount8Bit[shiftRowsDown(pawns, r+i*sign) & 0xFF] * (128 >> i);
// Cache shelter value in pawn info
ei.pi->setKingShelter(us, s, shelter);
}
ei.mgValue += sign * Value(shelter);
}
// King safety. This is quite complicated, and is almost certainly far
// King safety. This is quite complicated, and is almost certainly far
// from optimally tuned.
Color them = opposite_color(us);
@@ -744,7 +762,7 @@ namespace {
// quality of the pawn shelter.
int attackUnits =
Min((ei.kingAttackersCount[them] * ei.kingAttackersWeight[them]) / 2, 25)
+ (ei.kingAdjacentZoneAttacksCount[them] + count_1s_max_15(undefended)) * 3
+ (ei.kingAdjacentZoneAttacksCount[them] + count_1s_max_15<HasPopCnt>(undefended)) * 3
+ InitKingDanger[relative_square(us, s)] - (shelter >> 5);
// Analyse safe queen contact checks
@@ -760,7 +778,7 @@ namespace {
{
// The bitboard b now contains the squares available for safe queen
// contact checks.
int count = count_1s_max_15(b);
int count = count_1s_max_15<HasPopCnt>(b);
attackUnits += QueenContactCheckBonus * count * (sente ? 2 : 1);
// Is there a mate threat?
@@ -800,12 +818,12 @@ namespace {
// Queen checks
b2 = b & ei.attacked_by(them, QUEEN);
if( b2)
attackUnits += QueenCheckBonus * count_1s_max_15(b2);
attackUnits += QueenCheckBonus * count_1s_max_15<HasPopCnt>(b2);
// Rook checks
b2 = b & ei.attacked_by(them, ROOK);
if (b2)
attackUnits += RookCheckBonus * count_1s_max_15(b2);
attackUnits += RookCheckBonus * count_1s_max_15<HasPopCnt>(b2);
}
if (QueenCheckBonus > 0 || BishopCheckBonus > 0)
{
@@ -814,12 +832,12 @@ namespace {
// Queen checks
b2 = b & ei.attacked_by(them, QUEEN);
if (b2)
attackUnits += QueenCheckBonus * count_1s_max_15(b2);
attackUnits += QueenCheckBonus * count_1s_max_15<HasPopCnt>(b2);
// Bishop checks
b2 = b & ei.attacked_by(them, BISHOP);
if (b2)
attackUnits += BishopCheckBonus * count_1s_max_15(b2);
attackUnits += BishopCheckBonus * count_1s_max_15<HasPopCnt>(b2);
}
if (KnightCheckBonus > 0)
{
@@ -828,7 +846,7 @@ namespace {
// Knight checks
b2 = b & ei.attacked_by(them, KNIGHT);
if (b2)
attackUnits += KnightCheckBonus * count_1s_max_15(b2);
attackUnits += KnightCheckBonus * count_1s_max_15<HasPopCnt>(b2);
}
// Analyse discovered checks (only for non-pawns right now, consider
@@ -837,7 +855,7 @@ namespace {
{
b = p.discovered_check_candidates(them) & ~p.pawns();
if (b)
attackUnits += DiscoveredCheckBonus * count_1s_max_15(b) * (sente? 2 : 1);
attackUnits += DiscoveredCheckBonus * count_1s_max_15<HasPopCnt>(b) * (sente? 2 : 1);
}
// Has a mate threat been found? We don't do anything here if the
@@ -920,29 +938,23 @@ namespace {
&& (squares_behind(us, s) & pos.rooks_and_queens(them)))
b3 = b2;
if ((b2 & pos.pieces_of_color(them)) == EmptyBoardBB)
{
// There are no enemy pieces in the pawn's path! Are any of the
// squares in the pawn's path attacked by the enemy?
if (b3 == EmptyBoardBB)
// No enemy attacks, huge bonus!
ebonus += Value(tr * (b2 == b4 ? 17 : 15));
else
// OK, there are enemy attacks. Are those squares which are
// attacked by the enemy also attacked by us? If yes, big bonus
// (but smaller than when there are no enemy attacks), if no,
// somewhat smaller bonus.
ebonus += Value(tr * ((b3 & b4) == b3 ? 13 : 8));
}
// Squares attacked or occupied by enemy pieces
b3 |= (b2 & pos.pieces_of_color(them));
// There are no enemy pawns in the pawn's path
assert((b2 & pos.pieces_of_color_and_type(them, PAWN)) == EmptyBoardBB);
// Are any of the squares in the pawn's path attacked or occupied by the enemy?
if (b3 == EmptyBoardBB)
// No enemy attacks or pieces, huge bonus!
ebonus += Value(tr * (b2 == b4 ? 17 : 15));
else
{
// There are some enemy pieces in the pawn's path. While this is
// sad, we still assign a moderate bonus if all squares in the path
// which are either occupied by or attacked by enemy pieces are
// also attacked by us.
if (((b3 | (b2 & pos.pieces_of_color(them))) & ~b4) == EmptyBoardBB)
ebonus += Value(tr * 6);
}
// OK, there are enemy attacks or pieces (but not pawns). Are those
// squares which are attacked by the enemy also attacked by us?
// If yes, big bonus (but smaller than when there are no enemy attacks),
// if no, somewhat smaller bonus.
ebonus += Value(tr * ((b3 & b4) == b3 ? 13 : 8));
// At last, add a small bonus when there are no *friendly* pieces
// in the pawn's path.
if ((b2 & pos.pieces_of_color(us)) == EmptyBoardBB)
@@ -982,7 +994,7 @@ namespace {
}
}
}
// Rook pawns are a special case: They are sometimes worse, and
// Rook pawns are a special case: They are sometimes worse, and
// sometimes better than other passed pawns. It is difficult to find
// good rules for determining whether they are good or bad. For now,
// we try the following: Increase the value for rook pawns if the
@@ -990,10 +1002,10 @@ namespace {
// value if the other side has a rook or queen.
if (square_file(s) == FILE_A || square_file(s) == FILE_H)
{
if( pos.non_pawn_material(them) <= KnightValueMidgame
&& pos.piece_count(them, KNIGHT) <= 1)
if ( pos.non_pawn_material(them) <= KnightValueMidgame
&& pos.piece_count(them, KNIGHT) <= 1)
ebonus += ebonus / 4;
else if(pos.rooks_and_queens(them))
else if (pos.rooks_and_queens(them))
ebonus -= ebonus / 4;
}
@@ -1005,9 +1017,9 @@ namespace {
// Does either side have an unstoppable passed pawn?
if (hasUnstoppable[WHITE] && !hasUnstoppable[BLACK])
ei.egValue += UnstoppablePawnValue - Value(0x40 * movesToGo[WHITE]);
ei.egValue += UnstoppablePawnValue - Value(0x40 * movesToGo[WHITE]);
else if (hasUnstoppable[BLACK] && !hasUnstoppable[WHITE])
ei.egValue -= UnstoppablePawnValue - Value(0x40 * movesToGo[BLACK]);
ei.egValue -= UnstoppablePawnValue - Value(0x40 * movesToGo[BLACK]);
else if (hasUnstoppable[BLACK] && hasUnstoppable[WHITE])
{
// Both sides have unstoppable pawns! Try to find out who queens
@@ -1105,7 +1117,7 @@ namespace {
// squares one, two or three squares behind a friendly pawn are counted
// twice. Finally, the space bonus is scaled by a weight taken from the
// material hash table.
template<bool HasPopCnt>
void evaluate_space(const Position &pos, Color us, EvalInfo &ei) {
Color them = opposite_color(us);
@@ -1133,8 +1145,8 @@ namespace {
behindFriendlyPawns |= (behindFriendlyPawns << 16);
}
int space = count_1s_max_15(safeSquares)
+ count_1s_max_15(behindFriendlyPawns & safeSquares);
int space = count_1s_max_15<HasPopCnt>(safeSquares)
+ count_1s_max_15<HasPopCnt>(behindFriendlyPawns & safeSquares);
ei.mgValue += Sign[us] * apply_weight(Value(space * ei.mi->space_weight()), WeightSpace);
}
@@ -1164,15 +1176,6 @@ namespace {
}
// count_1s_8bit() counts the number of nonzero bits in the 8 least
// significant bits of a Bitboard. This function is used by the king
// shield evaluation.
int count_1s_8bit(Bitboard b) {
return int(BitCount8Bit[b & 0xFF]);
}
// compute_weight() computes the value of an evaluation weight, by combining
// an UCI-configurable weight with an internal weight.

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -39,7 +39,7 @@
/// arguments to the evaluation function, and the search can make use of its
/// contents to make intelligent search decisions.
///
/// At the moment, this is not utilized very much: The only part of the
/// At the moment, this is not utilized very much: The only part of the
/// EvalInfo object which is used by the search is futilityMargin.
class Position;
@@ -53,16 +53,16 @@ struct EvalInfo {
PawnInfo* pi;
// attackedBy[color][piece type] is a bitboard representing all squares
// attacked by a given color and piece type. attackedBy[color][0] contains
// attacked by a given color and piece type, attackedBy[color][0] contains
// all squares attacked by the given color.
Bitboard attackedBy[2][8];
Bitboard attacked_by(Color c) const { return attackedBy[c][0]; }
Bitboard attacked_by(Color c, PieceType pt) const { return attackedBy[c][pt]; }
// kingZone[color] is the zone around the enemy king which is considered
// by the king safety evaluation. This consists of the squares directly
// by the king safety evaluation. This consists of the squares directly
// adjacent to the king, and the three (or two, for a king on an edge file)
// squares two ranks in front of the king. For instance, if black's king
// squares two ranks in front of the king. For instance, if black's king
// is on g8, kingZone[WHITE] is a bitboard containing the squares f8, h8,
// f7, g7, h7, f6, g6 and h6.
Bitboard kingZone[2];
@@ -91,7 +91,7 @@ struct EvalInfo {
// Middle game and endgame mobility scores.
Value mgMobility, egMobility;
// Extra futility margin. This is added to the standard futility margin
// Extra futility margin. This is added to the standard futility margin
// in the quiescence search.
Value futilityMargin;
};

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -32,14 +32,13 @@
//// Functions
////
/// Constructor
History::History() {
this->clear();
}
History::History() { clear(); }
/// History::clear() clears the history tables.
/// History::clear() clears the history tables
void History::clear() {
memset(history, 0, 2 * 8 * 64 * sizeof(int));
@@ -48,55 +47,59 @@ void History::clear() {
}
/// History::success() registers a move as being successful. This is done
/// History::success() registers a move as being successful. This is done
/// whenever a non-capturing move causes a beta cutoff in the main search.
/// The three parameters are the moving piece, the move itself, and the
/// search depth.
/// The three parameters are the moving piece, the destination square, and
/// the search depth.
void History::success(Piece p, Square to, Depth d) {
void History::success(Piece p, Move m, Depth d) {
assert(piece_is_ok(p));
assert(move_is_ok(m));
assert(square_is_ok(to));
history[p][move_to(m)] += int(d) * int(d);
successCount[p][move_to(m)]++;
history[p][to] += int(d) * int(d);
successCount[p][to]++;
// Prevent history overflow:
if(history[p][move_to(m)] >= HistoryMax)
for(int i = 0; i < 16; i++)
for(int j = 0; j < 64; j++)
history[i][j] /= 2;
// Prevent history overflow
if (history[p][to] >= HistoryMax)
for (int i = 0; i < 16; i++)
for (int j = 0; j < 64; j++)
history[i][j] /= 4;
}
/// History::failure() registers a move as being unsuccessful. The function is
/// History::failure() registers a move as being unsuccessful. The function is
/// called for each non-capturing move which failed to produce a beta cutoff
/// at a node where a beta cutoff was finally found.
void History::failure(Piece p, Move m) {
assert(piece_is_ok(p));
assert(move_is_ok(m));
void History::failure(Piece p, Square to) {
failureCount[p][move_to(m)]++;
assert(piece_is_ok(p));
assert(square_is_ok(to));
failureCount[p][to]++;
}
/// History::move_ordering_score() returns an integer value used to order the
/// non-capturing moves in the MovePicker class.
int History::move_ordering_score(Piece p, Move m) const {
assert(piece_is_ok(p));
assert(move_is_ok(m));
int History::move_ordering_score(Piece p, Square to) const {
return history[p][move_to(m)];
assert(piece_is_ok(p));
assert(square_is_ok(to));
return history[p][to];
}
/// History::ok_to_prune() decides whether a move has been sufficiently
/// unsuccessful that it makes sense to prune it entirely.
bool History::ok_to_prune(Piece p, Move m, Depth d) const {
assert(piece_is_ok(p));
assert(move_is_ok(m));
bool History::ok_to_prune(Piece p, Square to, Depth d) const {
return (int(d) * successCount[p][move_to(m)] < failureCount[p][move_to(m)]);
assert(piece_is_ok(p));
assert(square_is_ok(to));
return (int(d) * successCount[p][to] < failureCount[p][to]);
}

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -34,19 +34,22 @@
//// Types
////
/// The History class stores statistics about how often different moves have
/// been successful or unsuccessful during the current search. These
/// statistics are used for reduction and move ordering decisions.
/// The History class stores statistics about how often different moves
/// have been successful or unsuccessful during the current search. These
/// statistics are used for reduction and move ordering decisions. History
/// entries are stored according only to moving piece and destination square,
/// in particular two moves with different origin but same destination and
/// same piece will be considered identical.
class History {
public:
History();
void clear();
void success(Piece p, Move m, Depth d);
void failure(Piece p, Move m);
int move_ordering_score(Piece p, Move m) const;
bool ok_to_prune(Piece p, Move m, Depth d) const;
void success(Piece p, Square to, Depth d);
void failure(Piece p, Square to);
int move_ordering_score(Piece p, Square to) const;
bool ok_to_prune(Piece p, Square to, Depth d) const;
private:
int history[16][64]; // [piece][square]
@@ -61,17 +64,13 @@ private:
/// HistoryMax controls how often the history counters will be scaled down:
/// When the history score for a move gets bigger than HistoryMax, all
/// entries in the table are divided by 2. It is difficult to guess what
/// the ideal value of this constant is. Scaling down the scores often has
/// entries in the table are divided by 2. It is difficult to guess what
/// the ideal value of this constant is. Scaling down the scores often has
/// the effect that parts of the search tree which have been searched
/// recently have a bigger importance for move ordering than the moves which
/// have been searched a long time ago.
///
/// Note that HistoryMax should probably be changed whenever the constant
/// OnePly in depth.h is changed. This is somewhat annoying. Perhaps it
/// would be better to scale down the history table at regular intervals?
const int HistoryMax = 50000;
const int HistoryMax = 25000 * OnePly;
#endif // !defined(HISTORY_H_INCLUDED)

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -23,7 +23,7 @@
// x86 assembly language locks or OS spin locks may perform faster than
// mutex locks on some platforms. On my machine, mutexes seem to be the
// mutex locks on some platforms. On my machine, mutexes seem to be the
// best.
//#define ASM_LOCK

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,29 +17,28 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// To profile with callgrind uncomment following line
//#define USE_CALLGRIND
////
//// Includes
////
#include <iostream>
#include <string>
#include "benchmark.h"
#include "bitboard.h"
#include "direction.h"
#include "endgame.h"
#include "evaluate.h"
#include "material.h"
#include "mersenne.h"
#include "bitcount.h"
#include "misc.h"
#include "movepick.h"
#include "position.h"
#include "search.h"
#include "thread.h"
#include "uci.h"
#include "ucioption.h"
using std::string;
#ifdef USE_CALLGRIND
#include <valgrind/callgrind.h>
#endif
using namespace std;
////
//// Functions
@@ -48,50 +47,43 @@ using std::string;
int main(int argc, char *argv[]) {
// Disable IO buffering
std::cout.rdbuf()->pubsetbuf(NULL, 0);
std::cin.rdbuf()->pubsetbuf(NULL, 0);
cout.rdbuf()->pubsetbuf(NULL, 0);
cin.rdbuf()->pubsetbuf(NULL, 0);
// Initialization
init_mersenne();
init_direction_table();
init_bitboards();
init_uci_options();
Position::init_zobrist();
Position::init_piece_square_tables();
MovePicker::init_phase_table();
init_eval(1);
init_bitbases();
init_threads();
// Initialization through global resources manager
Application::initialize();
// Make random number generation less deterministic, for book moves
for (int i = abs(get_system_time() % 10000); i > 0; i--)
genrand_int32();
#ifdef USE_CALLGRIND
CALLGRIND_START_INSTRUMENTATION;
#endif
// Process command line arguments
if (argc >= 2 && string(argv[1]) == "bench")
// Process command line arguments if any
if (argc > 1)
{
if (argc < 4 || argc > 7)
if (string(argv[1]) != "bench" || argc < 4 || argc > 8)
cout << "Usage: stockfish bench <hash size> <threads> "
<< "[time = 60s] [fen positions file = default] "
<< "[time, depth or node limited = time] "
<< "[timing file name = none]" << endl;
else
{
std::cout << "Usage: stockfish bench <hash size> <threads> "
<< "[time = 60s] [fen positions file = default] "
<< "[time, depth or node limited = time]"
<< std::endl;
exit(0);
string time = argc > 4 ? argv[4] : "60";
string fen = argc > 5 ? argv[5] : "default";
string lim = argc > 6 ? argv[6] : "time";
string tim = argc > 7 ? argv[7] : "";
benchmark(string(argv[2]) + " " + string(argv[3]) + " " + time + " " + fen + " " + lim + " " + tim);
}
string time = argc > 4 ? argv[4] : "60";
string fen = argc > 5 ? argv[5] : "default";
string lim = argc > 6 ? argv[6] : "time";
benchmark(string(argv[2]) + " " + string(argv[3]) + " " + time + " " + fen + " " + lim);
return 0;
}
// Print copyright notice
std::cout << engine_name() << ". Copyright (C) "
<< "2004-2008 Tord Romstad, Marco Costalba. "
<< std::endl;
cout << engine_name()
<< ". By Tord Romstad, Marco Costalba, Joona Kiiski." << endl;
if (CpuHasPOPCNT)
cout << "Good! CPU has hardware POPCNT. We will use it." << endl;
// Enter UCI mode
uci_main_loop();
return 0;
}

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -23,12 +23,12 @@
////
#include <cassert>
#include <cstring>
#include <sstream>
#include <map>
#include "material.h"
using std::string;
////
//// Local definitions
@@ -36,6 +36,7 @@
namespace {
// Values modified by Joona Kiiski
const Value BishopPairMidgameBonus = Value(109);
const Value BishopPairEndgameBonus = Value(97);
@@ -59,9 +60,9 @@ public:
EndgameScalingFunctionBase* getESF(Key key, Color* c) const;
private:
void add(const std::string& keyCode, EndgameEvaluationFunctionBase* f);
void add(const std::string& keyCode, Color c, EndgameScalingFunctionBase* f);
Key buildKey(const std::string& keyCode);
void add(const string& keyCode, EndgameEvaluationFunctionBase* f);
void add(const string& keyCode, Color c, EndgameScalingFunctionBase* f);
Key buildKey(const string& keyCode);
struct ScalingInfo
{
@@ -90,9 +91,8 @@ MaterialInfoTable::MaterialInfoTable(unsigned int numOfEntries) {
{
std::cerr << "Failed to allocate " << (numOfEntries * sizeof(MaterialInfo))
<< " bytes for material hash table." << std::endl;
exit(EXIT_FAILURE);
Application::exit_with_failure();
}
clear();
}
@@ -100,17 +100,8 @@ MaterialInfoTable::MaterialInfoTable(unsigned int numOfEntries) {
MaterialInfoTable::~MaterialInfoTable() {
delete [] entries;
delete funcs;
}
/// MaterialInfoTable::clear() clears a material hash table by setting
/// all entries to 0.
void MaterialInfoTable::clear() {
memset(entries, 0, size * sizeof(MaterialInfo));
delete [] entries;
}
@@ -152,14 +143,14 @@ MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) {
else if ( pos.non_pawn_material(BLACK) == Value(0)
&& pos.piece_count(BLACK, PAWN) == 0
&& pos.non_pawn_material(WHITE) >= RookValueEndgame)
&& pos.non_pawn_material(WHITE) >= RookValueMidgame)
{
mi->evaluationFunction = &EvaluateKXK;
return mi;
}
else if ( pos.non_pawn_material(WHITE) == Value(0)
&& pos.piece_count(WHITE, PAWN) == 0
&& pos.non_pawn_material(BLACK) >= RookValueEndgame)
&& pos.non_pawn_material(BLACK) >= RookValueMidgame)
{
mi->evaluationFunction = &EvaluateKKX;
return mi;
@@ -352,7 +343,7 @@ EndgameFunctions::EndgameFunctions() {
add("KRPKRPP", BLACK, &ScaleKRPKRPP);
}
Key EndgameFunctions::buildKey(const std::string& keyCode) {
Key EndgameFunctions::buildKey(const string& keyCode) {
assert(keyCode.length() > 0 && keyCode[0] == 'K');
assert(keyCode.length() < 8);
@@ -373,12 +364,12 @@ Key EndgameFunctions::buildKey(const std::string& keyCode) {
return Position(s.str()).get_material_key();
}
void EndgameFunctions::add(const std::string& keyCode, EndgameEvaluationFunctionBase* f) {
void EndgameFunctions::add(const string& keyCode, EndgameEvaluationFunctionBase* f) {
EEFmap.insert(std::pair<Key, EndgameEvaluationFunctionBase*>(buildKey(keyCode), f));
}
void EndgameFunctions::add(const std::string& keyCode, Color c, EndgameScalingFunctionBase* f) {
void EndgameFunctions::add(const string& keyCode, Color c, EndgameScalingFunctionBase* f) {
ScalingInfo s = {c, f};
ESFmap.insert(std::pair<Key, ScalingInfo>(buildKey(keyCode), s));

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -49,6 +49,8 @@ class MaterialInfo {
friend class MaterialInfoTable;
public:
MaterialInfo() : key(0) { clear(); }
Value mg_value() const;
Value eg_value() const;
ScaleFactor scale_factor(const Position& pos, Color c) const;
@@ -57,7 +59,7 @@ public:
Value evaluate(const Position& pos) const;
private:
void clear();
inline void clear();
Key key;
int16_t mgValue;
@@ -87,7 +89,6 @@ class MaterialInfoTable {
public:
MaterialInfoTable(unsigned numOfEntries);
~MaterialInfoTable();
void clear();
MaterialInfo* get_material_info(const Position& pos);
private:
@@ -116,20 +117,20 @@ inline Value MaterialInfo::eg_value() const {
/// MaterialInfo::clear() resets a MaterialInfo object to an empty state,
/// with all slots at their default values.
/// with all slots at their default values but the key.
inline void MaterialInfo::clear() {
mgValue = egValue = 0;
factor[WHITE] = factor[BLACK] = uint8_t(SCALE_FACTOR_NORMAL);
spaceWeight = 0;
evaluationFunction = NULL;
scalingFunction[WHITE] = scalingFunction[BLACK] = NULL;
spaceWeight = 0;
}
/// MaterialInfo::scale_factor takes a position and a color as input, and
/// returns a scale factor for the given color. We have to provide the
/// returns a scale factor for the given color. We have to provide the
/// position in addition to the color, because the scale factor need not
/// to be a constant: It can also be a function which should be applied to
/// the position. For instance, in KBP vs K endgames, a scaling function
@@ -167,7 +168,7 @@ inline bool MaterialInfo::specialized_eval_exists() const {
/// MaterialInfo::evaluate applies a specialized evaluation function
/// to a given position object. It should only be called when
/// to a given position object. It should only be called when
/// specialized_eval_exists() returns 'true'.
inline Value MaterialInfo::evaluate(const Position& pos) const {

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -38,6 +38,7 @@
# include <windows.h>
# include <time.h>
# include "dos.h"
static int gettimeofday(struct timeval* tp, struct timezone*)
{
SYSTEMTIME systime;
@@ -64,6 +65,7 @@ static int gettimeofday(struct timeval* tp, struct timezone*)
#include <iostream>
#include <sstream>
#include "bitcount.h"
#include "misc.h"
using namespace std;
@@ -71,7 +73,7 @@ using namespace std;
/// Version number. If this is left empty, the current date (in the format
/// YYMMDD) is used as a version number.
static const string EngineVersion = "1.3.1";
static const string EngineVersion = "1.4";
static const string AppName = "Stockfish";
static const string AppTag = "";
@@ -80,8 +82,10 @@ static const string AppTag = "";
//// Variables
////
long dbg_cnt0 = 0;
long dbg_cnt1 = 0;
bool Chess960;
uint64_t dbg_cnt0 = 0;
uint64_t dbg_cnt1 = 0;
bool dbg_show_mean = false;
bool dbg_show_hit_rate = false;
@@ -159,8 +163,10 @@ void dbg_print_mean(ofstream& logFile) {
const string engine_name() {
const string cpu64(CpuHas64BitPath ? " 64bit" : "");
if (!EngineVersion.empty())
return "Stockfish " + EngineVersion;
return AppName+ " " + EngineVersion + cpu64;
string date(__DATE__); // From compiler, format is "Sep 21 2008"
string months("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec");
@@ -173,7 +179,7 @@ const string engine_name() {
string name = AppName + " " + AppTag + " ";
s << name << date.substr(date.length() - 2) << setfill('0')
<< setw(2) << mon << setw(2) << day;
<< setw(2) << mon << setw(2) << day << cpu64;
return s.str();
}

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -29,6 +29,8 @@
#include <fstream>
#include <string>
#include "application.h"
#include "types.h"
////
//// Macros
@@ -38,6 +40,13 @@
#define Max(x, y) (((x) < (y))? (y) : (x))
////
//// Variables
////
extern bool Chess960;
////
//// Prototypes
////
@@ -47,6 +56,7 @@ extern int get_system_time();
extern int cpu_count();
extern int Bioskey();
////
//// Debug
////
@@ -54,8 +64,8 @@ extern int Bioskey();
extern bool dbg_show_mean;
extern bool dbg_show_hit_rate;
extern long dbg_cnt0;
extern long dbg_cnt1;
extern uint64_t dbg_cnt0;
extern uint64_t dbg_cnt1;
extern void dbg_hit_on(bool b);
extern void dbg_hit_on_c(bool c, bool b);

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -27,7 +27,6 @@
#include "move.h"
#include "piece.h"
#include "position.h"
#include "ucioption.h"
////
@@ -130,8 +129,8 @@ const std::string move_to_string(Move move) {
return (from == SQ_E1 ? "e1c1" : "e8c8");
}
str = square_to_string(from) + square_to_string(to);
if (move_promotion(move))
str += piece_type_to_char(move_promotion(move), false);
if (move_is_promotion(move))
str += piece_type_to_char(move_promotion_piece(move), false);
}
return str;
}

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -78,16 +78,20 @@ inline Square move_to(Move m) {
return Square(m & 0x3F);
}
inline PieceType move_promotion(Move m) {
inline PieceType move_promotion_piece(Move m) {
return PieceType((int(m) >> 12) & 7);
}
inline bool move_is_ep(Move m) {
return bool((int(m) >> 15) & 1);
inline int move_is_promotion(Move m) {
return m & (7 << 12);
}
inline bool move_is_castle(Move m) {
return bool((int(m) >> 16) & 1);
inline int move_is_ep(Move m) {
return m & (1 << 15);
}
inline int move_is_castle(Move m) {
return m & (1 << 16);
}
inline bool move_is_short_castle(Move m) {
@@ -119,7 +123,7 @@ inline Move make_ep_move(Square from, Square to) {
//// Prototypes
////
extern std::ostream &operator << (std::ostream &os, Move m);
extern std::ostream& operator<<(std::ostream &os, Move m);
extern Move move_from_string(const Position &pos, const std::string &str);
extern const std::string move_to_string(Move m);
extern bool move_is_ok(Move m);

View File

@@ -1,6 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2008 Marco Costalba
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -23,6 +24,7 @@
#include <cassert>
#include "bitcount.h"
#include "movegen.h"
// Simple macro to wrap a very common while loop, no facny, no flexibility,
@@ -52,16 +54,19 @@ namespace {
template<CastlingSide Side>
MoveStack* generate_castle_moves(const Position& pos, MoveStack* mlist);
template<Color Us, Rank, Bitboard, SquareDelta>
template<Color Us>
MoveStack* generate_pawn_blocking_evasions(const Position&, Bitboard, Bitboard, MoveStack*);
template<Color, Color, Bitboard, SquareDelta, SquareDelta, SquareDelta>
template<Color Us>
MoveStack* generate_pawn_captures(const Position& pos, MoveStack* mlist);
template<Color, Color, Bitboard, Bitboard, SquareDelta, SquareDelta, SquareDelta>
template<Color Us, SquareDelta Diagonal>
MoveStack* generate_pawn_captures_diagonal(MoveStack* mlist, Bitboard pawns, Bitboard enemyPieces);
template<Color Us>
MoveStack* generate_pawn_noncaptures(const Position& pos, MoveStack* mlist);
template<Color, Color, Bitboard, Bitboard, SquareDelta>
template<Color Us>
MoveStack* generate_pawn_checks(const Position&, Bitboard, Square, MoveStack*);
template<Color Us, SquareDelta Direction>
@@ -84,11 +89,8 @@ namespace {
template<>
inline MoveStack* generate_piece_checks<PAWN>(const Position& p, MoveStack* m, Color us, Bitboard dc, Square ksq) {
if (us == WHITE)
return generate_pawn_checks<WHITE, BLACK, Rank8BB, Rank3BB, DELTA_N>(p, dc, ksq, m);
else
return generate_pawn_checks<BLACK, WHITE, Rank1BB, Rank6BB, DELTA_S>(p, dc, ksq, m);
return (us == WHITE ? generate_pawn_checks<WHITE>(p, dc, ksq, m)
: generate_pawn_checks<BLACK>(p, dc, ksq, m));
}
// Template generate_piece_moves() with specializations and overloads
@@ -104,11 +106,11 @@ namespace {
assert(Piece == PAWN);
if (Type == CAPTURE)
return (us == WHITE ? generate_pawn_captures<WHITE, BLACK, Rank8BB, DELTA_NE, DELTA_NW, DELTA_N>(p, m)
: generate_pawn_captures<BLACK, WHITE, Rank1BB, DELTA_SE, DELTA_SW, DELTA_S>(p, m));
return (us == WHITE ? generate_pawn_captures<WHITE>(p, m)
: generate_pawn_captures<BLACK>(p, m));
else
return (us == WHITE ? generate_pawn_noncaptures<WHITE, BLACK, Rank8BB, Rank3BB, DELTA_NE, DELTA_NW, DELTA_N>(p, m)
: generate_pawn_noncaptures<BLACK, WHITE, Rank1BB, Rank6BB, DELTA_SE, DELTA_SW, DELTA_S>(p, m));
return (us == WHITE ? generate_pawn_noncaptures<WHITE>(p, m)
: generate_pawn_noncaptures<BLACK>(p, m));
}
template<PieceType>
@@ -117,10 +119,9 @@ namespace {
template<>
inline MoveStack* generate_piece_moves<PAWN>(const Position& p, MoveStack* m,
Color us, Bitboard t, Bitboard pnd) {
if (us == WHITE)
return generate_pawn_blocking_evasions<WHITE, RANK_8, Rank3BB, DELTA_N>(p, pnd, t, m);
else
return generate_pawn_blocking_evasions<BLACK, RANK_1, Rank6BB, DELTA_S>(p, pnd, t, m);
return (us == WHITE ? generate_pawn_blocking_evasions<WHITE>(p, pnd, t, m)
: generate_pawn_blocking_evasions<BLACK>(p, pnd, t, m));
}
}
@@ -131,7 +132,7 @@ namespace {
/// generate_captures generates() all pseudo-legal captures and queen
/// promotions. The return value is the number of moves generated.
/// promotions. The return value is the number of moves generated.
int generate_captures(const Position& pos, MoveStack* mlist) {
@@ -392,7 +393,6 @@ bool move_is_legal(const Position& pos, const Move m, Bitboard pinned) {
assert(pinned == pos.pinned_pieces(pos.side_to_move()));
Color us = pos.side_to_move();
Color them = opposite_color(us);
Square from = move_from(m);
Piece pc = pos.piece_on(from);
@@ -401,6 +401,7 @@ bool move_is_legal(const Position& pos, const Move m, Bitboard pinned) {
if (color_of_piece(pc) != us)
return false;
Color them = opposite_color(us);
Square to = move_to(m);
// En passant moves
@@ -496,16 +497,21 @@ bool move_is_legal(const Position& pos, const Move m, Bitboard pinned) {
// Proceed according to the type of the moving piece.
if (type_of_piece(pc) == PAWN)
{
// Move direction must be compatible with pawn color
int direction = to - from;
if ((us == WHITE) != (direction > 0))
return false;
// If the destination square is on the 8/1th rank, the move must
// be a promotion.
if ( ( (square_rank(to) == RANK_8 && us == WHITE)
||(square_rank(to) == RANK_1 && us != WHITE))
&& !move_promotion(m))
&& !move_is_promotion(m))
return false;
// Proceed according to the square delta between the source and
// destionation squares.
switch (to - from)
switch (direction)
{
case DELTA_NW:
case DELTA_NE:
@@ -554,7 +560,7 @@ bool move_is_legal(const Position& pos, const Move m, Bitboard pinned) {
// Luckly we can handle all the other pieces in one go
return ( pos.piece_attacks_square(pos.piece_on(from), from, to)
&& pos.pl_move_is_legal(m, pinned)
&& !move_promotion(m));
&& !move_is_promotion(m));
}
@@ -604,24 +610,27 @@ namespace {
return mlist;
}
template<Color Us, Color Them, Bitboard TRank8BB, SquareDelta TDELTA_NE,
SquareDelta TDELTA_NW, SquareDelta TDELTA_N
>
MoveStack* generate_pawn_captures(const Position& pos, MoveStack* mlist) {
template<Color Us, SquareDelta Diagonal>
MoveStack* generate_pawn_captures_diagonal(MoveStack* mlist, Bitboard pawns, Bitboard enemyPieces) {
// Calculate our parametrized parameters at compile time
const Bitboard TRank8BB = (Us == WHITE ? Rank8BB : Rank1BB);
const Bitboard TFileABB = (Diagonal == DELTA_NE ? FileABB : FileHBB);
const SquareDelta TDELTA_NE = (Us == WHITE ? DELTA_NE : DELTA_SE);
const SquareDelta TDELTA_NW = (Us == WHITE ? DELTA_NW : DELTA_SW);
const SquareDelta TTDELTA_NE = (Diagonal == DELTA_NE ? TDELTA_NE : TDELTA_NW);
Square to;
Bitboard pawns = pos.pawns(Us);
Bitboard enemyPieces = pos.pieces_of_color(Them);
// Captures in the a1-h8 (a8-h1 for black) direction
Bitboard b1 = move_pawns<Us, DELTA_NE>(pawns) & ~FileABB & enemyPieces;
// 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;
// Capturing promotions
Bitboard b2 = b1 & TRank8BB;
while (b2)
{
to = pop_1st_bit(&b2);
(*mlist++).move = make_promotion_move(to - TDELTA_NE, to, QUEEN);
(*mlist++).move = make_promotion_move(to - TTDELTA_NE, to, QUEEN);
}
// Capturing non-promotions
@@ -629,30 +638,29 @@ namespace {
while (b2)
{
to = pop_1st_bit(&b2);
(*mlist++).move = make_move(to - TDELTA_NE, to);
(*mlist++).move = make_move(to - TTDELTA_NE, to);
}
return mlist;
}
// Captures in the h1-a8 (h8-a1 for black) direction
b1 = move_pawns<Us, DELTA_NW>(pawns) & ~FileHBB & enemyPieces;
template<Color Us>
MoveStack* generate_pawn_captures(const Position& pos, MoveStack* mlist) {
// Capturing promotions
b2 = b1 & TRank8BB;
while (b2)
{
to = pop_1st_bit(&b2);
(*mlist++).move = make_promotion_move(to - TDELTA_NW, to, QUEEN);
}
// Calculate our parametrized parameters at compile time
const Color Them = (Us == WHITE ? BLACK : WHITE);
const Bitboard TRank8BB = (Us == WHITE ? Rank8BB : Rank1BB);
const SquareDelta TDELTA_N = (Us == WHITE ? DELTA_N : DELTA_S);
// Capturing non-promotions
b2 = b1 & ~TRank8BB;
while (b2)
{
to = pop_1st_bit(&b2);
(*mlist++).move = make_move(to - TDELTA_NW, to);
}
Square to;
Bitboard pawns = pos.pawns(Us);
Bitboard enemyPieces = pos.pieces_of_color(opposite_color(Us));
// Standard captures and capturing promotions in both directions
mlist = generate_pawn_captures_diagonal<Us, DELTA_NE>(mlist, pawns, enemyPieces);
mlist = generate_pawn_captures_diagonal<Us, DELTA_NW>(mlist, pawns, enemyPieces);
// Non-capturing promotions
b1 = move_pawns<Us, DELTA_N>(pawns) & pos.empty_squares() & TRank8BB;
Bitboard b1 = move_pawns<Us, DELTA_N>(pawns) & pos.empty_squares() & TRank8BB;
while (b1)
{
to = pop_1st_bit(&b1);
@@ -677,16 +685,21 @@ namespace {
return mlist;
}
template<Color Us, Color Them, Bitboard TRank8BB, Bitboard TRank3BB,
SquareDelta TDELTA_NE, SquareDelta TDELTA_NW, SquareDelta TDELTA_N
>
template<Color Us>
MoveStack* generate_pawn_noncaptures(const Position& pos, MoveStack* mlist) {
Bitboard pawns = pos.pawns(Us);
Bitboard enemyPieces = pos.pieces_of_color(Them);
Bitboard emptySquares = pos.empty_squares();
// Calculate our parametrized parameters at compile time
const Bitboard TRank8BB = (Us == WHITE ? Rank8BB : Rank1BB);
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);
Bitboard b1, b2;
Square to;
Bitboard pawns = pos.pawns(Us);
Bitboard enemyPieces = pos.pieces_of_color(opposite_color(Us));
Bitboard emptySquares = pos.empty_squares();
// Underpromotion captures in the a1-h8 (a8-h1 for black) direction
b1 = move_pawns<Us, DELTA_NE>(pawns) & ~FileABB & enemyPieces & TRank8BB;
@@ -736,19 +749,27 @@ namespace {
}
template<Color Us, Color Them, Bitboard TRank8BB, Bitboard TRank3BB, SquareDelta TDELTA_N>
template<Color Us>
MoveStack* generate_pawn_checks(const Position& pos, Bitboard dc, Square ksq, MoveStack* mlist)
{
// Find all friendly pawns not on the enemy king's file
Bitboard b1, b2, b3;
Bitboard empty = pos.empty_squares();
// Calculate our parametrized parameters at compile time
const Color Them = (Us == WHITE ? BLACK : WHITE);
const Bitboard TRank8BB = (Us == WHITE ? Rank8BB : Rank1BB);
const Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB);
const SquareDelta TDELTA_N = (Us == WHITE ? DELTA_N : DELTA_S);
const SquareDelta TDELTA_S = (Us == WHITE ? DELTA_S : DELTA_N);
if (dc != EmptyBoardBB)
Bitboard b1, b2, b3;
Bitboard pawns = pos.pawns(Us);
if (dc & pawns)
{
Bitboard empty = pos.empty_squares();
// 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.
b1 = pos.pawns(Us) & ~file_bb(ksq);
b1 = pawns & ~file_bb(ksq);
// Discovered checks, single pawn pushes, no promotions
b2 = b3 = move_pawns<Us, DELTA_N>(b1 & dc) & empty & ~TRank8BB;
@@ -768,10 +789,17 @@ namespace {
}
// Direct checks. These are possible only for pawns on neighboring files
// of the enemy king.
b1 = pos.pawns(Us) & neighboring_files_bb(ksq) & ~dc;
// and in the two ranks that, after the push, are in front of the enemy king.
b1 = pawns & neighboring_files_bb(ksq) & ~dc;
// We can get false positives if (ksq + x) is not in [0,63] range but
// is not a problem, they will be filtered out later.
b2 = b1 & (rank_bb(ksq + 2 * TDELTA_S) | rank_bb(ksq + 3 * TDELTA_S));
if (!b2)
return mlist;
// Direct checks, single pawn pushes
Bitboard empty = pos.empty_squares();
b2 = move_pawns<Us, DELTA_N>(b1) & empty;
b3 = b2 & pos.pawn_attacks(Them, ksq);
while (b3)
@@ -810,30 +838,36 @@ namespace {
// Direct checks
b = target & ~dc;
if (Piece == KING || !b)
return mlist;
Bitboard checkSqs = pos.piece_attacks<Piece>(ksq) & pos.empty_squares();
if (!checkSqs)
return mlist;
while (b)
if (Piece != KING || 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 checkSqs = pos.piece_attacks<Piece>(ksq) & pos.empty_squares();
if (!checkSqs)
return mlist;
Bitboard bb = pos.piece_attacks<Piece>(from) & checkSqs;
SERIALIZE_MOVES(bb);
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.piece_attacks<Piece>(from) & checkSqs;
SERIALIZE_MOVES(bb);
}
}
return mlist;
}
template<Color Us, Rank TRANK_8, Bitboard TRank3BB, SquareDelta TDELTA_N>
template<Color Us>
MoveStack* generate_pawn_blocking_evasions(const Position& pos, Bitboard pinned,
Bitboard blockSquares, MoveStack* mlist) {
// Calculate our parametrized parameters at compile time
const Bitboard TRank8BB = (Us == WHITE ? Rank8BB : Rank1BB);
const Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB);
const SquareDelta TDELTA_N = (Us == WHITE ? DELTA_N : DELTA_S);
Square to;
// Find non-pinned pawns and push them one square
@@ -848,7 +882,7 @@ namespace {
assert(pos.piece_on(to) == EMPTY);
if (square_rank(to) == TRANK_8)
if (square_rank(to) == TRank8BB)
{
(*mlist++).move = make_promotion_move(to - TDELTA_N, to, QUEEN);
(*mlist++).move = make_promotion_move(to - TDELTA_N, to, ROOK);

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -63,23 +63,25 @@ namespace {
/// search captures, promotions and some checks) and about how important good
/// move ordering is at the current node.
MovePicker::MovePicker(const Position& p, bool pv, Move ttm,
const SearchStack& ss, Depth d) : pos(p) {
pvNode = pv;
MovePicker::MovePicker(const Position& p, Move ttm, Depth d,
const History& h, SearchStack* ss) : pos(p), H(h) {
ttMove = ttm;
mateKiller = (ss.mateKiller == ttm)? MOVE_NONE : ss.mateKiller;
killer1 = ss.killers[0];
killer2 = ss.killers[1];
depth = d;
movesPicked = 0;
numOfMoves = 0;
numOfBadCaptures = 0;
if (ss)
{
mateKiller = (ss->mateKiller == ttm)? MOVE_NONE : ss->mateKiller;
killer1 = ss->killers[0];
killer2 = ss->killers[1];
} else
mateKiller = killer1 = killer2 = MOVE_NONE;
movesPicked = numOfMoves = numOfBadCaptures = 0;
checkKillers = checkLegal = finished = false;
if (p.is_check())
phaseIndex = EvasionsPhaseIndex;
else if (depth > Depth(0))
else if (d > Depth(0))
phaseIndex = MainSearchPhaseIndex;
else if (depth == Depth(0))
else if (d == Depth(0))
phaseIndex = QsearchWithChecksPhaseIndex;
else
phaseIndex = QsearchWithoutChecksPhaseIndex;
@@ -139,18 +141,32 @@ Move MovePicker::get_next_move() {
score_captures();
std::sort(moves, moves + numOfMoves);
movesPicked = 0;
checkLegal = true;
break;
case PH_BAD_CAPTURES:
// It's probably a good idea to use SEE move ordering here. FIXME
movesPicked = 0;
case PH_KILLERS:
movesPicked = numOfMoves = 0;
checkLegal = false;
if (killer1 != MOVE_NONE && move_is_legal(pos, killer1, pinned) && !pos.move_is_capture(killer1))
moves[numOfMoves++].move = killer1;
if (killer2 != MOVE_NONE && move_is_legal(pos, killer2, pinned) && !pos.move_is_capture(killer2) )
moves[numOfMoves++].move = killer2;
break;
case PH_NONCAPTURES:
checkKillers = (numOfMoves != 0); // previous phase is PH_KILLERS
numOfMoves = generate_noncaptures(pos, moves);
score_noncaptures();
std::sort(moves, moves + numOfMoves);
movesPicked = 0;
checkLegal = true;
break;
case PH_BAD_CAPTURES:
// Bad captures SEE value is already calculated by score_captures()
// so just sort them to get SEE move ordering.
std::sort(badCaptures, badCaptures + numOfBadCaptures);
movesPicked = 0;
break;
case PH_EVASIONS:
@@ -231,7 +247,7 @@ void MovePicker::score_captures() {
seeValue = pos.see(m);
if (seeValue >= 0)
{
if (move_promotion(m))
if (move_is_promotion(m))
moves[i].score = QueenValueMidgame;
else
moves[i].score = int(pos.midgame_value_of_piece_on(move_to(m)))
@@ -252,26 +268,23 @@ void MovePicker::score_noncaptures() {
// First score by history, when no history is available then use
// piece/square tables values. This seems to be better then a
// random choice when we don't have an history for any move.
Move m;
Piece piece;
Square from, to;
int hs;
for (int i = 0; i < numOfMoves; i++)
{
m = moves[i].move;
if (m == killer1)
hs = HistoryMax + 2;
else if (m == killer2)
hs = HistoryMax + 1;
else
hs = H.move_ordering_score(pos.piece_on(move_from(m)), m);
from = move_from(moves[i].move);
to = move_to(moves[i].move);
piece = pos.piece_on(from);
hs = H.move_ordering_score(piece, to);
// Ensure history is always preferred to pst
if (hs > 0)
hs += 1000;
// pst based scoring
moves[i].score = hs + pos.mg_pst_delta(m);
moves[i].score = hs + pos.pst_delta<Position::MidGame>(piece, from, to);
}
}
@@ -287,7 +300,7 @@ void MovePicker::score_evasions() {
int seeScore = pos.see(m);
moves[i].score = (seeScore >= 0)? seeScore + HistoryMax : seeScore;
} else
moves[i].score = H.move_ordering_score(pos.piece_on(move_from(m)), m);
moves[i].score = H.move_ordering_score(pos.piece_on(move_from(m)), move_to(m));
}
}
@@ -297,7 +310,7 @@ void MovePicker::score_qcaptures() {
for (int i = 0; i < numOfMoves; i++)
{
Move m = moves[i].move;
if (move_promotion(m))
if (move_is_promotion(m))
moves[i].score = QueenValueMidgame;
else
moves[i].score = int(pos.midgame_value_of_piece_on(move_to(m)))
@@ -320,13 +333,15 @@ Move MovePicker::pick_move_from_list() {
switch (PhaseTable[phaseIndex]) {
case PH_GOOD_CAPTURES:
case PH_KILLERS:
case PH_NONCAPTURES:
while (movesPicked < numOfMoves)
{
Move move = moves[movesPicked++].move;
if ( move != ttMove
&& move != mateKiller
&& pos.pl_move_is_legal(move, pinned))
&& (!checkKillers || (move != killer1 && move != killer2))
&& (!checkLegal || pos.pl_move_is_legal(move, pinned)))
return move;
}
break;
@@ -381,9 +396,7 @@ void MovePicker::init_phase_table() {
PhaseTable[i++] = PH_TT_MOVE;
PhaseTable[i++] = PH_MATE_KILLER;
PhaseTable[i++] = PH_GOOD_CAPTURES;
// PH_KILLER_1 and PH_KILLER_2 are not yet used.
// PhaseTable[i++] = PH_KILLER_1;
// PhaseTable[i++] = PH_KILLER_2;
PhaseTable[i++] = PH_KILLERS;
PhaseTable[i++] = PH_NONCAPTURES;
PhaseTable[i++] = PH_BAD_CAPTURES;
PhaseTable[i++] = PH_STOP;

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -26,6 +26,7 @@
////
#include "depth.h"
#include "history.h"
#include "lock.h"
#include "position.h"
@@ -38,8 +39,8 @@ struct EvalInfo;
struct SearchStack;
/// MovePicker is a class which is used to pick one legal move at a time from
/// the current position. It is initialized with a Position object and a few
/// moves we have reason to believe are good. The most important method is
/// the current position. It is initialized with a Position object and a few
/// moves we have reason to believe are good. The most important method is
/// MovePicker::pick_next_move(), which returns a new legal move each time it
/// is called, until there are no legal moves left, when MOVE_NONE is returned.
/// In order to improve the efficiency of the alpha beta algorithm, MovePicker
@@ -47,7 +48,7 @@ struct SearchStack;
class MovePicker {
MovePicker& operator=(const MovePicker&); // Silence a warning under MSVC
MovePicker& operator=(const MovePicker&); // silence a warning under MSVC
public:
@@ -55,21 +56,19 @@ public:
PH_TT_MOVE, // Transposition table move
PH_MATE_KILLER, // Mate killer from the current ply
PH_GOOD_CAPTURES, // Queen promotions and captures with SEE values >= 0
PH_BAD_CAPTURES, // Queen promotions and captures with SEE values < 0
PH_KILLER_1, // Killer move 1 from the current ply (not used yet).
PH_KILLER_2, // Killer move 2 from the current ply (not used yet).
PH_KILLERS, // Killer moves from the current ply
PH_NONCAPTURES, // Non-captures and underpromotions
PH_BAD_CAPTURES, // Queen promotions and captures with SEE values < 0
PH_EVASIONS, // Check evasions
PH_QCAPTURES, // Captures in quiescence search
PH_QCHECKS, // Checks in quiescence search
PH_QCHECKS, // Non-capture checks in quiescence search
PH_STOP
};
MovePicker(const Position& p, bool pvnode, Move ttm, const SearchStack& ss, Depth d);
MovePicker(const Position& p, Move ttm, Depth d, const History& h, SearchStack* ss = NULL);
Move get_next_move();
Move get_next_move(Lock &lock);
Move get_next_move(Lock& lock);
int number_of_moves() const;
int current_move_score() const;
Bitboard discovered_check_candidates() const;
static void init_phase_table();
@@ -82,14 +81,14 @@ private:
Move pick_move_from_list();
const Position& pos;
const History& H;
Move ttMove, mateKiller, killer1, killer2;
Bitboard pinned, dc;
MoveStack moves[256], badCaptures[64];
bool pvNode;
Depth depth;
int phaseIndex;
int numOfMoves, numOfBadCaptures;
int movesPicked;
bool checkKillers, checkLegal;
bool finished;
};
@@ -108,7 +107,7 @@ inline int MovePicker::number_of_moves() const {
}
/// MovePicker::discovered_check_candidates() returns a bitboard containing
/// all pieces which can possibly give discovered check. This bitboard is
/// all pieces which can possibly give discovered check. This bitboard is
/// computed by the constructor function.
inline Bitboard MovePicker::discovered_check_candidates() const {

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -23,8 +23,8 @@
////
#include <cassert>
#include <cstring>
#include "bitcount.h"
#include "pawns.h"
#include "position.h"
@@ -39,93 +39,93 @@ namespace {
// Doubled pawn penalty by file, middle game.
const Value DoubledPawnMidgamePenalty[8] = {
Value(20), Value(30), Value(34), Value(34),
Value(34), Value(34), Value(30), Value(20)
Value(13), Value(20), Value(23), Value(23),
Value(23), Value(23), Value(20), Value(13)
};
// Doubled pawn penalty by file, endgame.
const Value DoubledPawnEndgamePenalty[8] = {
Value(35), Value(40), Value(40), Value(40),
Value(40), Value(40), Value(40), Value(35)
Value(43), Value(48), Value(48), Value(48),
Value(48), Value(48), Value(48), Value(43)
};
// Isolated pawn penalty by file, middle game.
const Value IsolatedPawnMidgamePenalty[8] = {
Value(20), Value(30), Value(34), Value(34),
Value(34), Value(34), Value(30), Value(20)
Value(25), Value(36), Value(40), Value(40),
Value(40), Value(40), Value(36), Value(25)
};
// Isolated pawn penalty by file, endgame.
const Value IsolatedPawnEndgamePenalty[8] = {
Value(35), Value(40), Value(40), Value(40),
Value(40), Value(40), Value(40), Value(35)
Value(30), Value(35), Value(35), Value(35),
Value(35), Value(35), Value(35), Value(30)
};
// Backward pawn penalty by file, middle game.
const Value BackwardPawnMidgamePenalty[8] = {
Value(16), Value(24), Value(27), Value(27),
Value(27), Value(27), Value(24), Value(16)
Value(20), Value(29), Value(33), Value(33),
Value(33), Value(33), Value(29), Value(20)
};
// Backward pawn penalty by file, endgame.
const Value BackwardPawnEndgamePenalty[8] = {
Value(28), Value(32), Value(32), Value(32),
Value(32), Value(32), Value(32), Value(28)
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(14), Value(16), Value(17), Value(18),
Value(18), Value(17), Value(16), Value(14)
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(16), Value(16), Value(16), Value(16),
Value(16), Value(16), Value(16), Value(16)
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(12), Value(12), Value(20),
Value(40), Value(90), Value( 0), Value( 0)
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(24), Value(24), Value(40),
Value(80), Value(180), Value(0), Value( 0)
Value( 0), Value( 13), Value(13), Value(29),
Value(68), Value(166), Value( 0), Value( 0)
};
// Pawn storm tables for positions with opposite castling:
const int QStormTable[64] = {
0, 0, 0, 0, 0, 0, 0, 0,
-22,-22,-22,-13,-4, 0, 0, 0,
-4, -9, -9, -9,-4, 0, 0, 0,
9, 18, 22, 18, 9, 0, 0, 0,
22, 31, 31, 22, 0, 0, 0, 0,
31, 40, 40, 31, 0, 0, 0, 0,
31, 40, 40, 31, 0, 0, 0, 0,
-22,-22,-22,-14,-6, 0, 0, 0,
-6,-10,-10,-10,-6, 0, 0, 0,
4, 12, 16, 12, 4, 0, 0, 0,
16, 23, 23, 16, 0, 0, 0, 0,
23, 31, 31, 23, 0, 0, 0, 0,
23, 31, 31, 23, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
};
const int KStormTable[64] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0,-4,-13,-22,-27,-27,
0, 0, 0,-4, -9,-13,-18,-18,
0, 0, 0, 0, 9, 9, 9, 9,
0, 0, 0, 0, 9, 18, 27, 27,
0, 0, 0, 0, 9, 27, 40, 36,
0, 0, 0, 0, 0, 31, 40, 31,
0, 0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0,-10,-19,-28,-33,-33,
0, 0, 0,-10,-15,-19,-24,-24,
0, 0, 0, 0, 1, 1, 1, 1,
0, 0, 0, 0, 1, 10, 19, 19,
0, 0, 0, 0, 1, 19, 31, 27,
0, 0, 0, 0, 0, 22, 31, 22,
0, 0, 0, 0, 0, 0, 0, 0
};
// Pawn storm open file bonuses by file
const int16_t KStormOpenFileBonus[8] = { 45, 45, 30, 0, 0, 0, 0, 0 };
const int16_t QStormOpenFileBonus[8] = { 0, 0, 0, 0, 0, 30, 45, 30 };
const int16_t KStormOpenFileBonus[8] = { 31, 31, 18, 0, 0, 0, 0, 0 };
const int16_t QStormOpenFileBonus[8] = { 0, 0, 0, 0, 0, 26, 42, 26 };
// Pawn storm lever bonuses by file
const int StormLeverBonus[8] = { 20, 20, 10, 0, 0, 10, 20, 20 };
const int StormLeverBonus[8] = { -8, -8, -13, 0, 0, -13, -8, -8 };
}
@@ -144,9 +144,8 @@ PawnInfoTable::PawnInfoTable(unsigned numOfEntries) {
{
std::cerr << "Failed to allocate " << (numOfEntries * sizeof(PawnInfo))
<< " bytes for pawn hash table." << std::endl;
exit(EXIT_FAILURE);
Application::exit_with_failure();
}
clear();
}
@@ -157,14 +156,6 @@ PawnInfoTable::~PawnInfoTable() {
}
/// PawnInfoTable::clear() clears the pawn hash table by setting all
/// entries to 0.
void PawnInfoTable::clear() {
memset(entries, 0, size * sizeof(PawnInfo));
}
/// PawnInfoTable::get_pawn_info() takes a position object as input, computes
/// a PawnInfo object, and returns a pointer to it. The result is also
/// stored in a hash table, so we don't have to recompute everything when
@@ -202,7 +193,7 @@ PawnInfo *PawnInfoTable::get_pawn_info(const Position &pos) {
// Initialize pawn storm scores by giving bonuses for open files
for (File f = FILE_A; f <= FILE_H; f++)
if (pos.file_is_half_open(us, f))
if (Position::file_is_half_open(ourPawns, f))
{
pi->ksStormValue[us] += KStormOpenFileBonus[f];
pi->qsStormValue[us] += QStormOpenFileBonus[f];
@@ -222,9 +213,9 @@ PawnInfo *PawnInfoTable::get_pawn_info(const Position &pos) {
pi->halfOpenFiles[us] &= ~(1 << f);
// Passed, isolated or doubled pawn?
passed = pos.pawn_is_passed(us, s);
isolated = pos.pawn_is_isolated(us, s);
doubled = pos.pawn_is_doubled(us, s);
passed = Position::pawn_is_passed(theirPawns, us, s);
isolated = Position::pawn_is_isolated(ourPawns, s);
doubled = Position::pawn_is_doubled(ourPawns, us, s);
// We calculate kingside and queenside pawn storm
// scores for both colors. These are used when evaluating
@@ -328,7 +319,7 @@ PawnInfo *PawnInfoTable::get_pawn_info(const Position &pos) {
// Test for candidate passed pawn
candidate = !passed
&& pos.file_is_half_open(them, f)
&& Position::file_is_half_open(theirPawns, 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);
@@ -348,7 +339,7 @@ PawnInfo *PawnInfoTable::get_pawn_info(const Position &pos) {
{
mv -= IsolatedPawnMidgamePenalty[f];
ev -= IsolatedPawnEndgamePenalty[f];
if (pos.file_is_half_open(them, f))
if (Position::file_is_half_open(theirPawns, f))
{
mv -= IsolatedPawnMidgamePenalty[f] / 2;
ev -= IsolatedPawnEndgamePenalty[f] / 2;
@@ -363,7 +354,7 @@ PawnInfo *PawnInfoTable::get_pawn_info(const Position &pos) {
{
mv -= BackwardPawnMidgamePenalty[f];
ev -= BackwardPawnEndgamePenalty[f];
if (pos.file_is_half_open(them, f))
if (Position::file_is_half_open(theirPawns, f))
{
mv -= BackwardPawnMidgamePenalty[f] / 2;
ev -= BackwardPawnEndgamePenalty[f] / 2;

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -33,9 +33,9 @@
////
/// PawnInfo is a class which contains various information about a pawn
/// structure. Currently, it only includes a middle game and an end game
/// pawn structure evaluation, and a bitboard of passed pawns. We may want
/// to add further information in the future. A lookup to the pawn hash table
/// structure. Currently, it only includes a middle game and an end game
/// pawn structure evaluation, and a bitboard of passed pawns. We may want
/// to add further information in the future. A lookup to the pawn hash table
/// (performed by calling the get_pawn_info method in a PawnInfoTable object)
/// returns a pointer to a PawnInfo object.
class Position;
@@ -45,6 +45,8 @@ class PawnInfo {
friend class PawnInfoTable;
public:
PawnInfo() : key(0) { clear(); }
Value mg_value() const;
Value eg_value() const;
Value kingside_storm_value(Color c) const;
@@ -53,18 +55,21 @@ public:
int file_is_half_open(Color c, File f) const;
int has_open_file_to_left(Color c, File f) const;
int has_open_file_to_right(Color c, File f) const;
int kingShelter(Color c, Square ksq) const;
void setKingShelter(Color c, Square ksq, int value);
private:
void clear();
inline void clear();
Key key;
Bitboard passedPawns;
int16_t mgValue, egValue;
int16_t ksStormValue[2], qsStormValue[2];
uint8_t halfOpenFiles[2];
Square kingSquares[2];
int16_t kingShelters[2];
};
/// The PawnInfoTable class represents a pawn hash table. It is basically
/// just an array of PawnInfo objects and a few methods for accessing these
/// objects. The most important method is get_pawn_info, which looks up a
@@ -75,7 +80,6 @@ class PawnInfoTable {
public:
PawnInfoTable(unsigned numOfEntries);
~PawnInfoTable();
void clear();
PawnInfo* get_pawn_info(const Position& pos);
private:
@@ -120,6 +124,15 @@ inline int PawnInfo::has_open_file_to_right(Color c, File f) const {
return halfOpenFiles[c] & ~((1 << int(f+1)) - 1);
}
inline int PawnInfo::kingShelter(Color c, Square ksq) const {
return (kingSquares[c] == ksq ? kingShelters[c] : -1);
}
inline void PawnInfo::setKingShelter(Color c, Square ksq, int value) {
kingSquares[c] = ksq;
kingShelters[c] = (int16_t)value;
}
inline void PawnInfo::clear() {
passedPawns = EmptyBoardBB;
@@ -127,6 +140,7 @@ inline void PawnInfo::clear() {
ksStormValue[WHITE] = ksStormValue[BLACK] = 0;
qsStormValue[WHITE] = qsStormValue[BLACK] = 0;
halfOpenFiles[WHITE] = halfOpenFiles[BLACK] = 0xFF;
kingSquares[WHITE] = kingSquares[BLACK] = SQ_NONE;
}

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -27,6 +27,7 @@
#include <fstream>
#include <iostream>
#include "bitcount.h"
#include "mersenne.h"
#include "movegen.h"
#include "movepick.h"
@@ -35,13 +36,13 @@
#include "san.h"
#include "ucioption.h"
using std::string;
////
//// Variables
////
extern SearchStack EmptySearchStack;
int Position::castleRightsMask[64];
Key Position::zobrist[2][8][64];
@@ -65,7 +66,7 @@ Position::Position(const Position& pos) {
copy(pos);
}
Position::Position(const std::string& fen) {
Position::Position(const string& fen) {
from_fen(fen);
}
@@ -74,9 +75,9 @@ Position::Position(const std::string& fen) {
/// string. This function is not very robust - make sure that input FENs are
/// correct (this is assumed to be the responsibility of the GUI).
void Position::from_fen(const std::string& fen) {
void Position::from_fen(const string& fen) {
static const std::string pieceLetters = "KQRBNPkqrbnp";
static const string pieceLetters = "KQRBNPkqrbnp";
static const Piece pieces[] = { WK, WQ, WR, WB, WN, WP, BK, BQ, BR, BB, BN, BP };
clear();
@@ -100,7 +101,7 @@ void Position::from_fen(const std::string& fen) {
continue;
}
size_t idx = pieceLetters.find(fen[i]);
if (idx == std::string::npos)
if (idx == string::npos)
{
std::cout << "Error in FEN at character " << i << std::endl;
return;
@@ -213,18 +214,18 @@ void Position::from_fen(const std::string& fen) {
st->materialKey = compute_material_key();
st->mgValue = compute_value<MidGame>();
st->egValue = compute_value<EndGame>();
npMaterial[WHITE] = compute_non_pawn_material(WHITE);
npMaterial[BLACK] = compute_non_pawn_material(BLACK);
st->npMaterial[WHITE] = compute_non_pawn_material(WHITE);
st->npMaterial[BLACK] = compute_non_pawn_material(BLACK);
}
/// Position::to_fen() converts the position object to a FEN string. This is
/// probably only useful for debugging.
const std::string Position::to_fen() const {
const string Position::to_fen() const {
static const std::string pieceLetters = " PNBRQK pnbrqk";
std::string fen;
static const string pieceLetters = " PNBRQK pnbrqk";
string fen;
int skip;
for (Rank rank = RANK_8; rank >= RANK_1; rank--)
@@ -274,7 +275,7 @@ const std::string Position::to_fen() const {
void Position::print(Move m) const {
static const std::string pieceLetters = " PNBRQK PNBRQK .";
static const string pieceLetters = " PNBRQK PNBRQK .";
// Check for reentrancy, as example when called from inside
// MovePicker that is used also here in move_to_san()
@@ -286,7 +287,7 @@ void Position::print(Move m) const {
std::cout << std::endl;
if (m != MOVE_NONE)
{
std::string col = (color_of_piece_on(move_from(m)) == BLACK ? ".." : "");
string col = (color_of_piece_on(move_from(m)) == BLACK ? ".." : "");
std::cout << "Move is: " << col << move_to_san(*this, m) << std::endl;
}
for (Rank rank = RANK_8; rank >= RANK_1; rank--)
@@ -314,9 +315,10 @@ void Position::print(Move m) const {
/// Position::copy() creates a copy of the input position.
void Position::copy(const Position &pos) {
void Position::copy(const Position& pos) {
memcpy(this, &pos, sizeof(Position));
saveState(); // detach and copy state info
}
@@ -377,9 +379,7 @@ Bitboard Position::discovered_check_candidates(Color c) const {
}
/// Position::attacks_to() computes a bitboard containing all pieces which
/// attacks a given square. There are two versions of this function: One
/// which finds attackers of both colors, and one which only finds the
/// attackers for one side.
/// attacks a given square.
Bitboard Position::attacks_to(Square s) const {
@@ -460,7 +460,9 @@ void Position::find_checkers() {
bool Position::pl_move_is_legal(Move m) const {
return pl_move_is_legal(m, pinned_pieces(side_to_move()));
// If we're in check, all pseudo-legal moves are legal, because our
// check evasion generator only generates true legal moves.
return is_check() || pl_move_is_legal(m, pinned_pieces(side_to_move()));
}
bool Position::pl_move_is_legal(Move m, Bitboard pinned) const {
@@ -468,11 +470,7 @@ bool Position::pl_move_is_legal(Move m, Bitboard pinned) const {
assert(is_ok());
assert(move_is_ok(m));
assert(pinned == pinned_pieces(side_to_move()));
// If we're in check, all pseudo-legal moves are legal, because our
// check evasion generator only generates true legal moves.
if (is_check())
return true;
assert(!is_check());
// Castling moves are checked for legality during move generation.
if (move_is_castle(m))
@@ -557,12 +555,12 @@ bool Position::move_is_check(Move m, Bitboard dcCandidates) const {
&& (direction_between_squares(from, ksq) != direction_between_squares(to, ksq)))
return true;
if (move_promotion(m)) // Promotion with check?
if (move_is_promotion(m)) // Promotion with check?
{
Bitboard b = occupied_squares();
clear_bit(&b, from);
switch (move_promotion(m))
switch (move_promotion_piece(m))
{
case KNIGHT:
return bit_is_set(piece_attacks<KNIGHT>(to), ksq);
@@ -660,6 +658,7 @@ inline void Position::update_checkers(Bitboard* pCheckersBB, Square ksq, Square
const bool Rook = (Piece == QUEEN || Piece == ROOK);
const bool Slider = Bishop || Rook;
// Direct checks
if ( ( (Bishop && bit_is_set(BishopPseudoAttacks[ksq], to))
|| (Rook && bit_is_set(RookPseudoAttacks[ksq], to)))
&& bit_is_set(piece_attacks<Piece>(ksq), to)) // slow, try to early skip
@@ -670,6 +669,7 @@ inline void Position::update_checkers(Bitboard* pCheckersBB, Square ksq, Square
&& bit_is_set(piece_attacks<Piece>(ksq), to))
set_bit(pCheckersBB, to);
// Discovery checks
if (Piece != QUEEN && bit_is_set(dcCandidates, from))
{
if (Piece != ROOK)
@@ -703,6 +703,7 @@ void Position::do_move(Move m, StateInfo& newSt, Bitboard dcCandidates) {
int castleRights, rule50;
Square epSquare;
Value mgValue, egValue;
Value npMaterial[2];
};
memcpy(&newSt, st, sizeof(ReducedStateInfo));
@@ -720,7 +721,7 @@ void Position::do_move(Move m, StateInfo& newSt, Bitboard dcCandidates) {
if (move_is_castle(m))
do_castle_move(m);
else if (move_promotion(m))
else if (move_is_promotion(m))
do_promotion_move(m);
else if (move_is_ep(m))
do_ep_move(m);
@@ -734,7 +735,8 @@ void Position::do_move(Move m, StateInfo& newSt, Bitboard dcCandidates) {
assert(color_of_piece_on(from) == us);
assert(color_of_piece_on(to) == them || piece_on(to) == EMPTY);
PieceType piece = type_of_piece_on(from);
Piece piece = piece_on(from);
PieceType pt = type_of_piece(piece);
st->capture = type_of_piece_on(to);
@@ -742,26 +744,23 @@ void Position::do_move(Move m, StateInfo& newSt, Bitboard dcCandidates) {
do_capture_move(st->capture, them, to);
// Move the piece
clear_bit(&(byColorBB[us]), from);
clear_bit(&(byTypeBB[piece]), from);
clear_bit(&(byTypeBB[0]), from); // HACK: byTypeBB[0] == occupied squares
set_bit(&(byColorBB[us]), to);
set_bit(&(byTypeBB[piece]), to);
set_bit(&(byTypeBB[0]), to); // HACK: byTypeBB[0] == occupied squares
Bitboard move_bb = make_move_bb(from, to);
do_move_bb(&(byColorBB[us]), move_bb);
do_move_bb(&(byTypeBB[pt]), move_bb);
do_move_bb(&(byTypeBB[0]), move_bb); // HACK: byTypeBB[0] == occupied squares
board[to] = board[from];
board[from] = EMPTY;
// Update hash key
st->key ^= zobrist[us][piece][from] ^ zobrist[us][piece][to];
st->key ^= zobrist[us][pt][from] ^ zobrist[us][pt][to];
// Update incremental scores
st->mgValue -= pst<MidGame>(us, piece, from);
st->mgValue += pst<MidGame>(us, piece, to);
st->egValue -= pst<EndGame>(us, piece, from);
st->egValue += pst<EndGame>(us, piece, to);
st->mgValue += pst_delta<MidGame>(piece, from, to);
st->egValue += pst_delta<EndGame>(piece, from, to);
// If the moving piece was a king, update the king square
if (piece == KING)
if (pt == KING)
kingSquare[us] = to;
// Reset en passant square
@@ -772,7 +771,7 @@ void Position::do_move(Move m, StateInfo& newSt, Bitboard dcCandidates) {
}
// If the moving piece was a pawn do some special extra work
if (piece == PAWN)
if (pt == PAWN)
{
// Reset rule 50 draw counter
st->rule50 = 0;
@@ -793,19 +792,22 @@ void Position::do_move(Move m, StateInfo& newSt, Bitboard dcCandidates) {
}
// Update piece lists
pieceList[us][piece][index[from]] = to;
pieceList[us][pt][index[from]] = to;
index[to] = index[from];
// Update castle rights
st->key ^= zobCastle[st->castleRights];
st->castleRights &= castleRightsMask[from];
st->castleRights &= castleRightsMask[to];
st->key ^= zobCastle[st->castleRights];
// Update castle rights, try to shortcut a common case
if ((castleRightsMask[from] & castleRightsMask[to]) != ALL_CASTLES)
{
st->key ^= zobCastle[st->castleRights];
st->castleRights &= castleRightsMask[from];
st->castleRights &= castleRightsMask[to];
st->key ^= zobCastle[st->castleRights];
}
// Update checkers bitboard, piece must be already moved
st->checkersBB = EmptyBoardBB;
Square ksq = king_square(them);
switch (piece)
switch (pt)
{
case PAWN: update_checkers<PAWN>(&(st->checkersBB), ksq, from, to, dcCandidates); break;
case KNIGHT: update_checkers<KNIGHT>(&(st->checkersBB), ksq, from, to, dcCandidates); break;
@@ -839,6 +841,7 @@ void Position::do_capture_move(PieceType capture, Color them, Square to) {
// Remove captured piece
clear_bit(&(byColorBB[them]), to);
clear_bit(&(byTypeBB[capture]), to);
clear_bit(&(byTypeBB[0]), to);
// Update hash key
st->key ^= zobrist[them][capture][to];
@@ -853,7 +856,7 @@ void Position::do_capture_move(PieceType capture, Color them, Square to) {
// Update material
if (capture != PAWN)
npMaterial[them] -= piece_value_midgame(capture);
st->npMaterial[them] -= piece_value_midgame(capture);
// Update material hash key
st->materialKey ^= zobMaterial[them][capture][pieceCount[them][capture]];
@@ -919,9 +922,11 @@ void Position::do_castle_move(Move m) {
set_bit(&(byTypeBB[0]), rto); // HACK: byTypeBB[0] == occupied squares
// Update board array
Piece king = piece_of_color_and_type(us, KING);
Piece rook = piece_of_color_and_type(us, ROOK);
board[kfrom] = board[rfrom] = EMPTY;
board[kto] = piece_of_color_and_type(us, KING);
board[rto] = piece_of_color_and_type(us, ROOK);
board[kto] = king;
board[rto] = rook;
// Update king square
kingSquare[us] = kto;
@@ -934,14 +939,10 @@ void Position::do_castle_move(Move m) {
index[rto] = tmp;
// Update incremental scores
st->mgValue -= pst<MidGame>(us, KING, kfrom);
st->mgValue += pst<MidGame>(us, KING, kto);
st->egValue -= pst<EndGame>(us, KING, kfrom);
st->egValue += pst<EndGame>(us, KING, kto);
st->mgValue -= pst<MidGame>(us, ROOK, rfrom);
st->mgValue += pst<MidGame>(us, ROOK, rto);
st->egValue -= pst<EndGame>(us, ROOK, rfrom);
st->egValue += pst<EndGame>(us, ROOK, rto);
st->mgValue += pst_delta<MidGame>(king, kfrom, kto);
st->egValue += pst_delta<EndGame>(king, kfrom, kto);
st->mgValue += pst_delta<MidGame>(rook, rfrom, rto);
st->egValue += pst_delta<EndGame>(rook, rfrom, rto);
// Update hash key
st->key ^= zobrist[us][KING][kfrom] ^ zobrist[us][KING][kto];
@@ -978,7 +979,7 @@ void Position::do_promotion_move(Move m) {
assert(is_ok());
assert(move_is_ok(m));
assert(move_promotion(m));
assert(move_is_promotion(m));
us = side_to_move();
them = opposite_color(us);
@@ -992,7 +993,7 @@ void Position::do_promotion_move(Move m) {
st->capture = type_of_piece_on(to);
if (st->capture)
do_capture_move(st->capture, them, to);
do_capture_move(st->capture, them, to);
// Remove pawn
clear_bit(&(byColorBB[us]), from);
@@ -1001,7 +1002,7 @@ void Position::do_promotion_move(Move m) {
board[from] = EMPTY;
// Insert promoted piece
promotion = move_promotion(m);
promotion = move_promotion_piece(m);
assert(promotion >= KNIGHT && promotion <= QUEEN);
set_bit(&(byColorBB[us]), to);
set_bit(&(byTypeBB[promotion]), to);
@@ -1035,7 +1036,7 @@ void Position::do_promotion_move(Move m) {
st->egValue += pst<EndGame>(us, promotion, to);
// Update material
npMaterial[us] += piece_value_midgame(promotion);
st->npMaterial[us] += piece_value_midgame(promotion);
// Clear the en passant square
if (st->epSquare != SQ_NONE)
@@ -1081,21 +1082,17 @@ void Position::do_ep_move(Move m) {
assert(piece_on(from) == piece_of_color_and_type(us, PAWN));
assert(piece_on(capsq) == piece_of_color_and_type(them, PAWN));
// Remove captured piece
// Remove captured pawn
clear_bit(&(byColorBB[them]), capsq);
clear_bit(&(byTypeBB[PAWN]), capsq);
clear_bit(&(byTypeBB[0]), capsq); // HACK: byTypeBB[0] == occupied squares
board[capsq] = EMPTY;
// Remove moving piece from source square
clear_bit(&(byColorBB[us]), from);
clear_bit(&(byTypeBB[PAWN]), from);
clear_bit(&(byTypeBB[0]), from); // HACK: byTypeBB[0] == occupied squares
// Put moving piece on destination square
set_bit(&(byColorBB[us]), to);
set_bit(&(byTypeBB[PAWN]), to);
set_bit(&(byTypeBB[0]), to); // HACK: byTypeBB[0] == occupied squares
// Move capturing pawn
Bitboard move_bb = make_move_bb(from, to);
do_move_bb(&(byColorBB[us]), move_bb);
do_move_bb(&(byTypeBB[PAWN]), move_bb);
do_move_bb(&(byTypeBB[0]), move_bb); // HACK: byTypeBB[0] == occupied squares
board[to] = board[from];
board[from] = EMPTY;
@@ -1121,12 +1118,11 @@ void Position::do_ep_move(Move m) {
st->pawnKey ^= zobrist[them][PAWN][capsq];
// Update incremental scores
Piece pawn = piece_of_color_and_type(us, PAWN);
st->mgValue += pst_delta<MidGame>(pawn, from, to);
st->egValue += pst_delta<EndGame>(pawn, from, to);
st->mgValue -= pst<MidGame>(them, PAWN, capsq);
st->mgValue -= pst<MidGame>(us, PAWN, from);
st->mgValue += pst<MidGame>(us, PAWN, to);
st->egValue -= pst<EndGame>(them, PAWN, capsq);
st->egValue -= pst<EndGame>(us, PAWN, from);
st->egValue += pst<EndGame>(us, PAWN, to);
// Reset en passant square
st->epSquare = SQ_NONE;
@@ -1152,7 +1148,7 @@ void Position::undo_move(Move m) {
if (move_is_castle(m))
undo_castle_move(m);
else if (move_promotion(m))
else if (move_is_promotion(m))
undo_promotion_move(m);
else if (move_is_ep(m))
undo_ep_move(m);
@@ -1171,17 +1167,13 @@ void Position::undo_move(Move m) {
assert(color_of_piece_on(to) == us);
// Put the piece back at the source square
Bitboard move_bb = make_move_bb(to, from);
piece = type_of_piece_on(to);
set_bit(&(byColorBB[us]), from);
set_bit(&(byTypeBB[piece]), from);
set_bit(&(byTypeBB[0]), from); // HACK: byTypeBB[0] == occupied squares
do_move_bb(&(byColorBB[us]), move_bb);
do_move_bb(&(byTypeBB[piece]), move_bb);
do_move_bb(&(byTypeBB[0]), move_bb); // HACK: byTypeBB[0] == occupied squares
board[from] = piece_of_color_and_type(us, piece);
// Clear the destination square
clear_bit(&(byColorBB[us]), to);
clear_bit(&(byTypeBB[piece]), to);
clear_bit(&(byTypeBB[0]), to); // HACK: byTypeBB[0] == occupied squares
// If the moving piece was a king, update the king square
if (piece == KING)
kingSquare[us] = from;
@@ -1194,16 +1186,12 @@ void Position::undo_move(Move m) {
{
assert(st->capture != KING);
// Replace the captured piece
// Restore the captured piece
set_bit(&(byColorBB[them]), to);
set_bit(&(byTypeBB[st->capture]), to);
set_bit(&(byTypeBB[0]), to);
board[to] = piece_of_color_and_type(them, st->capture);
// Update material
if (st->capture != PAWN)
npMaterial[them] += piece_value_midgame(st->capture);
// Update piece list
pieceList[them][st->capture][pieceCount[them][st->capture]] = to;
index[to] = pieceCount[them][st->capture];
@@ -1298,7 +1286,7 @@ void Position::undo_promotion_move(Move m) {
PieceType promotion;
assert(move_is_ok(m));
assert(move_promotion(m));
assert(move_is_promotion(m));
// When we have arrived here, some work has already been done by
// Position::undo_move. In particular, the side to move has been switched,
@@ -1312,7 +1300,7 @@ void Position::undo_promotion_move(Move m) {
assert(piece_on(from) == EMPTY);
// Remove promoted piece
promotion = move_promotion(m);
promotion = move_promotion_piece(m);
assert(piece_on(to)==piece_of_color_and_type(us, promotion));
assert(promotion >= KNIGHT && promotion <= QUEEN);
clear_bit(&(byColorBB[us]), to);
@@ -1325,9 +1313,6 @@ void Position::undo_promotion_move(Move m) {
set_bit(&(byTypeBB[0]), from); // HACK: byTypeBB[0] == occupied squares
board[from] = piece_of_color_and_type(us, PAWN);
// Update material
npMaterial[us] -= piece_value_midgame(promotion);
// Update piece list
pieceList[us][PAWN][pieceCount[us][PAWN]] = from;
index[from] = pieceCount[us][PAWN];
@@ -1349,11 +1334,6 @@ void Position::undo_promotion_move(Move m) {
set_bit(&(byTypeBB[0]), to); // HACK: byTypeBB[0] == occupied squares
board[to] = piece_of_color_and_type(them, st->capture);
// Update material. Because the move is a promotion move, we know
// that the captured piece cannot be a pawn.
assert(st->capture != PAWN);
npMaterial[them] += piece_value_midgame(st->capture);
// Update piece list
pieceList[them][st->capture][pieceCount[them][st->capture]] = to;
index[to] = pieceCount[them][st->capture];
@@ -1388,31 +1368,27 @@ void Position::undo_ep_move(Move m) {
assert(piece_on(from) == EMPTY);
assert(piece_on(capsq) == EMPTY);
// Replace captured piece
// Restore captured pawn
set_bit(&(byColorBB[them]), capsq);
set_bit(&(byTypeBB[PAWN]), capsq);
set_bit(&(byTypeBB[0]), capsq);
board[capsq] = piece_of_color_and_type(them, PAWN);
// Remove moving piece from destination square
clear_bit(&(byColorBB[us]), to);
clear_bit(&(byTypeBB[PAWN]), to);
clear_bit(&(byTypeBB[0]), to);
// Move capturing pawn back to source square
Bitboard move_bb = make_move_bb(to, from);
do_move_bb(&(byColorBB[us]), move_bb);
do_move_bb(&(byTypeBB[PAWN]), move_bb);
do_move_bb(&(byTypeBB[0]), move_bb);
board[to] = EMPTY;
// Replace moving piece at source square
set_bit(&(byColorBB[us]), from);
set_bit(&(byTypeBB[PAWN]), from);
set_bit(&(byTypeBB[0]), from);
board[from] = piece_of_color_and_type(us, PAWN);
// Update piece list:
// Update piece list
pieceList[us][PAWN][index[to]] = from;
index[from] = index[to];
pieceList[them][PAWN][pieceCount[them][PAWN]] = capsq;
index[capsq] = pieceCount[them][PAWN];
// Update piece count:
// Update piece count
pieceCount[them][PAWN]++;
}
@@ -1426,12 +1402,13 @@ void Position::do_null_move(StateInfo& backupSt) {
assert(!is_check());
// Back up the information necessary to undo the null move to the supplied
// StateInfo object. In the case of a null move, the only thing we need to
// remember is the last move made and the en passant square.
// StateInfo object.
// Note that differently from normal case here backupSt is actually used as
// a backup storage not as a new state to be used.
backupSt.lastMove = st->lastMove;
backupSt.epSquare = st->epSquare;
backupSt.key = st->key;
backupSt.mgValue = st->mgValue;
backupSt.egValue = st->egValue;
backupSt.previous = st->previous;
st->previous = &backupSt;
@@ -1464,21 +1441,16 @@ void Position::undo_null_move() {
assert(!is_check());
// Restore information from the our backup StateInfo object
st->lastMove = st->previous->lastMove;
st->epSquare = st->previous->epSquare;
st->key = st->previous->key;
st->mgValue = st->previous->mgValue;
st->egValue = st->previous->egValue;
st->previous = st->previous->previous;
if (st->epSquare != SQ_NONE)
st->key ^= zobEp[st->epSquare];
// Update the necessary information
sideToMove = opposite_color(sideToMove);
st->rule50--;
gamePly--;
st->key ^= zobSideToMove;
st->mgValue += (sideToMove == WHITE)? TempoValueMidgame : -TempoValueMidgame;
st->egValue += (sideToMove == WHITE)? TempoValueEndgame : -TempoValueEndgame;
assert(is_ok());
}
@@ -1513,7 +1485,7 @@ int Position::see(Square from, Square to) const {
0, 0
};
Bitboard attackers, occ, b;
Bitboard attackers, stmAttackers, occ, b;
assert(square_is_ok(from) || from == SQ_NONE);
assert(square_is_ok(to));
@@ -1537,7 +1509,6 @@ int Position::see(Square from, Square to) const {
Square capQq = (side_to_move() == WHITE)? (to - DELTA_N) : (to - DELTA_S);
capture = piece_on(capQq);
assert(type_of_piece_on(capQq) == PAWN);
// Remove the captured pawn
@@ -1572,7 +1543,8 @@ int Position::see(Square from, Square to) const {
}
// If the opponent has no attackers we are finished
if ((attackers & pieces_of_color(them)) == EmptyBoardBB)
stmAttackers = attackers & pieces_of_color(them);
if (!stmAttackers)
return seeValues[capture];
attackers &= occ; // Remove the moving piece
@@ -1594,12 +1566,12 @@ int Position::see(Square from, Square to) const {
// Locate the least valuable attacker for the side to move. The loop
// below looks like it is potentially infinite, but it isn't. We know
// that the side to move still has at least one attacker left.
for (pt = PAWN; !(attackers & pieces_of_color_and_type(c, pt)); pt++)
for (pt = PAWN; !(stmAttackers & pieces_of_type(pt)); pt++)
assert(pt < KING);
// Remove the attacker we just found from the 'attackers' bitboard,
// and scan for new X-ray attacks behind the attacker.
b = attackers & pieces_of_color_and_type(c, pt);
b = stmAttackers & pieces_of_type(pt);
occ ^= (b & (~b + 1));
attackers |= (rook_attacks_bb(to, occ) & rooks_and_queens())
| (bishop_attacks_bb(to, occ) & bishops_and_queens());
@@ -1615,15 +1587,16 @@ int Position::see(Square from, Square to) const {
// before beginning the next iteration
lastCapturingPieceValue = seeValues[pt];
c = opposite_color(c);
stmAttackers = attackers & pieces_of_color(c);
// Stop after a king capture
if (pt == KING && (attackers & pieces_of_color(c)))
if (pt == KING && stmAttackers)
{
assert(n < 32);
swapList[n++] = 100;
swapList[n++] = QueenValueMidgame*10;
break;
}
} while (attackers & pieces_of_color(c));
} while (stmAttackers);
// Having built the swap list, we negamax through it to find the best
// achievable score from the point of view of the side to move
@@ -1634,15 +1607,16 @@ int Position::see(Square from, Square to) const {
}
/// Position::setStartState() copies the content of the argument
/// Position::saveState() copies the content of the current state
/// inside startState and makes st point to it. This is needed
/// when the st pointee could become stale, as example because
/// the caller is about to going out of scope.
void Position::setStartState(const StateInfo& s) {
void Position::saveState() {
startState = s;
startState = *st;
st = &startState;
st->previous = NULL; // as a safe guard
}
@@ -1993,7 +1967,7 @@ void Position::init_piece_square_tables() {
/// the white and black sides reversed. This is only useful for debugging,
/// especially for finding evaluation symmetry bugs.
void Position::flipped_copy(const Position &pos) {
void Position::flipped_copy(const Position& pos) {
assert(pos.is_ok());
@@ -2044,8 +2018,8 @@ void Position::flipped_copy(const Position &pos) {
st->egValue = compute_value<EndGame>();
// Material
npMaterial[WHITE] = compute_non_pawn_material(WHITE);
npMaterial[BLACK] = compute_non_pawn_material(BLACK);
st->npMaterial[WHITE] = compute_non_pawn_material(WHITE);
st->npMaterial[BLACK] = compute_non_pawn_material(BLACK);
assert(is_ok());
}
@@ -2181,10 +2155,10 @@ bool Position::is_ok(int* failedStep) const {
if (failedStep) (*failedStep)++;
if (debugNonPawnMaterial)
{
if (npMaterial[WHITE] != compute_non_pawn_material(WHITE))
if (st->npMaterial[WHITE] != compute_non_pawn_material(WHITE))
return false;
if (npMaterial[BLACK] != compute_non_pawn_material(BLACK))
if (st->npMaterial[BLACK] != compute_non_pawn_material(BLACK))
return false;
}

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -21,7 +21,7 @@
#if !defined(POSITION_H_INCLUDED)
#define POSITION_H_INCLUDED
// Disable a silly and noisy warning from MSVC compiler
// Disable some silly and noisy warning from MSVC compiler
#if defined(_MSC_VER)
// Forcing value to bool 'true' or 'false' (performance warning)
@@ -50,13 +50,12 @@
//// Constants
////
/// FEN string for the initial position:
const std::string StartPosition =
"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
/// FEN string for the initial position
const std::string StartPosition = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
/// Maximum number of plies per game (220 should be enough, because the
/// maximum search depth is 100, and during position setup we reset the
/// move counter for every non-reversible move):
/// move counter for every non-reversible move).
const int MaxGameLength = 220;
@@ -67,11 +66,11 @@ const int MaxGameLength = 220;
/// Castle rights, encoded as bit fields
enum CastleRights {
NO_CASTLES = 0,
WHITE_OO = 1,
BLACK_OO = 2,
WHITE_OOO = 4,
BLACK_OOO = 8,
NO_CASTLES = 0,
WHITE_OO = 1,
BLACK_OO = 2,
WHITE_OOO = 4,
BLACK_OOO = 8,
ALL_CASTLES = 15
};
@@ -92,34 +91,33 @@ struct StateInfo {
int castleRights, rule50;
Square epSquare;
Value mgValue, egValue;
Value npMaterial[2];
PieceType capture;
Bitboard checkersBB;
Move lastMove;
StateInfo* previous;
};
/// The position data structure. A position consists of the following data:
/// The position data structure. A position consists of the following data:
///
/// * For each piece type, a bitboard representing the squares occupied
/// by pieces of that type.
/// * For each color, a bitboard representing the squares occupiecd by
/// * For each color, a bitboard representing the squares occupied by
/// pieces of that color.
/// * A bitboard of all occupied squares.
/// * A bitboard of all checking pieces.
/// * A 64-entry array of pieces, indexed by the squares of the board.
/// * The current side to move.
/// * Information about the castling rights for both sides.
/// * The initial files of the kings and both pairs of rooks. This is
/// * The initial files of the kings and both pairs of rooks. This is
/// used to implement the Chess960 castling rules.
/// * The en passant square (which is SQ_NONE if no en passant capture is
/// possible).
/// * The squares of the kings for both sides.
/// * The last move played.
/// * Hash keys for the position itself, the current pawn structure, and
/// the current material situation.
/// * Hash keys for all previous positions in the game (for detecting
/// * Hash keys for all previous positions in the game for detecting
/// repetition draws.
/// * A counter for detecting 50 move rule draws.
@@ -129,6 +127,11 @@ class Position {
friend class EndgameFunctions;
public:
enum GamePhase {
MidGame,
EndGame
};
// Constructors
Position() {};
Position(const Position& pos);
@@ -140,8 +143,8 @@ public:
void print(Move m = MOVE_NONE) const;
// Copying
void copy(const Position &pos);
void flipped_copy(const Position &pos);
void copy(const Position& pos);
void flipped_copy(const Position& pos);
// The piece on a given square
Piece piece_on(Square s) const;
@@ -241,18 +244,19 @@ public:
// Information about pawns
bool pawn_is_passed(Color c, Square s) const;
bool pawn_is_isolated(Color c, Square s) const;
bool pawn_is_doubled(Color c, Square s) const;
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);
// Open and half-open files
bool file_is_open(File f) const;
bool file_is_half_open(Color c, File f) const;
static bool file_is_open(Bitboard pawns, File f);
static bool file_is_half_open(Bitboard pawns, File f);
// Weak squares
bool square_is_weak(Square s, Color c) const;
// Doing and undoing moves
void setStartState(const StateInfo& st);
void saveState();
void do_move(Move m, StateInfo& st);
void do_move(Move m, StateInfo& st, Bitboard dcCandidates);
void undo_move(Move m);
@@ -274,7 +278,7 @@ public:
Value eg_value() const;
Value non_pawn_material(Color c) const;
Phase game_phase() const;
Value mg_pst_delta(Move m) const;
template<GamePhase> Value pst_delta(Piece piece, Square from, Square to) const;
// Game termination checks
bool is_mate() const;
@@ -330,10 +334,6 @@ private:
Key compute_material_key() const;
// Computing incremental evaluation scores and material counts
enum GamePhase {
MidGame,
EndGame
};
template<GamePhase> Value pst(Color c, PieceType pt, Square s) const;
template<GamePhase> Value compute_value() const;
Value compute_non_pawn_material(Color c) const;
@@ -356,7 +356,6 @@ private:
Color sideToMove;
int gamePly;
Key history[MaxGameLength];
Value npMaterial[2];
File initialKFile, initialKRFile, initialQRFile;
StateInfo startState;
StateInfo* st;
@@ -497,10 +496,6 @@ inline Bitboard Position::bishops_and_queens(Color c) const {
return bishops_and_queens() & pieces_of_color(c);
}
inline Bitboard Position::sliders_of_color(Color c) const {
return sliders() & pieces_of_color(c);
}
inline int Position::piece_count(Color c, PieceType pt) const {
return pieceCount[c][pt];
}
@@ -541,14 +536,14 @@ inline Bitboard Position::pawn_attacks(Color c, Square s) const {
return StepAttackBB[piece_of_color_and_type(c, PAWN)][s];
}
template<>
inline Bitboard Position::piece_attacks<PAWN>(Square s) const {
return StepAttackBB[piece_of_color_and_type(opposite_color(sideToMove), PAWN)][s];
template<PieceType Piece> // Knight and King
inline Bitboard Position::piece_attacks(Square s) const {
return StepAttackBB[Piece][s];
}
template<>
inline Bitboard Position::piece_attacks<KNIGHT>(Square s) const {
return StepAttackBB[KNIGHT][s];
inline Bitboard Position::piece_attacks<PAWN>(Square s) const {
return StepAttackBB[piece_of_color_and_type(opposite_color(sideToMove), PAWN)][s];
}
template<>
@@ -566,11 +561,6 @@ inline Bitboard Position::piece_attacks<QUEEN>(Square s) const {
return piece_attacks<ROOK>(s) | piece_attacks<BISHOP>(s);
}
template<>
inline Bitboard Position::piece_attacks<KING>(Square s) const {
return StepAttackBB[KING][s];
}
inline Bitboard Position::checkers() const {
return st->checkersBB;
}
@@ -602,20 +592,24 @@ inline bool Position::pawn_is_passed(Color c, Square s) const {
return !(pawns(opposite_color(c)) & passed_pawn_mask(c, s));
}
inline bool Position::pawn_is_isolated(Color c, Square s) const {
return !(pawns(c) & neighboring_files_bb(s));
inline bool Position::pawn_is_passed(Bitboard theirPawns, Color c, Square s) {
return !(theirPawns & passed_pawn_mask(c, s));
}
inline bool Position::pawn_is_doubled(Color c, Square s) const {
return pawns(c) & squares_behind(c, s);
inline bool Position::pawn_is_isolated(Bitboard ourPawns, Square s) {
return !(ourPawns & neighboring_files_bb(s));
}
inline bool Position::file_is_open(File f) const {
return !(pawns() & file_bb(f));
inline bool Position::pawn_is_doubled(Bitboard ourPawns, Color c, Square s) {
return ourPawns & squares_behind(c, s);
}
inline bool Position::file_is_half_open(Color c, File f) const {
return !(pawns(c) & file_bb(f));
inline bool Position::file_is_open(Bitboard pawns, File f) {
return !(pawns & file_bb(f));
}
inline bool Position::file_is_half_open(Bitboard pawns, File f) {
return !(pawns & file_bb(f));
}
inline bool Position::square_is_weak(Square s, Color c) const {
@@ -634,15 +628,16 @@ inline Key Position::get_material_key() const {
return st->materialKey;
}
template<Position::GamePhase Phase>
template<Position::GamePhase Ph>
inline Value Position::pst(Color c, PieceType pt, Square s) const {
return (Phase == MidGame ? MgPieceSquareTable[piece_of_color_and_type(c, pt)][s]
: EgPieceSquareTable[piece_of_color_and_type(c, pt)][s]);
return (Ph == MidGame ? MgPieceSquareTable[piece_of_color_and_type(c, pt)][s]
: EgPieceSquareTable[piece_of_color_and_type(c, pt)][s]);
}
inline Value Position::mg_pst_delta(Move m) const {
return MgPieceSquareTable[piece_on(move_from(m))][move_to(m)]
-MgPieceSquareTable[piece_on(move_from(m))][move_from(m)];
template<Position::GamePhase Ph>
inline Value Position::pst_delta(Piece piece, Square from, Square to) const {
return (Ph == MidGame ? MgPieceSquareTable[piece][to] - MgPieceSquareTable[piece][from]
: EgPieceSquareTable[piece][to] - EgPieceSquareTable[piece][from]);
}
inline Value Position::mg_value() const {
@@ -654,7 +649,7 @@ inline Value Position::eg_value() const {
}
inline Value Position::non_pawn_material(Color c) const {
return npMaterial[c];
return st->npMaterial[c];
}
inline Phase Position::game_phase() const {
@@ -722,10 +717,7 @@ inline bool Position::move_is_capture(Move m) const {
// Move must not be MOVE_NONE !
return ( !square_is_empty(move_to(m))
&& (color_of_piece_on(move_to(m)) != color_of_piece_on(move_from(m)))
)
|| move_is_ep(m);
return (!square_is_empty(move_to(m)) && !move_is_castle(m)) || move_is_ep(m);
}
#endif // !defined(POSITION_H_INCLUDED)

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -29,7 +29,7 @@
////
//// Variables
//// Constants modified by Joona Kiiski
////
static const Value MP = PawnValueMidgame;
@@ -41,70 +41,70 @@ static const Value MQ = QueenValueMidgame;
static const int MgPST[][64] = {
{ },
{// Pawn
// A B C D E F G H
0, 0, 0, 0, 0, 0, 0, 0,
MP-38, MP-12, MP- 0, MP+12, MP+12, MP- 0, MP-12, MP-38,
MP-38, MP-12, MP+ 6, MP+38, MP+38, MP+ 6, MP-12, MP-38,
MP-38, MP-12, MP+16, MP+64, MP+64, MP+16, MP-12, MP-38,
MP-38, MP-12, MP+16, MP+38, MP+38, MP+16, MP-12, MP-38,
MP-38, MP-12, MP+ 6, MP+12, MP+12, MP+ 6, MP-12, MP-38,
MP-38, MP-12, MP- 0, MP+12, MP+12, MP- 0, MP-12, MP-38,
0, 0, 0, 0, 0, 0, 0, 0
// A B C D E F G H
0, 0, 0, 0, 0, 0, 0, 0,
MP-28, MP-6, MP+ 4, MP+14, MP+14, MP+ 4, MP-6, MP-28,
MP-28, MP-6, MP+ 9, MP+36, MP+36, MP+ 9, MP-6, MP-28,
MP-28, MP-6, MP+17, MP+58, MP+58, MP+17, MP-6, MP-28,
MP-28, MP-6, MP+17, MP+36, MP+36, MP+17, MP-6, MP-28,
MP-28, MP-6, MP+ 9, MP+14, MP+14, MP+ 9, MP-6, MP-28,
MP-28, MP-6, MP+ 4, MP+14, MP+14, MP+ 4, MP-6, MP-28,
0, 0, 0, 0, 0, 0, 0, 0
},
{// Knight
// A B C D E F G H
MK-128, MK-102, MK-76, MK-64, MK-64, MK-76, MK-102, MK-128,
MK- 89, MK- 64, MK-38, MK-25, MK-25, MK-38, MK- 64, MK- 89,
MK- 51, MK- 25, MK- 0, MK+12, MK+12, MK- 0, MK- 25, MK- 51,
MK- 25, MK- 0, MK+25, MK+38, MK+38, MK+25, MK- 0, MK- 25,
MK- 12, MK+ 12, MK+38, MK+51, MK+51, MK+38, MK+ 12, MK- 12,
MK- 12, MK+ 12, MK+38, MK+51, MK+51, MK+38, MK+ 12, MK- 12,
MK- 51, MK- 25, MK- 0, MK+12, MK+12, MK- 0, MK- 25, MK- 51,
MK-182, MK- 64, MK-38, MK-25, MK-25, MK-38, MK- 64, MK-182
MK-135, MK-107, MK-80, MK-67, MK-67, MK-80, MK-107, MK-135,
MK- 93, MK- 67, MK-39, MK-25, MK-25, MK-39, MK- 67, MK- 93,
MK- 53, MK- 25, MK+ 1, MK+13, MK+13, MK+ 1, MK- 25, MK- 53,
MK- 25, MK+ 1, MK+27, MK+41, MK+41, MK+27, MK+ 1, MK- 25,
MK- 11, MK+ 13, MK+41, MK+55, MK+55, MK+41, MK+ 13, MK- 11,
MK- 11, MK+ 13, MK+41, MK+55, MK+55, MK+41, MK+ 13, MK- 11,
MK- 53, MK- 25, MK+ 1, MK+13, MK+13, MK+ 1, MK- 25, MK- 53,
MK-193, MK- 67, MK-39, MK-25, MK-25, MK-39, MK- 67, MK-193
},
{// Bishop
// A B C D E F G H
MB-46, MB-46, MB-40, MB-35, MB-35, MB-40, MB-46, MB-46,
MB-20, MB- 0, MB- 5, MB- 0, MB- 0, MB- 5, MB- 0, MB-20,
MB-15, MB- 5, MB+10, MB+ 5, MB+ 5, MB+10, MB- 5, MB-15,
MB-10, MB- 0, MB+ 5, MB+20, MB+20, MB+ 5, MB- 0, MB-10,
MB-10, MB- 0, MB+ 5, MB+20, MB+20, MB+ 5, MB- 0, MB-10,
MB-15, MB- 5, MB+10, MB+ 5, MB+ 5, MB+10, MB- 5, MB-15,
MB-20, MB- 0, MB- 5, MB- 0, MB- 0, MB- 5, MB- 0, MB-20,
MB-20, MB-20, MB-15, MB-10, MB-10, MB-15, MB-20, MB-20
MB-40, MB-40, MB-35, MB-30, MB-30, MB-35, MB-40, MB-40,
MB-17, MB+ 0, MB- 4, MB+ 0, MB+ 0, MB- 4, MB+ 0, MB-17,
MB-13, MB- 4, MB+ 8, MB+ 4, MB+ 4, MB+ 8, MB- 4, MB-13,
MB- 8, MB+ 0, MB+ 4, MB+17, MB+17, MB+ 4, MB+ 0, MB- 8,
MB- 8, MB+ 0, MB+ 4, MB+17, MB+17, MB+ 4, MB+ 0, MB- 8,
MB-13, MB- 4, MB+ 8, MB+ 4, MB+ 4, MB+ 8, MB- 4, MB-13,
MB-17, MB+ 0, MB- 4, MB+ 0, MB+ 0, MB- 4, MB+ 0, MB-17,
MB-17, MB-17, MB-13, MB- 8, MB- 8, MB-13, MB-17, MB-17
},
{// Rook
// A B C D E F G H
MR-18, MR-10, MR-3, MR+4, MR+4, MR-3, MR-10, MR-18,
MR-18, MR-10, MR-3, MR+4, MR+4, MR-3, MR-10, MR-18,
MR-18, MR-10, MR-3, MR+4, MR+4, MR-3, MR-10, MR-18,
MR-18, MR-10, MR-3, MR+4, MR+4, MR-3, MR-10, MR-18,
MR-18, MR-10, MR-3, MR+4, MR+4, MR-3, MR-10, MR-18,
MR-18, MR-10, MR-3, MR+4, MR+4, MR-3, MR-10, MR-18,
MR-18, MR-10, MR-3, MR+4, MR+4, MR-3, MR-10, MR-18,
MR-18, MR-10, MR-3, MR+4, MR+4, MR-3, MR-10, MR-18
// A B C D E F G H
MR-12, MR-7, MR-2, MR+2, MR+2, MR-2, MR-7, MR-12,
MR-12, MR-7, MR-2, MR+2, MR+2, MR-2, MR-7, MR-12,
MR-12, MR-7, MR-2, MR+2, MR+2, MR-2, MR-7, MR-12,
MR-12, MR-7, MR-2, MR+2, MR+2, MR-2, MR-7, MR-12,
MR-12, MR-7, MR-2, MR+2, MR+2, MR-2, MR-7, MR-12,
MR-12, MR-7, MR-2, MR+2, MR+2, MR-2, MR-7, MR-12,
MR-12, MR-7, MR-2, MR+2, MR+2, MR-2, MR-7, MR-12,
MR-12, MR-7, MR-2, MR+2, MR+2, MR-2, MR-7, MR-12
},
{// Queen
//A B C D E F G H
MQ, MQ, MQ, MQ, MQ, MQ, MQ, MQ,
MQ, MQ, MQ, MQ, MQ, MQ, MQ, MQ,
MQ, MQ, MQ, MQ, MQ, MQ, MQ, MQ,
MQ, MQ, MQ, MQ, MQ, MQ, MQ, MQ,
MQ, MQ, MQ, MQ, MQ, MQ, MQ, MQ,
MQ, MQ, MQ, MQ, MQ, MQ, MQ, MQ,
MQ, MQ, MQ, MQ, MQ, MQ, MQ, MQ,
MQ, MQ, MQ, MQ, MQ, MQ, MQ, MQ
// A B C D E F G H
MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8,
MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8,
MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8,
MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8,
MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8,
MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8,
MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8,
MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8
},
{// King
//A B C D E F G H
302, 328, 276, 225, 225, 276, 328, 302,
276, 302, 251, 200, 200, 251, 302, 276,
225, 251, 200, 149, 149, 200, 251, 225,
200, 225, 175, 124, 124, 175, 225, 200,
175, 200, 149, 98, 98, 149, 200, 175,
149, 175, 124, 72, 72, 124, 175, 149,
124, 149, 98, 47, 47, 98, 149, 124,
98, 124, 72, 21, 21, 72, 124, 98
287, 311, 262, 214, 214, 262, 311, 287,
262, 287, 238, 190, 190, 238, 287, 262,
214, 238, 190, 142, 142, 190, 238, 214,
190, 214, 167, 119, 119, 167, 214, 190,
167, 190, 142, 94, 94, 142, 190, 167,
142, 167, 119, 69, 69, 119, 167, 142,
119, 142, 94, 46, 46, 94, 142, 119,
94, 119, 69, 21, 21, 69, 119, 94
}
};
@@ -117,70 +117,70 @@ static const Value EQ = QueenValueEndgame;
static const int EgPST[][64] = {
{ },
{// Pawn
//A B C D E F G H
0, 0, 0, 0, 0, 0, 0, 0,
EP, EP, EP, EP, EP, EP, EP, EP,
EP, EP, EP, EP, EP, EP, EP, EP,
EP, EP, EP, EP, EP, EP, EP, EP,
EP, EP, EP, EP, EP, EP, EP, EP,
EP, EP, EP, EP, EP, EP, EP, EP,
EP, EP, EP, EP, EP, EP, EP, EP,
0, 0, 0, 0, 0, 0, 0, 0
// A B C D E F G H
0, 0, 0, 0, 0, 0, 0, 0,
EP-8, EP-8, EP-8, EP-8, EP-8, EP-8, EP-8, EP-8,
EP-8, EP-8, EP-8, EP-8, EP-8, EP-8, EP-8, EP-8,
EP-8, EP-8, EP-8, EP-8, EP-8, EP-8, EP-8, EP-8,
EP-8, EP-8, EP-8, EP-8, EP-8, EP-8, EP-8, EP-8,
EP-8, EP-8, EP-8, EP-8, EP-8, EP-8, EP-8, EP-8,
EP-8, EP-8, EP-8, EP-8, EP-8, EP-8, EP-8, EP-8,
0, 0, 0, 0, 0, 0, 0, 0
},
{// Knight
// A B C D E F G H
EK-102, EK-76, EK-51, EK-38, EK-38, EK-51, EK-76, EK-102,
EK- 76, EK-51, EK-25, EK-12, EK-12, EK-25, EK-51, EK-76,
EK- 51, EK-25, EK- 0, EK+12, EK+12, EK- 0, EK-25, EK-51,
EK- 38, EK-12, EK+12, EK+25, EK+25, EK+12, EK-12, EK-38,
EK- 38, EK-12, EK+12, EK+25, EK+25, EK+12, EK-12, EK-38,
EK- 51, EK-25, EK- 0, EK+12, EK+12, EK- 0, EK-25, EK-51,
EK- 76, EK-51, EK-25, EK-12, EK-12, EK-25, EK-51, EK-76,
EK-102, EK-76, EK-51, EK-38, EK-38, EK-51, EK-76, EK-102
EK-104, EK-79, EK-55, EK-42, EK-42, EK-55, EK-79, EK-104,
EK- 79, EK-55, EK-30, EK-17, EK-17, EK-30, EK-55, EK- 79,
EK- 55, EK-30, EK- 6, EK+ 5, EK+ 5, EK- 6, EK-30, EK- 55,
EK- 42, EK-17, EK+ 5, EK+18, EK+18, EK+ 5, EK-17, EK- 42,
EK- 42, EK-17, EK+ 5, EK+18, EK+18, EK+ 5, EK-17, EK- 42,
EK- 55, EK-30, EK- 6, EK+ 5, EK+ 5, EK- 6, EK-30, EK- 55,
EK- 79, EK-55, EK-30, EK-17, EK-17, EK-30, EK-55, EK- 79,
EK-104, EK-79, EK-55, EK-42, EK-42, EK-55, EK-79, EK-104
},
{// Bishop
// A B C D E F G H
EB-46, EB-30, EB-23, EB-15, EB-15, EB-23, EB-30, EB-46,
EB-30, EB-15, EB- 7, EB- 0, EB- 0, EB- 7, EB-15, EB-30,
EB-23, EB- 7, EB- 0, EB+ 7, EB+ 7, EB- 0, EB- 7, EB-23,
EB-15, EB- 0, EB+ 7, EB+15, EB+15, EB+ 7, EB- 0, EB-15,
EB-15, EB- 0, EB+ 7, EB+15, EB+15, EB+ 7, EB- 0, EB-15,
EB-23, EB- 7, EB- 0, EB+ 7, EB+ 7, EB- 0, EB- 7, EB-23,
EB-30, EB-15, EB- 7, EB- 0, EB- 0, EB- 7, EB-15, EB-30,
EB-46, EB-30, EB-23, EB-15, EB-15, EB-23, EB-30, EB-46
EB-59, EB-42, EB-35, EB-26, EB-26, EB-35, EB-42, EB-59,
EB-42, EB-26, EB-18, EB-11, EB-11, EB-18, EB-26, EB-42,
EB-35, EB-18, EB-11, EB- 4, EB- 4, EB-11, EB-18, EB-35,
EB-26, EB-11, EB- 4, EB+ 4, EB+ 4, EB- 4, EB-11, EB-26,
EB-26, EB-11, EB- 4, EB+ 4, EB+ 4, EB- 4, EB-11, EB-26,
EB-35, EB-18, EB-11, EB- 4, EB- 4, EB-11, EB-18, EB-35,
EB-42, EB-26, EB-18, EB-11, EB-11, EB-18, EB-26, EB-42,
EB-59, EB-42, EB-35, EB-26, EB-26, EB-35, EB-42, EB-59
},
{// Rook
// A B C D E F G H
ER-3, ER-3, ER-3, ER-3, ER-3, ER-3, ER-3, ER-3,
ER-3, ER-3, ER-3, ER-3, ER-3, ER-3, ER-3, ER-3,
ER-3, ER-3, ER-3, ER-3, ER-3, ER-3, ER-3, ER-3,
ER-3, ER-3, ER-3, ER-3, ER-3, ER-3, ER-3, ER-3,
ER-3, ER-3, ER-3, ER-3, ER-3, ER-3, ER-3, ER-3,
ER-3, ER-3, ER-3, ER-3, ER-3, ER-3, ER-3, ER-3,
ER-3, ER-3, ER-3, ER-3, ER-3, ER-3, ER-3, ER-3,
ER-3, ER-3, ER-3, ER-3, ER-3, ER-3, ER-3, ER-3
ER+3, ER+3, ER+3, ER+3, ER+3, ER+3, ER+3, ER+3,
ER+3, ER+3, ER+3, ER+3, ER+3, ER+3, ER+3, ER+3,
ER+3, ER+3, ER+3, ER+3, ER+3, ER+3, ER+3, ER+3,
ER+3, ER+3, ER+3, ER+3, ER+3, ER+3, ER+3, ER+3,
ER+3, ER+3, ER+3, ER+3, ER+3, ER+3, ER+3, ER+3,
ER+3, ER+3, ER+3, ER+3, ER+3, ER+3, ER+3, ER+3,
ER+3, ER+3, ER+3, ER+3, ER+3, ER+3, ER+3, ER+3,
ER+3, ER+3, ER+3, ER+3, ER+3, ER+3, ER+3, ER+3
},
{// Queen
// A B C D E F G H
EQ-61, EQ-40, EQ-30, EQ-20, EQ-20, EQ-30, EQ-40, EQ-61,
EQ-40, EQ-20, EQ-10, EQ- 0, EQ- 0, EQ-10, EQ-20, EQ-40,
EQ-30, EQ-10, EQ- 0, EQ+10, EQ+10, EQ- 0, EQ-10, EQ-30,
EQ-20, EQ- 0, EQ+10, EQ+20, EQ+20, EQ+10, EQ- 0, EQ-20,
EQ-20, EQ- 0, EQ+10, EQ+20, EQ+20, EQ+10, EQ- 0, EQ-20,
EQ-30, EQ-10, EQ- 0, EQ+10, EQ+10, EQ- 0, EQ-10, EQ-30,
EQ-40, EQ-20, EQ-10, EQ- 0, EQ- 0, EQ-10, EQ-20, EQ-40,
EQ-61, EQ-40, EQ-30, EQ-20, EQ-20, EQ-30, EQ-40, EQ-61
EQ-80, EQ-54, EQ-42, EQ-30, EQ-30, EQ-42, EQ-54, EQ-80,
EQ-54, EQ-30, EQ-18, EQ- 6, EQ- 6, EQ-18, EQ-30, EQ-54,
EQ-42, EQ-18, EQ- 6, EQ+ 6, EQ+ 6, EQ- 6, EQ-18, EQ-42,
EQ-30, EQ- 6, EQ+ 6, EQ+18, EQ+18, EQ+ 6, EQ- 6, EQ-30,
EQ-30, EQ- 6, EQ+ 6, EQ+18, EQ+18, EQ+ 6, EQ- 6, EQ-30,
EQ-42, EQ-18, EQ- 6, EQ+ 6, EQ+ 6, EQ- 6, EQ-18, EQ-42,
EQ-54, EQ-30, EQ-18, EQ- 6, EQ- 6, EQ-18, EQ-30, EQ-54,
EQ-80, EQ-54, EQ-42, EQ-30, EQ-30, EQ-42, EQ-54, EQ-80
},
{// King
//A B C D E F G H
16, 78, 108, 139, 139, 108, 78, 16,
78, 139, 170, 200, 200, 170, 139, 78,
108, 170, 200, 230, 230, 200, 170, 108,
139, 200, 230, 261, 261, 230, 200, 139,
139, 200, 230, 261, 261, 230, 200, 139,
108, 170, 200, 230, 230, 200, 170, 108,
78, 139, 170, 200, 200, 170, 139, 78,
16, 78, 108, 139, 139, 108, 78, 16
18, 77, 105, 135, 135, 105, 77, 18,
77, 135, 165, 193, 193, 165, 135, 77,
105, 165, 193, 222, 222, 193, 165, 105,
135, 193, 222, 251, 251, 222, 193, 135,
135, 193, 222, 251, 251, 222, 193, 135,
105, 165, 193, 222, 222, 193, 165, 105,
77, 135, 165, 193, 193, 165, 135, 77,
18, 77, 105, 135, 135, 105, 77, 18
}
};

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -28,10 +28,11 @@
#include <string>
#include <sstream>
#include "history.h"
#include "movepick.h"
#include "san.h"
extern SearchStack EmptySearchStack;
using std::string;
////
//// Local definitions
@@ -39,8 +40,6 @@ extern SearchStack EmptySearchStack;
namespace {
/// Types
enum Ambiguity {
AMBIGUITY_NONE,
AMBIGUITY_FILE,
@@ -48,12 +47,11 @@ namespace {
AMBIGUITY_BOTH
};
/// Functions
const History H; // used as dummy argument for MovePicker c'tor
Ambiguity move_ambiguity(const Position& pos, Move m);
const std::string time_string(int milliseconds);
const std::string score_string(Value v);
const string time_string(int milliseconds);
const string score_string(Value v);
}
@@ -65,7 +63,7 @@ namespace {
/// that the move is a legal move from the position. The return value is
/// a string containing the move in short algebraic notation.
const std::string move_to_san(const Position& pos, Move m) {
const string move_to_san(const Position& pos, Move m) {
assert(pos.is_ok());
assert(move_is_ok(m));
@@ -77,7 +75,7 @@ const std::string move_to_san(const Position& pos, Move m) {
to = move_to(m);
pt = type_of_piece(pos.piece_on(move_from(m)));
std::string san = "";
string san = "";
if (m == MOVE_NONE)
return "(none)";
@@ -115,10 +113,10 @@ const std::string move_to_san(const Position& pos, Move m) {
san += "x";
}
san += square_to_string(move_to(m));
if (move_promotion(m))
if (move_is_promotion(m))
{
san += '=';
san += piece_type_to_char(move_promotion(m), true);
san += piece_type_to_char(move_promotion_piece(m), true);
}
}
// Is the move check? We don't use pos.move_is_check(m) here, because
@@ -139,11 +137,11 @@ const std::string move_to_san(const Position& pos, Move m) {
/// the move is returned. On failure (i.e. if the string is unparsable, or
/// if the move is illegal or ambiguous), MOVE_NONE is returned.
Move move_from_san(const Position& pos, const std::string& movestr) {
Move move_from_san(const Position& pos, const string& movestr) {
assert(pos.is_ok());
MovePicker mp = MovePicker(pos, false, MOVE_NONE, EmptySearchStack, OnePly);
MovePicker mp = MovePicker(pos, MOVE_NONE, OnePly, H);
// Castling moves
if (movestr == "O-O-O" || movestr == "O-O-O+")
@@ -167,7 +165,7 @@ Move move_from_san(const Position& pos, const std::string& movestr) {
// Normal moves. We use a simple FSM to parse the san string.
enum { START, TO_FILE, TO_RANK, PROMOTION_OR_CHECK, PROMOTION, CHECK, END };
static const std::string pieceLetters = "KQRBN";
static const string pieceLetters = "KQRBN";
PieceType pt = NO_PIECE_TYPE, promotion = NO_PIECE_TYPE;
File fromFile = FILE_NONE, toFile = FILE_NONE;
Rank fromRank = RANK_NONE, toRank = RANK_NONE;
@@ -177,7 +175,7 @@ Move move_from_san(const Position& pos, const std::string& movestr) {
for (size_t i = 0; i < movestr.length(); i++)
{
char type, c = movestr[i];
if (pieceLetters.find(c) != std::string::npos)
if (pieceLetters.find(c) != string::npos)
type = 'P';
else if (c >= 'a' && c <= 'h')
type = 'F';
@@ -275,7 +273,7 @@ Move move_from_san(const Position& pos, const std::string& movestr) {
while ((m = mp.get_next_move()) != MOVE_NONE)
if ( pos.type_of_piece_on(move_from(m)) == pt
&& move_to(m) == to
&& move_promotion(m) == promotion
&& move_promotion_piece(m) == promotion
&& (fromFile == FILE_NONE || fromFile == square_file(move_from(m)))
&& (fromRank == RANK_NONE || fromRank == square_rank(move_from(m))))
{
@@ -293,11 +291,11 @@ Move move_from_san(const Position& pos, const std::string& movestr) {
/// length of 80 characters. After a line break, 'startColumn' spaces are
/// inserted at the beginning of the new line.
const std::string line_to_san(const Position& pos, Move line[], int startColumn, bool breakLines) {
const string line_to_san(const Position& pos, Move line[], int startColumn, bool breakLines) {
StateInfo st;
std::stringstream s;
std::string moveStr;
string moveStr;
size_t length = 0;
size_t maxLength = 80 - startColumn;
Position p(pos);
@@ -326,8 +324,8 @@ const std::string line_to_san(const Position& pos, Move line[], int startColumn,
/// It is used to write search information to the log file (which is created
/// when the UCI parameter "Use Search Log" is "true").
const std::string pretty_pv(const Position& pos, int time, int depth,
uint64_t nodes, Value score, Move pv[]) {
const string pretty_pv(const Position& pos, int time, int depth,
uint64_t nodes, Value score, Move pv[]) {
std::stringstream s;
// Depth
@@ -367,7 +365,7 @@ namespace {
if (type_of_piece(pc) == KING)
return AMBIGUITY_NONE;
MovePicker mp = MovePicker(pos, false, MOVE_NONE, EmptySearchStack, OnePly);
MovePicker mp = MovePicker(pos, MOVE_NONE, OnePly, H);
Move mv, moveList[8];
int n = 0;
@@ -397,7 +395,7 @@ namespace {
}
const std::string time_string(int milliseconds) {
const string time_string(int milliseconds) {
std::stringstream s;
s << std::setfill('0');
@@ -414,7 +412,7 @@ namespace {
}
const std::string score_string(Value v) {
const string score_string(Value v) {
std::stringstream s;

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -26,12 +26,7 @@
////
#include "depth.h"
#include "history.h"
#include "lock.h"
#include "movegen.h"
#include "position.h"
#include "tt.h"
#include "value.h"
#include "move.h"
////
@@ -65,26 +60,13 @@ struct SearchStack {
};
////
//// Global variables
////
extern SearchStack EmptySearchStack;
extern TranspositionTable TT;
extern int ActiveThreads;
extern Lock SMPLock;
// Perhaps better to make H local, and pass as parameter to MovePicker?
extern History H;
////
//// Prototypes
////
extern void init_threads();
extern void stop_threads();
extern void 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 maxNodes, int maxTime, Move searchMoves[]);
extern int64_t nodes_searched();

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -66,13 +66,14 @@ struct Thread {
SplitPoint *splitPoint;
int activeSplitPoints;
uint64_t nodes;
uint64_t betaCutOffs[2];
bool failHighPly1;
volatile bool stop;
volatile bool running;
volatile bool idle;
volatile bool workIsWaiting;
volatile bool printCurrentLine;
unsigned char pad[64];
unsigned char pad[64]; // set some distance among local data for each thread
};

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -69,7 +69,7 @@ void TranspositionTable::set_size(unsigned mbSize) {
{
std::cerr << "Failed to allocate " << mbSize
<< " MB for transposition table." << std::endl;
exit(EXIT_FAILURE);
Application::exit_with_failure();
}
clear();
}
@@ -97,14 +97,14 @@ void TranspositionTable::clear() {
/// is bigger than the depth of t2. A TTEntry of type VALUE_TYPE_EVAL
/// never replaces another entry for the same position.
void TranspositionTable::store(const Position& p, Value v, ValueType t, Depth d, Move m) {
void TranspositionTable::store(const Key posKey, Value v, ValueType t, Depth d, Move m) {
TTEntry *tte, *replace;
tte = replace = first_entry(p);
tte = replace = first_entry(posKey);
for (int i = 0; i < 4; i++, tte++)
{
if (!tte->key() || tte->key() == p.get_key()) // empty or overwrite old
if (!tte->key() || tte->key() == posKey) // empty or overwrite old
{
// Do not overwrite when new type is VALUE_TYPE_EVAL
if (tte->key() && t == VALUE_TYPE_EVAL)
@@ -113,7 +113,7 @@ void TranspositionTable::store(const Position& p, Value v, ValueType t, Depth d,
if (m == MOVE_NONE)
m = tte->move();
*tte = TTEntry(p.get_key(), v, t, d, m, generation);
*tte = TTEntry(posKey, v, t, d, m, generation);
return;
}
else if (i == 0) // replace would be a no-op in this common case
@@ -126,7 +126,7 @@ void TranspositionTable::store(const Position& p, Value v, ValueType t, Depth d,
if (c1 + c2 + c3 > 0)
replace = tte;
}
*replace = TTEntry(p.get_key(), v, t, d, m, generation);
*replace = TTEntry(posKey, v, t, d, m, generation);
writes++;
}
@@ -135,12 +135,12 @@ void TranspositionTable::store(const Position& p, Value v, ValueType t, Depth d,
/// transposition table. Returns a pointer to the TTEntry or NULL
/// if position is not found.
TTEntry* TranspositionTable::retrieve(const Position& pos) const {
TTEntry* TranspositionTable::retrieve(const Key posKey) const {
TTEntry *tte = first_entry(pos);
TTEntry *tte = first_entry(posKey);
for (int i = 0; i < 4; i++, tte++)
if (tte->key() == pos.get_key())
if (tte->key() == posKey)
return tte;
return NULL;
@@ -150,9 +150,9 @@ TTEntry* TranspositionTable::retrieve(const Position& pos) const {
/// TranspositionTable::first_entry returns a pointer to the first
/// entry of a cluster given a position.
inline TTEntry* TranspositionTable::first_entry(const Position& pos) const {
inline TTEntry* TranspositionTable::first_entry(const Key posKey) const {
return entries + (int(pos.get_key() & (size - 1)) << 2);
return entries + (int(posKey & (size - 1)) << 2);
}
/// TranspositionTable::new_search() is called at the beginning of every new
@@ -179,7 +179,7 @@ void TranspositionTable::insert_pv(const Position& pos, Move pv[]) {
for (int i = 0; pv[i] != MOVE_NONE; i++)
{
store(p, VALUE_NONE, VALUE_TYPE_NONE, Depth(-127*OnePly), pv[i]);
store(p.get_key(), VALUE_NONE, VALUE_TYPE_NONE, Depth(-127*OnePly), pv[i]);
p.do_move(pv[i], st);
}
}

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -83,16 +83,22 @@ public:
~TranspositionTable();
void set_size(unsigned mbSize);
void clear();
void store(const Position& pos, Value v, ValueType type, Depth d, Move m);
TTEntry* retrieve(const Position& pos) const;
void store(const Key posKey, Value v, ValueType type, Depth d, Move m);
TTEntry* retrieve(const Key posKey) const;
void new_search();
void insert_pv(const Position& pos, Move pv[]);
int full() const;
private:
inline TTEntry* first_entry(const Position& pos) const;
inline TTEntry* first_entry(const Key posKey) const;
unsigned size, writes;
// Be sure 'writes' is at least one cacheline away
// from read only variables.
unsigned char pad_before[64 - sizeof(unsigned)];
unsigned writes; // heavy SMP read/write access here
unsigned char pad_after[64];
unsigned size;
TTEntry* entries;
uint8_t generation;
};

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -41,7 +41,29 @@ typedef __int64 int64_t;
#endif // !defined(_MSC_VER)
// Hash keys:
// Hash keys
typedef uint64_t Key;
// Bitboard type
typedef uint64_t Bitboard;
////
//// Compiler specific defines
////
// Quiet a warning on Intel compiler
#if !defined(__SIZEOF_INT__ )
#define __SIZEOF_INT__ 0
#endif
// Check for 64 bits for different compilers: Intel, MSVC and gcc
#if defined(__x86_64) || defined(_M_X64) || defined(_WIN64) || (__SIZEOF_INT__ > 4)
#define IS_64BIT
#endif
#if defined(IS_64BIT) && !defined(_WIN64) && (defined(__GNUC__) || defined(__INTEL_COMPILER))
#define USE_BSFQ
#endif
#endif // !defined(TYPES_H_INCLUDED)

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -38,6 +38,7 @@
#include "uci.h"
#include "ucioption.h"
using namespace std;
////
//// Local definitions:
@@ -45,22 +46,21 @@
namespace {
// UCIInputParser is a class for parsing UCI input. The class
// UCIInputParser is a class for parsing UCI input. The class
// is actually a string stream built on a given input string.
typedef std::istringstream UCIInputParser;
typedef istringstream UCIInputParser;
// The root position. This is set up when the user (or in practice, the GUI)
// sends the "position" UCI command. The root position is sent to the think()
// The root position. This is set up when the user (or in practice, the GUI)
// sends the "position" UCI command. The root position is sent to the think()
// function when the program receives the "go" command.
Position RootPosition;
// Local functions
void get_command();
void handle_command(const std::string &command);
void set_option(UCIInputParser &uip);
void set_position(UCIInputParser &uip);
void go(UCIInputParser &uip);
bool handle_command(const string& command);
void set_option(UCIInputParser& uip);
void set_position(UCIInputParser& uip);
bool go(UCIInputParser& uip);
}
@@ -68,17 +68,25 @@ namespace {
//// Functions
////
/// uci_main_loop() is the only global function in this file. It is
/// uci_main_loop() is the only global function in this file. It is
/// called immediately after the program has finished initializing.
/// The program remains in this loop until it receives the "quit" UCI
/// command.
/// command. It waits for a command from the user, and passes this
/// command to handle_command and also intercepts EOF from stdin,
/// by translating EOF to the "quit" command. This ensures that Stockfish
/// exits gracefully if the GUI dies unexpectedly.
void uci_main_loop() {
RootPosition.from_fen(StartPosition);
string command;
while (1)
get_command();
do {
// Wait for a command from stdin
if (!getline(cin, command))
command = "quit";
} while (handle_command(command));
}
@@ -88,64 +96,43 @@ void uci_main_loop() {
namespace {
// get_command() waits for a command from the user, and passes
// this command to handle_command. get_command also intercepts
// EOF from stdin, by translating EOF to the "quit" command. This
// ensures that Stockfish exits gracefully if the GUI dies
// unexpectedly.
void get_command() {
std::string command;
if (!std::getline(std::cin, command))
command = "quit";
handle_command(command);
}
// handle_command() takes a text string as input, uses a
// UCIInputParser object to parse this text string as a UCI command,
// and calls the appropriate functions. In addition to the UCI
// and calls the appropriate functions. In addition to the UCI
// commands, the function also supports a few debug commands.
void handle_command(const std::string &command) {
bool handle_command(const string& command) {
UCIInputParser uip(command);
std::string token;
string token;
uip >> token; // operator >> skips any whitespace
uip >> token; // operator>>() skips any whitespace
if (token == "quit")
return false;
if (token == "go")
return go(uip);
if (token == "uci")
{
OpeningBook.close();
stop_threads();
quit_eval();
exit(0);
}
else if (token == "uci")
{
std::cout << "id name " << engine_name() << std::endl
<< "id author Tord Romstad, Marco Costalba"
<< std::endl;
cout << "id name " << engine_name()
<< "\nid author Tord Romstad, Marco Costalba, Joona Kiiski\n";
print_uci_options();
std::cout << "uciok" << std::endl;
cout << "uciok" << endl;
}
else if (token == "ucinewgame")
{
TT.clear();
push_button("Clear Hash");
Position::init_piece_square_tables();
RootPosition.from_fen(StartPosition);
}
else if (token == "isready")
std::cout << "readyok" << std::endl;
cout << "readyok" << endl;
else if (token == "position")
set_position(uip);
else if (token == "setoption")
set_option(uip);
else if (token == "go")
go(uip);
// The remaining commands are for debugging purposes only.
// Perhaps they should be removed later in order to reduce the
@@ -160,55 +147,49 @@ namespace {
else if (token == "eval")
{
EvalInfo ei;
std::cout << "Incremental mg: " << RootPosition.mg_value()
<< std::endl;
std::cout << "Incremental eg: " << RootPosition.eg_value()
<< std::endl;
std::cout << "Full eval: "
<< evaluate(RootPosition, ei, 0)
<< std::endl;
cout << "Incremental mg: " << RootPosition.mg_value()
<< "\nIncremental eg: " << RootPosition.eg_value()
<< "\nFull eval: " << evaluate(RootPosition, ei, 0) << endl;
}
else if (token == "key")
{
std::cout << "key: " << std::hex << RootPosition.get_key()
<< " material key: " << RootPosition.get_material_key()
<< " pawn key: " << RootPosition.get_pawn_key()
<< std::endl;
}
cout << "key: " << hex << RootPosition.get_key()
<< "\nmaterial key: " << RootPosition.get_material_key()
<< "\npawn key: " << RootPosition.get_pawn_key() << endl;
else
{
std::cout << "Unknown command: " << command << std::endl;
cout << "Unknown command: " << command << endl;
while (!uip.eof())
{
uip >> token;
std::cout << token << std::endl;
cout << token << endl;
}
}
return true;
}
// set_position() is called when Stockfish receives the "position" UCI
// command. The input parameter is a UCIInputParser. It is assumed
// command. The input parameter is a UCIInputParser. It is assumed
// that this parser has consumed the first token of the UCI command
// ("position"), and is ready to read the second token ("startpos"
// or "fen", if the input is well-formed).
void set_position(UCIInputParser &uip) {
void set_position(UCIInputParser& uip) {
std::string token;
string token;
uip >> token; // operator >> skips any whitespace
uip >> token; // operator>>() skips any whitespace
if (token == "startpos")
RootPosition.from_fen(StartPosition);
else if (token == "fen")
{
std::string fen;
string fen;
while (token != "moves" && !uip.eof())
{
uip >> token;
fen += token;
fen += ' ';
uip >> token;
fen += token;
fen += ' ';
}
RootPosition.from_fen(fen);
}
@@ -229,23 +210,23 @@ namespace {
if (RootPosition.rule_50_counter() == 0)
RootPosition.reset_game_ply();
}
// Our StateInfo st is about going out of scope,
// so save its content before they disappear.
RootPosition.setStartState(st);
// Our StateInfo st is about going out of scope so copy
// its content inside RootPosition before they disappear.
RootPosition.saveState();
}
}
}
// set_option() is called when Stockfish receives the "setoption" UCI
// command. The input parameter is a UCIInputParser. It is assumed
// command. The input parameter is a UCIInputParser. It is assumed
// that this parser has consumed the first token of the UCI command
// ("setoption"), and is ready to read the second token ("name", if
// the input is well-formed).
void set_option(UCIInputParser &uip) {
void set_option(UCIInputParser& uip) {
std::string token, name;
string token, name;
uip >> token;
if (token == "name")
@@ -261,7 +242,7 @@ namespace {
}
if (token == "value")
{
std::getline(uip, token); // reads until end of line
getline(uip, token); // reads until end of line
set_option_value(name, token);
} else
push_button(name);
@@ -269,17 +250,18 @@ namespace {
}
// go() is called when Stockfish receives the "go" UCI command. The
// input parameter is a UCIInputParser. It is assumed that this
// go() is called when Stockfish receives the "go" UCI command. The
// input parameter is a UCIInputParser. It is assumed that this
// parser has consumed the first token of the UCI command ("go"),
// and is ready to read the second token. The function sets the
// and is ready to read the second token. The function sets the
// thinking time and other parameters from the input string, and
// calls think() (defined in search.cpp) with the appropriate
// parameters.
// parameters. Returns false if a quit command is received while
// thinking, returns true otherwise.
void go(UCIInputParser &uip) {
bool go(UCIInputParser& uip) {
std::string token;
string token;
int time[2] = {0, 0}, inc[2] = {0, 0};
int movesToGo = 0, depth = 0, nodes = 0, moveTime = 0;
@@ -329,7 +311,8 @@ namespace {
assert(RootPosition.is_ok());
think(RootPosition, infinite, ponder, RootPosition.side_to_move(), time,
inc, movesToGo, depth, nodes, moveTime, searchMoves);
return think(RootPosition, infinite, ponder, RootPosition.side_to_move(),
time, inc, movesToGo, depth, nodes, moveTime, searchMoves);
}
}

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -33,13 +33,7 @@
#include "thread.h"
#include "ucioption.h"
////
//// Variables
////
bool Chess960;
using std::string;
////
//// Local definitions
@@ -53,11 +47,11 @@ namespace {
enum OptionType { SPIN, COMBO, CHECK, STRING, BUTTON };
typedef std::vector<std::string> ComboValues;
typedef std::vector<string> ComboValues;
struct Option {
std::string name, defaultValue, currentValue;
string name, defaultValue, currentValue;
OptionType type;
size_t idx;
int minValue, maxValue;
@@ -71,7 +65,7 @@ namespace {
bool operator<(const Option& o) const { return this->idx < o.idx; }
};
typedef std::map<std::string, Option> Options;
typedef std::map<string, Option> Options;
///
/// Constants
@@ -125,8 +119,6 @@ namespace {
o["Full Depth Moves (PV nodes)"] = Option(14, 1, 100);
o["Full Depth Moves (non-PV nodes)"] = Option(3, 1, 100);
o["Threat Depth"] = Option(5, 0, 100);
o["Futility Pruning (Main Search)"] = Option(true);
o["Futility Pruning (Quiescence Search)"] = Option(true);
o["LSN filtering"] = Option(false);
o["LSN Time Margin (sec)"] = Option(4, 1, 10);
o["LSN Value Margin"] = Option(200, 100, 600);
@@ -155,7 +147,7 @@ namespace {
// stringify converts a value of type T to a std::string
template<typename T>
std::string stringify(const T& v) {
string stringify(const T& v) {
std::ostringstream ss;
ss << v;
@@ -168,7 +160,7 @@ namespace {
// type changes a template seems a proper solution.
template<typename T>
T get_option_value(const std::string& optionName) {
T get_option_value(const string& optionName) {
T ret = T();
if (options.find(optionName) == options.end())
@@ -245,9 +237,7 @@ void print_uci_options() {
std::cout << " default " << it->defaultValue;
if (it->type == SPIN)
std::cout << " min " << it->minValue
<< " max " << it->maxValue;
std::cout << " min " << it->minValue << " max " << it->maxValue;
else if (it->type == COMBO)
for (ComboValues::const_iterator itc = it->comboValues.begin();
itc != it->comboValues.end(); ++itc)
@@ -260,7 +250,7 @@ void print_uci_options() {
/// get_option_value_bool() returns the current value of a UCI parameter of
/// type "check".
bool get_option_value_bool(const std::string& optionName) {
bool get_option_value_bool(const string& optionName) {
return get_option_value<bool>(optionName);
}
@@ -271,7 +261,7 @@ bool get_option_value_bool(const std::string& optionName) {
/// it could also be used with a "combo" parameter, where all the available
/// values are integers.
int get_option_value_int(const std::string& optionName) {
int get_option_value_int(const string& optionName) {
return get_option_value<int>(optionName);
}
@@ -280,9 +270,9 @@ int get_option_value_int(const std::string& optionName) {
/// get_option_value_string() returns the current value of a UCI parameter as
/// a string. It is used with parameters of type "combo" and "string".
const std::string get_option_value_string(const std::string& optionName) {
string get_option_value_string(const string& optionName) {
return get_option_value<std::string>(optionName);
return get_option_value<string>(optionName);
}
@@ -290,28 +280,27 @@ const std::string get_option_value_string(const std::string& optionName) {
/// the function does not check that the new value is legal for the given
/// parameter: This is assumed to be the responsibility of the GUI.
void set_option_value(const std::string& optionName,
const std::string& newValue) {
void set_option_value(const string& name, const string& value) {
// UCI protocol uses "true" and "false" instead of "1" and "0", so convert
// newValue according to standard C++ convention before to store it.
std::string v(newValue);
// value according to standard C++ convention before to store it.
string v(value);
if (v == "true")
v = "1";
else if (v == "false")
v = "0";
if (options.find(optionName) != options.end())
options[optionName].currentValue = v;
if (options.find(name) != options.end())
options[name].currentValue = v;
else
std::cout << "No such option: " << optionName << std::endl;
std::cout << "No such option: " << name << std::endl;
}
/// push_button() is used to tell the engine that a UCI parameter of type
/// "button" has been selected:
void push_button(const std::string& buttonName) {
void push_button(const string& buttonName) {
set_option_value(buttonName, "true");
}
@@ -321,7 +310,7 @@ void push_button(const std::string& buttonName) {
/// been selected since the last time the function was called, in this case
/// it also resets the button.
bool button_was_pressed(const std::string& buttonName) {
bool button_was_pressed(const string& buttonName) {
if (!get_option_value<bool>(buttonName))
return false;

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -27,27 +27,18 @@
#include <string>
////
//// Variables
////
extern bool Chess960;
////
//// Prototypes
////
extern void init_uci_options();
extern void print_uci_options();
extern bool get_option_value_bool(const std::string &optionName);
extern int get_option_value_int(const std::string &optionName);
extern const std::string get_option_value_string(const std::string &optionName);
extern bool button_was_pressed(const std::string &buttonName);
extern void set_option_value(const std::string &optionName,
const std::string &newValue);
extern void push_button(const std::string &buttonName);
extern bool get_option_value_bool(const std::string& optionName);
extern int get_option_value_int(const std::string& optionName);
extern std::string get_option_value_string(const std::string& optionName);
extern bool button_was_pressed(const std::string& buttonName);
extern void set_option_value(const std::string& optionName,const std::string& newValue);
extern void push_button(const std::string& buttonName);
#endif // !defined(UCIOPTION_H_INCLUDED)

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba
Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -62,16 +62,16 @@ enum Value {
///
/// Values modified by Joona Kiiski
const Value PawnValueMidgame = Value(0x0CC);
const Value PawnValueEndgame = Value(0x101);
const Value KnightValueMidgame = Value(0x332);
const Value PawnValueMidgame = Value(0x0C6);
const Value PawnValueEndgame = Value(0x102);
const Value KnightValueMidgame = Value(0x331);
const Value KnightValueEndgame = Value(0x34E);
const Value BishopValueMidgame = Value(0x345);
const Value BishopValueEndgame = Value(0x356);
const Value RookValueMidgame = Value(0x4F8);
const Value RookValueEndgame = Value(0x500);
const Value QueenValueMidgame = Value(0x9D5);
const Value QueenValueEndgame = Value(0x9FB);
const Value BishopValueMidgame = Value(0x344);
const Value BishopValueEndgame = Value(0x359);
const Value RookValueMidgame = Value(0x4F6);
const Value RookValueEndgame = Value(0x4FE);
const Value QueenValueMidgame = Value(0x9D9);
const Value QueenValueEndgame = Value(0x9FE);
const Value PieceValueMidgame[17] = {
Value(0),
@@ -93,7 +93,7 @@ const Value PieceValueEndgame[17] = {
Value(0), Value(0), Value(0)
};
/// Bonus for having the side to move
/// Bonus for having the side to move (modified by Joona Kiiski)
const Value TempoValueMidgame = Value(48);
const Value TempoValueEndgame = Value(21);