Compare commits

..

391 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
Marco Costalba f032ba54c5 Stockfish 1.3.1
Mainteinance version to fix broken Glaurung 2
book reading.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-03 07:49:34 +01:00
Marco Costalba 5a7876d0d0 Revert Glaurung 1 book compatibility patch
It breaks also Glaurung 2 book parsing.

We really need to work on book.cpp, but for now just
leave compatibility just for Glaurung 2 books.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-03 07:46:27 +01:00
Marco Costalba e87931bbfc Stockfish 1.3
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-02 11:53:08 +01:00
Marco Costalba aa5c375ca9 Fix a very old UCI option parsing bug
We currently fail on an option with a sapece in the name,
as example

setoption name Clear Hash

returns error message "Option Clear not found". This
patch fixes this off-by-one type bug.

Thanks to Joona for spotting this.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-02 11:52:49 +01:00
Marco Costalba cd1cc39b04 Nicely simplify MovePicker::pick_move_from_list
It is a positive fall back from previous patch.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-02 10:08:10 +01:00
Marco Costalba 4e151f7e0d Sort moves just after scoring
Instead of a delayed selection sort so that the highest
score move is picked up from the list when needed, sort all
the moves up front just after score them.

Selection sort is O(n*n) while std::sort is O(n*log n), it
is true that delayed selection allows us to just pick the move
until a cut off occurs or up to a given limit (12), but with
an average of 30 non capture-moves delayed pick become slower
just after 5-6 moves and we now pick up to 12.

Profiling seem to prove this idea and movepick.cpp is now 10%
faster.

Also tests seem to confirm this:

After 700 games at 1+0: Mod vs Orig +178 -160 =362 +9 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-05-02 10:07:46 +01:00
Marco Costalba d13e4c16c2 Update polyglot.ini
Upadte to new parameters and parameters values.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-04-30 15:16:35 +01:00
Marco Costalba 1906df4494 Stockfish 1.3 rc1
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-04-30 09:18:20 +02:00
Marco Costalba 39f2eda285 Do not razor after a null move
We don't want to return unproven null move fails high, so
that if a position is so good that null move fails high we
want to check this with real do_move() / undo_move() test,
not just razoring the position because, from the opponent
point of view, is very bad.

These are tests results at 1+0

Mod vs Orig +252 -264 =483  49.40%
Mod vs Toga II 1.4.1SE  +365 -325 =309  52.00%

So it seems a very slightly regression regarding orig version (but
withing error bar) and a nice increase against Toga that is what we
are interested most. Orig version scores 49.75% against Toga, so
we welcome this change ;-)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-04-30 08:55:38 +02:00
Marco Costalba 00a3380885 Fix assignment of pv[0] when creating root move list
It is bogusly assigned from moves[i].move instead of mlist[i].move
or equivalently to moves[count].move that it seem more clear to me.

Bug is hidden while all the moves are included, in this default case
moves[i].move and mlist[i].move are the same variable.

Also a bit of cleanup while there.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-04-29 16:01:57 +02:00
Marco Costalba f1d982e2c0 Merge Joona's razoring tweaks
After proof testing on 3 different engines these
are the results:

Stockfish - Toga II 1.4.1SE +130 -132 =132 49.75%
Stockfish - Deep Sieng 3.0  +145 -110 =150 54.45%
Stockfish - HIARCS 12 MP    +94  -149 =150 43.00%

So it seems no regressions occurs, although also no
improvment. But anyhow this patch increases Stockfish
strenght against itself, so merge it.

Note that this patch not only adds back razoring at depth
one, but also increases razor depth limit from 3 to 4
because hard coded depth 4 limit is no more overwritten
by UCI parameter that otherwise defaults to 3.
2009-04-28 09:00:09 +02:00
Marco Costalba fbca16da57 Hardcode depth limit for selective search
Because futility margins array has a fixed size we cannot
arbitrarly choose or change the SelectiveDepth parameter,
otherwise we have a crash for values bigger then array size.

On the other hand tweaking of this parameter requires some
modification to the hardcoded margins, so makes sense to hard
code also this very bounded one.

Who wants to experiment is of course free to change the sources.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-04-28 08:47:26 +02:00
Marco Costalba 1e97cdd9f3 Fix a warning under MSVC
Somehow silly warning C4800:
'int' :forcing value to bool 'true' or 'false'(performance warning)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-04-27 18:00:45 +01:00
Marco Costalba ab69f50c64 Micro optimize Position::move_is_check()
More then optimization it is worth a bit of better
code self documenting.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-04-27 17:39:59 +02:00
Marco Costalba b35e593551 Inline Position::move_is_capture()
This is a very hot path function, profiling on Intel compiler
shows that inlining cuts in half the overhead.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-04-27 16:36:33 +02:00
Marco Costalba 20d88dbf98 Retire timeoday.cpp
Move the only function gettimeofday in misc.cpp
where is used.

This avoids polluting the global namespace.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-04-27 13:48:14 +01:00
Marco Costalba ef60043725 Small cleanup in misc.cpp
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-04-27 13:38:47 +01:00
Marco Costalba 2f2e48fad2 Code style cleanup in transposition table code
Assorted fixes but no functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-04-27 13:21:49 +01:00
Marco Costalba 2550c6383b Fix a bogus assert in tt.cpp
Max hash size is 4096 MB, not 1024 MB, see the corresponding
"Hash" UCI parameter in ucioption.cpp

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-04-27 10:29:33 +01:00
Marco Costalba fb560fa5d7 Convert piece.cpp to C++
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-04-27 10:12:34 +01:00
Marco Costalba 11491e71ee Remove an useless comparison in futility pruning
Currently futility is allowed when depth < SelectiveDepth
and SelectiveDepth is 7*OnePly, so the comprison is
always true.

Patch could introduce a functional change only if
we choose to increase SelectiveDepth.

Currently no functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-04-27 09:45:15 +01:00
Marco Costalba bd26374f21 Small code tidy up and test results
When testing at 1'+0" time control results are still
reasonably good. We have made two sessions on two
different PC.

After 840 games Mod - Orig: +221 -194 =425 +10 ELO (two CPU)

After 935 games Mod - Orig: +246 -222 =467  +9 ELO (single CPU)

So it seems that with fast CPU and/or longer time controls
benefits of the patch are a bit reduced. This could be due
to the fact that only 3% of nodes are pruned by razoring at
depth one and these nodes are very swallow ones, mostly get
pruned anyway with only a slightly additional cost, even
without performing any do_move() call.

Another reason is that sometime (0,3%% of cases) a possible
good move is missed typically in positions when moving side
gives check, as example in the following one

3r2k1/pbpp1nbp/1p6/3P3q/6RP/1P4P1/P4Pb1/3Q2K1 w - -

The winning move Rxg7+ is missed.

Bottom line is that patch seems good for blitz times, perhaps
also for longer times. We should test against a third engine
(Toga ?) to have a final answer regarding this new setup.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-04-26 13:51:54 +01:00
Joona Kiiski d20e0cf048 Razor again at depth one
Some time ago it was found by Marco Costalba that it's better
to disable razoring at depth one, because given the very low
evaluation of the node, futility pruning would already do
the job at very low cost and avoiding missing important moves.

Now enable razoring there again, but only when our quickly evaluated
material advantage is more than a rook. The idea is to try razoring
only when it's extremely likely that it will succeed.

Extreme lightning speed test show promising result:
Orig - Mod: +1285 =1495 -1348

This needs to be tested with longer time controls though.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-04-26 13:51:50 +01:00
Joona Kiiski 342ceb1c91 Make futility and razor margins more tunable
Restructure RazorMargins and FutilityMargins arrays so that their
values can be more easily tuned.

Add RazorApprMargins array which replaces razorAtDepthOne concept,
because setting RazorApprMargin very high value at ply one is
same as not razoring there at all.

Comment out setting razoring and futility margins through uci to
avoid errors while tuning.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-04-26 13:51:47 +01:00
Marco Costalba f010b6db71 Do not hardcode default values of UCI variables
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-04-26 13:41:17 +01:00
Marco Costalba 7c267587fc Greatly speedup has_mate_threat()
Instead of loop across all legal moves to find a mate
loop across possible check moves only.

This reduces more then 10 times the number of moves to
check for a possible mate.

Also rename generate_checks() in generate_non_capture_checks()
so to better clarify what the function does.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-04-26 13:40:26 +01:00
Marco Costalba 24485c96ec Micro optimize generate_piece_checks() take 2
Add some missing bits of this patch.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-04-19 21:09:53 +02:00
Joona Kiiski f98385e129 Add missing header file to make stockfish compile with latest Inter C++ Compiler under Linux (memcpy needs cstring)
Correct some references glaurung -> stockfish in Makefile

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-04-19 20:57:23 +01:00
Marco Costalba 2acc89c6e8 Simplify Position::is_mate()
Should be a bit faster too.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-04-19 17:13:04 +01:00
Marco Costalba a52ab2afbf Micro optimize generate_piece_checks()
Avoid calculating piece attacks if there aren't
available check sqaures for the given piece.

About 15% of cases. Not a biggie but still something
especially in the middle game where king is well covered
inside his castle.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-04-18 16:28:12 +01:00
Marco Costalba de050db2b0 MovePicker: retire per square MVV/LVA ordering
Is not used anyway and in case we need it again we
can resurrect from git archives.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-04-18 14:24:21 +01:00
Marco Costalba e68ebe618c In qsearch store the cut move in TT
And upon reentering the same position try it as first.

Normally qsearch moves order is already very good, first move
is the cut off in almost 90% of cases. With this patch, we get
a cut off on TT move of 98%.

Another good side effect is that we don't generate captures
and/or checks when we already have a TT move.

Unfortunatly we found a TT move only in 1% of cases. So real
impact of this patch is relatively low.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-04-18 14:04:00 +01:00
Marco Costalba 4634be8ba6 Merge Joona's new aspiration window search
It seems very positive.

After 999 games at 1'+0" result is: +249 -216 =534 +11 ELO

And after another 456 games we still have: +122 -113 =221
2009-04-18 09:15:42 +01:00
Marco Costalba e7f03913ea Introduce move_pawns() helper in movegen.cpp
This let us to have more readable code keeping the
same speed.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-04-18 09:13:31 +01:00
Marco Costalba e30720b0bf Remove failHigh/Low bits from IterationInfoType
We don't use that info anyway.

Also document a little more new aspiration window code.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-04-18 09:12:41 +01:00
Joona Kiiski 7af1b40b4e Restore calling insert_pv after search is aborted + small clean-up
Restore old behaviour that after search is aborted we call insert_pv,
before breaking out from the iterative deepening loop.

Remove one useless FIXME and document other better.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-04-18 09:12:18 +01:00
Marco Costalba ecec7dbf89 Little code style tweaks
Let the code be more conformant to current style.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-04-18 09:12:07 +01:00
Marco Costalba 8da2153ee8 Revert previous patch as per Joona request
Joona says patch gives bad results after testing,
so revert for now.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-04-18 09:11:56 +01:00
Joona Kiiski 22f9f0cabe Improve handling of fail-highs in assumed PV
Check all fail highs in assumed PV with greater care (fruit/Toga already does this).
Add a flag when aspiration search fails high at ply 1 to prevent search to
be terminated prematurely.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-04-18 09:11:41 +01:00
Joona Kiiski 3e7e1a7c53 Revert "Implement a fallback system when aspiration search fails low and we are out of time."
This reverts commit 55dd98f7c717b94a659931cd20e088334b1cf7a6.

Revert fallback-system for root_search

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-04-18 09:11:30 +01:00
Joona Kiiski 0ea716463b Implement a fallback system when aspiration search fails low and we are out of time.
However also this patch is immediately reverted. For three reasons:
1) the case it affects is very rare (and then we are likely to lose anyway),
   so we can well live without this.

2) Because the case is so rare it's hard to test this change properly.

3) To perform fallback search, we must reset so many global variables that this
   patch is very likely both buggy and extremely bad style.

Consider including this again if we clean-up global variables one day...

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-04-18 09:11:15 +01:00
Joona Kiiski 6c4e36aab6 Revert "Implement bestValue in root_search."
This reverts commit 9a39f93f35254787b7b57980019dde276a89c48c.

Revert bestValue in root_search

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-04-18 09:11:05 +01:00
Joona Kiiski 6f28bcd483 Implement bestValue in root_search.
However just after finished writing this patch I realized that this
is not the way to go. So this will be immediately reverted.

(Just save this here in git in case I change my mind later :) )

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-04-18 09:10:54 +01:00
Joona Kiiski acef5d6a59 Dynamic aspiration search without research.
Implement system where aspiration search window is calculated using
values from previous iterations.

And then some crazy experimental stuff: If search fails low at the root,
don't widen window, but continue and hope we will find a better move
with given window. If search fails high at the root, cut immediately,
add some more time and start new iteration.

Note: this patch is not complete implementation, but a first test
for this idea. There are many FIXMEs left around. Most importantly
how to deal with the situation when we don't have any move!

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-04-18 09:10:41 +01:00
Marco Costalba 44b497a972 Re-fix square.h warning to avoid a compile error under MSVC
This fix adds ugliness to an already ugly previous fix...hopefully
it is the last one :-(

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-04-13 12:02:22 +01:00
Marco Costalba b893583bb6 Fix a gcc warning due to order of initialization in Option
Move idx declaration before minValue and maxValue and silence
this last warning.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-04-13 12:02:14 +01:00
Marco Costalba e81d0d08c3 Fix a compile error with Intel icc
To make std::sort() work operator<() should be
declared const.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-04-13 12:02:06 +01:00
Marco Costalba 72c7595f8a Fix a warning under Intel compiler in square.h
We need to cast to char the whole expression...

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-04-13 12:01:55 +01:00
Marco Costalba e38ad4d42b Fix a very nasty conversion bug in Option c'tor
Sometimes C++ can be really bad!

In this case an hard coded c string selects Option c'tor
with int argument instead of the std::string one becuase
it is considered a better matching by the compiler.

Fix the bug changing the argument type from std::string to
const char* so to be a better match then the int one.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-04-12 01:10:50 +01:00
Marco Costalba fad772f387 Store UCI options of type CHECK according to C++ convention
Store boolean values as "1" and "0" instead of "true" and "false"
and convert back to UCI protocol convention when needed.

This is simpler then the other way around.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-04-11 16:01:33 +01:00
Marco Costalba ebb0f31928 Restore original UCI option printing order
For each option store its index so to be printed
according to insertion order.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-04-11 16:01:21 +01:00
Marco Costalba f0701e2b0f Use a map instead of a vector to store UCI options
Apart from the teoretical speed increase, the main reason
of this patch is a good amount of code cleanup.

Note that now UCI options are printed in alphabetical
order and not in insertion order as before. Next patch
will take care of restoring old behaviour.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-04-11 16:01:08 +01:00
Marco Costalba 95aadb5e53 Remove unused currentMoveCaptureValue from search stack
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-04-11 11:09:37 +01:00
Marco Costalba 17ef886fc3 Less aggressive null move dynamic reduction
In null move search do not jump directly in
qsearch() from depth(4*OnePly), but only
from depth(3*OnePly).

After 999 games at 1+0: +248 -224 =527 +8ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-04-11 10:58:10 +01:00
Marco Costalba 8590a6f3b7 Revert dynamic LMR
It doesn't seem to work against Toga. After more then 400 games
we are at -13 ELO while, without it we are at + 5 ELO after 1000
games.

So revert for now to keep code simple.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-04-03 20:34:22 +01:00
Marco Costalba 7b05b83bf2 Fix compile in the debug mode
Due to previous patches we end up with a compile
error in debug mode.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-03-31 20:50:24 +01:00
Marco Costalba d7ef09727a Silence idiotic warning on two's complement of an unsigned
MSVC gives:

warning C4146: unary minus operator applied to unsigned type,
               result still unsigned

When finds -b where b is an unsigned integer. So rewrite the two's
complement in a way to avoid the warning. Theoretically the new
version is slower, but in practice changes nothing.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-03-31 20:50:10 +01:00
Marco Costalba 683595fee1 Silence a bunch of warnings under MSVC /W4
Still some remain, but are really the silly ones.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-03-31 20:49:56 +01:00
Marco Costalba 659c54582d Revert setting a flag when TT value equals static evaluation
Strangely enough it seems that optimization doesn't work.

After 760 games at 1+0: +155 -184 =421 -13 ELO

Probably the overhead, although small, for setting the flag
is not compensated by the saved evaluation call.

This could be due to the fact that after a TT value is stored,
if and when we hit the position again the stored TT value is
actually used as a cut-off so that we don't need to go on
with another search and evaluation is avoided in any case.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-03-31 20:41:06 +01:00
Marco Costalba 2c0cd95ecf An VALUE_TYPE_EVAL score cannot overwrite an entry
If we want to store a value of type VALUE_TYPE_EVAL for
a given position and we found an already exsisting entry
for the same position then we skip.

We don't want to overwrite a more valuable score with a
lesser one. Note that also in case the exsisting entry is
of VALUE_TYPE_EVAL type the overwrite is unuseful because
we would store the same score again.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-03-30 09:09:27 +01:00
Marco Costalba 6a8e46d53e Remember when TT value equals static evaluation value
When the stored TT value equals the static value set a
proper flag so to not call evaluation() if we hit the
same position again but use the stored TT value instead.

This is another trick to avoid calling costly evaluation()
in qsearch.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-03-30 08:54:09 +01:00
Marco Costalba c6c4713ab2 Document TTEntry and move layouts
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-03-30 08:29:02 +01:00
Marco Costalba 9e44a6dba9 A move needs 17 bits not 19
Fix a bug in the way a move is stored and read in a TT entry.
We use a mask of 19 bits insteaad of 17 so that the last
two bits in the TT entry end up to be random data.

This bug will bite us when we will use these two until now
unused bits.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-03-29 17:23:41 +01:00
Marco Costalba 941f4e1643 Remove some obsolete code in movepick.cpp
This fixes some warning under Intel compiler.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-03-27 19:35:08 +01:00
Marco Costalba dcdac83187 Revert storing of TT when returning from "stand pat"
After testing it seems patch is bad:

After 999 games 1+0: +242 -271 =486 -10 ELO

So restore saving of TT at the end but using new Joona
idea of storing as VALUE_TYPE_UPPER/VALUE_TYPE_LOWER instead
of VALUE_TYPE_EXACT.

Some optimization is still possible but better test new ideas
one by one.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-03-27 15:30:45 +01:00
Marco Costalba 5a0581498c Cache evaluation score in qsearch
Instead of just drop evaluation score after stand pat
logic save it in TT so to be reused if the same position
occurs again.

Note that we NEVER use the cached value apart to avoid an
evaluation call, in particulary we never return to caller
after a succesful tt hit.

To accomodate this a new value type VALUE_TYPE_EVAL has been
introduced so that ok_to_use_TT() always returns false.

With this patch we cut about 15% of total evaluation calls.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-03-24 18:28:42 +01:00
Marco Costalba 1c087dd806 Let to toggle dynamic LMR
It is now disabled by default due to bad results
against a pool of engines...more testing is needed tough.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-03-24 18:28:25 +01:00
Marco Costalba 095a96b461 In qsearch update TT only if returning from stand pat
This is the only "correct" exact value we can store.

Otherwise there could be spurious failed high/low nodes.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-03-24 11:26:43 +01:00
Marco Costalba 72af519e7f When asked for position key print it as an hex value
Merged from Glaurung current development snapshot.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-03-24 10:50:13 +01:00
Marco Costalba db46602b1f Wait at least until iteration 3 before to stop the search
It was 2 before.

Merged from Glaurung current development snapshot.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-03-24 10:49:02 +01:00
Marco Costalba d3f99aea6b Let zobrist keys to be compatible with Glaurung 1
Some changes to the zobrist keys, to make them identical
to those used by Glaurung 1.

The only purpose is to make it possible for both programs
to use the same opening book.

Merged from Glaurung current development snapshot.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-03-24 10:40:22 +01:00
Marco Costalba 0e835bd334 Fixed a sliding attack bitboard bug in 32-bit mode
This is what prevented USE_32BIT_ATTACKS from working
on some architectures (like PowerPC).

Merged from Glaurung current development snapshot.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-03-24 10:30:27 +01:00
Marco Costalba 43276cbec5 Fix a bug in insert_pv() where minimum depth is zero
We implicitly considered the minimum depth stored in TT
to be Depth(0), but because we store values in TT also in
qsearch() where depth is < 0, we need to use a negative
number as minimum depth.

Bug spotted by Joona Kiiski.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-03-23 15:30:20 +01:00
Marco Costalba a9e55d4326 Revert odd depths razoring
I have just made a new rule that no modification
that increases pruning is allowed if after 1000 games
ELO is not increased by at least 10 point (was +5 in this case)

Yes, I like this kind of nosense rules :-)
2009-03-23 12:02:15 +01:00
Marco Costalba 4d70e3aeac More aggressive dynamic LMR
Previous setup didn't change anything

After 996 games 1+0: +267 -261 =468 +2 ELO

Now with this new setup we have

After 999 games 1+0: +277 -245 =477 +11 ELO

Seems reasonable...

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-03-23 11:58:28 +01:00
Marco Costalba 24b7ad54c7 LMR dynamic reduction
Reduce of two plies near the leafs and when we still
have enough depth to go so to limit horizon effects.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-03-22 23:53:22 +01:00
Marco Costalba 0ff3bf34cd Always print a best move when requested
Little fix merged from iPhone Glaurung.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-03-22 23:53:10 +01:00
Marco Costalba 66d165921d Better castle move detector in move_to_san()
Merged from iPhone Glaurung.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-03-22 23:52:59 +01:00
Marco Costalba b82c3021fa Fix a smal bug in Position::from_fen
We could fail to parse an en-passant position
in same cases.

Merged from iPhone Glaurung.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-03-22 23:52:23 +01:00
Marco Costalba 320630ca1a Merge new pawn storm evaluation
More accuracy in pawn storm evaluation
directly from iPhone Glaurung.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-03-22 23:52:06 +01:00
Marco Costalba ef8acdc73b Fix a small bug in king safety
Merged from iPhone Glaurung.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-03-22 13:11:24 +01:00
Marco Costalba cc8e915ed5 Merge KBPP vs KB endgame from iPhone Glaurung
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-03-22 13:06:29 +01:00
Marco Costalba 16abc165d8 Fix: In qsearch do not use TT value when in a PV node
We already do like this in search_pv(), so extend
also in qsearch().

Bug spotted by Joona Kiiski.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-03-21 14:51:31 +01:00
Marco Costalba 74160ac602 Big headers cleanup
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-03-19 12:55:32 +01:00
Marco Costalba feb5342b39 Safe guard some wild and ugly casts
These casts are needed but plain ugly, at least be
sure they don't hide any subtle conversion bug.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-03-16 13:59:41 +01:00
Marco Costalba 6cddf9183c Partially revert pawns storm bug fix
Try to save space and use the minimum size
possible.

In particular restore int16_t for values and int8_t
for halfOpenFiles.

Use int16_t for storm values insted of int and also
instead of original buggy and too small int8_t.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-03-16 08:02:33 +01:00
Marco Costalba b870f5a091 Silence a good bunch of Intel warnings
Note that some pawns and material info has been switched
to int from int8_t.

This is a waste of space but it is not clear if we have a
faster or slower code (or nothing changed), some test should be
needed.

Few warnings still are alive.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-03-15 18:19:08 +01:00
Marco Costalba fcecc5212e Fix an overflow bug in pawns stormValue
These fields are defined as int8_t but values bigger
then 127 are stored there so that we silently overflow.

Fix bringing up all the fields to a sane int type. This
will increase memory usage, but apart from being safe, it is
not clear if code is slower or faster. Test is needed.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-03-15 18:18:56 +01:00
Marco Costalba 8de91be61e Fix a silly warning on Intel compiler
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-03-15 18:18:42 +01:00
Marco Costalba ca4e78db8d Revert NULL move beta corrections
After testing result is bad -25 ELO
2009-03-15 16:44:12 +01:00
Marco Costalba bfcfaf7101 Retire Null Driven IID
It does not seem to clearly improve things and
in any case is disabled by default, so retire for now.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-03-15 16:43:28 +01:00
Marco Costalba c8773c720a Merge Joona Kiiski NULL search beta correction
Prune more moves after a null search because of
a lower beta limit then in main search.

In test positions reduces the searched nodes of 30% !!!!

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-03-14 13:00:22 +01:00
Marco Costalba 3ed603cd64 Merge Joona Kiiski evaluation tweaks
Merge tewaks to many evaluation parameters
by Joona Kiiski.

