Compare commits

..

918 Commits

Author SHA1 Message Date
Marco Costalba 315c58354e Stockfish 2.1
stockfish bench signature is: 6487630

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-05-03 12:11:19 +01:00
Marco Costalba 5ef2b8c494 Reintroduce permanent PV entries in TT
We are now ready to release so restore this
improvment before 2.1

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-05-03 12:11:10 +01:00
Marco Costalba 9c5a53ca45 Update Readme.txt to 32 threads and bsfq on Windows
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-05-03 12:11:02 +01:00
Marco Costalba b1929960f9 Fix bug in evaluate_passed_pawns()
If blockSq is already on rank 8, blockSq + pawn_push(Us) is on rank 9,
outside of board. It does not make sense to measure king distance to
a field outside the board.

Bug spotted by Fruity:
http://open-chess.org/viewtopic.php?f=5&t=1156&start=10

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-05-03 12:10:53 +01:00
Marco Costalba 8447248705 Retire "Pawn Structure" UCI option
Almost useless for the user and now is in sync with
the material value that is already weighted.

A small speedup of 0,4% because we avoid an apply_weight()
call in a fast path.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-05-02 17:50:46 +01:00
Marco Costalba a10487b074 Rename stuff in evaluate.cpp
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-05-02 17:50:37 +01:00
Marco Costalba db31efb8a6 Additional tweaks in evaluate_unstoppable_pawns()
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-05-01 12:15:40 +01:00
Marco Costalba 75acd52415 Remove redundancy in evaluate_unstoppable_pawns()
Spotted by Fruity
http://open-chess.org/viewtopic.php?f=5&t=1156&start=20

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-05-01 10:31:27 +01:00
Marco Costalba 18c9b5ee86 Small reformat in evaluate_unstoppable_pawns()
Also simplify tracing because evaluate_unstoppable_pawns()
return always zero if both colors have non pawn material.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-05-01 09:58:45 +01:00
Marco Costalba 33bd67e052 Update polyglot.ini
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-05-01 07:49:40 +01:00
Marco Costalba 4dc7ba1619 Rename check related functions
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-29 18:56:48 +01:00
Marco Costalba 92d70fb667 Small renaming in thread.cpp
To better self document the code.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-29 13:08:35 +01:00
Marco Costalba 0bf475ec55 Rename Option in UCIOPtion
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-29 13:08:27 +01:00
Marco Costalba bb7713c8e9 Limit history range to +-2000
Extensive test series on tweaking history limit and bonus
formula. At the end this was the best.

After 11959 games:

Mod vs Orig 2087 - 1934 - 7938 ELO +4 (+- 3.7) LOS 92%

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-28 08:00:34 +01:00
Marco Costalba e656ddcf18 Perft counts leaf nodes not generated moves.
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-27 23:21:46 +01:00
Marco Costalba 1d0159075e Use probe() as name for looking up into an hash table
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-27 07:31:51 +01:00
Marco Costalba 321320b081 Tidy up uci.cpp and siblings
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-26 13:23:47 +01:00
Marco Costalba ca9d40c145 Move OpeningBook and RK where are actually used
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-26 13:23:39 +01:00
Marco Costalba 03f4d1e8d6 Fix a compile error with gcc
It seems gcc does not like an extra semicolon.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-25 22:59:56 +01:00
Marco Costalba 87f2b52ace Move MovePickerExt specializations away from headings
This unclutters a bit the heading part of search.cpp

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-25 13:35:13 +01:00
Marco Costalba 09d01ee9dc Tidy up benchmark.cpp
Node count is different just becuase now we don't log on
"bench.txt" file anymore so that we avoid some calls to
pretty_pv() that calls Position::do_move().

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-25 12:07:30 +01:00
Marco Costalba 05cfb00f26 Large API rename in ThreadsManager
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-25 10:30:39 +01:00
Marco Costalba 339e1b49f6 Don't allocate MAX_THREADS hash tables if not necessary
This prevent crashing on mobile devices with limited RAM,
currently with MAX_THREADS = 32 we would need 44MB that
could be too much for a poor cellphone.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-24 19:23:07 +01:00
Marco Costalba fecefbb99c Move pawn and material tables under Thread class
This change allows to remove some quite a bit of code
and seems the natural thing to do.

Introduced file thread.cpp to move away from search.cpp a lot
of threads related stuff.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-24 17:07:22 +01:00
Marco Costalba c9d7e99de6 Rename MOVES_MAX in MAX_MOVES
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-24 08:54:36 +01:00
Marco Costalba ccd5ccbcdb Retire extensions as UCI option
There is no real need why an user should change these values.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-24 08:52:16 +01:00
Marco Costalba 633c83f648 Document why we use per-thread pawn and material tables
Arisen from a discussion on talkchess.

No fnctional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-24 08:18:39 +01:00
Marco Costalba fe213d30fa Fix some comments in early stop detection
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-23 15:52:51 +01:00
Marco Costalba 8b2adcf99e Retire UseLogFile in search.cpp
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-23 15:00:44 +01:00
Marco Costalba 1d368bbbdc Introduce and use SearchLimits
Pack a bit of global variables related to search limits in
a single struct.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-23 13:11:03 +01:00
Marco Costalba bbfe452f85 Use move_is_special() in pawn endgame condition
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-22 12:30:51 +01:00
Marco Costalba 8bf9dc8254 Retire SearchStartTime global
Use a static variable inside current_search_time() instead.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-22 12:30:43 +01:00
Marco Costalba f349143a6b Reduce loops in init_threads() and exit_threads()
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-22 12:30:35 +01:00
Marco Costalba 79e50a2fbf Move wake_sleeping_thread() to Thread class
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-20 12:05:07 +01:00
Marco Costalba 2c317d7b28 Correctly implementg selDepth feature
Send to GUI the deepest search depth apart from
qsearch of the PV line.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-20 12:04:59 +01:00
Marco Costalba fdc9f8cbd7 Move sleepLock and sleepCond under Thread
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-20 12:04:52 +01:00
Marco Costalba 2e6839c9a0 Increase risk of blunders at low skill levels
According to Heinz's tests current setup is in fact too
strong for weak players. This seems the best according
to his tests.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-20 12:04:43 +01:00
Marco Costalba 67b0d0b1cc Use only history to score non captures
It seems gain is practically unuseful, so remove.

After 13554 games:
Mod vs Orig 2252 - 2319 - 8983 ELO -1 (+- 3.4)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-17 22:32:12 +01:00
Marco Costalba 068561f86a Small simplification in scale_by_game_phase()
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-17 10:31:26 +01:00
Marco Costalba 076b62310e Move ply to SearchStack
Shrink search() signature for better readibility.

We get also a nice 1.3% speed increase.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-17 08:59:54 +01:00
Marco Costalba 5ba85ef441 Remove one indentation level in get_next_move()
Small renaming and fix some comments.

No functional and no speed change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-16 12:57:06 +01:00
Marco Costalba c13b53a514 Code style in tt.cpp
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-16 10:49:35 +01:00
Marco Costalba a860576493 Better self-document LMR reduction() formula
Suggested by Onno

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-16 10:49:27 +01:00
Marco Costalba 786564068b Promote OptionsMap to a class
And add a bit of documentation too.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-16 10:49:20 +01:00
Marco Costalba 6056a43419 Fix a stale comment
Spotted by Onno

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-16 10:21:31 +01:00
Marco Costalba f8e767388b Remove src/COPYING file
It is enough the one in the base directory

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-14 07:06:56 +01:00
Marco Costalba b41b590457 Remove "divide by zero" workaround
It is now useless because of the condition at the beginning.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-14 07:04:32 +01:00
Marco Costalba 7f367e6019 Cleanup debug counters
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-13 18:51:56 +01:00
Marco Costalba 54f1c383d3 Move move_is_legal() under Position class
It is a more logical place than in move generation file.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-13 13:18:19 +01:00
Marco Costalba fe8f5b3497 Some more cleanup in endgame.cpp
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-13 13:17:21 +01:00
Marco Costalba 6608a16a6a Fix some warnings and a compile error with icc
Unfortunatly icc does not understand that weakerSide and
strongerSide belongs to the base class :-(

So we have define them in the derived class.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-12 08:05:41 +01:00
Marco Costalba b5d5646c84 Move EndgameFunctions to endgame.cpp
And cleanup code while there.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-11 21:25:24 +01:00
Marco Costalba 08c464c690 Increase MaterialTableSize 8 times
Now that we prefetch in material hash table we
can increase its size and gain something.

Hit rate is now of 98% from 92%

Speedup of 0.8%

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-11 18:15:40 +01:00
Marco Costalba f28ddbb852 Introduce and use NoPawnsSF[] in material.cpp
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-11 18:11:16 +01:00
Marco Costalba c88eebc989 Tempeltize material imbalance
Speedup of almost 1%

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-11 12:35:54 +01:00
Marco Costalba 7a84b8ca34 Sync material.h with pawns.h
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-11 12:24:10 +01:00
Marco Costalba 6738b65be9 Prefetch also material tables
Prefetch both pawn and material tables in do_move() and
prefetch always, not only after a pawn move or a capture.

Speed up of 0,7%

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-11 12:24:02 +01:00
Marco Costalba 2f1935078d Assorted code style and comments in pawns.cpp and pawns.h
The only interesting thing is that a backward or isolated
pawn cannot be a candidate passer, so code this condition.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-10 12:16:36 +01:00
Marco Costalba 8e71ee7ec6 Retire mate threat extension
It seems we have a lot of totally useless code !

After 8577 games 1504 - 1451 - 5622 ELO +2 (+- 4.4)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-08 07:48:05 +01:00
Marco Costalba 9bee5f51d8 Fix a compile error in debug mode
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-07 08:09:41 +01:00
Marco Costalba 927f1b0bd3 Assorted code style and comments in search.cpp
Nothing really serious....

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-05 19:00:40 +01:00
Marco Costalba 04108d4541 Added -Wshadow option and fixed resulting warnings
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-04 12:11:01 +01:00
Marco Costalba f7ef48b478 Teach SF to blunder
Add blunder cabability to skill level feature.

The idea is that instead of choosing the best move at the end
of the ID loop, we now do this at a randomly chosen sampling depth
dependent on SkillLevel, so that at low skill levels we sample when
ID loop has reached only a small depth and so we have an higher
probability to pick up a blunder.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-02 10:04:34 +01:00
Joona Kiiski 2e8998eac9 Use prob cut search to prune bad captures
The idea is to try a shallow search with reduced beta
on bad captures so to quickly prune them out in case
are really bad.

After 5529 games 966 - 868 - 3695  ELO +6 (+- 5.4) LOS 91%

Tested also version without upper limitation to 8 plies:

After 8780 games 1537 - 1398 - 5850  ELO +5 (+- 4.3) LOS 93%

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-02 08:39:54 +01:00
Marco Costalba 8402b40341 Retire recapture extension also for PvNode
Seems that extension is useless.

After 10105 games
Mod vs Orig 1738 - 1702 - 6665  ELO +1 (+- 4)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-01 22:02:18 +01:00
Marco Costalba 408fdcc93f Use a constant instead of value_mate_in(PLY_MAX)
And also apply the same to value_mated_in(PLY_MAX)

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-01 21:46:45 +01:00
Marco Costalba b27e237b04 Retire value_is_mate()
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-01 21:46:34 +01:00
Marco Costalba f5b8db7a1e Simplify wait_for_stop_or_ponderhit()
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-01 21:46:27 +01:00
Marco Costalba 8d4caebabe Retire update_killers()
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-04-01 21:46:12 +01:00
Marco Costalba d173285da5 Fine tune skill level
Rescaled Skill level from 0 to 20. At level 19 is still
comparable with Crafty 20.14, while at low levels strength
increase is now less steep.

Thanks to Joona and Heinz for testing and valuable
comments.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-03-28 13:09:13 +01:00
Marco Costalba 41fe70d703 Add "Skill level functionality
It is now possible to adjust skill level of Stockfish
from 10 (full strength) to 0.

Skill adjustment is done in such a way that is CPU speed and
time control largely independent, at least at low skills. It
means that given a skill we have same play level on a mobile
phone and on a super OCTAL CPU, at 1' per game or at 180'.

At skill 9 strength is that of an average engine, I have used
Crafty 20.14 to tune and we are more or less there. At skill 0
engine is pretty weak but still shows a realistic play.

When skill is not used we don't have any impact on the regular
code.

Idea to use MultiPV is from Heinz van Saanen, implementation and
formulas by me.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-03-27 11:50:22 +01:00
Marco Costalba d372f2e39a Fix a compile error with icc
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-03-26 09:25:26 +01:00
Marco Costalba 4270aec558 Send PV line to GUI only after resolving a fail high
This is how Shredder, Rybka and others do and
avoids user is confused by a fail high (sent to GUI)
followed by a fail low (not sent).

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-03-24 13:21:54 +01:00
Marco Costalba f427acbd27 Triviality in position.cpp
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-03-24 13:21:47 +01:00
Marco Costalba 87ca13a79a Retire move_ambiguity() altogether
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-03-23 13:09:04 +01:00
Marco Costalba d52d91064f Simplify move_ambiguity()
And additional small touches in move.cpp

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-03-22 13:23:41 +01:00
Marco Costalba 920b1abede Do not send ponder move if we don't have it
Has been reported by Justin Blanchard that
this creates problems on some buggy GUI.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-03-19 16:08:19 +01:00
Marco Costalba 5ea08e79c4 Use intrinsic in pop_1st_bit() under MSVC 64 bits
Around 1% speedup when compiled with MSVC 64

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-03-17 14:29:09 +01:00
Marco Costalba 635be39acf Additional cleanup in bitbase.cpp
Also better document what code does.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-03-12 18:22:22 +01:00
Marco Costalba c1c0984452 Move KPKBitbase[] where it belongs
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-03-12 12:12:41 +01:00
Marco Costalba d653aeca05 Fix a couple of issues in bitbase.cpp
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-03-12 11:22:02 +01:00
Marco Costalba 09d217bff7 Reintroduce initialization of some bitboards
With off-by-one bug in InFrontBB[] loop fixed.

Also use int instead of File to workaround a bug
in mingw 4.4.0 in first loop that cycles forever.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-03-10 19:23:39 +01:00
Marco Costalba d9113d127b Rename NonSlidingAttacksBB[] in StepAttacksBB[]
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-03-10 08:10:26 +01:00
Marco Costalba c2511243b4 Update copyright notes in rkiss.h
New info after a thread on talkchess:

http://www.talkchess.com/forum/viewtopic.php?t=38313

and some emails exchange with Heinz.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-03-10 08:08:34 +01:00
Marco Costalba d85cf6d9c3 Revert previous patch due to miscompile under gcc
I need to understand what's going on, in the
meantime revert.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-03-10 08:08:04 +01:00
Marco Costalba a617b03875 Change initialization of some bitboards
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-03-08 19:44:19 +01:00
Marco Costalba c980163316 Increase MAX_THREADS to 32
No speed regression after 8731 games:
Mod vs Orig 1394 - 1342 - 5995  ELO +2 (+- 4.1)

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-03-08 13:16:33 +01:00
Marco Costalba 76506bd3d1 Introduce and use rot() in rkiss.h
Also fix indentation.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-03-07 19:04:54 +01:00
Marco Costalba 9069193125 Simplify aspirationDelta update rule
After 7522 games:
Mod vs Orig 1229 - 1148 - 5145  ELO +3 (+- 4.5) LOS 83%

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-03-02 22:01:30 +01:00
Marco Costalba 0c775fae4b Be sure to read options before to call trace_evaluate()
Otherwise in case we change an option with setoption and
then ask for "eval" command the evaluation is not updated.

Spotted by Justin Blanchard.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-03-01 13:32:42 +01:00
Marco Costalba 1f73a9ed63 Fix aspiration corner case
Fix a corner case where we start aspiration window and
suddendly we get a VALUE_KNOWN_WIN / MATE score, this makes
aspiration to blow up in a series of researches loops.

Exit aspiration loop in that case.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-02-28 20:17:57 +01:00
Marco Costalba af236373cb Remove a FIXME in id_loop()
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-02-28 20:16:22 +01:00
Marco Costalba ce2845d333 Score root move list during first iteration
Use first iteration to get a proper startup score
and possibly detect an easy move.

After 5180 games:
Mod vs Orig 847 - 823 - 3510  ELO +1 (+- 5.5)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-02-28 07:51:28 +01:00
Marco Costalba 204efb109b Remove an useless condition in equal SEE pruning
Because we are never in check there and evaluation cannot
return a mated value the condition is useless.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-02-27 09:45:54 +01:00
Marco Costalba 91a2766308 Prune moves with equal SEE in qsearch
After 5166 games:
Mod vs Orig 890 - 762 - 3514  ELO +8 (+- 5.5) LOS 96%

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-02-27 09:19:59 +01:00
Marco Costalba bd33766da0 Add evaluation tracing code
This patch is based on Justin Blanchard's original
work and allows to breakdown evaluation in its sub terms and
show to the user.

Tracing code has zero speed impact when not used.

Note that tracing code is not thread-safe, but this
should not be a problem given the typical usage scenario.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-02-26 14:26:27 +01:00
Marco Costalba dd718d92a7 Correctly round evaluation to grain size
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-02-23 23:52:51 +01:00
Marco Costalba 23cbb221b2 Depth dependant singular extension margin
After 7965 games:
Mod vs Orig 1324 - 1249 - 5392  ELO +3 (+- 4.4) LOS 81%

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-02-23 23:51:20 +01:00
Marco Costalba 0fcda095df Move all enum types definitions to types.h
Cleanup headers while there.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-02-23 21:52:55 +01:00
Marco Costalba 95212222c7 Retire color.h
Move contents to piece.h and square.h

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-02-23 18:42:45 +01:00
Marco Costalba 2ff2b59727 Rename piece_of_color_and_type() to make_piece()
To be aligned with make_square()

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-02-23 18:42:35 +01:00
Marco Costalba 5b2ac7590c Retire piece_type_from_char()
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-02-23 18:42:27 +01:00
Marco Costalba 2511386155 Triviality in main.cpp
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-02-23 18:41:58 +01:00
Marco Costalba deb212cb05 Retire enum SquareDelta
Use Square instead. At the end is the same because we were
anyway foreseen operators on mixed terms (Square, SquareDelta).

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-02-23 18:41:35 +01:00
Marco Costalba aa40d0a917 Small simplifications in square.h
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-02-23 18:41:27 +01:00
Marco Costalba b3108547de Introduce and use speed_to_uci()
And retire nps()

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-02-19 13:31:35 +01:00
Marco Costalba 706b44a966 Rename SplitPoint parentSstack
Now that we don't have anymore a search stack array in
SplitPoint we can rename this data member to somthing more
usual.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-02-18 17:04:55 +01:00
Marco Costalba 823a5918e7 Retire SearchStack sstack[] from SplitPoint
Use a local variable instead. To make it work we need to
correctly init next ply search stack at the beginning of the
search because now that ss is allocated on the stack instead
of on the global storage it contains garbage.

As a side effect we can peform a fast search stack
init in id_loop().

With this patch size of SplitPoint goes from 71944 to 136 bytes,
and consequently size of Thread goes from 575568 to 1104 bytes.

Finally the size of ThreadsManager that contains all the thread
info goes from 9209248 to just 17824 bytes !!

No functional change also in faked split.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-02-18 16:54:49 +01:00
Marco Costalba 932ae761c6 Sync Root new depth to what we do in search()
This allow us to restore the old depth 12 benchmark
and fixes one and for all the depth mess.

Test confirms no regression:
After 5658 games 892 - 924 - 3842  ELO -1 (+- 5.2)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-02-18 11:24:42 +01:00
Marco Costalba 29fa6f3c5f Unify best move update logic
Try to rewrite the Root case using as most as common
code as possible.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-02-17 09:51:22 +01:00
Marco Costalba 5815718177 Do not special case reductions for MultiPV case
Note that this introduces an asymmetry in which best move
is searched deeper then others also in MultiPV, but this is
not an error per se.

No functional change when MultiPV = 1

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-02-17 09:08:27 +01:00
Marco Costalba 6a19f5832a Avoid permanent PV entries in TT
This patch removes a condition that allows a PV entry to remain
in TT across games for an unlimited time.

Although this produces a nice ELO boost in the long term it
is an artifact that affects tests results bewteen version
with and without this feature.

So remove now and readd before to release because it actually
seems a strong feature.

As example a verification tournament against SF 2.0.1 starting around
+10 ELO after 4K games sligltly climbed to +21 ELO after 14K games !!!

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-02-16 08:57:35 +01:00
Marco Costalba 4ead60e2a7 Write the LogFile only at the end of an iteration
Skip writing fail high/low sequences. Note that we don't need
fail high/low markers anymore in pretty_pv().

No functional change but some do/undo move sequences.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-02-13 11:45:49 +01:00
Marco Costalba 2786aed195 Spell checking fixes in search.cpp
Reported by Eelco on open-chess.org

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-02-12 19:06:07 +01:00
Marco Costalba 876ceb1feb Rename iteration in depth in id_loop()
And retire the redundant one.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-02-12 18:53:02 +01:00
Marco Costalba 29076043e0 Start to count iterations from 1
First search should be done at iteration = 1, not 2. So offset
the variable by one.

As a nice side effect now search correctly stops at PLY_MAX
included, not after searching (PLY_MAX - 1) as before.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-02-12 18:17:37 +01:00
Marco Costalba aa84731fb9 Fix wrong reported depth
Interestingly this patch will make people complain search depth
is reduced against 2.0.1 ;-) but actually it is only an artifact.

Spotted by Joona.

No functional change apart from a different do / undo move
sequence due to teh fact that we don't call pv_info_to_uci()
anymore before entering id loop.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-02-12 17:58:25 +01:00
Marco Costalba c006435bb4 Move sending of PV line to id_loop()
No functional change apart form move reordering because
pv_info_to_uci() performs a do / undo_move sequence.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-02-11 06:28:55 +01:00
Marco Costalba 141410f177 Maximum aspiration delta of 24
After 9080 games
1430 - 1342 - 6308  ELO +3 (+- 2.9)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-02-10 21:09:20 +01:00
Joona Kiiski 3abff79df3 Maximum aspiration delta of 64
After 9242 games
Mod vs Orig: 1483 - 1373 - 6386  ELO +4 (+- 2.9)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-02-09 23:52:24 +01:00
Marco Costalba 62c707e1d5 Simplify latest patches
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-02-06 12:41:47 +01:00
Joona Kiiski 26e7673c18 Retire some conditions from ok_to_use_TT_pv
After 4844 games 768 - 747 - 3329  ELO +2

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-02-05 11:06:08 +01:00
Marco Costalba b366c7dc38 Use TT for pruning also in PV nodes
Biggest advantage is be able to analize positions
without "loss of memory" when goind back/forth in
a position.

Patch has proven to fix analysys problems and is even
worths some elo points.

After 5811 games Mod- Orig:
1037 - 902 - 3872 +8 ELO  (+- 3.6) LOS 97%

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-31 13:07:26 +01:00
Marco Costalba 2f6788104f Silence silly MSVC warning c4146
Warning C4146: unary minus operator applied to
unsigned type, result still unsigned.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-29 14:10:05 +01:00
Marco Costalba 69726f4df3 Remove defined(IS_64BIT) in init_sliding_attacks()
No functional change bith in 32 and 64 bits.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-29 14:06:29 +01:00
Marco Costalba f3e0b32def Do not use <algorithm> in to_fen()
Seems there are some problems on HP-UX compiler.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-29 13:28:00 +01:00
Marco Costalba 188700d7f1 Retire obsolete reentrancy check in pos.print()
We dont' call MovePicker from print() anymore, so that
reentrancy check in now not needed.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-29 12:17:47 +01:00
Marco Costalba 9ba7f701ea Retire singleEvasion
This let us get rid of number_of_evasions()

After 5487 games
Mod- Orig: 851 - 852 - 3784 +0 ELO  (+- 3.7)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-27 07:55:04 +01:00
Marco Costalba afae86bfb4 Add a MovePicker c'tor specialized for qsearch
This simple patch shows a speed increase of
more then 2% !

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-23 23:13:14 +01:00
Marco Costalba f352008958 Introduce and use qsearch_scoring()
Move qsearch scoring functionality out of RootMoveList
initialization. Will be needed by future patches.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-23 10:54:16 +01:00
Marco Costalba 6849f0800e Retire InitialDepth
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-23 10:52:51 +01:00
Marco Costalba 5194b2bb06 Pass TT move instead of Rml[0].pv[0] to MovePicker
This is used for secondary scoring so it does not
changes the fact that Rml[0].pv[0] is always tried
as first anyhow.

It happens this is even a no functional change patch
becuase we reinsert PV in TT after a search so that
TT move is actually Rml[0].pv[0].

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-23 09:11:31 +01:00
Joona Kiiski a8f457d425 Different searchedMoves system
After 8751 games on russian cluster
Mod- Orig: 1426 - 1323 - 6002  ELO +4 (+- 2.9) LOS 86%

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-23 08:36:47 +01:00
Marco Costalba 79b1a7417f Remove special Root cases
So to better spot where the differences really
count. Also add some more additional cleanup.

Harmless functional change and no regression.

After 5780 games
Mod- Orig: 931 - 955 - 3894 ELO -1 (+- 3.6)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-23 08:36:12 +01:00
Marco Costalba b67de36671 Retire init_ss_array()
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-20 19:34:25 +01:00
Marco Costalba 59c85346d2 Small cleanup in init_sliding_attacks()
No functional change both in 32 and 64 bits.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-19 19:50:44 +01:00
Marco Costalba e8f885145b Numbers formatting in bitboard.cpp
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-19 19:50:32 +01:00
Marco Costalba 324ca87aff Use opposite_color_squares() instead of same_color_squares()
It is almost alwasy the requested test and is a bit faster too.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-19 13:50:51 +01:00
Marco Costalba 4f3fe89fb6 Retire RelativeRankBB[]
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-19 13:33:38 +01:00
Marco Costalba 45acec1865 Retire some unused functions in bitboard.h
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-19 13:33:26 +01:00
Marco Costalba a38b14bd33 Fix some warnings under icc
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-18 18:53:19 +01:00
Marco Costalba d91d6da3c4 Sort root moves moves in MovePickerExt
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-18 18:52:52 +01:00
Marco Costalba 5bad5fc0a7 Fix a (bestValue == -VALUE_INFINITE) assert
In case of a Root node we can leave with bestValue set
to -VALUE_INFINITE if search is stopped by the GUI and
stopReques flag is raised.

This patch fixes the issue.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-18 13:30:13 +01:00
Marco Costalba 6119e4ea37 Additional cleanup in id_loop()
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-18 13:30:13 +01:00
Marco Costalba 5555b60b38 Use a global RootMoveList object instead of a pointer
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-18 13:30:12 +01:00
Marco Costalba 846087e4fb Move globals to id_loop()
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-18 13:30:11 +01:00
Marco Costalba 2e2f1064ba Introduce and use MovePickerExt
A bit of template magic to restore a proper and readable moves
'while' loop that now is again 'similar' to the one that used
to be in search().

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-18 13:30:11 +01:00
Marco Costalba 392c7f2ab6 Unify root_search() step 3
Retire root_search()

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-18 13:30:10 +01:00
Marco Costalba 6b8026806c Unify root_search() step 2
Enable the change: now we use search() instead of root_search()

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-18 13:29:57 +01:00
Marco Costalba 299bda9ea3 Unify root_search() step 1
Teach search() to behave as a root node if requested.
Just added code, but still no functional change.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-18 13:28:34 +01:00
Joona Kiiski 998845763a Fix very theoretical History corner case
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-17 20:22:10 +01:00
Marco Costalba 842efefcad Sync root_search() with search()
This will let unification easier.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-16 13:45:34 +01:00
Marco Costalba c17a127c42 Move fail loops out of root_search() to id_loop()
And sync root_search() with search()

After 9384 games Mod - Orig:
1532 - 1433 - 6419  ELO +3 (+- 2.8)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-16 13:45:23 +01:00
Marco Costalba e06c99cad0 Last touches in history.h
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-15 18:03:43 +01:00
Marco Costalba 04001f776e Fix a warning with __popcnt64() intrinsics
Returns an int64_t while we want a simple int.

This occurs only when compiling with MSVC on a 64 bit platform.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-15 12:05:31 +01:00
Marco Costalba 877b468e3e Partially restore HistoryMax
Should be not useful but better safe than sorry.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-15 11:31:14 +01:00
Marco Costalba 13a42284b6 Move Min() and Max() macros to types.h
As usual a bit of cleanup while there...

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-15 11:00:00 +01:00
Marco Costalba 3bb1ab34e4 Clarify we want Score and Value to be integers
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-15 10:37:36 +01:00
Marco Costalba 7faeab0878 Retire history.cpp
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-15 10:02:45 +01:00
Marco Costalba 2052407090 Retire HistoryMax
Infact we don't use it anymore already.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-15 09:30:39 +01:00
Joona Kiiski d6fdd4f6d9 Set HistoryMax infinitely high
Respin this old idea. Earlier we tried only
with < 1000 games and result was inconclusive.

After 5845 games
Mod vs Orig: 935 - 936 - 3974 ELO (+-3.6)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-14 19:13:22 +01:00
Marco Costalba b85bcc039c Simplify from_fen()
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-14 12:56:31 +01:00
Marco Costalba 62cd133b3a Initialize killers at ss+2 also in root_search()
After 4955 games:
Mod - Orig: 786 - 768 - 3401 +1 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-14 07:27:06 +01:00
Marco Costalba 6442981cb6 Fix an hang on 32 bits while allocating big TT table
If size_t is defined as a 32 bit quanitity then we have an
overflow in the left term of the while condition if mbSize
is bigger then 2048.

For instance if mbSize is 2049 then when newSize will reach
0x80000000 (2048MB) comparison is still true, 'while' loops
again and we have an overflow in the expression (2*newSize)
so that result is 0 and at that point 'while' keeps looping
forever hanging the application.

This patch fixes the bug and also makes operator new do not
throw an exception upon failure but return a NULL pointer
instead.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-13 22:03:18 +01:00
Marco Costalba d4b92ae9a0 Set unbuffered I/O also for C standard library
In input_available() we use function select(), so
we have to set as unbuffered also C library I/O
functions otherwise we can miss some input.

For instance in case GUI sends "go infinite\nstop\n" we
parse the "go infinite" but then input_available() under Linux
is unable to detect that we still have "stop" to be processed.

This is because "select" uses file descriptors instead of file
pointers. So it cannot know about the buffer associated to a file
pointer.

This patch, by BB+, should fix the problem.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-11 18:58:56 +01:00
Marco Costalba 611a29f767 Big book.cpp cleanup
Better document PolyGlot formats and greatly
reduce line count.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-10 19:55:02 +01:00
Marco Costalba d84ffc0cfa Compile fix in types.h
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-10 12:54:08 +01:00
Marco Costalba caa02b0e43 Small cleanup in execute_uci_command()
With a little fall out in siblings functions...

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-09 16:24:30 +01:00
Marco Costalba a8741bd59f Simplify set_option()
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-09 15:15:52 +01:00
Joona Kiiski 06c14d0a37 TTEntry simplification
Now that move is fitted in 16 bits we can simplify TTEntry.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-09 13:20:04 +01:00
Marco Costalba 15153a1de7 Don't copy Position in pretty_pv()
Also let do_setup_move() don't reuse same StateInfo so that
we can remove the check about different StateInfo objects
before memcpy() in do_move.

Functional change due to harmless additionals
do_move() / undo_move() steps.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-09 12:55:22 +01:00
Marco Costalba c89762288b Merge line_to_san() into pretty_pv()
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-08 18:31:14 +01:00
Marco Costalba b4acf83704 Ressurect move.cpp
Actually it is san.cpp renamed. Because now has the move
conversions functions and doesn't have any more the bulky
move_from_san(), it is better to call it move.cpp

Remove san.h while there.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-08 17:52:02 +01:00
Joona Kiiski ee0afea1e5 Fix build failure under Linux
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-08 16:26:55 +01:00
Marco Costalba c82906a2c3 Retire move_from_san()
It is unused and it is big.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-08 16:23:46 +01:00
Marco Costalba 6b49d509a1 Greatly simplify move_from_uci()
Use a reverse logic: among the list of generated legal moves
transformed in UCI coordinate notation find the one that
matches the given string.

It is a bit slower, but here is not performance critical and
is much more simplified then before.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-08 16:12:42 +01:00
Marco Costalba 82d5386435 Move uci move parsing under san.cpp
This partially reverts 1e7aaed8bc keeping the conversion
functions from/to move to uci string in the same file.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-08 15:53:49 +01:00
Joona Kiiski f4b4d4901c Change Emergency time maximum from 60000 to 30000
I got report from Werner that Shredder Gui has problems with
UCI values which maximum value is greater than 30000.

Of course it's stupid to change engine to fix a GUI's bug,
but on the other hand 30000 ms as maximum value is clearly enough,
so why not to be merciful

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-08 14:27:11 +01:00
Joona Kiiski 8d86e95e37 Fix Makefile's GPL-notice to be similar to other files
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-08 14:26:59 +01:00
Marco Costalba 0f81f97bb6 Improve I/O responsivness
Added checking of (stdin->_cnt > 0) from Greko.

This seems to greatly improve responsivness when running
under console. Now while running a 'stockfish bench', any key
press immediately is detected by SF while before there was a
delay of some fraction of a second.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-08 14:17:41 +01:00
Marco Costalba d9b96f0e49 Fix reading a book under-promotion move
This is an old Glaurung bug that prevented a Polyglot
book move to be read correctly in case of underpromotion.

This patch fixes the bug restoring support for both
queen and underpromotions.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-08 13:23:25 +01:00
Marco Costalba 4fa0395eb8 Triviality in data_available()
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-08 12:53:41 +01:00
Marco Costalba b3545737fa Force inlining of move generation functions
MSVC (and possibly other compilers) does not inline
as requested, so force it to do so.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-07 16:57:15 +01:00
Marco Costalba 44fbbeafc9 Small tweak to generate_castle_moves()
Move the castling condition test out of the
function. This avoids a function call most of
the times.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-07 16:57:14 +01:00
Marco Costalba 57b3ca916f Unify move generation
Functional change due only to moves reorder. Anyhow after
5242 games at 15"+0.1 TC verified we have no regression.

Mod vs Orig 994 - 958 - 3290 +2 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-07 16:56:42 +01:00
Marco Costalba 12f4bbc8f2 Templetize move generation API
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-07 14:46:29 +01:00
Marco Costalba 1e7aaed8bc Retire move.cpp
Move its functions where they belong.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-07 13:40:13 +01:00
Marco Costalba a46b53e1c2 Use 16 bits to store a move instead of 17
Shrink of 1 bit so to fit a move in an uint_16 and
possibly a MoveStack in an uint_32.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-07 12:13:05 +01:00
Marco Costalba dcbc8a7e75 Use a 32 bit bitwise 'and' in SimpleHash lookup
A bit faster on 32 bits machines, more similar to
TranspositionTable::first_entry() and same result.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-07 11:25:13 +01:00
Marco Costalba 0ddf84870a Introduce SimpleHash class
And use it for pawns and material infos.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-07 11:20:49 +01:00
Marco Costalba 803c8e0be3 Small tidy up of inttypes for Windows
There was a strange "int16" type and "int64_t"
was defined twice.

Spotted by Joona.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-06 23:28:06 +01:00
Joona Kiiski fca74b1882 Simplify 50 move rule condition
We never reach a position where rule50 > 100.
When rule50 == 100, it's either draw or mate and
there is no way search could go deeper.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-06 14:46:49 +01:00
Joona Kiiski b08ba446f6 Clean up position setup code
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-06 13:54:03 +01:00
Joona Kiiski 1a20d72701 Parse halfmove clock and fullmove number from FEN
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-06 13:44:11 +01:00
Joona Kiiski 916c0cbfbc Minimal restructuring of value.h
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-06 13:36:02 +01:00
Marco Costalba 2e46db4369 Do not make any assumption on the move in move_is_legal()
We must be able to filter out also moves where move_is_ok()
is false.

And actually we are. Tested on all the default position injecting
a number from -1000000 to 1000000 casted to a Move.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-06 13:33:40 +01:00
Marco Costalba 5fc8f86a4f Change move_is_ok() and square_is_ok() in something useful
As is defined now is always true, tested with:

  for (long i=-1000000; i < 1000000; i++)
      if (!move_is_ok(Move(i)))
          exit(0);

Reason is that move_from() and move_to() already truncate the
input value to something in the range [0, 63] that is always
a possible square.

So change definition to something useful.

The same applies also to square_is_ok()

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-06 10:55:48 +01:00
Marco Costalba c14dae1fa2 Improve update_killers() signature
Will be used by future patches and is cleaner.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-06 09:09:53 +01:00
Joona Kiiski d4ded09e17 Fix variable naming in prototypes at uci.cpp
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-05 23:41:08 +01:00
Joona Kiiski 631fa6a100 Remove a false comment
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-05 23:38:33 +01:00
Marco Costalba dadf6a6fe9 Set moveCount base to 1 as in search()
Now first move has moveCount == 1 also in root_search()

Also added small readibility touches.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-05 23:19:12 +01:00
Marco Costalba 6a5dc14251 Use killers also in root_search()
After 4238 games
Mod-Orig 800 - 686 - 2752 +9 ELO

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-05 23:17:28 +01:00
Marco Costalba 55b16593a4 Perft should return an int64_t not an int
Found by Louis Zulli with his super fast
hardware: 65M nodes/sec at perft !

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-05 21:13:21 +01:00
Marco Costalba 7614501362 Fix POPCNT support for Intel compiler under Windows
Reported by Martin Wyngaarden that also confirmed
this patch to work.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-05 21:12:19 +01:00
Marco Costalba 22ca7a601f Esplicitly inline generate_piece_moves() & friends
Should be already inlined by the compiler when
optimizing but better safe than sorry ;-)

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-05 09:59:20 +01:00
Marco Costalba 97212bafc9 Use 'moveCount' name also in RootSearch
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-04 11:35:54 +01:00
Marco Costalba 07fcc8076d Use -O3 instead of -fast for Linux icc
Reported by Heinz and confirmed by Joona to increase
the speed of 6% !

No change for icc on OSX

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-04 11:12:43 +01:00
Marco Costalba be5b32bb9c Another round of bitboard.cpp cleanups
Also renamed StepAttackBB[] in NonSlidingAttacksBB[]

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-04 11:12:31 +01:00
Marco Costalba 9da1f45b1d Restore development version
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-04 09:55:42 +01:00
Marco Costalba 096351d1f5 Stockfish 2.0.1
Always same siganture: 7224363

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-04 08:24:05 +01:00
Marco Costalba 6b96e6f33d Update Readme and polyglot files
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-03 23:55:12 +01:00
Marco Costalba f200f3ccd2 Another attempt at fixing Chess960
Keep the isChess960 flag inside Position so that is
copied with the Position, but esplicitly highlight the
fact that a FEN string has not enough information to detect
Chess960 in general case. To do this add a boolean argument
isChess960 to from_fen() function so to self document this
shortcoming of FEN notation.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-03 22:50:38 +01:00
Marco Costalba 2bb555025f Revert Chess960 fix
Will be substituted by a better next patch.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-03 22:48:08 +01:00
Tord Romstad d5f2e32b5c Reintroduce the old "trapped bishop in the corner" evaluation term
for Chess960 games.

After 1918 games at 30"
Mod - Orig: 1052-866 (+532,-346,=1040), Elo +33.8
2011-01-03 22:32:57 +01:00
Joona Kiiski 83d8d54216 Use simple macro to enable operators
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-03 22:27:17 +01:00
Marco Costalba 078354060e Workaround broken function-style cast support in HP-UX
It seems HP's ANSI C++ doesn't understand very well
standard function-style cast.

Reported by Richard Lloyd.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-03 11:36:32 +01:00
Marco Costalba 5973e09854 Readd SRWLOCK and Condition Variables under Windows
And set them as default.

Introduce compile switch OLD_LOCKS to allow to fallback on
compatible locks supported by Windows XP and older versions.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-03 10:49:33 +01:00
Marco Costalba 22ede4442c Fix Chess960 regression
Introduced by me in before 1.9 and found by Tord that says:

The 'isChess960' slot in the 'Position' class is currently
set depending on the initial files of the rooks, and not on the value
of the UCI_Chess960 parameter. This is incorrect, as there are lots of
Chess960 positions where the rooks start on the usual files. As a
consequence (unless I am missing something), Stockfish will occasionally
output castling moves as e1g1/e1c1 rather than the correct e1h1/e1a1 format
in Chess960 games. It is possible that some or even most GUIs are robust
enough to accept both notations, but I wouldn't bet on it. And in any case,
Stockfish's behavior clearly violates the protocol.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-03 00:41:39 +01:00
Marco Costalba deee18c758 Another (final?) attempt at squares_delta()
This time I have removed the function alltogether !

Sorry to work above a patch of UncombedCoconut (Justin Blanchard)
but I couldn't resist ;-)

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-02 11:52:51 +01:00
Marco Costalba 0693ff178e Fix old Glaurung bug related to search logging
When we log best and ponder move to a file before to
return from think we change the position. If position is
then not resended by GUI, as for manual user input we got
an error:

justinb@malibu:~$ stockfish
Stockfish 2.0 JA 64bit by Tord Romstad, Marco Costalba, Joona Kiiski
setoption name Use Search Log value true
go depth 1
info depth 1
info depth 1 seldepth 1 multipv 1 score cp 72 time 59 nodes 20 nps 338 pv g1f3
info depth 2
info depth 2 seldepth 2 multipv 1 score cp 12 time 59 nodes 44 nps 745 pv g1f3 g8f6
info nodes 84 nps 1423 time 59
bestmove g1f3 ponder g8f6
go depth 1
info depth 1 score mate 0
info nodes 87 nps 0 time 0
bestmove (none) ponder (none)

Bug spotted and fixed by UncombedCoconut.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-02 11:22:41 +01:00
Marco Costalba 57c51dd1ef Simplify squares_delta()
And rename in ray_direction()

Patch from UncombedCoconut.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-02 10:59:08 +01:00
Marco Costalba f902ddaa89 Fix a crash on multi-pv
Bug reported by Tobias Haspel and fixed by Joona.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-01 23:10:37 +01:00
Marco Costalba 24485df3df Restore development version
And set "Use Sleeping Threads" to true because it keeps
much more responsive and cool my QUAD during tests :-)

It will be reverted back before to release that's the
reason to bundle it here.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-01 16:19:08 +01:00
Marco Costalba aa2de53a83 Stockfish 2.0 (take 2)
Always same siganture: 7224363

Hopefully some more bug fixed and restored
compatibility with WIndows XP.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-01 16:10:30 +01:00
Marco Costalba f826923f8e Don't use SRWLOCK and Condition Variables under Windows
They are not compatible with Windows XP

Revert to old CRITICAL_SECTION locks and events.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-01 16:07:32 +01:00
Marco Costalba 3201a43460 Fix an off-by-one bug in sort_multipv()
Second parameter of insertion_sort() is a pointer to the
element _after_ the last of the list, e.g. end() when sorting
all items.

If we want to sort say the first 2 moves we should write:

sort_multipv(2);

So, becuase in root moves loop move counter 'i' starts
from 0, we need to pass:

sort_multipv(i+1);

To sort up to move 'i' included.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-01 16:07:30 +01:00
Marco Costalba 5405efabcb Remove artificial Iteration >= 3 constraint on time manager
It doesn't seem to have any meaning.

Also add a FIXME on the MaxNodes condition that now is broken
in SMP case due to known issue with pos.nodes_searched()

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-01 16:07:29 +01:00
Marco Costalba 6df86fc9da Fix: Honour UCI "quit" command while still in the book
We were not quitting the engine after a "quit" command
while still in the book and pondering.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-01 16:07:28 +01:00
Marco Costalba 7315001f37 Simplify "ponderhit" handling
If flag StopOnPonderhit is set it means that we UseTimeManagement
and also we are at Iteration >= 3.

So we can safely simplify the formula.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-01 16:07:26 +01:00
Marco Costalba 191662a159 Retire ponderhit()
It is called only from one place, so move code there.

Add a bit of renaming and documentation while at there.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-01 16:07:25 +01:00
Marco Costalba a01df59f5e Restore development version
And set "Use Sleeping Threads" to true because it keeps
much more responsive and cool my QUAD during tests :-)

It will be reverted back before to release that's the
reason to bundle it here.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-01 12:30:03 +01:00
Marco Costalba 9f3c7ded5c Stockfish 2.0
stockfish bench signature is: 7224363

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2011-01-01 11:47:34 +01:00
Marco Costalba df73af30dd Send correct searched nodes statistic
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-12-31 19:47:17 +01:00
Marco Costalba 9394db765f Remove dubious castle detector
It was introduced by patch 66d16592 of 22/3/2009 merging
from Glarurung iPhone.

Tord says:
That change is only found in the Glaurung iPhone app, and not
in the latest Glaurung UCI source code. I don't remember why
this was added (and the iPhone app, unlike the UCI engine,
was never version controlled), but it was almost certainly
because it was somehow needed in the communication between
the engine and the iPhone GUI, and that it was never meant to be
included in the UCI engine. My guess is that it has something to
do with castling moves being entered as e1-g1 in the GUI, but
represented as e1-h1 in the chess engine.

Removing it in Stockfish should be completely safe, and won't harm
the iPhone version. Initially the iPhone GUI called functions in the
chess engine for checking for legality of moves, writing the move
list in SAN format, and various other tasks, but this is no longer
the case in the current version.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-12-31 14:32:25 +01:00
Marco Costalba 4d6258bb32 Implement "seldepth" UCI info
This is the "selective search depth in plies" and we set
equal to PV line length.

Tested that works under FritzGUI.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-12-31 14:27:24 +01:00
Marco Costalba 3e8bb6f63d Retire a couple of unused debug functions
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-12-30 16:44:10 +01:00
Marco Costalba 3835f49aa1 Leave threads go to sleep when waiting for a ponderhit
No need to heat up CPU in this case ;-)

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-12-30 16:18:22 +01:00
Marco Costalba 8e75384dd2 Move printing of best move on think
It seems a more appropiate place (IMHO) and helps to clarify
that idle_loop() should return a move, not a score.

Fix also handling of stalemate positions (we were not
sending any score) and we don't need to wait on "ponderhit",
this is done when returning in think().

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-12-30 16:12:51 +01:00
Marco Costalba db4a68a99b Unify single and multi PV 'new best move' handling
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-12-30 14:03:08 +01:00
Marco Costalba f803f33e63 Move print_pv_info() under RootMove
And rename to pv_info_to_uci()

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-12-30 12:27:59 +01:00
Marco Costalba 6f2e4c006c Better document value_to_uci()
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-12-30 11:46:53 +01:00
Marco Costalba afe0203f98 Standardize root_search() signature
Now pass alpha and beta by copy as in serach()

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-12-30 10:54:33 +01:00
Marco Costalba b01e5fc612 Move extract_pv_from_tt() and insert_pv_in_tt() under RootMove
Functional change only due to additional do/undo move
but absolutly harmless.

Also handle re-insertion in tt of PV lines also for multi PV case.
2010-12-29 15:24:40 +01:00
Marco Costalba d2a4aac53d Use rml[0].pv[] instead of dedicated pv[] array
We have a small functionality change in case we have a
fail-high so that both rml[].pv and pv[] are updated, but if,
after researching, we have a fail-low then rml score is updated
again but pv[] remains the same and coming back from search we
used a PV line that has failed-low (after having failed-high).

With this patch we always use the 'correct' PV line, i.e. the
line with highest score at the end of the whole search.

Retire also redundant RootMove's 'move' member and directly
use pv[0] instead.
2010-12-29 09:22:30 +01:00
Marco Costalba 58c6e64069 Last small touches in RootMoveList
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-12-28 23:10:21 +01:00
Marco Costalba 3346ccc9d9 Retire LMR intermediate research
It does not seem to improve anything.

After 8344 games Mod - Orig:
1362 - 1321 - 5661 ELO +2

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-12-28 18:51:08 +01:00
Marco Costalba 0007b43a91 Use insertion_sort() in RootMoveList
Simplify code and get a bit of extra speed, about +0.5%

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-12-28 18:36:34 +01:00
Marco Costalba 6235904898 Redefine MoveStack comparison as the natural one
Define symbol '<' to mean 'minor of', as it should be. Its meaning
was reversed to be used with std::sort() that sorts in ascending order
while we want a descending order.

But now that we use our own sorting code we don't need this
trick anymore.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-12-28 13:06:53 +01:00
Marco Costalba 5b08494312 Fix broken last patch series
When a reference breaks things !

Here we take a reference (that is a pointer) to an
entry in a vector that changes below us --> BOOM !

References are essential but should be considered with
care in C++ because could lead to nasty surprises.

Restored functionality.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-12-28 13:01:14 +01:00
Marco Costalba 30c14fdc95 Speedup moves root list sorting
Instead of a default member by member copy use set_pv()
to copy the useful part of pv[] array and skip the remaining.

This greatly speeds up sorting of root move list !

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-12-27 13:55:34 +01:00
Marco Costalba e8b5420300 Use a std::vector to store root moves
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-12-27 13:10:32 +01:00
Marco Costalba 12eb27b6e9 Rename RootMoveList members removing 'move'
It is redundant being a move list ;-)

Also better document the two scores used by root list.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-12-27 11:36:57 +01:00
Marco Costalba e7ab3a0d16 Retire DirectionTable[]
With this patch even word 'direction' is disappeared !

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-12-27 03:08:10 +01:00
Marco Costalba 4dded4e72f Retire direction.cpp
Move the code to bitboard.cpp

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-12-26 16:51:21 +01:00
Marco Costalba cb7f20913e Retire enum Direction
Use SquareDelta instead

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-12-26 16:17:51 +01:00
Marco Costalba f08a6eed0d Retire SignedDirectionTable[] and RayBB[]
Function ray_bb() was used just in one endgame where can
be used squares_in_front_of() instead.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-12-26 12:12:58 +01:00
Marco Costalba 6080fecf9c Retire direction.h
Move all to square.h

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-12-26 10:58:52 +01:00
Marco Costalba 94a67c49b0 Simplify enum SquareDelta definition
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-12-26 10:43:22 +01:00
Marco Costalba 0a73a23dc9 Unify MovePicker c'tor call
And use the standard one.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-12-25 18:03:43 +01:00
Marco Costalba a0f0a7dc4f Use generate_moves() in san.cpp
Instead of MovePicker and cleanup san.cpp

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-12-25 17:54:08 +01:00
Marco Costalba 61c03b9d22 Ignore two braindamaged remarks under icc
Remark 1418: external function definition with no prior declaration

and

Remark 1419: external declaration in primary source file

Can be safely ignored because are pure idiocy.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-12-25 09:16:30 +01:00
Marco Costalba dee8780829 Renamed thread_should_stop() in cutoff_at_splitpoint()
It is more clear what happened.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-12-25 00:11:53 +01:00
Marco Costalba d40a12f948 Simplify a condition in update of best move
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-12-24 17:09:39 +01:00
Marco Costalba f97c5b6909 Triviality in struct PieceLetters
And little touches in search() too.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-12-24 16:58:25 +01:00
Marco Costalba d55a5a4d81 Better clarify how we use TT depth in qsearch
Namely we use only two types of depth in TT:
DEPTH_QS_CHECKS or DEPTH_QS_NO_CHECKS.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-12-18 11:19:31 +01:00
Marco Costalba 201e8d5f87 Second cleanup wave on check_is_useless()
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-12-18 10:20:15 +01:00
Joona Kiiski 47f5560e2d Let check_is_useless() follow SF coding style
No functional change

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-12-14 18:57:22 +01:00
Tord Romstad cf85ffbb97 Fixed a bug in move_from_uci(): En passant captures were not handled
correctly.
2010-12-14 12:07:37 +01:00
Joona Kiiski 6596dc9516 Selective checks at qsearch
After 5821 games
Mod- Orig:  1014 - 869 - 3938 ELO +8 (+- 3.6) LOS 97%

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-12-14 07:50:37 +01:00
Marco Costalba 6afcfd00f2 Retire uci_main_loop()
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-12-13 20:38:41 +01:00
Marco Costalba 2d63f2157e Small cleanup in uci.cpp
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-12-13 20:29:40 +01:00
Marco Costalba 56de5ae561 Retire square_from_string()
And rename move_from/to_string() in a more specific
move_from/to_uci() that is a simple coordinate notation.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-12-13 20:29:38 +01:00
Marco Costalba 556b63b6b6 Move the last multi-threads globals to ThreadsManager
Also rename ThreadsManager memeber data to be lower case.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-12-13 07:30:59 +01:00
Marco Costalba 4ad03c9bad Further reduce sleep lock contention
Use one sleep lock per thread insted of a single one shared.

Also renamed WaitLock in SleepLock.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-12-13 07:30:59 +01:00
Marco Costalba dedc6d7588 Allow threads to sleep when available
By mean of an an UCI option it is possible let the available
threads to sleep, this should help with Hyper Threading although
is not the best solution when number of threads equals number
of available cores.

Option is disabled by default.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-12-11 09:22:38 +01:00
Marco Costalba 38e7ec3e44 Increase MAX_THREADS to 16
No speed regression and no functional change.

After 7826 games Mod- Orig:
1188 - 1230 - 5408 ELO -1 (+- 3.1)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-12-10 07:24:48 +01:00
Marco Costalba 421f7b74c6 Increase PV LMR to SF 1.8 levels
Non-PV LMR is left unchanged.

After 8819 games
Mod- Orig:  1442 - 1343 - 6034 ELO +3 (+- 2.9) LOS 86%

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-12-07 13:13:06 +01:00
Marco Costalba 0da461f23b Various cleanups in Position's ancillary functions
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-12-06 18:01:18 +01:00
Marco Costalba 97a6e1559e Fix a crash due to a broken Book::open()
Bug introduced in 9dcc2aad98

We can be asked to open a non-exsistent file,
in this case we should gracefully handle the
case and silently return instead of exiting.

Bug discovered and bisected down by Joona.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-12-05 09:24:18 +01:00
Joona Kiiski 8a858aea34 New try for unstoppable pawn evaluation
This time we try very hard to avoid false positives.
The obvious downside is that we also miss many true
winning positions.

After 10544 games on RC
Mod- Orig:  1744  - 1646 - 7154 ELO +3 (+- 2.7) LOS 83%

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-12-04 09:07:45 +01:00
Marco Costalba 03dd1d3c13 Allow razoring after a null move
After 8322 games on Russian Cluster
Mod- Orig:  1341 - 1281 - 5700 ELO +2 (+- 3) LOS 75%

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-12-04 09:04:54 +01:00
Joona Kiiski 5529706426 Prune all negative see moves at low depths
After 2036 games Mod- Orig:
381 - 278 - 1377 ELO +17 (+- 6.2) LOS 99%

One of the biggest increases ever !

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-12-02 07:42:18 +01:00
Marco Costalba 6ed409ecee Fix bestmove output in multi PV case
When MultiPV > 1, always take bestmove from the RootMoveList
(and don't bother with a ponder move). Without that the bestmove
is most probably incorrect.

Patch from Peter Petrov.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-11-28 17:05:49 +01:00
Marco Costalba 200fc56e9c Fix 'generation' type to uint8_t
When we store this value in TT we cut this to 9 bits,
so we need a smaller variable otherwise comparisons
like:

   replace->generation() == generation

Are always false if generation is bigger then the maximum
TT storable value.

This fixes a very nasty and difficult to spot bug (2 weeks for
regression hunting).

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-11-28 17:01:01 +01:00
Marco Costalba d0dc05ad41 Revert sleeping threads
Revert 141caf1d5b + c59efc53c9

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-11-27 21:26:00 +01:00
Marco Costalba 9ecdfd2401 Revert "Allow split point master to sleep (take 2)"
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-11-27 21:25:59 +01:00
Marco Costalba 5d6b2f2144 We don't need a stringstream in buildKey()
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-11-23 13:01:11 +01:00
Marco Costalba efeb37c33f Retire Application class
It is a redundant boiler plate, just call initialization and
resource release directly from main()

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-11-22 18:36:18 +01:00
Marco Costalba 00d9fe8af0 Retire piece.cpp
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-11-22 13:13:48 +01:00
Marco Costalba 85df24624a UCI options names should not be case sensitive
Correctly handle uci option names in a case insensitive way.

Alos fix some indentation while there.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-11-21 23:52:51 +01:00
Marco Costalba f44aea7508 Retire "New Game" UCI option
Was introduced by 403db5a6e9
on 1/12/2009 to correctly handle "loose on time"
LSN filtering functionality, but is now unused.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-11-21 14:25:30 +01:00
Marco Costalba fa80479b1d Remove hardcoded 16 from benchmark default positions size
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-11-21 13:06:53 +01:00
Marco Costalba df6ba1fa5c Micro-optimize pl_move_is_legal()
This L1/L2 optimization has an incredible +4.7% speedup
in perft test where this function is the most time consumer.

Verified a speed up also in normal bench, although smaller.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-11-21 12:49:16 +01:00
Marco Costalba f57d51b7f3 Store "true" and "false" in bool options
UCI protocol uses "true" and "false" for check and button types,
so store that values instead of "1" and "0", this simplifies a
bit the code.

Also a bit strictier option's type checking in debug mode.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-11-20 18:06:38 +01:00
Marco Costalba 358ccf206b Debug counters don't need to be global
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-11-20 11:48:04 +01:00
Marco Costalba 24e6ed907b Small touches to engine_name()
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-11-19 23:57:11 +01:00
Marco Costalba bdfd656c24 Use occupied_squares() in book_key()
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-11-16 19:28:09 +01:00
Marco Costalba d08a8d76f7 Rearrange pawn moves generation
This patch greatly cleanups generation of pawn moves but
we change the order in which moves are generated so there is
a change in functionality, but not in perft.

The only real functionality change is that now when type == CHECK
we generate knight underpromotion captures only if give check and
not always as before.

Perft is 2% faster and fully verified.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-11-16 13:43:05 +01:00
Marco Costalba 6f70e762a9 Introduce generate_promotions()
A bit ugly to guarantee no functional change.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-11-16 13:02:52 +01:00
Marco Costalba b36900ef44 Simplify generate_pawn_captures()
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-11-15 18:58:15 +01:00
Marco Costalba a1c02815cc Cleanup Bioskey()
And rename in dataAvailable()

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-11-15 18:58:00 +01:00
Marco Costalba 660378d10e Let bench to have full defaults arguments
Now stockfish bench' defaults to

stockfish bench 128 1 12 default depth

that is the most used line (at least by me)

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-11-09 05:05:08 +01:00
Marco Costalba 9dcc2aad98 Various cleanup in book.cpp
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-11-08 18:51:42 +01:00
Marco Costalba fad595f5b6 Let benchmark to default to depth 12
And also simplify a lot the code.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-11-08 13:53:44 +01:00
Marco Costalba d2d953713f Move PieceValue[] and SlidingArray[] where they belong
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-11-08 13:18:18 +01:00
Marco Costalba c28b9ef182 Allow split point master to sleep (take 2)
Let to sleep even split point master, it will be waken
up by its slaves when they return from the search.

This time let it be enabled by an UCI option, so
people is free to test it on their Hyper Thread box.

Option is disabled by default.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-11-07 23:51:09 +01:00
Marco Costalba da6e2b5fd1 Use namespace in position.cpp
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-11-07 13:51:03 +01:00
Marco Costalba b06f0460a2 Retire uci.h and benchmark.h
Moved the single prototipes where are needed.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-11-07 13:31:33 +01:00
Marco Costalba d2ad5acddd Object OpeningBook doen't need to be global
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-11-07 13:12:48 +01:00
Marco Costalba 4cd53b68d0 Make rkiss seed deterministic
Search at fixed depth with one thread must be
reproducible so remove randomess from time().

Also better license description.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-11-07 12:48:23 +01:00
Marco Costalba 8fb16df70e Let rkiss.h to follow SF coding style
Fix also Makefile after mersenne.cpp has been removed

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-11-07 12:22:15 +01:00
Marco Costalba f5e28ef512 Use Heinz's RKiss instead of marsenne
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-11-07 11:52:59 +01:00
Marco Costalba 287556f97d Fix an off by one bug in print_uci_options()
Last option was not printed.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-11-07 10:53:31 +01:00
Marco Costalba 469e7c5143 Retire bitbase.h
Moved the only prototipe where is needed.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-11-07 10:53:19 +01:00
Marco Costalba bacb645939 Rewrite options handling in an object oriented fashion
Big rewrite and about 100 lines removed.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-11-05 06:10:05 +01:00
Marco Costalba fb50e16cdd Retire push_button() and button_was_pressed()
Directly access the underlying bool option.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-11-03 13:19:55 +01:00
Marco Costalba 9f626725ae Prefer int to uint8_t when possible
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-11-01 13:17:01 +01:00
Marco Costalba cfca92cd7c Add "mingw" compiler to Makefile
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-11-01 12:17:54 +01:00
Marco Costalba d607febb38 Fix MinGW warnings
I finally got SF to compile under MinGW (after adding pthread libraries)
and here are the fixed warnings.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-11-01 11:44:46 +01:00
Marco Costalba 19cf779629 Allocate RootPosition on the stack
And pass it as an argument.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-31 11:53:49 +01:00
Marco Costalba d74025a34e Update nodes after a do_move()
And also store the node counter in Position and not in Thread.
This will allow to properly count nodes also in sub trees with
SMP active.

This requires a surprisingly high number of changes
in a lot of places to make it work properly.

No functional change but node count changed for obvious reasons.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-31 11:22:40 +01:00
Marco Costalba 49a6fee4fa Fix some icc's "statement is unreachable" warnings
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-30 19:19:40 +01:00
Marco Costalba 2991ff0dc2 Move moveCount update near the SpNode case
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-30 18:26:41 +01:00
Marco Costalba c416133e2f Introduce and use TranspositionTable::refresh()
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-30 15:22:10 +01:00
Marco Costalba ff95bbd41f Use margins[] array in evaluate
It will be used by future patches.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-30 14:24:19 +01:00
Marco Costalba 2d7a417d0a More readable search/qsearch dispatch
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-30 12:32:38 +01:00
Marco Costalba f790752daa Fix last leak detected by Valgrind
This was subtle and google was my friend.

The leak was in _dl_allocate_tls called by pthread_create() and
is due to the fact that threads are created in joinable state so that
once terminated are not freed. To make the thread to release
its resources upon termination we should set them in detached state.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-24 09:57:30 +01:00
Marco Costalba 5254ca22f3 Fix a memcpy() warning under Valgrind
Fix warning: "Source and destination overlap in memcpy"

This happens when we call multiple time do_move() with the
same state, for instance when we don't need to undo the move.

This is what valgrind docs say:

You don't want the two blocks to overlap because one of them could
get partially overwritten by the copying.

You might think that Memcheck is being overly pedantic reporting this
in the case where 'dst' is less than 'src'. For example, the obvious way
to implement memcpy() is by copying from the first byte to the last.
However, the optimisation guides of some architectures recommend copying
from the last byte down to the first. Also, some implementations of
memcpy() zero 'dst' before copying, because zeroing the destination's
cache line(s) can improve performance.

In addition, for many of these functions, the POSIX standards have wording
along the lines "If copying takes place between objects that overlap,
the behavior is undefined." Hence overlapping copies violate the standard.

The moral of the story is: if you want to write truly portable code, don't
make any assumptions about the language implementation.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-24 09:56:57 +01:00
Marco Costalba 5b445cdf59 Revert previous patch
It seems we have a speed regression under Linux, anyhow
commit and revert to leave some documentation in case we
want to try again in the future.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-24 09:53:19 +01:00
Marco Costalba 96e589646d Allow split point master to sleep
Let to sleep even split point master, it will be waken up
by its slaves when they return from the search.

With this patch we get maximum HT speedup

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-23 13:50:54 +01:00
Marco Costalba c81bf3743f Re-add "Pass evalMargin through SearchStack as eval"
It has more sense to treat the two evaluation metrics
in the same way.

As a side effect now we use the correct eval margin when
pruning in a SplitPoint node.

No functional change in single thread.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-23 08:07:26 +01:00
Marco Costalba f6e11ee2a3 Finally retire sp_search()
Fix the movcount updating bug and let search() to completely
subsititute sp_search().

No functional change even with fakes split.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-23 07:51:35 +01:00
Marco Costalba 65606bc49e Temporary restore old sp_search()
There is a bug in the conversion that is triggered when testing
with faked split and that I missed somehow :-(

To allow proper testing on cluster restore old sp_search()
until I don't fiugre up what's happened.

Restored to be functional equivalent to old behaviour both in
single thread and in faked split.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-18 08:34:25 +01:00
Marco Costalba 3b7bf34b02 Revert "Pass evalMargin through SearchStack as eval"
Restore full no functional change also in Faked Split mode.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-18 08:19:48 +01:00
Marco Costalba 141caf1d5b Don't wake up /sleep threads in think() anymore
When entering and exiting from think() we don't need any special
wake up / sleeping code because we want available threads to keep
sleeping.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-17 13:12:58 +01:00
Marco Costalba c59efc53c9 Enable sleeping of available threads
This simple patch has devastating consequences ;-)

Now an available thread goes to sleep and is waked up after
being allocated.

This patch allows Stockfish to dramatically increase performances
on HyperThreading systems.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-17 11:38:00 +01:00
Marco Costalba 8fdc635255 Use fast SRWLOCK locks under Windows
They are fast and also have the same semantic of Linux ones.

This allow to simplify the code and especially to use
SleepConditionVariableSRW() to wait on a condition releaseing the lock,
this has the same semantic as pthread_cond_wait().

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-17 11:04:52 +01:00
Marco Costalba 472971f851 Remove some ifdef from wake_sleeping_thread()
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-17 09:35:44 +01:00
Marco Costalba 389edb8099 Retire put_threads_to_sleep()
Obsoleted by previous patches.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-17 09:03:39 +01:00
Marco Costalba 13d8231746 Retire THREAD_SLEEPING and use THREAD_AVAILABLE instead
This is a prerequisite for future work and anyhow removes
a state flag, so it is good anyhow.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-17 08:59:07 +01:00
Marco Costalba 9440fb06da Retire AllThreadsShouldSleep flag
It is redundant and complicates the already complicated
SMP code for no reason.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-17 08:39:03 +01:00
Marco Costalba 3a564ed5db Destroy wait conditions before exiting
We already do this for locks. Also rename SitIdleEvent
in WaitCond to be uniform with Lunix naming.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-17 07:36:14 +01:00
Marco Costalba 1fdb436e78 Change thread API to use one wait condition per thread
This is the native way done in Windows and we will use it
for future work, so change Linux to do the same.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-17 08:00:42 +01:00
Marco Costalba dcf2edfdea Do not shadow SplitPoint struct with search() parameter
Also retire move_is_killer() is called only from one place.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-16 15:39:07 +01:00
Marco Costalba 85a7456bd7 Fixed some warnings when using -Weffc++ gcc option
Plus some other icc warnings popped up with new and strictier
compile options.

No functional and speed change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-16 15:00:20 +01:00
Marco Costalba d664773a83 Fix a shadowed variable warning under icc
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-16 15:00:07 +01:00
Marco Costalba f092667460 Retire now obsoleted do_sp_search() trampoline code
We can call search() directly from idle_loop()

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-16 12:20:16 +01:00
Marco Costalba 19ff8e2902 Pass evalMargin through SearchStack as eval
It has more sense to treat the two evaluation metrics
in the same way.

As a side effect now we use the correct eval margin when
pruning in a SplitPoint node.

No functional change in single thread.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-16 11:54:44 +01:00
Marco Costalba a7f4ee7540 Unify sp_search() and search() step 3
Remove old sp_search() code.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-16 11:40:49 +01:00
Marco Costalba f7722d4de7 Unify sp_search() and search() step 2
Modify search() to be able to handle split points

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-16 11:20:43 +01:00
Marco Costalba 37055ad002 Unify sp_search() and search() step 1
Rewrite sp_search() to have same signature of search()

This is the first prerequistite step toward unification.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-16 09:49:45 +01:00
Marco Costalba 79a7647fe0 Pass moveCount by value in split()
Actually it is an error to update back moveCount value after split()
because it is used in update_history() to access movesSearched[]
array. But becasue this vector is not updated in the split point
we end up with an access of stale data.

Bug has been hidden til now because we 'forgot' to update
moveCount before returning from split().

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-12 12:33:44 +01:00
Marco Costalba 00950fec00 Sync sp_search() with search()
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-12 12:19:47 +01:00
Marco Costalba 7c7a77698a Better document some threads functions
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-12 12:11:20 +01:00
Marco Costalba 083ed1ce94 Document an assert in idle_loop()
Thanks to Bruno Causse for the clarification.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-11 19:56:35 +01:00
Marco Costalba 2feeb206ff Use VALUE_DRAW instead of VALUE_ZERO where better
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-10 09:05:46 +01:00
Marco Costalba 5dfbbb79be Use do_move_bb() in move_attacks_square()
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-10 08:32:12 +01:00
Marco Costalba d440ddb487 Another cleanup in evaluate_pawns()
Suggested by Marek Kwiatkowski.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-10 08:32:03 +01:00
Marco Costalba 9c9914d72a Micro optimize open files calculation
Committed mostly because is also a cleanup...

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-09 15:22:00 +01:00
Marco Costalba a0474a72a6 Rearrange pawn penalities arrays
A clean up that is also a prerequisite for next patches.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-09 13:43:43 +01:00
Marco Costalba 7733dadfd7 Small codestyle touches
Mostly suggested by Justin (UncombedCoconut), the 0ULL -> 0 conversion
is mine.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-09 13:05:58 +01:00
Marco Costalba 9ca4359f36 Properly set to zero stuff returned by 'new'
Language guarantees that c'tor is called, but without any c'tor
it happens to work by accident because OS zeroes out the freshly
allocated pages. The problem is that if I deallocate and allocate
again, the second time pages are no more newly come by the OS and
so could contain stale info.

A practical case could be if we change TT size or numbers of
threads on the fly while already running.

Bug spotted by Justin Blanchard.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-07 03:57:33 +01:00
Marco Costalba f00c976bb2 Retire updateKingTables[]
Suggested by Marek Kwiatkowski.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-06 19:28:27 +01:00
Marco Costalba 1bbbc13b46 Skip ei.kingZone[] initialization together with king safety
Another microptimization by Marek Kwiatkowski.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-05 22:32:53 +01:00
Marco Costalba 1ee1d852fe Skip an useless compare in space evaluation
Spotted by Marek Kwiatkowski.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-05 22:16:09 +01:00
Marco Costalba 812e843939 Restore development version
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-10-05 19:40:49 +01:00
Marco Costalba 71e14bb67b Stockfish 1.9.1
Fix release to workaround chess960 on some GUIs

Signature is:

stockfish bench 128 1 12 default depth

Node counts: 10914593

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

No functional change.

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

ISO C++ forbids braced-groups within expressions

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

No functional and no performance change.

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

Perhaps we will readd with a proper fix...

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

No functional change.

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

No functional change.

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

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

stockfish bench 128 1 12 default depth

Node counts: 10914593

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

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

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

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

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

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

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

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

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

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

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

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

No functional change.

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

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

No functional change.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

No functional change.

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

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

No functional change.

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

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

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

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

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

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

No functional change.

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

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

No functional change.

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

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

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

No functional change.

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

No functional change.

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

No functional change.

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

No functional change.

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

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

No functional change.

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

No functional change.

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

Should be no functional change apart from rounding issues.

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

No functional change.

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

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

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

Unified also outpost bonus tables for knights and bishops.

No functional change.

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

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

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

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

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

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

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

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

No functional change.

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

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

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

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

No functional change.

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

So keep it becuase it allows a good semplification.

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

No functional change.

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

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

No functional change.

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

No functional change.

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

No functional change.

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

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

No functional change.

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

No functional change, zero overhead at runtime.

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

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

No functional change.

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

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

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

No fuctional change.

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

No functional change.

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

No functional change.

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

No functional change.

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

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

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

No fuctional change.

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

Also remove unused DEPTH_ZERO and DEPTH_MAX.

No functional change.

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

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

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

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

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

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

Proposed by Ralph and done with QtCreator

No functional change.

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

Spotted by Ralph Stoesser.

No functional change.

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

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

No functional change.

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

Verified is correct.

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

No functional change.

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

Should be more clear now.

No functional change.

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

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

Also introduce and use TimeManager::available_time()

No functional change.

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

No functional change.

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

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

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

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

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

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

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

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

Suggested by Joona.

No functional change.

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

No functional change.

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

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

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

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

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

All tests show positive score :-)

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

Remark by Ralph Stoesser.

No functional change.

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

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

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

Bugs report and fixes by Marek Kwiatkowski

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

Verified to restore original behaviour.

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

No functional change.

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

Suggested by Tord.

No functional change.

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

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

No functional change.

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

Also some indulge on STL algorithms :-)

No functional change.

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

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

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

No functional change.

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

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

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

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

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

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

No functional change.

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

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

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

Spotted by Ralph Stoesser, fix suggested by Richard Vida.

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

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

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

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

No functional change

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

Also check #include-directives

No functional change

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

No functional change.

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

Idea by Ralph Stoesser.

No functional change.

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

Suggestions by Joona and Ralph.

No functional change.

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

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

Spotted by Ralph Stoesser.

No functional change.

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

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

No functional change

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

No functional change

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

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

No functional change

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

No functional change

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

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

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

Spotted by Marek Kwiatkowski.

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

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

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

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

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

Also additional small cleanup while there.

No functional change.

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

No functional change.

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

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

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

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

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

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

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

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

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

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

No functional change

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

No functional change.

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

No functional change.

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

So revert.

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

No functional change.

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

No functional change.

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

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

No functional change also with faked split.

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

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

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

No functional change on MSVC.

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

Reported by Richard Lloyd

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

log(double(0 * 0) / 2)

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

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

Also fixed some few other warnings.

Bug spotted by Richard Lloyd.

No functional change.

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

No functional change.

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

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

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

Just before the release ;-)

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

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

Spotted by Ralph Stoesser.

No functional change.

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

It works basically like this:

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

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

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

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

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

Spotted by Ralph Stoesser.

No functional change.

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

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

No functional change.

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

Test result for the whole series is:

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

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

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

No functional change.

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

(Almost) No functional change

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

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

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

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

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

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

Original idea by Ralph Stoesser fixed by me.

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

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

Some Movepicker c'tor cleanup while there.

No functional change.

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

No functional change.

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

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

No functional change.

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

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

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

Revert bogus commit.

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

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

No functional change.

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

No functional change.

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

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

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

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

No functional change.

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

No functional change.

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

Also rewritten a bit update_pv()

No functional change.

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

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

No functional change.

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

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

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

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

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

A good semplification of function calling and a speedup too.

No functional change also with faked split.

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

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

No functional change.

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

No functional change also with faked split.

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

No functional change also with faked split.

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

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

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

No functional change tested wit Faked Split.

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

Also a bit of renaming and code shuffle while there.

No functional change.

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

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

Also a small touch at null zugzwang verification.

No functional change.

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

No functional change.

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

No functional change.

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

No functional change.

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

No functional change.

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

No functional change.

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

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

No functional change.

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

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

This bug is a fall down of previous patch.

No functional change.

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

Gives 1% speedup on Intel compiler

No functional change.

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

No functional change.

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

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

No functional change.

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

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

Almost 45% of researches give a different ttMove !

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

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

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

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

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

Space save of 2KB in L1 cache.

No functional change.

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

This is a prerequisite for next patch.

No functional change.

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

No functional change.

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

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

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

Another nitpick report by Marek Kwiatkowski  ;-)

No functional change.

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

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

Spotted by Marek Kwiatkowski

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

Spotted and fixed by Ralph Stoesser.

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

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

No functional change.

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

No functional change

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

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

Constants have been balanced after ~34k iterations.

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

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

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

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

After 922 games at 1+0 with 2 threads

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

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

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

Spotted by Marek Kwiatkowski.

No functional change.

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

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

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

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

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

No functional change.

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

Spotted by Ralph Stoesser.

No functional change.

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

Verified to be equivalent with tuning branch.

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

Patch from Oystein Johansen

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

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

No functional change.

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

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

No functional change.

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

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

No functional change.

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

It is more natural and intuitive in this way.

No functional change.

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

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

No functional change.

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

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

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

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

No functional change.

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

Also removed an useless setting of mateKiller in sp_search()

No functional change (tested with FakeSplit)

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

No functional change.

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

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

No functional change.

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

Also reintroduced some asserts and cleaned up a bit.

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

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

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

No functional change in fake mode

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

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

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

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

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

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

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

No functional change.

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

No functional change.

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

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

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

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

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

No functional and speed change.

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

No functional and speed change.

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

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

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

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

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

No functional change.

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

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

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

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

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

No functional change.

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

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

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

No functional change.

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

Tested at different time controls:

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

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

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

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

A testing marathon by Joona for this important change.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

No functional change.

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

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

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

Also rearranged a bit main() code flow.

No functional change.

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

No functional change.

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

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

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

So revert the idea.

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

No functional change.

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

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

Just introduced the logic, but no functional change.

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

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

No functional change.

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

Also small tweaks in bitboard.h

No functional change.

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

   stockfish bench 128 1 5 default perft

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

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

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

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

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

No functional change.

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

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

No functional change.

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

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

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

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

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

Zugzwang verified on position:

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

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

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

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

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

Feature requested by Salvo Spitaleri.

No functional change.

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

No functional change

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

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

Thanks for Jouni Uski for reporting the problem

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

Warnings reported by Richard Lloyd.

No functional change.

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

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

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

Verified 100% functional equivalent to 1.7

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

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

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

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

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

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

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

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

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

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

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

No functional change.

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

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

Spotted by Richard Lloyd.

No functional change.

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

./stockfish bench 128 1 12 default depth
8299338

./stockfish bench 128 1 13 default depth
15694903

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

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

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

No functional change.

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

A very small increase, if any.

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

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

No functional change.

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

No functional change.

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

This fixes a couple of warnings under MSVC.

No functional change.

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

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

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

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

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

Also small comments tweaks.

No functional change.

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

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

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

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

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

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

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

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

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

No functional change.

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

No functional change.

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

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

No functional change.

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

No functional change.

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

No functional change.

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

No functional change.

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

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

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

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

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

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

No functional change.

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

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

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

No functional change.

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

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

Strangely no functional change, but should be.

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

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

Remaining stuff is triviality and documentation tweaks.

No functional change.

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

No functional change.

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

No functional change.

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

No functional change.

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

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

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

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

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

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

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

No functional change.

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

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

No functional change.

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

No functional change

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

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

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

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

No functional change

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

No functional change

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

No functional change

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

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

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

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

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

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

Also add one FIXME for illogical behaviour

No functional change

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

No functional change

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

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

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

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

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

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

No functional change.

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

No functional change.

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

No functional change.

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

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

No functional change.

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

So revert the patch and come back to single lock.

No functional change.

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

No functional change.

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

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

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

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

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

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

No functional change.

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

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

No functional change and a good semplification.

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

No functional change.

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

No functional change.

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

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

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

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

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

No functional change.

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

It is important the name reflects this.

No functional change.

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

No functional change.

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

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

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

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

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

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

No functional change.

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

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

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

No functional change.

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

No functional change.

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

No functional change.

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

No functional change.

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

- Renamed Idle in AllThreadsShouldSleep

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

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

No functional change.

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

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

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

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

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

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

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

No functional change.

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

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

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

No functional change.

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

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

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

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

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

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

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

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

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

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

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

No functional change.

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

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

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

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

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

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

No real change, just move reordering.

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

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

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

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

This patch restores proper ordering.

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

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

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

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

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

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

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

No functional change.

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

No functional change.

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

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

Bug introduced by 30e8f0c9ad6a473 of 13/02/2009

No functional change.

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

No functional change.

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

No functional change.

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

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

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

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

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

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

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

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

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

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

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

Idea suggested by Richard Vida.

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

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

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

No functional change.

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

No functional change.

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

No functional change.

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

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

No functional change

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

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

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

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

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

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

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

Testing result is very positive.

1CPU:
953-1149

4CPU:
545 - 656

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

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

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

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

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

No functional change.

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

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

in search(), line 1615.

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

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

No functional change.

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

No functional change and big code remove.

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

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

Test results for the whole futility pruning series:

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

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

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

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

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

So remove old dated hack

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

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

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

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

No functional change.

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

Bug spotted by Bruno Causse.

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

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

After 998 games at 1+0

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

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

No functional change.

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

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

Rearrange the last loop to fix this race.

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

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

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

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

No functional change.

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

No functional change.

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

No functional change.

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

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

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

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

No functional change.

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

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

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

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

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

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

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

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

No functional change.

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

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

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

No functional change.

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

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

No functional change.

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

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

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

No functional change.

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

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

No functional change.

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

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

Bug spotted by Bruno Causse.

No functional change (for single CPU case)

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

No functional change

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

No functional change.

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

No functional change.

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

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

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

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

Joona's test results are positive:

32-bit 1CPU:

Mod - Orig: 1073 - 993

64-bit 4CPU:

Mod - Orig: 759 - 721

Functionality Signature: 11448962

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

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

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

No functional change.

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

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

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

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

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

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

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

Bug found by Pascal Georges.

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

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

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

Here are testing results:

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

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

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

This is a 2.0 type change!

After 977 games at 1+0

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

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

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

Functionality Signature: 12581900

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

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

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

Bug fixed by Justin Blanchard

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

No functional change.

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

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

Bug reported and fixed by Justin Blanchard.

No functional change.

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

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

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

Functionality Signature: 16627355

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

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

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

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

Functionality Signature: 17655312

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

No functional change.

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

No functional change.

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

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

No functional change.

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

No functional change.

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

No functional change.

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

No functional change.

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

No functional change.

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

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

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

After 967 games at 1+0

Mod vs Orig 240 529 198 +15 ELO

Functionality Signature: 21222553

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

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-12-30 13:25:21 +01:00
Marco Costalba cf486cf229 Restore development version
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-12-30 13:25:21 +01:00
65 changed files with 7755 additions and 11287 deletions
+13 -15
View File
@@ -3,13 +3,13 @@
Stockfish is a free UCI chess engine derived from Glaurung 2.1. It is
not a complete chess program, but requires some UCI compatible GUI
(like XBoard with PolyGlot, eboard, Jos, Arena, Sigma Chess, Shredder,
(like XBoard with PolyGlot, eboard, Josè, Arena, Sigma Chess, Shredder,
Chess Partner, or Fritz) in order to be used comfortably. Read the
documentation for your GUI of choice for information about how to use
Stockfish with your GUI.
This version of Stockfish supports up to 8 CPUs, but has not been
tested thoroughly with more than 2. The program tries to detect the
This version of Stockfish supports up to 32 CPUs, but has not been
tested thoroughly with more than 4. The program tries to detect the
number of CPUs on your computer and set the number of search threads
accordingly, but please be aware that the detection is not always
correct. It is therefore recommended to inspect the value of the
@@ -41,10 +41,10 @@ This distribution of Stockfish consists of the following files:
3. Opening books
----------------
This version of Stockfish has experimental support for PolyGlot opening
books. For information about how to create such books, consult the
PolyGlot documentation. The book file can be selected by setting the
UCI parameter "Book File".
This version of Stockfish has support for PolyGlot opening books.
For information about how to create such books, consult the PolyGlot
documentation. The book file can be selected by setting the UCI
parameter "Book File".
4. Compiling it yourself
@@ -60,9 +60,12 @@ Stockfish has POPCNT instruction runtime detection and support. This can
give an extra speed on Core i7 or similar systems. To enable this feature
compile with 'make icc-profile-popcnt'
On 64 bit Unix-like systems the 'bsfq' assembly instruction will be used
for bit counting. Detection is automatic at compile time, but in case you
experience compile problems you can comment out #define USE_BSFQ line in types.h
On 64 bit systems the 'bsfq' assembly instruction will be used for bit
counting. Detection is automatic at compile time, but in case you experience
compile problems you can comment out #define USE_BSFQ line in types.h
In general is recommended to run 'make help' to see a list of make targets
with corresponding descriptions.
5. Terms of use
@@ -83,8 +86,3 @@ source code, these changes must also be made available under the GPL.
For full details, read the copy of the GPL found in the file named
Copying.txt.
6. Feedback
-----------
The author's e-mail address is mcostalba@gmail.com
+39 -63
View File
@@ -1,63 +1,39 @@
[PolyGlot]
EngineDir = .
EngineCommand = ./stockfish
Book = false
BookFile = book.bin
Log = true
LogFile = stockfish.log
Resign = true
ResignScore = 600
[Engine]
Hash = 128
Threads = 1
OwnBook = false
Book File = book.bin
Use Search Log = false
Mobility (Middle Game) = 100
Mobility (Endgame) = 100
Pawn Structure (Middle Game) = 100
Pawn Structure (Endgame) = 100
Passed Pawns (Middle Game) = 100
Passed Pawns (Endgame) = 100
Aggressiveness = 100
Cowardice = 100
King Safety Curve = Quadratic
Quadratic = Linear
King Safety Coefficient = 40
King Safety X Intercept = 0
King Safety Max Slope = 30
King Safety Max Value = 500
Queen Contact Check Bonus = 3
Queen Check Bonus = 2
Rook Check Bonus = 1
Bishop Check Bonus = 1
Knight Check Bonus = 1
Discovered Check Bonus = 3
Mate Threat Bonus = 3
Check Extension (PV nodes) = 2
Check Extension (non-PV nodes) = 1
Single Reply Extension (PV nodes) = 2
Single Reply Extension (non-PV nodes) = 2
Mate Threat Extension (PV nodes) = 0
Mate Threat Extension (non-PV nodes) = 0
Pawn Push to 7th Extension (PV nodes) = 1
Pawn Push to 7th Extension (non-PV nodes) = 1
Passed Pawn Extension (PV nodes) = 1
Passed Pawn Extension (non-PV nodes) = 0
Pawn Endgame Extension (PV nodes) = 2
Pawn Endgame Extension (non-PV nodes) = 2
Full Depth Moves (PV nodes) = 14
Full Depth Moves (non-PV nodes) = 3
Threat Depth = 5
Futility Pruning (Main Search) = true
Futility Pruning (Quiescence Search) = true
Randomness = 0
Minimum Split Depth = 4
Maximum Number of Threads per Split Point = 5
[PolyGlot]
EngineDir = .
EngineCommand = ./stockfish
Book = false
BookFile = book.bin
Log = false
LogFile = stockfish.log
Resign = true
ResignScore = 600
[Engine]
Hash = 128
Threads = 1
OwnBook = false
Book File = book.bin
Best Book Move = false
Use Search Log = false
Search Log Filename = SearchLog.txt
Mobility (Middle Game) = 100
Mobility (Endgame) = 100
Passed Pawns (Middle Game) = 100
Passed Pawns (Endgame) = 100
Space = 100
Aggressiveness = 100
Cowardice = 100
Minimum Split Depth = 4
Maximum Number of Threads per Split Point = 5
Use Sleeping Threads = false
Skill Level = 20
Emergency Move Horizon = 40
Emergency Base Time = 200
Emergency Move Time = 70
Minimum Thinking Time = 20
-674
View File
@@ -1,674 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program 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.
This program 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/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
+467 -256
View File
@@ -1,8 +1,6 @@
# Stockfish, a UCI chess playing engine derived from Glaurung 2.1
# Copyright (C) 2004-2007 Tord Romstad
# Copyright (C) 2008 Marco Costalba
# This file is part of Stockfish.
# Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
# Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
#
# Stockfish is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -18,297 +16,510 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
### Executable name. Do not change
### ==========================================================================
### Section 1. General Configuration
### ==========================================================================
### Executable name
EXE = stockfish
### Installation dir definitions
PREFIX = /usr/local
BINDIR = $(PREFIX)/bin
### ==========================================================================
### Compiler speed switches for both GCC and ICC. These settings are generally
### fast on a broad range of systems, but may be changed experimentally
### ==========================================================================
GCCFLAGS = -O3 -msse
ICCFLAGS = -fast -msse
ICCFLAGS-OSX = -fast -mdynamic-no-pic
### ==========================================================================
### Enable/disable debugging, disabled by default
### ==========================================================================
GCCFLAGS += -DNDEBUG
ICCFLAGS += -DNDEBUG
ICCFLAGS-OSX += -DNDEBUG
### ==========================================================================
### Remove below comments to compile for a big-endian machine
### ==========================================================================
#GCCFLAGS += -DBIGENDIAN
#ICCFLAGS += -DBIGENDIAN
#ICCFLAGS-OSX += -DBIGENDIAN
### ==========================================================================
### Run built-in benchmark for pgo-builds with: 32MB hash 1 thread 10 depth
### These settings are generally fast, but may be changed experimentally
### ==========================================================================
### Built-in benchmark for pgo-builds
PGOBENCH = ./$(EXE) bench 32 1 10 default depth
### Object files
OBJS = benchmark.o bitbase.o bitboard.o book.o endgame.o evaluate.o main.o \
material.o misc.o move.o movegen.o movepick.o pawns.o position.o \
search.o thread.o timeman.o tt.o uci.o ucioption.o
### General compiler settings. Do not change
GCCFLAGS += -g -Wall -fno-exceptions -fno-rtti
ICCFLAGS += -g -Wall -fno-exceptions -fno-rtti -wd383,869,981,10187,10188,11505,11503
ICCFLAGS-OSX += -g -Wall -fno-exceptions -fno-rtti -wd383,869,981,10187,10188,11505,11503
### ==========================================================================
### Section 2. High-level Configuration
### ==========================================================================
#
# flag --- Comp switch --- Description
# ----------------------------------------------------------------------------
#
# debug = no/yes --- -DNDEBUG --- Enable/Disable debug mode
# optimize = yes/no --- (-O3/-fast etc.) --- Enable/Disable optimizations
# arch = (name) --- (-arch) --- Target architecture
# os = (name) --- --- Target operating system
# bits = 64/32 --- -DIS_64BIT --- 64-/32-bit operating system
# bigendian = no/yes --- -DBIGENDIAN --- big/little-endian byte order
# prefetch = no/yes --- -DUSE_PREFETCH --- Use prefetch x86 asm-instruction
# bsfq = no/yes --- -DUSE_BSFQ --- Use bsfq x86_64 asm-instruction
# --- (Works only with GCC and ICC 64-bit)
# popcnt = no/yes --- -DUSE_POPCNT --- Use popcnt x86_64 asm-instruction
#
# Note that Makefile is space sensitive, so when adding new architectures
# or modifying existing flags, you have to make sure there are no extra spaces
# at the end of the line for flag values.
### 2.1. General
debug = no
optimize = yes
### 2.2 Architecture specific
# General-section
ifeq ($(ARCH),general-64)
arch = any
os = any
bits = 64
bigendian = no
prefetch = no
bsfq = no
popcnt = no
endif
ifeq ($(ARCH),general-32)
arch = any
os = any
bits = 32
bigendian = no
prefetch = no
bsfq = no
popcnt = no
endif
ifeq ($(ARCH),bigendian-64)
arch = any
os = any
bits = 64
bigendian = yes
prefetch = no
bsfq = no
popcnt = no
endif
ifeq ($(ARCH),bigendian-32)
arch = any
os = any
bits = 32
bigendian = yes
prefetch = no
bsfq = no
popcnt = no
endif
# x86-section
ifeq ($(ARCH),x86-64)
arch = x86_64
os = any
bits = 64
bigendian = no
prefetch = yes
bsfq = yes
popcnt = no
endif
ifeq ($(ARCH),x86-64-modern)
arch = x86_64
os = any
bits = 64
bigendian = no
prefetch = yes
bsfq = yes
popcnt = yes
endif
ifeq ($(ARCH),x86-32)
arch = i386
os = any
bits = 32
bigendian = no
prefetch = yes
bsfq = no
popcnt = no
endif
ifeq ($(ARCH),x86-32-old)
arch = i386
os = any
bits = 32
bigendian = no
prefetch = no
bsfq = no
popcnt = no
endif
# osx-section
ifeq ($(ARCH),osx-ppc-64)
arch = ppc64
os = osx
bits = 64
bigendian = yes
prefetch = no
bsfq = no
popcnt = no
endif
ifeq ($(ARCH),osx-ppc-32)
arch = ppc
os = osx
bits = 32
bigendian = yes
prefetch = no
bsfq = no
popcnt = no
endif
ifeq ($(ARCH),osx-x86-64)
arch = x86_64
os = osx
bits = 64
bigendian = no
prefetch = yes
bsfq = yes
popcnt = no
endif
ifeq ($(ARCH),osx-x86-32)
arch = i386
os = osx
bits = 32
bigendian = no
prefetch = yes
bsfq = no
popcnt = no
endif
### General linker settings. Do not change
LDFLAGS = -lpthread
### ==========================================================================
### Section 3. Low-level configuration
### ==========================================================================
### 3.1 Selecting compiler (default = gcc)
ifeq ($(COMP),)
COMP=gcc
endif
### Object files. Do not change
OBJS = application.o bitboard.o pawns.o material.o endgame.o evaluate.o main.o \
misc.o move.o movegen.o history.o movepick.o search.o piece.o \
position.o direction.o tt.o value.o uci.o ucioption.o \
mersenne.o book.o bitbase.o san.o benchmark.o
ifeq ($(COMP),mingw)
comp=mingw
CXX=g++
profile_prepare = gcc-profile-prepare
profile_make = gcc-profile-make
profile_use = gcc-profile-use
profile_clean = gcc-profile-clean
endif
ifeq ($(COMP),gcc)
comp=gcc
CXX=g++
profile_prepare = gcc-profile-prepare
profile_make = gcc-profile-make
profile_use = gcc-profile-use
profile_clean = gcc-profile-clean
endif
ifeq ($(COMP),icc)
comp=icc
CXX=icpc
profile_prepare = icc-profile-prepare
profile_make = icc-profile-make
profile_use = icc-profile-use
profile_clean = icc-profile-clean
endif
### 3.2 General compiler settings
CXXFLAGS = -g -Wall -Wcast-qual -fno-exceptions -fno-rtti $(EXTRACXXFLAGS)
ifeq ($(comp),gcc)
CXXFLAGS += -ansi -pedantic -Wno-long-long -Wextra -Wshadow
endif
ifeq ($(comp),mingw)
CXXFLAGS += -Wextra -Wshadow
endif
ifeq ($(comp),icc)
CXXFLAGS += -wd383,981,1418,1419,10187,10188,11505,11503 -Wcheck -Wabi -Wdeprecated -strict-ansi
endif
ifeq ($(os),osx)
CXXFLAGS += -arch $(arch)
endif
### 3.3 General linker settings
LDFLAGS = -lpthread $(EXTRALDFLAGS)
ifeq ($(os),osx)
LDFLAGS += -arch $(arch)
endif
### 3.4 Debugging
ifeq ($(debug),no)
CXXFLAGS += -DNDEBUG
endif
### 3.5 Optimization
ifeq ($(optimize),yes)
ifeq ($(comp),gcc)
CXXFLAGS += -O3
ifeq ($(os),osx)
ifeq ($(arch),i386)
CXXFLAGS += -mdynamic-no-pic
endif
ifeq ($(arch),x86_64)
CXXFLAGS += -mdynamic-no-pic
endif
endif
endif
ifeq ($(comp),mingw)
CXXFLAGS += -O3
endif
ifeq ($(comp),icc)
ifeq ($(os),osx)
CXXFLAGS += -fast -mdynamic-no-pic
else
CXXFLAGS += -O3
endif
endif
endif
### 3.6. Bits
ifeq ($(bits),64)
CXXFLAGS += -DIS_64BIT
endif
### 3.7 Endianess
ifeq ($(bigendian),yes)
CXXFLAGS += -DBIGENDIAN
endif
### 3.8 prefetch
ifeq ($(prefetch),yes)
CXXFLAGS += -msse
DEPENDFLAGS += -msse
else
CXXFLAGS += -DNO_PREFETCH
endif
### 3.9 bsfq
ifeq ($(bsfq),yes)
CXXFLAGS += -DUSE_BSFQ
endif
### 3.10 popcnt
ifeq ($(popcnt),yes)
CXXFLAGS += -DUSE_POPCNT
endif
### ==========================================================================
### Section 4. Public targets
### ==========================================================================
### General rules. Do not change
default:
$(MAKE) gcc
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) build
help:
@echo ""
@echo "Makefile options:"
@echo "To compile stockfish, type: "
@echo ""
@echo "make > Default: Compiler = g++"
@echo "make gcc-popcnt > Compiler = g++ + popcnt-support"
@echo "make icc > Compiler = icpc"
@echo "make icc-profile > Compiler = icpc + automatic pgo-build"
@echo "make icc-profile-popcnt > Compiler = icpc + automatic pgo-build + popcnt-support"
@echo "make osx-ppc32 > PPC-Mac OS X 32 bit. Compiler = g++"
@echo "make osx-ppc64 > PPC-Mac OS X 64 bit. Compiler = g++"
@echo "make osx-x86 > x86-Mac OS X 32 bit. Compiler = g++"
@echo "make osx-x86_64 > x86-Mac OS X 64 bit. Compiler = g++"
@echo "make osx-icc32 > x86-Mac OS X 32 bit. Compiler = icpc"
@echo "make osx-icc64 > x86-Mac OS X 64 bit. Compiler = icpc"
@echo "make osx-icc32-profile > OSX 32 bit. Compiler = icpc + automatic pgo-build"
@echo "make osx-icc64-profile > OSX 64 bit. Compiler = icpc + automatic pgo-build"
@echo "make strip > Strip executable"
@echo "make clean > Clean up"
@echo "make target ARCH=arch [COMP=comp]"
@echo ""
@echo "Supported targets:"
@echo ""
@echo "build > Build unoptimized version"
@echo "profile-build > Build PGO-optimized version"
@echo "popcnt-profile-build > Build PGO-optimized version with optional popcnt-support"
@echo "strip > Strip executable"
@echo "install > Install executable"
@echo "clean > Clean up"
@echo "testrun > Make sample run"
@echo ""
@echo "Supported archs:"
@echo ""
@echo "x86-64 > x86 64-bit"
@echo "x86-64-modern > x86 64-bit with runtime support for popcnt-instruction"
@echo "x86-32 > x86 32-bit excluding very old hardware without SSE-support"
@echo "x86-32-old > x86 32-bit including also very old hardware"
@echo "osx-ppc-64 > PPC-Mac OS X 64 bit"
@echo "osx-ppc-32 > PPC-Mac OS X 32 bit"
@echo "osx-x86-64 > x86-Mac OS X 64 bit"
@echo "osx-x86-32 > x86-Mac OS X 32 bit"
@echo "general-64 > unspecified 64-bit"
@echo "general-32 > unspecified 32-bit"
@echo "bigendian-64 > unspecified 64-bit with bigendian byte order"
@echo "bigendian-32 > unspecified 32-bit with bigendian byte order"
@echo ""
@echo "Supported comps:"
@echo ""
@echo "gcc > Gnu compiler (default)"
@echo "icc > Intel compiler"
@echo "mingw > Gnu compiler with MinGW under Windows"
@echo ""
@echo "Non-standard targets:"
@echo ""
@echo "make hpux > Compile for HP-UX. Compiler = aCC"
@echo ""
@echo "Examples. If you don't know what to do, you likely want to run: "
@echo ""
@echo "make profile-build ARCH=x86-64 (This is for 64-bit systems)"
@echo "make profile-build ARCH=x86-32 (This is for 32-bit systems)"
@echo ""
all: $(EXE) .depend
build:
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) config-sanity
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) all
clean:
$(RM) *.o .depend *~ $(EXE)
### Possible targets. You may add your own ones here
gcc:
$(MAKE) \
CXX='g++' \
CXXFLAGS="$(GCCFLAGS)" \
all
gcc-popcnt:
$(MAKE) \
CXX='g++' \
CXXFLAGS="$(GCCFLAGS) -DUSE_POPCNT" \
all
icc:
$(MAKE) \
CXX='icpc' \
CXXFLAGS="$(ICCFLAGS)" \
all
icc-profile-make:
$(MAKE) \
CXX='icpc' \
CXXFLAGS="$(ICCFLAGS)" \
CXXFLAGS+='-prof-gen=srcpos -prof_dir ./profdir' \
all
icc-profile-use:
$(MAKE) \
CXX='icpc' \
CXXFLAGS="$(ICCFLAGS)" \
CXXFLAGS+='-prof_use -prof_dir ./profdir' \
all
icc-profile:
@rm -rf profdir
@mkdir profdir
profile-build:
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) config-sanity
@echo ""
@echo "Step 0/4. Preparing for profile build."
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_prepare)
@echo ""
@echo "Step 1/4. Building executable for benchmark ..."
@touch *.cpp *.h
$(MAKE) icc-profile-make
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_make)
@echo ""
@echo "Running benchmark for pgo-build ..."
@echo "Step 2/4. Running benchmark for pgo-build ..."
@$(PGOBENCH) > /dev/null
@echo "Benchmark finished. Build final executable now ..."
@echo ""
@touch *.cpp *.h
$(MAKE) icc-profile-use
@rm -rf profdir bench.txt
icc-profile-make-with-popcnt:
$(MAKE) \
CXX='icpc' \
CXXFLAGS="$(ICCFLAGS) -DUSE_POPCNT" \
CXXFLAGS+='-prof-gen=srcpos -prof_dir ./profdir' \
all
icc-profile-use-with-popcnt:
$(MAKE) \
CXX='icpc' \
CXXFLAGS="$(ICCFLAGS) -DUSE_POPCNT" \
CXXFLAGS+='-prof_use -prof_dir ./profdir' \
all
icc-profile-popcnt:
@rm -rf profdir
@mkdir profdir
@touch *.cpp *.h
$(MAKE) icc-profile-make
@echo "Step 3/4. Building final executable ..."
@touch *.cpp
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_use)
@echo ""
@echo "Running benchmark for pgo-build (popcnt disabled)..."
@echo "Step 4/4. Deleting profile data ..."
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_clean)
popcnt-profile-build:
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) config-sanity
@echo ""
@echo "Step 0/6. Preparing for profile build."
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_prepare)
@echo ""
@echo "Step 1/6. Building executable for benchmark (popcnt disabled)..."
@touch *.cpp *.h
$(MAKE) ARCH=x86-64 COMP=$(COMP) $(profile_make)
@echo ""
@echo "Step 2/6. Running benchmark for pgo-build (popcnt disabled)..."
@$(PGOBENCH) > /dev/null
@touch *.cpp *.h
$(MAKE) icc-profile-make-with-popcnt
@echo ""
@echo "Running benchmark for pgo-build (popcnt enabled)..."
@echo "Step 3/6. Building executable for benchmark (popcnt enabled)..."
@touch *.cpp *.h
$(MAKE) ARCH=x86-64-modern COMP=$(COMP) $(profile_make)
@echo ""
@echo "Step 4/6. Running benchmark for pgo-build (popcnt enabled)..."
@$(PGOBENCH) > /dev/null
@echo "Benchmarks finished. Build final executable now ..."
@echo ""
@echo "Step 5/6. Building final executable ..."
@touch *.cpp *.h
$(MAKE) icc-profile-use-with-popcnt
@rm -rf profdir bench.txt
osx-ppc32:
$(MAKE) \
CXX='g++' \
CXXFLAGS="$(GCCFLAGS)" \
CXXFLAGS+='-arch ppc' \
LDFLAGS+='-arch ppc' \
all
osx-ppc64:
$(MAKE) \
CXX='g++' \
CXXFLAGS="$(GCCFLAGS)" \
CXXFLAGS+='-arch ppc64' \
LDFLAGS+='-arch ppc64' \
all
osx-x86:
$(MAKE) \
CXX='g++' \
CXXFLAGS="$(GCCFLAGS)" \
CXXFLAGS+='-arch i386' \
LDFLAGS+='-arch i386' \
all
osx-x86_64:
$(MAKE) \
CXX='g++' \
CXXFLAGS="$(GCCFLAGS)" \
CXXFLAGS+='-arch x86_64' \
LDFLAGS+='-arch x86_64' \
all
osx-icc32:
$(MAKE) \
CXX='icpc' \
CXXFLAGS="$(ICCFLAGS-OSX)" \
CXXFLAGS+='-arch i386' \
LDFLAGS+='-arch i386' \
all
osx-icc64:
$(MAKE) \
CXX='icpc' \
CXXFLAGS="$(ICCFLAGS-OSX)" \
CXXFLAGS+='-arch x86_64' \
LDFLAGS+='-arch x86_64' \
all
osx-icc32-profile-make:
$(MAKE) \
CXX='icpc' \
CXXFLAGS="$(ICCFLAGS-OSX)" \
CXXFLAGS+='-arch i386' \
CXXFLAGS+='-prof_gen -prof_dir ./profdir' \
LDFLAGS+='-arch i386' \
all
osx-icc32-profile-use:
$(MAKE) \
CXX='icpc' \
CXXFLAGS="$(ICCFLAGS-OSX)" \
CXXFLAGS+='-arch i386' \
CXXFLAGS+='-prof_use -prof_dir ./profdir' \
LDFLAGS+='-arch i386' \
all
osx-icc32-profile:
@rm -rf profdir
@mkdir profdir
@touch *.cpp *.h
$(MAKE) osx-icc32-profile-make
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_use)
@echo ""
@echo "Running benchmark for pgo-build ..."
@$(PGOBENCH) > /dev/null
@echo "Benchmark finished. Build final executable now ..."
@echo "Step 6/6. Deleting profile data ..."
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_clean)
@echo ""
@touch *.cpp *.h
$(MAKE) osx-icc32-profile-use
@rm -rf profdir bench.txt
osx-icc64-profile-make:
$(MAKE) \
CXX='icpc' \
CXXFLAGS="$(ICCFLAGS-OSX)" \
CXXFLAGS+='-arch x86_64' \
CXXFLAGS+='-prof_gen -prof_dir ./profdir' \
LDFLAGS+='-arch x86_64' \
all
osx-icc64-profile-use:
$(MAKE) \
CXX='icpc' \
CXXFLAGS="$(ICCFLAGS-OSX)" \
CXXFLAGS+='-arch x86_64' \
CXXFLAGS+='-prof_use -prof_dir ./profdir' \
LDFLAGS+='-arch x86_64' \
all
osx-icc64-profile:
@rm -rf profdir
@mkdir profdir
@touch *.cpp *.h
$(MAKE) osx-icc64-profile-make
@echo ""
@echo "Running benchmark for pgo-build ..."
@$(PGOBENCH) > /dev/null
@echo "Benchmark finished. Build final executable now ..."
@echo ""
@touch *.cpp *.h
$(MAKE) osx-icc64-profile-use
@rm -rf profdir bench.txt
strip:
strip $(EXE)
install:
-mkdir -p -m 755 $(BINDIR)
-cp $(EXE) $(BINDIR)
-strip $(BINDIR)/$(EXE)
clean:
$(RM) $(EXE) $(EXE).exe *.o .depend *~ core bench.txt *.gcda
testrun:
@$(PGOBENCH)
### ==========================================================================
### Section 5. Private targets
### ==========================================================================
all: $(EXE) .depend
config-sanity:
@echo ""
@echo "Config:"
@echo "debug: '$(debug)'"
@echo "optimize: '$(optimize)'"
@echo "arch: '$(arch)'"
@echo "os: '$(os)'"
@echo "bits: '$(bits)'"
@echo "bigendian: '$(bigendian)'"
@echo "prefetch: '$(prefetch)'"
@echo "bsfq: '$(bsfq)'"
@echo "popcnt: '$(popcnt)'"
@echo ""
@echo "Flags:"
@echo "CXX: $(CXX)"
@echo "CXXFLAGS: $(CXXFLAGS)"
@echo "LDFLAGS: $(LDFLAGS)"
@echo ""
@echo "Testing config sanity. If this fails, try 'make help' ..."
@echo ""
@test "$(debug)" = "yes" || test "$(debug)" = "no"
@test "$(optimize)" = "yes" || test "$(optimize)" = "no"
@test "$(arch)" = "any" || test "$(arch)" = "x86_64" || test "$(arch)" = "i386" || \
test "$(arch)" = "ppc64" || test "$(arch)" = "ppc"
@test "$(os)" = "any" || test "$(os)" = "osx"
@test "$(bits)" = "32" || test "$(bits)" = "64"
@test "$(bigendian)" = "yes" || test "$(bigendian)" = "no"
@test "$(prefetch)" = "yes" || test "$(prefetch)" = "no"
@test "$(bsfq)" = "yes" || test "$(bsfq)" = "no"
@test "$(popcnt)" = "yes" || test "$(popcnt)" = "no"
@test "$(comp)" = "gcc" || test "$(comp)" = "icc" || test "$(comp)" = "mingw"
### Compilation. Do not change
$(EXE): $(OBJS)
$(CXX) $(LDFLAGS) -o $@ $(OBJS)
$(CXX) -o $@ $(OBJS) $(LDFLAGS)
gcc-profile-prepare:
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) gcc-profile-clean
gcc-profile-make:
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
EXTRACXXFLAGS='-fprofile-generate' \
EXTRALDFLAGS='-lgcov' \
all
gcc-profile-use:
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
EXTRACXXFLAGS='-fprofile-use' \
all
gcc-profile-clean:
@rm -rf *.gcda *.gcno bench.txt
icc-profile-prepare:
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) icc-profile-clean
@mkdir profdir
icc-profile-make:
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
EXTRACXXFLAGS='-prof-gen=srcpos -prof_dir ./profdir' \
all
icc-profile-use:
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
EXTRACXXFLAGS='-prof_use -prof_dir ./profdir' \
all
icc-profile-clean:
@rm -rf profdir bench.txt
### Dependencies. Do not change
.depend:
$(CXX) -msse -MM $(OBJS:.o=.cpp) > $@
-@$(CXX) $(DEPENDFLAGS) -MM $(OBJS:.o=.cpp) > $@ 2> /dev/null
-include .depend
### ==========================================================================
### Section 6. Non-standard targets
### ==========================================================================
hpux:
$(MAKE) \
CXX='/opt/aCC/bin/aCC -AA +hpxstd98 -DBIGENDIAN -mt +O3 -DNDEBUG -DNO_PREFETCH' \
CXXFLAGS="" \
LDFLAGS="" \
all
include .depend
-75
View File
@@ -1,75 +0,0 @@
/*
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();
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() {
// A static Application object is allocated
// once only when this function is called.
static Application singleton;
}
void Application::exit_with_failure() {
exit(EXIT_FAILURE); // d'tor will be called automatically
}
+85 -113
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,29 +17,20 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
////
//// Includes
////
#include <fstream>
#include <sstream>
#include <iostream>
#include <vector>
#include "benchmark.h"
#include "position.h"
#include "search.h"
#include "thread.h"
#include "ucioption.h"
using namespace std;
////
//// Variables
////
const string BenchmarkPositions[] = {
static const string Defaults[] = {
"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1",
"r4rk1/1b2qppp/p1n1p3/1p6/1b1PN3/3BRN2/PP3PPP/R2Q2K1 b - - 7 16",
"4r1k1/ppq3pp/3b4/2pP4/2Q1p3/4B1P1/PP5P/R5K1 b - - 0 20",
"r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq -",
"8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - -",
"4rrk1/pp1n3p/3q2pQ/2p1pb2/2PP4/2P3N1/P2B2PP/4RRK1 b - - 7 19",
"rq3rk1/ppp2ppp/1bnpb3/3N2B1/3NP3/7P/PPPQ1PP1/2KR3R w - - 7 14",
"r1bq1r1k/1pp1n1pp/1p1p4/4p2Q/4Pp2/1BNP4/PPP2PPP/3R1RK1 w - - 2 14",
@@ -51,131 +42,112 @@ const string BenchmarkPositions[] = {
"r1bq1r1k/b1p1npp1/p2p3p/1p6/3PP3/1B2NN2/PP3PPP/R2Q1RK1 w - - 1 16",
"3r1rk1/p5pp/bpp1pp2/8/q1PP1P2/b3P3/P2NQRPP/1R2B1K1 b - - 6 22",
"r1q2rk1/2p1bppp/2Pp4/p6b/Q1PNp3/4B3/PP1R1PPP/2K4R w - - 2 18",
"4k2r/1pb2ppp/1p2p3/1R1p4/3P4/2r1PN2/P4PPP/1R4K1 b - 3 22",
"3q2k1/pb3p1p/4pbp1/2r5/PpN2N2/1P2P2P/5PP1/Q2R2K1 b - - 4 26"
"4k2r/1pb2ppp/1p2p3/1R1p4/3P4/2r1PN2/P4PPP/1R4K1 b - - 3 22",
"3q2k1/pb3p1p/4pbp1/2r5/PpN2N2/1P2P2P/5PP1/Q2R2K1 b - - 4 26",
""
};
////
//// Functions
////
/// benchmark() runs a simple benchmark by letting Stockfish analyze a set
/// of positions for a given time each. There are four parameters; the
/// of positions for a given limit each. There are five parameters; the
/// transposition table size, the number of search threads that should
/// be used, the time in seconds spent for each position (optional, default
/// is 60) and an optional file name where to look for positions in fen
/// format (default are the BenchmarkPositions defined above).
/// be used, the limit value spent for each position (optional, default
/// is ply 12), an optional file name where to look for positions in fen
/// format (default are the BenchmarkPositions defined above) and the type
/// of the limit value: depth (default), time in secs or number of nodes.
/// The analysis is written to a file named bench.txt.
void benchmark(const string& commandLine) {
void benchmark(int argc, char* argv[]) {
istringstream csVal(commandLine);
istringstream csStr(commandLine);
string ttSize, threads, fileName, limitType, timFile;
int val, secsPerPos, maxDepth, maxNodes;
vector<string> fenList;
SearchLimits limits;
int64_t totalNodes;
int time;
csStr >> ttSize;
csVal >> val;
if (val < 4 || val > 1024)
{
cerr << "The hash table size must be between 4 and 1024" << endl;
Application::exit_with_failure();
}
csStr >> threads;
csVal >> val;
if (val < 1 || val > THREAD_MAX)
{
cerr << "The number of threads must be between 1 and " << THREAD_MAX << endl;
Application::exit_with_failure();
}
set_option_value("Hash", ttSize);
set_option_value("Threads", threads);
set_option_value("OwnBook", "false");
set_option_value("Use Search Log", "true");
set_option_value("Search Log Filename", "bench.txt");
// Load default positions
for (int i = 0; !Defaults[i].empty(); i++)
fenList.push_back(Defaults[i]);
csVal >> val;
csVal >> fileName;
csVal >> limitType;
csVal >> timFile;
// Assign default values to missing arguments
string ttSize = argc > 2 ? argv[2] : "128";
string threads = argc > 3 ? argv[3] : "1";
string valStr = argc > 4 ? argv[4] : "12";
string fenFile = argc > 5 ? argv[5] : "default";
string valType = argc > 6 ? argv[6] : "depth";
secsPerPos = maxDepth = maxNodes = 0;
Options["Hash"].set_value(ttSize);
Options["Threads"].set_value(threads);
Options["OwnBook"].set_value("false");
if (limitType == "time")
secsPerPos = val * 1000;
else if (limitType == "depth" || limitType == "perft")
maxDepth = val;
// Search should be limited by nodes, time or depth ?
if (valType == "nodes")
limits.maxNodes = atoi(valStr.c_str());
else if (valType == "time")
limits.maxTime = 1000 * atoi(valStr.c_str()); // maxTime is in ms
else
maxNodes = val;
limits.maxDepth = atoi(valStr.c_str());
vector<string> positions;
if (fileName != "default")
// Do we need to load positions from a given FEN file ?
if (fenFile != "default")
{
ifstream fenFile(fileName.c_str());
if (!fenFile.is_open())
{
cerr << "Unable to open positions file " << fileName << endl;
Application::exit_with_failure();
}
string pos;
while (fenFile.good())
{
getline(fenFile, pos);
if (!pos.empty())
positions.push_back(pos);
}
fenFile.close();
} else
for (int i = 0; i < 16; i++)
positions.push_back(string(BenchmarkPositions[i]));
string fen;
ifstream f(fenFile.c_str());
ofstream timingFile;
if (!timFile.empty())
{
timingFile.open(timFile.c_str(), ios::out | ios::app);
if (!timingFile.is_open())
if (f.is_open())
{
cerr << "Unable to open timing file " << timFile << endl;
Application::exit_with_failure();
fenList.clear();
while (getline(f, fen))
if (!fen.empty())
fenList.push_back(fen);
f.close();
}
else
{
cerr << "Unable to open FEN file " << fenFile << endl;
exit(EXIT_FAILURE);
}
}
vector<string>::iterator it;
int cnt = 1;
int64_t totalNodes = 0;
int startTime = get_system_time();
// Ok, let's start the benchmark !
totalNodes = 0;
time = get_system_time();
for (it = positions.begin(); it != positions.end(); ++it, ++cnt)
for (size_t i = 0; i < fenList.size(); i++)
{
Move moves[1] = {MOVE_NONE};
int dummy[2] = {0, 0};
Position pos(*it);
cerr << "\nBench position: " << cnt << '/' << positions.size() << endl << endl;
if (limitType == "perft")
totalNodes += perft(pos, maxDepth * OnePly);
else if (!think(pos, false, false, 0, dummy, dummy, 0, maxDepth, maxNodes, secsPerPos, moves))
break;
totalNodes += nodes_searched();
Move moves[] = { MOVE_NONE };
Position pos(fenList[i], false, 0);
cerr << "\nBench position: " << i + 1 << '/' << fenList.size() << endl;
if (valType == "perft")
{
int64_t cnt = perft(pos, limits.maxDepth * ONE_PLY);
totalNodes += cnt;
cerr << "\nPerft " << limits.maxDepth << " nodes counted: " << cnt << endl;
}
else
{
if (!think(pos, limits, moves))
break;
totalNodes += pos.nodes_searched();
}
}
cnt = get_system_time() - startTime;
cerr << "==============================="
<< "\nTotal time (ms) : " << cnt
time = get_system_time() - time;
cerr << "\n==============================="
<< "\nTotal time (ms) : " << time
<< "\nNodes searched : " << totalNodes
<< "\nNodes/second : " << (int)(totalNodes/(cnt/1000.0)) << endl << endl;
<< "\nNodes/second : " << (int)(totalNodes / (time / 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.
// 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;
cin >> time;
#endif
}
-37
View File
@@ -1,37 +0,0 @@
/*
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(BENCHMARK_H_INCLUDED)
#define BENCHMARK_H_INCLUDED
////
//// Includes
////
#include <string>
////
//// Prototypes
////
extern void benchmark(const std::string& commandLine);
#endif // !defined(BENCHMARK_H_INCLUDED)
+163 -229
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,22 +17,10 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
////
//// Includes
////
#include <cassert>
#include "bitbase.h"
#include "bitboard.h"
#include "move.h"
#include "square.h"
////
//// Local definitions
////
#include "types.h"
namespace {
@@ -46,305 +34,251 @@ namespace {
struct KPKPosition {
void from_index(int index);
int to_index() const;
bool is_legal() const;
bool is_immediate_draw() const;
bool is_immediate_win() const;
Bitboard wk_attacks() const;
Bitboard bk_attacks() const;
Bitboard pawn_attacks() const;
Bitboard wk_attacks() const { return StepAttacksBB[WK][whiteKingSquare]; }
Bitboard bk_attacks() const { return StepAttacksBB[BK][blackKingSquare]; }
Bitboard pawn_attacks() const { return StepAttacksBB[WP][pawnSquare]; }
Square whiteKingSquare, blackKingSquare, pawnSquare;
Color sideToMove;
};
// The possible pawns squares are 24, the first 4 files and ranks from 2 to 7
const int IndexMax = 2 * 24 * 64 * 64; // color * wp_sq * wk_sq * bk_sq
Result *Bitbase;
const int IndexMax = 2*24*64*64;
int UnknownCount = 0;
void initialize();
bool next_iteration();
Result classify_wtm(const KPKPosition &p);
Result classify_btm(const KPKPosition &p);
int compute_index(Square wksq, Square bksq, Square psq, Color stm);
int compress_result(Result r);
// Each uint32_t stores results of 32 positions, one per bit
uint32_t KPKBitbase[IndexMax / 32];
Result classify_wtm(const KPKPosition& pos, const Result bb[]);
Result classify_btm(const KPKPosition& pos, const Result bb[]);
int compute_index(Square wksq, Square bksq, Square wpsq, Color stm);
}
////
//// Functions
////
uint32_t probe_kpk_bitbase(Square wksq, Square wpsq, Square bksq, Color stm) {
void generate_kpk_bitbase(uint8_t bitbase[]) {
// Allocate array and initialize:
Bitbase = new Result[IndexMax];
initialize();
int index = compute_index(wksq, bksq, wpsq, stm);
// Iterate until all positions are classified:
while(next_iteration());
return KPKBitbase[index / 32] & (1 << (index & 31));
}
// Compress bitbase into the supplied parameter:
int i, j, b;
for(i = 0; i < 24576; i++) {
for(b = 0, j = 0; j < 8; b |= (compress_result(Bitbase[8*i+j]) << j), j++);
assert(b == int(uint8_t(b)));
bitbase[i] = (uint8_t)b;
void init_kpk_bitbase() {
Result bb[IndexMax];
KPKPosition pos;
bool repeat;
// Initialize table
for (int i = 0; i < IndexMax; i++)
{
pos.from_index(i);
bb[i] = !pos.is_legal() ? RESULT_INVALID
: pos.is_immediate_draw() ? RESULT_DRAW
: pos.is_immediate_win() ? RESULT_WIN : RESULT_UNKNOWN;
}
// Release allocated memory:
delete [] Bitbase;
// Iterate until all positions are classified (30 cycles needed)
do {
repeat = false;
for (int i = 0; i < IndexMax; i++)
if (bb[i] == RESULT_UNKNOWN)
{
pos.from_index(i);
bb[i] = (pos.sideToMove == WHITE) ? classify_wtm(pos, bb)
: classify_btm(pos, bb);
if (bb[i] != RESULT_UNKNOWN)
repeat = true;
}
} while (repeat);
// Map 32 position results into one KPKBitbase[] entry
for (int i = 0; i < IndexMax / 32; i++)
for (int j = 0; j < 32; j++)
if (bb[32 * i + j] == RESULT_WIN || bb[32 * i + j] == RESULT_LOSS)
KPKBitbase[i] |= (1 << j);
}
namespace {
// A KPK bitbase index is an integer in [0, IndexMax] range
//
// Information is mapped in this way
//
// bit 0: side to move (WHITE or BLACK)
// bit 1- 6: black king square (from SQ_A1 to SQ_H8)
// bit 7-12: white king square (from SQ_A1 to SQ_H8)
// bit 13-14: white pawn file (from FILE_A to FILE_D)
// bit 15-17: white pawn rank - 1 (from RANK_2 - 1 to RANK_7 - 1)
int compute_index(Square wksq, Square bksq, Square wpsq, Color stm) {
assert(square_file(wpsq) <= FILE_D);
int p = int(square_file(wpsq)) + 4 * int(square_rank(wpsq) - 1);
int r = int(stm) + 2 * int(bksq) + 128 * int(wksq) + 8192 * p;
assert(r >= 0 && r < IndexMax);
return r;
}
void KPKPosition::from_index(int index) {
int s;
int s = (index / 8192) % 24;
sideToMove = Color(index % 2);
blackKingSquare = Square((index / 2) % 64);
whiteKingSquare = Square((index / 128) % 64);
s = (index / 8192) % 24;
pawnSquare = make_square(File(s % 4), Rank(s / 4 + 1));
}
int KPKPosition::to_index() const {
return compute_index(whiteKingSquare, blackKingSquare, pawnSquare,
sideToMove);
}
bool KPKPosition::is_legal() const {
if(whiteKingSquare == pawnSquare || whiteKingSquare == blackKingSquare ||
pawnSquare == blackKingSquare)
return false;
if(sideToMove == WHITE) {
if(bit_is_set(this->wk_attacks(), blackKingSquare))
return false;
if(bit_is_set(this->pawn_attacks(), blackKingSquare))
if ( whiteKingSquare == pawnSquare
|| whiteKingSquare == blackKingSquare
|| blackKingSquare == pawnSquare)
return false;
if (sideToMove == WHITE)
{
if ( bit_is_set(wk_attacks(), blackKingSquare)
|| bit_is_set(pawn_attacks(), blackKingSquare))
return false;
}
else {
if(bit_is_set(this->bk_attacks(), whiteKingSquare))
else if (bit_is_set(bk_attacks(), whiteKingSquare))
return false;
}
return true;
}
bool KPKPosition::is_immediate_draw() const {
if(sideToMove == BLACK) {
Bitboard wka = this->wk_attacks();
Bitboard bka = this->bk_attacks();
// Case 1: Stalemate
if((bka & ~(wka | this->pawn_attacks())) == EmptyBoardBB)
return true;
if (sideToMove == BLACK)
{
Bitboard wka = wk_attacks();
Bitboard bka = bk_attacks();
// Case 2: King can capture pawn
if(bit_is_set(bka, pawnSquare) && !bit_is_set(wka, pawnSquare))
return true;
// Case 1: Stalemate
if ((bka & ~(wka | pawn_attacks())) == EmptyBoardBB)
return true;
// Case 2: King can capture pawn
if (bit_is_set(bka, pawnSquare) && !bit_is_set(wka, pawnSquare))
return true;
}
else {
// Case 1: Stalemate
if(whiteKingSquare == SQ_A8 && pawnSquare == SQ_A7 &&
(blackKingSquare == SQ_C7 || blackKingSquare == SQ_C8))
return true;
else
{
// Case 1: Stalemate (possible pawn files are only from A to D)
if ( whiteKingSquare == SQ_A8
&& pawnSquare == SQ_A7
&& (blackKingSquare == SQ_C7 || blackKingSquare == SQ_C8))
return true;
}
return false;
}
bool KPKPosition::is_immediate_win() const {
// The position is an immediate win if it is white to move and the white
// pawn can be promoted without getting captured:
return
sideToMove == WHITE &&
square_rank(pawnSquare) == RANK_7 &&
(square_distance(blackKingSquare, pawnSquare+DELTA_N) > 1 ||
bit_is_set(this->wk_attacks(), pawnSquare+DELTA_N));
// The position is an immediate win if it is white to move and the
// white pawn can be promoted without getting captured.
return sideToMove == WHITE
&& square_rank(pawnSquare) == RANK_7
&& whiteKingSquare != pawnSquare + DELTA_N
&& ( square_distance(blackKingSquare, pawnSquare + DELTA_N) > 1
|| bit_is_set(wk_attacks(), pawnSquare + DELTA_N));
}
Bitboard KPKPosition::wk_attacks() const {
return StepAttackBB[WK][whiteKingSquare];
}
Bitboard KPKPosition::bk_attacks() const {
return StepAttackBB[BK][blackKingSquare];
}
Bitboard KPKPosition::pawn_attacks() const {
return StepAttackBB[WP][pawnSquare];
}
void initialize() {
KPKPosition p;
for(int i = 0; i < IndexMax; i++) {
p.from_index(i);
if(!p.is_legal())
Bitbase[i] = RESULT_INVALID;
else if(p.is_immediate_draw())
Bitbase[i] = RESULT_DRAW;
else if(p.is_immediate_win())
Bitbase[i] = RESULT_WIN;
else {
Bitbase[i] = RESULT_UNKNOWN;
UnknownCount++;
}
}
}
bool next_iteration() {
KPKPosition p;
int previousUnknownCount = UnknownCount;
for(int i = 0; i < IndexMax; i++)
if(Bitbase[i] == RESULT_UNKNOWN) {
p.from_index(i);
Bitbase[i] = (p.sideToMove == WHITE)? classify_wtm(p) : classify_btm(p);
if(Bitbase[i] == RESULT_WIN || Bitbase[i] == RESULT_LOSS ||
Bitbase[i] == RESULT_DRAW)
UnknownCount--;
}
return UnknownCount != previousUnknownCount;
}
Result classify_wtm(const KPKPosition &p) {
Result classify_wtm(const KPKPosition& pos, const Result bb[]) {
// If one move leads to a position classified as RESULT_LOSS, the result
// of the current position is RESULT_WIN. If all moves lead to positions
// classified as RESULT_DRAW, the current position is classified as
// RESULT_DRAW. Otherwise, the current position is classified as
// RESULT_UNKNOWN.
// of the current position is RESULT_WIN. If all moves lead to positions
// classified as RESULT_DRAW, the current position is classified RESULT_DRAW
// otherwise the current position is classified as RESULT_UNKNOWN.
bool unknownFound = false;
Bitboard b;
Square s;
Result r;
// King moves
b = p.wk_attacks();
while(b) {
s = pop_1st_bit(&b);
switch(Bitbase[compute_index(s, p.blackKingSquare, p.pawnSquare,
BLACK)]) {
case RESULT_LOSS:
return RESULT_WIN;
b = pos.wk_attacks();
while (b)
{
s = pop_1st_bit(&b);
r = bb[compute_index(s, pos.blackKingSquare, pos.pawnSquare, BLACK)];
case RESULT_UNKNOWN:
unknownFound = true;
break;
if (r == RESULT_LOSS)
return RESULT_WIN;
case RESULT_DRAW: case RESULT_INVALID:
break;
default:
assert(false);
}
if (r == RESULT_UNKNOWN)
unknownFound = true;
}
// Pawn moves
if(square_rank(p.pawnSquare) < RANK_7) {
s = p.pawnSquare + DELTA_N;
switch(Bitbase[compute_index(p.whiteKingSquare, p.blackKingSquare, s,
BLACK)]) {
case RESULT_LOSS:
return RESULT_WIN;
if (square_rank(pos.pawnSquare) < RANK_7)
{
s = pos.pawnSquare + DELTA_N;
r = bb[compute_index(pos.whiteKingSquare, pos.blackKingSquare, s, BLACK)];
case RESULT_UNKNOWN:
unknownFound = true;
break;
if (r == RESULT_LOSS)
return RESULT_WIN;
case RESULT_DRAW: case RESULT_INVALID:
break;
if (r == RESULT_UNKNOWN)
unknownFound = true;
default:
assert(false);
}
// Double pawn push
if ( square_rank(s) == RANK_3
&& s != pos.whiteKingSquare
&& s != pos.blackKingSquare)
{
s += DELTA_N;
r = bb[compute_index(pos.whiteKingSquare, pos.blackKingSquare, s, BLACK)];
if(square_rank(s) == RANK_3 &&
s != p.whiteKingSquare && s != p.blackKingSquare) {
s += DELTA_N;
switch(Bitbase[compute_index(p.whiteKingSquare, p.blackKingSquare, s,
BLACK)]) {
case RESULT_LOSS:
return RESULT_WIN;
if (r == RESULT_LOSS)
return RESULT_WIN;
case RESULT_UNKNOWN:
unknownFound = true;
break;
case RESULT_DRAW: case RESULT_INVALID:
break;
default:
assert(false);
if (r == RESULT_UNKNOWN)
unknownFound = true;
}
}
}
return unknownFound? RESULT_UNKNOWN : RESULT_DRAW;
return unknownFound ? RESULT_UNKNOWN : RESULT_DRAW;
}
Result classify_btm(const KPKPosition &p) {
Result classify_btm(const KPKPosition& pos, const Result bb[]) {
// If one move leads to a position classified as RESULT_DRAW, the result
// of the current position is RESULT_DRAW. If all moves lead to positions
// of the current position is RESULT_DRAW. If all moves lead to positions
// classified as RESULT_WIN, the current position is classified as
// RESULT_LOSS. Otherwise, the current position is classified as
// RESULT_LOSS. Otherwise, the current position is classified as
// RESULT_UNKNOWN.
bool unknownFound = false;
Bitboard b;
Square s;
Result r;
// King moves
b = p.bk_attacks();
while(b) {
s = pop_1st_bit(&b);
switch(Bitbase[compute_index(p.whiteKingSquare, s, p.pawnSquare,
WHITE)]) {
case RESULT_DRAW:
return RESULT_DRAW;
b = pos.bk_attacks();
while (b)
{
s = pop_1st_bit(&b);
r = bb[compute_index(pos.whiteKingSquare, s, pos.pawnSquare, WHITE)];
case RESULT_UNKNOWN:
unknownFound = true;
break;
if (r == RESULT_DRAW)
return RESULT_DRAW;
case RESULT_WIN: case RESULT_INVALID:
break;
default:
assert(false);
}
if (r == RESULT_UNKNOWN)
unknownFound = true;
}
return unknownFound? RESULT_UNKNOWN : RESULT_LOSS;
}
int compute_index(Square wksq, Square bksq, Square psq, Color stm) {
int p = int(square_file(psq)) + (int(square_rank(psq)) - 1) * 4;
int result = int(stm) + 2*int(bksq) + 128*int(wksq) + 8192*p;
assert(result >= 0 && result < IndexMax);
return result;
}
int compress_result(Result r) {
return (r == RESULT_WIN || r == RESULT_LOSS)? 1 : 0;
return unknownFound ? RESULT_UNKNOWN : RESULT_LOSS;
}
}
-38
View File
@@ -1,38 +0,0 @@
/*
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(BITBASE_H_INCLUDED)
#define BITBASE_H_INCLUDED
////
//// Includes
////
#include "types.h"
////
//// Prototypes
////
extern void generate_kpk_bitbase(uint8_t bitbase[]);
#endif // !defined(BITBASE_H_INCLUDED)
+277 -335
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,68 +17,61 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
////
//// Includes
////
#include <iostream>
#include "bitboard.h"
#include "bitcount.h"
#include "direction.h"
#if defined(IS_64BIT)
const uint64_t BMult[64] = {
0x440049104032280ULL, 0x1021023c82008040ULL, 0x404040082000048ULL,
0x48c4440084048090ULL, 0x2801104026490000ULL, 0x4100880442040800ULL,
0x181011002e06040ULL, 0x9101004104200e00ULL, 0x1240848848310401ULL,
0x2000142828050024ULL, 0x1004024d5000ULL, 0x102044400800200ULL,
0x8108108820112000ULL, 0xa880818210c00046ULL, 0x4008008801082000ULL,
0x60882404049400ULL, 0x104402004240810ULL, 0xa002084250200ULL,
0x100b0880801100ULL, 0x4080201220101ULL, 0x44008080a00000ULL,
0x202200842000ULL, 0x5006004882d00808ULL, 0x200045080802ULL,
0x86100020200601ULL, 0xa802080a20112c02ULL, 0x80411218080900ULL,
0x200a0880080a0ULL, 0x9a01010000104000ULL, 0x28008003100080ULL,
0x211021004480417ULL, 0x401004188220806ULL, 0x825051400c2006ULL,
0x140c0210943000ULL, 0x242800300080ULL, 0xc2208120080200ULL,
0x0440049104032280ULL, 0x1021023C82008040ULL, 0x0404040082000048ULL,
0x48C4440084048090ULL, 0x2801104026490000ULL, 0x4100880442040800ULL,
0x0181011002E06040ULL, 0x9101004104200E00ULL, 0x1240848848310401ULL,
0x2000142828050024ULL, 0x00001004024D5000ULL, 0x0102044400800200ULL,
0x8108108820112000ULL, 0xA880818210C00046ULL, 0x4008008801082000ULL,
0x0060882404049400ULL, 0x0104402004240810ULL, 0x000A002084250200ULL,
0x00100B0880801100ULL, 0x0004080201220101ULL, 0x0044008080A00000ULL,
0x0000202200842000ULL, 0x5006004882D00808ULL, 0x0000200045080802ULL,
0x0086100020200601ULL, 0xA802080A20112C02ULL, 0x0080411218080900ULL,
0x000200A0880080A0ULL, 0x9A01010000104000ULL, 0x0028008003100080ULL,
0x0211021004480417ULL, 0x0401004188220806ULL, 0x00825051400C2006ULL,
0x00140C0210943000ULL, 0x0000242800300080ULL, 0x00C2208120080200ULL,
0x2430008200002200ULL, 0x1010100112008040ULL, 0x8141050100020842ULL,
0x822081014405ULL, 0x800c049e40400804ULL, 0x4a0404028a000820ULL,
0x22060201041200ULL, 0x360904200840801ULL, 0x881a08208800400ULL,
0x60202c00400420ULL, 0x1204440086061400ULL, 0x8184042804040ULL,
0x64040315300400ULL, 0xc01008801090a00ULL, 0x808010401140c00ULL,
0x4004830c2020040ULL, 0x80005002020054ULL, 0x40000c14481a0490ULL,
0x10500101042048ULL, 0x1010100200424000ULL, 0x640901901040ULL,
0xa0201014840ULL, 0x840082aa011002ULL, 0x10010840084240aULL,
0x420400810420608ULL, 0x8d40230408102100ULL, 0x4a00200612222409ULL,
0xa08520292120600ULL
0x0000822081014405ULL, 0x800C049E40400804ULL, 0x4A0404028A000820ULL,
0x0022060201041200ULL, 0x0360904200840801ULL, 0x0881A08208800400ULL,
0x0060202C00400420ULL, 0x1204440086061400ULL, 0x0008184042804040ULL,
0x0064040315300400ULL, 0x0C01008801090A00ULL, 0x0808010401140C00ULL,
0x04004830C2020040ULL, 0x0080005002020054ULL, 0x40000C14481A0490ULL,
0x0010500101042048ULL, 0x1010100200424000ULL, 0x0000640901901040ULL,
0x00000A0201014840ULL, 0x00840082AA011002ULL, 0x010010840084240AULL,
0x0420400810420608ULL, 0x8D40230408102100ULL, 0x4A00200612222409ULL,
0x0A08520292120600ULL
};
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
0x0A8002C000108020ULL, 0x4440200140003000ULL, 0x8080200010011880ULL,
0x0380180080141000ULL, 0x1A00060008211044ULL, 0x410001000A0C0008ULL,
0x9500060004008100ULL, 0x0100024284A20700ULL, 0x0000802140008000ULL,
0x0080C01002A00840ULL, 0x0402004282011020ULL, 0x9862000820420050ULL,
0x0001001448011100ULL, 0x6432800200800400ULL, 0x040100010002000CULL,
0x0002800D0010C080ULL, 0x90C0008000803042ULL, 0x4010004000200041ULL,
0x0003010010200040ULL, 0x0A40828028001000ULL, 0x0123010008000430ULL,
0x0024008004020080ULL, 0x0060040001104802ULL, 0x00582200028400D1ULL,
0x4000802080044000ULL, 0x0408208200420308ULL, 0x0610038080102000ULL,
0x3601000900100020ULL, 0x0000080080040180ULL, 0x00C2020080040080ULL,
0x0080084400100102ULL, 0x4022408200014401ULL, 0x0040052040800082ULL,
0x0B08200280804000ULL, 0x008A80A008801000ULL, 0x4000480080801000ULL,
0x0911808800801401ULL, 0x822A003002001894ULL, 0x401068091400108AULL,
0x000004A10A00004CULL, 0x2000800640008024ULL, 0x1486408102020020ULL,
0x000100A000D50041ULL, 0x00810050020B0020ULL, 0x0204000800808004ULL,
0x00020048100A000CULL, 0x0112000831020004ULL, 0x0009000040810002ULL,
0x0440490200208200ULL, 0x8910401000200040ULL, 0x6404200050008480ULL,
0x4B824A2010010100ULL, 0x04080801810C0080ULL, 0x00000400802A0080ULL,
0x8224080110026400ULL, 0x40002C4104088200ULL, 0x01002100104A0282ULL,
0x1208400811048021ULL, 0x3201014A40D02001ULL, 0x0005100019200501ULL,
0x0101000208001005ULL, 0x0002008450080702ULL, 0x001002080301D00CULL,
0x410201CE5C030092ULL
};
const int BShift[64] = {
@@ -98,53 +91,53 @@ const int RShift[64] = {
#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,
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,
0x0880A4403064080BULL, 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,
0xD7445CDEC88002C0ULL, 0xD0A505C1F2001722ULL, 0xE065D1C896002182ULL,
0x9A8C41E75A000892ULL, 0x8900B10C89002AA8ULL, 0x9B28D1C1D60005A2ULL,
0x015D6C88DE002D9AULL, 0xB1DBFC802E8016A9ULL, 0x149A1042D9D60029ULL,
0xB9C08050599E002FULL, 0x132208C3AF300403ULL, 0xC1000CE2E9C50070ULL,
0x9D9AA13C99020012ULL, 0xB6B078DAF71E0046ULL, 0x9D880182FB6E002EULL,
0x52889F467E850037ULL, 0xDA6DC008D19A8480ULL, 0x468286034F902420ULL,
0x7140AC09DC54C020ULL, 0xD76FFFFA39548808ULL, 0xEA901C4141500808ULL,
0xC91004093F953A02ULL, 0x02882AFA8F6BB402ULL, 0xAEBE335692442C01ULL,
0x0E904A22079FB91EULL, 0x13A514851055F606ULL, 0x76C782018C8FE632ULL,
0x1DC012A9D116DA06ULL, 0x3C9E0037264FFFA6ULL, 0x2036002853C6E4A2ULL,
0xE3FE08500AFB47D4ULL, 0xF38AF25C86B025C2ULL, 0xC0800E2182CF9A40ULL,
0x72002480D1F60673ULL, 0x2500200BAE6E9B53ULL, 0xC60018C1EEFCA252ULL,
0x0600590473E3608AULL, 0x46002C4AB3FE51B2ULL, 0xA200011486BCC8D2ULL,
0xB680078095784C63ULL, 0x2742002639BF11AEULL, 0xC7D60021A5BDB142ULL,
0xC8C04016BB83D820ULL, 0xBD520028123B4842ULL, 0x9D1600344AC2A832ULL,
0x6A808005631C8A05ULL, 0x604600A148D5389AULL, 0xE2E40103D40DEA65ULL,
0x945B5A0087C62A81ULL, 0x012DC200CD82D28EULL, 0x2431C600B5F9EF76ULL,
0xFB142A006A9B314AULL, 0x06870E00A1C97D62ULL, 0x2A9DB2004A2689A2ULL,
0xD3594600CAF5D1A2ULL, 0xEE0E4900439344A7ULL, 0x89C4D266CA25007AULL,
0x3E0013A2743F97E3ULL, 0x0180E31A0431378AULL, 0x3A9E465A4D42A512ULL,
0x98D0A11A0C0D9CC2ULL, 0x8E711C1ABA19B01EULL, 0x8DCDC836DD201142ULL,
0x5AC08A4735370479ULL,
};
const int BShift[64] = {
@@ -163,54 +156,8 @@ const int RShift[64] = {
#endif // defined(IS_64BIT)
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
}
};
// Global bitboards definitions with static storage duration are
// automatically set to zero before enter main().
Bitboard RMask[64];
int RAttackIndex[64];
Bitboard RAttacks[0x19000];
@@ -222,12 +169,17 @@ Bitboard BAttacks[0x1480];
Bitboard SetMaskBB[65];
Bitboard ClearMaskBB[65];
Bitboard StepAttackBB[16][64];
Bitboard RayBB[64][8];
Bitboard SquaresByColorBB[2];
Bitboard FileBB[8];
Bitboard RankBB[8];
Bitboard NeighboringFilesBB[8];
Bitboard ThisAndNeighboringFilesBB[8];
Bitboard InFrontBB[2][8];
Bitboard StepAttacksBB[16][64];
Bitboard BetweenBB[64][64];
Bitboard SquaresInFrontMask[2][64];
Bitboard PassedPawnMask[2][64];
Bitboard OutpostMask[2][64];
Bitboard AttackSpanMask[2][64];
Bitboard BishopPseudoAttacks[64];
Bitboard RookPseudoAttacks[64];
@@ -236,73 +188,49 @@ Bitboard QueenPseudoAttacks[64];
uint8_t BitCount8Bit[256];
////
//// Local definitions
////
namespace {
void init_masks();
void init_ray_bitboards();
void init_attacks();
void init_between_bitboards();
Bitboard sliding_attacks(int sq, Bitboard block, int dirs, int deltas[][2],
int fmin, int fmax, int rmin, int rmax);
Bitboard index_to_bitboard(int index, Bitboard mask);
void init_sliding_attacks(Bitboard attacks[],
int attackIndex[], Bitboard mask[],
const int shift[2], const Bitboard mult[],
int deltas[][2]);
void init_step_attacks();
void init_pseudo_attacks();
void init_between_bitboards();
Bitboard index_to_bitboard(int index, Bitboard mask);
Bitboard sliding_attacks(int sq, Bitboard occupied, int deltas[][2],
int fmin, int fmax, int rmin, int rmax);
void init_sliding_attacks(Bitboard attacks[], int attackIndex[], Bitboard mask[],
const int shift[], const Bitboard mult[], int deltas[][2]);
}
////
//// Functions
////
/// print_bitboard() prints a bitboard in an easily readable format to the
/// standard output. This is sometimes useful for debugging.
/// standard output. This is sometimes useful for debugging.
void print_bitboard(Bitboard b) {
for(Rank r = RANK_8; r >= RANK_1; r--) {
std::cout << "+---+---+---+---+---+---+---+---+" << std::endl;
for(File f = FILE_A; f <= FILE_H; f++)
std::cout << "| " << (bit_is_set(b, make_square(f, r))? 'X' : ' ') << ' ';
std::cout << "|" << std::endl;
for (Rank r = RANK_8; r >= RANK_1; r--)
{
std::cout << "+---+---+---+---+---+---+---+---+" << '\n';
for (File f = FILE_A; f <= FILE_H; f++)
std::cout << "| " << (bit_is_set(b, make_square(f, r)) ? 'X' : ' ') << ' ';
std::cout << "|\n";
}
std::cout << "+---+---+---+---+---+---+---+---+" << std::endl;
}
/// init_bitboards() initializes various bitboard arrays. It is called during
/// program initialization.
void init_bitboards() {
int rookDeltas[4][2] = {{0,1},{0,-1},{1,0},{-1,0}};
int bishopDeltas[4][2] = {{1,1},{-1,1},{1,-1},{-1,-1}};
init_masks();
init_ray_bitboards();
init_attacks();
init_between_bitboards();
init_sliding_attacks(RAttacks, RAttackIndex, RMask, RShift, RMult, rookDeltas);
init_sliding_attacks(BAttacks, BAttackIndex, BMask, BShift, BMult, bishopDeltas);
init_pseudo_attacks();
}
/// 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(IS_64BIT) && !defined(USE_BSFQ)
CACHE_LINE_ALIGNMENT
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,
46, 29, 48, 10, 31, 35, 54, 21, 50, 41, 57, 63, 6, 12, 18, 24, 27, 33, 39,
16, 37, 45, 47, 30, 53, 49, 56, 62, 11, 23, 32, 36, 44, 52, 55, 61, 22, 43,
51, 60, 42, 59, 58
static CACHE_LINE_ALIGNMENT
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, 46, 29, 48, 10, 31, 35, 54, 21, 50, 41, 57, 63, 6, 12, 18, 24, 27,
33, 39, 16, 37, 45, 47, 30, 53, 49, 56, 62, 11, 23, 32, 36, 44, 52, 55, 61,
22, 43, 51, 60, 42, 59, 58
};
Square first_1(Bitboard b) {
@@ -319,13 +247,14 @@ Square pop_1st_bit(Bitboard* b) {
static CACHE_LINE_ALIGNMENT
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
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]);
@@ -366,29 +295,23 @@ Square pop_1st_bit(Bitboard* bb) {
return ret;
}
#endif
#endif // !defined(USE_BSFQ)
int bitScanReverse32(uint32_t b)
{
int result = 0;
if (b > 0xFFFF) {
b >>= 16;
result += 16;
}
if (b > 0xFF) {
b >>= 8;
result += 8;
}
if (b > 0xF) {
b >>= 4;
result += 4;
}
if (b > 0x3) {
b >>= 2;
result += 2;
}
return result + (b > 0) + (b > 1);
/// init_bitboards() initializes various bitboard arrays. It is called during
/// program initialization.
void init_bitboards() {
int rookDeltas[4][2] = {{0,1},{0,-1},{1,0},{-1,0}};
int bishopDeltas[4][2] = {{1,1},{-1,1},{1,-1},{-1,-1}};
init_masks();
init_step_attacks();
init_sliding_attacks(RAttacks, RAttackIndex, RMask, RShift, RMult, rookDeltas);
init_sliding_attacks(BAttacks, BAttackIndex, BMask, BShift, BMult, bishopDeltas);
init_pseudo_attacks();
init_between_bitboards();
}
namespace {
@@ -399,146 +322,165 @@ namespace {
// be necessary to touch any of them.
void init_masks() {
SetMaskBB[SQ_NONE] = 0ULL;
SquaresByColorBB[DARK] = 0xAA55AA55AA55AA55ULL;
SquaresByColorBB[LIGHT] = ~SquaresByColorBB[DARK];
FileBB[FILE_A] = FileABB;
RankBB[RANK_1] = Rank1BB;
for (int f = FILE_B; f <= FILE_H; f++)
{
FileBB[f] = FileBB[f - 1] << 1;
RankBB[f] = RankBB[f - 1] << 8;
}
for (int f = FILE_A; f <= FILE_H; f++)
{
NeighboringFilesBB[f] = (f > FILE_A ? FileBB[f - 1] : 0) | (f < FILE_H ? FileBB[f + 1] : 0);
ThisAndNeighboringFilesBB[f] = FileBB[f] | NeighboringFilesBB[f];
}
for (int rw = RANK_7, rb = RANK_2; rw >= RANK_1; rw--, rb++)
{
InFrontBB[WHITE][rw] = InFrontBB[WHITE][rw + 1] | RankBB[rw + 1];
InFrontBB[BLACK][rb] = InFrontBB[BLACK][rb - 1] | RankBB[rb - 1];
}
SetMaskBB[SQ_NONE] = EmptyBoardBB;
ClearMaskBB[SQ_NONE] = ~SetMaskBB[SQ_NONE];
for(Square s = SQ_A1; s <= SQ_H8; s++) {
SetMaskBB[s] = (1ULL << s);
ClearMaskBB[s] = ~SetMaskBB[s];
for (Square s = SQ_A1; s <= SQ_H8; s++)
{
SetMaskBB[s] = (1ULL << s);
ClearMaskBB[s] = ~SetMaskBB[s];
}
for(Color c = WHITE; c <= BLACK; c++)
for(Square s = SQ_A1; s <= SQ_H8; s++) {
PassedPawnMask[c][s] =
in_front_bb(c, s) & this_and_neighboring_files_bb(s);
OutpostMask[c][s] = in_front_bb(c, s) & neighboring_files_bb(s);
}
for (Bitboard b = 0ULL; b < 256ULL; b++)
BitCount8Bit[b] = (uint8_t)count_1s(b);
}
void init_ray_bitboards() {
int d[8] = {1, -1, 16, -16, 17, -17, 15, -15};
for(int i = 0; i < 128; i = (i + 9) & ~8) {
for(int j = 0; j < 8; j++) {
RayBB[(i&7)|((i>>4)<<3)][j] = EmptyBoardBB;
for(int k = i + d[j]; (k & 0x88) == 0; k += d[j])
set_bit(&(RayBB[(i&7)|((i>>4)<<3)][j]), Square((k&7)|((k>>4)<<3)));
}
}
}
void init_attacks() {
int i, j, k, l;
int step[16][8] = {
{0},
{7,9,0}, {17,15,10,6,-6,-10,-15,-17}, {9,7,-7,-9,0}, {8,1,-1,-8,0},
{9,7,-7,-9,8,1,-1,-8}, {9,7,-7,-9,8,1,-1,-8}, {0}, {0},
{-7,-9,0}, {17,15,10,6,-6,-10,-15,-17}, {9,7,-7,-9,0}, {8,1,-1,-8,0},
{9,7,-7,-9,8,1,-1,-8}, {9,7,-7,-9,8,1,-1,-8}
};
for(i = 0; i < 64; i++) {
for(j = 0; j <= int(BK); j++) {
StepAttackBB[j][i] = EmptyBoardBB;
for(k = 0; k < 8 && step[j][k] != 0; k++) {
l = i + step[j][k];
if(l >= 0 && l < 64 && abs((i&7) - (l&7)) < 3)
StepAttackBB[j][i] |= (1ULL << l);
for (Color c = WHITE; c <= BLACK; c++)
for (Square s = SQ_A1; s <= SQ_H8; s++)
{
SquaresInFrontMask[c][s] = in_front_bb(c, s) & file_bb(s);
PassedPawnMask[c][s] = in_front_bb(c, s) & this_and_neighboring_files_bb(s);
AttackSpanMask[c][s] = in_front_bb(c, s) & neighboring_files_bb(s);
}
}
}
for (Bitboard b = 0; b < 256; b++)
BitCount8Bit[b] = (uint8_t)count_1s<CNT32>(b);
}
void init_step_attacks() {
Bitboard sliding_attacks(int sq, Bitboard block, int dirs, int deltas[][2],
int fmin=0, int fmax=7, int rmin=0, int rmax=7) {
Bitboard result = 0ULL;
int rk = sq / 8, fl = sq % 8, r, f, i;
for(i = 0; i < dirs; i++) {
int dx = deltas[i][0], dy = deltas[i][1];
for(f = fl+dx, r = rk+dy;
(dx==0 || (f>=fmin && f<=fmax)) && (dy==0 || (r>=rmin && r<=rmax));
f += dx, r += dy) {
result |= (1ULL << (f + r*8));
if(block & (1ULL << (f + r*8))) break;
}
}
return result;
}
void init_between_bitboards() {
SquareDelta step[8] = {
DELTA_E, DELTA_W, DELTA_N, DELTA_S, DELTA_NE, DELTA_SW, DELTA_NW, DELTA_SE
const int step[][9] = {
{0},
{7,9,0}, {17,15,10,6,-6,-10,-15,-17,0}, {0}, {0}, {0},
{9,7,-7,-9,8,1,-1,-8,0}, {0}, {0},
{-7,-9,0}, {17,15,10,6,-6,-10,-15,-17,0}, {0}, {0}, {0},
{9,7,-7,-9,8,1,-1,-8,0}
};
SignedDirection d;
for(Square s1 = SQ_A1; s1 <= SQ_H8; s1++)
for(Square s2 = SQ_A1; s2 <= SQ_H8; s2++) {
BetweenBB[s1][s2] = EmptyBoardBB;
d = signed_direction_between_squares(s1, s2);
if(d != SIGNED_DIR_NONE)
for(Square s3 = s1 + step[d]; s3 != s2; s3 += step[d])
set_bit(&(BetweenBB[s1][s2]), s3);
}
for (Square s = SQ_A1; s <= SQ_H8; s++)
for (Piece pc = WP; pc <= BK; pc++)
for (int k = 0; step[pc][k] != 0; k++)
{
Square to = s + Square(step[pc][k]);
if (square_is_ok(to) && square_distance(s, to) < 3)
set_bit(&StepAttacksBB[pc][s], to);
}
}
Bitboard sliding_attacks(int sq, Bitboard occupied, int deltas[][2],
int fmin, int fmax, int rmin, int rmax) {
int dx, dy, f, r;
int rk = sq / 8;
int fl = sq % 8;
Bitboard attacks = EmptyBoardBB;
for (int i = 0; i < 4; i++)
{
dx = deltas[i][0];
dy = deltas[i][1];
f = fl + dx;
r = rk + dy;
while ( (dx == 0 || (f >= fmin && f <= fmax))
&& (dy == 0 || (r >= rmin && r <= rmax)))
{
attacks |= (1ULL << (f + r * 8));
if (occupied & (1ULL << (f + r * 8)))
break;
f += dx;
r += dy;
}
}
return attacks;
}
Bitboard index_to_bitboard(int index, Bitboard mask) {
int i, j, bits = count_1s(mask);
Bitboard result = 0ULL;
for(i = 0; i < bits; i++) {
j = pop_1st_bit(&mask);
if(index & (1 << i)) result |= (1ULL << j);
Bitboard result = EmptyBoardBB;
int sq, cnt = 0;
while (mask)
{
sq = pop_1st_bit(&mask);
if (index & (1 << cnt++))
result |= (1ULL << sq);
}
return result;
}
void init_sliding_attacks(Bitboard attacks[], int attackIndex[], Bitboard mask[],
const int shift[], const Bitboard mult[], int deltas[][2]) {
Bitboard b, v;
int i, j, index;
void init_sliding_attacks(Bitboard attacks[],
int attackIndex[], Bitboard mask[],
const int shift[2], const Bitboard mult[],
int deltas[][2]) {
int i, j, k, index = 0;
Bitboard b;
for(i = 0; i < 64; i++) {
attackIndex[i] = index;
mask[i] = sliding_attacks(i, 0ULL, 4, deltas, 1, 6, 1, 6);
for (i = index = 0; i < 64; i++)
{
attackIndex[i] = index;
mask[i] = sliding_attacks(i, 0, deltas, 1, 6, 1, 6);
j = 1 << ((CpuIs64Bit ? 64 : 32) - shift[i]);
#if defined(IS_64BIT)
j = (1 << (64 - shift[i]));
#else
j = (1 << (32 - shift[i]));
#endif
for(k = 0; k < j; k++) {
#if defined(IS_64BIT)
b = index_to_bitboard(k, mask[i]);
attacks[index + ((b * mult[i]) >> shift[i])] =
sliding_attacks(i, b, 4, deltas);
#else
b = index_to_bitboard(k, mask[i]);
attacks[index +
(unsigned(int(b) * int(mult[i]) ^
int(b >> 32) * int(mult[i] >> 32))
>> shift[i])] =
sliding_attacks(i, b, 4, deltas);
#endif
}
index += j;
for (int k = 0; k < j; k++)
{
b = index_to_bitboard(k, mask[i]);
v = CpuIs64Bit ? b * mult[i] : unsigned(b * mult[i] ^ (b >> 32) * (mult[i] >> 32));
attacks[index + (v >> shift[i])] = sliding_attacks(i, b, deltas, 0, 7, 0, 7);
}
index += j;
}
}
void init_pseudo_attacks() {
Square s;
for(s = SQ_A1; s <= SQ_H8; s++) {
BishopPseudoAttacks[s] = bishop_attacks_bb(s, EmptyBoardBB);
RookPseudoAttacks[s] = rook_attacks_bb(s, EmptyBoardBB);
QueenPseudoAttacks[s] = queen_attacks_bb(s, EmptyBoardBB);
for (Square s = SQ_A1; s <= SQ_H8; s++)
{
BishopPseudoAttacks[s] = bishop_attacks_bb(s, EmptyBoardBB);
RookPseudoAttacks[s] = rook_attacks_bb(s, EmptyBoardBB);
QueenPseudoAttacks[s] = queen_attacks_bb(s, EmptyBoardBB);
}
}
void init_between_bitboards() {
Square s1, s2, s3, d;
int f, r;
for (s1 = SQ_A1; s1 <= SQ_H8; s1++)
for (s2 = SQ_A1; s2 <= SQ_H8; s2++)
if (bit_is_set(QueenPseudoAttacks[s1], s2))
{
f = file_distance(s1, s2);
r = rank_distance(s1, s2);
d = (s2 - s1) / Max(f, r);
for (s3 = s1 + d; s3 != s2; s3 += d)
set_bit(&(BetweenBB[s1][s2]), s3);
}
}
}
+69 -129
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,64 +18,47 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined(BITBOARD_H_INCLUDED)
#define BITBOARD_H_INCLUDED
////
//// Includes
////
#include "direction.h"
#include "piece.h"
#include "square.h"
#include "types.h"
////
//// Constants and variables
////
const Bitboard EmptyBoardBB = 0ULL;
const Bitboard WhiteSquaresBB = 0x55AA55AA55AA55AAULL;
const Bitboard BlackSquaresBB = 0xAA55AA55AA55AA55ULL;
const Bitboard EmptyBoardBB = 0;
const Bitboard FileABB = 0x0101010101010101ULL;
const Bitboard FileBBB = 0x0202020202020202ULL;
const Bitboard FileCBB = 0x0404040404040404ULL;
const Bitboard FileDBB = 0x0808080808080808ULL;
const Bitboard FileEBB = 0x1010101010101010ULL;
const Bitboard FileFBB = 0x2020202020202020ULL;
const Bitboard FileGBB = 0x4040404040404040ULL;
const Bitboard FileHBB = 0x8080808080808080ULL;
const Bitboard FileBBB = FileABB << 1;
const Bitboard FileCBB = FileABB << 2;
const Bitboard FileDBB = FileABB << 3;
const Bitboard FileEBB = FileABB << 4;
const Bitboard FileFBB = FileABB << 5;
const Bitboard FileGBB = FileABB << 6;
const Bitboard FileHBB = FileABB << 7;
const Bitboard Rank1BB = 0xFFULL;
const Bitboard Rank2BB = 0xFF00ULL;
const Bitboard Rank3BB = 0xFF0000ULL;
const Bitboard Rank4BB = 0xFF000000ULL;
const Bitboard Rank5BB = 0xFF00000000ULL;
const Bitboard Rank6BB = 0xFF0000000000ULL;
const Bitboard Rank7BB = 0xFF000000000000ULL;
const Bitboard Rank8BB = 0xFF00000000000000ULL;
const Bitboard Rank1BB = 0xFF;
const Bitboard Rank2BB = Rank1BB << (8 * 1);
const Bitboard Rank3BB = Rank1BB << (8 * 2);
const Bitboard Rank4BB = Rank1BB << (8 * 3);
const Bitboard Rank5BB = Rank1BB << (8 * 4);
const Bitboard Rank6BB = Rank1BB << (8 * 5);
const Bitboard Rank7BB = Rank1BB << (8 * 6);
const Bitboard Rank8BB = Rank1BB << (8 * 7);
extern const Bitboard SquaresByColorBB[2];
extern const Bitboard FileBB[8];
extern const Bitboard NeighboringFilesBB[8];
extern const Bitboard ThisAndNeighboringFilesBB[8];
extern const Bitboard RankBB[8];
extern const Bitboard RelativeRankBB[2][8];
extern const Bitboard InFrontBB[2][8];
extern Bitboard SquaresByColorBB[2];
extern Bitboard FileBB[8];
extern Bitboard NeighboringFilesBB[8];
extern Bitboard ThisAndNeighboringFilesBB[8];
extern Bitboard RankBB[8];
extern Bitboard InFrontBB[2][8];
extern Bitboard SetMaskBB[65];
extern Bitboard ClearMaskBB[65];
extern Bitboard StepAttackBB[16][64];
extern Bitboard RayBB[64][8];
extern Bitboard StepAttacksBB[16][64];
extern Bitboard BetweenBB[64][64];
extern Bitboard SquaresInFrontMask[2][64];
extern Bitboard PassedPawnMask[2][64];
extern Bitboard OutpostMask[2][64];
extern Bitboard AttackSpanMask[2][64];
extern const uint64_t RMult[64];
extern const int RShift[64];
@@ -96,10 +79,6 @@ extern Bitboard QueenPseudoAttacks[64];
extern uint8_t BitCount8Bit[256];
////
//// Inline functions
////
/// Functions for testing whether a given bit is set in a bitboard, and for
/// setting and clearing bits.
@@ -127,16 +106,16 @@ inline void do_move_bb(Bitboard *b, Bitboard move_bb) {
*b ^= move_bb;
}
/// rank_bb() and file_bb() gives a bitboard containing all squares on a given
/// file or rank. It is also possible to pass a square as input to these
/// functions.
/// rank_bb() and file_bb() take a file or a square as input and return
/// a bitboard representing all squares on the given file or rank.
inline Bitboard rank_bb(Rank r) {
return RankBB[r];
}
inline Bitboard rank_bb(Square s) {
return rank_bb(square_rank(s));
return RankBB[square_rank(s)];
}
inline Bitboard file_bb(File f) {
@@ -144,11 +123,11 @@ inline Bitboard file_bb(File f) {
}
inline Bitboard file_bb(Square s) {
return file_bb(square_file(s));
return FileBB[square_file(s)];
}
/// neighboring_files_bb takes a file or a square as input, and returns a
/// neighboring_files_bb takes a file or a square as input and returns a
/// bitboard representing all squares on the neighboring files.
inline Bitboard neighboring_files_bb(File f) {
@@ -156,31 +135,19 @@ inline Bitboard neighboring_files_bb(File f) {
}
inline Bitboard neighboring_files_bb(Square s) {
return neighboring_files_bb(square_file(s));
return NeighboringFilesBB[square_file(s)];
}
/// this_and_neighboring_files_bb takes a file or a square as input, and
/// returns a bitboard representing all squares on the given and neighboring
/// files.
/// this_and_neighboring_files_bb takes a file or a square as input and returns
/// a bitboard representing all squares on the given and neighboring files.
inline Bitboard this_and_neighboring_files_bb(File f) {
return ThisAndNeighboringFilesBB[f];
}
inline Bitboard this_and_neighboring_files_bb(Square s) {
return this_and_neighboring_files_bb(square_file(s));
}
/// 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
/// 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
/// rank.
inline Bitboard relative_rank_bb(Color c, Rank r) {
return RelativeRankBB[c][r];
return ThisAndNeighboringFilesBB[square_file(s)];
}
@@ -195,28 +162,7 @@ inline Bitboard in_front_bb(Color c, Rank r) {
}
inline Bitboard in_front_bb(Color c, Square s) {
return in_front_bb(c, square_rank(s));
}
/// 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
/// given direction from a given square.
inline Bitboard ray_bb(Square s, SignedDirection d) {
return RayBB[s][d];
return InFrontBB[c][square_rank(s)];
}
@@ -242,17 +188,13 @@ inline Bitboard bishop_attacks_bb(Square s, Bitboard blockers) {
inline Bitboard rook_attacks_bb(Square s, Bitboard blockers) {
Bitboard b = blockers & RMask[s];
return RAttacks[RAttackIndex[s] +
(unsigned(int(b) * int(RMult[s]) ^
int(b >> 32) * int(RMult[s] >> 32))
>> RShift[s])];
(unsigned(int(b) * int(RMult[s]) ^ int(b >> 32) * int(RMult[s] >> 32)) >> RShift[s])];
}
inline Bitboard bishop_attacks_bb(Square s, Bitboard blockers) {
Bitboard b = blockers & BMask[s];
return BAttacks[BAttackIndex[s] +
(unsigned(int(b) * int(BMult[s]) ^
int(b >> 32) * int(BMult[s] >> 32))
>> BShift[s])];
(unsigned(int(b) * int(BMult[s]) ^ int(b >> 32) * int(BMult[s] >> 32)) >> BShift[s])];
}
#endif
@@ -274,46 +216,40 @@ inline Bitboard squares_between(Square s1, Square s2) {
/// squares_in_front_of takes a color and a square as input, and returns a
/// bitboard representing all squares along the line in front of the square,
/// from the point of view of the given color. For instance,
/// squares_in_front_of(BLACK, SQ_E4) returns a bitboard with the squares
/// e3, e2 and e1 set.
/// from the point of view of the given color. Definition of the table is:
/// SquaresInFrontOf[c][s] = in_front_bb(c, s) & file_bb(s)
inline Bitboard squares_in_front_of(Color c, Square s) {
return in_front_bb(c, s) & file_bb(s);
}
/// squares_behind is similar to squares_in_front, but returns the squares
/// behind the square instead of in front of the square.
inline Bitboard squares_behind(Color c, Square s) {
return in_front_bb(opposite_color(c), s) & file_bb(s);
return SquaresInFrontMask[c][s];
}
/// passed_pawn_mask takes a color and a square as input, and returns a
/// bitboard mask which can be used to test if a pawn of the given color on
/// the given square is a passed pawn.
/// the given square is a passed pawn. Definition of the table is:
/// PassedPawnMask[c][s] = in_front_bb(c, s) & this_and_neighboring_files_bb(s)
inline Bitboard passed_pawn_mask(Color c, Square s) {
return PassedPawnMask[c][s];
}
/// outpost_mask takes a color and a square as input, and returns a bitboard
/// mask which can be used to test whether a piece on the square can possibly
/// be driven away by an enemy pawn.
/// attack_span_mask takes a color and a square as input, and returns a bitboard
/// representing all squares that can be attacked by a pawn of the given color
/// when it moves along its file starting from the given square. Definition is:
/// AttackSpanMask[c][s] = in_front_bb(c, s) & neighboring_files_bb(s);
inline Bitboard outpost_mask(Color c, Square s) {
return OutpostMask[c][s];
inline Bitboard attack_span_mask(Color c, Square s) {
return AttackSpanMask[c][s];
}
/// isolated_pawn_mask takes a square as input, and returns a bitboard mask
/// which can be used to test whether a pawn on the given square is isolated.
/// squares_aligned returns true if the squares s1, s2 and s3 are aligned
/// either on a straight or on a diagonal line.
inline Bitboard isolated_pawn_mask(Square s) {
return neighboring_files_bb(s);
inline bool squares_aligned(Square s1, Square s2, Square s3) {
return (BetweenBB[s1][s2] | BetweenBB[s1][s3] | BetweenBB[s2][s3])
& ((1ULL << s1) | (1ULL << s2) | (1ULL << s3));
}
@@ -321,15 +257,25 @@ inline Bitboard isolated_pawn_mask(Square s) {
/// pop_1st_bit() finds and clears the least significant nonzero bit in a
/// nonzero bitboard.
#if defined(USE_BSFQ) // Assembly code by Heinz van Saanen
#if defined(USE_BSFQ)
inline Square first_1(Bitboard b) {
#if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
FORCE_INLINE Square first_1(Bitboard b) {
unsigned long index;
_BitScanForward64(&index, b);
return (Square) index;
}
#else
FORCE_INLINE Square first_1(Bitboard b) { // Assembly code by Heinz van Saanen
Bitboard dummy;
__asm__("bsfq %1, %0": "=r"(dummy): "rm"(b) );
return (Square)(dummy);
return (Square) dummy;
}
#endif
inline Square pop_1st_bit(Bitboard* b) {
FORCE_INLINE Square pop_1st_bit(Bitboard* b) {
const Square s = first_1(*b);
*b &= ~(1ULL<<s);
return s;
@@ -343,13 +289,7 @@ extern Square pop_1st_bit(Bitboard* b);
#endif
////
//// Prototypes
////
extern void print_bitboard(Bitboard b);
extern void init_bitboards();
extern int bitScanReverse32(uint32_t b);
#endif // !defined(BITBOARD_H_INCLUDED)
+35 -104
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,79 +18,28 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined(BITCOUNT_H_INCLUDED)
#define BITCOUNT_H_INCLUDED
#include "types.h"
// Select type of intrinsic bit count instruction to use, see
// README.txt on how to pgo compile with POPCNT support.
enum BitCountType {
CNT64,
CNT64_MAX15,
CNT32,
CNT32_MAX15,
CNT_POPCNT
};
#if defined(__INTEL_COMPILER) && defined(USE_POPCNT) // Intel compiler
/// count_1s() counts the number of nonzero bits in a bitboard.
/// We have different optimized versions according if platform
/// is 32 or 64 bits, and to the maximum number of nonzero bits.
/// We also support hardware popcnt instruction. See Readme.txt
/// on how to pgo compile with popcnt support.
template<BitCountType> inline int count_1s(Bitboard);
#include <nmmintrin.h>
inline bool cpu_has_popcnt() {
int CPUInfo[4] = {-1};
__cpuid(CPUInfo, 0x00000001);
return (CPUInfo[2] >> 23) & 1;
}
#define POPCNT_INTRINSIC(x) _mm_popcnt_u64(x)
#elif defined(_MSC_VER) && 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;
}
#define POPCNT_INTRINSIC(x) __popcnt64(x)
#elif defined(__GNUC__) && defined(USE_POPCNT) // Gcc compiler
inline void __cpuid(unsigned int op,
unsigned int *eax, unsigned int *ebx,
unsigned int *ecx, unsigned int *edx)
{
*eax = op;
*ecx = 0;
__asm__("cpuid" : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx)
: "0" (*eax), "2" (*ecx));
}
inline bool cpu_has_popcnt() {
unsigned int eax, ebx, ecx, edx;
__cpuid(1, &eax, &ebx, &ecx, &edx);
return (ecx >> 23) & 1;
}
#define POPCNT_INTRINSIC(x) ({ \
unsigned long __ret; \
__asm__("popcnt %1, %0" : "=r" (__ret) : "r" (x)); \
__ret; })
#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) {
template<>
inline int count_1s<CNT64>(Bitboard b) {
b -= ((b>>1) & 0x5555555555555555ULL);
b = ((b>>2) & 0x3333333333333333ULL) + (b & 0x3333333333333333ULL);
b = ((b>>4) + b) & 0x0F0F0F0F0F0F0F0FULL;
@@ -98,16 +47,16 @@ inline int count_1s(Bitboard b) {
return int(b >> 56);
}
inline int count_1s_max_15(Bitboard b) {
template<>
inline int count_1s<CNT64_MAX15>(Bitboard b) {
b -= (b>>1) & 0x5555555555555555ULL;
b = ((b>>2) & 0x3333333333333333ULL) + (b & 0x3333333333333333ULL);
b *= 0x1111111111111111ULL;
return int(b >> 60);
}
#else // if !defined(IS_64BIT)
inline int count_1s(Bitboard b) {
template<>
inline int count_1s<CNT32>(Bitboard b) {
unsigned w = unsigned(b >> 32), v = unsigned(b);
v -= (v >> 1) & 0x55555555; // 0-2 in 2 bits
w -= (w >> 1) & 0x55555555;
@@ -119,7 +68,8 @@ inline int count_1s(Bitboard b) {
return int(v >> 24);
}
inline int count_1s_max_15(Bitboard b) {
template<>
inline int count_1s<CNT32_MAX15>(Bitboard b) {
unsigned w = unsigned(b >> 32), v = unsigned(b);
v -= (v >> 1) & 0x55555555; // 0-2 in 2 bits
w -= (w >> 1) & 0x55555555;
@@ -130,38 +80,19 @@ inline int count_1s_max_15(Bitboard b) {
return int(v >> 28);
}
#endif // BITCOUNT
/// count_1s() counts the number of nonzero bits in a bitboard.
/// If template parameter is true an intrinsic is called, otherwise
/// we fallback on a software implementation.
template<bool UseIntrinsic>
inline int count_1s(Bitboard b) {
return UseIntrinsic ? POPCNT_INTRINSIC(b) : count_1s(b);
}
template<bool UseIntrinsic>
inline int count_1s_max_15(Bitboard b) {
return UseIntrinsic ? POPCNT_INTRINSIC(b) : count_1s_max_15(b);
}
// 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;
template<>
inline int count_1s<CNT_POPCNT>(Bitboard b) {
#if !defined(USE_POPCNT)
return int(b != 0); // Avoid 'b not used' warning
#elif defined(_MSC_VER) && defined(__INTEL_COMPILER)
return _mm_popcnt_u64(b);
#elif defined(_MSC_VER)
return (int)__popcnt64(b);
#elif defined(__GNUC__)
unsigned long ret;
__asm__("popcnt %1, %0" : "=r" (ret) : "r" (b));
return ret;
#endif
}
#endif // !defined(BITCOUNT_H_INCLUDED)
+138 -196
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,42 +20,21 @@
/*
The code in this file is based on the opening book code in PolyGlot
by Fabien Letouzey. PolyGlot is available under the GNU General
by Fabien Letouzey. PolyGlot is available under the GNU General
Public License, and can be downloaded from http://wbec-ridderkerk.nl
*/
////
//// Includes
////
#include <cassert>
#include <iostream>
#include "book.h"
#include "mersenne.h"
#include "movegen.h"
using namespace std;
////
//// Global variables
////
Book OpeningBook;
////
//// Local definitions
////
namespace {
/// Book entry size in bytes
const int EntrySize = 16;
/// Random numbers from PolyGlot, used to compute book hash keys
// Random numbers from PolyGlot, used to compute book hash keys
const uint64_t Random64[781] = {
0x9D39247E33776D41ULL, 0x2AF7398005AAA5C7ULL, 0x44DB015024623547ULL,
0x9C15F73E62A76AE2ULL, 0x75834465489C0C89ULL, 0x3290AC3A203001BFULL,
@@ -320,31 +299,62 @@ namespace {
0xF8D626AAAF278509ULL
};
// Indices to the Random64[] array
const int PieceIdx = 0;
const int CastleIdx = 768;
const int EnPassantIdx = 772;
const int TurnIdx = 780;
/// Indices to the Random64[] array
// book_key() builds up a PolyGlot hash key out of a position
uint64_t book_key(const Position& pos) {
const int RandomPiece = 0;
const int RandomCastle = 768;
const int RandomEnPassant = 772;
const int RandomTurn = 780;
// Piece offset is calculated as (64 * PolyPieceType + square), where
// PolyPieceType is: BP = 0, WP = 1, BN = 2, WN = 3 .... BK = 10, WK = 11
static const int PieceToPoly[] = { 0, 1, 3, 5, 7, 9, 11, 0, 0, 0, 2, 4, 6, 8, 10 };
uint64_t result = 0;
Bitboard b = pos.occupied_squares();
/// Prototypes
while (b)
{
Square s = pop_1st_bit(&b);
int p = PieceToPoly[int(pos.piece_on(s))];
result ^= Random64[PieceIdx + 64 * p + int(s)];
}
if (pos.can_castle_kingside(WHITE))
result ^= Random64[CastleIdx + 0];
if (pos.can_castle_queenside(WHITE))
result ^= Random64[CastleIdx + 1];
if (pos.can_castle_kingside(BLACK))
result ^= Random64[CastleIdx + 2];
if (pos.can_castle_queenside(BLACK))
result ^= Random64[CastleIdx + 3];
if (pos.ep_square() != SQ_NONE)
result ^= Random64[EnPassantIdx + square_file(pos.ep_square())];
if (pos.side_to_move() == WHITE)
result ^= Random64[TurnIdx];
return result;
}
uint64_t book_key(const Position& pos);
uint64_t book_piece_key(Piece p, Square s);
uint64_t book_castle_key(const Position& pos);
uint64_t book_ep_key(const Position& pos);
uint64_t book_color_key(const Position& pos);
}
////
//// Functions
////
/// Book c'tor. Make random number generation less deterministic, for book moves
Book::Book() {
for (int i = abs(get_system_time() % 10000); i > 0; i--)
RKiss.rand<unsigned>();
}
/// Destructor. Be sure file is closed before we leave.
/// Book destructor. Be sure file is closed before we leave.
Book::~Book() {
@@ -352,102 +362,121 @@ Book::~Book() {
}
/// Book::open() opens a book file with a given file name
void Book::open(const string& fName) {
// Close old file before opening the new
close();
fileName = fName;
ifstream::open(fileName.c_str(), ifstream::in | ifstream::binary);
if (!is_open())
return;
// Get the book size in number of entries
seekg(0, ios::end);
bookSize = tellg() / EntrySize;
seekg(0, ios::beg);
if (!good())
{
cerr << "Failed to open book file " << fileName << endl;
Application::exit_with_failure();
}
}
/// Book::close() closes the file only if it is open, otherwise
/// we can end up in a little mess due to how std::ifstream works.
void Book::close() {
if (is_open())
ifstream::close();
if (bookFile.is_open())
bookFile.close();
bookName = "";
}
/// Book::file_name() returns the file name of the currently active book,
/// or the empty string if no book is open.
/// Book::open() opens a book file with a given file name
const string Book::file_name() const {
void Book::open(const string& fileName) {
return is_open() ? fileName : "";
// Close old file before opening the new
close();
bookFile.open(fileName.c_str(), ifstream::in | ifstream::binary);
// Silently return when asked to open a non-exsistent file
if (!bookFile.is_open())
return;
// Get the book size in number of entries
bookFile.seekg(0, ios::end);
bookSize = long(bookFile.tellg()) / sizeof(BookEntry);
if (!bookFile.good())
{
cerr << "Failed to open book file " << fileName << endl;
exit(EXIT_FAILURE);
}
// Set only if successful
bookName = fileName;
}
/// 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. If findBestMove is true then
/// return always the highest rated book move.
Move Book::get_move(const Position& pos) {
Move Book::get_move(const Position& pos, bool findBestMove) {
if (!is_open() || bookSize == 0)
if (!bookFile.is_open() || bookSize == 0)
return MOVE_NONE;
int bookMove = 0, scoresSum = 0;
uint64_t key = book_key(pos);
BookEntry entry;
int bookMove = MOVE_NONE;
unsigned score, scoresSum = 0, bestScore = 0;
uint64_t key = book_key(pos);
// Choose a book move among the possible moves for the given position
for (int idx = find_key(key); idx < bookSize; idx++)
for (int idx = find_entry(key); idx < bookSize; idx++)
{
read_entry(entry, idx);
entry = read_entry(idx);
if (entry.key != key)
break;
int score = entry.count;
score = entry.count;
assert(score > 0);
// Choose book move according to its score. If a move has a very
// high score it has more probability to be choosen then a one with
// lower score. Note that first entry is always chosen.
scoresSum += score;
if (int(genrand_int32() % scoresSum) < score)
if (!findBestMove)
{
// Choose book move according to its score. If a move has a very
// high score it has more probability to be choosen then a one with
// lower score. Note that first entry is always chosen.
scoresSum += score;
if (RKiss.rand<unsigned>() % scoresSum < score)
bookMove = entry.move;
}
else if (score > bestScore)
{
bestScore = score;
bookMove = entry.move;
}
}
if (!bookMove)
return MOVE_NONE;
MoveStack mlist[256];
MoveStack* last = generate_moves(pos, mlist);
// A PolyGlot book move is encoded as follows:
//
// bit 0- 5: destination square (from 0 to 63)
// bit 6-11: origin square (from 0 to 63)
// bit 12-13-14: promotion piece (from KNIGHT == 1 to QUEEN == 4)
//
// Castling moves follow "king captures rook" representation. So in case
// book move is a promotion we have to convert to our representation, in
// all other cases we can directly compare with a Move after having
// masked out special Move's flags that are not supported by PolyGlot.
int p = (bookMove >> 12) & 7;
if (p)
bookMove = int(make_promotion_move(move_from(Move(bookMove)),
move_to(Move(bookMove)), PieceType(p + 1)));
// Verify the book move (if any) is legal
MoveStack mlist[MAX_MOVES];
MoveStack* last = generate<MV_LEGAL>(pos, mlist);
for (MoveStack* cur = mlist; cur != last; cur++)
if ((int(cur->move) & 07777) == bookMove)
if ((int(cur->move) & ~(3 << 14)) == bookMove) // Mask out special flags
return cur->move;
return MOVE_NONE;
}
/// Book::find_key() takes a book key as input, and does a binary search
/// Book::find_entry() takes a book key as input, and does a binary search
/// through the book file for the given key. The index to the first book
/// entry with the same key as the input is returned. When the key is not
/// found in the book file, bookSize is returned.
int Book::find_key(uint64_t key) {
int Book::find_entry(uint64_t key) {
int left, right, mid;
BookEntry entry;
// Binary search (finds the leftmost entry)
left = 0;
@@ -461,8 +490,7 @@ int Book::find_key(uint64_t key) {
assert(mid >= left && mid < right);
read_entry(entry, mid);
if (key <= entry.key)
if (key <= read_entry(mid).key)
right = mid;
else
left = mid + 1;
@@ -470,114 +498,28 @@ int Book::find_key(uint64_t key) {
assert(left == right);
read_entry(entry, left);
return (entry.key == key)? left : bookSize;
return read_entry(left).key == key ? left : bookSize;
}
/// Book::read_entry() takes a BookEntry reference and an integer index as
/// input, and looks up the opening book entry at the given index in the book
/// file. The book entry is copied to the first input parameter.
/// Book::read_entry() takes an integer index, and returns the BookEntry
/// at the given index in the book file.
void Book::read_entry(BookEntry& entry, int idx) {
BookEntry Book::read_entry(int idx) {
assert(idx >= 0 && idx < bookSize);
assert(is_open());
assert(bookFile.is_open());
seekg(idx * EntrySize, ios_base::beg);
*this >> entry;
if (!good())
BookEntry e;
bookFile.seekg(idx * sizeof(BookEntry), ios_base::beg);
*this >> e.key >> e.move >> e.count >> e.learn;
if (!bookFile.good())
{
cerr << "Failed to read book entry at index " << idx << endl;
Application::exit_with_failure();
}
}
/// Book::read_integer() reads size chars from the file stream
/// and converts them in an integer number.
uint64_t Book::read_integer(int size) {
char buf[8];
read(buf, size);
// Numbers are stored on disk as a binary byte stream
uint64_t n = 0ULL;
for (int i = 0; i < size; i++)
n = (n << 8) + (unsigned char)buf[i];
return n;
}
////
//// Local definitions
////
namespace {
uint64_t book_key(const Position& pos) {
uint64_t result = 0ULL;
for (Color c = WHITE; c <= BLACK; c++)
{
Bitboard b = pos.pieces_of_color(c);
while (b)
{
Square s = pop_1st_bit(&b);
Piece p = pos.piece_on(s);
assert(piece_is_ok(p));
assert(color_of_piece(p) == c);
result ^= book_piece_key(p, s);
}
}
result ^= book_castle_key(pos);
result ^= book_ep_key(pos);
result ^= book_color_key(pos);
return result;
}
uint64_t book_piece_key(Piece p, Square s) {
/// 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 result = 0ULL;
if (pos.can_castle_kingside(WHITE))
result ^= Random64[RandomCastle+0];
if (pos.can_castle_queenside(WHITE))
result ^= Random64[RandomCastle+1];
if (pos.can_castle_kingside(BLACK))
result ^= Random64[RandomCastle+2];
if (pos.can_castle_queenside(BLACK))
result ^= Random64[RandomCastle+3];
return result;
}
uint64_t book_ep_key(const Position& pos) {
return (pos.ep_square() == SQ_NONE ? 0ULL : Random64[RandomEnPassant + square_file(pos.ep_square())]);
}
uint64_t book_color_key(const Position& pos) {
return (pos.side_to_move() == WHITE ? Random64[RandomTurn] : 0ULL);
exit(EXIT_FAILURE);
}
return e;
}
+25 -38
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,68 +17,55 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
The code in this file is based on the opening book code in PolyGlot
by Fabien Letouzey. PolyGlot is available under the GNU General
Public License, and can be downloaded from http://wbec-ridderkerk.nl
*/
#if !defined(BOOK_H_INCLUDED)
#define BOOK_H_INCLUDED
////
//// Includes
////
#include <fstream>
#include <string>
#include "move.h"
#include "position.h"
#include "rkiss.h"
////
//// Types
////
// A Polyglot book is a series of "entries" of 16 bytes. All integers are
// stored highest byte first (regardless of size). The entries are ordered
// according to key. Lowest key first.
struct BookEntry {
uint64_t key;
uint16_t move;
uint16_t count;
uint16_t n;
uint16_t sum;
uint32_t learn;
};
class Book : private std::ifstream {
class Book {
public:
Book();
~Book();
void open(const std::string& fName);
void open(const std::string& fileName);
void close();
const std::string file_name() const;
Move get_move(const Position& pos);
Move get_move(const Position& pos, bool findBestMove);
const std::string name() const { return bookName; }
private:
Book& operator>>(uint64_t& n) { n = read_integer(8); return *this; }
Book& operator>>(uint16_t& n) { n = (uint16_t)read_integer(2); return *this; }
void operator>>(BookEntry& e) { *this >> e.key >> e.move >> e.count >> e.n >> e.sum; }
// read n chars from the file stream and converts them in an
// integer number. Integers are stored with highest byte first.
template<int n> uint64_t get_int();
uint64_t read_integer(int size);
void read_entry(BookEntry& e, int n);
int find_key(uint64_t key);
template<typename T>
Book& operator>>(T& n) { n = (T)get_int<sizeof(T)>(); return *this; }
std::string fileName;
BookEntry read_entry(int idx);
int find_entry(uint64_t key);
std::ifstream bookFile;
std::string bookName;
int bookSize;
RKISS RKiss;
};
////
//// Global variables
////
extern Book OpeningBook;
// Yes, we indulge a bit here ;-)
template<int n> inline uint64_t Book::get_int() { return 256 * get_int<n-1>() + bookFile.get(); }
template<> inline uint64_t Book::get_int<1>() { return bookFile.get(); }
#endif // !defined(BOOK_H_INCLUDED)
-50
View File
@@ -1,50 +0,0 @@
/*
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(COLOR_H_INCLUDED)
#define COLOR_H_INCLUDED
////
//// Types
////
enum Color {
WHITE,
BLACK,
COLOR_NONE
};
////
//// Inline functions
////
inline void operator++ (Color &c, int) { c = Color(int(c) + 1); }
inline Color opposite_color(Color c) {
return Color(int(c) ^ 1);
}
inline bool color_is_ok(Color c) {
return c == WHITE || c == BLACK;
}
#endif // !defined(COLOR_H_INCLUDED)
-59
View File
@@ -1,59 +0,0 @@
/*
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(DEPTH_H_INCLUDED)
#define DEPTH_H_INCLUDED
////
//// Types
////
enum Depth {
DEPTH_ZERO = 0,
DEPTH_MAX = 200 // 100 * OnePly;
};
////
//// Constants
////
const Depth OnePly = Depth(2);
////
//// Inline functions
////
inline Depth operator+ (Depth d, int i) { return Depth(int(d) + i); }
inline Depth operator+ (Depth d1, Depth d2) { return Depth(int(d1) + int(d2)); }
inline void operator+= (Depth &d, int i) { d = Depth(int(d) + i); }
inline void operator+= (Depth &d1, Depth d2) { d1 += int(d2); }
inline Depth operator- (Depth d, int i) { return Depth(int(d) - i); }
inline Depth operator- (Depth d1, Depth d2) { return Depth(int(d1) - int(d2)); }
inline void operator-= (Depth & d, int i) { d = Depth(int(d) - i); }
inline Depth operator* (Depth d, int i) { return Depth(int(d) * i); }
inline Depth operator* (int i, Depth d) { return Depth(int(d) * i); }
inline void operator*= (Depth &d, int i) { d = Depth(int(d) * i); }
inline Depth operator/ (Depth d, int i) { return Depth(int(d) / i); }
inline void operator/= (Depth &d, int i) { d = Depth(int(d) / i); }
#endif // !defined(DEPTH_H_INCLUDED)
-87
View File
@@ -1,87 +0,0 @@
/*
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 "direction.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
////
uint8_t DirectionTable[64][64];
uint8_t SignedDirectionTable[64][64];
////
//// Functions
////
void init_direction_table() {
for (Square s1 = SQ_A1; s1 <= SQ_H8; s1++)
for (Square s2 = SQ_A1; s2 <= SQ_H8; s2++)
{
DirectionTable[s1][s2] = uint8_t(DIR_NONE);
SignedDirectionTable[s1][s2] = uint8_t(SIGNED_DIR_NONE);
if (s1 == s2)
continue;
for (SignedDirection d = SIGNED_DIR_E; d != SIGNED_DIR_NONE; d++)
{
if (reachable(s1, s2, d))
{
SignedDirectionTable[s1][s2] = uint8_t(d);
DirectionTable[s1][s2] = uint8_t(d / 2);
break;
}
}
}
}
-92
View File
@@ -1,92 +0,0 @@
/*
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(DIRECTION_H_INCLUDED)
#define DIRECTION_H_INCLUDED
////
//// Includes
////
#include "square.h"
#include "types.h"
////
//// Types
////
enum Direction {
DIR_E = 0, DIR_N = 1, DIR_NE = 2, DIR_NW = 3, DIR_NONE = 4
};
enum SignedDirection {
SIGNED_DIR_E = 0, SIGNED_DIR_W = 1,
SIGNED_DIR_N = 2, SIGNED_DIR_S = 3,
SIGNED_DIR_NE = 4, SIGNED_DIR_SW = 5,
SIGNED_DIR_NW = 6, SIGNED_DIR_SE = 7,
SIGNED_DIR_NONE = 8
};
////
//// Variables
////
extern uint8_t DirectionTable[64][64];
extern uint8_t SignedDirectionTable[64][64];
////
//// Inline functions
////
inline void operator++ (Direction& d, int) {
d = Direction(int(d) + 1);
}
inline void operator++ (SignedDirection& d, int) {
d = SignedDirection(int(d) + 1);
}
inline Direction direction_between_squares(Square s1, Square s2) {
return Direction(DirectionTable[s1][s2]);
}
inline SignedDirection signed_direction_between_squares(Square s1, Square 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
////
extern void init_direction_table();
#endif // !defined(DIRECTION_H_INCLUDED)
+203 -176
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,27 +17,21 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
////
//// Includes
////
#include <cassert>
#include "bitbase.h"
#include "bitcount.h"
#include "endgame.h"
#include "pawns.h"
using std::string;
////
//// Local definitions
////
extern uint32_t probe_kpk_bitbase(Square wksq, Square wpsq, Square bksq, Color stm);
namespace {
// Table used to drive the defending king towards the edge of the board
// in KX vs K and KQ vs KR endgames.
const uint8_t MateTable[64] = {
const int MateTable[64] = {
100, 90, 80, 70, 70, 80, 90, 100,
90, 70, 60, 50, 50, 60, 70, 90,
80, 60, 40, 30, 30, 40, 60, 80,
@@ -50,7 +44,7 @@ namespace {
// Table used to drive the defending king towards a corner square of the
// right color in KBN vs K endgames.
const uint8_t KBNKMateTable[64] = {
const int KBNKMateTable[64] = {
200, 190, 180, 170, 160, 150, 140, 130,
190, 180, 170, 160, 150, 140, 130, 140,
180, 170, 155, 140, 140, 125, 140, 150,
@@ -65,75 +59,136 @@ namespace {
// the two kings in basic endgames.
const int DistanceBonus[8] = { 0, 0, 100, 80, 60, 40, 20, 10 };
// Bitbase for KP vs K
uint8_t KPKBitbase[24576];
// Penalty for big distance between king and knight for the defending king
// and knight in KR vs KN endgames.
const int KRKNKingKnightDistancePenalty[8] = { 0, 0, 4, 10, 20, 32, 48, 70 };
// Various inline functions for accessing the above arrays
inline Value mate_table(Square s) {
return Value(MateTable[s]);
// Build corresponding key code for the opposite color: "KBPKN" -> "KNKBP"
const string swap_colors(const string& keyCode) {
size_t idx = keyCode.find('K', 1);
return keyCode.substr(idx) + keyCode.substr(0, idx);
}
inline Value kbnk_mate_table(Square s) {
return Value(KBNKMateTable[s]);
// Get the material key of a position out of the given endgame key code
// like "KBPKN". The trick here is to first build up a FEN string and then
// let a Position object to do the work for us. Note that the FEN string
// could correspond to an illegal position.
Key mat_key(const string& keyCode) {
assert(keyCode.length() > 0 && keyCode.length() < 8);
assert(keyCode[0] == 'K');
string fen;
size_t i = 0;
// First add white and then black pieces
do fen += keyCode[i]; while (keyCode[++i] != 'K');
do fen += char(tolower(keyCode[i])); while (++i < keyCode.length());
// Add file padding and remaining empty ranks
fen += string(1, '0' + int(8 - keyCode.length())) + "/8/8/8/8/8/8/8 w - -";
// Build a Position out of the fen string and get its material key
return Position(fen, false, 0).get_material_key();
}
inline Value distance_bonus(int d) {
return Value(DistanceBonus[d]);
}
typedef EndgameBase<Value> EF;
typedef EndgameBase<ScaleFactor> SF;
inline Value krkn_king_knight_distance_penalty(int d) {
return Value(KRKNKingKnightDistancePenalty[d]);
}
} // namespace
// Function for probing the KP vs K bitbase
int probe_kpk(Square wksq, Square wpsq, Square bksq, Color stm);
/// Endgames member definitions
template<> const Endgames::EFMap& Endgames::get<EF>() const { return maps.first; }
template<> const Endgames::SFMap& Endgames::get<SF>() const { return maps.second; }
Endgames::Endgames() {
add<Endgame<Value, KNNK> >("KNNK");
add<Endgame<Value, KPK> >("KPK");
add<Endgame<Value, KBNK> >("KBNK");
add<Endgame<Value, KRKP> >("KRKP");
add<Endgame<Value, KRKB> >("KRKB");
add<Endgame<Value, KRKN> >("KRKN");
add<Endgame<Value, KQKR> >("KQKR");
add<Endgame<Value, KBBKN> >("KBBKN");
add<Endgame<ScaleFactor, KNPK> >("KNPK");
add<Endgame<ScaleFactor, KRPKR> >("KRPKR");
add<Endgame<ScaleFactor, KBPKB> >("KBPKB");
add<Endgame<ScaleFactor, KBPPKB> >("KBPPKB");
add<Endgame<ScaleFactor, KBPKN> >("KBPKN");
add<Endgame<ScaleFactor, KRPPKRP> >("KRPPKRP");
}
Endgames::~Endgames() {
for (EFMap::const_iterator it = get<EF>().begin(); it != get<EF>().end(); ++it)
delete it->second;
for (SFMap::const_iterator it = get<SF>().begin(); it != get<SF>().end(); ++it)
delete it->second;
}
template<class T>
void Endgames::add(const string& keyCode) {
typedef typename T::Base F;
typedef std::map<Key, F*> M;
const_cast<M&>(get<F>()).insert(std::pair<Key, F*>(mat_key(keyCode), new T(WHITE)));
const_cast<M&>(get<F>()).insert(std::pair<Key, F*>(mat_key(swap_colors(keyCode)), new T(BLACK)));
}
template<class T>
T* Endgames::get(Key key) const {
typename std::map<Key, T*>::const_iterator it = get<T>().find(key);
return it != get<T>().end() ? it->second : NULL;
}
// Explicit template instantiations
template EF* Endgames::get<EF>(Key key) const;
template SF* Endgames::get<SF>(Key key) const;
////
//// Functions
////
/// Mate with KX vs K. This function is used to evaluate positions with
/// King and plenty of material vs a lone king. It simply gives the
/// attacking side a bonus for driving the defending king towards the edge
/// of the board, and for keeping the distance between the two kings small.
template<>
Value EvaluationFunction<KXK>::apply(const Position& pos) {
Value Endgame<Value, KXK>::apply(const Position& pos) const {
assert(pos.non_pawn_material(weakerSide) == Value(0));
assert(pos.piece_count(weakerSide, PAWN) == Value(0));
assert(pos.non_pawn_material(weakerSide) == VALUE_ZERO);
assert(pos.piece_count(weakerSide, PAWN) == VALUE_ZERO);
Square winnerKSq = pos.king_square(strongerSide);
Square loserKSq = pos.king_square(weakerSide);
Value result = pos.non_pawn_material(strongerSide)
+ pos.piece_count(strongerSide, PAWN) * PawnValueEndgame
+ mate_table(loserKSq)
+ distance_bonus(square_distance(winnerKSq, loserKSq));
+ MateTable[loserKSq]
+ DistanceBonus[square_distance(winnerKSq, loserKSq)];
if ( pos.piece_count(strongerSide, QUEEN) > 0
|| pos.piece_count(strongerSide, ROOK) > 0
if ( pos.piece_count(strongerSide, QUEEN)
|| pos.piece_count(strongerSide, ROOK)
|| pos.piece_count(strongerSide, BISHOP) > 1)
// TODO: check for two equal-colored bishops!
result += VALUE_KNOWN_WIN;
return (strongerSide == pos.side_to_move() ? result : -result);
return strongerSide == pos.side_to_move() ? result : -result;
}
/// Mate with KBN vs K. This is similar to KX vs K, but we have to drive the
/// defending king towards a corner square of the right color.
template<>
Value EvaluationFunction<KBNK>::apply(const Position& pos) {
Value Endgame<Value, KBNK>::apply(const Position& pos) const {
assert(pos.non_pawn_material(weakerSide) == Value(0));
assert(pos.piece_count(weakerSide, PAWN) == Value(0));
assert(pos.non_pawn_material(weakerSide) == VALUE_ZERO);
assert(pos.piece_count(weakerSide, PAWN) == VALUE_ZERO);
assert(pos.non_pawn_material(strongerSide) == KnightValueMidgame + BishopValueMidgame);
assert(pos.piece_count(strongerSide, BISHOP) == 1);
assert(pos.piece_count(strongerSide, KNIGHT) == 1);
@@ -143,26 +198,29 @@ Value EvaluationFunction<KBNK>::apply(const Position& pos) {
Square loserKSq = pos.king_square(weakerSide);
Square bishopSquare = pos.piece_list(strongerSide, BISHOP, 0);
if (square_color(bishopSquare) == BLACK)
// kbnk_mate_table() tries to drive toward corners A1 or H8,
// if we have a bishop that cannot reach the above squares we
// mirror the kings so to drive enemy toward corners A8 or H1.
if (opposite_color_squares(bishopSquare, SQ_A1))
{
winnerKSq = flop_square(winnerKSq);
loserKSq = flop_square(loserKSq);
}
Value result = VALUE_KNOWN_WIN
+ distance_bonus(square_distance(winnerKSq, loserKSq))
+ kbnk_mate_table(loserKSq);
+ DistanceBonus[square_distance(winnerKSq, loserKSq)]
+ KBNKMateTable[loserKSq];
return (strongerSide == pos.side_to_move() ? result : -result);
return strongerSide == pos.side_to_move() ? result : -result;
}
/// KP vs K. This endgame is evaluated with the help of a bitbase.
template<>
Value EvaluationFunction<KPK>::apply(const Position& pos) {
Value Endgame<Value, KPK>::apply(const Position& pos) const {
assert(pos.non_pawn_material(strongerSide) == Value(0));
assert(pos.non_pawn_material(weakerSide) == Value(0));
assert(pos.non_pawn_material(strongerSide) == VALUE_ZERO);
assert(pos.non_pawn_material(weakerSide) == VALUE_ZERO);
assert(pos.piece_count(strongerSide, PAWN) == 1);
assert(pos.piece_count(weakerSide, PAWN) == 0);
@@ -186,19 +244,19 @@ Value EvaluationFunction<KPK>::apply(const Position& pos) {
if (square_file(wpsq) >= FILE_E)
{
wksq = flop_square(wksq);
bksq = flop_square(bksq);
wpsq = flop_square(wpsq);
wksq = flop_square(wksq);
bksq = flop_square(bksq);
wpsq = flop_square(wpsq);
}
if (!probe_kpk(wksq, wpsq, bksq, stm))
if (!probe_kpk_bitbase(wksq, wpsq, bksq, stm))
return VALUE_DRAW;
Value result = VALUE_KNOWN_WIN
+ PawnValueEndgame
+ Value(square_rank(wpsq));
return (strongerSide == pos.side_to_move() ? result : -result);
return strongerSide == pos.side_to_move() ? result : -result;
}
@@ -207,7 +265,7 @@ Value EvaluationFunction<KPK>::apply(const Position& pos) {
/// far advanced with support of the king, while the attacking king is far
/// away.
template<>
Value EvaluationFunction<KRKP>::apply(const Position& pos) {
Value Endgame<Value, KRKP>::apply(const Position& pos) const {
assert(pos.non_pawn_material(strongerSide) == RookValueMidgame);
assert(pos.piece_count(strongerSide, PAWN) == 0);
@@ -239,7 +297,7 @@ Value EvaluationFunction<KRKP>::apply(const Position& pos) {
// If the weaker side's king is too far from the pawn and the rook,
// it's a win
else if ( square_distance(bksq, bpsq) - (tempo^1) >= 3
else if ( square_distance(bksq, bpsq) - (tempo ^ 1) >= 3
&& square_distance(bksq, wrsq) >= 3)
result = RookValueEndgame - Value(square_distance(wksq, bpsq));
@@ -257,14 +315,14 @@ Value EvaluationFunction<KRKP>::apply(const Position& pos) {
+ Value(square_distance(bksq, bpsq + DELTA_S) * 8)
+ Value(square_distance(bpsq, queeningSq) * 8);
return (strongerSide == pos.side_to_move() ? result : -result);
return strongerSide == pos.side_to_move() ? result : -result;
}
/// KR vs KB. This is very simple, and always returns drawish scores. The
/// score is slightly bigger when the defending king is close to the edge.
template<>
Value EvaluationFunction<KRKB>::apply(const Position& pos) {
Value Endgame<Value, KRKB>::apply(const Position& pos) const {
assert(pos.non_pawn_material(strongerSide) == RookValueMidgame);
assert(pos.piece_count(strongerSide, PAWN) == 0);
@@ -272,15 +330,15 @@ Value EvaluationFunction<KRKB>::apply(const Position& pos) {
assert(pos.piece_count(weakerSide, PAWN) == 0);
assert(pos.piece_count(weakerSide, BISHOP) == 1);
Value result = mate_table(pos.king_square(weakerSide));
return (pos.side_to_move() == strongerSide ? result : -result);
Value result = Value(MateTable[pos.king_square(weakerSide)]);
return strongerSide == pos.side_to_move() ? result : -result;
}
/// KR vs KN. The attacking side has slightly better winning chances than
/// in KR vs KB, particularly if the king and the knight are far apart.
template<>
Value EvaluationFunction<KRKN>::apply(const Position& pos) {
Value Endgame<Value, KRKN>::apply(const Position& pos) const {
assert(pos.non_pawn_material(strongerSide) == RookValueMidgame);
assert(pos.piece_count(strongerSide, PAWN) == 0);
@@ -291,10 +349,12 @@ Value EvaluationFunction<KRKN>::apply(const Position& pos) {
Square defendingKSq = pos.king_square(weakerSide);
Square nSq = pos.piece_list(weakerSide, KNIGHT, 0);
Value result = Value(10) + mate_table(defendingKSq) +
krkn_king_knight_distance_penalty(square_distance(defendingKSq, nSq));
int d = square_distance(defendingKSq, nSq);
Value result = Value(10)
+ MateTable[defendingKSq]
+ KRKNKingKnightDistancePenalty[d];
return (strongerSide == pos.side_to_move())? result : -result;
return strongerSide == pos.side_to_move() ? result : -result;
}
@@ -304,7 +364,7 @@ Value EvaluationFunction<KRKN>::apply(const Position& pos) {
/// for the defending side in the search, this is usually sufficient to be
/// able to win KQ vs KR.
template<>
Value EvaluationFunction<KQKR>::apply(const Position& pos) {
Value Endgame<Value, KQKR>::apply(const Position& pos) const {
assert(pos.non_pawn_material(strongerSide) == QueenValueMidgame);
assert(pos.piece_count(strongerSide, PAWN) == 0);
@@ -316,14 +376,14 @@ Value EvaluationFunction<KQKR>::apply(const Position& pos) {
Value result = QueenValueEndgame
- RookValueEndgame
+ mate_table(loserKSq)
+ distance_bonus(square_distance(winnerKSq, loserKSq));
+ MateTable[loserKSq]
+ DistanceBonus[square_distance(winnerKSq, loserKSq)];
return (strongerSide == pos.side_to_move())? result : -result;
return strongerSide == pos.side_to_move() ? result : -result;
}
template<>
Value EvaluationFunction<KBBKN>::apply(const Position& pos) {
Value Endgame<Value, KBBKN>::apply(const Position& pos) const {
assert(pos.piece_count(strongerSide, BISHOP) == 2);
assert(pos.non_pawn_material(strongerSide) == 2*BishopValueMidgame);
@@ -337,37 +397,37 @@ Value EvaluationFunction<KBBKN>::apply(const Position& pos) {
Square nsq = pos.piece_list(weakerSide, KNIGHT, 0);
// Bonus for attacking king close to defending king
result += distance_bonus(square_distance(wksq, bksq));
result += Value(DistanceBonus[square_distance(wksq, bksq)]);
// Bonus for driving the defending king and knight apart
result += Value(square_distance(bksq, nsq) * 32);
// Bonus for restricting the knight's mobility
result += Value((8 - count_1s_max_15(pos.attacks_from<KNIGHT>(nsq))) * 8);
result += Value((8 - count_1s<CNT32_MAX15>(pos.attacks_from<KNIGHT>(nsq))) * 8);
return (strongerSide == pos.side_to_move() ? result : -result);
return strongerSide == pos.side_to_move() ? result : -result;
}
/// K and two minors vs K and one or two minors or K and two knights against
/// king alone are always draw.
template<>
Value EvaluationFunction<KmmKm>::apply(const Position&) {
return Value(0);
Value Endgame<Value, KmmKm>::apply(const Position&) const {
return VALUE_DRAW;
}
template<>
Value EvaluationFunction<KNNK>::apply(const Position&) {
return Value(0);
Value Endgame<Value, KNNK>::apply(const Position&) const {
return VALUE_DRAW;
}
/// KBPKScalingFunction scales endgames where the stronger side has king,
/// bishop and one or more pawns. It checks for draws with rook pawns and a
/// bishop of the wrong color. If such a draw is detected, ScaleFactor(0) is
/// bishop of the wrong color. If such a draw is detected, SCALE_FACTOR_ZERO is
/// returned. If not, the return value is SCALE_FACTOR_NONE, i.e. no scaling
/// will be used.
template<>
ScaleFactor ScalingFunction<KBPsK>::apply(const Position& pos) {
ScaleFactor Endgame<ScaleFactor, KBPsK>::apply(const Position& pos) const {
assert(pos.non_pawn_material(strongerSide) == BishopValueMidgame);
assert(pos.piece_count(strongerSide, BISHOP) == 1);
@@ -387,8 +447,8 @@ ScaleFactor ScalingFunction<KBPsK>::apply(const Position& pos) {
Square queeningSq = relative_square(strongerSide, make_square(pawnFile, RANK_8));
Square kingSq = pos.king_square(weakerSide);
if ( square_color(queeningSq) != square_color(bishopSq)
&& file_distance(square_file(kingSq), pawnFile) <= 1)
if ( opposite_color_squares(queeningSq, bishopSq)
&& abs(square_file(kingSq) - pawnFile) <= 1)
{
// The bishop has the wrong color, and the defending king is on the
// file of the pawn(s) or the neighboring file. Find the rank of the
@@ -401,15 +461,15 @@ ScaleFactor ScalingFunction<KBPsK>::apply(const Position& pos) {
}
else
{
for(rank = RANK_2; (rank_bb(rank) & pawns) == EmptyBoardBB; rank++) {}
rank = Rank(rank^7); // HACK to get the relative rank
for (rank = RANK_2; (rank_bb(rank) & pawns) == EmptyBoardBB; rank++) {}
rank = Rank(rank ^ 7); // HACK to get the relative rank
assert(rank >= RANK_2 && rank <= RANK_7);
}
// If the defending king has distance 1 to the promotion square or
// is placed somewhere in front of the pawn, it's a draw.
if ( square_distance(kingSq, queeningSq) <= 1
|| relative_rank(strongerSide, kingSq) >= rank)
return ScaleFactor(0);
return SCALE_FACTOR_ZERO;
}
}
return SCALE_FACTOR_NONE;
@@ -421,7 +481,7 @@ ScaleFactor ScalingFunction<KBPsK>::apply(const Position& pos) {
/// It tests for fortress draws with a rook on the third rank defended by
/// a pawn.
template<>
ScaleFactor ScalingFunction<KQKRPs>::apply(const Position& pos) {
ScaleFactor Endgame<ScaleFactor, KQKRPs>::apply(const Position& pos) const {
assert(pos.non_pawn_material(strongerSide) == QueenValueMidgame);
assert(pos.piece_count(strongerSide, QUEEN) == 1);
@@ -432,13 +492,13 @@ ScaleFactor ScalingFunction<KQKRPs>::apply(const Position& pos) {
Square kingSq = pos.king_square(weakerSide);
if ( relative_rank(weakerSide, kingSq) <= RANK_2
&& relative_rank(weakerSide, pos.king_square(strongerSide)) >= RANK_4
&& (pos.pieces(ROOK, weakerSide) & relative_rank_bb(weakerSide, RANK_3))
&& (pos.pieces(PAWN, weakerSide) & relative_rank_bb(weakerSide, RANK_2))
&& (pos.pieces(ROOK, weakerSide) & rank_bb(relative_rank(weakerSide, RANK_3)))
&& (pos.pieces(PAWN, weakerSide) & rank_bb(relative_rank(weakerSide, RANK_2)))
&& (pos.attacks_from<KING>(kingSq) & pos.pieces(PAWN, weakerSide)))
{
Square rsq = pos.piece_list(weakerSide, ROOK, 0);
if (pos.attacks_from<PAWN>(rsq, strongerSide) & pos.pieces(PAWN, weakerSide))
return ScaleFactor(0);
return SCALE_FACTOR_ZERO;
}
return SCALE_FACTOR_NONE;
}
@@ -452,7 +512,7 @@ ScaleFactor ScalingFunction<KQKRPs>::apply(const Position& pos) {
/// It would also be nice to rewrite the actual code for this function,
/// which is mostly copied from Glaurung 1.x, and not very pretty.
template<>
ScaleFactor ScalingFunction<KRPKR>::apply(const Position &pos) {
ScaleFactor Endgame<ScaleFactor, KRPKR>::apply(const Position& pos) const {
assert(pos.non_pawn_material(strongerSide) == RookValueMidgame);
assert(pos.piece_count(strongerSide, PAWN) == 1);
@@ -495,7 +555,7 @@ ScaleFactor ScalingFunction<KRPKR>::apply(const Position &pos) {
&& square_distance(bksq, queeningSq) <= 1
&& wksq <= SQ_H5
&& (square_rank(brsq) == RANK_6 || (r <= RANK_3 && square_rank(wrsq) != RANK_6)))
return ScaleFactor(0);
return SCALE_FACTOR_ZERO;
// The defending side saves a draw by checking from behind in case the pawn
// has advanced to the 6th rank with the king behind.
@@ -503,13 +563,13 @@ ScaleFactor ScalingFunction<KRPKR>::apply(const Position &pos) {
&& square_distance(bksq, queeningSq) <= 1
&& square_rank(wksq) + tempo <= RANK_6
&& (square_rank(brsq) == RANK_1 || (!tempo && abs(square_file(brsq) - f) >= 3)))
return ScaleFactor(0);
return SCALE_FACTOR_ZERO;
if ( r >= RANK_6
&& bksq == queeningSq
&& square_rank(brsq) == RANK_1
&& (!tempo || square_distance(wksq, wpsq) >= 2))
return ScaleFactor(0);
return SCALE_FACTOR_ZERO;
// White pawn on a7 and rook on a8 is a draw if black's king is on g7 or h7
// and the black rook is behind the pawn.
@@ -518,7 +578,7 @@ ScaleFactor ScalingFunction<KRPKR>::apply(const Position &pos) {
&& (bksq == SQ_H7 || bksq == SQ_G7)
&& square_file(brsq) == FILE_A
&& (square_rank(brsq) <= RANK_3 || square_file(wksq) >= FILE_D || square_rank(wksq) <= RANK_5))
return ScaleFactor(0);
return SCALE_FACTOR_ZERO;
// If the defending king blocks the pawn and the attacking king is too far
// away, it's a draw.
@@ -526,7 +586,7 @@ ScaleFactor ScalingFunction<KRPKR>::apply(const Position &pos) {
&& bksq == wpsq + DELTA_N
&& square_distance(wksq, wpsq) - tempo >= 2
&& square_distance(wksq, brsq) - tempo >= 2)
return ScaleFactor(0);
return SCALE_FACTOR_ZERO;
// Pawn on the 7th rank supported by the rook from behind usually wins if the
// attacking king is closer to the queening square than the defending king,
@@ -549,8 +609,8 @@ ScaleFactor ScalingFunction<KRPKR>::apply(const Position &pos) {
|| ( square_distance(wksq, queeningSq) < square_distance(bksq, wrsq) + tempo
&& (square_distance(wksq, wpsq + DELTA_N) < square_distance(bksq, wrsq) + tempo))))
return ScaleFactor( SCALE_FACTOR_MAX
- (8 * square_distance(wpsq, queeningSq)
+ 2 * square_distance(wksq, queeningSq)));
- 8 * square_distance(wpsq, queeningSq)
- 2 * square_distance(wksq, queeningSq));
// If the pawn is not far advanced, and the defending king is somewhere in
// the pawn's path, it's probably a draw.
@@ -570,7 +630,7 @@ ScaleFactor ScalingFunction<KRPKR>::apply(const Position &pos) {
/// single pattern: If the stronger side has no pawns and the defending king
/// is actively placed, the position is drawish.
template<>
ScaleFactor ScalingFunction<KRPPKRP>::apply(const Position &pos) {
ScaleFactor Endgame<ScaleFactor, KRPPKRP>::apply(const Position& pos) const {
assert(pos.non_pawn_material(strongerSide) == RookValueMidgame);
assert(pos.piece_count(strongerSide, PAWN) == 2);
@@ -609,43 +669,35 @@ ScaleFactor ScalingFunction<KRPPKRP>::apply(const Position &pos) {
/// against king. There is just a single rule here: If all pawns are on
/// the same rook file and are blocked by the defending king, it's a draw.
template<>
ScaleFactor ScalingFunction<KPsK>::apply(const Position &pos) {
ScaleFactor Endgame<ScaleFactor, KPsK>::apply(const Position& pos) const {
assert(pos.non_pawn_material(strongerSide) == Value(0));
assert(pos.non_pawn_material(strongerSide) == VALUE_ZERO);
assert(pos.piece_count(strongerSide, PAWN) >= 2);
assert(pos.non_pawn_material(weakerSide) == Value(0));
assert(pos.non_pawn_material(weakerSide) == VALUE_ZERO);
assert(pos.piece_count(weakerSide, PAWN) == 0);
Square ksq = pos.king_square(weakerSide);
Bitboard pawns = pos.pieces(PAWN, strongerSide);
// Are all pawns on the 'a' file?
if ((pawns & ~FileABB) == EmptyBoardBB)
{
// Does the defending king block the pawns?
Square ksq = pos.king_square(weakerSide);
if (square_distance(ksq, relative_square(strongerSide, SQ_A8)) <= 1)
return ScaleFactor(0);
else if( square_file(ksq) == FILE_A
&& (in_front_bb(strongerSide, ksq) & pawns) == EmptyBoardBB)
return ScaleFactor(0);
else
return SCALE_FACTOR_NONE;
if ( square_distance(ksq, relative_square(strongerSide, SQ_A8)) <= 1
|| ( square_file(ksq) == FILE_A
&& (in_front_bb(strongerSide, ksq) & pawns) == EmptyBoardBB))
return SCALE_FACTOR_ZERO;
}
// Are all pawns on the 'h' file?
else if ((pawns & ~FileHBB) == EmptyBoardBB)
{
// Does the defending king block the pawns?
Square ksq = pos.king_square(weakerSide);
if (square_distance(ksq, relative_square(strongerSide, SQ_H8)) <= 1)
return ScaleFactor(0);
else if ( square_file(ksq) == FILE_H
&& (in_front_bb(strongerSide, ksq) & pawns) == EmptyBoardBB)
return ScaleFactor(0);
else
return SCALE_FACTOR_NONE;
if ( square_distance(ksq, relative_square(strongerSide, SQ_H8)) <= 1
|| ( square_file(ksq) == FILE_H
&& (in_front_bb(strongerSide, ksq) & pawns) == EmptyBoardBB))
return SCALE_FACTOR_ZERO;
}
else
return SCALE_FACTOR_NONE;
return SCALE_FACTOR_NONE;
}
@@ -655,7 +707,7 @@ ScaleFactor ScalingFunction<KPsK>::apply(const Position &pos) {
/// it's a draw. If the two bishops have opposite color, it's almost always
/// a draw.
template<>
ScaleFactor ScalingFunction<KBPKB>::apply(const Position &pos) {
ScaleFactor Endgame<ScaleFactor, KBPKB>::apply(const Position& pos) const {
assert(pos.non_pawn_material(strongerSide) == BishopValueMidgame);
assert(pos.piece_count(strongerSide, BISHOP) == 1);
@@ -672,12 +724,12 @@ ScaleFactor ScalingFunction<KBPKB>::apply(const Position &pos) {
// Case 1: Defending king blocks the pawn, and cannot be driven away
if ( square_file(weakerKingSq) == square_file(pawnSq)
&& relative_rank(strongerSide, pawnSq) < relative_rank(strongerSide, weakerKingSq)
&& ( square_color(weakerKingSq) != square_color(strongerBishopSq)
&& ( opposite_color_squares(weakerKingSq, strongerBishopSq)
|| relative_rank(strongerSide, weakerKingSq) <= RANK_6))
return ScaleFactor(0);
return SCALE_FACTOR_ZERO;
// Case 2: Opposite colored bishops
if (square_color(strongerBishopSq) != square_color(weakerBishopSq))
if (opposite_color_squares(strongerBishopSq, weakerBishopSq))
{
// We assume that the position is drawn in the following three situations:
//
@@ -690,15 +742,17 @@ ScaleFactor ScalingFunction<KBPKB>::apply(const Position &pos) {
// reasonably well.
if (relative_rank(strongerSide, pawnSq) <= RANK_5)
return ScaleFactor(0);
return SCALE_FACTOR_ZERO;
else
{
Bitboard ray = ray_bb(pawnSq, (strongerSide == WHITE)? SIGNED_DIR_N : SIGNED_DIR_S);
if (ray & pos.pieces(KING, weakerSide))
return ScaleFactor(0);
if( (pos.attacks_from<BISHOP>(weakerBishopSq) & ray)
&& square_distance(weakerBishopSq, pawnSq) >= 3)
return ScaleFactor(0);
Bitboard path = squares_in_front_of(strongerSide, pawnSq);
if (path & pos.pieces(KING, weakerSide))
return SCALE_FACTOR_ZERO;
if ( (pos.attacks_from<BISHOP>(weakerBishopSq) & path)
&& square_distance(weakerBishopSq, pawnSq) >= 3)
return SCALE_FACTOR_ZERO;
}
}
return SCALE_FACTOR_NONE;
@@ -708,7 +762,7 @@ ScaleFactor ScalingFunction<KBPKB>::apply(const Position &pos) {
/// KBPPKBScalingFunction scales KBPP vs KB endgames. It detects a few basic
/// draws with opposite-colored bishops.
template<>
ScaleFactor ScalingFunction<KBPPKB>::apply(const Position& pos) {
ScaleFactor Endgame<ScaleFactor, KBPPKB>::apply(const Position& pos) const {
assert(pos.non_pawn_material(strongerSide) == BishopValueMidgame);
assert(pos.piece_count(strongerSide, BISHOP) == 1);
@@ -720,8 +774,7 @@ ScaleFactor ScalingFunction<KBPPKB>::apply(const Position& pos) {
Square wbsq = pos.piece_list(strongerSide, BISHOP, 0);
Square bbsq = pos.piece_list(weakerSide, BISHOP, 0);
if (square_color(wbsq) == square_color(bbsq))
// Not opposite-colored bishops, no scaling
if (!opposite_color_squares(wbsq, bbsq))
return SCALE_FACTOR_NONE;
Square ksq = pos.king_square(weakerSide);
@@ -749,8 +802,8 @@ ScaleFactor ScalingFunction<KBPPKB>::apply(const Position& pos) {
// some square in the frontmost pawn's path.
if ( square_file(ksq) == square_file(blockSq1)
&& relative_rank(strongerSide, ksq) >= relative_rank(strongerSide, blockSq1)
&& square_color(ksq) != square_color(wbsq))
return ScaleFactor(0);
&& opposite_color_squares(ksq, wbsq))
return SCALE_FACTOR_ZERO;
else
return SCALE_FACTOR_NONE;
@@ -759,16 +812,17 @@ ScaleFactor ScalingFunction<KBPPKB>::apply(const Position& pos) {
// in front of the frontmost pawn's path, and the square diagonally behind
// this square on the file of the other pawn.
if ( ksq == blockSq1
&& square_color(ksq) != square_color(wbsq)
&& opposite_color_squares(ksq, wbsq)
&& ( bbsq == blockSq2
|| (pos.attacks_from<BISHOP>(blockSq2) & pos.pieces(BISHOP, weakerSide))
|| rank_distance(r1, r2) >= 2))
return ScaleFactor(0);
|| abs(r1 - r2) >= 2))
return SCALE_FACTOR_ZERO;
else if ( ksq == blockSq2
&& square_color(ksq) != square_color(wbsq)
&& opposite_color_squares(ksq, wbsq)
&& ( bbsq == blockSq1
|| (pos.attacks_from<BISHOP>(blockSq1) & pos.pieces(BISHOP, weakerSide))))
return ScaleFactor(0);
return SCALE_FACTOR_ZERO;
else
return SCALE_FACTOR_NONE;
@@ -784,7 +838,7 @@ ScaleFactor ScalingFunction<KBPPKB>::apply(const Position& pos) {
/// square of the king is not of the same color as the stronger side's bishop,
/// it's a draw.
template<>
ScaleFactor ScalingFunction<KBPKN>::apply(const Position &pos) {
ScaleFactor Endgame<ScaleFactor, KBPKN>::apply(const Position& pos) const {
assert(pos.non_pawn_material(strongerSide) == BishopValueMidgame);
assert(pos.piece_count(strongerSide, BISHOP) == 1);
@@ -799,9 +853,9 @@ ScaleFactor ScalingFunction<KBPKN>::apply(const Position &pos) {
if ( square_file(weakerKingSq) == square_file(pawnSq)
&& relative_rank(strongerSide, pawnSq) < relative_rank(strongerSide, weakerKingSq)
&& ( square_color(weakerKingSq) != square_color(strongerBishopSq)
&& ( opposite_color_squares(weakerKingSq, strongerBishopSq)
|| relative_rank(strongerSide, weakerKingSq) <= RANK_6))
return ScaleFactor(0);
return SCALE_FACTOR_ZERO;
return SCALE_FACTOR_NONE;
}
@@ -811,12 +865,12 @@ ScaleFactor ScalingFunction<KBPKN>::apply(const Position &pos) {
/// If the pawn is a rook pawn on the 7th rank and the defending king prevents
/// the pawn from advancing, the position is drawn.
template<>
ScaleFactor ScalingFunction<KNPK>::apply(const Position &pos) {
ScaleFactor Endgame<ScaleFactor, KNPK>::apply(const Position& pos) const {
assert(pos.non_pawn_material(strongerSide) == KnightValueMidgame);
assert(pos.piece_count(strongerSide, KNIGHT) == 1);
assert(pos.piece_count(strongerSide, PAWN) == 1);
assert(pos.non_pawn_material(weakerSide) == Value(0));
assert(pos.non_pawn_material(weakerSide) == VALUE_ZERO);
assert(pos.piece_count(weakerSide, PAWN) == 0);
Square pawnSq = pos.piece_list(strongerSide, PAWN, 0);
@@ -824,11 +878,11 @@ ScaleFactor ScalingFunction<KNPK>::apply(const Position &pos) {
if ( pawnSq == relative_square(strongerSide, SQ_A7)
&& square_distance(weakerKingSq, relative_square(strongerSide, SQ_A8)) <= 1)
return ScaleFactor(0);
return SCALE_FACTOR_ZERO;
if ( pawnSq == relative_square(strongerSide, SQ_H7)
&& square_distance(weakerKingSq, relative_square(strongerSide, SQ_H8)) <= 1)
return ScaleFactor(0);
return SCALE_FACTOR_ZERO;
return SCALE_FACTOR_NONE;
}
@@ -841,10 +895,10 @@ ScaleFactor ScalingFunction<KNPK>::apply(const Position &pos) {
/// advanced and not on a rook file; in this case it is often possible to win
/// (e.g. 8/4k3/3p4/3P4/6K1/8/8/8 w - - 0 1).
template<>
ScaleFactor ScalingFunction<KPKP>::apply(const Position &pos) {
ScaleFactor Endgame<ScaleFactor, KPKP>::apply(const Position& pos) const {
assert(pos.non_pawn_material(strongerSide) == Value(0));
assert(pos.non_pawn_material(weakerSide) == Value(0));
assert(pos.non_pawn_material(strongerSide) == VALUE_ZERO);
assert(pos.non_pawn_material(weakerSide) == VALUE_ZERO);
assert(pos.piece_count(WHITE, PAWN) == 1);
assert(pos.piece_count(BLACK, PAWN) == 1);
@@ -881,32 +935,5 @@ ScaleFactor ScalingFunction<KPKP>::apply(const Position &pos) {
// Probe the KPK bitbase with the weakest side's pawn removed. If it's a
// draw, it's probably at least a draw even with the pawn.
if (probe_kpk(wksq, wpsq, bksq, stm))
return SCALE_FACTOR_NONE;
else
return ScaleFactor(0);
}
/// init_bitbases() is called during program initialization, and simply loads
/// bitbases from disk into memory. At the moment, there is only the bitbase
/// for KP vs K, but we may decide to add other bitbases later.
void init_bitbases() {
generate_kpk_bitbase(KPKBitbase);
}
namespace {
// Probe the KP vs K bitbase:
int probe_kpk(Square wksq, Square wpsq, Square bksq, Color stm) {
int wp = int(square_file(wpsq)) + (int(square_rank(wpsq)) - 1) * 4;
int index = int(stm) + 2*int(bksq) + 128*int(wksq) + 8192*wp;
assert(index >= 0 && index < 24576*8);
return KPKBitbase[index/8] & (1 << (index&7));
}
return probe_kpk_bitbase(wksq, wpsq, bksq, stm) ? SCALE_FACTOR_NONE : SCALE_FACTOR_ZERO;
}
+69 -63
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,90 +17,96 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined(ENDGAME_H_INCLUDED)
#define ENDGAME_H_INCLUDED
////
//// Includes
////
#include <string>
#include <map>
#include "position.h"
#include "scale.h"
#include "value.h"
#include "types.h"
////
//// Types
////
/// EndgameType lists all supported endgames
enum EndgameType {
// 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
KNNK, // KNN vs K
KmmKm, // K and two minors vs K and one or two minors
// Evaluation functions
// Scaling functions
KBPsK, // KB+pawns vs K
KQKRPs, // KQ vs KR+pawns
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
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
KNNK, // KNN vs K
KmmKm, // K and two minors vs K and one or two minors
// Scaling functions
KBPsK, // KB+pawns vs K
KQKRPs, // KQ vs KR+pawns
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
/// Base and derived templates for endgame evaluation and scaling functions
template<typename T>
class EndgameFunctionBase {
public:
EndgameFunctionBase(Color c) : strongerSide(c), weakerSide(opposite_color(c)) {}
virtual ~EndgameFunctionBase() {}
virtual T apply(const Position&) = 0;
Color color() const { return strongerSide; }
struct EndgameBase {
protected:
typedef EndgameBase<T> Base;
virtual ~EndgameBase() {}
virtual Color color() const = 0;
virtual T apply(const Position&) const = 0;
};
template<typename T, EndgameType>
struct Endgame : public EndgameBase<T> {
explicit Endgame(Color c) : strongerSide(c), weakerSide(opposite_color(c)) {}
Color color() const { return strongerSide; }
T apply(const Position&) const;
private:
Color strongerSide, weakerSide;
};
typedef EndgameFunctionBase<Value> EndgameEvaluationFunctionBase;
typedef EndgameFunctionBase<ScaleFactor> EndgameScalingFunctionBase;
/// Endgames class stores in two std::map the pointers to endgame evaluation
/// and scaling base objects. Then we use polymorphism to invoke the actual
/// endgame function calling its apply() method that is virtual.
/// Templates subclass for various concrete endgames
class Endgames {
template<EndgameType>
struct EvaluationFunction : public EndgameEvaluationFunctionBase {
typedef EndgameEvaluationFunctionBase Base;
explicit EvaluationFunction(Color c): EndgameEvaluationFunctionBase(c) {}
Value apply(const Position&);
typedef std::map<Key, EndgameBase<Value>* > EFMap;
typedef std::map<Key, EndgameBase<ScaleFactor>* > SFMap;
public:
Endgames();
~Endgames();
template<class T> T* get(Key key) const;
private:
template<class T> void add(const std::string& keyCode);
// Here we store two maps, for evaluate and scaling functions...
std::pair<EFMap, SFMap> maps;
// ...and here is the accessing template function
template<typename T> const std::map<Key, T*>& get() const;
};
template<EndgameType>
struct ScalingFunction : public EndgameScalingFunctionBase {
typedef EndgameScalingFunctionBase Base;
explicit ScalingFunction(Color c) : EndgameScalingFunctionBase(c) {}
ScaleFactor apply(const Position&);
};
////
//// Prototypes
////
extern void init_bitbases();
#endif // !defined(ENDGAME_H_INCLUDED)
+741 -776
View File
File diff suppressed because it is too large Load Diff
+5 -87
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,97 +17,15 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined(EVALUATE_H_INCLUDED)
#define EVALUATE_H_INCLUDED
////
//// Includes
////
#include "types.h"
#include <iostream>
#include "material.h"
#include "pawns.h"
////
//// Types
////
/// The EvalInfo struct contains various information computed and collected
/// by the evaluation function. An EvalInfo object is passed as one of the
/// arguments to the evaluation function, and the search can make use of its
/// contents to make intelligent search decisions.
///
/// At the moment, this is not utilized very much: The only part of the
/// EvalInfo object which is used by the search is futilityMargin.
class Position;
struct EvalInfo {
// Middle game and endgame evaluations
Score value;
// Pointers to material and pawn hash table entries
MaterialInfo* mi;
PawnInfo* pi;
// attackedBy[color][piece type] is a bitboard representing all squares
// attacked by a given color and piece type, attackedBy[color][0] contains
// all squares attacked by the given color.
Bitboard attackedBy[2][8];
Bitboard attacked_by(Color c) const { return attackedBy[c][0]; }
Bitboard attacked_by(Color c, PieceType pt) const { return attackedBy[c][pt]; }
// kingZone[color] is the zone around the enemy king which is considered
// by the king safety evaluation. This consists of the squares directly
// adjacent to the king, and the three (or two, for a king on an edge file)
// squares two ranks in front of the king. For instance, if black's king
// is on g8, kingZone[WHITE] is a bitboard containing the squares f8, h8,
// f7, g7, h7, f6, g6 and h6.
Bitboard kingZone[2];
// kingAttackersCount[color] is the number of pieces of the given color
// which attack a square in the kingZone of the enemy king.
int kingAttackersCount[2];
// kingAttackersWeight[color] is the sum of the "weight" of the pieces of the
// given color which attack a square in the kingZone of the enemy king. The
// weights of the individual piece types are given by the variables
// QueenAttackWeight, RookAttackWeight, BishopAttackWeight and
// KnightAttackWeight in evaluate.cpp
int kingAttackersWeight[2];
// kingAdjacentZoneAttacksCount[color] is the number of attacks to squares
// directly adjacent to the king of the given color. Pieces which attack
// more than one square are counted multiple times. For instance, if black's
// king is on g8 and there's a white knight on g5, this knight adds
// 2 to kingAdjacentZoneAttacksCount[BLACK].
int kingAdjacentZoneAttacksCount[2];
// mateThreat[color] is a move for the given side which gives a direct mate.
Move mateThreat[2];
// Middle game and endgame mobility scores.
Score mobility;
// Extra futility margin. This is added to the standard futility margin
// in the quiescence search.
Value futilityMargin;
};
////
//// Prototypes
////
extern Value evaluate(const Position& pos, EvalInfo& ei, int threadID);
extern Value quick_evaluate(const Position& pos);
extern void init_eval(int threads);
extern void quit_eval();
extern void read_weights(Color sideToMove);
extern Value evaluate(const Position& pos, Value& margin);
extern std::string trace_evaluate(const Position& pos);
extern void read_evaluation_uci_options(Color sideToMove);
#endif // !defined(EVALUATE_H_INCLUDED)
-92
View File
@@ -1,92 +0,0 @@
/*
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 <cassert>
#include <cstring>
#include "history.h"
////
//// Functions
////
/// Constructor
History::History() { clear(); }
/// History::clear() clears the history tables
void History::clear() {
memset(history, 0, 2 * 8 * 64 * sizeof(int));
}
/// History::success() registers a move as being successful. This is done
/// whenever a non-capturing move causes a beta cutoff in the main search.
/// The three parameters are the moving piece, the destination square, and
/// the search depth.
void History::success(Piece p, Square to, Depth d) {
assert(piece_is_ok(p));
assert(square_is_ok(to));
history[p][to] += int(d) * int(d);
// Prevent history overflow
if (history[p][to] >= HistoryMax)
for (int i = 0; i < 16; i++)
for (int j = 0; j < 64; j++)
history[i][j] /= 4;
}
/// History::failure() registers a move as being unsuccessful. The function is
/// called for each non-capturing move which failed to produce a beta cutoff
/// at a node where a beta cutoff was finally found.
void History::failure(Piece p, Square to, Depth d) {
assert(piece_is_ok(p));
assert(square_is_ok(to));
history[p][to] -= int(d) * int(d);
if (history[p][to] < 0)
history[p][to] = 0;
}
/// History::move_ordering_score() returns an integer value used to order the
/// non-capturing moves in the MovePicker class.
int History::move_ordering_score(Piece p, Square to) const {
assert(piece_is_ok(p));
assert(square_is_ok(to));
return history[p][to];
}
+27 -30
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,22 +17,11 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined(HISTORY_H_INCLUDED)
#define HISTORY_H_INCLUDED
////
//// Includes
////
#include "depth.h"
#include "move.h"
#include "piece.h"
////
//// Types
////
#include <cstring>
#include "types.h"
/// The History class stores statistics about how often different moves
/// have been successful or unsuccessful during the current search. These
@@ -44,30 +33,38 @@
class History {
public:
History();
void clear();
void success(Piece p, Square to, Depth d);
void failure(Piece p, Square to, Depth d);
int move_ordering_score(Piece p, Square to) const;
Value value(Piece p, Square to) const;
void update(Piece p, Square to, Value bonus);
Value gain(Piece p, Square to) const;
void update_gain(Piece p, Square to, Value g);
static const Value MaxValue = Value(2000);
private:
int history[16][64]; // [piece][square]
Value history[16][64]; // [piece][to_square]
Value maxGains[16][64]; // [piece][to_square]
};
inline void History::clear() {
memset(history, 0, 16 * 64 * sizeof(Value));
memset(maxGains, 0, 16 * 64 * sizeof(Value));
}
////
//// Constants and variables
////
inline Value History::value(Piece p, Square to) const {
return history[p][to];
}
/// HistoryMax controls how often the history counters will be scaled down:
/// When the history score for a move gets bigger than HistoryMax, all
/// entries in the table are divided by 4. It is difficult to guess what
/// the ideal value of this constant is. Scaling down the scores often has
/// the effect that parts of the search tree which have been searched
/// recently have a bigger importance for move ordering than the moves which
/// have been searched a long time ago.
inline void History::update(Piece p, Square to, Value bonus) {
if (abs(history[p][to] + bonus) < MaxValue) history[p][to] += bonus;
}
const int HistoryMax = 25000 * OnePly;
inline Value History::gain(Piece p, Square to) const {
return maxGains[p][to];
}
inline void History::update_gain(Piece p, Square to, Value g) {
maxGains[p][to] = Max(g, maxGains[p][to] - 1);
}
#endif // !defined(HISTORY_H_INCLUDED)
+35 -59
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,72 +17,24 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined(LOCK_H_INCLUDED)
#define LOCK_H_INCLUDED
// x86 assembly language locks or OS spin locks may perform faster than
// mutex locks on some platforms. On my machine, mutexes seem to be the
// best.
//#define ASM_LOCK
//#define OS_SPIN_LOCK
#if defined(ASM_LOCK)
typedef volatile int Lock;
static inline void LockX86(Lock *lock) {
int dummy;
asm __volatile__("1: movl $1, %0" "\n\t"
" xchgl (%1), %0" "\n\t" " testl %0, %0" "\n\t"
" jz 3f" "\n\t" "2: pause" "\n\t"
" movl (%1), %0" "\n\t" " testl %0, %0" "\n\t"
" jnz 2b" "\n\t" " jmp 1b" "\n\t" "3:"
"\n\t":"=&q"(dummy)
:"q"(lock)
:"cc");
}
static inline void UnlockX86(Lock *lock) {
int dummy;
asm __volatile__("movl $0, (%1)":"=&q"(dummy)
:"q"(lock));
}
# define lock_init(x, y) (*(x) = 0)
# define lock_grab(x) LockX86(x)
# define lock_release(x) UnlockX86(x)
# define lock_destroy(x)
#elif defined(OS_SPIN_LOCK)
# include <libkern/OSAtomic.h>
typedef OSSpinLock Lock;
# define lock_init(x, y) (*(x) = 0)
# define lock_grab(x) OSSpinLockLock(x)
# define lock_release(x) OSSpinLockUnlock(x)
# define lock_destroy(x)
#elif !defined(_MSC_VER)
#if !defined(_MSC_VER)
# include <pthread.h>
typedef pthread_mutex_t Lock;
typedef pthread_cond_t WaitCondition;
# define lock_init(x, y) pthread_mutex_init(x, y)
# define lock_init(x) pthread_mutex_init(x, NULL)
# define lock_grab(x) pthread_mutex_lock(x)
# define lock_release(x) pthread_mutex_unlock(x)
# define lock_destroy(x) pthread_mutex_destroy(x)
# define cond_destroy(x) pthread_cond_destroy(x)
# define cond_init(x) pthread_cond_init(x, NULL)
# define cond_signal(x) pthread_cond_signal(x)
# define cond_wait(x,y) pthread_cond_wait(x,y)
#else
@@ -90,14 +42,38 @@ typedef pthread_mutex_t Lock;
#include <windows.h>
#undef WIN32_LEAN_AND_MEAN
// Default fast and race free locks and condition variables
#if !defined(OLD_LOCKS)
typedef SRWLOCK Lock;
typedef CONDITION_VARIABLE WaitCondition;
# define lock_init(x) InitializeSRWLock(x)
# define lock_grab(x) AcquireSRWLockExclusive(x)
# define lock_release(x) ReleaseSRWLockExclusive(x)
# define lock_destroy(x) (x)
# define cond_destroy(x) (x)
# define cond_init(x) InitializeConditionVariable(x)
# define cond_signal(x) WakeConditionVariable(x)
# define cond_wait(x,y) SleepConditionVariableSRW(x, y, INFINITE,0)
// Fallback solution to build for Windows XP and older versions, note that
// cond_wait() is racy between lock_release() and WaitForSingleObject().
#else
typedef CRITICAL_SECTION Lock;
# define lock_init(x, y) InitializeCriticalSection(x)
typedef HANDLE WaitCondition;
# define lock_init(x) InitializeCriticalSection(x)
# define lock_grab(x) EnterCriticalSection(x)
# define lock_release(x) LeaveCriticalSection(x)
# define lock_destroy(x) DeleteCriticalSection(x)
# define cond_init(x) { *x = CreateEvent(0, FALSE, FALSE, 0); }
# define cond_destroy(x) CloseHandle(*x)
# define cond_signal(x) SetEvent(*x)
# define cond_wait(x,y) { lock_release(y); WaitForSingleObject(*x, INFINITE); lock_grab(y); }
#endif
#endif
#endif // !defined(LOCK_H_INCLUDED)
+41 -43
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,18 +20,16 @@
// To profile with callgrind uncomment following line
//#define USE_CALLGRIND
////
//// Includes
////
#include <cstdio>
#include <iostream>
#include <string>
#include "benchmark.h"
#include "bitcount.h"
#include "misc.h"
#include "uci.h"
#include "bitboard.h"
#include "evaluate.h"
#include "position.h"
#include "thread.h"
#include "search.h"
#include "ucioption.h"
#ifdef USE_CALLGRIND
#include <valgrind/callgrind.h>
@@ -39,51 +37,51 @@
using namespace std;
extern bool execute_uci_command(const string& cmd);
extern void benchmark(int argc, char* argv[]);
extern void init_kpk_bitbase();
////
//// Functions
////
int main(int argc, char* argv[]) {
int main(int argc, char *argv[]) {
// Disable IO buffering
// Disable IO buffering for C and C++ standard libraries
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
cout.rdbuf()->pubsetbuf(NULL, 0);
cin.rdbuf()->pubsetbuf(NULL, 0);
// Initialization through global resources manager
Application::initialize();
// Startup initializations
init_bitboards();
Position::init_zobrist();
Position::init_piece_square_tables();
init_kpk_bitbase();
init_search();
Threads.init();
#ifdef USE_CALLGRIND
CALLGRIND_START_INSTRUMENTATION;
#endif
// Process command line arguments if any
if (argc > 1)
if (argc < 2)
{
if (string(argv[1]) != "bench" || argc < 4 || argc > 8)
cout << "Usage: stockfish bench <hash size> <threads> "
<< "[time = 60s] [fen positions file = default] "
<< "[time, depth, perft or node limited = time] "
<< "[timing file name = none]" << endl;
else
{
string time = argc > 4 ? argv[4] : "60";
string fen = argc > 5 ? argv[5] : "default";
string lim = argc > 6 ? argv[6] : "time";
string tim = argc > 7 ? argv[7] : "";
benchmark(string(argv[2]) + " " + string(argv[3]) + " " + time + " " + fen + " " + lim + " " + tim);
}
return 0;
// Print copyright notice
cout << engine_name() << " by " << engine_authors() << endl;
if (CpuHasPOPCNT)
cout << "Good! CPU has hardware POPCNT." << endl;
// Wait for a command from the user, and passes this command to
// execute_uci_command() and also intercepts EOF from stdin to
// ensure that we exit gracefully if the GUI dies unexpectedly.
string cmd;
while (getline(cin, cmd) && execute_uci_command(cmd)) {}
}
else if (string(argv[1]) == "bench" && argc < 8)
benchmark(argc, argv);
else
cout << "Usage: stockfish bench [hash size = 128] [threads = 1] "
<< "[limit = 12] [fen positions file = default] "
<< "[limited by depth, time, nodes or perft = depth]" << endl;
// Print copyright notice
cout << engine_name()
<< ". By Tord Romstad, Marco Costalba, Joona Kiiski." << endl;
if (CpuHasPOPCNT)
cout << "Good! CPU has hardware POPCNT. We will use it." << endl;
// Enter UCI mode
uci_main_loop();
Threads.exit();
return 0;
}
+225 -370
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,120 +17,257 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
////
//// Includes
////
#include <cassert>
#include <sstream>
#include <map>
#include <cstring>
#include "material.h"
using namespace std;
////
//// Local definitions
////
namespace {
// Values modified by Joona Kiiski
const Value MidgameLimit = Value(15581);
const Value EndgameLimit = Value(3998);
// Scale factors used when one side has no more pawns
const int NoPawnsSF[4] = { 6, 12, 32 };
// Polynomial material balance parameters
const Value RedundantQueenPenalty = Value(320);
const Value RedundantRookPenalty = Value(554);
const int LinearCoefficients[6] = { 1617, -162, -1172, -190, 105, 26 };
const int QuadraticCoefficientsSameColor[][6] = {
const int QuadraticCoefficientsSameColor[][8] = {
{ 7, 7, 7, 7, 7, 7 }, { 39, 2, 7, 7, 7, 7 }, { 35, 271, -4, 7, 7, 7 },
{ 7, 25, 4, 7, 7, 7 }, { -27, -2, 46, 100, 56, 7 }, { 58, 29, 83, 148, -3, -25 } };
const int QuadraticCoefficientsOppositeColor[][6] = {
const int QuadraticCoefficientsOppositeColor[][8] = {
{ 41, 41, 41, 41, 41, 41 }, { 37, 41, 41, 41, 41, 41 }, { 10, 62, 41, 41, 41, 41 },
{ 57, 64, 39, 41, 41, 41 }, { 50, 40, 23, -22, 41, 41 }, { 106, 101, 3, 151, 171, 41 } };
// Named endgame evaluation and scaling functions, these
// are accessed direcly and not through the function maps.
EvaluationFunction<KmmKm> EvaluateKmmKm(WHITE);
EvaluationFunction<KXK> EvaluateKXK(WHITE), EvaluateKKX(BLACK);
ScalingFunction<KBPsK> ScaleKBPsK(WHITE), ScaleKKBPs(BLACK);
ScalingFunction<KQKRPs> ScaleKQKRPs(WHITE), ScaleKRPsKQ(BLACK);
ScalingFunction<KPsK> ScaleKPsK(WHITE), ScaleKKPs(BLACK);
ScalingFunction<KPKP> ScaleKPKPw(WHITE), ScaleKPKPb(BLACK);
// Endgame evaluation and scaling functions accessed direcly and not through
// the function maps because correspond to more then one material hash key.
Endgame<Value, KmmKm> EvaluateKmmKm[] = { Endgame<Value, KmmKm>(WHITE), Endgame<Value, KmmKm>(BLACK) };
Endgame<Value, KXK> EvaluateKXK[] = { Endgame<Value, KXK>(WHITE), Endgame<Value, KXK>(BLACK) };
typedef EndgameEvaluationFunctionBase EF;
typedef EndgameScalingFunctionBase SF;
}
Endgame<ScaleFactor, KBPsK> ScaleKBPsK[] = { Endgame<ScaleFactor, KBPsK>(WHITE), Endgame<ScaleFactor, KBPsK>(BLACK) };
Endgame<ScaleFactor, KQKRPs> ScaleKQKRPs[] = { Endgame<ScaleFactor, KQKRPs>(WHITE), Endgame<ScaleFactor, KQKRPs>(BLACK) };
Endgame<ScaleFactor, KPsK> ScaleKPsK[] = { Endgame<ScaleFactor, KPsK>(WHITE), Endgame<ScaleFactor, KPsK>(BLACK) };
Endgame<ScaleFactor, KPKP> ScaleKPKP[] = { Endgame<ScaleFactor, KPKP>(WHITE), Endgame<ScaleFactor, KPKP>(BLACK) };
////
//// Classes
////
/// EndgameFunctions class stores endgame evaluation and scaling functions
/// in two std::map. Because STL library is not guaranteed to be thread
/// safe even for read access, the maps, although with identical content,
/// are replicated for each thread. This is faster then using locks.
class EndgameFunctions {
public:
EndgameFunctions();
~EndgameFunctions();
template<class T> T* get(Key key) const;
private:
template<class T> void add(const string& keyCode);
static Key buildKey(const string& keyCode);
static const string swapColors(const string& keyCode);
// Here we store two maps, for evaluate and scaling functions
pair<map<Key, EF*>, map<Key, SF*> > maps;
// Maps accessing functions returning const and non-const references
template<typename T> const map<Key, T*>& get() const { return maps.first; }
template<typename T> map<Key, T*>& get() { return maps.first; }
};
// Explicit specializations of a member function shall be declared in
// the namespace of which the class template is a member.
template<> const map<Key, SF*>&
EndgameFunctions::get<SF>() const { return maps.second; }
template<> map<Key, SF*>&
EndgameFunctions::get<SF>() { return maps.second; }
////
//// Functions
////
/// MaterialInfoTable c'tor and d'tor, called once by each thread
MaterialInfoTable::MaterialInfoTable(unsigned int numOfEntries) {
size = numOfEntries;
entries = new MaterialInfo[size];
funcs = new EndgameFunctions();
if (!entries || !funcs)
{
cerr << "Failed to allocate " << numOfEntries * sizeof(MaterialInfo)
<< " bytes for material hash table." << endl;
Application::exit_with_failure();
// Helper templates used to detect a given material distribution
template<Color Us> bool is_KXK(const Position& pos) {
const Color Them = (Us == WHITE ? BLACK : WHITE);
return pos.non_pawn_material(Them) == VALUE_ZERO
&& pos.piece_count(Them, PAWN) == 0
&& pos.non_pawn_material(Us) >= RookValueMidgame;
}
template<Color Us> bool is_KBPsKs(const Position& pos) {
return pos.non_pawn_material(Us) == BishopValueMidgame
&& pos.piece_count(Us, BISHOP) == 1
&& pos.piece_count(Us, PAWN) >= 1;
}
template<Color Us> bool is_KQKRPs(const Position& pos) {
const Color Them = (Us == WHITE ? BLACK : WHITE);
return pos.piece_count(Us, PAWN) == 0
&& pos.non_pawn_material(Us) == QueenValueMidgame
&& pos.piece_count(Us, QUEEN) == 1
&& pos.piece_count(Them, ROOK) == 1
&& pos.piece_count(Them, PAWN) >= 1;
}
} // namespace
/// MaterialInfoTable c'tor and d'tor allocate and free the space for Endgames
void MaterialInfoTable::init() { Base::init(); if (!funcs) funcs = new Endgames(); }
MaterialInfoTable::~MaterialInfoTable() { delete funcs; }
/// MaterialInfoTable::get_material_info() takes a position object as input,
/// computes or looks up a MaterialInfo object, and returns a pointer to it.
/// If the material configuration is not already present in the table, it
/// is stored there, so we don't have to recompute everything when the
/// same material configuration occurs again.
MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) const {
Key key = pos.get_material_key();
MaterialInfo* mi = probe(key);
// If mi->key matches the position's material hash key, it means that we
// have analysed this material configuration before, and we can simply
// return the information we found the last time instead of recomputing it.
if (mi->key == key)
return mi;
// Initialize MaterialInfo entry
memset(mi, 0, sizeof(MaterialInfo));
mi->key = key;
mi->factor[WHITE] = mi->factor[BLACK] = (uint8_t)SCALE_FACTOR_NORMAL;
// Store game phase
mi->gamePhase = MaterialInfoTable::game_phase(pos);
// Let's look if we have a specialized evaluation function for this
// particular material configuration. First we look for a fixed
// configuration one, then a generic one if previous search failed.
if ((mi->evaluationFunction = funcs->get<EndgameBase<Value> >(key)) != NULL)
return mi;
if (is_KXK<WHITE>(pos))
{
mi->evaluationFunction = &EvaluateKXK[WHITE];
return mi;
}
if (is_KXK<BLACK>(pos))
{
mi->evaluationFunction = &EvaluateKXK[BLACK];
return mi;
}
if (!pos.pieces(PAWN) && !pos.pieces(ROOK) && !pos.pieces(QUEEN))
{
// Minor piece endgame with at least one minor piece per side and
// no pawns. Note that the case KmmK is already handled by KXK.
assert((pos.pieces(KNIGHT, WHITE) | pos.pieces(BISHOP, WHITE)));
assert((pos.pieces(KNIGHT, BLACK) | pos.pieces(BISHOP, 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[WHITE];
return mi;
}
}
// OK, we didn't find any special evaluation function for the current
// material configuration. Is there a suitable scaling function?
//
// We face problems when there are several conflicting applicable
// scaling functions and we need to decide which one to use.
EndgameBase<ScaleFactor>* sf;
if ((sf = funcs->get<EndgameBase<ScaleFactor> >(key)) != NULL)
{
mi->scalingFunction[sf->color()] = sf;
return mi;
}
// Generic scaling functions that refer to more then one material
// distribution. Should be probed after the specialized ones.
// Note that these ones don't return after setting the function.
if (is_KBPsKs<WHITE>(pos))
mi->scalingFunction[WHITE] = &ScaleKBPsK[WHITE];
if (is_KBPsKs<BLACK>(pos))
mi->scalingFunction[BLACK] = &ScaleKBPsK[BLACK];
if (is_KQKRPs<WHITE>(pos))
mi->scalingFunction[WHITE] = &ScaleKQKRPs[WHITE];
else if (is_KQKRPs<BLACK>(pos))
mi->scalingFunction[BLACK] = &ScaleKQKRPs[BLACK];
Value npm_w = pos.non_pawn_material(WHITE);
Value npm_b = pos.non_pawn_material(BLACK);
if (npm_w + npm_b == VALUE_ZERO)
{
if (pos.piece_count(BLACK, PAWN) == 0)
{
assert(pos.piece_count(WHITE, PAWN) >= 2);
mi->scalingFunction[WHITE] = &ScaleKPsK[WHITE];
}
else if (pos.piece_count(WHITE, PAWN) == 0)
{
assert(pos.piece_count(BLACK, PAWN) >= 2);
mi->scalingFunction[BLACK] = &ScaleKPsK[BLACK];
}
else if (pos.piece_count(WHITE, PAWN) == 1 && pos.piece_count(BLACK, PAWN) == 1)
{
// This is a special case because we set scaling functions
// for both colors instead of only one.
mi->scalingFunction[WHITE] = &ScaleKPKP[WHITE];
mi->scalingFunction[BLACK] = &ScaleKPKP[BLACK];
}
}
// No pawns makes it difficult to win, even with a material advantage
if (pos.piece_count(WHITE, PAWN) == 0 && npm_w - npm_b <= BishopValueMidgame)
{
mi->factor[WHITE] = uint8_t
(npm_w == npm_b || npm_w < RookValueMidgame ? 0 : NoPawnsSF[Min(pos.piece_count(WHITE, BISHOP), 2)]);
}
if (pos.piece_count(BLACK, PAWN) == 0 && npm_b - npm_w <= BishopValueMidgame)
{
mi->factor[BLACK] = uint8_t
(npm_w == npm_b || npm_b < RookValueMidgame ? 0 : NoPawnsSF[Min(pos.piece_count(BLACK, BISHOP), 2)]);
}
// Compute the space weight
if (npm_w + npm_b >= 2 * QueenValueMidgame + 4 * RookValueMidgame + 2 * KnightValueMidgame)
{
int minorPieceCount = pos.piece_count(WHITE, KNIGHT) + pos.piece_count(WHITE, BISHOP)
+ pos.piece_count(BLACK, KNIGHT) + pos.piece_count(BLACK, BISHOP);
mi->spaceWeight = minorPieceCount * minorPieceCount;
}
// Evaluate the material imbalance. We use PIECE_TYPE_NONE as a place holder
// for the bishop pair "extended piece", this allow us to be more flexible
// in defining bishop pair bonuses.
const int pieceCount[2][8] = {
{ pos.piece_count(WHITE, BISHOP) > 1, pos.piece_count(WHITE, PAWN), pos.piece_count(WHITE, KNIGHT),
pos.piece_count(WHITE, BISHOP) , pos.piece_count(WHITE, ROOK), pos.piece_count(WHITE, QUEEN) },
{ pos.piece_count(BLACK, BISHOP) > 1, pos.piece_count(BLACK, PAWN), pos.piece_count(BLACK, KNIGHT),
pos.piece_count(BLACK, BISHOP) , pos.piece_count(BLACK, ROOK), pos.piece_count(BLACK, QUEEN) } };
mi->value = int16_t((imbalance<WHITE>(pieceCount) - imbalance<BLACK>(pieceCount)) / 16);
return mi;
}
MaterialInfoTable::~MaterialInfoTable() {
delete funcs;
delete [] entries;
/// MaterialInfoTable::imbalance() calculates imbalance comparing piece count of each
/// piece type for both colors.
template<Color Us>
int MaterialInfoTable::imbalance(const int pieceCount[][8]) {
const Color Them = (Us == WHITE ? BLACK : WHITE);
int pt1, pt2, pc, v;
int value = 0;
// Redundancy of major pieces, formula based on Kaufman's paper
// "The Evaluation of Material Imbalances in Chess"
if (pieceCount[Us][ROOK] > 0)
value -= RedundantRookPenalty * (pieceCount[Us][ROOK] - 1)
+ RedundantQueenPenalty * pieceCount[Us][QUEEN];
// Second-degree polynomial material imbalance by Tord Romstad
for (pt1 = PIECE_TYPE_NONE; pt1 <= QUEEN; pt1++)
{
pc = pieceCount[Us][pt1];
if (!pc)
continue;
v = LinearCoefficients[pt1];
for (pt2 = PIECE_TYPE_NONE; pt2 <= pt1; pt2++)
v += QuadraticCoefficientsSameColor[pt1][pt2] * pieceCount[Us][pt2]
+ QuadraticCoefficientsOppositeColor[pt1][pt2] * pieceCount[Them][pt2];
value += pc * v;
}
return value;
}
@@ -142,289 +279,7 @@ Phase MaterialInfoTable::game_phase(const Position& pos) {
Value npm = pos.non_pawn_material(WHITE) + pos.non_pawn_material(BLACK);
if (npm >= MidgameLimit)
return PHASE_MIDGAME;
else if (npm <= EndgameLimit)
return PHASE_ENDGAME;
return Phase(((npm - EndgameLimit) * 128) / (MidgameLimit - EndgameLimit));
}
/// MaterialInfoTable::get_material_info() takes a position object as input,
/// computes or looks up a MaterialInfo object, and returns a pointer to it.
/// If the material configuration is not already present in the table, it
/// is stored there, so we don't have to recompute everything when the
/// same material configuration occurs again.
MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) {
Key key = pos.get_material_key();
int index = key & (size - 1);
MaterialInfo* mi = entries + index;
// If mi->key matches the position's material hash key, it means that we
// have analysed this material configuration before, and we can simply
// return the information we found the last time instead of recomputing it.
if (mi->key == key)
return mi;
// Clear the MaterialInfo object, and set its key
mi->clear();
mi->key = key;
// Store game phase
mi->gamePhase = MaterialInfoTable::game_phase(pos);
// Let's look if we have a specialized evaluation function for this
// particular material configuration. First we look for a fixed
// configuration one, then a generic one if previous search failed.
if ((mi->evaluationFunction = funcs->get<EF>(key)) != NULL)
return mi;
else if ( pos.non_pawn_material(BLACK) == Value(0)
&& pos.piece_count(BLACK, PAWN) == 0
&& pos.non_pawn_material(WHITE) >= RookValueMidgame)
{
mi->evaluationFunction = &EvaluateKXK;
return mi;
}
else if ( pos.non_pawn_material(WHITE) == Value(0)
&& pos.piece_count(WHITE, PAWN) == 0
&& pos.non_pawn_material(BLACK) >= RookValueMidgame)
{
mi->evaluationFunction = &EvaluateKKX;
return mi;
}
else if ( pos.pieces(PAWN) == EmptyBoardBB
&& pos.pieces(ROOK) == EmptyBoardBB
&& pos.pieces(QUEEN) == EmptyBoardBB)
{
// Minor piece endgame with at least one minor piece per side and
// no pawns. Note that the case KmmK is already handled by KXK.
assert((pos.pieces(KNIGHT, WHITE) | pos.pieces(BISHOP, WHITE)));
assert((pos.pieces(KNIGHT, BLACK) | pos.pieces(BISHOP, 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
// material configuration. Is there a suitable scaling function?
//
// The code below is rather messy, and it could easily get worse later,
// if we decide to add more special cases. We face problems when there
// are several conflicting applicable scaling functions and we need to
// decide which one to use.
SF* sf;
if ((sf = funcs->get<SF>(key)) != NULL)
{
mi->scalingFunction[sf->color()] = sf;
return mi;
}
// Generic scaling functions that refer to more then one material
// distribution. Should be probed after the specialized ones.
// Note that these ones don't return after setting the function.
if ( pos.non_pawn_material(WHITE) == BishopValueMidgame
&& pos.piece_count(WHITE, BISHOP) == 1
&& pos.piece_count(WHITE, PAWN) >= 1)
mi->scalingFunction[WHITE] = &ScaleKBPsK;
if ( pos.non_pawn_material(BLACK) == BishopValueMidgame
&& pos.piece_count(BLACK, BISHOP) == 1
&& pos.piece_count(BLACK, PAWN) >= 1)
mi->scalingFunction[BLACK] = &ScaleKKBPs;
if ( pos.piece_count(WHITE, PAWN) == 0
&& pos.non_pawn_material(WHITE) == QueenValueMidgame
&& pos.piece_count(WHITE, QUEEN) == 1
&& pos.piece_count(BLACK, ROOK) == 1
&& pos.piece_count(BLACK, PAWN) >= 1)
mi->scalingFunction[WHITE] = &ScaleKQKRPs;
else if ( pos.piece_count(BLACK, PAWN) == 0
&& pos.non_pawn_material(BLACK) == QueenValueMidgame
&& pos.piece_count(BLACK, QUEEN) == 1
&& pos.piece_count(WHITE, ROOK) == 1
&& pos.piece_count(WHITE, PAWN) >= 1)
mi->scalingFunction[BLACK] = &ScaleKRPsKQ;
if (pos.non_pawn_material(WHITE) + pos.non_pawn_material(BLACK) == Value(0))
{
if (pos.piece_count(BLACK, PAWN) == 0)
{
assert(pos.piece_count(WHITE, PAWN) >= 2);
mi->scalingFunction[WHITE] = &ScaleKPsK;
}
else if (pos.piece_count(WHITE, PAWN) == 0)
{
assert(pos.piece_count(BLACK, PAWN) >= 2);
mi->scalingFunction[BLACK] = &ScaleKKPs;
}
else if (pos.piece_count(WHITE, PAWN) == 1 && pos.piece_count(BLACK, PAWN) == 1)
{
// This is a special case because we set scaling functions
// for both colors instead of only one.
mi->scalingFunction[WHITE] = &ScaleKPKPw;
mi->scalingFunction[BLACK] = &ScaleKPKPb;
}
}
// 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
const int pieceCount[2][6] = { { pos.piece_count(WHITE, BISHOP) > 1, pos.piece_count(WHITE, PAWN), pos.piece_count(WHITE, KNIGHT),
pos.piece_count(WHITE, BISHOP), pos.piece_count(WHITE, ROOK), pos.piece_count(WHITE, QUEEN) },
{ pos.piece_count(BLACK, BISHOP) > 1, pos.piece_count(BLACK, PAWN), pos.piece_count(BLACK, KNIGHT),
pos.piece_count(BLACK, BISHOP), pos.piece_count(BLACK, ROOK), pos.piece_count(BLACK, QUEEN) } };
Color c, them;
int sign, pt1, pt2, pc;
int v, vv, matValue = 0;
for (c = WHITE, sign = 1; c <= BLACK; c++, sign = -sign)
{
// No pawns makes it difficult to win, even with a material advantage
if ( pos.piece_count(c, PAWN) == 0
&& pos.non_pawn_material(c) - pos.non_pawn_material(opposite_color(c)) <= BishopValueMidgame)
{
if ( pos.non_pawn_material(c) == pos.non_pawn_material(opposite_color(c))
|| pos.non_pawn_material(c) < RookValueMidgame)
mi->factor[c] = 0;
else
{
switch (pos.piece_count(c, BISHOP)) {
case 2:
mi->factor[c] = 32;
break;
case 1:
mi->factor[c] = 12;
break;
case 0:
mi->factor[c] = 6;
break;
}
}
}
// Redundancy of major pieces, formula based on Kaufman's paper
// "The Evaluation of Material Imbalances in Chess"
// http://mywebpages.comcast.net/danheisman/Articles/evaluation_of_material_imbalance.htm
if (pieceCount[c][ROOK] >= 1)
matValue -= sign * ((pieceCount[c][ROOK] - 1) * RedundantRookPenalty + pieceCount[c][QUEEN] * RedundantQueenPenalty);
them = opposite_color(c);
v = 0;
// Second-degree polynomial material imbalance by Tord Romstad
//
// We use NO_PIECE_TYPE as a place holder for the bishop pair "extended piece",
// this allow us to be more flexible in defining bishop pair bonuses.
for (pt1 = NO_PIECE_TYPE; pt1 <= QUEEN; pt1++)
{
pc = pieceCount[c][pt1];
if (!pc)
continue;
vv = LinearCoefficients[pt1];
for (pt2 = NO_PIECE_TYPE; pt2 <= pt1; pt2++)
vv += pieceCount[c][pt2] * QuadraticCoefficientsSameColor[pt1][pt2]
+ pieceCount[them][pt2] * QuadraticCoefficientsOppositeColor[pt1][pt2];
v += pc * vv;
}
matValue += sign * v;
}
mi->value = int16_t(matValue / 16);
return mi;
}
/// EndgameFunctions member definitions.
EndgameFunctions::EndgameFunctions() {
add<EvaluationFunction<KNNK> >("KNNK");
add<EvaluationFunction<KPK> >("KPK");
add<EvaluationFunction<KBNK> >("KBNK");
add<EvaluationFunction<KRKP> >("KRKP");
add<EvaluationFunction<KRKB> >("KRKB");
add<EvaluationFunction<KRKN> >("KRKN");
add<EvaluationFunction<KQKR> >("KQKR");
add<EvaluationFunction<KBBKN> >("KBBKN");
add<ScalingFunction<KNPK> >("KNPK");
add<ScalingFunction<KRPKR> >("KRPKR");
add<ScalingFunction<KBPKB> >("KBPKB");
add<ScalingFunction<KBPPKB> >("KBPPKB");
add<ScalingFunction<KBPKN> >("KBPKN");
add<ScalingFunction<KRPPKRP> >("KRPPKRP");
}
EndgameFunctions::~EndgameFunctions() {
for (map<Key, EF*>::iterator it = maps.first.begin(); it != maps.first.end(); ++it)
delete (*it).second;
for (map<Key, SF*>::iterator it = maps.second.begin(); it != maps.second.end(); ++it)
delete (*it).second;
}
Key EndgameFunctions::buildKey(const string& keyCode) {
assert(keyCode.length() > 0 && keyCode[0] == 'K');
assert(keyCode.length() < 8);
stringstream s;
bool upcase = false;
// Build up a fen string 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();
}
const string EndgameFunctions::swapColors(const string& keyCode) {
// Build corresponding key for the opposite color: "KBPKN" -> "KNKBP"
size_t idx = keyCode.find("K", 1);
return keyCode.substr(idx) + keyCode.substr(0, idx);
}
template<class T>
void EndgameFunctions::add(const string& keyCode) {
typedef typename T::Base F;
get<F>().insert(pair<Key, F*>(buildKey(keyCode), new T(WHITE)));
get<F>().insert(pair<Key, F*>(buildKey(swapColors(keyCode)), new T(BLACK)));
}
template<class T>
T* EndgameFunctions::get(Key key) const {
typename map<Key, T*>::const_iterator it(get<T>().find(key));
return (it != get<T>().end() ? it->second : NULL);
return npm >= MidgameLimit ? PHASE_MIDGAME
: npm <= EndgameLimit ? PHASE_ENDGAME
: Phase(((npm - EndgameLimit) * 128) / (MidgameLimit - EndgameLimit));
}
+36 -96
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,22 +17,15 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined(MATERIAL_H_INCLUDED)
#define MATERIAL_H_INCLUDED
////
//// Includes
////
#include "endgame.h"
#include "position.h"
#include "scale.h"
#include "tt.h"
#include "types.h"
////
//// Types
////
const int MaterialTableSize = 8192;
/// MaterialInfo is a class which contains various information about a
/// material configuration. It contains a material balance evaluation,
@@ -49,8 +42,6 @@ class MaterialInfo {
friend class MaterialInfoTable;
public:
MaterialInfo() : key(0) { clear(); }
Score material_value() const;
ScaleFactor scale_factor(const Position& pos, Color c) const;
int space_weight() const;
@@ -59,66 +50,34 @@ public:
Value evaluate(const Position& pos) const;
private:
inline void clear();
Key key;
int16_t value;
uint8_t factor[2];
EndgameEvaluationFunctionBase* evaluationFunction;
EndgameScalingFunctionBase* scalingFunction[2];
EndgameBase<Value>* evaluationFunction;
EndgameBase<ScaleFactor>* scalingFunction[2];
int spaceWeight;
Phase gamePhase;
};
/// The MaterialInfoTable class represents a pawn hash table. It is basically
/// just an array of MaterialInfo objects and a few methods for accessing these
/// objects. The most important method is get_material_info, which looks up a
/// position in the table and returns a pointer to a MaterialInfo object.
class EndgameFunctions;
class MaterialInfoTable {
/// The MaterialInfoTable class represents a pawn hash table. The most important
/// method is get_material_info, which returns a pointer to a MaterialInfo object.
class MaterialInfoTable : public SimpleHash<MaterialInfo, MaterialTableSize> {
public:
MaterialInfoTable(unsigned numOfEntries);
~MaterialInfoTable();
MaterialInfo* get_material_info(const Position& pos);
void init();
MaterialInfo* get_material_info(const Position& pos) const;
static Phase game_phase(const Position& pos);
private:
unsigned size;
MaterialInfo* entries;
EndgameFunctions* funcs;
template<Color Us>
static int imbalance(const int pieceCount[][8]);
Endgames* funcs;
};
////
//// Inline functions
////
/// MaterialInfo::material_value simply returns the material balance
/// evaluation that is independent from game phase.
inline Score MaterialInfo::material_value() const {
return make_score(value, value);
}
/// MaterialInfo::clear() resets a MaterialInfo object to an empty state,
/// with all slots at their default values but the key.
inline void MaterialInfo::clear() {
value = 0;
factor[WHITE] = factor[BLACK] = uint8_t(SCALE_FACTOR_NORMAL);
evaluationFunction = NULL;
scalingFunction[WHITE] = scalingFunction[BLACK] = NULL;
spaceWeight = 0;
}
/// MaterialInfo::scale_factor takes a position and a color as input, and
/// returns a scale factor for the given color. We have to provide the
/// position in addition to the color, because the scale factor need not
@@ -128,50 +87,31 @@ inline void MaterialInfo::clear() {
inline ScaleFactor MaterialInfo::scale_factor(const Position& pos, Color c) const {
if (scalingFunction[c] != NULL)
{
ScaleFactor sf = scalingFunction[c]->apply(pos);
if (sf != SCALE_FACTOR_NONE)
return sf;
}
return ScaleFactor(factor[c]);
if (!scalingFunction[c])
return ScaleFactor(factor[c]);
ScaleFactor sf = scalingFunction[c]->apply(pos);
return sf == SCALE_FACTOR_NONE ? ScaleFactor(factor[c]) : sf;
}
/// MaterialInfo::space_weight() simply returns the weight for the space
/// evaluation for this material configuration.
inline int MaterialInfo::space_weight() const {
return spaceWeight;
}
/// MaterialInfo::game_phase() returns the game phase according
/// to this material configuration.
inline Phase MaterialInfo::game_phase() const {
return gamePhase;
}
/// MaterialInfo::specialized_eval_exists decides whether there is a
/// specialized evaluation function for the current material configuration,
/// or if the normal evaluation function should be used.
inline bool MaterialInfo::specialized_eval_exists() const {
return evaluationFunction != NULL;
}
/// MaterialInfo::evaluate applies a specialized evaluation function
/// to a given position object. It should only be called when
/// specialized_eval_exists() returns 'true'.
inline Value MaterialInfo::evaluate(const Position& pos) const {
return evaluationFunction->apply(pos);
}
inline Score MaterialInfo::material_value() const {
return make_score(value, value);
}
inline int MaterialInfo::space_weight() const {
return spaceWeight;
}
inline Phase MaterialInfo::game_phase() const {
return gamePhase;
}
inline bool MaterialInfo::specialized_eval_exists() const {
return evaluationFunction != NULL;
}
#endif // !defined(MATERIAL_H_INCLUDED)
-149
View File
@@ -1,149 +0,0 @@
/*
A C-program for MT19937, with initialization improved 2002/1/26.
Coded by Takuji Nishimura and Makoto Matsumoto.
Before using, initialize the state by using init_genrand(seed)
or init_by_array(init_key, key_length).
Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The names of its contributors may not be used to endorse or promote
products derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Any feedback is very welcome.
http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space)
*/
#include "types.h"
#include "mersenne.h"
/* Period parameters */
#define N 624
#define M 397
#define MATRIX_A 0x9908b0dfUL /* constant vector a */
#define UPPER_MASK 0x80000000UL /* most significant w-r bits */
#define LOWER_MASK 0x7fffffffUL /* least significant r bits */
static unsigned long mt[N]; /* the array for the state vector */
static int mti=N+1; /* mti==N+1 means mt[N] is not initialized */
/* initializes mt[N] with a seed */
static void init_genrand(unsigned long s)
{
mt[0]= s & 0xffffffffUL;
for (mti=1; mti<N; mti++) {
mt[mti] =
(1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti);
/* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
/* In the previous versions, MSBs of the seed affect */
/* only MSBs of the array mt[]. */
/* 2002/01/09 modified by Makoto Matsumoto */
mt[mti] &= 0xffffffffUL;
/* for >32 bit machines */
}
}
/* initialize by an array with array-length */
/* init_key is the array for initializing keys */
/* key_length is its length */
/* slight change for C++, 2004/2/26 */
static void init_by_array(unsigned long init_key[], int key_length)
{
int i, j, k;
init_genrand(19650218UL);
i=1; j=0;
k = (N>key_length ? N : key_length);
for (; k; k--) {
mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525UL))
+ init_key[j] + j; /* non linear */
mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
i++; j++;
if (i>=N) { mt[0] = mt[N-1]; i=1; }
if (j>=key_length) j=0;
}
for (k=N-1; k; k--) {
mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941UL))
- i; /* non linear */
mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
i++;
if (i>=N) { mt[0] = mt[N-1]; i=1; }
}
mt[0] = 0x80000000UL; /* MSB is 1; assuring non-zero initial array */
}
/* generates a random number on [0,0xffffffff]-interval */
uint32_t genrand_int32(void) {
unsigned long y;
static unsigned long mag01[2]={0x0UL, MATRIX_A};
/* mag01[x] = x * MATRIX_A for x=0,1 */
if (mti >= N) { /* generate N words at one time */
int kk;
if (mti == N+1) /* if init_genrand() has not been called, */
init_genrand(5489UL); /* a default initial seed is used */
for (kk=0;kk<N-M;kk++) {
y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
mt[kk] = mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1UL];
}
for (;kk<N-1;kk++) {
y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
mt[kk] = mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1UL];
}
y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK);
mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1UL];
mti = 0;
}
y = mt[mti++];
/* Tempering */
y ^= (y >> 11);
y ^= (y << 7) & 0x9d2c5680UL;
y ^= (y << 15) & 0xefc60000UL;
y ^= (y >> 18);
return y;
}
uint64_t genrand_int64(void) {
uint64_t x, y;
x = genrand_int32(); y = genrand_int32();
return (x<<32)|y;
}
void init_mersenne(void) {
unsigned long init[4]={0x123, 0x234, 0x345, 0x456}, length=4;
init_by_array(init, length);
}
-40
View File
@@ -1,40 +0,0 @@
/*
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(MERSENNE_H_INCLUDED)
#define MERSENNE_H_INCLUDED
////
//// Includes
////
#include "types.h"
////
//// Prototypes
////
extern uint32_t genrand_int32(void);
extern uint64_t genrand_int64(void);
extern void init_mersenne(void);
#endif // !defined(MERSENNE_H_INCLUDED)
+173 -181
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,16 +17,14 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
////
//// Includes
////
#if !defined(_MSC_VER)
# include <sys/time.h>
# include <sys/types.h>
# include <unistd.h>
# if defined(__hpux)
# include <sys/pstat.h>
# endif
#else
@@ -36,6 +34,10 @@
#endif
#if !defined(NO_PREFETCH)
# include <xmmintrin.h>
#endif
#include <cassert>
#include <cstdio>
#include <iomanip>
@@ -44,180 +46,145 @@
#include "bitcount.h"
#include "misc.h"
#include "thread.h"
using namespace std;
/// Version number. If this is left empty, the current date (in the format
/// YYMMDD) is used as a version number.
/// Version number. If EngineVersion is left empty, then AppTag plus
/// current date (in the format YYMMDD) is used as a version number.
static const string EngineVersion = "1.6.3";
static const string AppName = "Stockfish";
static const string EngineVersion = "2.1";
static const string AppTag = "";
////
//// Variables
////
bool Chess960;
uint64_t dbg_cnt0 = 0;
uint64_t dbg_cnt1 = 0;
bool dbg_show_mean = false;
bool dbg_show_hit_rate = false;
////
//// 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() {
cout << "Total " << dbg_cnt0 << " Hit " << dbg_cnt1
<< " hit rate (%) " << (dbg_cnt1*100)/(dbg_cnt0 ? dbg_cnt0 : 1) << endl;
}
void dbg_print_mean() {
cout << "Total " << dbg_cnt0 << " Mean "
<< (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.
/// This will be either "Stockfish YYMMDD" (where YYMMDD is the date when the
/// program was compiled) or "Stockfish <version number>", depending on whether
/// the constant EngineVersion (defined in misc.h) is empty.
/// This will be either "Stockfish YYMMDD" (where YYMMDD is the date when
/// the program was compiled) or "Stockfish <version number>", depending
/// on whether the constant EngineVersion is empty.
const string engine_name() {
const string cpu64(CpuHas64BitPath ? " 64bit" : "");
const string months("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec");
const string cpu64(CpuIs64Bit ? " 64bit" : "");
if (!EngineVersion.empty())
return AppName+ " " + EngineVersion + cpu64;
return AppName + " " + EngineVersion + cpu64;
string date(__DATE__); // From compiler, format is "Sep 21 2008"
string months("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec");
stringstream s, date(__DATE__); // From compiler, format is "Sep 21 2008"
string month, day, year;
size_t mon = 1 + months.find(date.substr(0, 3)) / 4;
date >> month >> day >> year;
stringstream s;
string day = (date[4] == ' ' ? date.substr(5, 1) : date.substr(4, 2));
string name = AppName + " " + AppTag + " ";
s << name << date.substr(date.length() - 2) << setfill('0')
<< setw(2) << mon << setw(2) << day << cpu64;
s << setfill('0') << AppName + " " + AppTag + " "
<< year.substr(2, 2) << setw(2)
<< (1 + months.find(month) / 4) << setw(2)
<< day << cpu64;
return s.str();
}
/// get_system_time() returns the current system time, measured in
/// milliseconds.
/// Our brave developers! Required by UCI
const string engine_authors() {
return "Tord Romstad, Marco Costalba and Joona Kiiski";
}
/// Debug stuff. Helper functions used mainly for debugging purposes
static uint64_t dbg_hit_cnt0;
static uint64_t dbg_hit_cnt1;
static uint64_t dbg_mean_cnt0;
static uint64_t dbg_mean_cnt1;
void dbg_print_hit_rate() {
if (dbg_hit_cnt0)
cout << "Total " << dbg_hit_cnt0 << " Hit " << dbg_hit_cnt1
<< " hit rate (%) " << 100 * dbg_hit_cnt1 / dbg_hit_cnt0 << endl;
}
void dbg_print_mean() {
if (dbg_mean_cnt0)
cout << "Total " << dbg_mean_cnt0 << " Mean "
<< (float)dbg_mean_cnt1 / dbg_mean_cnt0 << endl;
}
void dbg_mean_of(int v) {
dbg_mean_cnt0++;
dbg_mean_cnt1 += v;
}
void dbg_hit_on(bool b) {
dbg_hit_cnt0++;
if (b)
dbg_hit_cnt1++;
}
void dbg_hit_on_c(bool c, bool b) { if (c) dbg_hit_on(b); }
void dbg_before() { dbg_hit_on(false); }
void dbg_after() { dbg_hit_on(true); dbg_hit_cnt0--; }
/// get_system_time() returns the current system time, measured in milliseconds
int get_system_time() {
#if defined(_MSC_VER)
struct _timeb t;
_ftime(&t);
return int(t.time*1000 + t.millitm);
struct _timeb t;
_ftime(&t);
return int(t.time * 1000 + t.millitm);
#else
struct timeval t;
gettimeofday(&t, NULL);
return t.tv_sec*1000 + t.tv_usec/1000;
struct timeval t;
gettimeofday(&t, NULL);
return t.tv_sec * 1000 + t.tv_usec / 1000;
#endif
}
/// cpu_count() tries to detect the number of CPU cores.
#if !defined(_MSC_VER)
# if defined(_SC_NPROCESSORS_ONLN)
int cpu_count() {
return Min(sysconf(_SC_NPROCESSORS_ONLN), 8);
}
# else
int cpu_count() {
return 1;
}
# endif
#else
/// cpu_count() tries to detect the number of CPU cores
int cpu_count() {
#if defined(_MSC_VER)
SYSTEM_INFO s;
GetSystemInfo(&s);
return Min(s.dwNumberOfProcessors, 8);
}
return Min(s.dwNumberOfProcessors, MAX_THREADS);
#else
# if defined(_SC_NPROCESSORS_ONLN)
return Min(sysconf(_SC_NPROCESSORS_ONLN), MAX_THREADS);
# elif defined(__hpux)
struct pst_dynamic psd;
if (pstat_getdynamic(&psd, sizeof(psd), (size_t)1, 0) == -1)
return 1;
return Min(psd.psd_proc_cnt, MAX_THREADS);
# else
return 1;
# endif
#endif
}
/*
From Beowulf, from Olithink
*/
/// Check for console input. Original code from Beowulf, Olithink and Greko
#ifndef _WIN32
/* Non-windows version */
int Bioskey()
{
fd_set readfds;
int input_available() {
fd_set readfds;
struct timeval timeout;
FD_ZERO(&readfds);
FD_SET(fileno(stdin), &readfds);
/* Set to timeout immediately */
timeout.tv_sec = 0;
timeout.tv_sec = 0; // Set to timeout immediately
timeout.tv_usec = 0;
select(16, &readfds, 0, 0, &timeout);
@@ -225,54 +192,79 @@ int Bioskey()
}
#else
/* Windows-version */
#include <windows.h>
#include <conio.h>
int Bioskey()
{
static int init = 0,
pipe;
static HANDLE inh;
DWORD dw;
/* If we're running under XBoard then we can't use _kbhit() as the input
* commands are sent to us directly over the internal pipe */
#if defined(FILE_CNT)
if (stdin->_cnt > 0)
return stdin->_cnt;
#endif
if (!init) {
init = 1;
inh = GetStdHandle(STD_INPUT_HANDLE);
pipe = !GetConsoleMode(inh, &dw);
if (!pipe) {
SetConsoleMode(inh, dw & ~(ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT));
FlushConsoleInputBuffer(inh);
}
}
if (pipe) {
if (!PeekNamedPipe(inh, NULL, 0, NULL, &dw, NULL))
return 1;
return dw;
} else {
// Count the number of unread input records, including keyboard,
// mouse, and window-resizing input records.
GetNumberOfConsoleInputEvents(inh, &dw);
if (dw <= 0)
return 0;
int input_available() {
// Read data from console without removing it from the buffer
INPUT_RECORD rec[256];
DWORD recCnt;
if (!PeekConsoleInput(inh, rec, Min(dw, 256), &recCnt))
return 0;
static HANDLE inh = NULL;
static bool usePipe = false;
INPUT_RECORD rec[256];
DWORD nchars, recCnt;
// Search for at least one keyboard event
for (DWORD i = 0; i < recCnt; i++)
if (rec[i].EventType == KEY_EVENT)
return 1;
if (!inh)
{
inh = GetStdHandle(STD_INPUT_HANDLE);
if (GetConsoleMode(inh, &nchars))
{
SetConsoleMode(inh, nchars & ~(ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT));
FlushConsoleInputBuffer(inh);
} else
usePipe = true;
}
return 0;
}
// When using Standard C input functions, also check if there
// is anything in the buffer. After a call to such functions,
// the input waiting in the pipe will be copied to the buffer,
// and the call to PeekNamedPipe can indicate no input available.
// Setting stdin to unbuffered was not enough. [from Greko]
if (stdin->_cnt > 0)
return 1;
// When running under a GUI the input commands are sent to us
// directly over the internal pipe. If PeekNamedPipe() returns 0
// then something went wrong. Probably the parent program exited.
// Returning 1 will make the next call to the input function
// return EOF, where this should be catched then.
if (usePipe)
return PeekNamedPipe(inh, NULL, 0, NULL, &nchars, NULL) ? nchars : 1;
// Count the number of unread input records, including keyboard,
// mouse, and window-resizing input records.
GetNumberOfConsoleInputEvents(inh, &nchars);
// Read data from console without removing it from the buffer
if (nchars <= 0 || !PeekConsoleInput(inh, rec, Min(nchars, 256), &recCnt))
return 0;
// Search for at least one keyboard event
for (DWORD i = 0; i < recCnt; i++)
if (rec[i].EventType == KEY_EVENT)
return 1;
return 0;
}
#endif
/// prefetch() preloads the given address in L1/L2 cache. This is a non
/// blocking function and do not stalls the CPU waiting for data to be
/// loaded from memory, that can be quite slow.
#if defined(NO_PREFETCH)
void prefetch(char*) {}
#else
void prefetch(char* addr) {
#if defined(__INTEL_COMPILER) || defined(__ICL)
// This hack prevents prefetches to be optimized away by
// Intel compiler. Both MSVC and gcc seems not affected.
__asm__ ("");
#endif
_mm_prefetch(addr, _MM_HINT_T2);
_mm_prefetch(addr+64, _MM_HINT_T2); // 64 bytes ahead
}
#endif
+4 -43
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,55 +17,18 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined(MISC_H_INCLUDED)
#define MISC_H_INCLUDED
////
//// Includes
////
#include <fstream>
#include <string>
#include "application.h"
#include "types.h"
////
//// Macros
////
#define Min(x, y) (((x) < (y))? (x) : (y))
#define Max(x, y) (((x) < (y))? (y) : (x))
////
//// Variables
////
extern bool Chess960;
////
//// Prototypes
////
extern const std::string engine_name();
extern const std::string engine_authors();
extern int get_system_time();
extern int cpu_count();
extern int Bioskey();
////
//// Debug
////
extern bool dbg_show_mean;
extern bool dbg_show_hit_rate;
extern uint64_t dbg_cnt0;
extern uint64_t dbg_cnt1;
extern int input_available();
extern void prefetch(char* addr);
extern void dbg_hit_on(bool b);
extern void dbg_hit_on_c(bool c, bool b);
@@ -74,7 +37,5 @@ 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)
+210 -104
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,136 +17,242 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
////
//// Includes
////
#include <cassert>
#include <cstring>
#include <iomanip>
#include <string>
#include <sstream>
#include "move.h"
#include "piece.h"
#include "position.h"
#include "movegen.h"
#include "search.h"
using std::string;
////
//// Functions
////
/// move_from_string() takes a position and a string as input, and attempts to
/// convert the string to a move, using simple coordinate notation (g1f3,
/// a7a8q, etc.). In order to correctly parse en passant captures and castling
/// moves, we need the position. This function is not robust, and expects that
/// the input move is legal and correctly formatted.
Move move_from_string(const Position& pos, const std::string& str) {
Square from, to;
Piece piece;
Color us = pos.side_to_move();
if (str.length() < 4)
return MOVE_NONE;
// Read the from and to squares
from = square_from_string(str.substr(0, 2));
to = square_from_string(str.substr(2, 4));
// Find the moving piece
piece = pos.piece_on(from);
// If the string has more than 4 characters, try to interpret the 5th
// character as a promotion
if (type_of_piece(piece) == PAWN && str.length() > 4)
{
switch (tolower(str[4])) {
case 'n':
return make_promotion_move(from, to, KNIGHT);
case 'b':
return make_promotion_move(from, to, BISHOP);
case 'r':
return make_promotion_move(from, to, ROOK);
case 'q':
return make_promotion_move(from, to, QUEEN);
}
}
if (piece == piece_of_color_and_type(us, KING))
{
// 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
// if the distance between the source and destination squares is more
// than 1.
if (pos.piece_on(to) == piece_of_color_and_type(us, ROOK))
return make_castle_move(from, to);
else if (square_distance(from, to) > 1)
{
// This is a castling move, but we have to translate it to the
// internal "king captures rook" representation.
SquareDelta delta = (to > from ? DELTA_E : DELTA_W);
Square s = from + delta;
while (relative_rank(us, s) == RANK_1 && pos.piece_on(s) != piece_of_color_and_type(us, ROOK))
s += delta;
return (relative_rank(us, s) == RANK_1 ? make_castle_move(from, s) : MOVE_NONE);
}
}
else if (piece == piece_of_color_and_type(us, PAWN))
{
// En passant move? We assume that a pawn move is an en passant move
// without further testing if the destination square is epSquare.
if (to == pos.ep_square())
return make_ep_move(from, to);
}
return make_move(from, to);
namespace {
const string time_string(int milliseconds);
const string score_string(Value v);
}
/// move_to_string() converts a move to a string in coordinate notation
/// (g1f3, a7a8q, etc.). The only special case is castling moves, where we
/// move_to_uci() converts a move to a string in coordinate notation
/// (g1f3, a7a8q, etc.). The only special case is castling moves, where we
/// print in the e1g1 notation in normal chess mode, and in e1h1 notation in
/// Chess960 mode.
const std::string move_to_string(Move move) {
const string move_to_uci(Move m, bool chess960) {
std::string str;
Square from = move_from(move);
Square to = move_to(move);
Square from = move_from(m);
Square to = move_to(m);
string promotion;
if (move == MOVE_NONE)
str = "(none)";
else if (move == MOVE_NULL)
str = "0000";
if (m == MOVE_NONE)
return "(none)";
if (m == MOVE_NULL)
return "0000";
if (move_is_short_castle(m) && !chess960)
return from == SQ_E1 ? "e1g1" : "e8g8";
if (move_is_long_castle(m) && !chess960)
return from == SQ_E1 ? "e1c1" : "e8c8";
if (move_is_promotion(m))
promotion = char(tolower(piece_type_to_char(move_promotion_piece(m))));
return square_to_string(from) + square_to_string(to) + promotion;
}
/// move_from_uci() takes a position and a string representing a move in
/// simple coordinate notation and returns an equivalent Move if any.
/// Moves are guaranteed to be legal.
Move move_from_uci(const Position& pos, const string& str) {
MoveStack mlist[MAX_MOVES];
MoveStack* last = generate<MV_LEGAL>(pos, mlist);
for (MoveStack* cur = mlist; cur != last; cur++)
if (str == move_to_uci(cur->move, pos.is_chess960()))
return cur->move;
return MOVE_NONE;
}
/// 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
/// a string containing the move in short algebraic notation.
const string move_to_san(Position& pos, Move m) {
assert(pos.is_ok());
assert(move_is_ok(m));
MoveStack mlist[MAX_MOVES];
Square from = move_from(m);
Square to = move_to(m);
PieceType pt = pos.type_of_piece_on(from);
string san;
if (m == MOVE_NONE)
return "(none)";
if (m == MOVE_NULL)
return "(null)";
if (move_is_long_castle(m))
san = "O-O-O";
else if (move_is_short_castle(m))
san = "O-O";
else
{
if (!Chess960)
if (pt != PAWN)
{
if (move_is_short_castle(move))
return (from == SQ_E1 ? "e1g1" : "e8g8");
san = piece_type_to_char(pt);
if (move_is_long_castle(move))
return (from == SQ_E1 ? "e1c1" : "e8c8");
// Collect all legal moves of piece type 'pt' with destination 'to'
MoveStack* last = generate<MV_LEGAL>(pos, mlist);
int f = 0, r = 0;
for (MoveStack* cur = mlist; cur != last; cur++)
if ( move_to(cur->move) == to
&& pos.type_of_piece_on(move_from(cur->move)) == pt)
{
if (square_file(move_from(cur->move)) == square_file(from))
f++;
if (square_rank(move_from(cur->move)) == square_rank(from))
r++;
}
assert(f > 0 && r > 0);
// Disambiguation if we have more then one piece with destination 'to'
if (f == 1 && r > 1)
san += file_to_char(square_file(from));
else if (f > 1 && r == 1)
san += rank_to_char(square_rank(from));
else if (f > 1 && r > 1)
san += square_to_string(from);
}
if (pos.move_is_capture(m))
{
if (pt == PAWN)
san += file_to_char(square_file(from));
san += 'x';
}
san += square_to_string(to);
if (move_is_promotion(m))
{
san += '=';
san += piece_type_to_char(move_promotion_piece(m));
}
str = square_to_string(from) + square_to_string(to);
if (move_is_promotion(move))
str += piece_type_to_char(move_promotion_piece(move), false);
}
return str;
// The move gives check? We don't use pos.move_gives_check() here
// because we need to test for a mate after the move is done.
StateInfo st;
pos.do_move(m, st);
if (pos.in_check())
san += pos.is_mate() ? "#" : "+";
pos.undo_move(m);
return san;
}
/// Overload the << operator, to make it easier to print moves.
/// pretty_pv() creates a human-readable string from a position and a PV.
/// It is used to write search information to the log file (which is created
/// when the UCI parameter "Use Search Log" is "true").
std::ostream &operator << (std::ostream& os, Move m) {
const string pretty_pv(Position& pos, int depth, Value score, int time, Move pv[]) {
return os << move_to_string(m);
const int64_t K = 1000;
const int64_t M = 1000000;
const int startColumn = 28;
const size_t maxLength = 80 - startColumn;
const string lf = string("\n") + string(startColumn, ' ');
StateInfo state[PLY_MAX_PLUS_2], *st = state;
Move* m = pv;
string san;
std::stringstream s;
size_t length = 0;
// First print depth, score, time and searched nodes...
s << std::setw(2) << depth
<< std::setw(8) << score_string(score)
<< std::setw(8) << time_string(time);
if (pos.nodes_searched() < M)
s << std::setw(8) << pos.nodes_searched() / 1 << " ";
else if (pos.nodes_searched() < K * M)
s << std::setw(7) << pos.nodes_searched() / K << "K ";
else
s << std::setw(7) << pos.nodes_searched() / M << "M ";
// ...then print the full PV line in short algebraic notation
while (*m != MOVE_NONE)
{
san = move_to_san(pos, *m);
length += san.length() + 1;
if (length > maxLength)
{
length = san.length() + 1;
s << lf;
}
s << san << ' ';
pos.do_move(*m++, *st++);
}
// Restore original position before to leave
while (m != pv) pos.undo_move(*--m);
return s.str();
}
/// move_is_ok(), for debugging.
namespace {
bool move_is_ok(Move m) {
const string time_string(int millisecs) {
return square_is_ok(move_from(m)) && square_is_ok(move_to(m));
const int MSecMinute = 1000 * 60;
const int MSecHour = 1000 * 60 * 60;
int hours = millisecs / MSecHour;
int minutes = (millisecs % MSecHour) / MSecMinute;
int seconds = ((millisecs % MSecHour) % MSecMinute) / 1000;
std::stringstream s;
if (hours)
s << hours << ':';
s << std::setfill('0') << std::setw(2) << minutes << ':' << std::setw(2) << seconds;
return s.str();
}
const string score_string(Value v) {
std::stringstream s;
if (v >= VALUE_MATE - 200)
s << "#" << (VALUE_MATE - v + 1) / 2;
else if (v <= -VALUE_MATE + 200)
s << "-#" << (VALUE_MATE + v) / 2;
else
s << std::setprecision(2) << std::fixed << std::showpos << float(v) / PawnValueMidgame;
return s.str();
}
}
+46 -81
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,34 +17,23 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined(MOVE_H_INCLUDED)
#define MOVE_H_INCLUDED
////
//// Includes
////
#include <iostream>
#include <string>
#include "misc.h"
#include "piece.h"
#include "square.h"
#include "types.h"
// Maximum number of allowed moves per position
const int MAX_MOVES = 256;
////
//// Types
////
class Position;
/// A move needs 17 bits to be stored
/// A move needs 16 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
/// bit 12-13: promotion piece type - 2 (from KNIGHT-2 to QUEEN-2)
/// bit 14-15: special move flag: promotion (1), en passant (2), castle (3)
///
/// Special cases are MOVE_NONE and MOVE_NULL. We can sneak these in
/// because in any normal move destination square is always different
@@ -62,34 +51,33 @@ struct MoveStack {
int score;
};
// Note that operator< is set up such that sorting will be in descending order
inline bool operator<(const MoveStack& f, const MoveStack& s) { return s.score < f.score; }
inline bool operator<(const MoveStack& f, const MoveStack& s) { return f.score < s.score; }
// An helper insertion sort implementation
template<typename T>
inline void insertion_sort(T* firstMove, T* lastMove)
// An helper insertion sort implementation, works with pointers and iterators
template<typename T, typename K>
inline void insertion_sort(K firstMove, K lastMove)
{
T value;
T *cur, *p, *d;
K cur, p, d;
if (firstMove != lastMove)
for (cur = firstMove + 1; cur != lastMove; cur++)
{
p = d = cur;
value = *p--;
if (value < *p)
if (*p < value)
{
do *d = *p;
while (--d != firstMove && value < *--p);
while (--d != firstMove && *--p < value);
*d = value;
}
}
}
// Our dedicated sort in range [firstMove, lastMove), it is well
// tuned for non-captures where we have a lot of zero scored moves.
// Our dedicated sort in range [firstMove, lastMove), first splits
// positive scores from ramining then order seaprately the two sets.
template<typename T>
inline void sort_moves(T* firstMove, T* lastMove)
inline void sort_moves(T* firstMove, T* lastMove, T** lastPositive)
{
T tmp;
T *p, *d;
@@ -101,11 +89,11 @@ inline void sort_moves(T* firstMove, T* lastMove)
// Split positives vs non-positives
do {
while ((++p)->score > 0);
while ((++p)->score > 0) {}
if (p != d)
{
while (--d != p && d->score <= 0);
while (--d != p && d->score <= 0) {}
tmp = *p;
*p = *d;
@@ -114,29 +102,9 @@ inline void sort_moves(T* firstMove, T* lastMove)
} while (p != d);
// Sort positives
insertion_sort<T>(firstMove, p);
d = lastMove;
p--;
// Split zero vs negatives
do {
while ((++p)->score == 0);
if (p != d)
{
while (--d != p && d->score < 0);
tmp = *p;
*p = *d;
*d = tmp;
}
} while (p != d);
// Sort negatives
insertion_sort<T>(p, lastMove);
// Sort just positive scored moves, remaining only when we get there
insertion_sort<T, T*>(firstMove, p);
*lastPositive = p;
}
// Picks up the best move in range [curMove, lastMove), one per cycle.
@@ -150,7 +118,7 @@ inline T pick_best(T* curMove, T* lastMove)
bestMove = *curMove;
while (++curMove != lastMove)
{
if (*curMove < bestMove)
if (bestMove < *curMove)
{
tmp = *curMove;
*curMove = bestMove;
@@ -160,9 +128,6 @@ inline T pick_best(T* curMove, T* lastMove)
return bestMove;
}
////
//// Inline functions
////
inline Square move_from(Move m) {
return Square((int(m) >> 6) & 0x3F);
@@ -172,24 +137,20 @@ inline Square move_to(Move m) {
return Square(m & 0x3F);
}
inline PieceType move_promotion_piece(Move m) {
return PieceType((int(m) >> 12) & 7);
inline bool move_is_special(Move m) {
return m & (3 << 14);
}
inline int move_is_special(Move m) {
return m & (0x1F << 12);
}
inline int move_is_promotion(Move m) {
return m & (7 << 12);
inline bool move_is_promotion(Move m) {
return (m & (3 << 14)) == (1 << 14);
}
inline int move_is_ep(Move m) {
return m & (1 << 15);
return (m & (3 << 14)) == (2 << 14);
}
inline int move_is_castle(Move m) {
return m & (1 << 16);
return (m & (3 << 14)) == (3 << 14);
}
inline bool move_is_short_castle(Move m) {
@@ -200,31 +161,35 @@ inline bool move_is_long_castle(Move m) {
return move_is_castle(m) && (move_to(m) < move_from(m));
}
inline Move make_promotion_move(Square from, Square to, PieceType promotion) {
return Move(int(to) | (int(from) << 6) | (int(promotion) << 12));
inline PieceType move_promotion_piece(Move m) {
return move_is_promotion(m) ? PieceType(((int(m) >> 12) & 3) + 2) : PIECE_TYPE_NONE;
}
inline Move make_move(Square from, Square to) {
return Move(int(to) | (int(from) << 6));
}
inline Move make_castle_move(Square from, Square to) {
return Move(int(to) | (int(from) << 6) | (1 << 16));
inline Move make_promotion_move(Square from, Square to, PieceType promotion) {
return Move(int(to) | (int(from) << 6) | ((int(promotion) - 2) << 12) | (1 << 14));
}
inline Move make_ep_move(Square from, Square to) {
return Move(int(to) | (int(from) << 6) | (1 << 15));
return Move(int(to) | (int(from) << 6) | (2 << 14));
}
inline Move make_castle_move(Square from, Square to) {
return Move(int(to) | (int(from) << 6) | (3 << 14));
}
////
//// Prototypes
////
inline bool move_is_ok(Move m) {
return move_from(m) != move_to(m); // Catches also MOVE_NONE
}
extern std::ostream& operator<<(std::ostream &os, Move m);
extern Move move_from_string(const Position &pos, const std::string &str);
extern const std::string move_to_string(Move m);
extern bool move_is_ok(Move m);
class Position;
extern const std::string move_to_uci(Move m, bool chess960);
extern Move move_from_uci(const Position& pos, const std::string& str);
extern const std::string move_to_san(Position& pos, Move m);
extern const std::string pretty_pv(Position& pos, int depth, Value score, int time, Move pv[]);
#endif // !defined(MOVE_H_INCLUDED)
+271 -422
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,11 +17,6 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
////
//// Includes
////
#include <cassert>
#include "bitcount.h"
@@ -34,10 +29,6 @@
// Version used for pawns, where the 'from' square is given as a delta from the 'to' square
#define SERIALIZE_MOVES_D(b, d) while (b) { to = pop_1st_bit(&b); (*mlist++).move = make_move(to + (d), to); }
////
//// Local definitions
////
namespace {
enum CastlingSide {
@@ -45,115 +36,180 @@ namespace {
QUEEN_SIDE
};
enum MoveType {
CAPTURE,
NON_CAPTURE,
CHECK,
EVASION
};
template<CastlingSide>
MoveStack* generate_castle_moves(const Position&, MoveStack*, Color us);
// Helper templates
template<CastlingSide Side>
MoveStack* generate_castle_moves(const Position&, MoveStack*);
template<Color Us, MoveType Type>
template<Color, MoveType>
MoveStack* generate_pawn_moves(const Position&, MoveStack*, Bitboard, Square);
// Template generate_piece_moves (captures and non-captures) with specializations and overloads
template<PieceType>
MoveStack* generate_piece_moves(const Position&, MoveStack*, Color, Bitboard);
template<PieceType Pt>
inline MoveStack* generate_discovered_checks(const Position& pos, MoveStack* mlist, Square from) {
assert(Pt != QUEEN);
Bitboard b = pos.attacks_from<Pt>(from) & pos.empty_squares();
if (Pt == KING)
{
Square ksq = pos.king_square(opposite_color(pos.side_to_move()));
b &= ~QueenPseudoAttacks[ksq];
}
SERIALIZE_MOVES(b);
return mlist;
}
template<PieceType Pt>
inline MoveStack* generate_direct_checks(const Position& pos, MoveStack* mlist, Color us,
Bitboard dc, Square ksq) {
assert(Pt != KING);
Bitboard checkSqs, b;
Square from;
const Square* ptr = pos.piece_list_begin(us, Pt);
if ((from = *ptr++) == SQ_NONE)
return mlist;
checkSqs = pos.attacks_from<Pt>(ksq) & pos.empty_squares();
do
{
if ( (Pt == QUEEN && !(QueenPseudoAttacks[from] & checkSqs))
|| (Pt == ROOK && !(RookPseudoAttacks[from] & checkSqs))
|| (Pt == BISHOP && !(BishopPseudoAttacks[from] & checkSqs)))
continue;
if (dc && bit_is_set(dc, from))
continue;
b = pos.attacks_from<Pt>(from) & checkSqs;
SERIALIZE_MOVES(b);
} while ((from = *ptr++) != SQ_NONE);
return mlist;
}
template<>
MoveStack* generate_piece_moves<KING>(const Position&, MoveStack*, Color, Bitboard);
FORCE_INLINE MoveStack* generate_direct_checks<PAWN>(const Position& p, MoveStack* m, Color us, Bitboard dc, Square ksq) {
template<PieceType Piece, MoveType Type>
inline MoveStack* generate_piece_moves(const Position& p, MoveStack* m, Color us, Bitboard t) {
return (us == WHITE ? generate_pawn_moves<WHITE, MV_CHECK>(p, m, dc, ksq)
: generate_pawn_moves<BLACK, MV_CHECK>(p, m, dc, ksq));
}
assert(Piece == PAWN);
assert(Type == CAPTURE || Type == NON_CAPTURE || Type == EVASION);
template<PieceType Pt, MoveType Type>
FORCE_INLINE MoveStack* generate_piece_moves(const Position& p, MoveStack* m, Color us, Bitboard t) {
assert(Pt == PAWN);
assert(Type == MV_CAPTURE || Type == MV_NON_CAPTURE || Type == MV_EVASION);
return (us == WHITE ? generate_pawn_moves<WHITE, Type>(p, m, t, SQ_NONE)
: generate_pawn_moves<BLACK, Type>(p, m, t, SQ_NONE));
}
// Templates for non-capture checks generation
template<PieceType Pt>
FORCE_INLINE MoveStack* generate_piece_moves(const Position& pos, MoveStack* mlist, Color us, Bitboard target) {
template<PieceType Piece>
MoveStack* generate_discovered_checks(const Position&, MoveStack*, Square);
Bitboard b;
Square from;
const Square* ptr = pos.piece_list_begin(us, Pt);
template<PieceType>
MoveStack* generate_direct_checks(const Position&, MoveStack*, Color, Bitboard, Square);
if (*ptr != SQ_NONE)
{
do {
from = *ptr;
b = pos.attacks_from<Pt>(from) & target;
SERIALIZE_MOVES(b);
} while (*++ptr != SQ_NONE);
}
return mlist;
}
template<>
inline MoveStack* generate_direct_checks<PAWN>(const Position& p, MoveStack* m, Color us, Bitboard dc, Square ksq) {
FORCE_INLINE MoveStack* generate_piece_moves<KING>(const Position& pos, MoveStack* mlist, Color us, Bitboard target) {
return (us == WHITE ? generate_pawn_moves<WHITE, CHECK>(p, m, dc, ksq)
: generate_pawn_moves<BLACK, CHECK>(p, m, dc, ksq));
Bitboard b;
Square from = pos.king_square(us);
b = pos.attacks_from<KING>(from) & target;
SERIALIZE_MOVES(b);
return mlist;
}
}
////
//// Functions
////
/// generate_captures() generates all pseudo-legal captures and queen
/// generate<MV_CAPTURE> generates all pseudo-legal captures and queen
/// promotions. Returns a pointer to the end of the move list.
MoveStack* generate_captures(const Position& pos, MoveStack* mlist) {
assert(pos.is_ok());
assert(!pos.is_check());
Color us = pos.side_to_move();
Bitboard target = pos.pieces_of_color(opposite_color(us));
mlist = generate_piece_moves<QUEEN>(pos, mlist, us, target);
mlist = generate_piece_moves<ROOK>(pos, mlist, us, target);
mlist = generate_piece_moves<BISHOP>(pos, mlist, us, target);
mlist = generate_piece_moves<KNIGHT>(pos, mlist, us, target);
mlist = generate_piece_moves<PAWN, CAPTURE>(pos, mlist, us, target);
return generate_piece_moves<KING>(pos, mlist, us, target);
}
/// generate_noncaptures() generates all pseudo-legal non-captures and
///
/// generate<MV_NON_CAPTURE> generates all pseudo-legal non-captures and
/// underpromotions. Returns a pointer to the end of the move list.
///
/// generate<MV_NON_EVASION> generates all pseudo-legal captures and
/// non-captures. Returns a pointer to the end of the move list.
MoveStack* generate_noncaptures(const Position& pos, MoveStack* mlist) {
template<MoveType Type>
MoveStack* generate(const Position& pos, MoveStack* mlist) {
assert(pos.is_ok());
assert(!pos.is_check());
assert(!pos.in_check());
Color us = pos.side_to_move();
Bitboard target = pos.empty_squares();
Bitboard target;
if (Type == MV_CAPTURE || Type == MV_NON_EVASION)
target = pos.pieces_of_color(opposite_color(us));
else if (Type == MV_NON_CAPTURE)
target = pos.empty_squares();
else
assert(false);
if (Type == MV_NON_EVASION)
{
mlist = generate_piece_moves<PAWN, MV_CAPTURE>(pos, mlist, us, target);
mlist = generate_piece_moves<PAWN, MV_NON_CAPTURE>(pos, mlist, us, pos.empty_squares());
target |= pos.empty_squares();
}
else
mlist = generate_piece_moves<PAWN, Type>(pos, mlist, us, target);
mlist = generate_piece_moves<PAWN, NON_CAPTURE>(pos, mlist, us, target);
mlist = generate_piece_moves<KNIGHT>(pos, mlist, us, target);
mlist = generate_piece_moves<BISHOP>(pos, mlist, us, target);
mlist = generate_piece_moves<ROOK>(pos, mlist, us, target);
mlist = generate_piece_moves<QUEEN>(pos, mlist, us, target);
mlist = generate_piece_moves<KING>(pos, mlist, us, target);
mlist = generate_castle_moves<KING_SIDE>(pos, mlist);
return generate_castle_moves<QUEEN_SIDE>(pos, mlist);
if (Type != MV_CAPTURE)
{
if (pos.can_castle_kingside(us))
mlist = generate_castle_moves<KING_SIDE>(pos, mlist, us);
if (pos.can_castle_queenside(us))
mlist = generate_castle_moves<QUEEN_SIDE>(pos, mlist, us);
}
return mlist;
}
// Explicit template instantiations
template MoveStack* generate<MV_CAPTURE>(const Position& pos, MoveStack* mlist);
template MoveStack* generate<MV_NON_CAPTURE>(const Position& pos, MoveStack* mlist);
template MoveStack* generate<MV_NON_EVASION>(const Position& pos, MoveStack* mlist);
/// generate_non_capture_checks() generates all pseudo-legal non-captures and knight
/// underpromotions that give check. Returns a pointer to the end of the move list.
MoveStack* generate_non_capture_checks(const Position& pos, MoveStack* mlist) {
template<>
MoveStack* generate<MV_NON_CAPTURE_CHECK>(const Position& pos, MoveStack* mlist) {
assert(pos.is_ok());
assert(!pos.is_check());
assert(!pos.in_check());
Bitboard b, dc;
Square from;
Color us = pos.side_to_move();
Square ksq = pos.king_square(opposite_color(us));
assert(pos.piece_on(ksq) == piece_of_color_and_type(opposite_color(us), KING));
assert(pos.piece_on(ksq) == make_piece(opposite_color(us), KING));
// Discovered non-capture checks
b = dc = pos.discovered_check_candidates(us);
@@ -183,11 +239,11 @@ MoveStack* generate_non_capture_checks(const Position& pos, MoveStack* mlist) {
/// generate_evasions() generates all pseudo-legal check evasions when
/// the side to move is in check. Returns a pointer to the end of the move list.
MoveStack* generate_evasions(const Position& pos, MoveStack* mlist) {
template<>
MoveStack* generate<MV_EVASION>(const Position& pos, MoveStack* mlist) {
assert(pos.is_ok());
assert(pos.is_check());
assert(pos.in_check());
Bitboard b, target;
Square from, checksq;
@@ -197,7 +253,7 @@ MoveStack* generate_evasions(const Position& pos, MoveStack* mlist) {
Bitboard checkers = pos.checkers();
Bitboard sliderAttacks = EmptyBoardBB;
assert(pos.piece_on(ksq) == piece_of_color_and_type(us, KING));
assert(pos.piece_on(ksq) == make_piece(us, KING));
assert(checkers);
// Find squares attacked by slider checkers, we will remove
@@ -218,7 +274,7 @@ MoveStack* generate_evasions(const Position& pos, MoveStack* mlist) {
case QUEEN:
// In case of a queen remove also squares attacked in the other direction to
// avoid possible illegal moves when queen and king are on adjacent squares.
if (direction_is_straight(checksq, ksq))
if (RookPseudoAttacks[checksq] & (1ULL << ksq))
sliderAttacks |= RookPseudoAttacks[checksq] | pos.attacks_from<BISHOP>(checksq);
else
sliderAttacks |= BishopPseudoAttacks[checksq] | pos.attacks_from<ROOK>(checksq);
@@ -240,7 +296,7 @@ MoveStack* generate_evasions(const Position& pos, MoveStack* mlist) {
// checker piece is possible.
target = squares_between(checksq, ksq) | checkers;
mlist = generate_piece_moves<PAWN, EVASION>(pos, mlist, us, target);
mlist = generate_piece_moves<PAWN, MV_EVASION>(pos, mlist, us, target);
mlist = generate_piece_moves<KNIGHT>(pos, mlist, us, target);
mlist = generate_piece_moves<BISHOP>(pos, mlist, us, target);
mlist = generate_piece_moves<ROOK>(pos, mlist, us, target);
@@ -248,325 +304,169 @@ MoveStack* generate_evasions(const Position& pos, MoveStack* mlist) {
}
/// generate_moves() computes a complete list of legal or pseudo-legal moves in
/// the current position. This function is not very fast, and should be used
/// only in non time-critical paths.
/// generate<MV_LEGAL / MV_PSEUDO_LEGAL> computes a complete list of legal
/// or pseudo-legal moves in the current position.
template<>
MoveStack* generate<MV_PSEUDO_LEGAL>(const Position& pos, MoveStack* mlist) {
MoveStack* generate_moves(const Position& pos, MoveStack* mlist, bool pseudoLegal) {
assert(pos.is_ok());
return pos.in_check() ? generate<MV_EVASION>(pos, mlist)
: generate<MV_NON_EVASION>(pos, mlist);
}
template<>
MoveStack* generate<MV_LEGAL>(const Position& pos, MoveStack* mlist) {
assert(pos.is_ok());
MoveStack *last, *cur = mlist;
Bitboard pinned = pos.pinned_pieces(pos.side_to_move());
// Generate pseudo-legal moves
if (pos.is_check())
last = generate_evasions(pos, mlist);
else
last = generate_noncaptures(pos, generate_captures(pos, mlist));
if (pseudoLegal)
return last;
last = generate<MV_PSEUDO_LEGAL>(pos, mlist);
// Remove illegal moves from the list
while (cur != last)
if (pos.pl_move_is_legal(cur->move, pinned))
cur++;
else
if (!pos.pl_move_is_legal(cur->move, pinned))
cur->move = (--last)->move;
else
cur++;
return last;
}
/// move_is_legal() takes a position and a (not necessarily pseudo-legal)
/// move and tests whether the move is legal. This version is not very fast
/// and should be used only in non time-critical paths.
bool move_is_legal(const Position& pos, const Move m) {
MoveStack mlist[256];
MoveStack *cur, *last = generate_moves(pos, mlist, true);
for (cur = mlist; cur != last; cur++)
if (cur->move == m)
return pos.pl_move_is_legal(m, pos.pinned_pieces(pos.side_to_move()));
return false;
}
/// Fast version of move_is_legal() that takes a position a move and a
/// bitboard of pinned pieces as input, and tests whether the move is legal.
bool move_is_legal(const Position& pos, const Move m, Bitboard pinned) {
assert(pos.is_ok());
assert(move_is_ok(m));
assert(pinned == pos.pinned_pieces(pos.side_to_move()));
Color us = pos.side_to_move();
Color them = opposite_color(us);
Square from = move_from(m);
Square to = move_to(m);
Piece pc = pos.piece_on(from);
// Use a slower but simpler function for uncommon cases
if (move_is_ep(m) || move_is_castle(m))
return move_is_legal(pos, m);
// If the from square is not occupied by a piece belonging to the side to
// move, the move is obviously not legal.
if (color_of_piece(pc) != us)
return false;
// The destination square cannot be occupied by a friendly piece
if (pos.color_of_piece_on(to) == us)
return false;
// Handle the special case of a pawn move
if (type_of_piece(pc) == PAWN)
{
// Move direction must be compatible with pawn color
int direction = to - from;
if ((us == WHITE) != (direction > 0))
return false;
// A pawn move is a promotion iff the destination square is
// on the 8/1th rank.
if (( (square_rank(to) == RANK_8 && us == WHITE)
||(square_rank(to) == RANK_1 && us != WHITE)) != bool(move_is_promotion(m)))
return false;
// Proceed according to the square delta between the origin and
// destination squares.
switch (direction)
{
case DELTA_NW:
case DELTA_NE:
case DELTA_SW:
case DELTA_SE:
// Capture. The destination square must be occupied by an enemy
// piece (en passant captures was handled earlier).
if (pos.color_of_piece_on(to) != them)
return false;
break;
case DELTA_N:
case DELTA_S:
// Pawn push. The destination square must be empty.
if (!pos.square_is_empty(to))
return false;
break;
case DELTA_NN:
// Double white pawn push. The destination square must be on the fourth
// rank, and both the destination square and the square between the
// source and destination squares must be empty.
if ( square_rank(to) != RANK_4
|| !pos.square_is_empty(to)
|| !pos.square_is_empty(from + DELTA_N))
return false;
break;
case DELTA_SS:
// Double black pawn push. The destination square must be on the fifth
// rank, and both the destination square and the square between the
// source and destination squares must be empty.
if ( square_rank(to) != RANK_5
|| !pos.square_is_empty(to)
|| !pos.square_is_empty(from + DELTA_S))
return false;
break;
default:
return false;
}
// The move is pseudo-legal, check if it is also legal
return pos.is_check() ? pos.pl_move_is_evasion(m, pinned) : pos.pl_move_is_legal(m, pinned);
}
// Luckly we can handle all the other pieces in one go
return bit_is_set(pos.attacks_from(pc, from), to)
&& (pos.is_check() ? pos.pl_move_is_evasion(m, pinned) : pos.pl_move_is_legal(m, pinned))
&& !move_is_promotion(m);
}
namespace {
template<PieceType Piece>
MoveStack* generate_piece_moves(const Position& pos, MoveStack* mlist, Color us, Bitboard target) {
Bitboard b;
Square from;
const Square* ptr = pos.piece_list_begin(us, Piece);
while ((from = *ptr++) != SQ_NONE)
{
b = pos.attacks_from<Piece>(from) & target;
SERIALIZE_MOVES(b);
}
return mlist;
}
template<>
MoveStack* generate_piece_moves<KING>(const Position& pos, MoveStack* mlist, Color us, Bitboard target) {
Bitboard b;
Square from = pos.king_square(us);
b = pos.attacks_from<KING>(from) & target;
SERIALIZE_MOVES(b);
return mlist;
}
template<Color Us, SquareDelta Direction>
template<Square Delta>
inline Bitboard move_pawns(Bitboard p) {
if (Direction == DELTA_N)
return Us == WHITE ? p << 8 : p >> 8;
else if (Direction == DELTA_NE)
return Us == WHITE ? p << 9 : p >> 7;
else if (Direction == DELTA_NW)
return Us == WHITE ? p << 7 : p >> 9;
else
return p;
return Delta == DELTA_N ? p << 8 : Delta == DELTA_S ? p >> 8 :
Delta == DELTA_NE ? p << 9 : Delta == DELTA_SE ? p >> 7 :
Delta == DELTA_NW ? p << 7 : Delta == DELTA_SW ? p >> 9 : p;
}
template<Color Us, MoveType Type, SquareDelta Diagonal>
inline MoveStack* generate_pawn_captures(MoveStack* mlist, Bitboard pawns, Bitboard enemyPieces) {
template<MoveType Type, Square Delta>
inline MoveStack* generate_pawn_captures(MoveStack* mlist, Bitboard pawns, Bitboard target) {
// Calculate our parametrized parameters at compile time
const Bitboard TRank8BB = (Us == WHITE ? Rank8BB : Rank1BB);
const Bitboard TFileABB = (Diagonal == DELTA_NE ? FileABB : FileHBB);
const SquareDelta TDELTA_NE = (Us == WHITE ? DELTA_NE : DELTA_SE);
const SquareDelta TDELTA_NW = (Us == WHITE ? DELTA_NW : DELTA_SW);
const SquareDelta TTDELTA_NE = (Diagonal == DELTA_NE ? TDELTA_NE : TDELTA_NW);
const Bitboard TFileABB = (Delta == DELTA_NE || Delta == DELTA_SE ? FileABB : FileHBB);
Bitboard b1, b2;
Bitboard b;
Square to;
// Captures in the a1-h8 (a8-h1 for black) diagonal or in the h1-a8 (h8-a1 for black)
b1 = move_pawns<Us, Diagonal>(pawns) & ~TFileABB & enemyPieces;
b = move_pawns<Delta>(pawns) & target & ~TFileABB;
SERIALIZE_MOVES_D(b, -Delta);
return mlist;
}
// Capturing promotions and under-promotions
if (b1 & TRank8BB)
template<Color Us, MoveType Type, Square Delta>
inline MoveStack* generate_promotions(const Position& pos, MoveStack* mlist, Bitboard pawnsOn7, Bitboard target) {
const Bitboard TFileABB = (Delta == DELTA_NE || Delta == DELTA_SE ? FileABB : FileHBB);
Bitboard b;
Square to;
// Promotions and under-promotions, both captures and non-captures
b = move_pawns<Delta>(pawnsOn7) & target;
if (Delta != DELTA_N && Delta != DELTA_S)
b &= ~TFileABB;
while (b)
{
b2 = b1 & TRank8BB;
b1 &= ~TRank8BB;
while (b2)
to = pop_1st_bit(&b);
if (Type == MV_CAPTURE || Type == MV_EVASION)
(*mlist++).move = make_promotion_move(to - Delta, to, QUEEN);
if (Type == MV_NON_CAPTURE || Type == MV_EVASION)
{
to = pop_1st_bit(&b2);
if (Type == CAPTURE || Type == EVASION)
(*mlist++).move = make_promotion_move(to - TTDELTA_NE, to, QUEEN);
if (Type == NON_CAPTURE || Type == EVASION)
{
(*mlist++).move = make_promotion_move(to - TTDELTA_NE, to, ROOK);
(*mlist++).move = make_promotion_move(to - TTDELTA_NE, to, BISHOP);
(*mlist++).move = make_promotion_move(to - TTDELTA_NE, to, KNIGHT);
}
// This is the only possible under promotion that can give a check
// not already included in the queen-promotion. It is not sure that
// the promoted knight will give check, but it doesn't worth to verify.
if (Type == CHECK)
(*mlist++).move = make_promotion_move(to - TTDELTA_NE, to, KNIGHT);
(*mlist++).move = make_promotion_move(to - Delta, to, ROOK);
(*mlist++).move = make_promotion_move(to - Delta, to, BISHOP);
(*mlist++).move = make_promotion_move(to - Delta, to, KNIGHT);
}
// This is the only possible under promotion that can give a check
// not already included in the queen-promotion.
if ( Type == MV_CHECK
&& bit_is_set(pos.attacks_from<KNIGHT>(to), pos.king_square(opposite_color(Us))))
(*mlist++).move = make_promotion_move(to - Delta, to, KNIGHT);
else (void)pos; // Silence a warning under MSVC
}
// Serialize standard captures
if (Type == CAPTURE || Type == EVASION)
SERIALIZE_MOVES_D(b1, -TTDELTA_NE);
return mlist;
}
template<Color Us, MoveType Type>
MoveStack* generate_pawn_moves(const Position& pos, MoveStack* mlist, Bitboard target, Square ksq) {
// Calculate our parametrized parameters at compile time
const Color Them = (Us == WHITE ? BLACK : WHITE);
const Bitboard TRank8BB = (Us == WHITE ? Rank8BB : Rank1BB);
const Bitboard TRank7BB = (Us == WHITE ? Rank7BB : Rank2BB);
const Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB);
const SquareDelta TDELTA_N = (Us == WHITE ? DELTA_N : DELTA_S);
// Calculate our parametrized parameters at compile time, named
// according to the point of view of white side.
const Color Them = (Us == WHITE ? BLACK : WHITE);
const Bitboard TRank7BB = (Us == WHITE ? Rank7BB : Rank2BB);
const Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB);
const Square TDELTA_N = (Us == WHITE ? DELTA_N : DELTA_S);
const Square TDELTA_NE = (Us == WHITE ? DELTA_NE : DELTA_SE);
const Square TDELTA_NW = (Us == WHITE ? DELTA_NW : DELTA_SW);
Square to;
Bitboard b1, b2, enemyPieces, emptySquares;
Bitboard b1, b2, dc1, dc2, pawnPushes, emptySquares;
Bitboard pawns = pos.pieces(PAWN, Us);
Bitboard pawnsOn7 = pawns & TRank7BB;
Bitboard enemyPieces = (Type == MV_CAPTURE ? target : pos.pieces_of_color(Them));
// Standard captures and capturing promotions and underpromotions
if (Type == CAPTURE || Type == EVASION || (pawns & TRank7BB))
// Pre-calculate pawn pushes before changing emptySquares definition
if (Type != MV_CAPTURE)
{
enemyPieces = (Type == CAPTURE ? target : pos.pieces_of_color(opposite_color(Us)));
if (Type == EVASION)
enemyPieces &= target; // Capture only the checker piece
mlist = generate_pawn_captures<Us, Type, DELTA_NE>(mlist, pawns, enemyPieces);
mlist = generate_pawn_captures<Us, Type, DELTA_NW>(mlist, pawns, enemyPieces);
emptySquares = (Type == MV_NON_CAPTURE ? target : pos.empty_squares());
pawnPushes = move_pawns<TDELTA_N>(pawns & ~TRank7BB) & emptySquares;
}
// Non-capturing promotions and underpromotions
if (pawns & TRank7BB)
if (Type == MV_EVASION)
{
b1 = move_pawns<Us, DELTA_N>(pawns) & TRank8BB & pos.empty_squares();
if (Type == EVASION)
b1 &= target; // Only blocking promotion pushes
while (b1)
{
to = pop_1st_bit(&b1);
if (Type == CAPTURE || Type == EVASION)
(*mlist++).move = make_promotion_move(to - TDELTA_N, to, QUEEN);
if (Type == NON_CAPTURE || Type == EVASION)
{
(*mlist++).move = make_promotion_move(to - TDELTA_N, to, ROOK);
(*mlist++).move = make_promotion_move(to - TDELTA_N, to, BISHOP);
(*mlist++).move = make_promotion_move(to - TDELTA_N, to, KNIGHT);
}
// This is the only possible under promotion that can give a check
// not already included in the queen-promotion.
if (Type == CHECK && bit_is_set(pos.attacks_from<KNIGHT>(to), pos.king_square(Them)))
(*mlist++).move = make_promotion_move(to - TDELTA_N, to, KNIGHT);
}
emptySquares &= target; // Only blocking squares
enemyPieces &= target; // Capture only the checker piece
}
// Standard pawn pushes and double pushes
if (Type != CAPTURE)
// Promotions and underpromotions
if (pawnsOn7)
{
emptySquares = (Type == NON_CAPTURE ? target : pos.empty_squares());
if (Type == MV_CAPTURE)
emptySquares = pos.empty_squares();
// Single and double pawn pushes
b1 = move_pawns<Us, DELTA_N>(pawns) & emptySquares & ~TRank8BB;
b2 = move_pawns<Us, DELTA_N>(b1 & TRank3BB) & emptySquares;
pawns &= ~TRank7BB;
mlist = generate_promotions<Us, Type, TDELTA_NE>(pos, mlist, pawnsOn7, enemyPieces);
mlist = generate_promotions<Us, Type, TDELTA_NW>(pos, mlist, pawnsOn7, enemyPieces);
mlist = generate_promotions<Us, Type, TDELTA_N >(pos, mlist, pawnsOn7, emptySquares);
}
// Filter out unwanted pushes according to the move type
if (Type == EVASION)
// Standard captures
if (Type == MV_CAPTURE || Type == MV_EVASION)
{
mlist = generate_pawn_captures<Type, TDELTA_NE>(mlist, pawns, enemyPieces);
mlist = generate_pawn_captures<Type, TDELTA_NW>(mlist, pawns, enemyPieces);
}
// Single and double pawn pushes
if (Type != MV_CAPTURE)
{
b1 = pawnPushes & emptySquares;
b2 = move_pawns<TDELTA_N>(pawnPushes & TRank3BB) & emptySquares;
if (Type == MV_CHECK)
{
b1 &= target;
b2 &= target;
}
else if (Type == CHECK)
{
// Pawn moves which give direct cheks
// Consider only pawn moves which give direct checks
b1 &= pos.attacks_from<PAWN>(ksq, Them);
b2 &= pos.attacks_from<PAWN>(ksq, Them);
// Pawn moves which gives discovered check. This is possible only if
// the pawn is not on the same file as the enemy king, because we
// don't generate captures.
// Add pawn moves which gives discovered check. This is possible only
// if the pawn is not on the same file as the enemy king, because we
// don't generate captures.
if (pawns & target) // For CHECK type target is dc bitboard
{
Bitboard dc1 = move_pawns<Us, DELTA_N>(pawns & target & ~file_bb(ksq)) & emptySquares & ~TRank8BB;
Bitboard dc2 = move_pawns<Us, DELTA_N>(dc1 & TRank3BB) & emptySquares;
dc1 = move_pawns<TDELTA_N>(pawns & target & ~file_bb(ksq)) & emptySquares;
dc2 = move_pawns<TDELTA_N>(dc1 & TRank3BB) & emptySquares;
b1 |= dc1;
b2 |= dc2;
@@ -577,7 +477,7 @@ namespace {
}
// En passant captures
if ((Type == CAPTURE || Type == EVASION) && pos.ep_square() != SQ_NONE)
if ((Type == MV_CAPTURE || Type == MV_EVASION) && pos.ep_square() != SQ_NONE)
{
assert(Us != WHITE || square_rank(pos.ep_square()) == RANK_6);
assert(Us != BLACK || square_rank(pos.ep_square()) == RANK_3);
@@ -585,7 +485,7 @@ namespace {
// An en passant capture can be an evasion only if the checking piece
// is the double pushed pawn and so is in the target. Otherwise this
// is a discovery check and we are forced to do otherwise.
if (Type == EVASION && !bit_is_set(target, pos.ep_square() - TDELTA_N))
if (Type == MV_EVASION && !bit_is_set(target, pos.ep_square() - TDELTA_N))
return mlist;
b1 = pawns & pos.attacks_from<PAWN>(pos.ep_square(), Them);
@@ -601,93 +501,42 @@ namespace {
return mlist;
}
template<PieceType Piece>
MoveStack* generate_discovered_checks(const Position& pos, MoveStack* mlist, Square from) {
assert(Piece != QUEEN);
Bitboard b = pos.attacks_from<Piece>(from) & pos.empty_squares();
if (Piece == KING)
{
Square ksq = pos.king_square(opposite_color(pos.side_to_move()));
b &= ~QueenPseudoAttacks[ksq];
}
SERIALIZE_MOVES(b);
return mlist;
}
template<PieceType Piece>
MoveStack* generate_direct_checks(const Position& pos, MoveStack* mlist, Color us,
Bitboard dc, Square ksq) {
assert(Piece != KING);
Bitboard checkSqs, b;
Square from;
const Square* ptr = pos.piece_list_begin(us, Piece);
if ((from = *ptr++) == SQ_NONE)
return mlist;
checkSqs = pos.attacks_from<Piece>(ksq) & pos.empty_squares();
do
{
if ( (Piece == QUEEN && !(QueenPseudoAttacks[from] & checkSqs))
|| (Piece == ROOK && !(RookPseudoAttacks[from] & checkSqs))
|| (Piece == BISHOP && !(BishopPseudoAttacks[from] & checkSqs)))
continue;
if (dc && bit_is_set(dc, from))
continue;
b = pos.attacks_from<Piece>(from) & checkSqs;
SERIALIZE_MOVES(b);
} while ((from = *ptr++) != SQ_NONE);
return mlist;
}
template<CastlingSide Side>
MoveStack* generate_castle_moves(const Position& pos, MoveStack* mlist) {
MoveStack* generate_castle_moves(const Position& pos, MoveStack* mlist, Color us) {
Color us = pos.side_to_move();
Color them = opposite_color(us);
Square ksq = pos.king_square(us);
if ( (Side == KING_SIDE && pos.can_castle_kingside(us))
||(Side == QUEEN_SIDE && pos.can_castle_queenside(us)))
{
Color them = opposite_color(us);
Square ksq = pos.king_square(us);
assert(pos.piece_on(ksq) == make_piece(us, KING));
assert(pos.piece_on(ksq) == piece_of_color_and_type(us, KING));
Square rsq = (Side == KING_SIDE ? pos.initial_kr_square(us) : pos.initial_qr_square(us));
Square s1 = relative_square(us, Side == KING_SIDE ? SQ_G1 : SQ_C1);
Square s2 = relative_square(us, Side == KING_SIDE ? SQ_F1 : SQ_D1);
Square s;
bool illegal = false;
Square rsq = (Side == KING_SIDE ? pos.initial_kr_square(us) : pos.initial_qr_square(us));
Square s1 = relative_square(us, Side == KING_SIDE ? SQ_G1 : SQ_C1);
Square s2 = relative_square(us, Side == KING_SIDE ? SQ_F1 : SQ_D1);
Square s;
bool illegal = false;
assert(pos.piece_on(rsq) == make_piece(us, ROOK));
assert(pos.piece_on(rsq) == piece_of_color_and_type(us, ROOK));
// It is a bit complicated to correctly handle Chess960
for (s = Min(ksq, s1); s <= Max(ksq, s1); s++)
if ( (s != ksq && s != rsq && pos.square_is_occupied(s))
||(pos.attackers_to(s) & pos.pieces_of_color(them)))
illegal = true;
for (s = Min(rsq, s2); s <= Max(rsq, s2); s++)
if (s != ksq && s != rsq && pos.square_is_occupied(s))
illegal = true;
if ( Side == QUEEN_SIDE
&& square_file(rsq) == FILE_B
&& ( pos.piece_on(relative_square(us, SQ_A1)) == piece_of_color_and_type(them, ROOK)
|| pos.piece_on(relative_square(us, SQ_A1)) == piece_of_color_and_type(them, QUEEN)))
// It is a bit complicated to correctly handle Chess960
for (s = Min(ksq, s1); s <= Max(ksq, s1); s++)
if ( (s != ksq && s != rsq && pos.square_is_occupied(s))
||(pos.attackers_to(s) & pos.pieces_of_color(them)))
illegal = true;
if (!illegal)
(*mlist++).move = make_castle_move(ksq, rsq);
}
for (s = Min(rsq, s2); s <= Max(rsq, s2); s++)
if (s != ksq && s != rsq && pos.square_is_occupied(s))
illegal = true;
if ( Side == QUEEN_SIDE
&& square_file(rsq) == FILE_B
&& ( pos.piece_on(relative_square(us, SQ_A1)) == make_piece(them, ROOK)
|| pos.piece_on(relative_square(us, SQ_A1)) == make_piece(them, QUEEN)))
illegal = true;
if (!illegal)
(*mlist++).move = make_castle_move(ksq, rsq);
return mlist;
}
}
} // namespace
+14 -18
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,28 +17,24 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined(MOVEGEN_H_INCLUDED)
#define MOVEGEN_H_INCLUDED
////
//// Includes
////
#include "move.h"
#include "position.h"
enum MoveType {
MV_CAPTURE,
MV_NON_CAPTURE,
MV_CHECK,
MV_NON_CAPTURE_CHECK,
MV_EVASION,
MV_NON_EVASION,
MV_LEGAL,
MV_PSEUDO_LEGAL
};
////
//// Prototypes
////
extern MoveStack* generate_captures(const Position& pos, MoveStack* mlist);
extern MoveStack* generate_noncaptures(const Position& pos, MoveStack* mlist);
extern MoveStack* generate_non_capture_checks(const Position& pos, MoveStack* mlist);
extern MoveStack* generate_evasions(const Position& pos, MoveStack* mlist);
extern MoveStack* generate_moves(const Position& pos, MoveStack* mlist, bool pseudoLegal = false);
extern bool move_is_legal(const Position& pos, const Move m, Bitboard pinned);
extern bool move_is_legal(const Position& pos, const Move m);
template<MoveType>
MoveStack* generate(const Position& pos, MoveStack* mlist);
#endif // !defined(MOVEGEN_H_INCLUDED)
+160 -170
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,51 +18,35 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
////
//// Includes
////
#include <cassert>
#include "history.h"
#include "movegen.h"
#include "movepick.h"
#include "search.h"
#include "value.h"
////
//// Local definitions
////
#include "types.h"
namespace {
enum MovegenPhase {
PH_TT_MOVES, // Transposition table move and mate killer
PH_GOOD_CAPTURES, // Queen promotions and captures with SEE values >= 0
PH_KILLERS, // Killer moves from the current ply
PH_NONCAPTURES, // Non-captures and underpromotions
PH_BAD_CAPTURES, // Queen promotions and captures with SEE values < 0
PH_EVASIONS, // Check evasions
PH_QCAPTURES, // Captures in quiescence search
PH_QCHECKS, // Non-capture checks in quiescence search
PH_TT_MOVES, // Transposition table move and mate killer
PH_GOOD_CAPTURES, // Queen promotions and captures with SEE values >= 0
PH_KILLERS, // Killer moves from the current ply
PH_NONCAPTURES, // Non-captures and underpromotions
PH_BAD_CAPTURES, // Queen promotions and captures with SEE values < 0
PH_EVASIONS, // Check evasions
PH_QCAPTURES, // Captures in quiescence search
PH_QCHECKS, // Non-capture checks in quiescence search
PH_STOP
};
CACHE_LINE_ALIGNMENT
const uint8_t MainSearchPhaseTable[] = { PH_TT_MOVES, PH_GOOD_CAPTURES, PH_KILLERS, PH_NONCAPTURES, PH_BAD_CAPTURES, PH_STOP};
const uint8_t EvasionsPhaseTable[] = { PH_TT_MOVES, PH_EVASIONS, PH_STOP};
const uint8_t QsearchWithChecksPhaseTable[] = { PH_TT_MOVES, PH_QCAPTURES, PH_QCHECKS, PH_STOP};
const uint8_t QsearchWithoutChecksPhaseTable[] = { PH_TT_MOVES, PH_QCAPTURES, PH_STOP};
const uint8_t MainSearchTable[] = { PH_TT_MOVES, PH_GOOD_CAPTURES, PH_KILLERS, PH_NONCAPTURES, PH_BAD_CAPTURES, PH_STOP };
const uint8_t EvasionTable[] = { PH_TT_MOVES, PH_EVASIONS, PH_STOP };
const uint8_t QsearchWithChecksTable[] = { PH_TT_MOVES, PH_QCAPTURES, PH_QCHECKS, PH_STOP };
const uint8_t QsearchWithoutChecksTable[] = { PH_TT_MOVES, PH_QCAPTURES, PH_STOP };
}
////
//// Functions
////
/// Constructor for the MovePicker class. Apart from the position for which
/// it is asked to pick legal moves, MovePicker also wants some information
/// to help it to return the presumably good moves first, to decide which
@@ -70,34 +54,67 @@ namespace {
/// search captures, promotions and some checks) and about how important good
/// move ordering is at the current node.
MovePicker::MovePicker(const Position& p, Move ttm, Depth d,
const History& h, SearchStack* ss) : pos(p), H(h) {
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const History& h,
SearchStack* ss, Value beta) : pos(p), H(h) {
int searchTT = ttm;
ttMoves[0].move = ttm;
finished = false;
lastBadCapture = badCaptures;
badCaptureThreshold = 0;
badCaptures = moves + MAX_MOVES;
assert(d > DEPTH_ZERO);
pinned = p.pinned_pieces(pos.side_to_move());
if (ss && !p.is_check())
if (p.in_check())
{
ttMoves[1].move = (ss->mateKiller == ttm)? MOVE_NONE : ss->mateKiller;
ttMoves[1].move = killers[0].move = killers[1].move = MOVE_NONE;
phasePtr = EvasionTable;
}
else
{
ttMoves[1].move = (ss->mateKiller == ttm) ? MOVE_NONE : ss->mateKiller;
searchTT |= ttMoves[1].move;
killers[0].move = ss->killers[0];
killers[1].move = ss->killers[1];
} else
ttMoves[1].move = killers[0].move = killers[1].move = MOVE_NONE;
if (p.is_check())
phasePtr = EvasionsPhaseTable;
else if (d > Depth(0))
phasePtr = MainSearchPhaseTable;
else if (d == Depth(0))
phasePtr = QsearchWithChecksPhaseTable;
// Consider sligtly negative captures as good if at low
// depth and far from beta.
if (ss && ss->eval < beta - PawnValueMidgame && d < 3 * ONE_PLY)
badCaptureThreshold = -PawnValueMidgame;
phasePtr = MainSearchTable;
}
phasePtr += int(!searchTT) - 1;
go_next_phase();
}
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const History& h)
: pos(p), H(h) {
int searchTT = ttm;
ttMoves[0].move = ttm;
ttMoves[1].move = MOVE_NONE;
assert(d <= DEPTH_ZERO);
pinned = p.pinned_pieces(pos.side_to_move());
if (p.in_check())
phasePtr = EvasionTable;
else if (d >= DEPTH_QS_CHECKS)
phasePtr = QsearchWithChecksTable;
else
phasePtr = QsearchWithoutChecksPhaseTable;
{
phasePtr = QsearchWithoutChecksTable;
phasePtr += !searchTT - 1;
// Skip TT move if is not a capture or a promotion, this avoids
// qsearch tree explosion due to a possible perpetual check or
// similar rare cases when TT table is full.
if (ttm != MOVE_NONE && !pos.move_is_capture_or_promotion(ttm))
searchTT = ttMoves[0].move = MOVE_NONE;
}
phasePtr += int(!searchTT) - 1;
go_next_phase();
}
@@ -117,7 +134,7 @@ void MovePicker::go_next_phase() {
return;
case PH_GOOD_CAPTURES:
lastMove = generate_captures(pos, moves);
lastMove = generate<MV_CAPTURE>(pos, moves);
score_captures();
return;
@@ -127,36 +144,35 @@ void MovePicker::go_next_phase() {
return;
case PH_NONCAPTURES:
lastMove = generate_noncaptures(pos, moves);
lastMove = generate<MV_NON_CAPTURE>(pos, moves);
score_noncaptures();
sort_moves(moves, lastMove);
sort_moves(moves, lastMove, &lastGoodNonCapture);
return;
case PH_BAD_CAPTURES:
// Bad captures SEE value is already calculated so just sort them
// to get SEE move ordering.
// Bad captures SEE value is already calculated so just pick
// them in order to get SEE move ordering.
curMove = badCaptures;
lastMove = lastBadCapture;
lastMove = moves + MAX_MOVES;
return;
case PH_EVASIONS:
assert(pos.is_check());
lastMove = generate_evasions(pos, moves);
assert(pos.in_check());
lastMove = generate<MV_EVASION>(pos, moves);
score_evasions();
return;
case PH_QCAPTURES:
lastMove = generate_captures(pos, moves);
lastMove = generate<MV_CAPTURE>(pos, moves);
score_captures();
return;
case PH_QCHECKS:
// Perhaps we should order moves move here? FIXME
lastMove = generate_non_capture_checks(pos, moves);
lastMove = generate<MV_NON_CAPTURE_CHECK>(pos, moves);
return;
case PH_STOP:
lastMove = curMove + 1; // hack to be friendly for get_next_move()
lastMove = curMove + 1; // Avoid another go_next_phase() call
return;
default:
@@ -200,28 +216,15 @@ void MovePicker::score_captures() {
}
void MovePicker::score_noncaptures() {
// First score by history, when no history is available then use
// piece/square tables values. This seems to be better then a
// random choice when we don't have an history for any move.
Move m;
Piece piece;
Square from, to;
int hs;
Square from;
for (MoveStack* cur = moves; cur != lastMove; cur++)
{
m = cur->move;
from = move_from(m);
to = move_to(m);
piece = pos.piece_on(from);
hs = H.move_ordering_score(piece, to);
// Ensure history is always preferred to pst
if (hs > 0)
hs += 1000;
// pst based scoring
cur->score = hs + mg_value(pos.pst_delta(piece, from, to));
cur->score = H.value(pos.piece_on(from), move_to(m));
}
}
@@ -233,24 +236,29 @@ void MovePicker::score_evasions() {
Move m;
int seeScore;
// Skip if we don't have at least two moves to order
if (lastMove < moves + 2)
return;
for (MoveStack* cur = moves; cur != lastMove; cur++)
{
m = cur->move;
if ((seeScore = pos.see_sign(m)) < 0)
cur->score = seeScore;
cur->score = seeScore - History::MaxValue; // Be sure we are at the bottom
else if (pos.move_is_capture(m))
cur->score = pos.midgame_value_of_piece_on(move_to(m))
- pos.type_of_piece_on(move_from(m)) + HistoryMax;
- pos.type_of_piece_on(move_from(m)) + History::MaxValue;
else
cur->score = H.move_ordering_score(pos.piece_on(move_from(m)), move_to(m));
cur->score = H.value(pos.piece_on(move_from(m)), move_to(m));
}
}
/// MovePicker::get_next_move() is the most important method of the MovePicker
/// class. It returns a new legal move every time it is called, until there
/// are no more moves left.
/// It picks the move with the biggest score from a list of generated moves taking
/// care not to return the tt move if has already been searched previously.
/// are no more moves left. It picks the move with the biggest score from a list
/// of generated moves taking care not to return the tt move if has already been
/// searched previously. Note that this function is not thread safe so should be
/// lock protected by caller when accessed through a shared MovePicker object.
Move MovePicker::get_next_move() {
@@ -258,103 +266,85 @@ Move MovePicker::get_next_move() {
while (true)
{
while (curMove != lastMove)
{
switch (phase) {
while (curMove == lastMove)
go_next_phase();
case PH_TT_MOVES:
move = (curMove++)->move;
if ( move != MOVE_NONE
&& move_is_legal(pos, move, pinned))
return move;
break;
switch (phase) {
case PH_GOOD_CAPTURES:
move = pick_best(curMove++, lastMove).move;
if ( move != ttMoves[0].move
&& move != ttMoves[1].move
&& pos.pl_move_is_legal(move, pinned))
{
// Check for a non negative SEE now
int seeValue = pos.see_sign(move);
if (seeValue >= 0)
return move;
// Losing capture, move it to the badCaptures[] array, note
// that move has now been already checked for legality.
assert(int(lastBadCapture - badCaptures) < 63);
lastBadCapture->move = move;
lastBadCapture->score = seeValue;
lastBadCapture++;
}
break;
case PH_KILLERS:
move = (curMove++)->move;
if ( move != MOVE_NONE
&& move != ttMoves[0].move
&& move != ttMoves[1].move
&& move_is_legal(pos, move, pinned)
&& !pos.move_is_capture(move))
return move;
break;
case PH_NONCAPTURES:
move = (curMove++)->move;
if ( move != ttMoves[0].move
&& move != ttMoves[1].move
&& move != killers[0].move
&& move != killers[1].move
&& pos.pl_move_is_legal(move, pinned))
return move;
break;
case PH_BAD_CAPTURES:
move = pick_best(curMove++, lastMove).move;
case PH_TT_MOVES:
move = (curMove++)->move;
if ( move != MOVE_NONE
&& pos.move_is_legal(move, pinned))
return move;
break;
case PH_EVASIONS:
case PH_QCAPTURES:
move = pick_best(curMove++, lastMove).move;
if ( move != ttMoves[0].move
&& pos.pl_move_is_legal(move, pinned))
case PH_GOOD_CAPTURES:
move = pick_best(curMove++, lastMove).move;
if ( move != ttMoves[0].move
&& move != ttMoves[1].move
&& pos.pl_move_is_legal(move, pinned))
{
// Check for a non negative SEE now
int seeValue = pos.see_sign(move);
if (seeValue >= badCaptureThreshold)
return move;
break;
case PH_QCHECKS:
move = (curMove++)->move;
if ( move != ttMoves[0].move
&& pos.pl_move_is_legal(move, pinned))
return move;
break;
case PH_STOP:
return MOVE_NONE;
default:
assert(false);
break;
// Losing capture, move it to the tail of the array, note
// that move has now been already checked for legality.
(--badCaptures)->move = move;
badCaptures->score = seeValue;
}
break;
case PH_KILLERS:
move = (curMove++)->move;
if ( move != MOVE_NONE
&& pos.move_is_legal(move, pinned)
&& move != ttMoves[0].move
&& move != ttMoves[1].move
&& !pos.move_is_capture(move))
return move;
break;
case PH_NONCAPTURES:
// Sort negative scored moves only when we get there
if (curMove == lastGoodNonCapture)
insertion_sort<MoveStack>(lastGoodNonCapture, lastMove);
move = (curMove++)->move;
if ( move != ttMoves[0].move
&& move != ttMoves[1].move
&& move != killers[0].move
&& move != killers[1].move
&& pos.pl_move_is_legal(move, pinned))
return move;
break;
case PH_BAD_CAPTURES:
move = pick_best(curMove++, lastMove).move;
return move;
case PH_EVASIONS:
case PH_QCAPTURES:
move = pick_best(curMove++, lastMove).move;
if ( move != ttMoves[0].move
&& pos.pl_move_is_legal(move, pinned))
return move;
break;
case PH_QCHECKS:
move = (curMove++)->move;
if ( move != ttMoves[0].move
&& pos.pl_move_is_legal(move, pinned))
return move;
break;
case PH_STOP:
return MOVE_NONE;
default:
assert(false);
break;
}
go_next_phase();
}
}
/// A variant of get_next_move() which takes a lock as a parameter, used to
/// prevent multiple threads from picking the same move at a split point.
Move MovePicker::get_next_move(Lock &lock) {
lock_grab(&lock);
if (finished)
{
lock_release(&lock);
return MOVE_NONE;
}
Move m = get_next_move();
if (m == MOVE_NONE)
finished = true;
lock_release(&lock);
return m;
}
+13 -40
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,43 +17,32 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined MOVEPICK_H_INCLUDED
#define MOVEPICK_H_INCLUDED
////
//// Includes
////
#include "depth.h"
#include "history.h"
#include "lock.h"
#include "move.h"
#include "position.h"
////
//// Types
////
#include "types.h"
struct SearchStack;
/// MovePicker is a class which is used to pick one legal move at a time from
/// the current position. It is initialized with a Position object and a few
/// moves we have reason to believe are good. The most important method is
/// MovePicker::pick_next_move(), which returns a new legal move each time it
/// MovePicker::get_next_move(), which returns a new legal move each time it
/// is called, until there are no legal moves left, when MOVE_NONE is returned.
/// In order to improve the efficiency of the alpha beta algorithm, MovePicker
/// attempts to return the moves which are most likely to be strongest first.
/// attempts to return the moves which are most likely to get a cut-off first.
class MovePicker {
MovePicker& operator=(const MovePicker&); // silence a warning under MSVC
MovePicker& operator=(const MovePicker&); // Silence a warning under MSVC
public:
MovePicker(const Position& p, Move ttm, Depth d, const History& h, SearchStack* ss = NULL);
MovePicker(const Position&, Move, Depth, const History&, SearchStack*, Value);
MovePicker(const Position&, Move, Depth, const History&);
Move get_next_move();
Move get_next_move(Lock& lock);
int number_of_evasions() const;
private:
void score_captures();
@@ -63,28 +52,12 @@ private:
const Position& pos;
const History& H;
MoveStack ttMoves[2], killers[2];
bool finished;
int phase;
const uint8_t* phasePtr;
MoveStack *curMove, *lastMove, *lastBadCapture;
Bitboard pinned;
MoveStack moves[256], badCaptures[64];
MoveStack ttMoves[2], killers[2];
int badCaptureThreshold, phase;
const uint8_t* phasePtr;
MoveStack *curMove, *lastMove, *lastGoodNonCapture, *badCaptures;
MoveStack moves[MAX_MOVES];
};
////
//// Inline functions
////
/// MovePicker::number_of_evasions() simply returns the number of moves in
/// evasions phase. It is intended to be used in positions where the side to
/// move is in check, for detecting checkmates or situations where there is
/// only a single reply to check.
/// WARNING: It works as long as PH_EVASIONS is the _only_ phase for evasions.
inline int MovePicker::number_of_evasions() const {
return int(lastMove - moves);
}
#endif // !defined(MOVEPICK_H_INCLUDED)
+118 -243
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,46 +17,37 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
////
//// Includes
////
#include <cassert>
#include <cstring>
#include "bitboard.h"
#include "bitcount.h"
#include "pawns.h"
#include "position.h"
////
//// Local definitions
////
namespace {
/// Constants and variables
#define S(mg, eg) make_score(mg, eg)
// Doubled pawn penalty by file
const Score DoubledPawnPenalty[8] = {
S(13, 43), S(20, 48), S(23, 48), S(23, 48),
S(23, 48), S(23, 48), S(20, 48), S(13, 43)
};
// Doubled pawn penalty by opposed flag and file
const Score DoubledPawnPenalty[2][8] = {
{ S(13, 43), S(20, 48), S(23, 48), S(23, 48),
S(23, 48), S(23, 48), S(20, 48), S(13, 43) },
{ S(13, 43), S(20, 48), S(23, 48), S(23, 48),
S(23, 48), S(23, 48), S(20, 48), S(13, 43) }};
// Isolated pawn penalty by file
const Score IsolatedPawnPenalty[8] = {
S(25, 30), S(36, 35), S(40, 35), S(40, 35),
S(40, 35), S(40, 35), S(36, 35), S(25, 30)
};
// Isolated pawn penalty by opposed flag and file
const Score IsolatedPawnPenalty[2][8] = {
{ S(37, 45), S(54, 52), S(60, 52), S(60, 52),
S(60, 52), S(60, 52), S(54, 52), S(37, 45) },
{ S(25, 30), S(36, 35), S(40, 35), S(40, 35),
S(40, 35), S(40, 35), S(36, 35), S(25, 30) }};
// Backward pawn penalty by file
const Score BackwardPawnPenalty[8] = {
S(20, 28), S(29, 31), S(33, 31), S(33, 31),
S(33, 31), S(33, 31), S(29, 31), S(20, 28)
};
// Backward pawn penalty by opposed flag and file
const Score BackwardPawnPenalty[2][8] = {
{ S(30, 42), S(43, 46), S(49, 46), S(49, 46),
S(49, 46), S(49, 46), S(43, 46), S(30, 42) },
{ S(20, 28), S(29, 31), S(33, 31), S(33, 31),
S(33, 31), S(33, 31), S(29, 31), S(20, 28) }};
// Pawn chain membership bonus by file
const Score ChainBonus[8] = {
@@ -70,87 +61,28 @@ namespace {
S(34,68), S(83,166), S(0, 0), S( 0, 0)
};
// Pawn storm tables for positions with opposite castling
const int QStormTable[64] = {
0, 0, 0, 0, 0, 0, 0, 0,
-22,-22,-22,-14,-6, 0, 0, 0,
-6,-10,-10,-10,-6, 0, 0, 0,
4, 12, 16, 12, 4, 0, 0, 0,
16, 23, 23, 16, 0, 0, 0, 0,
23, 31, 31, 23, 0, 0, 0, 0,
23, 31, 31, 23, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
};
const Score PawnStructureWeight = S(233, 201);
const int KStormTable[64] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0,-10,-19,-28,-33,-33,
0, 0, 0,-10,-15,-19,-24,-24,
0, 0, 0, 0, 1, 1, 1, 1,
0, 0, 0, 0, 1, 10, 19, 19,
0, 0, 0, 0, 1, 19, 31, 27,
0, 0, 0, 0, 0, 22, 31, 22,
0, 0, 0, 0, 0, 0, 0, 0
};
#undef S
// Pawn storm open file bonuses by file
const int16_t KStormOpenFileBonus[8] = { 31, 31, 18, 0, 0, 0, 0, 0 };
const int16_t QStormOpenFileBonus[8] = { 0, 0, 0, 0, 0, 26, 42, 26 };
// Pawn storm lever bonuses by file
const int StormLeverBonus[8] = { -8, -8, -13, 0, 0, -13, -8, -8 };
}
////
//// Functions
////
/// Constructor
PawnInfoTable::PawnInfoTable(unsigned numOfEntries) {
size = numOfEntries;
entries = new PawnInfo[size];
if (!entries)
{
std::cerr << "Failed to allocate " << (numOfEntries * sizeof(PawnInfo))
<< " bytes for pawn hash table." << std::endl;
Application::exit_with_failure();
inline Score apply_weight(Score v, Score w) {
return make_score((int(mg_value(v)) * mg_value(w)) / 0x100,
(int(eg_value(v)) * eg_value(w)) / 0x100);
}
}
/// Destructor
PawnInfoTable::~PawnInfoTable() {
delete [] entries;
}
/// PawnInfo::clear() resets to zero the PawnInfo entry. Note that
/// kingSquares[] is initialized to SQ_NONE instead.
void PawnInfo::clear() {
memset(this, 0, sizeof(PawnInfo));
kingSquares[WHITE] = kingSquares[BLACK] = SQ_NONE;
}
/// PawnInfoTable::get_pawn_info() takes a position object as input, computes
/// a PawnInfo object, and returns a pointer to it. The result is also
/// stored in a hash table, so we don't have to recompute everything when
/// the same pawn structure occurs again.
/// a PawnInfo object, and returns a pointer to it. The result is also stored
/// in an hash table, so we don't have to recompute everything when the same
/// pawn structure occurs again.
PawnInfo* PawnInfoTable::get_pawn_info(const Position& pos) {
PawnInfo* PawnInfoTable::get_pawn_info(const Position& pos) const {
assert(pos.is_ok());
Key key = pos.get_pawn_key();
int index = int(key & (size - 1));
PawnInfo* pi = entries + index;
PawnInfo* pi = probe(key);
// 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
@@ -158,19 +90,24 @@ PawnInfo* PawnInfoTable::get_pawn_info(const Position& pos) {
if (pi->key == key)
return pi;
// Clear the PawnInfo object, and set the key
pi->clear();
// Initialize PawnInfo entry
pi->key = key;
pi->passedPawns[WHITE] = pi->passedPawns[BLACK] = 0;
pi->kingSquares[WHITE] = pi->kingSquares[BLACK] = SQ_NONE;
pi->halfOpenFiles[WHITE] = pi->halfOpenFiles[BLACK] = 0xFF;
// Calculate pawn attacks
Bitboard whitePawns = pos.pieces(PAWN, WHITE);
Bitboard blackPawns = pos.pieces(PAWN, BLACK);
pi->pawnAttacks[WHITE] = ((whitePawns << 9) & ~FileABB) | ((whitePawns << 7) & ~FileHBB);
pi->pawnAttacks[BLACK] = ((blackPawns >> 7) & ~FileABB) | ((blackPawns >> 9) & ~FileHBB);
Bitboard wPawns = pos.pieces(PAWN, WHITE);
Bitboard bPawns = pos.pieces(PAWN, BLACK);
pi->pawnAttacks[WHITE] = ((wPawns << 9) & ~FileABB) | ((wPawns << 7) & ~FileHBB);
pi->pawnAttacks[BLACK] = ((bPawns >> 7) & ~FileABB) | ((bPawns >> 9) & ~FileHBB);
// Evaluate pawns for both colors and weight the result
pi->value = evaluate_pawns<WHITE>(pos, wPawns, bPawns, pi)
- evaluate_pawns<BLACK>(pos, bPawns, wPawns, pi);
pi->value = apply_weight(pi->value, PawnStructureWeight);
// Evaluate pawns for both colors
pi->value = evaluate_pawns<WHITE>(pos, whitePawns, blackPawns, pi)
- evaluate_pawns<BLACK>(pos, blackPawns, whitePawns, pi);
return pi;
}
@@ -180,189 +117,127 @@ PawnInfo* PawnInfoTable::get_pawn_info(const Position& pos) {
template<Color Us>
Score PawnInfoTable::evaluate_pawns(const Position& pos, Bitboard ourPawns,
Bitboard theirPawns, PawnInfo* pi) {
const BitCountType Max15 = CpuIs64Bit ? CNT64_MAX15 : CNT32_MAX15;
const Color Them = (Us == WHITE ? BLACK : WHITE);
Bitboard b;
Square s;
File f;
Rank r;
bool passed, isolated, doubled, chain, backward, candidate;
int bonus;
Score value = make_score(0, 0);
bool passed, isolated, doubled, opposed, chain, backward, candidate;
Score value = SCORE_ZERO;
const Square* ptr = pos.piece_list_begin(Us, PAWN);
// Initialize pawn storm scores by giving bonuses for open files
for (f = FILE_A; f <= FILE_H; f++)
if (!(ourPawns & file_bb(f)))
{
pi->ksStormValue[Us] += KStormOpenFileBonus[f];
pi->qsStormValue[Us] += QStormOpenFileBonus[f];
pi->halfOpenFiles[Us] |= (1 << f);
}
// Loop through all pawns of the current color and score each pawn
while ((s = *ptr++) != SQ_NONE)
{
assert(pos.piece_on(s) == make_piece(Us, PAWN));
f = square_file(s);
r = square_rank(s);
assert(pos.piece_on(s) == piece_of_color_and_type(Us, PAWN));
// This file cannot be half open
pi->halfOpenFiles[Us] &= ~(1 << f);
// Passed, isolated or doubled pawn?
passed = Position::pawn_is_passed(theirPawns, Us, s);
isolated = Position::pawn_is_isolated(ourPawns, s);
doubled = Position::pawn_is_doubled(ourPawns, Us, s);
// Our rank plus previous one. Used for chain detection
b = rank_bb(r) | rank_bb(Us == WHITE ? r - Rank(1) : r + Rank(1));
// We calculate kingside and queenside pawn storm
// scores for both colors. These are used when evaluating
// middle game positions with opposite side castling.
//
// Each pawn is given a base score given by a piece square table
// (KStormTable[] or QStormTable[]). Pawns which seem to have good
// chances of creating an open file by exchanging itself against an
// enemy pawn on an adjacent file gets an additional bonus.
// Kingside pawn storms
bonus = KStormTable[relative_square(Us, s)];
if (f >= FILE_F)
{
Bitboard b = outpost_mask(Us, s) & theirPawns & (FileFBB | FileGBB | FileHBB);
while (b)
{
Square s2 = pop_1st_bit(&b);
if (!(theirPawns & neighboring_files_bb(s2) & rank_bb(s2)))
{
// The enemy pawn has no pawn beside itself, which makes it
// particularly vulnerable. Big bonus, especially against a
// weakness on the rook file.
if (square_file(s2) == FILE_H)
bonus += 4*StormLeverBonus[f] - 8*square_distance(s, s2);
else
bonus += 2*StormLeverBonus[f] - 4*square_distance(s, s2);
} else
// There is at least one enemy pawn beside the enemy pawn we look
// at, which means that the pawn has somewhat better chances of
// defending itself by advancing. Smaller bonus.
bonus += StormLeverBonus[f] - 2*square_distance(s, s2);
}
}
pi->ksStormValue[Us] += bonus;
// Queenside pawn storms
bonus = QStormTable[relative_square(Us, s)];
if (f <= FILE_C)
{
Bitboard b = outpost_mask(Us, s) & theirPawns & (FileABB | FileBBB | FileCBB);
while (b)
{
Square s2 = pop_1st_bit(&b);
if (!(theirPawns & neighboring_files_bb(s2) & rank_bb(s2)))
{
// The enemy pawn has no pawn beside itself, which makes it
// particularly vulnerable. Big bonus, especially against a
// weakness on the rook file.
if (square_file(s2) == FILE_A)
bonus += 4*StormLeverBonus[f] - 16*square_distance(s, s2);
else
bonus += 2*StormLeverBonus[f] - 8*square_distance(s, s2);
} else
// There is at least one enemy pawn beside the enemy pawn we look
// at, which means that the pawn has somewhat better chances of
// defending itself by advancing. Smaller bonus.
bonus += StormLeverBonus[f] - 4*square_distance(s, s2);
}
}
pi->qsStormValue[Us] += bonus;
// Member of a pawn chain (but not the backward one)? We could speed up
// the test a little by introducing an array of masks indexed by color
// and square for doing the test, but because everything is hashed,
// it probably won't make any noticable difference.
chain = ourPawns
& neighboring_files_bb(f)
& (rank_bb(r) | rank_bb(r - (Us == WHITE ? 1 : -1)));
// Flag the pawn as passed, isolated, doubled or member of a pawn
// chain (but not the backward one).
passed = !(theirPawns & passed_pawn_mask(Us, s));
doubled = ourPawns & squares_in_front_of(Us, s);
opposed = theirPawns & squares_in_front_of(Us, s);
isolated = !(ourPawns & neighboring_files_bb(f));
chain = ourPawns & neighboring_files_bb(f) & b;
// Test for backward pawn
//
// If the pawn is passed, isolated, or member of a pawn chain
// it cannot be backward. If can capture an enemy pawn or if
// there are friendly pawns behind on neighboring files it cannot
// be backward either.
if ( (passed | isolated | chain)
|| (ourPawns & behind_bb(Us, r) & neighboring_files_bb(f))
|| (pos.attacks_from<PAWN>(s, Us) & theirPawns))
backward = false;
else
backward = false;
// If the pawn is passed, isolated, or member of a pawn chain it cannot
// be backward. If there are friendly pawns behind on neighboring files
// or if can capture an enemy pawn it cannot be backward either.
if ( !(passed | isolated | chain)
&& !(ourPawns & attack_span_mask(Them, s))
&& !(pos.attacks_from<PAWN>(s, Us) & theirPawns))
{
// We now know that there are no friendly pawns beside or behind this
// pawn on neighboring files. We now check whether the pawn is
// backward by looking in the forward direction on the neighboring
// files, and seeing whether we meet a friendly or an enemy pawn first.
Bitboard b = pos.attacks_from<PAWN>(s, Us);
b = pos.attacks_from<PAWN>(s, Us);
// Note that we are sure to find something because pawn is not passed
// nor isolated, so loop is potentially infinite, but it isn't.
while (!(b & (ourPawns | theirPawns)))
Us == WHITE ? b <<= 8 : b >>= 8;
// The friendly pawn needs to be at least two ranks closer than the enemy
// pawn in order to help the potentially backward pawn advance.
// The friendly pawn needs to be at least two ranks closer than the
// enemy pawn in order to help the potentially backward pawn advance.
backward = (b | (Us == WHITE ? b << 8 : b >> 8)) & theirPawns;
}
// Test for candidate passed pawn
candidate = !passed
&& !(theirPawns & file_bb(f))
&& ( count_1s_max_15(neighboring_files_bb(f) & (behind_bb(Us, r) | rank_bb(r)) & ourPawns)
- count_1s_max_15(neighboring_files_bb(f) & in_front_bb(Us, r) & theirPawns)
>= 0);
assert(opposed | passed | (attack_span_mask(Us, s) & theirPawns));
// In order to prevent doubled passed pawns from receiving a too big
// bonus, only the frontmost passed pawn on each file is considered as
// a true passed pawn.
if (passed && (ourPawns & squares_in_front_of(Us, s)))
passed = false;
// A not passed pawn is a candidate to become passed if it is free to
// advance and if the number of friendly pawns beside or behind this
// pawn on neighboring files is higher or equal than the number of
// enemy pawns in the forward direction on the neighboring files.
candidate = !(opposed | passed | backward | isolated)
&& (b = attack_span_mask(Them, s + pawn_push(Us)) & ourPawns) != EmptyBoardBB
&& count_1s<Max15>(b) >= count_1s<Max15>(attack_span_mask(Us, s) & theirPawns);
// Passed pawns will be properly scored in evaluation because we need
// full attack info to evaluate passed pawns. Only the frontmost passed
// pawn on each file is considered a true passed pawn.
if (passed && !doubled)
set_bit(&(pi->passedPawns[Us]), s);
// Score this pawn
if (passed)
set_bit(&(pi->passedPawns), s);
if (isolated)
{
value -= IsolatedPawnPenalty[f];
if (!(theirPawns & file_bb(f)))
value -= IsolatedPawnPenalty[f] / 2;
}
value -= IsolatedPawnPenalty[opposed][f];
if (doubled)
value -= DoubledPawnPenalty[f];
value -= DoubledPawnPenalty[opposed][f];
if (backward)
{
value -= BackwardPawnPenalty[f];
if (!(theirPawns & file_bb(f)))
value -= BackwardPawnPenalty[f] / 2;
}
value -= BackwardPawnPenalty[opposed][f];
if (chain)
value += ChainBonus[f];
if (candidate)
value += CandidateBonus[relative_rank(Us, s)];
}
return value;
}
/// PawnInfo::updateShelter calculates and caches king shelter. It is called
/// only when king square changes, about 20% of total get_king_shelter() calls.
int PawnInfo::updateShelter(const Position& pos, Color c, Square ksq) {
/// PawnInfo::updateShelter() calculates and caches king shelter. It is called
/// only when king square changes, about 20% of total king_shelter() calls.
template<Color Us>
Score PawnInfo::updateShelter(const Position& pos, Square ksq) {
unsigned shelter = 0;
Bitboard pawns = pos.pieces(PAWN, c) & this_and_neighboring_files_bb(ksq);
unsigned r = ksq & (7 << 3);
for (int i = 1, k = (c ? -8 : 8); i < 4; i++)
const int Shift = (Us == WHITE ? 8 : -8);
Bitboard pawns;
int r, shelter = 0;
if (relative_rank(Us, ksq) <= RANK_4)
{
r += k;
shelter += BitCount8Bit[(pawns >> r) & 0xFF] * (128 >> i);
pawns = pos.pieces(PAWN, Us) & this_and_neighboring_files_bb(ksq);
r = ksq & (7 << 3);
for (int i = 0; i < 3; i++)
{
r += Shift;
shelter += BitCount8Bit[(pawns >> r) & 0xFF] * (64 >> i);
}
}
kingSquares[c] = ksq;
kingShelters[c] = shelter;
return shelter;
kingSquares[Us] = ksq;
kingShelters[Us] = make_score(shelter, 0);
return kingShelters[Us];
}
// Explicit template instantiation
template Score PawnInfo::updateShelter<WHITE>(const Position& pos, Square ksq);
template Score PawnInfo::updateShelter<BLACK>(const Position& pos, Square ksq);
+34 -62
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,20 +17,14 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined(PAWNS_H_INCLUDED)
#define PAWNS_H_INCLUDED
////
//// Includes
////
#include "position.h"
#include "tt.h"
#include "types.h"
#include "bitboard.h"
#include "value.h"
////
//// Types
////
const int PawnTableSize = 16384;
/// PawnInfo is a class which contains various information about a pawn
/// structure. Currently, it only includes a middle game and an end game
@@ -38,86 +32,63 @@
/// to add further information in the future. A lookup to the pawn hash table
/// (performed by calling the get_pawn_info method in a PawnInfoTable object)
/// returns a pointer to a PawnInfo object.
class Position;
class PawnInfo {
friend class PawnInfoTable;
public:
PawnInfo() { clear(); }
Score pawns_value() const;
Value kingside_storm_value(Color c) const;
Value queenside_storm_value(Color c) const;
Bitboard pawn_attacks(Color c) const;
Bitboard passed_pawns() const;
Bitboard passed_pawns(Color c) const;
int file_is_half_open(Color c, File f) const;
int has_open_file_to_left(Color c, File f) const;
int has_open_file_to_right(Color c, File f) const;
int get_king_shelter(const Position& pos, Color c, Square ksq);
private:
void clear();
int updateShelter(const Position& pos, Color c, Square ksq);
Key key;
Bitboard passedPawns;
Bitboard pawnAttacks[2];
Score value;
int16_t ksStormValue[2], qsStormValue[2];
uint8_t halfOpenFiles[2];
Square kingSquares[2];
uint8_t kingShelters[2];
};
/// The PawnInfoTable class represents a pawn hash table. It is basically
/// just an array of PawnInfo objects and a few methods for accessing these
/// objects. The most important method is get_pawn_info, which looks up a
/// position in the table and returns a pointer to a PawnInfo object.
class PawnInfoTable {
public:
PawnInfoTable(unsigned numOfEntries);
~PawnInfoTable();
PawnInfo* get_pawn_info(const Position& pos);
template<Color Us>
Score king_shelter(const Position& pos, Square ksq);
private:
template<Color Us>
Score evaluate_pawns(const Position& pos, Bitboard ourPawns, Bitboard theirPawns, PawnInfo* pi);
Score updateShelter(const Position& pos, Square ksq);
unsigned size;
PawnInfo* entries;
Key key;
Bitboard passedPawns[2];
Bitboard pawnAttacks[2];
Square kingSquares[2];
Score value;
int halfOpenFiles[2];
Score kingShelters[2];
};
////
//// Inline functions
////
/// The PawnInfoTable class represents a pawn hash table. The most important
/// method is get_pawn_info, which returns a pointer to a PawnInfo object.
class PawnInfoTable : public SimpleHash<PawnInfo, PawnTableSize> {
public:
PawnInfo* get_pawn_info(const Position& pos) const;
private:
template<Color Us>
static Score evaluate_pawns(const Position& pos, Bitboard ourPawns, Bitboard theirPawns, PawnInfo* pi);
};
inline Score PawnInfo::pawns_value() const {
return value;
}
inline Bitboard PawnInfo::passed_pawns() const {
return passedPawns;
}
inline Bitboard PawnInfo::pawn_attacks(Color c) const {
return pawnAttacks[c];
}
inline Value PawnInfo::kingside_storm_value(Color c) const {
return Value(ksStormValue[c]);
}
inline Value PawnInfo::queenside_storm_value(Color c) const {
return Value(qsStormValue[c]);
inline Bitboard PawnInfo::passed_pawns(Color c) const {
return passedPawns[c];
}
inline int PawnInfo::file_is_half_open(Color c, File f) const {
return (halfOpenFiles[c] & (1 << int(f)));
return halfOpenFiles[c] & (1 << int(f));
}
inline int PawnInfo::has_open_file_to_left(Color c, File f) const {
@@ -128,8 +99,9 @@ inline int PawnInfo::has_open_file_to_right(Color c, File f) const {
return halfOpenFiles[c] & ~((1 << int(f+1)) - 1);
}
inline int PawnInfo::get_king_shelter(const Position& pos, Color c, Square ksq) {
return (kingSquares[c] == ksq ? kingShelters[c] : updateShelter(pos, c, ksq));
template<Color Us>
inline Score PawnInfo::king_shelter(const Position& pos, Square ksq) {
return kingSquares[Us] == ksq ? kingShelters[Us] : updateShelter<Us>(pos, ksq);
}
#endif // !defined(PAWNS_H_INCLUDED)
-49
View File
@@ -1,49 +0,0 @@
/*
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 <string>
#include "piece.h"
using namespace std;
////
//// Functions
////
/// Translating piece types to/from English piece letters
static const string PieceChars(" pnbrqk PNBRQK");
char piece_type_to_char(PieceType pt, bool upcase) {
return PieceChars[pt + upcase * 7];
}
PieceType piece_type_from_char(char c) {
size_t idx = PieceChars.find(c);
return idx != string::npos ? PieceType(idx % 7) : NO_PIECE_TYPE;
}
-107
View File
@@ -1,107 +0,0 @@
/*
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(PIECE_H_INCLUDED)
#define PIECE_H_INCLUDED
////
//// Includes
////
#include "color.h"
#include "square.h"
////
//// Types
////
enum PieceType {
NO_PIECE_TYPE = 0,
PAWN = 1, KNIGHT = 2, BISHOP = 3, ROOK = 4, QUEEN = 5, KING = 6
};
enum Piece {
NO_PIECE = 0, WP = 1, WN = 2, WB = 3, WR = 4, WQ = 5, WK = 6,
BP = 9, BN = 10, BB = 11, BR = 12, BQ = 13, BK = 14,
EMPTY = 16, OUTSIDE = 17
};
////
//// Constants
////
const int SlidingArray[18] = {
0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0
};
////
//// Inline functions
////
inline Piece operator+ (Piece p, int i) { return Piece(int(p) + i); }
inline void operator++ (Piece &p, int) { p = Piece(int(p) + 1); }
inline Piece operator- (Piece p, int i) { return Piece(int(p) - i); }
inline void operator-- (Piece &p, int) { p = Piece(int(p) - 1); }
inline PieceType operator+ (PieceType p, int i) {return PieceType(int(p) + i);}
inline void operator++ (PieceType &p, int) { p = PieceType(int(p) + 1); }
inline PieceType operator- (PieceType p, int i) {return PieceType(int(p) - i);}
inline void operator-- (PieceType &p, int) { p = PieceType(int(p) - 1); }
inline PieceType type_of_piece(Piece p) {
return PieceType(int(p) & 7);
}
inline Color color_of_piece(Piece p) {
return Color(int(p) >> 3);
}
inline Piece piece_of_color_and_type(Color c, PieceType pt) {
return Piece((int(c) << 3) | int(pt));
}
inline int piece_is_slider(Piece p) {
return SlidingArray[int(p)];
}
inline SquareDelta pawn_push(Color 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));
}
////
//// Prototypes
////
extern char piece_type_to_char(PieceType pt, bool upcase = false);
extern PieceType piece_type_from_char(char c);
#endif // !defined(PIECE_H_INCLUDED)
+709 -648
View File
File diff suppressed because it is too large Load Diff
+97 -113
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,73 +17,41 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined(POSITION_H_INCLUDED)
#define POSITION_H_INCLUDED
// Disable some silly and noisy warning from MSVC compiler
#if defined(_MSC_VER)
// Forcing value to bool 'true' or 'false' (performance warning)
#pragma warning(disable: 4800)
// Conditional expression is constant
#pragma warning(disable: 4127)
#endif
////
//// Includes
////
#include "bitboard.h"
#include "color.h"
#include "direction.h"
#include "move.h"
#include "piece.h"
#include "square.h"
#include "value.h"
////
//// Constants
////
/// FEN string for the initial position
const std::string StartPosition = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
#include "types.h"
/// Maximum number of plies per game (220 should be enough, because the
/// maximum search depth is 100, and during position setup we reset the
/// move counter for every non-reversible move).
const int MaxGameLength = 220;
////
//// Types
////
class Position;
/// struct checkInfo is initialized at c'tor time and keeps
/// info used to detect if a move gives check.
struct CheckInfo {
CheckInfo(const Position&);
explicit CheckInfo(const Position&);
Square ksq;
Bitboard dcCandidates;
Bitboard checkSq[8];
Square ksq;
};
/// Castle rights, encoded as bit fields
enum CastleRights {
NO_CASTLES = 0,
WHITE_OO = 1,
BLACK_OO = 2,
WHITE_OOO = 4,
BLACK_OOO = 8,
ALL_CASTLES = 15
CASTLES_NONE = 0,
WHITE_OO = 1,
BLACK_OO = 2,
WHITE_OOO = 4,
BLACK_OOO = 8,
ALL_CASTLES = 15
};
/// Game phase
@@ -100,13 +68,13 @@ enum Phase {
struct StateInfo {
Key pawnKey, materialKey;
int castleRights, rule50, pliesFromNull;
int castleRights, rule50, gamePly, pliesFromNull;
Square epSquare;
Score value;
Value npMaterial[2];
PieceType capturedType;
Key key;
PieceType capture;
Bitboard checkersBB;
StateInfo* previous;
};
@@ -136,8 +104,8 @@ struct StateInfo {
class Position {
friend class MaterialInfo;
friend class EndgameFunctions;
Position(); // No default or copy c'tor allowed
Position(const Position& pos);
public:
enum GamePhase {
@@ -146,18 +114,16 @@ public:
};
// Constructors
Position() {}
Position(const Position& pos);
Position(const std::string& fen);
Position(const Position& pos, int threadID);
Position(const std::string& fen, bool isChess960, int threadID);
// Text input/output
void from_fen(const std::string& fen);
void from_fen(const std::string& fen, bool isChess960);
const std::string to_fen() const;
void print(Move m = MOVE_NONE) const;
// Copying
void copy(const Position& pos);
void flipped_copy(const Position& pos);
void flip();
// The piece on a given square
Piece piece_on(Square s) const;
@@ -202,7 +168,7 @@ public:
// Checking pieces and under check information
Bitboard checkers() const;
bool is_check() const;
bool in_check() const;
// Piece lists
Square piece_list(Color c, PieceType pt, int index) const;
@@ -211,30 +177,33 @@ public:
// Information about attacks to or from a given square
Bitboard attackers_to(Square s) const;
Bitboard attacks_from(Piece p, Square s) const;
static Bitboard attacks_from(Piece p, Square s, Bitboard occ);
template<PieceType> Bitboard attacks_from(Square s) const;
template<PieceType> Bitboard attacks_from(Square s, Color c) const;
// Properties of moves
bool pl_move_is_legal(Move m, Bitboard pinned) const;
bool pl_move_is_evasion(Move m, Bitboard pinned) const;
bool move_is_check(Move m) const;
bool move_is_check(Move m, const CheckInfo& ci) const;
bool move_is_legal(const Move m) const;
bool move_is_legal(const Move m, Bitboard pinned) const;
bool move_gives_check(Move m) const;
bool move_gives_check(Move m, const CheckInfo& ci) const;
bool move_is_capture(Move m) const;
bool move_is_capture_or_promotion(Move m) const;
bool move_is_passed_pawn_push(Move m) const;
bool move_attacks_square(Move m, Square s) const;
// Piece captured with previous moves
PieceType captured_piece_type() const;
// Information about pawns
bool pawn_is_passed(Color c, Square s) const;
static bool pawn_is_passed(Bitboard theirPawns, Color c, Square s);
static bool pawn_is_isolated(Bitboard ourPawns, Square s);
static bool pawn_is_doubled(Bitboard ourPawns, Color c, Square s);
// Weak squares
bool square_is_weak(Square s, Color c) const;
// Doing and undoing moves
void saveState();
void do_setup_move(Move m);
void do_move(Move m, StateInfo& st);
void do_move(Move m, StateInfo& st, const CheckInfo& ci, bool moveIsCheck);
void undo_move(Move m);
@@ -244,7 +213,6 @@ public:
// Static exchange evaluation
int see(Square from, Square to) const;
int see(Move m) const;
int see(Square to) const;
int see_sign(Move m) const;
// Accessing hash keys
@@ -256,24 +224,25 @@ public:
// Incremental evaluation
Score value() const;
Value non_pawn_material(Color c) const;
Score pst_delta(Piece piece, Square from, Square to) const;
static Score pst_delta(Piece piece, Square from, Square to);
// Game termination checks
bool is_mate() const;
bool is_draw() const;
// Check if one side threatens a mate in one
bool has_mate_threat(Color c);
// Number of plies since the last non-reversible move
int rule_50_counter() const;
// Number of plies from starting position
int startpos_ply_counter() const;
// Other properties of the position
bool opposite_colored_bishops() const;
bool has_pawn_on_7th(Color c) const;
bool is_chess960() const;
// Reset the gamePly variable to 0
void reset_game_ply();
// Current thread ID searching on the position
int thread() const;
int64_t nodes_searched() const;
void set_nodes_searched(int64_t n);
// Position consistency check, for debugging
bool is_ok(int* failedStep = NULL) const;
@@ -286,12 +255,14 @@ private:
// Initialization helper functions (used while setting up a position)
void clear();
void detach();
void put_piece(Piece p, Square s);
void allow_oo(Color c);
void allow_ooo(Color c);
void do_allow_oo(Color c);
void do_allow_ooo(Color c);
bool set_castling_rights(char token);
// Helper functions for doing and undoing moves
void do_capture_move(Bitboard& key, PieceType capture, Color them, Square to, bool ep);
void do_capture_move(Key& key, PieceType capture, Color them, Square to, bool ep);
void do_castle_move(Move m);
void undo_castle_move(Move m);
void find_checkers();
@@ -305,7 +276,7 @@ private:
Key compute_material_key() const;
// Computing incremental evaluation scores and material counts
Score pst(Color c, PieceType pt, Square s) const;
static Score pst(Color c, PieceType pt, Square s);
Score compute_value() const;
Value compute_non_pawn_material(Color c) const;
@@ -324,27 +295,35 @@ private:
// Other info
Color sideToMove;
int gamePly;
Key history[MaxGameLength];
File initialKFile, initialKRFile, initialQRFile;
int castleRightsMask[64];
StateInfo startState;
File initialKFile, initialKRFile, initialQRFile;
bool chess960;
int startPosPlyCounter;
int threadID;
int64_t nodes;
StateInfo* st;
// Static variables
static int castleRightsMask[64];
static Key zobrist[2][8][64];
static Key zobEp[64];
static Key zobCastle[16];
static Key zobMaterial[2][8][16];
static Key zobSideToMove;
static Score PieceSquareTable[16][64];
static Key zobExclusion;
static const Value seeValues[8];
static const Value PieceValueMidgame[17];
static const Value PieceValueEndgame[17];
};
inline int64_t Position::nodes_searched() const {
return nodes;
}
////
//// Inline functions
////
inline void Position::set_nodes_searched(int64_t n) {
nodes = n;
}
inline Piece Position::piece_on(Square s) const {
return board[s];
@@ -359,7 +338,7 @@ inline PieceType Position::type_of_piece_on(Square s) const {
}
inline bool Position::square_is_empty(Square s) const {
return piece_on(s) == EMPTY;
return piece_on(s) == PIECE_NONE;
}
inline bool Position::square_is_occupied(Square s) const {
@@ -367,11 +346,11 @@ inline bool Position::square_is_occupied(Square s) const {
}
inline Value Position::midgame_value_of_piece_on(Square s) const {
return piece_value_midgame(piece_on(s));
return PieceValueMidgame[piece_on(s)];
}
inline Value Position::endgame_value_of_piece_on(Square s) const {
return piece_value_endgame(piece_on(s));
return PieceValueEndgame[piece_on(s)];
}
inline Color Position::side_to_move() const {
@@ -383,7 +362,7 @@ inline Bitboard Position::occupied_squares() const {
}
inline Bitboard Position::empty_squares() const {
return ~(occupied_squares());
return ~occupied_squares();
}
inline Bitboard Position::pieces_of_color(Color c) const {
@@ -410,8 +389,8 @@ inline int Position::piece_count(Color c, PieceType pt) const {
return pieceCount[c][pt];
}
inline Square Position::piece_list(Color c, PieceType pt, int index) const {
return pieceList[c][pt][index];
inline Square Position::piece_list(Color c, PieceType pt, int idx) const {
return pieceList[c][pt][idx];
}
inline const Square* Position::piece_list_begin(Color c, PieceType pt) const {
@@ -448,12 +427,12 @@ inline Square Position::initial_qr_square(Color c) const {
template<>
inline Bitboard Position::attacks_from<PAWN>(Square s, Color c) const {
return StepAttackBB[piece_of_color_and_type(c, PAWN)][s];
return StepAttacksBB[make_piece(c, PAWN)][s];
}
template<PieceType Piece> // Knight and King and white pawns
inline Bitboard Position::attacks_from(Square s) const {
return StepAttackBB[Piece][s];
return StepAttacksBB[Piece][s];
}
template<>
@@ -475,7 +454,7 @@ inline Bitboard Position::checkers() const {
return st->checkersBB;
}
inline bool Position::is_check() const {
inline bool Position::in_check() const {
return st->checkersBB != EmptyBoardBB;
}
@@ -483,20 +462,8 @@ inline bool Position::pawn_is_passed(Color c, Square s) const {
return !(pieces(PAWN, opposite_color(c)) & passed_pawn_mask(c, s));
}
inline bool Position::pawn_is_passed(Bitboard theirPawns, Color c, Square s) {
return !(theirPawns & passed_pawn_mask(c, s));
}
inline bool Position::pawn_is_isolated(Bitboard ourPawns, Square s) {
return !(ourPawns & neighboring_files_bb(s));
}
inline bool Position::pawn_is_doubled(Bitboard ourPawns, Color c, Square s) {
return ourPawns & squares_behind(c, s);
}
inline bool Position::square_is_weak(Square s, Color c) const {
return !(pieces(PAWN, c) & outpost_mask(opposite_color(c), s));
return !(pieces(PAWN, opposite_color(c)) & attack_span_mask(c, s));
}
inline Key Position::get_key() const {
@@ -515,11 +482,11 @@ inline Key Position::get_material_key() const {
return st->materialKey;
}
inline Score Position::pst(Color c, PieceType pt, Square s) const {
return PieceSquareTable[piece_of_color_and_type(c, pt)][s];
inline Score Position::pst(Color c, PieceType pt, Square s) {
return PieceSquareTable[make_piece(c, pt)][s];
}
inline Score Position::pst_delta(Piece piece, Square from, Square to) const {
inline Score Position::pst_delta(Piece piece, Square from, Square to) {
return PieceSquareTable[piece][to] - PieceSquareTable[piece][from];
}
@@ -534,25 +501,26 @@ inline Value Position::non_pawn_material(Color c) const {
inline bool Position::move_is_passed_pawn_push(Move m) const {
Color c = side_to_move();
return piece_on(move_from(m)) == piece_of_color_and_type(c, PAWN)
return piece_on(move_from(m)) == make_piece(c, PAWN)
&& pawn_is_passed(c, move_to(m));
}
inline int Position::rule_50_counter() const {
return st->rule50;
inline int Position::startpos_ply_counter() const {
return startPosPlyCounter;
}
inline bool Position::opposite_colored_bishops() const {
return piece_count(WHITE, BISHOP) == 1
&& piece_count(BLACK, BISHOP) == 1
&& square_color(piece_list(WHITE, BISHOP, 0)) != square_color(piece_list(BLACK, BISHOP, 0));
return piece_count(WHITE, BISHOP) == 1 && piece_count(BLACK, BISHOP) == 1
&& opposite_color_squares(piece_list(WHITE, BISHOP, 0), piece_list(BLACK, BISHOP, 0));
}
inline bool Position::has_pawn_on_7th(Color c) const {
return pieces(PAWN, c) & rank_bb(relative_rank(c, RANK_7));
}
return pieces(PAWN, c) & relative_rank_bb(c, RANK_7);
inline bool Position::is_chess960() const {
return chess960;
}
inline bool Position::move_is_capture(Move m) const {
@@ -567,4 +535,20 @@ inline bool Position::move_is_capture_or_promotion(Move m) const {
return (m & (0x1F << 12)) ? !move_is_castle(m) : !square_is_empty(move_to(m));
}
inline PieceType Position::captured_piece_type() const {
return st->capturedType;
}
inline int Position::thread() const {
return threadID;
}
inline void Position::do_allow_oo(Color c) {
st->castleRights |= (1 + int(c));
}
inline void Position::do_allow_ooo(Color c) {
st->castleRights |= (4 + 4*int(c));
}
#endif // !defined(POSITION_H_INCLUDED)
+17 -20
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,28 +17,30 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined(PSQTAB_H_INCLUDED)
#define PSQTAB_H_INCLUDED
////
//// Includes
////
#include "value.h"
#include "types.h"
namespace {
////
//// Constants modified by Joona Kiiski
////
static const Value MP = PawnValueMidgame;
static const Value MK = KnightValueMidgame;
static const Value MB = BishopValueMidgame;
static const Value MR = RookValueMidgame;
static const Value MQ = QueenValueMidgame;
const Value MP = PawnValueMidgame;
const Value MK = KnightValueMidgame;
const Value MB = BishopValueMidgame;
const Value MR = RookValueMidgame;
const Value MQ = QueenValueMidgame;
static const int MgPST[][64] = {
const Value EP = PawnValueEndgame;
const Value EK = KnightValueEndgame;
const Value EB = BishopValueEndgame;
const Value ER = RookValueEndgame;
const Value EQ = QueenValueEndgame;
const int MgPST[][64] = {
{ },
{// Pawn
// A B C D E F G H
@@ -108,13 +110,7 @@ static const int MgPST[][64] = {
}
};
static const Value EP = PawnValueEndgame;
static const Value EK = KnightValueEndgame;
static const Value EB = BishopValueEndgame;
static const Value ER = RookValueEndgame;
static const Value EQ = QueenValueEndgame;
static const int EgPST[][64] = {
const int EgPST[][64] = {
{ },
{// Pawn
// A B C D E F G H
@@ -184,5 +180,6 @@ static const int EgPST[][64] = {
}
};
} // namespace
#endif // !defined(PSQTAB_H_INCLUDED)
+77
View File
@@ -0,0 +1,77 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Stockfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
This file is based on original code by Heinz van Saanen and is
available under 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.
** George Marsaglia invented the RNG-Kiss-family in the early 90's.
** This is a specific version that Heinz van Saanen derived and
** tested from some public domain code by Bob Jenkins:
**
** Quite platform independent
** Passes ALL dieharder tests! Here *nix sys-rand() e.g. fails miserably:-)
** ~12 times faster than my *nix sys-rand()
** ~4 times faster than SSE2-version of Mersenne twister
** Average cycle length: ~2^126
** 64 bit seed
** Return doubles with a full 53 bit mantissa
** Thread safe
*/
#if !defined(RKISS_H_INCLUDED)
#define RKISS_H_INCLUDED
#include "types.h"
class RKISS {
// Keep variables always together
struct S { uint64_t a, b, c, d; } s;
uint64_t rotate(uint64_t x, uint64_t k) const {
return (x << k) | (x >> (64 - k));
}
// Return 64 bit unsigned integer in between [0, 2^64 - 1]
uint64_t rand64() {
const uint64_t
e = s.a - rotate(s.b, 7);
s.a = s.b ^ rotate(s.c, 13);
s.b = s.c + rotate(s.d, 37);
s.c = s.d + e;
return s.d = e + s.a;
}
// Init seed and scramble a few rounds
void raninit() {
s.a = 0xf1ea5eed;
s.b = s.c = s.d = 0xd4e12c77;
for (int i = 0; i < 73; i++)
rand64();
}
public:
RKISS() { raninit(); }
template<typename T> T rand() { return T(rand64()); }
};
#endif // !defined(RKISS_H_INCLUDED)
-436
View File
@@ -1,436 +0,0 @@
/*
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 <cassert>
#include <cstring>
#include <iomanip>
#include <string>
#include <sstream>
#include "history.h"
#include "movepick.h"
#include "san.h"
using std::string;
////
//// Local definitions
////
namespace {
enum Ambiguity {
AMBIGUITY_NONE,
AMBIGUITY_FILE,
AMBIGUITY_RANK,
AMBIGUITY_BOTH
};
const History H; // used as dummy argument for MovePicker c'tor
Ambiguity move_ambiguity(const Position& pos, Move m);
const string time_string(int milliseconds);
const string score_string(Value v);
}
////
//// Functions
////
/// 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
/// a string containing the move in short algebraic notation.
const string move_to_san(const Position& pos, Move m) {
assert(pos.is_ok());
assert(move_is_ok(m));
Square from, to;
PieceType pt;
from = move_from(m);
to = move_to(m);
pt = type_of_piece(pos.piece_on(move_from(m)));
string san = "";
if (m == MOVE_NONE)
return "(none)";
else if (m == MOVE_NULL)
return "(null)";
else if (move_is_long_castle(m) || (int(to - from) == -2 && pt == KING))
san = "O-O-O";
else if (move_is_short_castle(m) || (int(to - from) == 2 && pt == KING))
san = "O-O";
else
{
if (pt != PAWN)
{
san += piece_type_to_char(pt, true);
switch (move_ambiguity(pos, m)) {
case AMBIGUITY_NONE:
break;
case AMBIGUITY_FILE:
san += file_to_char(square_file(from));
break;
case AMBIGUITY_RANK:
san += rank_to_char(square_rank(from));
break;
case AMBIGUITY_BOTH:
san += square_to_string(from);
break;
default:
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);
}
}
// Is the move check? We don't use pos.move_is_check(m) here, because
// Position::move_is_check doesn't detect all checks (not castling moves,
// promotions and en passant captures).
StateInfo st;
Position p(pos);
p.do_move(m, st);
if (p.is_check())
san += p.is_mate()? "#" : "+";
return san;
}
/// 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,
/// the move is returned. On failure (i.e. if the string is unparsable, or
/// if the move is illegal or ambiguous), MOVE_NONE is returned.
Move move_from_san(const Position& pos, const string& movestr) {
assert(pos.is_ok());
MovePicker mp = MovePicker(pos, MOVE_NONE, OnePly, H);
Bitboard pinned = pos.pinned_pieces(pos.side_to_move());
// Castling moves
if (movestr == "O-O-O" || movestr == "O-O-O+")
{
Move m;
while ((m = mp.get_next_move()) != MOVE_NONE)
if (move_is_long_castle(m) && pos.pl_move_is_legal(m, pinned))
return m;
return MOVE_NONE;
}
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, pinned))
return m;
return MOVE_NONE;
}
// 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;
to = make_square(toFile, toRank);
int matches = 0;
while ((m = mp.get_next_move()) != MOVE_NONE)
if ( pos.type_of_piece_on(move_from(m)) == pt
&& move_to(m) == to
&& move_promotion_piece(m) == promotion
&& (fromFile == FILE_NONE || fromFile == square_file(move_from(m)))
&& (fromRank == RANK_NONE || fromRank == square_rank(move_from(m))))
{
move = m;
matches++;
}
return (matches == 1 ? move : MOVE_NONE);
}
/// line_to_san() takes a position and a line (an array of moves representing
/// a sequence of legal moves from the position) as input, and returns a
/// string containing the line in short algebraic notation. If the boolean
/// parameter 'breakLines' is true, line breaks are inserted, with a line
/// length of 80 characters. After a line break, 'startColumn' spaces are
/// inserted at the beginning of the new line.
const string line_to_san(const Position& pos, Move line[], int startColumn, bool breakLines) {
StateInfo st;
std::stringstream s;
string moveStr;
size_t length = 0;
size_t maxLength = 80 - startColumn;
Position p(pos);
for (int i = 0; line[i] != MOVE_NONE; i++)
{
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 << ' ';
if (line[i] == MOVE_NULL)
p.do_null_move(st);
else
p.do_move(line[i], st);
}
return s.str();
}
/// pretty_pv() creates a human-readable string from a position and a PV.
/// It is used to write search information to the log file (which is created
/// when the UCI parameter "Use Search Log" is "true").
const string pretty_pv(const Position& pos, int time, int depth,
uint64_t nodes, Value score, ValueType type, Move pv[]) {
std::stringstream s;
// Depth
s << std::setw(2) << depth << " ";
// Score
s << ((type == VALUE_TYPE_LOWER)? ">" : ((type == VALUE_TYPE_UPPER)? "<" : " "));
s << std::setw(7) << score_string(score);
// Time
s << std::setw(8) << time_string(time) << " ";
// Nodes
if (nodes < 1000000ULL)
s << std::setw(8) << nodes << " ";
else if (nodes < 1000000000ULL)
s << std::setw(7) << nodes/1000ULL << 'k' << " ";
else
s << std::setw(7) << nodes/1000000ULL << 'M' << " ";
// PV
s << line_to_san(pos, pv, 30, true);
return s.str();
}
namespace {
Ambiguity move_ambiguity(const Position& pos, Move m) {
Square from = move_from(m);
Square to = move_to(m);
Piece pc = pos.piece_on(from);
// King moves are never ambiguous, because there is never two kings of
// the same color.
if (type_of_piece(pc) == KING)
return AMBIGUITY_NONE;
MovePicker mp = MovePicker(pos, MOVE_NONE, OnePly, H);
Bitboard pinned = pos.pinned_pieces(pos.side_to_move());
Move mv, moveList[8];
int n = 0;
while ((mv = mp.get_next_move()) != MOVE_NONE)
if (move_to(mv) == to && pos.piece_on(move_from(mv)) == pc && pos.pl_move_is_legal(mv, pinned))
moveList[n++] = mv;
if (n == 1)
return AMBIGUITY_NONE;
int f = 0, r = 0;
for (int i = 0; i < n; i++)
{
if (square_file(move_from(moveList[i])) == square_file(from))
f++;
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;
}
const string time_string(int milliseconds) {
std::stringstream s;
s << std::setfill('0');
int hours = milliseconds / (1000*60*60);
int minutes = (milliseconds - hours*1000*60*60) / (1000*60);
int seconds = (milliseconds - hours*1000*60*60 - minutes*1000*60) / 1000;
if (hours)
s << hours << ':';
s << std::setw(2) << minutes << ':' << std::setw(2) << seconds;
return s.str();
}
const string score_string(Value v) {
std::stringstream s;
if (v >= VALUE_MATE - 200)
s << "#" << (VALUE_MATE - v + 1) / 2;
else if(v <= -VALUE_MATE + 200)
s << "-#" << (VALUE_MATE + v) / 2;
else
{
float floatScore = float(v) / float(PawnValueMidgame);
if (v >= 0)
s << '+';
s << std::setprecision(2) << std::fixed << floatScore;
}
return s.str();
}
}
-44
View File
@@ -1,44 +0,0 @@
/*
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(SAN_H_INCLUDED)
#define SAN_H_INCLUDED
////
//// Includes
////
#include <string>
#include "move.h"
#include "position.h"
#include "value.h"
////
//// Prototypes
////
extern const std::string move_to_san(const Position& pos, Move m);
extern Move move_from_san(const Position& pos, const std::string& str);
extern const std::string line_to_san(const Position& pos, Move line[], int startColumn, bool breakLines);
extern const std::string pretty_pv(const Position& pos, int time, int depth, uint64_t nodes, Value score, ValueType type, Move pv[]);
#endif // !defined(SAN_H_INCLUDED)
-52
View File
@@ -1,52 +0,0 @@
/*
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(SCALE_H_INCLUDED)
#define SCALE_H_INCLUDED
////
//// Includes
////
#include "value.h"
////
//// Types
////
enum ScaleFactor {
SCALE_FACTOR_ZERO = 0,
SCALE_FACTOR_NORMAL = 64,
SCALE_FACTOR_MAX = 128,
SCALE_FACTOR_NONE = 255
};
////
//// Inline functions
////
inline Value apply_scale_factor(Value v, ScaleFactor f) {
return Value((v * f) / int(SCALE_FACTOR_NORMAL));
}
#endif // !defined(SCALE_H_INCLUDED)
+1598 -2482
View File
File diff suppressed because it is too large Load Diff
+32 -35
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,30 +17,16 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined(SEARCH_H_INCLUDED)
#define SEARCH_H_INCLUDED
////
//// Includes
////
#include <cstring>
#include "depth.h"
#include "move.h"
#include "types.h"
////
//// Constants
////
const int PLY_MAX = 100;
const int PLY_MAX_PLUS_2 = 102;
const int KILLER_MAX = 2;
////
//// Types
////
class Position;
struct SplitPoint;
/// The SearchStack struct keeps track of the information we need to remember
/// from nodes shallower and deeper in the tree during the search. Each
@@ -48,29 +34,40 @@ const int KILLER_MAX = 2;
/// current ply.
struct SearchStack {
Move pv[PLY_MAX_PLUS_2];
int ply;
Move currentMove;
Move mateKiller;
Move threatMove;
Move killers[KILLER_MAX];
Move excludedMove;
Move bestMove;
Move killers[2];
Depth reduction;
void init(int ply);
void initKillers();
Value eval;
Value evalMargin;
bool skipNullMove;
SplitPoint* sp;
};
////
//// Prototypes
////
/// The SearchLimits struct stores information sent by GUI about available time
/// to search the current move, maximum depth/time, if we are in analysis mode
/// or if we have to ponder while is our opponent's side to move.
extern void init_threads();
extern void stop_threads();
extern bool think(const Position &pos, bool infinite, bool ponder, int side_to_move,
int time[], int increment[], int movesToGo, int maxDepth,
int maxNodes, int maxTime, Move searchMoves[]);
extern int perft(Position &pos, Depth depth);
extern int64_t nodes_searched();
struct SearchLimits {
SearchLimits() { memset(this, 0, sizeof(SearchLimits)); }
SearchLimits(int t, int i, int mtg, int mt, int md, int mn, bool inf, bool pon)
: time(t), increment(i), movesToGo(mtg), maxTime(mt), maxDepth(md),
maxNodes(mn), infinite(inf), ponder(pon) {}
bool useTimeManagement() const { return !(maxTime | maxDepth | maxNodes | int(infinite)); }
int time, increment, movesToGo, maxTime, maxDepth, maxNodes;
bool infinite, ponder;
};
extern void init_search();
extern int64_t perft(Position& pos, Depth depth);
extern bool think(Position& pos, const SearchLimits& limits, Move searchMoves[]);
#endif // !defined(SEARCH_H_INCLUDED)
-201
View File
@@ -1,201 +0,0 @@
/*
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(SQUARE_H_INCLUDED)
#define SQUARE_H_INCLUDED
////
//// Includes
////
#include <cstdlib> // for abs()
#include <string>
#include "color.h"
#include "misc.h"
////
//// Types
////
enum Square {
SQ_A1, SQ_B1, SQ_C1, SQ_D1, SQ_E1, SQ_F1, SQ_G1, SQ_H1,
SQ_A2, SQ_B2, SQ_C2, SQ_D2, SQ_E2, SQ_F2, SQ_G2, SQ_H2,
SQ_A3, SQ_B3, SQ_C3, SQ_D3, SQ_E3, SQ_F3, SQ_G3, SQ_H3,
SQ_A4, SQ_B4, SQ_C4, SQ_D4, SQ_E4, SQ_F4, SQ_G4, SQ_H4,
SQ_A5, SQ_B5, SQ_C5, SQ_D5, SQ_E5, SQ_F5, SQ_G5, SQ_H5,
SQ_A6, SQ_B6, SQ_C6, SQ_D6, SQ_E6, SQ_F6, SQ_G6, SQ_H6,
SQ_A7, SQ_B7, SQ_C7, SQ_D7, SQ_E7, SQ_F7, SQ_G7, SQ_H7,
SQ_A8, SQ_B8, SQ_C8, SQ_D8, SQ_E8, SQ_F8, SQ_G8, SQ_H8,
SQ_NONE
};
enum File {
FILE_A, FILE_B, FILE_C, FILE_D, FILE_E, FILE_F, FILE_G, FILE_H, FILE_NONE
};
enum Rank {
RANK_1, RANK_2, RANK_3, RANK_4, RANK_5, RANK_6, RANK_7, RANK_8, RANK_NONE
};
enum SquareDelta {
DELTA_SSW = -021, DELTA_SS = -020, DELTA_SSE = -017, DELTA_SWW = -012,
DELTA_SW = -011, DELTA_S = -010, DELTA_SE = -07, DELTA_SEE = -06,
DELTA_W = -01, DELTA_ZERO = 0, DELTA_E = 01, DELTA_NWW = 06, DELTA_NW = 07,
DELTA_N = 010, DELTA_NE = 011, DELTA_NEE = 012, DELTA_NNW = 017,
DELTA_NN = 020, DELTA_NNE = 021
};
////
//// Constants
////
const int FlipMask = 070;
const int FlopMask = 07;
////
//// Inline functions
////
inline File operator+ (File x, int i) { return File(int(x) + i); }
inline File operator+ (File x, File y) { return x + int(y); }
inline void operator++ (File &x, int) { x = File(int(x) + 1); }
inline void operator+= (File &x, int i) { x = File(int(x) + i); }
inline File operator- (File x, int i) { return File(int(x) - i); }
inline void operator-- (File &x, int) { x = File(int(x) - 1); }
inline void operator-= (File &x, int i) { x = File(int(x) - i); }
inline Rank operator+ (Rank x, int i) { return Rank(int(x) + i); }
inline Rank operator+ (Rank x, Rank y) { return x + int(y); }
inline void operator++ (Rank &x, int) { x = Rank(int(x) + 1); }
inline void operator+= (Rank &x, int i) { x = Rank(int(x) + i); }
inline Rank operator- (Rank x, int i) { return Rank(int(x) - i); }
inline void operator-- (Rank &x, int) { x = Rank(int(x) - 1); }
inline void operator-= (Rank &x, int i) { x = Rank(int(x) - i); }
inline Square operator+ (Square x, int i) { return Square(int(x) + i); }
inline void operator++ (Square &x, int) { x = Square(int(x) + 1); }
inline void operator+= (Square &x, int i) { x = Square(int(x) + i); }
inline Square operator- (Square x, int i) { return Square(int(x) - i); }
inline void operator-- (Square &x, int) { x = Square(int(x) - 1); }
inline void operator-= (Square &x, int i) { x = Square(int(x) - i); }
inline Square operator+ (Square x, SquareDelta i) { return Square(int(x) + i); }
inline void operator+= (Square &x, SquareDelta i) { x = Square(int(x) + i); }
inline Square operator- (Square x, SquareDelta i) { return Square(int(x) - i); }
inline void operator-= (Square &x, SquareDelta i) { x = Square(int(x) - i); }
inline SquareDelta operator- (Square x, Square y) {
return SquareDelta(int(x) - int(y));
}
inline Square make_square(File f, Rank r) {
return Square(int(f) | (int(r) << 3));
}
inline File square_file(Square s) {
return File(int(s) & 7);
}
inline Rank square_rank(Square s) {
return Rank(int(s) >> 3);
}
inline Square flip_square(Square s) {
return Square(int(s) ^ FlipMask);
}
inline Square flop_square(Square s) {
return Square(int(s) ^ FlopMask);
}
inline Square relative_square(Color c, Square s) {
return Square(int(s) ^ (int(c) * FlipMask));
}
inline Rank relative_rank(Color c, Square s) {
return square_rank(relative_square(c, s));
}
inline Color square_color(Square s) {
return Color((int(square_file(s)) + int(square_rank(s))) & 1);
}
inline int file_distance(File f1, File f2) {
return abs(int(f1) - int(f2));
}
inline int file_distance(Square s1, Square s2) {
return file_distance(square_file(s1), square_file(s2));
}
inline int rank_distance(Rank r1, Rank r2) {
return abs(int(r1) - int(r2));
}
inline int rank_distance(Square s1, Square s2) {
return rank_distance(square_rank(s1), square_rank(s2));
}
inline int square_distance(Square s1, Square 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) {
return char(f - FILE_A + int('a'));
}
inline Rank rank_from_char(char c) {
return Rank(c - '1') + RANK_1;
}
inline char rank_to_char(Rank r) {
return char(r - RANK_1 + int('1'));
}
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)
+345
View File
@@ -0,0 +1,345 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Stockfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <iostream>
#include "thread.h"
#include "ucioption.h"
ThreadsManager Threads; // Global object definition
namespace { extern "C" {
// start_routine() is the C function which is called when a new thread
// is launched. It simply calls idle_loop() with the supplied threadID.
// There are two versions of this function; one for POSIX threads and
// one for Windows threads.
#if defined(_MSC_VER)
DWORD WINAPI start_routine(LPVOID threadID) {
Threads.idle_loop(*(int*)threadID, NULL);
return 0;
}
#else
void* start_routine(void* threadID) {
Threads.idle_loop(*(int*)threadID, NULL);
return NULL;
}
#endif
} }
// wake_up() wakes up the thread, normally at the beginning of the search or,
// if "sleeping threads" is used, when there is some work to do.
void Thread::wake_up() {
lock_grab(&sleepLock);
cond_signal(&sleepCond);
lock_release(&sleepLock);
}
// cutoff_occurred() checks whether a beta cutoff has occurred in
// the thread's currently active split point, or in some ancestor of
// the current split point.
bool Thread::cutoff_occurred() const {
for (SplitPoint* sp = splitPoint; sp; sp = sp->parent)
if (sp->is_betaCutoff)
return true;
return false;
}
// is_available_to() checks whether the thread is available to help the thread with
// threadID "master" at a split point. An obvious requirement is that thread must be
// idle. With more than two threads, this is not by itself sufficient: If the thread
// is the master of some active split point, it is only available as a slave to the
// threads which are busy searching the split point at the top of "slave"'s split
// point stack (the "helpful master concept" in YBWC terminology).
bool Thread::is_available_to(int master) const {
if (state != AVAILABLE)
return false;
// Make a local copy to be sure doesn't become zero under our feet while
// testing next condition and so leading to an out of bound access.
int localActiveSplitPoints = activeSplitPoints;
// No active split points means that the thread is available as a slave for any
// other thread otherwise apply the "helpful master" concept if possible.
if ( !localActiveSplitPoints
|| splitPoints[localActiveSplitPoints - 1].is_slave[master])
return true;
return false;
}
// read_uci_options() updates number of active threads and other internal
// parameters according to the UCI options values. It is called before
// to start a new search.
void ThreadsManager::read_uci_options() {
maxThreadsPerSplitPoint = Options["Maximum Number of Threads per Split Point"].value<int>();
minimumSplitDepth = Options["Minimum Split Depth"].value<int>() * ONE_PLY;
useSleepingThreads = Options["Use Sleeping Threads"].value<bool>();
activeThreads = Options["Threads"].value<int>();
}
// init() is called during startup. Initializes locks and condition variables
// and launches all threads sending them immediately to sleep.
void ThreadsManager::init() {
int threadID[MAX_THREADS];
// This flag is needed to properly end the threads when program exits
allThreadsShouldExit = false;
// Threads will sent to sleep as soon as created, only main thread is kept alive
activeThreads = 1;
threads[0].state = Thread::SEARCHING;
// Allocate pawn and material hash tables for main thread
init_hash_tables();
lock_init(&mpLock);
// Initialize thread and split point locks
for (int i = 0; i < MAX_THREADS; i++)
{
lock_init(&threads[i].sleepLock);
cond_init(&threads[i].sleepCond);
for (int j = 0; j < MAX_ACTIVE_SPLIT_POINTS; j++)
lock_init(&(threads[i].splitPoints[j].lock));
}
// Create and startup all the threads but the main that is already running
for (int i = 1; i < MAX_THREADS; i++)
{
threads[i].state = Thread::INITIALIZING;
threadID[i] = i;
#if defined(_MSC_VER)
bool ok = (CreateThread(NULL, 0, start_routine, (LPVOID)&threadID[i], 0, NULL) != NULL);
#else
pthread_t pthreadID;
bool ok = (pthread_create(&pthreadID, NULL, start_routine, (void*)&threadID[i]) == 0);
pthread_detach(pthreadID);
#endif
if (!ok)
{
std::cout << "Failed to create thread number " << i << std::endl;
::exit(EXIT_FAILURE);
}
// Wait until the thread has finished launching and is gone to sleep
while (threads[i].state == Thread::INITIALIZING) {}
}
}
// exit() is called to cleanly exit the threads when the program finishes
void ThreadsManager::exit() {
// Force the woken up threads to exit idle_loop() and hence terminate
allThreadsShouldExit = true;
for (int i = 0; i < MAX_THREADS; i++)
{
// Wake up all the threads and waits for termination
if (i != 0)
{
threads[i].wake_up();
while (threads[i].state != Thread::TERMINATED) {}
}
// Now we can safely destroy the locks and wait conditions
lock_destroy(&threads[i].sleepLock);
cond_destroy(&threads[i].sleepCond);
for (int j = 0; j < MAX_ACTIVE_SPLIT_POINTS; j++)
lock_destroy(&(threads[i].splitPoints[j].lock));
}
lock_destroy(&mpLock);
}
// init_hash_tables() dynamically allocates pawn and material hash tables
// according to the number of active threads. This avoids preallocating
// memory for all possible threads if only few are used as, for instance,
// on mobile devices where memory is scarce and allocating for MAX_THREADS
// threads could even result in a crash.
void ThreadsManager::init_hash_tables() {
for (int i = 0; i < activeThreads; i++)
{
threads[i].pawnTable.init();
threads[i].materialTable.init();
}
}
// available_slave_exists() tries to find an idle thread which is available as
// a slave for the thread with threadID "master".
bool ThreadsManager::available_slave_exists(int master) const {
assert(master >= 0 && master < activeThreads);
for (int i = 0; i < activeThreads; i++)
if (i != master && threads[i].is_available_to(master))
return true;
return false;
}
// split() does the actual work of distributing the work at a node between
// several available threads. If it does not succeed in splitting the
// node (because no idle threads are available, or because we have no unused
// split point objects), the function immediately returns. If splitting is
// possible, a SplitPoint object is initialized with all the data that must be
// copied to the helper threads and we tell our helper threads that they have
// been assigned work. This will cause them to instantly leave their idle loops and
// call search().When all threads have returned from search() then split() returns.
template <bool Fake>
void ThreadsManager::split(Position& pos, SearchStack* ss, Value* alpha, const Value beta,
Value* bestValue, Depth depth, Move threatMove,
int moveCount, MovePicker* mp, bool pvNode) {
assert(pos.is_ok());
assert(*bestValue >= -VALUE_INFINITE);
assert(*bestValue <= *alpha);
assert(*alpha < beta);
assert(beta <= VALUE_INFINITE);
assert(depth > DEPTH_ZERO);
assert(pos.thread() >= 0 && pos.thread() < activeThreads);
assert(activeThreads > 1);
int i, master = pos.thread();
Thread& masterThread = threads[master];
lock_grab(&mpLock);
// If no other thread is available to help us, or if we have too many
// active split points, don't split.
if ( !available_slave_exists(master)
|| masterThread.activeSplitPoints >= MAX_ACTIVE_SPLIT_POINTS)
{
lock_release(&mpLock);
return;
}
// Pick the next available split point object from the split point stack
SplitPoint& splitPoint = masterThread.splitPoints[masterThread.activeSplitPoints++];
// Initialize the split point object
splitPoint.parent = masterThread.splitPoint;
splitPoint.master = master;
splitPoint.is_betaCutoff = false;
splitPoint.depth = depth;
splitPoint.threatMove = threatMove;
splitPoint.alpha = *alpha;
splitPoint.beta = beta;
splitPoint.pvNode = pvNode;
splitPoint.bestValue = *bestValue;
splitPoint.mp = mp;
splitPoint.moveCount = moveCount;
splitPoint.pos = &pos;
splitPoint.nodes = 0;
splitPoint.ss = ss;
for (i = 0; i < activeThreads; i++)
splitPoint.is_slave[i] = false;
masterThread.splitPoint = &splitPoint;
// If we are here it means we are not available
assert(masterThread.state != Thread::AVAILABLE);
int workersCnt = 1; // At least the master is included
// Allocate available threads setting state to THREAD_BOOKED
for (i = 0; !Fake && i < activeThreads && workersCnt < maxThreadsPerSplitPoint; i++)
if (i != master && threads[i].is_available_to(master))
{
threads[i].state = Thread::BOOKED;
threads[i].splitPoint = &splitPoint;
splitPoint.is_slave[i] = true;
workersCnt++;
}
assert(Fake || workersCnt > 1);
// We can release the lock because slave threads are already booked and master is not available
lock_release(&mpLock);
// Tell the threads that they have work to do. This will make them leave
// their idle loop.
for (i = 0; i < activeThreads; i++)
if (i == master || splitPoint.is_slave[i])
{
assert(i == master || threads[i].state == Thread::BOOKED);
threads[i].state = Thread::WORKISWAITING; // This makes the slave to exit from idle_loop()
if (useSleepingThreads && i != master)
threads[i].wake_up();
}
// Everything is set up. The master thread enters the idle loop, from
// which it will instantly launch a search, because its state is
// THREAD_WORKISWAITING. We send the split point as a second parameter to the
// idle loop, which means that the main thread will return from the idle
// loop when all threads have finished their work at this split point.
idle_loop(master, &splitPoint);
// We have returned from the idle loop, which means that all threads are
// finished. Update alpha and bestValue, and return.
lock_grab(&mpLock);
*alpha = splitPoint.alpha;
*bestValue = splitPoint.bestValue;
masterThread.activeSplitPoints--;
masterThread.splitPoint = splitPoint.parent;
pos.set_nodes_searched(pos.nodes_searched() + splitPoint.nodes);
lock_release(&mpLock);
}
// Explicit template instantiations
template void ThreadsManager::split<false>(Position&, SearchStack*, Value*, const Value, Value*, Depth, Move, int, MovePicker*, bool);
template void ThreadsManager::split<true>(Position&, SearchStack*, Value*, const Value, Value*, Depth, Move, int, MovePicker*, bool);
+92 -40
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,64 +17,116 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined(THREAD_H_INCLUDED)
#define THREAD_H_INCLUDED
////
//// Includes
////
#include <cstring>
#include "lock.h"
#include "material.h"
#include "movepick.h"
#include "pawns.h"
#include "position.h"
#include "search.h"
////
//// Constants and variables
////
const int THREAD_MAX = 8;
////
//// Types
////
const int MAX_THREADS = 32;
const int MAX_ACTIVE_SPLIT_POINTS = 8;
struct SplitPoint {
SplitPoint *parent;
Position pos;
SearchStack sstack[THREAD_MAX][PLY_MAX_PLUS_2];
SearchStack *parentSstack;
int ply;
// Const data after splitPoint has been setup
SplitPoint* parent;
const Position* pos;
Depth depth;
volatile Value alpha, beta, bestValue, futilityValue;
Value approximateEval;
bool pvNode;
int master, slaves[THREAD_MAX];
Value beta;
int ply;
int master;
Move threatMove;
// Const pointers to shared data
MovePicker* mp;
SearchStack* ss;
// Shared data
Lock lock;
MovePicker *mp;
volatile int moves;
volatile int cpus;
bool finished;
volatile int64_t nodes;
volatile Value alpha;
volatile Value bestValue;
volatile int moveCount;
volatile bool is_betaCutoff;
volatile bool is_slave[MAX_THREADS];
};
/// Thread struct is used to keep together all the thread related stuff like locks,
/// state and especially split points. We also use per-thread pawn and material hash
/// tables so that once we get a pointer to an entry its life time is unlimited and
/// we don't have to care about someone changing the entry under our feet.
struct Thread {
SplitPoint *splitPoint;
enum ThreadState
{
INITIALIZING, // Thread is initializing itself
SEARCHING, // Thread is performing work
AVAILABLE, // Thread is waiting for work
BOOKED, // Other thread (master) has booked us as a slave
WORKISWAITING, // Master has ordered us to start
TERMINATED // We are quitting and thread is terminated
};
void wake_up();
bool cutoff_occurred() const;
bool is_available_to(int master) const;
MaterialInfoTable materialTable;
PawnInfoTable pawnTable;
int maxPly;
Lock sleepLock;
WaitCondition sleepCond;
volatile ThreadState state;
SplitPoint* volatile splitPoint;
volatile int activeSplitPoints;
uint64_t nodes;
uint64_t betaCutOffs[2];
bool failHighPly1;
volatile bool stop;
volatile bool running;
volatile bool idle;
volatile bool workIsWaiting;
volatile bool printCurrentLine;
unsigned char pad[64]; // set some distance among local data for each thread
SplitPoint splitPoints[MAX_ACTIVE_SPLIT_POINTS];
};
/// ThreadsManager class is used to handle all the threads related stuff like init,
/// starting, parking and, the most important, launching a slave thread at a split
/// point. All the access to shared thread data is done through this class.
class ThreadsManager {
/* As long as the single ThreadsManager object is defined as a global we don't
need to explicitly initialize to zero its data members because variables with
static storage duration are automatically set to zero before enter main()
*/
public:
Thread& operator[](int threadID) { return threads[threadID]; }
void init();
void exit();
void init_hash_tables();
int min_split_depth() const { return minimumSplitDepth; }
int size() const { return activeThreads; }
void set_size(int cnt) { activeThreads = cnt; }
void read_uci_options();
bool available_slave_exists(int master) const;
void idle_loop(int threadID, SplitPoint* sp);
template <bool Fake>
void split(Position& pos, SearchStack* ss, Value* alpha, const Value beta, Value* bestValue,
Depth depth, Move threatMove, int moveCount, MovePicker* mp, bool pvNode);
private:
Lock mpLock;
Depth minimumSplitDepth;
int maxThreadsPerSplitPoint;
bool useSleepingThreads;
int activeThreads;
volatile bool allThreadsShouldExit;
Thread threads[MAX_THREADS];
};
extern ThreadsManager Threads;
#endif // !defined(THREAD_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-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Stockfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <cmath>
#include "misc.h"
#include "search.h"
#include "timeman.h"
#include "ucioption.h"
namespace {
/// Constants
const int MoveHorizon = 50; // Plan time management at most this many moves ahead
const float MaxRatio = 3.0f; // When in trouble, we can step over reserved time with this ratio
const float StealRatio = 0.33f; // However we must not steal time from remaining moves over this ratio
// MoveImportance[] is based on naive statistical analysis of "how many games are still undecided
// after n half-moves". Game is considered "undecided" as long as neither side has >275cp advantage.
// Data was extracted from CCRL game database with some simple filtering criteria.
const int MoveImportance[512] = {
7780, 7780, 7780, 7780, 7780, 7780, 7780, 7780, 7780, 7780, 7780, 7780, 7780, 7780, 7780, 7780,
7780, 7780, 7780, 7780, 7778, 7778, 7776, 7776, 7776, 7773, 7770, 7768, 7766, 7763, 7757, 7751,
7743, 7735, 7724, 7713, 7696, 7689, 7670, 7656, 7627, 7605, 7571, 7549, 7522, 7493, 7462, 7425,
7385, 7350, 7308, 7272, 7230, 7180, 7139, 7094, 7055, 7010, 6959, 6902, 6841, 6778, 6705, 6651,
6569, 6508, 6435, 6378, 6323, 6253, 6152, 6085, 5995, 5931, 5859, 5794, 5717, 5646, 5544, 5462,
5364, 5282, 5172, 5078, 4988, 4901, 4831, 4764, 4688, 4609, 4536, 4443, 4365, 4293, 4225, 4155,
4085, 4005, 3927, 3844, 3765, 3693, 3634, 3560, 3479, 3404, 3331, 3268, 3207, 3146, 3077, 3011,
2947, 2894, 2828, 2776, 2727, 2676, 2626, 2589, 2538, 2490, 2442, 2394, 2345, 2302, 2243, 2192,
2156, 2115, 2078, 2043, 2004, 1967, 1922, 1893, 1845, 1809, 1772, 1736, 1702, 1674, 1640, 1605,
1566, 1536, 1509, 1479, 1452, 1423, 1388, 1362, 1332, 1304, 1289, 1266, 1250, 1228, 1206, 1180,
1160, 1134, 1118, 1100, 1080, 1068, 1051, 1034, 1012, 1001, 980, 960, 945, 934, 916, 900, 888,
878, 865, 852, 828, 807, 787, 770, 753, 744, 731, 722, 706, 700, 683, 676, 671, 664, 652, 641,
634, 627, 613, 604, 591, 582, 568, 560, 552, 540, 534, 529, 519, 509, 495, 484, 474, 467, 460,
450, 438, 427, 419, 410, 406, 399, 394, 387, 382, 377, 372, 366, 359, 353, 348, 343, 337, 333,
328, 321, 315, 309, 303, 298, 293, 287, 284, 281, 277, 273, 265, 261, 255, 251, 247, 241, 240,
235, 229, 218, 217, 213, 212, 208, 206, 197, 193, 191, 189, 185, 184, 180, 177, 172, 170, 170,
170, 166, 163, 159, 158, 156, 155, 151, 146, 141, 138, 136, 132, 130, 128, 125, 123, 122, 118,
118, 118, 117, 115, 114, 108, 107, 105, 105, 105, 102, 97, 97, 95, 94, 93, 91, 88, 86, 83, 80,
80, 79, 79, 79, 78, 76, 75, 72, 72, 71, 70, 68, 65, 63, 61, 61, 59, 59, 59, 58, 56, 55, 54, 54,
52, 49, 48, 48, 48, 48, 45, 45, 45, 44, 43, 41, 41, 41, 41, 40, 40, 38, 37, 36, 34, 34, 34, 33,
31, 29, 29, 29, 28, 28, 28, 28, 28, 28, 28, 27, 27, 27, 27, 27, 24, 24, 23, 23, 22, 21, 20, 20,
19, 19, 19, 19, 19, 18, 18, 18, 18, 17, 17, 17, 17, 17, 16, 16, 15, 15, 14, 14, 14, 12, 12, 11,
9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 2, 2, 2, 2,
2, 1, 1, 1, 1, 1, 1, 1 };
int move_importance(int ply) { return MoveImportance[Min(ply, 511)]; }
/// Function Prototypes
enum TimeType { OptimumTime, MaxTime };
template<TimeType>
int remaining(int myTime, int movesToGo, int currentPly);
}
void TimeManager::pv_instability(int curChanges, int prevChanges) {
unstablePVExtraTime = curChanges * (optimumSearchTime / 2)
+ prevChanges * (optimumSearchTime / 3);
}
void TimeManager::init(const SearchLimits& limits, int currentPly)
{
/* We support four different kind of time controls:
increment == 0 && movesToGo == 0 means: x basetime [sudden death!]
increment == 0 && movesToGo != 0 means: x moves in y minutes
increment > 0 && movesToGo == 0 means: x basetime + z increment
increment > 0 && movesToGo != 0 means: x moves in y minutes + z increment
Time management is adjusted by following UCI parameters:
emergencyMoveHorizon: Be prepared to always play at least this many moves
emergencyBaseTime : Always attempt to keep at least this much time (in ms) at clock
emergencyMoveTime : Plus attempt to keep at least this much time for each remaining emergency move
minThinkingTime : No matter what, use at least this much thinking before doing the move
*/
int hypMTG, hypMyTime, t1, t2;
// Read uci parameters
int emergencyMoveHorizon = Options["Emergency Move Horizon"].value<int>();
int emergencyBaseTime = Options["Emergency Base Time"].value<int>();
int emergencyMoveTime = Options["Emergency Move Time"].value<int>();
int minThinkingTime = Options["Minimum Thinking Time"].value<int>();
// Initialize to maximum values but unstablePVExtraTime that is reset
unstablePVExtraTime = 0;
optimumSearchTime = maximumSearchTime = limits.time;
// We calculate optimum time usage for different hypothetic "moves to go"-values and choose the
// minimum of calculated search time values. Usually the greatest hypMTG gives the minimum values.
for (hypMTG = 1; hypMTG <= (limits.movesToGo ? Min(limits.movesToGo, MoveHorizon) : MoveHorizon); hypMTG++)
{
// Calculate thinking time for hypothetic "moves to go"-value
hypMyTime = limits.time
+ limits.increment * (hypMTG - 1)
- emergencyBaseTime
- emergencyMoveTime * Min(hypMTG, emergencyMoveHorizon);
hypMyTime = Max(hypMyTime, 0);
t1 = minThinkingTime + remaining<OptimumTime>(hypMyTime, hypMTG, currentPly);
t2 = minThinkingTime + remaining<MaxTime>(hypMyTime, hypMTG, currentPly);
optimumSearchTime = Min(optimumSearchTime, t1);
maximumSearchTime = Min(maximumSearchTime, t2);
}
if (Options["Ponder"].value<bool>())
optimumSearchTime += optimumSearchTime / 4;
// Make sure that maxSearchTime is not over absoluteMaxSearchTime
optimumSearchTime = Min(optimumSearchTime, maximumSearchTime);
}
namespace {
template<TimeType T>
int remaining(int myTime, int movesToGo, int currentPly)
{
const float TMaxRatio = (T == OptimumTime ? 1 : MaxRatio);
const float TStealRatio = (T == OptimumTime ? 0 : StealRatio);
int thisMoveImportance = move_importance(currentPly);
int otherMovesImportance = 0;
for (int i = 1; i < movesToGo; i++)
otherMovesImportance += move_importance(currentPly + 2 * i);
float ratio1 = (TMaxRatio * thisMoveImportance) / float(TMaxRatio * thisMoveImportance + otherMovesImportance);
float ratio2 = (thisMoveImportance + TStealRatio * otherMovesImportance) / float(thisMoveImportance + otherMovesImportance);
return int(floor(myTime * Min(ratio1, ratio2)));
}
}
+16 -16
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,23 +17,23 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined(TIMEMAN_H_INCLUDED)
#define TIMEMAN_H_INCLUDED
#if !defined(APPLICATION_H_INCLUDED)
#define APPLICATION_H_INCLUDED
/// Singleton class used to housekeep memory and global resources
/// so to be sure we always leave in a clean state.
class Application {
Application();
Application(const Application&);
~Application();
struct SearchLimits;
class TimeManager {
public:
static void initialize();
static void exit_with_failure();
void init(const SearchLimits& limits, int currentPly);
void pv_instability(int curChanges, int prevChanges);
int available_time() const { return optimumSearchTime + unstablePVExtraTime; }
int maximum_time() const { return maximumSearchTime; }
private:
int optimumSearchTime;
int maximumSearchTime;
int unstablePVExtraTime;
};
#endif // !defined(APPLICATION_H_INCLUDED)
#endif // !defined(TIMEMAN_H_INCLUDED)
+46 -160
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,31 +17,18 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
////
//// Includes
////
#include <cassert>
#include <cmath>
#include <cstring>
#include <xmmintrin.h>
#include <iostream>
#include "movegen.h"
#include "tt.h"
// The main transposition table
TranspositionTable TT;
////
//// Functions
////
TranspositionTable TT; // Our global transposition table
TranspositionTable::TranspositionTable() {
size = writes = 0;
entries = 0;
generation = 0;
size = generation = 0;
entries = NULL;
}
TranspositionTable::~TranspositionTable() {
@@ -50,40 +37,39 @@ TranspositionTable::~TranspositionTable() {
}
/// TranspositionTable::set_size sets the size of the transposition table,
/// TranspositionTable::set_size() sets the size of the transposition table,
/// measured in megabytes.
void TranspositionTable::set_size(size_t mbSize) {
assert(mbSize >= 4 && mbSize <= 8192);
size_t newSize = 1024;
// We store a cluster of ClusterSize number of TTEntry for each position
// and newSize is the maximum number of storable positions.
while ((2 * newSize) * sizeof(TTCluster) <= (mbSize << 20))
// Transposition table consists of clusters and each cluster consists
// of ClusterSize number of TTEntries. Each non-empty entry contains
// information of exactly one position and newSize is the number of
// clusters we are going to allocate.
while (2ULL * newSize * sizeof(TTCluster) <= (mbSize << 20))
newSize *= 2;
if (newSize != size)
if (newSize == size)
return;
size = newSize;
delete [] entries;
entries = new (std::nothrow) TTCluster[size];
if (!entries)
{
size = newSize;
delete [] entries;
entries = new TTCluster[size];
if (!entries)
{
std::cerr << "Failed to allocate " << mbSize
<< " MB for transposition table." << std::endl;
Application::exit_with_failure();
}
clear();
std::cerr << "Failed to allocate " << mbSize
<< " MB for transposition table." << std::endl;
exit(EXIT_FAILURE);
}
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
/// user asks the program to clear the table (from the UCI interface).
/// Perhaps we should also clear it when the "ucinewgame" command is recieved?
void TranspositionTable::clear() {
@@ -91,66 +77,51 @@ void TranspositionTable::clear() {
}
/// TranspositionTable::first_entry returns a pointer to the first
/// entry of a cluster given a position. The low 32 bits of the key
/// are used to get the index in the table.
/// TranspositionTable::store() writes a new entry containing position key and
/// valuable information of current position. The lowest order bits of position
/// key are used to decide on which cluster the position will be placed.
/// When a new entry is written and there are no empty entries available in cluster,
/// it replaces the least valuable of entries. A TTEntry t1 is considered to be
/// more valuable than a TTEntry t2 if t1 is from the current search and t2 is from
/// a previous search, or if the depth of t1 is bigger than the depth of t2.
inline TTEntry* TranspositionTable::first_entry(const Key posKey) const {
return entries[uint32_t(posKey) & (size - 1)].data;
}
/// TranspositionTable::store writes a new entry containing a position,
/// a value, a value type, a search depth, and a best move to the
/// transposition table. Transposition table is organized in clusters of
/// four TTEntry objects, and when a new entry is written, it replaces
/// the least valuable of the four entries in a cluster. A TTEntry t1 is
/// considered to be more valuable than a TTEntry t2 if t1 is from the
/// current search and t2 is from a previous search, or if the depth of t1
/// is bigger than the depth of t2. A TTEntry of type VALUE_TYPE_EVAL
/// never replaces another entry for the same position.
void TranspositionTable::store(const Key posKey, Value v, ValueType t, Depth d, Move m) {
void TranspositionTable::store(const Key posKey, Value v, ValueType t, Depth d, Move m, Value statV, Value kingD) {
int c1, c2, c3;
TTEntry *tte, *replace;
uint32_t posKey32 = posKey >> 32; // Use the high 32 bits as key
uint32_t posKey32 = posKey >> 32; // Use the high 32 bits as key inside the cluster
tte = replace = first_entry(posKey);
for (int i = 0; i < ClusterSize; i++, tte++)
{
if (!tte->key() || tte->key() == posKey32) // empty or overwrite old
if (!tte->key() || tte->key() == posKey32) // Empty or overwrite old
{
// Do not overwrite when new type is VALUE_TYPE_EV_LO
if (tte->key() && t == VALUE_TYPE_EV_LO)
return;
// Preserve any existing ttMove
if (m == MOVE_NONE)
m = tte->move();
*tte = TTEntry(posKey32, v, t, d, m, generation);
tte->save(posKey32, v, t, d, m, generation, statV, kingD);
return;
}
else if (i == 0) // replace would be a no-op in this common case
continue;
int c1 = (replace->generation() == generation ? 2 : 0);
int c2 = (tte->generation() == generation ? -2 : 0);
int c3 = (tte->depth() < replace->depth() ? 1 : 0);
// Implement replace strategy
c1 = (replace->generation() == generation ? 2 : 0);
c2 = (tte->generation() == generation || tte->type() == VALUE_TYPE_EXACT ? -2 : 0);
c3 = (tte->depth() < replace->depth() ? 1 : 0);
if (c1 + c2 + c3 > 0)
replace = tte;
}
*replace = TTEntry(posKey32, v, t, d, m, generation);
writes++;
replace->save(posKey32, v, t, d, m, generation, statV, kingD);
}
/// TranspositionTable::retrieve looks up the current position in the
/// transposition table. Returns a pointer to the TTEntry or NULL
/// if position is not found.
/// TranspositionTable::probe() looks up the current position in the
/// transposition table. Returns a pointer to the TTEntry or NULL if
/// position is not found.
TTEntry* TranspositionTable::retrieve(const Key posKey) const {
TTEntry* TranspositionTable::probe(const Key posKey) const {
uint32_t posKey32 = posKey >> 32;
TTEntry* tte = first_entry(posKey);
@@ -163,96 +134,11 @@ TTEntry* TranspositionTable::retrieve(const Key posKey) const {
}
/// TranspositionTable::prefetch looks up the current position in the
/// transposition table and load it in L1/L2 cache. This is a non
/// blocking function and do not stalls the CPU waiting for data
/// to be loaded from RAM, that can be very slow. When we will
/// subsequently call retrieve() the TT data will be already
/// quickly accessible in L1/L2 CPU cache.
void TranspositionTable::prefetch(const Key posKey) const {
#if defined(__INTEL_COMPILER) || defined(__ICL)
// This hack prevents prefetches to be optimized away by the
// Intel compiler. Both MSVC and gcc seems not affected.
__asm__ ("");
#endif
char const* addr = (char*)first_entry(posKey);
_mm_prefetch(addr, _MM_HINT_T2);
_mm_prefetch(addr+64, _MM_HINT_T2); // 64 bytes ahead
}
/// TranspositionTable::new_search() is called at the beginning of every new
/// search. It increments the "generation" variable, which is used to
/// distinguish transposition table entries from previous searches from
/// entries from the current search.
void TranspositionTable::new_search() {
generation++;
writes = 0;
}
/// TranspositionTable::insert_pv() is called at the end of a search
/// iteration, and inserts the PV back into the PV. This makes sure
/// the old PV moves are searched first, even if the old TT entries
/// have been overwritten.
void TranspositionTable::insert_pv(const Position& pos, Move pv[]) {
StateInfo st;
Position p(pos);
for (int i = 0; pv[i] != MOVE_NONE; i++)
{
TTEntry *tte = retrieve(p.get_key());
if (!tte || tte->move() != pv[i])
store(p.get_key(), VALUE_NONE, VALUE_TYPE_NONE, Depth(-127*OnePly), pv[i]);
p.do_move(pv[i], st);
}
}
/// TranspositionTable::extract_pv() extends a PV by adding moves from the
/// transposition table at the end. This should ensure that the PV is almost
/// always at least two plies long, which is important, because otherwise we
/// will often get single-move PVs when the search stops while failing high,
/// and a single-move PV means that we don't have a ponder move.
void TranspositionTable::extract_pv(const Position& pos, Move pv[], const int PLY_MAX) {
const TTEntry* tte;
StateInfo st;
Position p(pos);
int ply = 0;
// Update position to the end of current PV
while (pv[ply] != MOVE_NONE)
p.do_move(pv[ply++], st);
// Try to add moves from TT while possible
while ( (tte = retrieve(p.get_key())) != NULL
&& tte->move() != MOVE_NONE
&& move_is_legal(p, tte->move())
&& (!p.is_draw() || ply < 2)
&& ply < PLY_MAX)
{
pv[ply] = tte->move();
p.do_move(pv[ply++], st);
}
pv[ply] = MOVE_NONE;
}
/// TranspositionTable::full() returns the permill of all transposition table
/// entries which have received at least one write during the current search.
/// It is used to display the "info hashfull ..." information in UCI.
int TranspositionTable::full() const {
double N = double(size) * ClusterSize;
return int(1000 * (1 - exp(writes * log(1.0 - 1.0/N))));
}
+104 -55
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,108 +17,157 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined(TT_H_INCLUDED)
#define TT_H_INCLUDED
////
//// Includes
////
#include <iostream>
#include "depth.h"
#include "position.h"
#include "value.h"
#include "move.h"
#include "types.h"
////
//// Types
////
/// The TTEntry class is the class of transposition table entries
/// The TTEntry is the class of transposition table entries
///
/// A TTEntry needs 96 bits to be stored
/// A TTEntry needs 128 bits to be stored
///
/// bit 0-31: key
/// bit 32-63: data
/// bit 64-79: value
/// bit 80-95: depth
/// bit 96-111: static value
/// bit 112-127: margin of static value
///
/// the 32 bits of the data field are so defined
///
/// bit 0-16: move
/// bit 17-19: not used
/// bit 20-22: value type
/// bit 0-15: move
/// bit 16-20: not used
/// bit 21-22: value type
/// bit 23-31: generation
class TTEntry {
public:
TTEntry() {}
TTEntry(uint32_t k, Value v, ValueType t, Depth d, Move m, int generation)
: key_ (k), data((m & 0x1FFFF) | (t << 20) | (generation << 23)),
value_(int16_t(v)), depth_(int16_t(d)) {}
void save(uint32_t k, Value v, ValueType t, Depth d, Move m, int g, Value statV, Value statM) {
uint32_t key() const { return key_; }
Depth depth() const { return Depth(depth_); }
Move move() const { return Move(data & 0x1FFFF); }
Value value() const { return Value(value_); }
ValueType type() const { return ValueType((data >> 20) & 7); }
int generation() const { return (data >> 23); }
key32 = (uint32_t)k;
move16 = (uint16_t)m;
valueType = (uint8_t)t;
generation8 = (uint8_t)g;
value16 = (int16_t)v;
depth16 = (int16_t)d;
staticValue = (int16_t)statV;
staticMargin = (int16_t)statM;
}
void set_generation(int g) { generation8 = (uint8_t)g; }
uint32_t key() const { return key32; }
Depth depth() const { return (Depth)depth16; }
Move move() const { return (Move)move16; }
Value value() const { return (Value)value16; }
ValueType type() const { return (ValueType)valueType; }
int generation() const { return (int)generation8; }
Value static_value() const { return (Value)staticValue; }
Value static_value_margin() const { return (Value)staticMargin; }
private:
uint32_t key_;
uint32_t data;
int16_t value_;
int16_t depth_;
uint32_t key32;
uint16_t move16;
uint8_t valueType, generation8;
int16_t value16, depth16, staticValue, staticMargin;
};
/// This is the number of TTEntry slots for each position
const int ClusterSize = 5;
/// This is the number of TTEntry slots for each cluster
const int ClusterSize = 4;
/// Each group of ClusterSize number of TTEntry form a TTCluster
/// that is indexed by a single position key. Cluster is padded
/// to a cache line size so to guarantee always aligned accesses.
/// TTCluster consists of ClusterSize number of TTEntries. Size of TTCluster
/// must not be bigger than a cache line size. In case it is less, it should
/// be padded to guarantee always aligned accesses.
struct TTCluster {
TTEntry data[ClusterSize];
char cache_line_padding[64 - sizeof(TTEntry[ClusterSize])];
};
/// The transposition table class. This is basically just a huge array
/// containing TTEntry objects, and a few methods for writing new entries
/// and reading new ones.
/// The transposition table class. This is basically just a huge array containing
/// TTCluster objects, and a few methods for writing and reading entries.
class TranspositionTable {
TranspositionTable(const TranspositionTable&);
TranspositionTable& operator=(const TranspositionTable&);
public:
TranspositionTable();
~TranspositionTable();
void set_size(size_t mbSize);
void clear();
void store(const Key posKey, Value v, ValueType type, Depth d, Move m);
TTEntry* retrieve(const Key posKey) const;
void prefetch(const Key posKey) const;
void store(const Key posKey, Value v, ValueType type, Depth d, Move m, Value statV, Value kingD);
TTEntry* probe(const Key posKey) const;
void new_search();
void insert_pv(const Position& pos, Move pv[]);
void extract_pv(const Position& pos, Move pv[], const int PLY_MAX);
int full() const;
TTEntry* first_entry(const Key posKey) const;
void refresh(const TTEntry* tte) const;
private:
inline TTEntry* first_entry(const Key posKey) const;
// Be sure 'writes' is at least one cache line away
// from read only variables.
unsigned char pad_before[64 - sizeof(unsigned)];
unsigned writes; // heavy SMP read/write access here
unsigned char pad_after[64];
size_t size;
TTCluster* entries;
uint8_t generation;
uint8_t generation; // Size must be not bigger then TTEntry::generation8
};
extern TranspositionTable TT;
/// TranspositionTable::first_entry() returns a pointer to the first entry of
/// a cluster given a position. The lowest order bits of the key are used to
/// get the index of the cluster.
inline TTEntry* TranspositionTable::first_entry(const Key posKey) const {
return entries[((uint32_t)posKey) & (size - 1)].data;
}
/// TranspositionTable::refresh() updates the 'generation' value of the TTEntry
/// to avoid aging. Normally called after a TT hit.
inline void TranspositionTable::refresh(const TTEntry* tte) const {
const_cast<TTEntry*>(tte)->set_generation(generation);
}
/// A simple fixed size hash table used to store pawns and material
/// configurations. It is basically just an array of Entry objects.
/// Without cluster concept or overwrite policy.
template<class Entry, int HashSize>
struct SimpleHash {
typedef SimpleHash<Entry, HashSize> Base;
void init() {
if (entries)
return;
entries = new (std::nothrow) Entry[HashSize];
if (!entries)
{
std::cerr << "Failed to allocate " << HashSize * sizeof(Entry)
<< " bytes for hash table." << std::endl;
exit(EXIT_FAILURE);
}
memset(entries, 0, HashSize * sizeof(Entry));
}
virtual ~SimpleHash() { delete [] entries; }
Entry* probe(Key key) const { return entries + ((uint32_t)key & (HashSize - 1)); }
void prefetch(Key key) const { ::prefetch((char*)probe(key)); }
protected:
Entry* entries;
};
#endif // !defined(TT_H_INCLUDED)
+428 -34
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,55 +17,76 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined(TYPES_H_INCLUDED)
#define TYPES_H_INCLUDED
#if !defined(_MSC_VER)
#include <climits>
#include <cstdlib>
#include <inttypes.h>
#if defined(_MSC_VER)
// Disable some silly and noisy warning from MSVC compiler
#pragma warning(disable: 4800) // Forcing value to bool 'true' or 'false'
#pragma warning(disable: 4127) // Conditional expression is constant
#pragma warning(disable: 4146) // Unary minus operator applied to unsigned type
// MSVC does not support <inttypes.h>
typedef signed __int8 int8_t;
typedef unsigned __int8 uint8_t;
typedef signed __int16 int16_t;
typedef unsigned __int16 uint16_t;
typedef signed __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef signed __int64 int64_t;
typedef unsigned __int64 uint64_t;
#else
typedef __int8 int8_t;
typedef unsigned __int8 uint8_t;
typedef __int16 int16;
typedef unsigned __int16 uint16_t;
typedef __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
#include <inttypes.h>
typedef __int16 int16_t;
typedef __int64 int64_t;
#endif // !defined(_MSC_VER)
// Hash keys
typedef uint64_t Key;
// Bitboard type
typedef uint64_t Bitboard;
////
//// Compiler specific defines
////
// Quiet a warning on Intel compiler
#if !defined(__SIZEOF_INT__ )
#define __SIZEOF_INT__ 0
#endif
// Check for 64 bits for different compilers: Intel, MSVC and gcc
#if defined(__x86_64) || defined(_M_X64) || defined(_WIN64) || (__SIZEOF_INT__ > 4)
#define Min(x, y) (((x) < (y)) ? (x) : (y))
#define Max(x, y) (((x) < (y)) ? (y) : (x))
////
//// Configuration
////
//// For Linux and OSX configuration is done automatically using Makefile.
//// To get started type "make help".
////
//// For windows part of the configuration is detected automatically, but
//// some switches need to be set manually:
////
//// -DNDEBUG | Disable debugging mode. Use always.
////
//// -DNO_PREFETCH | Disable use of prefetch asm-instruction. A must if you want the
//// | executable to run on some very old machines.
////
//// -DUSE_POPCNT | Add runtime support for use of popcnt asm-instruction.
//// | Works only in 64-bit mode. For compiling requires hardware
//// | with popcnt support. Around 4% speed-up.
////
//// -DOLD_LOCKS | By default under Windows are used the fast Slim Reader/Writer (SRW)
//// | Locks and Condition Variables: these are not supported by Windows XP
//// | and older, to compile for those platforms you should enable OLD_LOCKS.
// Automatic detection for 64-bit under Windows
#if defined(_WIN64)
#define IS_64BIT
#endif
#if defined(IS_64BIT) && (defined(__GNUC__) || defined(__INTEL_COMPILER))
// Automatic detection for use of bsfq asm-instruction under Windows
#if defined(_WIN64)
#define USE_BSFQ
#endif
// Intel header for _mm_popcnt_u64() intrinsic
#if defined(USE_POPCNT) && defined(_MSC_VER) && defined(__INTEL_COMPILER)
#include <nmmintrin.h>
#endif
// Cache line alignment specification
#if defined(_MSC_VER) || defined(__INTEL_COMPILER)
#define CACHE_LINE_ALIGNMENT __declspec(align(64))
@@ -73,4 +94,377 @@ typedef uint64_t Bitboard;
#define CACHE_LINE_ALIGNMENT __attribute__ ((aligned(64)))
#endif
// Define a __cpuid() function for gcc compilers, for Intel and MSVC
// is already available as an intrinsic.
#if defined(_MSC_VER)
#include <intrin.h>
#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
inline void __cpuid(int CPUInfo[4], int InfoType)
{
int* eax = CPUInfo + 0;
int* ebx = CPUInfo + 1;
int* ecx = CPUInfo + 2;
int* edx = CPUInfo + 3;
*eax = InfoType;
*ecx = 0;
__asm__("cpuid" : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx)
: "0" (*eax), "2" (*ecx));
}
#else
inline void __cpuid(int CPUInfo[4], int)
{
CPUInfo[0] = CPUInfo[1] = CPUInfo[2] = CPUInfo[3] = 0;
}
#endif
// Define FORCE_INLINE macro to force inlining overriding compiler choice
#if defined(_MSC_VER)
#define FORCE_INLINE __forceinline
#elif defined(__GNUC__)
#define FORCE_INLINE inline __attribute__((always_inline))
#else
#define FORCE_INLINE inline
#endif
/// cpu_has_popcnt() detects support for popcnt instruction at runtime
inline bool cpu_has_popcnt() {
int CPUInfo[4] = {-1};
__cpuid(CPUInfo, 0x00000001);
return (CPUInfo[2] >> 23) & 1;
}
/// CpuHasPOPCNT is a global constant initialized at startup that
/// is set to true if CPU on which application runs supports popcnt
/// hardware instruction. Unless USE_POPCNT is not defined.
#if defined(USE_POPCNT)
const bool CpuHasPOPCNT = cpu_has_popcnt();
#else
const bool CpuHasPOPCNT = false;
#endif
/// CpuIs64Bit is a global constant initialized at compile time that
/// is set to true if CPU on which application runs is a 64 bits.
#if defined(IS_64BIT)
const bool CpuIs64Bit = true;
#else
const bool CpuIs64Bit = false;
#endif
#include <string>
typedef uint64_t Key;
typedef uint64_t Bitboard;
const int PLY_MAX = 100;
const int PLY_MAX_PLUS_2 = PLY_MAX + 2;
enum ValueType {
VALUE_TYPE_NONE = 0,
VALUE_TYPE_UPPER = 1,
VALUE_TYPE_LOWER = 2,
VALUE_TYPE_EXACT = VALUE_TYPE_UPPER | VALUE_TYPE_LOWER
};
enum Value {
VALUE_ZERO = 0,
VALUE_DRAW = 0,
VALUE_KNOWN_WIN = 15000,
VALUE_MATE = 30000,
VALUE_INFINITE = 30001,
VALUE_NONE = 30002,
VALUE_MATE_IN_PLY_MAX = VALUE_MATE - PLY_MAX,
VALUE_MATED_IN_PLY_MAX = -VALUE_MATE + PLY_MAX,
VALUE_ENSURE_INTEGER_SIZE_P = INT_MAX,
VALUE_ENSURE_INTEGER_SIZE_N = INT_MIN
};
enum PieceType {
PIECE_TYPE_NONE = 0,
PAWN = 1, KNIGHT = 2, BISHOP = 3, ROOK = 4, QUEEN = 5, KING = 6
};
enum Piece {
PIECE_NONE_DARK_SQ = 0, WP = 1, WN = 2, WB = 3, WR = 4, WQ = 5, WK = 6,
BP = 9, BN = 10, BB = 11, BR = 12, BQ = 13, BK = 14, PIECE_NONE = 16
};
enum Color {
WHITE, BLACK, COLOR_NONE
};
enum Depth {
ONE_PLY = 2,
DEPTH_ZERO = 0 * ONE_PLY,
DEPTH_QS_CHECKS = -1 * ONE_PLY,
DEPTH_QS_NO_CHECKS = -2 * ONE_PLY,
DEPTH_NONE = -127 * ONE_PLY
};
enum Square {
SQ_A1, SQ_B1, SQ_C1, SQ_D1, SQ_E1, SQ_F1, SQ_G1, SQ_H1,
SQ_A2, SQ_B2, SQ_C2, SQ_D2, SQ_E2, SQ_F2, SQ_G2, SQ_H2,
SQ_A3, SQ_B3, SQ_C3, SQ_D3, SQ_E3, SQ_F3, SQ_G3, SQ_H3,
SQ_A4, SQ_B4, SQ_C4, SQ_D4, SQ_E4, SQ_F4, SQ_G4, SQ_H4,
SQ_A5, SQ_B5, SQ_C5, SQ_D5, SQ_E5, SQ_F5, SQ_G5, SQ_H5,
SQ_A6, SQ_B6, SQ_C6, SQ_D6, SQ_E6, SQ_F6, SQ_G6, SQ_H6,
SQ_A7, SQ_B7, SQ_C7, SQ_D7, SQ_E7, SQ_F7, SQ_G7, SQ_H7,
SQ_A8, SQ_B8, SQ_C8, SQ_D8, SQ_E8, SQ_F8, SQ_G8, SQ_H8,
SQ_NONE,
DELTA_N = 8,
DELTA_E = 1,
DELTA_S = -8,
DELTA_W = -1,
DELTA_NN = DELTA_N + DELTA_N,
DELTA_NE = DELTA_N + DELTA_E,
DELTA_SE = DELTA_S + DELTA_E,
DELTA_SS = DELTA_S + DELTA_S,
DELTA_SW = DELTA_S + DELTA_W,
DELTA_NW = DELTA_N + DELTA_W
};
enum File {
FILE_A, FILE_B, FILE_C, FILE_D, FILE_E, FILE_F, FILE_G, FILE_H
};
enum Rank {
RANK_1, RANK_2, RANK_3, RANK_4, RANK_5, RANK_6, RANK_7, RANK_8
};
enum SquareColor {
DARK, LIGHT
};
enum ScaleFactor {
SCALE_FACTOR_ZERO = 0,
SCALE_FACTOR_NORMAL = 64,
SCALE_FACTOR_MAX = 128,
SCALE_FACTOR_NONE = 255
};
/// Score enum keeps a midgame and an endgame value in a single
/// integer (enum), first LSB 16 bits are used to store endgame
/// value, while upper bits are used for midgame value. Compiler
/// is free to choose the enum type as long as can keep its data,
/// so ensure Score to be an integer type.
enum Score {
SCORE_ZERO = 0,
SCORE_ENSURE_INTEGER_SIZE_P = INT_MAX,
SCORE_ENSURE_INTEGER_SIZE_N = INT_MIN
};
#define ENABLE_OPERATORS_ON(T) \
inline T operator+ (const T d1, const T d2) { return T(int(d1) + int(d2)); } \
inline T operator- (const T d1, const T d2) { return T(int(d1) - int(d2)); } \
inline T operator* (int i, const T d) { return T(i * int(d)); } \
inline T operator* (const T d, int i) { return T(int(d) * i); } \
inline T operator/ (const T d, int i) { return T(int(d) / i); } \
inline T operator- (const T d) { return T(-int(d)); } \
inline T operator++ (T& d, int) {d = T(int(d) + 1); return d; } \
inline T operator-- (T& d, int) { d = T(int(d) - 1); return d; } \
inline void operator+= (T& d1, const T d2) { d1 = d1 + d2; } \
inline void operator-= (T& d1, const T d2) { d1 = d1 - d2; } \
inline void operator*= (T& d, int i) { d = T(int(d) * i); } \
inline void operator/= (T& d, int i) { d = T(int(d) / i); }
ENABLE_OPERATORS_ON(Value)
ENABLE_OPERATORS_ON(PieceType)
ENABLE_OPERATORS_ON(Piece)
ENABLE_OPERATORS_ON(Color)
ENABLE_OPERATORS_ON(Depth)
ENABLE_OPERATORS_ON(Square)
ENABLE_OPERATORS_ON(File)
ENABLE_OPERATORS_ON(Rank)
#undef ENABLE_OPERATORS_ON
// Extra operators for adding integers to a Value
inline Value operator+ (Value v, int i) { return Value(int(v) + i); }
inline Value operator- (Value v, int i) { return Value(int(v) - i); }
// Extracting the _signed_ lower and upper 16 bits it not so trivial
// because according to the standard a simple cast to short is
// implementation defined and so is a right shift of a signed integer.
inline Value mg_value(Score s) { return Value(((int(s) + 32768) & ~0xffff) / 0x10000); }
// Unfortunatly on Intel 64 bit we have a small speed regression, so use a faster code in
// this case, although not 100% standard compliant it seems to work for Intel and MSVC.
#if defined(IS_64BIT) && (!defined(__GNUC__) || defined(__INTEL_COMPILER))
inline Value eg_value(Score s) { return Value(int16_t(s & 0xffff)); }
#else
inline Value eg_value(Score s) { return Value((int)(unsigned(s) & 0x7fffu) - (int)(unsigned(s) & 0x8000u)); }
#endif
inline Score make_score(int mg, int eg) { return Score((mg << 16) + eg); }
// Division must be handled separately for each term
inline Score operator/(Score s, int i) { return make_score(mg_value(s) / i, eg_value(s) / i); }
// Only declared but not defined. We don't want to multiply two scores due to
// a very high risk of overflow. So user should explicitly convert to integer.
inline Score operator*(Score s1, Score s2);
// Remaining Score operators are standard
inline Score operator+ (const Score d1, const Score d2) { return Score(int(d1) + int(d2)); }
inline Score operator- (const Score d1, const Score d2) { return Score(int(d1) - int(d2)); }
inline Score operator* (int i, const Score d) { return Score(i * int(d)); }
inline Score operator* (const Score d, int i) { return Score(int(d) * i); }
inline Score operator- (const Score d) { return Score(-int(d)); }
inline void operator+= (Score& d1, const Score d2) { d1 = d1 + d2; }
inline void operator-= (Score& d1, const Score d2) { d1 = d1 - d2; }
inline void operator*= (Score& d, int i) { d = Score(int(d) * i); }
inline void operator/= (Score& d, int i) { d = Score(int(d) / i); }
const Value PawnValueMidgame = Value(0x0C6);
const Value PawnValueEndgame = Value(0x102);
const Value KnightValueMidgame = Value(0x331);
const Value KnightValueEndgame = Value(0x34E);
const Value BishopValueMidgame = Value(0x344);
const Value BishopValueEndgame = Value(0x359);
const Value RookValueMidgame = Value(0x4F6);
const Value RookValueEndgame = Value(0x4FE);
const Value QueenValueMidgame = Value(0x9D9);
const Value QueenValueEndgame = Value(0x9FE);
inline Value value_mate_in(int ply) {
return VALUE_MATE - ply;
}
inline Value value_mated_in(int ply) {
return -VALUE_MATE + ply;
}
inline Piece make_piece(Color c, PieceType pt) {
return Piece((int(c) << 3) | int(pt));
}
inline PieceType type_of_piece(Piece p) {
return PieceType(int(p) & 7);
}
inline Color color_of_piece(Piece p) {
return Color(int(p) >> 3);
}
inline Color opposite_color(Color c) {
return Color(int(c) ^ 1);
}
inline bool color_is_ok(Color c) {
return c == WHITE || c == BLACK;
}
inline bool piece_type_is_ok(PieceType pt) {
return pt >= PAWN && pt <= KING;
}
inline bool piece_is_ok(Piece p) {
return piece_type_is_ok(type_of_piece(p)) && color_is_ok(color_of_piece(p));
}
inline char piece_type_to_char(PieceType pt) {
static const char ch[] = " PNBRQK";
return ch[pt];
}
inline Square make_square(File f, Rank r) {
return Square((int(r) << 3) | int(f));
}
inline File square_file(Square s) {
return File(int(s) & 7);
}
inline Rank square_rank(Square s) {
return Rank(int(s) >> 3);
}
inline Square flip_square(Square s) {
return Square(int(s) ^ 56);
}
inline Square flop_square(Square s) {
return Square(int(s) ^ 7);
}
inline Square relative_square(Color c, Square s) {
return Square(int(s) ^ (int(c) * 56));
}
inline Rank relative_rank(Color c, Rank r) {
return Rank(int(r) ^ (int(c) * 7));
}
inline Rank relative_rank(Color c, Square s) {
return relative_rank(c, square_rank(s));
}
inline SquareColor square_color(Square s) {
return SquareColor(int(square_rank(s) + s) & 1);
}
inline bool opposite_color_squares(Square s1, Square s2) {
int s = int(s1) ^ int(s2);
return ((s >> 3) ^ s) & 1;
}
inline int file_distance(Square s1, Square s2) {
return abs(square_file(s1) - square_file(s2));
}
inline int rank_distance(Square s1, Square s2) {
return abs(square_rank(s1) - square_rank(s2));
}
inline int square_distance(Square s1, Square 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) {
return char(f - FILE_A + int('a'));
}
inline Rank rank_from_char(char c) {
return Rank(c - '1') + RANK_1;
}
inline char rank_to_char(Rank r) {
return char(r - RANK_1 + int('1'));
}
inline const std::string square_to_string(Square s) {
char ch[] = { file_to_char(square_file(s)), rank_to_char(square_rank(s)), 0 };
return std::string(ch);
}
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 s >= SQ_A1 && s <= SQ_H8;
}
inline Square pawn_push(Color c) {
return c == WHITE ? DELTA_N : DELTA_S;
}
#endif // !defined(TYPES_H_INCLUDED)
+140 -218
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,309 +17,231 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
////
//// Includes
////
#include <cassert>
#include <iostream>
#include <sstream>
#include <string>
#include "book.h"
#include "evaluate.h"
#include "misc.h"
#include "move.h"
#include "movegen.h"
#include "position.h"
#include "san.h"
#include "search.h"
#include "uci.h"
#include "ucioption.h"
using namespace std;
////
//// Local definitions:
////
namespace {
// UCIInputParser is a class for parsing UCI input. The class
// FEN string for the initial position
const string StartPositionFEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
// UCIParser is a class for parsing UCI input. The class
// is actually a string stream built on a given input string.
typedef istringstream UCIParser;
typedef istringstream UCIInputParser;
// The root position. This is set up when the user (or in practice, the GUI)
// sends the "position" UCI command. The root position is sent to the think()
// function when the program receives the "go" command.
Position RootPosition;
// Local functions
bool handle_command(const string& command);
void set_option(UCIInputParser& uip);
void set_position(UCIInputParser& uip);
bool go(UCIInputParser& uip);
void perft(UCIInputParser& uip);
void set_option(UCIParser& up);
void set_position(Position& pos, UCIParser& up);
bool go(Position& pos, UCIParser& up);
void perft(Position& pos, UCIParser& up);
}
////
//// Functions
////
/// execute_uci_command() takes a string as input, uses a UCIParser
/// object to parse this text string as a UCI command, and calls
/// the appropriate functions. In addition to the UCI commands,
/// the function also supports a few debug commands.
/// uci_main_loop() is the only global function in this file. It is
/// called immediately after the program has finished initializing.
/// The program remains in this loop until it receives the "quit" UCI
/// command. 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.
bool execute_uci_command(const string& cmd) {
void uci_main_loop() {
static Position pos(StartPositionFEN, false, 0); // The root position
RootPosition.from_fen(StartPosition);
string command;
UCIParser up(cmd);
string token;
do {
// Wait for a command from stdin
if (!getline(cin, command))
command = "quit";
up >> token; // operator>>() skips any whitespace
} while (handle_command(command));
}
if (token == "quit")
return false;
if (token == "go")
return go(pos, up);
////
//// Local functions
////
if (token == "ucinewgame")
pos.from_fen(StartPositionFEN, false);
namespace {
else if (token == "isready")
cout << "readyok" << endl;
// handle_command() takes a text string as input, uses a
// UCIInputParser object to parse this text string as a UCI command,
// and calls the appropriate functions. In addition to the UCI
// commands, the function also supports a few debug commands.
else if (token == "position")
set_position(pos, up);
bool handle_command(const string& command) {
else if (token == "setoption")
set_option(up);
UCIInputParser uip(command);
string token;
else if (token == "perft")
perft(pos, up);
if (!(uip >> token)) // operator>>() skips any whitespace
return true;
else if (token == "d")
pos.print();
if (token == "quit")
return false;
else if (token == "flip")
pos.flip();
if (token == "go")
return go(uip);
if (token == "uci")
{
cout << "id name " << engine_name()
<< "\nid author Tord Romstad, Marco Costalba, Joona Kiiski\n";
print_uci_options();
cout << "uciok" << endl;
}
else if (token == "ucinewgame")
{
push_button("New Game");
Position::init_piece_square_tables();
RootPosition.from_fen(StartPosition);
}
else if (token == "isready")
cout << "readyok" << endl;
else if (token == "position")
set_position(uip);
else if (token == "setoption")
set_option(uip);
// The remaining commands are for debugging purposes only.
// Perhaps they should be removed later in order to reduce the
// size of the program binary.
else if (token == "d")
RootPosition.print();
else if (token == "flip")
{
Position p(RootPosition);
RootPosition.flipped_copy(p);
}
else if (token == "eval")
{
EvalInfo ei;
cout << "Incremental mg: " << mg_value(RootPosition.value())
<< "\nIncremental eg: " << eg_value(RootPosition.value())
<< "\nFull eval: " << evaluate(RootPosition, ei, 0) << endl;
}
else if (token == "key")
cout << "key: " << hex << RootPosition.get_key()
<< "\nmaterial key: " << RootPosition.get_material_key()
<< "\npawn key: " << RootPosition.get_pawn_key() << endl;
else if (token == "perft")
perft(uip);
else
cout << "Unknown command: " << command << endl;
return true;
else if (token == "eval")
{
read_evaluation_uci_options(pos.side_to_move());
cout << trace_evaluate(pos) << endl;
}
else if (token == "key")
cout << "key: " << hex << pos.get_key()
<< "\nmaterial key: " << pos.get_material_key()
<< "\npawn key: " << pos.get_pawn_key() << endl;
// set_position() is called when Stockfish receives the "position" UCI
// command. The input parameter is a UCIInputParser. It is assumed
// that this parser has consumed the first token of the UCI command
// ("position"), and is ready to read the second token ("startpos"
// or "fen", if the input is well-formed).
else if (token == "uci")
cout << "id name " << engine_name()
<< "\nid author " << engine_authors()
<< "\n" << Options.print_all()
<< "\nuciok" << endl;
else
cout << "Unknown command: " << cmd << endl;
void set_position(UCIInputParser& uip) {
return true;
}
string token;
if (!(uip >> token)) // operator>>() skips any whitespace
return;
namespace {
// set_position() is called when engine receives the "position" UCI
// command. The function sets up the position described in the given
// fen string ("fen") or the starting position ("startpos") and then
// makes the moves given in the following move list ("moves").
void set_position(Position& pos, UCIParser& up) {
string token, fen;
up >> token; // operator>>() skips any whitespace
if (token == "startpos")
RootPosition.from_fen(StartPosition);
{
pos.from_fen(StartPositionFEN, false);
up >> token; // Consume "moves" token if any
}
else if (token == "fen")
{
string fen;
while (uip >> token && token != "moves")
{
fen += token;
fen += ' ';
}
RootPosition.from_fen(fen);
}
while (up >> token && token != "moves")
fen += token + " ";
if (uip.good())
{
if (token != "moves")
uip >> token;
if (token == "moves")
{
Move move;
StateInfo st;
while (uip >> token)
{
move = move_from_string(RootPosition, token);
RootPosition.do_move(move, st);
if (RootPosition.rule_50_counter() == 0)
RootPosition.reset_game_ply();
}
// Our StateInfo st is about going out of scope so copy
// its content inside RootPosition before they disappear.
RootPosition.saveState();
}
pos.from_fen(fen, Options["UCI_Chess960"].value<bool>());
}
else return;
// Parse move list (if any)
while (up >> token)
pos.do_setup_move(move_from_uci(pos, token));
}
// set_option() is called when Stockfish receives the "setoption" UCI
// command. The input parameter is a UCIInputParser. It is assumed
// that this parser has consumed the first token of the UCI command
// ("setoption"), and is ready to read the second token ("name", if
// the input is well-formed).
// set_option() is called when engine receives the "setoption" UCI
// command. The function updates the corresponding UCI option ("name")
// to the given value ("value").
void set_option(UCIInputParser& uip) {
void set_option(UCIParser& up) {
string token, name, value;
string token, name;
string value = "true"; // UCI buttons don't have a "value" field
if (!(uip >> token)) // operator>>() skips any whitespace
return;
up >> token; // Consume "name" token
up >> name; // Read option name
if (token == "name" && uip >> name)
{
while (uip >> token && token != "value")
name += (" " + token);
// Handle names with included spaces
while (up >> token && token != "value")
name += " " + token;
if (token == "value" && uip >> value)
{
while (uip >> token)
value += (" " + token);
up >> value; // Read option value
set_option_value(name, value);
} else
push_button(name);
}
// Handle values with included spaces
while (up >> token)
value += " " + token;
if (Options.find(name) != Options.end())
Options[name].set_value(value);
else
cout << "No such option: " << name << endl;
}
// go() is called when Stockfish receives the "go" UCI command. The
// input parameter is a UCIInputParser. It is assumed that this
// parser has consumed the first token of the UCI command ("go"),
// and is ready to read the second token. The function sets the
// thinking time and other parameters from the input string, and
// calls think() (defined in search.cpp) with the appropriate
// parameters. Returns false if a quit command is received while
// thinking, returns true otherwise.
// go() is called when engine receives the "go" UCI command. The
// function sets the thinking time and other parameters from the input
// string, and then calls think(). Returns false if a quit command
// is received while thinking, true otherwise.
bool go(UCIInputParser& uip) {
bool go(Position& pos, UCIParser& up) {
string token;
SearchLimits limits;
Move searchMoves[MAX_MOVES], *cur = searchMoves;
int time[] = { 0, 0 }, inc[] = { 0, 0 };
int time[2] = {0, 0}, inc[2] = {0, 0};
int movesToGo = 0, depth = 0, nodes = 0, moveTime = 0;
bool infinite = false, ponder = false;
Move searchMoves[500];
searchMoves[0] = MOVE_NONE;
while (uip >> token)
while (up >> token)
{
if (token == "infinite")
infinite = true;
limits.infinite = true;
else if (token == "ponder")
ponder = true;
limits.ponder = true;
else if (token == "wtime")
uip >> time[0];
up >> time[WHITE];
else if (token == "btime")
uip >> time[1];
up >> time[BLACK];
else if (token == "winc")
uip >> inc[0];
up >> inc[WHITE];
else if (token == "binc")
uip >> inc[1];
up >> inc[BLACK];
else if (token == "movestogo")
uip >> movesToGo;
up >> limits.movesToGo;
else if (token == "depth")
uip >> depth;
up >> limits.maxDepth;
else if (token == "nodes")
uip >> nodes;
up >> limits.maxNodes;
else if (token == "movetime")
uip >> moveTime;
up >> limits.maxTime;
else if (token == "searchmoves")
{
int numOfMoves = 0;
while (uip >> token)
searchMoves[numOfMoves++] = move_from_string(RootPosition, token);
searchMoves[numOfMoves] = MOVE_NONE;
}
while (up >> token)
*cur++ = move_from_uci(pos, token);
}
assert(RootPosition.is_ok());
*cur = MOVE_NONE;
limits.time = time[pos.side_to_move()];
limits.increment = inc[pos.side_to_move()];
return think(RootPosition, infinite, ponder, RootPosition.side_to_move(),
time, inc, movesToGo, depth, nodes, moveTime, searchMoves);
assert(pos.is_ok());
return think(pos, limits, searchMoves);
}
void perft(UCIInputParser& uip) {
string token;
int depth, tm, n;
Position pos = RootPosition;
// perft() is called when engine receives the "perft" command.
// The function calls perft() passing the required search depth
// then prints counted leaf nodes and elapsed time.
if (!(uip >> depth))
void perft(Position& pos, UCIParser& up) {
int depth, time;
int64_t n;
if (!(up >> depth))
return;
tm = get_system_time();
time = get_system_time();
n = perft(pos, depth * OnePly);
n = perft(pos, depth * ONE_PLY);
time = get_system_time() - time;
tm = get_system_time() - tm;
std::cout << "\nNodes " << n
<< "\nTime (ms) " << tm
<< "\nNodes/second " << (int)(n/(tm/1000.0)) << std::endl;
<< "\nTime (ms) " << time
<< "\nNodes/second " << int(n / (time / 1000.0)) << std::endl;
}
}
-31
View File
@@ -1,31 +0,0 @@
/*
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(UCI_H_INCLUDED)
#define UCI_H_INCLUDED
////
//// Prototypes
////
extern void uci_main_loop();
#endif // !defined(UCI_H_INCLUDED)
+99 -290
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,192 +17,88 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
////
//// Includes
////
#include <algorithm>
#include <cassert>
#include <map>
#include <string>
#include <cctype>
#include <iostream>
#include <sstream>
#include <vector>
#include "misc.h"
#include "thread.h"
#include "ucioption.h"
using std::string;
using std::cout;
using std::endl;
////
//// Local definitions
////
OptionsMap Options; // Global object
namespace {
///
/// Types
///
// Our case insensitive less() function as required by UCI protocol
bool CaseInsensitiveLess::operator() (const string& s1, const string& s2) const {
enum OptionType { SPIN, COMBO, CHECK, STRING, BUTTON };
int c1, c2;
size_t i = 0;
typedef std::vector<string> ComboValues;
while (i < s1.size() && i < s2.size())
{
c1 = tolower(s1[i]);
c2 = tolower(s2[i++]);
struct Option {
string name, defaultValue, currentValue;
OptionType type;
size_t idx;
int minValue, maxValue;
ComboValues comboValues;
Option();
Option(const char* defaultValue, OptionType = STRING);
Option(bool defaultValue, OptionType = CHECK);
Option(int defaultValue, int minValue, int maxValue);
bool operator<(const Option& o) const { return this->idx < o.idx; }
};
typedef std::map<string, Option> Options;
///
/// Constants
///
// load_defaults populates the options map with the hard
// coded names and default values.
void load_defaults(Options& o) {
o["Use Search Log"] = Option(false);
o["Search Log Filename"] = Option("SearchLog.txt");
o["Book File"] = Option("book.bin");
o["Mobility (Middle Game)"] = Option(100, 0, 200);
o["Mobility (Endgame)"] = Option(100, 0, 200);
o["Pawn Structure (Middle Game)"] = Option(100, 0, 200);
o["Pawn Structure (Endgame)"] = Option(100, 0, 200);
o["Passed Pawns (Middle Game)"] = Option(100, 0, 200);
o["Passed Pawns (Endgame)"] = Option(100, 0, 200);
o["Space"] = Option(100, 0, 200);
o["Aggressiveness"] = Option(100, 0, 200);
o["Cowardice"] = Option(100, 0, 200);
o["King Safety Curve"] = Option("Quadratic", COMBO);
o["King Safety Curve"].comboValues.push_back("Quadratic");
o["King Safety Curve"].comboValues.push_back("Linear"); /*, "From File"*/
o["King Safety Coefficient"] = Option(40, 1, 100);
o["King Safety X Intercept"] = Option(0, 0, 20);
o["King Safety Max Slope"] = Option(30, 10, 100);
o["King Safety Max Value"] = Option(500, 100, 1000);
o["Queen Contact Check Bonus"] = Option(3, 0, 8);
o["Queen Check Bonus"] = Option(2, 0, 4);
o["Rook Check Bonus"] = Option(1, 0, 4);
o["Bishop Check Bonus"] = Option(1, 0, 4);
o["Knight Check Bonus"] = Option(1, 0, 4);
o["Discovered Check Bonus"] = Option(3, 0, 8);
o["Mate Threat Bonus"] = Option(3, 0, 8);
o["Check Extension (PV nodes)"] = Option(2, 0, 2);
o["Check Extension (non-PV nodes)"] = Option(1, 0, 2);
o["Single Reply Extension (PV nodes)"] = Option(2, 0, 2);
o["Single Reply Extension (non-PV nodes)"] = Option(2, 0, 2);
o["Mate Threat Extension (PV nodes)"] = Option(0, 0, 2);
o["Mate Threat Extension (non-PV nodes)"] = Option(0, 0, 2);
o["Pawn Push to 7th Extension (PV nodes)"] = Option(1, 0, 2);
o["Pawn Push to 7th Extension (non-PV nodes)"] = Option(1, 0, 2);
o["Passed Pawn Extension (PV nodes)"] = Option(1, 0, 2);
o["Passed Pawn Extension (non-PV nodes)"] = Option(0, 0, 2);
o["Pawn Endgame Extension (PV nodes)"] = Option(2, 0, 2);
o["Pawn Endgame Extension (non-PV nodes)"] = Option(2, 0, 2);
o["Full Depth Moves (PV nodes)"] = Option(10, 1, 100);
o["Full Depth Moves (non-PV nodes)"] = Option(3, 1, 100);
o["Threat Depth"] = Option(5, 0, 100);
o["Randomness"] = Option(0, 0, 10);
o["Minimum Split Depth"] = Option(4, 4, 7);
o["Maximum Number of Threads per Split Point"] = Option(5, 4, 8);
o["Threads"] = Option(1, 1, THREAD_MAX);
o["Hash"] = Option(32, 4, 8192);
o["Clear Hash"] = Option(false, BUTTON);
o["New Game"] = Option(false, BUTTON);
o["Ponder"] = Option(true);
o["OwnBook"] = Option(true);
o["MultiPV"] = Option(1, 1, 500);
o["UCI_ShowCurrLine"] = Option(false);
o["UCI_Chess960"] = Option(false);
o["UCI_AnalyseMode"] = Option(false);
// Any option should know its name so to be easily printed
for (Options::iterator it = o.begin(); it != o.end(); ++it)
it->second.name = it->first;
if (c1 != c2)
return c1 < c2;
}
///
/// Variables
///
Options options;
// stringify converts a value of type T to a std::string
template<typename T>
string stringify(const T& v) {
std::ostringstream ss;
ss << v;
return ss.str();
}
// get_option_value implements the various get_option_value_<type>
// functions defined later, because only the option value
// type changes a template seems a proper solution.
template<typename T>
T get_option_value(const string& optionName) {
T ret = T();
if (options.find(optionName) == options.end())
return ret;
std::istringstream ss(options[optionName].currentValue);
ss >> ret;
return ret;
}
// Specialization for std::string where instruction 'ss >> ret;'
// would erroneusly tokenize a string with spaces.
template<>
string get_option_value<string>(const string& optionName) {
if (options.find(optionName) == options.end())
return string();
return options[optionName].currentValue;
}
return s1.size() < s2.size();
}
////
//// Functions
////
/// init_uci_options() initializes the UCI options. Currently, the only
/// thing this function does is to initialize the default value of the
/// "Threads" parameter to the number of available CPU cores.
// stringify() converts a numeric value of type T to a std::string
template<typename T>
static string stringify(const T& v) {
void init_uci_options() {
std::ostringstream ss;
ss << v;
return ss.str();
}
load_defaults(options);
// Set optimal value for parameter "Minimum Split Depth"
// according to number of available cores.
assert(options.find("Threads") != options.end());
assert(options.find("Minimum Split Depth") != options.end());
/// OptionsMap c'tor initializes the UCI options to their hard coded default
/// values and initializes the default value of "Threads" and "Minimum Split Depth"
/// parameters according to the number of CPU cores.
Option& thr = options["Threads"];
Option& msd = options["Minimum Split Depth"];
OptionsMap::OptionsMap() {
OptionsMap& o = *this;
o["Use Search Log"] = UCIOption(false);
o["Search Log Filename"] = UCIOption("SearchLog.txt");
o["Book File"] = UCIOption("book.bin");
o["Best Book Move"] = UCIOption(false);
o["Mobility (Middle Game)"] = UCIOption(100, 0, 200);
o["Mobility (Endgame)"] = UCIOption(100, 0, 200);
o["Passed Pawns (Middle Game)"] = UCIOption(100, 0, 200);
o["Passed Pawns (Endgame)"] = UCIOption(100, 0, 200);
o["Space"] = UCIOption(100, 0, 200);
o["Aggressiveness"] = UCIOption(100, 0, 200);
o["Cowardice"] = UCIOption(100, 0, 200);
o["Minimum Split Depth"] = UCIOption(4, 4, 7);
o["Maximum Number of Threads per Split Point"] = UCIOption(5, 4, 8);
o["Threads"] = UCIOption(1, 1, MAX_THREADS);
o["Use Sleeping Threads"] = UCIOption(false);
o["Hash"] = UCIOption(32, 4, 8192);
o["Clear Hash"] = UCIOption(false, "button");
o["Ponder"] = UCIOption(true);
o["OwnBook"] = UCIOption(true);
o["MultiPV"] = UCIOption(1, 1, 500);
o["Skill Level"] = UCIOption(20, 0, 20);
o["Emergency Move Horizon"] = UCIOption(40, 0, 50);
o["Emergency Base Time"] = UCIOption(200, 0, 30000);
o["Emergency Move Time"] = UCIOption(70, 0, 5000);
o["Minimum Thinking Time"] = UCIOption(20, 0, 5000);
o["UCI_Chess960"] = UCIOption(false);
o["UCI_AnalyseMode"] = UCIOption(false);
// Set some SMP parameters accordingly to the detected CPU count
UCIOption& thr = o["Threads"];
UCIOption& msd = o["Minimum Split Depth"];
thr.defaultValue = thr.currentValue = stringify(cpu_count());
@@ -211,151 +107,64 @@ void init_uci_options() {
}
/// print_uci_options() prints all the UCI options to the standard output,
/// in the format defined by the UCI protocol.
/// OptionsMap::print_all() returns a string with all the UCI options in chronological
/// insertion order (the idx field) and in the format defined by the UCI protocol.
void print_uci_options() {
string OptionsMap::print_all() const {
static const char optionTypeName[][16] = {
"spin", "combo", "check", "string", "button"
};
std::stringstream s;
// Build up a vector out of the options map and sort it according to idx
// field, that is the chronological insertion order in options map.
std::vector<Option> vec;
for (Options::const_iterator it = options.begin(); it != options.end(); ++it)
vec.push_back(it->second);
for (size_t i = 0; i <= size(); i++)
for (OptionsMap::const_iterator it = begin(); it != end(); ++it)
if (it->second.idx == i)
{
const UCIOption& o = it->second;
s << "\noption name " << it->first << " type " << o.type;
std::sort(vec.begin(), vec.end());
if (o.type != "button")
s << " default " << o.defaultValue;
for (std::vector<Option>::const_iterator it = vec.begin(); it != vec.end(); ++it)
{
std::cout << "\noption name " << it->name
<< " type " << optionTypeName[it->type];
if (o.type == "spin")
s << " min " << o.minValue << " max " << o.maxValue;
if (it->type == BUTTON)
continue;
if (it->type == CHECK)
std::cout << " default " << (it->defaultValue == "1" ? "true" : "false");
else
std::cout << " default " << it->defaultValue;
if (it->type == SPIN)
std::cout << " min " << it->minValue << " max " << it->maxValue;
else if (it->type == COMBO)
for (ComboValues::const_iterator itc = it->comboValues.begin();
itc != it->comboValues.end(); ++itc)
std::cout << " var " << *itc;
}
std::cout << std::endl;
break;
}
return s.str();
}
/// get_option_value_bool() returns the current value of a UCI parameter of
/// type "check".
/// Option class c'tors
bool get_option_value_bool(const string& optionName) {
UCIOption::UCIOption(const char* def) : type("string"), minValue(0), maxValue(0), idx(Options.size())
{ defaultValue = currentValue = def; }
return get_option_value<bool>(optionName);
}
UCIOption::UCIOption(bool def, string t) : type(t), minValue(0), maxValue(0), idx(Options.size())
{ defaultValue = currentValue = (def ? "true" : "false"); }
UCIOption::UCIOption(int def, int minv, int maxv) : type("spin"), minValue(minv), maxValue(maxv), idx(Options.size())
{ defaultValue = currentValue = stringify(def); }
/// get_option_value_int() returns the value of a UCI parameter as an integer.
/// Normally, this function will be used for a parameter of type "spin", but
/// it could also be used with a "combo" parameter, where all the available
/// values are integers.
/// set_value() updates currentValue of the Option object. Normally it's up to
/// the GUI to check for option's limits, but we could receive the new value
/// directly from the user by teminal window. So let's check the bounds anyway.
int get_option_value_int(const string& optionName) {
void UCIOption::set_value(const string& v) {
return get_option_value<int>(optionName);
}
assert(!type.empty());
/// 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".
string get_option_value_string(const string& optionName) {
return get_option_value<string>(optionName);
}
/// set_option_value() inserts a new value for a UCI parameter. Note that
/// the function does not check that the new value is legal for the given
/// parameter: This is assumed to be the responsibility of the GUI.
void set_option_value(const string& name, const string& value) {
// 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 (options.find(name) == options.end())
{
std::cout << "No such option: " << name << std::endl;
return;
}
// Normally it's up to the GUI to check for option's limits,
// but we could receive the new value directly from the user
// by teminal window. So let's check the bounds anyway.
Option& opt = options[name];
if (opt.type == CHECK && v != "0" && v != "1")
if (v.empty())
return;
else if (opt.type == SPIN)
if ((type == "check" || type == "button") != (v == "true" || v == "false"))
return;
if (type == "spin")
{
int val = atoi(v.c_str());
if (val < opt.minValue || val > opt.maxValue)
if (val < minValue || val > maxValue)
return;
}
opt.currentValue = v;
}
/// push_button() is used to tell the engine that a UCI parameter of type
/// "button" has been selected:
void push_button(const string& buttonName) {
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 {
// Define constructors of Option class.
Option::Option() {} // To allow insertion in a std::map
Option::Option(const char* def, OptionType t)
: defaultValue(def), currentValue(def), type(t), idx(options.size()), minValue(0), maxValue(0) {}
Option::Option(bool def, OptionType t)
: defaultValue(stringify(def)), currentValue(stringify(def)), type(t), idx(options.size()), minValue(0), maxValue(0) {}
Option::Option(int def, int minv, int maxv)
: defaultValue(stringify(def)), currentValue(stringify(def)), type(SPIN), idx(options.size()), minValue(minv), maxValue(maxv) {}
currentValue = v;
}
+58 -17
View File
@@ -1,7 +1,7 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2009 Marco Costalba
Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,28 +17,69 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined(UCIOPTION_H_INCLUDED)
#define UCIOPTION_H_INCLUDED
////
//// Includes
////
#include <cassert>
#include <cstdlib>
#include <map>
#include <string>
////
//// Prototypes
////
class UCIOption {
public:
UCIOption() {} // To be used in a std::map
UCIOption(const char* defaultValue);
UCIOption(bool defaultValue, std::string type = "check");
UCIOption(int defaultValue, int minValue, int maxValue);
extern void init_uci_options();
extern void print_uci_options();
extern bool get_option_value_bool(const std::string& optionName);
extern int get_option_value_int(const std::string& optionName);
extern std::string get_option_value_string(const std::string& optionName);
extern bool button_was_pressed(const std::string& buttonName);
extern void set_option_value(const std::string& optionName,const std::string& newValue);
extern void push_button(const std::string& buttonName);
void set_value(const std::string& v);
template<typename T> T value() const;
private:
friend class OptionsMap;
std::string defaultValue, currentValue, type;
int minValue, maxValue;
size_t idx;
};
/// Custom comparator because UCI options should not be case sensitive
struct CaseInsensitiveLess {
bool operator() (const std::string&, const std::string&) const;
};
/// Our options container is actually a map with a customized c'tor
class OptionsMap : public std::map<std::string, UCIOption, CaseInsensitiveLess> {
public:
OptionsMap();
std::string print_all() const;
};
extern OptionsMap Options;
/// Option::value() definition and specializations
template<typename T>
T UCIOption::value() const {
assert(type == "spin");
return T(atoi(currentValue.c_str()));
}
template<>
inline std::string UCIOption::value<std::string>() const {
assert(type == "string");
return currentValue;
}
template<>
inline bool UCIOption::value<bool>() const {
assert(type == "check" || type == "button");
return currentValue == "true";
}
#endif // !defined(UCIOPTION_H_INCLUDED)
-96
View File
@@ -1,96 +0,0 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-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 <sstream>
#include <string>
#include "value.h"
////
//// Functions
////
/// value_to_tt() adjusts a mate score from "plies to mate from the root" to
/// "plies to mate from the current ply". Non-mate scores are unchanged.
/// The function is called before storing a value to the transposition table.
Value value_to_tt(Value v, int ply) {
if(v >= value_mate_in(100))
return v + ply;
else if(v <= value_mated_in(100))
return v - ply;
else
return v;
}
/// value_from_tt() is the inverse of value_to_tt(): It adjusts a mate score
/// from the transposition table to a mate score corrected for the current
/// ply depth.
Value value_from_tt(Value v, int ply) {
if(v >= value_mate_in(100))
return v - ply;
else if(v <= value_mated_in(100))
return v + ply;
else
return v;
}
/// value_to_centipawns() converts a value from Stockfish's somewhat unusual
/// scale of pawn = 256 to the more conventional pawn = 100.
int value_to_centipawns(Value v) {
return (int(v) * 100) / int(PawnValueMidgame);
}
/// value_from_centipawns() converts a centipawn value to Stockfish's internal
/// evaluation scale. It's used when reading the values of UCI options
/// containing material values (e.g. futility pruning margins).
Value value_from_centipawns(int cp) {
return Value((cp * 256) / 100);
}
/// value_to_string() converts a value to a string suitable for use with the
/// UCI protocol.
const std::string value_to_string(Value v) {
std::stringstream s;
if(abs(v) < VALUE_MATE - 200)
s << "cp " << value_to_centipawns(v);
else {
s << "mate ";
if(v > 0)
s << (VALUE_MATE - v + 1) / 2;
else
s << -(VALUE_MATE + v) / 2;
}
return s.str();
}
-208
View File
@@ -1,208 +0,0 @@
/*
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(VALUE_H_INCLUDED)
#define VALUE_H_INCLUDED
////
//// Includes
////
#include "piece.h"
////
//// Types
////
enum ValueType {
VALUE_TYPE_NONE = 0,
VALUE_TYPE_UPPER = 1, // Upper bound
VALUE_TYPE_LOWER = 2, // Lower bound
VALUE_TYPE_EXACT = 3, // Exact score
VALUE_TYPE_EVAL = 4, // Evaluation cache
VALUE_TYPE_EV_UP = 5, // Evaluation cache for upper bound
VALUE_TYPE_EV_LO = 6 // Evaluation cache for lower bound
};
enum Value {
VALUE_DRAW = 0,
VALUE_KNOWN_WIN = 15000,
VALUE_MATE = 30000,
VALUE_INFINITE = 30001,
VALUE_NONE = 30002,
VALUE_ENSURE_SIGNED = -1
};
/// Score enum keeps a midgame and an endgame value in a single
/// integer (enum), first LSB 16 bits are used to store endgame
/// value, while upper bits are used for midgame value.
// Compiler is free to choose the enum type as long as can keep
// its data, so ensure Score to be an integer type.
enum Score { ENSURE_32_BITS_SIZE_P = (1 << 16), ENSURE_32_BITS_SIZE_N = -(1 << 16)};
// Extracting the _signed_ lower and upper 16 bits it not so trivial
// because according to the standard a simple cast to short is
// implementation defined and so is a right shift of a signed integer.
inline Value mg_value(Score s) { return Value(((int(s) + 32768) & ~0xffff) / 0x10000); }
// Unfortunatly on Intel 64 bit we have a small speed regression, so use a faster code in
// this case, although not 100% standard compliant it seems to work for Intel and MSVC.
#if defined(IS_64BIT) && (!defined(__GNUC__) || defined(__INTEL_COMPILER))
inline Value eg_value(Score s) { return Value(int16_t(s & 0xffff)); }
#else
inline Value eg_value(Score s) { return Value((int)(unsigned(s) & 0x7fffu) - (int)(unsigned(s) & 0x8000u)); }
#endif
inline Score make_score(int mg, int eg) { return Score((mg << 16) + eg); }
inline Score operator-(Score s) { return Score(-int(s)); }
inline Score operator+(Score s1, Score s2) { return Score(int(s1) + int(s2)); }
inline Score operator-(Score s1, Score s2) { return Score(int(s1) - int(s2)); }
inline void operator+=(Score& s1, Score s2) { s1 = Score(int(s1) + int(s2)); }
inline void operator-=(Score& s1, Score s2) { s1 = Score(int(s1) - int(s2)); }
inline Score operator*(int i, Score s) { return Score(i * int(s)); }
// Division must be handled separately for each term
inline Score operator/(Score s, int i) { return make_score(mg_value(s) / i, eg_value(s) / i); }
// Only declared but not defined. We don't want to multiply two scores due to
// a very high risk of overflow. So user should explicitly convert to integer.
inline Score operator*(Score s1, Score s2);
////
//// Constants and variables
////
/// Piece values, middle game and endgame
/// Important: If the material values are changed, one must also
/// adjust the piece square tables, and the method game_phase() in the
/// Position class!
///
/// Values modified by Joona Kiiski
const Value PawnValueMidgame = Value(0x0C6);
const Value PawnValueEndgame = Value(0x102);
const Value KnightValueMidgame = Value(0x331);
const Value KnightValueEndgame = Value(0x34E);
const Value BishopValueMidgame = Value(0x344);
const Value BishopValueEndgame = Value(0x359);
const Value RookValueMidgame = Value(0x4F6);
const Value RookValueEndgame = Value(0x4FE);
const Value QueenValueMidgame = Value(0x9D9);
const Value QueenValueEndgame = Value(0x9FE);
const Value PieceValueMidgame[17] = {
Value(0),
PawnValueMidgame, KnightValueMidgame, BishopValueMidgame,
RookValueMidgame, QueenValueMidgame,
Value(0), Value(0), Value(0),
PawnValueMidgame, KnightValueMidgame, BishopValueMidgame,
RookValueMidgame, QueenValueMidgame,
Value(0), Value(0), Value(0)
};
const Value PieceValueEndgame[17] = {
Value(0),
PawnValueEndgame, KnightValueEndgame, BishopValueEndgame,
RookValueEndgame, QueenValueEndgame,
Value(0), Value(0), Value(0),
PawnValueEndgame, KnightValueEndgame, BishopValueEndgame,
RookValueEndgame, QueenValueEndgame,
Value(0), Value(0), Value(0)
};
/// Bonus for having the side to move (modified by Joona Kiiski)
const Score TempoValue = make_score(48, 22);
////
//// Inline functions
////
inline Value operator+ (Value v, int i) { return Value(int(v) + i); }
inline Value operator+ (Value v1, Value v2) { return Value(int(v1) + int(v2)); }
inline void operator+= (Value &v1, Value v2) {
v1 = Value(int(v1) + int(v2));
}
inline Value operator- (Value v, int i) { return Value(int(v) - i); }
inline Value operator- (Value v) { return Value(-int(v)); }
inline Value operator- (Value v1, Value v2) { return Value(int(v1) - int(v2)); }
inline void operator-= (Value &v1, Value v2) {
v1 = Value(int(v1) - int(v2));
}
inline Value operator* (Value v, int i) { return Value(int(v) * i); }
inline void operator*= (Value &v, int i) { v = Value(int(v) * i); }
inline Value operator* (int i, Value v) { return Value(int(v) * i); }
inline Value operator/ (Value v, int i) { return Value(int(v) / i); }
inline void operator/= (Value &v, int i) { v = Value(int(v) / i); }
inline Value value_mate_in(int ply) {
return Value(VALUE_MATE - Value(ply));
}
inline Value value_mated_in(int ply) {
return Value(-VALUE_MATE + Value(ply));
}
inline bool is_upper_bound(ValueType vt) {
return (int(vt) & int(VALUE_TYPE_UPPER)) != 0;
}
inline bool is_lower_bound(ValueType vt) {
return (int(vt) & int(VALUE_TYPE_LOWER)) != 0;
}
inline Value piece_value_midgame(PieceType pt) {
return PieceValueMidgame[pt];
}
inline Value piece_value_endgame(PieceType pt) {
return PieceValueEndgame[pt];
}
inline Value piece_value_midgame(Piece p) {
return PieceValueMidgame[p];
}
inline Value piece_value_endgame(Piece p) {
return PieceValueEndgame[p];
}
////
//// Prototypes
////
extern Value value_to_tt(Value v, int ply);
extern Value value_from_tt(Value v, int ply);
extern int value_to_centipawns(Value v);
extern Value value_from_centipawns(int cp);
extern const std::string value_to_string(Value v);
#endif // !defined(VALUE_H_INCLUDED)