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". UCI parameter "Book File".
4. Compiling it yourself 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 The exception is computer with big-endian CPUs, like PowerPC
Macintoshes. Some of the bitboard routines in the current version of Macintoshes. Some of the bitboard routines in the current version of
Stockfish are endianness-sensitive, and won't work on a big-endian CPU. 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 Stockfish has POPCNT instruction runtime detection and support. This can
systems, regardless of the endianness. If Stockfish segfaults give an extra speed on Core i7 or similar systems. To enable this feature
immediately after startup, try to comment out the line with (disabled by default) simply uncomment #define USE_POPCNT in bitcount.h
"#define USE_FOLDED_BITSCAN" near the beginning of bitboard.h and before to compile.
recompile.
Finally, even if Stockfish does work without any changes on your On 64 bit Unix-like systems the 'bsfq' assembly instruction will be used
computer, it might be possible to improve the performance by changing for bit counting. Detection is automatic at compile time, but in case you
some of the #define directives in bitboard.h. The default settings experience compile problems you can comment out #define USE_BSFQ line in types.h
are optimized for 64-bit CPUs. On 32-bit CPUs, it is probably better
to switch on USE_32BIT_ATTACKS, and to use BITCOUNT_SWAR_32 instead of
BITCOUNT_SWAR_64. For computers with very little memory (like
handheld devices), it is possible to conserve memory by defining
USE_COMPACT_ROOK_ATTACKS.
6. Terms of use 5. Terms of use
--------------- ---------------
Stockfish is free, and distributed under the GNU General Public License 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. Copying.txt.
7. Feedback 6. Feedback
----------- -----------
The author's e-mail address is mcostalba@gmail.com The author's e-mail address is mcostalba@gmail.com

View File