After test they seem good!

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-03-14 12:55:14 +01:00
Marco Costalba f637ddc1e8 Micro optimize move_is_check()
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-03-07 21:05:49 +01:00
Marco Costalba 964bd86272 Micro optimize pl_move_is_legal()
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-03-07 21:05:31 +01:00
Marco Costalba 72b88e09e1 Micro optimize previous patch
Also remove some Intel warnings, not all :-(

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-03-06 20:47:19 +01:00
Marco Costalba 3e663d8c50 Introduce evaluate_pieces<>() to remove redundancy
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-03-06 19:19:45 +01:00
Marco Costalba 8c9c51c721 Fix compile error with inlines under gcc and Intel
It seems that these compilers do not like inline functions
that call a template when template definition is not in scope.

So move functions from header to in *.cpp file

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-03-05 00:38:45 +01:00
Marco Costalba 7fe1632a49 Fix some comments in position.cpp
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-03-04 22:51:20 +01:00
Marco Costalba 7c84b39a42 Avoid to call useless sliders attacks in update_checkers()
Quickly filter out some calls to sliders attacks
when we already know that will fail for sure.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-03-04 22:51:04 +01:00
Marco Costalba 68e711aac6 Super fast hidden_checkers()
Rewritten hidden_checkers() to avoid calling
sliders attacks functions but just a much
faster squares_between()

Also a good code semplification.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-03-04 22:50:51 +01:00
Marco Costalba 02cd96e4c2 Cleanup SearchStack initialization
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-03-03 21:01:00 +01:00
Marco Costalba 772a37cd54 Micro optimize copy of new state in do_move()
Instead of copying all, copy only the fields that
are updated incrementally, not the ones that are
recalcuated form scratch anyway.

This reduces copy overhead of 30%.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-03-02 18:00:42 +01:00
Marco Costalba c02613860a Revert hidden checkers rework
It is slower the previous uglier but faster code.

So completely restore old one for now :-(

Just leave in the rework of status backup/restore in do_move().

We will cherry pick bits of previous work once we are sure
we have fixed the performance regression.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-03-02 16:20:00 +01:00
Marco Costalba 9b6b9e67fe Use checker info to remove a bunch of hidden checks updates
Another powerful condition let us remove a big chunk of
useless updates.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-28 18:43:36 +01:00
Marco Costalba 6a8cfe79da Stricter condition to check for dc candidates
Another optimization that let us remove another half
of find_hidden_checks(them, DcCandidates) calls.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-28 18:43:20 +01:00
Marco Costalba 1f97b48a31 Split calculation of pinners from dc candidates
This let us to calculate only pinners when we now that
dc candidates are not possible.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-28 18:43:02 +01:00
Marco Costalba a96cba0ec8 Slightly better condition in update_hidden_checks()
Use a more strict condition to check if we have captured
an opponent pinner or hidden checker.

With this patch the occurrence of checkerCaptured == true are
reduced of 50%.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-28 18:42:51 +01:00
Marco Costalba f9f30412e7 Compute pinned and friends incrementally
In do_move() use previous pinned bitboards values to compute
the new one after the move. In particulary we end up with the
same bitboards in most cases. So detect these cases and just
keep the old values.

This should speedup a lot this slow computation in a very hot
path so that we can use this important info everywhere in the
code at very cheap cost.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-28 18:42:30 +01:00
Marco Costalba 55f9afee2a Fix a subtle bug due to the StateInfo pointer became stale
There was one occurence when the StateInfo variable went
out of scope before the corresponding Position object.

This yelds to a crash. Bug was not hit before because occurs
only when using an UCI interface and not the usual benchmark.

The fix consists in copying internally the content of the
about to stale StateInfo.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-23 21:45:12 +01:00
Marco Costalba 962216440c Teach SEE about pinned pieces
Remove pinned pieces from attacks when calculating
SEE value.

Algorithm is not perfect, there should be no false
positives, but can happen that we miss to remove a
pinned piece. Currently we don't cach 100% of cases,
but is a tradeoff between speed and accuracy. In any
case we stay on the safe side, so we remove an attacker
when we are sure it is pinned.

About only 0,5% of cases are affected by this patch, not
a lot given the hard work: this is a difficult patch!

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-23 21:45:01 +01:00
Marco Costalba 243fa483d7 Small Position::clear() cleanup
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-23 21:44:46 +01:00
Marco Costalba da7a62852a Do not copy the whole old state in do_move()
Instead of copy the old state in the new one, copy only
fields that will be updated incrementally, not the ones
that will be recalculcated anyway.

This let us copy 13 bytes instead of 28 for each do_move()
call.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-23 21:44:29 +01:00
Marco Costalba 0bf45823da Update pinned bitboards and friends in do_move()
Probably is slightly slow, but code is surely better
in this way. We will optimize later for speed.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-23 21:44:17 +01:00
Marco Costalba 4324276419 Fix some asserts unhidden by a debug compile
Fallback form previous patches.
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-23 21:44:04 +01:00
Marco Costalba 43bc5479c2 Avoid resetting pinners[c]
Small optimization. No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-22 21:19:04 +01:00
Marco Costalba 8f59de48f5 Introduce StateInfo instead of UndoInfo
We don't backup anymore but use the renamed StateInfo
argument passed in do_move() to store the new position
state when doing a move.

Backup is now just revert to previous StateInfo that we know
because we store a pointer to it.
Note that now backing store is up to the caller, Position is
stateless in that regard, state is accessed through a pointer.

This patch will let us remove all the backup/restore copying,
just a pointer switch is now necessary.

Note that do_null_move() still uses StateInfo as backup.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-22 21:18:50 +01:00
Marco Costalba 2f6c5f00e6 Wrap state variables in a named struct
This will allow us to more easily move the state
out of Position class.

No functioanl change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-22 21:18:35 +01:00
Marco Costalba 2f21ec39ad Convert also undo_null_move() to avoid passing UndoInfo object
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-22 21:18:14 +01:00
Marco Costalba 9b257ba29d Passing UndoInfo is not needed anymore when undoing the move
We store it now in the same UndoInfo struct as 'previous'
field, so when doing a move we also know where to get
the previous info when undoing the back the move.

This is needed for future patches and is a nice cleanup anyway.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-22 21:18:02 +01:00
Marco Costalba 1b0fee9b17 Remove two useless calls to pinned_pieces()
Are obsoleted by new pinned caching code.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-22 21:17:44 +01:00
Marco Costalba b7cb6180cf Position: Unify and templetize mg_pst() and eg_pst()
Also templetize compute_value() can be simpler now that
the above is templetized too.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-20 22:50:35 +01:00
Marco Costalba f30aa83f8a Unify compute_mg_value() and compute_eg_value()
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-20 22:50:20 +01:00
Marco Costalba 1dc27f3232 Use a union to fast and simply backup info in do_move()
This nice union trick let us optimize the speed and
remove the now unuseful backup() and restore() functions.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-20 22:50:08 +01:00
Marco Costalba 95cfc0e306 In Position backup and restore contiguous data
Give the compiler one more chance to optimize the copy.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-20 22:49:54 +01:00
Marco Costalba 9e1d142fdd Finally remove any occurence of dcCandidates from search.cpp
This ends our cleanup series.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-19 17:35:23 +01:00
Marco Costalba 683e6dc656 Do not pass discovery check candidates in Position::do_move()
Also remove any bit of 'pinned' and co. from MovePicker class.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-19 17:29:36 +01:00
Marco Costalba c6630abe0d Do not pass pinned argument in Position::move_is_check()
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-19 17:01:08 +01:00
Marco Costalba 734941672e Do not pass pinned argument in Position::pl_move_is_legal()
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-19 16:48:57 +01:00
Marco Costalba 0a0ea36e25 Cleanup pinned and friends in movegen.cpp
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-19 16:37:03 +01:00
Marco Costalba 5f142ec209 Cache pinned and discovery check bitboards
After have been calculated cache their values
so to avoid another expensive call to hidden_checks()
if pinned_pieces() or discovered_check_candidates() are
called with the same position.

Add also interface to get pinners bitboard, we already have
this value so save it instead of discard.

Now that, after the first call to pinned_pieces() the following
are very cheap we can rewrite and cleanup all the checking handling.

So this patch is a prerequisite for future work.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-19 16:28:35 +01:00
Marco Costalba 7f4f18f959 Revert mobility of pinned pieces for now
We will redo after rewriting the handling of
pinned bitboard and its friends.
2009-02-19 15:49:54 +01:00
Marco Costalba c45818e9f8 Remove xxx_of_color() for real
Remove also from assert expressions. Was hidden
in release mode.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-17 17:26:15 +01:00
Marco Costalba 7013efce4e Change piece_attacks_square() API
An extra argument let us simplify some code.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-17 12:00:05 +01:00
Marco Costalba 9f5b709db7 Mobility is zero for a pinned piece
A little bit more overhead, but better mobility evaluation.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-17 11:29:14 +01:00
Marco Costalba 2c955f25de Remove xxx_of_color() helpers
They hide the underlying uniform function call with
no benefit.

A little bit more verbose but now is clear what happens.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-17 10:54:47 +01:00
Marco Costalba f32992f88c Avoid a call to move_is_capture() in extension()
Pass value as an argument instead or recalculating it.
Altough call is cheap this is a very hot path so with
this patch total time spent for move_is_capture() is almost
halved.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-13 20:57:03 +01:00
Marco Costalba e71d520758 Add scan for X-ray attacks in piece_attacks_square()
Used to avoid pruning interesting moves.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-13 20:56:46 +01:00
Marco Costalba 52ed0e9563 Fix a subtle bug in Position::move_is_capture()
Currently fails if we test with a move that is not of
from the side to move but from the opponent.

This is the typical case of the threat from null move
search. The result is an erroneus prune of the defending
moves, see PruneDefendingMoves in ok_to_prune()

Fix the test to work also with threat moves.

Bug was always in but was unhidden by a patch of 17/12/2008
"Trigger of PawnEndgameExtension if capture is not a pawn"

Until then it was hidden by a tricky check in the prune
conditions instead of the natural move_is_capture()

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-13 20:56:26 +01:00
Marco Costalba 30e8f0c9ad Do not manually build endgame functions hash keys
Use Position::compute_material_key() to do the job,
so we are sure there is not key mismatch during
endgame function lookups.

This fixes two endgames hash errors that caused two
endgames to be disabled.

This patch is also a code cleanup because removes a lot
of messy key assignments.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-13 20:55:59 +01:00
Marco Costalba 67375f4693 Use template for endgame scaling functions
Also integrate scaling and evaluation in a
single base class.

Nice use of templates here :-)

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-13 20:55:29 +01:00
Marco Costalba 039badfda8 Use templates for end game evaluation functions
Huge simplification and no speed cost penalty.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-13 20:55:14 +01:00
Marco Costalba 088ecc242f Small code formatting in position.cpp
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-13 20:54:56 +01:00
Marco Costalba a188a047ab Use update_checkers<>() also for PAWN
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-13 20:54:37 +01:00
Marco Costalba 1d2247aea3 Introduce update_checkers() to simplify do_move()
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-13 20:54:17 +01:00
Marco Costalba 8365f8ac1e Remove square_is_attacked()
Use attacks_to() instead. No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-13 20:53:58 +01:00
Marco Costalba 68d36b6f59 Rename generate_piece_blocking_evasions()
In generate_piece_moves() to be more uniform with other
functions. Unfortunatly the different number of calling arguments
do not allow us to easily integrate in generate_piece_moves()
template family.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-13 20:53:39 +01:00
Marco Costalba 33c608e140 Final touches to generate_evasions()
Small code tidy up and a little optimization
to avoid calling generate_piece_blocking_evasions()
when blockSquares is empty (30% of cases).

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-13 20:53:13 +01:00
Marco Costalba ff60dafe8d Simplify legality check in generate_evasions()
Now that we have removed sliders checkers attacks
from evasion's set we can simplyfy legality check.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-13 20:52:52 +01:00
Marco Costalba 214f9dcc27 generate_evasions() avoid an usless check for enpassant case
Remove ugly and useless code.
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-11 19:01:26 +01:00
Marco Costalba 1dc1cecf01 Optimize generate_piece_blocking_evasions()
Rewrite as in generate_piece_moves() using a for
loop instead of the slower serializing of the
bitboard with pop_1st_bit()

This will allow also to merge with generate_piece_moves()
when we will drop legality constrain on generate_evasions()

Generated moves are not changed, but are generated in a
different order, this changes the number of nodes at fixed
depth test.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-11 19:01:06 +01:00
Marco Costalba 67535711e8 generate_evasions() avoid to calculate pinned pieces
Pass as function argument.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-11 19:00:52 +01:00
Marco Costalba 56f607fe0f Drop a double semicolon
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-11 19:00:35 +01:00
Marco Costalba 9d044cf4ee Last touches to movegen.cpp
Of course no functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-10 19:01:51 +01:00
Marco Costalba 769f2fdecb Remove special case of pawn checks generation
Also additional renaming.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-10 19:01:49 +01:00
Marco Costalba 9bffe811c4 Remove special case of pawn move generatation
Code cleanup. No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-10 19:01:47 +01:00
Marco Costalba 3e20c6c07d Simplify generate_evasions()
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-10 19:01:45 +01:00
Marco Costalba 4f5f97107e Simplify generate_checks()
Also rearrange signatures to be uniform.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-10 19:01:43 +01:00
Marco Costalba 151d47dc85 Micro-optimize do_generate_pawn_checks()
Discovery check candidates are normally empty, so
avoid discovery checks generation in that common case.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-10 19:01:41 +01:00
Marco Costalba 33ddeec5e0 Templetize generate_piece_checks_king()
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-10 19:01:39 +01:00
Marco Costalba 4573d618e4 Small optimization in generate_evasions()
Find squares attacked by slider checkers, we will
remove them from king evasions set so to avoid a couple
of cycles in the slow king evasions legality check loop.

Not a biggie, but now generate_evasions() is faster then
generate_non_captures(), before was slower.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-07 13:26:57 +01:00
Marco Costalba 1156eb865b Simplify newly introduced castling_is_check()
Use bit_is_set() instead of open coding.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-07 13:26:50 +01:00
Marco Costalba 76381cbd69 Small code style tidy up
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-07 13:26:42 +01:00
Marco Costalba fa322b3768 Fix casting warnings under Intel Compiler
Int to Char warning fixed changing the function
signature to int.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-07 13:26:29 +01:00
Marco Costalba 2ea7449f2a Fix Makefile
Was broken after we removed color.cpp and square.cpp

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-07 13:26:17 +01:00
Marco Costalba ee6e8851be Templetize generate_castle_moves()
Cleanup the code and remove lines.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-06 07:14:38 +01:00
Marco Costalba 03211296f1 Add generation of castling checks
When we generate checks one case is missing: generation
of castling moves that give check to the opponent king.

This is a very rare case but anyway it is a case
and we can do this without slowing down the common
case of no castling checks.

So this is the patch.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-06 07:14:16 +01:00
Marco Costalba cc76951483 Remove square.cpp
Move the few stuff in square.h

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-04 19:41:56 +01:00
Marco Costalba f0858cd229 Move constants from piece.cpp to piece.h
Leave in piece.cpp only a couple of functions that
need #include <cstring>

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-04 19:41:38 +01:00
Marco Costalba 225d89c51b PawnInfo::clear() retire memset() and fix Ubuntu compile
Go back to original direct assignment, this allows to
add an include in pawns.h to teach about memset()

This fix a compile error under Ubuntu.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-04 19:41:17 +01:00
Marco Costalba 8bef9e59a0 Remove the useless color.cpp
Integrate the only (inline) function in color.h

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-04 19:40:43 +01:00
Marco Costalba 82bf08e4f2 Final endgame.cpp space inflate
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-04 19:40:31 +01:00
Marco Costalba c32904f0a0 Revert previous commit.
Optimization is correct but slightly slower
so it is a pessimization :-)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-02-04 19:40:09 +01:00
Marco Costalba 6cfb661ca5 Yet another count_1s() optimization
No functional change

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-01-25 19:29:15 +01:00
Marco Costalba be43219136 Rever count_1s() optimizations
They are wrong for all ones case.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-01-25 18:00:57 +01:00
Marco Costalba d5b77ad45e MovePicker, remove a variable
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-01-25 13:52:35 +01:00
Marco Costalba c6d62b7da5 MovePicker::find_best_index() never returns -1
So avoid checking for it.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-01-25 13:36:59 +01:00
Marco Costalba 3e6e57231e Rewrite count_1s() to be similar to 64bit counterpart
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-01-11 17:15:18 +01:00
Marco Costalba 14c1fd4d27 Micro optimize count_1s_max_15() for 32 bit system
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-01-11 17:05:29 +01:00
Marco Costalba 4b53bb02f6 Fix a very old bug in queen mobility
For queen mobility could be bigger then 15, so
we need count_1s() not count_1s_max_15().

This bug was introduced by patch:
"Group common evaluate code" of 24/9/2008

So it's almost 4 months and two release old!

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-01-10 16:11:33 +01:00
Marco Costalba ec2927286a Start to space inflate endgame.cpp
Still a lot to do, it's a big file!

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-01-08 15:46:57 +01:00
Marco Costalba bdbbc4e06b Rewrite evaluate_common() as a template
Seems to speed up this very hot path and code is
cleaner too.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-01-07 15:48:22 +01:00
Marco Costalba 539051b1e0 Big trailing whitespace cleanup part 2
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-01-07 15:48:11 +01:00
Marco Costalba c97104e854 Big trailing whitespace cleanup part 1
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-01-07 15:47:59 +01:00
Marco Costalba 5cacefe7c6 Another micro-optmization in valuate_passed_pawns()
very small gain, but still a gain at the cost of
an extra indentation level.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-01-07 15:47:31 +01:00
Marco Costalba 9b87d151bc Fix a small bug in rook pawn evaluation
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-01-06 16:10:22 +01:00
Marco Costalba cbfbf25d1b evaluate_passed_pawns() micro-optmization
No functional change, only a bit faster.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-01-06 16:06:08 +01:00
Marco Costalba 90585a8a36 Final space inflate of evaluatio.cpp
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-01-06 15:59:08 +01:00
Marco Costalba e236a0c652 Space inflate evaluate_passed_pawns()
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-01-06 15:49:33 +01:00
Marco Costalba d0804341c5 Piece mobility: filter out squares protected by pawns
Do not consider squares protected by enemy pawns
in mobility evaluation.

This reduces the mobility value by about 15%

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-01-05 15:14:16 +01:00
Marco Costalba dc4e2d8184 Take in account odd depths in razoring formula
This is somewhat taken from Stockfish 1.2 Default,
only the razoring thresold are updated, not the
razoring depth.

At the end razoring is a bit more aggressive. Results
seems slightly positive.

After 999 games +239 =536 -224 Elo +5

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-01-05 12:41:27 +01:00
Marco Costalba e828753a3a Fix dbg_mean_of() to enable statistics when called
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-30 12:54:21 +01:00
Marco Costalba 33bb8305a9 Restore development versioning and LSN filtering
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-30 12:42:23 +01:00
Marco Costalba cc3c1dc25a Stockfish 1.2 optimistic
Optimistic razoring settings. It is stronger with
most engines but weaker with someones.

The default is instead more solid and uniform with all
the opponents.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-29 12:24:34 +01:00
Marco Costalba 11763d2b7f Stockfish 1.2
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-29 12:18:49 +01:00
Marco Costalba d99a95df29 Micro optimization in extension()
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-29 12:18:36 +01:00
Marco Costalba 0da1d6a846 Remove a gcc warning on an unused variable
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-29 12:18:23 +01:00
Marco Costalba 5d94305af3 Properly handle odd depths in razor formula
A little bit more aggressive, but should be more
in line with the depths logic.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-28 19:38:44 +01:00
Marco Costalba e4fd9a2df7 Safer razoring formula
Add also the possibility to razor at ply one.
It is disable dby default but it seems stronger
against Stockfish itself. It is still not clear if
is stronger against other engines. By now leave
disabled.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-28 12:55:33 +01:00
Marco Costalba aedc6c6f1f Don't silently accept an option name mismatch
With this we could have found earlier the futility
name option bug!

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-28 12:37:13 +01:00
Marco Costalba dae4e7df07 Tweak again futility margings
Lower margins near the leafs, higher at high depth.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-25 20:08:45 +01:00
Marco Costalba 96a32eec69 Expose new futility margin interface to UCI
Now futility margin it's actually a scale factor
to apply to the base ones.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-25 19:41:24 +01:00
Marco Costalba e46d3670fd Tweak futility margins
Less prune at the bottom and at the middle, a bit more
at the top.

After 747 games: +215 =345 -187 +13 elo

Also introduced a vector of margins, now that start to be a lot
it is a more flexible solution.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-25 12:05:45 +01:00
Marco Costalba 8cd5cb930d Try razoring only for depth > OnePly
Because razoring verification after qsearch() cuts more
then 40% of candidates, do not waste a costly qsearch for
nodes at depth one that will be probably discarded anyway
by futility.

Also tight razoring conditions to keep dangerous false
negatives below 0,05%. Still not clear if it is enough.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-24 09:35:57 +01:00
Marco Costalba 2feb9d5100 Futility pruning till ply 6 included
Seems good:

After 796 games: +211 = 393 -192 +8 elo

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-24 09:34:09 +01:00
Marco Costalba d11426c777 Fix a comment
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-23 12:02:10 +01:00
Marco Costalba e96f56adfa Merge futility pruning from Glaurung 2.2
It seems much more powerful then previous one.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-23 12:01:48 +01:00
Marco Costalba e3b03f13b3 Passed pawns: consider enemy rooks or queens from behind
Merged from Glaurung 2.2

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-22 12:10:15 +01:00
Marco Costalba 54b7da120f King safety: retire rook contact check
Merged from Glaurung 2.2

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-22 12:07:00 +01:00
Marco Costalba 3fafc9768a Set the 'Problem' variable only at ply == 1
Bug fix merged from Glaurung 2.2 for search_pv()

Added the same fix also to sp_search_pv() where
was missing.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-22 11:44:00 +01:00
Marco Costalba 23490bd825 Retire EvaluatePawnStorms and UseEasyMove constants
Merged from Glaurung 2.2

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-21 20:10:20 +01:00
Marco Costalba 61c6a3d5a0 Merge cosmetics from Glaurung 2.2
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-21 17:02:34 +01:00
Marco Costalba 31d4f0b734 Merge space weigth evaluation fromGlaurung 2.2
Is a new evaluation rule that gives bonus in midgame
to the side that has more space behind pawns for its
minor pieces.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-21 16:26:36 +01:00
Marco Costalba f178f0a291 Merged two new endgames from Glaurung 2.2
It is two bishop against a knight and two minor
pieces against one minor piece.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-21 15:38:10 +01:00
Marco Costalba 72ca727b38 SEE: add support for enpassant moves
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-21 10:44:41 +01:00
Marco Costalba 2d0146fe1d Call poll() before to check for stopped search
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-21 10:44:12 +01:00
Marco Costalba 96d0501735 Less aggressive razoring
Use a margin to compare with beta so that positions
that after the verifying qsearch have gained a lot of points
are not discarded just becasue not above beta.

Also remove the second condition on depth <= OnePly, it
was too risky and added only a 2% more of pruned nodes.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-21 10:42:39 +01:00
Marco Costalba b58ad355ca Revert: "Do not razor when in check"
It is slightly weaker after 500 games. Keep the
check on mate values.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-18 22:01:56 +01:00
Marco Costalba 17000d1ea0 Trigger of PawnEndgameExtension if capture is not a pawn
Instead of a rook.

This gives an unexpected graeat increase!

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-17 19:36:51 +01:00
Marco Costalba b09cbaebb9 search_pv: an enpassant move is a capture
Fix the logic in search_pv and sp_search_pv

An additional issue to consider is that a castle move
is not a capture but destination square is not empty.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-16 22:20:53 +01:00
Marco Costalba 725c504a5f qsearch: take in account enpassant in futility formula
Should not change anything at ELO level but it is
the correct thing to do.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-16 22:20:42 +01:00
Marco Costalba bfbfc24d07 qsearch: do not call evaluate when in check
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-16 22:20:18 +01:00
Marco Costalba a55b06d3c9 Restore development versioning and LSN filtering
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-15 22:23:03 +01:00
Marco Costalba ecc19381b4 Do not razor while in check or value is mate
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-15 22:20:03 +01:00
Marco Costalba dae2f600d6 Do not null search when beta is a mate value
Also do not return unproven mates in null search.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-15 22:19:25 +01:00
Marco Costalba 4c294932e7 Better document null move dynamic reduction
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-15 22:18:56 +01:00
Marco Costalba c831b00544 Introduce beta counters to order moves at ply one
Instead of number of searched nodes use the number of
opponent beta-cutoff occurred under the move subtree.

After 570 games 1+0 we have: +150 =288 -132 (+11 ELO)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-15 22:13:42 +01:00
Marco Costalba 5b853c9be6 Debugging: move debug function definitions in misc.cpp
Also activate writing on log file.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-14 17:26:05 +01:00
Marco Costalba 5f8f83bc05 Debugging: print to file
Print debug info on log file, not only on std::cout

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-14 14:57:17 +01:00
Marco Costalba 8ee3124487 Fix two bugs in ok_to_prune() (2)
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-12 22:27:43 +01:00
Marco Costalba 07b45151d2 Disable "Null driven IID" by default
Testing is not clear. Probably we need to test
at deeper depths to have some clear results.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-11 20:39:08 +01:00
Marco Costalba 9e3ab9099f Null move only for depth > OnePly
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-11 20:38:52 +01:00
Marco Costalba f09884d72f Null driven IID: remove IIDMargin from see() condition
This seems to cut searched nodes also more.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-10 21:43:09 +01:00
Marco Costalba ab29d8df67 Fix inflate pawns.cpp fallout
Catched counting the nodes searched at
fixed depth. A quick and reliable cross check,
expecially in inflate only patches.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-10 21:35:07 +01:00
Marco Costalba 389dc0e83b Add behind_bb() helper to simplify code logic
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-10 00:14:24 +01:00
Marco Costalba 67aac4889e Space inflate pawns.cpp
Hopefully no functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-10 00:14:15 +01:00
Marco Costalba aaad48464b Add a see() function that take only destination square
In this case firstlocates the least valuable attacker, if any,
then proceed as usual.

This will be used by next patch.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-10 00:13:59 +01:00
Marco Costalba 235df6a887 Stockfish 1.1a
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-08 12:03:46 +01:00
Marco Costalba 8d86c87e1e Add "Null driven IID" UCI option (default true)
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-08 10:57:40 +01:00
Marco Costalba c172af1b61 Null move driven internal iterative deepening
When a null move fails low due to a capture, try
to detect if without the capture we are above beta,
in this case there is a good possibility this is
a cut-node and the capture is just a null move
artifact due to side to move change. So if we still
don't have a TT move it's a good time to start an IID.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-08 10:46:52 +01:00
Marco Costalba b7c36d078b Stockfish 1.1
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-06 17:18:59 +01:00
Marco Costalba db1b0bfa1d Revert see() shortcut for LxH and equal captures
It happens that more then 70% of cases are HxL, where
we call see() anyway. The mesured saving of calling
see is about 0,5% of total time, but considering the
added burden in score_captures() the saving is only
0,35% locally and due to more difficult inlining of
the function it ends up that we have no advantage at all,
possibly a small slow down!

So revert.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-06 12:32:23 +01:00
Marco Costalba 6f946f823c Fix two gcc warnings in san.cpp
One good, the other silly.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-06 12:32:11 +01:00
Marco Costalba 2de78ebc7b Fix an Intel warning in san.cpp
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-06 12:31:48 +01:00
Marco Costalba 32934c0c8d MovePicker: avoid calling see() for LxH and equal captures
No functional change but should speed-up the captures scoring.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-06 11:37:19 +01:00
Marco Costalba b4fcfed55b Null capture pruning
Null move can fail low because of a capture artifact due
to the side to move change. Try to detect this condition
and fail high instead.

This pruning is very powerful, around 7% of nodes, but is
still experimental so is disabled by default.

Set UseNullCapturePruning to true to enable.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-06 11:31:14 +01:00
Marco Costalba dc2302b701 Position::move_is_capture() does not handle MOVE_NONE
Actually square 0 can be dirty, so that move_is_capture(0)
can return any random values.

Add an assert to be sure it is caught.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-06 11:18:31 +01:00
Marco Costalba 268c12bf31 Allow to call Position::print() from MovePicker
Fix a recursion issue that gives a stack overflow.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-06 11:18:08 +01:00
Marco Costalba 9f943a132a san.cpp: rewrite broken move_from_san
Use a state machine to parse the input. Fixed
the many broken cases.

Tested on more then 15 milions nodes.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-05 09:06:51 +01:00
Marco Costalba 20390fcb3c san.cpp cleanup
Hopefully no functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-12-05 09:06:30 +01:00
Marco Costalba d95b9189d8 Revert opponent time advantage logic
Strength increase was due to an hidden bug introduced
by the patch, namely the time per move to /30 instead
of /40 (see previous patch).

After testing this feature do not add any substantial
increase so is removed.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-11-30 19:23:33 +01:00
Marco Costalba 9d5d69e435 Revert sigmoid interpolator
After deep test (1000 games) it seems do not improve anything,
actually seems slightly weaker.

So remove it for now.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-11-30 21:16:47 +01:00
Marco Costalba 08265aef81 san.cpp pass position as constant reference
Make a copy of the position when needed instead
of passing as a reference. It is cleaner and
let us to simplify also Position::print()

A small space inflate while there.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-11-30 01:25:16 +01:00
Marco Costalba 9d1e4d041d piece_type_to_char() default argument in declaration
Default argument should be in declaration where it
is visible through header include, not in definition.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-11-30 00:38:33 +01:00
Marco Costalba cff3a6d33e Revert threat move ordering
Does not seem to improve anything.

Anyhow idea is nice, maybe we still have to find
correct recipe.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-11-26 11:22:30 +01:00
Marco Costalba 20a2ca366f Tweak allocated time per move
It seems better to give more time in middle game then
at the end.

Also Toga uses the same limit.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-11-25 20:41:06 +01:00
Marco Costalba c3ba5fb9d3 Rewrok the extendeable patch
Cleanup and document.

The real functional change is that not mate threat
moves are never pruned, as could happen before.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-11-25 20:40:49 +01:00
Marco Costalba eba8925d81 MovePicker: take advantage of threat move for ordering
If the null move was refuted by a capture then give a
bonus if we move away the captured piece.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-11-25 20:40:34 +01:00
Marco Costalba ee9f650242 Use extendable instead of depth extension
We can have depth(0) also in problematic cases
according to how extensions are tweaked by the user.

In any case we don't want to prune these moves.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-11-25 20:40:12 +01:00
Marco Costalba 8a0dd93c56 Generate moves for powerful pieces first
This seems to reduce searched nodes by a
surprising 2.5%

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-11-24 20:43:29 +01:00
Marco Costalba 5a72ff128e Benchmark: print nodes searched at the end of testing
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-11-24 20:43:11 +01:00
Marco Costalba 3f63dd1023 Easy debug macro enabling
Now you don't need to toggle show_debug_xxxx anymore

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-11-22 15:59:26 +01:00
Marco Costalba 62ab7e4612 Introduce node limited benchmarking
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-11-22 11:56:14 +01:00
Marco Costalba 1867785231 Introduce depth limited benchmarking
Also print some more info.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-11-22 11:02:05 +01:00
Marco Costalba bac4da70c9 Remove an include in movepick.h
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Signed-off-by: unknown <Marco@.(none)>
2008-11-19 22:15:41 +01:00
Marco Costalba 8189ae9e1c Fix a silly bug that disabled second killer
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Signed-off-by: unknown <Marco@.(none)>
2008-11-19 22:15:26 +01:00
Marco Costalba 1d525bb45f qsearch: restore pruning of pv nodes with negative SEE
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
Signed-off-by: unknown <Marco@.(none)>
2008-11-19 22:15:14 +01:00
Marco Costalba da7d872eda Fix Intel warnings and init_search_stack argument
Should be a reference not a copy!

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-11-16 12:46:12 +01:00
Marco Costalba 49d52b8266 Set killer slots number to 2
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-11-16 12:37:48 +01:00
Marco Costalba 75d001addd MovePicker: fix a nasty bug in EvalInfo optimization
EvalInfo has missing attack info when a specialized
endgame function is used.

We missed this case and were using an empty attack bitboard
instead so that no captures were generated for endgames.

After testing the EvalInfo optimization gave worst results,
so after a (long) debug session this nasty bug was found.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-11-16 12:37:48 +01:00
Marco Costalba 7daaf03b39 Add and use update_killers()
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-11-16 12:37:48 +01:00
Marco Costalba 2e778445d5 Add and use move_is_killer() helper
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-11-16 12:37:48 +01:00
Marco Costalba 93bc05cf69 Convert killers to a vector
Add infrastructure to threat killer moves as a vector,
this will allow us to easily parametrize the number of
killer moves, instead of hardcode this value to two as is now.

This patch just add the infrastructure, no functional
change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-11-16 12:37:47 +01:00
Marco Costalba a7227ac26f qsearch: do not prune pv nodes with negative SEE
Also small micro-optimization, take a line out of
the moves loop.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-11-16 12:37:47 +01:00
Marco Costalba bb0da595a7 Disable per-square MVV/LVA for now
Needs more testing.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-11-16 12:37:47 +01:00
Marco Costalba 20d7197a9b MovePicker: use EvalInfo to skip generating captures
When we know already no captures are possible in a given
position.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-11-16 12:37:46 +01:00
Marco Costalba f4758ced90 Position::to_fen(): fix a bug in side to move representation
Was introduced almost two months ago in patch:
"Space inflate Position::to_fen()"

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-11-16 12:37:46 +01:00
Marco Costalba 3c05bd70eb Print the move in addition to position
Teach Position::print() to optionally print a
given move in san notation in addition to
the ASCII representation of the board.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-11-16 12:37:46 +01:00
Marco Costalba 7000e100bd Enable per-square MVV/LVA
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-11-16 12:37:46 +01:00
Marco Costalba 2ed22e4fc8 MovePicker:find bad captures during scoring
Instead of pospone until picking. No functional
change and probably no performance change but it is
needed for following patch.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-11-16 12:37:46 +01:00
Marco Costalba 940c53c366 MovePicker: introduce per square MVV/LVA ordering
Just added the infrastructure, no functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-11-16 12:37:45 +01:00
Marco Costalba 4df8651c82 Fix hashfull info
Do not count has a replacement when a TT entry is
written in an empty slot.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-11-16 12:37:45 +01:00
Marco Costalba 2d4e2bc62a Fix in ok_to_history(): castle move is not a capture
It is erroneusly considered a capture because king
moves on the same square of the rook.

Use the correct function Position::move_is_capture()
instead of the open coded (and buggy) one.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-11-10 19:19:40 +01:00
Marco Costalba d89a03cc35 Small tidyup of TranspositionTable::store()
Hopefully without bugs this time!

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-11-10 19:19:40 +01:00
Marco Costalba 34b1d0538b Fix a logic bug in TranspositionTable::store()
Make the logic work as advertised in the function
description.

Still a fallback from TT cleanup.

This should be less serious then the one in retrieve(),
but it's still a bug.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-11-10 19:19:40 +01:00
Marco Costalba cdf1f23bc5 Micro optimization of update_history()
Remove an useless comparison.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-11-10 19:19:40 +01:00
Marco Costalba e86468cc63 Use cut-off checks in qsearch as killer moves
Killers should not be captures, but checks are not
and are produced also in qsearch.

Use this information, will be useful for move ordering.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-11-10 19:19:40 +01:00
Marco Costalba e7bad2687a Smaller null move reduction when depth is high
Lower probability to miss something important.

It seems to increase strenght. Idea form Cyclone.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-11-10 19:19:39 +01:00
Marco Costalba 3f610e2b13 Introduce LastIterations variable
Is set during the last iteration.

Sometime also during the second last.

During the last iteration is set in the 95% of cases.