@@ -24,7 +24,7 @@
EXE = stockfish 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 \ misc.o move.o movegen.o history.o movepick.o search.o piece.o \
position.o direction.o tt.o value.o uci.o ucioption.o \ position.o direction.o tt.o value.o uci.o ucioption.o \
mersenne.o book.o bitbase.o san.o benchmark.o mersenne.o book.o bitbase.o san.o benchmark.o
@@ -44,9 +44,8 @@ clean:
### Compiler: ### Compiler:
### ###
# CXX = g++ CXX = g++
# CXX = g++-4.2 # CXX = icpc
CXX = icpc
### ###
@@ -66,24 +65,25 @@ include .depend
### Compiler and linker switches ### Compiler and linker switches
### ###
# Enable/disable debugging: # Enable/disable debugging, disabled by default
CXXFLAGS += -DNDEBUG 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. # 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 # 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: # 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 # 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 # 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 # 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 # 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 # wait 15 minutes for the benchmark to complete). Then do a 'make clean', and
# recompile with -prof_use. # recompile with -prof_use.
# CXXFLAGS += -prof_gen -prof_dir profdata # CXXFLAGS += -prof-gen -prof-dir./profdata
# CXXFLAGS += -prof_use -prof_dir ./profdata # CXXFLAGS += -prof-use -ipo -prof_dir./profdata
# Profiler guided optimization with GCC. I've never been able to make this # 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 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -30,12 +30,13 @@
#include "thread.h" #include "thread.h"
#include "ucioption.h" #include "ucioption.h"
using namespace std;
//// ////
//// Variables //// Variables
//// ////
const std::string BenchmarkPositions[] = { const string BenchmarkPositions[] = {
"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1", "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1",
"r4rk1/1b2qppp/p1n1p3/1p6/1b1PN3/3BRN2/PP3PPP/R2Q2K1 b - - 7 16", "r4rk1/1b2qppp/p1n1p3/1p6/1b1PN3/3BRN2/PP3PPP/R2Q2K1 b - - 7 16",
"4r1k1/ppq3pp/3b4/2pP4/2Q1p3/4B1P1/PP5P/R5K1 b - - 0 20", "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). /// format (default are the BenchmarkPositions defined above).
/// The analysis is written to a file named bench.txt. /// 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); istringstream csVal(commandLine);
std::istringstream csStr(commandLine); istringstream csStr(commandLine);
std::string ttSize, threads, fileName, limitType; string ttSize, threads, fileName, limitType, timFile;
int val, secsPerPos, maxDepth, maxNodes; int val, secsPerPos, maxDepth, maxNodes;
csStr >> ttSize; csStr >> ttSize;
csVal >> val; csVal >> val;
if (val < 4 || val > 1024) if (val < 4 || val > 1024)
{ {
std::cerr << "The hash table size must be between 4 and 1024" << std::endl; cerr << "The hash table size must be between 4 and 1024" << endl;
exit(EXIT_FAILURE); Application::exit_with_failure();
} }
csStr >> threads; csStr >> threads;
csVal >> val; csVal >> val;
if (val < 1 || val > THREAD_MAX) if (val < 1 || val > THREAD_MAX)
{ {
std::cerr << "The number of threads must be between 1 and " << THREAD_MAX cerr << "The number of threads must be between 1 and " << THREAD_MAX << endl;
<< std::endl; Application::exit_with_failure();
exit(EXIT_FAILURE);
} }
set_option_value("Hash", ttSize); set_option_value("Hash", ttSize);
set_option_value("Threads", threads); set_option_value("Threads", threads);
@@ -98,6 +98,7 @@ void benchmark(const std::string& commandLine) {
csVal >> val; csVal >> val;
csVal >> fileName; csVal >> fileName;
csVal >> limitType; csVal >> limitType;
csVal >> timFile;
secsPerPos = maxDepth = maxNodes = 0; secsPerPos = maxDepth = maxNodes = 0;
@@ -108,44 +109,71 @@ void benchmark(const std::string& commandLine) {
else else
maxNodes = val; maxNodes = val;
std::vector<std::string> positions; vector<string> positions;
if (fileName != "default") if (fileName != "default")
{ {
std::ifstream fenFile(fileName.c_str()); ifstream fenFile(fileName.c_str());
if (!fenFile.is_open()) if (!fenFile.is_open())
{ {
std::cerr << "Unable to open positions file " << fileName cerr << "Unable to open positions file " << fileName << endl;
<< std::endl; Application::exit_with_failure();
exit(EXIT_FAILURE);
} }
std::string pos; string pos;
while (fenFile.good()) while (fenFile.good())
{ {
std::getline(fenFile, pos); getline(fenFile, pos);
if (!pos.empty()) if (!pos.empty())
positions.push_back(pos); positions.push_back(pos);
} }
fenFile.close(); fenFile.close();
} else } else
for (int i = 0; i < 16; i++) 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(); ofstream timingFile;
std::vector<std::string>::iterator it; 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; int cnt = 1;
int64_t totalNodes = 0; int64_t totalNodes = 0;
int startTime = get_system_time();
for (it = positions.begin(); it != positions.end(); ++it, ++cnt) for (it = positions.begin(); it != positions.end(); ++it, ++cnt)
{ {
Move moves[1] = {MOVE_NONE}; Move moves[1] = {MOVE_NONE};
int dummy[2] = {0, 0}; int dummy[2] = {0, 0};
Position pos(*it); Position pos(*it);
std::cout << "\nProcessing position " << cnt << '/' << positions.size() << std::endl << std::endl; cerr << "\nBench position: " << cnt << '/' << positions.size() << endl << endl;
think(pos, true, false, 0, dummy, dummy, 0, maxDepth, maxNodes, secsPerPos, moves); if (!think(pos, true, false, 0, dummy, dummy, 0, maxDepth, maxNodes, secsPerPos, moves))
break;
totalNodes += nodes_searched(); totalNodes += nodes_searched();
} }
std::cout << "\nProcessing time (ms) " << get_system_time() - startTime << std::endl
<< "Nodes searched " << totalNodes << std::endl cnt = get_system_time() - startTime;
<< "Press any key to exit" << std::endl; cerr << "==============================="
std::cin >> fileName; << "\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 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by

View File

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

View File

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

View File

@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -22,137 +22,14 @@
//// Includes //// Includes
//// ////
#ifdef _MSC_VER
#include <intrin.h>
#ifdef _WIN64
#pragma intrinsic(_BitScanForward64)
#else
#pragma intrinsic(_BitScanForward)
#endif
#define USING_INTRINSICS
#endif
#include <iostream> #include <iostream>
#include "bitboard.h" #include "bitboard.h"
#include "bitcount.h"
#include "direction.h" #include "direction.h"
#if defined(USE_COMPACT_ROOK_ATTACKS) #if defined(IS_64BIT)
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)
const uint64_t BMult[64] = { const uint64_t BMult[64] = {
0x440049104032280ULL, 0x1021023c82008040ULL, 0x404040082000048ULL, 0x440049104032280ULL, 0x1021023c82008040ULL, 0x404040082000048ULL,
@@ -179,6 +56,31 @@ const uint64_t BMult[64] = {
0xa08520292120600ULL 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] = { const int BShift[64] = {
58, 59, 59, 59, 59, 59, 59, 58, 59, 59, 59, 59, 59, 59, 59, 59, 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, 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 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]; Bitboard BMask[64];
int BAttackIndex[64]; int BAttackIndex[64];
@@ -225,9 +205,6 @@ namespace {
const int shift[2], const Bitboard mult[], const int shift[2], const Bitboard mult[],
int deltas[][2]); int deltas[][2]);
void init_pseudo_attacks(); 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_ray_bitboards();
init_attacks(); init_attacks();
init_between_bitboards(); init_between_bitboards();
#if defined(USE_COMPACT_ROOK_ATTACKS) init_sliding_attacks(RAttacks, RAttackIndex, RMask, RShift, RMult, rookDeltas);
init_file_and_rank_attacks(); init_sliding_attacks(BAttacks, BAttackIndex, BMask, BShift, BMult, bishopDeltas);
#else
init_sliding_attacks(RAttacks, RAttackIndex, RMask, RShift,
RMult, rookDeltas);
#endif
init_sliding_attacks(BAttacks, BAttackIndex, BMask, BShift,
BMult, bishopDeltas);
init_pseudo_attacks(); 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. /// 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 /// pop_1st_bit() finds and clears the least significant nonzero bit in a
/// nonzero bitboard. /// nonzero bitboard.
#if defined(USE_32BIT_ATTACKS) #if defined(IS_64BIT) && !defined(USE_BSFQ)
// 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
static const int BitTable[64] = { 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, 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 51, 60, 42, 59, 58
}; };
/// first_1() finds the least significant nonzero bit in a nonzero bitboard.
Square first_1(Bitboard b) { Square first_1(Bitboard b) {
return Square(BitTable[((b & -b) * 0x218a392cd3d5dbfULL) >> 58]); return Square(BitTable[((b & -b) * 0x218a392cd3d5dbfULL) >> 58]);
} }
Square pop_1st_bit(Bitboard* b) {
/// pop_1st_bit() finds and clears the least significant nonzero bit in a
/// nonzero bitboard.
Square pop_1st_bit(Bitboard *b) {
Bitboard bb = *b; Bitboard bb = *b;
*b &= (*b - 1); *b &= (*b - 1);
return Square(BitTable[((bb & -bb) * 0x218a392cd3d5dbfULL) >> 58]); 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 { namespace {
@@ -480,25 +427,25 @@ namespace {
attackIndex[i] = index; attackIndex[i] = index;
mask[i] = sliding_attacks(i, 0ULL, 4, deltas, 1, 6, 1, 6); mask[i] = sliding_attacks(i, 0ULL, 4, deltas, 1, 6, 1, 6);
#if defined(USE_32BIT_ATTACKS) #if defined(IS_64BIT)
j = (1 << (32 - shift[i]));
#else
j = (1 << (64 - shift[i])); j = (1 << (64 - shift[i]));
#else
j = (1 << (32 - shift[i]));
#endif #endif
for(k = 0; k < j; k++) { 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]); b = index_to_bitboard(k, mask[i]);
attacks[index + attacks[index +
(unsigned(int(b) * int(mult[i]) ^ (unsigned(int(b) * int(mult[i]) ^
int(b >> 32) * int(mult[i] >> 32)) int(b >> 32) * int(mult[i] >> 32))
>> shift[i])] = >> shift[i])] =
sliding_attacks(i, b, 4, deltas); 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 #endif
} }
index += j; 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 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -22,43 +22,6 @@
#if !defined(BITBOARD_H_INCLUDED) #if !defined(BITBOARD_H_INCLUDED)
#define 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 //// Includes
//// ////
@@ -69,13 +32,6 @@
#include "types.h" #include "types.h"
////
//// Types
////
typedef uint64_t Bitboard;
//// ////
//// Constants and variables //// Constants and variables
//// ////
@@ -160,20 +116,12 @@ extern Bitboard BetweenBB[64][64];
extern Bitboard PassedPawnMask[2][64]; extern Bitboard PassedPawnMask[2][64];
extern Bitboard OutpostMask[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 uint64_t RMult[64];
extern const int RShift[64]; extern const int RShift[64];
extern Bitboard RMask[64]; extern Bitboard RMask[64];
extern int RAttackIndex[64]; extern int RAttackIndex[64];
extern Bitboard RAttacks[0x19000]; extern Bitboard RAttacks[0x19000];
#endif // defined(USE_COMPACT_ROOK_ATTACKS)
extern const uint64_t BMult[64]; extern const uint64_t BMult[64];
extern const int BShift[64]; extern const int BShift[64];
extern Bitboard BMask[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 /// 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 /// file or rank. It is also possible to pass a square as input to these
/// functions. /// 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 /// bishop_attacks_bb() and queen_attacks_bb() all take a square and a
/// bitboard of occupied squares as input, and return a bitboard representing /// bitboard of occupied squares as input, and return a bitboard representing
/// all squares attacked by a rook, bishop or queen on the given square. /// all squares attacked by a rook, bishop or queen on the given square.
#if defined(USE_COMPACT_ROOK_ATTACKS) #if defined(IS_64BIT)
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);
}
inline Bitboard rook_attacks_bb(Square s, Bitboard blockers) { 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) { inline Bitboard rook_attacks_bb(Square s, Bitboard blockers) {
Bitboard b = blockers & RMask[s]; Bitboard b = blockers & RMask[s];
@@ -330,17 +284,6 @@ inline Bitboard rook_attacks_bb(Square s, Bitboard blockers) {
>> RShift[s])]; >> 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) { inline Bitboard bishop_attacks_bb(Square s, Bitboard blockers) {
Bitboard b = blockers & BMask[s]; Bitboard b = blockers & BMask[s];
return BAttacks[BAttackIndex[s] + return BAttacks[BAttackIndex[s] +
@@ -349,14 +292,7 @@ inline Bitboard bishop_attacks_bb(Square s, Bitboard blockers) {
>> BShift[s])]; >> BShift[s])];
} }
#else // defined(USE_32BIT_ATTACKS) #endif
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)
inline Bitboard queen_attacks_bb(Square s, Bitboard blockers) { inline Bitboard queen_attacks_bb(Square s, Bitboard blockers) {
return rook_attacks_bb(s, blockers) | bishop_attacks_bb(s, 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) { inline Square __attribute__((always_inline)) first_1(Bitboard b) {
int r; Bitboard dummy;
for(r = 0; b; r++, b &= b - 1); __asm__("bsfq %1, %0": "=r"(dummy): "rm"(b) );
return r; return (Square)(dummy);
} }
inline int count_1s_max_15(Bitboard b) { inline Square __attribute__((always_inline)) pop_1st_bit(Bitboard* b) {
return count_1s(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) { extern Square first_1(Bitboard b);
unsigned w = unsigned(b >> 32), v = unsigned(b); extern Square pop_1st_bit(Bitboard* 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) { #endif
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
//// ////
@@ -483,8 +386,6 @@ inline int count_1s_max_15(Bitboard b) {
extern void print_bitboard(Bitboard b); extern void print_bitboard(Bitboard b);
extern void init_bitboards(); extern void init_bitboards();
extern Square first_1(Bitboard b);
extern Square pop_1st_bit(Bitboard *b);
#endif // !defined(BITBOARD_H_INCLUDED) #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 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -35,6 +35,7 @@
#include "mersenne.h" #include "mersenne.h"
#include "movegen.h" #include "movegen.h"
using namespace std;
//// ////
//// Global variables //// Global variables
@@ -49,7 +50,11 @@ Book OpeningBook;
namespace { 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] = { const uint64_t Random64[781] = {
0x9D39247E33776D41ULL, 0x2AF7398005AAA5C7ULL, 0x44DB015024623547ULL, 0x9D39247E33776D41ULL, 0x2AF7398005AAA5C7ULL, 0x44DB015024623547ULL,
@@ -318,30 +323,19 @@ namespace {
/// Indices to the Random64[] array /// Indices to the Random64[] array
const int RandomPiece = 0; const int RandomPiece = 0;
const int RandomCastle = 768; const int RandomCastle = 768;
const int RandomEnPassant = 772; const int RandomEnPassant = 772;
const int RandomTurn = 780; 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
};
/// Prototypes /// 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_piece_key(Piece p, Square s);
uint64_t book_castle_key(const Position &pos); uint64_t book_castle_key(const Position& pos);
uint64_t book_ep_key(const Position &pos); uint64_t book_ep_key(const Position& pos);
uint64_t book_color_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);
} }
@@ -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; fileName = fName;
bookFile.open(fileName.c_str(), std::ifstream::in | std::ifstream::binary); ifstream::open(fileName.c_str(), ifstream::in | ifstream::binary);
if (!bookFile.is_open()) if (!is_open())
return; return;
bookFile.seekg(0, std::ios::end); // Get the book size in number of entries
bookSize = bookFile.tellg() / 16; seekg(0, ios::end);
bookFile.seekg(0, std::ios::beg); bookSize = tellg() / EntrySize;
seekg(0, ios::beg);
if (!bookFile.good()) if (!good())
{ {
std::cerr << "Failed to open book file " << fileName << std::endl; cerr << "Failed to open book file " << fileName << endl;
exit(EXIT_FAILURE); 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() { void Book::close() {
if (bookFile.is_open()) if (is_open())
bookFile.close(); ifstream::close();
}
/// Book::is_open() tests whether a book file has been opened.
bool Book::is_open() const {
return bookFile.is_open() && bookSize != 0;
} }
/// Book::file_name() returns the file name of the currently active book, /// Book::file_name() returns the file name of the currently active book,
/// or the empty string if no book is open. /// or the empty string if no book is open.
const 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_NONE if no book move is found.
Move Book::get_move(const Position &pos) const { Move Book::get_move(const Position& pos) {
if(this->is_open()) {
int bestMove = 0, bestScore = 0, move, score; if (!is_open() || bookSize == 0)
uint64_t key = book_key(pos); return MOVE_NONE;
BookEntry entry;
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); assert(score > 0);
bestScore += score; // Choose book move according to its score. If a move has a very
if(int(genrand_int32() % bestScore) < score) // high score it has more probability to be choosen then a one with
bestMove = move; // lower score. Note that first entry is always chosen.
} scoresSum += score;
if (int(genrand_int32() % scoresSum) < score)
if(bestMove != 0) { bookMove = entry.move;
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;
}
} }
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; return MOVE_NONE;
} }
/// Book::find_key() takes a book key as input, and does a binary search /// 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 /// 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 /// entry with the same key as the input is returned. When the key is not
/// found in the book file, bookSize is returned. /// 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; int left, right, mid;
BookEntry entry; BookEntry entry;
@@ -452,46 +455,59 @@ int Book::find_key(uint64_t key) const {
assert(left <= right); assert(left <= right);
while(left < right) { while (left < right)
mid = (left + right) / 2; {
assert(mid >= left && mid < right); mid = (left + right) / 2;
this->read_entry(entry, mid); assert(mid >= left && mid < right);
if(key <= entry.key) read_entry(entry, mid);
right = mid; if (key <= entry.key)
else right = mid;
left = mid + 1; else
left = mid + 1;
} }
assert(left == right); assert(left == right);
this->read_entry(entry, left); read_entry(entry, left);
return (entry.key == key)? left : bookSize; return (entry.key == key)? left : bookSize;
} }
/// Book::read_entry() takes a BookEntry reference and an integer index as /// 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 /// 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(idx >= 0 && idx < bookSize);
assert(bookFile.is_open()); assert(is_open());
bookFile.seekg(n*16, std::ios_base::beg); seekg(idx * EntrySize, ios_base::beg);
if (!bookFile.good()) *this >> entry;
if (!good())
{ {
std::cerr << "Failed to read book entry at index " << n << std::endl; cerr << "Failed to read book entry at index " << idx << endl;
exit(EXIT_FAILURE); Application::exit_with_failure();
} }
entry.key = read_integer64(bookFile); }
entry.move = read_integer16(bookFile);
entry.count = read_integer16(bookFile);
entry.n = read_integer16(bookFile); /// Book::read_integer() reads size chars from the file stream
entry.sum = read_integer16(bookFile); /// 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 { namespace {
uint64_t book_key(const Position &pos) { uint64_t book_key(const Position& pos) {
uint64_t result = 0ULL; uint64_t result = 0ULL;
for(Color c = WHITE; c <= BLACK; c++) { for (Color c = WHITE; c <= BLACK; c++)
Bitboard b = pos.pieces_of_color(c); {
Square s; Bitboard b = pos.pieces_of_color(c);
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);
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_castle_key(pos);
result ^= book_ep_key(pos); result ^= book_ep_key(pos);
result ^= book_color_key(pos); result ^= book_color_key(pos);
return result; return result;
} }
uint64_t book_piece_key(Piece p, Square s) { 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; uint64_t result = 0ULL;
if(pos.can_castle_kingside(WHITE)) if (pos.can_castle_kingside(WHITE))
result ^= Random64[RandomCastle+0]; result ^= Random64[RandomCastle+0];
if(pos.can_castle_queenside(WHITE))
result ^= Random64[RandomCastle+1]; if (pos.can_castle_queenside(WHITE))
if(pos.can_castle_kingside(BLACK)) result ^= Random64[RandomCastle+1];
result ^= Random64[RandomCastle+2];
if(pos.can_castle_queenside(BLACK)) if (pos.can_castle_kingside(BLACK))
result ^= Random64[RandomCastle+3]; result ^= Random64[RandomCastle+2];
if (pos.can_castle_queenside(BLACK))
result ^= Random64[RandomCastle+3];
return result; return result;
} }
uint64_t book_ep_key(const Position &pos) { uint64_t book_ep_key(const Position& pos) {
return (pos.ep_square() == SQ_NONE)? return (pos.ep_square() == SQ_NONE ? 0ULL : Random64[RandomEnPassant + square_file(pos.ep_square())]);
0ULL : Random64[RandomEnPassant + square_file(pos.ep_square())];
} }
uint64_t book_color_key(const Position &pos) { uint64_t book_color_key(const Position& pos) {
return (pos.side_to_move() == WHITE)? Random64[RandomTurn] : 0ULL; 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;
} }
} }

View File

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

View File

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

View File

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

View File

@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -26,6 +26,32 @@
#include "square.h" #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 //// Variables
//// ////
@@ -39,25 +65,23 @@ uint8_t SignedDirectionTable[64][64];
//// ////
void init_direction_table() { 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++)
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);
DirectionTable[s1][s2] = uint8_t(DIR_NONE); SignedDirectionTable[s1][s2] = uint8_t(SIGNED_DIR_NONE);
SignedDirectionTable[s1][s2] = uint8_t(SIGNED_DIR_NONE); if (s1 == s2)
if(s1 == s2) continue; continue;
for(SignedDirection d = SIGNED_DIR_E; d <= SIGNED_DIR_SE; d++) {
SquareDelta delta = deltas[d]; for (SignedDirection d = SIGNED_DIR_E; d != SIGNED_DIR_NONE; d++)
Square s3, s4; {
for(s4 = s1 + delta, s3 = s1; if (reachable(s1, s2, d))
square_distance(s4, s3) == 1 && s4 != s2 && square_is_ok(s4); {
s3 = s4, s4 += delta); SignedDirectionTable[s1][s2] = uint8_t(d);
if(s4 == s2 && square_distance(s4, s3) == 1) { DirectionTable[s1][s2] = uint8_t(d / 2);
SignedDirectionTable[s1][s2] = uint8_t(d); break;
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 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by

View File

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

View File

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

View File

@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -25,6 +25,7 @@
#include <cassert> #include <cassert>
#include <cstring> #include <cstring>
#include "bitcount.h"
#include "evaluate.h" #include "evaluate.h"
#include "material.h" #include "material.h"
#include "pawns.h" #include "pawns.h"
@@ -39,23 +40,20 @@
namespace { 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; const int GrainSize = 4;
// Evaluation weights // Evaluation weights, initialized from UCI options
int WeightMobilityMidgame = 0x100; int WeightMobilityMidgame, WeightMobilityEndgame;
int WeightMobilityEndgame = 0x100; int WeightPawnStructureMidgame, WeightPawnStructureEndgame;
int WeightPawnStructureMidgame = 0x100; int WeightPassedPawnsMidgame, WeightPassedPawnsEndgame;
int WeightPawnStructureEndgame = 0x100; int WeightKingSafety[2];
int WeightPassedPawnsMidgame = 0x100;
int WeightPassedPawnsEndgame = 0x100;
int WeightKingSafety[2] = { 0x100, 0x100 };
int WeightSpace; int WeightSpace;
// Internal evaluation weights. These are applied on top of the evaluation // Internal evaluation weights. These are applied on top of the evaluation
// weights read from UCI parameters. The purpose is to be able to change // weights read from UCI parameters. The purpose is to be able to change
// the evaluation weights while keeping the default values of the UCI // the evaluation weights while keeping the default values of the UCI
// parameters at 100, which looks prettier. // parameters at 100, which looks prettier.
// //
@@ -70,6 +68,8 @@ namespace {
const int WeightKingOppSafetyInternal = 0x101; const int WeightKingOppSafetyInternal = 0x101;
const int WeightSpaceInternal = 0x02F; const int WeightSpaceInternal = 0x02F;
// Mobility and outposts bonus modified by Joona Kiiski
//
// Visually better to define tables constants // Visually better to define tables constants
typedef Value V; typedef Value V;
@@ -77,70 +77,70 @@ namespace {
// of attacked squares not occupied by friendly piecess. // of attacked squares not occupied by friendly piecess.
const Value MidgameKnightMobilityBonus[] = { const Value MidgameKnightMobilityBonus[] = {
// 0 1 2 3 4 5 6 7 8 // 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[] = { const Value EndgameKnightMobilityBonus[] = {
// 0 1 2 3 4 5 6 7 8 // 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 // 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. // queens are also included.
const Value MidgameBishopMobilityBonus[] = { const Value MidgameBishopMobilityBonus[] = {
// 0 1 2 3 4 5 6 7 // 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 // 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[] = { const Value EndgameBishopMobilityBonus[] = {
// 0 1 2 3 4 5 6 7 // 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 // 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 // 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. // queens and rooks are also included.
const Value MidgameRookMobilityBonus[] = { const Value MidgameRookMobilityBonus[] = {
// 0 1 2 3 4 5 6 7 // 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 // 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[] = { const Value EndgameRookMobilityBonus[] = {
// 0 1 2 3 4 5 6 7 // 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 // 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 // Queen mobility bonus in middle game and endgame, indexed by the number
// of attacked squares not occupied by friendly pieces. // of attacked squares not occupied by friendly pieces.
const Value MidgameQueenMobilityBonus[] = { const Value MidgameQueenMobilityBonus[] = {
// 0 1 2 3 4 5 6 7 // 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 // 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 // 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 // 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[] = { const Value EndgameQueenMobilityBonus[] = {
// 0 1 2 3 4 5 6 7 // 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 // 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 // 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 // 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 // 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 // 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), // 1
V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(0), // 2 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(0), V(4), V(8), V(8), V(4), 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(4),V(17),V(26),V(26),V(17), V(4), V(0), // 4
V(0),V(10),V(30),V(40),V(40),V(30),V(10), V(0), // 5 V(0), V(8),V(26),V(35),V(35),V(26), V(8), V(0), // 5
V(0), V(5),V(20),V(20),V(20),V(20), V(5), V(0), // 6 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), // 7
V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(0) // 8 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(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(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(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(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), // 7
V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(0) // 8 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 // Bonus for unstoppable passed pawns
const Value UnstoppablePawnValue = Value(0x500); 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 MidgameRookOn7thBonus = Value(47);
const Value EndgameRookOn7thBonus = Value(98); const Value EndgameRookOn7thBonus = Value(98);
const Value MidgameQueenOn7thBonus = Value(27); const Value MidgameQueenOn7thBonus = Value(27);
const Value EndgameQueenOn7thBonus = Value(54); const Value EndgameQueenOn7thBonus = Value(54);
// Rooks on open files (modified by Joona Kiiski)
// Rooks on open files
const Value RookOpenFileBonus = Value(43); const Value RookOpenFileBonus = Value(43);
const Value RookHalfOpenFileBonus = Value(19); const Value RookHalfOpenFileBonus = Value(19);
// Penalty for rooks trapped inside a friendly king which has lost the // Penalty for rooks trapped inside a friendly king which has lost the
// right to castle: // right to castle.
const Value TrappedRookPenalty = Value(180); const Value TrappedRookPenalty = Value(180);
// Penalty for a bishop on a7/h7 (a2/h2 for black) which is trapped by // Penalty for a bishop on a7/h7 (a2/h2 for black) which is trapped by
// enemy pawns: // enemy pawns.
const Value TrappedBishopA7H7Penalty = Value(300); 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] = { const Bitboard MaskA7H7[2] = {
((1ULL << SQ_A7) | (1ULL << SQ_H7)), ((1ULL << SQ_A7) | (1ULL << SQ_H7)),
((1ULL << SQ_A2) | (1ULL << SQ_H2)) ((1ULL << SQ_A2) | (1ULL << SQ_H2))
}; };
// Penalty for a bishop on a1/h1 (a8/h8 for black) which is trapped by // 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. // happen in Chess960 games.
const Value TrappedBishopA1H1Penalty = Value(100); 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] = { const Bitboard MaskA1H1[2] = {
((1ULL << SQ_A1) | (1ULL << SQ_H1)), ((1ULL << SQ_A1) | (1ULL << SQ_H1)),
((1ULL << SQ_A8) | (1ULL << SQ_H8)) ((1ULL << SQ_A8) | (1ULL << SQ_H8))
}; };
// The SpaceMask[color] contains area of the board which is consdered by // 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 // based on how many squares inside this area are safe and available for
// friendly minor pieces. // friendly minor pieces.
const Bitboard SpaceMask[2] = { const Bitboard SpaceMask[2] = {
@@ -221,30 +220,26 @@ namespace {
(1ULL<<SQ_C5) | (1ULL<<SQ_D5) | (1ULL<<SQ_E5) | (1ULL<<SQ_F5) (1ULL<<SQ_C5) | (1ULL<<SQ_D5) | (1ULL<<SQ_E5) | (1ULL<<SQ_F5)
}; };
/// King safety constants and variables. The king safety scores are taken /// King safety constants and variables. The king safety scores are taken
/// from the array SafetyTable[]. Various little "meta-bonuses" measuring /// from the array SafetyTable[]. Various little "meta-bonuses" measuring
/// the strength of the attack are added up into an integer, which is used /// the strength of the attack are added up into an integer, which is used
/// as an index to SafetyTable[]. /// as an index to SafetyTable[].
// Attack weights for each piece type. // Attack weights for each piece type
const int QueenAttackWeight = 5; const int QueenAttackWeight = 5;
const int RookAttackWeight = 3; const int RookAttackWeight = 3;
const int BishopAttackWeight = 2; const int BishopAttackWeight = 2;
const int KnightAttackWeight = 2; const int KnightAttackWeight = 2;
// Bonuses for safe checks for each piece type. // Bonuses for safe checks, initialized from UCI options
int QueenContactCheckBonus = 3; int QueenContactCheckBonus, DiscoveredCheckBonus;
int QueenCheckBonus = 2; int QueenCheckBonus, RookCheckBonus, BishopCheckBonus, KnightCheckBonus;
int RookCheckBonus = 1;
int BishopCheckBonus = 1;
int KnightCheckBonus = 1;
int DiscoveredCheckBonus = 3;
// Scan for queen contact mates? // Scan for queen contact mates?
const bool QueenContactMates = true; const bool QueenContactMates = true;
// Bonus for having a mate threat. // Bonus for having a mate threat, initialized from UCI options
int MateThreatBonus = 3; int MateThreatBonus;
// InitKingDanger[] contains bonuses based on the position of the defending // InitKingDanger[] contains bonuses based on the position of the defending
// king. // king.
@@ -259,40 +254,41 @@ namespace {
15, 15, 15, 15, 15, 15, 15, 15 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(). // in init_safety().
Value SafetyTable[100]; Value SafetyTable[100];
// Pawn and material hash tables, indexed by the current thread id // Pawn and material hash tables, indexed by the current thread id
PawnInfoTable *PawnTable[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}; MaterialInfoTable* MaterialTable[8] = {0, 0, 0, 0, 0, 0, 0, 0};
// Sizes of pawn and material hash tables // Sizes of pawn and material hash tables
const int PawnTableSize = 16384; const int PawnTableSize = 16384;
const int MaterialTableSize = 1024; 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]; uint8_t BitCount8Bit[256];
// Function prototypes // 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); void evaluate_pieces(const Position& p, Color us, EvalInfo& ei);
template<> template<bool HasPopCnt>
void evaluate_pieces<KING>(const Position& p, Color us, EvalInfo &ei); void evaluate_king(const Position& p, Color us, EvalInfo &ei);
void evaluate_passed_pawns(const Position &pos, EvalInfo &ei); void evaluate_passed_pawns(const Position &pos, EvalInfo &ei);
void evaluate_trapped_bishop_a7h7(const Position &pos, Square s, Color us, void evaluate_trapped_bishop_a7h7(const Position &pos, Square s, Color us,
EvalInfo &ei); EvalInfo &ei);
void evaluate_trapped_bishop_a1h1(const Position &pos, Square s, Color us, void evaluate_trapped_bishop_a1h1(const Position &pos, Square s, Color us,
EvalInfo &ei); EvalInfo &ei);
template<bool HasPopCnt>
void evaluate_space(const Position &p, Color us, EvalInfo &ei); void evaluate_space(const Position &p, Color us, EvalInfo &ei);
inline Value apply_weight(Value v, int w); inline Value apply_weight(Value v, int w);
Value scale_by_game_phase(Value mv, Value ev, Phase ph, const ScaleFactor sf[]); 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 compute_weight(int uciWeight, int internalWeight);
int weight_option(const std::string& opt, int weight); int weight_option(const std::string& opt, int weight);
void init_safety(); void init_safety();
@@ -304,11 +300,19 @@ namespace {
//// Functions //// 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 /// values, an endgame score and a middle game score, and interpolates
/// between them based on the remaining material. /// 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(pos.is_ok());
assert(threadID >= 0 && threadID < THREAD_MAX); 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 // Initialize pawn attack bitboards for both sides
ei.attackedBy[WHITE][PAWN] = ((pos.pawns(WHITE) << 9) & ~FileABB) | ((pos.pawns(WHITE) << 7) & ~FileHBB); 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.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[WHITE] = count_1s_max_15<HasPopCnt>(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[BLACK] = count_1s_max_15<HasPopCnt>(ei.attackedBy[BLACK][PAWN] & ei.attackedBy[WHITE][KING])/2;
// Evaluate pieces // Evaluate pieces
for (Color c = WHITE; c <= BLACK; c++) for (Color c = WHITE; c <= BLACK; c++)
{ {
evaluate_pieces<KNIGHT>(pos, c, ei); evaluate_pieces<KNIGHT, HasPopCnt>(pos, c, ei);
evaluate_pieces<BISHOP>(pos, c, ei); evaluate_pieces<BISHOP, HasPopCnt>(pos, c, ei);
evaluate_pieces<ROOK>(pos, c, ei); evaluate_pieces<ROOK, HasPopCnt>(pos, c, ei);
evaluate_pieces<QUEEN>(pos, c, ei); evaluate_pieces<QUEEN, HasPopCnt>(pos, c, ei);
// Sum up all attacked squares // Sum up all attacked squares
ei.attackedBy[c][0] = ei.attackedBy[c][PAWN] | ei.attackedBy[c][KNIGHT] 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]; | 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 // because we need complete attack information for all pieces when computing
// the king safety evaluation. // the king safety evaluation.
for (Color c = WHITE; c <= BLACK; c++) 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, // Evaluate passed pawns. We evaluate passed pawns for both sides at once,
// because we need to know which side promotes first in positions where // 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 // Evaluate space for both sides
if (ei.mi->space_weight() > 0) if (ei.mi->space_weight() > 0)
{ {
evaluate_space(pos, WHITE, ei); evaluate_space<HasPopCnt>(pos, WHITE, ei);
evaluate_space(pos, BLACK, 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); return (ei.mateThreat[stm] == MOVE_NONE ? v : 8 * QueenValueMidgame - v);
} }
} // namespace
/// quick_evaluate() does a very approximate evaluation of the current position. /// quick_evaluate() does a very approximate evaluation of the current position.
/// It currently considers only material and piece square table scores. Perhaps /// It currently considers only material and piece square table scores. Perhaps
@@ -505,6 +510,8 @@ void quit_eval() {
{ {
delete PawnTable[i]; delete PawnTable[i];
delete MaterialTable[i]; delete MaterialTable[i];
PawnTable[i] = NULL;
MaterialTable[i] = NULL;
} }
} }
@@ -533,76 +540,76 @@ void read_weights(Color us) {
namespace { namespace {
// evaluate_common() computes terms common to all pieces attack // evaluate_mobility() computes mobility and attacks for every piece
template<PieceType Piece> template<PieceType Piece, bool HasPopCnt>
int evaluate_common(const Position& p, const Bitboard& b, Color us, EvalInfo& ei, Square s = SQ_NONE) { 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 int AttackWeight[] = { 0, 0, KnightAttackWeight, BishopAttackWeight, RookAttackWeight, QueenAttackWeight };
static const Value* MgBonus[] = { 0, 0, MidgameKnightMobilityBonus, MidgameBishopMobilityBonus, MidgameRookMobilityBonus, MidgameQueenMobilityBonus }; static const Value* MgBonus[] = { 0, 0, MidgameKnightMobilityBonus, MidgameBishopMobilityBonus, MidgameRookMobilityBonus, MidgameQueenMobilityBonus };
static const Value* EgBonus[] = { 0, 0, EndgameKnightMobilityBonus, EndgameBishopMobilityBonus, EndgameRookMobilityBonus, EndgameQueenMobilityBonus }; 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 // Update attack info
ei.attackedBy[us][Piece] |= b; ei.attackedBy[us][Piece] |= b;
// King attack // King attacks
if (b & ei.kingZone[us]) if (b & ei.kingZone[us])
{ {
ei.kingAttackersCount[us]++; ei.kingAttackersCount[us]++;
ei.kingAttackersWeight[us] += AttackWeight[Piece]; ei.kingAttackersWeight[us] += AttackWeight[Piece];
Bitboard bb = (b & ei.attackedBy[them][KING]); Bitboard bb = (b & ei.attackedBy[them][KING]);
if (bb) 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 // Remove squares protected by enemy pawns
Bitboard bb = (b & ~ei.attackedBy[them][PAWN]); Bitboard bb = (b & ~ei.attackedBy[them][PAWN]);
// Mobility // Mobility
int mob = (Piece != QUEEN ? count_1s_max_15(bb & ~p.pieces_of_color(us)) int mob = (Piece != QUEEN ? count_1s_max_15<HasPopCnt>(bb & ~p.pieces_of_color(us))
: count_1s(bb & ~p.pieces_of_color(us))); : count_1s<HasPopCnt>(bb & ~p.pieces_of_color(us)));
ei.mgMobility += Sign[us] * MgBonus[Piece][mob]; ei.mgMobility += Sign[us] * MgBonus[Piece][mob];
ei.egMobility += Sign[us] * EgBonus[Piece][mob]; ei.egMobility += Sign[us] * EgBonus[Piece][mob];
return mob;
}
// Bishop and Knight outposts
if ( (Piece != BISHOP && Piece != KNIGHT) // compile time condition // evaluate_outposts() evaluates bishop and knight outposts squares
|| !p.square_is_weak(s, them))
return mob; template<PieceType Piece>
void evaluate_outposts(const Position& p, Color us, Color them, EvalInfo& ei, Square s) {
// Initial bonus based on square // Initial bonus based on square
Value v, bonus; Value bonus = (Piece == BISHOP ? BishopOutpostBonus[relative_square(us, s)]
v = bonus = OutpostBonus[Piece][relative_square(us, s)]; : KnightOutpostBonus[relative_square(us, s)]);
// Increase bonus if supported by pawn, especially if the opponent has // Increase bonus if supported by pawn, especially if the opponent has
// no minor piece which can exchange the outpost piece // 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.knights(them) == EmptyBoardBB
if ( p.piece_count(them, KNIGHT) == 0
&& (SquaresByColorBB[square_color(s)] & p.bishops(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.mgValue += Sign[us] * bonus;
ei.egValue += Sign[us] * bonus; ei.egValue += Sign[us] * bonus;
return mob;
} }
// evaluate_pieces<>() assigns bonuses and penalties to the pieces of a given // evaluate_pieces<>() assigns bonuses and penalties to the pieces of a given
// color. // color.
template<PieceType Piece> template<PieceType Piece, bool HasPopCnt>
void evaluate_pieces(const Position& pos, Color us, EvalInfo& ei) { void evaluate_pieces(const Position& pos, Color us, EvalInfo& ei) {
Bitboard b; Bitboard b;
Square s, ksq; Square s, ksq;
Color them;
int mob; int mob;
File f; File f;
Color them = opposite_color(us);
for (int i = 0, e = pos.piece_count(us, Piece); i < e; i++) 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)); b = bishop_attacks_bb(s, pos.occupied_squares() & ~pos.queens(us));
else if (Piece == ROOK) else if (Piece == ROOK)
b = rook_attacks_bb(s, pos.occupied_squares() & ~pos.rooks_and_queens(us)); b = rook_attacks_bb(s, pos.occupied_squares() & ~pos.rooks_and_queens(us));
else
assert(false);
// Attacks, mobility and outposts // Attacks and mobility
mob = evaluate_common<Piece>(pos, b, us, ei, s); 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 // Special patterns: trapped bishops on a7/h7/a2/h2
// and trapped bishops on a1/h1/a8/h8 in Chess960. // and trapped bishops on a1/h1/a8/h8 in Chess960.
@@ -632,8 +645,6 @@ namespace {
if (Piece == ROOK || Piece == QUEEN) if (Piece == ROOK || Piece == QUEEN)
{ {
// Queen or rook on 7th rank // Queen or rook on 7th rank
them = opposite_color(us);
if ( relative_rank(us, s) == RANK_7 if ( relative_rank(us, s) == RANK_7
&& relative_rank(us, pos.king_square(them)) == RANK_8) && relative_rank(us, pos.king_square(them)) == RANK_8)
{ {
@@ -695,11 +706,10 @@ namespace {
return b >> (num << 3); return b >> (num << 3);
} }
// evaluate_pieces<KING>() assigns bonuses and penalties to a king of a given // evaluate_king<>() assigns bonuses and penalties to a king of a given color.
// color.
template<> template<bool HasPopCnt>
void evaluate_pieces<KING>(const Position& p, Color us, EvalInfo& ei) { void evaluate_king(const Position& p, Color us, EvalInfo& ei) {
int shelter = 0, sign = Sign[us]; int shelter = 0, sign = Sign[us];
Square s = p.king_square(us); Square s = p.king_square(us);
@@ -707,15 +717,23 @@ namespace {
// King shelter // King shelter
if (relative_rank(us, s) <= RANK_4) if (relative_rank(us, s) <= RANK_4)
{ {
Bitboard pawns = p.pawns(us) & this_and_neighboring_files_bb(s); // Shelter cache lookup
Rank r = square_rank(s); shelter = ei.pi->kingShelter(us, s);
for (int i = 1; i < 4; i++) if (shelter == -1)
shelter += count_1s_8bit(shiftRowsDown(pawns, r+i*sign)) * (128>>i); {
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); 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. // from optimally tuned.
Color them = opposite_color(us); Color them = opposite_color(us);
@@ -744,7 +762,7 @@ namespace {
// quality of the pawn shelter. // quality of the pawn shelter.
int attackUnits = int attackUnits =
Min((ei.kingAttackersCount[them] * ei.kingAttackersWeight[them]) / 2, 25) 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); + InitKingDanger[relative_square(us, s)] - (shelter >> 5);
// Analyse safe queen contact checks // Analyse safe queen contact checks
@@ -760,7 +778,7 @@ namespace {
{ {
// The bitboard b now contains the squares available for safe queen // The bitboard b now contains the squares available for safe queen
// contact checks. // contact checks.
int count = count_1s_max_15(b); int count = count_1s_max_15<HasPopCnt>(b);
attackUnits += QueenContactCheckBonus * count * (sente ? 2 : 1); attackUnits += QueenContactCheckBonus * count * (sente ? 2 : 1);
// Is there a mate threat? // Is there a mate threat?
@@ -800,12 +818,12 @@ namespace {
// Queen checks // Queen checks
b2 = b & ei.attacked_by(them, QUEEN); b2 = b & ei.attacked_by(them, QUEEN);
if( b2) if( b2)
attackUnits += QueenCheckBonus * count_1s_max_15(b2); attackUnits += QueenCheckBonus * count_1s_max_15<HasPopCnt>(b2);
// Rook checks // Rook checks
b2 = b & ei.attacked_by(them, ROOK); b2 = b & ei.attacked_by(them, ROOK);
if (b2) if (b2)
attackUnits += RookCheckBonus * count_1s_max_15(b2); attackUnits += RookCheckBonus * count_1s_max_15<HasPopCnt>(b2);
} }
if (QueenCheckBonus > 0 || BishopCheckBonus > 0) if (QueenCheckBonus > 0 || BishopCheckBonus > 0)
{ {
@@ -814,12 +832,12 @@ namespace {
// Queen checks // Queen checks
b2 = b & ei.attacked_by(them, QUEEN); b2 = b & ei.attacked_by(them, QUEEN);
if (b2) if (b2)
attackUnits += QueenCheckBonus * count_1s_max_15(b2); attackUnits += QueenCheckBonus * count_1s_max_15<HasPopCnt>(b2);
// Bishop checks // Bishop checks
b2 = b & ei.attacked_by(them, BISHOP); b2 = b & ei.attacked_by(them, BISHOP);
if (b2) if (b2)
attackUnits += BishopCheckBonus * count_1s_max_15(b2); attackUnits += BishopCheckBonus * count_1s_max_15<HasPopCnt>(b2);
} }
if (KnightCheckBonus > 0) if (KnightCheckBonus > 0)
{ {
@@ -828,7 +846,7 @@ namespace {
// Knight checks // Knight checks
b2 = b & ei.attacked_by(them, KNIGHT); b2 = b & ei.attacked_by(them, KNIGHT);
if (b2) 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 // Analyse discovered checks (only for non-pawns right now, consider
@@ -837,7 +855,7 @@ namespace {
{ {
b = p.discovered_check_candidates(them) & ~p.pawns(); b = p.discovered_check_candidates(them) & ~p.pawns();
if (b) 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 // 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))) && (squares_behind(us, s) & pos.rooks_and_queens(them)))
b3 = b2; b3 = b2;
if ((b2 & pos.pieces_of_color(them)) == EmptyBoardBB) // Squares attacked or occupied by enemy pieces
{ b3 |= (b2 & pos.pieces_of_color(them));
// There are no enemy pieces in the pawn's path! Are any of the
// squares in the pawn's path attacked by the enemy? // There are no enemy pawns in the pawn's path
if (b3 == EmptyBoardBB) assert((b2 & pos.pieces_of_color_and_type(them, PAWN)) == EmptyBoardBB);
// No enemy attacks, huge bonus!
ebonus += Value(tr * (b2 == b4 ? 17 : 15)); // Are any of the squares in the pawn's path attacked or occupied by the enemy?
else if (b3 == EmptyBoardBB)
// OK, there are enemy attacks. Are those squares which are // No enemy attacks or pieces, huge bonus!
// attacked by the enemy also attacked by us? If yes, big bonus ebonus += Value(tr * (b2 == b4 ? 17 : 15));
// (but smaller than when there are no enemy attacks), if no,
// somewhat smaller bonus.
ebonus += Value(tr * ((b3 & b4) == b3 ? 13 : 8));
}
else else
{ // OK, there are enemy attacks or pieces (but not pawns). Are those
// There are some enemy pieces in the pawn's path. While this is // squares which are attacked by the enemy also attacked by us?
// sad, we still assign a moderate bonus if all squares in the path // If yes, big bonus (but smaller than when there are no enemy attacks),
// which are either occupied by or attacked by enemy pieces are // if no, somewhat smaller bonus.
// also attacked by us. ebonus += Value(tr * ((b3 & b4) == b3 ? 13 : 8));
if (((b3 | (b2 & pos.pieces_of_color(them))) & ~b4) == EmptyBoardBB)
ebonus += Value(tr * 6);
}
// At last, add a small bonus when there are no *friendly* pieces // At last, add a small bonus when there are no *friendly* pieces
// in the pawn's path. // in the pawn's path.
if ((b2 & pos.pieces_of_color(us)) == EmptyBoardBB) 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 // sometimes better than other passed pawns. It is difficult to find
// good rules for determining whether they are good or bad. For now, // good rules for determining whether they are good or bad. For now,
// we try the following: Increase the value for rook pawns if the // 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. // value if the other side has a rook or queen.
if (square_file(s) == FILE_A || square_file(s) == FILE_H) if (square_file(s) == FILE_A || square_file(s) == FILE_H)
{ {
if( pos.non_pawn_material(them) <= KnightValueMidgame if ( pos.non_pawn_material(them) <= KnightValueMidgame
&& pos.piece_count(them, KNIGHT) <= 1) && pos.piece_count(them, KNIGHT) <= 1)
ebonus += ebonus / 4; ebonus += ebonus / 4;
else if(pos.rooks_and_queens(them)) else if (pos.rooks_and_queens(them))
ebonus -= ebonus / 4; ebonus -= ebonus / 4;
} }
@@ -1005,9 +1017,9 @@ namespace {
// Does either side have an unstoppable passed pawn? // Does either side have an unstoppable passed pawn?
if (hasUnstoppable[WHITE] && !hasUnstoppable[BLACK]) 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]) 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]) else if (hasUnstoppable[BLACK] && hasUnstoppable[WHITE])
{ {
// Both sides have unstoppable pawns! Try to find out who queens // 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 // 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 // twice. Finally, the space bonus is scaled by a weight taken from the
// material hash table. // material hash table.
template<bool HasPopCnt>
void evaluate_space(const Position &pos, Color us, EvalInfo &ei) { void evaluate_space(const Position &pos, Color us, EvalInfo &ei) {
Color them = opposite_color(us); Color them = opposite_color(us);
@@ -1133,8 +1145,8 @@ namespace {
behindFriendlyPawns |= (behindFriendlyPawns << 16); behindFriendlyPawns |= (behindFriendlyPawns << 16);
} }
int space = count_1s_max_15(safeSquares) int space = count_1s_max_15<HasPopCnt>(safeSquares)
+ count_1s_max_15(behindFriendlyPawns & safeSquares); + count_1s_max_15<HasPopCnt>(behindFriendlyPawns & safeSquares);
ei.mgValue += Sign[us] * apply_weight(Value(space * ei.mi->space_weight()), WeightSpace); 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 // compute_weight() computes the value of an evaluation weight, by combining
// an UCI-configurable weight with an internal weight. // 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 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -39,7 +39,7 @@
/// arguments to the evaluation function, and the search can make use of its /// arguments to the evaluation function, and the search can make use of its
/// contents to make intelligent search decisions. /// 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. /// EvalInfo object which is used by the search is futilityMargin.
class Position; class Position;
@@ -53,16 +53,16 @@ struct EvalInfo {
PawnInfo* pi; PawnInfo* pi;
// attackedBy[color][piece type] is a bitboard representing all squares // 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. // all squares attacked by the given color.
Bitboard attackedBy[2][8]; Bitboard attackedBy[2][8];
Bitboard attacked_by(Color c) const { return attackedBy[c][0]; } Bitboard attacked_by(Color c) const { return attackedBy[c][0]; }
Bitboard attacked_by(Color c, PieceType pt) const { return attackedBy[c][pt]; } Bitboard attacked_by(Color c, PieceType pt) const { return attackedBy[c][pt]; }
// kingZone[color] is the zone around the enemy king which is considered // 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) // 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, // is on g8, kingZone[WHITE] is a bitboard containing the squares f8, h8,
// f7, g7, h7, f6, g6 and h6. // f7, g7, h7, f6, g6 and h6.
Bitboard kingZone[2]; Bitboard kingZone[2];
@@ -91,7 +91,7 @@ struct EvalInfo {
// Middle game and endgame mobility scores. // Middle game and endgame mobility scores.
Value mgMobility, egMobility; 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. // in the quiescence search.
Value futilityMargin; Value futilityMargin;
}; };

View File

@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -32,14 +32,13 @@
//// Functions //// Functions
//// ////
/// Constructor /// Constructor
History::History() { History::History() { clear(); }
this->clear();
}
/// History::clear() clears the history tables. /// History::clear() clears the history tables
void History::clear() { void History::clear() {
memset(history, 0, 2 * 8 * 64 * sizeof(int)); 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. /// 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 /// The three parameters are the moving piece, the destination square, and
/// search depth. /// 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(piece_is_ok(p));
assert(move_is_ok(m)); assert(square_is_ok(to));
history[p][move_to(m)] += int(d) * int(d); history[p][to] += int(d) * int(d);
successCount[p][move_to(m)]++; successCount[p][to]++;
// Prevent history overflow: // Prevent history overflow
if(history[p][move_to(m)] >= HistoryMax) if (history[p][to] >= HistoryMax)
for(int i = 0; i < 16; i++) for (int i = 0; i < 16; i++)
for(int j = 0; j < 64; j++) for (int j = 0; j < 64; j++)
history[i][j] /= 2; 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 /// called for each non-capturing move which failed to produce a beta cutoff
/// at a node where a beta cutoff was finally found. /// at a node where a beta cutoff was finally found.
void History::failure(Piece p, Move m) { void History::failure(Piece p, Square to) {
assert(piece_is_ok(p));
assert(move_is_ok(m));
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 /// History::move_ordering_score() returns an integer value used to order the
/// non-capturing moves in the MovePicker class. /// non-capturing moves in the MovePicker class.
int History::move_ordering_score(Piece p, Move m) const { int History::move_ordering_score(Piece p, Square to) const {
assert(piece_is_ok(p));
assert(move_is_ok(m));
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 /// History::ok_to_prune() decides whether a move has been sufficiently
/// unsuccessful that it makes sense to prune it entirely. /// unsuccessful that it makes sense to prune it entirely.
bool History::ok_to_prune(Piece p, Move m, Depth d) const { bool History::ok_to_prune(Piece p, Square to, Depth d) const {
assert(piece_is_ok(p));
assert(move_is_ok(m));
return (int(d) * successCount[p][move_to(m)] < failureCount[p][move_to(m)]); 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 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -34,19 +34,22 @@
//// Types //// Types
//// ////
/// The History class stores statistics about how often different moves have /// The History class stores statistics about how often different moves
/// been successful or unsuccessful during the current search. These /// have been successful or unsuccessful during the current search. These
/// statistics are used for reduction and move ordering decisions. /// 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 { class History {
public: public:
History(); History();
void clear(); void clear();
void success(Piece p, Move m, Depth d); void success(Piece p, Square to, Depth d);
void failure(Piece p, Move m); void failure(Piece p, Square to);
int move_ordering_score(Piece p, Move m) const; int move_ordering_score(Piece p, Square to) const;
bool ok_to_prune(Piece p, Move m, Depth d) const; bool ok_to_prune(Piece p, Square to, Depth d) const;
private: private:
int history[16][64]; // [piece][square] int history[16][64]; // [piece][square]
@@ -61,17 +64,13 @@ private:
/// HistoryMax controls how often the history counters will be scaled down: /// HistoryMax controls how often the history counters will be scaled down:
/// When the history score for a move gets bigger than HistoryMax, all /// 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 /// 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 ideal value of this constant is. Scaling down the scores often has
/// the effect that parts of the search tree which have been searched /// the effect that parts of the search tree which have been searched
/// recently have a bigger importance for move ordering than the moves which /// recently have a bigger importance for move ordering than the moves which
/// have been searched a long time ago. /// have been searched a long time ago.
///
/// 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) #endif // !defined(HISTORY_H_INCLUDED)

View File

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

View File

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

View File

@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -23,12 +23,12 @@
//// ////
#include <cassert> #include <cassert>
#include <cstring>
#include <sstream> #include <sstream>
#include <map> #include <map>
#include "material.h" #include "material.h"
using std::string;
//// ////
//// Local definitions //// Local definitions
@@ -36,6 +36,7 @@
namespace { namespace {
// Values modified by Joona Kiiski
const Value BishopPairMidgameBonus = Value(109); const Value BishopPairMidgameBonus = Value(109);
const Value BishopPairEndgameBonus = Value(97); const Value BishopPairEndgameBonus = Value(97);
@@ -59,9 +60,9 @@ public:
EndgameScalingFunctionBase* getESF(Key key, Color* c) const; EndgameScalingFunctionBase* getESF(Key key, Color* c) const;
private: private:
void add(const std::string& keyCode, EndgameEvaluationFunctionBase* f); void add(const string& keyCode, EndgameEvaluationFunctionBase* f);
void add(const std::string& keyCode, Color c, EndgameScalingFunctionBase* f); void add(const string& keyCode, Color c, EndgameScalingFunctionBase* f);
Key buildKey(const std::string& keyCode); Key buildKey(const string& keyCode);
struct ScalingInfo struct ScalingInfo
{ {
@@ -90,9 +91,8 @@ MaterialInfoTable::MaterialInfoTable(unsigned int numOfEntries) {
{ {
std::cerr << "Failed to allocate " << (numOfEntries * sizeof(MaterialInfo)) std::cerr << "Failed to allocate " << (numOfEntries * sizeof(MaterialInfo))
<< " bytes for material hash table." << std::endl; << " 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() { MaterialInfoTable::~MaterialInfoTable() {
delete [] entries;
delete funcs; delete funcs;
} delete [] entries;
/// MaterialInfoTable::clear() clears a material hash table by setting
/// all entries to 0.
void MaterialInfoTable::clear() {
memset(entries, 0, size * sizeof(MaterialInfo));
} }
@@ -152,14 +143,14 @@ MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) {
else if ( pos.non_pawn_material(BLACK) == Value(0) else if ( pos.non_pawn_material(BLACK) == Value(0)
&& pos.piece_count(BLACK, PAWN) == 0 && pos.piece_count(BLACK, PAWN) == 0
&& pos.non_pawn_material(WHITE) >= RookValueEndgame) && pos.non_pawn_material(WHITE) >= RookValueMidgame)
{ {
mi->evaluationFunction = &EvaluateKXK; mi->evaluationFunction = &EvaluateKXK;
return mi; return mi;
} }
else if ( pos.non_pawn_material(WHITE) == Value(0) else if ( pos.non_pawn_material(WHITE) == Value(0)
&& pos.piece_count(WHITE, PAWN) == 0 && pos.piece_count(WHITE, PAWN) == 0
&& pos.non_pawn_material(BLACK) >= RookValueEndgame) && pos.non_pawn_material(BLACK) >= RookValueMidgame)
{ {
mi->evaluationFunction = &EvaluateKKX; mi->evaluationFunction = &EvaluateKKX;
return mi; return mi;
@@ -352,7 +343,7 @@ EndgameFunctions::EndgameFunctions() {
add("KRPKRPP", BLACK, &ScaleKRPKRPP); 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() > 0 && keyCode[0] == 'K');
assert(keyCode.length() < 8); assert(keyCode.length() < 8);
@@ -373,12 +364,12 @@ Key EndgameFunctions::buildKey(const std::string& keyCode) {
return Position(s.str()).get_material_key(); 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)); 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}; ScalingInfo s = {c, f};
ESFmap.insert(std::pair<Key, ScalingInfo>(buildKey(keyCode), s)); 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 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -49,6 +49,8 @@ class MaterialInfo {
friend class MaterialInfoTable; friend class MaterialInfoTable;
public: public:
MaterialInfo() : key(0) { clear(); }
Value mg_value() const; Value mg_value() const;
Value eg_value() const; Value eg_value() const;
ScaleFactor scale_factor(const Position& pos, Color c) const; ScaleFactor scale_factor(const Position& pos, Color c) const;
@@ -57,7 +59,7 @@ public:
Value evaluate(const Position& pos) const; Value evaluate(const Position& pos) const;
private: private:
void clear(); inline void clear();
Key key; Key key;
int16_t mgValue; int16_t mgValue;
@@ -87,7 +89,6 @@ class MaterialInfoTable {
public: public:
MaterialInfoTable(unsigned numOfEntries); MaterialInfoTable(unsigned numOfEntries);
~MaterialInfoTable(); ~MaterialInfoTable();
void clear();
MaterialInfo* get_material_info(const Position& pos); MaterialInfo* get_material_info(const Position& pos);
private: private:
@@ -116,20 +117,20 @@ inline Value MaterialInfo::eg_value() const {
/// MaterialInfo::clear() resets a MaterialInfo object to an empty state, /// 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() { inline void MaterialInfo::clear() {
mgValue = egValue = 0; mgValue = egValue = 0;
factor[WHITE] = factor[BLACK] = uint8_t(SCALE_FACTOR_NORMAL); factor[WHITE] = factor[BLACK] = uint8_t(SCALE_FACTOR_NORMAL);
spaceWeight = 0;
evaluationFunction = NULL; evaluationFunction = NULL;
scalingFunction[WHITE] = scalingFunction[BLACK] = NULL; scalingFunction[WHITE] = scalingFunction[BLACK] = NULL;
spaceWeight = 0;
} }
/// MaterialInfo::scale_factor takes a position and a color as input, and /// 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 /// 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 /// 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 /// 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 /// 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'. /// specialized_eval_exists() returns 'true'.
inline Value MaterialInfo::evaluate(const Position& pos) const { 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 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -29,7 +29,7 @@
//// ////
//// Variables //// Constants modified by Joona Kiiski
//// ////
static const Value MP = PawnValueMidgame; static const Value MP = PawnValueMidgame;
@@ -41,70 +41,70 @@ static const Value MQ = QueenValueMidgame;
static const int MgPST[][64] = { static const int MgPST[][64] = {
{ }, { },
{// Pawn {// Pawn
// A B C D E F G H // A B C D E F G H
0, 0, 0, 0, 0, 0, 0, 0, 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-28, MP-6, MP+ 4, MP+14, MP+14, MP+ 4, MP-6, MP-28,
MP-38, MP-12, MP+ 6, MP+38, MP+38, MP+ 6, MP-12, MP-38, MP-28, MP-6, MP+ 9, MP+36, MP+36, MP+ 9, MP-6, MP-28,
MP-38, MP-12, MP+16, MP+64, MP+64, MP+16, MP-12, MP-38, MP-28, MP-6, MP+17, MP+58, MP+58, MP+17, MP-6, MP-28,
MP-38, MP-12, MP+16, MP+38, MP+38, MP+16, MP-12, MP-38, MP-28, MP-6, MP+17, MP+36, MP+36, MP+17, MP-6, MP-28,
MP-38, MP-12, MP+ 6, MP+12, MP+12, MP+ 6, MP-12, MP-38, MP-28, MP-6, MP+ 9, MP+14, MP+14, MP+ 9, MP-6, MP-28,
MP-38, MP-12, MP- 0, MP+12, MP+12, MP- 0, MP-12, MP-38, MP-28, MP-6, MP+ 4, MP+14, MP+14, MP+ 4, MP-6, MP-28,
0, 0, 0, 0, 0, 0, 0, 0 0, 0, 0, 0, 0, 0, 0, 0
}, },
{// Knight {// Knight
// A B C D E F G H // 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-135, MK-107, MK-80, MK-67, MK-67, MK-80, MK-107, MK-135,
MK- 89, MK- 64, MK-38, MK-25, MK-25, MK-38, MK- 64, MK- 89, MK- 93, MK- 67, MK-39, MK-25, MK-25, MK-39, MK- 67, MK- 93,
MK- 51, MK- 25, MK- 0, MK+12, MK+12, MK- 0, MK- 25, MK- 51, MK- 53, MK- 25, MK+ 1, MK+13, MK+13, MK+ 1, MK- 25, MK- 53,
MK- 25, MK- 0, MK+25, MK+38, MK+38, MK+25, MK- 0, MK- 25, MK- 25, MK+ 1, MK+27, MK+41, MK+41, MK+27, MK+ 1, MK- 25,
MK- 12, MK+ 12, MK+38, MK+51, MK+51, MK+38, MK+ 12, MK- 12, MK- 11, MK+ 13, MK+41, MK+55, MK+55, MK+41, MK+ 13, MK- 11,
MK- 12, MK+ 12, MK+38, MK+51, MK+51, MK+38, MK+ 12, MK- 12, MK- 11, MK+ 13, MK+41, MK+55, MK+55, MK+41, MK+ 13, MK- 11,
MK- 51, MK- 25, MK- 0, MK+12, MK+12, MK- 0, MK- 25, MK- 51, MK- 53, MK- 25, MK+ 1, MK+13, MK+13, MK+ 1, MK- 25, MK- 53,
MK-182, MK- 64, MK-38, MK-25, MK-25, MK-38, MK- 64, MK-182 MK-193, MK- 67, MK-39, MK-25, MK-25, MK-39, MK- 67, MK-193
}, },
{// Bishop {// Bishop
// A B C D E F G H // 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-40, MB-40, MB-35, MB-30, MB-30, MB-35, MB-40, MB-40,
MB-20, MB- 0, MB- 5, MB- 0, MB- 0, MB- 5, MB- 0, MB-20, MB-17, MB+ 0, MB- 4, MB+ 0, MB+ 0, MB- 4, MB+ 0, MB-17,
MB-15, MB- 5, MB+10, MB+ 5, MB+ 5, MB+10, MB- 5, MB-15, MB-13, MB- 4, MB+ 8, MB+ 4, MB+ 4, MB+ 8, MB- 4, MB-13,
MB-10, MB- 0, MB+ 5, MB+20, MB+20, MB+ 5, MB- 0, MB-10, MB- 8, MB+ 0, MB+ 4, MB+17, MB+17, MB+ 4, MB+ 0, MB- 8,
MB-10, MB- 0, MB+ 5, MB+20, MB+20, MB+ 5, MB- 0, MB-10, MB- 8, MB+ 0, MB+ 4, MB+17, MB+17, MB+ 4, MB+ 0, MB- 8,
MB-15, MB- 5, MB+10, MB+ 5, MB+ 5, MB+10, MB- 5, MB-15, MB-13, MB- 4, MB+ 8, MB+ 4, MB+ 4, MB+ 8, MB- 4, MB-13,
MB-20, MB- 0, MB- 5, MB- 0, MB- 0, MB- 5, MB- 0, MB-20, MB-17, MB+ 0, MB- 4, MB+ 0, MB+ 0, MB- 4, MB+ 0, MB-17,
MB-20, MB-20, MB-15, MB-10, MB-10, MB-15, MB-20, MB-20 MB-17, MB-17, MB-13, MB- 8, MB- 8, MB-13, MB-17, MB-17
}, },
{// Rook {// Rook
// A B C D E F G H // 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-12, MR-7, MR-2, MR+2, MR+2, MR-2, MR-7, MR-12,
MR-18, MR-10, MR-3, MR+4, MR+4, MR-3, MR-10, MR-18, MR-12, MR-7, MR-2, MR+2, MR+2, MR-2, MR-7, MR-12,
MR-18, MR-10, MR-3, MR+4, MR+4, MR-3, MR-10, MR-18, MR-12, MR-7, MR-2, MR+2, MR+2, MR-2, MR-7, MR-12,
MR-18, MR-10, MR-3, MR+4, MR+4, MR-3, MR-10, MR-18, MR-12, MR-7, MR-2, MR+2, MR+2, MR-2, MR-7, MR-12,
MR-18, MR-10, MR-3, MR+4, MR+4, MR-3, MR-10, MR-18, MR-12, MR-7, MR-2, MR+2, MR+2, MR-2, MR-7, MR-12,
MR-18, MR-10, MR-3, MR+4, MR+4, MR-3, MR-10, MR-18, MR-12, MR-7, MR-2, MR+2, MR+2, MR-2, MR-7, MR-12,
MR-18, MR-10, MR-3, MR+4, MR+4, MR-3, MR-10, MR-18, MR-12, MR-7, MR-2, MR+2, MR+2, MR-2, MR-7, MR-12,
MR-18, MR-10, MR-3, MR+4, MR+4, MR-3, MR-10, MR-18 MR-12, MR-7, MR-2, MR+2, MR+2, MR-2, MR-7, MR-12
}, },
{// Queen {// Queen
//A B C D E F G H // A B C D E F G H
MQ, MQ, MQ, MQ, MQ, MQ, MQ, MQ, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8,
MQ, MQ, MQ, MQ, MQ, MQ, MQ, MQ, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8,
MQ, MQ, MQ, MQ, MQ, MQ, MQ, MQ, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8,
MQ, MQ, MQ, MQ, MQ, MQ, MQ, MQ, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8,
MQ, MQ, MQ, MQ, MQ, MQ, MQ, MQ, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8,
MQ, MQ, MQ, MQ, MQ, MQ, MQ, MQ, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8,
MQ, MQ, MQ, MQ, MQ, MQ, MQ, MQ, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8,
MQ, MQ, MQ, MQ, MQ, MQ, MQ, MQ MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8, MQ+8
}, },
{// King {// King
//A B C D E F G H //A B C D E F G H
302, 328, 276, 225, 225, 276, 328, 302, 287, 311, 262, 214, 214, 262, 311, 287,
276, 302, 251, 200, 200, 251, 302, 276, 262, 287, 238, 190, 190, 238, 287, 262,
225, 251, 200, 149, 149, 200, 251, 225, 214, 238, 190, 142, 142, 190, 238, 214,
200, 225, 175, 124, 124, 175, 225, 200, 190, 214, 167, 119, 119, 167, 214, 190,
175, 200, 149, 98, 98, 149, 200, 175, 167, 190, 142, 94, 94, 142, 190, 167,
149, 175, 124, 72, 72, 124, 175, 149, 142, 167, 119, 69, 69, 119, 167, 142,
124, 149, 98, 47, 47, 98, 149, 124, 119, 142, 94, 46, 46, 94, 142, 119,
98, 124, 72, 21, 21, 72, 124, 98 94, 119, 69, 21, 21, 69, 119, 94
} }
}; };
@@ -117,70 +117,70 @@ static const Value EQ = QueenValueEndgame;
static const int EgPST[][64] = { static const int EgPST[][64] = {
{ }, { },
{// Pawn {// Pawn
//A B C D E F G H // A B C D E F G H
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
EP, EP, EP, EP, EP, EP, EP, EP, EP-8, EP-8, EP-8, EP-8, EP-8, EP-8, EP-8, EP-8,
EP, EP, EP, EP, EP, EP, EP, EP, EP-8, EP-8, EP-8, EP-8, EP-8, EP-8, EP-8, EP-8,
EP, EP, EP, EP, EP, EP, EP, EP, EP-8, EP-8, EP-8, EP-8, EP-8, EP-8, EP-8, EP-8,
EP, EP, EP, EP, EP, EP, EP, EP, EP-8, EP-8, EP-8, EP-8, EP-8, EP-8, EP-8, EP-8,
EP, EP, EP, EP, EP, EP, EP, EP, EP-8, EP-8, EP-8, EP-8, EP-8, EP-8, EP-8, EP-8,
EP, EP, EP, EP, EP, EP, EP, EP, EP-8, EP-8, EP-8, EP-8, EP-8, EP-8, EP-8, EP-8,
0, 0, 0, 0, 0, 0, 0, 0 0, 0, 0, 0, 0, 0, 0, 0
}, },
{// Knight {// Knight
// A B C D E F G H // 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-104, EK-79, EK-55, EK-42, EK-42, EK-55, EK-79, EK-104,
EK- 76, EK-51, EK-25, EK-12, EK-12, EK-25, EK-51, EK-76, EK- 79, EK-55, EK-30, EK-17, EK-17, EK-30, EK-55, EK- 79,
EK- 51, EK-25, EK- 0, EK+12, EK+12, EK- 0, EK-25, EK-51, EK- 55, EK-30, EK- 6, EK+ 5, EK+ 5, EK- 6, EK-30, EK- 55,
EK- 38, EK-12, EK+12, EK+25, EK+25, EK+12, EK-12, EK-38, EK- 42, EK-17, EK+ 5, EK+18, EK+18, EK+ 5, EK-17, EK- 42,
EK- 38, EK-12, EK+12, EK+25, EK+25, EK+12, EK-12, EK-38, EK- 42, EK-17, EK+ 5, EK+18, EK+18, EK+ 5, EK-17, EK- 42,
EK- 51, EK-25, EK- 0, EK+12, EK+12, EK- 0, EK-25, EK-51, EK- 55, EK-30, EK- 6, EK+ 5, EK+ 5, EK- 6, EK-30, EK- 55,
EK- 76, EK-51, EK-25, EK-12, EK-12, EK-25, EK-51, EK-76, EK- 79, EK-55, EK-30, EK-17, EK-17, EK-30, EK-55, EK- 79,
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
}, },
{// Bishop {// Bishop
// A B C D E F G H // 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-59, EB-42, EB-35, EB-26, EB-26, EB-35, EB-42, EB-59,
EB-30, EB-15, EB- 7, EB- 0, EB- 0, EB- 7, EB-15, EB-30, EB-42, EB-26, EB-18, EB-11, EB-11, EB-18, EB-26, EB-42,
EB-23, EB- 7, EB- 0, EB+ 7, EB+ 7, EB- 0, EB- 7, EB-23, EB-35, EB-18, EB-11, EB- 4, EB- 4, EB-11, EB-18, EB-35,
EB-15, EB- 0, EB+ 7, EB+15, EB+15, EB+ 7, EB- 0, EB-15, EB-26, EB-11, EB- 4, EB+ 4, EB+ 4, EB- 4, EB-11, EB-26,
EB-15, EB- 0, EB+ 7, EB+15, EB+15, EB+ 7, EB- 0, EB-15, EB-26, EB-11, EB- 4, EB+ 4, EB+ 4, EB- 4, EB-11, EB-26,
EB-23, EB- 7, EB- 0, EB+ 7, EB+ 7, EB- 0, EB- 7, EB-23, EB-35, EB-18, EB-11, EB- 4, EB- 4, EB-11, EB-18, EB-35,
EB-30, EB-15, EB- 7, EB- 0, EB- 0, EB- 7, EB-15, EB-30, EB-42, EB-26, EB-18, EB-11, EB-11, EB-18, EB-26, EB-42,
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
}, },
{// Rook {// Rook
// A B C D E F G H // 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 {// Queen
// A B C D E F G H // 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-80, EQ-54, EQ-42, EQ-30, EQ-30, EQ-42, EQ-54, EQ-80,
EQ-40, EQ-20, EQ-10, EQ- 0, EQ- 0, EQ-10, EQ-20, EQ-40, EQ-54, EQ-30, EQ-18, EQ- 6, EQ- 6, EQ-18, EQ-30, EQ-54,
EQ-30, EQ-10, EQ- 0, EQ+10, EQ+10, EQ- 0, EQ-10, EQ-30, EQ-42, EQ-18, EQ- 6, EQ+ 6, EQ+ 6, EQ- 6, EQ-18, EQ-42,
EQ-20, EQ- 0, EQ+10, EQ+20, EQ+20, EQ+10, EQ- 0, EQ-20, EQ-30, EQ- 6, EQ+ 6, EQ+18, EQ+18, EQ+ 6, EQ- 6, EQ-30,
EQ-20, EQ- 0, EQ+10, EQ+20, EQ+20, EQ+10, EQ- 0, EQ-20, EQ-30, EQ- 6, EQ+ 6, EQ+18, EQ+18, EQ+ 6, EQ- 6, EQ-30,
EQ-30, EQ-10, EQ- 0, EQ+10, EQ+10, EQ- 0, EQ-10, EQ-30, EQ-42, EQ-18, EQ- 6, EQ+ 6, EQ+ 6, EQ- 6, EQ-18, EQ-42,
EQ-40, EQ-20, EQ-10, EQ- 0, EQ- 0, EQ-10, EQ-20, EQ-40, EQ-54, EQ-30, EQ-18, EQ- 6, EQ- 6, EQ-18, EQ-30, EQ-54,
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
}, },
{// King {// King
//A B C D E F G H //A B C D E F G H
16, 78, 108, 139, 139, 108, 78, 16, 18, 77, 105, 135, 135, 105, 77, 18,
78, 139, 170, 200, 200, 170, 139, 78, 77, 135, 165, 193, 193, 165, 135, 77,
108, 170, 200, 230, 230, 200, 170, 108, 105, 165, 193, 222, 222, 193, 165, 105,
139, 200, 230, 261, 261, 230, 200, 139, 135, 193, 222, 251, 251, 222, 193, 135,
139, 200, 230, 261, 261, 230, 200, 139, 135, 193, 222, 251, 251, 222, 193, 135,
108, 170, 200, 230, 230, 200, 170, 108, 105, 165, 193, 222, 222, 193, 165, 105,
78, 139, 170, 200, 200, 170, 139, 78, 77, 135, 165, 193, 193, 165, 135, 77,
16, 78, 108, 139, 139, 108, 78, 16 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 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -28,10 +28,11 @@
#include <string> #include <string>
#include <sstream> #include <sstream>
#include "history.h"
#include "movepick.h" #include "movepick.h"
#include "san.h" #include "san.h"
extern SearchStack EmptySearchStack; using std::string;
//// ////
//// Local definitions //// Local definitions
@@ -39,8 +40,6 @@ extern SearchStack EmptySearchStack;
namespace { namespace {
/// Types
enum Ambiguity { enum Ambiguity {
AMBIGUITY_NONE, AMBIGUITY_NONE,
AMBIGUITY_FILE, AMBIGUITY_FILE,
@@ -48,12 +47,11 @@ namespace {
AMBIGUITY_BOTH AMBIGUITY_BOTH
}; };
const History H; // used as dummy argument for MovePicker c'tor
/// Functions
Ambiguity move_ambiguity(const Position& pos, Move m); Ambiguity move_ambiguity(const Position& pos, Move m);
const std::string time_string(int milliseconds); const string time_string(int milliseconds);
const std::string score_string(Value v); 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 /// that the move is a legal move from the position. The return value is
/// a string containing the move in short algebraic notation. /// a string containing the move in short algebraic notation.
const 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(pos.is_ok());
assert(move_is_ok(m)); assert(move_is_ok(m));
@@ -77,7 +75,7 @@ const std::string move_to_san(const Position& pos, Move m) {
to = move_to(m); to = move_to(m);
pt = type_of_piece(pos.piece_on(move_from(m))); pt = type_of_piece(pos.piece_on(move_from(m)));
std::string san = ""; string san = "";
if (m == MOVE_NONE) if (m == MOVE_NONE)
return "(none)"; return "(none)";
@@ -115,10 +113,10 @@ const std::string move_to_san(const Position& pos, Move m) {
san += "x"; san += "x";
} }
san += square_to_string(move_to(m)); san += square_to_string(move_to(m));
if (move_promotion(m)) if (move_is_promotion(m))
{ {
san += '='; 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 // 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 /// 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. /// 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()); assert(pos.is_ok());
MovePicker mp = MovePicker(pos, false, MOVE_NONE, EmptySearchStack, OnePly); MovePicker mp = MovePicker(pos, MOVE_NONE, OnePly, H);
// Castling moves // Castling moves
if (movestr == "O-O-O" || movestr == "O-O-O+") 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. // Normal moves. We use a simple FSM to parse the san string.
enum { START, TO_FILE, TO_RANK, PROMOTION_OR_CHECK, PROMOTION, CHECK, END }; 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; PieceType pt = NO_PIECE_TYPE, promotion = NO_PIECE_TYPE;
File fromFile = FILE_NONE, toFile = FILE_NONE; File fromFile = FILE_NONE, toFile = FILE_NONE;
Rank fromRank = RANK_NONE, toRank = RANK_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++) for (size_t i = 0; i < movestr.length(); i++)
{ {
char type, c = movestr[i]; char type, c = movestr[i];
if (pieceLetters.find(c) != std::string::npos) if (pieceLetters.find(c) != string::npos)
type = 'P'; type = 'P';
else if (c >= 'a' && c <= 'h') else if (c >= 'a' && c <= 'h')
type = 'F'; 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) while ((m = mp.get_next_move()) != MOVE_NONE)
if ( pos.type_of_piece_on(move_from(m)) == pt if ( pos.type_of_piece_on(move_from(m)) == pt
&& move_to(m) == to && move_to(m) == to
&& move_promotion(m) == promotion && move_promotion_piece(m) == promotion
&& (fromFile == FILE_NONE || fromFile == square_file(move_from(m))) && (fromFile == FILE_NONE || fromFile == square_file(move_from(m)))
&& (fromRank == RANK_NONE || fromRank == square_rank(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 /// length of 80 characters. After a line break, 'startColumn' spaces are
/// inserted at the beginning of the new line. /// 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; StateInfo st;
std::stringstream s; std::stringstream s;
std::string moveStr; string moveStr;
size_t length = 0; size_t length = 0;
size_t maxLength = 80 - startColumn; size_t maxLength = 80 - startColumn;
Position p(pos); Position p(pos);
@@ -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 /// It is used to write search information to the log file (which is created
/// when the UCI parameter "Use Search Log" is "true"). /// when the UCI parameter "Use Search Log" is "true").
const std::string pretty_pv(const Position& pos, int time, int depth, const string pretty_pv(const Position& pos, int time, int depth,
uint64_t nodes, Value score, Move pv[]) { uint64_t nodes, Value score, Move pv[]) {
std::stringstream s; std::stringstream s;
// Depth // Depth
@@ -367,7 +365,7 @@ namespace {
if (type_of_piece(pc) == KING) if (type_of_piece(pc) == KING)
return AMBIGUITY_NONE; return AMBIGUITY_NONE;
MovePicker mp = MovePicker(pos, false, MOVE_NONE, EmptySearchStack, OnePly); MovePicker mp = MovePicker(pos, MOVE_NONE, OnePly, H);
Move mv, moveList[8]; Move mv, moveList[8];
int n = 0; int n = 0;
@@ -397,7 +395,7 @@ namespace {
} }
const std::string time_string(int milliseconds) { const string time_string(int milliseconds) {
std::stringstream s; std::stringstream s;
s << std::setfill('0'); 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; std::stringstream s;

View File

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

View File

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

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 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -26,12 +26,7 @@
//// ////
#include "depth.h" #include "depth.h"
#include "history.h" #include "move.h"
#include "lock.h"
#include "movegen.h"
#include "position.h"
#include "tt.h"
#include "value.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 //// Prototypes
//// ////
extern void init_threads(); extern void init_threads();
extern void stop_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 time[], int increment[], int movesToGo, int maxDepth,
int maxNodes, int maxTime, Move searchMoves[]); int maxNodes, int maxTime, Move searchMoves[]);
extern int64_t nodes_searched(); extern int64_t nodes_searched();

View File

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

View File

@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -66,13 +66,14 @@ struct Thread {
SplitPoint *splitPoint; SplitPoint *splitPoint;
int activeSplitPoints; int activeSplitPoints;
uint64_t nodes; uint64_t nodes;
uint64_t betaCutOffs[2];
bool failHighPly1; bool failHighPly1;
volatile bool stop; volatile bool stop;
volatile bool running; volatile bool running;
volatile bool idle; volatile bool idle;
volatile bool workIsWaiting; volatile bool workIsWaiting;
volatile bool printCurrentLine; 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 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -69,7 +69,7 @@ void TranspositionTable::set_size(unsigned mbSize) {
{ {
std::cerr << "Failed to allocate " << mbSize std::cerr << "Failed to allocate " << mbSize
<< " MB for transposition table." << std::endl; << " MB for transposition table." << std::endl;
exit(EXIT_FAILURE); Application::exit_with_failure();
} }
clear(); clear();
} }
@@ -97,14 +97,14 @@ void TranspositionTable::clear() {
/// is bigger than the depth of t2. A TTEntry of type VALUE_TYPE_EVAL /// is bigger than the depth of t2. A TTEntry of type VALUE_TYPE_EVAL
/// never replaces another entry for the same position. /// never replaces another entry for the same position.
void TranspositionTable::store(const 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; TTEntry *tte, *replace;
tte = replace = first_entry(p); tte = replace = first_entry(posKey);
for (int i = 0; i < 4; i++, tte++) 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 // Do not overwrite when new type is VALUE_TYPE_EVAL
if (tte->key() && t == 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) if (m == MOVE_NONE)
m = tte->move(); m = tte->move();
*tte = TTEntry(p.get_key(), v, t, d, m, generation); *tte = TTEntry(posKey, v, t, d, m, generation);
return; return;
} }
else if (i == 0) // replace would be a no-op in this common case 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) if (c1 + c2 + c3 > 0)
replace = tte; replace = tte;
} }
*replace = TTEntry(p.get_key(), v, t, d, m, generation); *replace = TTEntry(posKey, v, t, d, m, generation);
writes++; 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 /// transposition table. Returns a pointer to the TTEntry or NULL
/// if position is not found. /// 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++) for (int i = 0; i < 4; i++, tte++)
if (tte->key() == pos.get_key()) if (tte->key() == posKey)
return tte; return tte;
return NULL; return NULL;
@@ -150,9 +150,9 @@ TTEntry* TranspositionTable::retrieve(const Position& pos) const {
/// TranspositionTable::first_entry returns a pointer to the first /// TranspositionTable::first_entry returns a pointer to the first
/// entry of a cluster given a position. /// 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 /// 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++) 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); p.do_move(pv[i], st);
} }
} }

View File

@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -83,16 +83,22 @@ public:
~TranspositionTable(); ~TranspositionTable();
void set_size(unsigned mbSize); void set_size(unsigned mbSize);
void clear(); void clear();
void store(const Position& pos, Value v, ValueType type, Depth d, Move m); void store(const Key posKey, Value v, ValueType type, Depth d, Move m);
TTEntry* retrieve(const Position& pos) const; TTEntry* retrieve(const Key posKey) const;
void new_search(); void new_search();
void insert_pv(const Position& pos, Move pv[]); void insert_pv(const Position& pos, Move pv[]);
int full() const; int full() const;
private: 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; TTEntry* entries;
uint8_t generation; uint8_t generation;
}; };

View File

@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -41,7 +41,29 @@ typedef __int64 int64_t;
#endif // !defined(_MSC_VER) #endif // !defined(_MSC_VER)
// Hash keys: // Hash keys
typedef uint64_t Key; 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) #endif // !defined(TYPES_H_INCLUDED)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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