During the second last is set in the 40% of cases.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-11-10 19:19:39 +01:00
Marco Costalba 6cc11272e2 Restore development versioning and LSN filtering
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-11-10 19:19:39 +01:00
Marco Costalba a28c17ecb6 Fix a missed initialization in get_option_value()
Spotted and reported by Dann Corbit.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2008-11-04 20:59:11 +01:00
63 changed files with 5546 additions and 5378 deletions
+9 -19
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
+3 -10
View File
@@ -2,13 +2,13 @@
[PolyGlot] [PolyGlot]
EngineDir = . EngineDir = .
EngineCommand = ./glaurung EngineCommand = ./stockfish
Book = false Book = false
BookFile = book.bin BookFile = book.bin
Log = true Log = true
LogFile = glaurung.log LogFile = stockfish.log
Resign = true Resign = true
ResignScore = 600 ResignScore = 600
@@ -34,8 +34,7 @@ King Safety Coefficient = 40
King Safety X Intercept = 0 King Safety X Intercept = 0
King Safety Max Slope = 30 King Safety Max Slope = 30
King Safety Max Value = 500 King Safety Max Value = 500
Queen Contact Check Bonus = 4 Queen Contact Check Bonus = 3
Rook Contact Check Bonus = 2
Queen Check Bonus = 2 Queen Check Bonus = 2
Rook Check Bonus = 1 Rook Check Bonus = 1
Bishop Check Bonus = 1 Bishop Check Bonus = 1
@@ -57,14 +56,8 @@ Pawn Endgame Extension (non-PV nodes) = 2
Full Depth Moves (PV nodes) = 14 Full Depth Moves (PV nodes) = 14
Full Depth Moves (non-PV nodes) = 3 Full Depth Moves (non-PV nodes) = 3
Threat Depth = 5 Threat Depth = 5
Selective Plies = 7
Futility Pruning (Main Search) = true Futility Pruning (Main Search) = true
Futility Pruning (Quiescence Search) = true Futility Pruning (Quiescence Search) = true
Futility Margin 0 = 50
Futility Margin 1 = 100
Futility Margin 2 = 300
Maximum Razoring Depth = 3
Razoring Margin = 300
Randomness = 0 Randomness = 0
Minimum Split Depth = 4 Minimum Split Depth = 4
Maximum Number of Threads per Split Point = 5 Maximum Number of Threads per Split Point = 5
+16 -16
View File
@@ -24,9 +24,9 @@
EXE = stockfish EXE = stockfish
OBJS = bitboard.o color.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 square.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
@@ -37,16 +37,15 @@ OBJS = bitboard.o color.o pawns.o material.o endgame.o evaluate.o main.o \
all: $(EXE) .depend all: $(EXE) .depend
clean: clean:
$(RM) *.o .depend glaurung $(RM) *.o .depend stockfish
### ###
### 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 ./glaurung 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
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
}
+23 -11
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
@@ -18,17 +18,29 @@
*/ */
#if !defined(PHASE_H_INCLUDED) #if !defined(APPLICATION_H_INCLUDED)
#define PHASE_H_INCLUDED #define APPLICATION_H_INCLUDED
////
//// Types
////
enum Phase { /// Singleton class used to housekeep memory and global resources
PHASE_ENDGAME = 0, /// so to be sure we always leave in a clean state.
PHASE_MIDGAME = 128
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)
#endif // !defined(PHASE_H_INCLUDED)
+71 -24
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; string ttSize, threads, fileName, limitType, timFile;
int val, secsPerPos; 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);
@@ -95,38 +95,85 @@ void benchmark(const std::string& commandLine) {
set_option_value("Use Search Log", "true"); set_option_value("Use Search Log", "true");
set_option_value("Search Log Filename", "bench.txt"); set_option_value("Search Log Filename", "bench.txt");
csVal >> secsPerPos; csVal >> val;
csVal >> fileName; csVal >> fileName;
csVal >> limitType;
csVal >> timFile;
std::vector<std::string> positions; secsPerPos = maxDepth = maxNodes = 0;
if (limitType == "time")
secsPerPos = val * 1000;
else if (limitType == "depth")
maxDepth = val;
else
maxNodes = val;
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]));
std::vector<std::string>::iterator it; ofstream timingFile;
for (it = positions.begin(); it != positions.end(); ++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;
int64_t totalNodes = 0;
int startTime = get_system_time();
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);
think(pos, true, false, 0, dummy, dummy, 0, 0, 0, secsPerPos * 1000, moves); cerr << "\nBench position: " << cnt << '/' << positions.size() << endl << endl;
if (!think(pos, true, false, 0, dummy, dummy, 0, maxDepth, maxNodes, secsPerPos, moves))
break;
totalNodes += nodes_searched();
} }
cnt = get_system_time() - startTime;
cerr << "==============================="
<< "\nTotal time (ms) : " << cnt
<< "\nNodes searched : " << totalNodes
<< "\nNodes/second : " << (int)(totalNodes/(cnt/1000.0)) << endl << endl;
if (!timFile.empty())
{
timingFile << cnt << endl << endl;
timingFile.close();
}
// Under MS Visual C++ debug window always unconditionally closes
// when program exits, this is bad because we want to read results before.
#if (defined(WINDOWS) || defined(WIN32) || defined(WIN64))
cerr << "Press any key to exit" << endl;
cin >> fileName;
#endif
} }
+1 -1
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 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
+3 -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
@@ -89,7 +89,8 @@ void generate_kpk_bitbase(uint8_t bitbase[]) {
int i, j, b; int i, j, b;
for(i = 0; i < 24576; i++) { for(i = 0; i < 24576; i++) {
for(b = 0, j = 0; j < 8; b |= (compress_result(Bitbase[8*i+j]) << j), j++); for(b = 0, j = 0; j < 8; b |= (compress_result(Bitbase[8*i+j]) << j), j++);
bitbase[i] = b; assert(b == int(uint8_t(b)));
bitbase[i] = (uint8_t)b;
} }
// Release allocated memory: // Release allocated memory:
+1 -1
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 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
+177 -303
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,195 +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(IS_64BIT)
//// Constants and variables
////
const Bitboard SquaresByColorBB[2] = {BlackSquaresBB, WhiteSquaresBB};
const Bitboard FileBB[8] = {
FileABB, FileBBB, FileCBB, FileDBB, FileEBB, FileFBB, FileGBB, FileHBB
};
const Bitboard NeighboringFilesBB[8] = {
FileBBB, FileABB|FileCBB, FileBBB|FileDBB, FileCBB|FileEBB,
FileDBB|FileFBB, FileEBB|FileGBB, FileFBB|FileHBB, FileGBB
};
const Bitboard ThisAndNeighboringFilesBB[8] = {
FileABB|FileBBB, FileABB|FileBBB|FileCBB,
FileBBB|FileCBB|FileDBB, FileCBB|FileDBB|FileEBB,
FileDBB|FileEBB|FileFBB, FileEBB|FileFBB|FileGBB,
FileFBB|FileGBB|FileHBB, FileGBB|FileHBB
};
const Bitboard RankBB[8] = {
Rank1BB, Rank2BB, Rank3BB, Rank4BB, Rank5BB, Rank6BB, Rank7BB, Rank8BB
};
const Bitboard RelativeRankBB[2][8] = {
{
Rank1BB, Rank2BB, Rank3BB, Rank4BB, Rank5BB, Rank6BB, Rank7BB, Rank8BB
},
{
Rank8BB, Rank7BB, Rank6BB, Rank5BB, Rank4BB, Rank3BB, Rank2BB, Rank1BB
}
};
const Bitboard InFrontBB[2][8] = {
{
Rank2BB | Rank3BB | Rank4BB | Rank5BB | Rank6BB | Rank7BB | Rank8BB,
Rank3BB | Rank4BB | Rank5BB | Rank6BB | Rank7BB | Rank8BB,
Rank4BB | Rank5BB | Rank6BB | Rank7BB | Rank8BB,
Rank5BB | Rank6BB | Rank7BB | Rank8BB,
Rank6BB | Rank7BB | Rank8BB,
Rank7BB | Rank8BB,
Rank8BB,
EmptyBoardBB
},
{
EmptyBoardBB,
Rank1BB,
Rank2BB | Rank1BB,
Rank3BB | Rank2BB | Rank1BB,
Rank4BB | Rank3BB | Rank2BB | Rank1BB,
Rank5BB | Rank4BB | Rank3BB | Rank2BB | Rank1BB,
Rank6BB | Rank5BB | Rank4BB | Rank3BB | Rank2BB | Rank1BB,
Rank7BB | Rank6BB | Rank5BB | Rank4BB | Rank3BB | Rank2BB | Rank1BB
}
};
#if defined(USE_COMPACT_ROOK_ATTACKS)
Bitboard RankAttacks[8][64], FileAttacks[8][64];
#elif defined(USE_32BIT_ATTACKS)
const uint64_t RMult[64] = {
0xd7445cdec88002c0ULL, 0xd0a505c1f2001722ULL, 0xe065d1c896002182ULL,
0x9a8c41e75a000892ULL, 0x8900b10c89002aa8ULL, 0x9b28d1c1d60005a2ULL,
0x15d6c88de002d9aULL, 0xb1dbfc802e8016a9ULL, 0x149a1042d9d60029ULL,
0xb9c08050599e002fULL, 0x132208c3af300403ULL, 0xc1000ce2e9c50070ULL,
0x9d9aa13c99020012ULL, 0xb6b078daf71e0046ULL, 0x9d880182fb6e002eULL,
0x52889f467e850037ULL, 0xda6dc008d19a8480ULL, 0x468286034f902420ULL,
0x7140ac09dc54c020ULL, 0xd76ffffa39548808ULL, 0xea901c4141500808ULL,
0xc91004093f953a02ULL, 0x2882afa8f6bb402ULL, 0xaebe335692442c01ULL,
0xe904a22079fb91eULL, 0x13a514851055f606ULL, 0x76c782018c8fe632ULL,
0x1dc012a9d116da06ULL, 0x3c9e0037264fffa6ULL, 0x2036002853c6e4a2ULL,
0xe3fe08500afb47d4ULL, 0xf38af25c86b025c2ULL, 0xc0800e2182cf9a40ULL,
0x72002480d1f60673ULL, 0x2500200bae6e9b53ULL, 0xc60018c1eefca252ULL,
0x600590473e3608aULL, 0x46002c4ab3fe51b2ULL, 0xa200011486bcc8d2ULL,
0xb680078095784c63ULL, 0x2742002639bf11aeULL, 0xc7d60021a5bdb142ULL,
0xc8c04016bb83d820ULL, 0xbd520028123b4842ULL, 0x9d1600344ac2a832ULL,
0x6a808005631c8a05ULL, 0x604600a148d5389aULL, 0xe2e40103d40dea65ULL,
0x945b5a0087c62a81ULL, 0x12dc200cd82d28eULL, 0x2431c600b5f9ef76ULL,
0xfb142a006a9b314aULL, 0x6870e00a1c97d62ULL, 0x2a9db2004a2689a2ULL,
0xd3594600caf5d1a2ULL, 0xee0e4900439344a7ULL, 0x89c4d266ca25007aULL,
0x3e0013a2743f97e3ULL, 0x180e31a0431378aULL, 0x3a9e465a4d42a512ULL,
0x98d0a11a0c0d9cc2ULL, 0x8e711c1aba19b01eULL, 0x8dcdc836dd201142ULL,
0x5ac08a4735370479ULL,
};
const int RShift[64] = {
20, 21, 21, 21, 21, 21, 21, 20, 21, 22, 22, 22, 22, 22, 22, 21,
21, 22, 22, 22, 22, 22, 22, 21, 21, 22, 22, 22, 22, 22, 22, 21,
21, 22, 22, 22, 22, 22, 22, 21, 21, 22, 22, 22, 22, 22, 22, 21,
21, 22, 22, 22, 22, 22, 22, 21, 20, 21, 21, 21, 21, 21, 21, 20
};
#else // if defined(USE_32BIT_ATTACKS)
const uint64_t RMult[64] = {
0xa8002c000108020ULL, 0x4440200140003000ULL, 0x8080200010011880ULL,
0x380180080141000ULL, 0x1a00060008211044ULL, 0x410001000a0c0008ULL,
0x9500060004008100ULL, 0x100024284a20700ULL, 0x802140008000ULL,
0x80c01002a00840ULL, 0x402004282011020ULL, 0x9862000820420050ULL,
0x1001448011100ULL, 0x6432800200800400ULL, 0x40100010002000cULL,
0x2800d0010c080ULL, 0x90c0008000803042ULL, 0x4010004000200041ULL,
0x3010010200040ULL, 0xa40828028001000ULL, 0x123010008000430ULL,
0x24008004020080ULL, 0x60040001104802ULL, 0x582200028400d1ULL,
0x4000802080044000ULL, 0x408208200420308ULL, 0x610038080102000ULL,
0x3601000900100020ULL, 0x80080040180ULL, 0xc2020080040080ULL,
0x80084400100102ULL, 0x4022408200014401ULL, 0x40052040800082ULL,
0xb08200280804000ULL, 0x8a80a008801000ULL, 0x4000480080801000ULL,
0x911808800801401ULL, 0x822a003002001894ULL, 0x401068091400108aULL,
0x4a10a00004cULL, 0x2000800640008024ULL, 0x1486408102020020ULL,
0x100a000d50041ULL, 0x810050020b0020ULL, 0x204000800808004ULL,
0x20048100a000cULL, 0x112000831020004ULL, 0x9000040810002ULL,
0x440490200208200ULL, 0x8910401000200040ULL, 0x6404200050008480ULL,
0x4b824a2010010100ULL, 0x4080801810c0080ULL, 0x400802a0080ULL,
0x8224080110026400ULL, 0x40002c4104088200ULL, 0x1002100104a0282ULL,
0x1208400811048021ULL, 0x3201014a40d02001ULL, 0x5100019200501ULL,
0x101000208001005ULL, 0x2008450080702ULL, 0x1002080301d00cULL,
0x410201ce5c030092ULL
};
const int RShift[64] = {
52, 53, 53, 53, 53, 53, 53, 52, 53, 54, 54, 54, 54, 54, 54, 53,
53, 54, 54, 54, 54, 54, 54, 53, 53, 54, 54, 54, 54, 54, 54, 53,
53, 54, 54, 54, 54, 54, 54, 53, 53, 54, 54, 54, 54, 54, 54, 53,
53, 54, 54, 54, 54, 54, 54, 53, 52, 53, 53, 53, 53, 53, 53, 52
};
#endif // defined(USE_32BIT_ATTACKS)
#if !defined(USE_COMPACT_ROOK_ATTACKS)
Bitboard RMask[64];
int RAttackIndex[64];
Bitboard RAttacks[0x19000];
#endif
#if defined(USE_32BIT_ATTACKS)
const uint64_t BMult[64] = {
0x54142844c6a22981ULL, 0x710358a6ea25c19eULL, 0x704f746d63a4a8dcULL,
0xbfed1a0b80f838c5ULL, 0x90561d5631e62110ULL, 0x2804260376e60944ULL,
0x84a656409aa76871ULL, 0xf0267f64c28b6197ULL, 0x70764ebb762f0585ULL,
0x92aa09e0cfe161deULL, 0x41ee1f6bb266f60eULL, 0xddcbf04f6039c444ULL,
0x5a3fab7bac0d988aULL, 0xd3727877fa4eaa03ULL, 0xd988402d868ddaaeULL,
0x812b291afa075c7cULL, 0x94faf987b685a932ULL, 0x3ed867d8470d08dbULL,
0x92517660b8901de8ULL, 0x2d97e43e058814b4ULL, 0x880a10c220b25582ULL,
0xc7c6520d1f1a0477ULL, 0xdbfc7fbcd7656aa6ULL, 0x78b1b9bfb1a2b84fULL,
0x2f20037f112a0bc1ULL, 0x657171ea2269a916ULL, 0xc08302b07142210eULL,
0x880a4403064080bULL, 0x3602420842208c00ULL, 0x852800dc7e0b6602ULL,
0x595a3fbbaa0f03b2ULL, 0x9f01411558159d5eULL, 0x2b4a4a5f88b394f2ULL,
0x4afcbffc292dd03aULL, 0x4a4094a3b3f10522ULL, 0xb06f00b491f30048ULL,
0xd5b3820280d77004ULL, 0x8b2e01e7c8e57a75ULL, 0x2d342794e886c2e6ULL,
0xc302c410cde21461ULL, 0x111f426f1379c274ULL, 0xe0569220abb31588ULL,
0x5026d3064d453324ULL, 0xe2076040c343cd8aULL, 0x93efd1e1738021eeULL,
0xb680804bed143132ULL, 0x44e361b21986944cULL, 0x44c60170ef5c598cULL,
0xf4da475c195c9c94ULL, 0xa3afbb5f72060b1dULL, 0xbc75f410e41c4ffcULL,
0xb51c099390520922ULL, 0x902c011f8f8ec368ULL, 0x950b56b3d6f5490aULL,
0x3909e0635bf202d0ULL, 0x5744f90206ec10ccULL, 0xdc59fd76317abbc1ULL,
0x881c7c67fcbfc4f6ULL, 0x47ca41e7e440d423ULL, 0xeb0c88112048d004ULL,
0x51c60e04359aef1aULL, 0x1aa1fe0e957a5554ULL, 0xdd9448db4f5e3104ULL,
0xdc01f6dca4bebbdcULL,
};
const int BShift[64] = {
26, 27, 27, 27, 27, 27, 27, 26, 27, 27, 27, 27, 27, 27, 27, 27,
27, 27, 25, 25, 25, 25, 27, 27, 27, 27, 25, 23, 23, 25, 27, 27,
27, 27, 25, 23, 23, 25, 27, 27, 27, 27, 25, 25, 25, 25, 27, 27,
27, 27, 27, 27, 27, 27, 27, 27, 26, 27, 27, 27, 27, 27, 27, 26
};
#else // if defined(USE_32BIT_ATTACKS)
const uint64_t BMult[64] = { const uint64_t BMult[64] = {
0x440049104032280ULL, 0x1021023c82008040ULL, 0x404040082000048ULL, 0x440049104032280ULL, 0x1021023c82008040ULL, 0x404040082000048ULL,
@@ -237,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,
@@ -244,14 +88,92 @@ 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];
Bitboard BAttacks[0x1480]; Bitboard BAttacks[0x1480];
Bitboard SetMaskBB[64]; Bitboard SetMaskBB[65];
Bitboard ClearMaskBB[64]; Bitboard ClearMaskBB[65];
Bitboard StepAttackBB[16][64]; Bitboard StepAttackBB[16][64];
Bitboard RayBB[64][8]; Bitboard RayBB[64][8];
@@ -270,6 +192,7 @@ Bitboard QueenPseudoAttacks[64];
//// ////
namespace { namespace {
void init_masks(); void init_masks();
void init_ray_bitboards(); void init_ray_bitboards();
void init_attacks(); void init_attacks();
@@ -282,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
} }
@@ -316,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,
@@ -405,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 {
@@ -433,6 +323,8 @@ namespace {
// be necessary to touch any of them. // be necessary to touch any of them.
void init_masks() { void init_masks() {
SetMaskBB[SQ_NONE] = 0ULL;
ClearMaskBB[SQ_NONE] = ~SetMaskBB[SQ_NONE];
for(Square s = SQ_A1; s <= SQ_H8; s++) { for(Square s = SQ_A1; s <= SQ_H8; s++) {
SetMaskBB[s] = (1ULL << s); SetMaskBB[s] = (1ULL << s);
ClearMaskBB[s] = ~SetMaskBB[s]; ClearMaskBB[s] = ~SetMaskBB[s];
@@ -448,7 +340,7 @@ namespace {
void init_ray_bitboards() { void init_ray_bitboards() {
int d[8] = {1, -1, 16, -16, 17, -17, 15, -15}; int d[8] = {1, -1, 16, -16, 17, -17, 15, -15};
for(int i = 0; i < 128; i = i + 9 & ~8) { for(int i = 0; i < 128; i = (i + 9) & ~8) {
for(int j = 0; j < 8; j++) { for(int j = 0; j < 8; j++) {
RayBB[(i&7)|((i>>4)<<3)][j] = EmptyBoardBB; RayBB[(i&7)|((i>>4)<<3)][j] = EmptyBoardBB;
for(int k = i + d[j]; (k & 0x88) == 0; k += d[j]) for(int k = i + d[j]; (k & 0x88) == 0; k += d[j])
@@ -534,19 +426,26 @@ namespace {
for(i = 0; i < 64; i++) { for(i = 0; i < 64; i++) {
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(IS_64BIT)
j = (1 << (64 - shift[i])); j = (1 << (64 - shift[i]));
#else
j = (1 << (32 - shift[i]));
#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;
@@ -563,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)
} }
+100 -144
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
//// ////
@@ -84,8 +40,7 @@ const Bitboard EmptyBoardBB = 0ULL;
const Bitboard WhiteSquaresBB = 0x55AA55AA55AA55AAULL; const Bitboard WhiteSquaresBB = 0x55AA55AA55AA55AAULL;
const Bitboard BlackSquaresBB = 0xAA55AA55AA55AA55ULL; const Bitboard BlackSquaresBB = 0xAA55AA55AA55AA55ULL;
const Bitboard SquaresByColorBB[2] = { BlackSquaresBB, WhiteSquaresBB };
extern const Bitboard SquaresByColorBB[2];
const Bitboard FileABB = 0x0101010101010101ULL; const Bitboard FileABB = 0x0101010101010101ULL;
const Bitboard FileBBB = 0x0202020202020202ULL; const Bitboard FileBBB = 0x0202020202020202ULL;
@@ -96,9 +51,21 @@ const Bitboard FileFBB = 0x2020202020202020ULL;
const Bitboard FileGBB = 0x4040404040404040ULL; const Bitboard FileGBB = 0x4040404040404040ULL;
const Bitboard FileHBB = 0x8080808080808080ULL; const Bitboard FileHBB = 0x8080808080808080ULL;
extern const Bitboard FileBB[8]; const Bitboard FileBB[8] = {
extern const Bitboard NeighboringFilesBB[8]; FileABB, FileBBB, FileCBB, FileDBB, FileEBB, FileFBB, FileGBB, FileHBB
extern const Bitboard ThisAndNeighboringFilesBB[8]; };
const Bitboard NeighboringFilesBB[8] = {
FileBBB, FileABB|FileCBB, FileBBB|FileDBB, FileCBB|FileEBB,
FileDBB|FileFBB, FileEBB|FileGBB, FileFBB|FileHBB, FileGBB
};
const Bitboard ThisAndNeighboringFilesBB[8] = {
FileABB|FileBBB, FileABB|FileBBB|FileCBB,
FileBBB|FileCBB|FileDBB, FileCBB|FileDBB|FileEBB,
FileDBB|FileEBB|FileFBB, FileEBB|FileFBB|FileGBB,
FileFBB|FileGBB|FileHBB, FileGBB|FileHBB
};
const Bitboard Rank1BB = 0xFFULL; const Bitboard Rank1BB = 0xFFULL;
const Bitboard Rank2BB = 0xFF00ULL; const Bitboard Rank2BB = 0xFF00ULL;
@@ -109,12 +76,38 @@ const Bitboard Rank6BB = 0xFF0000000000ULL;
const Bitboard Rank7BB = 0xFF000000000000ULL; const Bitboard Rank7BB = 0xFF000000000000ULL;
const Bitboard Rank8BB = 0xFF00000000000000ULL; const Bitboard Rank8BB = 0xFF00000000000000ULL;
extern const Bitboard RankBB[8]; const Bitboard RankBB[8] = {
extern const Bitboard RelativeRankBB[2][8]; Rank1BB, Rank2BB, Rank3BB, Rank4BB, Rank5BB, Rank6BB, Rank7BB, Rank8BB
extern const Bitboard InFrontBB[2][8]; };
extern Bitboard SetMaskBB[64]; const Bitboard RelativeRankBB[2][8] = {
extern Bitboard ClearMaskBB[64]; { Rank1BB, Rank2BB, Rank3BB, Rank4BB, Rank5BB, Rank6BB, Rank7BB, Rank8BB },
{ Rank8BB, Rank7BB, Rank6BB, Rank5BB, Rank4BB, Rank3BB, Rank2BB, Rank1BB }
};
const Bitboard InFrontBB[2][8] = {
{ Rank2BB | Rank3BB | Rank4BB | Rank5BB | Rank6BB | Rank7BB | Rank8BB,
Rank3BB | Rank4BB | Rank5BB | Rank6BB | Rank7BB | Rank8BB,
Rank4BB | Rank5BB | Rank6BB | Rank7BB | Rank8BB,
Rank5BB | Rank6BB | Rank7BB | Rank8BB,
Rank6BB | Rank7BB | Rank8BB,
Rank7BB | Rank8BB,
Rank8BB,
EmptyBoardBB
},
{ EmptyBoardBB,
Rank1BB,
Rank2BB | Rank1BB,
Rank3BB | Rank2BB | Rank1BB,
Rank4BB | Rank3BB | Rank2BB | Rank1BB,
Rank5BB | Rank4BB | Rank3BB | Rank2BB | Rank1BB,
Rank6BB | Rank5BB | Rank4BB | Rank3BB | Rank2BB | Rank1BB,
Rank7BB | Rank6BB | Rank5BB | Rank4BB | Rank3BB | Rank2BB | Rank1BB
}
};
extern Bitboard SetMaskBB[65];
extern Bitboard ClearMaskBB[65];
extern Bitboard StepAttackBB[16][64]; extern Bitboard StepAttackBB[16][64];
extern Bitboard RayBB[64][8]; extern Bitboard RayBB[64][8];
@@ -123,15 +116,11 @@ 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];
@@ -164,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.
@@ -212,7 +212,7 @@ inline Bitboard this_and_neighboring_files_bb(Square s) {
/// relative_rank_bb() takes a color and a rank as input, and returns a bitboard /// relative_rank_bb() takes a color and a rank as input, and returns a bitboard
/// representing all squares on the given rank from the given color's point of /// representing all squares on the given rank from the given color's point of
/// view. For instance, relative_rank_bb(WHITE, 7) gives all squares on the /// view. For instance, relative_rank_bb(WHITE, 7) gives all squares on the
/// 7th rank, while relative_rank_bb(BLACK, 7) gives all squares on the 2nd /// 7th rank, while relative_rank_bb(BLACK, 7) gives all squares on the 2nd
/// rank. /// rank.
@@ -236,6 +236,19 @@ inline Bitboard in_front_bb(Color c, Square s) {
} }
/// behind_bb() takes a color and a rank or square as input, and returns a
/// bitboard representing all the squares on all ranks behind of the rank
/// (or square), from the given color's point of view.
inline Bitboard behind_bb(Color c, Rank r) {
return InFrontBB[opposite_color(c)][r];
}
inline Bitboard behind_bb(Color c, Square s) {
return in_front_bb(opposite_color(c), square_rank(s));
}
/// ray_bb() gives a bitboard representing all squares along the ray in a /// ray_bb() gives a bitboard representing all squares along the ray in a
/// given direction from a given square. /// given direction from a given square.
@@ -244,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];
@@ -276,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] +
@@ -295,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);
@@ -364,62 +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 - ((v >> 1) & 0x55555555);
w = w - ((w >> 1) & 0x55555555);
v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
w = (w & 0x33333333) + ((w >> 2) & 0x33333333);
v = (v + (v >> 4)) & 0x0F0F0F0F;
w = (w + (w >> 4)) & 0x0F0F0F0F;
v = ((v+w) * 0x01010101) >> 24; // mul is fast on amd procs
return int(v);
}
inline int count_1s_max_15(Bitboard b) { #endif
unsigned w = unsigned(b >> 32), v = unsigned(b);
v = v - ((v >> 1) & 0x55555555);
w = w - ((w >> 1) & 0x55555555);
v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
w = (w & 0x33333333) + ((w >> 2) & 0x33333333);
v = ((v+w) * 0x11111111) >> 28;
return int(v);
}
#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
//// ////
@@ -428,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
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)
+150 -159
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;
} }
} }
+12 -19
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;
}; };
-36
View File
@@ -1,36 +0,0 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 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 "color.h"
////
//// Functions
////
/// color_is_ok(), for debugging:
bool color_is_ok(Color c) {
return c == WHITE || c == BLACK;
}
+5 -16
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,12 +21,6 @@
#if !defined(COLOR_H_INCLUDED) #if !defined(COLOR_H_INCLUDED)
#define COLOR_H_INCLUDED #define COLOR_H_INCLUDED
////
//// Includes
////
#include "misc.h"
//// ////
//// Types //// Types
@@ -43,19 +37,14 @@ 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 i) { c = Color(int(c) + 1); }
inline Color opposite_color(Color c) { inline Color opposite_color(Color c) {
return Color(int(c) ^ 1); return Color(int(c) ^ 1);
} }
inline bool color_is_ok(Color c) {
//// return c == WHITE || c == BLACK;
//// Prototypes }
////
extern bool color_is_ok(Color c);
#endif // !defined(COLOR_H_INCLUDED) #endif // !defined(COLOR_H_INCLUDED)
+1 -4
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 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);
+45 -21
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 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; }
}
} }
}
} }
+14 -5
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 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,8 +38,8 @@ enum Direction {
}; };
enum SignedDirection { enum SignedDirection {
SIGNED_DIR_E = 0, SIGNED_DIR_W = 1, SIGNED_DIR_E = 0, SIGNED_DIR_W = 1,
SIGNED_DIR_N = 2, SIGNED_DIR_S = 3, SIGNED_DIR_N = 2, SIGNED_DIR_S = 3,
SIGNED_DIR_NE = 4, SIGNED_DIR_SW = 5, SIGNED_DIR_NE = 4, SIGNED_DIR_SW = 5,
SIGNED_DIR_NW = 6, SIGNED_DIR_SE = 7, SIGNED_DIR_NW = 6, SIGNED_DIR_SE = 7,
SIGNED_DIR_NONE = 8 SIGNED_DIR_NONE = 8
@@ -58,9 +58,11 @@ extern uint8_t SignedDirectionTable[64][64];
//// Inline functions //// Inline functions
//// ////
inline void operator++ (Direction &d, int) { d = Direction(int(d) + 1); } inline void operator++ (Direction& d, int) {
d = Direction(int(d) + 1);
}
inline void operator++ (SignedDirection &d, int) { inline void operator++ (SignedDirection& d, int) {
d = SignedDirection(int(d) + 1); d = SignedDirection(int(d) + 1);
} }
@@ -72,6 +74,13 @@ inline SignedDirection signed_direction_between_squares(Square s1, Square s2) {
return SignedDirection(SignedDirectionTable[s1][s2]); return SignedDirection(SignedDirectionTable[s1][s2]);
} }
inline int direction_is_diagonal(Square s1, Square s2) {
return DirectionTable[s1][s2] & 2;
}
inline bool direction_is_straight(Square s1, Square s2) {
return DirectionTable[s1][s2] < 2;
}
//// ////
//// Prototypes //// Prototypes
+477 -404
View File
File diff suppressed because it is too large Load Diff
+64 -180
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,149 +34,61 @@
//// Types //// Types
//// ////
/// Abstract base class for all special endgame evaluation functions: enum EndgameType {
class EndgameEvaluationFunction { // Evaluation functions
KXK, // Generic "mate lone king" eval
KBNK, // KBN vs K
KPK, // KP vs K
KRKP, // KR vs KP
KRKB, // KR vs KB
KRKN, // KR vs KN
KQKR, // KQ vs KR
KBBKN, // KBB vs KN
KmmKm, // K and two minors vs K and one or two minors
// Scaling functions
KBPK, // KBP vs K
KQKRP, // KQ vs KRP
KRPKR, // KRP vs KR
KRPPKRP, // KRPP vs KRP
KPsK, // King and pawns vs king
KBPKB, // KBP vs KB
KBPPKB, // KBPP vs KB
KBPKN, // KBP vs KN
KNPK, // KNP vs K
KPKP // KP vs KP
};
/// Template abstract base class for all special endgame functions
template<typename T>
class EndgameFunctionBase {
public: public:
EndgameEvaluationFunction(Color c); EndgameFunctionBase(Color c) : strongerSide(c), weakerSide(opposite_color(c)) {}
virtual ~EndgameEvaluationFunction() { } virtual ~EndgameFunctionBase() {}
virtual T apply(const Position&) = 0;
virtual Value apply(const Position &pos) =0;
protected: protected:
Color strongerSide, weakerSide; Color strongerSide, weakerSide;
}; };
typedef EndgameFunctionBase<Value> EndgameEvaluationFunctionBase;
typedef EndgameFunctionBase<ScaleFactor> EndgameScalingFunctionBase;
/// Subclasses for various concrete endgames:
// Generic "mate lone king" eval: /// Templates subclass for various concrete endgames
class KXKEvaluationFunction : public EndgameEvaluationFunction {
public: template<EndgameType>
KXKEvaluationFunction(Color c); struct EvaluationFunction : public EndgameEvaluationFunctionBase {
Value apply(const Position &pos); explicit EvaluationFunction(Color c): EndgameEvaluationFunctionBase(c) {}
Value apply(const Position&);
}; };
// KBN vs K: template<EndgameType>
class KBNKEvaluationFunction : public EndgameEvaluationFunction { struct ScalingFunction : public EndgameScalingFunctionBase {
public: explicit ScalingFunction(Color c) : EndgameScalingFunctionBase(c) {}
KBNKEvaluationFunction(Color c); ScaleFactor apply(const Position&);
Value apply(const Position &pos);
};
// KP vs K:
class KPKEvaluationFunction : public EndgameEvaluationFunction {
public:
KPKEvaluationFunction(Color c);
Value apply(const Position &pos);
};
// KR vs KP:
class KRKPEvaluationFunction : public EndgameEvaluationFunction {
public:
KRKPEvaluationFunction(Color c);
Value apply(const Position &pos);
};
// KR vs KB:
class KRKBEvaluationFunction : public EndgameEvaluationFunction {
public:
KRKBEvaluationFunction(Color c);
Value apply(const Position &pos);
};
// KR vs KN:
class KRKNEvaluationFunction : public EndgameEvaluationFunction {
public:
KRKNEvaluationFunction(Color c);
Value apply(const Position &pos);
};
// KQ vs KR:
class KQKREvaluationFunction : public EndgameEvaluationFunction {
public:
KQKREvaluationFunction(Color c);
Value apply(const Position &pos);
};
/// Abstract base class for all evaluation scaling functions:
class ScalingFunction {
public:
ScalingFunction(Color c);
virtual ~ScalingFunction() { }
virtual ScaleFactor apply(const Position &pos) =0;
protected:
Color strongerSide, weakerSide;
};
/// Subclasses for various concrete endgames:
// KBP vs K:
class KBPKScalingFunction : public ScalingFunction {
public:
KBPKScalingFunction(Color c);
ScaleFactor apply(const Position &pos);
};
// KQ vs KRP:
class KQKRPScalingFunction: public ScalingFunction {
public:
KQKRPScalingFunction(Color c);
ScaleFactor apply(const Position &pos);
};
// KRP vs KR:
class KRPKRScalingFunction : public ScalingFunction {
public:
KRPKRScalingFunction(Color c);
ScaleFactor apply(const Position &pos);
};
// KRPP vs KRP:
class KRPPKRPScalingFunction : public ScalingFunction {
public:
KRPPKRPScalingFunction(Color c);
ScaleFactor apply(const Position &pos);
};
// King and pawns vs king:
class KPsKScalingFunction : public ScalingFunction {
public:
KPsKScalingFunction(Color c);
ScaleFactor apply(const Position &pos);
};
// KBP vs KB:
class KBPKBScalingFunction : public ScalingFunction {
public:
KBPKBScalingFunction(Color c);
ScaleFactor apply(const Position &pos);
};
// KBP vs KN:
class KBPKNScalingFunction : public ScalingFunction {
public:
KBPKNScalingFunction(Color c);
ScaleFactor apply(const Position &pos);
};
// KNP vs K:
class KNPKScalingFunction : public ScalingFunction {
public:
KNPKScalingFunction(Color c);
ScaleFactor apply(const Position &pos);
};
// KP vs KP:
class KPKPScalingFunction : public ScalingFunction {
public:
KPKPScalingFunction(Color c);
ScaleFactor apply(const Position &pos);
}; };
@@ -184,54 +96,26 @@ public:
//// Constants and variables //// Constants and variables
//// ////
// Generic "mate lone king" eval: extern EvaluationFunction<KXK> EvaluateKXK, EvaluateKKX; // Generic "mate lone king" eval
extern KXKEvaluationFunction EvaluateKXK, EvaluateKKX; extern EvaluationFunction<KBNK> EvaluateKBNK, EvaluateKKBN; // KBN vs K
extern EvaluationFunction<KPK> EvaluateKPK, EvaluateKKP; // KP vs K
// KBN vs K: extern EvaluationFunction<KRKP> EvaluateKRKP, EvaluateKPKR; // KR vs KP
extern KBNKEvaluationFunction EvaluateKBNK, EvaluateKKBN; extern EvaluationFunction<KRKB> EvaluateKRKB, EvaluateKBKR; // KR vs KB
extern EvaluationFunction<KRKN> EvaluateKRKN, EvaluateKNKR; // KR vs KN
// KP vs K: extern EvaluationFunction<KQKR> EvaluateKQKR, EvaluateKRKQ; // KQ vs KR
extern KPKEvaluationFunction EvaluateKPK, EvaluateKKP; extern EvaluationFunction<KBBKN> EvaluateKBBKN, EvaluateKNKBB; // KBB vs KN
extern EvaluationFunction<KmmKm> EvaluateKmmKm; // K and two minors vs K and one or two minors:
// KR vs KP:
extern KRKPEvaluationFunction EvaluateKRKP, EvaluateKPKR;
// KR vs KB:
extern KRKBEvaluationFunction EvaluateKRKB, EvaluateKBKR;
// KR vs KN:
extern KRKNEvaluationFunction EvaluateKRKN, EvaluateKNKR;
// KQ vs KR:
extern KQKREvaluationFunction EvaluateKQKR, EvaluateKRKQ;
// KBP vs K:
extern KBPKScalingFunction ScaleKBPK, ScaleKKBP;
// KQ vs KRP:
extern KQKRPScalingFunction ScaleKQKRP, ScaleKRPKQ;
// KRP vs KR:
extern KRPKRScalingFunction ScaleKRPKR, ScaleKRKRP;
// KRPP vs KRP:
extern KRPPKRPScalingFunction ScaleKRPPKRP, ScaleKRPKRPP;
// King and pawns vs king:
extern KPsKScalingFunction ScaleKPsK, ScaleKKPs;
// KBP vs KB:
extern KBPKBScalingFunction ScaleKBPKB, ScaleKBKBP;
// KBP vs KN:
extern KBPKNScalingFunction ScaleKBPKN, ScaleKNKBP;
// KNP vs K:
extern KNPKScalingFunction ScaleKNPK, ScaleKKNP;
// KP vs KP:
extern KPKPScalingFunction ScaleKPKPw, ScaleKPKPb;
extern ScalingFunction<KBPK> ScaleKBPK, ScaleKKBP; // KBP vs K
extern ScalingFunction<KQKRP> ScaleKQKRP, ScaleKRPKQ; // KQ vs KRP
extern ScalingFunction<KRPKR> ScaleKRPKR, ScaleKRKRP; // KRP vs KR
extern ScalingFunction<KRPPKRP> ScaleKRPPKRP, ScaleKRPKRPP; // KRPP vs KRP
extern ScalingFunction<KPsK> ScaleKPsK, ScaleKKPs; // King and pawns vs king
extern ScalingFunction<KBPKB> ScaleKBPKB, ScaleKBKBP; // KBP vs KB
extern ScalingFunction<KBPPKB> ScaleKBPPKB, ScaleKBKBPP; // KBPP vs KB
extern ScalingFunction<KBPKN> ScaleKBPKN, ScaleKNKBP; // KBP vs KN
extern ScalingFunction<KNPK> ScaleKNPK, ScaleKKNP; // KNP vs K
extern ScalingFunction<KPKP> ScaleKPKPw, ScaleKPKPb; // KP vs KP
//// ////
//// Prototypes //// Prototypes
+497 -462
View File
File diff suppressed because it is too large Load Diff
+15 -14
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,41 +27,42 @@
#include "material.h" #include "material.h"
#include "pawns.h" #include "pawns.h"
#include "position.h"
//// ////
//// Types //// Types
//// ////
/// The EvalInfo struct contains various information computed and collected /// The EvalInfo struct contains various information computed and collected
/// by the evaluation function. An EvalInfo object is passed as one of the /// by the evaluation function. An EvalInfo object is passed as one of the
/// arguments to the evaluation function, and the search can make use of its /// 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;
struct EvalInfo { struct EvalInfo {
// Middle game and endgame evaluations: // Middle game and endgame evaluations
Value mgValue, egValue; Value mgValue, egValue;
// Pointers to material and pawn hash table entries: // Pointers to material and pawn hash table entries
MaterialInfo *mi; MaterialInfo* mi;
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];
@@ -90,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;
}; };
@@ -100,8 +101,8 @@ struct EvalInfo {
//// Prototypes //// Prototypes
//// ////
extern Value evaluate(const Position &pos, EvalInfo &ei, int threadID); extern Value evaluate(const Position& pos, EvalInfo& ei, int threadID);
extern Value quick_evaluate(const Position &pos); extern Value quick_evaluate(const Position& pos);
extern void init_eval(int threads); extern void init_eval(int threads);
extern void quit_eval(); extern void quit_eval();
extern void read_weights(Color sideToMove); extern void read_weights(Color sideToMove);
+33 -30
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]);
} }
+14 -15
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 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)
+3 -3
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 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
@@ -87,7 +87,7 @@ typedef pthread_mutex_t Lock;
#else #else
# include <windows.h> #include <windows.h>
typedef CRITICAL_SECTION Lock; typedef CRITICAL_SECTION Lock;
# define lock_init(x, y) InitializeCriticalSection(x) # define lock_init(x, y) InitializeCriticalSection(x)
+37 -44
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,49 +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
Application::initialize();
init_mersenne(); #ifdef USE_CALLGRIND
init_direction_table(); CALLGRIND_START_INSTRUMENTATION;
init_bitboards(); #endif
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 // Process command line arguments if any
for (int i = abs(get_system_time() % 10000); i > 0; i--) if (argc > 1)
genrand_int32();
// Process command line arguments
if (argc >= 2 && string(argv[1]) == "bench")
{ {
if (argc < 4 || argc > 6) 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: glaurung bench <hash size> <threads> " string time = argc > 4 ? argv[4] : "60";
<< "[time = 60s] [fen positions file = default]" string fen = argc > 5 ? argv[5] : "default";
<< std::endl; string lim = argc > 6 ? argv[6] : "time";
exit(0); string tim = argc > 7 ? argv[7] : "";
benchmark(string(argv[2]) + " " + string(argv[3]) + " " + time + " " + fen + " " + lim + " " + tim);
} }
string time = argc > 4 ? argv[4] : "60";
string fen = argc > 5 ? argv[5] : "default";
benchmark(string(argv[2]) + " " + string(argv[3]) + " " + time + " " + fen);
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;
} }
+106 -66
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 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,11 +23,12 @@
//// ////
#include <cassert> #include <cassert>
#include <cstring> #include <sstream>
#include <map> #include <map>
#include "material.h" #include "material.h"
using std::string;
//// ////
//// Local definitions //// Local definitions
@@ -35,8 +36,9 @@
namespace { namespace {
const Value BishopPairMidgameBonus = Value(100); // Values modified by Joona Kiiski
const Value BishopPairEndgameBonus = Value(100); const Value BishopPairMidgameBonus = Value(109);
const Value BishopPairEndgameBonus = Value(97);
Key KNNKMaterialKey, KKNNMaterialKey; Key KNNKMaterialKey, KKNNMaterialKey;
@@ -54,20 +56,21 @@ class EndgameFunctions {
public: public:
EndgameFunctions(); EndgameFunctions();
EndgameEvaluationFunction* getEEF(Key key) const; EndgameEvaluationFunctionBase* getEEF(Key key) const;
ScalingFunction* getESF(Key key, Color* c) const; EndgameScalingFunctionBase* getESF(Key key, Color* c) const;
private: private:
void add(Key k, EndgameEvaluationFunction* f); void add(const string& keyCode, EndgameEvaluationFunctionBase* f);
void add(Key k, Color c, ScalingFunction* f); void add(const string& keyCode, Color c, EndgameScalingFunctionBase* f);
Key buildKey(const string& keyCode);
struct ScalingInfo struct ScalingInfo
{ {
Color col; Color col;
ScalingFunction* fun; EndgameScalingFunctionBase* fun;
}; };
std::map<Key, EndgameEvaluationFunction*> EEFmap; std::map<Key, EndgameEvaluationFunctionBase*> EEFmap;
std::map<Key, ScalingInfo> ESFmap; std::map<Key, ScalingInfo> ESFmap;
}; };
@@ -88,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();
} }
@@ -98,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));
} }
@@ -143,24 +136,41 @@ MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) {
} }
// Let's look if we have a specialized evaluation function for this // Let's look if we have a specialized evaluation function for this
// particular material configuration. // particular material configuration. First we look for a fixed
// configuration one, then a generic one if previous search failed.
if ((mi->evaluationFunction = funcs->getEEF(key)) != NULL) if ((mi->evaluationFunction = funcs->getEEF(key)) != NULL)
return mi; return mi;
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;
} }
else if ( pos.pawns() == EmptyBoardBB
&& pos.rooks() == EmptyBoardBB
&& pos.queens() == EmptyBoardBB)
{
// Minor piece endgame with at least one minor piece per side,
// and no pawns.
assert(pos.knights(WHITE) | pos.bishops(WHITE));
assert(pos.knights(BLACK) | pos.bishops(BLACK));
if ( pos.piece_count(WHITE, BISHOP) + pos.piece_count(WHITE, KNIGHT) <= 2
&& pos.piece_count(BLACK, BISHOP) + pos.piece_count(BLACK, KNIGHT) <= 2)
{
mi->evaluationFunction = &EvaluateKmmKm;
return mi;
}
}
// OK, we didn't find any special evaluation function for the current // OK, we didn't find any special evaluation function for the current
// material configuration. Is there a suitable scaling function? // material configuration. Is there a suitable scaling function?
@@ -170,7 +180,7 @@ MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) {
// are several conflicting applicable scaling functions and we need to // are several conflicting applicable scaling functions and we need to
// decide which one to use. // decide which one to use.
Color c; Color c;
ScalingFunction* sf; EndgameScalingFunctionBase* sf;
if ((sf = funcs->getESF(key, &c)) != NULL) if ((sf = funcs->getESF(key, &c)) != NULL)
{ {
@@ -221,6 +231,18 @@ MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) {
} }
} }
// Compute the space weight
if (pos.non_pawn_material(WHITE) + pos.non_pawn_material(BLACK) >=
2*QueenValueMidgame + 4*RookValueMidgame + 2*KnightValueMidgame)
{
int minorPieceCount = pos.piece_count(WHITE, KNIGHT)
+ pos.piece_count(BLACK, KNIGHT)
+ pos.piece_count(WHITE, BISHOP)
+ pos.piece_count(BLACK, BISHOP);
mi->spaceWeight = minorPieceCount * minorPieceCount;
}
// Evaluate the material balance // Evaluate the material balance
int sign; int sign;
@@ -287,61 +309,79 @@ MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) {
EndgameFunctions::EndgameFunctions() { EndgameFunctions::EndgameFunctions() {
typedef Key ZM[2][8][16]; KNNKMaterialKey = buildKey("KNNK");
const ZM& z = Position::zobMaterial; KKNNMaterialKey = buildKey("KKNN");
static const Color W = WHITE; add("KPK", &EvaluateKPK);
static const Color B = BLACK; add("KKP", &EvaluateKKP);
add("KBNK", &EvaluateKBNK);
add("KKBN", &EvaluateKKBN);
add("KRKP", &EvaluateKRKP);
add("KPKR", &EvaluateKPKR);
add("KRKB", &EvaluateKRKB);
add("KBKR", &EvaluateKBKR);
add("KRKN", &EvaluateKRKN);
add("KNKR", &EvaluateKNKR);
add("KQKR", &EvaluateKQKR);
add("KRKQ", &EvaluateKRKQ);
add("KBBKN", &EvaluateKBBKN);
add("KNKBB", &EvaluateKNKBB);
KNNKMaterialKey = z[W][KNIGHT][1] ^ z[W][KNIGHT][2]; add("KNPK", WHITE, &ScaleKNPK);
KKNNMaterialKey = z[B][KNIGHT][1] ^ z[B][KNIGHT][2]; add("KKNP", BLACK, &ScaleKKNP);
add("KRPKR", WHITE, &ScaleKRPKR);
add(z[W][PAWN][1], &EvaluateKPK); add("KRKRP", BLACK, &ScaleKRKRP);
add(z[B][PAWN][1], &EvaluateKKP); add("KBPKB", WHITE, &ScaleKBPKB);
add("KBKBP", BLACK, &ScaleKBKBP);
add(z[W][BISHOP][1] ^ z[W][KNIGHT][1], &EvaluateKBNK); add("KBPPKB", WHITE, &ScaleKBPPKB);
add(z[B][BISHOP][1] ^ z[B][KNIGHT][1], &EvaluateKKBN); add("KBKBPP", BLACK, &ScaleKBKBPP);
add(z[W][ROOK][1] ^ z[B][PAWN][1], &EvaluateKRKP); add("KBPKN", WHITE, &ScaleKBPKN);
add(z[W][PAWN][1] ^ z[B][ROOK][1], &EvaluateKPKR); add("KNKBP", BLACK, &ScaleKNKBP);
add(z[W][ROOK][1] ^ z[B][BISHOP][1], &EvaluateKRKB); add("KRPPKRP", WHITE, &ScaleKRPPKRP);
add(z[W][BISHOP][1] ^ z[B][ROOK][1], &EvaluateKBKR); add("KRPKRPP", BLACK, &ScaleKRPKRPP);
add(z[W][ROOK][1] ^ z[B][KNIGHT][1], &EvaluateKRKN); add("KRPPKRP", WHITE, &ScaleKRPPKRP);
add(z[W][KNIGHT][1] ^ z[B][ROOK][1], &EvaluateKNKR); add("KRPKRPP", BLACK, &ScaleKRPKRPP);
add(z[W][QUEEN][1] ^ z[B][ROOK][1], &EvaluateKQKR);
add(z[W][ROOK][1] ^ z[B][QUEEN][1], &EvaluateKRKQ);
add(z[W][KNIGHT][1] ^ z[W][PAWN][1], W, &ScaleKNPK);
add(z[B][KNIGHT][1] ^ z[B][PAWN][1], B, &ScaleKKNP);
add(z[W][ROOK][1] ^ z[W][PAWN][1] ^ z[B][ROOK][1] , W, &ScaleKRPKR);
add(z[W][ROOK][1] ^ z[B][ROOK][1] ^ z[B][PAWN][1] , B, &ScaleKRKRP);
add(z[W][BISHOP][1] ^ z[W][PAWN][1] ^ z[B][BISHOP][1], W, &ScaleKBPKB);
add(z[W][BISHOP][1] ^ z[B][BISHOP][1] ^ z[B][PAWN][1] , B, &ScaleKBKBP);
add(z[W][BISHOP][1] ^ z[W][PAWN][1] ^ z[B][KNIGHT][1], W, &ScaleKBPKN);
add(z[W][KNIGHT][1] ^ z[B][BISHOP][1] ^ z[B][PAWN][1] , B, &ScaleKNKBP);
add(z[W][ROOK][1] ^ z[W][PAWN][1] ^ z[W][PAWN][2] ^ z[B][ROOK][1] ^ z[B][PAWN][1], W, &ScaleKRPPKRP);
add(z[W][ROOK][1] ^ z[W][PAWN][1] ^ z[B][ROOK][1] ^ z[B][PAWN][1] ^ z[B][PAWN][2], B, &ScaleKRPKRPP);
} }
void EndgameFunctions::add(Key k, EndgameEvaluationFunction* f) { Key EndgameFunctions::buildKey(const string& keyCode) {
EEFmap.insert(std::pair<Key, EndgameEvaluationFunction*>(k, f)); assert(keyCode.length() > 0 && keyCode[0] == 'K');
assert(keyCode.length() < 8);
std::stringstream s;
bool upcase = false;
// Build up a fen substring with the given pieces, note
// that the fen string could be of an illegal position.
for (size_t i = 0; i < keyCode.length(); i++)
{
if (keyCode[i] == 'K')
upcase = !upcase;
s << char(upcase? toupper(keyCode[i]) : tolower(keyCode[i]));
}
s << 8 - keyCode.length() << "/8/8/8/8/8/8/8 w -";
return Position(s.str()).get_material_key();
} }
void EndgameFunctions::add(Key k, Color c, ScalingFunction* f) { void EndgameFunctions::add(const string& keyCode, EndgameEvaluationFunctionBase* f) {
EEFmap.insert(std::pair<Key, EndgameEvaluationFunctionBase*>(buildKey(keyCode), 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>(k, s)); ESFmap.insert(std::pair<Key, ScalingInfo>(buildKey(keyCode), s));
} }
EndgameEvaluationFunction* EndgameFunctions::getEEF(Key key) const { EndgameEvaluationFunctionBase* EndgameFunctions::getEEF(Key key) const {
std::map<Key, EndgameEvaluationFunction*>::const_iterator it(EEFmap.find(key)); std::map<Key, EndgameEvaluationFunctionBase*>::const_iterator it(EEFmap.find(key));
return (it != EEFmap.end() ? it->second : NULL); return (it != EEFmap.end() ? it->second : NULL);
} }
ScalingFunction* EndgameFunctions::getESF(Key key, Color* c) const { EndgameScalingFunctionBase* EndgameFunctions::getESF(Key key, Color* c) const {
std::map<Key, ScalingInfo>::const_iterator it(ESFmap.find(key)); std::map<Key, ScalingInfo>::const_iterator it(ESFmap.find(key));
if (it == ESFmap.end()) if (it == ESFmap.end())
+21 -8
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 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,21 +49,25 @@ 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;
int space_weight() const;
bool specialized_eval_exists() const; bool specialized_eval_exists() const;
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;
int16_t egValue; int16_t egValue;
uint8_t factor[2]; uint8_t factor[2];
EndgameEvaluationFunction* evaluationFunction; EndgameEvaluationFunctionBase* evaluationFunction;
ScalingFunction* scalingFunction[2]; EndgameScalingFunctionBase* scalingFunction[2];
int spaceWeight;
}; };
@@ -85,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:
@@ -114,7 +117,7 @@ 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() {
@@ -122,11 +125,12 @@ inline void MaterialInfo::clear() {
factor[WHITE] = factor[BLACK] = uint8_t(SCALE_FACTOR_NORMAL); factor[WHITE] = factor[BLACK] = uint8_t(SCALE_FACTOR_NORMAL);
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
@@ -144,6 +148,15 @@ inline ScaleFactor MaterialInfo::scale_factor(const Position& pos, Color c) cons
} }
/// MaterialInfo::space_weight() simply returns the weight for the space
/// evaluation for this material configuration.
inline int MaterialInfo::space_weight() const {
return spaceWeight;
}
/// MaterialInfo::specialized_eval_exists decides whether there is a /// MaterialInfo::specialized_eval_exists decides whether there is a
/// specialized evaluation function for the current material configuration, /// specialized evaluation function for the current material configuration,
/// or if the normal evaluation function should be used. /// or if the normal evaluation function should be used.
@@ -155,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 {
+1 -1
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 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
+108 -22
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,28 +29,63 @@
# include <unistd.h> # include <unistd.h>
#else #else
/*
(c) Copyright 1992 Eric Backus
This software may be used freely so long as this copyright notice is
left intact. There is no warrantee on this software.
*/
# include <windows.h> # include <windows.h>
# include <time.h> # include <time.h>
# include "dos.h" # include "dos.h"
int gettimeofday(struct timeval * tp, struct timezone * tzp);
static int gettimeofday(struct timeval* tp, struct timezone*)
{
SYSTEMTIME systime;
if (tp)
{
struct tm tmrec;
time_t theTime = time(NULL);
tmrec = *localtime(&theTime);
tp->tv_sec = mktime(&tmrec);
GetLocalTime(&systime); /* system time */
tp->tv_usec = systime.wMilliseconds * 1000;
}
return 0;
}
#endif #endif
#include <cassert>
#include <cstdio> #include <cstdio>
#include <iomanip> #include <iomanip>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include "bitcount.h"
#include "misc.h" #include "misc.h"
using namespace std;
/// Version number. If this is left empty, the current date (in the format
/// YYMMDD) is used as a version number.
static const string EngineVersion = "1.4";
static const string AppName = "Stockfish";
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;
@@ -60,17 +95,65 @@ bool dbg_show_hit_rate = false;
//// Functions //// Functions
//// ////
void dbg_hit_on(bool b) {
assert(!dbg_show_mean);
dbg_show_hit_rate = true;
dbg_cnt0++;
if (b)
dbg_cnt1++;
}
void dbg_hit_on_c(bool c, bool b) {
if (c)
dbg_hit_on(b);
}
void dbg_before() {
assert(!dbg_show_mean);
dbg_show_hit_rate = true;
dbg_cnt0++;
}
void dbg_after() {
assert(!dbg_show_mean);
dbg_show_hit_rate = true;
dbg_cnt1++;
}
void dbg_mean_of(int v) {
assert(!dbg_show_hit_rate);
dbg_show_mean = true;
dbg_cnt0++;
dbg_cnt1 += v;
}
void dbg_print_hit_rate() { void dbg_print_hit_rate() {
std::cout << "Total " << dbg_cnt0 << " Hit " << dbg_cnt1 cout << "Total " << dbg_cnt0 << " Hit " << dbg_cnt1
<< " hit rate (%) " << (dbg_cnt1*100)/(dbg_cnt0 ? dbg_cnt0 : 1) << " hit rate (%) " << (dbg_cnt1*100)/(dbg_cnt0 ? dbg_cnt0 : 1) << endl;
<< std::endl;
} }
void dbg_print_mean() { void dbg_print_mean() {
std::cout << "Total " << dbg_cnt0 << " Mean " cout << "Total " << dbg_cnt0 << " Mean "
<< (float)dbg_cnt1 / (dbg_cnt0 ? dbg_cnt0 : 1) << std::endl; << (float)dbg_cnt1 / (dbg_cnt0 ? dbg_cnt0 : 1) << endl;
}
void dbg_print_hit_rate(ofstream& logFile) {
logFile << "Total " << dbg_cnt0 << " Hit " << dbg_cnt1
<< " hit rate (%) " << (dbg_cnt1*100)/(dbg_cnt0 ? dbg_cnt0 : 1) << endl;
}
void dbg_print_mean(ofstream& logFile) {
logFile << "Total " << dbg_cnt0 << " Mean "
<< (float)dbg_cnt1 / (dbg_cnt0 ? dbg_cnt0 : 1) << endl;
} }
/// engine_name() returns the full name of the current Stockfish version. /// engine_name() returns the full name of the current Stockfish version.
@@ -78,24 +161,27 @@ void dbg_print_mean() {
/// program was compiled) or "Stockfish <version number>", depending on whether /// program was compiled) or "Stockfish <version number>", depending on whether
/// the constant EngineVersion (defined in misc.h) is empty. /// the constant EngineVersion (defined in misc.h) is empty.
const std::string engine_name() { const string engine_name() {
if (EngineVersion.empty()) const string cpu64(CpuHas64BitPath ? " 64bit" : "");
{
std::string date(__DATE__); // From compiler, format is "Sep 21 2008"
std::string months("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec");
size_t mon = 1 + months.find(date.substr(0, 3)) / 4; if (!EngineVersion.empty())
return AppName+ " " + EngineVersion + cpu64;
std::stringstream s; string date(__DATE__); // From compiler, format is "Sep 21 2008"
std::string day = (date[4] == ' ' ? date.substr(5, 1) : date.substr(4, 2)); string months("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec");
s << "Stockfish " << date.substr(date.length() - 2) << std::setfill('0') size_t mon = 1 + months.find(date.substr(0, 3)) / 4;
<< std::setw(2) << mon << std::setw(2) << day;
return s.str(); stringstream s;
} else string day = (date[4] == ' ' ? date.substr(5, 1) : date.substr(4, 2));
return "Stockfish " + EngineVersion;
string name = AppName + " " + AppTag + " ";
s << name << date.substr(date.length() - 2) << setfill('0')
<< setw(2) << mon << setw(2) << day << cpu64;
return s.str();
} }
+25 -25
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 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,19 +26,11 @@
//// Includes //// Includes
//// ////
#include <fstream>
#include <string> #include <string>
#include "application.h"
//// #include "types.h"
//// Constants
////
/// Version number. If this is left empty, the current date (in the format
/// YYMMDD) is used as a version number.
const std::string EngineVersion = "1.01";
//// ////
//// Macros //// Macros
@@ -48,6 +40,13 @@ const std::string EngineVersion = "1.01";
#define Max(x, y) (((x) < (y))? (y) : (x)) #define Max(x, y) (((x) < (y))? (y) : (x))
////
//// Variables
////
extern bool Chess960;
//// ////
//// Prototypes //// Prototypes
//// ////
@@ -57,24 +56,25 @@ extern int get_system_time();
extern int cpu_count(); extern int cpu_count();
extern int Bioskey(); extern int Bioskey();
//// ////
//// Debug //// Debug
//// ////
extern long dbg_cnt0;
extern long dbg_cnt1;
inline void dbg_hit_on(bool b) { dbg_cnt0++; if (b) dbg_cnt1++; }
inline void dbg_hit_on_c(bool c, bool b) { if (c) dbg_hit_on(b); }
inline void dbg_before() { dbg_cnt0++; }
inline void dbg_after() { dbg_cnt1++; }
inline void dbg_mean_of(int v) { dbg_cnt0++; dbg_cnt1 += v; }
extern void dbg_print_hit_rate();
extern void dbg_print_mean();
extern bool dbg_show_mean; extern bool dbg_show_mean;
extern bool dbg_show_hit_rate; extern bool dbg_show_hit_rate;
extern uint64_t dbg_cnt0;
extern uint64_t dbg_cnt1;
extern void dbg_hit_on(bool b);
extern void dbg_hit_on_c(bool c, bool b);
extern void dbg_before();
extern void dbg_after();
extern void dbg_mean_of(int v);
extern void dbg_print_hit_rate();
extern void dbg_print_mean();
extern void dbg_print_hit_rate(std::ofstream& logFile);
extern void dbg_print_mean(std::ofstream& logFile);
#endif // !defined(MISC_H_INCLUDED) #endif // !defined(MISC_H_INCLUDED)
+8 -9
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 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"
//// ////
@@ -72,13 +71,13 @@ Move move_from_string(const Position& pos, const std::string& str) {
} }
} }
if (piece == king_of_color(us)) if (piece == piece_of_color_and_type(us, KING))
{ {
// Is this a castling move? A king move is assumed to be a castling // Is this a castling move? A king move is assumed to be a castling
// move if the destination square is occupied by a friendly rook, or // move if the destination square is occupied by a friendly rook, or
// if the distance between the source and destination squares is more // if the distance between the source and destination squares is more
// than 1. // than 1.
if (pos.piece_on(to) == rook_of_color(us)) if (pos.piece_on(to) == piece_of_color_and_type(us, ROOK))
return make_castle_move(from, to); return make_castle_move(from, to);
else if (square_distance(from, to) > 1) else if (square_distance(from, to) > 1)
@@ -87,13 +86,13 @@ Move move_from_string(const Position& pos, const std::string& str) {
// internal "king captures rook" representation. // internal "king captures rook" representation.
SquareDelta delta = (to > from ? DELTA_E : DELTA_W); SquareDelta delta = (to > from ? DELTA_E : DELTA_W);
Square s = from + delta; Square s = from + delta;
while (relative_rank(us, s) == RANK_1 && pos.piece_on(s) != rook_of_color(us)) while (relative_rank(us, s) == RANK_1 && pos.piece_on(s) != piece_of_color_and_type(us, ROOK))
s += delta; s += delta;
return (relative_rank(us, s) == RANK_1 ? make_castle_move(from, s) : MOVE_NONE); return (relative_rank(us, s) == RANK_1 ? make_castle_move(from, s) : MOVE_NONE);
} }
} }
else if (piece == pawn_of_color(us)) else if (piece == piece_of_color_and_type(us, PAWN))
{ {
// En passant move? We assume that a pawn move is an en passant move // En passant move? We assume that a pawn move is an en passant move
// without further testing if the destination square is epSquare. // without further testing if the destination square is epSquare.
@@ -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;
} }
@@ -139,7 +138,7 @@ const std::string move_to_string(Move move) {
/// Overload the << operator, to make it easier to print moves. /// Overload the << operator, to make it easier to print moves.
std::ostream &operator << (std::ostream &os, Move m) { std::ostream &operator << (std::ostream& os, Move m) {
return os << move_to_string(m); return os << move_to_string(m);
} }
+30 -11
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,10 +38,22 @@
class Position; class Position;
/// A move needs 17 bits to be stored
///
/// bit 0- 5: destination square (from 0 to 63)
/// bit 6-11: origin square (from 0 to 63)
/// bit 12-14: promotion piece type
/// bit 15: en passant flag
/// bit 16: castle flag
///
/// Special cases are MOVE_NONE and MOVE_NULL. We can sneak these in
/// because in any normal move destination square is always different
/// from origin square while MOVE_NONE and MOVE_NULL have the same
/// origin and destination square, 0 and 1 respectively.
enum Move { enum Move {
MOVE_NONE = 0, MOVE_NONE = 0,
MOVE_NULL = 65, MOVE_NULL = 65
MOVE_MAX = 0xFFFFFF
}; };
@@ -50,29 +62,36 @@ struct MoveStack {
int score; int score;
}; };
// Note that operator< is set up such that std::sort() will sort in descending order
inline bool operator<(const MoveStack& f, const MoveStack& s) { return s.score < f.score; }
//// ////
//// Inline functions //// Inline functions
//// ////
inline Square move_from(Move m) { inline Square move_from(Move m) {
return Square((int(m) >> 6) & 077); return Square((int(m) >> 6) & 0x3F);
} }
inline Square move_to(Move m) { inline Square move_to(Move m) {
return Square(m & 077); 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) {
@@ -104,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);
+377 -358
View File
File diff suppressed because it is too large Load Diff
+7 -7
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,12 +32,12 @@
//// Prototypes //// Prototypes
//// ////
extern int generate_captures(const Position &pos, MoveStack *mlist); extern int generate_captures(const Position& pos, MoveStack* mlist);
extern int generate_noncaptures(const Position &pos, MoveStack *mlist); extern int generate_noncaptures(const Position& pos, MoveStack* mlist);
extern int generate_checks(const Position &pos, MoveStack *mlist, Bitboard dc); extern int generate_non_capture_checks(const Position& pos, MoveStack* mlist, Bitboard dc);
extern int generate_evasions(const Position &pos, MoveStack *mlist); extern int generate_evasions(const Position& pos, MoveStack* mlist, Bitboard pinned);
extern int generate_legal_moves(const Position &pos, MoveStack *mlist); extern int generate_legal_moves(const Position& pos, MoveStack* mlist);
extern bool move_is_legal(const Position &pos, const Move m, Bitboard pinned); extern bool move_is_legal(const Position& pos, const Move m, Bitboard pinned);
#endif // !defined(MOVEGEN_H_INCLUDED) #endif // !defined(MOVEGEN_H_INCLUDED)
+98 -175
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,9 +23,11 @@
//// Includes //// Includes
//// ////
#include <algorithm>
#include <cassert> #include <cassert>
#include "history.h" #include "history.h"
#include "evaluate.h"
#include "movegen.h" #include "movegen.h"
#include "movepick.h" #include "movepick.h"
#include "search.h" #include "search.h"
@@ -49,7 +51,6 @@ namespace {
} }
//// ////
//// Functions //// Functions
//// ////
@@ -62,29 +63,33 @@ 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 pvnode, Move ttm, Move mk, MovePicker::MovePicker(const Position& p, Move ttm, Depth d,
Move k1, Move k2, Depth d) : pos(p) { const History& h, SearchStack* ss) : pos(p), H(h) {
pvNode = pvnode;
ttMove = ttm; ttMove = ttm;
mateKiller = (mk == ttm)? MOVE_NONE : mk; if (ss)
killer1 = k1; {
killer2 = k2; 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;
dc = p.discovered_check_candidates(p.side_to_move());
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;
pinned = p.pinned_pieces(p.side_to_move()); Color us = pos.side_to_move();
dc = p.discovered_check_candidates(us);
pinned = p.pinned_pieces(us);
finished = false; finished = false;
} }
@@ -128,40 +133,60 @@ Move MovePicker::get_next_move() {
assert(move_is_ok(mateKiller)); assert(move_is_ok(mateKiller));
if (move_is_legal(pos, mateKiller, pinned)) if (move_is_legal(pos, mateKiller, pinned))
return mateKiller; return mateKiller;
} }
break; break;
case PH_GOOD_CAPTURES: case PH_GOOD_CAPTURES:
numOfMoves = generate_captures(pos, moves); numOfMoves = generate_captures(pos, moves);
score_captures(); score_captures();
std::sort(moves, moves + numOfMoves);
movesPicked = 0; movesPicked = 0;
checkLegal = true;
break; break;
case PH_BAD_CAPTURES: case PH_KILLERS:
badCapturesPicked = 0; movesPicked = numOfMoves = 0;
checkLegal = false;
if (killer1 != MOVE_NONE && move_is_legal(pos, killer1, pinned) && !pos.move_is_capture(killer1))
moves[numOfMoves++].move = killer1;
if (killer2 != MOVE_NONE && move_is_legal(pos, killer2, pinned) && !pos.move_is_capture(killer2) )
moves[numOfMoves++].move = killer2;
break; 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);
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; movesPicked = 0;
break; break;
case PH_EVASIONS: case PH_EVASIONS:
assert(pos.is_check()); assert(pos.is_check());
numOfMoves = generate_evasions(pos, moves); numOfMoves = generate_evasions(pos, moves, pinned);
score_evasions(); score_evasions();
std::sort(moves, moves + numOfMoves);
movesPicked = 0; movesPicked = 0;
break; break;
case PH_QCAPTURES: case PH_QCAPTURES:
numOfMoves = generate_captures(pos, moves); numOfMoves = generate_captures(pos, moves);
score_qcaptures(); score_qcaptures();
std::sort(moves, moves + numOfMoves);
movesPicked = 0; movesPicked = 0;
break; break;
case PH_QCHECKS: case PH_QCHECKS:
numOfMoves = generate_checks(pos, moves, dc); // Perhaps we should order moves move here? FIXME
numOfMoves = generate_non_capture_checks(pos, moves, dc);
movesPicked = 0; movesPicked = 0;
break; break;
@@ -211,6 +236,8 @@ void MovePicker::score_captures() {
// where it is possible to recapture with the hanging piece). Exchanging // where it is possible to recapture with the hanging piece). Exchanging
// big pieces before capturing a hanging piece probably helps to reduce // big pieces before capturing a hanging piece probably helps to reduce
// the subtree size. // the subtree size.
// While scoring captures it moves all captures with negative SEE values
// to the badCaptures[] array.
Move m; Move m;
int seeValue; int seeValue;
@@ -220,13 +247,20 @@ 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)))
-int(pos.type_of_piece_on(move_from(m))); -int(pos.type_of_piece_on(move_from(m)));
} else }
else
{
// Losing capture, move it to the badCaptures[] array
assert(numOfBadCaptures < 63);
moves[i].score = seeValue; moves[i].score = seeValue;
badCaptures[numOfBadCaptures++] = moves[i];
moves[i--] = moves[--numOfMoves];
}
} }
} }
@@ -234,25 +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);
piece = pos.piece_on(from);
hs = H.move_ordering_score(piece, to);
if (m == killer1) // Ensure history is always preferred to pst
hs = HistoryMax + 2;
else if (m == killer2)
hs = HistoryMax + 1;
else
hs = H.move_ordering_score(pos.piece_on(move_from(m)), m);
// Ensure moves in history are always sorted as first
if (hs > 0) if (hs > 0)
hs += 1000; hs += 1000;
moves[i].score = hs + pos.mg_pst_delta(m); // pst based scoring
moves[i].score = hs + pos.pst_delta<Position::MidGame>(piece, from, to);
} }
} }
@@ -268,9 +300,8 @@ 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));
} }
// FIXME try psqt also here
} }
void MovePicker::score_qcaptures() { void MovePicker::score_qcaptures() {
@@ -279,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)))
@@ -288,121 +319,43 @@ void MovePicker::score_qcaptures() {
} }
/// find_best_index() loops across the moves and returns index of
/// the highest scored one.
int MovePicker::find_best_index() {
int bestScore = -10000000, bestIndex = -1;
for (int i = movesPicked; i < numOfMoves; i++)
if (moves[i].score > bestScore)
{
bestIndex = i;
bestScore = moves[i].score;
}
return bestIndex;
}
/// MovePicker::pick_move_from_list() picks the move with the biggest score /// MovePicker::pick_move_from_list() picks the move with the biggest score
/// from a list of generated moves (moves[] or badCaptures[], depending on /// from a list of generated moves (moves[] or badCaptures[], depending on
/// the current move generation phase). It takes care not to return the /// the current move generation phase). It takes care not to return the
/// transposition table move if that has already been serched previously. /// transposition table move if that has already been serched previously.
/// While picking captures in the PH_GOOD_CAPTURES phase (i.e. while picking
/// non-losing captures in the main search), it moves all captures with
/// negative SEE values to the badCaptures[] array.
Move MovePicker::pick_move_from_list() { Move MovePicker::pick_move_from_list() {
int bestIndex; assert(movesPicked >= 0);
Move move; assert(!pos.is_check() || PhaseTable[phaseIndex] == PH_EVASIONS || PhaseTable[phaseIndex] == PH_STOP);
assert( pos.is_check() || PhaseTable[phaseIndex] != PH_EVASIONS);
switch (PhaseTable[phaseIndex]) { switch (PhaseTable[phaseIndex]) {
case PH_GOOD_CAPTURES: case PH_GOOD_CAPTURES:
assert(!pos.is_check()); case PH_KILLERS:
assert(movesPicked >= 0);
while (movesPicked < numOfMoves)
{
int bestScore = -10000000;
bestIndex = -1;
for (int i = movesPicked; i < numOfMoves; i++)
{
if (moves[i].score < 0)
{
// Losing capture, move it to the badCaptures[] array
assert(numOfBadCaptures < 63);
badCaptures[numOfBadCaptures++] = moves[i];
moves[i--] = moves[--numOfMoves];
}
else if (moves[i].score > bestScore)
{
bestIndex = i;
bestScore = moves[i].score;
}
}
if (bestIndex != -1) // Found a good capture
{
move = moves[bestIndex].move;
moves[bestIndex] = moves[movesPicked++];
if ( move != ttMove
&& move != mateKiller
&& pos.pl_move_is_legal(move, pinned))
return move;
}
}
break;
case PH_NONCAPTURES: case PH_NONCAPTURES:
assert(!pos.is_check());
assert(movesPicked >= 0);
while (movesPicked < numOfMoves) while (movesPicked < numOfMoves)
{ {
// If this is a PV node or we have only picked a few moves, scan Move move = moves[movesPicked++].move;
// the entire move list for the best move. If many moves have already if ( move != ttMove
// been searched and it is not a PV node, we are probably failing low && move != mateKiller
// anyway, so we just pick the first move from the list. && (!checkKillers || (move != killer1 && move != killer2))
bestIndex = (pvNode || movesPicked < 12) ? find_best_index() : movesPicked; && (!checkLegal || pos.pl_move_is_legal(move, pinned)))
return move;
if (bestIndex != -1)
{
move = moves[bestIndex].move;
moves[bestIndex] = moves[movesPicked++];
if ( move != ttMove
&& move != mateKiller
&& pos.pl_move_is_legal(move, pinned))
return move;
}
} }
break; break;
case PH_EVASIONS: case PH_EVASIONS:
assert(pos.is_check()); if (movesPicked < numOfMoves)
assert(movesPicked >= 0); return moves[movesPicked++].move;
while (movesPicked < numOfMoves) break;
{
bestIndex = find_best_index();
if (bestIndex != -1)
{
move = moves[bestIndex].move;
moves[bestIndex] = moves[movesPicked++];
return move;
}
}
break;
case PH_BAD_CAPTURES: case PH_BAD_CAPTURES:
assert(!pos.is_check()); while (movesPicked < numOfBadCaptures)
assert(badCapturesPicked >= 0);
// It's probably a good idea to use SEE move ordering here, instead
// of just picking the first move. FIXME
while (badCapturesPicked < numOfBadCaptures)
{ {
move = badCaptures[badCapturesPicked++].move; Move move = badCaptures[movesPicked++].move;
if ( move != ttMove if ( move != ttMove
&& move != mateKiller && move != mateKiller
&& pos.pl_move_is_legal(move, pinned)) && pos.pl_move_is_legal(move, pinned))
@@ -411,34 +364,13 @@ Move MovePicker::pick_move_from_list() {
break; break;
case PH_QCAPTURES: case PH_QCAPTURES:
assert(!pos.is_check());
assert(movesPicked >= 0);
while (movesPicked < numOfMoves)
{
bestIndex = (movesPicked < 4 ? find_best_index() : movesPicked);
if (bestIndex != -1)
{
move = moves[bestIndex].move;
moves[bestIndex] = moves[movesPicked++];
// Remember to change the line below if we decide to hash the qsearch!
// Maybe also postpone the legality check until after futility pruning?
if (/* move != ttMove && */ pos.pl_move_is_legal(move, pinned))
return move;
}
}
break;
case PH_QCHECKS: case PH_QCHECKS:
assert(!pos.is_check());
assert(movesPicked >= 0);
// Perhaps we should do something better than just picking the first
// move here? FIXME
while (movesPicked < numOfMoves) while (movesPicked < numOfMoves)
{ {
move = moves[movesPicked++].move; Move move = moves[movesPicked++].move;
// Remember to change the line below if we decide to hash the qsearch! // Maybe postpone the legality check until after futility pruning?
if (/* move != ttMove && */ pos.pl_move_is_legal(move, pinned)) if ( move != ttMove
&& pos.pl_move_is_legal(move, pinned))
return move; return move;
} }
break; break;
@@ -450,19 +382,10 @@ Move MovePicker::pick_move_from_list() {
} }
/// MovePicker::current_move_type() returns the type of the just
/// picked next move. It can be used in search to further differentiate
/// according to the current move type: capture, non capture, escape, etc.
MovePicker::MovegenPhase MovePicker::current_move_type() const {
return PhaseTable[phaseIndex];
}
/// MovePicker::init_phase_table() initializes the PhaseTable[], /// MovePicker::init_phase_table() initializes the PhaseTable[],
/// MainSearchPhaseIndex, EvasionPhaseIndex, QsearchWithChecksPhaseIndex /// MainSearchPhaseIndex, EvasionPhaseIndex, QsearchWithChecksPhaseIndex
/// and QsearchWithoutChecksPhaseIndex variables. It is only called once /// and QsearchWithoutChecksPhaseIndex. It is only called once during
/// during program startup, and never again while the program is running. /// program startup, and never again while the program is running.
void MovePicker::init_phase_table() { void MovePicker::init_phase_table() {
@@ -473,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;
@@ -487,12 +408,14 @@ void MovePicker::init_phase_table() {
// Quiescence search with checks // Quiescence search with checks
QsearchWithChecksPhaseIndex = i - 1; QsearchWithChecksPhaseIndex = i - 1;
PhaseTable[i++] = PH_TT_MOVE;
PhaseTable[i++] = PH_QCAPTURES; PhaseTable[i++] = PH_QCAPTURES;
PhaseTable[i++] = PH_QCHECKS; PhaseTable[i++] = PH_QCHECKS;
PhaseTable[i++] = PH_STOP; PhaseTable[i++] = PH_STOP;
// Quiescence search without checks // Quiescence search without checks
QsearchWithoutChecksPhaseIndex = i - 1; QsearchWithoutChecksPhaseIndex = i - 1;
PhaseTable[i++] = PH_TT_MOVE;
PhaseTable[i++] = PH_QCAPTURES; PhaseTable[i++] = PH_QCAPTURES;
PhaseTable[i++] = PH_STOP; PhaseTable[i++] = PH_STOP;
} }
+18 -17
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 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"
@@ -34,9 +35,12 @@
//// Types //// Types
//// ////
struct EvalInfo;
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
@@ -44,28 +48,27 @@
class MovePicker { class MovePicker {
MovePicker& operator=(const MovePicker&); // silence a warning under MSVC
public: public:
enum MovegenPhase { enum MovegenPhase {
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, Move mk, Move k1, Move k2, 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;
MovegenPhase current_move_type() const;
Bitboard discovered_check_candidates() const; Bitboard discovered_check_candidates() const;
static void init_phase_table(); static void init_phase_table();
@@ -76,17 +79,16 @@ private:
void score_evasions(); void score_evasions();
void score_qcaptures(); void score_qcaptures();
Move pick_move_from_list(); Move pick_move_from_list();
int find_best_index();
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, badCapturesPicked; int movesPicked;
bool checkKillers, checkLegal;
bool finished; bool finished;
}; };
@@ -101,12 +103,11 @@ private:
/// a single reply to check. /// a single reply to check.
inline int MovePicker::number_of_moves() const { inline int MovePicker::number_of_moves() const {
return numOfMoves; return numOfMoves;
} }
/// 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 {
+221 -221
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,9 +23,10 @@
//// ////
#include <cassert> #include <cassert>
#include <cstring>
#include "bitcount.h"
#include "pawns.h" #include "pawns.h"
#include "position.h"
//// ////
@@ -38,98 +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)
}; };
// Evaluate pawn storms?
const bool EvaluatePawnStorms = true;
// 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 int KStormOpenFileBonus[8] = { const int16_t KStormOpenFileBonus[8] = { 31, 31, 18, 0, 0, 0, 0, 0 };
45, 45, 30, 0, 0, 0, 0, 0 const int16_t QStormOpenFileBonus[8] = { 0, 0, 0, 0, 0, 26, 42, 26 };
};
const int QStormOpenFileBonus[8] = { // Pawn storm lever bonuses by file
0, 0, 0, 0, 0, 30, 45, 30 const int StormLeverBonus[8] = { -8, -8, -13, 0, 0, -13, -8, -8 };
};
} }
@@ -141,14 +137,15 @@ namespace {
/// Constructor /// Constructor
PawnInfoTable::PawnInfoTable(unsigned numOfEntries) { PawnInfoTable::PawnInfoTable(unsigned numOfEntries) {
size = numOfEntries; size = numOfEntries;
entries = new PawnInfo[size]; entries = new PawnInfo[size];
if(entries == NULL) { if (entries == NULL)
std::cerr << "Failed to allocate " << (numOfEntries * sizeof(PawnInfo)) {
<< " bytes for pawn hash table." << std::endl; std::cerr << "Failed to allocate " << (numOfEntries * sizeof(PawnInfo))
exit(EXIT_FAILURE); << " bytes for pawn hash table." << std::endl;
Application::exit_with_failure();
} }
this->clear();
} }
@@ -159,20 +156,13 @@ 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
/// the same pawn structure occurs again. /// the same pawn structure occurs again.
PawnInfo *PawnInfoTable::get_pawn_info(const Position &pos) { PawnInfo *PawnInfoTable::get_pawn_info(const Position &pos) {
assert(pos.is_ok()); assert(pos.is_ok());
Key key = pos.get_pawn_key(); Key key = pos.get_pawn_key();
@@ -181,207 +171,217 @@ PawnInfo *PawnInfoTable::get_pawn_info(const Position &pos) {
// If pi->key matches the position's pawn hash key, it means that we // If pi->key matches the position's pawn hash key, it means that we
// have analysed this pawn structure before, and we can simply return the // have analysed this pawn structure before, and we can simply return the
// information we found the last time instead of recomputing it: // information we found the last time instead of recomputing it
if(pi->key == key) if (pi->key == key)
return pi; return pi;
// Clear the PawnInfo object, and set the key: // Clear the PawnInfo object, and set the key
pi->clear(); pi->clear();
pi->key = key; pi->key = key;
Value mgValue[2] = {Value(0), Value(0)}; Value mgValue[2] = {Value(0), Value(0)};
Value egValue[2] = {Value(0), Value(0)}; Value egValue[2] = {Value(0), Value(0)};
// Loop through the pawns for both colors: // Loop through the pawns for both colors
for(Color us = WHITE; us <= BLACK; us++) { for (Color us = WHITE; us <= BLACK; us++)
{
Color them = opposite_color(us); Color them = opposite_color(us);
Bitboard ourPawns = pos.pawns(us); Bitboard ourPawns = pos.pawns(us);
Bitboard theirPawns = pos.pawns(them); Bitboard theirPawns = pos.pawns(them);
Bitboard pawns = ourPawns; Bitboard pawns = ourPawns;
int bonus;
// Initialize pawn storm scores by giving bonuses for open files: // Initialize pawn storm scores by giving bonuses for open files
if(EvaluatePawnStorms) for (File f = FILE_A; f <= FILE_H; f++)
for(File f = FILE_A; f <= FILE_H; f++) if (Position::file_is_half_open(ourPawns, f))
if(pos.file_is_half_open(us, f)) { {
pi->ksStormValue[us] += KStormOpenFileBonus[f]; pi->ksStormValue[us] += KStormOpenFileBonus[f];
pi->qsStormValue[us] += QStormOpenFileBonus[f]; pi->qsStormValue[us] += QStormOpenFileBonus[f];
} }
// Loop through all pawns of the current color and score each pawn: // Loop through all pawns of the current color and score each pawn
while(pawns) { while (pawns)
Square s = pop_1st_bit(&pawns); {
File f = square_file(s); bool passed, doubled, isolated, backward, chain, candidate;
Rank r = square_rank(s); Square s = pop_1st_bit(&pawns);
bool passed, doubled, isolated, backward, chain, candidate; File f = square_file(s);
int bonus; Rank r = square_rank(s);
assert(pos.piece_on(s) == pawn_of_color(us)); assert(pos.piece_on(s) == piece_of_color_and_type(us, PAWN));
// The file containing the pawn is not half open: // The file containing the pawn is not half open
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);
if(EvaluatePawnStorms) {
// 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
// middle game positions with opposite side castling. // middle game positions with opposite side castling.
// //
// Each pawn is given a base score given by a piece square table // Each pawn is given a base score given by a piece square table
// (KStormTable[] or QStormTable[]). This score is increased if // (KStormTable[] or QStormTable[]). Pawns which seem to have good
// there are enemy pawns on adjacent files in front of the pawn. // chances of creating an open file by exchanging itself against an
// This is because we want to be able to open files against the // enemy pawn on an adjacent file gets an additional bonus.
// enemy king, and to avoid blocking the pawn structure (e.g. white
// pawns on h6, g5, black pawns on h7, g6, f7).
// Kingside pawn storms: // Kingside pawn storms
bonus = KStormTable[relative_square(us, s)]; bonus = KStormTable[relative_square(us, s)];
if(bonus > 0 && outpost_mask(us, s) & theirPawns) { if (f >= FILE_F)
switch(f) { {
Bitboard b = outpost_mask(us, s) & theirPawns & (FileFBB | FileGBB | FileHBB);
case FILE_F: while (b)
bonus += bonus / 4; {
break; Square s2 = pop_1st_bit(&b);
if (!(theirPawns & neighboring_files_bb(s2) & rank_bb(s2)))
case FILE_G: {
bonus += bonus / 2 + bonus / 4; // The enemy pawn has no pawn beside itself, which makes it
break; // particularly vulnerable. Big bonus, especially against a
// weakness on the rook file.
case FILE_H: if (square_file(s2) == FILE_H)
bonus += bonus / 2; bonus += 4*StormLeverBonus[f] - 8*square_distance(s, s2);
break; else
bonus += 2*StormLeverBonus[f] - 4*square_distance(s, s2);
default: } else
break; // There is at least one enemy pawn beside the enemy pawn we look
} // at, which means that the pawn has somewhat better chances of
// defending itself by advancing. Smaller bonus.
bonus += StormLeverBonus[f] - 2*square_distance(s, s2);
}
} }
pi->ksStormValue[us] += bonus; pi->ksStormValue[us] += bonus;
// Queenside pawn storms: // Queenside pawn storms
bonus = QStormTable[relative_square(us, s)]; bonus = QStormTable[relative_square(us, s)];
if(bonus > 0 && passed_pawn_mask(us, s) & theirPawns) { if (f <= FILE_C)
switch(f) { {
Bitboard b = outpost_mask(us, s) & theirPawns & (FileABB | FileBBB | FileCBB);
case FILE_A: while (b)
bonus += bonus / 2; {
break; Square s2 = pop_1st_bit(&b);
if (!(theirPawns & neighboring_files_bb(s2) & rank_bb(s2)))
case FILE_B: {
bonus += bonus / 2 + bonus / 4; // The enemy pawn has no pawn beside itself, which makes it
break; // particularly vulnerable. Big bonus, especially against a
// weakness on the rook file.
case FILE_C: if (square_file(s2) == FILE_A)
bonus += bonus / 2; bonus += 4*StormLeverBonus[f] - 16*square_distance(s, s2);
break; else
bonus += 2*StormLeverBonus[f] - 8*square_distance(s, s2);
default: } else
break; // There is at least one enemy pawn beside the enemy pawn we look
} // at, which means that the pawn has somewhat better chances of
// defending itself by advancing. Smaller bonus.
bonus += StormLeverBonus[f] - 4*square_distance(s, s2);
}
} }
pi->qsStormValue[us] += bonus; pi->qsStormValue[us] += bonus;
}
// Member of a pawn chain? We could speed up the test a little by // Member of a pawn chain (but not the backward one)? We could speed up
// introducing an array of masks indexed by color and square for doing // the test a little by introducing an array of masks indexed by color
// the test, but because everything is hashed, it probably won't make // and square for doing the test, but because everything is hashed,
// any noticable difference. // it probably won't make any noticable difference.
chain = (us == WHITE)? chain = ourPawns
(ourPawns & neighboring_files_bb(f) & (rank_bb(r) | rank_bb(r-1))) : & neighboring_files_bb(f)
(ourPawns & neighboring_files_bb(f) & (rank_bb(r) | rank_bb(r+1))); & (rank_bb(r) | rank_bb(r - (us == WHITE ? 1 : -1)));
// Test for backward pawn
// Test for backward pawn. //
// If the pawn is passed, isolated, or member of a pawn chain
// If the pawn is isolated, passed, or member of a pawn chain, it cannot // it cannot be backward. If can capture an enemy pawn or if
// be backward: // there are friendly pawns behind on neighboring files it cannot
if(passed || isolated || chain) // be backward either.
backward = false; if ( passed
// If the pawn can capture an enemy pawn, it's not backward: || isolated
else if(pos.pawn_attacks(us, s) & theirPawns) || chain
backward = false; || (pos.pawn_attacks(us, s) & theirPawns)
// Check for friendly pawns behind on neighboring files: || (ourPawns & behind_bb(us, r) & neighboring_files_bb(f)))
else if(ourPawns & in_front_bb(them, r) & neighboring_files_bb(f)) backward = false;
backward = false; else
else { {
// We now know that there is no friendly pawns beside or behind this // We now know that there are no friendly pawns beside or behind this
// pawn on neighboring files. We now check whether the pawn is // pawn on neighboring files. We now check whether the pawn is
// backward by looking in the forward direction on the neighboring // backward by looking in the forward direction on the neighboring
// files, and seeing whether we meet a friendly or an enemy pawn first. // files, and seeing whether we meet a friendly or an enemy pawn first.
Bitboard b; Bitboard b;
if(us == WHITE) { if (us == WHITE)
for(b=pos.pawn_attacks(us, s); !(b&(ourPawns|theirPawns)); b<<=8); {
backward = (b | (b << 8)) & theirPawns; for (b = pos.pawn_attacks(us, s); !(b & (ourPawns | theirPawns)); b <<= 8);
backward = (b | (b << 8)) & theirPawns;
}
else
{
for (b = pos.pawn_attacks(us, s); !(b & (ourPawns | theirPawns)); b >>= 8);
backward = (b | (b >> 8)) & theirPawns;
}
} }
else {
for(b=pos.pawn_attacks(us, s); !(b&(ourPawns|theirPawns)); b>>=8); // Test for candidate passed pawn
backward = (b | (b >> 8)) & theirPawns; candidate = !passed
&& Position::file_is_half_open(theirPawns, f)
&& ( count_1s_max_15(neighboring_files_bb(f) & (behind_bb(us, r) | rank_bb(r)) & ourPawns)
- count_1s_max_15(neighboring_files_bb(f) & in_front_bb(us, r) & theirPawns)
>= 0);
// In order to prevent doubled passed pawns from receiving a too big
// bonus, only the frontmost passed pawn on each file is considered as
// a true passed pawn.
if (passed && (ourPawns & squares_in_front_of(us, s)))
{
// candidate = true;
passed = false;
} }
}
// Test for candidate passed pawn. // Score this pawn
candidate = Value mv = Value(0), ev = Value(0);
(!passed && pos.file_is_half_open(them, f) && if (isolated)
count_1s_max_15(neighboring_files_bb(f) {
& (in_front_bb(them, r) | rank_bb(r)) mv -= IsolatedPawnMidgamePenalty[f];
& ourPawns) ev -= IsolatedPawnEndgamePenalty[f];
- count_1s_max_15(neighboring_files_bb(f) & in_front_bb(us, r) if (Position::file_is_half_open(theirPawns, f))
& theirPawns) {
>= 0); mv -= IsolatedPawnMidgamePenalty[f] / 2;
ev -= IsolatedPawnEndgamePenalty[f] / 2;
// In order to prevent doubled passed pawns from receiving a too big }
// bonus, only the frontmost passed pawn on each file is considered as
// a true passed pawn.
if(passed && (ourPawns & squares_in_front_of(us, s))) {
// candidate = true;
passed = false;
}
// Score this pawn:
Value mv = Value(0), ev = Value(0);
if(isolated) {
mv -= IsolatedPawnMidgamePenalty[f];
ev -= IsolatedPawnEndgamePenalty[f];
if(pos.file_is_half_open(them, f)) {
mv -= IsolatedPawnMidgamePenalty[f] / 2;
ev -= IsolatedPawnEndgamePenalty[f] / 2;
} }
} if (doubled)
if(doubled) { {
mv -= DoubledPawnMidgamePenalty[f]; mv -= DoubledPawnMidgamePenalty[f];
ev -= DoubledPawnEndgamePenalty[f]; ev -= DoubledPawnEndgamePenalty[f];
} }
if(backward) { if (backward)
mv -= BackwardPawnMidgamePenalty[f]; {
ev -= BackwardPawnEndgamePenalty[f]; mv -= BackwardPawnMidgamePenalty[f];
if(pos.file_is_half_open(them, f)) { ev -= BackwardPawnEndgamePenalty[f];
mv -= BackwardPawnMidgamePenalty[f] / 2; if (Position::file_is_half_open(theirPawns, f))
ev -= BackwardPawnEndgamePenalty[f] / 2; {
mv -= BackwardPawnMidgamePenalty[f] / 2;
ev -= BackwardPawnEndgamePenalty[f] / 2;
}
}
if (chain)
{
mv += ChainMidgameBonus[f];
ev += ChainEndgameBonus[f];
}
if (candidate)
{
mv += CandidateMidgameBonus[relative_rank(us, s)];
ev += CandidateEndgameBonus[relative_rank(us, s)];
} }
}
if(chain) {
mv += ChainMidgameBonus[f];
ev += ChainEndgameBonus[f];
}
if(candidate) {
mv += CandidateMidgameBonus[relative_rank(us, s)];
ev += CandidateEndgameBonus[relative_rank(us, s)];
}
mgValue[us] += mv; mgValue[us] += mv;
egValue[us] += ev; egValue[us] += ev;
// If the pawn is passed, set the square of the pawn in the passedPawns // If the pawn is passed, set the square of the pawn in the passedPawns
// bitboard: // bitboard
if(passed) if (passed)
set_bit(&(pi->passedPawns), s); set_bit(&(pi->passedPawns), s);
} } // while(pawns)
} } // for(colors)
pi->mgValue = int16_t(mgValue[WHITE] - mgValue[BLACK]); pi->mgValue = int16_t(mgValue[WHITE] - mgValue[BLACK]);
pi->egValue = int16_t(egValue[WHITE] - egValue[BLACK]); pi->egValue = int16_t(egValue[WHITE] - egValue[BLACK]);
return pi; return pi;
} }
+35 -19
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,45 +25,51 @@
//// Includes //// Includes
//// ////
#include "position.h" #include "bitboard.h"
#include "value.h"
//// ////
//// Types //// Types
//// ////
/// 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 PawnInfo { 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;
Value queenside_storm_value(Color c) const; Value queenside_storm_value(Color c) const;
Bitboard passed_pawns() const; Bitboard passed_pawns() const;
bool file_is_half_open(Color c, File f) const; int file_is_half_open(Color c, File f) const;
bool has_open_file_to_left(Color c, File f) const; int has_open_file_to_left(Color c, File f) const;
bool 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;
int8_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
@@ -74,12 +80,11 @@ 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:
unsigned size; unsigned size;
PawnInfo *entries; PawnInfo* entries;
}; };
@@ -107,24 +112,35 @@ inline Value PawnInfo::queenside_storm_value(Color c) const {
return Value(qsStormValue[c]); return Value(qsStormValue[c]);
} }
inline bool PawnInfo::file_is_half_open(Color c, File f) const { inline int PawnInfo::file_is_half_open(Color c, File f) const {
return (halfOpenFiles[c] & (1 << int(f))); return (halfOpenFiles[c] & (1 << int(f)));
} }
inline bool PawnInfo::has_open_file_to_left(Color c, File f) const { inline int PawnInfo::has_open_file_to_left(Color c, File f) const {
return halfOpenFiles[c] & ((1 << int(f)) - 1); return halfOpenFiles[c] & ((1 << int(f)) - 1);
} }
inline bool PawnInfo::has_open_file_to_right(Color c, File f) const { 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() {
mgValue = egValue = 0;
passedPawns = EmptyBoardBB; passedPawns = EmptyBoardBB;
mgValue = egValue = 0;
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;
} }
+12 -58
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,74 +22,28 @@
//// Includes //// Includes
//// ////
#include <cstring> #include <string>
#include "piece.h" #include "piece.h"
using namespace std;
////
//// Constants and variables
////
const int SlidingArray[18] = {
0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0
};
const SquareDelta Directions[16][16] = {
{DELTA_ZERO},
{DELTA_NW, DELTA_NE, DELTA_ZERO},
{DELTA_SSW, DELTA_SSE, DELTA_SWW, DELTA_SEE,
DELTA_NWW, DELTA_NEE, DELTA_NNW, DELTA_NNE, DELTA_ZERO},
{DELTA_SE, DELTA_SW, DELTA_NE, DELTA_NW, DELTA_ZERO},
{DELTA_S, DELTA_E, DELTA_W, DELTA_N, DELTA_ZERO},
{DELTA_S, DELTA_E, DELTA_W, DELTA_N,
DELTA_SE, DELTA_SW, DELTA_NE, DELTA_NW, DELTA_ZERO},
{DELTA_S, DELTA_E, DELTA_W, DELTA_N,
DELTA_SE, DELTA_SW, DELTA_NE, DELTA_NW, DELTA_ZERO},
{DELTA_ZERO},
{DELTA_ZERO},
{DELTA_SW, DELTA_SE, DELTA_ZERO},
{DELTA_SSW, DELTA_SSE, DELTA_SWW, DELTA_SEE,
DELTA_NWW, DELTA_NEE, DELTA_NNW, DELTA_NNE, DELTA_ZERO},
{DELTA_SE, DELTA_SW, DELTA_NE, DELTA_NW, DELTA_ZERO},
{DELTA_S, DELTA_E, DELTA_W, DELTA_N, DELTA_ZERO},
{DELTA_S, DELTA_E, DELTA_W, DELTA_N,
DELTA_SE, DELTA_SW, DELTA_NE, DELTA_NW, DELTA_ZERO},
{DELTA_S, DELTA_E, DELTA_W, DELTA_N,
DELTA_SE, DELTA_SW, DELTA_NE, DELTA_NW, DELTA_ZERO},
};
const SquareDelta PawnPush[2] = {
DELTA_N, DELTA_S
};
//// ////
//// Functions //// Functions
//// ////
/// Translating piece types to/from English piece letters: /// Translating piece types to/from English piece letters
static const char PieceChars[] = " pnbrqk"; static const string PieceChars(" pnbrqk PNBRQK");
char piece_type_to_char(PieceType pt, bool upcase = false) { char piece_type_to_char(PieceType pt, bool upcase) {
return upcase? toupper(PieceChars[pt]) : PieceChars[pt];
return PieceChars[pt + upcase * 7];
} }
PieceType piece_type_from_char(char c) { PieceType piece_type_from_char(char c) {
const char *ch = strchr(PieceChars, tolower(c));
return ch? PieceType(ch - PieceChars) : NO_PIECE_TYPE; size_t idx = PieceChars.find(c);
}
return idx != string::npos ? PieceType(idx % 7) : NO_PIECE_TYPE;
/// piece_is_ok() and piece_type_is_ok(), for debugging:
bool piece_is_ok(Piece pc) {
return
piece_type_is_ok(type_of_piece(pc)) &&
color_is_ok(color_of_piece(pc));
}
bool piece_type_is_ok(PieceType pc) {
return pc >= PAWN && pc <= KING;
} }
+16 -38
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,7 +26,6 @@
//// ////
#include "color.h" #include "color.h"
#include "misc.h"
#include "square.h" #include "square.h"
@@ -47,15 +46,12 @@ enum Piece {
//// ////
//// Constants and variables //// Constants
//// ////
const PieceType PieceTypeMin = PAWN; const int SlidingArray[18] = {
const PieceType PieceTypeMax = KING; 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0
};
extern const int SlidingArray[18];
extern const SquareDelta Directions[16][16];
extern const SquareDelta PawnPush[2];
//// ////
@@ -83,40 +79,24 @@ inline Piece piece_of_color_and_type(Color c, PieceType pt) {
return Piece((int(c) << 3) | int(pt)); return Piece((int(c) << 3) | int(pt));
} }
inline Piece pawn_of_color(Color c) {
return piece_of_color_and_type(c, PAWN);
}
inline Piece knight_of_color(Color c) {
return piece_of_color_and_type(c, KNIGHT);
}
inline Piece bishop_of_color(Color c) {
return piece_of_color_and_type(c, BISHOP);
}
inline Piece rook_of_color(Color c) {
return piece_of_color_and_type(c, ROOK);
}
inline Piece queen_of_color(Color c) {
return piece_of_color_and_type(c, QUEEN);
}
inline Piece king_of_color(Color c) {
return piece_of_color_and_type(c, KING);
}
inline int piece_is_slider(Piece p) { inline int piece_is_slider(Piece p) {
return SlidingArray[int(p)]; return SlidingArray[int(p)];
} }
inline int piece_type_is_slider(PieceType pt) { inline int piece_is_slider(PieceType pt) {
return SlidingArray[int(pt)]; return SlidingArray[int(pt)];
} }
inline SquareDelta pawn_push(Color c) { inline SquareDelta pawn_push(Color c) {
return PawnPush[c]; return (c == WHITE ? DELTA_N : DELTA_S);
}
inline bool piece_type_is_ok(PieceType pc) {
return pc >= PAWN && pc <= KING;
}
inline bool piece_is_ok(Piece pc) {
return piece_type_is_ok(type_of_piece(pc)) && color_is_ok(color_of_piece(pc));
} }
@@ -124,10 +104,8 @@ inline SquareDelta pawn_push(Color c) {
//// Prototypes //// Prototypes
//// ////
extern char piece_type_to_char(PieceType pt, bool upcase); extern char piece_type_to_char(PieceType pt, bool upcase = false);
extern PieceType piece_type_from_char(char c); extern PieceType piece_type_from_char(char c);
extern bool piece_is_ok(Piece pc);
extern bool piece_type_is_ok(PieceType pt);
#endif // !defined(PIECE_H_INCLUDED) #endif // !defined(PIECE_H_INCLUDED)
+588 -664
View File
File diff suppressed because it is too large Load Diff
+150 -129
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,12 +21,16 @@
#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)
#pragma warning(disable: 4800) #pragma warning(disable: 4800)
// Conditional expression is constant
#pragma warning(disable: 4127)
#endif #endif
//// ////
@@ -38,7 +42,6 @@
#include "direction.h" #include "direction.h"
#include "move.h" #include "move.h"
#include "piece.h" #include "piece.h"
#include "phase.h"
#include "square.h" #include "square.h"
#include "value.h" #include "value.h"
@@ -47,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;
@@ -61,56 +63,61 @@ const int MaxGameLength = 220;
//// Types //// Types
//// ////
/// 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
}; };
/// Game phase
/// The UndoInfo struct stores information we need to restore a Position enum Phase {
/// object to its previous state when we retract a move. Whenever a move PHASE_ENDGAME = 0,
/// is made on the board (by calling Position::do_move), an UndoInfo object PHASE_MIDGAME = 128
/// must be passed as a parameter. When the move is unmade (by calling
/// Position::undo_move), the same UndoInfo object must be passed again.
struct UndoInfo {
int castleRights;
Square epSquare;
Bitboard checkersBB;
Key key, pawnKey, materialKey;
int rule50;
Move lastMove;
PieceType capture;
Value mgValue, egValue;
}; };
/// The position data structure. A position consists of the following data: /// The StateInfo struct stores information we need to restore a Position
/// object to its previous state when we retract a move. Whenever a move
/// is made on the board (by calling Position::do_move), an StateInfo object
/// must be passed as a parameter.
struct StateInfo {
Key key, pawnKey, materialKey;
int castleRights, rule50;
Square epSquare;
Value mgValue, egValue;
Value npMaterial[2];
PieceType capture;
Bitboard checkersBB;
StateInfo* previous;
};
/// 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.
@@ -120,19 +127,24 @@ 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);
Position(const std::string &fen); Position(const std::string& fen);
// Text input/output // Text input/output
void from_fen(const std::string &fen); void from_fen(const std::string& fen);
const std::string to_fen() const; const std::string to_fen() const;
void print() 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;
@@ -174,13 +186,13 @@ public:
// Number of pieces of each color and type // Number of pieces of each color and type
int piece_count(Color c, PieceType pt) const; int piece_count(Color c, PieceType pt) const;
// The en passant square: // The en passant square
Square ep_square() const; Square ep_square() const;
// Current king position for each color // Current king position for each color
Square king_square(Color c) const; Square king_square(Color c) const;
// Castling rights. // Castling rights
bool can_castle_kingside(Color c) const; bool can_castle_kingside(Color c) const;
bool can_castle_queenside(Color c) const; bool can_castle_queenside(Color c) const;
bool can_castle(Color c) const; bool can_castle(Color c) const;
@@ -197,6 +209,7 @@ public:
// Bitboards for pinned pieces and discovered check candidates // Bitboards for pinned pieces and discovered check candidates
Bitboard discovered_check_candidates(Color c) const; Bitboard discovered_check_candidates(Color c) const;
Bitboard pinned_pieces(Color c, Bitboard& p) const;
Bitboard pinned_pieces(Color c) const; Bitboard pinned_pieces(Color c) const;
// Checking pieces // Checking pieces
@@ -215,7 +228,7 @@ public:
template<PieceType> template<PieceType>
Bitboard piece_attacks_square(Square f, Square t) const; // Dispatch at compile-time Bitboard piece_attacks_square(Square f, Square t) const; // Dispatch at compile-time
bool piece_attacks_square(Square f, Square t) const; // Dispatch at run-time bool piece_attacks_square(Piece p, Square f, Square t) const; // Dispatch at run-time
// Properties of moves // Properties of moves
bool pl_move_is_legal(Move m) const; bool pl_move_is_legal(Move m) const;
@@ -231,28 +244,29 @@ 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 backup(UndoInfo &u) const; void saveState();
void restore(const UndoInfo &u); void do_move(Move m, StateInfo& st);
void do_move(Move m, UndoInfo &u); void do_move(Move m, StateInfo& st, Bitboard dcCandidates);
void do_move(Move m, UndoInfo &u, Bitboard dcCandidates); void undo_move(Move m);
void undo_move(Move m, const UndoInfo &u); void do_null_move(StateInfo& st);
void do_null_move(UndoInfo &u); void undo_null_move();
void undo_null_move(const UndoInfo &u);
// Static exchange evaluation // Static exchange evaluation
int see(Square from, Square to) const; int see(Square from, Square to) const;
int see(Move m) const; int see(Move m) const;
int see(Square to) const;
// Accessing hash keys // Accessing hash keys
Key get_key() const; Key get_key() const;
@@ -264,10 +278,10 @@ 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(); bool is_mate() const;
bool is_draw() const; bool is_draw() const;
// Check if one side threatens a mate in one // Check if one side threatens a mate in one
@@ -291,6 +305,7 @@ public:
static void init_piece_square_tables(); static void init_piece_square_tables();
private: private:
// Initialization helper functions (used while setting up a position) // Initialization helper functions (used while setting up a position)
void clear(); void clear();
void put_piece(Piece p, Square s); void put_piece(Piece p, Square s);
@@ -298,17 +313,20 @@ private:
void allow_ooo(Color c); void allow_ooo(Color c);
// Helper functions for doing and undoing moves // Helper functions for doing and undoing moves
void do_capture_move(Move m, PieceType capture, Color them, Square to); void do_capture_move(PieceType capture, Color them, Square to);
void do_castle_move(Move m); void do_castle_move(Move m);
void do_promotion_move(Move m, UndoInfo &u); void do_promotion_move(Move m);
void do_ep_move(Move m); void do_ep_move(Move m);
void undo_castle_move(Move m); void undo_castle_move(Move m);
void undo_promotion_move(Move m, const UndoInfo &u); void undo_promotion_move(Move m);
void undo_ep_move(Move m); void undo_ep_move(Move m);
void find_checkers(); void find_checkers();
template<PieceType Piece, bool FindPinned> template<PieceType Piece>
Bitboard hidden_checks(Color c, Square ksq) const; void update_checkers(Bitboard* pCheckersBB, Square ksq, Square from, Square to, Bitboard dcCandidates);
template<bool FindPinned>
Bitboard hidden_checkers(Color c) const;
// Computing hash keys from scratch (for initialization and debugging) // Computing hash keys from scratch (for initialization and debugging)
Key compute_key() const; Key compute_key() const;
@@ -316,15 +334,12 @@ 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
Value mg_pst(Color c, PieceType pt, Square s) const; template<GamePhase> Value pst(Color c, PieceType pt, Square s) const;
Value eg_pst(Color c, PieceType pt, Square s) const; template<GamePhase> Value compute_value() const;
Value compute_mg_value() const;
Value compute_eg_value() const;
Value compute_non_pawn_material(Color c) const; Value compute_non_pawn_material(Color c) const;
// Bitboards // Bitboards
Bitboard byColorBB[2], byTypeBB[8]; Bitboard byColorBB[2], byTypeBB[8];
Bitboard checkersBB;
// Board // Board
Piece board[64]; Piece board[64];
@@ -337,16 +352,13 @@ private:
int index[64]; int index[64];
// Other info // Other info
Color sideToMove;
int castleRights;
File initialKFile, initialKRFile, initialQRFile;
Square epSquare;
Square kingSquare[2]; Square kingSquare[2];
Move lastMove; Color sideToMove;
Key key, pawnKey, materialKey, history[MaxGameLength]; int gamePly;
int rule50, gamePly; Key history[MaxGameLength];
Value mgValue, egValue; File initialKFile, initialKRFile, initialQRFile;
Value npMaterial[2]; StateInfo startState;
StateInfo* st;
// Static variables // Static variables
static int castleRightsMask[64]; static int castleRightsMask[64];
@@ -484,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];
} }
@@ -497,7 +505,7 @@ inline Square Position::piece_list(Color c, PieceType pt, int index) const {
} }
inline Square Position::ep_square() const { inline Square Position::ep_square() const {
return epSquare; return st->epSquare;
} }
inline Square Position::king_square(Color c) const { inline Square Position::king_square(Color c) const {
@@ -505,11 +513,11 @@ inline Square Position::king_square(Color c) const {
} }
inline bool Position::can_castle_kingside(Color side) const { inline bool Position::can_castle_kingside(Color side) const {
return castleRights & (1+int(side)); return st->castleRights & (1+int(side));
} }
inline bool Position::can_castle_queenside(Color side) const { inline bool Position::can_castle_queenside(Color side) const {
return castleRights & (4+4*int(side)); return st->castleRights & (4+4*int(side));
} }
inline bool Position::can_castle(Color side) const { inline bool Position::can_castle(Color side) const {
@@ -525,12 +533,17 @@ inline Square Position::initial_qr_square(Color c) const {
} }
inline Bitboard Position::pawn_attacks(Color c, Square s) const { inline Bitboard Position::pawn_attacks(Color c, Square s) const {
return StepAttackBB[pawn_of_color(c)][s]; return StepAttackBB[piece_of_color_and_type(c, PAWN)][s];
}
template<PieceType Piece> // Knight and King
inline Bitboard Position::piece_attacks(Square s) const {
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<>
@@ -548,17 +561,12 @@ 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 checkersBB; return st->checkersBB;
} }
inline bool Position::is_check() const { inline bool Position::is_check() const {
return checkersBB != EmptyBoardBB; return st->checkersBB != EmptyBoardBB;
} }
inline bool Position::pawn_attacks_square(Color c, Square f, Square t) const { inline bool Position::pawn_attacks_square(Color c, Square f, Square t) const {
@@ -570,24 +578,38 @@ Bitboard Position::piece_attacks_square(Square f, Square t) const {
return bit_is_set(piece_attacks<Piece>(f), t); return bit_is_set(piece_attacks<Piece>(f), t);
} }
inline Bitboard Position::attacks_to(Square s, Color c) const {
return attacks_to(s) & pieces_of_color(c);
}
inline bool Position::square_is_attacked(Square s, Color c) const {
return attacks_to(s, c) != EmptyBoardBB;
}
inline bool Position::pawn_is_passed(Color c, Square s) const { 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 {
@@ -595,53 +617,46 @@ inline bool Position::square_is_weak(Square s, Color c) const {
} }
inline Key Position::get_key() const { inline Key Position::get_key() const {
return key; return st->key;
} }
inline Key Position::get_pawn_key() const { inline Key Position::get_pawn_key() const {
return pawnKey; return st->pawnKey;
} }
inline Key Position::get_material_key() const { inline Key Position::get_material_key() const {
return materialKey; return st->materialKey;
} }
inline Value Position::mg_pst(Color c, PieceType pt, Square s) const { template<Position::GamePhase Ph>
return MgPieceSquareTable[piece_of_color_and_type(c, pt)][s]; inline Value Position::pst(Color c, PieceType pt, Square s) const {
return (Ph == MidGame ? MgPieceSquareTable[piece_of_color_and_type(c, pt)][s]
: EgPieceSquareTable[piece_of_color_and_type(c, pt)][s]);
} }
inline Value Position::mg_pst_delta(Move m) const { 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::eg_pst(Color c, PieceType pt, Square s) const {
return EgPieceSquareTable[piece_of_color_and_type(c, pt)][s];
} }
inline Value Position::mg_value() const { inline Value Position::mg_value() const {
return mgValue; return st->mgValue;
} }
inline Value Position::eg_value() const { inline Value Position::eg_value() const {
return egValue; return st->egValue;
} }
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 {
// The purpose of the Value(325) terms below is to make sure the difference // Values modified by Joona Kiiski
// between MidgameLimit and EndgameLimit is a power of 2, which should make static const Value MidgameLimit = Value(15713);
// the division at the end of the function a bit faster. static const Value EndgameLimit = Value(4428);
static const Value MidgameLimit = 2 * QueenValueMidgame
+ 2 * RookValueMidgame
+ 6 * BishopValueMidgame
+ Value(325);
static const Value EndgameLimit = 4 * RookValueMidgame - Value(325);
Value npm = non_pawn_material(WHITE) + non_pawn_material(BLACK); Value npm = non_pawn_material(WHITE) + non_pawn_material(BLACK);
@@ -656,34 +671,34 @@ inline Phase Position::game_phase() const {
inline bool Position::move_is_deep_pawn_push(Move m) const { inline bool Position::move_is_deep_pawn_push(Move m) const {
Color c = side_to_move(); Color c = side_to_move();
return piece_on(move_from(m)) == pawn_of_color(c) return piece_on(move_from(m)) == piece_of_color_and_type(c, PAWN)
&& relative_rank(c, move_to(m)) > RANK_4; && relative_rank(c, move_to(m)) > RANK_4;
} }
inline bool Position::move_is_pawn_push_to_7th(Move m) const { inline bool Position::move_is_pawn_push_to_7th(Move m) const {
Color c = side_to_move(); Color c = side_to_move();
return piece_on(move_from(m)) == pawn_of_color(c) return piece_on(move_from(m)) == piece_of_color_and_type(c, PAWN)
&& relative_rank(c, move_to(m)) == RANK_7; && relative_rank(c, move_to(m)) == RANK_7;
} }
inline bool Position::move_is_passed_pawn_push(Move m) const { inline bool Position::move_is_passed_pawn_push(Move m) const {
Color c = side_to_move(); Color c = side_to_move();
return piece_on(move_from(m)) == pawn_of_color(c) return piece_on(move_from(m)) == piece_of_color_and_type(c, PAWN)
&& pawn_is_passed(c, move_to(m)); && pawn_is_passed(c, move_to(m));
} }
inline bool Position::move_was_passed_pawn_push(Move m) const { inline bool Position::move_was_passed_pawn_push(Move m) const {
Color c = opposite_color(side_to_move()); Color c = opposite_color(side_to_move());
return piece_on(move_to(m)) == pawn_of_color(c) return piece_on(move_to(m)) == piece_of_color_and_type(c, PAWN)
&& pawn_is_passed(c, move_to(m)); && pawn_is_passed(c, move_to(m));
} }
inline int Position::rule_50_counter() const { inline int Position::rule_50_counter() const {
return rule50; return st->rule50;
} }
inline bool Position::opposite_colored_bishops() const { inline bool Position::opposite_colored_bishops() const {
@@ -698,5 +713,11 @@ inline bool Position::has_pawn_on_7th(Color c) const {
return pawns(c) & relative_rank_bb(c, RANK_7); return pawns(c) & relative_rank_bb(c, RANK_7);
} }
inline bool Position::move_is_capture(Move m) const {
// Move must not be MOVE_NONE !
return (!square_is_empty(move_to(m)) && !move_is_castle(m)) || move_is_ep(m);
}
#endif // !defined(POSITION_H_INCLUDED) #endif // !defined(POSITION_H_INCLUDED)
+102 -103
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,12 +25,11 @@
//// Includes //// Includes
//// ////
#include "position.h"
#include "value.h" #include "value.h"
//// ////
//// Variables //// Constants modified by Joona Kiiski
//// ////
static const Value MP = PawnValueMidgame; static const Value MP = PawnValueMidgame;
@@ -42,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
} }
}; };
@@ -118,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
} }
}; };
+271 -256
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,9 +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"
using std::string;
//// ////
//// Local definitions //// Local definitions
@@ -38,8 +40,6 @@
namespace { namespace {
/// Types
enum Ambiguity { enum Ambiguity {
AMBIGUITY_NONE, AMBIGUITY_NONE,
AMBIGUITY_FILE, AMBIGUITY_FILE,
@@ -47,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);
const string time_string(int milliseconds);
Ambiguity move_ambiguity(Position &pos, Move m); const string score_string(Value v);
const std::string time_string(int milliseconds);
const std::string score_string(Value v);
} }
@@ -61,206 +60,227 @@ namespace {
//// ////
/// move_to_san() takes a position and a move as input, where it is assumed /// move_to_san() takes a position and a move as input, where it is assumed
/// 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(Position &pos, Move m) { const string move_to_san(const Position& pos, Move m) {
std::string str;
assert(pos.is_ok()); assert(pos.is_ok());
assert(move_is_ok(m)); assert(move_is_ok(m));
if(m == MOVE_NONE) { Square from, to;
str = "(none)"; PieceType pt;
return str;
}
else if(m == MOVE_NULL) {
str = "(null)";
return str;
}
else if(move_is_long_castle(m))
str = "O-O-O";
else if(move_is_short_castle(m))
str = "O-O";
else {
Square from, to;
Piece pc;
from = move_from(m); from = move_from(m);
to = move_to(m); to = move_to(m);
pc = pos.piece_on(move_from(m)); pt = type_of_piece(pos.piece_on(move_from(m)));
str = ""; string san = "";
if(type_of_piece(pc) == PAWN) { if (m == MOVE_NONE)
if(pos.move_is_capture(m)) return "(none)";
str += file_to_char(square_file(move_from(m))); else if (m == MOVE_NULL)
} return "(null)";
else { else if (move_is_long_castle(m) || (int(to - from) == -2 && pt == KING))
str += piece_type_to_char(type_of_piece(pc), true); san = "O-O-O";
else if (move_is_short_castle(m) || (int(to - from) == 2 && pt == KING))
Ambiguity amb = move_ambiguity(pos, m); san = "O-O";
switch(amb) { else
{
case AMBIGUITY_NONE: if (pt != PAWN)
break; {
san += piece_type_to_char(pt, true);
case AMBIGUITY_FILE: switch (move_ambiguity(pos, m)) {
str += file_to_char(square_file(from)); case AMBIGUITY_NONE:
break; break;
case AMBIGUITY_FILE:
case AMBIGUITY_RANK: san += file_to_char(square_file(from));
str += rank_to_char(square_rank(from)); break;
break; case AMBIGUITY_RANK:
san += rank_to_char(square_rank(from));
case AMBIGUITY_BOTH: break;
str += square_to_string(from); case AMBIGUITY_BOTH:
break; san += square_to_string(from);
break;
default: default:
assert(false); assert(false);
}
}
if (pos.move_is_capture(m))
{
if (pt == PAWN)
san += file_to_char(square_file(move_from(m)));
san += "x";
}
san += square_to_string(move_to(m));
if (move_is_promotion(m))
{
san += '=';
san += piece_type_to_char(move_promotion_piece(m), true);
} }
}
if(pos.move_is_capture(m))
str += "x";
str += square_to_string(move_to(m));
if(move_promotion(m)) {
str += "=";
str += piece_type_to_char(move_promotion(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
// Position::move_is_check doesn't detect all checks (not castling moves, // Position::move_is_check doesn't detect all checks (not castling moves,
// promotions and en passant captures). // promotions and en passant captures).
UndoInfo u; StateInfo st;
pos.do_move(m, u); Position p(pos);
if(pos.is_check()) p.do_move(m, st);
str += pos.is_mate()? "#" : "+"; if (p.is_check())
pos.undo_move(m, u); san += p.is_mate()? "#" : "+";
return str; return san;
} }
/// move_from_san() takes a position and a string as input, and tries to /// move_from_san() takes a position and a string as input, and tries to
/// interpret the string as a move in short algebraic notation. On success, /// interpret the string as a move in short algebraic notation. On success,
/// 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(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, MOVE_NONE, MOVE_NONE, MovePicker mp = MovePicker(pos, MOVE_NONE, OnePly, H);
MOVE_NONE, OnePly);
// Castling moves // Castling moves
if(movestr == "O-O-O") { if (movestr == "O-O-O" || movestr == "O-O-O+")
Move m; {
while((m = mp.get_next_move()) != MOVE_NONE) Move m;
if(move_is_long_castle(m) && pos.pl_move_is_legal(m)) while ((m = mp.get_next_move()) != MOVE_NONE)
return m; if (move_is_long_castle(m) && pos.pl_move_is_legal(m))
return MOVE_NONE; return m;
}
else if(movestr == "O-O") {
Move m;
while((m = mp.get_next_move()) != MOVE_NONE)
if(move_is_short_castle(m) && pos.pl_move_is_legal(m))
return m;
return MOVE_NONE;
}
// Normal moves
const char *cstr = movestr.c_str();
const char *c;
char *cc;
char str[10];
int i;
// Initialize str[] by making a copy of movestr with the characters
// 'x', '=', '+' and '#' removed.
cc = str;
for(i=0, c=cstr; i<10 && *c!='\0' && *c!='\n' && *c!=' '; i++, c++)
if(!strchr("x=+#", *c)) {
*cc = strchr("nrq", *c)? toupper(*c) : *c;
cc++;
}
*cc = '\0';
size_t left = 0, right = strlen(str) - 1;
PieceType pt = NO_PIECE_TYPE, promotion;
Square to;
File fromFile = FILE_NONE;
Rank fromRank = RANK_NONE;
// Promotion?
if(strchr("BNRQ", str[right])) {
promotion = piece_type_from_char(str[right]);
right--;
}
else
promotion = NO_PIECE_TYPE;
// Find the moving piece:
if(left < right) {
if(strchr("BNRQK", str[left])) {
pt = piece_type_from_char(str[left]);
left++;
}
else
pt = PAWN;
}
// Find the to square:
if(left < right) {
if(str[right] < '1' || str[right] > '8' ||
str[right-1] < 'a' || str[right-1] > 'h')
return MOVE_NONE; return MOVE_NONE;
to = make_square(file_from_char(str[right-1]), rank_from_char(str[right]));
right -= 2;
} }
else else if (movestr == "O-O" || movestr == "O-O+")
{
Move m;
while ((m = mp.get_next_move()) != MOVE_NONE)
if (move_is_short_castle(m) && pos.pl_move_is_legal(m))
return m;
return MOVE_NONE; return MOVE_NONE;
// Find the file and/or rank of the from square:
if(left <= right) {
if(strchr("abcdefgh", str[left])) {
fromFile = file_from_char(str[left]);
left++;
}
if(strchr("12345678", str[left]))
fromRank = rank_from_char(str[left]);
} }
// Look for a matching move: // Normal moves. We use a simple FSM to parse the san string.
enum { START, TO_FILE, TO_RANK, PROMOTION_OR_CHECK, PROMOTION, CHECK, END };
static const string pieceLetters = "KQRBN";
PieceType pt = NO_PIECE_TYPE, promotion = NO_PIECE_TYPE;
File fromFile = FILE_NONE, toFile = FILE_NONE;
Rank fromRank = RANK_NONE, toRank = RANK_NONE;
Square to;
int state = START;
for (size_t i = 0; i < movestr.length(); i++)
{
char type, c = movestr[i];
if (pieceLetters.find(c) != string::npos)
type = 'P';
else if (c >= 'a' && c <= 'h')
type = 'F';
else if (c >= '1' && c <= '8')
type = 'R';
else
type = c;
switch (type) {
case 'P':
if (state == START)
{
pt = piece_type_from_char(c);
state = TO_FILE;
}
else if (state == PROMOTION)
{
promotion = piece_type_from_char(c);
state = (i < movestr.length() - 1) ? CHECK : END;
}
else
return MOVE_NONE;
break;
case 'F':
if (state == START)
{
pt = PAWN;
fromFile = toFile = file_from_char(c);
state = TO_RANK;
}
else if (state == TO_FILE)
{
toFile = file_from_char(c);
state = TO_RANK;
}
else if (state == TO_RANK && toFile != FILE_NONE)
{
// Previous file was for disambiguation
fromFile = toFile;
toFile = file_from_char(c);
}
else
return MOVE_NONE;
break;
case 'R':
if (state == TO_RANK)
{
toRank = rank_from_char(c);
state = (i < movestr.length() - 1) ? PROMOTION_OR_CHECK : END;
}
else if (state == TO_FILE && fromRank == RANK_NONE)
{
// It's a disambiguation rank instead of a file
fromRank = rank_from_char(c);
}
else
return MOVE_NONE;
break;
case 'x': case 'X':
if (state == TO_RANK)
{
// Previous file was for disambiguation, or it's a pawn capture
fromFile = toFile;
state = TO_FILE;
}
else if (state != TO_FILE)
return MOVE_NONE;
break;
case '=':
if (state == PROMOTION_OR_CHECK)
state = PROMOTION;
else
return MOVE_NONE;
break;
case '+': case '#':
if (state == PROMOTION_OR_CHECK || state == CHECK)
state = END;
else
return MOVE_NONE;
break;
default:
return MOVE_NONE;
break;
}
}
if (state != END)
return MOVE_NONE;
// Look for a matching move
Move m, move = MOVE_NONE; Move m, move = MOVE_NONE;
to = make_square(toFile, toRank);
int matches = 0; int matches = 0;
while((m = mp.get_next_move()) != MOVE_NONE) { while ((m = mp.get_next_move()) != MOVE_NONE)
bool match = true; if ( pos.type_of_piece_on(move_from(m)) == pt
if(pos.type_of_piece_on(move_from(m)) != pt) && move_to(m) == to
match = false; && move_promotion_piece(m) == promotion
else if(move_to(m) != to) && (fromFile == FILE_NONE || fromFile == square_file(move_from(m)))
match = false; && (fromRank == RANK_NONE || fromRank == square_rank(move_from(m))))
else if(move_promotion(m) != promotion) {
match = false; move = m;
else if(fromFile != FILE_NONE && fromFile != square_file(move_from(m))) matches++;
match = false; }
else if(fromRank != RANK_NONE && fromRank != square_rank(move_from(m))) return (matches == 1 ? move : MOVE_NONE);
match = false;
if(match) {
move = m;
matches++;
}
}
if(matches == 1)
return move;
else
return MOVE_NONE;
} }
@@ -271,34 +291,31 @@ Move move_from_san(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, const string line_to_san(const Position& pos, Move line[], int startColumn, bool breakLines) {
bool breakLines) {
Position p = Position(pos); StateInfo st;
UndoInfo u;
std::stringstream s; std::stringstream s;
std::string moveStr; string moveStr;
size_t length, maxLength; size_t length = 0;
size_t maxLength = 80 - startColumn;
Position p(pos);
length = 0; for (int i = 0; line[i] != MOVE_NONE; i++)
maxLength = 80 - startColumn; {
moveStr = move_to_san(p, line[i]);
length += moveStr.length() + 1;
if (breakLines && length > maxLength)
{
s << '\n' << std::setw(startColumn) << ' ';
length = moveStr.length() + 1;
}
s << moveStr << ' ';
for(int i = 0; line[i] != MOVE_NONE; i++) { if (line[i] == MOVE_NULL)
moveStr = move_to_san(p, line[i]); p.do_null_move(st);
length += moveStr.length() + 1; else
if(breakLines && length > maxLength) { p.do_move(line[i], st);
s << "\n";
for(int j = 0; j < startColumn; j++)
s << " ";
length = moveStr.length() + 1;
}
s << moveStr << " ";
if(line[i] == MOVE_NULL)
p.do_null_move(u);
else
p.do_move(line[i], u);
} }
return s.str(); return s.str();
} }
@@ -307,26 +324,26 @@ 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
s << std::setw(2) << std::setfill(' ') << depth << " "; s << std::setw(2) << depth << " ";
// Score // Score
s << std::setw(8) << score_string(score); s << std::setw(8) << score_string(score);
// Time // Time
s << std::setw(8) << std::setfill(' ') << time_string(time) << " "; s << std::setw(8) << time_string(time) << " ";
// Nodes // Nodes
if(nodes < 1000000ULL) if (nodes < 1000000ULL)
s << std::setw(8) << std::setfill(' ') << nodes << " "; s << std::setw(8) << nodes << " ";
else if(nodes < 1000000000ULL) else if (nodes < 1000000000ULL)
s << std::setw(7) << std::setfill(' ') << nodes/1000ULL << 'k' << " "; s << std::setw(7) << nodes/1000ULL << 'k' << " ";
else else
s << std::setw(7) << std::setfill(' ') << nodes/1000000ULL << 'M' << " "; s << std::setw(7) << nodes/1000000ULL << 'M' << " ";
// PV // PV
s << line_to_san(pos, pv, 30, true); s << line_to_san(pos, pv, 30, true);
@@ -337,82 +354,80 @@ const std::string pretty_pv(const Position &pos, int time, int depth,
namespace { namespace {
Ambiguity move_ambiguity(Position &pos, Move m) { Ambiguity move_ambiguity(const Position& pos, Move m) {
Square from, to;
Piece pc;
from = move_from(m); Square from = move_from(m);
to = move_to(m); Square to = move_to(m);
pc = pos.piece_on(from); Piece pc = pos.piece_on(from);
// King moves are never ambiguous, because there is never two kings of // King moves are never ambiguous, because there is never two kings of
// the same color. // the same color.
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, MOVE_NONE, MOVE_NONE, MovePicker mp = MovePicker(pos, MOVE_NONE, OnePly, H);
MOVE_NONE, OnePly);
Move mv, moveList[8]; Move mv, moveList[8];
int i, j, n;
n = 0; int n = 0;
while((mv = mp.get_next_move()) != MOVE_NONE) while ((mv = mp.get_next_move()) != MOVE_NONE)
if(move_to(mv) == to && pos.piece_on(move_from(mv)) == pc if (move_to(mv) == to && pos.piece_on(move_from(mv)) == pc && pos.pl_move_is_legal(mv))
&& pos.pl_move_is_legal(mv)) moveList[n++] = mv;
moveList[n++] = mv;
if(n == 1)
return AMBIGUITY_NONE;
j = 0; if (n == 1)
for(i = 0; i < n; i++) return AMBIGUITY_NONE;
if(square_file(move_from(moveList[i])) == square_file(from))
j++;
if(j == 1)
return AMBIGUITY_FILE;
j = 0; int f = 0, r = 0;
for(i = 0; i < n; i++) for (int i = 0; i < n; i++)
if(square_rank(move_from(moveList[i])) == square_rank(from)) {
j++; if (square_file(move_from(moveList[i])) == square_file(from))
if(j == 1) f++;
return AMBIGUITY_RANK;
if (square_rank(move_from(moveList[i])) == square_rank(from))
r++;
}
if (f == 1)
return AMBIGUITY_FILE;
if (r == 1)
return AMBIGUITY_RANK;
return AMBIGUITY_BOTH; return AMBIGUITY_BOTH;
} }
const std::string time_string(int milliseconds) { const string time_string(int milliseconds) {
std::stringstream s; std::stringstream s;
s << std::setfill('0');
int hours = milliseconds / (1000 * 60 * 60); int hours = milliseconds / (1000*60*60);
int minutes = (milliseconds - hours*1000*60*60) / (60*1000); int minutes = (milliseconds - hours*1000*60*60) / (1000*60);
int seconds = (milliseconds - hours*1000*60*60 - minutes*60*1000) / 1000; int seconds = (milliseconds - hours*1000*60*60 - minutes*1000*60) / 1000;
if(hours) if (hours)
s << hours << ':'; s << hours << ':';
s << std::setw(2) << std::setfill('0') << minutes << ':';
s << std::setw(2) << std::setfill('0') << seconds;
s << std::setw(2) << minutes << ':' << std::setw(2) << seconds;
return s.str(); return s.str();
} }
const std::string score_string(Value v) { const string score_string(Value v) {
std::stringstream s; std::stringstream s;
if(abs(v) >= VALUE_MATE - 200) { if (v >= VALUE_MATE - 200)
if(v < 0)
s << "-#" << (VALUE_MATE + v) / 2;
else
s << "#" << (VALUE_MATE - v + 1) / 2; s << "#" << (VALUE_MATE - v + 1) / 2;
} else if(v <= -VALUE_MATE + 200)
else { s << "-#" << (VALUE_MATE + v) / 2;
float floatScore = float(v) / float(PawnValueMidgame); else
if(v >= 0) {
s << '+'; float floatScore = float(v) / float(PawnValueMidgame);
s << std::setprecision(2) << std::fixed << floatScore; if (v >= 0)
s << '+';
s << std::setprecision(2) << std::fixed << floatScore;
} }
return s.str(); return s.str();
} }
} }
+5 -8
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 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
@@ -36,12 +36,9 @@
//// Prototypes //// Prototypes
//// ////
extern const std::string move_to_san(Position &pos, Move m); extern const std::string move_to_san(const Position& pos, Move m);
extern Move move_from_san(Position &pos, const std::string &str); extern Move move_from_san(const Position& pos, const std::string& str);
extern const std::string line_to_san(const Position &pos, Move line[], extern const std::string line_to_san(const Position& pos, Move line[], int startColumn, bool breakLines);
int startColumn, bool breakLines); extern const std::string pretty_pv(const Position& pos, int time, int depth, uint64_t nodes, Value score, Move pv[]);
extern const std::string pretty_pv(const Position &pos, int time, int depth,
uint64_t nodes, Value score, Move pv[]);
#endif // !defined(SAN_H_INCLUDED) #endif // !defined(SAN_H_INCLUDED)
+1 -1
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 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
+764 -533
View File
File diff suppressed because it is too large Load Diff
+9 -25
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 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,14 +25,8 @@
//// Includes //// Includes
//// ////
#include "types.h"
#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"
//// ////
@@ -41,6 +35,7 @@
const int PLY_MAX = 100; const int PLY_MAX = 100;
const int PLY_MAX_PLUS_2 = 102; const int PLY_MAX_PLUS_2 = 102;
const int KILLER_MAX = 2;
//// ////
@@ -55,34 +50,23 @@ const int PLY_MAX_PLUS_2 = 102;
struct SearchStack { struct SearchStack {
Move pv[PLY_MAX]; Move pv[PLY_MAX];
Move currentMove; Move currentMove;
Value currentMoveCaptureValue; Move mateKiller;
Move mateKiller, killer1, killer2;
Move threatMove; Move threatMove;
Move killers[KILLER_MAX];
Depth reduction; Depth reduction;
void init(int ply);
void initKillers();
}; };
////
//// Global variables
////
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();
-85
View File
@@ -1,85 +0,0 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 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 <cassert>
#include <string>
#include "square.h"
////
//// Functions
////
/// Translating files, ranks and squares to/from characters and strings:
File file_from_char(char c) {
return File(c - 'a') + FILE_A;
}
char file_to_char(File f) {
return char(f - FILE_A) + 'a';
}
Rank rank_from_char(char c) {
return Rank(c - '1') + RANK_1;
}
char rank_to_char(Rank r) {
return char(r - RANK_1) + '1';
}
Square square_from_string(const std::string &str) {
return make_square(file_from_char(str[0]), rank_from_char(str[1]));
}
const std::string square_to_string(Square s) {
std::string str;
str += file_to_char(square_file(s));
str += rank_to_char(square_rank(s));
return str;
}
/// file_is_ok(), rank_is_ok() and square_is_ok(), for debugging:
bool file_is_ok(File f) {
return f >= FILE_A && f <= FILE_H;
}
bool rank_is_ok(Rank r) {
return r >= RANK_1 && r <= RANK_8;
}
bool square_is_ok(Square s) {
return file_is_ok(square_file(s)) && rank_is_ok(square_rank(s));
}
+35 -13
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 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
@@ -159,21 +159,43 @@ inline int square_distance(Square s1, Square s2) {
return Max(file_distance(s1, s2), rank_distance(s1, s2)); return Max(file_distance(s1, s2), rank_distance(s1, s2));
} }
inline File file_from_char(char c) {
return File(c - 'a') + FILE_A;
}
//// inline char file_to_char(File f) {
//// Prototypes return char(f - FILE_A + int('a'));
//// }
extern File file_from_char(char c); inline Rank rank_from_char(char c) {
extern char file_to_char(File f); return Rank(c - '1') + RANK_1;
extern Rank rank_from_char(char c); }
extern char rank_to_char(Rank r);
extern Square square_from_string(const std::string &str);
extern const std::string square_to_string(Square s);
extern bool file_is_ok(File f); inline char rank_to_char(Rank r) {
extern bool rank_is_ok(Rank r); return char(r - RANK_1 + int('1'));
extern bool square_is_ok(Square s); }
inline Square square_from_string(const std::string& str) {
return make_square(file_from_char(str[0]), rank_from_char(str[1]));
}
inline const std::string square_to_string(Square s) {
std::string str;
str += file_to_char(square_file(s));
str += rank_to_char(square_rank(s));
return str;
}
inline bool file_is_ok(File f) {
return f >= FILE_A && f <= FILE_H;
}
inline bool rank_is_ok(Rank r) {
return r >= RANK_1 && r <= RANK_8;
}
inline bool square_is_ok(Square s) {
return file_is_ok(square_file(s)) && rank_is_ok(square_rank(s));
}
#endif // !defined(SQUARE_H_INCLUDED) #endif // !defined(SQUARE_H_INCLUDED)
+3 -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
@@ -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
}; };
-28
View File
@@ -1,28 +0,0 @@
/*
(c) Copyright 1992 Eric Backus
This software may be used freely so long as this copyright notice is
left intact. There is no warrantee on this software.
*/
#include <windows.h>
#include <time.h>
#include "dos.h"
int gettimeofday(struct timeval * tp, struct timezone * tzp)
{
SYSTEMTIME systime;
if (tp) {
struct tm tmrec;
time_t theTime = time(NULL);
tmrec = *localtime(&theTime);
tp->tv_sec = mktime(&tmrec);
GetLocalTime(&systime); /* system time */
tp->tv_usec = systime.wMilliseconds * 1000;
}
return 0;
}
+63 -84
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,20 +33,13 @@
//// Functions //// Functions
//// ////
/// Constructor TranspositionTable::TranspositionTable() {
TranspositionTable::TranspositionTable(unsigned mbSize) { size = writes = 0;
size = 0;
generation = 0;
writes = 0;
entries = 0; entries = 0;
set_size(mbSize); generation = 0;
} }
/// Destructor
TranspositionTable::~TranspositionTable() { TranspositionTable::~TranspositionTable() {
delete [] entries; delete [] entries;
@@ -58,33 +51,33 @@ TranspositionTable::~TranspositionTable() {
void TranspositionTable::set_size(unsigned mbSize) { void TranspositionTable::set_size(unsigned mbSize) {
assert(mbSize >= 4 && mbSize <= 1024); assert(mbSize >= 4 && mbSize <= 4096);
unsigned newSize = 1024; unsigned newSize = 1024;
// We store a cluster of 4 TTEntry for each position and newSize is // We store a cluster of 4 TTEntry for each position and newSize is
// the maximum number of storable positions // the maximum number of storable positions
for ( ; newSize * 4 * (sizeof(TTEntry)) <= (mbSize << 20); newSize *= 2); while ((2 * newSize) * 4 * (sizeof(TTEntry)) <= (mbSize << 20))
newSize /= 2; newSize *= 2;
if (newSize != size) if (newSize != size)
{ {
size = newSize; size = newSize;
delete [] entries; delete [] entries;
entries = new TTEntry[size * 4]; entries = new TTEntry[size * 4];
if (!entries) if (!entries)
{ {
std::cerr << "Failed to allocate " << mbSize std::cerr << "Failed to allocate " << mbSize
<< " MB for transposition table." << " MB for transposition table." << std::endl;
<< std::endl; Application::exit_with_failure();
exit(EXIT_FAILURE); }
} clear();
clear();
} }
} }
/// TranspositionTable::clear overwrites the entire transposition table /// TranspositionTable::clear overwrites the entire transposition table
/// with zeroes. It is called whenever the table is resized, or when the /// with zeroes. It is called whenever the table is resized, or when the
/// user asks the program to clear the table (from the UCI interface). /// user asks the program to clear the table (from the UCI interface).
/// Perhaps we should also clear it when the "ucinewgame" command is recieved? /// Perhaps we should also clear it when the "ucinewgame" command is recieved?
@@ -96,43 +89,44 @@ void TranspositionTable::clear() {
/// TranspositionTable::store writes a new entry containing a position, /// TranspositionTable::store writes a new entry containing a position,
/// a value, a value type, a search depth, and a best move to the /// a value, a value type, a search depth, and a best move to the
/// transposition table. The transposition table is organized in clusters /// transposition table. Transposition table is organized in clusters of
/// of four TTEntry objects, and when a new entry is written, it replaces /// four TTEntry objects, and when a new entry is written, it replaces
/// the least valuable of the four entries in a cluster. A TTEntry t1 is /// the least valuable of the four entries in a cluster. A TTEntry t1 is
/// considered to be more valuable than a TTEntry t2 if t1 is from the /// considered to be more valuable than a TTEntry t2 if t1 is from the
/// current search and t2 is from a previous search, or if the depth of t1 /// current search and t2 is from a previous search, or if the depth of t1
/// is bigger than the depth of t2. /// is bigger than the depth of t2. A TTEntry of type VALUE_TYPE_EVAL
/// never replaces another entry for the same position.
void TranspositionTable::store(const Key posKey, Value v, ValueType t, Depth d, Move m) {
void TranspositionTable::store(const Position &pos, Value v, Depth d,
Move m, ValueType type) {
TTEntry *tte, *replace; TTEntry *tte, *replace;
tte = replace = first_entry(pos); tte = replace = first_entry(posKey);
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++, tte++)
{ {
if (!(tte+i)->key()) // still empty if (!tte->key() || tte->key() == posKey) // empty or overwrite old
{ {
*(tte+i) = TTEntry(pos.get_key(), v, type, d, m, generation); // Do not overwrite when new type is VALUE_TYPE_EVAL
writes++; if (tte->key() && t == VALUE_TYPE_EVAL)
return; return;
}
if ((tte+i)->key() == pos.get_key()) // overwrite old
{
if (m == MOVE_NONE)
m = (tte+i)->move();
*(tte+i) = TTEntry(pos.get_key(), v, type, d, m, generation); if (m == MOVE_NONE)
return; m = tte->move();
}
if ( i == 0 // already is (replace == tte+i), common case
|| replace->generation() < (tte+i)->generation())
continue;
if ( replace->generation() > (tte+i)->generation() *tte = TTEntry(posKey, v, t, d, m, generation);
|| (tte+i)->depth() < replace->depth()) return;
replace = tte+i; }
else if (i == 0) // replace would be a no-op in this common case
continue;
int c1 = (replace->generation() == generation ? 2 : 0);
int c2 = (tte->generation() == generation ? -2 : 0);
int c3 = (tte->depth() < replace->depth() ? 1 : 0);
if (c1 + c2 + c3 > 0)
replace = tte;
} }
*replace = TTEntry(pos.get_key(), v, type, d, m, generation); *replace = TTEntry(posKey, v, t, d, m, generation);
writes++; writes++;
} }
@@ -141,15 +135,14 @@ void TranspositionTable::store(const Position &pos, Value v, 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.
const 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() == posKey)
if (tte->key() == pos.get_key())
return tte; return tte;
}
return NULL; return NULL;
} }
@@ -157,13 +150,13 @@ const 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
/// search. It increments the "generation" variable, which is used to /// search. It increments the "generation" variable, which is used to
/// distinguish transposition table entries from previous searches from /// distinguish transposition table entries from previous searches from
/// entries from the current search. /// entries from the current search.
@@ -175,19 +168,19 @@ void TranspositionTable::new_search() {
/// TranspositionTable::insert_pv() is called at the end of a search /// TranspositionTable::insert_pv() is called at the end of a search
/// iteration, and inserts the PV back into the PV. This makes sure the /// iteration, and inserts the PV back into the PV. This makes sure
/// old PV moves are searched first, even if the old TT entries have been /// the old PV moves are searched first, even if the old TT entries
/// overwritten. /// have been overwritten.
void TranspositionTable::insert_pv(const Position &pos, Move pv[]) { void TranspositionTable::insert_pv(const Position& pos, Move pv[]) {
UndoInfo u; StateInfo st;
Position p(pos); Position p(pos);
for (int i = 0; pv[i] != MOVE_NONE; i++) for (int i = 0; pv[i] != MOVE_NONE; i++)
{ {
store(p, VALUE_NONE, Depth(0), pv[i], VALUE_TYPE_NONE); store(p.get_key(), VALUE_NONE, VALUE_TYPE_NONE, Depth(-127*OnePly), pv[i]);
p.do_move(pv[i], u); p.do_move(pv[i], st);
} }
} }
@@ -196,22 +189,8 @@ void TranspositionTable::insert_pv(const Position &pos, Move pv[]) {
/// entries which have received at least one write during the current search. /// entries which have received at least one write during the current search.
/// It is used to display the "info hashfull ..." information in UCI. /// It is used to display the "info hashfull ..." information in UCI.
int TranspositionTable::full() { int TranspositionTable::full() const {
double N = double(size) * 4.0; double N = double(size) * 4.0;
return int(1000 * (1 - exp(writes * log(1.0 - 1.0/N)))); return int(1000 * (1 - exp(writes * log(1.0 - 1.0/N))));
} }
/// Constructors
TTEntry::TTEntry() {
}
TTEntry::TTEntry(Key k, Value v, ValueType t, Depth d, Move m,
int generation) :
key_ (k), data((m & 0x7FFFF) | (t << 20) | (generation << 23)),
value_(v), depth_(int16_t(d)) {}
+35 -22
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,18 +34,35 @@
//// Types //// Types
//// ////
/// The TTEntry class is the class of transposition table entries. /// The TTEntry class is the class of transposition table entries
///
/// A TTEntry needs 128 bits to be stored
///
/// bit 0-63: key
/// bit 64-95: data
/// bit 96-111: value
/// bit 112-127: depth
///
/// the 32 bits of the data field are so defined
///
/// bit 0-16: move
/// bit 17-19: not used
/// bit 20-22: value type
/// bit 23-31: generation
class TTEntry { class TTEntry {
public: public:
TTEntry(); TTEntry() {}
TTEntry(Key k, Value v, ValueType t, Depth d, Move m, int generation); TTEntry(Key k, Value v, ValueType t, Depth d, Move m, int generation)
: key_ (k), data((m & 0x1FFFF) | (t << 20) | (generation << 23)),
value_(int16_t(v)), depth_(int16_t(d)) {}
Key key() const { return key_; } Key key() const { return key_; }
Depth depth() const { return Depth(depth_); } Depth depth() const { return Depth(depth_); }
Move move() const { return Move(data & 0x7FFFF); } Move move() const { return Move(data & 0x1FFFF); }
Value value() const { return Value(value_); } Value value() const { return Value(value_); }
ValueType type() const { return ValueType((data >> 20) & 3); } ValueType type() const { return ValueType((data >> 20) & 7); }
int generation() const { return (data >> 23); } int generation() const { return (data >> 23); }
private: private:
@@ -62,32 +79,28 @@ private:
class TranspositionTable { class TranspositionTable {
public: public:
TranspositionTable(unsigned mbSize); TranspositionTable();
~TranspositionTable(); ~TranspositionTable();
void set_size(unsigned mbSize); void set_size(unsigned mbSize);
void clear(); void clear();
void store(const Position &pos, Value v, Depth d, Move m, ValueType type); void store(const Key posKey, Value v, ValueType type, Depth d, Move m);
const 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(); int full() const;
private: private:
inline TTEntry* first_entry(const Position &pos) const; inline TTEntry* first_entry(const Key posKey) const;
// 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; unsigned size;
int writes;
TTEntry* entries; TTEntry* entries;
uint8_t generation; uint8_t generation;
}; };
////
//// Constants and variables
////
// Default transposition table size, in megabytes:
const int TTDefaultSize = 32;
#endif // !defined(TT_H_INCLUDED) #endif // !defined(TT_H_INCLUDED)
+24 -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
@@ -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)
+82 -91
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,6 +22,7 @@
//// Includes //// Includes
//// ////
#include <cassert>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <string> #include <string>
@@ -37,6 +38,7 @@
#include "uci.h" #include "uci.h"
#include "ucioption.h" #include "ucioption.h"
using namespace std;
//// ////
//// Local definitions: //// Local definitions:
@@ -44,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);
} }
@@ -67,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));
} }
@@ -87,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
@@ -159,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: " << 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);
} }
@@ -219,43 +201,48 @@ namespace {
if (token == "moves") if (token == "moves")
{ {
Move move; Move move;
UndoInfo u; StateInfo st;
while (!uip.eof()) while (!uip.eof())
{ {
uip >> token; uip >> token;
move = move_from_string(RootPosition, token); move = move_from_string(RootPosition, token);
RootPosition.do_move(move, u); RootPosition.do_move(move, st);
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 so copy
// its content inside RootPosition before they disappear.
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")
{ {
uip >> name; uip >> name;
uip >> token; while (!uip.eof())
while (!uip.eof() && token != "value")
{ {
name += (" " + token); uip >> token;
uip >> token; if (token == "value")
break;
name += (" " + token);
} }
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);
@@ -263,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;
@@ -321,7 +309,10 @@ namespace {
if (moveTime) if (moveTime)
infinite = true; // HACK infinite = true; // HACK
think(RootPosition, infinite, ponder, RootPosition.side_to_move(), time, assert(RootPosition.is_ok());
inc, movesToGo, depth, nodes, moveTime, searchMoves);
return think(RootPosition, infinite, ponder, RootPosition.side_to_move(),
time, inc, movesToGo, depth, nodes, moveTime, searchMoves);
} }
} }
+1 -1
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 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
+155 -184
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,7 +22,9 @@
//// Includes //// Includes
//// ////
#include <algorithm>
#include <cassert> #include <cassert>
#include <map>
#include <string> #include <string>
#include <sstream> #include <sstream>
#include <vector> #include <vector>
@@ -31,13 +33,7 @@
#include "thread.h" #include "thread.h"
#include "ucioption.h" #include "ucioption.h"
using std::string;
////
//// Variables
////
bool Chess960 = false;
//// ////
//// Local definitions //// Local definitions
@@ -51,96 +47,96 @@ 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;
int minValue, maxValue; int minValue, maxValue;
ComboValues comboValues; ComboValues comboValues;
Option(const char* name, const char* defaultValue, OptionType = STRING); Option();
Option(const char* name, bool defaultValue, OptionType = CHECK); Option(const char* defaultValue, OptionType = STRING);
Option(const char* name, int defaultValue, int minValue, int maxValue); Option(bool defaultValue, OptionType = CHECK);
Option(int defaultValue, int minValue, int maxValue);
bool operator<(const Option& o) const { return this->idx < o.idx; }
}; };
typedef std::vector<Option> Options; typedef std::map<string, Option> Options;
/// ///
/// Constants /// Constants
/// ///
// load_defaults populates the options vector with the hard // load_defaults populates the options map with the hard
// coded names and default values. // coded names and default values.
void load_defaults(Options& o) { void load_defaults(Options& o) {
o.push_back(Option("Use Search Log", false)); o["Use Search Log"] = Option(false);
o.push_back(Option("Search Log Filename", "SearchLog.txt")); o["Search Log Filename"] = Option("SearchLog.txt");
o.push_back(Option("Book File", "book.bin")); o["Book File"] = Option("book.bin");
o.push_back(Option("Mobility (Middle Game)", 100, 0, 200)); o["Mobility (Middle Game)"] = Option(100, 0, 200);
o.push_back(Option("Mobility (Endgame)", 100, 0, 200)); o["Mobility (Endgame)"] = Option(100, 0, 200);
o.push_back(Option("Pawn Structure (Middle Game)", 100, 0, 200)); o["Pawn Structure (Middle Game)"] = Option(100, 0, 200);
o.push_back(Option("Pawn Structure (Endgame)", 100, 0, 200)); o["Pawn Structure (Endgame)"] = Option(100, 0, 200);
o.push_back(Option("Passed Pawns (Middle Game)", 100, 0, 200)); o["Passed Pawns (Middle Game)"] = Option(100, 0, 200);
o.push_back(Option("Passed Pawns (Endgame)", 100, 0, 200)); o["Passed Pawns (Endgame)"] = Option(100, 0, 200);
o.push_back(Option("Aggressiveness", 100, 0, 200)); o["Space"] = Option(100, 0, 200);
o.push_back(Option("Cowardice", 100, 0, 200)); o["Aggressiveness"] = Option(100, 0, 200);
o.push_back(Option("King Safety Curve", "Quadratic", COMBO)); o["Cowardice"] = Option(100, 0, 200);
o["King Safety Curve"] = Option("Quadratic", COMBO);
o.back().comboValues.push_back("Quadratic"); o["King Safety Curve"].comboValues.push_back("Quadratic");
o.back().comboValues.push_back("Linear"); /*, "From File"*/ o["King Safety Curve"].comboValues.push_back("Linear"); /*, "From File"*/
o.push_back(Option("King Safety Coefficient", 40, 1, 100)); o["King Safety Coefficient"] = Option(40, 1, 100);
o.push_back(Option("King Safety X Intercept", 0, 0, 20)); o["King Safety X Intercept"] = Option(0, 0, 20);
o.push_back(Option("King Safety Max Slope", 30, 10, 100)); o["King Safety Max Slope"] = Option(30, 10, 100);
o.push_back(Option("King Safety Max Value", 500, 100, 1000)); o["King Safety Max Value"] = Option(500, 100, 1000);
o.push_back(Option("Queen Contact Check Bonus", 4, 0, 8)); o["Queen Contact Check Bonus"] = Option(3, 0, 8);
o.push_back(Option("Rook Contact Check Bonus", 2, 0, 4)); o["Queen Check Bonus"] = Option(2, 0, 4);
o.push_back(Option("Queen Check Bonus", 2, 0, 4)); o["Rook Check Bonus"] = Option(1, 0, 4);
o.push_back(Option("Rook Check Bonus", 1, 0, 4)); o["Bishop Check Bonus"] = Option(1, 0, 4);
o.push_back(Option("Bishop Check Bonus", 1, 0, 4)); o["Knight Check Bonus"] = Option(1, 0, 4);
o.push_back(Option("Knight Check Bonus", 1, 0, 4)); o["Discovered Check Bonus"] = Option(3, 0, 8);
o.push_back(Option("Discovered Check Bonus", 3, 0, 8)); o["Mate Threat Bonus"] = Option(3, 0, 8);
o.push_back(Option("Mate Threat Bonus", 3, 0, 8)); o["Check Extension (PV nodes)"] = Option(2, 0, 2);
o.push_back(Option("Check Extension (PV nodes)", 2, 0, 2)); o["Check Extension (non-PV nodes)"] = Option(1, 0, 2);
o.push_back(Option("Check Extension (non-PV nodes)", 1, 0, 2)); o["Single Reply Extension (PV nodes)"] = Option(2, 0, 2);
o.push_back(Option("Single Reply Extension (PV nodes)", 2, 0, 2)); o["Single Reply Extension (non-PV nodes)"] = Option(2, 0, 2);
o.push_back(Option("Single Reply Extension (non-PV nodes)", 2, 0, 2)); o["Mate Threat Extension (PV nodes)"] = Option(0, 0, 2);
o.push_back(Option("Mate Threat Extension (PV nodes)", 0, 0, 2)); o["Mate Threat Extension (non-PV nodes)"] = Option(0, 0, 2);
o.push_back(Option("Mate Threat Extension (non-PV nodes)", 0, 0, 2)); o["Pawn Push to 7th Extension (PV nodes)"] = Option(1, 0, 2);
o.push_back(Option("Pawn Push to 7th Extension (PV nodes)", 1, 0, 2)); o["Pawn Push to 7th Extension (non-PV nodes)"] = Option(1, 0, 2);
o.push_back(Option("Pawn Push to 7th Extension (non-PV nodes)", 1, 0, 2)); o["Passed Pawn Extension (PV nodes)"] = Option(1, 0, 2);
o.push_back(Option("Passed Pawn Extension (PV nodes)", 1, 0, 2)); o["Passed Pawn Extension (non-PV nodes)"] = Option(0, 0, 2);
o.push_back(Option("Passed Pawn Extension (non-PV nodes)", 0, 0, 2)); o["Pawn Endgame Extension (PV nodes)"] = Option(2, 0, 2);
o.push_back(Option("Pawn Endgame Extension (PV nodes)", 2, 0, 2)); o["Pawn Endgame Extension (non-PV nodes)"] = Option(2, 0, 2);
o.push_back(Option("Pawn Endgame Extension (non-PV nodes)", 2, 0, 2)); o["Full Depth Moves (PV nodes)"] = Option(14, 1, 100);
o.push_back(Option("Full Depth Moves (PV nodes)", 14, 1, 100)); o["Full Depth Moves (non-PV nodes)"] = Option(3, 1, 100);
o.push_back(Option("Full Depth Moves (non-PV nodes)", 3, 1, 100)); o["Threat Depth"] = Option(5, 0, 100);
o.push_back(Option("Threat Depth", 5, 0, 100)); o["LSN filtering"] = Option(false);
o.push_back(Option("Selective Plies", 7, 0, 10)); o["LSN Time Margin (sec)"] = Option(4, 1, 10);
o.push_back(Option("Futility Pruning (Main Search)", true)); o["LSN Value Margin"] = Option(200, 100, 600);
o.push_back(Option("Futility Pruning (Quiescence Search)", true)); o["Randomness"] = Option(0, 0, 10);
o.push_back(Option("Futility Margin 0", 50, 0, 1000)); o["Minimum Split Depth"] = Option(4, 4, 7);
o.push_back(Option("Futility Margin 1", 100, 0, 1000)); o["Maximum Number of Threads per Split Point"] = Option(5, 4, 8);
o.push_back(Option("Futility Margin 2", 300, 0, 1000)); o["Threads"] = Option(1, 1, 8);
o.push_back(Option("Maximum Razoring Depth", 3, 0, 4)); o["Hash"] = Option(32, 4, 4096);
o.push_back(Option("Razoring Margin", 300, 150, 600)); o["Clear Hash"] = Option(false, BUTTON);
o.push_back(Option("LSN filtering", false)); o["Ponder"] = Option(true);
o.push_back(Option("LSN Time Margin (sec)", 4, 1, 10)); o["OwnBook"] = Option(true);
o.push_back(Option("LSN Value Margin", 200, 100, 600)); o["MultiPV"] = Option(1, 1, 500);
o.push_back(Option("Randomness", 0, 0, 10)); o["UCI_ShowCurrLine"] = Option(false);
o.push_back(Option("Minimum Split Depth", 4, 4, 7)); o["UCI_Chess960"] = Option(false);
o.push_back(Option("Maximum Number of Threads per Split Point", 5, 4, 8));
o.push_back(Option("Threads", 1, 1, 8)); // Any option should know its name so to be easily printed
o.push_back(Option("Hash", 32, 4, 4096)); for (Options::iterator it = o.begin(); it != o.end(); ++it)
o.push_back(Option("Clear Hash", false, BUTTON)); it->second.name = it->first;
o.push_back(Option("Ponder", true));
o.push_back(Option("OwnBook", true));
o.push_back(Option("MultiPV", 1, 1, 500));
o.push_back(Option("UCI_ShowCurrLine", false));
o.push_back(Option("UCI_Chess960", false));
} }
/// ///
@@ -149,56 +145,32 @@ namespace {
Options options; Options options;
// Local functions
Options::iterator option_with_name(const std::string& optionName);
// 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;
return ss.str(); return ss.str();
} }
// We want conversion from a bool value to be "true" or "false",
// not "1" or "0", so add a specialization for bool type.
template<>
std::string stringify<bool>(const bool& v) {
return v ? "true" : "false";
}
// get_option_value implements the various get_option_value_<type> // get_option_value implements the various get_option_value_<type>
// functions defined later, because only the option value // functions defined later, because only the option value
// 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 ret = T();
Options::iterator it = option_with_name(optionName); if (options.find(optionName) == options.end())
return ret;
if (it != options.end()) std::istringstream ss(options[optionName].currentValue);
{ ss >> ret;
std::istringstream ss(it->currentValue);
ss >> ret;
}
return ret; return ret;
} }
// Unfortunatly we need a specialization to convert "false" and "true"
// to proper bool values. The culprit is that we use a non standard way
// to store a bool value in a string, in particular we use "false" and
// "true" instead of "0" and "1" due to how UCI protocol works.
template<>
bool get_option_value<bool>(const std::string& optionName) {
Options::iterator it = option_with_name(optionName);
return it != options.end() && it->currentValue == "true";
}
} }
//// ////
@@ -217,24 +189,19 @@ void init_uci_options() {
// According to Ken Dail's tests, Glaurung plays much better with 7 than // According to Ken Dail's tests, Glaurung plays much better with 7 than
// with 8 threads. This is weird, but it is probably difficult to find out // with 8 threads. This is weird, but it is probably difficult to find out
// why before I have a 8-core computer to experiment with myself. // why before I have a 8-core computer to experiment with myself.
Options::iterator it = option_with_name("Threads"); assert(options.find("Threads") != options.end());
assert(options.find("Minimum Split Depth") != options.end());
assert(it != options.end()); options["Threads"].defaultValue = stringify(Min(cpu_count(), 7));
options["Threads"].currentValue = stringify(Min(cpu_count(), 7));
it->defaultValue = stringify(Min(cpu_count(), 7));
it->currentValue = stringify(Min(cpu_count(), 7));
// Increase the minimum split depth when the number of CPUs is big. // Increase the minimum split depth when the number of CPUs is big.
// It would probably be better to let this depend on the number of threads // It would probably be better to let this depend on the number of threads
// instead. // instead.
if(cpu_count() > 4) if (cpu_count() > 4)
{ {
it = option_with_name("Minimum Split Depth"); options["Minimum Split Depth"].defaultValue = "6";
options["Minimum Split Depth"].currentValue = "6";
assert(it != options.end());
it->defaultValue = "6";
it->currentValue = "6";
} }
} }
@@ -248,32 +215,42 @@ void print_uci_options() {
"spin", "combo", "check", "string", "button" "spin", "combo", "check", "string", "button"
}; };
for (Options::iterator it = options.begin(); it != options.end(); ++it) // Build up a vector out of the options map and sort it according to idx
{ // field, that is the chronological insertion order in options map.
std::cout << "option name " << it->name std::vector<Option> vec;
<< " type " << optionTypeName[it->type]; for (Options::const_iterator it = options.begin(); it != options.end(); ++it)
vec.push_back(it->second);
if (it->type != BUTTON) std::sort(vec.begin(), vec.end());
{
for (std::vector<Option>::const_iterator it = vec.begin(); it != vec.end(); ++it)
{
std::cout << "\noption name " << it->name
<< " type " << optionTypeName[it->type];
if (it->type == BUTTON)
continue;
if (it->type == CHECK)
std::cout << " default " << (it->defaultValue == "1" ? "true" : "false");
else
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)
for (ComboValues::const_iterator itc = it->comboValues.begin();
else if (it->type == COMBO) itc != it->comboValues.end(); ++itc)
for(ComboValues::iterator itc = it->comboValues.begin(); std::cout << " var " << *itc;
itc != it->comboValues.end(); ++itc)
std::cout << " var " << *itc;
}
std::cout << std::endl;
} }
std::cout << std::endl;
} }
/// 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);
} }
@@ -284,84 +261,78 @@ 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);
} }
/// 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);
} }
/// button_was_pressed() tests whether a UCI parameter of type "button" has /// set_option_value() inserts a new value for a UCI parameter. Note that
/// been selected since the last time the function was called.
bool button_was_pressed(const std::string& buttonName) {
if (get_option_value<bool>(buttonName))
{
set_option_value(buttonName, "false");
return true;
}
return false;
}
/// set_option_value() inserts a new value for a UCI parameter. Note that
/// the function does not check that the new value is legal for the given /// 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) {
Options::iterator it = option_with_name(optionName); // UCI protocol uses "true" and "false" instead of "1" and "0", so convert
// value according to standard C++ convention before to store it.
string v(value);
if (v == "true")
v = "1";
else if (v == "false")
v = "0";
if (it != options.end()) if (options.find(name) != options.end())
it->currentValue = newValue; 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");
} }
/// button_was_pressed() tests whether a UCI parameter of type "button" has
/// been selected since the last time the function was called, in this case
/// it also resets the button.
bool button_was_pressed(const string& buttonName) {
if (!get_option_value<bool>(buttonName))
return false;
set_option_value(buttonName, "false");
return true;
}
namespace { namespace {
// Define constructors of Option class. // Define constructors of Option class.
Option::Option(const char* nm, const char* def, OptionType t) Option::Option() {} // To allow insertion in a std::map
: name(nm), defaultValue(def), currentValue(def), type(t), minValue(0), maxValue(0) {}
Option::Option(const char* nm, bool def, OptionType t) Option::Option(const char* def, OptionType t)
: name(nm), defaultValue(stringify(def)), currentValue(stringify(def)), type(t), minValue(0), maxValue(0) {} : defaultValue(def), currentValue(def), type(t), idx(options.size()), minValue(0), maxValue(0) {}
Option::Option(const char* nm, int def, int minv, int maxv) Option::Option(bool def, OptionType t)
: name(nm), defaultValue(stringify(def)), currentValue(stringify(def)), type(SPIN), minValue(minv), maxValue(maxv) {} : defaultValue(stringify(def)), currentValue(stringify(def)), type(t), idx(options.size()), minValue(0), maxValue(0) {}
// option_with_name() tries to find a UCI option with a given Option::Option(int def, int minv, int maxv)
// name. It returns an iterator to the UCI option or to options.end(), : defaultValue(stringify(def)), currentValue(stringify(def)), type(SPIN), idx(options.size()), minValue(minv), maxValue(maxv) {}
// depending on whether an option with the given name exists.
Options::iterator option_with_name(const std::string& optionName) {
for (Options::iterator it = options.begin(); it != options.end(); ++it)
if (it->name == optionName)
return it;
return options.end();
}
} }
+7 -16
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)
+1 -1
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 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
+18 -15
View File
@@ -1,7 +1,7 @@
/* /*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 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
@@ -36,7 +36,8 @@ enum ValueType {
VALUE_TYPE_NONE = 0, VALUE_TYPE_NONE = 0,
VALUE_TYPE_UPPER = 1, // Upper bound VALUE_TYPE_UPPER = 1, // Upper bound
VALUE_TYPE_LOWER = 2, // Lower bound VALUE_TYPE_LOWER = 2, // Lower bound
VALUE_TYPE_EXACT = 3 // Exact score VALUE_TYPE_EXACT = 3, // Exact score
VALUE_TYPE_EVAL = 4 // Evaluation cache
}; };
@@ -58,17 +59,19 @@ enum Value {
/// Important: If the material values are changed, one must also /// Important: If the material values are changed, one must also
/// adjust the piece square tables, and the method game_phase() in the /// adjust the piece square tables, and the method game_phase() in the
/// Position class! /// Position class!
///
/// Values modified by Joona Kiiski
const Value PawnValueMidgame = Value(0xCC); const Value PawnValueMidgame = Value(0x0C6);
const Value PawnValueEndgame = Value(0x100); const Value PawnValueEndgame = Value(0x102);
const Value KnightValueMidgame = Value(0x340); const Value KnightValueMidgame = Value(0x331);
const Value KnightValueEndgame = Value(0x340); const Value KnightValueEndgame = Value(0x34E);
const Value BishopValueMidgame = Value(0x340); const Value BishopValueMidgame = Value(0x344);
const Value BishopValueEndgame = Value(0x340); const Value BishopValueEndgame = Value(0x359);
const Value RookValueMidgame = Value(0x505); const Value RookValueMidgame = Value(0x4F6);
const Value RookValueEndgame = Value(0x505); const Value RookValueEndgame = Value(0x4FE);
const Value QueenValueMidgame = Value(0xA00); const Value QueenValueMidgame = Value(0x9D9);
const Value QueenValueEndgame = Value(0xA00); const Value QueenValueEndgame = Value(0x9FE);
const Value PieceValueMidgame[17] = { const Value PieceValueMidgame[17] = {
Value(0), Value(0),
@@ -90,10 +93,10 @@ 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(50); const Value TempoValueMidgame = Value(48);
const Value TempoValueEndgame = Value(20); const Value TempoValueEndgame = Value(21);
//// ////