Spaces:
Running
Running
Upload 92 files
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- .gitattributes +4 -0
- stockfish-4-win/.DS_Store +0 -0
- stockfish-4-win/Copying.txt +674 -0
- stockfish-4-win/Readme.md +70 -0
- stockfish-4-win/Windows/stockfish_4_32bit.exe +3 -0
- stockfish-4-win/Windows/stockfish_4_x64.exe +3 -0
- stockfish-4-win/Windows/stockfish_4_x64_modern.exe +3 -0
- stockfish-4-win/Windows/stockfish_4_x64_modern_sse42.exe +3 -0
- stockfish-4-win/logo.bmp +0 -0
- stockfish-4-win/polyglot.ini +47 -0
- stockfish-4-win/src/Makefile +565 -0
- stockfish-4-win/src/benchmark.cpp +145 -0
- stockfish-4-win/src/bitbase.cpp +175 -0
- stockfish-4-win/src/bitboard.cpp +339 -0
- stockfish-4-win/src/bitboard.h +322 -0
- stockfish-4-win/src/bitcount.h +105 -0
- stockfish-4-win/src/book.cpp +478 -0
- stockfish-4-win/src/book.h +45 -0
- stockfish-4-win/src/endgame.cpp +964 -0
- stockfish-4-win/src/endgame.h +125 -0
- stockfish-4-win/src/evaluate.cpp +1185 -0
- stockfish-4-win/src/evaluate.h +35 -0
- stockfish-4-win/src/main.cpp +52 -0
- stockfish-4-win/src/material.cpp +292 -0
- stockfish-4-win/src/material.h +77 -0
- stockfish-4-win/src/misc.cpp +204 -0
- stockfish-4-win/src/misc.h +68 -0
- stockfish-4-win/src/movegen.cpp +423 -0
- stockfish-4-win/src/movegen.h +58 -0
- stockfish-4-win/src/movepick.cpp +377 -0
- stockfish-4-win/src/movepick.h +110 -0
- stockfish-4-win/src/notation.cpp +263 -0
- stockfish-4-win/src/notation.h +35 -0
- stockfish-4-win/src/pawns.cpp +281 -0
- stockfish-4-win/src/pawns.h +78 -0
- stockfish-4-win/src/platform.h +116 -0
- stockfish-4-win/src/position.cpp +1453 -0
- stockfish-4-win/src/position.h +459 -0
- stockfish-4-win/src/psqtab.h +98 -0
- stockfish-4-win/src/rkiss.h +74 -0
- stockfish-4-win/src/search.cpp +1810 -0
- stockfish-4-win/src/search.h +112 -0
- stockfish-4-win/src/thread.cpp +394 -0
- stockfish-4-win/src/thread.h +178 -0
- stockfish-4-win/src/timeman.cpp +162 -0
- stockfish-4-win/src/timeman.h +39 -0
- stockfish-4-win/src/tt.cpp +121 -0
- stockfish-4-win/src/tt.h +118 -0
- stockfish-4-win/src/types.h +443 -0
- stockfish-4-win/src/uci.cpp +219 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,7 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
stockfish-4-win/Windows/stockfish_4_32bit.exe filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
stockfish-4-win/Windows/stockfish_4_x64_modern_sse42.exe filter=lfs diff=lfs merge=lfs -text
|
| 38 |
+
stockfish-4-win/Windows/stockfish_4_x64_modern.exe filter=lfs diff=lfs merge=lfs -text
|
| 39 |
+
stockfish-4-win/Windows/stockfish_4_x64.exe filter=lfs diff=lfs merge=lfs -text
|
stockfish-4-win/.DS_Store
ADDED
|
Binary file (6.15 kB). View file
|
|
|
stockfish-4-win/Copying.txt
ADDED
|
@@ -0,0 +1,674 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
GNU GENERAL PUBLIC LICENSE
|
| 2 |
+
Version 3, 29 June 2007
|
| 3 |
+
|
| 4 |
+
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
| 5 |
+
Everyone is permitted to copy and distribute verbatim copies
|
| 6 |
+
of this license document, but changing it is not allowed.
|
| 7 |
+
|
| 8 |
+
Preamble
|
| 9 |
+
|
| 10 |
+
The GNU General Public License is a free, copyleft license for
|
| 11 |
+
software and other kinds of works.
|
| 12 |
+
|
| 13 |
+
The licenses for most software and other practical works are designed
|
| 14 |
+
to take away your freedom to share and change the works. By contrast,
|
| 15 |
+
the GNU General Public License is intended to guarantee your freedom to
|
| 16 |
+
share and change all versions of a program--to make sure it remains free
|
| 17 |
+
software for all its users. We, the Free Software Foundation, use the
|
| 18 |
+
GNU General Public License for most of our software; it applies also to
|
| 19 |
+
any other work released this way by its authors. You can apply it to
|
| 20 |
+
your programs, too.
|
| 21 |
+
|
| 22 |
+
When we speak of free software, we are referring to freedom, not
|
| 23 |
+
price. Our General Public Licenses are designed to make sure that you
|
| 24 |
+
have the freedom to distribute copies of free software (and charge for
|
| 25 |
+
them if you wish), that you receive source code or can get it if you
|
| 26 |
+
want it, that you can change the software or use pieces of it in new
|
| 27 |
+
free programs, and that you know you can do these things.
|
| 28 |
+
|
| 29 |
+
To protect your rights, we need to prevent others from denying you
|
| 30 |
+
these rights or asking you to surrender the rights. Therefore, you have
|
| 31 |
+
certain responsibilities if you distribute copies of the software, or if
|
| 32 |
+
you modify it: responsibilities to respect the freedom of others.
|
| 33 |
+
|
| 34 |
+
For example, if you distribute copies of such a program, whether
|
| 35 |
+
gratis or for a fee, you must pass on to the recipients the same
|
| 36 |
+
freedoms that you received. You must make sure that they, too, receive
|
| 37 |
+
or can get the source code. And you must show them these terms so they
|
| 38 |
+
know their rights.
|
| 39 |
+
|
| 40 |
+
Developers that use the GNU GPL protect your rights with two steps:
|
| 41 |
+
(1) assert copyright on the software, and (2) offer you this License
|
| 42 |
+
giving you legal permission to copy, distribute and/or modify it.
|
| 43 |
+
|
| 44 |
+
For the developers' and authors' protection, the GPL clearly explains
|
| 45 |
+
that there is no warranty for this free software. For both users' and
|
| 46 |
+
authors' sake, the GPL requires that modified versions be marked as
|
| 47 |
+
changed, so that their problems will not be attributed erroneously to
|
| 48 |
+
authors of previous versions.
|
| 49 |
+
|
| 50 |
+
Some devices are designed to deny users access to install or run
|
| 51 |
+
modified versions of the software inside them, although the manufacturer
|
| 52 |
+
can do so. This is fundamentally incompatible with the aim of
|
| 53 |
+
protecting users' freedom to change the software. The systematic
|
| 54 |
+
pattern of such abuse occurs in the area of products for individuals to
|
| 55 |
+
use, which is precisely where it is most unacceptable. Therefore, we
|
| 56 |
+
have designed this version of the GPL to prohibit the practice for those
|
| 57 |
+
products. If such problems arise substantially in other domains, we
|
| 58 |
+
stand ready to extend this provision to those domains in future versions
|
| 59 |
+
of the GPL, as needed to protect the freedom of users.
|
| 60 |
+
|
| 61 |
+
Finally, every program is threatened constantly by software patents.
|
| 62 |
+
States should not allow patents to restrict development and use of
|
| 63 |
+
software on general-purpose computers, but in those that do, we wish to
|
| 64 |
+
avoid the special danger that patents applied to a free program could
|
| 65 |
+
make it effectively proprietary. To prevent this, the GPL assures that
|
| 66 |
+
patents cannot be used to render the program non-free.
|
| 67 |
+
|
| 68 |
+
The precise terms and conditions for copying, distribution and
|
| 69 |
+
modification follow.
|
| 70 |
+
|
| 71 |
+
TERMS AND CONDITIONS
|
| 72 |
+
|
| 73 |
+
0. Definitions.
|
| 74 |
+
|
| 75 |
+
"This License" refers to version 3 of the GNU General Public License.
|
| 76 |
+
|
| 77 |
+
"Copyright" also means copyright-like laws that apply to other kinds of
|
| 78 |
+
works, such as semiconductor masks.
|
| 79 |
+
|
| 80 |
+
"The Program" refers to any copyrightable work licensed under this
|
| 81 |
+
License. Each licensee is addressed as "you". "Licensees" and
|
| 82 |
+
"recipients" may be individuals or organizations.
|
| 83 |
+
|
| 84 |
+
To "modify" a work means to copy from or adapt all or part of the work
|
| 85 |
+
in a fashion requiring copyright permission, other than the making of an
|
| 86 |
+
exact copy. The resulting work is called a "modified version" of the
|
| 87 |
+
earlier work or a work "based on" the earlier work.
|
| 88 |
+
|
| 89 |
+
A "covered work" means either the unmodified Program or a work based
|
| 90 |
+
on the Program.
|
| 91 |
+
|
| 92 |
+
To "propagate" a work means to do anything with it that, without
|
| 93 |
+
permission, would make you directly or secondarily liable for
|
| 94 |
+
infringement under applicable copyright law, except executing it on a
|
| 95 |
+
computer or modifying a private copy. Propagation includes copying,
|
| 96 |
+
distribution (with or without modification), making available to the
|
| 97 |
+
public, and in some countries other activities as well.
|
| 98 |
+
|
| 99 |
+
To "convey" a work means any kind of propagation that enables other
|
| 100 |
+
parties to make or receive copies. Mere interaction with a user through
|
| 101 |
+
a computer network, with no transfer of a copy, is not conveying.
|
| 102 |
+
|
| 103 |
+
An interactive user interface displays "Appropriate Legal Notices"
|
| 104 |
+
to the extent that it includes a convenient and prominently visible
|
| 105 |
+
feature that (1) displays an appropriate copyright notice, and (2)
|
| 106 |
+
tells the user that there is no warranty for the work (except to the
|
| 107 |
+
extent that warranties are provided), that licensees may convey the
|
| 108 |
+
work under this License, and how to view a copy of this License. If
|
| 109 |
+
the interface presents a list of user commands or options, such as a
|
| 110 |
+
menu, a prominent item in the list meets this criterion.
|
| 111 |
+
|
| 112 |
+
1. Source Code.
|
| 113 |
+
|
| 114 |
+
The "source code" for a work means the preferred form of the work
|
| 115 |
+
for making modifications to it. "Object code" means any non-source
|
| 116 |
+
form of a work.
|
| 117 |
+
|
| 118 |
+
A "Standard Interface" means an interface that either is an official
|
| 119 |
+
standard defined by a recognized standards body, or, in the case of
|
| 120 |
+
interfaces specified for a particular programming language, one that
|
| 121 |
+
is widely used among developers working in that language.
|
| 122 |
+
|
| 123 |
+
The "System Libraries" of an executable work include anything, other
|
| 124 |
+
than the work as a whole, that (a) is included in the normal form of
|
| 125 |
+
packaging a Major Component, but which is not part of that Major
|
| 126 |
+
Component, and (b) serves only to enable use of the work with that
|
| 127 |
+
Major Component, or to implement a Standard Interface for which an
|
| 128 |
+
implementation is available to the public in source code form. A
|
| 129 |
+
"Major Component", in this context, means a major essential component
|
| 130 |
+
(kernel, window system, and so on) of the specific operating system
|
| 131 |
+
(if any) on which the executable work runs, or a compiler used to
|
| 132 |
+
produce the work, or an object code interpreter used to run it.
|
| 133 |
+
|
| 134 |
+
The "Corresponding Source" for a work in object code form means all
|
| 135 |
+
the source code needed to generate, install, and (for an executable
|
| 136 |
+
work) run the object code and to modify the work, including scripts to
|
| 137 |
+
control those activities. However, it does not include the work's
|
| 138 |
+
System Libraries, or general-purpose tools or generally available free
|
| 139 |
+
programs which are used unmodified in performing those activities but
|
| 140 |
+
which are not part of the work. For example, Corresponding Source
|
| 141 |
+
includes interface definition files associated with source files for
|
| 142 |
+
the work, and the source code for shared libraries and dynamically
|
| 143 |
+
linked subprograms that the work is specifically designed to require,
|
| 144 |
+
such as by intimate data communication or control flow between those
|
| 145 |
+
subprograms and other parts of the work.
|
| 146 |
+
|
| 147 |
+
The Corresponding Source need not include anything that users
|
| 148 |
+
can regenerate automatically from other parts of the Corresponding
|
| 149 |
+
Source.
|
| 150 |
+
|
| 151 |
+
The Corresponding Source for a work in source code form is that
|
| 152 |
+
same work.
|
| 153 |
+
|
| 154 |
+
2. Basic Permissions.
|
| 155 |
+
|
| 156 |
+
All rights granted under this License are granted for the term of
|
| 157 |
+
copyright on the Program, and are irrevocable provided the stated
|
| 158 |
+
conditions are met. This License explicitly affirms your unlimited
|
| 159 |
+
permission to run the unmodified Program. The output from running a
|
| 160 |
+
covered work is covered by this License only if the output, given its
|
| 161 |
+
content, constitutes a covered work. This License acknowledges your
|
| 162 |
+
rights of fair use or other equivalent, as provided by copyright law.
|
| 163 |
+
|
| 164 |
+
You may make, run and propagate covered works that you do not
|
| 165 |
+
convey, without conditions so long as your license otherwise remains
|
| 166 |
+
in force. You may convey covered works to others for the sole purpose
|
| 167 |
+
of having them make modifications exclusively for you, or provide you
|
| 168 |
+
with facilities for running those works, provided that you comply with
|
| 169 |
+
the terms of this License in conveying all material for which you do
|
| 170 |
+
not control copyright. Those thus making or running the covered works
|
| 171 |
+
for you must do so exclusively on your behalf, under your direction
|
| 172 |
+
and control, on terms that prohibit them from making any copies of
|
| 173 |
+
your copyrighted material outside their relationship with you.
|
| 174 |
+
|
| 175 |
+
Conveying under any other circumstances is permitted solely under
|
| 176 |
+
the conditions stated below. Sublicensing is not allowed; section 10
|
| 177 |
+
makes it unnecessary.
|
| 178 |
+
|
| 179 |
+
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
| 180 |
+
|
| 181 |
+
No covered work shall be deemed part of an effective technological
|
| 182 |
+
measure under any applicable law fulfilling obligations under article
|
| 183 |
+
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
| 184 |
+
similar laws prohibiting or restricting circumvention of such
|
| 185 |
+
measures.
|
| 186 |
+
|
| 187 |
+
When you convey a covered work, you waive any legal power to forbid
|
| 188 |
+
circumvention of technological measures to the extent such circumvention
|
| 189 |
+
is effected by exercising rights under this License with respect to
|
| 190 |
+
the covered work, and you disclaim any intention to limit operation or
|
| 191 |
+
modification of the work as a means of enforcing, against the work's
|
| 192 |
+
users, your or third parties' legal rights to forbid circumvention of
|
| 193 |
+
technological measures.
|
| 194 |
+
|
| 195 |
+
4. Conveying Verbatim Copies.
|
| 196 |
+
|
| 197 |
+
You may convey verbatim copies of the Program's source code as you
|
| 198 |
+
receive it, in any medium, provided that you conspicuously and
|
| 199 |
+
appropriately publish on each copy an appropriate copyright notice;
|
| 200 |
+
keep intact all notices stating that this License and any
|
| 201 |
+
non-permissive terms added in accord with section 7 apply to the code;
|
| 202 |
+
keep intact all notices of the absence of any warranty; and give all
|
| 203 |
+
recipients a copy of this License along with the Program.
|
| 204 |
+
|
| 205 |
+
You may charge any price or no price for each copy that you convey,
|
| 206 |
+
and you may offer support or warranty protection for a fee.
|
| 207 |
+
|
| 208 |
+
5. Conveying Modified Source Versions.
|
| 209 |
+
|
| 210 |
+
You may convey a work based on the Program, or the modifications to
|
| 211 |
+
produce it from the Program, in the form of source code under the
|
| 212 |
+
terms of section 4, provided that you also meet all of these conditions:
|
| 213 |
+
|
| 214 |
+
a) The work must carry prominent notices stating that you modified
|
| 215 |
+
it, and giving a relevant date.
|
| 216 |
+
|
| 217 |
+
b) The work must carry prominent notices stating that it is
|
| 218 |
+
released under this License and any conditions added under section
|
| 219 |
+
7. This requirement modifies the requirement in section 4 to
|
| 220 |
+
"keep intact all notices".
|
| 221 |
+
|
| 222 |
+
c) You must license the entire work, as a whole, under this
|
| 223 |
+
License to anyone who comes into possession of a copy. This
|
| 224 |
+
License will therefore apply, along with any applicable section 7
|
| 225 |
+
additional terms, to the whole of the work, and all its parts,
|
| 226 |
+
regardless of how they are packaged. This License gives no
|
| 227 |
+
permission to license the work in any other way, but it does not
|
| 228 |
+
invalidate such permission if you have separately received it.
|
| 229 |
+
|
| 230 |
+
d) If the work has interactive user interfaces, each must display
|
| 231 |
+
Appropriate Legal Notices; however, if the Program has interactive
|
| 232 |
+
interfaces that do not display Appropriate Legal Notices, your
|
| 233 |
+
work need not make them do so.
|
| 234 |
+
|
| 235 |
+
A compilation of a covered work with other separate and independent
|
| 236 |
+
works, which are not by their nature extensions of the covered work,
|
| 237 |
+
and which are not combined with it such as to form a larger program,
|
| 238 |
+
in or on a volume of a storage or distribution medium, is called an
|
| 239 |
+
"aggregate" if the compilation and its resulting copyright are not
|
| 240 |
+
used to limit the access or legal rights of the compilation's users
|
| 241 |
+
beyond what the individual works permit. Inclusion of a covered work
|
| 242 |
+
in an aggregate does not cause this License to apply to the other
|
| 243 |
+
parts of the aggregate.
|
| 244 |
+
|
| 245 |
+
6. Conveying Non-Source Forms.
|
| 246 |
+
|
| 247 |
+
You may convey a covered work in object code form under the terms
|
| 248 |
+
of sections 4 and 5, provided that you also convey the
|
| 249 |
+
machine-readable Corresponding Source under the terms of this License,
|
| 250 |
+
in one of these ways:
|
| 251 |
+
|
| 252 |
+
a) Convey the object code in, or embodied in, a physical product
|
| 253 |
+
(including a physical distribution medium), accompanied by the
|
| 254 |
+
Corresponding Source fixed on a durable physical medium
|
| 255 |
+
customarily used for software interchange.
|
| 256 |
+
|
| 257 |
+
b) Convey the object code in, or embodied in, a physical product
|
| 258 |
+
(including a physical distribution medium), accompanied by a
|
| 259 |
+
written offer, valid for at least three years and valid for as
|
| 260 |
+
long as you offer spare parts or customer support for that product
|
| 261 |
+
model, to give anyone who possesses the object code either (1) a
|
| 262 |
+
copy of the Corresponding Source for all the software in the
|
| 263 |
+
product that is covered by this License, on a durable physical
|
| 264 |
+
medium customarily used for software interchange, for a price no
|
| 265 |
+
more than your reasonable cost of physically performing this
|
| 266 |
+
conveying of source, or (2) access to copy the
|
| 267 |
+
Corresponding Source from a network server at no charge.
|
| 268 |
+
|
| 269 |
+
c) Convey individual copies of the object code with a copy of the
|
| 270 |
+
written offer to provide the Corresponding Source. This
|
| 271 |
+
alternative is allowed only occasionally and noncommercially, and
|
| 272 |
+
only if you received the object code with such an offer, in accord
|
| 273 |
+
with subsection 6b.
|
| 274 |
+
|
| 275 |
+
d) Convey the object code by offering access from a designated
|
| 276 |
+
place (gratis or for a charge), and offer equivalent access to the
|
| 277 |
+
Corresponding Source in the same way through the same place at no
|
| 278 |
+
further charge. You need not require recipients to copy the
|
| 279 |
+
Corresponding Source along with the object code. If the place to
|
| 280 |
+
copy the object code is a network server, the Corresponding Source
|
| 281 |
+
may be on a different server (operated by you or a third party)
|
| 282 |
+
that supports equivalent copying facilities, provided you maintain
|
| 283 |
+
clear directions next to the object code saying where to find the
|
| 284 |
+
Corresponding Source. Regardless of what server hosts the
|
| 285 |
+
Corresponding Source, you remain obligated to ensure that it is
|
| 286 |
+
available for as long as needed to satisfy these requirements.
|
| 287 |
+
|
| 288 |
+
e) Convey the object code using peer-to-peer transmission, provided
|
| 289 |
+
you inform other peers where the object code and Corresponding
|
| 290 |
+
Source of the work are being offered to the general public at no
|
| 291 |
+
charge under subsection 6d.
|
| 292 |
+
|
| 293 |
+
A separable portion of the object code, whose source code is excluded
|
| 294 |
+
from the Corresponding Source as a System Library, need not be
|
| 295 |
+
included in conveying the object code work.
|
| 296 |
+
|
| 297 |
+
A "User Product" is either (1) a "consumer product", which means any
|
| 298 |
+
tangible personal property which is normally used for personal, family,
|
| 299 |
+
or household purposes, or (2) anything designed or sold for incorporation
|
| 300 |
+
into a dwelling. In determining whether a product is a consumer product,
|
| 301 |
+
doubtful cases shall be resolved in favor of coverage. For a particular
|
| 302 |
+
product received by a particular user, "normally used" refers to a
|
| 303 |
+
typical or common use of that class of product, regardless of the status
|
| 304 |
+
of the particular user or of the way in which the particular user
|
| 305 |
+
actually uses, or expects or is expected to use, the product. A product
|
| 306 |
+
is a consumer product regardless of whether the product has substantial
|
| 307 |
+
commercial, industrial or non-consumer uses, unless such uses represent
|
| 308 |
+
the only significant mode of use of the product.
|
| 309 |
+
|
| 310 |
+
"Installation Information" for a User Product means any methods,
|
| 311 |
+
procedures, authorization keys, or other information required to install
|
| 312 |
+
and execute modified versions of a covered work in that User Product from
|
| 313 |
+
a modified version of its Corresponding Source. The information must
|
| 314 |
+
suffice to ensure that the continued functioning of the modified object
|
| 315 |
+
code is in no case prevented or interfered with solely because
|
| 316 |
+
modification has been made.
|
| 317 |
+
|
| 318 |
+
If you convey an object code work under this section in, or with, or
|
| 319 |
+
specifically for use in, a User Product, and the conveying occurs as
|
| 320 |
+
part of a transaction in which the right of possession and use of the
|
| 321 |
+
User Product is transferred to the recipient in perpetuity or for a
|
| 322 |
+
fixed term (regardless of how the transaction is characterized), the
|
| 323 |
+
Corresponding Source conveyed under this section must be accompanied
|
| 324 |
+
by the Installation Information. But this requirement does not apply
|
| 325 |
+
if neither you nor any third party retains the ability to install
|
| 326 |
+
modified object code on the User Product (for example, the work has
|
| 327 |
+
been installed in ROM).
|
| 328 |
+
|
| 329 |
+
The requirement to provide Installation Information does not include a
|
| 330 |
+
requirement to continue to provide support service, warranty, or updates
|
| 331 |
+
for a work that has been modified or installed by the recipient, or for
|
| 332 |
+
the User Product in which it has been modified or installed. Access to a
|
| 333 |
+
network may be denied when the modification itself materially and
|
| 334 |
+
adversely affects the operation of the network or violates the rules and
|
| 335 |
+
protocols for communication across the network.
|
| 336 |
+
|
| 337 |
+
Corresponding Source conveyed, and Installation Information provided,
|
| 338 |
+
in accord with this section must be in a format that is publicly
|
| 339 |
+
documented (and with an implementation available to the public in
|
| 340 |
+
source code form), and must require no special password or key for
|
| 341 |
+
unpacking, reading or copying.
|
| 342 |
+
|
| 343 |
+
7. Additional Terms.
|
| 344 |
+
|
| 345 |
+
"Additional permissions" are terms that supplement the terms of this
|
| 346 |
+
License by making exceptions from one or more of its conditions.
|
| 347 |
+
Additional permissions that are applicable to the entire Program shall
|
| 348 |
+
be treated as though they were included in this License, to the extent
|
| 349 |
+
that they are valid under applicable law. If additional permissions
|
| 350 |
+
apply only to part of the Program, that part may be used separately
|
| 351 |
+
under those permissions, but the entire Program remains governed by
|
| 352 |
+
this License without regard to the additional permissions.
|
| 353 |
+
|
| 354 |
+
When you convey a copy of a covered work, you may at your option
|
| 355 |
+
remove any additional permissions from that copy, or from any part of
|
| 356 |
+
it. (Additional permissions may be written to require their own
|
| 357 |
+
removal in certain cases when you modify the work.) You may place
|
| 358 |
+
additional permissions on material, added by you to a covered work,
|
| 359 |
+
for which you have or can give appropriate copyright permission.
|
| 360 |
+
|
| 361 |
+
Notwithstanding any other provision of this License, for material you
|
| 362 |
+
add to a covered work, you may (if authorized by the copyright holders of
|
| 363 |
+
that material) supplement the terms of this License with terms:
|
| 364 |
+
|
| 365 |
+
a) Disclaiming warranty or limiting liability differently from the
|
| 366 |
+
terms of sections 15 and 16 of this License; or
|
| 367 |
+
|
| 368 |
+
b) Requiring preservation of specified reasonable legal notices or
|
| 369 |
+
author attributions in that material or in the Appropriate Legal
|
| 370 |
+
Notices displayed by works containing it; or
|
| 371 |
+
|
| 372 |
+
c) Prohibiting misrepresentation of the origin of that material, or
|
| 373 |
+
requiring that modified versions of such material be marked in
|
| 374 |
+
reasonable ways as different from the original version; or
|
| 375 |
+
|
| 376 |
+
d) Limiting the use for publicity purposes of names of licensors or
|
| 377 |
+
authors of the material; or
|
| 378 |
+
|
| 379 |
+
e) Declining to grant rights under trademark law for use of some
|
| 380 |
+
trade names, trademarks, or service marks; or
|
| 381 |
+
|
| 382 |
+
f) Requiring indemnification of licensors and authors of that
|
| 383 |
+
material by anyone who conveys the material (or modified versions of
|
| 384 |
+
it) with contractual assumptions of liability to the recipient, for
|
| 385 |
+
any liability that these contractual assumptions directly impose on
|
| 386 |
+
those licensors and authors.
|
| 387 |
+
|
| 388 |
+
All other non-permissive additional terms are considered "further
|
| 389 |
+
restrictions" within the meaning of section 10. If the Program as you
|
| 390 |
+
received it, or any part of it, contains a notice stating that it is
|
| 391 |
+
governed by this License along with a term that is a further
|
| 392 |
+
restriction, you may remove that term. If a license document contains
|
| 393 |
+
a further restriction but permits relicensing or conveying under this
|
| 394 |
+
License, you may add to a covered work material governed by the terms
|
| 395 |
+
of that license document, provided that the further restriction does
|
| 396 |
+
not survive such relicensing or conveying.
|
| 397 |
+
|
| 398 |
+
If you add terms to a covered work in accord with this section, you
|
| 399 |
+
must place, in the relevant source files, a statement of the
|
| 400 |
+
additional terms that apply to those files, or a notice indicating
|
| 401 |
+
where to find the applicable terms.
|
| 402 |
+
|
| 403 |
+
Additional terms, permissive or non-permissive, may be stated in the
|
| 404 |
+
form of a separately written license, or stated as exceptions;
|
| 405 |
+
the above requirements apply either way.
|
| 406 |
+
|
| 407 |
+
8. Termination.
|
| 408 |
+
|
| 409 |
+
You may not propagate or modify a covered work except as expressly
|
| 410 |
+
provided under this License. Any attempt otherwise to propagate or
|
| 411 |
+
modify it is void, and will automatically terminate your rights under
|
| 412 |
+
this License (including any patent licenses granted under the third
|
| 413 |
+
paragraph of section 11).
|
| 414 |
+
|
| 415 |
+
However, if you cease all violation of this License, then your
|
| 416 |
+
license from a particular copyright holder is reinstated (a)
|
| 417 |
+
provisionally, unless and until the copyright holder explicitly and
|
| 418 |
+
finally terminates your license, and (b) permanently, if the copyright
|
| 419 |
+
holder fails to notify you of the violation by some reasonable means
|
| 420 |
+
prior to 60 days after the cessation.
|
| 421 |
+
|
| 422 |
+
Moreover, your license from a particular copyright holder is
|
| 423 |
+
reinstated permanently if the copyright holder notifies you of the
|
| 424 |
+
violation by some reasonable means, this is the first time you have
|
| 425 |
+
received notice of violation of this License (for any work) from that
|
| 426 |
+
copyright holder, and you cure the violation prior to 30 days after
|
| 427 |
+
your receipt of the notice.
|
| 428 |
+
|
| 429 |
+
Termination of your rights under this section does not terminate the
|
| 430 |
+
licenses of parties who have received copies or rights from you under
|
| 431 |
+
this License. If your rights have been terminated and not permanently
|
| 432 |
+
reinstated, you do not qualify to receive new licenses for the same
|
| 433 |
+
material under section 10.
|
| 434 |
+
|
| 435 |
+
9. Acceptance Not Required for Having Copies.
|
| 436 |
+
|
| 437 |
+
You are not required to accept this License in order to receive or
|
| 438 |
+
run a copy of the Program. Ancillary propagation of a covered work
|
| 439 |
+
occurring solely as a consequence of using peer-to-peer transmission
|
| 440 |
+
to receive a copy likewise does not require acceptance. However,
|
| 441 |
+
nothing other than this License grants you permission to propagate or
|
| 442 |
+
modify any covered work. These actions infringe copyright if you do
|
| 443 |
+
not accept this License. Therefore, by modifying or propagating a
|
| 444 |
+
covered work, you indicate your acceptance of this License to do so.
|
| 445 |
+
|
| 446 |
+
10. Automatic Licensing of Downstream Recipients.
|
| 447 |
+
|
| 448 |
+
Each time you convey a covered work, the recipient automatically
|
| 449 |
+
receives a license from the original licensors, to run, modify and
|
| 450 |
+
propagate that work, subject to this License. You are not responsible
|
| 451 |
+
for enforcing compliance by third parties with this License.
|
| 452 |
+
|
| 453 |
+
An "entity transaction" is a transaction transferring control of an
|
| 454 |
+
organization, or substantially all assets of one, or subdividing an
|
| 455 |
+
organization, or merging organizations. If propagation of a covered
|
| 456 |
+
work results from an entity transaction, each party to that
|
| 457 |
+
transaction who receives a copy of the work also receives whatever
|
| 458 |
+
licenses to the work the party's predecessor in interest had or could
|
| 459 |
+
give under the previous paragraph, plus a right to possession of the
|
| 460 |
+
Corresponding Source of the work from the predecessor in interest, if
|
| 461 |
+
the predecessor has it or can get it with reasonable efforts.
|
| 462 |
+
|
| 463 |
+
You may not impose any further restrictions on the exercise of the
|
| 464 |
+
rights granted or affirmed under this License. For example, you may
|
| 465 |
+
not impose a license fee, royalty, or other charge for exercise of
|
| 466 |
+
rights granted under this License, and you may not initiate litigation
|
| 467 |
+
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
| 468 |
+
any patent claim is infringed by making, using, selling, offering for
|
| 469 |
+
sale, or importing the Program or any portion of it.
|
| 470 |
+
|
| 471 |
+
11. Patents.
|
| 472 |
+
|
| 473 |
+
A "contributor" is a copyright holder who authorizes use under this
|
| 474 |
+
License of the Program or a work on which the Program is based. The
|
| 475 |
+
work thus licensed is called the contributor's "contributor version".
|
| 476 |
+
|
| 477 |
+
A contributor's "essential patent claims" are all patent claims
|
| 478 |
+
owned or controlled by the contributor, whether already acquired or
|
| 479 |
+
hereafter acquired, that would be infringed by some manner, permitted
|
| 480 |
+
by this License, of making, using, or selling its contributor version,
|
| 481 |
+
but do not include claims that would be infringed only as a
|
| 482 |
+
consequence of further modification of the contributor version. For
|
| 483 |
+
purposes of this definition, "control" includes the right to grant
|
| 484 |
+
patent sublicenses in a manner consistent with the requirements of
|
| 485 |
+
this License.
|
| 486 |
+
|
| 487 |
+
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
| 488 |
+
patent license under the contributor's essential patent claims, to
|
| 489 |
+
make, use, sell, offer for sale, import and otherwise run, modify and
|
| 490 |
+
propagate the contents of its contributor version.
|
| 491 |
+
|
| 492 |
+
In the following three paragraphs, a "patent license" is any express
|
| 493 |
+
agreement or commitment, however denominated, not to enforce a patent
|
| 494 |
+
(such as an express permission to practice a patent or covenant not to
|
| 495 |
+
sue for patent infringement). To "grant" such a patent license to a
|
| 496 |
+
party means to make such an agreement or commitment not to enforce a
|
| 497 |
+
patent against the party.
|
| 498 |
+
|
| 499 |
+
If you convey a covered work, knowingly relying on a patent license,
|
| 500 |
+
and the Corresponding Source of the work is not available for anyone
|
| 501 |
+
to copy, free of charge and under the terms of this License, through a
|
| 502 |
+
publicly available network server or other readily accessible means,
|
| 503 |
+
then you must either (1) cause the Corresponding Source to be so
|
| 504 |
+
available, or (2) arrange to deprive yourself of the benefit of the
|
| 505 |
+
patent license for this particular work, or (3) arrange, in a manner
|
| 506 |
+
consistent with the requirements of this License, to extend the patent
|
| 507 |
+
license to downstream recipients. "Knowingly relying" means you have
|
| 508 |
+
actual knowledge that, but for the patent license, your conveying the
|
| 509 |
+
covered work in a country, or your recipient's use of the covered work
|
| 510 |
+
in a country, would infringe one or more identifiable patents in that
|
| 511 |
+
country that you have reason to believe are valid.
|
| 512 |
+
|
| 513 |
+
If, pursuant to or in connection with a single transaction or
|
| 514 |
+
arrangement, you convey, or propagate by procuring conveyance of, a
|
| 515 |
+
covered work, and grant a patent license to some of the parties
|
| 516 |
+
receiving the covered work authorizing them to use, propagate, modify
|
| 517 |
+
or convey a specific copy of the covered work, then the patent license
|
| 518 |
+
you grant is automatically extended to all recipients of the covered
|
| 519 |
+
work and works based on it.
|
| 520 |
+
|
| 521 |
+
A patent license is "discriminatory" if it does not include within
|
| 522 |
+
the scope of its coverage, prohibits the exercise of, or is
|
| 523 |
+
conditioned on the non-exercise of one or more of the rights that are
|
| 524 |
+
specifically granted under this License. You may not convey a covered
|
| 525 |
+
work if you are a party to an arrangement with a third party that is
|
| 526 |
+
in the business of distributing software, under which you make payment
|
| 527 |
+
to the third party based on the extent of your activity of conveying
|
| 528 |
+
the work, and under which the third party grants, to any of the
|
| 529 |
+
parties who would receive the covered work from you, a discriminatory
|
| 530 |
+
patent license (a) in connection with copies of the covered work
|
| 531 |
+
conveyed by you (or copies made from those copies), or (b) primarily
|
| 532 |
+
for and in connection with specific products or compilations that
|
| 533 |
+
contain the covered work, unless you entered into that arrangement,
|
| 534 |
+
or that patent license was granted, prior to 28 March 2007.
|
| 535 |
+
|
| 536 |
+
Nothing in this License shall be construed as excluding or limiting
|
| 537 |
+
any implied license or other defenses to infringement that may
|
| 538 |
+
otherwise be available to you under applicable patent law.
|
| 539 |
+
|
| 540 |
+
12. No Surrender of Others' Freedom.
|
| 541 |
+
|
| 542 |
+
If conditions are imposed on you (whether by court order, agreement or
|
| 543 |
+
otherwise) that contradict the conditions of this License, they do not
|
| 544 |
+
excuse you from the conditions of this License. If you cannot convey a
|
| 545 |
+
covered work so as to satisfy simultaneously your obligations under this
|
| 546 |
+
License and any other pertinent obligations, then as a consequence you may
|
| 547 |
+
not convey it at all. For example, if you agree to terms that obligate you
|
| 548 |
+
to collect a royalty for further conveying from those to whom you convey
|
| 549 |
+
the Program, the only way you could satisfy both those terms and this
|
| 550 |
+
License would be to refrain entirely from conveying the Program.
|
| 551 |
+
|
| 552 |
+
13. Use with the GNU Affero General Public License.
|
| 553 |
+
|
| 554 |
+
Notwithstanding any other provision of this License, you have
|
| 555 |
+
permission to link or combine any covered work with a work licensed
|
| 556 |
+
under version 3 of the GNU Affero General Public License into a single
|
| 557 |
+
combined work, and to convey the resulting work. The terms of this
|
| 558 |
+
License will continue to apply to the part which is the covered work,
|
| 559 |
+
but the special requirements of the GNU Affero General Public License,
|
| 560 |
+
section 13, concerning interaction through a network will apply to the
|
| 561 |
+
combination as such.
|
| 562 |
+
|
| 563 |
+
14. Revised Versions of this License.
|
| 564 |
+
|
| 565 |
+
The Free Software Foundation may publish revised and/or new versions of
|
| 566 |
+
the GNU General Public License from time to time. Such new versions will
|
| 567 |
+
be similar in spirit to the present version, but may differ in detail to
|
| 568 |
+
address new problems or concerns.
|
| 569 |
+
|
| 570 |
+
Each version is given a distinguishing version number. If the
|
| 571 |
+
Program specifies that a certain numbered version of the GNU General
|
| 572 |
+
Public License "or any later version" applies to it, you have the
|
| 573 |
+
option of following the terms and conditions either of that numbered
|
| 574 |
+
version or of any later version published by the Free Software
|
| 575 |
+
Foundation. If the Program does not specify a version number of the
|
| 576 |
+
GNU General Public License, you may choose any version ever published
|
| 577 |
+
by the Free Software Foundation.
|
| 578 |
+
|
| 579 |
+
If the Program specifies that a proxy can decide which future
|
| 580 |
+
versions of the GNU General Public License can be used, that proxy's
|
| 581 |
+
public statement of acceptance of a version permanently authorizes you
|
| 582 |
+
to choose that version for the Program.
|
| 583 |
+
|
| 584 |
+
Later license versions may give you additional or different
|
| 585 |
+
permissions. However, no additional obligations are imposed on any
|
| 586 |
+
author or copyright holder as a result of your choosing to follow a
|
| 587 |
+
later version.
|
| 588 |
+
|
| 589 |
+
15. Disclaimer of Warranty.
|
| 590 |
+
|
| 591 |
+
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
| 592 |
+
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
| 593 |
+
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
| 594 |
+
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
| 595 |
+
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
| 596 |
+
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
| 597 |
+
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
| 598 |
+
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
| 599 |
+
|
| 600 |
+
16. Limitation of Liability.
|
| 601 |
+
|
| 602 |
+
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
| 603 |
+
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
| 604 |
+
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
| 605 |
+
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
| 606 |
+
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
| 607 |
+
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
| 608 |
+
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
| 609 |
+
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
| 610 |
+
SUCH DAMAGES.
|
| 611 |
+
|
| 612 |
+
17. Interpretation of Sections 15 and 16.
|
| 613 |
+
|
| 614 |
+
If the disclaimer of warranty and limitation of liability provided
|
| 615 |
+
above cannot be given local legal effect according to their terms,
|
| 616 |
+
reviewing courts shall apply local law that most closely approximates
|
| 617 |
+
an absolute waiver of all civil liability in connection with the
|
| 618 |
+
Program, unless a warranty or assumption of liability accompanies a
|
| 619 |
+
copy of the Program in return for a fee.
|
| 620 |
+
|
| 621 |
+
END OF TERMS AND CONDITIONS
|
| 622 |
+
|
| 623 |
+
How to Apply These Terms to Your New Programs
|
| 624 |
+
|
| 625 |
+
If you develop a new program, and you want it to be of the greatest
|
| 626 |
+
possible use to the public, the best way to achieve this is to make it
|
| 627 |
+
free software which everyone can redistribute and change under these terms.
|
| 628 |
+
|
| 629 |
+
To do so, attach the following notices to the program. It is safest
|
| 630 |
+
to attach them to the start of each source file to most effectively
|
| 631 |
+
state the exclusion of warranty; and each file should have at least
|
| 632 |
+
the "copyright" line and a pointer to where the full notice is found.
|
| 633 |
+
|
| 634 |
+
<one line to give the program's name and a brief idea of what it does.>
|
| 635 |
+
Copyright (C) <year> <name of author>
|
| 636 |
+
|
| 637 |
+
This program is free software: you can redistribute it and/or modify
|
| 638 |
+
it under the terms of the GNU General Public License as published by
|
| 639 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 640 |
+
(at your option) any later version.
|
| 641 |
+
|
| 642 |
+
This program is distributed in the hope that it will be useful,
|
| 643 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 644 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 645 |
+
GNU General Public License for more details.
|
| 646 |
+
|
| 647 |
+
You should have received a copy of the GNU General Public License
|
| 648 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 649 |
+
|
| 650 |
+
Also add information on how to contact you by electronic and paper mail.
|
| 651 |
+
|
| 652 |
+
If the program does terminal interaction, make it output a short
|
| 653 |
+
notice like this when it starts in an interactive mode:
|
| 654 |
+
|
| 655 |
+
<program> Copyright (C) <year> <name of author>
|
| 656 |
+
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
| 657 |
+
This is free software, and you are welcome to redistribute it
|
| 658 |
+
under certain conditions; type `show c' for details.
|
| 659 |
+
|
| 660 |
+
The hypothetical commands `show w' and `show c' should show the appropriate
|
| 661 |
+
parts of the General Public License. Of course, your program's commands
|
| 662 |
+
might be different; for a GUI interface, you would use an "about box".
|
| 663 |
+
|
| 664 |
+
You should also get your employer (if you work as a programmer) or school,
|
| 665 |
+
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
| 666 |
+
For more information on this, and how to apply and follow the GNU GPL, see
|
| 667 |
+
<http://www.gnu.org/licenses/>.
|
| 668 |
+
|
| 669 |
+
The GNU General Public License does not permit incorporating your program
|
| 670 |
+
into proprietary programs. If your program is a subroutine library, you
|
| 671 |
+
may consider it more useful to permit linking proprietary applications with
|
| 672 |
+
the library. If this is what you want to do, use the GNU Lesser General
|
| 673 |
+
Public License instead of this License. But first, please read
|
| 674 |
+
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
stockfish-4-win/Readme.md
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
### Overview
|
| 2 |
+
|
| 3 |
+
Stockfish is a free UCI chess engine derived from Glaurung 2.1. It is
|
| 4 |
+
not a complete chess program and requires some UCI-compatible GUI
|
| 5 |
+
(e.g. XBoard with PolyGlot, eboard, Arena, Sigma Chess, Shredder, Chess
|
| 6 |
+
Partner or Fritz) in order to be used comfortably. Read the
|
| 7 |
+
documentation for your GUI of choice for information about how to use
|
| 8 |
+
Stockfish with it.
|
| 9 |
+
|
| 10 |
+
This version of Stockfish supports up to 64 CPUs. The engine defaults
|
| 11 |
+
to one search thread it is therefore recommended to inspect the value of
|
| 12 |
+
the *Threads* UCI parameter, and to make sure it equals the number of CPU
|
| 13 |
+
cores on your computer.
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
### Files
|
| 17 |
+
|
| 18 |
+
This distribution of Stockfish consists of the following files:
|
| 19 |
+
|
| 20 |
+
* Readme.md, the file you are currently reading.
|
| 21 |
+
|
| 22 |
+
* Copying.txt, a text file containing the GNU General Public License.
|
| 23 |
+
|
| 24 |
+
* src, a subdirectory containing the full source code, including a Makefile
|
| 25 |
+
that can be used to compile Stockfish on Unix-like systems. For further
|
| 26 |
+
information about how to compile Stockfish yourself read section below.
|
| 27 |
+
|
| 28 |
+
* polyglot.ini, for using Stockfish with Fabien Letouzey's PolyGlot
|
| 29 |
+
adapter.
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
### Opening books
|
| 33 |
+
|
| 34 |
+
This version of Stockfish has support for PolyGlot opening books. For
|
| 35 |
+
information about how to create such books, consult the PolyGlot
|
| 36 |
+
documentation. The book file can be selected by setting the *Book File*
|
| 37 |
+
UCI parameter.
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
### Compiling it yourself
|
| 41 |
+
|
| 42 |
+
On Unix-like systems, it should be possible to compile Stockfish
|
| 43 |
+
directly from the source code with the included Makefile.
|
| 44 |
+
|
| 45 |
+
Stockfish has support for 32 or 64-bit CPUs, the hardware POPCNT
|
| 46 |
+
instruction, big-endian machines such as Power PC, and other platforms.
|
| 47 |
+
|
| 48 |
+
In general it is recommended to run `make help` to see a list of make
|
| 49 |
+
targets with corresponding descriptions. When not using Makefile to
|
| 50 |
+
compile (for instance with Microsoft MSVC) you need to manually
|
| 51 |
+
set/unset some switches in the compiler command line; see file *types.h*
|
| 52 |
+
for a quick reference.
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
### Terms of use
|
| 56 |
+
|
| 57 |
+
Stockfish is free, and distributed under the **GNU General Public License**
|
| 58 |
+
(GPL). Essentially, this means that you are free to do almost exactly
|
| 59 |
+
what you want with the program, including distributing it among your
|
| 60 |
+
friends, making it available for download from your web site, selling
|
| 61 |
+
it (either by itself or as part of some bigger software package), or
|
| 62 |
+
using it as the starting point for a software project of your own.
|
| 63 |
+
|
| 64 |
+
The only real limitation is that whenever you distribute Stockfish in
|
| 65 |
+
some way, you must always include the full source code, or a pointer
|
| 66 |
+
to where the source code can be found. If you make any changes to the
|
| 67 |
+
source code, these changes must also be made available under the GPL.
|
| 68 |
+
|
| 69 |
+
For full details, read the copy of the GPL found in the file named
|
| 70 |
+
*Copying.txt*
|
stockfish-4-win/Windows/stockfish_4_32bit.exe
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:48d7df295a019b0e84310e8b0264153e1b6e14808996191212115282ee38b9a6
|
| 3 |
+
size 860672
|
stockfish-4-win/Windows/stockfish_4_x64.exe
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:41403082407022143f8b981d0e1b4e32f75101d7c7a9d440da9fbda9e3ae77bd
|
| 3 |
+
size 1051648
|
stockfish-4-win/Windows/stockfish_4_x64_modern.exe
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:e4a70a652171e2d55f3d0fcafe5bb1c88afd82645ad3b4cd03a589c71ebac85e
|
| 3 |
+
size 1046528
|
stockfish-4-win/Windows/stockfish_4_x64_modern_sse42.exe
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:d3920c8b7e541c61e9eb4863b1599e47a4e4b01718835bcf8b79097632cd56de
|
| 3 |
+
size 1046528
|
stockfish-4-win/logo.bmp
ADDED
|
stockfish-4-win/polyglot.ini
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[PolyGlot]
|
| 2 |
+
|
| 3 |
+
EngineDir = .
|
| 4 |
+
EngineCommand = ./stockfish
|
| 5 |
+
|
| 6 |
+
Book = false
|
| 7 |
+
BookFile = book.bin
|
| 8 |
+
|
| 9 |
+
Log = false
|
| 10 |
+
LogFile = stockfish.log
|
| 11 |
+
|
| 12 |
+
Resign = true
|
| 13 |
+
ResignScore = 600
|
| 14 |
+
|
| 15 |
+
[Engine]
|
| 16 |
+
|
| 17 |
+
Write Debug Log = false
|
| 18 |
+
Write Search Log = false
|
| 19 |
+
Search Log Filename = SearchLog.txt
|
| 20 |
+
Book File = book.bin
|
| 21 |
+
Best Book Move = false
|
| 22 |
+
Contempt Factor = 0
|
| 23 |
+
Mobility (Midgame) = 100
|
| 24 |
+
Mobility (Endgame) = 100
|
| 25 |
+
Pawn Structure (Midgame) = 100
|
| 26 |
+
Pawn Structure (Endgame) = 100
|
| 27 |
+
Passed Pawns (Midgame) = 100
|
| 28 |
+
Passed Pawns (Endgame) = 100
|
| 29 |
+
Space = 100
|
| 30 |
+
Aggressiveness = 100
|
| 31 |
+
Cowardice = 100
|
| 32 |
+
Min Split Depth = 0
|
| 33 |
+
Max Threads per Split Point = 5
|
| 34 |
+
Threads = 1
|
| 35 |
+
Idle Threads Sleep = false
|
| 36 |
+
Hash = 128
|
| 37 |
+
Ponder = true
|
| 38 |
+
OwnBook = false
|
| 39 |
+
MultiPV = 1
|
| 40 |
+
Skill Level = 20
|
| 41 |
+
Emergency Move Horizon = 40
|
| 42 |
+
Emergency Base Time = 200
|
| 43 |
+
Emergency Move Time = 70
|
| 44 |
+
Minimum Thinking Time = 20
|
| 45 |
+
Slow Mover = 100
|
| 46 |
+
UCI_Chess960 = false
|
| 47 |
+
UCI_AnalyseMode = false
|
stockfish-4-win/src/Makefile
ADDED
|
@@ -0,0 +1,565 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 2 |
+
# Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 3 |
+
# Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 4 |
+
#
|
| 5 |
+
# Stockfish is free software: you can redistribute it and/or modify
|
| 6 |
+
# it under the terms of the GNU General Public License as published by
|
| 7 |
+
# the Free Software Foundation, either version 3 of the License, or
|
| 8 |
+
# (at your option) any later version.
|
| 9 |
+
#
|
| 10 |
+
# Stockfish is distributed in the hope that it will be useful,
|
| 11 |
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 12 |
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 13 |
+
# GNU General Public License for more details.
|
| 14 |
+
#
|
| 15 |
+
# You should have received a copy of the GNU General Public License
|
| 16 |
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
### ==========================================================================
|
| 20 |
+
### Section 1. General Configuration
|
| 21 |
+
### ==========================================================================
|
| 22 |
+
|
| 23 |
+
### Establish the operating system name
|
| 24 |
+
UNAME = $(shell uname)
|
| 25 |
+
|
| 26 |
+
### Executable name
|
| 27 |
+
EXE = stockfish
|
| 28 |
+
|
| 29 |
+
### Installation dir definitions
|
| 30 |
+
PREFIX = /usr/local
|
| 31 |
+
# Haiku has a non-standard filesystem layout
|
| 32 |
+
ifeq ($(UNAME),Haiku)
|
| 33 |
+
PREFIX=/boot/common
|
| 34 |
+
endif
|
| 35 |
+
BINDIR = $(PREFIX)/bin
|
| 36 |
+
|
| 37 |
+
### Built-in benchmark for pgo-builds and signature
|
| 38 |
+
PGOBENCH = ./$(EXE) bench 32 1 10 default depth
|
| 39 |
+
SIGNBENCH = ./$(EXE) bench
|
| 40 |
+
|
| 41 |
+
### Object files
|
| 42 |
+
OBJS = benchmark.o bitbase.o bitboard.o book.o endgame.o evaluate.o main.o \
|
| 43 |
+
material.o misc.o movegen.o movepick.o notation.o pawns.o position.o \
|
| 44 |
+
search.o thread.o timeman.o tt.o uci.o ucioption.o
|
| 45 |
+
|
| 46 |
+
### ==========================================================================
|
| 47 |
+
### Section 2. High-level Configuration
|
| 48 |
+
### ==========================================================================
|
| 49 |
+
#
|
| 50 |
+
# flag --- Comp switch --- Description
|
| 51 |
+
# ----------------------------------------------------------------------------
|
| 52 |
+
#
|
| 53 |
+
# debug = yes/no --- -DNDEBUG --- Enable/Disable debug mode
|
| 54 |
+
# optimize = yes/no --- (-O3/-fast etc.) --- Enable/Disable optimizations
|
| 55 |
+
# arch = (name) --- (-arch) --- Target architecture
|
| 56 |
+
# os = (name) --- --- Target operating system
|
| 57 |
+
# bits = 64/32 --- -DIS_64BIT --- 64-/32-bit operating system
|
| 58 |
+
# prefetch = yes/no --- -DUSE_PREFETCH --- Use prefetch x86 asm-instruction
|
| 59 |
+
# bsfq = yes/no --- -DUSE_BSFQ --- Use bsfq x86_64 asm-instruction (only
|
| 60 |
+
# with GCC and ICC 64-bit)
|
| 61 |
+
# popcnt = yes/no --- -DUSE_POPCNT --- Use popcnt x86_64 asm-instruction
|
| 62 |
+
# sse = yes/no --- -msse --- Use Intel Streaming SIMD Extensions
|
| 63 |
+
#
|
| 64 |
+
# Note that Makefile is space sensitive, so when adding new architectures
|
| 65 |
+
# or modifying existing flags, you have to make sure there are no extra spaces
|
| 66 |
+
# at the end of the line for flag values.
|
| 67 |
+
|
| 68 |
+
### 2.1. General
|
| 69 |
+
debug = no
|
| 70 |
+
optimize = yes
|
| 71 |
+
|
| 72 |
+
### 2.2 Architecture specific
|
| 73 |
+
|
| 74 |
+
# General-section
|
| 75 |
+
ifeq ($(ARCH),general-64)
|
| 76 |
+
arch = any
|
| 77 |
+
os = any
|
| 78 |
+
bits = 64
|
| 79 |
+
prefetch = no
|
| 80 |
+
bsfq = no
|
| 81 |
+
popcnt = no
|
| 82 |
+
sse = no
|
| 83 |
+
endif
|
| 84 |
+
|
| 85 |
+
ifeq ($(ARCH),general-32)
|
| 86 |
+
arch = any
|
| 87 |
+
os = any
|
| 88 |
+
bits = 32
|
| 89 |
+
prefetch = no
|
| 90 |
+
bsfq = no
|
| 91 |
+
popcnt = no
|
| 92 |
+
sse = no
|
| 93 |
+
endif
|
| 94 |
+
|
| 95 |
+
# x86-section
|
| 96 |
+
ifeq ($(ARCH),x86-64)
|
| 97 |
+
arch = x86_64
|
| 98 |
+
os = any
|
| 99 |
+
bits = 64
|
| 100 |
+
prefetch = yes
|
| 101 |
+
bsfq = yes
|
| 102 |
+
popcnt = no
|
| 103 |
+
sse = yes
|
| 104 |
+
endif
|
| 105 |
+
|
| 106 |
+
ifeq ($(ARCH),x86-64-modern)
|
| 107 |
+
arch = x86_64
|
| 108 |
+
os = any
|
| 109 |
+
bits = 64
|
| 110 |
+
prefetch = yes
|
| 111 |
+
bsfq = yes
|
| 112 |
+
popcnt = yes
|
| 113 |
+
sse = yes
|
| 114 |
+
endif
|
| 115 |
+
|
| 116 |
+
ifeq ($(ARCH),x86-32)
|
| 117 |
+
arch = i386
|
| 118 |
+
os = any
|
| 119 |
+
bits = 32
|
| 120 |
+
prefetch = yes
|
| 121 |
+
bsfq = no
|
| 122 |
+
popcnt = no
|
| 123 |
+
sse = yes
|
| 124 |
+
endif
|
| 125 |
+
|
| 126 |
+
ifeq ($(ARCH),x86-32-old)
|
| 127 |
+
arch = i386
|
| 128 |
+
os = any
|
| 129 |
+
bits = 32
|
| 130 |
+
prefetch = no
|
| 131 |
+
bsfq = no
|
| 132 |
+
popcnt = no
|
| 133 |
+
sse = no
|
| 134 |
+
endif
|
| 135 |
+
|
| 136 |
+
#arm section
|
| 137 |
+
ifeq ($(ARCH),armv7)
|
| 138 |
+
arch = armv7
|
| 139 |
+
os = any
|
| 140 |
+
bits = 32
|
| 141 |
+
prefetch = yes
|
| 142 |
+
bsfq = yes
|
| 143 |
+
popcnt = no
|
| 144 |
+
sse = no
|
| 145 |
+
endif
|
| 146 |
+
|
| 147 |
+
# osx-section
|
| 148 |
+
ifeq ($(ARCH),osx-ppc-64)
|
| 149 |
+
arch = ppc64
|
| 150 |
+
os = osx
|
| 151 |
+
bits = 64
|
| 152 |
+
prefetch = no
|
| 153 |
+
bsfq = no
|
| 154 |
+
popcnt = no
|
| 155 |
+
sse = no
|
| 156 |
+
endif
|
| 157 |
+
|
| 158 |
+
ifeq ($(ARCH),osx-ppc-32)
|
| 159 |
+
arch = ppc
|
| 160 |
+
os = osx
|
| 161 |
+
bits = 32
|
| 162 |
+
prefetch = no
|
| 163 |
+
bsfq = no
|
| 164 |
+
popcnt = no
|
| 165 |
+
sse = no
|
| 166 |
+
endif
|
| 167 |
+
|
| 168 |
+
ifeq ($(ARCH),osx-x86-64)
|
| 169 |
+
arch = x86_64
|
| 170 |
+
os = osx
|
| 171 |
+
bits = 64
|
| 172 |
+
prefetch = yes
|
| 173 |
+
bsfq = yes
|
| 174 |
+
popcnt = no
|
| 175 |
+
sse = yes
|
| 176 |
+
endif
|
| 177 |
+
|
| 178 |
+
ifeq ($(ARCH),osx-x86-32)
|
| 179 |
+
arch = i386
|
| 180 |
+
os = osx
|
| 181 |
+
bits = 32
|
| 182 |
+
prefetch = yes
|
| 183 |
+
bsfq = no
|
| 184 |
+
popcnt = no
|
| 185 |
+
sse = yes
|
| 186 |
+
endif
|
| 187 |
+
|
| 188 |
+
|
| 189 |
+
### ==========================================================================
|
| 190 |
+
### Section 3. Low-level configuration
|
| 191 |
+
### ==========================================================================
|
| 192 |
+
|
| 193 |
+
### 3.1 Selecting compiler (default = gcc)
|
| 194 |
+
ifeq ($(COMP),)
|
| 195 |
+
COMP=gcc
|
| 196 |
+
endif
|
| 197 |
+
|
| 198 |
+
ifeq ($(COMP),mingw)
|
| 199 |
+
comp=mingw
|
| 200 |
+
CXX=g++
|
| 201 |
+
profile_prepare = gcc-profile-prepare
|
| 202 |
+
profile_make = gcc-profile-make
|
| 203 |
+
profile_use = gcc-profile-use
|
| 204 |
+
profile_clean = gcc-profile-clean
|
| 205 |
+
endif
|
| 206 |
+
|
| 207 |
+
ifeq ($(COMP),gcc)
|
| 208 |
+
comp=gcc
|
| 209 |
+
CXX=g++
|
| 210 |
+
profile_prepare = gcc-profile-prepare
|
| 211 |
+
profile_make = gcc-profile-make
|
| 212 |
+
profile_use = gcc-profile-use
|
| 213 |
+
profile_clean = gcc-profile-clean
|
| 214 |
+
endif
|
| 215 |
+
|
| 216 |
+
ifeq ($(COMP),icc)
|
| 217 |
+
comp=icc
|
| 218 |
+
CXX=icpc
|
| 219 |
+
profile_prepare = icc-profile-prepare
|
| 220 |
+
profile_make = icc-profile-make
|
| 221 |
+
profile_use = icc-profile-use
|
| 222 |
+
profile_clean = icc-profile-clean
|
| 223 |
+
endif
|
| 224 |
+
|
| 225 |
+
ifeq ($(COMP),clang)
|
| 226 |
+
comp=clang
|
| 227 |
+
CXX=clang++
|
| 228 |
+
profile_prepare = gcc-profile-prepare
|
| 229 |
+
profile_make = gcc-profile-make
|
| 230 |
+
profile_use = gcc-profile-use
|
| 231 |
+
profile_clean = gcc-profile-clean
|
| 232 |
+
endif
|
| 233 |
+
|
| 234 |
+
### 3.2 General compiler settings
|
| 235 |
+
CXXFLAGS = -Wall -Wcast-qual -fno-exceptions -fno-rtti $(EXTRACXXFLAGS)
|
| 236 |
+
|
| 237 |
+
ifeq ($(comp),gcc)
|
| 238 |
+
CXXFLAGS += -ansi -pedantic -Wno-long-long -Wextra -Wshadow
|
| 239 |
+
endif
|
| 240 |
+
|
| 241 |
+
ifeq ($(comp),mingw)
|
| 242 |
+
CXXFLAGS += -Wextra -Wshadow
|
| 243 |
+
endif
|
| 244 |
+
|
| 245 |
+
ifeq ($(comp),icc)
|
| 246 |
+
CXXFLAGS += -wd383,981,1418,1419,1476,10187,10188,11505,11503 -Wcheck -Wabi -Wdeprecated -strict-ansi
|
| 247 |
+
endif
|
| 248 |
+
|
| 249 |
+
ifeq ($(comp),clang)
|
| 250 |
+
CXXFLAGS += -ansi -pedantic -Wno-long-long -Wextra -Wshadow
|
| 251 |
+
endif
|
| 252 |
+
|
| 253 |
+
ifeq ($(os),osx)
|
| 254 |
+
CXXFLAGS += -arch $(arch) -mmacosx-version-min=10.0
|
| 255 |
+
endif
|
| 256 |
+
|
| 257 |
+
### 3.3 General linker settings
|
| 258 |
+
LDFLAGS = $(EXTRALDFLAGS)
|
| 259 |
+
|
| 260 |
+
ifeq ($(comp),mingw)
|
| 261 |
+
LDFLAGS += -static-libstdc++ -static-libgcc
|
| 262 |
+
endif
|
| 263 |
+
|
| 264 |
+
### On mingw use Windows threads, otherwise POSIX
|
| 265 |
+
ifneq ($(comp),mingw)
|
| 266 |
+
# Haiku has pthreads in its libroot, so only link it in on other platforms
|
| 267 |
+
ifneq ($(UNAME),Haiku)
|
| 268 |
+
LDFLAGS += -lpthread
|
| 269 |
+
endif
|
| 270 |
+
endif
|
| 271 |
+
|
| 272 |
+
ifeq ($(os),osx)
|
| 273 |
+
LDFLAGS += -arch $(arch) -mmacosx-version-min=10.0
|
| 274 |
+
endif
|
| 275 |
+
|
| 276 |
+
### 3.4 Debugging
|
| 277 |
+
ifeq ($(debug),no)
|
| 278 |
+
CXXFLAGS += -DNDEBUG
|
| 279 |
+
else
|
| 280 |
+
CXXFLAGS += -g
|
| 281 |
+
endif
|
| 282 |
+
|
| 283 |
+
### 3.5 Optimization
|
| 284 |
+
ifeq ($(optimize),yes)
|
| 285 |
+
|
| 286 |
+
ifeq ($(comp),gcc)
|
| 287 |
+
CXXFLAGS += -O3
|
| 288 |
+
|
| 289 |
+
ifeq ($(os),osx)
|
| 290 |
+
ifeq ($(arch),i386)
|
| 291 |
+
CXXFLAGS += -mdynamic-no-pic
|
| 292 |
+
endif
|
| 293 |
+
ifeq ($(arch),x86_64)
|
| 294 |
+
CXXFLAGS += -mdynamic-no-pic
|
| 295 |
+
endif
|
| 296 |
+
endif
|
| 297 |
+
|
| 298 |
+
ifeq ($(arch),armv7)
|
| 299 |
+
CXXFLAGS += -fno-gcse
|
| 300 |
+
endif
|
| 301 |
+
endif
|
| 302 |
+
|
| 303 |
+
ifeq ($(comp),mingw)
|
| 304 |
+
CXXFLAGS += -O3
|
| 305 |
+
endif
|
| 306 |
+
|
| 307 |
+
ifeq ($(comp),icc)
|
| 308 |
+
ifeq ($(os),osx)
|
| 309 |
+
CXXFLAGS += -fast -mdynamic-no-pic
|
| 310 |
+
else
|
| 311 |
+
CXXFLAGS += -O3
|
| 312 |
+
endif
|
| 313 |
+
endif
|
| 314 |
+
|
| 315 |
+
ifeq ($(comp),clang)
|
| 316 |
+
### -O4 requires a linker that supports LLVM's LTO
|
| 317 |
+
CXXFLAGS += -O3
|
| 318 |
+
|
| 319 |
+
ifeq ($(os),osx)
|
| 320 |
+
ifeq ($(arch),i386)
|
| 321 |
+
CXXFLAGS += -mdynamic-no-pic
|
| 322 |
+
endif
|
| 323 |
+
ifeq ($(arch),x86_64)
|
| 324 |
+
CXXFLAGS += -mdynamic-no-pic
|
| 325 |
+
endif
|
| 326 |
+
endif
|
| 327 |
+
endif
|
| 328 |
+
endif
|
| 329 |
+
|
| 330 |
+
### 3.6. Bits
|
| 331 |
+
ifeq ($(bits),64)
|
| 332 |
+
CXXFLAGS += -DIS_64BIT
|
| 333 |
+
endif
|
| 334 |
+
|
| 335 |
+
### 3.7 prefetch
|
| 336 |
+
ifeq ($(prefetch),yes)
|
| 337 |
+
ifeq ($(sse),yes)
|
| 338 |
+
CXXFLAGS += -msse
|
| 339 |
+
DEPENDFLAGS += -msse
|
| 340 |
+
endif
|
| 341 |
+
else
|
| 342 |
+
CXXFLAGS += -DNO_PREFETCH
|
| 343 |
+
endif
|
| 344 |
+
|
| 345 |
+
### 3.8 bsfq
|
| 346 |
+
ifeq ($(bsfq),yes)
|
| 347 |
+
CXXFLAGS += -DUSE_BSFQ
|
| 348 |
+
endif
|
| 349 |
+
|
| 350 |
+
### 3.9 popcnt
|
| 351 |
+
ifeq ($(popcnt),yes)
|
| 352 |
+
CXXFLAGS += -msse3 -DUSE_POPCNT
|
| 353 |
+
endif
|
| 354 |
+
|
| 355 |
+
### 3.10 Link Time Optimization, it works since gcc 4.5 but not on mingw.
|
| 356 |
+
### This is a mix of compile and link time options because the lto link phase
|
| 357 |
+
### needs access to the optimization flags.
|
| 358 |
+
ifeq ($(comp),gcc)
|
| 359 |
+
ifeq ($(optimize),yes)
|
| 360 |
+
ifeq ($(debug),no)
|
| 361 |
+
GCC_MAJOR := `$(CXX) -dumpversion | cut -f1 -d.`
|
| 362 |
+
GCC_MINOR := `$(CXX) -dumpversion | cut -f2 -d.`
|
| 363 |
+
ifeq (1,$(shell expr \( $(GCC_MAJOR) \> 4 \) \| \( $(GCC_MAJOR) \= 4 \& $(GCC_MINOR) \>= 5 \)))
|
| 364 |
+
CXXFLAGS += -flto
|
| 365 |
+
LDFLAGS += $(CXXFLAGS)
|
| 366 |
+
endif
|
| 367 |
+
endif
|
| 368 |
+
endif
|
| 369 |
+
endif
|
| 370 |
+
|
| 371 |
+
### ==========================================================================
|
| 372 |
+
### Section 4. Public targets
|
| 373 |
+
### ==========================================================================
|
| 374 |
+
|
| 375 |
+
help:
|
| 376 |
+
@echo ""
|
| 377 |
+
@echo "To compile stockfish, type: "
|
| 378 |
+
@echo ""
|
| 379 |
+
@echo "make target ARCH=arch [COMP=comp]"
|
| 380 |
+
@echo ""
|
| 381 |
+
@echo "Supported targets:"
|
| 382 |
+
@echo ""
|
| 383 |
+
@echo "build > Standard build"
|
| 384 |
+
@echo "signature-build > Standard build with embedded signature"
|
| 385 |
+
@echo "profile-build > PGO build"
|
| 386 |
+
@echo "signature-profile-build > PGO build with embedded signature"
|
| 387 |
+
@echo "strip > Strip executable"
|
| 388 |
+
@echo "install > Install executable"
|
| 389 |
+
@echo "clean > Clean up"
|
| 390 |
+
@echo ""
|
| 391 |
+
@echo "Supported archs:"
|
| 392 |
+
@echo ""
|
| 393 |
+
@echo "x86-64 > x86 64-bit"
|
| 394 |
+
@echo "x86-64-modern > x86 64-bit with popcnt support"
|
| 395 |
+
@echo "x86-32 > x86 32-bit with SSE support"
|
| 396 |
+
@echo "x86-32-old > x86 32-bit fall back for old hardware"
|
| 397 |
+
@echo "osx-ppc-64 > PPC-Mac OS X 64 bit"
|
| 398 |
+
@echo "osx-ppc-32 > PPC-Mac OS X 32 bit"
|
| 399 |
+
@echo "osx-x86-64 > x86-Mac OS X 64 bit"
|
| 400 |
+
@echo "osx-x86-32 > x86-Mac OS X 32 bit"
|
| 401 |
+
@echo "armv7 > ARMv7 32 bit"
|
| 402 |
+
@echo "general-64 > unspecified 64-bit"
|
| 403 |
+
@echo "general-32 > unspecified 32-bit"
|
| 404 |
+
@echo ""
|
| 405 |
+
@echo "Supported compilers:"
|
| 406 |
+
@echo ""
|
| 407 |
+
@echo "gcc > Gnu compiler (default)"
|
| 408 |
+
@echo "mingw > Gnu compiler with MinGW under Windows"
|
| 409 |
+
@echo "clang > LLVM Clang compiler"
|
| 410 |
+
@echo "icc > Intel compiler"
|
| 411 |
+
@echo ""
|
| 412 |
+
@echo "Non-standard targets:"
|
| 413 |
+
@echo ""
|
| 414 |
+
@echo "make hpux > Compile for HP-UX. Compiler = aCC"
|
| 415 |
+
@echo ""
|
| 416 |
+
@echo "Examples. If you don't know what to do, you likely want to run: "
|
| 417 |
+
@echo ""
|
| 418 |
+
@echo "make build ARCH=x86-64 (This is for 64-bit systems)"
|
| 419 |
+
@echo "make build ARCH=x86-32 (This is for 32-bit systems)"
|
| 420 |
+
@echo ""
|
| 421 |
+
|
| 422 |
+
.PHONY: build profile-build embed-signature
|
| 423 |
+
build:
|
| 424 |
+
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) config-sanity
|
| 425 |
+
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) all
|
| 426 |
+
|
| 427 |
+
profile-build:
|
| 428 |
+
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) config-sanity
|
| 429 |
+
@echo ""
|
| 430 |
+
@echo "Step 0/4. Preparing for profile build."
|
| 431 |
+
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_prepare)
|
| 432 |
+
@echo ""
|
| 433 |
+
@echo "Step 1/4. Building executable for benchmark ..."
|
| 434 |
+
@touch *.cpp *.h
|
| 435 |
+
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_make)
|
| 436 |
+
@echo ""
|
| 437 |
+
@echo "Step 2/4. Running benchmark for pgo-build ..."
|
| 438 |
+
@$(PGOBENCH) > /dev/null
|
| 439 |
+
@echo ""
|
| 440 |
+
@echo "Step 3/4. Building final executable ..."
|
| 441 |
+
@touch *.cpp
|
| 442 |
+
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_use)
|
| 443 |
+
@echo ""
|
| 444 |
+
@echo "Step 4/4. Deleting profile data ..."
|
| 445 |
+
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_clean)
|
| 446 |
+
|
| 447 |
+
embed-signature:
|
| 448 |
+
@echo "Running benchmark for getting the signature ..."
|
| 449 |
+
@$(SIGNBENCH) 2>&1 | sed -n 's/Nodes searched : \(.*\)/\/string Version\/s\/"\\(.*\\)"\/"sig-\1"\//p' > sign.txt
|
| 450 |
+
@sed -f sign.txt misc.cpp > misc2.cpp
|
| 451 |
+
@mv misc2.cpp misc.cpp
|
| 452 |
+
@rm sign.txt
|
| 453 |
+
|
| 454 |
+
signature-build: build embed-signature
|
| 455 |
+
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) all
|
| 456 |
+
|
| 457 |
+
signature-profile-build: build embed-signature profile-build
|
| 458 |
+
|
| 459 |
+
strip:
|
| 460 |
+
strip $(EXE)
|
| 461 |
+
|
| 462 |
+
install:
|
| 463 |
+
-mkdir -p -m 755 $(BINDIR)
|
| 464 |
+
-cp $(EXE) $(BINDIR)
|
| 465 |
+
-strip $(BINDIR)/$(EXE)
|
| 466 |
+
|
| 467 |
+
clean:
|
| 468 |
+
$(RM) $(EXE) $(EXE).exe *.o .depend *~ core bench.txt *.gcda
|
| 469 |
+
|
| 470 |
+
default:
|
| 471 |
+
help
|
| 472 |
+
|
| 473 |
+
### ==========================================================================
|
| 474 |
+
### Section 5. Private targets
|
| 475 |
+
### ==========================================================================
|
| 476 |
+
|
| 477 |
+
all: $(EXE) .depend
|
| 478 |
+
|
| 479 |
+
config-sanity:
|
| 480 |
+
@echo ""
|
| 481 |
+
@echo "Config:"
|
| 482 |
+
@echo "debug: '$(debug)'"
|
| 483 |
+
@echo "optimize: '$(optimize)'"
|
| 484 |
+
@echo "arch: '$(arch)'"
|
| 485 |
+
@echo "os: '$(os)'"
|
| 486 |
+
@echo "bits: '$(bits)'"
|
| 487 |
+
@echo "prefetch: '$(prefetch)'"
|
| 488 |
+
@echo "bsfq: '$(bsfq)'"
|
| 489 |
+
@echo "popcnt: '$(popcnt)'"
|
| 490 |
+
@echo "sse: '$(sse)'"
|
| 491 |
+
@echo ""
|
| 492 |
+
@echo "Flags:"
|
| 493 |
+
@echo "CXX: $(CXX)"
|
| 494 |
+
@echo "CXXFLAGS: $(CXXFLAGS)"
|
| 495 |
+
@echo "LDFLAGS: $(LDFLAGS)"
|
| 496 |
+
@echo ""
|
| 497 |
+
@echo "Testing config sanity. If this fails, try 'make help' ..."
|
| 498 |
+
@echo ""
|
| 499 |
+
@test "$(debug)" = "yes" || test "$(debug)" = "no"
|
| 500 |
+
@test "$(optimize)" = "yes" || test "$(optimize)" = "no"
|
| 501 |
+
@test "$(arch)" = "any" || test "$(arch)" = "x86_64" || test "$(arch)" = "i386" || \
|
| 502 |
+
test "$(arch)" = "ppc64" || test "$(arch)" = "ppc" || test "$(arch)" = "armv7"
|
| 503 |
+
@test "$(os)" = "any" || test "$(os)" = "osx"
|
| 504 |
+
@test "$(bits)" = "32" || test "$(bits)" = "64"
|
| 505 |
+
@test "$(prefetch)" = "yes" || test "$(prefetch)" = "no"
|
| 506 |
+
@test "$(bsfq)" = "yes" || test "$(bsfq)" = "no"
|
| 507 |
+
@test "$(popcnt)" = "yes" || test "$(popcnt)" = "no"
|
| 508 |
+
@test "$(sse)" = "yes" || test "$(sse)" = "no"
|
| 509 |
+
@test "$(comp)" = "gcc" || test "$(comp)" = "icc" || test "$(comp)" = "mingw" || test "$(comp)" = "clang"
|
| 510 |
+
|
| 511 |
+
$(EXE): $(OBJS)
|
| 512 |
+
$(CXX) -o $@ $(OBJS) $(LDFLAGS)
|
| 513 |
+
|
| 514 |
+
gcc-profile-prepare:
|
| 515 |
+
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) gcc-profile-clean
|
| 516 |
+
|
| 517 |
+
gcc-profile-make:
|
| 518 |
+
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
|
| 519 |
+
EXTRACXXFLAGS='-fprofile-generate' \
|
| 520 |
+
EXTRALDFLAGS='-lgcov' \
|
| 521 |
+
all
|
| 522 |
+
|
| 523 |
+
gcc-profile-use:
|
| 524 |
+
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
|
| 525 |
+
EXTRACXXFLAGS='-fprofile-use' \
|
| 526 |
+
EXTRALDFLAGS='-lgcov' \
|
| 527 |
+
all
|
| 528 |
+
|
| 529 |
+
gcc-profile-clean:
|
| 530 |
+
@rm -rf *.gcda *.gcno bench.txt
|
| 531 |
+
|
| 532 |
+
icc-profile-prepare:
|
| 533 |
+
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) icc-profile-clean
|
| 534 |
+
@mkdir profdir
|
| 535 |
+
|
| 536 |
+
icc-profile-make:
|
| 537 |
+
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
|
| 538 |
+
EXTRACXXFLAGS='-prof-gen=srcpos -prof_dir ./profdir' \
|
| 539 |
+
all
|
| 540 |
+
|
| 541 |
+
icc-profile-use:
|
| 542 |
+
$(MAKE) ARCH=$(ARCH) COMP=$(COMP) \
|
| 543 |
+
EXTRACXXFLAGS='-prof_use -prof_dir ./profdir' \
|
| 544 |
+
all
|
| 545 |
+
|
| 546 |
+
icc-profile-clean:
|
| 547 |
+
@rm -rf profdir bench.txt
|
| 548 |
+
|
| 549 |
+
.depend:
|
| 550 |
+
-@$(CXX) $(DEPENDFLAGS) -MM $(OBJS:.o=.cpp) > $@ 2> /dev/null
|
| 551 |
+
|
| 552 |
+
-include .depend
|
| 553 |
+
|
| 554 |
+
|
| 555 |
+
### ==========================================================================
|
| 556 |
+
### Section 6. Non-standard targets
|
| 557 |
+
### ==========================================================================
|
| 558 |
+
|
| 559 |
+
hpux:
|
| 560 |
+
$(MAKE) \
|
| 561 |
+
CXX='/opt/aCC/bin/aCC -AA +hpxstd98 -mt +O3 -DNDEBUG -DNO_PREFETCH' \
|
| 562 |
+
CXXFLAGS="" \
|
| 563 |
+
LDFLAGS="" \
|
| 564 |
+
all
|
| 565 |
+
|
stockfish-4-win/src/benchmark.cpp
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
+
Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
+
|
| 6 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 7 |
+
it under the terms of the GNU General Public License as published by
|
| 8 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 9 |
+
(at your option) any later version.
|
| 10 |
+
|
| 11 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 12 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 13 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 14 |
+
GNU General Public License for more details.
|
| 15 |
+
|
| 16 |
+
You should have received a copy of the GNU General Public License
|
| 17 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 18 |
+
*/
|
| 19 |
+
|
| 20 |
+
#include <fstream>
|
| 21 |
+
#include <iostream>
|
| 22 |
+
#include <istream>
|
| 23 |
+
#include <vector>
|
| 24 |
+
|
| 25 |
+
#include "misc.h"
|
| 26 |
+
#include "position.h"
|
| 27 |
+
#include "search.h"
|
| 28 |
+
#include "thread.h"
|
| 29 |
+
#include "tt.h"
|
| 30 |
+
#include "ucioption.h"
|
| 31 |
+
|
| 32 |
+
using namespace std;
|
| 33 |
+
|
| 34 |
+
static const char* Defaults[] = {
|
| 35 |
+
"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1",
|
| 36 |
+
"r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 10",
|
| 37 |
+
"8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - - 0 11",
|
| 38 |
+
"4rrk1/pp1n3p/3q2pQ/2p1pb2/2PP4/2P3N1/P2B2PP/4RRK1 b - - 7 19",
|
| 39 |
+
"rq3rk1/ppp2ppp/1bnpb3/3N2B1/3NP3/7P/PPPQ1PP1/2KR3R w - - 7 14",
|
| 40 |
+
"r1bq1r1k/1pp1n1pp/1p1p4/4p2Q/4Pp2/1BNP4/PPP2PPP/3R1RK1 w - - 2 14",
|
| 41 |
+
"r3r1k1/2p2ppp/p1p1bn2/8/1q2P3/2NPQN2/PPP3PP/R4RK1 b - - 2 15",
|
| 42 |
+
"r1bbk1nr/pp3p1p/2n5/1N4p1/2Np1B2/8/PPP2PPP/2KR1B1R w kq - 0 13",
|
| 43 |
+
"r1bq1rk1/ppp1nppp/4n3/3p3Q/3P4/1BP1B3/PP1N2PP/R4RK1 w - - 1 16",
|
| 44 |
+
"4r1k1/r1q2ppp/ppp2n2/4P3/5Rb1/1N1BQ3/PPP3PP/R5K1 w - - 1 17",
|
| 45 |
+
"2rqkb1r/ppp2p2/2npb1p1/1N1Nn2p/2P1PP2/8/PP2B1PP/R1BQK2R b KQ - 0 11",
|
| 46 |
+
"r1bq1r1k/b1p1npp1/p2p3p/1p6/3PP3/1B2NN2/PP3PPP/R2Q1RK1 w - - 1 16",
|
| 47 |
+
"3r1rk1/p5pp/bpp1pp2/8/q1PP1P2/b3P3/P2NQRPP/1R2B1K1 b - - 6 22",
|
| 48 |
+
"r1q2rk1/2p1bppp/2Pp4/p6b/Q1PNp3/4B3/PP1R1PPP/2K4R w - - 2 18",
|
| 49 |
+
"4k2r/1pb2ppp/1p2p3/1R1p4/3P4/2r1PN2/P4PPP/1R4K1 b - - 3 22",
|
| 50 |
+
"3q2k1/pb3p1p/4pbp1/2r5/PpN2N2/1P2P2P/5PP1/Q2R2K1 b - - 4 26"
|
| 51 |
+
};
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
/// benchmark() runs a simple benchmark by letting Stockfish analyze a set
|
| 55 |
+
/// of positions for a given limit each. There are five parameters; the
|
| 56 |
+
/// transposition table size, the number of search threads that should
|
| 57 |
+
/// be used, the limit value spent for each position (optional, default is
|
| 58 |
+
/// depth 12), an optional file name where to look for positions in fen
|
| 59 |
+
/// format (defaults are the positions defined above) and the type of the
|
| 60 |
+
/// limit value: depth (default), time in secs or number of nodes.
|
| 61 |
+
|
| 62 |
+
void benchmark(const Position& current, istream& is) {
|
| 63 |
+
|
| 64 |
+
string token;
|
| 65 |
+
Search::LimitsType limits;
|
| 66 |
+
vector<string> fens;
|
| 67 |
+
|
| 68 |
+
// Assign default values to missing arguments
|
| 69 |
+
string ttSize = (is >> token) ? token : "32";
|
| 70 |
+
string threads = (is >> token) ? token : "1";
|
| 71 |
+
string limit = (is >> token) ? token : "12";
|
| 72 |
+
string fenFile = (is >> token) ? token : "default";
|
| 73 |
+
string limitType = (is >> token) ? token : "depth";
|
| 74 |
+
|
| 75 |
+
Options["Hash"] = ttSize;
|
| 76 |
+
Options["Threads"] = threads;
|
| 77 |
+
TT.clear();
|
| 78 |
+
|
| 79 |
+
if (limitType == "time")
|
| 80 |
+
limits.movetime = 1000 * atoi(limit.c_str()); // movetime is in ms
|
| 81 |
+
|
| 82 |
+
else if (limitType == "nodes")
|
| 83 |
+
limits.nodes = atoi(limit.c_str());
|
| 84 |
+
|
| 85 |
+
else if (limitType == "mate")
|
| 86 |
+
limits.mate = atoi(limit.c_str());
|
| 87 |
+
|
| 88 |
+
else
|
| 89 |
+
limits.depth = atoi(limit.c_str());
|
| 90 |
+
|
| 91 |
+
if (fenFile == "default")
|
| 92 |
+
fens.assign(Defaults, Defaults + 16);
|
| 93 |
+
|
| 94 |
+
else if (fenFile == "current")
|
| 95 |
+
fens.push_back(current.fen());
|
| 96 |
+
|
| 97 |
+
else
|
| 98 |
+
{
|
| 99 |
+
string fen;
|
| 100 |
+
ifstream file(fenFile.c_str());
|
| 101 |
+
|
| 102 |
+
if (!file.is_open())
|
| 103 |
+
{
|
| 104 |
+
cerr << "Unable to open file " << fenFile << endl;
|
| 105 |
+
return;
|
| 106 |
+
}
|
| 107 |
+
|
| 108 |
+
while (getline(file, fen))
|
| 109 |
+
if (!fen.empty())
|
| 110 |
+
fens.push_back(fen);
|
| 111 |
+
|
| 112 |
+
file.close();
|
| 113 |
+
}
|
| 114 |
+
|
| 115 |
+
int64_t nodes = 0;
|
| 116 |
+
Search::StateStackPtr st;
|
| 117 |
+
Time::point elapsed = Time::now();
|
| 118 |
+
|
| 119 |
+
for (size_t i = 0; i < fens.size(); i++)
|
| 120 |
+
{
|
| 121 |
+
Position pos(fens[i], Options["UCI_Chess960"], Threads.main());
|
| 122 |
+
|
| 123 |
+
cerr << "\nPosition: " << i + 1 << '/' << fens.size() << endl;
|
| 124 |
+
|
| 125 |
+
if (limitType == "perft")
|
| 126 |
+
{
|
| 127 |
+
size_t cnt = Search::perft(pos, limits.depth * ONE_PLY);
|
| 128 |
+
cerr << "\nPerft " << limits.depth << " leaf nodes: " << cnt << endl;
|
| 129 |
+
nodes += cnt;
|
| 130 |
+
}
|
| 131 |
+
else
|
| 132 |
+
{
|
| 133 |
+
Threads.start_thinking(pos, limits, vector<Move>(), st);
|
| 134 |
+
Threads.wait_for_think_finished();
|
| 135 |
+
nodes += Search::RootPos.nodes_searched();
|
| 136 |
+
}
|
| 137 |
+
}
|
| 138 |
+
|
| 139 |
+
elapsed = Time::now() - elapsed + 1; // Assure positive to avoid a 'divide by zero'
|
| 140 |
+
|
| 141 |
+
cerr << "\n==========================="
|
| 142 |
+
<< "\nTotal time (ms) : " << elapsed
|
| 143 |
+
<< "\nNodes searched : " << nodes
|
| 144 |
+
<< "\nNodes/second : " << 1000 * nodes / elapsed << endl;
|
| 145 |
+
}
|
stockfish-4-win/src/bitbase.cpp
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
+
Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
+
|
| 6 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 7 |
+
it under the terms of the GNU General Public License as published by
|
| 8 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 9 |
+
(at your option) any later version.
|
| 10 |
+
|
| 11 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 12 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 13 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 14 |
+
GNU General Public License for more details.
|
| 15 |
+
|
| 16 |
+
You should have received a copy of the GNU General Public License
|
| 17 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 18 |
+
*/
|
| 19 |
+
|
| 20 |
+
#include <cassert>
|
| 21 |
+
#include <vector>
|
| 22 |
+
|
| 23 |
+
#include "bitboard.h"
|
| 24 |
+
#include "types.h"
|
| 25 |
+
|
| 26 |
+
namespace {
|
| 27 |
+
|
| 28 |
+
// The possible pawns squares are 24, the first 4 files and ranks from 2 to 7
|
| 29 |
+
const unsigned IndexMax = 2*24*64*64; // stm * psq * wksq * bksq = 196608
|
| 30 |
+
|
| 31 |
+
// Each uint32_t stores results of 32 positions, one per bit
|
| 32 |
+
uint32_t KPKBitbase[IndexMax / 32];
|
| 33 |
+
|
| 34 |
+
// A KPK bitbase index is an integer in [0, IndexMax] range
|
| 35 |
+
//
|
| 36 |
+
// Information is mapped in a way that minimizes number of iterations:
|
| 37 |
+
//
|
| 38 |
+
// bit 0- 5: white king square (from SQ_A1 to SQ_H8)
|
| 39 |
+
// bit 6-11: black king square (from SQ_A1 to SQ_H8)
|
| 40 |
+
// bit 12: side to move (WHITE or BLACK)
|
| 41 |
+
// bit 13-14: white pawn file (from FILE_A to FILE_D)
|
| 42 |
+
// bit 15-17: white pawn RANK_7 - rank (from RANK_7 - RANK_7 to RANK_7 - RANK_2)
|
| 43 |
+
unsigned index(Color us, Square bksq, Square wksq, Square psq) {
|
| 44 |
+
return wksq + (bksq << 6) + (us << 12) + (file_of(psq) << 13) + ((RANK_7 - rank_of(psq)) << 15);
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
enum Result {
|
| 48 |
+
INVALID = 0,
|
| 49 |
+
UNKNOWN = 1,
|
| 50 |
+
DRAW = 2,
|
| 51 |
+
WIN = 4
|
| 52 |
+
};
|
| 53 |
+
|
| 54 |
+
inline Result& operator|=(Result& r, Result v) { return r = Result(r | v); }
|
| 55 |
+
|
| 56 |
+
struct KPKPosition {
|
| 57 |
+
|
| 58 |
+
operator Result() const { return res; }
|
| 59 |
+
Result classify_leaf(unsigned idx);
|
| 60 |
+
Result classify(const std::vector<KPKPosition>& db)
|
| 61 |
+
{ return us == WHITE ? classify<WHITE>(db) : classify<BLACK>(db); }
|
| 62 |
+
|
| 63 |
+
private:
|
| 64 |
+
template<Color Us> Result classify(const std::vector<KPKPosition>& db);
|
| 65 |
+
|
| 66 |
+
Color us;
|
| 67 |
+
Square bksq, wksq, psq;
|
| 68 |
+
Result res;
|
| 69 |
+
};
|
| 70 |
+
|
| 71 |
+
} // namespace
|
| 72 |
+
|
| 73 |
+
|
| 74 |
+
bool Bitbases::probe_kpk(Square wksq, Square wpsq, Square bksq, Color us) {
|
| 75 |
+
|
| 76 |
+
assert(file_of(wpsq) <= FILE_D);
|
| 77 |
+
|
| 78 |
+
unsigned idx = index(us, bksq, wksq, wpsq);
|
| 79 |
+
return KPKBitbase[idx / 32] & (1 << (idx & 0x1F));
|
| 80 |
+
}
|
| 81 |
+
|
| 82 |
+
|
| 83 |
+
void Bitbases::init_kpk() {
|
| 84 |
+
|
| 85 |
+
unsigned idx, repeat = 1;
|
| 86 |
+
std::vector<KPKPosition> db(IndexMax);
|
| 87 |
+
|
| 88 |
+
// Initialize db with known win / draw positions
|
| 89 |
+
for (idx = 0; idx < IndexMax; idx++)
|
| 90 |
+
db[idx].classify_leaf(idx);
|
| 91 |
+
|
| 92 |
+
// Iterate through the positions until no more of the unknown positions can be
|
| 93 |
+
// changed to either wins or draws (15 cycles needed).
|
| 94 |
+
while (repeat)
|
| 95 |
+
for (repeat = idx = 0; idx < IndexMax; idx++)
|
| 96 |
+
if (db[idx] == UNKNOWN && db[idx].classify(db) != UNKNOWN)
|
| 97 |
+
repeat = 1;
|
| 98 |
+
|
| 99 |
+
// Map 32 results into one KPKBitbase[] entry
|
| 100 |
+
for (idx = 0; idx < IndexMax; idx++)
|
| 101 |
+
if (db[idx] == WIN)
|
| 102 |
+
KPKBitbase[idx / 32] |= 1 << (idx & 0x1F);
|
| 103 |
+
}
|
| 104 |
+
|
| 105 |
+
|
| 106 |
+
namespace {
|
| 107 |
+
|
| 108 |
+
Result KPKPosition::classify_leaf(unsigned idx) {
|
| 109 |
+
|
| 110 |
+
wksq = Square((idx >> 0) & 0x3F);
|
| 111 |
+
bksq = Square((idx >> 6) & 0x3F);
|
| 112 |
+
us = Color ((idx >> 12) & 0x01);
|
| 113 |
+
psq = File ((idx >> 13) & 0x03) | Rank(RANK_7 - (idx >> 15));
|
| 114 |
+
|
| 115 |
+
// Check if two pieces are on the same square or if a king can be captured
|
| 116 |
+
if ( wksq == psq || wksq == bksq || bksq == psq
|
| 117 |
+
|| (StepAttacksBB[KING][wksq] & bksq)
|
| 118 |
+
|| (us == WHITE && (StepAttacksBB[PAWN][psq] & bksq)))
|
| 119 |
+
return res = INVALID;
|
| 120 |
+
|
| 121 |
+
if (us == WHITE)
|
| 122 |
+
{
|
| 123 |
+
// Immediate win if pawn can be promoted without getting captured
|
| 124 |
+
if ( rank_of(psq) == RANK_7
|
| 125 |
+
&& wksq != psq + DELTA_N
|
| 126 |
+
&& ( square_distance(bksq, psq + DELTA_N) > 1
|
| 127 |
+
||(StepAttacksBB[KING][wksq] & (psq + DELTA_N))))
|
| 128 |
+
return res = WIN;
|
| 129 |
+
}
|
| 130 |
+
// Immediate draw if is stalemate or king captures undefended pawn
|
| 131 |
+
else if ( !(StepAttacksBB[KING][bksq] & ~(StepAttacksBB[KING][wksq] | StepAttacksBB[PAWN][psq]))
|
| 132 |
+
|| (StepAttacksBB[KING][bksq] & psq & ~StepAttacksBB[KING][wksq]))
|
| 133 |
+
return res = DRAW;
|
| 134 |
+
|
| 135 |
+
return res = UNKNOWN;
|
| 136 |
+
}
|
| 137 |
+
|
| 138 |
+
template<Color Us>
|
| 139 |
+
Result KPKPosition::classify(const std::vector<KPKPosition>& db) {
|
| 140 |
+
|
| 141 |
+
// White to Move: If one move leads to a position classified as WIN, the result
|
| 142 |
+
// of the current position is WIN. If all moves lead to positions classified
|
| 143 |
+
// as DRAW, the current position is classified DRAW otherwise the current
|
| 144 |
+
// position is classified as UNKNOWN.
|
| 145 |
+
//
|
| 146 |
+
// Black to Move: If one move leads to a position classified as DRAW, the result
|
| 147 |
+
// of the current position is DRAW. If all moves lead to positions classified
|
| 148 |
+
// as WIN, the position is classified WIN otherwise the current position is
|
| 149 |
+
// classified UNKNOWN.
|
| 150 |
+
|
| 151 |
+
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
| 152 |
+
|
| 153 |
+
Result r = INVALID;
|
| 154 |
+
Bitboard b = StepAttacksBB[KING][Us == WHITE ? wksq : bksq];
|
| 155 |
+
|
| 156 |
+
while (b)
|
| 157 |
+
r |= Us == WHITE ? db[index(Them, bksq, pop_lsb(&b), psq)]
|
| 158 |
+
: db[index(Them, pop_lsb(&b), wksq, psq)];
|
| 159 |
+
|
| 160 |
+
if (Us == WHITE && rank_of(psq) < RANK_7)
|
| 161 |
+
{
|
| 162 |
+
Square s = psq + DELTA_N;
|
| 163 |
+
r |= db[index(BLACK, bksq, wksq, s)]; // Single push
|
| 164 |
+
|
| 165 |
+
if (rank_of(s) == RANK_3 && s != wksq && s != bksq)
|
| 166 |
+
r |= db[index(BLACK, bksq, wksq, s + DELTA_N)]; // Double push
|
| 167 |
+
}
|
| 168 |
+
|
| 169 |
+
if (Us == WHITE)
|
| 170 |
+
return res = r & WIN ? WIN : r & UNKNOWN ? UNKNOWN : DRAW;
|
| 171 |
+
else
|
| 172 |
+
return res = r & DRAW ? DRAW : r & UNKNOWN ? UNKNOWN : WIN;
|
| 173 |
+
}
|
| 174 |
+
|
| 175 |
+
} // namespace
|
stockfish-4-win/src/bitboard.cpp
ADDED
|
@@ -0,0 +1,339 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
+
Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
+
|
| 6 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 7 |
+
it under the terms of the GNU General Public License as published by
|
| 8 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 9 |
+
(at your option) any later version.
|
| 10 |
+
|
| 11 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 12 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 13 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 14 |
+
GNU General Public License for more details.
|
| 15 |
+
|
| 16 |
+
You should have received a copy of the GNU General Public License
|
| 17 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 18 |
+
*/
|
| 19 |
+
|
| 20 |
+
#include <algorithm>
|
| 21 |
+
#include <cstring>
|
| 22 |
+
#include <iostream>
|
| 23 |
+
|
| 24 |
+
#include "bitboard.h"
|
| 25 |
+
#include "bitcount.h"
|
| 26 |
+
#include "misc.h"
|
| 27 |
+
#include "rkiss.h"
|
| 28 |
+
|
| 29 |
+
CACHE_LINE_ALIGNMENT
|
| 30 |
+
|
| 31 |
+
Bitboard RMasks[SQUARE_NB];
|
| 32 |
+
Bitboard RMagics[SQUARE_NB];
|
| 33 |
+
Bitboard* RAttacks[SQUARE_NB];
|
| 34 |
+
unsigned RShifts[SQUARE_NB];
|
| 35 |
+
|
| 36 |
+
Bitboard BMasks[SQUARE_NB];
|
| 37 |
+
Bitboard BMagics[SQUARE_NB];
|
| 38 |
+
Bitboard* BAttacks[SQUARE_NB];
|
| 39 |
+
unsigned BShifts[SQUARE_NB];
|
| 40 |
+
|
| 41 |
+
Bitboard SquareBB[SQUARE_NB];
|
| 42 |
+
Bitboard FileBB[FILE_NB];
|
| 43 |
+
Bitboard RankBB[RANK_NB];
|
| 44 |
+
Bitboard AdjacentFilesBB[FILE_NB];
|
| 45 |
+
Bitboard InFrontBB[COLOR_NB][RANK_NB];
|
| 46 |
+
Bitboard StepAttacksBB[PIECE_NB][SQUARE_NB];
|
| 47 |
+
Bitboard BetweenBB[SQUARE_NB][SQUARE_NB];
|
| 48 |
+
Bitboard DistanceRingsBB[SQUARE_NB][8];
|
| 49 |
+
Bitboard ForwardBB[COLOR_NB][SQUARE_NB];
|
| 50 |
+
Bitboard PassedPawnMask[COLOR_NB][SQUARE_NB];
|
| 51 |
+
Bitboard PawnAttackSpan[COLOR_NB][SQUARE_NB];
|
| 52 |
+
Bitboard PseudoAttacks[PIECE_TYPE_NB][SQUARE_NB];
|
| 53 |
+
|
| 54 |
+
int SquareDistance[SQUARE_NB][SQUARE_NB];
|
| 55 |
+
|
| 56 |
+
namespace {
|
| 57 |
+
|
| 58 |
+
// De Bruijn sequences. See chessprogramming.wikispaces.com/BitScan
|
| 59 |
+
const uint64_t DeBruijn_64 = 0x3F79D71B4CB0A89ULL;
|
| 60 |
+
const uint32_t DeBruijn_32 = 0x783A9B23;
|
| 61 |
+
|
| 62 |
+
CACHE_LINE_ALIGNMENT
|
| 63 |
+
|
| 64 |
+
int MS1BTable[256];
|
| 65 |
+
Square BSFTable[SQUARE_NB];
|
| 66 |
+
Bitboard RTable[0x19000]; // Storage space for rook attacks
|
| 67 |
+
Bitboard BTable[0x1480]; // Storage space for bishop attacks
|
| 68 |
+
|
| 69 |
+
typedef unsigned (Fn)(Square, Bitboard);
|
| 70 |
+
|
| 71 |
+
void init_magics(Bitboard table[], Bitboard* attacks[], Bitboard magics[],
|
| 72 |
+
Bitboard masks[], unsigned shifts[], Square deltas[], Fn index);
|
| 73 |
+
|
| 74 |
+
FORCE_INLINE unsigned bsf_index(Bitboard b) {
|
| 75 |
+
|
| 76 |
+
// Matt Taylor's folding for 32 bit systems, extended to 64 bits by Kim Walisch
|
| 77 |
+
b ^= (b - 1);
|
| 78 |
+
return Is64Bit ? (b * DeBruijn_64) >> 58
|
| 79 |
+
: ((unsigned(b) ^ unsigned(b >> 32)) * DeBruijn_32) >> 26;
|
| 80 |
+
}
|
| 81 |
+
}
|
| 82 |
+
|
| 83 |
+
/// lsb()/msb() finds the least/most significant bit in a nonzero bitboard.
|
| 84 |
+
/// pop_lsb() finds and clears the least significant bit in a nonzero bitboard.
|
| 85 |
+
|
| 86 |
+
#ifndef USE_BSFQ
|
| 87 |
+
|
| 88 |
+
Square lsb(Bitboard b) { return BSFTable[bsf_index(b)]; }
|
| 89 |
+
|
| 90 |
+
Square pop_lsb(Bitboard* b) {
|
| 91 |
+
|
| 92 |
+
Bitboard bb = *b;
|
| 93 |
+
*b = bb & (bb - 1);
|
| 94 |
+
return BSFTable[bsf_index(bb)];
|
| 95 |
+
}
|
| 96 |
+
|
| 97 |
+
Square msb(Bitboard b) {
|
| 98 |
+
|
| 99 |
+
unsigned b32;
|
| 100 |
+
int result = 0;
|
| 101 |
+
|
| 102 |
+
if (b > 0xFFFFFFFF)
|
| 103 |
+
{
|
| 104 |
+
b >>= 32;
|
| 105 |
+
result = 32;
|
| 106 |
+
}
|
| 107 |
+
|
| 108 |
+
b32 = unsigned(b);
|
| 109 |
+
|
| 110 |
+
if (b32 > 0xFFFF)
|
| 111 |
+
{
|
| 112 |
+
b32 >>= 16;
|
| 113 |
+
result += 16;
|
| 114 |
+
}
|
| 115 |
+
|
| 116 |
+
if (b32 > 0xFF)
|
| 117 |
+
{
|
| 118 |
+
b32 >>= 8;
|
| 119 |
+
result += 8;
|
| 120 |
+
}
|
| 121 |
+
|
| 122 |
+
return (Square)(result + MS1BTable[b32]);
|
| 123 |
+
}
|
| 124 |
+
|
| 125 |
+
#endif // ifndef USE_BSFQ
|
| 126 |
+
|
| 127 |
+
|
| 128 |
+
/// Bitboards::print() prints a bitboard in an easily readable format to the
|
| 129 |
+
/// standard output. This is sometimes useful for debugging.
|
| 130 |
+
|
| 131 |
+
void Bitboards::print(Bitboard b) {
|
| 132 |
+
|
| 133 |
+
sync_cout;
|
| 134 |
+
|
| 135 |
+
for (Rank rank = RANK_8; rank >= RANK_1; rank--)
|
| 136 |
+
{
|
| 137 |
+
std::cout << "+---+---+---+---+---+---+---+---+" << '\n';
|
| 138 |
+
|
| 139 |
+
for (File file = FILE_A; file <= FILE_H; file++)
|
| 140 |
+
std::cout << "| " << (b & (file | rank) ? "X " : " ");
|
| 141 |
+
|
| 142 |
+
std::cout << "|\n";
|
| 143 |
+
}
|
| 144 |
+
std::cout << "+---+---+---+---+---+---+---+---+" << sync_endl;
|
| 145 |
+
}
|
| 146 |
+
|
| 147 |
+
|
| 148 |
+
/// Bitboards::init() initializes various bitboard arrays. It is called during
|
| 149 |
+
/// program initialization.
|
| 150 |
+
|
| 151 |
+
void Bitboards::init() {
|
| 152 |
+
|
| 153 |
+
for (int k = 0, i = 0; i < 8; i++)
|
| 154 |
+
while (k < (2 << i))
|
| 155 |
+
MS1BTable[k++] = i;
|
| 156 |
+
|
| 157 |
+
for (int i = 0; i < 64; i++)
|
| 158 |
+
BSFTable[bsf_index(1ULL << i)] = Square(i);
|
| 159 |
+
|
| 160 |
+
for (Square s = SQ_A1; s <= SQ_H8; s++)
|
| 161 |
+
SquareBB[s] = 1ULL << s;
|
| 162 |
+
|
| 163 |
+
FileBB[FILE_A] = FileABB;
|
| 164 |
+
RankBB[RANK_1] = Rank1BB;
|
| 165 |
+
|
| 166 |
+
for (int i = 1; i < 8; i++)
|
| 167 |
+
{
|
| 168 |
+
FileBB[i] = FileBB[i - 1] << 1;
|
| 169 |
+
RankBB[i] = RankBB[i - 1] << 8;
|
| 170 |
+
}
|
| 171 |
+
|
| 172 |
+
for (File f = FILE_A; f <= FILE_H; f++)
|
| 173 |
+
AdjacentFilesBB[f] = (f > FILE_A ? FileBB[f - 1] : 0) | (f < FILE_H ? FileBB[f + 1] : 0);
|
| 174 |
+
|
| 175 |
+
for (Rank r = RANK_1; r < RANK_8; r++)
|
| 176 |
+
InFrontBB[WHITE][r] = ~(InFrontBB[BLACK][r + 1] = InFrontBB[BLACK][r] | RankBB[r]);
|
| 177 |
+
|
| 178 |
+
for (Color c = WHITE; c <= BLACK; c++)
|
| 179 |
+
for (Square s = SQ_A1; s <= SQ_H8; s++)
|
| 180 |
+
{
|
| 181 |
+
ForwardBB[c][s] = InFrontBB[c][rank_of(s)] & FileBB[file_of(s)];
|
| 182 |
+
PawnAttackSpan[c][s] = InFrontBB[c][rank_of(s)] & AdjacentFilesBB[file_of(s)];
|
| 183 |
+
PassedPawnMask[c][s] = ForwardBB[c][s] | PawnAttackSpan[c][s];
|
| 184 |
+
}
|
| 185 |
+
|
| 186 |
+
for (Square s1 = SQ_A1; s1 <= SQ_H8; s1++)
|
| 187 |
+
for (Square s2 = SQ_A1; s2 <= SQ_H8; s2++)
|
| 188 |
+
{
|
| 189 |
+
SquareDistance[s1][s2] = std::max(file_distance(s1, s2), rank_distance(s1, s2));
|
| 190 |
+
if (s1 != s2)
|
| 191 |
+
DistanceRingsBB[s1][SquareDistance[s1][s2] - 1] |= s2;
|
| 192 |
+
}
|
| 193 |
+
|
| 194 |
+
int steps[][9] = { {}, { 7, 9 }, { 17, 15, 10, 6, -6, -10, -15, -17 },
|
| 195 |
+
{}, {}, {}, { 9, 7, -7, -9, 8, 1, -1, -8 } };
|
| 196 |
+
|
| 197 |
+
for (Color c = WHITE; c <= BLACK; c++)
|
| 198 |
+
for (PieceType pt = PAWN; pt <= KING; pt++)
|
| 199 |
+
for (Square s = SQ_A1; s <= SQ_H8; s++)
|
| 200 |
+
for (int k = 0; steps[pt][k]; k++)
|
| 201 |
+
{
|
| 202 |
+
Square to = s + Square(c == WHITE ? steps[pt][k] : -steps[pt][k]);
|
| 203 |
+
|
| 204 |
+
if (is_ok(to) && square_distance(s, to) < 3)
|
| 205 |
+
StepAttacksBB[make_piece(c, pt)][s] |= to;
|
| 206 |
+
}
|
| 207 |
+
|
| 208 |
+
Square RDeltas[] = { DELTA_N, DELTA_E, DELTA_S, DELTA_W };
|
| 209 |
+
Square BDeltas[] = { DELTA_NE, DELTA_SE, DELTA_SW, DELTA_NW };
|
| 210 |
+
|
| 211 |
+
init_magics(RTable, RAttacks, RMagics, RMasks, RShifts, RDeltas, magic_index<ROOK>);
|
| 212 |
+
init_magics(BTable, BAttacks, BMagics, BMasks, BShifts, BDeltas, magic_index<BISHOP>);
|
| 213 |
+
|
| 214 |
+
for (Square s = SQ_A1; s <= SQ_H8; s++)
|
| 215 |
+
{
|
| 216 |
+
PseudoAttacks[QUEEN][s] = PseudoAttacks[BISHOP][s] = attacks_bb<BISHOP>(s, 0);
|
| 217 |
+
PseudoAttacks[QUEEN][s] |= PseudoAttacks[ ROOK][s] = attacks_bb< ROOK>(s, 0);
|
| 218 |
+
}
|
| 219 |
+
|
| 220 |
+
for (Square s1 = SQ_A1; s1 <= SQ_H8; s1++)
|
| 221 |
+
for (Square s2 = SQ_A1; s2 <= SQ_H8; s2++)
|
| 222 |
+
if (PseudoAttacks[QUEEN][s1] & s2)
|
| 223 |
+
{
|
| 224 |
+
Square delta = (s2 - s1) / square_distance(s1, s2);
|
| 225 |
+
|
| 226 |
+
for (Square s = s1 + delta; s != s2; s += delta)
|
| 227 |
+
BetweenBB[s1][s2] |= s;
|
| 228 |
+
}
|
| 229 |
+
}
|
| 230 |
+
|
| 231 |
+
|
| 232 |
+
namespace {
|
| 233 |
+
|
| 234 |
+
Bitboard sliding_attack(Square deltas[], Square sq, Bitboard occupied) {
|
| 235 |
+
|
| 236 |
+
Bitboard attack = 0;
|
| 237 |
+
|
| 238 |
+
for (int i = 0; i < 4; i++)
|
| 239 |
+
for (Square s = sq + deltas[i];
|
| 240 |
+
is_ok(s) && square_distance(s, s - deltas[i]) == 1;
|
| 241 |
+
s += deltas[i])
|
| 242 |
+
{
|
| 243 |
+
attack |= s;
|
| 244 |
+
|
| 245 |
+
if (occupied & s)
|
| 246 |
+
break;
|
| 247 |
+
}
|
| 248 |
+
|
| 249 |
+
return attack;
|
| 250 |
+
}
|
| 251 |
+
|
| 252 |
+
|
| 253 |
+
Bitboard pick_random(RKISS& rk, int booster) {
|
| 254 |
+
|
| 255 |
+
// Values s1 and s2 are used to rotate the candidate magic of a
|
| 256 |
+
// quantity known to be the optimal to quickly find the magics.
|
| 257 |
+
int s1 = booster & 63, s2 = (booster >> 6) & 63;
|
| 258 |
+
|
| 259 |
+
Bitboard m = rk.rand<Bitboard>();
|
| 260 |
+
m = (m >> s1) | (m << (64 - s1));
|
| 261 |
+
m &= rk.rand<Bitboard>();
|
| 262 |
+
m = (m >> s2) | (m << (64 - s2));
|
| 263 |
+
return m & rk.rand<Bitboard>();
|
| 264 |
+
}
|
| 265 |
+
|
| 266 |
+
|
| 267 |
+
// init_magics() computes all rook and bishop attacks at startup. Magic
|
| 268 |
+
// bitboards are used to look up attacks of sliding pieces. As a reference see
|
| 269 |
+
// chessprogramming.wikispaces.com/Magic+Bitboards. In particular, here we
|
| 270 |
+
// use the so called "fancy" approach.
|
| 271 |
+
|
| 272 |
+
void init_magics(Bitboard table[], Bitboard* attacks[], Bitboard magics[],
|
| 273 |
+
Bitboard masks[], unsigned shifts[], Square deltas[], Fn index) {
|
| 274 |
+
|
| 275 |
+
int MagicBoosters[][8] = { { 3191, 2184, 1310, 3618, 2091, 1308, 2452, 3996 },
|
| 276 |
+
{ 1059, 3608, 605, 3234, 3326, 38, 2029, 3043 } };
|
| 277 |
+
RKISS rk;
|
| 278 |
+
Bitboard occupancy[4096], reference[4096], edges, b;
|
| 279 |
+
int i, size, booster;
|
| 280 |
+
|
| 281 |
+
// attacks[s] is a pointer to the beginning of the attacks table for square 's'
|
| 282 |
+
attacks[SQ_A1] = table;
|
| 283 |
+
|
| 284 |
+
for (Square s = SQ_A1; s <= SQ_H8; s++)
|
| 285 |
+
{
|
| 286 |
+
// Board edges are not considered in the relevant occupancies
|
| 287 |
+
edges = ((Rank1BB | Rank8BB) & ~rank_bb(s)) | ((FileABB | FileHBB) & ~file_bb(s));
|
| 288 |
+
|
| 289 |
+
// Given a square 's', the mask is the bitboard of sliding attacks from
|
| 290 |
+
// 's' computed on an empty board. The index must be big enough to contain
|
| 291 |
+
// all the attacks for each possible subset of the mask and so is 2 power
|
| 292 |
+
// the number of 1s of the mask. Hence we deduce the size of the shift to
|
| 293 |
+
// apply to the 64 or 32 bits word to get the index.
|
| 294 |
+
masks[s] = sliding_attack(deltas, s, 0) & ~edges;
|
| 295 |
+
shifts[s] = (Is64Bit ? 64 : 32) - popcount<Max15>(masks[s]);
|
| 296 |
+
|
| 297 |
+
// Use Carry-Rippler trick to enumerate all subsets of masks[s] and
|
| 298 |
+
// store the corresponding sliding attack bitboard in reference[].
|
| 299 |
+
b = size = 0;
|
| 300 |
+
do {
|
| 301 |
+
occupancy[size] = b;
|
| 302 |
+
reference[size++] = sliding_attack(deltas, s, b);
|
| 303 |
+
b = (b - masks[s]) & masks[s];
|
| 304 |
+
} while (b);
|
| 305 |
+
|
| 306 |
+
// Set the offset for the table of the next square. We have individual
|
| 307 |
+
// table sizes for each square with "Fancy Magic Bitboards".
|
| 308 |
+
if (s < SQ_H8)
|
| 309 |
+
attacks[s + 1] = attacks[s] + size;
|
| 310 |
+
|
| 311 |
+
booster = MagicBoosters[Is64Bit][rank_of(s)];
|
| 312 |
+
|
| 313 |
+
// Find a magic for square 's' picking up an (almost) random number
|
| 314 |
+
// until we find the one that passes the verification test.
|
| 315 |
+
do {
|
| 316 |
+
do magics[s] = pick_random(rk, booster);
|
| 317 |
+
while (popcount<Max15>((magics[s] * masks[s]) >> 56) < 6);
|
| 318 |
+
|
| 319 |
+
std::memset(attacks[s], 0, size * sizeof(Bitboard));
|
| 320 |
+
|
| 321 |
+
// A good magic must map every possible occupancy to an index that
|
| 322 |
+
// looks up the correct sliding attack in the attacks[s] database.
|
| 323 |
+
// Note that we build up the database for square 's' as a side
|
| 324 |
+
// effect of verifying the magic.
|
| 325 |
+
for (i = 0; i < size; i++)
|
| 326 |
+
{
|
| 327 |
+
Bitboard& attack = attacks[s][index(s, occupancy[i])];
|
| 328 |
+
|
| 329 |
+
if (attack && attack != reference[i])
|
| 330 |
+
break;
|
| 331 |
+
|
| 332 |
+
assert(reference[i] != 0);
|
| 333 |
+
|
| 334 |
+
attack = reference[i];
|
| 335 |
+
}
|
| 336 |
+
} while (i != size);
|
| 337 |
+
}
|
| 338 |
+
}
|
| 339 |
+
}
|
stockfish-4-win/src/bitboard.h
ADDED
|
@@ -0,0 +1,322 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
+
Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
+
|
| 6 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 7 |
+
it under the terms of the GNU General Public License as published by
|
| 8 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 9 |
+
(at your option) any later version.
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 13 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 15 |
+
GNU General Public License for more details.
|
| 16 |
+
|
| 17 |
+
You should have received a copy of the GNU General Public License
|
| 18 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 19 |
+
*/
|
| 20 |
+
|
| 21 |
+
#ifndef BITBOARD_H_INCLUDED
|
| 22 |
+
#define BITBOARD_H_INCLUDED
|
| 23 |
+
|
| 24 |
+
#include "types.h"
|
| 25 |
+
|
| 26 |
+
namespace Bitboards {
|
| 27 |
+
|
| 28 |
+
void init();
|
| 29 |
+
void print(Bitboard b);
|
| 30 |
+
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
namespace Bitbases {
|
| 34 |
+
|
| 35 |
+
void init_kpk();
|
| 36 |
+
bool probe_kpk(Square wksq, Square wpsq, Square bksq, Color us);
|
| 37 |
+
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
const Bitboard FileABB = 0x0101010101010101ULL;
|
| 41 |
+
const Bitboard FileBBB = FileABB << 1;
|
| 42 |
+
const Bitboard FileCBB = FileABB << 2;
|
| 43 |
+
const Bitboard FileDBB = FileABB << 3;
|
| 44 |
+
const Bitboard FileEBB = FileABB << 4;
|
| 45 |
+
const Bitboard FileFBB = FileABB << 5;
|
| 46 |
+
const Bitboard FileGBB = FileABB << 6;
|
| 47 |
+
const Bitboard FileHBB = FileABB << 7;
|
| 48 |
+
|
| 49 |
+
const Bitboard Rank1BB = 0xFF;
|
| 50 |
+
const Bitboard Rank2BB = Rank1BB << (8 * 1);
|
| 51 |
+
const Bitboard Rank3BB = Rank1BB << (8 * 2);
|
| 52 |
+
const Bitboard Rank4BB = Rank1BB << (8 * 3);
|
| 53 |
+
const Bitboard Rank5BB = Rank1BB << (8 * 4);
|
| 54 |
+
const Bitboard Rank6BB = Rank1BB << (8 * 5);
|
| 55 |
+
const Bitboard Rank7BB = Rank1BB << (8 * 6);
|
| 56 |
+
const Bitboard Rank8BB = Rank1BB << (8 * 7);
|
| 57 |
+
|
| 58 |
+
CACHE_LINE_ALIGNMENT
|
| 59 |
+
|
| 60 |
+
extern Bitboard RMasks[SQUARE_NB];
|
| 61 |
+
extern Bitboard RMagics[SQUARE_NB];
|
| 62 |
+
extern Bitboard* RAttacks[SQUARE_NB];
|
| 63 |
+
extern unsigned RShifts[SQUARE_NB];
|
| 64 |
+
|
| 65 |
+
extern Bitboard BMasks[SQUARE_NB];
|
| 66 |
+
extern Bitboard BMagics[SQUARE_NB];
|
| 67 |
+
extern Bitboard* BAttacks[SQUARE_NB];
|
| 68 |
+
extern unsigned BShifts[SQUARE_NB];
|
| 69 |
+
|
| 70 |
+
extern Bitboard SquareBB[SQUARE_NB];
|
| 71 |
+
extern Bitboard FileBB[FILE_NB];
|
| 72 |
+
extern Bitboard RankBB[RANK_NB];
|
| 73 |
+
extern Bitboard AdjacentFilesBB[FILE_NB];
|
| 74 |
+
extern Bitboard InFrontBB[COLOR_NB][RANK_NB];
|
| 75 |
+
extern Bitboard StepAttacksBB[PIECE_NB][SQUARE_NB];
|
| 76 |
+
extern Bitboard BetweenBB[SQUARE_NB][SQUARE_NB];
|
| 77 |
+
extern Bitboard DistanceRingsBB[SQUARE_NB][8];
|
| 78 |
+
extern Bitboard ForwardBB[COLOR_NB][SQUARE_NB];
|
| 79 |
+
extern Bitboard PassedPawnMask[COLOR_NB][SQUARE_NB];
|
| 80 |
+
extern Bitboard PawnAttackSpan[COLOR_NB][SQUARE_NB];
|
| 81 |
+
extern Bitboard PseudoAttacks[PIECE_TYPE_NB][SQUARE_NB];
|
| 82 |
+
|
| 83 |
+
extern int SquareDistance[SQUARE_NB][SQUARE_NB];
|
| 84 |
+
|
| 85 |
+
const Bitboard DarkSquares = 0xAA55AA55AA55AA55ULL;
|
| 86 |
+
|
| 87 |
+
/// Overloads of bitwise operators between a Bitboard and a Square for testing
|
| 88 |
+
/// whether a given bit is set in a bitboard, and for setting and clearing bits.
|
| 89 |
+
|
| 90 |
+
inline Bitboard operator&(Bitboard b, Square s) {
|
| 91 |
+
return b & SquareBB[s];
|
| 92 |
+
}
|
| 93 |
+
|
| 94 |
+
inline Bitboard& operator|=(Bitboard& b, Square s) {
|
| 95 |
+
return b |= SquareBB[s];
|
| 96 |
+
}
|
| 97 |
+
|
| 98 |
+
inline Bitboard& operator^=(Bitboard& b, Square s) {
|
| 99 |
+
return b ^= SquareBB[s];
|
| 100 |
+
}
|
| 101 |
+
|
| 102 |
+
inline Bitboard operator|(Bitboard b, Square s) {
|
| 103 |
+
return b | SquareBB[s];
|
| 104 |
+
}
|
| 105 |
+
|
| 106 |
+
inline Bitboard operator^(Bitboard b, Square s) {
|
| 107 |
+
return b ^ SquareBB[s];
|
| 108 |
+
}
|
| 109 |
+
|
| 110 |
+
inline bool more_than_one(Bitboard b) {
|
| 111 |
+
return b & (b - 1);
|
| 112 |
+
}
|
| 113 |
+
|
| 114 |
+
inline int square_distance(Square s1, Square s2) {
|
| 115 |
+
return SquareDistance[s1][s2];
|
| 116 |
+
}
|
| 117 |
+
|
| 118 |
+
inline int file_distance(Square s1, Square s2) {
|
| 119 |
+
return abs(file_of(s1) - file_of(s2));
|
| 120 |
+
}
|
| 121 |
+
|
| 122 |
+
inline int rank_distance(Square s1, Square s2) {
|
| 123 |
+
return abs(rank_of(s1) - rank_of(s2));
|
| 124 |
+
}
|
| 125 |
+
|
| 126 |
+
|
| 127 |
+
/// shift_bb() moves bitboard one step along direction Delta. Mainly for pawns.
|
| 128 |
+
|
| 129 |
+
template<Square Delta>
|
| 130 |
+
inline Bitboard shift_bb(Bitboard b) {
|
| 131 |
+
|
| 132 |
+
return Delta == DELTA_N ? b << 8 : Delta == DELTA_S ? b >> 8
|
| 133 |
+
: Delta == DELTA_NE ? (b & ~FileHBB) << 9 : Delta == DELTA_SE ? (b & ~FileHBB) >> 7
|
| 134 |
+
: Delta == DELTA_NW ? (b & ~FileABB) << 7 : Delta == DELTA_SW ? (b & ~FileABB) >> 9
|
| 135 |
+
: 0;
|
| 136 |
+
}
|
| 137 |
+
|
| 138 |
+
|
| 139 |
+
/// rank_bb() and file_bb() take a file or a square as input and return
|
| 140 |
+
/// a bitboard representing all squares on the given file or rank.
|
| 141 |
+
|
| 142 |
+
inline Bitboard rank_bb(Rank r) {
|
| 143 |
+
return RankBB[r];
|
| 144 |
+
}
|
| 145 |
+
|
| 146 |
+
inline Bitboard rank_bb(Square s) {
|
| 147 |
+
return RankBB[rank_of(s)];
|
| 148 |
+
}
|
| 149 |
+
|
| 150 |
+
inline Bitboard file_bb(File f) {
|
| 151 |
+
return FileBB[f];
|
| 152 |
+
}
|
| 153 |
+
|
| 154 |
+
inline Bitboard file_bb(Square s) {
|
| 155 |
+
return FileBB[file_of(s)];
|
| 156 |
+
}
|
| 157 |
+
|
| 158 |
+
|
| 159 |
+
/// adjacent_files_bb() takes a file as input and returns a bitboard representing
|
| 160 |
+
/// all squares on the adjacent files.
|
| 161 |
+
|
| 162 |
+
inline Bitboard adjacent_files_bb(File f) {
|
| 163 |
+
return AdjacentFilesBB[f];
|
| 164 |
+
}
|
| 165 |
+
|
| 166 |
+
|
| 167 |
+
/// in_front_bb() takes a color and a rank as input, and returns a bitboard
|
| 168 |
+
/// representing all the squares on all ranks in front of the rank, from the
|
| 169 |
+
/// given color's point of view. For instance, in_front_bb(BLACK, RANK_3) will
|
| 170 |
+
/// give all squares on ranks 1 and 2.
|
| 171 |
+
|
| 172 |
+
inline Bitboard in_front_bb(Color c, Rank r) {
|
| 173 |
+
return InFrontBB[c][r];
|
| 174 |
+
}
|
| 175 |
+
|
| 176 |
+
|
| 177 |
+
/// between_bb() returns a bitboard representing all squares between two squares.
|
| 178 |
+
/// For instance, between_bb(SQ_C4, SQ_F7) returns a bitboard with the bits for
|
| 179 |
+
/// square d5 and e6 set. If s1 and s2 are not on the same line, file or diagonal,
|
| 180 |
+
/// 0 is returned.
|
| 181 |
+
|
| 182 |
+
inline Bitboard between_bb(Square s1, Square s2) {
|
| 183 |
+
return BetweenBB[s1][s2];
|
| 184 |
+
}
|
| 185 |
+
|
| 186 |
+
|
| 187 |
+
/// forward_bb() takes a color and a square as input, and returns a bitboard
|
| 188 |
+
/// representing all squares along the line in front of the square, from the
|
| 189 |
+
/// point of view of the given color. Definition of the table is:
|
| 190 |
+
/// ForwardBB[c][s] = in_front_bb(c, s) & file_bb(s)
|
| 191 |
+
|
| 192 |
+
inline Bitboard forward_bb(Color c, Square s) {
|
| 193 |
+
return ForwardBB[c][s];
|
| 194 |
+
}
|
| 195 |
+
|
| 196 |
+
|
| 197 |
+
/// pawn_attack_span() takes a color and a square as input, and returns a bitboard
|
| 198 |
+
/// representing all squares that can be attacked by a pawn of the given color
|
| 199 |
+
/// when it moves along its file starting from the given square. Definition is:
|
| 200 |
+
/// PawnAttackSpan[c][s] = in_front_bb(c, s) & adjacent_files_bb(s);
|
| 201 |
+
|
| 202 |
+
inline Bitboard pawn_attack_span(Color c, Square s) {
|
| 203 |
+
return PawnAttackSpan[c][s];
|
| 204 |
+
}
|
| 205 |
+
|
| 206 |
+
|
| 207 |
+
/// passed_pawn_mask() takes a color and a square as input, and returns a
|
| 208 |
+
/// bitboard mask which can be used to test if a pawn of the given color on
|
| 209 |
+
/// the given square is a passed pawn. Definition of the table is:
|
| 210 |
+
/// PassedPawnMask[c][s] = pawn_attack_span(c, s) | forward_bb(c, s)
|
| 211 |
+
|
| 212 |
+
inline Bitboard passed_pawn_mask(Color c, Square s) {
|
| 213 |
+
return PassedPawnMask[c][s];
|
| 214 |
+
}
|
| 215 |
+
|
| 216 |
+
|
| 217 |
+
/// squares_of_color() returns a bitboard representing all squares with the same
|
| 218 |
+
/// color of the given square.
|
| 219 |
+
|
| 220 |
+
inline Bitboard squares_of_color(Square s) {
|
| 221 |
+
return DarkSquares & s ? DarkSquares : ~DarkSquares;
|
| 222 |
+
}
|
| 223 |
+
|
| 224 |
+
|
| 225 |
+
/// squares_aligned() returns true if the squares s1, s2 and s3 are aligned
|
| 226 |
+
/// either on a straight or on a diagonal line.
|
| 227 |
+
|
| 228 |
+
inline bool squares_aligned(Square s1, Square s2, Square s3) {
|
| 229 |
+
return (BetweenBB[s1][s2] | BetweenBB[s1][s3] | BetweenBB[s2][s3])
|
| 230 |
+
& ( SquareBB[s1] | SquareBB[s2] | SquareBB[s3]);
|
| 231 |
+
}
|
| 232 |
+
|
| 233 |
+
|
| 234 |
+
/// Functions for computing sliding attack bitboards. Function attacks_bb() takes
|
| 235 |
+
/// a square and a bitboard of occupied squares as input, and returns a bitboard
|
| 236 |
+
/// representing all squares attacked by Pt (bishop or rook) on the given square.
|
| 237 |
+
template<PieceType Pt>
|
| 238 |
+
FORCE_INLINE unsigned magic_index(Square s, Bitboard occ) {
|
| 239 |
+
|
| 240 |
+
Bitboard* const Masks = Pt == ROOK ? RMasks : BMasks;
|
| 241 |
+
Bitboard* const Magics = Pt == ROOK ? RMagics : BMagics;
|
| 242 |
+
unsigned* const Shifts = Pt == ROOK ? RShifts : BShifts;
|
| 243 |
+
|
| 244 |
+
if (Is64Bit)
|
| 245 |
+
return unsigned(((occ & Masks[s]) * Magics[s]) >> Shifts[s]);
|
| 246 |
+
|
| 247 |
+
unsigned lo = unsigned(occ) & unsigned(Masks[s]);
|
| 248 |
+
unsigned hi = unsigned(occ >> 32) & unsigned(Masks[s] >> 32);
|
| 249 |
+
return (lo * unsigned(Magics[s]) ^ hi * unsigned(Magics[s] >> 32)) >> Shifts[s];
|
| 250 |
+
}
|
| 251 |
+
|
| 252 |
+
template<PieceType Pt>
|
| 253 |
+
inline Bitboard attacks_bb(Square s, Bitboard occ) {
|
| 254 |
+
return (Pt == ROOK ? RAttacks : BAttacks)[s][magic_index<Pt>(s, occ)];
|
| 255 |
+
}
|
| 256 |
+
|
| 257 |
+
|
| 258 |
+
/// lsb()/msb() finds the least/most significant bit in a nonzero bitboard.
|
| 259 |
+
/// pop_lsb() finds and clears the least significant bit in a nonzero bitboard.
|
| 260 |
+
|
| 261 |
+
#ifdef USE_BSFQ
|
| 262 |
+
|
| 263 |
+
# if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
|
| 264 |
+
|
| 265 |
+
FORCE_INLINE Square lsb(Bitboard b) {
|
| 266 |
+
unsigned long index;
|
| 267 |
+
_BitScanForward64(&index, b);
|
| 268 |
+
return (Square) index;
|
| 269 |
+
}
|
| 270 |
+
|
| 271 |
+
FORCE_INLINE Square msb(Bitboard b) {
|
| 272 |
+
unsigned long index;
|
| 273 |
+
_BitScanReverse64(&index, b);
|
| 274 |
+
return (Square) index;
|
| 275 |
+
}
|
| 276 |
+
|
| 277 |
+
# elif defined(__arm__)
|
| 278 |
+
|
| 279 |
+
FORCE_INLINE int lsb32(uint32_t v) {
|
| 280 |
+
__asm__("rbit %0, %1" : "=r"(v) : "r"(v));
|
| 281 |
+
return __builtin_clz(v);
|
| 282 |
+
}
|
| 283 |
+
|
| 284 |
+
FORCE_INLINE Square msb(Bitboard b) {
|
| 285 |
+
return (Square) (63 - __builtin_clzll(b));
|
| 286 |
+
}
|
| 287 |
+
|
| 288 |
+
FORCE_INLINE Square lsb(Bitboard b) {
|
| 289 |
+
return (Square) (uint32_t(b) ? lsb32(uint32_t(b)) : 32 + lsb32(uint32_t(b >> 32)));
|
| 290 |
+
}
|
| 291 |
+
|
| 292 |
+
# else
|
| 293 |
+
|
| 294 |
+
FORCE_INLINE Square lsb(Bitboard b) { // Assembly code by Heinz van Saanen
|
| 295 |
+
Bitboard index;
|
| 296 |
+
__asm__("bsfq %1, %0": "=r"(index): "rm"(b) );
|
| 297 |
+
return (Square) index;
|
| 298 |
+
}
|
| 299 |
+
|
| 300 |
+
FORCE_INLINE Square msb(Bitboard b) {
|
| 301 |
+
Bitboard index;
|
| 302 |
+
__asm__("bsrq %1, %0": "=r"(index): "rm"(b) );
|
| 303 |
+
return (Square) index;
|
| 304 |
+
}
|
| 305 |
+
|
| 306 |
+
# endif
|
| 307 |
+
|
| 308 |
+
FORCE_INLINE Square pop_lsb(Bitboard* b) {
|
| 309 |
+
const Square s = lsb(*b);
|
| 310 |
+
*b &= *b - 1;
|
| 311 |
+
return s;
|
| 312 |
+
}
|
| 313 |
+
|
| 314 |
+
#else // if defined(USE_BSFQ)
|
| 315 |
+
|
| 316 |
+
extern Square msb(Bitboard b);
|
| 317 |
+
extern Square lsb(Bitboard b);
|
| 318 |
+
extern Square pop_lsb(Bitboard* b);
|
| 319 |
+
|
| 320 |
+
#endif
|
| 321 |
+
|
| 322 |
+
#endif // #ifndef BITBOARD_H_INCLUDED
|
stockfish-4-win/src/bitcount.h
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
+
Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
+
|
| 6 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 7 |
+
it under the terms of the GNU General Public License as published by
|
| 8 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 9 |
+
(at your option) any later version.
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 13 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 15 |
+
GNU General Public License for more details.
|
| 16 |
+
|
| 17 |
+
You should have received a copy of the GNU General Public License
|
| 18 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 19 |
+
*/
|
| 20 |
+
|
| 21 |
+
#ifndef BITCOUNT_H_INCLUDED
|
| 22 |
+
#define BITCOUNT_H_INCLUDED
|
| 23 |
+
|
| 24 |
+
#include <cassert>
|
| 25 |
+
#include "types.h"
|
| 26 |
+
|
| 27 |
+
enum BitCountType {
|
| 28 |
+
CNT_64,
|
| 29 |
+
CNT_64_MAX15,
|
| 30 |
+
CNT_32,
|
| 31 |
+
CNT_32_MAX15,
|
| 32 |
+
CNT_HW_POPCNT
|
| 33 |
+
};
|
| 34 |
+
|
| 35 |
+
/// Determine at compile time the best popcount<> specialization according if
|
| 36 |
+
/// platform is 32 or 64 bits, to the maximum number of nonzero bits to count
|
| 37 |
+
/// and if hardware popcnt instruction is available.
|
| 38 |
+
const BitCountType Full = HasPopCnt ? CNT_HW_POPCNT : Is64Bit ? CNT_64 : CNT_32;
|
| 39 |
+
const BitCountType Max15 = HasPopCnt ? CNT_HW_POPCNT : Is64Bit ? CNT_64_MAX15 : CNT_32_MAX15;
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
/// popcount() counts the number of nonzero bits in a bitboard
|
| 43 |
+
template<BitCountType> inline int popcount(Bitboard);
|
| 44 |
+
|
| 45 |
+
template<>
|
| 46 |
+
inline int popcount<CNT_64>(Bitboard b) {
|
| 47 |
+
b -= (b >> 1) & 0x5555555555555555ULL;
|
| 48 |
+
b = ((b >> 2) & 0x3333333333333333ULL) + (b & 0x3333333333333333ULL);
|
| 49 |
+
b = ((b >> 4) + b) & 0x0F0F0F0F0F0F0F0FULL;
|
| 50 |
+
return (b * 0x0101010101010101ULL) >> 56;
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
template<>
|
| 54 |
+
inline int popcount<CNT_64_MAX15>(Bitboard b) {
|
| 55 |
+
b -= (b >> 1) & 0x5555555555555555ULL;
|
| 56 |
+
b = ((b >> 2) & 0x3333333333333333ULL) + (b & 0x3333333333333333ULL);
|
| 57 |
+
return (b * 0x1111111111111111ULL) >> 60;
|
| 58 |
+
}
|
| 59 |
+
|
| 60 |
+
template<>
|
| 61 |
+
inline int popcount<CNT_32>(Bitboard b) {
|
| 62 |
+
unsigned w = unsigned(b >> 32), v = unsigned(b);
|
| 63 |
+
v -= (v >> 1) & 0x55555555; // 0-2 in 2 bits
|
| 64 |
+
w -= (w >> 1) & 0x55555555;
|
| 65 |
+
v = ((v >> 2) & 0x33333333) + (v & 0x33333333); // 0-4 in 4 bits
|
| 66 |
+
w = ((w >> 2) & 0x33333333) + (w & 0x33333333);
|
| 67 |
+
v = ((v >> 4) + v + (w >> 4) + w) & 0x0F0F0F0F;
|
| 68 |
+
return (v * 0x01010101) >> 24;
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
template<>
|
| 72 |
+
inline int popcount<CNT_32_MAX15>(Bitboard b) {
|
| 73 |
+
unsigned w = unsigned(b >> 32), v = unsigned(b);
|
| 74 |
+
v -= (v >> 1) & 0x55555555; // 0-2 in 2 bits
|
| 75 |
+
w -= (w >> 1) & 0x55555555;
|
| 76 |
+
v = ((v >> 2) & 0x33333333) + (v & 0x33333333); // 0-4 in 4 bits
|
| 77 |
+
w = ((w >> 2) & 0x33333333) + (w & 0x33333333);
|
| 78 |
+
return ((v + w) * 0x11111111) >> 28;
|
| 79 |
+
}
|
| 80 |
+
|
| 81 |
+
template<>
|
| 82 |
+
inline int popcount<CNT_HW_POPCNT>(Bitboard b) {
|
| 83 |
+
|
| 84 |
+
#ifndef USE_POPCNT
|
| 85 |
+
|
| 86 |
+
assert(false);
|
| 87 |
+
return b != 0; // Avoid 'b not used' warning
|
| 88 |
+
|
| 89 |
+
#elif defined(_MSC_VER) && defined(__INTEL_COMPILER)
|
| 90 |
+
|
| 91 |
+
return _mm_popcnt_u64(b);
|
| 92 |
+
|
| 93 |
+
#elif defined(_MSC_VER)
|
| 94 |
+
|
| 95 |
+
return (int)__popcnt64(b);
|
| 96 |
+
|
| 97 |
+
#else
|
| 98 |
+
|
| 99 |
+
__asm__("popcnt %1, %0" : "=r" (b) : "r" (b));
|
| 100 |
+
return b;
|
| 101 |
+
|
| 102 |
+
#endif
|
| 103 |
+
}
|
| 104 |
+
|
| 105 |
+
#endif // #ifndef BITCOUNT_H_INCLUDED
|
stockfish-4-win/src/book.cpp
ADDED
|
@@ -0,0 +1,478 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
+
Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
+
|
| 6 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 7 |
+
it under the terms of the GNU General Public License as published by
|
| 8 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 9 |
+
(at your option) any later version.
|
| 10 |
+
|
| 11 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 12 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 13 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 14 |
+
GNU General Public License for more details.
|
| 15 |
+
|
| 16 |
+
You should have received a copy of the GNU General Public License
|
| 17 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 18 |
+
*/
|
| 19 |
+
|
| 20 |
+
/*
|
| 21 |
+
The code in this file is based on the opening book code in PolyGlot
|
| 22 |
+
by Fabien Letouzey. PolyGlot is available under the GNU General
|
| 23 |
+
Public License, and can be downloaded from http://wbec-ridderkerk.nl
|
| 24 |
+
*/
|
| 25 |
+
|
| 26 |
+
#include <algorithm>
|
| 27 |
+
#include <cassert>
|
| 28 |
+
#include <iostream>
|
| 29 |
+
|
| 30 |
+
#include "book.h"
|
| 31 |
+
#include "misc.h"
|
| 32 |
+
#include "movegen.h"
|
| 33 |
+
|
| 34 |
+
using namespace std;
|
| 35 |
+
|
| 36 |
+
namespace {
|
| 37 |
+
|
| 38 |
+
// A Polyglot book is a series of "entries" of 16 bytes. All integers are
|
| 39 |
+
// stored in big-endian format, with highest byte first (regardless of size).
|
| 40 |
+
// The entries are ordered according to the key in ascending order.
|
| 41 |
+
struct Entry {
|
| 42 |
+
uint64_t key;
|
| 43 |
+
uint16_t move;
|
| 44 |
+
uint16_t count;
|
| 45 |
+
uint32_t learn;
|
| 46 |
+
};
|
| 47 |
+
|
| 48 |
+
// Random numbers from PolyGlot, used to compute book hash keys
|
| 49 |
+
const union {
|
| 50 |
+
Key PolyGlotRandoms[781];
|
| 51 |
+
struct {
|
| 52 |
+
Key psq[12][64]; // [piece][square]
|
| 53 |
+
Key castle[4]; // [castle right]
|
| 54 |
+
Key enpassant[8]; // [file]
|
| 55 |
+
Key turn;
|
| 56 |
+
} Zobrist;
|
| 57 |
+
} PG = {{
|
| 58 |
+
0x9D39247E33776D41ULL, 0x2AF7398005AAA5C7ULL, 0x44DB015024623547ULL,
|
| 59 |
+
0x9C15F73E62A76AE2ULL, 0x75834465489C0C89ULL, 0x3290AC3A203001BFULL,
|
| 60 |
+
0x0FBBAD1F61042279ULL, 0xE83A908FF2FB60CAULL, 0x0D7E765D58755C10ULL,
|
| 61 |
+
0x1A083822CEAFE02DULL, 0x9605D5F0E25EC3B0ULL, 0xD021FF5CD13A2ED5ULL,
|
| 62 |
+
0x40BDF15D4A672E32ULL, 0x011355146FD56395ULL, 0x5DB4832046F3D9E5ULL,
|
| 63 |
+
0x239F8B2D7FF719CCULL, 0x05D1A1AE85B49AA1ULL, 0x679F848F6E8FC971ULL,
|
| 64 |
+
0x7449BBFF801FED0BULL, 0x7D11CDB1C3B7ADF0ULL, 0x82C7709E781EB7CCULL,
|
| 65 |
+
0xF3218F1C9510786CULL, 0x331478F3AF51BBE6ULL, 0x4BB38DE5E7219443ULL,
|
| 66 |
+
0xAA649C6EBCFD50FCULL, 0x8DBD98A352AFD40BULL, 0x87D2074B81D79217ULL,
|
| 67 |
+
0x19F3C751D3E92AE1ULL, 0xB4AB30F062B19ABFULL, 0x7B0500AC42047AC4ULL,
|
| 68 |
+
0xC9452CA81A09D85DULL, 0x24AA6C514DA27500ULL, 0x4C9F34427501B447ULL,
|
| 69 |
+
0x14A68FD73C910841ULL, 0xA71B9B83461CBD93ULL, 0x03488B95B0F1850FULL,
|
| 70 |
+
0x637B2B34FF93C040ULL, 0x09D1BC9A3DD90A94ULL, 0x3575668334A1DD3BULL,
|
| 71 |
+
0x735E2B97A4C45A23ULL, 0x18727070F1BD400BULL, 0x1FCBACD259BF02E7ULL,
|
| 72 |
+
0xD310A7C2CE9B6555ULL, 0xBF983FE0FE5D8244ULL, 0x9F74D14F7454A824ULL,
|
| 73 |
+
0x51EBDC4AB9BA3035ULL, 0x5C82C505DB9AB0FAULL, 0xFCF7FE8A3430B241ULL,
|
| 74 |
+
0x3253A729B9BA3DDEULL, 0x8C74C368081B3075ULL, 0xB9BC6C87167C33E7ULL,
|
| 75 |
+
0x7EF48F2B83024E20ULL, 0x11D505D4C351BD7FULL, 0x6568FCA92C76A243ULL,
|
| 76 |
+
0x4DE0B0F40F32A7B8ULL, 0x96D693460CC37E5DULL, 0x42E240CB63689F2FULL,
|
| 77 |
+
0x6D2BDCDAE2919661ULL, 0x42880B0236E4D951ULL, 0x5F0F4A5898171BB6ULL,
|
| 78 |
+
0x39F890F579F92F88ULL, 0x93C5B5F47356388BULL, 0x63DC359D8D231B78ULL,
|
| 79 |
+
0xEC16CA8AEA98AD76ULL, 0x5355F900C2A82DC7ULL, 0x07FB9F855A997142ULL,
|
| 80 |
+
0x5093417AA8A7ED5EULL, 0x7BCBC38DA25A7F3CULL, 0x19FC8A768CF4B6D4ULL,
|
| 81 |
+
0x637A7780DECFC0D9ULL, 0x8249A47AEE0E41F7ULL, 0x79AD695501E7D1E8ULL,
|
| 82 |
+
0x14ACBAF4777D5776ULL, 0xF145B6BECCDEA195ULL, 0xDABF2AC8201752FCULL,
|
| 83 |
+
0x24C3C94DF9C8D3F6ULL, 0xBB6E2924F03912EAULL, 0x0CE26C0B95C980D9ULL,
|
| 84 |
+
0xA49CD132BFBF7CC4ULL, 0xE99D662AF4243939ULL, 0x27E6AD7891165C3FULL,
|
| 85 |
+
0x8535F040B9744FF1ULL, 0x54B3F4FA5F40D873ULL, 0x72B12C32127FED2BULL,
|
| 86 |
+
0xEE954D3C7B411F47ULL, 0x9A85AC909A24EAA1ULL, 0x70AC4CD9F04F21F5ULL,
|
| 87 |
+
0xF9B89D3E99A075C2ULL, 0x87B3E2B2B5C907B1ULL, 0xA366E5B8C54F48B8ULL,
|
| 88 |
+
0xAE4A9346CC3F7CF2ULL, 0x1920C04D47267BBDULL, 0x87BF02C6B49E2AE9ULL,
|
| 89 |
+
0x092237AC237F3859ULL, 0xFF07F64EF8ED14D0ULL, 0x8DE8DCA9F03CC54EULL,
|
| 90 |
+
0x9C1633264DB49C89ULL, 0xB3F22C3D0B0B38EDULL, 0x390E5FB44D01144BULL,
|
| 91 |
+
0x5BFEA5B4712768E9ULL, 0x1E1032911FA78984ULL, 0x9A74ACB964E78CB3ULL,
|
| 92 |
+
0x4F80F7A035DAFB04ULL, 0x6304D09A0B3738C4ULL, 0x2171E64683023A08ULL,
|
| 93 |
+
0x5B9B63EB9CEFF80CULL, 0x506AACF489889342ULL, 0x1881AFC9A3A701D6ULL,
|
| 94 |
+
0x6503080440750644ULL, 0xDFD395339CDBF4A7ULL, 0xEF927DBCF00C20F2ULL,
|
| 95 |
+
0x7B32F7D1E03680ECULL, 0xB9FD7620E7316243ULL, 0x05A7E8A57DB91B77ULL,
|
| 96 |
+
0xB5889C6E15630A75ULL, 0x4A750A09CE9573F7ULL, 0xCF464CEC899A2F8AULL,
|
| 97 |
+
0xF538639CE705B824ULL, 0x3C79A0FF5580EF7FULL, 0xEDE6C87F8477609DULL,
|
| 98 |
+
0x799E81F05BC93F31ULL, 0x86536B8CF3428A8CULL, 0x97D7374C60087B73ULL,
|
| 99 |
+
0xA246637CFF328532ULL, 0x043FCAE60CC0EBA0ULL, 0x920E449535DD359EULL,
|
| 100 |
+
0x70EB093B15B290CCULL, 0x73A1921916591CBDULL, 0x56436C9FE1A1AA8DULL,
|
| 101 |
+
0xEFAC4B70633B8F81ULL, 0xBB215798D45DF7AFULL, 0x45F20042F24F1768ULL,
|
| 102 |
+
0x930F80F4E8EB7462ULL, 0xFF6712FFCFD75EA1ULL, 0xAE623FD67468AA70ULL,
|
| 103 |
+
0xDD2C5BC84BC8D8FCULL, 0x7EED120D54CF2DD9ULL, 0x22FE545401165F1CULL,
|
| 104 |
+
0xC91800E98FB99929ULL, 0x808BD68E6AC10365ULL, 0xDEC468145B7605F6ULL,
|
| 105 |
+
0x1BEDE3A3AEF53302ULL, 0x43539603D6C55602ULL, 0xAA969B5C691CCB7AULL,
|
| 106 |
+
0xA87832D392EFEE56ULL, 0x65942C7B3C7E11AEULL, 0xDED2D633CAD004F6ULL,
|
| 107 |
+
0x21F08570F420E565ULL, 0xB415938D7DA94E3CULL, 0x91B859E59ECB6350ULL,
|
| 108 |
+
0x10CFF333E0ED804AULL, 0x28AED140BE0BB7DDULL, 0xC5CC1D89724FA456ULL,
|
| 109 |
+
0x5648F680F11A2741ULL, 0x2D255069F0B7DAB3ULL, 0x9BC5A38EF729ABD4ULL,
|
| 110 |
+
0xEF2F054308F6A2BCULL, 0xAF2042F5CC5C2858ULL, 0x480412BAB7F5BE2AULL,
|
| 111 |
+
0xAEF3AF4A563DFE43ULL, 0x19AFE59AE451497FULL, 0x52593803DFF1E840ULL,
|
| 112 |
+
0xF4F076E65F2CE6F0ULL, 0x11379625747D5AF3ULL, 0xBCE5D2248682C115ULL,
|
| 113 |
+
0x9DA4243DE836994FULL, 0x066F70B33FE09017ULL, 0x4DC4DE189B671A1CULL,
|
| 114 |
+
0x51039AB7712457C3ULL, 0xC07A3F80C31FB4B4ULL, 0xB46EE9C5E64A6E7CULL,
|
| 115 |
+
0xB3819A42ABE61C87ULL, 0x21A007933A522A20ULL, 0x2DF16F761598AA4FULL,
|
| 116 |
+
0x763C4A1371B368FDULL, 0xF793C46702E086A0ULL, 0xD7288E012AEB8D31ULL,
|
| 117 |
+
0xDE336A2A4BC1C44BULL, 0x0BF692B38D079F23ULL, 0x2C604A7A177326B3ULL,
|
| 118 |
+
0x4850E73E03EB6064ULL, 0xCFC447F1E53C8E1BULL, 0xB05CA3F564268D99ULL,
|
| 119 |
+
0x9AE182C8BC9474E8ULL, 0xA4FC4BD4FC5558CAULL, 0xE755178D58FC4E76ULL,
|
| 120 |
+
0x69B97DB1A4C03DFEULL, 0xF9B5B7C4ACC67C96ULL, 0xFC6A82D64B8655FBULL,
|
| 121 |
+
0x9C684CB6C4D24417ULL, 0x8EC97D2917456ED0ULL, 0x6703DF9D2924E97EULL,
|
| 122 |
+
0xC547F57E42A7444EULL, 0x78E37644E7CAD29EULL, 0xFE9A44E9362F05FAULL,
|
| 123 |
+
0x08BD35CC38336615ULL, 0x9315E5EB3A129ACEULL, 0x94061B871E04DF75ULL,
|
| 124 |
+
0xDF1D9F9D784BA010ULL, 0x3BBA57B68871B59DULL, 0xD2B7ADEEDED1F73FULL,
|
| 125 |
+
0xF7A255D83BC373F8ULL, 0xD7F4F2448C0CEB81ULL, 0xD95BE88CD210FFA7ULL,
|
| 126 |
+
0x336F52F8FF4728E7ULL, 0xA74049DAC312AC71ULL, 0xA2F61BB6E437FDB5ULL,
|
| 127 |
+
0x4F2A5CB07F6A35B3ULL, 0x87D380BDA5BF7859ULL, 0x16B9F7E06C453A21ULL,
|
| 128 |
+
0x7BA2484C8A0FD54EULL, 0xF3A678CAD9A2E38CULL, 0x39B0BF7DDE437BA2ULL,
|
| 129 |
+
0xFCAF55C1BF8A4424ULL, 0x18FCF680573FA594ULL, 0x4C0563B89F495AC3ULL,
|
| 130 |
+
0x40E087931A00930DULL, 0x8CFFA9412EB642C1ULL, 0x68CA39053261169FULL,
|
| 131 |
+
0x7A1EE967D27579E2ULL, 0x9D1D60E5076F5B6FULL, 0x3810E399B6F65BA2ULL,
|
| 132 |
+
0x32095B6D4AB5F9B1ULL, 0x35CAB62109DD038AULL, 0xA90B24499FCFAFB1ULL,
|
| 133 |
+
0x77A225A07CC2C6BDULL, 0x513E5E634C70E331ULL, 0x4361C0CA3F692F12ULL,
|
| 134 |
+
0xD941ACA44B20A45BULL, 0x528F7C8602C5807BULL, 0x52AB92BEB9613989ULL,
|
| 135 |
+
0x9D1DFA2EFC557F73ULL, 0x722FF175F572C348ULL, 0x1D1260A51107FE97ULL,
|
| 136 |
+
0x7A249A57EC0C9BA2ULL, 0x04208FE9E8F7F2D6ULL, 0x5A110C6058B920A0ULL,
|
| 137 |
+
0x0CD9A497658A5698ULL, 0x56FD23C8F9715A4CULL, 0x284C847B9D887AAEULL,
|
| 138 |
+
0x04FEABFBBDB619CBULL, 0x742E1E651C60BA83ULL, 0x9A9632E65904AD3CULL,
|
| 139 |
+
0x881B82A13B51B9E2ULL, 0x506E6744CD974924ULL, 0xB0183DB56FFC6A79ULL,
|
| 140 |
+
0x0ED9B915C66ED37EULL, 0x5E11E86D5873D484ULL, 0xF678647E3519AC6EULL,
|
| 141 |
+
0x1B85D488D0F20CC5ULL, 0xDAB9FE6525D89021ULL, 0x0D151D86ADB73615ULL,
|
| 142 |
+
0xA865A54EDCC0F019ULL, 0x93C42566AEF98FFBULL, 0x99E7AFEABE000731ULL,
|
| 143 |
+
0x48CBFF086DDF285AULL, 0x7F9B6AF1EBF78BAFULL, 0x58627E1A149BBA21ULL,
|
| 144 |
+
0x2CD16E2ABD791E33ULL, 0xD363EFF5F0977996ULL, 0x0CE2A38C344A6EEDULL,
|
| 145 |
+
0x1A804AADB9CFA741ULL, 0x907F30421D78C5DEULL, 0x501F65EDB3034D07ULL,
|
| 146 |
+
0x37624AE5A48FA6E9ULL, 0x957BAF61700CFF4EULL, 0x3A6C27934E31188AULL,
|
| 147 |
+
0xD49503536ABCA345ULL, 0x088E049589C432E0ULL, 0xF943AEE7FEBF21B8ULL,
|
| 148 |
+
0x6C3B8E3E336139D3ULL, 0x364F6FFA464EE52EULL, 0xD60F6DCEDC314222ULL,
|
| 149 |
+
0x56963B0DCA418FC0ULL, 0x16F50EDF91E513AFULL, 0xEF1955914B609F93ULL,
|
| 150 |
+
0x565601C0364E3228ULL, 0xECB53939887E8175ULL, 0xBAC7A9A18531294BULL,
|
| 151 |
+
0xB344C470397BBA52ULL, 0x65D34954DAF3CEBDULL, 0xB4B81B3FA97511E2ULL,
|
| 152 |
+
0xB422061193D6F6A7ULL, 0x071582401C38434DULL, 0x7A13F18BBEDC4FF5ULL,
|
| 153 |
+
0xBC4097B116C524D2ULL, 0x59B97885E2F2EA28ULL, 0x99170A5DC3115544ULL,
|
| 154 |
+
0x6F423357E7C6A9F9ULL, 0x325928EE6E6F8794ULL, 0xD0E4366228B03343ULL,
|
| 155 |
+
0x565C31F7DE89EA27ULL, 0x30F5611484119414ULL, 0xD873DB391292ED4FULL,
|
| 156 |
+
0x7BD94E1D8E17DEBCULL, 0xC7D9F16864A76E94ULL, 0x947AE053EE56E63CULL,
|
| 157 |
+
0xC8C93882F9475F5FULL, 0x3A9BF55BA91F81CAULL, 0xD9A11FBB3D9808E4ULL,
|
| 158 |
+
0x0FD22063EDC29FCAULL, 0xB3F256D8ACA0B0B9ULL, 0xB03031A8B4516E84ULL,
|
| 159 |
+
0x35DD37D5871448AFULL, 0xE9F6082B05542E4EULL, 0xEBFAFA33D7254B59ULL,
|
| 160 |
+
0x9255ABB50D532280ULL, 0xB9AB4CE57F2D34F3ULL, 0x693501D628297551ULL,
|
| 161 |
+
0xC62C58F97DD949BFULL, 0xCD454F8F19C5126AULL, 0xBBE83F4ECC2BDECBULL,
|
| 162 |
+
0xDC842B7E2819E230ULL, 0xBA89142E007503B8ULL, 0xA3BC941D0A5061CBULL,
|
| 163 |
+
0xE9F6760E32CD8021ULL, 0x09C7E552BC76492FULL, 0x852F54934DA55CC9ULL,
|
| 164 |
+
0x8107FCCF064FCF56ULL, 0x098954D51FFF6580ULL, 0x23B70EDB1955C4BFULL,
|
| 165 |
+
0xC330DE426430F69DULL, 0x4715ED43E8A45C0AULL, 0xA8D7E4DAB780A08DULL,
|
| 166 |
+
0x0572B974F03CE0BBULL, 0xB57D2E985E1419C7ULL, 0xE8D9ECBE2CF3D73FULL,
|
| 167 |
+
0x2FE4B17170E59750ULL, 0x11317BA87905E790ULL, 0x7FBF21EC8A1F45ECULL,
|
| 168 |
+
0x1725CABFCB045B00ULL, 0x964E915CD5E2B207ULL, 0x3E2B8BCBF016D66DULL,
|
| 169 |
+
0xBE7444E39328A0ACULL, 0xF85B2B4FBCDE44B7ULL, 0x49353FEA39BA63B1ULL,
|
| 170 |
+
0x1DD01AAFCD53486AULL, 0x1FCA8A92FD719F85ULL, 0xFC7C95D827357AFAULL,
|
| 171 |
+
0x18A6A990C8B35EBDULL, 0xCCCB7005C6B9C28DULL, 0x3BDBB92C43B17F26ULL,
|
| 172 |
+
0xAA70B5B4F89695A2ULL, 0xE94C39A54A98307FULL, 0xB7A0B174CFF6F36EULL,
|
| 173 |
+
0xD4DBA84729AF48ADULL, 0x2E18BC1AD9704A68ULL, 0x2DE0966DAF2F8B1CULL,
|
| 174 |
+
0xB9C11D5B1E43A07EULL, 0x64972D68DEE33360ULL, 0x94628D38D0C20584ULL,
|
| 175 |
+
0xDBC0D2B6AB90A559ULL, 0xD2733C4335C6A72FULL, 0x7E75D99D94A70F4DULL,
|
| 176 |
+
0x6CED1983376FA72BULL, 0x97FCAACBF030BC24ULL, 0x7B77497B32503B12ULL,
|
| 177 |
+
0x8547EDDFB81CCB94ULL, 0x79999CDFF70902CBULL, 0xCFFE1939438E9B24ULL,
|
| 178 |
+
0x829626E3892D95D7ULL, 0x92FAE24291F2B3F1ULL, 0x63E22C147B9C3403ULL,
|
| 179 |
+
0xC678B6D860284A1CULL, 0x5873888850659AE7ULL, 0x0981DCD296A8736DULL,
|
| 180 |
+
0x9F65789A6509A440ULL, 0x9FF38FED72E9052FULL, 0xE479EE5B9930578CULL,
|
| 181 |
+
0xE7F28ECD2D49EECDULL, 0x56C074A581EA17FEULL, 0x5544F7D774B14AEFULL,
|
| 182 |
+
0x7B3F0195FC6F290FULL, 0x12153635B2C0CF57ULL, 0x7F5126DBBA5E0CA7ULL,
|
| 183 |
+
0x7A76956C3EAFB413ULL, 0x3D5774A11D31AB39ULL, 0x8A1B083821F40CB4ULL,
|
| 184 |
+
0x7B4A38E32537DF62ULL, 0x950113646D1D6E03ULL, 0x4DA8979A0041E8A9ULL,
|
| 185 |
+
0x3BC36E078F7515D7ULL, 0x5D0A12F27AD310D1ULL, 0x7F9D1A2E1EBE1327ULL,
|
| 186 |
+
0xDA3A361B1C5157B1ULL, 0xDCDD7D20903D0C25ULL, 0x36833336D068F707ULL,
|
| 187 |
+
0xCE68341F79893389ULL, 0xAB9090168DD05F34ULL, 0x43954B3252DC25E5ULL,
|
| 188 |
+
0xB438C2B67F98E5E9ULL, 0x10DCD78E3851A492ULL, 0xDBC27AB5447822BFULL,
|
| 189 |
+
0x9B3CDB65F82CA382ULL, 0xB67B7896167B4C84ULL, 0xBFCED1B0048EAC50ULL,
|
| 190 |
+
0xA9119B60369FFEBDULL, 0x1FFF7AC80904BF45ULL, 0xAC12FB171817EEE7ULL,
|
| 191 |
+
0xAF08DA9177DDA93DULL, 0x1B0CAB936E65C744ULL, 0xB559EB1D04E5E932ULL,
|
| 192 |
+
0xC37B45B3F8D6F2BAULL, 0xC3A9DC228CAAC9E9ULL, 0xF3B8B6675A6507FFULL,
|
| 193 |
+
0x9FC477DE4ED681DAULL, 0x67378D8ECCEF96CBULL, 0x6DD856D94D259236ULL,
|
| 194 |
+
0xA319CE15B0B4DB31ULL, 0x073973751F12DD5EULL, 0x8A8E849EB32781A5ULL,
|
| 195 |
+
0xE1925C71285279F5ULL, 0x74C04BF1790C0EFEULL, 0x4DDA48153C94938AULL,
|
| 196 |
+
0x9D266D6A1CC0542CULL, 0x7440FB816508C4FEULL, 0x13328503DF48229FULL,
|
| 197 |
+
0xD6BF7BAEE43CAC40ULL, 0x4838D65F6EF6748FULL, 0x1E152328F3318DEAULL,
|
| 198 |
+
0x8F8419A348F296BFULL, 0x72C8834A5957B511ULL, 0xD7A023A73260B45CULL,
|
| 199 |
+
0x94EBC8ABCFB56DAEULL, 0x9FC10D0F989993E0ULL, 0xDE68A2355B93CAE6ULL,
|
| 200 |
+
0xA44CFE79AE538BBEULL, 0x9D1D84FCCE371425ULL, 0x51D2B1AB2DDFB636ULL,
|
| 201 |
+
0x2FD7E4B9E72CD38CULL, 0x65CA5B96B7552210ULL, 0xDD69A0D8AB3B546DULL,
|
| 202 |
+
0x604D51B25FBF70E2ULL, 0x73AA8A564FB7AC9EULL, 0x1A8C1E992B941148ULL,
|
| 203 |
+
0xAAC40A2703D9BEA0ULL, 0x764DBEAE7FA4F3A6ULL, 0x1E99B96E70A9BE8BULL,
|
| 204 |
+
0x2C5E9DEB57EF4743ULL, 0x3A938FEE32D29981ULL, 0x26E6DB8FFDF5ADFEULL,
|
| 205 |
+
0x469356C504EC9F9DULL, 0xC8763C5B08D1908CULL, 0x3F6C6AF859D80055ULL,
|
| 206 |
+
0x7F7CC39420A3A545ULL, 0x9BFB227EBDF4C5CEULL, 0x89039D79D6FC5C5CULL,
|
| 207 |
+
0x8FE88B57305E2AB6ULL, 0xA09E8C8C35AB96DEULL, 0xFA7E393983325753ULL,
|
| 208 |
+
0xD6B6D0ECC617C699ULL, 0xDFEA21EA9E7557E3ULL, 0xB67C1FA481680AF8ULL,
|
| 209 |
+
0xCA1E3785A9E724E5ULL, 0x1CFC8BED0D681639ULL, 0xD18D8549D140CAEAULL,
|
| 210 |
+
0x4ED0FE7E9DC91335ULL, 0xE4DBF0634473F5D2ULL, 0x1761F93A44D5AEFEULL,
|
| 211 |
+
0x53898E4C3910DA55ULL, 0x734DE8181F6EC39AULL, 0x2680B122BAA28D97ULL,
|
| 212 |
+
0x298AF231C85BAFABULL, 0x7983EED3740847D5ULL, 0x66C1A2A1A60CD889ULL,
|
| 213 |
+
0x9E17E49642A3E4C1ULL, 0xEDB454E7BADC0805ULL, 0x50B704CAB602C329ULL,
|
| 214 |
+
0x4CC317FB9CDDD023ULL, 0x66B4835D9EAFEA22ULL, 0x219B97E26FFC81BDULL,
|
| 215 |
+
0x261E4E4C0A333A9DULL, 0x1FE2CCA76517DB90ULL, 0xD7504DFA8816EDBBULL,
|
| 216 |
+
0xB9571FA04DC089C8ULL, 0x1DDC0325259B27DEULL, 0xCF3F4688801EB9AAULL,
|
| 217 |
+
0xF4F5D05C10CAB243ULL, 0x38B6525C21A42B0EULL, 0x36F60E2BA4FA6800ULL,
|
| 218 |
+
0xEB3593803173E0CEULL, 0x9C4CD6257C5A3603ULL, 0xAF0C317D32ADAA8AULL,
|
| 219 |
+
0x258E5A80C7204C4BULL, 0x8B889D624D44885DULL, 0xF4D14597E660F855ULL,
|
| 220 |
+
0xD4347F66EC8941C3ULL, 0xE699ED85B0DFB40DULL, 0x2472F6207C2D0484ULL,
|
| 221 |
+
0xC2A1E7B5B459AEB5ULL, 0xAB4F6451CC1D45ECULL, 0x63767572AE3D6174ULL,
|
| 222 |
+
0xA59E0BD101731A28ULL, 0x116D0016CB948F09ULL, 0x2CF9C8CA052F6E9FULL,
|
| 223 |
+
0x0B090A7560A968E3ULL, 0xABEEDDB2DDE06FF1ULL, 0x58EFC10B06A2068DULL,
|
| 224 |
+
0xC6E57A78FBD986E0ULL, 0x2EAB8CA63CE802D7ULL, 0x14A195640116F336ULL,
|
| 225 |
+
0x7C0828DD624EC390ULL, 0xD74BBE77E6116AC7ULL, 0x804456AF10F5FB53ULL,
|
| 226 |
+
0xEBE9EA2ADF4321C7ULL, 0x03219A39EE587A30ULL, 0x49787FEF17AF9924ULL,
|
| 227 |
+
0xA1E9300CD8520548ULL, 0x5B45E522E4B1B4EFULL, 0xB49C3B3995091A36ULL,
|
| 228 |
+
0xD4490AD526F14431ULL, 0x12A8F216AF9418C2ULL, 0x001F837CC7350524ULL,
|
| 229 |
+
0x1877B51E57A764D5ULL, 0xA2853B80F17F58EEULL, 0x993E1DE72D36D310ULL,
|
| 230 |
+
0xB3598080CE64A656ULL, 0x252F59CF0D9F04BBULL, 0xD23C8E176D113600ULL,
|
| 231 |
+
0x1BDA0492E7E4586EULL, 0x21E0BD5026C619BFULL, 0x3B097ADAF088F94EULL,
|
| 232 |
+
0x8D14DEDB30BE846EULL, 0xF95CFFA23AF5F6F4ULL, 0x3871700761B3F743ULL,
|
| 233 |
+
0xCA672B91E9E4FA16ULL, 0x64C8E531BFF53B55ULL, 0x241260ED4AD1E87DULL,
|
| 234 |
+
0x106C09B972D2E822ULL, 0x7FBA195410E5CA30ULL, 0x7884D9BC6CB569D8ULL,
|
| 235 |
+
0x0647DFEDCD894A29ULL, 0x63573FF03E224774ULL, 0x4FC8E9560F91B123ULL,
|
| 236 |
+
0x1DB956E450275779ULL, 0xB8D91274B9E9D4FBULL, 0xA2EBEE47E2FBFCE1ULL,
|
| 237 |
+
0xD9F1F30CCD97FB09ULL, 0xEFED53D75FD64E6BULL, 0x2E6D02C36017F67FULL,
|
| 238 |
+
0xA9AA4D20DB084E9BULL, 0xB64BE8D8B25396C1ULL, 0x70CB6AF7C2D5BCF0ULL,
|
| 239 |
+
0x98F076A4F7A2322EULL, 0xBF84470805E69B5FULL, 0x94C3251F06F90CF3ULL,
|
| 240 |
+
0x3E003E616A6591E9ULL, 0xB925A6CD0421AFF3ULL, 0x61BDD1307C66E300ULL,
|
| 241 |
+
0xBF8D5108E27E0D48ULL, 0x240AB57A8B888B20ULL, 0xFC87614BAF287E07ULL,
|
| 242 |
+
0xEF02CDD06FFDB432ULL, 0xA1082C0466DF6C0AULL, 0x8215E577001332C8ULL,
|
| 243 |
+
0xD39BB9C3A48DB6CFULL, 0x2738259634305C14ULL, 0x61CF4F94C97DF93DULL,
|
| 244 |
+
0x1B6BACA2AE4E125BULL, 0x758F450C88572E0BULL, 0x959F587D507A8359ULL,
|
| 245 |
+
0xB063E962E045F54DULL, 0x60E8ED72C0DFF5D1ULL, 0x7B64978555326F9FULL,
|
| 246 |
+
0xFD080D236DA814BAULL, 0x8C90FD9B083F4558ULL, 0x106F72FE81E2C590ULL,
|
| 247 |
+
0x7976033A39F7D952ULL, 0xA4EC0132764CA04BULL, 0x733EA705FAE4FA77ULL,
|
| 248 |
+
0xB4D8F77BC3E56167ULL, 0x9E21F4F903B33FD9ULL, 0x9D765E419FB69F6DULL,
|
| 249 |
+
0xD30C088BA61EA5EFULL, 0x5D94337FBFAF7F5BULL, 0x1A4E4822EB4D7A59ULL,
|
| 250 |
+
0x6FFE73E81B637FB3ULL, 0xDDF957BC36D8B9CAULL, 0x64D0E29EEA8838B3ULL,
|
| 251 |
+
0x08DD9BDFD96B9F63ULL, 0x087E79E5A57D1D13ULL, 0xE328E230E3E2B3FBULL,
|
| 252 |
+
0x1C2559E30F0946BEULL, 0x720BF5F26F4D2EAAULL, 0xB0774D261CC609DBULL,
|
| 253 |
+
0x443F64EC5A371195ULL, 0x4112CF68649A260EULL, 0xD813F2FAB7F5C5CAULL,
|
| 254 |
+
0x660D3257380841EEULL, 0x59AC2C7873F910A3ULL, 0xE846963877671A17ULL,
|
| 255 |
+
0x93B633ABFA3469F8ULL, 0xC0C0F5A60EF4CDCFULL, 0xCAF21ECD4377B28CULL,
|
| 256 |
+
0x57277707199B8175ULL, 0x506C11B9D90E8B1DULL, 0xD83CC2687A19255FULL,
|
| 257 |
+
0x4A29C6465A314CD1ULL, 0xED2DF21216235097ULL, 0xB5635C95FF7296E2ULL,
|
| 258 |
+
0x22AF003AB672E811ULL, 0x52E762596BF68235ULL, 0x9AEBA33AC6ECC6B0ULL,
|
| 259 |
+
0x944F6DE09134DFB6ULL, 0x6C47BEC883A7DE39ULL, 0x6AD047C430A12104ULL,
|
| 260 |
+
0xA5B1CFDBA0AB4067ULL, 0x7C45D833AFF07862ULL, 0x5092EF950A16DA0BULL,
|
| 261 |
+
0x9338E69C052B8E7BULL, 0x455A4B4CFE30E3F5ULL, 0x6B02E63195AD0CF8ULL,
|
| 262 |
+
0x6B17B224BAD6BF27ULL, 0xD1E0CCD25BB9C169ULL, 0xDE0C89A556B9AE70ULL,
|
| 263 |
+
0x50065E535A213CF6ULL, 0x9C1169FA2777B874ULL, 0x78EDEFD694AF1EEDULL,
|
| 264 |
+
0x6DC93D9526A50E68ULL, 0xEE97F453F06791EDULL, 0x32AB0EDB696703D3ULL,
|
| 265 |
+
0x3A6853C7E70757A7ULL, 0x31865CED6120F37DULL, 0x67FEF95D92607890ULL,
|
| 266 |
+
0x1F2B1D1F15F6DC9CULL, 0xB69E38A8965C6B65ULL, 0xAA9119FF184CCCF4ULL,
|
| 267 |
+
0xF43C732873F24C13ULL, 0xFB4A3D794A9A80D2ULL, 0x3550C2321FD6109CULL,
|
| 268 |
+
0x371F77E76BB8417EULL, 0x6BFA9AAE5EC05779ULL, 0xCD04F3FF001A4778ULL,
|
| 269 |
+
0xE3273522064480CAULL, 0x9F91508BFFCFC14AULL, 0x049A7F41061A9E60ULL,
|
| 270 |
+
0xFCB6BE43A9F2FE9BULL, 0x08DE8A1C7797DA9BULL, 0x8F9887E6078735A1ULL,
|
| 271 |
+
0xB5B4071DBFC73A66ULL, 0x230E343DFBA08D33ULL, 0x43ED7F5A0FAE657DULL,
|
| 272 |
+
0x3A88A0FBBCB05C63ULL, 0x21874B8B4D2DBC4FULL, 0x1BDEA12E35F6A8C9ULL,
|
| 273 |
+
0x53C065C6C8E63528ULL, 0xE34A1D250E7A8D6BULL, 0xD6B04D3B7651DD7EULL,
|
| 274 |
+
0x5E90277E7CB39E2DULL, 0x2C046F22062DC67DULL, 0xB10BB459132D0A26ULL,
|
| 275 |
+
0x3FA9DDFB67E2F199ULL, 0x0E09B88E1914F7AFULL, 0x10E8B35AF3EEAB37ULL,
|
| 276 |
+
0x9EEDECA8E272B933ULL, 0xD4C718BC4AE8AE5FULL, 0x81536D601170FC20ULL,
|
| 277 |
+
0x91B534F885818A06ULL, 0xEC8177F83F900978ULL, 0x190E714FADA5156EULL,
|
| 278 |
+
0xB592BF39B0364963ULL, 0x89C350C893AE7DC1ULL, 0xAC042E70F8B383F2ULL,
|
| 279 |
+
0xB49B52E587A1EE60ULL, 0xFB152FE3FF26DA89ULL, 0x3E666E6F69AE2C15ULL,
|
| 280 |
+
0x3B544EBE544C19F9ULL, 0xE805A1E290CF2456ULL, 0x24B33C9D7ED25117ULL,
|
| 281 |
+
0xE74733427B72F0C1ULL, 0x0A804D18B7097475ULL, 0x57E3306D881EDB4FULL,
|
| 282 |
+
0x4AE7D6A36EB5DBCBULL, 0x2D8D5432157064C8ULL, 0xD1E649DE1E7F268BULL,
|
| 283 |
+
0x8A328A1CEDFE552CULL, 0x07A3AEC79624C7DAULL, 0x84547DDC3E203C94ULL,
|
| 284 |
+
0x990A98FD5071D263ULL, 0x1A4FF12616EEFC89ULL, 0xF6F7FD1431714200ULL,
|
| 285 |
+
0x30C05B1BA332F41CULL, 0x8D2636B81555A786ULL, 0x46C9FEB55D120902ULL,
|
| 286 |
+
0xCCEC0A73B49C9921ULL, 0x4E9D2827355FC492ULL, 0x19EBB029435DCB0FULL,
|
| 287 |
+
0x4659D2B743848A2CULL, 0x963EF2C96B33BE31ULL, 0x74F85198B05A2E7DULL,
|
| 288 |
+
0x5A0F544DD2B1FB18ULL, 0x03727073C2E134B1ULL, 0xC7F6AA2DE59AEA61ULL,
|
| 289 |
+
0x352787BAA0D7C22FULL, 0x9853EAB63B5E0B35ULL, 0xABBDCDD7ED5C0860ULL,
|
| 290 |
+
0xCF05DAF5AC8D77B0ULL, 0x49CAD48CEBF4A71EULL, 0x7A4C10EC2158C4A6ULL,
|
| 291 |
+
0xD9E92AA246BF719EULL, 0x13AE978D09FE5557ULL, 0x730499AF921549FFULL,
|
| 292 |
+
0x4E4B705B92903BA4ULL, 0xFF577222C14F0A3AULL, 0x55B6344CF97AAFAEULL,
|
| 293 |
+
0xB862225B055B6960ULL, 0xCAC09AFBDDD2CDB4ULL, 0xDAF8E9829FE96B5FULL,
|
| 294 |
+
0xB5FDFC5D3132C498ULL, 0x310CB380DB6F7503ULL, 0xE87FBB46217A360EULL,
|
| 295 |
+
0x2102AE466EBB1148ULL, 0xF8549E1A3AA5E00DULL, 0x07A69AFDCC42261AULL,
|
| 296 |
+
0xC4C118BFE78FEAAEULL, 0xF9F4892ED96BD438ULL, 0x1AF3DBE25D8F45DAULL,
|
| 297 |
+
0xF5B4B0B0D2DEEEB4ULL, 0x962ACEEFA82E1C84ULL, 0x046E3ECAAF453CE9ULL,
|
| 298 |
+
0xF05D129681949A4CULL, 0x964781CE734B3C84ULL, 0x9C2ED44081CE5FBDULL,
|
| 299 |
+
0x522E23F3925E319EULL, 0x177E00F9FC32F791ULL, 0x2BC60A63A6F3B3F2ULL,
|
| 300 |
+
0x222BBFAE61725606ULL, 0x486289DDCC3D6780ULL, 0x7DC7785B8EFDFC80ULL,
|
| 301 |
+
0x8AF38731C02BA980ULL, 0x1FAB64EA29A2DDF7ULL, 0xE4D9429322CD065AULL,
|
| 302 |
+
0x9DA058C67844F20CULL, 0x24C0E332B70019B0ULL, 0x233003B5A6CFE6ADULL,
|
| 303 |
+
0xD586BD01C5C217F6ULL, 0x5E5637885F29BC2BULL, 0x7EBA726D8C94094BULL,
|
| 304 |
+
0x0A56A5F0BFE39272ULL, 0xD79476A84EE20D06ULL, 0x9E4C1269BAA4BF37ULL,
|
| 305 |
+
0x17EFEE45B0DEE640ULL, 0x1D95B0A5FCF90BC6ULL, 0x93CBE0B699C2585DULL,
|
| 306 |
+
0x65FA4F227A2B6D79ULL, 0xD5F9E858292504D5ULL, 0xC2B5A03F71471A6FULL,
|
| 307 |
+
0x59300222B4561E00ULL, 0xCE2F8642CA0712DCULL, 0x7CA9723FBB2E8988ULL,
|
| 308 |
+
0x2785338347F2BA08ULL, 0xC61BB3A141E50E8CULL, 0x150F361DAB9DEC26ULL,
|
| 309 |
+
0x9F6A419D382595F4ULL, 0x64A53DC924FE7AC9ULL, 0x142DE49FFF7A7C3DULL,
|
| 310 |
+
0x0C335248857FA9E7ULL, 0x0A9C32D5EAE45305ULL, 0xE6C42178C4BBB92EULL,
|
| 311 |
+
0x71F1CE2490D20B07ULL, 0xF1BCC3D275AFE51AULL, 0xE728E8C83C334074ULL,
|
| 312 |
+
0x96FBF83A12884624ULL, 0x81A1549FD6573DA5ULL, 0x5FA7867CAF35E149ULL,
|
| 313 |
+
0x56986E2EF3ED091BULL, 0x917F1DD5F8886C61ULL, 0xD20D8C88C8FFE65FULL,
|
| 314 |
+
0x31D71DCE64B2C310ULL, 0xF165B587DF898190ULL, 0xA57E6339DD2CF3A0ULL,
|
| 315 |
+
0x1EF6E6DBB1961EC9ULL, 0x70CC73D90BC26E24ULL, 0xE21A6B35DF0C3AD7ULL,
|
| 316 |
+
0x003A93D8B2806962ULL, 0x1C99DED33CB890A1ULL, 0xCF3145DE0ADD4289ULL,
|
| 317 |
+
0xD0E4427A5514FB72ULL, 0x77C621CC9FB3A483ULL, 0x67A34DAC4356550BULL,
|
| 318 |
+
0xF8D626AAAF278509ULL
|
| 319 |
+
}};
|
| 320 |
+
|
| 321 |
+
// polyglot_key() returns the PolyGlot hash key of the given position
|
| 322 |
+
Key polyglot_key(const Position& pos) {
|
| 323 |
+
|
| 324 |
+
Key key = 0;
|
| 325 |
+
Bitboard b = pos.pieces();
|
| 326 |
+
|
| 327 |
+
while (b)
|
| 328 |
+
{
|
| 329 |
+
Square s = pop_lsb(&b);
|
| 330 |
+
Piece p = pos.piece_on(s);
|
| 331 |
+
|
| 332 |
+
// PolyGlot pieces are: BP = 0, WP = 1, BN = 2, ... BK = 10, WK = 11
|
| 333 |
+
key ^= PG.Zobrist.psq[2 * (type_of(p) - 1) + (color_of(p) == WHITE)][s];
|
| 334 |
+
}
|
| 335 |
+
|
| 336 |
+
b = pos.can_castle(ALL_CASTLES);
|
| 337 |
+
|
| 338 |
+
while (b)
|
| 339 |
+
key ^= PG.Zobrist.castle[pop_lsb(&b)];
|
| 340 |
+
|
| 341 |
+
if (pos.ep_square() != SQ_NONE)
|
| 342 |
+
key ^= PG.Zobrist.enpassant[file_of(pos.ep_square())];
|
| 343 |
+
|
| 344 |
+
if (pos.side_to_move() == WHITE)
|
| 345 |
+
key ^= PG.Zobrist.turn;
|
| 346 |
+
|
| 347 |
+
return key;
|
| 348 |
+
}
|
| 349 |
+
|
| 350 |
+
} // namespace
|
| 351 |
+
|
| 352 |
+
PolyglotBook::PolyglotBook() : rkiss(Time::now() % 10000) {}
|
| 353 |
+
|
| 354 |
+
PolyglotBook::~PolyglotBook() { if (is_open()) close(); }
|
| 355 |
+
|
| 356 |
+
|
| 357 |
+
/// operator>>() reads sizeof(T) chars from the file's binary byte stream and
|
| 358 |
+
/// converts them in a number of type T. A Polyglot book stores numbers in
|
| 359 |
+
/// big-endian format.
|
| 360 |
+
|
| 361 |
+
template<typename T> PolyglotBook& PolyglotBook::operator>>(T& n) {
|
| 362 |
+
|
| 363 |
+
n = 0;
|
| 364 |
+
for (size_t i = 0; i < sizeof(T); i++)
|
| 365 |
+
n = T((n << 8) + ifstream::get());
|
| 366 |
+
|
| 367 |
+
return *this;
|
| 368 |
+
}
|
| 369 |
+
|
| 370 |
+
template<> PolyglotBook& PolyglotBook::operator>>(Entry& e) {
|
| 371 |
+
return *this >> e.key >> e.move >> e.count >> e.learn;
|
| 372 |
+
}
|
| 373 |
+
|
| 374 |
+
|
| 375 |
+
/// open() tries to open a book file with the given name after closing any
|
| 376 |
+
/// exsisting one.
|
| 377 |
+
|
| 378 |
+
bool PolyglotBook::open(const char* fName) {
|
| 379 |
+
|
| 380 |
+
if (is_open()) // Cannot close an already closed file
|
| 381 |
+
close();
|
| 382 |
+
|
| 383 |
+
ifstream::open(fName, ifstream::in | ifstream::binary);
|
| 384 |
+
|
| 385 |
+
fileName = is_open() ? fName : "";
|
| 386 |
+
ifstream::clear(); // Reset any error flag to allow retry ifstream::open()
|
| 387 |
+
return !fileName.empty();
|
| 388 |
+
}
|
| 389 |
+
|
| 390 |
+
|
| 391 |
+
/// probe() tries to find a book move for the given position. If no move is
|
| 392 |
+
/// found returns MOVE_NONE. If pickBest is true returns always the highest
|
| 393 |
+
/// rated move, otherwise randomly chooses one, based on the move score.
|
| 394 |
+
|
| 395 |
+
Move PolyglotBook::probe(const Position& pos, const string& fName, bool pickBest) {
|
| 396 |
+
|
| 397 |
+
if (fileName != fName && !open(fName.c_str()))
|
| 398 |
+
return MOVE_NONE;
|
| 399 |
+
|
| 400 |
+
Entry e;
|
| 401 |
+
uint16_t best = 0;
|
| 402 |
+
unsigned sum = 0;
|
| 403 |
+
Move move = MOVE_NONE;
|
| 404 |
+
Key key = polyglot_key(pos);
|
| 405 |
+
|
| 406 |
+
seekg(find_first(key) * sizeof(Entry), ios_base::beg);
|
| 407 |
+
|
| 408 |
+
while (*this >> e, e.key == key && good())
|
| 409 |
+
{
|
| 410 |
+
best = max(best, e.count);
|
| 411 |
+
sum += e.count;
|
| 412 |
+
|
| 413 |
+
// Choose book move according to its score. If a move has a very
|
| 414 |
+
// high score it has higher probability to be choosen than a move
|
| 415 |
+
// with lower score. Note that first entry is always chosen.
|
| 416 |
+
if ( (sum && rkiss.rand<unsigned>() % sum < e.count)
|
| 417 |
+
|| (pickBest && e.count == best))
|
| 418 |
+
move = Move(e.move);
|
| 419 |
+
}
|
| 420 |
+
|
| 421 |
+
if (!move)
|
| 422 |
+
return MOVE_NONE;
|
| 423 |
+
|
| 424 |
+
// A PolyGlot book move is encoded as follows:
|
| 425 |
+
//
|
| 426 |
+
// bit 0- 5: destination square (from 0 to 63)
|
| 427 |
+
// bit 6-11: origin square (from 0 to 63)
|
| 428 |
+
// bit 12-14: promotion piece (from KNIGHT == 1 to QUEEN == 4)
|
| 429 |
+
//
|
| 430 |
+
// Castling moves follow "king captures rook" representation. So in case book
|
| 431 |
+
// move is a promotion we have to convert to our representation, in all the
|
| 432 |
+
// other cases we can directly compare with a Move after having masked out
|
| 433 |
+
// the special Move's flags (bit 14-15) that are not supported by PolyGlot.
|
| 434 |
+
int pt = (move >> 12) & 7;
|
| 435 |
+
if (pt)
|
| 436 |
+
move = make<PROMOTION>(from_sq(move), to_sq(move), PieceType(pt + 1));
|
| 437 |
+
|
| 438 |
+
// Add 'special move' flags and verify it is legal
|
| 439 |
+
for (MoveList<LEGAL> it(pos); *it; ++it)
|
| 440 |
+
if (move == (*it ^ type_of(*it)))
|
| 441 |
+
return *it;
|
| 442 |
+
|
| 443 |
+
return MOVE_NONE;
|
| 444 |
+
}
|
| 445 |
+
|
| 446 |
+
|
| 447 |
+
/// find_first() takes a book key as input, and does a binary search through
|
| 448 |
+
/// the book file for the given key. Returns the index of the leftmost book
|
| 449 |
+
/// entry with the same key as the input.
|
| 450 |
+
|
| 451 |
+
size_t PolyglotBook::find_first(Key key) {
|
| 452 |
+
|
| 453 |
+
seekg(0, ios::end); // Move pointer to end, so tellg() gets file's size
|
| 454 |
+
|
| 455 |
+
size_t low = 0, mid, high = (size_t)tellg() / sizeof(Entry) - 1;
|
| 456 |
+
Entry e;
|
| 457 |
+
|
| 458 |
+
assert(low <= high);
|
| 459 |
+
|
| 460 |
+
while (low < high && good())
|
| 461 |
+
{
|
| 462 |
+
mid = (low + high) / 2;
|
| 463 |
+
|
| 464 |
+
assert(mid >= low && mid < high);
|
| 465 |
+
|
| 466 |
+
seekg(mid * sizeof(Entry), ios_base::beg);
|
| 467 |
+
*this >> e;
|
| 468 |
+
|
| 469 |
+
if (key <= e.key)
|
| 470 |
+
high = mid;
|
| 471 |
+
else
|
| 472 |
+
low = mid + 1;
|
| 473 |
+
}
|
| 474 |
+
|
| 475 |
+
assert(low == high);
|
| 476 |
+
|
| 477 |
+
return low;
|
| 478 |
+
}
|
stockfish-4-win/src/book.h
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
+
Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
+
|
| 6 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 7 |
+
it under the terms of the GNU General Public License as published by
|
| 8 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 9 |
+
(at your option) any later version.
|
| 10 |
+
|
| 11 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 12 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 13 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 14 |
+
GNU General Public License for more details.
|
| 15 |
+
|
| 16 |
+
You should have received a copy of the GNU General Public License
|
| 17 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 18 |
+
*/
|
| 19 |
+
|
| 20 |
+
#ifndef BOOK_H_INCLUDED
|
| 21 |
+
#define BOOK_H_INCLUDED
|
| 22 |
+
|
| 23 |
+
#include <fstream>
|
| 24 |
+
#include <string>
|
| 25 |
+
|
| 26 |
+
#include "position.h"
|
| 27 |
+
#include "rkiss.h"
|
| 28 |
+
|
| 29 |
+
class PolyglotBook : private std::ifstream {
|
| 30 |
+
public:
|
| 31 |
+
PolyglotBook();
|
| 32 |
+
~PolyglotBook();
|
| 33 |
+
Move probe(const Position& pos, const std::string& fName, bool pickBest);
|
| 34 |
+
|
| 35 |
+
private:
|
| 36 |
+
template<typename T> PolyglotBook& operator>>(T& n);
|
| 37 |
+
|
| 38 |
+
bool open(const char* fName);
|
| 39 |
+
size_t find_first(Key key);
|
| 40 |
+
|
| 41 |
+
RKISS rkiss;
|
| 42 |
+
std::string fileName;
|
| 43 |
+
};
|
| 44 |
+
|
| 45 |
+
#endif // #ifndef BOOK_H_INCLUDED
|
stockfish-4-win/src/endgame.cpp
ADDED
|
@@ -0,0 +1,964 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
+
Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
+
|
| 6 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 7 |
+
it under the terms of the GNU General Public License as published by
|
| 8 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 9 |
+
(at your option) any later version.
|
| 10 |
+
|
| 11 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 12 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 13 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 14 |
+
GNU General Public License for more details.
|
| 15 |
+
|
| 16 |
+
You should have received a copy of the GNU General Public License
|
| 17 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 18 |
+
*/
|
| 19 |
+
|
| 20 |
+
#include <algorithm>
|
| 21 |
+
#include <cassert>
|
| 22 |
+
|
| 23 |
+
#include "bitboard.h"
|
| 24 |
+
#include "bitcount.h"
|
| 25 |
+
#include "endgame.h"
|
| 26 |
+
#include "movegen.h"
|
| 27 |
+
|
| 28 |
+
using std::string;
|
| 29 |
+
|
| 30 |
+
namespace {
|
| 31 |
+
|
| 32 |
+
// Table used to drive the defending king towards the edge of the board
|
| 33 |
+
// in KX vs K and KQ vs KR endgames.
|
| 34 |
+
const int MateTable[SQUARE_NB] = {
|
| 35 |
+
100, 90, 80, 70, 70, 80, 90, 100,
|
| 36 |
+
90, 70, 60, 50, 50, 60, 70, 90,
|
| 37 |
+
80, 60, 40, 30, 30, 40, 60, 80,
|
| 38 |
+
70, 50, 30, 20, 20, 30, 50, 70,
|
| 39 |
+
70, 50, 30, 20, 20, 30, 50, 70,
|
| 40 |
+
80, 60, 40, 30, 30, 40, 60, 80,
|
| 41 |
+
90, 70, 60, 50, 50, 60, 70, 90,
|
| 42 |
+
100, 90, 80, 70, 70, 80, 90, 100,
|
| 43 |
+
};
|
| 44 |
+
|
| 45 |
+
// Table used to drive the defending king towards a corner square of the
|
| 46 |
+
// right color in KBN vs K endgames.
|
| 47 |
+
const int KBNKMateTable[SQUARE_NB] = {
|
| 48 |
+
200, 190, 180, 170, 160, 150, 140, 130,
|
| 49 |
+
190, 180, 170, 160, 150, 140, 130, 140,
|
| 50 |
+
180, 170, 155, 140, 140, 125, 140, 150,
|
| 51 |
+
170, 160, 140, 120, 110, 140, 150, 160,
|
| 52 |
+
160, 150, 140, 110, 120, 140, 160, 170,
|
| 53 |
+
150, 140, 125, 140, 140, 155, 170, 180,
|
| 54 |
+
140, 130, 140, 150, 160, 170, 180, 190,
|
| 55 |
+
130, 140, 150, 160, 170, 180, 190, 200
|
| 56 |
+
};
|
| 57 |
+
|
| 58 |
+
// The attacking side is given a descending bonus based on distance between
|
| 59 |
+
// the two kings in basic endgames.
|
| 60 |
+
const int DistanceBonus[8] = { 0, 0, 100, 80, 60, 40, 20, 10 };
|
| 61 |
+
|
| 62 |
+
// Get the material key of a Position out of the given endgame key code
|
| 63 |
+
// like "KBPKN". The trick here is to first forge an ad-hoc fen string
|
| 64 |
+
// and then let a Position object to do the work for us. Note that the
|
| 65 |
+
// fen string could correspond to an illegal position.
|
| 66 |
+
Key key(const string& code, Color c) {
|
| 67 |
+
|
| 68 |
+
assert(code.length() > 0 && code.length() < 8);
|
| 69 |
+
assert(code[0] == 'K');
|
| 70 |
+
|
| 71 |
+
string sides[] = { code.substr(code.find('K', 1)), // Weaker
|
| 72 |
+
code.substr(0, code.find('K', 1)) }; // Stronger
|
| 73 |
+
|
| 74 |
+
std::transform(sides[c].begin(), sides[c].end(), sides[c].begin(), tolower);
|
| 75 |
+
|
| 76 |
+
string fen = sides[0] + char('0' + int(8 - code.length()))
|
| 77 |
+
+ sides[1] + "/8/8/8/8/8/8/8 w - - 0 10";
|
| 78 |
+
|
| 79 |
+
return Position(fen, false, NULL).material_key();
|
| 80 |
+
}
|
| 81 |
+
|
| 82 |
+
template<typename M>
|
| 83 |
+
void delete_endgame(const typename M::value_type& p) { delete p.second; }
|
| 84 |
+
|
| 85 |
+
} // namespace
|
| 86 |
+
|
| 87 |
+
|
| 88 |
+
/// Endgames members definitions
|
| 89 |
+
|
| 90 |
+
Endgames::Endgames() {
|
| 91 |
+
|
| 92 |
+
add<KK>("KK");
|
| 93 |
+
add<KPK>("KPK");
|
| 94 |
+
add<KBK>("KBK");
|
| 95 |
+
add<KNK>("KNK");
|
| 96 |
+
add<KNNK>("KNNK");
|
| 97 |
+
add<KBNK>("KBNK");
|
| 98 |
+
add<KRKP>("KRKP");
|
| 99 |
+
add<KRKB>("KRKB");
|
| 100 |
+
add<KRKN>("KRKN");
|
| 101 |
+
add<KQKP>("KQKP");
|
| 102 |
+
add<KQKR>("KQKR");
|
| 103 |
+
add<KBBKN>("KBBKN");
|
| 104 |
+
|
| 105 |
+
add<KNPK>("KNPK");
|
| 106 |
+
add<KNPKB>("KNPKB");
|
| 107 |
+
add<KRPKR>("KRPKR");
|
| 108 |
+
add<KBPKB>("KBPKB");
|
| 109 |
+
add<KBPKN>("KBPKN");
|
| 110 |
+
add<KBPPKB>("KBPPKB");
|
| 111 |
+
add<KRPPKRP>("KRPPKRP");
|
| 112 |
+
}
|
| 113 |
+
|
| 114 |
+
Endgames::~Endgames() {
|
| 115 |
+
|
| 116 |
+
for_each(m1.begin(), m1.end(), delete_endgame<M1>);
|
| 117 |
+
for_each(m2.begin(), m2.end(), delete_endgame<M2>);
|
| 118 |
+
}
|
| 119 |
+
|
| 120 |
+
template<EndgameType E>
|
| 121 |
+
void Endgames::add(const string& code) {
|
| 122 |
+
|
| 123 |
+
map((Endgame<E>*)0)[key(code, WHITE)] = new Endgame<E>(WHITE);
|
| 124 |
+
map((Endgame<E>*)0)[key(code, BLACK)] = new Endgame<E>(BLACK);
|
| 125 |
+
}
|
| 126 |
+
|
| 127 |
+
|
| 128 |
+
/// Mate with KX vs K. This function is used to evaluate positions with
|
| 129 |
+
/// King and plenty of material vs a lone king. It simply gives the
|
| 130 |
+
/// attacking side a bonus for driving the defending king towards the edge
|
| 131 |
+
/// of the board, and for keeping the distance between the two kings small.
|
| 132 |
+
template<>
|
| 133 |
+
Value Endgame<KXK>::operator()(const Position& pos) const {
|
| 134 |
+
|
| 135 |
+
assert(pos.non_pawn_material(weakerSide) == VALUE_ZERO);
|
| 136 |
+
assert(!pos.count<PAWN>(weakerSide));
|
| 137 |
+
assert(!pos.checkers()); // Eval is never called when in check
|
| 138 |
+
|
| 139 |
+
// Stalemate detection with lone king
|
| 140 |
+
if (pos.side_to_move() == weakerSide && !MoveList<LEGAL>(pos).size())
|
| 141 |
+
return VALUE_DRAW;
|
| 142 |
+
|
| 143 |
+
Square winnerKSq = pos.king_square(strongerSide);
|
| 144 |
+
Square loserKSq = pos.king_square(weakerSide);
|
| 145 |
+
|
| 146 |
+
Value result = pos.non_pawn_material(strongerSide)
|
| 147 |
+
+ pos.count<PAWN>(strongerSide) * PawnValueEg
|
| 148 |
+
+ MateTable[loserKSq]
|
| 149 |
+
+ DistanceBonus[square_distance(winnerKSq, loserKSq)];
|
| 150 |
+
|
| 151 |
+
if ( pos.count<QUEEN>(strongerSide)
|
| 152 |
+
|| pos.count<ROOK>(strongerSide)
|
| 153 |
+
|| pos.bishop_pair(strongerSide))
|
| 154 |
+
result += VALUE_KNOWN_WIN;
|
| 155 |
+
|
| 156 |
+
return strongerSide == pos.side_to_move() ? result : -result;
|
| 157 |
+
}
|
| 158 |
+
|
| 159 |
+
|
| 160 |
+
/// Mate with KBN vs K. This is similar to KX vs K, but we have to drive the
|
| 161 |
+
/// defending king towards a corner square of the right color.
|
| 162 |
+
template<>
|
| 163 |
+
Value Endgame<KBNK>::operator()(const Position& pos) const {
|
| 164 |
+
|
| 165 |
+
assert(pos.non_pawn_material(strongerSide) == KnightValueMg + BishopValueMg);
|
| 166 |
+
assert(pos.non_pawn_material(weakerSide) == VALUE_ZERO);
|
| 167 |
+
assert(pos.count<BISHOP>(strongerSide) == 1);
|
| 168 |
+
assert(pos.count<KNIGHT>(strongerSide) == 1);
|
| 169 |
+
assert(pos.count< PAWN>(strongerSide) == 0);
|
| 170 |
+
assert(pos.count< PAWN>(weakerSide ) == 0);
|
| 171 |
+
|
| 172 |
+
Square winnerKSq = pos.king_square(strongerSide);
|
| 173 |
+
Square loserKSq = pos.king_square(weakerSide);
|
| 174 |
+
Square bishopSq = pos.list<BISHOP>(strongerSide)[0];
|
| 175 |
+
|
| 176 |
+
// kbnk_mate_table() tries to drive toward corners A1 or H8,
|
| 177 |
+
// if we have a bishop that cannot reach the above squares we
|
| 178 |
+
// mirror the kings so to drive enemy toward corners A8 or H1.
|
| 179 |
+
if (opposite_colors(bishopSq, SQ_A1))
|
| 180 |
+
{
|
| 181 |
+
winnerKSq = mirror(winnerKSq);
|
| 182 |
+
loserKSq = mirror(loserKSq);
|
| 183 |
+
}
|
| 184 |
+
|
| 185 |
+
Value result = VALUE_KNOWN_WIN
|
| 186 |
+
+ DistanceBonus[square_distance(winnerKSq, loserKSq)]
|
| 187 |
+
+ KBNKMateTable[loserKSq];
|
| 188 |
+
|
| 189 |
+
return strongerSide == pos.side_to_move() ? result : -result;
|
| 190 |
+
}
|
| 191 |
+
|
| 192 |
+
|
| 193 |
+
/// KP vs K. This endgame is evaluated with the help of a bitbase.
|
| 194 |
+
template<>
|
| 195 |
+
Value Endgame<KPK>::operator()(const Position& pos) const {
|
| 196 |
+
|
| 197 |
+
assert(pos.non_pawn_material(strongerSide) == VALUE_ZERO);
|
| 198 |
+
assert(pos.non_pawn_material(weakerSide) == VALUE_ZERO);
|
| 199 |
+
assert(pos.count<PAWN>(strongerSide) == 1);
|
| 200 |
+
assert(pos.count<PAWN>(weakerSide ) == 0);
|
| 201 |
+
|
| 202 |
+
Square wksq, bksq, wpsq;
|
| 203 |
+
Color us;
|
| 204 |
+
|
| 205 |
+
if (strongerSide == WHITE)
|
| 206 |
+
{
|
| 207 |
+
wksq = pos.king_square(WHITE);
|
| 208 |
+
bksq = pos.king_square(BLACK);
|
| 209 |
+
wpsq = pos.list<PAWN>(WHITE)[0];
|
| 210 |
+
us = pos.side_to_move();
|
| 211 |
+
}
|
| 212 |
+
else
|
| 213 |
+
{
|
| 214 |
+
wksq = ~pos.king_square(BLACK);
|
| 215 |
+
bksq = ~pos.king_square(WHITE);
|
| 216 |
+
wpsq = ~pos.list<PAWN>(BLACK)[0];
|
| 217 |
+
us = ~pos.side_to_move();
|
| 218 |
+
}
|
| 219 |
+
|
| 220 |
+
if (file_of(wpsq) >= FILE_E)
|
| 221 |
+
{
|
| 222 |
+
wksq = mirror(wksq);
|
| 223 |
+
bksq = mirror(bksq);
|
| 224 |
+
wpsq = mirror(wpsq);
|
| 225 |
+
}
|
| 226 |
+
|
| 227 |
+
if (!Bitbases::probe_kpk(wksq, wpsq, bksq, us))
|
| 228 |
+
return VALUE_DRAW;
|
| 229 |
+
|
| 230 |
+
Value result = VALUE_KNOWN_WIN + PawnValueEg + Value(rank_of(wpsq));
|
| 231 |
+
|
| 232 |
+
return strongerSide == pos.side_to_move() ? result : -result;
|
| 233 |
+
}
|
| 234 |
+
|
| 235 |
+
|
| 236 |
+
/// KR vs KP. This is a somewhat tricky endgame to evaluate precisely without
|
| 237 |
+
/// a bitbase. The function below returns drawish scores when the pawn is
|
| 238 |
+
/// far advanced with support of the king, while the attacking king is far
|
| 239 |
+
/// away.
|
| 240 |
+
template<>
|
| 241 |
+
Value Endgame<KRKP>::operator()(const Position& pos) const {
|
| 242 |
+
|
| 243 |
+
assert(pos.non_pawn_material(strongerSide) == RookValueMg);
|
| 244 |
+
assert(pos.non_pawn_material(weakerSide) == 0);
|
| 245 |
+
assert(pos.count<PAWN>(strongerSide) == 0);
|
| 246 |
+
assert(pos.count<PAWN>(weakerSide ) == 1);
|
| 247 |
+
|
| 248 |
+
Square wksq, wrsq, bksq, bpsq;
|
| 249 |
+
int tempo = (pos.side_to_move() == strongerSide);
|
| 250 |
+
|
| 251 |
+
wksq = pos.king_square(strongerSide);
|
| 252 |
+
bksq = pos.king_square(weakerSide);
|
| 253 |
+
wrsq = pos.list<ROOK>(strongerSide)[0];
|
| 254 |
+
bpsq = pos.list<PAWN>(weakerSide)[0];
|
| 255 |
+
|
| 256 |
+
if (strongerSide == BLACK)
|
| 257 |
+
{
|
| 258 |
+
wksq = ~wksq;
|
| 259 |
+
wrsq = ~wrsq;
|
| 260 |
+
bksq = ~bksq;
|
| 261 |
+
bpsq = ~bpsq;
|
| 262 |
+
}
|
| 263 |
+
|
| 264 |
+
Square queeningSq = file_of(bpsq) | RANK_1;
|
| 265 |
+
Value result;
|
| 266 |
+
|
| 267 |
+
// If the stronger side's king is in front of the pawn, it's a win
|
| 268 |
+
if (wksq < bpsq && file_of(wksq) == file_of(bpsq))
|
| 269 |
+
result = RookValueEg - Value(square_distance(wksq, bpsq));
|
| 270 |
+
|
| 271 |
+
// If the weaker side's king is too far from the pawn and the rook,
|
| 272 |
+
// it's a win
|
| 273 |
+
else if ( square_distance(bksq, bpsq) - (tempo ^ 1) >= 3
|
| 274 |
+
&& square_distance(bksq, wrsq) >= 3)
|
| 275 |
+
result = RookValueEg - Value(square_distance(wksq, bpsq));
|
| 276 |
+
|
| 277 |
+
// If the pawn is far advanced and supported by the defending king,
|
| 278 |
+
// the position is drawish
|
| 279 |
+
else if ( rank_of(bksq) <= RANK_3
|
| 280 |
+
&& square_distance(bksq, bpsq) == 1
|
| 281 |
+
&& rank_of(wksq) >= RANK_4
|
| 282 |
+
&& square_distance(wksq, bpsq) - tempo > 2)
|
| 283 |
+
result = Value(80 - square_distance(wksq, bpsq) * 8);
|
| 284 |
+
|
| 285 |
+
else
|
| 286 |
+
result = Value(200)
|
| 287 |
+
- Value(square_distance(wksq, bpsq + DELTA_S) * 8)
|
| 288 |
+
+ Value(square_distance(bksq, bpsq + DELTA_S) * 8)
|
| 289 |
+
+ Value(square_distance(bpsq, queeningSq) * 8);
|
| 290 |
+
|
| 291 |
+
return strongerSide == pos.side_to_move() ? result : -result;
|
| 292 |
+
}
|
| 293 |
+
|
| 294 |
+
|
| 295 |
+
/// KR vs KB. This is very simple, and always returns drawish scores. The
|
| 296 |
+
/// score is slightly bigger when the defending king is close to the edge.
|
| 297 |
+
template<>
|
| 298 |
+
Value Endgame<KRKB>::operator()(const Position& pos) const {
|
| 299 |
+
|
| 300 |
+
assert(pos.non_pawn_material(strongerSide) == RookValueMg);
|
| 301 |
+
assert(pos.non_pawn_material(weakerSide ) == BishopValueMg);
|
| 302 |
+
assert(pos.count<BISHOP>(weakerSide ) == 1);
|
| 303 |
+
assert(pos.count< PAWN>(weakerSide ) == 0);
|
| 304 |
+
assert(pos.count< PAWN>(strongerSide) == 0);
|
| 305 |
+
|
| 306 |
+
Value result = Value(MateTable[pos.king_square(weakerSide)]);
|
| 307 |
+
return strongerSide == pos.side_to_move() ? result : -result;
|
| 308 |
+
}
|
| 309 |
+
|
| 310 |
+
|
| 311 |
+
/// KR vs KN. The attacking side has slightly better winning chances than
|
| 312 |
+
/// in KR vs KB, particularly if the king and the knight are far apart.
|
| 313 |
+
template<>
|
| 314 |
+
Value Endgame<KRKN>::operator()(const Position& pos) const {
|
| 315 |
+
|
| 316 |
+
assert(pos.non_pawn_material(strongerSide) == RookValueMg);
|
| 317 |
+
assert(pos.non_pawn_material(weakerSide ) == KnightValueMg);
|
| 318 |
+
assert(pos.count<KNIGHT>(weakerSide ) == 1);
|
| 319 |
+
assert(pos.count< PAWN>(weakerSide ) == 0);
|
| 320 |
+
assert(pos.count< PAWN>(strongerSide) == 0);
|
| 321 |
+
|
| 322 |
+
const int penalty[8] = { 0, 10, 14, 20, 30, 42, 58, 80 };
|
| 323 |
+
|
| 324 |
+
Square bksq = pos.king_square(weakerSide);
|
| 325 |
+
Square bnsq = pos.list<KNIGHT>(weakerSide)[0];
|
| 326 |
+
Value result = Value(MateTable[bksq] + penalty[square_distance(bksq, bnsq)]);
|
| 327 |
+
return strongerSide == pos.side_to_move() ? result : -result;
|
| 328 |
+
}
|
| 329 |
+
|
| 330 |
+
|
| 331 |
+
/// KQ vs KP. In general, a win for the stronger side, however, there are a few
|
| 332 |
+
/// important exceptions. Pawn on 7th rank, A,C,F or H file, with king next can
|
| 333 |
+
/// be a draw, so we scale down to distance between kings only.
|
| 334 |
+
template<>
|
| 335 |
+
Value Endgame<KQKP>::operator()(const Position& pos) const {
|
| 336 |
+
|
| 337 |
+
assert(pos.non_pawn_material(strongerSide) == QueenValueMg);
|
| 338 |
+
assert(pos.non_pawn_material(weakerSide ) == VALUE_ZERO);
|
| 339 |
+
assert(pos.count<PAWN>(strongerSide) == 0);
|
| 340 |
+
assert(pos.count<PAWN>(weakerSide ) == 1);
|
| 341 |
+
|
| 342 |
+
Square winnerKSq = pos.king_square(strongerSide);
|
| 343 |
+
Square loserKSq = pos.king_square(weakerSide);
|
| 344 |
+
Square pawnSq = pos.list<PAWN>(weakerSide)[0];
|
| 345 |
+
|
| 346 |
+
Value result = QueenValueEg
|
| 347 |
+
- PawnValueEg
|
| 348 |
+
+ DistanceBonus[square_distance(winnerKSq, loserKSq)];
|
| 349 |
+
|
| 350 |
+
if ( square_distance(loserKSq, pawnSq) == 1
|
| 351 |
+
&& relative_rank(weakerSide, pawnSq) == RANK_7)
|
| 352 |
+
{
|
| 353 |
+
File f = file_of(pawnSq);
|
| 354 |
+
|
| 355 |
+
if (f == FILE_A || f == FILE_C || f == FILE_F || f == FILE_H)
|
| 356 |
+
result = Value(DistanceBonus[square_distance(winnerKSq, loserKSq)]);
|
| 357 |
+
}
|
| 358 |
+
return strongerSide == pos.side_to_move() ? result : -result;
|
| 359 |
+
}
|
| 360 |
+
|
| 361 |
+
|
| 362 |
+
/// KQ vs KR. This is almost identical to KX vs K: We give the attacking
|
| 363 |
+
/// king a bonus for having the kings close together, and for forcing the
|
| 364 |
+
/// defending king towards the edge. If we also take care to avoid null move
|
| 365 |
+
/// for the defending side in the search, this is usually sufficient to be
|
| 366 |
+
/// able to win KQ vs KR.
|
| 367 |
+
template<>
|
| 368 |
+
Value Endgame<KQKR>::operator()(const Position& pos) const {
|
| 369 |
+
|
| 370 |
+
assert(pos.non_pawn_material(strongerSide) == QueenValueMg);
|
| 371 |
+
assert(pos.non_pawn_material(weakerSide ) == RookValueMg);
|
| 372 |
+
assert(pos.count<PAWN>(strongerSide) == 0);
|
| 373 |
+
assert(pos.count<PAWN>(weakerSide ) == 0);
|
| 374 |
+
|
| 375 |
+
Square winnerKSq = pos.king_square(strongerSide);
|
| 376 |
+
Square loserKSq = pos.king_square(weakerSide);
|
| 377 |
+
|
| 378 |
+
Value result = QueenValueEg
|
| 379 |
+
- RookValueEg
|
| 380 |
+
+ MateTable[loserKSq]
|
| 381 |
+
+ DistanceBonus[square_distance(winnerKSq, loserKSq)];
|
| 382 |
+
|
| 383 |
+
return strongerSide == pos.side_to_move() ? result : -result;
|
| 384 |
+
}
|
| 385 |
+
|
| 386 |
+
template<>
|
| 387 |
+
Value Endgame<KBBKN>::operator()(const Position& pos) const {
|
| 388 |
+
|
| 389 |
+
assert(pos.non_pawn_material(strongerSide) == 2 * BishopValueMg);
|
| 390 |
+
assert(pos.non_pawn_material(weakerSide ) == KnightValueMg);
|
| 391 |
+
assert(pos.count<BISHOP>(strongerSide) == 2);
|
| 392 |
+
assert(pos.count<KNIGHT>(weakerSide ) == 1);
|
| 393 |
+
assert(!pos.pieces(PAWN));
|
| 394 |
+
|
| 395 |
+
Value result = BishopValueEg;
|
| 396 |
+
Square wksq = pos.king_square(strongerSide);
|
| 397 |
+
Square bksq = pos.king_square(weakerSide);
|
| 398 |
+
Square nsq = pos.list<KNIGHT>(weakerSide)[0];
|
| 399 |
+
|
| 400 |
+
// Bonus for attacking king close to defending king
|
| 401 |
+
result += Value(DistanceBonus[square_distance(wksq, bksq)]);
|
| 402 |
+
|
| 403 |
+
// Bonus for driving the defending king and knight apart
|
| 404 |
+
result += Value(square_distance(bksq, nsq) * 32);
|
| 405 |
+
|
| 406 |
+
// Bonus for restricting the knight's mobility
|
| 407 |
+
result += Value((8 - popcount<Max15>(pos.attacks_from<KNIGHT>(nsq))) * 8);
|
| 408 |
+
|
| 409 |
+
return strongerSide == pos.side_to_move() ? result : -result;
|
| 410 |
+
}
|
| 411 |
+
|
| 412 |
+
|
| 413 |
+
/// Some cases of trivial draws
|
| 414 |
+
template<> Value Endgame<KK>::operator()(const Position&) const { return VALUE_DRAW; }
|
| 415 |
+
template<> Value Endgame<KBK>::operator()(const Position&) const { return VALUE_DRAW; }
|
| 416 |
+
template<> Value Endgame<KNK>::operator()(const Position&) const { return VALUE_DRAW; }
|
| 417 |
+
template<> Value Endgame<KNNK>::operator()(const Position&) const { return VALUE_DRAW; }
|
| 418 |
+
template<> Value Endgame<KmmKm>::operator()(const Position&) const { return VALUE_DRAW; }
|
| 419 |
+
|
| 420 |
+
|
| 421 |
+
/// K, bishop and one or more pawns vs K. It checks for draws with rook pawns and
|
| 422 |
+
/// a bishop of the wrong color. If such a draw is detected, SCALE_FACTOR_DRAW
|
| 423 |
+
/// is returned. If not, the return value is SCALE_FACTOR_NONE, i.e. no scaling
|
| 424 |
+
/// will be used.
|
| 425 |
+
template<>
|
| 426 |
+
ScaleFactor Endgame<KBPsK>::operator()(const Position& pos) const {
|
| 427 |
+
|
| 428 |
+
assert(pos.non_pawn_material(strongerSide) == BishopValueMg);
|
| 429 |
+
assert(pos.count<BISHOP>(strongerSide) == 1);
|
| 430 |
+
assert(pos.count< PAWN>(strongerSide) >= 1);
|
| 431 |
+
|
| 432 |
+
// No assertions about the material of weakerSide, because we want draws to
|
| 433 |
+
// be detected even when the weaker side has some pawns.
|
| 434 |
+
|
| 435 |
+
Bitboard pawns = pos.pieces(strongerSide, PAWN);
|
| 436 |
+
File pawnFile = file_of(pos.list<PAWN>(strongerSide)[0]);
|
| 437 |
+
|
| 438 |
+
// All pawns are on a single rook file ?
|
| 439 |
+
if ( (pawnFile == FILE_A || pawnFile == FILE_H)
|
| 440 |
+
&& !(pawns & ~file_bb(pawnFile)))
|
| 441 |
+
{
|
| 442 |
+
Square bishopSq = pos.list<BISHOP>(strongerSide)[0];
|
| 443 |
+
Square queeningSq = relative_square(strongerSide, pawnFile | RANK_8);
|
| 444 |
+
Square kingSq = pos.king_square(weakerSide);
|
| 445 |
+
|
| 446 |
+
if ( opposite_colors(queeningSq, bishopSq)
|
| 447 |
+
&& abs(file_of(kingSq) - pawnFile) <= 1)
|
| 448 |
+
{
|
| 449 |
+
// The bishop has the wrong color, and the defending king is on the
|
| 450 |
+
// file of the pawn(s) or the adjacent file. Find the rank of the
|
| 451 |
+
// frontmost pawn.
|
| 452 |
+
Rank rank;
|
| 453 |
+
if (strongerSide == WHITE)
|
| 454 |
+
{
|
| 455 |
+
for (rank = RANK_7; !(rank_bb(rank) & pawns); rank--) {}
|
| 456 |
+
assert(rank >= RANK_2 && rank <= RANK_7);
|
| 457 |
+
}
|
| 458 |
+
else
|
| 459 |
+
{
|
| 460 |
+
for (rank = RANK_2; !(rank_bb(rank) & pawns); rank++) {}
|
| 461 |
+
rank = Rank(rank ^ 7); // HACK to get the relative rank
|
| 462 |
+
assert(rank >= RANK_2 && rank <= RANK_7);
|
| 463 |
+
}
|
| 464 |
+
// If the defending king has distance 1 to the promotion square or
|
| 465 |
+
// is placed somewhere in front of the pawn, it's a draw.
|
| 466 |
+
if ( square_distance(kingSq, queeningSq) <= 1
|
| 467 |
+
|| relative_rank(strongerSide, kingSq) >= rank)
|
| 468 |
+
return SCALE_FACTOR_DRAW;
|
| 469 |
+
}
|
| 470 |
+
}
|
| 471 |
+
|
| 472 |
+
// All pawns on same B or G file? Then potential draw
|
| 473 |
+
if ( (pawnFile == FILE_B || pawnFile == FILE_G)
|
| 474 |
+
&& !(pos.pieces(PAWN) & ~file_bb(pawnFile))
|
| 475 |
+
&& pos.non_pawn_material(weakerSide) == 0
|
| 476 |
+
&& pos.count<PAWN>(weakerSide) >= 1)
|
| 477 |
+
{
|
| 478 |
+
// Get weaker pawn closest to opponent's queening square
|
| 479 |
+
Bitboard wkPawns = pos.pieces(weakerSide, PAWN);
|
| 480 |
+
Square weakerPawnSq = strongerSide == WHITE ? msb(wkPawns) : lsb(wkPawns);
|
| 481 |
+
|
| 482 |
+
Square strongerKingSq = pos.king_square(strongerSide);
|
| 483 |
+
Square weakerKingSq = pos.king_square(weakerSide);
|
| 484 |
+
Square bishopSq = pos.list<BISHOP>(strongerSide)[0];
|
| 485 |
+
|
| 486 |
+
// Draw if weaker pawn is on rank 7, bishop can't attack the pawn, and
|
| 487 |
+
// weaker king can stop opposing opponent's king from penetrating.
|
| 488 |
+
if ( relative_rank(strongerSide, weakerPawnSq) == RANK_7
|
| 489 |
+
&& opposite_colors(bishopSq, weakerPawnSq)
|
| 490 |
+
&& square_distance(weakerPawnSq, weakerKingSq) <= square_distance(weakerPawnSq, strongerKingSq))
|
| 491 |
+
return SCALE_FACTOR_DRAW;
|
| 492 |
+
}
|
| 493 |
+
|
| 494 |
+
return SCALE_FACTOR_NONE;
|
| 495 |
+
}
|
| 496 |
+
|
| 497 |
+
|
| 498 |
+
/// K and queen vs K, rook and one or more pawns. It tests for fortress draws with
|
| 499 |
+
/// a rook on the third rank defended by a pawn.
|
| 500 |
+
template<>
|
| 501 |
+
ScaleFactor Endgame<KQKRPs>::operator()(const Position& pos) const {
|
| 502 |
+
|
| 503 |
+
assert(pos.non_pawn_material(strongerSide) == QueenValueMg);
|
| 504 |
+
assert(pos.count<QUEEN>(strongerSide) == 1);
|
| 505 |
+
assert(pos.count< PAWN>(strongerSide) == 0);
|
| 506 |
+
assert(pos.count< ROOK>(weakerSide ) == 1);
|
| 507 |
+
assert(pos.count< PAWN>(weakerSide ) >= 1);
|
| 508 |
+
|
| 509 |
+
Square kingSq = pos.king_square(weakerSide);
|
| 510 |
+
if ( relative_rank(weakerSide, kingSq) <= RANK_2
|
| 511 |
+
&& relative_rank(weakerSide, pos.king_square(strongerSide)) >= RANK_4
|
| 512 |
+
&& (pos.pieces(weakerSide, ROOK) & rank_bb(relative_rank(weakerSide, RANK_3)))
|
| 513 |
+
&& (pos.pieces(weakerSide, PAWN) & rank_bb(relative_rank(weakerSide, RANK_2)))
|
| 514 |
+
&& (pos.attacks_from<KING>(kingSq) & pos.pieces(weakerSide, PAWN)))
|
| 515 |
+
{
|
| 516 |
+
Square rsq = pos.list<ROOK>(weakerSide)[0];
|
| 517 |
+
if (pos.attacks_from<PAWN>(rsq, strongerSide) & pos.pieces(weakerSide, PAWN))
|
| 518 |
+
return SCALE_FACTOR_DRAW;
|
| 519 |
+
}
|
| 520 |
+
return SCALE_FACTOR_NONE;
|
| 521 |
+
}
|
| 522 |
+
|
| 523 |
+
|
| 524 |
+
/// K, rook and one pawn vs K and a rook. This function knows a handful of the
|
| 525 |
+
/// most important classes of drawn positions, but is far from perfect. It would
|
| 526 |
+
/// probably be a good idea to add more knowledge in the future.
|
| 527 |
+
///
|
| 528 |
+
/// It would also be nice to rewrite the actual code for this function,
|
| 529 |
+
/// which is mostly copied from Glaurung 1.x, and not very pretty.
|
| 530 |
+
template<>
|
| 531 |
+
ScaleFactor Endgame<KRPKR>::operator()(const Position& pos) const {
|
| 532 |
+
|
| 533 |
+
assert(pos.non_pawn_material(strongerSide) == RookValueMg);
|
| 534 |
+
assert(pos.non_pawn_material(weakerSide) == RookValueMg);
|
| 535 |
+
assert(pos.count<PAWN>(strongerSide) == 1);
|
| 536 |
+
assert(pos.count<PAWN>(weakerSide ) == 0);
|
| 537 |
+
|
| 538 |
+
Square wksq = pos.king_square(strongerSide);
|
| 539 |
+
Square bksq = pos.king_square(weakerSide);
|
| 540 |
+
Square wrsq = pos.list<ROOK>(strongerSide)[0];
|
| 541 |
+
Square wpsq = pos.list<PAWN>(strongerSide)[0];
|
| 542 |
+
Square brsq = pos.list<ROOK>(weakerSide)[0];
|
| 543 |
+
|
| 544 |
+
// Orient the board in such a way that the stronger side is white, and the
|
| 545 |
+
// pawn is on the left half of the board.
|
| 546 |
+
if (strongerSide == BLACK)
|
| 547 |
+
{
|
| 548 |
+
wksq = ~wksq;
|
| 549 |
+
wrsq = ~wrsq;
|
| 550 |
+
wpsq = ~wpsq;
|
| 551 |
+
bksq = ~bksq;
|
| 552 |
+
brsq = ~brsq;
|
| 553 |
+
}
|
| 554 |
+
if (file_of(wpsq) > FILE_D)
|
| 555 |
+
{
|
| 556 |
+
wksq = mirror(wksq);
|
| 557 |
+
wrsq = mirror(wrsq);
|
| 558 |
+
wpsq = mirror(wpsq);
|
| 559 |
+
bksq = mirror(bksq);
|
| 560 |
+
brsq = mirror(brsq);
|
| 561 |
+
}
|
| 562 |
+
|
| 563 |
+
File f = file_of(wpsq);
|
| 564 |
+
Rank r = rank_of(wpsq);
|
| 565 |
+
Square queeningSq = f | RANK_8;
|
| 566 |
+
int tempo = (pos.side_to_move() == strongerSide);
|
| 567 |
+
|
| 568 |
+
// If the pawn is not too far advanced and the defending king defends the
|
| 569 |
+
// queening square, use the third-rank defence.
|
| 570 |
+
if ( r <= RANK_5
|
| 571 |
+
&& square_distance(bksq, queeningSq) <= 1
|
| 572 |
+
&& wksq <= SQ_H5
|
| 573 |
+
&& (rank_of(brsq) == RANK_6 || (r <= RANK_3 && rank_of(wrsq) != RANK_6)))
|
| 574 |
+
return SCALE_FACTOR_DRAW;
|
| 575 |
+
|
| 576 |
+
// The defending side saves a draw by checking from behind in case the pawn
|
| 577 |
+
// has advanced to the 6th rank with the king behind.
|
| 578 |
+
if ( r == RANK_6
|
| 579 |
+
&& square_distance(bksq, queeningSq) <= 1
|
| 580 |
+
&& rank_of(wksq) + tempo <= RANK_6
|
| 581 |
+
&& (rank_of(brsq) == RANK_1 || (!tempo && abs(file_of(brsq) - f) >= 3)))
|
| 582 |
+
return SCALE_FACTOR_DRAW;
|
| 583 |
+
|
| 584 |
+
if ( r >= RANK_6
|
| 585 |
+
&& bksq == queeningSq
|
| 586 |
+
&& rank_of(brsq) == RANK_1
|
| 587 |
+
&& (!tempo || square_distance(wksq, wpsq) >= 2))
|
| 588 |
+
return SCALE_FACTOR_DRAW;
|
| 589 |
+
|
| 590 |
+
// White pawn on a7 and rook on a8 is a draw if black's king is on g7 or h7
|
| 591 |
+
// and the black rook is behind the pawn.
|
| 592 |
+
if ( wpsq == SQ_A7
|
| 593 |
+
&& wrsq == SQ_A8
|
| 594 |
+
&& (bksq == SQ_H7 || bksq == SQ_G7)
|
| 595 |
+
&& file_of(brsq) == FILE_A
|
| 596 |
+
&& (rank_of(brsq) <= RANK_3 || file_of(wksq) >= FILE_D || rank_of(wksq) <= RANK_5))
|
| 597 |
+
return SCALE_FACTOR_DRAW;
|
| 598 |
+
|
| 599 |
+
// If the defending king blocks the pawn and the attacking king is too far
|
| 600 |
+
// away, it's a draw.
|
| 601 |
+
if ( r <= RANK_5
|
| 602 |
+
&& bksq == wpsq + DELTA_N
|
| 603 |
+
&& square_distance(wksq, wpsq) - tempo >= 2
|
| 604 |
+
&& square_distance(wksq, brsq) - tempo >= 2)
|
| 605 |
+
return SCALE_FACTOR_DRAW;
|
| 606 |
+
|
| 607 |
+
// Pawn on the 7th rank supported by the rook from behind usually wins if the
|
| 608 |
+
// attacking king is closer to the queening square than the defending king,
|
| 609 |
+
// and the defending king cannot gain tempi by threatening the attacking rook.
|
| 610 |
+
if ( r == RANK_7
|
| 611 |
+
&& f != FILE_A
|
| 612 |
+
&& file_of(wrsq) == f
|
| 613 |
+
&& wrsq != queeningSq
|
| 614 |
+
&& (square_distance(wksq, queeningSq) < square_distance(bksq, queeningSq) - 2 + tempo)
|
| 615 |
+
&& (square_distance(wksq, queeningSq) < square_distance(bksq, wrsq) + tempo))
|
| 616 |
+
return ScaleFactor(SCALE_FACTOR_MAX - 2 * square_distance(wksq, queeningSq));
|
| 617 |
+
|
| 618 |
+
// Similar to the above, but with the pawn further back
|
| 619 |
+
if ( f != FILE_A
|
| 620 |
+
&& file_of(wrsq) == f
|
| 621 |
+
&& wrsq < wpsq
|
| 622 |
+
&& (square_distance(wksq, queeningSq) < square_distance(bksq, queeningSq) - 2 + tempo)
|
| 623 |
+
&& (square_distance(wksq, wpsq + DELTA_N) < square_distance(bksq, wpsq + DELTA_N) - 2 + tempo)
|
| 624 |
+
&& ( square_distance(bksq, wrsq) + tempo >= 3
|
| 625 |
+
|| ( square_distance(wksq, queeningSq) < square_distance(bksq, wrsq) + tempo
|
| 626 |
+
&& (square_distance(wksq, wpsq + DELTA_N) < square_distance(bksq, wrsq) + tempo))))
|
| 627 |
+
return ScaleFactor( SCALE_FACTOR_MAX
|
| 628 |
+
- 8 * square_distance(wpsq, queeningSq)
|
| 629 |
+
- 2 * square_distance(wksq, queeningSq));
|
| 630 |
+
|
| 631 |
+
// If the pawn is not far advanced, and the defending king is somewhere in
|
| 632 |
+
// the pawn's path, it's probably a draw.
|
| 633 |
+
if (r <= RANK_4 && bksq > wpsq)
|
| 634 |
+
{
|
| 635 |
+
if (file_of(bksq) == file_of(wpsq))
|
| 636 |
+
return ScaleFactor(10);
|
| 637 |
+
if ( abs(file_of(bksq) - file_of(wpsq)) == 1
|
| 638 |
+
&& square_distance(wksq, bksq) > 2)
|
| 639 |
+
return ScaleFactor(24 - 2 * square_distance(wksq, bksq));
|
| 640 |
+
}
|
| 641 |
+
return SCALE_FACTOR_NONE;
|
| 642 |
+
}
|
| 643 |
+
|
| 644 |
+
|
| 645 |
+
/// K, rook and two pawns vs K, rook and one pawn. There is only a single
|
| 646 |
+
/// pattern: If the stronger side has no passed pawns and the defending king
|
| 647 |
+
/// is actively placed, the position is drawish.
|
| 648 |
+
template<>
|
| 649 |
+
ScaleFactor Endgame<KRPPKRP>::operator()(const Position& pos) const {
|
| 650 |
+
|
| 651 |
+
assert(pos.non_pawn_material(strongerSide) == RookValueMg);
|
| 652 |
+
assert(pos.non_pawn_material(weakerSide) == RookValueMg);
|
| 653 |
+
assert(pos.count<PAWN>(strongerSide) == 2);
|
| 654 |
+
assert(pos.count<PAWN>(weakerSide ) == 1);
|
| 655 |
+
|
| 656 |
+
Square wpsq1 = pos.list<PAWN>(strongerSide)[0];
|
| 657 |
+
Square wpsq2 = pos.list<PAWN>(strongerSide)[1];
|
| 658 |
+
Square bksq = pos.king_square(weakerSide);
|
| 659 |
+
|
| 660 |
+
// Does the stronger side have a passed pawn?
|
| 661 |
+
if ( pos.pawn_is_passed(strongerSide, wpsq1)
|
| 662 |
+
|| pos.pawn_is_passed(strongerSide, wpsq2))
|
| 663 |
+
return SCALE_FACTOR_NONE;
|
| 664 |
+
|
| 665 |
+
Rank r = std::max(relative_rank(strongerSide, wpsq1), relative_rank(strongerSide, wpsq2));
|
| 666 |
+
|
| 667 |
+
if ( file_distance(bksq, wpsq1) <= 1
|
| 668 |
+
&& file_distance(bksq, wpsq2) <= 1
|
| 669 |
+
&& relative_rank(strongerSide, bksq) > r)
|
| 670 |
+
{
|
| 671 |
+
switch (r) {
|
| 672 |
+
case RANK_2: return ScaleFactor(10);
|
| 673 |
+
case RANK_3: return ScaleFactor(10);
|
| 674 |
+
case RANK_4: return ScaleFactor(15);
|
| 675 |
+
case RANK_5: return ScaleFactor(20);
|
| 676 |
+
case RANK_6: return ScaleFactor(40);
|
| 677 |
+
default: assert(false);
|
| 678 |
+
}
|
| 679 |
+
}
|
| 680 |
+
return SCALE_FACTOR_NONE;
|
| 681 |
+
}
|
| 682 |
+
|
| 683 |
+
|
| 684 |
+
/// K and two or more pawns vs K. There is just a single rule here: If all pawns
|
| 685 |
+
/// are on the same rook file and are blocked by the defending king, it's a draw.
|
| 686 |
+
template<>
|
| 687 |
+
ScaleFactor Endgame<KPsK>::operator()(const Position& pos) const {
|
| 688 |
+
|
| 689 |
+
assert(pos.non_pawn_material(strongerSide) == VALUE_ZERO);
|
| 690 |
+
assert(pos.non_pawn_material(weakerSide) == VALUE_ZERO);
|
| 691 |
+
assert(pos.count<PAWN>(strongerSide) >= 2);
|
| 692 |
+
assert(pos.count<PAWN>(weakerSide ) == 0);
|
| 693 |
+
|
| 694 |
+
Square ksq = pos.king_square(weakerSide);
|
| 695 |
+
Bitboard pawns = pos.pieces(strongerSide, PAWN);
|
| 696 |
+
|
| 697 |
+
// Are all pawns on the 'a' file?
|
| 698 |
+
if (!(pawns & ~FileABB))
|
| 699 |
+
{
|
| 700 |
+
// Does the defending king block the pawns?
|
| 701 |
+
if ( square_distance(ksq, relative_square(strongerSide, SQ_A8)) <= 1
|
| 702 |
+
|| ( file_of(ksq) == FILE_A
|
| 703 |
+
&& !(in_front_bb(strongerSide, rank_of(ksq)) & pawns)))
|
| 704 |
+
return SCALE_FACTOR_DRAW;
|
| 705 |
+
}
|
| 706 |
+
// Are all pawns on the 'h' file?
|
| 707 |
+
else if (!(pawns & ~FileHBB))
|
| 708 |
+
{
|
| 709 |
+
// Does the defending king block the pawns?
|
| 710 |
+
if ( square_distance(ksq, relative_square(strongerSide, SQ_H8)) <= 1
|
| 711 |
+
|| ( file_of(ksq) == FILE_H
|
| 712 |
+
&& !(in_front_bb(strongerSide, rank_of(ksq)) & pawns)))
|
| 713 |
+
return SCALE_FACTOR_DRAW;
|
| 714 |
+
}
|
| 715 |
+
return SCALE_FACTOR_NONE;
|
| 716 |
+
}
|
| 717 |
+
|
| 718 |
+
|
| 719 |
+
/// K, bishop and a pawn vs K and a bishop. There are two rules: If the defending
|
| 720 |
+
/// king is somewhere along the path of the pawn, and the square of the king is
|
| 721 |
+
/// not of the same color as the stronger side's bishop, it's a draw. If the two
|
| 722 |
+
/// bishops have opposite color, it's almost always a draw.
|
| 723 |
+
template<>
|
| 724 |
+
ScaleFactor Endgame<KBPKB>::operator()(const Position& pos) const {
|
| 725 |
+
|
| 726 |
+
assert(pos.non_pawn_material(strongerSide) == BishopValueMg);
|
| 727 |
+
assert(pos.non_pawn_material(weakerSide ) == BishopValueMg);
|
| 728 |
+
assert(pos.count<BISHOP>(strongerSide) == 1);
|
| 729 |
+
assert(pos.count<BISHOP>(weakerSide ) == 1);
|
| 730 |
+
assert(pos.count< PAWN>(strongerSide) == 1);
|
| 731 |
+
assert(pos.count< PAWN>(weakerSide ) == 0);
|
| 732 |
+
|
| 733 |
+
Square pawnSq = pos.list<PAWN>(strongerSide)[0];
|
| 734 |
+
Square strongerBishopSq = pos.list<BISHOP>(strongerSide)[0];
|
| 735 |
+
Square weakerBishopSq = pos.list<BISHOP>(weakerSide)[0];
|
| 736 |
+
Square weakerKingSq = pos.king_square(weakerSide);
|
| 737 |
+
|
| 738 |
+
// Case 1: Defending king blocks the pawn, and cannot be driven away
|
| 739 |
+
if ( file_of(weakerKingSq) == file_of(pawnSq)
|
| 740 |
+
&& relative_rank(strongerSide, pawnSq) < relative_rank(strongerSide, weakerKingSq)
|
| 741 |
+
&& ( opposite_colors(weakerKingSq, strongerBishopSq)
|
| 742 |
+
|| relative_rank(strongerSide, weakerKingSq) <= RANK_6))
|
| 743 |
+
return SCALE_FACTOR_DRAW;
|
| 744 |
+
|
| 745 |
+
// Case 2: Opposite colored bishops
|
| 746 |
+
if (opposite_colors(strongerBishopSq, weakerBishopSq))
|
| 747 |
+
{
|
| 748 |
+
// We assume that the position is drawn in the following three situations:
|
| 749 |
+
//
|
| 750 |
+
// a. The pawn is on rank 5 or further back.
|
| 751 |
+
// b. The defending king is somewhere in the pawn's path.
|
| 752 |
+
// c. The defending bishop attacks some square along the pawn's path,
|
| 753 |
+
// and is at least three squares away from the pawn.
|
| 754 |
+
//
|
| 755 |
+
// These rules are probably not perfect, but in practice they work
|
| 756 |
+
// reasonably well.
|
| 757 |
+
|
| 758 |
+
if (relative_rank(strongerSide, pawnSq) <= RANK_5)
|
| 759 |
+
return SCALE_FACTOR_DRAW;
|
| 760 |
+
else
|
| 761 |
+
{
|
| 762 |
+
Bitboard path = forward_bb(strongerSide, pawnSq);
|
| 763 |
+
|
| 764 |
+
if (path & pos.pieces(weakerSide, KING))
|
| 765 |
+
return SCALE_FACTOR_DRAW;
|
| 766 |
+
|
| 767 |
+
if ( (pos.attacks_from<BISHOP>(weakerBishopSq) & path)
|
| 768 |
+
&& square_distance(weakerBishopSq, pawnSq) >= 3)
|
| 769 |
+
return SCALE_FACTOR_DRAW;
|
| 770 |
+
}
|
| 771 |
+
}
|
| 772 |
+
return SCALE_FACTOR_NONE;
|
| 773 |
+
}
|
| 774 |
+
|
| 775 |
+
|
| 776 |
+
/// K, bishop and two pawns vs K and bishop. It detects a few basic draws with
|
| 777 |
+
/// opposite-colored bishops.
|
| 778 |
+
template<>
|
| 779 |
+
ScaleFactor Endgame<KBPPKB>::operator()(const Position& pos) const {
|
| 780 |
+
|
| 781 |
+
assert(pos.non_pawn_material(strongerSide) == BishopValueMg);
|
| 782 |
+
assert(pos.non_pawn_material(weakerSide ) == BishopValueMg);
|
| 783 |
+
assert(pos.count<BISHOP>(strongerSide) == 1);
|
| 784 |
+
assert(pos.count<BISHOP>(weakerSide ) == 1);
|
| 785 |
+
assert(pos.count< PAWN>(strongerSide) == 2);
|
| 786 |
+
assert(pos.count< PAWN>(weakerSide ) == 0);
|
| 787 |
+
|
| 788 |
+
Square wbsq = pos.list<BISHOP>(strongerSide)[0];
|
| 789 |
+
Square bbsq = pos.list<BISHOP>(weakerSide)[0];
|
| 790 |
+
|
| 791 |
+
if (!opposite_colors(wbsq, bbsq))
|
| 792 |
+
return SCALE_FACTOR_NONE;
|
| 793 |
+
|
| 794 |
+
Square ksq = pos.king_square(weakerSide);
|
| 795 |
+
Square psq1 = pos.list<PAWN>(strongerSide)[0];
|
| 796 |
+
Square psq2 = pos.list<PAWN>(strongerSide)[1];
|
| 797 |
+
Rank r1 = rank_of(psq1);
|
| 798 |
+
Rank r2 = rank_of(psq2);
|
| 799 |
+
Square blockSq1, blockSq2;
|
| 800 |
+
|
| 801 |
+
if (relative_rank(strongerSide, psq1) > relative_rank(strongerSide, psq2))
|
| 802 |
+
{
|
| 803 |
+
blockSq1 = psq1 + pawn_push(strongerSide);
|
| 804 |
+
blockSq2 = file_of(psq2) | rank_of(psq1);
|
| 805 |
+
}
|
| 806 |
+
else
|
| 807 |
+
{
|
| 808 |
+
blockSq1 = psq2 + pawn_push(strongerSide);
|
| 809 |
+
blockSq2 = file_of(psq1) | rank_of(psq2);
|
| 810 |
+
}
|
| 811 |
+
|
| 812 |
+
switch (file_distance(psq1, psq2))
|
| 813 |
+
{
|
| 814 |
+
case 0:
|
| 815 |
+
// Both pawns are on the same file. Easy draw if defender firmly controls
|
| 816 |
+
// some square in the frontmost pawn's path.
|
| 817 |
+
if ( file_of(ksq) == file_of(blockSq1)
|
| 818 |
+
&& relative_rank(strongerSide, ksq) >= relative_rank(strongerSide, blockSq1)
|
| 819 |
+
&& opposite_colors(ksq, wbsq))
|
| 820 |
+
return SCALE_FACTOR_DRAW;
|
| 821 |
+
else
|
| 822 |
+
return SCALE_FACTOR_NONE;
|
| 823 |
+
|
| 824 |
+
case 1:
|
| 825 |
+
// Pawns on adjacent files. Draw if defender firmly controls the square
|
| 826 |
+
// in front of the frontmost pawn's path, and the square diagonally behind
|
| 827 |
+
// this square on the file of the other pawn.
|
| 828 |
+
if ( ksq == blockSq1
|
| 829 |
+
&& opposite_colors(ksq, wbsq)
|
| 830 |
+
&& ( bbsq == blockSq2
|
| 831 |
+
|| (pos.attacks_from<BISHOP>(blockSq2) & pos.pieces(weakerSide, BISHOP))
|
| 832 |
+
|| abs(r1 - r2) >= 2))
|
| 833 |
+
return SCALE_FACTOR_DRAW;
|
| 834 |
+
|
| 835 |
+
else if ( ksq == blockSq2
|
| 836 |
+
&& opposite_colors(ksq, wbsq)
|
| 837 |
+
&& ( bbsq == blockSq1
|
| 838 |
+
|| (pos.attacks_from<BISHOP>(blockSq1) & pos.pieces(weakerSide, BISHOP))))
|
| 839 |
+
return SCALE_FACTOR_DRAW;
|
| 840 |
+
else
|
| 841 |
+
return SCALE_FACTOR_NONE;
|
| 842 |
+
|
| 843 |
+
default:
|
| 844 |
+
// The pawns are not on the same file or adjacent files. No scaling.
|
| 845 |
+
return SCALE_FACTOR_NONE;
|
| 846 |
+
}
|
| 847 |
+
}
|
| 848 |
+
|
| 849 |
+
|
| 850 |
+
/// K, bisop and a pawn vs K and knight. There is a single rule: If the defending
|
| 851 |
+
/// king is somewhere along the path of the pawn, and the square of the king is
|
| 852 |
+
/// not of the same color as the stronger side's bishop, it's a draw.
|
| 853 |
+
template<>
|
| 854 |
+
ScaleFactor Endgame<KBPKN>::operator()(const Position& pos) const {
|
| 855 |
+
|
| 856 |
+
assert(pos.non_pawn_material(strongerSide) == BishopValueMg);
|
| 857 |
+
assert(pos.non_pawn_material(weakerSide ) == KnightValueMg);
|
| 858 |
+
assert(pos.count<BISHOP>(strongerSide) == 1);
|
| 859 |
+
assert(pos.count<KNIGHT>(weakerSide ) == 1);
|
| 860 |
+
assert(pos.count< PAWN>(strongerSide) == 1);
|
| 861 |
+
assert(pos.count< PAWN>(weakerSide ) == 0);
|
| 862 |
+
|
| 863 |
+
Square pawnSq = pos.list<PAWN>(strongerSide)[0];
|
| 864 |
+
Square strongerBishopSq = pos.list<BISHOP>(strongerSide)[0];
|
| 865 |
+
Square weakerKingSq = pos.king_square(weakerSide);
|
| 866 |
+
|
| 867 |
+
if ( file_of(weakerKingSq) == file_of(pawnSq)
|
| 868 |
+
&& relative_rank(strongerSide, pawnSq) < relative_rank(strongerSide, weakerKingSq)
|
| 869 |
+
&& ( opposite_colors(weakerKingSq, strongerBishopSq)
|
| 870 |
+
|| relative_rank(strongerSide, weakerKingSq) <= RANK_6))
|
| 871 |
+
return SCALE_FACTOR_DRAW;
|
| 872 |
+
|
| 873 |
+
return SCALE_FACTOR_NONE;
|
| 874 |
+
}
|
| 875 |
+
|
| 876 |
+
|
| 877 |
+
/// K, knight and a pawn vs K. There is a single rule: If the pawn is a rook pawn
|
| 878 |
+
/// on the 7th rank and the defending king prevents the pawn from advancing, the
|
| 879 |
+
/// position is drawn.
|
| 880 |
+
template<>
|
| 881 |
+
ScaleFactor Endgame<KNPK>::operator()(const Position& pos) const {
|
| 882 |
+
|
| 883 |
+
assert(pos.non_pawn_material(strongerSide) == KnightValueMg);
|
| 884 |
+
assert(pos.non_pawn_material(weakerSide ) == VALUE_ZERO);
|
| 885 |
+
assert(pos.count<KNIGHT>(strongerSide) == 1);
|
| 886 |
+
assert(pos.count< PAWN>(strongerSide) == 1);
|
| 887 |
+
assert(pos.count< PAWN>(weakerSide ) == 0);
|
| 888 |
+
|
| 889 |
+
Square pawnSq = pos.list<PAWN>(strongerSide)[0];
|
| 890 |
+
Square weakerKingSq = pos.king_square(weakerSide);
|
| 891 |
+
|
| 892 |
+
if ( pawnSq == relative_square(strongerSide, SQ_A7)
|
| 893 |
+
&& square_distance(weakerKingSq, relative_square(strongerSide, SQ_A8)) <= 1)
|
| 894 |
+
return SCALE_FACTOR_DRAW;
|
| 895 |
+
|
| 896 |
+
if ( pawnSq == relative_square(strongerSide, SQ_H7)
|
| 897 |
+
&& square_distance(weakerKingSq, relative_square(strongerSide, SQ_H8)) <= 1)
|
| 898 |
+
return SCALE_FACTOR_DRAW;
|
| 899 |
+
|
| 900 |
+
return SCALE_FACTOR_NONE;
|
| 901 |
+
}
|
| 902 |
+
|
| 903 |
+
|
| 904 |
+
/// K, knight and a pawn vs K and bishop. If knight can block bishop from taking
|
| 905 |
+
/// pawn, it's a win. Otherwise, drawn.
|
| 906 |
+
template<>
|
| 907 |
+
ScaleFactor Endgame<KNPKB>::operator()(const Position& pos) const {
|
| 908 |
+
|
| 909 |
+
Square pawnSq = pos.list<PAWN>(strongerSide)[0];
|
| 910 |
+
Square bishopSq = pos.list<BISHOP>(weakerSide)[0];
|
| 911 |
+
Square weakerKingSq = pos.king_square(weakerSide);
|
| 912 |
+
|
| 913 |
+
// King needs to get close to promoting pawn to prevent knight from blocking.
|
| 914 |
+
// Rules for this are very tricky, so just approximate.
|
| 915 |
+
if (forward_bb(strongerSide, pawnSq) & pos.attacks_from<BISHOP>(bishopSq))
|
| 916 |
+
return ScaleFactor(square_distance(weakerKingSq, pawnSq));
|
| 917 |
+
|
| 918 |
+
return SCALE_FACTOR_NONE;
|
| 919 |
+
}
|
| 920 |
+
|
| 921 |
+
|
| 922 |
+
/// K and a pawn vs K and a pawn. This is done by removing the weakest side's
|
| 923 |
+
/// pawn and probing the KP vs K bitbase: If the weakest side has a draw without
|
| 924 |
+
/// the pawn, she probably has at least a draw with the pawn as well. The exception
|
| 925 |
+
/// is when the stronger side's pawn is far advanced and not on a rook file; in
|
| 926 |
+
/// this case it is often possible to win (e.g. 8/4k3/3p4/3P4/6K1/8/8/8 w - - 0 1).
|
| 927 |
+
template<>
|
| 928 |
+
ScaleFactor Endgame<KPKP>::operator()(const Position& pos) const {
|
| 929 |
+
|
| 930 |
+
assert(pos.non_pawn_material(strongerSide) == VALUE_ZERO);
|
| 931 |
+
assert(pos.non_pawn_material(weakerSide ) == VALUE_ZERO);
|
| 932 |
+
assert(pos.count<PAWN>(WHITE) == 1);
|
| 933 |
+
assert(pos.count<PAWN>(BLACK) == 1);
|
| 934 |
+
|
| 935 |
+
Square wksq = pos.king_square(strongerSide);
|
| 936 |
+
Square bksq = pos.king_square(weakerSide);
|
| 937 |
+
Square wpsq = pos.list<PAWN>(strongerSide)[0];
|
| 938 |
+
Color us = pos.side_to_move();
|
| 939 |
+
|
| 940 |
+
if (strongerSide == BLACK)
|
| 941 |
+
{
|
| 942 |
+
wksq = ~wksq;
|
| 943 |
+
bksq = ~bksq;
|
| 944 |
+
wpsq = ~wpsq;
|
| 945 |
+
us = ~us;
|
| 946 |
+
}
|
| 947 |
+
|
| 948 |
+
if (file_of(wpsq) >= FILE_E)
|
| 949 |
+
{
|
| 950 |
+
wksq = mirror(wksq);
|
| 951 |
+
bksq = mirror(bksq);
|
| 952 |
+
wpsq = mirror(wpsq);
|
| 953 |
+
}
|
| 954 |
+
|
| 955 |
+
// If the pawn has advanced to the fifth rank or further, and is not a
|
| 956 |
+
// rook pawn, it's too dangerous to assume that it's at least a draw.
|
| 957 |
+
if ( rank_of(wpsq) >= RANK_5
|
| 958 |
+
&& file_of(wpsq) != FILE_A)
|
| 959 |
+
return SCALE_FACTOR_NONE;
|
| 960 |
+
|
| 961 |
+
// Probe the KPK bitbase with the weakest side's pawn removed. If it's a draw,
|
| 962 |
+
// it's probably at least a draw even with the pawn.
|
| 963 |
+
return Bitbases::probe_kpk(wksq, wpsq, bksq, us) ? SCALE_FACTOR_NONE : SCALE_FACTOR_DRAW;
|
| 964 |
+
}
|
stockfish-4-win/src/endgame.h
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
+
Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
+
|
| 6 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 7 |
+
it under the terms of the GNU General Public License as published by
|
| 8 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 9 |
+
(at your option) any later version.
|
| 10 |
+
|
| 11 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 12 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 13 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 14 |
+
GNU General Public License for more details.
|
| 15 |
+
|
| 16 |
+
You should have received a copy of the GNU General Public License
|
| 17 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 18 |
+
*/
|
| 19 |
+
|
| 20 |
+
#ifndef ENDGAME_H_INCLUDED
|
| 21 |
+
#define ENDGAME_H_INCLUDED
|
| 22 |
+
|
| 23 |
+
#include <map>
|
| 24 |
+
#include <string>
|
| 25 |
+
|
| 26 |
+
#include "position.h"
|
| 27 |
+
#include "types.h"
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
/// EndgameType lists all supported endgames
|
| 31 |
+
|
| 32 |
+
enum EndgameType {
|
| 33 |
+
|
| 34 |
+
// Evaluation functions
|
| 35 |
+
|
| 36 |
+
KK, // K vs K
|
| 37 |
+
KBK, // KB vs K
|
| 38 |
+
KNK, // KN vs K
|
| 39 |
+
KNNK, // KNN vs K
|
| 40 |
+
KXK, // Generic "mate lone king" eval
|
| 41 |
+
KBNK, // KBN vs K
|
| 42 |
+
KPK, // KP vs K
|
| 43 |
+
KRKP, // KR vs KP
|
| 44 |
+
KRKB, // KR vs KB
|
| 45 |
+
KRKN, // KR vs KN
|
| 46 |
+
KQKP, // KQ vs KP
|
| 47 |
+
KQKR, // KQ vs KR
|
| 48 |
+
KBBKN, // KBB vs KN
|
| 49 |
+
KmmKm, // K and two minors vs K and one or two minors
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
// Scaling functions
|
| 53 |
+
SCALE_FUNS,
|
| 54 |
+
|
| 55 |
+
KBPsK, // KB+pawns vs K
|
| 56 |
+
KQKRPs, // KQ vs KR+pawns
|
| 57 |
+
KRPKR, // KRP vs KR
|
| 58 |
+
KRPPKRP, // KRPP vs KRP
|
| 59 |
+
KPsK, // King and pawns vs king
|
| 60 |
+
KBPKB, // KBP vs KB
|
| 61 |
+
KBPPKB, // KBPP vs KB
|
| 62 |
+
KBPKN, // KBP vs KN
|
| 63 |
+
KNPK, // KNP vs K
|
| 64 |
+
KNPKB, // KNP vs KB
|
| 65 |
+
KPKP // KP vs KP
|
| 66 |
+
};
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
/// Endgame functions can be of two types according if return a Value or a
|
| 70 |
+
/// ScaleFactor. Type eg_fun<int>::type equals to either ScaleFactor or Value
|
| 71 |
+
/// depending if the template parameter is 0 or 1.
|
| 72 |
+
|
| 73 |
+
template<int> struct eg_fun { typedef Value type; };
|
| 74 |
+
template<> struct eg_fun<1> { typedef ScaleFactor type; };
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
/// Base and derived templates for endgame evaluation and scaling functions
|
| 78 |
+
|
| 79 |
+
template<typename T>
|
| 80 |
+
struct EndgameBase {
|
| 81 |
+
|
| 82 |
+
virtual ~EndgameBase() {}
|
| 83 |
+
virtual Color color() const = 0;
|
| 84 |
+
virtual T operator()(const Position&) const = 0;
|
| 85 |
+
};
|
| 86 |
+
|
| 87 |
+
|
| 88 |
+
template<EndgameType E, typename T = typename eg_fun<(E > SCALE_FUNS)>::type>
|
| 89 |
+
struct Endgame : public EndgameBase<T> {
|
| 90 |
+
|
| 91 |
+
explicit Endgame(Color c) : strongerSide(c), weakerSide(~c) {}
|
| 92 |
+
Color color() const { return strongerSide; }
|
| 93 |
+
T operator()(const Position&) const;
|
| 94 |
+
|
| 95 |
+
private:
|
| 96 |
+
Color strongerSide, weakerSide;
|
| 97 |
+
};
|
| 98 |
+
|
| 99 |
+
|
| 100 |
+
/// Endgames class stores in two std::map the pointers to endgame evaluation
|
| 101 |
+
/// and scaling base objects. Then we use polymorphism to invoke the actual
|
| 102 |
+
/// endgame function calling its operator() that is virtual.
|
| 103 |
+
|
| 104 |
+
class Endgames {
|
| 105 |
+
|
| 106 |
+
typedef std::map<Key, EndgameBase<eg_fun<0>::type>*> M1;
|
| 107 |
+
typedef std::map<Key, EndgameBase<eg_fun<1>::type>*> M2;
|
| 108 |
+
|
| 109 |
+
M1 m1;
|
| 110 |
+
M2 m2;
|
| 111 |
+
|
| 112 |
+
M1& map(M1::mapped_type) { return m1; }
|
| 113 |
+
M2& map(M2::mapped_type) { return m2; }
|
| 114 |
+
|
| 115 |
+
template<EndgameType E> void add(const std::string& code);
|
| 116 |
+
|
| 117 |
+
public:
|
| 118 |
+
Endgames();
|
| 119 |
+
~Endgames();
|
| 120 |
+
|
| 121 |
+
template<typename T> T probe(Key key, T& eg)
|
| 122 |
+
{ return eg = map(eg).count(key) ? map(eg)[key] : NULL; }
|
| 123 |
+
};
|
| 124 |
+
|
| 125 |
+
#endif // #ifndef ENDGAME_H_INCLUDED
|
stockfish-4-win/src/evaluate.cpp
ADDED
|
@@ -0,0 +1,1185 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
+
Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
+
|
| 6 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 7 |
+
it under the terms of the GNU General Public License as published by
|
| 8 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 9 |
+
(at your option) any later version.
|
| 10 |
+
|
| 11 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 12 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 13 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 14 |
+
GNU General Public License for more details.
|
| 15 |
+
|
| 16 |
+
You should have received a copy of the GNU General Public License
|
| 17 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 18 |
+
*/
|
| 19 |
+
|
| 20 |
+
#include <cassert>
|
| 21 |
+
#include <iomanip>
|
| 22 |
+
#include <sstream>
|
| 23 |
+
#include <algorithm>
|
| 24 |
+
|
| 25 |
+
#include "bitcount.h"
|
| 26 |
+
#include "evaluate.h"
|
| 27 |
+
#include "material.h"
|
| 28 |
+
#include "pawns.h"
|
| 29 |
+
#include "thread.h"
|
| 30 |
+
#include "ucioption.h"
|
| 31 |
+
|
| 32 |
+
namespace {
|
| 33 |
+
|
| 34 |
+
enum ExtendedPieceType { // Used for tracing
|
| 35 |
+
PST = 8, IMBALANCE, MOBILITY, THREAT, PASSED, UNSTOPPABLE, SPACE, TOTAL
|
| 36 |
+
};
|
| 37 |
+
|
| 38 |
+
namespace Tracing {
|
| 39 |
+
|
| 40 |
+
Score scores[COLOR_NB][TOTAL + 1];
|
| 41 |
+
std::stringstream stream;
|
| 42 |
+
|
| 43 |
+
void add(int idx, Score term_w, Score term_b = SCORE_ZERO);
|
| 44 |
+
void row(const char* name, int idx);
|
| 45 |
+
std::string do_trace(const Position& pos);
|
| 46 |
+
}
|
| 47 |
+
|
| 48 |
+
// Struct EvalInfo contains various information computed and collected
|
| 49 |
+
// by the evaluation functions.
|
| 50 |
+
struct EvalInfo {
|
| 51 |
+
|
| 52 |
+
// Pointers to material and pawn hash table entries
|
| 53 |
+
Material::Entry* mi;
|
| 54 |
+
Pawns::Entry* pi;
|
| 55 |
+
|
| 56 |
+
// attackedBy[color][piece type] is a bitboard representing all squares
|
| 57 |
+
// attacked by a given color and piece type, attackedBy[color][ALL_PIECES]
|
| 58 |
+
// contains all squares attacked by the given color.
|
| 59 |
+
Bitboard attackedBy[COLOR_NB][PIECE_TYPE_NB];
|
| 60 |
+
|
| 61 |
+
// kingRing[color] is the zone around the king which is considered
|
| 62 |
+
// by the king safety evaluation. This consists of the squares directly
|
| 63 |
+
// adjacent to the king, and the three (or two, for a king on an edge file)
|
| 64 |
+
// squares two ranks in front of the king. For instance, if black's king
|
| 65 |
+
// is on g8, kingRing[BLACK] is a bitboard containing the squares f8, h8,
|
| 66 |
+
// f7, g7, h7, f6, g6 and h6.
|
| 67 |
+
Bitboard kingRing[COLOR_NB];
|
| 68 |
+
|
| 69 |
+
// kingAttackersCount[color] is the number of pieces of the given color
|
| 70 |
+
// which attack a square in the kingRing of the enemy king.
|
| 71 |
+
int kingAttackersCount[COLOR_NB];
|
| 72 |
+
|
| 73 |
+
// kingAttackersWeight[color] is the sum of the "weight" of the pieces of the
|
| 74 |
+
// given color which attack a square in the kingRing of the enemy king. The
|
| 75 |
+
// weights of the individual piece types are given by the variables
|
| 76 |
+
// QueenAttackWeight, RookAttackWeight, BishopAttackWeight and
|
| 77 |
+
// KnightAttackWeight in evaluate.cpp
|
| 78 |
+
int kingAttackersWeight[COLOR_NB];
|
| 79 |
+
|
| 80 |
+
// kingAdjacentZoneAttacksCount[color] is the number of attacks to squares
|
| 81 |
+
// directly adjacent to the king of the given color. Pieces which attack
|
| 82 |
+
// more than one square are counted multiple times. For instance, if black's
|
| 83 |
+
// king is on g8 and there's a white knight on g5, this knight adds
|
| 84 |
+
// 2 to kingAdjacentZoneAttacksCount[BLACK].
|
| 85 |
+
int kingAdjacentZoneAttacksCount[COLOR_NB];
|
| 86 |
+
};
|
| 87 |
+
|
| 88 |
+
// Evaluation grain size, must be a power of 2
|
| 89 |
+
const int GrainSize = 4;
|
| 90 |
+
|
| 91 |
+
// Evaluation weights, initialized from UCI options
|
| 92 |
+
enum { Mobility, PawnStructure, PassedPawns, Space, KingDangerUs, KingDangerThem };
|
| 93 |
+
Score Weights[6];
|
| 94 |
+
|
| 95 |
+
typedef Value V;
|
| 96 |
+
#define S(mg, eg) make_score(mg, eg)
|
| 97 |
+
|
| 98 |
+
// Internal evaluation weights. These are applied on top of the evaluation
|
| 99 |
+
// weights read from UCI parameters. The purpose is to be able to change
|
| 100 |
+
// the evaluation weights while keeping the default values of the UCI
|
| 101 |
+
// parameters at 100, which looks prettier.
|
| 102 |
+
//
|
| 103 |
+
// Values modified by Joona Kiiski
|
| 104 |
+
const Score WeightsInternal[] = {
|
| 105 |
+
S(289, 344), S(233, 201), S(221, 273), S(46, 0), S(271, 0), S(307, 0)
|
| 106 |
+
};
|
| 107 |
+
|
| 108 |
+
// MobilityBonus[PieceType][attacked] contains bonuses for middle and end
|
| 109 |
+
// game, indexed by piece type and number of attacked squares not occupied by
|
| 110 |
+
// friendly pieces.
|
| 111 |
+
const Score MobilityBonus[][32] = {
|
| 112 |
+
{}, {},
|
| 113 |
+
{ S(-35,-30), S(-22,-20), S(-9,-10), S( 3, 0), S(15, 10), S(27, 20), // Knights
|
| 114 |
+
S( 37, 28), S( 42, 31), S(44, 33) },
|
| 115 |
+
{ S(-22,-27), S( -8,-13), S( 6, 1), S(20, 15), S(34, 29), S(48, 43), // Bishops
|
| 116 |
+
S( 60, 55), S( 68, 63), S(74, 68), S(77, 72), S(80, 75), S(82, 77),
|
| 117 |
+
S( 84, 79), S( 86, 81), S(87, 82), S(87, 82) },
|
| 118 |
+
{ S(-17,-33), S(-11,-16), S(-5, 0), S( 1, 16), S( 7, 32), S(13, 48), // Rooks
|
| 119 |
+
S( 18, 64), S( 22, 80), S(26, 96), S(29,109), S(31,115), S(33,119),
|
| 120 |
+
S( 35,122), S( 36,123), S(37,124), S(38,124) },
|
| 121 |
+
{ S(-12,-20), S( -8,-13), S(-5, -7), S(-2, -1), S( 1, 5), S( 4, 11), // Queens
|
| 122 |
+
S( 7, 17), S( 10, 23), S(13, 29), S(16, 34), S(18, 38), S(20, 40),
|
| 123 |
+
S( 22, 41), S( 23, 41), S(24, 41), S(25, 41), S(25, 41), S(25, 41),
|
| 124 |
+
S( 25, 41), S( 25, 41), S(25, 41), S(25, 41), S(25, 41), S(25, 41),
|
| 125 |
+
S( 25, 41), S( 25, 41), S(25, 41), S(25, 41), S(25, 41), S(25, 41),
|
| 126 |
+
S( 25, 41), S( 25, 41) }
|
| 127 |
+
};
|
| 128 |
+
|
| 129 |
+
// Outpost[PieceType][Square] contains bonuses of knights and bishops, indexed
|
| 130 |
+
// by piece type and square (from white's point of view).
|
| 131 |
+
const Value Outpost[][SQUARE_NB] = {
|
| 132 |
+
{
|
| 133 |
+
// A B C D E F G H
|
| 134 |
+
V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(0), // Knights
|
| 135 |
+
V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(0),
|
| 136 |
+
V(0), V(0), V(4), V(8), V(8), V(4), V(0), V(0),
|
| 137 |
+
V(0), V(4),V(17),V(26),V(26),V(17), V(4), V(0),
|
| 138 |
+
V(0), V(8),V(26),V(35),V(35),V(26), V(8), V(0),
|
| 139 |
+
V(0), V(4),V(17),V(17),V(17),V(17), V(4), V(0) },
|
| 140 |
+
{
|
| 141 |
+
V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(0), // Bishops
|
| 142 |
+
V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(0),
|
| 143 |
+
V(0), V(0), V(5), V(5), V(5), V(5), V(0), V(0),
|
| 144 |
+
V(0), V(5),V(10),V(10),V(10),V(10), V(5), V(0),
|
| 145 |
+
V(0),V(10),V(21),V(21),V(21),V(21),V(10), V(0),
|
| 146 |
+
V(0), V(5), V(8), V(8), V(8), V(8), V(5), V(0) }
|
| 147 |
+
};
|
| 148 |
+
|
| 149 |
+
// Threat[attacking][attacked] contains bonuses according to which piece
|
| 150 |
+
// type attacks which one.
|
| 151 |
+
const Score Threat[][PIECE_TYPE_NB] = {
|
| 152 |
+
{}, {},
|
| 153 |
+
{ S(0, 0), S( 7, 39), S( 0, 0), S(24, 49), S(41,100), S(41,100) }, // KNIGHT
|
| 154 |
+
{ S(0, 0), S( 7, 39), S(24, 49), S( 0, 0), S(41,100), S(41,100) }, // BISHOP
|
| 155 |
+
{ S(0, 0), S( 0, 22), S(15, 49), S(15, 49), S( 0, 0), S(24, 49) }, // ROOK
|
| 156 |
+
{ S(0, 0), S(15, 39), S(15, 39), S(15, 39), S(15, 39), S( 0, 0) } // QUEEN
|
| 157 |
+
};
|
| 158 |
+
|
| 159 |
+
// ThreatenedByPawn[PieceType] contains a penalty according to which piece
|
| 160 |
+
// type is attacked by an enemy pawn.
|
| 161 |
+
const Score ThreatenedByPawn[] = {
|
| 162 |
+
S(0, 0), S(0, 0), S(56, 70), S(56, 70), S(76, 99), S(86, 118)
|
| 163 |
+
};
|
| 164 |
+
|
| 165 |
+
#undef S
|
| 166 |
+
|
| 167 |
+
const Score Tempo = make_score(24, 11);
|
| 168 |
+
const Score BishopPin = make_score(66, 11);
|
| 169 |
+
const Score RookOn7th = make_score(11, 20);
|
| 170 |
+
const Score QueenOn7th = make_score( 3, 8);
|
| 171 |
+
const Score RookOnPawn = make_score(10, 28);
|
| 172 |
+
const Score QueenOnPawn = make_score( 4, 20);
|
| 173 |
+
const Score RookOpenFile = make_score(43, 21);
|
| 174 |
+
const Score RookSemiopenFile = make_score(19, 10);
|
| 175 |
+
const Score BishopPawns = make_score( 8, 12);
|
| 176 |
+
const Score MinorBehindPawn = make_score(16, 0);
|
| 177 |
+
const Score UndefendedMinor = make_score(25, 10);
|
| 178 |
+
const Score TrappedRook = make_score(90, 0);
|
| 179 |
+
|
| 180 |
+
// Penalty for a bishop on a1/h1 (a8/h8 for black) which is trapped by
|
| 181 |
+
// a friendly pawn on b2/g2 (b7/g7 for black). This can obviously only
|
| 182 |
+
// happen in Chess960 games.
|
| 183 |
+
const Score TrappedBishopA1H1 = make_score(50, 50);
|
| 184 |
+
|
| 185 |
+
// The SpaceMask[Color] contains the area of the board which is considered
|
| 186 |
+
// by the space evaluation. In the middle game, each side is given a bonus
|
| 187 |
+
// based on how many squares inside this area are safe and available for
|
| 188 |
+
// friendly minor pieces.
|
| 189 |
+
const Bitboard SpaceMask[] = {
|
| 190 |
+
(1ULL << SQ_C2) | (1ULL << SQ_D2) | (1ULL << SQ_E2) | (1ULL << SQ_F2) |
|
| 191 |
+
(1ULL << SQ_C3) | (1ULL << SQ_D3) | (1ULL << SQ_E3) | (1ULL << SQ_F3) |
|
| 192 |
+
(1ULL << SQ_C4) | (1ULL << SQ_D4) | (1ULL << SQ_E4) | (1ULL << SQ_F4),
|
| 193 |
+
(1ULL << SQ_C7) | (1ULL << SQ_D7) | (1ULL << SQ_E7) | (1ULL << SQ_F7) |
|
| 194 |
+
(1ULL << SQ_C6) | (1ULL << SQ_D6) | (1ULL << SQ_E6) | (1ULL << SQ_F6) |
|
| 195 |
+
(1ULL << SQ_C5) | (1ULL << SQ_D5) | (1ULL << SQ_E5) | (1ULL << SQ_F5)
|
| 196 |
+
};
|
| 197 |
+
|
| 198 |
+
// King danger constants and variables. The king danger scores are taken
|
| 199 |
+
// from the KingDanger[]. Various little "meta-bonuses" measuring
|
| 200 |
+
// the strength of the enemy attack are added up into an integer, which
|
| 201 |
+
// is used as an index to KingDanger[].
|
| 202 |
+
//
|
| 203 |
+
// KingAttackWeights[PieceType] contains king attack weights by piece type
|
| 204 |
+
const int KingAttackWeights[] = { 0, 0, 2, 2, 3, 5 };
|
| 205 |
+
|
| 206 |
+
// Bonuses for enemy's safe checks
|
| 207 |
+
const int QueenContactCheck = 6;
|
| 208 |
+
const int RookContactCheck = 4;
|
| 209 |
+
const int QueenCheck = 3;
|
| 210 |
+
const int RookCheck = 2;
|
| 211 |
+
const int BishopCheck = 1;
|
| 212 |
+
const int KnightCheck = 1;
|
| 213 |
+
|
| 214 |
+
// KingExposed[Square] contains penalties based on the position of the
|
| 215 |
+
// defending king, indexed by king's square (from white's point of view).
|
| 216 |
+
const int KingExposed[] = {
|
| 217 |
+
2, 0, 2, 5, 5, 2, 0, 2,
|
| 218 |
+
2, 2, 4, 8, 8, 4, 2, 2,
|
| 219 |
+
7, 10, 12, 12, 12, 12, 10, 7,
|
| 220 |
+
15, 15, 15, 15, 15, 15, 15, 15,
|
| 221 |
+
15, 15, 15, 15, 15, 15, 15, 15,
|
| 222 |
+
15, 15, 15, 15, 15, 15, 15, 15,
|
| 223 |
+
15, 15, 15, 15, 15, 15, 15, 15,
|
| 224 |
+
15, 15, 15, 15, 15, 15, 15, 15
|
| 225 |
+
};
|
| 226 |
+
|
| 227 |
+
// KingDanger[Color][attackUnits] contains the actual king danger weighted
|
| 228 |
+
// scores, indexed by color and by a calculated integer number.
|
| 229 |
+
Score KingDanger[COLOR_NB][128];
|
| 230 |
+
|
| 231 |
+
// Function prototypes
|
| 232 |
+
template<bool Trace>
|
| 233 |
+
Value do_evaluate(const Position& pos, Value& margin);
|
| 234 |
+
|
| 235 |
+
template<Color Us>
|
| 236 |
+
void init_eval_info(const Position& pos, EvalInfo& ei);
|
| 237 |
+
|
| 238 |
+
template<Color Us, bool Trace>
|
| 239 |
+
Score evaluate_pieces_of_color(const Position& pos, EvalInfo& ei, Score& mobility);
|
| 240 |
+
|
| 241 |
+
template<Color Us, bool Trace>
|
| 242 |
+
Score evaluate_king(const Position& pos, const EvalInfo& ei, Value margins[]);
|
| 243 |
+
|
| 244 |
+
template<Color Us, bool Trace>
|
| 245 |
+
Score evaluate_threats(const Position& pos, const EvalInfo& ei);
|
| 246 |
+
|
| 247 |
+
template<Color Us, bool Trace>
|
| 248 |
+
Score evaluate_passed_pawns(const Position& pos, const EvalInfo& ei);
|
| 249 |
+
|
| 250 |
+
template<Color Us>
|
| 251 |
+
int evaluate_space(const Position& pos, const EvalInfo& ei);
|
| 252 |
+
|
| 253 |
+
Score evaluate_unstoppable_pawns(const Position& pos, const EvalInfo& ei);
|
| 254 |
+
|
| 255 |
+
Value interpolate(const Score& v, Phase ph, ScaleFactor sf);
|
| 256 |
+
Score apply_weight(Score v, Score w);
|
| 257 |
+
Score weight_option(const std::string& mgOpt, const std::string& egOpt, Score internalWeight);
|
| 258 |
+
double to_cp(Value v);
|
| 259 |
+
}
|
| 260 |
+
|
| 261 |
+
|
| 262 |
+
namespace Eval {
|
| 263 |
+
|
| 264 |
+
/// evaluate() is the main evaluation function. It always computes two
|
| 265 |
+
/// values, an endgame score and a middle game score, and interpolates
|
| 266 |
+
/// between them based on the remaining material.
|
| 267 |
+
|
| 268 |
+
Value evaluate(const Position& pos, Value& margin) {
|
| 269 |
+
return do_evaluate<false>(pos, margin);
|
| 270 |
+
}
|
| 271 |
+
|
| 272 |
+
|
| 273 |
+
/// trace() is like evaluate() but instead of a value returns a string suitable
|
| 274 |
+
/// to be print on stdout with the detailed descriptions and values of each
|
| 275 |
+
/// evaluation term. Used mainly for debugging.
|
| 276 |
+
std::string trace(const Position& pos) {
|
| 277 |
+
return Tracing::do_trace(pos);
|
| 278 |
+
}
|
| 279 |
+
|
| 280 |
+
|
| 281 |
+
/// init() computes evaluation weights from the corresponding UCI parameters
|
| 282 |
+
/// and setup king tables.
|
| 283 |
+
|
| 284 |
+
void init() {
|
| 285 |
+
|
| 286 |
+
Weights[Mobility] = weight_option("Mobility (Midgame)", "Mobility (Endgame)", WeightsInternal[Mobility]);
|
| 287 |
+
Weights[PawnStructure] = weight_option("Pawn Structure (Midgame)", "Pawn Structure (Endgame)", WeightsInternal[PawnStructure]);
|
| 288 |
+
Weights[PassedPawns] = weight_option("Passed Pawns (Midgame)", "Passed Pawns (Endgame)", WeightsInternal[PassedPawns]);
|
| 289 |
+
Weights[Space] = weight_option("Space", "Space", WeightsInternal[Space]);
|
| 290 |
+
Weights[KingDangerUs] = weight_option("Cowardice", "Cowardice", WeightsInternal[KingDangerUs]);
|
| 291 |
+
Weights[KingDangerThem] = weight_option("Aggressiveness", "Aggressiveness", WeightsInternal[KingDangerThem]);
|
| 292 |
+
|
| 293 |
+
const int MaxSlope = 30;
|
| 294 |
+
const int Peak = 1280;
|
| 295 |
+
|
| 296 |
+
for (int t = 0, i = 1; i < 100; i++)
|
| 297 |
+
{
|
| 298 |
+
t = std::min(Peak, std::min(int(0.4 * i * i), t + MaxSlope));
|
| 299 |
+
|
| 300 |
+
KingDanger[1][i] = apply_weight(make_score(t, 0), Weights[KingDangerUs]);
|
| 301 |
+
KingDanger[0][i] = apply_weight(make_score(t, 0), Weights[KingDangerThem]);
|
| 302 |
+
}
|
| 303 |
+
}
|
| 304 |
+
|
| 305 |
+
} // namespace Eval
|
| 306 |
+
|
| 307 |
+
|
| 308 |
+
namespace {
|
| 309 |
+
|
| 310 |
+
template<bool Trace>
|
| 311 |
+
Value do_evaluate(const Position& pos, Value& margin) {
|
| 312 |
+
|
| 313 |
+
assert(!pos.checkers());
|
| 314 |
+
|
| 315 |
+
EvalInfo ei;
|
| 316 |
+
Value margins[COLOR_NB];
|
| 317 |
+
Score score, mobilityWhite, mobilityBlack;
|
| 318 |
+
Thread* th = pos.this_thread();
|
| 319 |
+
|
| 320 |
+
// margins[] store the uncertainty estimation of position's evaluation
|
| 321 |
+
// that typically is used by the search for pruning decisions.
|
| 322 |
+
margins[WHITE] = margins[BLACK] = VALUE_ZERO;
|
| 323 |
+
|
| 324 |
+
// Initialize score by reading the incrementally updated scores included
|
| 325 |
+
// in the position object (material + piece square tables) and adding
|
| 326 |
+
// Tempo bonus. Score is computed from the point of view of white.
|
| 327 |
+
score = pos.psq_score() + (pos.side_to_move() == WHITE ? Tempo : -Tempo);
|
| 328 |
+
|
| 329 |
+
// Probe the material hash table
|
| 330 |
+
ei.mi = Material::probe(pos, th->materialTable, th->endgames);
|
| 331 |
+
score += ei.mi->material_value();
|
| 332 |
+
|
| 333 |
+
// If we have a specialized evaluation function for the current material
|
| 334 |
+
// configuration, call it and return.
|
| 335 |
+
if (ei.mi->specialized_eval_exists())
|
| 336 |
+
{
|
| 337 |
+
margin = VALUE_ZERO;
|
| 338 |
+
return ei.mi->evaluate(pos);
|
| 339 |
+
}
|
| 340 |
+
|
| 341 |
+
// Probe the pawn hash table
|
| 342 |
+
ei.pi = Pawns::probe(pos, th->pawnsTable);
|
| 343 |
+
score += apply_weight(ei.pi->pawns_value(), Weights[PawnStructure]);
|
| 344 |
+
|
| 345 |
+
// Initialize attack and king safety bitboards
|
| 346 |
+
init_eval_info<WHITE>(pos, ei);
|
| 347 |
+
init_eval_info<BLACK>(pos, ei);
|
| 348 |
+
|
| 349 |
+
// Evaluate pieces and mobility
|
| 350 |
+
score += evaluate_pieces_of_color<WHITE, Trace>(pos, ei, mobilityWhite)
|
| 351 |
+
- evaluate_pieces_of_color<BLACK, Trace>(pos, ei, mobilityBlack);
|
| 352 |
+
|
| 353 |
+
score += apply_weight(mobilityWhite - mobilityBlack, Weights[Mobility]);
|
| 354 |
+
|
| 355 |
+
// Evaluate kings after all other pieces because we need complete attack
|
| 356 |
+
// information when computing the king safety evaluation.
|
| 357 |
+
score += evaluate_king<WHITE, Trace>(pos, ei, margins)
|
| 358 |
+
- evaluate_king<BLACK, Trace>(pos, ei, margins);
|
| 359 |
+
|
| 360 |
+
// Evaluate tactical threats, we need full attack information including king
|
| 361 |
+
score += evaluate_threats<WHITE, Trace>(pos, ei)
|
| 362 |
+
- evaluate_threats<BLACK, Trace>(pos, ei);
|
| 363 |
+
|
| 364 |
+
// Evaluate passed pawns, we need full attack information including king
|
| 365 |
+
score += evaluate_passed_pawns<WHITE, Trace>(pos, ei)
|
| 366 |
+
- evaluate_passed_pawns<BLACK, Trace>(pos, ei);
|
| 367 |
+
|
| 368 |
+
// If one side has only a king, check whether exists any unstoppable passed pawn
|
| 369 |
+
if (!pos.non_pawn_material(WHITE) || !pos.non_pawn_material(BLACK))
|
| 370 |
+
score += evaluate_unstoppable_pawns(pos, ei);
|
| 371 |
+
|
| 372 |
+
// Evaluate space for both sides, only in middle-game.
|
| 373 |
+
if (ei.mi->space_weight())
|
| 374 |
+
{
|
| 375 |
+
int s = evaluate_space<WHITE>(pos, ei) - evaluate_space<BLACK>(pos, ei);
|
| 376 |
+
score += apply_weight(s * ei.mi->space_weight(), Weights[Space]);
|
| 377 |
+
}
|
| 378 |
+
|
| 379 |
+
// Scale winning side if position is more drawish that what it appears
|
| 380 |
+
ScaleFactor sf = eg_value(score) > VALUE_DRAW ? ei.mi->scale_factor(pos, WHITE)
|
| 381 |
+
: ei.mi->scale_factor(pos, BLACK);
|
| 382 |
+
|
| 383 |
+
// If we don't already have an unusual scale factor, check for opposite
|
| 384 |
+
// colored bishop endgames, and use a lower scale for those.
|
| 385 |
+
if ( ei.mi->game_phase() < PHASE_MIDGAME
|
| 386 |
+
&& pos.opposite_bishops()
|
| 387 |
+
&& sf == SCALE_FACTOR_NORMAL)
|
| 388 |
+
{
|
| 389 |
+
// Only the two bishops ?
|
| 390 |
+
if ( pos.non_pawn_material(WHITE) == BishopValueMg
|
| 391 |
+
&& pos.non_pawn_material(BLACK) == BishopValueMg)
|
| 392 |
+
{
|
| 393 |
+
// Check for KBP vs KB with only a single pawn that is almost
|
| 394 |
+
// certainly a draw or at least two pawns.
|
| 395 |
+
bool one_pawn = (pos.count<PAWN>(WHITE) + pos.count<PAWN>(BLACK) == 1);
|
| 396 |
+
sf = one_pawn ? ScaleFactor(8) : ScaleFactor(32);
|
| 397 |
+
}
|
| 398 |
+
else
|
| 399 |
+
// Endgame with opposite-colored bishops, but also other pieces. Still
|
| 400 |
+
// a bit drawish, but not as drawish as with only the two bishops.
|
| 401 |
+
sf = ScaleFactor(50);
|
| 402 |
+
}
|
| 403 |
+
|
| 404 |
+
margin = margins[pos.side_to_move()];
|
| 405 |
+
Value v = interpolate(score, ei.mi->game_phase(), sf);
|
| 406 |
+
|
| 407 |
+
// In case of tracing add all single evaluation contributions for both white and black
|
| 408 |
+
if (Trace)
|
| 409 |
+
{
|
| 410 |
+
Tracing::add(PST, pos.psq_score());
|
| 411 |
+
Tracing::add(IMBALANCE, ei.mi->material_value());
|
| 412 |
+
Tracing::add(PAWN, ei.pi->pawns_value());
|
| 413 |
+
Tracing::add(UNSTOPPABLE, evaluate_unstoppable_pawns(pos, ei));
|
| 414 |
+
Score w = ei.mi->space_weight() * evaluate_space<WHITE>(pos, ei);
|
| 415 |
+
Score b = ei.mi->space_weight() * evaluate_space<BLACK>(pos, ei);
|
| 416 |
+
Tracing::add(SPACE, apply_weight(w, Weights[Space]), apply_weight(b, Weights[Space]));
|
| 417 |
+
Tracing::add(TOTAL, score);
|
| 418 |
+
Tracing::stream << "\nUncertainty margin: White: " << to_cp(margins[WHITE])
|
| 419 |
+
<< ", Black: " << to_cp(margins[BLACK])
|
| 420 |
+
<< "\nScaling: " << std::noshowpos
|
| 421 |
+
<< std::setw(6) << 100.0 * ei.mi->game_phase() / 128.0 << "% MG, "
|
| 422 |
+
<< std::setw(6) << 100.0 * (1.0 - ei.mi->game_phase() / 128.0) << "% * "
|
| 423 |
+
<< std::setw(6) << (100.0 * sf) / SCALE_FACTOR_NORMAL << "% EG.\n"
|
| 424 |
+
<< "Total evaluation: " << to_cp(v);
|
| 425 |
+
}
|
| 426 |
+
|
| 427 |
+
return pos.side_to_move() == WHITE ? v : -v;
|
| 428 |
+
}
|
| 429 |
+
|
| 430 |
+
|
| 431 |
+
// init_eval_info() initializes king bitboards for given color adding
|
| 432 |
+
// pawn attacks. To be done at the beginning of the evaluation.
|
| 433 |
+
|
| 434 |
+
template<Color Us>
|
| 435 |
+
void init_eval_info(const Position& pos, EvalInfo& ei) {
|
| 436 |
+
|
| 437 |
+
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
| 438 |
+
const Square Down = (Us == WHITE ? DELTA_S : DELTA_N);
|
| 439 |
+
|
| 440 |
+
Bitboard b = ei.attackedBy[Them][KING] = pos.attacks_from<KING>(pos.king_square(Them));
|
| 441 |
+
ei.attackedBy[Us][PAWN] = ei.pi->pawn_attacks(Us);
|
| 442 |
+
|
| 443 |
+
// Init king safety tables only if we are going to use them
|
| 444 |
+
if (pos.count<QUEEN>(Us) && pos.non_pawn_material(Us) > QueenValueMg + PawnValueMg)
|
| 445 |
+
{
|
| 446 |
+
ei.kingRing[Them] = b | shift_bb<Down>(b);
|
| 447 |
+
b &= ei.attackedBy[Us][PAWN];
|
| 448 |
+
ei.kingAttackersCount[Us] = b ? popcount<Max15>(b) / 2 : 0;
|
| 449 |
+
ei.kingAdjacentZoneAttacksCount[Us] = ei.kingAttackersWeight[Us] = 0;
|
| 450 |
+
} else
|
| 451 |
+
ei.kingRing[Them] = ei.kingAttackersCount[Us] = 0;
|
| 452 |
+
}
|
| 453 |
+
|
| 454 |
+
|
| 455 |
+
// evaluate_outposts() evaluates bishop and knight outposts squares
|
| 456 |
+
|
| 457 |
+
template<PieceType Piece, Color Us>
|
| 458 |
+
Score evaluate_outposts(const Position& pos, EvalInfo& ei, Square s) {
|
| 459 |
+
|
| 460 |
+
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
| 461 |
+
|
| 462 |
+
assert (Piece == BISHOP || Piece == KNIGHT);
|
| 463 |
+
|
| 464 |
+
// Initial bonus based on square
|
| 465 |
+
Value bonus = Outpost[Piece == BISHOP][relative_square(Us, s)];
|
| 466 |
+
|
| 467 |
+
// Increase bonus if supported by pawn, especially if the opponent has
|
| 468 |
+
// no minor piece which can exchange the outpost piece.
|
| 469 |
+
if (bonus && (ei.attackedBy[Us][PAWN] & s))
|
| 470 |
+
{
|
| 471 |
+
if ( !pos.pieces(Them, KNIGHT)
|
| 472 |
+
&& !(squares_of_color(s) & pos.pieces(Them, BISHOP)))
|
| 473 |
+
bonus += bonus + bonus / 2;
|
| 474 |
+
else
|
| 475 |
+
bonus += bonus / 2;
|
| 476 |
+
}
|
| 477 |
+
return make_score(bonus, bonus);
|
| 478 |
+
}
|
| 479 |
+
|
| 480 |
+
|
| 481 |
+
// evaluate_pieces<>() assigns bonuses and penalties to the pieces of a given color
|
| 482 |
+
|
| 483 |
+
template<PieceType Piece, Color Us, bool Trace>
|
| 484 |
+
Score evaluate_pieces(const Position& pos, EvalInfo& ei, Score& mobility, Bitboard mobilityArea) {
|
| 485 |
+
|
| 486 |
+
Bitboard b;
|
| 487 |
+
Square s;
|
| 488 |
+
Score score = SCORE_ZERO;
|
| 489 |
+
|
| 490 |
+
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
| 491 |
+
const Square* pl = pos.list<Piece>(Us);
|
| 492 |
+
|
| 493 |
+
ei.attackedBy[Us][Piece] = 0;
|
| 494 |
+
|
| 495 |
+
while ((s = *pl++) != SQ_NONE)
|
| 496 |
+
{
|
| 497 |
+
// Find attacked squares, including x-ray attacks for bishops and rooks
|
| 498 |
+
b = Piece == BISHOP ? attacks_bb<BISHOP>(s, pos.pieces() ^ pos.pieces(Us, QUEEN))
|
| 499 |
+
: Piece == ROOK ? attacks_bb< ROOK>(s, pos.pieces() ^ pos.pieces(Us, ROOK, QUEEN))
|
| 500 |
+
: pos.attacks_from<Piece>(s);
|
| 501 |
+
|
| 502 |
+
ei.attackedBy[Us][Piece] |= b;
|
| 503 |
+
|
| 504 |
+
if (b & ei.kingRing[Them])
|
| 505 |
+
{
|
| 506 |
+
ei.kingAttackersCount[Us]++;
|
| 507 |
+
ei.kingAttackersWeight[Us] += KingAttackWeights[Piece];
|
| 508 |
+
Bitboard bb = (b & ei.attackedBy[Them][KING]);
|
| 509 |
+
if (bb)
|
| 510 |
+
ei.kingAdjacentZoneAttacksCount[Us] += popcount<Max15>(bb);
|
| 511 |
+
}
|
| 512 |
+
|
| 513 |
+
int mob = Piece != QUEEN ? popcount<Max15>(b & mobilityArea)
|
| 514 |
+
: popcount<Full >(b & mobilityArea);
|
| 515 |
+
|
| 516 |
+
mobility += MobilityBonus[Piece][mob];
|
| 517 |
+
|
| 518 |
+
// Decrease score if we are attacked by an enemy pawn. Remaining part
|
| 519 |
+
// of threat evaluation must be done later when we have full attack info.
|
| 520 |
+
if (ei.attackedBy[Them][PAWN] & s)
|
| 521 |
+
score -= ThreatenedByPawn[Piece];
|
| 522 |
+
|
| 523 |
+
// Otherwise give a bonus if we are a bishop and can pin a piece or can
|
| 524 |
+
// give a discovered check through an x-ray attack.
|
| 525 |
+
else if ( Piece == BISHOP
|
| 526 |
+
&& (PseudoAttacks[Piece][pos.king_square(Them)] & s)
|
| 527 |
+
&& !more_than_one(BetweenBB[s][pos.king_square(Them)] & pos.pieces()))
|
| 528 |
+
score += BishopPin;
|
| 529 |
+
|
| 530 |
+
// Penalty for bishop with same coloured pawns
|
| 531 |
+
if (Piece == BISHOP)
|
| 532 |
+
score -= BishopPawns * ei.pi->pawns_on_same_color_squares(Us, s);
|
| 533 |
+
|
| 534 |
+
if (Piece == BISHOP || Piece == KNIGHT)
|
| 535 |
+
{
|
| 536 |
+
// Bishop and knight outposts squares
|
| 537 |
+
if (!(pos.pieces(Them, PAWN) & pawn_attack_span(Us, s)))
|
| 538 |
+
score += evaluate_outposts<Piece, Us>(pos, ei, s);
|
| 539 |
+
|
| 540 |
+
// Bishop or knight behind a pawn
|
| 541 |
+
if ( relative_rank(Us, s) < RANK_5
|
| 542 |
+
&& (pos.pieces(PAWN) & (s + pawn_push(Us))))
|
| 543 |
+
score += MinorBehindPawn;
|
| 544 |
+
}
|
| 545 |
+
|
| 546 |
+
if ( (Piece == ROOK || Piece == QUEEN)
|
| 547 |
+
&& relative_rank(Us, s) >= RANK_5)
|
| 548 |
+
{
|
| 549 |
+
// Major piece on 7th rank and enemy king trapped on 8th
|
| 550 |
+
if ( relative_rank(Us, s) == RANK_7
|
| 551 |
+
&& relative_rank(Us, pos.king_square(Them)) == RANK_8)
|
| 552 |
+
score += Piece == ROOK ? RookOn7th : QueenOn7th;
|
| 553 |
+
|
| 554 |
+
// Major piece attacking enemy pawns on the same rank/file
|
| 555 |
+
Bitboard pawns = pos.pieces(Them, PAWN) & PseudoAttacks[ROOK][s];
|
| 556 |
+
if (pawns)
|
| 557 |
+
score += popcount<Max15>(pawns) * (Piece == ROOK ? RookOnPawn : QueenOnPawn);
|
| 558 |
+
}
|
| 559 |
+
|
| 560 |
+
// Special extra evaluation for rooks
|
| 561 |
+
if (Piece == ROOK)
|
| 562 |
+
{
|
| 563 |
+
// Give a bonus for a rook on a open or semi-open file
|
| 564 |
+
if (ei.pi->semiopen(Us, file_of(s)))
|
| 565 |
+
score += ei.pi->semiopen(Them, file_of(s)) ? RookOpenFile : RookSemiopenFile;
|
| 566 |
+
|
| 567 |
+
if (mob > 3 || ei.pi->semiopen(Us, file_of(s)))
|
| 568 |
+
continue;
|
| 569 |
+
|
| 570 |
+
Square ksq = pos.king_square(Us);
|
| 571 |
+
|
| 572 |
+
// Penalize rooks which are trapped inside a king. Penalize more if
|
| 573 |
+
// king has lost right to castle.
|
| 574 |
+
if ( ((file_of(ksq) < FILE_E) == (file_of(s) < file_of(ksq)))
|
| 575 |
+
&& (rank_of(ksq) == rank_of(s) || relative_rank(Us, ksq) == RANK_1)
|
| 576 |
+
&& !ei.pi->semiopen_on_side(Us, file_of(ksq), file_of(ksq) < FILE_E))
|
| 577 |
+
score -= (TrappedRook - make_score(mob * 8, 0)) * (pos.can_castle(Us) ? 1 : 2);
|
| 578 |
+
}
|
| 579 |
+
|
| 580 |
+
// An important Chess960 pattern: A cornered bishop blocked by a friendly
|
| 581 |
+
// pawn diagonally in front of it is a very serious problem, especially
|
| 582 |
+
// when that pawn is also blocked.
|
| 583 |
+
if ( Piece == BISHOP
|
| 584 |
+
&& pos.is_chess960()
|
| 585 |
+
&& (s == relative_square(Us, SQ_A1) || s == relative_square(Us, SQ_H1)))
|
| 586 |
+
{
|
| 587 |
+
const enum Piece P = make_piece(Us, PAWN);
|
| 588 |
+
Square d = pawn_push(Us) + (file_of(s) == FILE_A ? DELTA_E : DELTA_W);
|
| 589 |
+
if (pos.piece_on(s + d) == P)
|
| 590 |
+
score -= !pos.is_empty(s + d + pawn_push(Us)) ? TrappedBishopA1H1 * 4
|
| 591 |
+
: pos.piece_on(s + d + d) == P ? TrappedBishopA1H1 * 2
|
| 592 |
+
: TrappedBishopA1H1;
|
| 593 |
+
}
|
| 594 |
+
}
|
| 595 |
+
|
| 596 |
+
if (Trace)
|
| 597 |
+
Tracing::scores[Us][Piece] = score;
|
| 598 |
+
|
| 599 |
+
return score;
|
| 600 |
+
}
|
| 601 |
+
|
| 602 |
+
|
| 603 |
+
// evaluate_threats<>() assigns bonuses according to the type of attacking piece
|
| 604 |
+
// and the type of attacked one.
|
| 605 |
+
|
| 606 |
+
template<Color Us, bool Trace>
|
| 607 |
+
Score evaluate_threats(const Position& pos, const EvalInfo& ei) {
|
| 608 |
+
|
| 609 |
+
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
| 610 |
+
|
| 611 |
+
Bitboard b, undefendedMinors, weakEnemies;
|
| 612 |
+
Score score = SCORE_ZERO;
|
| 613 |
+
|
| 614 |
+
// Undefended minors get penalized even if not under attack
|
| 615 |
+
undefendedMinors = pos.pieces(Them, BISHOP, KNIGHT)
|
| 616 |
+
& ~ei.attackedBy[Them][ALL_PIECES];
|
| 617 |
+
|
| 618 |
+
if (undefendedMinors)
|
| 619 |
+
score += UndefendedMinor;
|
| 620 |
+
|
| 621 |
+
// Enemy pieces not defended by a pawn and under our attack
|
| 622 |
+
weakEnemies = pos.pieces(Them)
|
| 623 |
+
& ~ei.attackedBy[Them][PAWN]
|
| 624 |
+
& ei.attackedBy[Us][ALL_PIECES];
|
| 625 |
+
|
| 626 |
+
// Add bonus according to type of attacked enemy piece and to the
|
| 627 |
+
// type of attacking piece, from knights to queens. Kings are not
|
| 628 |
+
// considered because are already handled in king evaluation.
|
| 629 |
+
if (weakEnemies)
|
| 630 |
+
for (PieceType pt1 = KNIGHT; pt1 < KING; pt1++)
|
| 631 |
+
{
|
| 632 |
+
b = ei.attackedBy[Us][pt1] & weakEnemies;
|
| 633 |
+
if (b)
|
| 634 |
+
for (PieceType pt2 = PAWN; pt2 < KING; pt2++)
|
| 635 |
+
if (b & pos.pieces(pt2))
|
| 636 |
+
score += Threat[pt1][pt2];
|
| 637 |
+
}
|
| 638 |
+
|
| 639 |
+
if (Trace)
|
| 640 |
+
Tracing::scores[Us][THREAT] = score;
|
| 641 |
+
|
| 642 |
+
return score;
|
| 643 |
+
}
|
| 644 |
+
|
| 645 |
+
|
| 646 |
+
// evaluate_pieces_of_color<>() assigns bonuses and penalties to all the
|
| 647 |
+
// pieces of a given color.
|
| 648 |
+
|
| 649 |
+
template<Color Us, bool Trace>
|
| 650 |
+
Score evaluate_pieces_of_color(const Position& pos, EvalInfo& ei, Score& mobility) {
|
| 651 |
+
|
| 652 |
+
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
| 653 |
+
|
| 654 |
+
Score score = mobility = SCORE_ZERO;
|
| 655 |
+
|
| 656 |
+
// Do not include in mobility squares protected by enemy pawns or occupied by our pieces
|
| 657 |
+
const Bitboard mobilityArea = ~(ei.attackedBy[Them][PAWN] | pos.pieces(Us, PAWN, KING));
|
| 658 |
+
|
| 659 |
+
score += evaluate_pieces<KNIGHT, Us, Trace>(pos, ei, mobility, mobilityArea);
|
| 660 |
+
score += evaluate_pieces<BISHOP, Us, Trace>(pos, ei, mobility, mobilityArea);
|
| 661 |
+
score += evaluate_pieces<ROOK, Us, Trace>(pos, ei, mobility, mobilityArea);
|
| 662 |
+
score += evaluate_pieces<QUEEN, Us, Trace>(pos, ei, mobility, mobilityArea);
|
| 663 |
+
|
| 664 |
+
// Sum up all attacked squares
|
| 665 |
+
ei.attackedBy[Us][ALL_PIECES] = ei.attackedBy[Us][PAWN] | ei.attackedBy[Us][KNIGHT]
|
| 666 |
+
| ei.attackedBy[Us][BISHOP] | ei.attackedBy[Us][ROOK]
|
| 667 |
+
| ei.attackedBy[Us][QUEEN] | ei.attackedBy[Us][KING];
|
| 668 |
+
if (Trace)
|
| 669 |
+
Tracing::scores[Us][MOBILITY] = apply_weight(mobility, Weights[Mobility]);
|
| 670 |
+
|
| 671 |
+
return score;
|
| 672 |
+
}
|
| 673 |
+
|
| 674 |
+
|
| 675 |
+
// evaluate_king<>() assigns bonuses and penalties to a king of a given color
|
| 676 |
+
|
| 677 |
+
template<Color Us, bool Trace>
|
| 678 |
+
Score evaluate_king(const Position& pos, const EvalInfo& ei, Value margins[]) {
|
| 679 |
+
|
| 680 |
+
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
| 681 |
+
|
| 682 |
+
Bitboard undefended, b, b1, b2, safe;
|
| 683 |
+
int attackUnits;
|
| 684 |
+
const Square ksq = pos.king_square(Us);
|
| 685 |
+
|
| 686 |
+
// King shelter and enemy pawns storm
|
| 687 |
+
Score score = ei.pi->king_safety<Us>(pos, ksq);
|
| 688 |
+
|
| 689 |
+
// King safety. This is quite complicated, and is almost certainly far
|
| 690 |
+
// from optimally tuned.
|
| 691 |
+
if ( ei.kingAttackersCount[Them] >= 2
|
| 692 |
+
&& ei.kingAdjacentZoneAttacksCount[Them])
|
| 693 |
+
{
|
| 694 |
+
// Find the attacked squares around the king which has no defenders
|
| 695 |
+
// apart from the king itself
|
| 696 |
+
undefended = ei.attackedBy[Them][ALL_PIECES] & ei.attackedBy[Us][KING];
|
| 697 |
+
undefended &= ~( ei.attackedBy[Us][PAWN] | ei.attackedBy[Us][KNIGHT]
|
| 698 |
+
| ei.attackedBy[Us][BISHOP] | ei.attackedBy[Us][ROOK]
|
| 699 |
+
| ei.attackedBy[Us][QUEEN]);
|
| 700 |
+
|
| 701 |
+
// Initialize the 'attackUnits' variable, which is used later on as an
|
| 702 |
+
// index to the KingDanger[] array. The initial value is based on the
|
| 703 |
+
// number and types of the enemy's attacking pieces, the number of
|
| 704 |
+
// attacked and undefended squares around our king, the square of the
|
| 705 |
+
// king, and the quality of the pawn shelter.
|
| 706 |
+
attackUnits = std::min(25, (ei.kingAttackersCount[Them] * ei.kingAttackersWeight[Them]) / 2)
|
| 707 |
+
+ 3 * (ei.kingAdjacentZoneAttacksCount[Them] + popcount<Max15>(undefended))
|
| 708 |
+
+ KingExposed[relative_square(Us, ksq)]
|
| 709 |
+
- mg_value(score) / 32;
|
| 710 |
+
|
| 711 |
+
// Analyse enemy's safe queen contact checks. First find undefended
|
| 712 |
+
// squares around the king attacked by enemy queen...
|
| 713 |
+
b = undefended & ei.attackedBy[Them][QUEEN] & ~pos.pieces(Them);
|
| 714 |
+
if (b)
|
| 715 |
+
{
|
| 716 |
+
// ...then remove squares not supported by another enemy piece
|
| 717 |
+
b &= ( ei.attackedBy[Them][PAWN] | ei.attackedBy[Them][KNIGHT]
|
| 718 |
+
| ei.attackedBy[Them][BISHOP] | ei.attackedBy[Them][ROOK]);
|
| 719 |
+
if (b)
|
| 720 |
+
attackUnits += QueenContactCheck
|
| 721 |
+
* popcount<Max15>(b)
|
| 722 |
+
* (Them == pos.side_to_move() ? 2 : 1);
|
| 723 |
+
}
|
| 724 |
+
|
| 725 |
+
// Analyse enemy's safe rook contact checks. First find undefended
|
| 726 |
+
// squares around the king attacked by enemy rooks...
|
| 727 |
+
b = undefended & ei.attackedBy[Them][ROOK] & ~pos.pieces(Them);
|
| 728 |
+
|
| 729 |
+
// Consider only squares where the enemy rook gives check
|
| 730 |
+
b &= PseudoAttacks[ROOK][ksq];
|
| 731 |
+
|
| 732 |
+
if (b)
|
| 733 |
+
{
|
| 734 |
+
// ...then remove squares not supported by another enemy piece
|
| 735 |
+
b &= ( ei.attackedBy[Them][PAWN] | ei.attackedBy[Them][KNIGHT]
|
| 736 |
+
| ei.attackedBy[Them][BISHOP] | ei.attackedBy[Them][QUEEN]);
|
| 737 |
+
if (b)
|
| 738 |
+
attackUnits += RookContactCheck
|
| 739 |
+
* popcount<Max15>(b)
|
| 740 |
+
* (Them == pos.side_to_move() ? 2 : 1);
|
| 741 |
+
}
|
| 742 |
+
|
| 743 |
+
// Analyse enemy's safe distance checks for sliders and knights
|
| 744 |
+
safe = ~(pos.pieces(Them) | ei.attackedBy[Us][ALL_PIECES]);
|
| 745 |
+
|
| 746 |
+
b1 = pos.attacks_from<ROOK>(ksq) & safe;
|
| 747 |
+
b2 = pos.attacks_from<BISHOP>(ksq) & safe;
|
| 748 |
+
|
| 749 |
+
// Enemy queen safe checks
|
| 750 |
+
b = (b1 | b2) & ei.attackedBy[Them][QUEEN];
|
| 751 |
+
if (b)
|
| 752 |
+
attackUnits += QueenCheck * popcount<Max15>(b);
|
| 753 |
+
|
| 754 |
+
// Enemy rooks safe checks
|
| 755 |
+
b = b1 & ei.attackedBy[Them][ROOK];
|
| 756 |
+
if (b)
|
| 757 |
+
attackUnits += RookCheck * popcount<Max15>(b);
|
| 758 |
+
|
| 759 |
+
// Enemy bishops safe checks
|
| 760 |
+
b = b2 & ei.attackedBy[Them][BISHOP];
|
| 761 |
+
if (b)
|
| 762 |
+
attackUnits += BishopCheck * popcount<Max15>(b);
|
| 763 |
+
|
| 764 |
+
// Enemy knights safe checks
|
| 765 |
+
b = pos.attacks_from<KNIGHT>(ksq) & ei.attackedBy[Them][KNIGHT] & safe;
|
| 766 |
+
if (b)
|
| 767 |
+
attackUnits += KnightCheck * popcount<Max15>(b);
|
| 768 |
+
|
| 769 |
+
// To index KingDanger[] attackUnits must be in [0, 99] range
|
| 770 |
+
attackUnits = std::min(99, std::max(0, attackUnits));
|
| 771 |
+
|
| 772 |
+
// Finally, extract the king danger score from the KingDanger[]
|
| 773 |
+
// array and subtract the score from evaluation. Set also margins[]
|
| 774 |
+
// value that will be used for pruning because this value can sometimes
|
| 775 |
+
// be very big, and so capturing a single attacking piece can therefore
|
| 776 |
+
// result in a score change far bigger than the value of the captured piece.
|
| 777 |
+
score -= KingDanger[Us == Search::RootColor][attackUnits];
|
| 778 |
+
margins[Us] += mg_value(KingDanger[Us == Search::RootColor][attackUnits]);
|
| 779 |
+
}
|
| 780 |
+
|
| 781 |
+
if (Trace)
|
| 782 |
+
Tracing::scores[Us][KING] = score;
|
| 783 |
+
|
| 784 |
+
return score;
|
| 785 |
+
}
|
| 786 |
+
|
| 787 |
+
|
| 788 |
+
// evaluate_passed_pawns<>() evaluates the passed pawns of the given color
|
| 789 |
+
|
| 790 |
+
template<Color Us, bool Trace>
|
| 791 |
+
Score evaluate_passed_pawns(const Position& pos, const EvalInfo& ei) {
|
| 792 |
+
|
| 793 |
+
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
| 794 |
+
|
| 795 |
+
Bitboard b, squaresToQueen, defendedSquares, unsafeSquares, supportingPawns;
|
| 796 |
+
Score score = SCORE_ZERO;
|
| 797 |
+
|
| 798 |
+
b = ei.pi->passed_pawns(Us);
|
| 799 |
+
|
| 800 |
+
while (b)
|
| 801 |
+
{
|
| 802 |
+
Square s = pop_lsb(&b);
|
| 803 |
+
|
| 804 |
+
assert(pos.pawn_is_passed(Us, s));
|
| 805 |
+
|
| 806 |
+
int r = int(relative_rank(Us, s) - RANK_2);
|
| 807 |
+
int rr = r * (r - 1);
|
| 808 |
+
|
| 809 |
+
// Base bonus based on rank
|
| 810 |
+
Value mbonus = Value(17 * rr);
|
| 811 |
+
Value ebonus = Value(7 * (rr + r + 1));
|
| 812 |
+
|
| 813 |
+
if (rr)
|
| 814 |
+
{
|
| 815 |
+
Square blockSq = s + pawn_push(Us);
|
| 816 |
+
|
| 817 |
+
// Adjust bonus based on kings proximity
|
| 818 |
+
ebonus += Value(square_distance(pos.king_square(Them), blockSq) * 5 * rr);
|
| 819 |
+
ebonus -= Value(square_distance(pos.king_square(Us), blockSq) * 2 * rr);
|
| 820 |
+
|
| 821 |
+
// If blockSq is not the queening square then consider also a second push
|
| 822 |
+
if (rank_of(blockSq) != (Us == WHITE ? RANK_8 : RANK_1))
|
| 823 |
+
ebonus -= Value(square_distance(pos.king_square(Us), blockSq + pawn_push(Us)) * rr);
|
| 824 |
+
|
| 825 |
+
// If the pawn is free to advance, increase bonus
|
| 826 |
+
if (pos.is_empty(blockSq))
|
| 827 |
+
{
|
| 828 |
+
squaresToQueen = forward_bb(Us, s);
|
| 829 |
+
defendedSquares = squaresToQueen & ei.attackedBy[Us][ALL_PIECES];
|
| 830 |
+
|
| 831 |
+
// If there is an enemy rook or queen attacking the pawn from behind,
|
| 832 |
+
// add all X-ray attacks by the rook or queen. Otherwise consider only
|
| 833 |
+
// the squares in the pawn's path attacked or occupied by the enemy.
|
| 834 |
+
if ( unlikely(forward_bb(Them, s) & pos.pieces(Them, ROOK, QUEEN))
|
| 835 |
+
&& (forward_bb(Them, s) & pos.pieces(Them, ROOK, QUEEN) & pos.attacks_from<ROOK>(s)))
|
| 836 |
+
unsafeSquares = squaresToQueen;
|
| 837 |
+
else
|
| 838 |
+
unsafeSquares = squaresToQueen & (ei.attackedBy[Them][ALL_PIECES] | pos.pieces(Them));
|
| 839 |
+
|
| 840 |
+
// If there aren't enemy attacks huge bonus, a bit smaller if at
|
| 841 |
+
// least block square is not attacked, otherwise smallest bonus.
|
| 842 |
+
int k = !unsafeSquares ? 15 : !(unsafeSquares & blockSq) ? 9 : 3;
|
| 843 |
+
|
| 844 |
+
// Big bonus if the path to queen is fully defended, a bit less
|
| 845 |
+
// if at least block square is defended.
|
| 846 |
+
if (defendedSquares == squaresToQueen)
|
| 847 |
+
k += 6;
|
| 848 |
+
|
| 849 |
+
else if (defendedSquares & blockSq)
|
| 850 |
+
k += (unsafeSquares & defendedSquares) == unsafeSquares ? 4 : 2;
|
| 851 |
+
|
| 852 |
+
mbonus += Value(k * rr), ebonus += Value(k * rr);
|
| 853 |
+
}
|
| 854 |
+
} // rr != 0
|
| 855 |
+
|
| 856 |
+
// Increase the bonus if the passed pawn is supported by a friendly pawn
|
| 857 |
+
// on the same rank and a bit smaller if it's on the previous rank.
|
| 858 |
+
supportingPawns = pos.pieces(Us, PAWN) & adjacent_files_bb(file_of(s));
|
| 859 |
+
if (supportingPawns & rank_bb(s))
|
| 860 |
+
ebonus += Value(r * 20);
|
| 861 |
+
|
| 862 |
+
else if (supportingPawns & rank_bb(s - pawn_push(Us)))
|
| 863 |
+
ebonus += Value(r * 12);
|
| 864 |
+
|
| 865 |
+
// Rook pawns are a special case: They are sometimes worse, and
|
| 866 |
+
// sometimes better than other passed pawns. It is difficult to find
|
| 867 |
+
// good rules for determining whether they are good or bad. For now,
|
| 868 |
+
// we try the following: Increase the value for rook pawns if the
|
| 869 |
+
// other side has no pieces apart from a knight, and decrease the
|
| 870 |
+
// value if the other side has a rook or queen.
|
| 871 |
+
if (file_of(s) == FILE_A || file_of(s) == FILE_H)
|
| 872 |
+
{
|
| 873 |
+
if (pos.non_pawn_material(Them) <= KnightValueMg)
|
| 874 |
+
ebonus += ebonus / 4;
|
| 875 |
+
else if (pos.pieces(Them, ROOK, QUEEN))
|
| 876 |
+
ebonus -= ebonus / 4;
|
| 877 |
+
}
|
| 878 |
+
score += make_score(mbonus, ebonus);
|
| 879 |
+
|
| 880 |
+
}
|
| 881 |
+
|
| 882 |
+
if (Trace)
|
| 883 |
+
Tracing::scores[Us][PASSED] = apply_weight(score, Weights[PassedPawns]);
|
| 884 |
+
|
| 885 |
+
// Add the scores to the middle game and endgame eval
|
| 886 |
+
return apply_weight(score, Weights[PassedPawns]);
|
| 887 |
+
}
|
| 888 |
+
|
| 889 |
+
|
| 890 |
+
// evaluate_unstoppable_pawns() evaluates the unstoppable passed pawns for both sides, this is quite
|
| 891 |
+
// conservative and returns a winning score only when we are very sure that the pawn is winning.
|
| 892 |
+
|
| 893 |
+
Score evaluate_unstoppable_pawns(const Position& pos, const EvalInfo& ei) {
|
| 894 |
+
|
| 895 |
+
Bitboard b, b2, blockers, supporters, queeningPath, candidates;
|
| 896 |
+
Square s, blockSq, queeningSquare;
|
| 897 |
+
Color c, winnerSide, loserSide;
|
| 898 |
+
bool pathDefended, opposed;
|
| 899 |
+
int pliesToGo, movesToGo, oppMovesToGo, sacptg, blockersCount, minKingDist, kingptg, d;
|
| 900 |
+
int pliesToQueen[] = { 256, 256 };
|
| 901 |
+
|
| 902 |
+
// Step 1. Hunt for unstoppable passed pawns. If we find at least one,
|
| 903 |
+
// record how many plies are required for promotion.
|
| 904 |
+
for (c = WHITE; c <= BLACK; c++)
|
| 905 |
+
{
|
| 906 |
+
// Skip if other side has non-pawn pieces
|
| 907 |
+
if (pos.non_pawn_material(~c))
|
| 908 |
+
continue;
|
| 909 |
+
|
| 910 |
+
b = ei.pi->passed_pawns(c);
|
| 911 |
+
|
| 912 |
+
while (b)
|
| 913 |
+
{
|
| 914 |
+
s = pop_lsb(&b);
|
| 915 |
+
queeningSquare = relative_square(c, file_of(s) | RANK_8);
|
| 916 |
+
queeningPath = forward_bb(c, s);
|
| 917 |
+
|
| 918 |
+
// Compute plies to queening and check direct advancement
|
| 919 |
+
movesToGo = rank_distance(s, queeningSquare) - int(relative_rank(c, s) == RANK_2);
|
| 920 |
+
oppMovesToGo = square_distance(pos.king_square(~c), queeningSquare) - int(c != pos.side_to_move());
|
| 921 |
+
pathDefended = ((ei.attackedBy[c][ALL_PIECES] & queeningPath) == queeningPath);
|
| 922 |
+
|
| 923 |
+
if (movesToGo >= oppMovesToGo && !pathDefended)
|
| 924 |
+
continue;
|
| 925 |
+
|
| 926 |
+
// Opponent king cannot block because path is defended and position
|
| 927 |
+
// is not in check. So only friendly pieces can be blockers.
|
| 928 |
+
assert(!pos.checkers());
|
| 929 |
+
assert((queeningPath & pos.pieces()) == (queeningPath & pos.pieces(c)));
|
| 930 |
+
|
| 931 |
+
// Add moves needed to free the path from friendly pieces and retest condition
|
| 932 |
+
movesToGo += popcount<Max15>(queeningPath & pos.pieces(c));
|
| 933 |
+
|
| 934 |
+
if (movesToGo >= oppMovesToGo && !pathDefended)
|
| 935 |
+
continue;
|
| 936 |
+
|
| 937 |
+
pliesToGo = 2 * movesToGo - int(c == pos.side_to_move());
|
| 938 |
+
pliesToQueen[c] = std::min(pliesToQueen[c], pliesToGo);
|
| 939 |
+
}
|
| 940 |
+
}
|
| 941 |
+
|
| 942 |
+
// Step 2. If either side cannot promote at least three plies before the other side then situation
|
| 943 |
+
// becomes too complex and we give up. Otherwise we determine the possibly "winning side"
|
| 944 |
+
if (abs(pliesToQueen[WHITE] - pliesToQueen[BLACK]) < 3)
|
| 945 |
+
return SCORE_ZERO;
|
| 946 |
+
|
| 947 |
+
winnerSide = (pliesToQueen[WHITE] < pliesToQueen[BLACK] ? WHITE : BLACK);
|
| 948 |
+
loserSide = ~winnerSide;
|
| 949 |
+
|
| 950 |
+
// Step 3. Can the losing side possibly create a new passed pawn and thus prevent the loss?
|
| 951 |
+
b = candidates = pos.pieces(loserSide, PAWN);
|
| 952 |
+
|
| 953 |
+
while (b)
|
| 954 |
+
{
|
| 955 |
+
s = pop_lsb(&b);
|
| 956 |
+
|
| 957 |
+
// Compute plies from queening
|
| 958 |
+
queeningSquare = relative_square(loserSide, file_of(s) | RANK_8);
|
| 959 |
+
movesToGo = rank_distance(s, queeningSquare) - int(relative_rank(loserSide, s) == RANK_2);
|
| 960 |
+
pliesToGo = 2 * movesToGo - int(loserSide == pos.side_to_move());
|
| 961 |
+
|
| 962 |
+
// Check if (without even considering any obstacles) we're too far away or doubled
|
| 963 |
+
if ( pliesToQueen[winnerSide] + 3 <= pliesToGo
|
| 964 |
+
|| (forward_bb(loserSide, s) & pos.pieces(loserSide, PAWN)))
|
| 965 |
+
candidates ^= s;
|
| 966 |
+
}
|
| 967 |
+
|
| 968 |
+
// If any candidate is already a passed pawn it _may_ promote in time. We give up.
|
| 969 |
+
if (candidates & ei.pi->passed_pawns(loserSide))
|
| 970 |
+
return SCORE_ZERO;
|
| 971 |
+
|
| 972 |
+
// Step 4. Check new passed pawn creation through king capturing and pawn sacrifices
|
| 973 |
+
b = candidates;
|
| 974 |
+
|
| 975 |
+
while (b)
|
| 976 |
+
{
|
| 977 |
+
s = pop_lsb(&b);
|
| 978 |
+
sacptg = blockersCount = 0;
|
| 979 |
+
minKingDist = kingptg = 256;
|
| 980 |
+
|
| 981 |
+
// Compute plies from queening
|
| 982 |
+
queeningSquare = relative_square(loserSide, file_of(s) | RANK_8);
|
| 983 |
+
movesToGo = rank_distance(s, queeningSquare) - int(relative_rank(loserSide, s) == RANK_2);
|
| 984 |
+
pliesToGo = 2 * movesToGo - int(loserSide == pos.side_to_move());
|
| 985 |
+
|
| 986 |
+
// Generate list of blocking pawns and supporters
|
| 987 |
+
supporters = adjacent_files_bb(file_of(s)) & candidates;
|
| 988 |
+
opposed = forward_bb(loserSide, s) & pos.pieces(winnerSide, PAWN);
|
| 989 |
+
blockers = passed_pawn_mask(loserSide, s) & pos.pieces(winnerSide, PAWN);
|
| 990 |
+
|
| 991 |
+
assert(blockers);
|
| 992 |
+
|
| 993 |
+
// How many plies does it take to remove all the blocking pawns?
|
| 994 |
+
while (blockers)
|
| 995 |
+
{
|
| 996 |
+
blockSq = pop_lsb(&blockers);
|
| 997 |
+
movesToGo = 256;
|
| 998 |
+
|
| 999 |
+
// Check pawns that can give support to overcome obstacle, for instance
|
| 1000 |
+
// black pawns: a4, b4 white: b2 then pawn in b4 is giving support.
|
| 1001 |
+
if (!opposed)
|
| 1002 |
+
{
|
| 1003 |
+
b2 = supporters & in_front_bb(winnerSide, rank_of(blockSq + pawn_push(winnerSide)));
|
| 1004 |
+
|
| 1005 |
+
while (b2) // This while-loop could be replaced with LSB/MSB (depending on color)
|
| 1006 |
+
{
|
| 1007 |
+
d = square_distance(blockSq, pop_lsb(&b2)) - 2;
|
| 1008 |
+
movesToGo = std::min(movesToGo, d);
|
| 1009 |
+
}
|
| 1010 |
+
}
|
| 1011 |
+
|
| 1012 |
+
// Check pawns that can be sacrificed against the blocking pawn
|
| 1013 |
+
b2 = pawn_attack_span(winnerSide, blockSq) & candidates & ~(1ULL << s);
|
| 1014 |
+
|
| 1015 |
+
while (b2) // This while-loop could be replaced with LSB/MSB (depending on color)
|
| 1016 |
+
{
|
| 1017 |
+
d = square_distance(blockSq, pop_lsb(&b2)) - 2;
|
| 1018 |
+
movesToGo = std::min(movesToGo, d);
|
| 1019 |
+
}
|
| 1020 |
+
|
| 1021 |
+
// If obstacle can be destroyed with an immediate pawn exchange / sacrifice,
|
| 1022 |
+
// it's not a real obstacle and we have nothing to add to pliesToGo.
|
| 1023 |
+
if (movesToGo <= 0)
|
| 1024 |
+
continue;
|
| 1025 |
+
|
| 1026 |
+
// Plies needed to sacrifice against all the blocking pawns
|
| 1027 |
+
sacptg += movesToGo * 2;
|
| 1028 |
+
blockersCount++;
|
| 1029 |
+
|
| 1030 |
+
// Plies needed for the king to capture all the blocking pawns
|
| 1031 |
+
d = square_distance(pos.king_square(loserSide), blockSq);
|
| 1032 |
+
minKingDist = std::min(minKingDist, d);
|
| 1033 |
+
kingptg = (minKingDist + blockersCount) * 2;
|
| 1034 |
+
}
|
| 1035 |
+
|
| 1036 |
+
// Check if pawn sacrifice plan _may_ save the day
|
| 1037 |
+
if (pliesToQueen[winnerSide] + 3 > pliesToGo + sacptg)
|
| 1038 |
+
return SCORE_ZERO;
|
| 1039 |
+
|
| 1040 |
+
// Check if king capture plan _may_ save the day (contains some false positives)
|
| 1041 |
+
if (pliesToQueen[winnerSide] + 3 > pliesToGo + kingptg)
|
| 1042 |
+
return SCORE_ZERO;
|
| 1043 |
+
}
|
| 1044 |
+
|
| 1045 |
+
// Winning pawn is unstoppable and will promote as first, return big score
|
| 1046 |
+
Score score = make_score(0, (Value) 1280 - 32 * pliesToQueen[winnerSide]);
|
| 1047 |
+
return winnerSide == WHITE ? score : -score;
|
| 1048 |
+
}
|
| 1049 |
+
|
| 1050 |
+
|
| 1051 |
+
// evaluate_space() computes the space evaluation for a given side. The
|
| 1052 |
+
// space evaluation is a simple bonus based on the number of safe squares
|
| 1053 |
+
// available for minor pieces on the central four files on ranks 2--4. Safe
|
| 1054 |
+
// squares one, two or three squares behind a friendly pawn are counted
|
| 1055 |
+
// twice. Finally, the space bonus is scaled by a weight taken from the
|
| 1056 |
+
// material hash table. The aim is to improve play on game opening.
|
| 1057 |
+
template<Color Us>
|
| 1058 |
+
int evaluate_space(const Position& pos, const EvalInfo& ei) {
|
| 1059 |
+
|
| 1060 |
+
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
| 1061 |
+
|
| 1062 |
+
// Find the safe squares for our pieces inside the area defined by
|
| 1063 |
+
// SpaceMask[]. A square is unsafe if it is attacked by an enemy
|
| 1064 |
+
// pawn, or if it is undefended and attacked by an enemy piece.
|
| 1065 |
+
Bitboard safe = SpaceMask[Us]
|
| 1066 |
+
& ~pos.pieces(Us, PAWN)
|
| 1067 |
+
& ~ei.attackedBy[Them][PAWN]
|
| 1068 |
+
& (ei.attackedBy[Us][ALL_PIECES] | ~ei.attackedBy[Them][ALL_PIECES]);
|
| 1069 |
+
|
| 1070 |
+
// Find all squares which are at most three squares behind some friendly pawn
|
| 1071 |
+
Bitboard behind = pos.pieces(Us, PAWN);
|
| 1072 |
+
behind |= (Us == WHITE ? behind >> 8 : behind << 8);
|
| 1073 |
+
behind |= (Us == WHITE ? behind >> 16 : behind << 16);
|
| 1074 |
+
|
| 1075 |
+
// Since SpaceMask[Us] is fully on our half of the board
|
| 1076 |
+
assert(unsigned(safe >> (Us == WHITE ? 32 : 0)) == 0);
|
| 1077 |
+
|
| 1078 |
+
// Count safe + (behind & safe) with a single popcount
|
| 1079 |
+
return popcount<Full>((Us == WHITE ? safe << 32 : safe >> 32) | (behind & safe));
|
| 1080 |
+
}
|
| 1081 |
+
|
| 1082 |
+
|
| 1083 |
+
// interpolate() interpolates between a middle game and an endgame score,
|
| 1084 |
+
// based on game phase. It also scales the return value by a ScaleFactor array.
|
| 1085 |
+
|
| 1086 |
+
Value interpolate(const Score& v, Phase ph, ScaleFactor sf) {
|
| 1087 |
+
|
| 1088 |
+
assert(mg_value(v) > -VALUE_INFINITE && mg_value(v) < VALUE_INFINITE);
|
| 1089 |
+
assert(eg_value(v) > -VALUE_INFINITE && eg_value(v) < VALUE_INFINITE);
|
| 1090 |
+
assert(ph >= PHASE_ENDGAME && ph <= PHASE_MIDGAME);
|
| 1091 |
+
|
| 1092 |
+
int ev = (eg_value(v) * int(sf)) / SCALE_FACTOR_NORMAL;
|
| 1093 |
+
int result = (mg_value(v) * int(ph) + ev * int(128 - ph)) / 128;
|
| 1094 |
+
return Value((result / GrainSize) * GrainSize); // Sign independent
|
| 1095 |
+
}
|
| 1096 |
+
|
| 1097 |
+
// apply_weight() weights score v by score w trying to prevent overflow
|
| 1098 |
+
Score apply_weight(Score v, Score w) {
|
| 1099 |
+
return make_score((int(mg_value(v)) * mg_value(w)) / 0x100,
|
| 1100 |
+
(int(eg_value(v)) * eg_value(w)) / 0x100);
|
| 1101 |
+
}
|
| 1102 |
+
|
| 1103 |
+
// weight_option() computes the value of an evaluation weight, by combining
|
| 1104 |
+
// two UCI-configurable weights (midgame and endgame) with an internal weight.
|
| 1105 |
+
|
| 1106 |
+
Score weight_option(const std::string& mgOpt, const std::string& egOpt, Score internalWeight) {
|
| 1107 |
+
|
| 1108 |
+
// Scale option value from 100 to 256
|
| 1109 |
+
int mg = Options[mgOpt] * 256 / 100;
|
| 1110 |
+
int eg = Options[egOpt] * 256 / 100;
|
| 1111 |
+
|
| 1112 |
+
return apply_weight(make_score(mg, eg), internalWeight);
|
| 1113 |
+
}
|
| 1114 |
+
|
| 1115 |
+
|
| 1116 |
+
// Tracing functions definitions
|
| 1117 |
+
|
| 1118 |
+
double to_cp(Value v) { return double(v) / double(PawnValueMg); }
|
| 1119 |
+
|
| 1120 |
+
void Tracing::add(int idx, Score wScore, Score bScore) {
|
| 1121 |
+
|
| 1122 |
+
scores[WHITE][idx] = wScore;
|
| 1123 |
+
scores[BLACK][idx] = bScore;
|
| 1124 |
+
}
|
| 1125 |
+
|
| 1126 |
+
void Tracing::row(const char* name, int idx) {
|
| 1127 |
+
|
| 1128 |
+
Score wScore = scores[WHITE][idx];
|
| 1129 |
+
Score bScore = scores[BLACK][idx];
|
| 1130 |
+
|
| 1131 |
+
switch (idx) {
|
| 1132 |
+
case PST: case IMBALANCE: case PAWN: case UNSTOPPABLE: case TOTAL:
|
| 1133 |
+
stream << std::setw(20) << name << " | --- --- | --- --- | "
|
| 1134 |
+
<< std::setw(6) << to_cp(mg_value(wScore)) << " "
|
| 1135 |
+
<< std::setw(6) << to_cp(eg_value(wScore)) << " \n";
|
| 1136 |
+
break;
|
| 1137 |
+
default:
|
| 1138 |
+
stream << std::setw(20) << name << " | " << std::noshowpos
|
| 1139 |
+
<< std::setw(5) << to_cp(mg_value(wScore)) << " "
|
| 1140 |
+
<< std::setw(5) << to_cp(eg_value(wScore)) << " | "
|
| 1141 |
+
<< std::setw(5) << to_cp(mg_value(bScore)) << " "
|
| 1142 |
+
<< std::setw(5) << to_cp(eg_value(bScore)) << " | "
|
| 1143 |
+
<< std::showpos
|
| 1144 |
+
<< std::setw(6) << to_cp(mg_value(wScore - bScore)) << " "
|
| 1145 |
+
<< std::setw(6) << to_cp(eg_value(wScore - bScore)) << " \n";
|
| 1146 |
+
}
|
| 1147 |
+
}
|
| 1148 |
+
|
| 1149 |
+
std::string Tracing::do_trace(const Position& pos) {
|
| 1150 |
+
|
| 1151 |
+
stream.str("");
|
| 1152 |
+
stream << std::showpoint << std::showpos << std::fixed << std::setprecision(2);
|
| 1153 |
+
std::memset(scores, 0, 2 * (TOTAL + 1) * sizeof(Score));
|
| 1154 |
+
|
| 1155 |
+
Value margin;
|
| 1156 |
+
do_evaluate<true>(pos, margin);
|
| 1157 |
+
|
| 1158 |
+
std::string totals = stream.str();
|
| 1159 |
+
stream.str("");
|
| 1160 |
+
|
| 1161 |
+
stream << std::setw(21) << "Eval term " << "| White | Black | Total \n"
|
| 1162 |
+
<< " | MG EG | MG EG | MG EG \n"
|
| 1163 |
+
<< "---------------------+-------------+-------------+---------------\n";
|
| 1164 |
+
|
| 1165 |
+
row("Material, PST, Tempo", PST);
|
| 1166 |
+
row("Material imbalance", IMBALANCE);
|
| 1167 |
+
row("Pawns", PAWN);
|
| 1168 |
+
row("Knights", KNIGHT);
|
| 1169 |
+
row("Bishops", BISHOP);
|
| 1170 |
+
row("Rooks", ROOK);
|
| 1171 |
+
row("Queens", QUEEN);
|
| 1172 |
+
row("Mobility", MOBILITY);
|
| 1173 |
+
row("King safety", KING);
|
| 1174 |
+
row("Threats", THREAT);
|
| 1175 |
+
row("Passed pawns", PASSED);
|
| 1176 |
+
row("Unstoppable pawns", UNSTOPPABLE);
|
| 1177 |
+
row("Space", SPACE);
|
| 1178 |
+
|
| 1179 |
+
stream << "---------------------+-------------+-------------+---------------\n";
|
| 1180 |
+
row("Total", TOTAL);
|
| 1181 |
+
stream << totals;
|
| 1182 |
+
|
| 1183 |
+
return stream.str();
|
| 1184 |
+
}
|
| 1185 |
+
}
|
stockfish-4-win/src/evaluate.h
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
+
Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
+
|
| 6 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 7 |
+
it under the terms of the GNU General Public License as published by
|
| 8 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 9 |
+
(at your option) any later version.
|
| 10 |
+
|
| 11 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 12 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 13 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 14 |
+
GNU General Public License for more details.
|
| 15 |
+
|
| 16 |
+
You should have received a copy of the GNU General Public License
|
| 17 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 18 |
+
*/
|
| 19 |
+
|
| 20 |
+
#ifndef EVALUATE_H_INCLUDED
|
| 21 |
+
#define EVALUATE_H_INCLUDED
|
| 22 |
+
|
| 23 |
+
#include "types.h"
|
| 24 |
+
|
| 25 |
+
class Position;
|
| 26 |
+
|
| 27 |
+
namespace Eval {
|
| 28 |
+
|
| 29 |
+
extern void init();
|
| 30 |
+
extern Value evaluate(const Position& pos, Value& margin);
|
| 31 |
+
extern std::string trace(const Position& pos);
|
| 32 |
+
|
| 33 |
+
}
|
| 34 |
+
|
| 35 |
+
#endif // #ifndef EVALUATE_H_INCLUDED
|
stockfish-4-win/src/main.cpp
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
+
Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
+
|
| 6 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 7 |
+
it under the terms of the GNU General Public License as published by
|
| 8 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 9 |
+
(at your option) any later version.
|
| 10 |
+
|
| 11 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 12 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 13 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 14 |
+
GNU General Public License for more details.
|
| 15 |
+
|
| 16 |
+
You should have received a copy of the GNU General Public License
|
| 17 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 18 |
+
*/
|
| 19 |
+
|
| 20 |
+
#include <iostream>
|
| 21 |
+
#include <string>
|
| 22 |
+
|
| 23 |
+
#include "bitboard.h"
|
| 24 |
+
#include "evaluate.h"
|
| 25 |
+
#include "position.h"
|
| 26 |
+
#include "search.h"
|
| 27 |
+
#include "thread.h"
|
| 28 |
+
#include "tt.h"
|
| 29 |
+
#include "ucioption.h"
|
| 30 |
+
|
| 31 |
+
int main(int argc, char* argv[]) {
|
| 32 |
+
|
| 33 |
+
std::cout << engine_info() << std::endl;
|
| 34 |
+
|
| 35 |
+
UCI::init(Options);
|
| 36 |
+
Bitboards::init();
|
| 37 |
+
Position::init();
|
| 38 |
+
Bitbases::init_kpk();
|
| 39 |
+
Search::init();
|
| 40 |
+
Eval::init();
|
| 41 |
+
Threads.init();
|
| 42 |
+
TT.set_size(Options["Hash"]);
|
| 43 |
+
|
| 44 |
+
std::string args;
|
| 45 |
+
|
| 46 |
+
for (int i = 1; i < argc; i++)
|
| 47 |
+
args += std::string(argv[i]) + " ";
|
| 48 |
+
|
| 49 |
+
UCI::loop(args);
|
| 50 |
+
|
| 51 |
+
Threads.exit();
|
| 52 |
+
}
|
stockfish-4-win/src/material.cpp
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
+
Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
+
|
| 6 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 7 |
+
it under the terms of the GNU General Public License as published by
|
| 8 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 9 |
+
(at your option) any later version.
|
| 10 |
+
|
| 11 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 12 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 13 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 14 |
+
GNU General Public License for more details.
|
| 15 |
+
|
| 16 |
+
You should have received a copy of the GNU General Public License
|
| 17 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 18 |
+
*/
|
| 19 |
+
|
| 20 |
+
#include <algorithm> // For std::min
|
| 21 |
+
#include <cassert>
|
| 22 |
+
#include <cstring>
|
| 23 |
+
|
| 24 |
+
#include "material.h"
|
| 25 |
+
|
| 26 |
+
using namespace std;
|
| 27 |
+
|
| 28 |
+
namespace {
|
| 29 |
+
|
| 30 |
+
// Values modified by Joona Kiiski
|
| 31 |
+
const Value MidgameLimit = Value(15581);
|
| 32 |
+
const Value EndgameLimit = Value(3998);
|
| 33 |
+
|
| 34 |
+
// Scale factors used when one side has no more pawns
|
| 35 |
+
const int NoPawnsSF[4] = { 6, 12, 32 };
|
| 36 |
+
|
| 37 |
+
// Polynomial material balance parameters
|
| 38 |
+
const Value RedundantQueen = Value(320);
|
| 39 |
+
const Value RedundantRook = Value(554);
|
| 40 |
+
|
| 41 |
+
// pair pawn knight bishop rook queen
|
| 42 |
+
const int LinearCoefficients[6] = { 1617, -162, -1172, -190, 105, 26 };
|
| 43 |
+
|
| 44 |
+
const int QuadraticCoefficientsSameColor[][PIECE_TYPE_NB] = {
|
| 45 |
+
// pair pawn knight bishop rook queen
|
| 46 |
+
{ 7 }, // Bishop pair
|
| 47 |
+
{ 39, 2 }, // Pawn
|
| 48 |
+
{ 35, 271, -4 }, // Knight
|
| 49 |
+
{ 7, 105, 4, 7 }, // Bishop
|
| 50 |
+
{ -27, -2, 46, 100, 56 }, // Rook
|
| 51 |
+
{ 58, 29, 83, 148, -3, -25 } // Queen
|
| 52 |
+
};
|
| 53 |
+
|
| 54 |
+
const int QuadraticCoefficientsOppositeColor[][PIECE_TYPE_NB] = {
|
| 55 |
+
// THEIR PIECES
|
| 56 |
+
// pair pawn knight bishop rook queen
|
| 57 |
+
{ 41 }, // Bishop pair
|
| 58 |
+
{ 37, 41 }, // Pawn
|
| 59 |
+
{ 10, 62, 41 }, // Knight OUR PIECES
|
| 60 |
+
{ 57, 64, 39, 41 }, // Bishop
|
| 61 |
+
{ 50, 40, 23, -22, 41 }, // Rook
|
| 62 |
+
{ 106, 101, 3, 151, 171, 41 } // Queen
|
| 63 |
+
};
|
| 64 |
+
|
| 65 |
+
// Endgame evaluation and scaling functions accessed direcly and not through
|
| 66 |
+
// the function maps because correspond to more then one material hash key.
|
| 67 |
+
Endgame<KmmKm> EvaluateKmmKm[] = { Endgame<KmmKm>(WHITE), Endgame<KmmKm>(BLACK) };
|
| 68 |
+
Endgame<KXK> EvaluateKXK[] = { Endgame<KXK>(WHITE), Endgame<KXK>(BLACK) };
|
| 69 |
+
|
| 70 |
+
Endgame<KBPsK> ScaleKBPsK[] = { Endgame<KBPsK>(WHITE), Endgame<KBPsK>(BLACK) };
|
| 71 |
+
Endgame<KQKRPs> ScaleKQKRPs[] = { Endgame<KQKRPs>(WHITE), Endgame<KQKRPs>(BLACK) };
|
| 72 |
+
Endgame<KPsK> ScaleKPsK[] = { Endgame<KPsK>(WHITE), Endgame<KPsK>(BLACK) };
|
| 73 |
+
Endgame<KPKP> ScaleKPKP[] = { Endgame<KPKP>(WHITE), Endgame<KPKP>(BLACK) };
|
| 74 |
+
|
| 75 |
+
// Helper templates used to detect a given material distribution
|
| 76 |
+
template<Color Us> bool is_KXK(const Position& pos) {
|
| 77 |
+
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
| 78 |
+
return !pos.count<PAWN>(Them)
|
| 79 |
+
&& pos.non_pawn_material(Them) == VALUE_ZERO
|
| 80 |
+
&& pos.non_pawn_material(Us) >= RookValueMg;
|
| 81 |
+
}
|
| 82 |
+
|
| 83 |
+
template<Color Us> bool is_KBPsKs(const Position& pos) {
|
| 84 |
+
return pos.non_pawn_material(Us) == BishopValueMg
|
| 85 |
+
&& pos.count<BISHOP>(Us) == 1
|
| 86 |
+
&& pos.count<PAWN >(Us) >= 1;
|
| 87 |
+
}
|
| 88 |
+
|
| 89 |
+
template<Color Us> bool is_KQKRPs(const Position& pos) {
|
| 90 |
+
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
| 91 |
+
return !pos.count<PAWN>(Us)
|
| 92 |
+
&& pos.non_pawn_material(Us) == QueenValueMg
|
| 93 |
+
&& pos.count<QUEEN>(Us) == 1
|
| 94 |
+
&& pos.count<ROOK>(Them) == 1
|
| 95 |
+
&& pos.count<PAWN>(Them) >= 1;
|
| 96 |
+
}
|
| 97 |
+
|
| 98 |
+
/// imbalance() calculates imbalance comparing piece count of each
|
| 99 |
+
/// piece type for both colors.
|
| 100 |
+
|
| 101 |
+
template<Color Us>
|
| 102 |
+
int imbalance(const int pieceCount[][PIECE_TYPE_NB]) {
|
| 103 |
+
|
| 104 |
+
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
| 105 |
+
|
| 106 |
+
int pt1, pt2, pc, v;
|
| 107 |
+
int value = 0;
|
| 108 |
+
|
| 109 |
+
// Redundancy of major pieces, formula based on Kaufman's paper
|
| 110 |
+
// "The Evaluation of Material Imbalances in Chess"
|
| 111 |
+
if (pieceCount[Us][ROOK] > 0)
|
| 112 |
+
value -= RedundantRook * (pieceCount[Us][ROOK] - 1)
|
| 113 |
+
+ RedundantQueen * pieceCount[Us][QUEEN];
|
| 114 |
+
|
| 115 |
+
// Second-degree polynomial material imbalance by Tord Romstad
|
| 116 |
+
for (pt1 = NO_PIECE_TYPE; pt1 <= QUEEN; pt1++)
|
| 117 |
+
{
|
| 118 |
+
pc = pieceCount[Us][pt1];
|
| 119 |
+
if (!pc)
|
| 120 |
+
continue;
|
| 121 |
+
|
| 122 |
+
v = LinearCoefficients[pt1];
|
| 123 |
+
|
| 124 |
+
for (pt2 = NO_PIECE_TYPE; pt2 <= pt1; pt2++)
|
| 125 |
+
v += QuadraticCoefficientsSameColor[pt1][pt2] * pieceCount[Us][pt2]
|
| 126 |
+
+ QuadraticCoefficientsOppositeColor[pt1][pt2] * pieceCount[Them][pt2];
|
| 127 |
+
|
| 128 |
+
value += pc * v;
|
| 129 |
+
}
|
| 130 |
+
return value;
|
| 131 |
+
}
|
| 132 |
+
|
| 133 |
+
} // namespace
|
| 134 |
+
|
| 135 |
+
namespace Material {
|
| 136 |
+
|
| 137 |
+
/// Material::probe() takes a position object as input, looks up a MaterialEntry
|
| 138 |
+
/// object, and returns a pointer to it. If the material configuration is not
|
| 139 |
+
/// already present in the table, it is computed and stored there, so we don't
|
| 140 |
+
/// have to recompute everything when the same material configuration occurs again.
|
| 141 |
+
|
| 142 |
+
Entry* probe(const Position& pos, Table& entries, Endgames& endgames) {
|
| 143 |
+
|
| 144 |
+
Key key = pos.material_key();
|
| 145 |
+
Entry* e = entries[key];
|
| 146 |
+
|
| 147 |
+
// If e->key matches the position's material hash key, it means that we
|
| 148 |
+
// have analysed this material configuration before, and we can simply
|
| 149 |
+
// return the information we found the last time instead of recomputing it.
|
| 150 |
+
if (e->key == key)
|
| 151 |
+
return e;
|
| 152 |
+
|
| 153 |
+
std::memset(e, 0, sizeof(Entry));
|
| 154 |
+
e->key = key;
|
| 155 |
+
e->factor[WHITE] = e->factor[BLACK] = (uint8_t)SCALE_FACTOR_NORMAL;
|
| 156 |
+
e->gamePhase = game_phase(pos);
|
| 157 |
+
|
| 158 |
+
// Let's look if we have a specialized evaluation function for this
|
| 159 |
+
// particular material configuration. First we look for a fixed
|
| 160 |
+
// configuration one, then a generic one if previous search failed.
|
| 161 |
+
if (endgames.probe(key, e->evaluationFunction))
|
| 162 |
+
return e;
|
| 163 |
+
|
| 164 |
+
if (is_KXK<WHITE>(pos))
|
| 165 |
+
{
|
| 166 |
+
e->evaluationFunction = &EvaluateKXK[WHITE];
|
| 167 |
+
return e;
|
| 168 |
+
}
|
| 169 |
+
|
| 170 |
+
if (is_KXK<BLACK>(pos))
|
| 171 |
+
{
|
| 172 |
+
e->evaluationFunction = &EvaluateKXK[BLACK];
|
| 173 |
+
return e;
|
| 174 |
+
}
|
| 175 |
+
|
| 176 |
+
if (!pos.pieces(PAWN) && !pos.pieces(ROOK) && !pos.pieces(QUEEN))
|
| 177 |
+
{
|
| 178 |
+
// Minor piece endgame with at least one minor piece per side and
|
| 179 |
+
// no pawns. Note that the case KmmK is already handled by KXK.
|
| 180 |
+
assert((pos.pieces(WHITE, KNIGHT) | pos.pieces(WHITE, BISHOP)));
|
| 181 |
+
assert((pos.pieces(BLACK, KNIGHT) | pos.pieces(BLACK, BISHOP)));
|
| 182 |
+
|
| 183 |
+
if ( pos.count<BISHOP>(WHITE) + pos.count<KNIGHT>(WHITE) <= 2
|
| 184 |
+
&& pos.count<BISHOP>(BLACK) + pos.count<KNIGHT>(BLACK) <= 2)
|
| 185 |
+
{
|
| 186 |
+
e->evaluationFunction = &EvaluateKmmKm[pos.side_to_move()];
|
| 187 |
+
return e;
|
| 188 |
+
}
|
| 189 |
+
}
|
| 190 |
+
|
| 191 |
+
// OK, we didn't find any special evaluation function for the current
|
| 192 |
+
// material configuration. Is there a suitable scaling function?
|
| 193 |
+
//
|
| 194 |
+
// We face problems when there are several conflicting applicable
|
| 195 |
+
// scaling functions and we need to decide which one to use.
|
| 196 |
+
EndgameBase<ScaleFactor>* sf;
|
| 197 |
+
|
| 198 |
+
if (endgames.probe(key, sf))
|
| 199 |
+
{
|
| 200 |
+
e->scalingFunction[sf->color()] = sf;
|
| 201 |
+
return e;
|
| 202 |
+
}
|
| 203 |
+
|
| 204 |
+
// Generic scaling functions that refer to more then one material
|
| 205 |
+
// distribution. Should be probed after the specialized ones.
|
| 206 |
+
// Note that these ones don't return after setting the function.
|
| 207 |
+
if (is_KBPsKs<WHITE>(pos))
|
| 208 |
+
e->scalingFunction[WHITE] = &ScaleKBPsK[WHITE];
|
| 209 |
+
|
| 210 |
+
if (is_KBPsKs<BLACK>(pos))
|
| 211 |
+
e->scalingFunction[BLACK] = &ScaleKBPsK[BLACK];
|
| 212 |
+
|
| 213 |
+
if (is_KQKRPs<WHITE>(pos))
|
| 214 |
+
e->scalingFunction[WHITE] = &ScaleKQKRPs[WHITE];
|
| 215 |
+
|
| 216 |
+
else if (is_KQKRPs<BLACK>(pos))
|
| 217 |
+
e->scalingFunction[BLACK] = &ScaleKQKRPs[BLACK];
|
| 218 |
+
|
| 219 |
+
Value npm_w = pos.non_pawn_material(WHITE);
|
| 220 |
+
Value npm_b = pos.non_pawn_material(BLACK);
|
| 221 |
+
|
| 222 |
+
if (npm_w + npm_b == VALUE_ZERO)
|
| 223 |
+
{
|
| 224 |
+
if (!pos.count<PAWN>(BLACK))
|
| 225 |
+
{
|
| 226 |
+
assert(pos.count<PAWN>(WHITE) >= 2);
|
| 227 |
+
e->scalingFunction[WHITE] = &ScaleKPsK[WHITE];
|
| 228 |
+
}
|
| 229 |
+
else if (!pos.count<PAWN>(WHITE))
|
| 230 |
+
{
|
| 231 |
+
assert(pos.count<PAWN>(BLACK) >= 2);
|
| 232 |
+
e->scalingFunction[BLACK] = &ScaleKPsK[BLACK];
|
| 233 |
+
}
|
| 234 |
+
else if (pos.count<PAWN>(WHITE) == 1 && pos.count<PAWN>(BLACK) == 1)
|
| 235 |
+
{
|
| 236 |
+
// This is a special case because we set scaling functions
|
| 237 |
+
// for both colors instead of only one.
|
| 238 |
+
e->scalingFunction[WHITE] = &ScaleKPKP[WHITE];
|
| 239 |
+
e->scalingFunction[BLACK] = &ScaleKPKP[BLACK];
|
| 240 |
+
}
|
| 241 |
+
}
|
| 242 |
+
|
| 243 |
+
// No pawns makes it difficult to win, even with a material advantage
|
| 244 |
+
if (!pos.count<PAWN>(WHITE) && npm_w - npm_b <= BishopValueMg)
|
| 245 |
+
{
|
| 246 |
+
e->factor[WHITE] = (uint8_t)
|
| 247 |
+
(npm_w == npm_b || npm_w < RookValueMg ? 0 : NoPawnsSF[std::min(pos.count<BISHOP>(WHITE), 2)]);
|
| 248 |
+
}
|
| 249 |
+
|
| 250 |
+
if (!pos.count<PAWN>(BLACK) && npm_b - npm_w <= BishopValueMg)
|
| 251 |
+
{
|
| 252 |
+
e->factor[BLACK] = (uint8_t)
|
| 253 |
+
(npm_w == npm_b || npm_b < RookValueMg ? 0 : NoPawnsSF[std::min(pos.count<BISHOP>(BLACK), 2)]);
|
| 254 |
+
}
|
| 255 |
+
|
| 256 |
+
// Compute the space weight
|
| 257 |
+
if (npm_w + npm_b >= 2 * QueenValueMg + 4 * RookValueMg + 2 * KnightValueMg)
|
| 258 |
+
{
|
| 259 |
+
int minorPieceCount = pos.count<KNIGHT>(WHITE) + pos.count<BISHOP>(WHITE)
|
| 260 |
+
+ pos.count<KNIGHT>(BLACK) + pos.count<BISHOP>(BLACK);
|
| 261 |
+
|
| 262 |
+
e->spaceWeight = make_score(minorPieceCount * minorPieceCount, 0);
|
| 263 |
+
}
|
| 264 |
+
|
| 265 |
+
// Evaluate the material imbalance. We use PIECE_TYPE_NONE as a place holder
|
| 266 |
+
// for the bishop pair "extended piece", this allow us to be more flexible
|
| 267 |
+
// in defining bishop pair bonuses.
|
| 268 |
+
const int pieceCount[COLOR_NB][PIECE_TYPE_NB] = {
|
| 269 |
+
{ pos.count<BISHOP>(WHITE) > 1, pos.count<PAWN>(WHITE), pos.count<KNIGHT>(WHITE),
|
| 270 |
+
pos.count<BISHOP>(WHITE) , pos.count<ROOK>(WHITE), pos.count<QUEEN >(WHITE) },
|
| 271 |
+
{ pos.count<BISHOP>(BLACK) > 1, pos.count<PAWN>(BLACK), pos.count<KNIGHT>(BLACK),
|
| 272 |
+
pos.count<BISHOP>(BLACK) , pos.count<ROOK>(BLACK), pos.count<QUEEN >(BLACK) } };
|
| 273 |
+
|
| 274 |
+
e->value = (int16_t)((imbalance<WHITE>(pieceCount) - imbalance<BLACK>(pieceCount)) / 16);
|
| 275 |
+
return e;
|
| 276 |
+
}
|
| 277 |
+
|
| 278 |
+
|
| 279 |
+
/// Material::game_phase() calculates the phase given the current
|
| 280 |
+
/// position. Because the phase is strictly a function of the material, it
|
| 281 |
+
/// is stored in MaterialEntry.
|
| 282 |
+
|
| 283 |
+
Phase game_phase(const Position& pos) {
|
| 284 |
+
|
| 285 |
+
Value npm = pos.non_pawn_material(WHITE) + pos.non_pawn_material(BLACK);
|
| 286 |
+
|
| 287 |
+
return npm >= MidgameLimit ? PHASE_MIDGAME
|
| 288 |
+
: npm <= EndgameLimit ? PHASE_ENDGAME
|
| 289 |
+
: Phase(((npm - EndgameLimit) * 128) / (MidgameLimit - EndgameLimit));
|
| 290 |
+
}
|
| 291 |
+
|
| 292 |
+
} // namespace Material
|
stockfish-4-win/src/material.h
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
+
Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
+
|
| 6 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 7 |
+
it under the terms of the GNU General Public License as published by
|
| 8 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 9 |
+
(at your option) any later version.
|
| 10 |
+
|
| 11 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 12 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 13 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 14 |
+
GNU General Public License for more details.
|
| 15 |
+
|
| 16 |
+
You should have received a copy of the GNU General Public License
|
| 17 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 18 |
+
*/
|
| 19 |
+
|
| 20 |
+
#ifndef MATERIAL_H_INCLUDED
|
| 21 |
+
#define MATERIAL_H_INCLUDED
|
| 22 |
+
|
| 23 |
+
#include "endgame.h"
|
| 24 |
+
#include "misc.h"
|
| 25 |
+
#include "position.h"
|
| 26 |
+
#include "types.h"
|
| 27 |
+
|
| 28 |
+
namespace Material {
|
| 29 |
+
|
| 30 |
+
/// Material::Entry contains various information about a material configuration.
|
| 31 |
+
/// It contains a material balance evaluation, a function pointer to a special
|
| 32 |
+
/// endgame evaluation function (which in most cases is NULL, meaning that the
|
| 33 |
+
/// standard evaluation function will be used), and "scale factors".
|
| 34 |
+
///
|
| 35 |
+
/// The scale factors are used to scale the evaluation score up or down.
|
| 36 |
+
/// For instance, in KRB vs KR endgames, the score is scaled down by a factor
|
| 37 |
+
/// of 4, which will result in scores of absolute value less than one pawn.
|
| 38 |
+
|
| 39 |
+
struct Entry {
|
| 40 |
+
|
| 41 |
+
Score material_value() const { return make_score(value, value); }
|
| 42 |
+
Score space_weight() const { return spaceWeight; }
|
| 43 |
+
Phase game_phase() const { return gamePhase; }
|
| 44 |
+
bool specialized_eval_exists() const { return evaluationFunction != NULL; }
|
| 45 |
+
Value evaluate(const Position& p) const { return (*evaluationFunction)(p); }
|
| 46 |
+
ScaleFactor scale_factor(const Position& pos, Color c) const;
|
| 47 |
+
|
| 48 |
+
Key key;
|
| 49 |
+
int16_t value;
|
| 50 |
+
uint8_t factor[COLOR_NB];
|
| 51 |
+
EndgameBase<Value>* evaluationFunction;
|
| 52 |
+
EndgameBase<ScaleFactor>* scalingFunction[COLOR_NB];
|
| 53 |
+
Score spaceWeight;
|
| 54 |
+
Phase gamePhase;
|
| 55 |
+
};
|
| 56 |
+
|
| 57 |
+
typedef HashTable<Entry, 8192> Table;
|
| 58 |
+
|
| 59 |
+
Entry* probe(const Position& pos, Table& entries, Endgames& endgames);
|
| 60 |
+
Phase game_phase(const Position& pos);
|
| 61 |
+
|
| 62 |
+
/// Material::scale_factor takes a position and a color as input, and
|
| 63 |
+
/// returns a scale factor for the given color. We have to provide the
|
| 64 |
+
/// position in addition to the color, because the scale factor need not
|
| 65 |
+
/// to be a constant: It can also be a function which should be applied to
|
| 66 |
+
/// the position. For instance, in KBP vs K endgames, a scaling function
|
| 67 |
+
/// which checks for draws with rook pawns and wrong-colored bishops.
|
| 68 |
+
|
| 69 |
+
inline ScaleFactor Entry::scale_factor(const Position& pos, Color c) const {
|
| 70 |
+
|
| 71 |
+
return !scalingFunction[c] || (*scalingFunction[c])(pos) == SCALE_FACTOR_NONE
|
| 72 |
+
? ScaleFactor(factor[c]) : (*scalingFunction[c])(pos);
|
| 73 |
+
}
|
| 74 |
+
|
| 75 |
+
}
|
| 76 |
+
|
| 77 |
+
#endif // #ifndef MATERIAL_H_INCLUDED
|
stockfish-4-win/src/misc.cpp
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
+
Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
+
|
| 6 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 7 |
+
it under the terms of the GNU General Public License as published by
|
| 8 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 9 |
+
(at your option) any later version.
|
| 10 |
+
|
| 11 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 12 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 13 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 14 |
+
GNU General Public License for more details.
|
| 15 |
+
|
| 16 |
+
You should have received a copy of the GNU General Public License
|
| 17 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 18 |
+
*/
|
| 19 |
+
|
| 20 |
+
#include <iomanip>
|
| 21 |
+
#include <iostream>
|
| 22 |
+
#include <sstream>
|
| 23 |
+
|
| 24 |
+
#include "misc.h"
|
| 25 |
+
#include "thread.h"
|
| 26 |
+
|
| 27 |
+
using namespace std;
|
| 28 |
+
|
| 29 |
+
/// Version number. If Version is left empty, then compile date, in the
|
| 30 |
+
/// format DD-MM-YY, is shown in engine_info.
|
| 31 |
+
static const string Version = "4";
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
/// engine_info() returns the full name of the current Stockfish version. This
|
| 35 |
+
/// will be either "Stockfish <Tag> DD-MM-YY" (where DD-MM-YY is the date when
|
| 36 |
+
/// the program was compiled) or "Stockfish <Version>", depending on whether
|
| 37 |
+
/// Version is empty.
|
| 38 |
+
|
| 39 |
+
const string engine_info(bool to_uci) {
|
| 40 |
+
|
| 41 |
+
const string months("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec");
|
| 42 |
+
string month, day, year;
|
| 43 |
+
stringstream s, date(__DATE__); // From compiler, format is "Sep 21 2008"
|
| 44 |
+
|
| 45 |
+
s << "Stockfish " << Version << setfill('0');
|
| 46 |
+
|
| 47 |
+
if (Version.empty())
|
| 48 |
+
{
|
| 49 |
+
date >> month >> day >> year;
|
| 50 |
+
s << setw(2) << day << setw(2) << (1 + months.find(month) / 4) << year.substr(2);
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
s << (Is64Bit ? " 64" : "")
|
| 54 |
+
<< (HasPopCnt ? " SSE4.2" : "")
|
| 55 |
+
<< (to_uci ? "\nid author ": " by ")
|
| 56 |
+
<< "Tord Romstad, Marco Costalba and Joona Kiiski";
|
| 57 |
+
|
| 58 |
+
return s.str();
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
|
| 62 |
+
/// Debug functions used mainly to collect run-time statistics
|
| 63 |
+
|
| 64 |
+
static uint64_t hits[2], means[2];
|
| 65 |
+
|
| 66 |
+
void dbg_hit_on(bool b) { hits[0]++; if (b) hits[1]++; }
|
| 67 |
+
void dbg_hit_on_c(bool c, bool b) { if (c) dbg_hit_on(b); }
|
| 68 |
+
void dbg_mean_of(int v) { means[0]++; means[1] += v; }
|
| 69 |
+
|
| 70 |
+
void dbg_print() {
|
| 71 |
+
|
| 72 |
+
if (hits[0])
|
| 73 |
+
cerr << "Total " << hits[0] << " Hits " << hits[1]
|
| 74 |
+
<< " hit rate (%) " << 100 * hits[1] / hits[0] << endl;
|
| 75 |
+
|
| 76 |
+
if (means[0])
|
| 77 |
+
cerr << "Total " << means[0] << " Mean "
|
| 78 |
+
<< (float)means[1] / means[0] << endl;
|
| 79 |
+
}
|
| 80 |
+
|
| 81 |
+
|
| 82 |
+
/// Our fancy logging facility. The trick here is to replace cin.rdbuf() and
|
| 83 |
+
/// cout.rdbuf() with two Tie objects that tie cin and cout to a file stream. We
|
| 84 |
+
/// can toggle the logging of std::cout and std:cin at runtime while preserving
|
| 85 |
+
/// usual i/o functionality and without changing a single line of code!
|
| 86 |
+
/// Idea from http://groups.google.com/group/comp.lang.c++/msg/1d941c0f26ea0d81
|
| 87 |
+
|
| 88 |
+
struct Tie: public streambuf { // MSVC requires splitted streambuf for cin and cout
|
| 89 |
+
|
| 90 |
+
Tie(streambuf* b, ofstream* f) : buf(b), file(f) {}
|
| 91 |
+
|
| 92 |
+
int sync() { return file->rdbuf()->pubsync(), buf->pubsync(); }
|
| 93 |
+
int overflow(int c) { return log(buf->sputc((char)c), "<< "); }
|
| 94 |
+
int underflow() { return buf->sgetc(); }
|
| 95 |
+
int uflow() { return log(buf->sbumpc(), ">> "); }
|
| 96 |
+
|
| 97 |
+
streambuf* buf;
|
| 98 |
+
ofstream* file;
|
| 99 |
+
|
| 100 |
+
int log(int c, const char* prefix) {
|
| 101 |
+
|
| 102 |
+
static int last = '\n';
|
| 103 |
+
|
| 104 |
+
if (last == '\n')
|
| 105 |
+
file->rdbuf()->sputn(prefix, 3);
|
| 106 |
+
|
| 107 |
+
return last = file->rdbuf()->sputc((char)c);
|
| 108 |
+
}
|
| 109 |
+
};
|
| 110 |
+
|
| 111 |
+
class Logger {
|
| 112 |
+
|
| 113 |
+
Logger() : in(cin.rdbuf(), &file), out(cout.rdbuf(), &file) {}
|
| 114 |
+
~Logger() { start(false); }
|
| 115 |
+
|
| 116 |
+
ofstream file;
|
| 117 |
+
Tie in, out;
|
| 118 |
+
|
| 119 |
+
public:
|
| 120 |
+
static void start(bool b) {
|
| 121 |
+
|
| 122 |
+
static Logger l;
|
| 123 |
+
|
| 124 |
+
if (b && !l.file.is_open())
|
| 125 |
+
{
|
| 126 |
+
l.file.open("io_log.txt", ifstream::out | ifstream::app);
|
| 127 |
+
cin.rdbuf(&l.in);
|
| 128 |
+
cout.rdbuf(&l.out);
|
| 129 |
+
}
|
| 130 |
+
else if (!b && l.file.is_open())
|
| 131 |
+
{
|
| 132 |
+
cout.rdbuf(l.out.buf);
|
| 133 |
+
cin.rdbuf(l.in.buf);
|
| 134 |
+
l.file.close();
|
| 135 |
+
}
|
| 136 |
+
}
|
| 137 |
+
};
|
| 138 |
+
|
| 139 |
+
|
| 140 |
+
/// Used to serialize access to std::cout to avoid multiple threads to write at
|
| 141 |
+
/// the same time.
|
| 142 |
+
|
| 143 |
+
std::ostream& operator<<(std::ostream& os, SyncCout sc) {
|
| 144 |
+
|
| 145 |
+
static Mutex m;
|
| 146 |
+
|
| 147 |
+
if (sc == io_lock)
|
| 148 |
+
m.lock();
|
| 149 |
+
|
| 150 |
+
if (sc == io_unlock)
|
| 151 |
+
m.unlock();
|
| 152 |
+
|
| 153 |
+
return os;
|
| 154 |
+
}
|
| 155 |
+
|
| 156 |
+
|
| 157 |
+
/// Trampoline helper to avoid moving Logger to misc.h
|
| 158 |
+
void start_logger(bool b) { Logger::start(b); }
|
| 159 |
+
|
| 160 |
+
|
| 161 |
+
/// timed_wait() waits for msec milliseconds. It is mainly an helper to wrap
|
| 162 |
+
/// conversion from milliseconds to struct timespec, as used by pthreads.
|
| 163 |
+
|
| 164 |
+
void timed_wait(WaitCondition& sleepCond, Lock& sleepLock, int msec) {
|
| 165 |
+
|
| 166 |
+
#ifdef _WIN32
|
| 167 |
+
int tm = msec;
|
| 168 |
+
#else
|
| 169 |
+
timespec ts, *tm = &ts;
|
| 170 |
+
uint64_t ms = Time::now() + msec;
|
| 171 |
+
|
| 172 |
+
ts.tv_sec = ms / 1000;
|
| 173 |
+
ts.tv_nsec = (ms % 1000) * 1000000LL;
|
| 174 |
+
#endif
|
| 175 |
+
|
| 176 |
+
cond_timedwait(sleepCond, sleepLock, tm);
|
| 177 |
+
}
|
| 178 |
+
|
| 179 |
+
|
| 180 |
+
/// prefetch() preloads the given address in L1/L2 cache. This is a non
|
| 181 |
+
/// blocking function and do not stalls the CPU waiting for data to be
|
| 182 |
+
/// loaded from memory, that can be quite slow.
|
| 183 |
+
#ifdef NO_PREFETCH
|
| 184 |
+
|
| 185 |
+
void prefetch(char*) {}
|
| 186 |
+
|
| 187 |
+
#else
|
| 188 |
+
|
| 189 |
+
void prefetch(char* addr) {
|
| 190 |
+
|
| 191 |
+
# if defined(__INTEL_COMPILER)
|
| 192 |
+
// This hack prevents prefetches to be optimized away by
|
| 193 |
+
// Intel compiler. Both MSVC and gcc seems not affected.
|
| 194 |
+
__asm__ ("");
|
| 195 |
+
# endif
|
| 196 |
+
|
| 197 |
+
# if defined(__INTEL_COMPILER) || defined(_MSC_VER)
|
| 198 |
+
_mm_prefetch(addr, _MM_HINT_T0);
|
| 199 |
+
# else
|
| 200 |
+
__builtin_prefetch(addr);
|
| 201 |
+
# endif
|
| 202 |
+
}
|
| 203 |
+
|
| 204 |
+
#endif
|
stockfish-4-win/src/misc.h
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
+
Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
+
|
| 6 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 7 |
+
it under the terms of the GNU General Public License as published by
|
| 8 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 9 |
+
(at your option) any later version.
|
| 10 |
+
|
| 11 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 12 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 13 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 14 |
+
GNU General Public License for more details.
|
| 15 |
+
|
| 16 |
+
You should have received a copy of the GNU General Public License
|
| 17 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 18 |
+
*/
|
| 19 |
+
|
| 20 |
+
#ifndef MISC_H_INCLUDED
|
| 21 |
+
#define MISC_H_INCLUDED
|
| 22 |
+
|
| 23 |
+
#include <fstream>
|
| 24 |
+
#include <string>
|
| 25 |
+
#include <vector>
|
| 26 |
+
|
| 27 |
+
#include "types.h"
|
| 28 |
+
|
| 29 |
+
extern const std::string engine_info(bool to_uci = false);
|
| 30 |
+
extern void timed_wait(WaitCondition&, Lock&, int);
|
| 31 |
+
extern void prefetch(char* addr);
|
| 32 |
+
extern void start_logger(bool b);
|
| 33 |
+
|
| 34 |
+
extern void dbg_hit_on(bool b);
|
| 35 |
+
extern void dbg_hit_on_c(bool c, bool b);
|
| 36 |
+
extern void dbg_mean_of(int v);
|
| 37 |
+
extern void dbg_print();
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
struct Log : public std::ofstream {
|
| 41 |
+
Log(const std::string& f = "log.txt") : std::ofstream(f.c_str(), std::ios::out | std::ios::app) {}
|
| 42 |
+
~Log() { if (is_open()) close(); }
|
| 43 |
+
};
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
namespace Time {
|
| 47 |
+
typedef int64_t point;
|
| 48 |
+
inline point now() { return system_time_to_msec(); }
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
template<class Entry, int Size>
|
| 53 |
+
struct HashTable {
|
| 54 |
+
HashTable() : e(Size, Entry()) {}
|
| 55 |
+
Entry* operator[](Key k) { return &e[(uint32_t)k & (Size - 1)]; }
|
| 56 |
+
|
| 57 |
+
private:
|
| 58 |
+
std::vector<Entry> e;
|
| 59 |
+
};
|
| 60 |
+
|
| 61 |
+
|
| 62 |
+
enum SyncCout { io_lock, io_unlock };
|
| 63 |
+
std::ostream& operator<<(std::ostream&, SyncCout);
|
| 64 |
+
|
| 65 |
+
#define sync_cout std::cout << io_lock
|
| 66 |
+
#define sync_endl std::endl << io_unlock
|
| 67 |
+
|
| 68 |
+
#endif // #ifndef MISC_H_INCLUDED
|
stockfish-4-win/src/movegen.cpp
ADDED
|
@@ -0,0 +1,423 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
+
Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
+
|
| 6 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 7 |
+
it under the terms of the GNU General Public License as published by
|
| 8 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 9 |
+
(at your option) any later version.
|
| 10 |
+
|
| 11 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 12 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 13 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 14 |
+
GNU General Public License for more details.
|
| 15 |
+
|
| 16 |
+
You should have received a copy of the GNU General Public License
|
| 17 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 18 |
+
*/
|
| 19 |
+
|
| 20 |
+
#include <cassert>
|
| 21 |
+
|
| 22 |
+
#include "movegen.h"
|
| 23 |
+
#include "position.h"
|
| 24 |
+
|
| 25 |
+
/// Simple macro to wrap a very common while loop, no facny, no flexibility,
|
| 26 |
+
/// hardcoded names 'mlist' and 'from'.
|
| 27 |
+
#define SERIALIZE(b) while (b) (mlist++)->move = make_move(from, pop_lsb(&b))
|
| 28 |
+
|
| 29 |
+
/// Version used for pawns, where the 'from' square is given as a delta from the 'to' square
|
| 30 |
+
#define SERIALIZE_PAWNS(b, d) while (b) { Square to = pop_lsb(&b); \
|
| 31 |
+
(mlist++)->move = make_move(to - (d), to); }
|
| 32 |
+
namespace {
|
| 33 |
+
|
| 34 |
+
template<CastlingSide Side, bool Checks, bool Chess960>
|
| 35 |
+
ExtMove* generate_castle(const Position& pos, ExtMove* mlist, Color us) {
|
| 36 |
+
|
| 37 |
+
if (pos.castle_impeded(us, Side) || !pos.can_castle(make_castle_right(us, Side)))
|
| 38 |
+
return mlist;
|
| 39 |
+
|
| 40 |
+
// After castling, the rook and king final positions are the same in Chess960
|
| 41 |
+
// as they would be in standard chess.
|
| 42 |
+
Square kfrom = pos.king_square(us);
|
| 43 |
+
Square rfrom = pos.castle_rook_square(us, Side);
|
| 44 |
+
Square kto = relative_square(us, Side == KING_SIDE ? SQ_G1 : SQ_C1);
|
| 45 |
+
Bitboard enemies = pos.pieces(~us);
|
| 46 |
+
|
| 47 |
+
assert(!pos.checkers());
|
| 48 |
+
|
| 49 |
+
const int K = Chess960 ? kto > kfrom ? -1 : 1
|
| 50 |
+
: Side == KING_SIDE ? -1 : 1;
|
| 51 |
+
|
| 52 |
+
for (Square s = kto; s != kfrom; s += (Square)K)
|
| 53 |
+
if (pos.attackers_to(s) & enemies)
|
| 54 |
+
return mlist;
|
| 55 |
+
|
| 56 |
+
// Because we generate only legal castling moves we need to verify that
|
| 57 |
+
// when moving the castling rook we do not discover some hidden checker.
|
| 58 |
+
// For instance an enemy queen in SQ_A1 when castling rook is in SQ_B1.
|
| 59 |
+
if (Chess960 && (pos.attackers_to(kto, pos.pieces() ^ rfrom) & enemies))
|
| 60 |
+
return mlist;
|
| 61 |
+
|
| 62 |
+
(mlist++)->move = make<CASTLE>(kfrom, rfrom);
|
| 63 |
+
|
| 64 |
+
if (Checks && !pos.move_gives_check((mlist - 1)->move, CheckInfo(pos)))
|
| 65 |
+
mlist--;
|
| 66 |
+
|
| 67 |
+
return mlist;
|
| 68 |
+
}
|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
template<GenType Type, Square Delta>
|
| 72 |
+
inline ExtMove* generate_promotions(ExtMove* mlist, Bitboard pawnsOn7,
|
| 73 |
+
Bitboard target, const CheckInfo* ci) {
|
| 74 |
+
|
| 75 |
+
Bitboard b = shift_bb<Delta>(pawnsOn7) & target;
|
| 76 |
+
|
| 77 |
+
while (b)
|
| 78 |
+
{
|
| 79 |
+
Square to = pop_lsb(&b);
|
| 80 |
+
|
| 81 |
+
if (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS)
|
| 82 |
+
(mlist++)->move = make<PROMOTION>(to - Delta, to, QUEEN);
|
| 83 |
+
|
| 84 |
+
if (Type == QUIETS || Type == EVASIONS || Type == NON_EVASIONS)
|
| 85 |
+
{
|
| 86 |
+
(mlist++)->move = make<PROMOTION>(to - Delta, to, ROOK);
|
| 87 |
+
(mlist++)->move = make<PROMOTION>(to - Delta, to, BISHOP);
|
| 88 |
+
(mlist++)->move = make<PROMOTION>(to - Delta, to, KNIGHT);
|
| 89 |
+
}
|
| 90 |
+
|
| 91 |
+
// Knight-promotion is the only one that can give a direct check not
|
| 92 |
+
// already included in the queen-promotion.
|
| 93 |
+
if (Type == QUIET_CHECKS && (StepAttacksBB[W_KNIGHT][to] & ci->ksq))
|
| 94 |
+
(mlist++)->move = make<PROMOTION>(to - Delta, to, KNIGHT);
|
| 95 |
+
else
|
| 96 |
+
(void)ci; // Silence a warning under MSVC
|
| 97 |
+
}
|
| 98 |
+
|
| 99 |
+
return mlist;
|
| 100 |
+
}
|
| 101 |
+
|
| 102 |
+
|
| 103 |
+
template<Color Us, GenType Type>
|
| 104 |
+
ExtMove* generate_pawn_moves(const Position& pos, ExtMove* mlist,
|
| 105 |
+
Bitboard target, const CheckInfo* ci) {
|
| 106 |
+
|
| 107 |
+
// Compute our parametrized parameters at compile time, named according to
|
| 108 |
+
// the point of view of white side.
|
| 109 |
+
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
| 110 |
+
const Bitboard TRank8BB = (Us == WHITE ? Rank8BB : Rank1BB);
|
| 111 |
+
const Bitboard TRank7BB = (Us == WHITE ? Rank7BB : Rank2BB);
|
| 112 |
+
const Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB);
|
| 113 |
+
const Square Up = (Us == WHITE ? DELTA_N : DELTA_S);
|
| 114 |
+
const Square Right = (Us == WHITE ? DELTA_NE : DELTA_SW);
|
| 115 |
+
const Square Left = (Us == WHITE ? DELTA_NW : DELTA_SE);
|
| 116 |
+
|
| 117 |
+
Bitboard b1, b2, dc1, dc2, emptySquares;
|
| 118 |
+
|
| 119 |
+
Bitboard pawnsOn7 = pos.pieces(Us, PAWN) & TRank7BB;
|
| 120 |
+
Bitboard pawnsNotOn7 = pos.pieces(Us, PAWN) & ~TRank7BB;
|
| 121 |
+
|
| 122 |
+
Bitboard enemies = (Type == EVASIONS ? pos.pieces(Them) & target:
|
| 123 |
+
Type == CAPTURES ? target : pos.pieces(Them));
|
| 124 |
+
|
| 125 |
+
// Single and double pawn pushes, no promotions
|
| 126 |
+
if (Type != CAPTURES)
|
| 127 |
+
{
|
| 128 |
+
emptySquares = (Type == QUIETS || Type == QUIET_CHECKS ? target : ~pos.pieces());
|
| 129 |
+
|
| 130 |
+
b1 = shift_bb<Up>(pawnsNotOn7) & emptySquares;
|
| 131 |
+
b2 = shift_bb<Up>(b1 & TRank3BB) & emptySquares;
|
| 132 |
+
|
| 133 |
+
if (Type == EVASIONS) // Consider only blocking squares
|
| 134 |
+
{
|
| 135 |
+
b1 &= target;
|
| 136 |
+
b2 &= target;
|
| 137 |
+
}
|
| 138 |
+
|
| 139 |
+
if (Type == QUIET_CHECKS)
|
| 140 |
+
{
|
| 141 |
+
b1 &= pos.attacks_from<PAWN>(ci->ksq, Them);
|
| 142 |
+
b2 &= pos.attacks_from<PAWN>(ci->ksq, Them);
|
| 143 |
+
|
| 144 |
+
// Add pawn pushes which give discovered check. This is possible only
|
| 145 |
+
// if the pawn is not on the same file as the enemy king, because we
|
| 146 |
+
// don't generate captures. Note that a possible discovery check
|
| 147 |
+
// promotion has been already generated among captures.
|
| 148 |
+
if (pawnsNotOn7 & ci->dcCandidates)
|
| 149 |
+
{
|
| 150 |
+
dc1 = shift_bb<Up>(pawnsNotOn7 & ci->dcCandidates) & emptySquares & ~file_bb(ci->ksq);
|
| 151 |
+
dc2 = shift_bb<Up>(dc1 & TRank3BB) & emptySquares;
|
| 152 |
+
|
| 153 |
+
b1 |= dc1;
|
| 154 |
+
b2 |= dc2;
|
| 155 |
+
}
|
| 156 |
+
}
|
| 157 |
+
|
| 158 |
+
SERIALIZE_PAWNS(b1, Up);
|
| 159 |
+
SERIALIZE_PAWNS(b2, Up + Up);
|
| 160 |
+
}
|
| 161 |
+
|
| 162 |
+
// Promotions and underpromotions
|
| 163 |
+
if (pawnsOn7 && (Type != EVASIONS || (target & TRank8BB)))
|
| 164 |
+
{
|
| 165 |
+
if (Type == CAPTURES)
|
| 166 |
+
emptySquares = ~pos.pieces();
|
| 167 |
+
|
| 168 |
+
if (Type == EVASIONS)
|
| 169 |
+
emptySquares &= target;
|
| 170 |
+
|
| 171 |
+
mlist = generate_promotions<Type, Right>(mlist, pawnsOn7, enemies, ci);
|
| 172 |
+
mlist = generate_promotions<Type, Left >(mlist, pawnsOn7, enemies, ci);
|
| 173 |
+
mlist = generate_promotions<Type, Up>(mlist, pawnsOn7, emptySquares, ci);
|
| 174 |
+
}
|
| 175 |
+
|
| 176 |
+
// Standard and en-passant captures
|
| 177 |
+
if (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS)
|
| 178 |
+
{
|
| 179 |
+
b1 = shift_bb<Right>(pawnsNotOn7) & enemies;
|
| 180 |
+
b2 = shift_bb<Left >(pawnsNotOn7) & enemies;
|
| 181 |
+
|
| 182 |
+
SERIALIZE_PAWNS(b1, Right);
|
| 183 |
+
SERIALIZE_PAWNS(b2, Left);
|
| 184 |
+
|
| 185 |
+
if (pos.ep_square() != SQ_NONE)
|
| 186 |
+
{
|
| 187 |
+
assert(rank_of(pos.ep_square()) == relative_rank(Us, RANK_6));
|
| 188 |
+
|
| 189 |
+
// An en passant capture can be an evasion only if the checking piece
|
| 190 |
+
// is the double pushed pawn and so is in the target. Otherwise this
|
| 191 |
+
// is a discovery check and we are forced to do otherwise.
|
| 192 |
+
if (Type == EVASIONS && !(target & (pos.ep_square() - Up)))
|
| 193 |
+
return mlist;
|
| 194 |
+
|
| 195 |
+
b1 = pawnsNotOn7 & pos.attacks_from<PAWN>(pos.ep_square(), Them);
|
| 196 |
+
|
| 197 |
+
assert(b1);
|
| 198 |
+
|
| 199 |
+
while (b1)
|
| 200 |
+
(mlist++)->move = make<ENPASSANT>(pop_lsb(&b1), pos.ep_square());
|
| 201 |
+
}
|
| 202 |
+
}
|
| 203 |
+
|
| 204 |
+
return mlist;
|
| 205 |
+
}
|
| 206 |
+
|
| 207 |
+
|
| 208 |
+
template<PieceType Pt, bool Checks> FORCE_INLINE
|
| 209 |
+
ExtMove* generate_moves(const Position& pos, ExtMove* mlist, Color us,
|
| 210 |
+
Bitboard target, const CheckInfo* ci) {
|
| 211 |
+
|
| 212 |
+
assert(Pt != KING && Pt != PAWN);
|
| 213 |
+
|
| 214 |
+
const Square* pl = pos.list<Pt>(us);
|
| 215 |
+
|
| 216 |
+
for (Square from = *pl; from != SQ_NONE; from = *++pl)
|
| 217 |
+
{
|
| 218 |
+
if (Checks)
|
| 219 |
+
{
|
| 220 |
+
if ( (Pt == BISHOP || Pt == ROOK || Pt == QUEEN)
|
| 221 |
+
&& !(PseudoAttacks[Pt][from] & target & ci->checkSq[Pt]))
|
| 222 |
+
continue;
|
| 223 |
+
|
| 224 |
+
if (unlikely(ci->dcCandidates) && (ci->dcCandidates & from))
|
| 225 |
+
continue;
|
| 226 |
+
}
|
| 227 |
+
|
| 228 |
+
Bitboard b = pos.attacks_from<Pt>(from) & target;
|
| 229 |
+
|
| 230 |
+
if (Checks)
|
| 231 |
+
b &= ci->checkSq[Pt];
|
| 232 |
+
|
| 233 |
+
SERIALIZE(b);
|
| 234 |
+
}
|
| 235 |
+
|
| 236 |
+
return mlist;
|
| 237 |
+
}
|
| 238 |
+
|
| 239 |
+
|
| 240 |
+
template<Color Us, GenType Type> FORCE_INLINE
|
| 241 |
+
ExtMove* generate_all(const Position& pos, ExtMove* mlist, Bitboard target,
|
| 242 |
+
const CheckInfo* ci = NULL) {
|
| 243 |
+
|
| 244 |
+
const bool Checks = Type == QUIET_CHECKS;
|
| 245 |
+
|
| 246 |
+
mlist = generate_pawn_moves<Us, Type>(pos, mlist, target, ci);
|
| 247 |
+
mlist = generate_moves<KNIGHT, Checks>(pos, mlist, Us, target, ci);
|
| 248 |
+
mlist = generate_moves<BISHOP, Checks>(pos, mlist, Us, target, ci);
|
| 249 |
+
mlist = generate_moves< ROOK, Checks>(pos, mlist, Us, target, ci);
|
| 250 |
+
mlist = generate_moves< QUEEN, Checks>(pos, mlist, Us, target, ci);
|
| 251 |
+
|
| 252 |
+
if (Type != QUIET_CHECKS && Type != EVASIONS)
|
| 253 |
+
{
|
| 254 |
+
Square from = pos.king_square(Us);
|
| 255 |
+
Bitboard b = pos.attacks_from<KING>(from) & target;
|
| 256 |
+
SERIALIZE(b);
|
| 257 |
+
}
|
| 258 |
+
|
| 259 |
+
if (Type != CAPTURES && Type != EVASIONS && pos.can_castle(Us))
|
| 260 |
+
{
|
| 261 |
+
if (pos.is_chess960())
|
| 262 |
+
{
|
| 263 |
+
mlist = generate_castle< KING_SIDE, Checks, true>(pos, mlist, Us);
|
| 264 |
+
mlist = generate_castle<QUEEN_SIDE, Checks, true>(pos, mlist, Us);
|
| 265 |
+
}
|
| 266 |
+
else
|
| 267 |
+
{
|
| 268 |
+
mlist = generate_castle< KING_SIDE, Checks, false>(pos, mlist, Us);
|
| 269 |
+
mlist = generate_castle<QUEEN_SIDE, Checks, false>(pos, mlist, Us);
|
| 270 |
+
}
|
| 271 |
+
}
|
| 272 |
+
|
| 273 |
+
return mlist;
|
| 274 |
+
}
|
| 275 |
+
|
| 276 |
+
|
| 277 |
+
} // namespace
|
| 278 |
+
|
| 279 |
+
|
| 280 |
+
/// generate<CAPTURES> generates all pseudo-legal captures and queen
|
| 281 |
+
/// promotions. Returns a pointer to the end of the move list.
|
| 282 |
+
///
|
| 283 |
+
/// generate<QUIETS> generates all pseudo-legal non-captures and
|
| 284 |
+
/// underpromotions. Returns a pointer to the end of the move list.
|
| 285 |
+
///
|
| 286 |
+
/// generate<NON_EVASIONS> generates all pseudo-legal captures and
|
| 287 |
+
/// non-captures. Returns a pointer to the end of the move list.
|
| 288 |
+
|
| 289 |
+
template<GenType Type>
|
| 290 |
+
ExtMove* generate(const Position& pos, ExtMove* mlist) {
|
| 291 |
+
|
| 292 |
+
assert(Type == CAPTURES || Type == QUIETS || Type == NON_EVASIONS);
|
| 293 |
+
assert(!pos.checkers());
|
| 294 |
+
|
| 295 |
+
Color us = pos.side_to_move();
|
| 296 |
+
|
| 297 |
+
Bitboard target = Type == CAPTURES ? pos.pieces(~us)
|
| 298 |
+
: Type == QUIETS ? ~pos.pieces()
|
| 299 |
+
: Type == NON_EVASIONS ? ~pos.pieces(us) : 0;
|
| 300 |
+
|
| 301 |
+
return us == WHITE ? generate_all<WHITE, Type>(pos, mlist, target)
|
| 302 |
+
: generate_all<BLACK, Type>(pos, mlist, target);
|
| 303 |
+
}
|
| 304 |
+
|
| 305 |
+
// Explicit template instantiations
|
| 306 |
+
template ExtMove* generate<CAPTURES>(const Position&, ExtMove*);
|
| 307 |
+
template ExtMove* generate<QUIETS>(const Position&, ExtMove*);
|
| 308 |
+
template ExtMove* generate<NON_EVASIONS>(const Position&, ExtMove*);
|
| 309 |
+
|
| 310 |
+
|
| 311 |
+
/// generate<QUIET_CHECKS> generates all pseudo-legal non-captures and knight
|
| 312 |
+
/// underpromotions that give check. Returns a pointer to the end of the move list.
|
| 313 |
+
template<>
|
| 314 |
+
ExtMove* generate<QUIET_CHECKS>(const Position& pos, ExtMove* mlist) {
|
| 315 |
+
|
| 316 |
+
assert(!pos.checkers());
|
| 317 |
+
|
| 318 |
+
Color us = pos.side_to_move();
|
| 319 |
+
CheckInfo ci(pos);
|
| 320 |
+
Bitboard dc = ci.dcCandidates;
|
| 321 |
+
|
| 322 |
+
while (dc)
|
| 323 |
+
{
|
| 324 |
+
Square from = pop_lsb(&dc);
|
| 325 |
+
PieceType pt = type_of(pos.piece_on(from));
|
| 326 |
+
|
| 327 |
+
if (pt == PAWN)
|
| 328 |
+
continue; // Will be generated togheter with direct checks
|
| 329 |
+
|
| 330 |
+
Bitboard b = pos.attacks_from(Piece(pt), from) & ~pos.pieces();
|
| 331 |
+
|
| 332 |
+
if (pt == KING)
|
| 333 |
+
b &= ~PseudoAttacks[QUEEN][ci.ksq];
|
| 334 |
+
|
| 335 |
+
SERIALIZE(b);
|
| 336 |
+
}
|
| 337 |
+
|
| 338 |
+
return us == WHITE ? generate_all<WHITE, QUIET_CHECKS>(pos, mlist, ~pos.pieces(), &ci)
|
| 339 |
+
: generate_all<BLACK, QUIET_CHECKS>(pos, mlist, ~pos.pieces(), &ci);
|
| 340 |
+
}
|
| 341 |
+
|
| 342 |
+
|
| 343 |
+
/// generate<EVASIONS> generates all pseudo-legal check evasions when the side
|
| 344 |
+
/// to move is in check. Returns a pointer to the end of the move list.
|
| 345 |
+
template<>
|
| 346 |
+
ExtMove* generate<EVASIONS>(const Position& pos, ExtMove* mlist) {
|
| 347 |
+
|
| 348 |
+
assert(pos.checkers());
|
| 349 |
+
|
| 350 |
+
int checkersCnt = 0;
|
| 351 |
+
Color us = pos.side_to_move();
|
| 352 |
+
Square ksq = pos.king_square(us), from = ksq /* For SERIALIZE */, checksq;
|
| 353 |
+
Bitboard sliderAttacks = 0;
|
| 354 |
+
Bitboard b = pos.checkers();
|
| 355 |
+
|
| 356 |
+
assert(pos.checkers());
|
| 357 |
+
|
| 358 |
+
// Find squares attacked by slider checkers, we will remove them from the king
|
| 359 |
+
// evasions so to skip known illegal moves avoiding useless legality check later.
|
| 360 |
+
do
|
| 361 |
+
{
|
| 362 |
+
checkersCnt++;
|
| 363 |
+
checksq = pop_lsb(&b);
|
| 364 |
+
|
| 365 |
+
assert(color_of(pos.piece_on(checksq)) == ~us);
|
| 366 |
+
|
| 367 |
+
switch (type_of(pos.piece_on(checksq)))
|
| 368 |
+
{
|
| 369 |
+
case BISHOP: sliderAttacks |= PseudoAttacks[BISHOP][checksq]; break;
|
| 370 |
+
case ROOK: sliderAttacks |= PseudoAttacks[ROOK][checksq]; break;
|
| 371 |
+
case QUEEN:
|
| 372 |
+
// If queen and king are far or not on a diagonal line we can safely
|
| 373 |
+
// remove all the squares attacked in the other direction becuase are
|
| 374 |
+
// not reachable by the king anyway.
|
| 375 |
+
if (between_bb(ksq, checksq) || !(PseudoAttacks[BISHOP][checksq] & ksq))
|
| 376 |
+
sliderAttacks |= PseudoAttacks[QUEEN][checksq];
|
| 377 |
+
|
| 378 |
+
// Otherwise we need to use real rook attacks to check if king is safe
|
| 379 |
+
// to move in the other direction. For example: king in B2, queen in A1
|
| 380 |
+
// a knight in B1, and we can safely move to C1.
|
| 381 |
+
else
|
| 382 |
+
sliderAttacks |= PseudoAttacks[BISHOP][checksq] | pos.attacks_from<ROOK>(checksq);
|
| 383 |
+
|
| 384 |
+
default:
|
| 385 |
+
break;
|
| 386 |
+
}
|
| 387 |
+
} while (b);
|
| 388 |
+
|
| 389 |
+
// Generate evasions for king, capture and non capture moves
|
| 390 |
+
b = pos.attacks_from<KING>(ksq) & ~pos.pieces(us) & ~sliderAttacks;
|
| 391 |
+
SERIALIZE(b);
|
| 392 |
+
|
| 393 |
+
if (checkersCnt > 1)
|
| 394 |
+
return mlist; // Double check, only a king move can save the day
|
| 395 |
+
|
| 396 |
+
// Generate blocking evasions or captures of the checking piece
|
| 397 |
+
Bitboard target = between_bb(checksq, ksq) | checksq;
|
| 398 |
+
|
| 399 |
+
return us == WHITE ? generate_all<WHITE, EVASIONS>(pos, mlist, target)
|
| 400 |
+
: generate_all<BLACK, EVASIONS>(pos, mlist, target);
|
| 401 |
+
}
|
| 402 |
+
|
| 403 |
+
|
| 404 |
+
/// generate<LEGAL> generates all the legal moves in the given position
|
| 405 |
+
|
| 406 |
+
template<>
|
| 407 |
+
ExtMove* generate<LEGAL>(const Position& pos, ExtMove* mlist) {
|
| 408 |
+
|
| 409 |
+
ExtMove *end, *cur = mlist;
|
| 410 |
+
Bitboard pinned = pos.pinned_pieces();
|
| 411 |
+
Square ksq = pos.king_square(pos.side_to_move());
|
| 412 |
+
|
| 413 |
+
end = pos.checkers() ? generate<EVASIONS>(pos, mlist)
|
| 414 |
+
: generate<NON_EVASIONS>(pos, mlist);
|
| 415 |
+
while (cur != end)
|
| 416 |
+
if ( (pinned || from_sq(cur->move) == ksq || type_of(cur->move) == ENPASSANT)
|
| 417 |
+
&& !pos.pl_move_is_legal(cur->move, pinned))
|
| 418 |
+
cur->move = (--end)->move;
|
| 419 |
+
else
|
| 420 |
+
cur++;
|
| 421 |
+
|
| 422 |
+
return end;
|
| 423 |
+
}
|
stockfish-4-win/src/movegen.h
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
+
Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
+
|
| 6 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 7 |
+
it under the terms of the GNU General Public License as published by
|
| 8 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 9 |
+
(at your option) any later version.
|
| 10 |
+
|
| 11 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 12 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 13 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 14 |
+
GNU General Public License for more details.
|
| 15 |
+
|
| 16 |
+
You should have received a copy of the GNU General Public License
|
| 17 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 18 |
+
*/
|
| 19 |
+
|
| 20 |
+
#ifndef MOVEGEN_H_INCLUDED
|
| 21 |
+
#define MOVEGEN_H_INCLUDED
|
| 22 |
+
|
| 23 |
+
#include "types.h"
|
| 24 |
+
|
| 25 |
+
enum GenType {
|
| 26 |
+
CAPTURES,
|
| 27 |
+
QUIETS,
|
| 28 |
+
QUIET_CHECKS,
|
| 29 |
+
EVASIONS,
|
| 30 |
+
NON_EVASIONS,
|
| 31 |
+
LEGAL
|
| 32 |
+
};
|
| 33 |
+
|
| 34 |
+
class Position;
|
| 35 |
+
|
| 36 |
+
template<GenType>
|
| 37 |
+
ExtMove* generate(const Position& pos, ExtMove* mlist);
|
| 38 |
+
|
| 39 |
+
/// The MoveList struct is a simple wrapper around generate(), sometimes comes
|
| 40 |
+
/// handy to use this class instead of the low level generate() function.
|
| 41 |
+
template<GenType T>
|
| 42 |
+
struct MoveList {
|
| 43 |
+
|
| 44 |
+
explicit MoveList(const Position& pos) : cur(mlist), last(generate<T>(pos, mlist)) { last->move = MOVE_NONE; }
|
| 45 |
+
void operator++() { cur++; }
|
| 46 |
+
Move operator*() const { return cur->move; }
|
| 47 |
+
size_t size() const { return last - mlist; }
|
| 48 |
+
bool contains(Move m) const {
|
| 49 |
+
for (const ExtMove* it(mlist); it != last; ++it) if (it->move == m) return true;
|
| 50 |
+
return false;
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
private:
|
| 54 |
+
ExtMove mlist[MAX_MOVES];
|
| 55 |
+
ExtMove *cur, *last;
|
| 56 |
+
};
|
| 57 |
+
|
| 58 |
+
#endif // #ifndef MOVEGEN_H_INCLUDED
|
stockfish-4-win/src/movepick.cpp
ADDED
|
@@ -0,0 +1,377 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
+
Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
+
|
| 6 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 7 |
+
it under the terms of the GNU General Public License as published by
|
| 8 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 9 |
+
(at your option) any later version.
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 13 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 15 |
+
GNU General Public License for more details.
|
| 16 |
+
|
| 17 |
+
You should have received a copy of the GNU General Public License
|
| 18 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 19 |
+
*/
|
| 20 |
+
|
| 21 |
+
#include <cassert>
|
| 22 |
+
|
| 23 |
+
#include "movepick.h"
|
| 24 |
+
#include "thread.h"
|
| 25 |
+
|
| 26 |
+
namespace {
|
| 27 |
+
|
| 28 |
+
enum Stages {
|
| 29 |
+
MAIN_SEARCH, CAPTURES_S1, KILLERS_S1, QUIETS_1_S1, QUIETS_2_S1, BAD_CAPTURES_S1,
|
| 30 |
+
EVASION, EVASIONS_S2,
|
| 31 |
+
QSEARCH_0, CAPTURES_S3, QUIET_CHECKS_S3,
|
| 32 |
+
QSEARCH_1, CAPTURES_S4,
|
| 33 |
+
PROBCUT, CAPTURES_S5,
|
| 34 |
+
RECAPTURE, CAPTURES_S6,
|
| 35 |
+
STOP
|
| 36 |
+
};
|
| 37 |
+
|
| 38 |
+
// Our insertion sort, guaranteed to be stable, as is needed
|
| 39 |
+
void insertion_sort(ExtMove* begin, ExtMove* end)
|
| 40 |
+
{
|
| 41 |
+
ExtMove tmp, *p, *q;
|
| 42 |
+
|
| 43 |
+
for (p = begin + 1; p < end; ++p)
|
| 44 |
+
{
|
| 45 |
+
tmp = *p;
|
| 46 |
+
for (q = p; q != begin && *(q-1) < tmp; --q)
|
| 47 |
+
*q = *(q-1);
|
| 48 |
+
*q = tmp;
|
| 49 |
+
}
|
| 50 |
+
}
|
| 51 |
+
|
| 52 |
+
// Unary predicate used by std::partition to split positive scores from remaining
|
| 53 |
+
// ones so to sort separately the two sets, and with the second sort delayed.
|
| 54 |
+
inline bool has_positive_score(const ExtMove& ms) { return ms.score > 0; }
|
| 55 |
+
|
| 56 |
+
// Picks and moves to the front the best move in the range [begin, end),
|
| 57 |
+
// it is faster than sorting all the moves in advance when moves are few, as
|
| 58 |
+
// normally are the possible captures.
|
| 59 |
+
inline ExtMove* pick_best(ExtMove* begin, ExtMove* end)
|
| 60 |
+
{
|
| 61 |
+
std::swap(*begin, *std::max_element(begin, end));
|
| 62 |
+
return begin;
|
| 63 |
+
}
|
| 64 |
+
}
|
| 65 |
+
|
| 66 |
+
|
| 67 |
+
/// Constructors of the MovePicker class. As arguments we pass information
|
| 68 |
+
/// to help it to return the presumably good moves first, to decide which
|
| 69 |
+
/// moves to return (in the quiescence search, for instance, we only want to
|
| 70 |
+
/// search captures, promotions and some checks) and about how important good
|
| 71 |
+
/// move ordering is at the current node.
|
| 72 |
+
|
| 73 |
+
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const HistoryStats& h,
|
| 74 |
+
Move* cm, Search::Stack* s) : pos(p), history(h), depth(d) {
|
| 75 |
+
|
| 76 |
+
assert(d > DEPTH_ZERO);
|
| 77 |
+
|
| 78 |
+
cur = end = moves;
|
| 79 |
+
endBadCaptures = moves + MAX_MOVES - 1;
|
| 80 |
+
countermoves = cm;
|
| 81 |
+
ss = s;
|
| 82 |
+
|
| 83 |
+
if (p.checkers())
|
| 84 |
+
stage = EVASION;
|
| 85 |
+
|
| 86 |
+
else
|
| 87 |
+
stage = MAIN_SEARCH;
|
| 88 |
+
|
| 89 |
+
ttMove = (ttm && pos.is_pseudo_legal(ttm) ? ttm : MOVE_NONE);
|
| 90 |
+
end += (ttMove != MOVE_NONE);
|
| 91 |
+
}
|
| 92 |
+
|
| 93 |
+
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const HistoryStats& h,
|
| 94 |
+
Square sq) : pos(p), history(h), cur(moves), end(moves) {
|
| 95 |
+
|
| 96 |
+
assert(d <= DEPTH_ZERO);
|
| 97 |
+
|
| 98 |
+
if (p.checkers())
|
| 99 |
+
stage = EVASION;
|
| 100 |
+
|
| 101 |
+
else if (d > DEPTH_QS_NO_CHECKS)
|
| 102 |
+
stage = QSEARCH_0;
|
| 103 |
+
|
| 104 |
+
else if (d > DEPTH_QS_RECAPTURES)
|
| 105 |
+
{
|
| 106 |
+
stage = QSEARCH_1;
|
| 107 |
+
|
| 108 |
+
// Skip TT move if is not a capture or a promotion, this avoids qsearch
|
| 109 |
+
// tree explosion due to a possible perpetual check or similar rare cases
|
| 110 |
+
// when TT table is full.
|
| 111 |
+
if (ttm && !pos.is_capture_or_promotion(ttm))
|
| 112 |
+
ttm = MOVE_NONE;
|
| 113 |
+
}
|
| 114 |
+
else
|
| 115 |
+
{
|
| 116 |
+
stage = RECAPTURE;
|
| 117 |
+
recaptureSquare = sq;
|
| 118 |
+
ttm = MOVE_NONE;
|
| 119 |
+
}
|
| 120 |
+
|
| 121 |
+
ttMove = (ttm && pos.is_pseudo_legal(ttm) ? ttm : MOVE_NONE);
|
| 122 |
+
end += (ttMove != MOVE_NONE);
|
| 123 |
+
}
|
| 124 |
+
|
| 125 |
+
MovePicker::MovePicker(const Position& p, Move ttm, const HistoryStats& h, PieceType pt)
|
| 126 |
+
: pos(p), history(h), cur(moves), end(moves) {
|
| 127 |
+
|
| 128 |
+
assert(!pos.checkers());
|
| 129 |
+
|
| 130 |
+
stage = PROBCUT;
|
| 131 |
+
|
| 132 |
+
// In ProbCut we generate only captures better than parent's captured piece
|
| 133 |
+
captureThreshold = PieceValue[MG][pt];
|
| 134 |
+
ttMove = (ttm && pos.is_pseudo_legal(ttm) ? ttm : MOVE_NONE);
|
| 135 |
+
|
| 136 |
+
if (ttMove && (!pos.is_capture(ttMove) || pos.see(ttMove) <= captureThreshold))
|
| 137 |
+
ttMove = MOVE_NONE;
|
| 138 |
+
|
| 139 |
+
end += (ttMove != MOVE_NONE);
|
| 140 |
+
}
|
| 141 |
+
|
| 142 |
+
|
| 143 |
+
/// score() assign a numerical move ordering score to each move in a move list.
|
| 144 |
+
/// The moves with highest scores will be picked first.
|
| 145 |
+
template<>
|
| 146 |
+
void MovePicker::score<CAPTURES>() {
|
| 147 |
+
// Winning and equal captures in the main search are ordered by MVV/LVA.
|
| 148 |
+
// Suprisingly, this appears to perform slightly better than SEE based
|
| 149 |
+
// move ordering. The reason is probably that in a position with a winning
|
| 150 |
+
// capture, capturing a more valuable (but sufficiently defended) piece
|
| 151 |
+
// first usually doesn't hurt. The opponent will have to recapture, and
|
| 152 |
+
// the hanging piece will still be hanging (except in the unusual cases
|
| 153 |
+
// where it is possible to recapture with the hanging piece). Exchanging
|
| 154 |
+
// big pieces before capturing a hanging piece probably helps to reduce
|
| 155 |
+
// the subtree size.
|
| 156 |
+
// In main search we want to push captures with negative SEE values to
|
| 157 |
+
// badCaptures[] array, but instead of doing it now we delay till when
|
| 158 |
+
// the move has been picked up in pick_move_from_list(), this way we save
|
| 159 |
+
// some SEE calls in case we get a cutoff (idea from Pablo Vazquez).
|
| 160 |
+
Move m;
|
| 161 |
+
|
| 162 |
+
for (ExtMove* it = moves; it != end; ++it)
|
| 163 |
+
{
|
| 164 |
+
m = it->move;
|
| 165 |
+
it->score = PieceValue[MG][pos.piece_on(to_sq(m))]
|
| 166 |
+
- type_of(pos.piece_moved(m));
|
| 167 |
+
|
| 168 |
+
if (type_of(m) == PROMOTION)
|
| 169 |
+
it->score += PieceValue[MG][promotion_type(m)] - PieceValue[MG][PAWN];
|
| 170 |
+
|
| 171 |
+
else if (type_of(m) == ENPASSANT)
|
| 172 |
+
it->score += PieceValue[MG][PAWN];
|
| 173 |
+
}
|
| 174 |
+
}
|
| 175 |
+
|
| 176 |
+
template<>
|
| 177 |
+
void MovePicker::score<QUIETS>() {
|
| 178 |
+
|
| 179 |
+
Move m;
|
| 180 |
+
|
| 181 |
+
for (ExtMove* it = moves; it != end; ++it)
|
| 182 |
+
{
|
| 183 |
+
m = it->move;
|
| 184 |
+
it->score = history[pos.piece_moved(m)][to_sq(m)];
|
| 185 |
+
}
|
| 186 |
+
}
|
| 187 |
+
|
| 188 |
+
template<>
|
| 189 |
+
void MovePicker::score<EVASIONS>() {
|
| 190 |
+
// Try good captures ordered by MVV/LVA, then non-captures if destination square
|
| 191 |
+
// is not under attack, ordered by history value, then bad-captures and quiet
|
| 192 |
+
// moves with a negative SEE. This last group is ordered by the SEE score.
|
| 193 |
+
Move m;
|
| 194 |
+
int seeScore;
|
| 195 |
+
|
| 196 |
+
for (ExtMove* it = moves; it != end; ++it)
|
| 197 |
+
{
|
| 198 |
+
m = it->move;
|
| 199 |
+
if ((seeScore = pos.see_sign(m)) < 0)
|
| 200 |
+
it->score = seeScore - HistoryStats::Max; // At the bottom
|
| 201 |
+
|
| 202 |
+
else if (pos.is_capture(m))
|
| 203 |
+
it->score = PieceValue[MG][pos.piece_on(to_sq(m))]
|
| 204 |
+
- type_of(pos.piece_moved(m)) + HistoryStats::Max;
|
| 205 |
+
else
|
| 206 |
+
it->score = history[pos.piece_moved(m)][to_sq(m)];
|
| 207 |
+
}
|
| 208 |
+
}
|
| 209 |
+
|
| 210 |
+
|
| 211 |
+
/// generate_next() generates, scores and sorts the next bunch of moves, when
|
| 212 |
+
/// there are no more moves to try for the current phase.
|
| 213 |
+
|
| 214 |
+
void MovePicker::generate_next() {
|
| 215 |
+
|
| 216 |
+
cur = moves;
|
| 217 |
+
|
| 218 |
+
switch (++stage) {
|
| 219 |
+
|
| 220 |
+
case CAPTURES_S1: case CAPTURES_S3: case CAPTURES_S4: case CAPTURES_S5: case CAPTURES_S6:
|
| 221 |
+
end = generate<CAPTURES>(pos, moves);
|
| 222 |
+
score<CAPTURES>();
|
| 223 |
+
return;
|
| 224 |
+
|
| 225 |
+
case KILLERS_S1:
|
| 226 |
+
cur = killers;
|
| 227 |
+
end = cur + 2;
|
| 228 |
+
|
| 229 |
+
killers[0].move = ss->killers[0];
|
| 230 |
+
killers[1].move = ss->killers[1];
|
| 231 |
+
killers[2].move = killers[3].move = MOVE_NONE;
|
| 232 |
+
|
| 233 |
+
// Be sure countermoves are different from killers
|
| 234 |
+
for (int i = 0; i < 2; i++)
|
| 235 |
+
if (countermoves[i] != cur->move && countermoves[i] != (cur+1)->move)
|
| 236 |
+
(end++)->move = countermoves[i];
|
| 237 |
+
|
| 238 |
+
if (countermoves[1] && countermoves[1] == countermoves[0]) // Due to SMP races
|
| 239 |
+
killers[3].move = MOVE_NONE;
|
| 240 |
+
|
| 241 |
+
return;
|
| 242 |
+
|
| 243 |
+
case QUIETS_1_S1:
|
| 244 |
+
endQuiets = end = generate<QUIETS>(pos, moves);
|
| 245 |
+
score<QUIETS>();
|
| 246 |
+
end = std::partition(cur, end, has_positive_score);
|
| 247 |
+
insertion_sort(cur, end);
|
| 248 |
+
return;
|
| 249 |
+
|
| 250 |
+
case QUIETS_2_S1:
|
| 251 |
+
cur = end;
|
| 252 |
+
end = endQuiets;
|
| 253 |
+
if (depth >= 3 * ONE_PLY)
|
| 254 |
+
insertion_sort(cur, end);
|
| 255 |
+
return;
|
| 256 |
+
|
| 257 |
+
case BAD_CAPTURES_S1:
|
| 258 |
+
// Just pick them in reverse order to get MVV/LVA ordering
|
| 259 |
+
cur = moves + MAX_MOVES - 1;
|
| 260 |
+
end = endBadCaptures;
|
| 261 |
+
return;
|
| 262 |
+
|
| 263 |
+
case EVASIONS_S2:
|
| 264 |
+
end = generate<EVASIONS>(pos, moves);
|
| 265 |
+
if (end > moves + 1)
|
| 266 |
+
score<EVASIONS>();
|
| 267 |
+
return;
|
| 268 |
+
|
| 269 |
+
case QUIET_CHECKS_S3:
|
| 270 |
+
end = generate<QUIET_CHECKS>(pos, moves);
|
| 271 |
+
return;
|
| 272 |
+
|
| 273 |
+
case EVASION: case QSEARCH_0: case QSEARCH_1: case PROBCUT: case RECAPTURE:
|
| 274 |
+
stage = STOP;
|
| 275 |
+
case STOP:
|
| 276 |
+
end = cur + 1; // Avoid another next_phase() call
|
| 277 |
+
return;
|
| 278 |
+
|
| 279 |
+
default:
|
| 280 |
+
assert(false);
|
| 281 |
+
}
|
| 282 |
+
}
|
| 283 |
+
|
| 284 |
+
|
| 285 |
+
/// next_move() is the most important method of the MovePicker class. It returns
|
| 286 |
+
/// a new pseudo legal move every time is called, until there are no more moves
|
| 287 |
+
/// left. It picks the move with the biggest score from a list of generated moves
|
| 288 |
+
/// taking care not returning the ttMove if has already been searched previously.
|
| 289 |
+
template<>
|
| 290 |
+
Move MovePicker::next_move<false>() {
|
| 291 |
+
|
| 292 |
+
Move move;
|
| 293 |
+
|
| 294 |
+
while (true)
|
| 295 |
+
{
|
| 296 |
+
while (cur == end)
|
| 297 |
+
generate_next();
|
| 298 |
+
|
| 299 |
+
switch (stage) {
|
| 300 |
+
|
| 301 |
+
case MAIN_SEARCH: case EVASION: case QSEARCH_0: case QSEARCH_1: case PROBCUT:
|
| 302 |
+
cur++;
|
| 303 |
+
return ttMove;
|
| 304 |
+
|
| 305 |
+
case CAPTURES_S1:
|
| 306 |
+
move = pick_best(cur++, end)->move;
|
| 307 |
+
if (move != ttMove)
|
| 308 |
+
{
|
| 309 |
+
if (pos.see_sign(move) >= 0)
|
| 310 |
+
return move;
|
| 311 |
+
|
| 312 |
+
// Losing capture, move it to the tail of the array
|
| 313 |
+
(endBadCaptures--)->move = move;
|
| 314 |
+
}
|
| 315 |
+
break;
|
| 316 |
+
|
| 317 |
+
case KILLERS_S1:
|
| 318 |
+
move = (cur++)->move;
|
| 319 |
+
if ( move != MOVE_NONE
|
| 320 |
+
&& pos.is_pseudo_legal(move)
|
| 321 |
+
&& move != ttMove
|
| 322 |
+
&& !pos.is_capture(move))
|
| 323 |
+
return move;
|
| 324 |
+
break;
|
| 325 |
+
|
| 326 |
+
case QUIETS_1_S1: case QUIETS_2_S1:
|
| 327 |
+
move = (cur++)->move;
|
| 328 |
+
if ( move != ttMove
|
| 329 |
+
&& move != killers[0].move
|
| 330 |
+
&& move != killers[1].move
|
| 331 |
+
&& move != killers[2].move
|
| 332 |
+
&& move != killers[3].move)
|
| 333 |
+
return move;
|
| 334 |
+
break;
|
| 335 |
+
|
| 336 |
+
case BAD_CAPTURES_S1:
|
| 337 |
+
return (cur--)->move;
|
| 338 |
+
|
| 339 |
+
case EVASIONS_S2: case CAPTURES_S3: case CAPTURES_S4:
|
| 340 |
+
move = pick_best(cur++, end)->move;
|
| 341 |
+
if (move != ttMove)
|
| 342 |
+
return move;
|
| 343 |
+
break;
|
| 344 |
+
|
| 345 |
+
case CAPTURES_S5:
|
| 346 |
+
move = pick_best(cur++, end)->move;
|
| 347 |
+
if (move != ttMove && pos.see(move) > captureThreshold)
|
| 348 |
+
return move;
|
| 349 |
+
break;
|
| 350 |
+
|
| 351 |
+
case CAPTURES_S6:
|
| 352 |
+
move = pick_best(cur++, end)->move;
|
| 353 |
+
if (to_sq(move) == recaptureSquare)
|
| 354 |
+
return move;
|
| 355 |
+
break;
|
| 356 |
+
|
| 357 |
+
case QUIET_CHECKS_S3:
|
| 358 |
+
move = (cur++)->move;
|
| 359 |
+
if (move != ttMove)
|
| 360 |
+
return move;
|
| 361 |
+
break;
|
| 362 |
+
|
| 363 |
+
case STOP:
|
| 364 |
+
return MOVE_NONE;
|
| 365 |
+
|
| 366 |
+
default:
|
| 367 |
+
assert(false);
|
| 368 |
+
}
|
| 369 |
+
}
|
| 370 |
+
}
|
| 371 |
+
|
| 372 |
+
|
| 373 |
+
/// Version of next_move() to use at split point nodes where the move is grabbed
|
| 374 |
+
/// from the split point's shared MovePicker object. This function is not thread
|
| 375 |
+
/// safe so must be lock protected by the caller.
|
| 376 |
+
template<>
|
| 377 |
+
Move MovePicker::next_move<true>() { return ss->splitPoint->movePicker->next_move<false>(); }
|
stockfish-4-win/src/movepick.h
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
+
Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
+
|
| 6 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 7 |
+
it under the terms of the GNU General Public License as published by
|
| 8 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 9 |
+
(at your option) any later version.
|
| 10 |
+
|
| 11 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 12 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 13 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 14 |
+
GNU General Public License for more details.
|
| 15 |
+
|
| 16 |
+
You should have received a copy of the GNU General Public License
|
| 17 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 18 |
+
*/
|
| 19 |
+
|
| 20 |
+
#ifndef MOVEPICK_H_INCLUDED
|
| 21 |
+
#define MOVEPICK_H_INCLUDED
|
| 22 |
+
|
| 23 |
+
#include <algorithm> // For std::max
|
| 24 |
+
#include <cstring> // For std::memset
|
| 25 |
+
|
| 26 |
+
#include "movegen.h"
|
| 27 |
+
#include "position.h"
|
| 28 |
+
#include "search.h"
|
| 29 |
+
#include "types.h"
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
/// The Stats struct stores moves statistics. According to the template parameter
|
| 33 |
+
/// the class can store History, Gains and Countermoves. History records how often
|
| 34 |
+
/// different moves have been successful or unsuccessful during the current search
|
| 35 |
+
/// and is used for reduction and move ordering decisions. Gains records the move's
|
| 36 |
+
/// best evaluation gain from one ply to the next and is used for pruning decisions.
|
| 37 |
+
/// Countermoves store the move that refute a previous one. Entries are stored
|
| 38 |
+
/// according only to moving piece and destination square, hence two moves with
|
| 39 |
+
/// different origin but same destination and piece will be considered identical.
|
| 40 |
+
template<bool Gain, typename T>
|
| 41 |
+
struct Stats {
|
| 42 |
+
|
| 43 |
+
static const Value Max = Value(2000);
|
| 44 |
+
|
| 45 |
+
const T* operator[](Piece p) const { return table[p]; }
|
| 46 |
+
void clear() { std::memset(table, 0, sizeof(table)); }
|
| 47 |
+
|
| 48 |
+
void update(Piece p, Square to, Move m) {
|
| 49 |
+
|
| 50 |
+
if (m == table[p][to].first)
|
| 51 |
+
return;
|
| 52 |
+
|
| 53 |
+
table[p][to].second = table[p][to].first;
|
| 54 |
+
table[p][to].first = m;
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
+
void update(Piece p, Square to, Value v) {
|
| 58 |
+
|
| 59 |
+
if (Gain)
|
| 60 |
+
table[p][to] = std::max(v, table[p][to] - 1);
|
| 61 |
+
|
| 62 |
+
else if (abs(table[p][to] + v) < Max)
|
| 63 |
+
table[p][to] += v;
|
| 64 |
+
}
|
| 65 |
+
|
| 66 |
+
private:
|
| 67 |
+
T table[PIECE_NB][SQUARE_NB];
|
| 68 |
+
};
|
| 69 |
+
|
| 70 |
+
typedef Stats< true, Value> GainsStats;
|
| 71 |
+
typedef Stats<false, Value> HistoryStats;
|
| 72 |
+
typedef Stats<false, std::pair<Move, Move> > CountermovesStats;
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
/// MovePicker class is used to pick one pseudo legal move at a time from the
|
| 76 |
+
/// current position. The most important method is next_move(), which returns a
|
| 77 |
+
/// new pseudo legal move each time it is called, until there are no moves left,
|
| 78 |
+
/// when MOVE_NONE is returned. In order to improve the efficiency of the alpha
|
| 79 |
+
/// beta algorithm, MovePicker attempts to return the moves which are most likely
|
| 80 |
+
/// to get a cut-off first.
|
| 81 |
+
|
| 82 |
+
class MovePicker {
|
| 83 |
+
|
| 84 |
+
MovePicker& operator=(const MovePicker&); // Silence a warning under MSVC
|
| 85 |
+
|
| 86 |
+
public:
|
| 87 |
+
MovePicker(const Position&, Move, Depth, const HistoryStats&, Square);
|
| 88 |
+
MovePicker(const Position&, Move, const HistoryStats&, PieceType);
|
| 89 |
+
MovePicker(const Position&, Move, Depth, const HistoryStats&, Move*, Search::Stack*);
|
| 90 |
+
|
| 91 |
+
template<bool SpNode> Move next_move();
|
| 92 |
+
|
| 93 |
+
private:
|
| 94 |
+
template<GenType> void score();
|
| 95 |
+
void generate_next();
|
| 96 |
+
|
| 97 |
+
const Position& pos;
|
| 98 |
+
const HistoryStats& history;
|
| 99 |
+
Search::Stack* ss;
|
| 100 |
+
Move* countermoves;
|
| 101 |
+
Depth depth;
|
| 102 |
+
Move ttMove;
|
| 103 |
+
ExtMove killers[4];
|
| 104 |
+
Square recaptureSquare;
|
| 105 |
+
int captureThreshold, stage;
|
| 106 |
+
ExtMove *cur, *end, *endQuiets, *endBadCaptures;
|
| 107 |
+
ExtMove moves[MAX_MOVES];
|
| 108 |
+
};
|
| 109 |
+
|
| 110 |
+
#endif // #ifndef MOVEPICK_H_INCLUDED
|
stockfish-4-win/src/notation.cpp
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
+
Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
+
|
| 6 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 7 |
+
it under the terms of the GNU General Public License as published by
|
| 8 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 9 |
+
(at your option) any later version.
|
| 10 |
+
|
| 11 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 12 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 13 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 14 |
+
GNU General Public License for more details.
|
| 15 |
+
|
| 16 |
+
You should have received a copy of the GNU General Public License
|
| 17 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 18 |
+
*/
|
| 19 |
+
|
| 20 |
+
#include <cassert>
|
| 21 |
+
#include <iomanip>
|
| 22 |
+
#include <sstream>
|
| 23 |
+
#include <stack>
|
| 24 |
+
|
| 25 |
+
#include "movegen.h"
|
| 26 |
+
#include "notation.h"
|
| 27 |
+
#include "position.h"
|
| 28 |
+
|
| 29 |
+
using namespace std;
|
| 30 |
+
|
| 31 |
+
static const char* PieceToChar[COLOR_NB] = { " PNBRQK", " pnbrqk" };
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
/// score_to_uci() converts a value to a string suitable for use with the UCI
|
| 35 |
+
/// protocol specifications:
|
| 36 |
+
///
|
| 37 |
+
/// cp <x> The score from the engine's point of view in centipawns.
|
| 38 |
+
/// mate <y> Mate in y moves, not plies. If the engine is getting mated
|
| 39 |
+
/// use negative values for y.
|
| 40 |
+
|
| 41 |
+
string score_to_uci(Value v, Value alpha, Value beta) {
|
| 42 |
+
|
| 43 |
+
stringstream s;
|
| 44 |
+
|
| 45 |
+
if (abs(v) < VALUE_MATE_IN_MAX_PLY)
|
| 46 |
+
s << "cp " << v * 100 / int(PawnValueMg);
|
| 47 |
+
else
|
| 48 |
+
s << "mate " << (v > 0 ? VALUE_MATE - v + 1 : -VALUE_MATE - v) / 2;
|
| 49 |
+
|
| 50 |
+
s << (v >= beta ? " lowerbound" : v <= alpha ? " upperbound" : "");
|
| 51 |
+
|
| 52 |
+
return s.str();
|
| 53 |
+
}
|
| 54 |
+
|
| 55 |
+
|
| 56 |
+
/// move_to_uci() converts a move to a string in coordinate notation
|
| 57 |
+
/// (g1f3, a7a8q, etc.). The only special case is castling moves, where we print
|
| 58 |
+
/// in the e1g1 notation in normal chess mode, and in e1h1 notation in chess960
|
| 59 |
+
/// mode. Internally castle moves are always coded as "king captures rook".
|
| 60 |
+
|
| 61 |
+
const string move_to_uci(Move m, bool chess960) {
|
| 62 |
+
|
| 63 |
+
Square from = from_sq(m);
|
| 64 |
+
Square to = to_sq(m);
|
| 65 |
+
|
| 66 |
+
if (m == MOVE_NONE)
|
| 67 |
+
return "(none)";
|
| 68 |
+
|
| 69 |
+
if (m == MOVE_NULL)
|
| 70 |
+
return "0000";
|
| 71 |
+
|
| 72 |
+
if (type_of(m) == CASTLE && !chess960)
|
| 73 |
+
to = (to > from ? FILE_G : FILE_C) | rank_of(from);
|
| 74 |
+
|
| 75 |
+
string move = square_to_string(from) + square_to_string(to);
|
| 76 |
+
|
| 77 |
+
if (type_of(m) == PROMOTION)
|
| 78 |
+
move += PieceToChar[BLACK][promotion_type(m)]; // Lower case
|
| 79 |
+
|
| 80 |
+
return move;
|
| 81 |
+
}
|
| 82 |
+
|
| 83 |
+
|
| 84 |
+
/// move_from_uci() takes a position and a string representing a move in
|
| 85 |
+
/// simple coordinate notation and returns an equivalent legal Move if any.
|
| 86 |
+
|
| 87 |
+
Move move_from_uci(const Position& pos, string& str) {
|
| 88 |
+
|
| 89 |
+
if (str.length() == 5) // Junior could send promotion piece in uppercase
|
| 90 |
+
str[4] = char(tolower(str[4]));
|
| 91 |
+
|
| 92 |
+
for (MoveList<LEGAL> it(pos); *it; ++it)
|
| 93 |
+
if (str == move_to_uci(*it, pos.is_chess960()))
|
| 94 |
+
return *it;
|
| 95 |
+
|
| 96 |
+
return MOVE_NONE;
|
| 97 |
+
}
|
| 98 |
+
|
| 99 |
+
|
| 100 |
+
/// move_to_san() takes a position and a legal Move as input and returns its
|
| 101 |
+
/// short algebraic notation representation.
|
| 102 |
+
|
| 103 |
+
const string move_to_san(Position& pos, Move m) {
|
| 104 |
+
|
| 105 |
+
if (m == MOVE_NONE)
|
| 106 |
+
return "(none)";
|
| 107 |
+
|
| 108 |
+
if (m == MOVE_NULL)
|
| 109 |
+
return "(null)";
|
| 110 |
+
|
| 111 |
+
assert(MoveList<LEGAL>(pos).contains(m));
|
| 112 |
+
|
| 113 |
+
Bitboard others, b;
|
| 114 |
+
string san;
|
| 115 |
+
Color us = pos.side_to_move();
|
| 116 |
+
Square from = from_sq(m);
|
| 117 |
+
Square to = to_sq(m);
|
| 118 |
+
Piece pc = pos.piece_on(from);
|
| 119 |
+
PieceType pt = type_of(pc);
|
| 120 |
+
|
| 121 |
+
if (type_of(m) == CASTLE)
|
| 122 |
+
san = to > from ? "O-O" : "O-O-O";
|
| 123 |
+
else
|
| 124 |
+
{
|
| 125 |
+
if (pt != PAWN)
|
| 126 |
+
{
|
| 127 |
+
san = PieceToChar[WHITE][pt]; // Upper case
|
| 128 |
+
|
| 129 |
+
// Disambiguation if we have more then one piece of type 'pt' that can
|
| 130 |
+
// reach 'to' with a legal move.
|
| 131 |
+
others = b = (pos.attacks_from(pc, to) & pos.pieces(us, pt)) ^ from;
|
| 132 |
+
|
| 133 |
+
while (b)
|
| 134 |
+
{
|
| 135 |
+
Move move = make_move(pop_lsb(&b), to);
|
| 136 |
+
if (!pos.pl_move_is_legal(move, pos.pinned_pieces()))
|
| 137 |
+
others ^= from_sq(move);
|
| 138 |
+
}
|
| 139 |
+
|
| 140 |
+
if (others)
|
| 141 |
+
{
|
| 142 |
+
if (!(others & file_bb(from)))
|
| 143 |
+
san += file_to_char(file_of(from));
|
| 144 |
+
|
| 145 |
+
else if (!(others & rank_bb(from)))
|
| 146 |
+
san += rank_to_char(rank_of(from));
|
| 147 |
+
|
| 148 |
+
else
|
| 149 |
+
san += square_to_string(from);
|
| 150 |
+
}
|
| 151 |
+
}
|
| 152 |
+
else if (pos.is_capture(m))
|
| 153 |
+
san = file_to_char(file_of(from));
|
| 154 |
+
|
| 155 |
+
if (pos.is_capture(m))
|
| 156 |
+
san += 'x';
|
| 157 |
+
|
| 158 |
+
san += square_to_string(to);
|
| 159 |
+
|
| 160 |
+
if (type_of(m) == PROMOTION)
|
| 161 |
+
san += string("=") + PieceToChar[WHITE][promotion_type(m)];
|
| 162 |
+
}
|
| 163 |
+
|
| 164 |
+
if (pos.move_gives_check(m, CheckInfo(pos)))
|
| 165 |
+
{
|
| 166 |
+
StateInfo st;
|
| 167 |
+
pos.do_move(m, st);
|
| 168 |
+
san += MoveList<LEGAL>(pos).size() ? "+" : "#";
|
| 169 |
+
pos.undo_move(m);
|
| 170 |
+
}
|
| 171 |
+
|
| 172 |
+
return san;
|
| 173 |
+
}
|
| 174 |
+
|
| 175 |
+
|
| 176 |
+
/// pretty_pv() formats human-readable search information, typically to be
|
| 177 |
+
/// appended to the search log file. It uses the two helpers below to pretty
|
| 178 |
+
/// format time and score respectively.
|
| 179 |
+
|
| 180 |
+
static string time_to_string(int64_t msecs) {
|
| 181 |
+
|
| 182 |
+
const int MSecMinute = 1000 * 60;
|
| 183 |
+
const int MSecHour = 1000 * 60 * 60;
|
| 184 |
+
|
| 185 |
+
int64_t hours = msecs / MSecHour;
|
| 186 |
+
int64_t minutes = (msecs % MSecHour) / MSecMinute;
|
| 187 |
+
int64_t seconds = ((msecs % MSecHour) % MSecMinute) / 1000;
|
| 188 |
+
|
| 189 |
+
stringstream s;
|
| 190 |
+
|
| 191 |
+
if (hours)
|
| 192 |
+
s << hours << ':';
|
| 193 |
+
|
| 194 |
+
s << setfill('0') << setw(2) << minutes << ':' << setw(2) << seconds;
|
| 195 |
+
|
| 196 |
+
return s.str();
|
| 197 |
+
}
|
| 198 |
+
|
| 199 |
+
static string score_to_string(Value v) {
|
| 200 |
+
|
| 201 |
+
stringstream s;
|
| 202 |
+
|
| 203 |
+
if (v >= VALUE_MATE_IN_MAX_PLY)
|
| 204 |
+
s << "#" << (VALUE_MATE - v + 1) / 2;
|
| 205 |
+
|
| 206 |
+
else if (v <= VALUE_MATED_IN_MAX_PLY)
|
| 207 |
+
s << "-#" << (VALUE_MATE + v) / 2;
|
| 208 |
+
|
| 209 |
+
else
|
| 210 |
+
s << setprecision(2) << fixed << showpos << float(v) / PawnValueMg;
|
| 211 |
+
|
| 212 |
+
return s.str();
|
| 213 |
+
}
|
| 214 |
+
|
| 215 |
+
string pretty_pv(Position& pos, int depth, Value value, int64_t msecs, Move pv[]) {
|
| 216 |
+
|
| 217 |
+
const int64_t K = 1000;
|
| 218 |
+
const int64_t M = 1000000;
|
| 219 |
+
|
| 220 |
+
std::stack<StateInfo> st;
|
| 221 |
+
Move* m = pv;
|
| 222 |
+
string san, padding;
|
| 223 |
+
size_t length;
|
| 224 |
+
stringstream s;
|
| 225 |
+
|
| 226 |
+
s << setw(2) << depth
|
| 227 |
+
<< setw(8) << score_to_string(value)
|
| 228 |
+
<< setw(8) << time_to_string(msecs);
|
| 229 |
+
|
| 230 |
+
if (pos.nodes_searched() < M)
|
| 231 |
+
s << setw(8) << pos.nodes_searched() / 1 << " ";
|
| 232 |
+
|
| 233 |
+
else if (pos.nodes_searched() < K * M)
|
| 234 |
+
s << setw(7) << pos.nodes_searched() / K << "K ";
|
| 235 |
+
|
| 236 |
+
else
|
| 237 |
+
s << setw(7) << pos.nodes_searched() / M << "M ";
|
| 238 |
+
|
| 239 |
+
padding = string(s.str().length(), ' ');
|
| 240 |
+
length = padding.length();
|
| 241 |
+
|
| 242 |
+
while (*m != MOVE_NONE)
|
| 243 |
+
{
|
| 244 |
+
san = move_to_san(pos, *m);
|
| 245 |
+
|
| 246 |
+
if (length + san.length() > 80)
|
| 247 |
+
{
|
| 248 |
+
s << "\n" + padding;
|
| 249 |
+
length = padding.length();
|
| 250 |
+
}
|
| 251 |
+
|
| 252 |
+
s << san << ' ';
|
| 253 |
+
length += san.length() + 1;
|
| 254 |
+
|
| 255 |
+
st.push(StateInfo());
|
| 256 |
+
pos.do_move(*m++, st.top());
|
| 257 |
+
}
|
| 258 |
+
|
| 259 |
+
while (m != pv)
|
| 260 |
+
pos.undo_move(*--m);
|
| 261 |
+
|
| 262 |
+
return s.str();
|
| 263 |
+
}
|
stockfish-4-win/src/notation.h
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
+
Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
+
|
| 6 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 7 |
+
it under the terms of the GNU General Public License as published by
|
| 8 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 9 |
+
(at your option) any later version.
|
| 10 |
+
|
| 11 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 12 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 13 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 14 |
+
GNU General Public License for more details.
|
| 15 |
+
|
| 16 |
+
You should have received a copy of the GNU General Public License
|
| 17 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 18 |
+
*/
|
| 19 |
+
|
| 20 |
+
#ifndef NOTATION_H_INCLUDED
|
| 21 |
+
#define NOTATION_H_INCLUDED
|
| 22 |
+
|
| 23 |
+
#include <string>
|
| 24 |
+
|
| 25 |
+
#include "types.h"
|
| 26 |
+
|
| 27 |
+
class Position;
|
| 28 |
+
|
| 29 |
+
std::string score_to_uci(Value v, Value alpha = -VALUE_INFINITE, Value beta = VALUE_INFINITE);
|
| 30 |
+
Move move_from_uci(const Position& pos, std::string& str);
|
| 31 |
+
const std::string move_to_uci(Move m, bool chess960);
|
| 32 |
+
const std::string move_to_san(Position& pos, Move m);
|
| 33 |
+
std::string pretty_pv(Position& pos, int depth, Value score, int64_t msecs, Move pv[]);
|
| 34 |
+
|
| 35 |
+
#endif // #ifndef NOTATION_H_INCLUDED
|
stockfish-4-win/src/pawns.cpp
ADDED
|
@@ -0,0 +1,281 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
+
Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
+
|
| 6 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 7 |
+
it under the terms of the GNU General Public License as published by
|
| 8 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 9 |
+
(at your option) any later version.
|
| 10 |
+
|
| 11 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 12 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 13 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 14 |
+
GNU General Public License for more details.
|
| 15 |
+
|
| 16 |
+
You should have received a copy of the GNU General Public License
|
| 17 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 18 |
+
*/
|
| 19 |
+
|
| 20 |
+
#include <algorithm>
|
| 21 |
+
#include <cassert>
|
| 22 |
+
|
| 23 |
+
#include "bitboard.h"
|
| 24 |
+
#include "bitcount.h"
|
| 25 |
+
#include "pawns.h"
|
| 26 |
+
#include "position.h"
|
| 27 |
+
|
| 28 |
+
namespace {
|
| 29 |
+
|
| 30 |
+
#define V Value
|
| 31 |
+
#define S(mg, eg) make_score(mg, eg)
|
| 32 |
+
|
| 33 |
+
// Doubled pawn penalty by opposed flag and file
|
| 34 |
+
const Score Doubled[2][FILE_NB] = {
|
| 35 |
+
{ S(13, 43), S(20, 48), S(23, 48), S(23, 48),
|
| 36 |
+
S(23, 48), S(23, 48), S(20, 48), S(13, 43) },
|
| 37 |
+
{ S(13, 43), S(20, 48), S(23, 48), S(23, 48),
|
| 38 |
+
S(23, 48), S(23, 48), S(20, 48), S(13, 43) }};
|
| 39 |
+
|
| 40 |
+
// Isolated pawn penalty by opposed flag and file
|
| 41 |
+
const Score Isolated[2][FILE_NB] = {
|
| 42 |
+
{ S(37, 45), S(54, 52), S(60, 52), S(60, 52),
|
| 43 |
+
S(60, 52), S(60, 52), S(54, 52), S(37, 45) },
|
| 44 |
+
{ S(25, 30), S(36, 35), S(40, 35), S(40, 35),
|
| 45 |
+
S(40, 35), S(40, 35), S(36, 35), S(25, 30) }};
|
| 46 |
+
|
| 47 |
+
// Backward pawn penalty by opposed flag and file
|
| 48 |
+
const Score Backward[2][FILE_NB] = {
|
| 49 |
+
{ S(30, 42), S(43, 46), S(49, 46), S(49, 46),
|
| 50 |
+
S(49, 46), S(49, 46), S(43, 46), S(30, 42) },
|
| 51 |
+
{ S(20, 28), S(29, 31), S(33, 31), S(33, 31),
|
| 52 |
+
S(33, 31), S(33, 31), S(29, 31), S(20, 28) }};
|
| 53 |
+
|
| 54 |
+
// Pawn chain membership bonus by file
|
| 55 |
+
const Score ChainMember[FILE_NB] = {
|
| 56 |
+
S(11,-1), S(13,-1), S(13,-1), S(14,-1),
|
| 57 |
+
S(14,-1), S(13,-1), S(13,-1), S(11,-1)
|
| 58 |
+
};
|
| 59 |
+
|
| 60 |
+
// Candidate passed pawn bonus by rank
|
| 61 |
+
const Score CandidatePassed[RANK_NB] = {
|
| 62 |
+
S( 0, 0), S( 6, 13), S(6,13), S(14,29),
|
| 63 |
+
S(34,68), S(83,166), S(0, 0), S( 0, 0)
|
| 64 |
+
};
|
| 65 |
+
|
| 66 |
+
// Weakness of our pawn shelter in front of the king indexed by [rank]
|
| 67 |
+
const Value ShelterWeakness[RANK_NB] =
|
| 68 |
+
{ V(100), V(0), V(27), V(73), V(92), V(101), V(101) };
|
| 69 |
+
|
| 70 |
+
// Danger of enemy pawns moving toward our king indexed by
|
| 71 |
+
// [no friendly pawn | pawn unblocked | pawn blocked][rank of enemy pawn]
|
| 72 |
+
const Value StormDanger[3][RANK_NB] = {
|
| 73 |
+
{ V( 0), V(64), V(128), V(51), V(26) },
|
| 74 |
+
{ V(26), V(32), V( 96), V(38), V(20) },
|
| 75 |
+
{ V( 0), V( 0), V( 64), V(25), V(13) }};
|
| 76 |
+
|
| 77 |
+
// Max bonus for king safety. Corresponds to start position with all the pawns
|
| 78 |
+
// in front of the king and no enemy pawn on the horizont.
|
| 79 |
+
const Value MaxSafetyBonus = V(263);
|
| 80 |
+
|
| 81 |
+
#undef S
|
| 82 |
+
#undef V
|
| 83 |
+
|
| 84 |
+
template<Color Us>
|
| 85 |
+
Score evaluate(const Position& pos, Pawns::Entry* e) {
|
| 86 |
+
|
| 87 |
+
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
| 88 |
+
const Square Up = (Us == WHITE ? DELTA_N : DELTA_S);
|
| 89 |
+
const Square Right = (Us == WHITE ? DELTA_NE : DELTA_SW);
|
| 90 |
+
const Square Left = (Us == WHITE ? DELTA_NW : DELTA_SE);
|
| 91 |
+
|
| 92 |
+
Bitboard b;
|
| 93 |
+
Square s;
|
| 94 |
+
File f;
|
| 95 |
+
Rank r;
|
| 96 |
+
bool passed, isolated, doubled, opposed, chain, backward, candidate;
|
| 97 |
+
Score value = SCORE_ZERO;
|
| 98 |
+
const Square* pl = pos.list<PAWN>(Us);
|
| 99 |
+
|
| 100 |
+
Bitboard ourPawns = pos.pieces(Us, PAWN);
|
| 101 |
+
Bitboard theirPawns = pos.pieces(Them, PAWN);
|
| 102 |
+
|
| 103 |
+
e->passedPawns[Us] = 0;
|
| 104 |
+
e->kingSquares[Us] = SQ_NONE;
|
| 105 |
+
e->semiopenFiles[Us] = 0xFF;
|
| 106 |
+
e->pawnAttacks[Us] = shift_bb<Right>(ourPawns) | shift_bb<Left>(ourPawns);
|
| 107 |
+
e->pawnsOnSquares[Us][BLACK] = popcount<Max15>(ourPawns & DarkSquares);
|
| 108 |
+
e->pawnsOnSquares[Us][WHITE] = pos.count<PAWN>(Us) - e->pawnsOnSquares[Us][BLACK];
|
| 109 |
+
|
| 110 |
+
// Loop through all pawns of the current color and score each pawn
|
| 111 |
+
while ((s = *pl++) != SQ_NONE)
|
| 112 |
+
{
|
| 113 |
+
assert(pos.piece_on(s) == make_piece(Us, PAWN));
|
| 114 |
+
|
| 115 |
+
f = file_of(s);
|
| 116 |
+
r = rank_of(s);
|
| 117 |
+
|
| 118 |
+
// This file cannot be semi-open
|
| 119 |
+
e->semiopenFiles[Us] &= ~(1 << f);
|
| 120 |
+
|
| 121 |
+
// Our rank plus previous one. Used for chain detection
|
| 122 |
+
b = rank_bb(r) | rank_bb(Us == WHITE ? r - Rank(1) : r + Rank(1));
|
| 123 |
+
|
| 124 |
+
// Flag the pawn as passed, isolated, doubled or member of a pawn
|
| 125 |
+
// chain (but not the backward one).
|
| 126 |
+
chain = ourPawns & adjacent_files_bb(f) & b;
|
| 127 |
+
isolated = !(ourPawns & adjacent_files_bb(f));
|
| 128 |
+
doubled = ourPawns & forward_bb(Us, s);
|
| 129 |
+
opposed = theirPawns & forward_bb(Us, s);
|
| 130 |
+
passed = !(theirPawns & passed_pawn_mask(Us, s));
|
| 131 |
+
|
| 132 |
+
// Test for backward pawn
|
| 133 |
+
backward = false;
|
| 134 |
+
|
| 135 |
+
// If the pawn is passed, isolated, or member of a pawn chain it cannot
|
| 136 |
+
// be backward. If there are friendly pawns behind on adjacent files
|
| 137 |
+
// or if can capture an enemy pawn it cannot be backward either.
|
| 138 |
+
if ( !(passed | isolated | chain)
|
| 139 |
+
&& !(ourPawns & pawn_attack_span(Them, s))
|
| 140 |
+
&& !(pos.attacks_from<PAWN>(s, Us) & theirPawns))
|
| 141 |
+
{
|
| 142 |
+
// We now know that there are no friendly pawns beside or behind this
|
| 143 |
+
// pawn on adjacent files. We now check whether the pawn is
|
| 144 |
+
// backward by looking in the forward direction on the adjacent
|
| 145 |
+
// files, and seeing whether we meet a friendly or an enemy pawn first.
|
| 146 |
+
b = pos.attacks_from<PAWN>(s, Us);
|
| 147 |
+
|
| 148 |
+
// Note that we are sure to find something because pawn is not passed
|
| 149 |
+
// nor isolated, so loop is potentially infinite, but it isn't.
|
| 150 |
+
while (!(b & (ourPawns | theirPawns)))
|
| 151 |
+
b = shift_bb<Up>(b);
|
| 152 |
+
|
| 153 |
+
// The friendly pawn needs to be at least two ranks closer than the
|
| 154 |
+
// enemy pawn in order to help the potentially backward pawn advance.
|
| 155 |
+
backward = (b | shift_bb<Up>(b)) & theirPawns;
|
| 156 |
+
}
|
| 157 |
+
|
| 158 |
+
assert(opposed | passed | (pawn_attack_span(Us, s) & theirPawns));
|
| 159 |
+
|
| 160 |
+
// A not passed pawn is a candidate to become passed if it is free to
|
| 161 |
+
// advance and if the number of friendly pawns beside or behind this
|
| 162 |
+
// pawn on adjacent files is higher or equal than the number of
|
| 163 |
+
// enemy pawns in the forward direction on the adjacent files.
|
| 164 |
+
candidate = !(opposed | passed | backward | isolated)
|
| 165 |
+
&& (b = pawn_attack_span(Them, s + pawn_push(Us)) & ourPawns) != 0
|
| 166 |
+
&& popcount<Max15>(b) >= popcount<Max15>(pawn_attack_span(Us, s) & theirPawns);
|
| 167 |
+
|
| 168 |
+
// Passed pawns will be properly scored in evaluation because we need
|
| 169 |
+
// full attack info to evaluate passed pawns. Only the frontmost passed
|
| 170 |
+
// pawn on each file is considered a true passed pawn.
|
| 171 |
+
if (passed && !doubled)
|
| 172 |
+
e->passedPawns[Us] |= s;
|
| 173 |
+
|
| 174 |
+
// Score this pawn
|
| 175 |
+
if (isolated)
|
| 176 |
+
value -= Isolated[opposed][f];
|
| 177 |
+
|
| 178 |
+
if (doubled)
|
| 179 |
+
value -= Doubled[opposed][f];
|
| 180 |
+
|
| 181 |
+
if (backward)
|
| 182 |
+
value -= Backward[opposed][f];
|
| 183 |
+
|
| 184 |
+
if (chain)
|
| 185 |
+
value += ChainMember[f];
|
| 186 |
+
|
| 187 |
+
if (candidate)
|
| 188 |
+
value += CandidatePassed[relative_rank(Us, s)];
|
| 189 |
+
}
|
| 190 |
+
|
| 191 |
+
return value;
|
| 192 |
+
}
|
| 193 |
+
|
| 194 |
+
} // namespace
|
| 195 |
+
|
| 196 |
+
namespace Pawns {
|
| 197 |
+
|
| 198 |
+
/// probe() takes a position object as input, computes a Entry object, and returns
|
| 199 |
+
/// a pointer to it. The result is also stored in a hash table, so we don't have
|
| 200 |
+
/// to recompute everything when the same pawn structure occurs again.
|
| 201 |
+
|
| 202 |
+
Entry* probe(const Position& pos, Table& entries) {
|
| 203 |
+
|
| 204 |
+
Key key = pos.pawn_key();
|
| 205 |
+
Entry* e = entries[key];
|
| 206 |
+
|
| 207 |
+
if (e->key == key)
|
| 208 |
+
return e;
|
| 209 |
+
|
| 210 |
+
e->key = key;
|
| 211 |
+
e->value = evaluate<WHITE>(pos, e) - evaluate<BLACK>(pos, e);
|
| 212 |
+
return e;
|
| 213 |
+
}
|
| 214 |
+
|
| 215 |
+
|
| 216 |
+
/// Entry::shelter_storm() calculates shelter and storm penalties for the file
|
| 217 |
+
/// the king is on, as well as the two adjacent files.
|
| 218 |
+
|
| 219 |
+
template<Color Us>
|
| 220 |
+
Value Entry::shelter_storm(const Position& pos, Square ksq) {
|
| 221 |
+
|
| 222 |
+
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
| 223 |
+
|
| 224 |
+
Value safety = MaxSafetyBonus;
|
| 225 |
+
Bitboard b = pos.pieces(PAWN) & (in_front_bb(Us, rank_of(ksq)) | rank_bb(ksq));
|
| 226 |
+
Bitboard ourPawns = b & pos.pieces(Us);
|
| 227 |
+
Bitboard theirPawns = b & pos.pieces(Them);
|
| 228 |
+
Rank rkUs, rkThem;
|
| 229 |
+
File kf = file_of(ksq);
|
| 230 |
+
|
| 231 |
+
kf = (kf == FILE_A) ? FILE_B : (kf == FILE_H) ? FILE_G : kf;
|
| 232 |
+
|
| 233 |
+
for (int f = kf - 1; f <= kf + 1; f++)
|
| 234 |
+
{
|
| 235 |
+
b = ourPawns & FileBB[f];
|
| 236 |
+
rkUs = b ? relative_rank(Us, Us == WHITE ? lsb(b) : msb(b)) : RANK_1;
|
| 237 |
+
safety -= ShelterWeakness[rkUs];
|
| 238 |
+
|
| 239 |
+
b = theirPawns & FileBB[f];
|
| 240 |
+
rkThem = b ? relative_rank(Us, Us == WHITE ? lsb(b) : msb(b)) : RANK_1;
|
| 241 |
+
safety -= StormDanger[rkUs == RANK_1 ? 0 : rkThem == rkUs + 1 ? 2 : 1][rkThem];
|
| 242 |
+
}
|
| 243 |
+
|
| 244 |
+
return safety;
|
| 245 |
+
}
|
| 246 |
+
|
| 247 |
+
|
| 248 |
+
/// Entry::update_safety() calculates and caches a bonus for king safety. It is
|
| 249 |
+
/// called only when king square changes, about 20% of total king_safety() calls.
|
| 250 |
+
|
| 251 |
+
template<Color Us>
|
| 252 |
+
Score Entry::update_safety(const Position& pos, Square ksq) {
|
| 253 |
+
|
| 254 |
+
kingSquares[Us] = ksq;
|
| 255 |
+
castleRights[Us] = pos.can_castle(Us);
|
| 256 |
+
minKPdistance[Us] = 0;
|
| 257 |
+
|
| 258 |
+
Bitboard pawns = pos.pieces(Us, PAWN);
|
| 259 |
+
if (pawns)
|
| 260 |
+
while (!(DistanceRingsBB[ksq][minKPdistance[Us]++] & pawns)) {}
|
| 261 |
+
|
| 262 |
+
if (relative_rank(Us, ksq) > RANK_4)
|
| 263 |
+
return kingSafety[Us] = make_score(0, -16 * minKPdistance[Us]);
|
| 264 |
+
|
| 265 |
+
Value bonus = shelter_storm<Us>(pos, ksq);
|
| 266 |
+
|
| 267 |
+
// If we can castle use the bonus after the castle if is bigger
|
| 268 |
+
if (pos.can_castle(make_castle_right(Us, KING_SIDE)))
|
| 269 |
+
bonus = std::max(bonus, shelter_storm<Us>(pos, relative_square(Us, SQ_G1)));
|
| 270 |
+
|
| 271 |
+
if (pos.can_castle(make_castle_right(Us, QUEEN_SIDE)))
|
| 272 |
+
bonus = std::max(bonus, shelter_storm<Us>(pos, relative_square(Us, SQ_C1)));
|
| 273 |
+
|
| 274 |
+
return kingSafety[Us] = make_score(bonus, -16 * minKPdistance[Us]);
|
| 275 |
+
}
|
| 276 |
+
|
| 277 |
+
// Explicit template instantiation
|
| 278 |
+
template Score Entry::update_safety<WHITE>(const Position& pos, Square ksq);
|
| 279 |
+
template Score Entry::update_safety<BLACK>(const Position& pos, Square ksq);
|
| 280 |
+
|
| 281 |
+
} // namespace Pawns
|
stockfish-4-win/src/pawns.h
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
+
Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
+
|
| 6 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 7 |
+
it under the terms of the GNU General Public License as published by
|
| 8 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 9 |
+
(at your option) any later version.
|
| 10 |
+
|
| 11 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 12 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 13 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 14 |
+
GNU General Public License for more details.
|
| 15 |
+
|
| 16 |
+
You should have received a copy of the GNU General Public License
|
| 17 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 18 |
+
*/
|
| 19 |
+
|
| 20 |
+
#ifndef PAWNS_H_INCLUDED
|
| 21 |
+
#define PAWNS_H_INCLUDED
|
| 22 |
+
|
| 23 |
+
#include "misc.h"
|
| 24 |
+
#include "position.h"
|
| 25 |
+
#include "types.h"
|
| 26 |
+
|
| 27 |
+
namespace Pawns {
|
| 28 |
+
|
| 29 |
+
/// Pawns::Entry contains various information about a pawn structure. Currently,
|
| 30 |
+
/// it only includes a middle game and end game pawn structure evaluation, and a
|
| 31 |
+
/// bitboard of passed pawns. We may want to add further information in the future.
|
| 32 |
+
/// A lookup to the pawn hash table (performed by calling the probe function)
|
| 33 |
+
/// returns a pointer to an Entry object.
|
| 34 |
+
|
| 35 |
+
struct Entry {
|
| 36 |
+
|
| 37 |
+
Score pawns_value() const { return value; }
|
| 38 |
+
Bitboard pawn_attacks(Color c) const { return pawnAttacks[c]; }
|
| 39 |
+
Bitboard passed_pawns(Color c) const { return passedPawns[c]; }
|
| 40 |
+
int pawns_on_same_color_squares(Color c, Square s) const { return pawnsOnSquares[c][!!(DarkSquares & s)]; }
|
| 41 |
+
int semiopen(Color c, File f) const { return semiopenFiles[c] & (1 << int(f)); }
|
| 42 |
+
int semiopen_on_side(Color c, File f, bool left) const {
|
| 43 |
+
|
| 44 |
+
return semiopenFiles[c] & (left ? ((1 << int(f)) - 1) : ~((1 << int(f+1)) - 1));
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
template<Color Us>
|
| 48 |
+
Score king_safety(const Position& pos, Square ksq) {
|
| 49 |
+
|
| 50 |
+
return kingSquares[Us] == ksq && castleRights[Us] == pos.can_castle(Us)
|
| 51 |
+
? kingSafety[Us] : update_safety<Us>(pos, ksq);
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
template<Color Us>
|
| 55 |
+
Score update_safety(const Position& pos, Square ksq);
|
| 56 |
+
|
| 57 |
+
template<Color Us>
|
| 58 |
+
Value shelter_storm(const Position& pos, Square ksq);
|
| 59 |
+
|
| 60 |
+
Key key;
|
| 61 |
+
Bitboard passedPawns[COLOR_NB];
|
| 62 |
+
Bitboard pawnAttacks[COLOR_NB];
|
| 63 |
+
Square kingSquares[COLOR_NB];
|
| 64 |
+
int minKPdistance[COLOR_NB];
|
| 65 |
+
int castleRights[COLOR_NB];
|
| 66 |
+
Score value;
|
| 67 |
+
int semiopenFiles[COLOR_NB];
|
| 68 |
+
Score kingSafety[COLOR_NB];
|
| 69 |
+
int pawnsOnSquares[COLOR_NB][COLOR_NB];
|
| 70 |
+
};
|
| 71 |
+
|
| 72 |
+
typedef HashTable<Entry, 16384> Table;
|
| 73 |
+
|
| 74 |
+
Entry* probe(const Position& pos, Table& entries);
|
| 75 |
+
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
+
#endif // #ifndef PAWNS_H_INCLUDED
|
stockfish-4-win/src/platform.h
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
+
Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
+
|
| 6 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 7 |
+
it under the terms of the GNU General Public License as published by
|
| 8 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 9 |
+
(at your option) any later version.
|
| 10 |
+
|
| 11 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 12 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 13 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 14 |
+
GNU General Public License for more details.
|
| 15 |
+
|
| 16 |
+
You should have received a copy of the GNU General Public License
|
| 17 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 18 |
+
*/
|
| 19 |
+
|
| 20 |
+
#ifndef PLATFORM_H_INCLUDED
|
| 21 |
+
#define PLATFORM_H_INCLUDED
|
| 22 |
+
|
| 23 |
+
#ifdef _MSC_VER
|
| 24 |
+
|
| 25 |
+
// Disable some silly and noisy warning from MSVC compiler
|
| 26 |
+
#pragma warning(disable: 4127) // Conditional expression is constant
|
| 27 |
+
#pragma warning(disable: 4146) // Unary minus operator applied to unsigned type
|
| 28 |
+
#pragma warning(disable: 4800) // Forcing value to bool 'true' or 'false'
|
| 29 |
+
#pragma warning(disable: 4996) // Function _ftime() may be unsafe
|
| 30 |
+
|
| 31 |
+
// MSVC does not support <inttypes.h>
|
| 32 |
+
typedef signed __int8 int8_t;
|
| 33 |
+
typedef unsigned __int8 uint8_t;
|
| 34 |
+
typedef signed __int16 int16_t;
|
| 35 |
+
typedef unsigned __int16 uint16_t;
|
| 36 |
+
typedef signed __int32 int32_t;
|
| 37 |
+
typedef unsigned __int32 uint32_t;
|
| 38 |
+
typedef signed __int64 int64_t;
|
| 39 |
+
typedef unsigned __int64 uint64_t;
|
| 40 |
+
|
| 41 |
+
#else
|
| 42 |
+
# include <inttypes.h>
|
| 43 |
+
#endif
|
| 44 |
+
|
| 45 |
+
#ifndef _WIN32 // Linux - Unix
|
| 46 |
+
|
| 47 |
+
# include <sys/time.h>
|
| 48 |
+
|
| 49 |
+
inline int64_t system_time_to_msec() {
|
| 50 |
+
timeval t;
|
| 51 |
+
gettimeofday(&t, NULL);
|
| 52 |
+
return t.tv_sec * 1000LL + t.tv_usec / 1000;
|
| 53 |
+
}
|
| 54 |
+
|
| 55 |
+
# include <pthread.h>
|
| 56 |
+
typedef pthread_mutex_t Lock;
|
| 57 |
+
typedef pthread_cond_t WaitCondition;
|
| 58 |
+
typedef pthread_t NativeHandle;
|
| 59 |
+
typedef void*(*pt_start_fn)(void*);
|
| 60 |
+
|
| 61 |
+
# define lock_init(x) pthread_mutex_init(&(x), NULL)
|
| 62 |
+
# define lock_grab(x) pthread_mutex_lock(&(x))
|
| 63 |
+
# define lock_release(x) pthread_mutex_unlock(&(x))
|
| 64 |
+
# define lock_destroy(x) pthread_mutex_destroy(&(x))
|
| 65 |
+
# define cond_destroy(x) pthread_cond_destroy(&(x))
|
| 66 |
+
# define cond_init(x) pthread_cond_init(&(x), NULL)
|
| 67 |
+
# define cond_signal(x) pthread_cond_signal(&(x))
|
| 68 |
+
# define cond_wait(x,y) pthread_cond_wait(&(x),&(y))
|
| 69 |
+
# define cond_timedwait(x,y,z) pthread_cond_timedwait(&(x),&(y),z)
|
| 70 |
+
# define thread_create(x,f,t) pthread_create(&(x),NULL,(pt_start_fn)f,t)
|
| 71 |
+
# define thread_join(x) pthread_join(x, NULL)
|
| 72 |
+
|
| 73 |
+
#else // Windows and MinGW
|
| 74 |
+
|
| 75 |
+
# include <sys/timeb.h>
|
| 76 |
+
|
| 77 |
+
inline int64_t system_time_to_msec() {
|
| 78 |
+
_timeb t;
|
| 79 |
+
_ftime(&t);
|
| 80 |
+
return t.time * 1000LL + t.millitm;
|
| 81 |
+
}
|
| 82 |
+
|
| 83 |
+
#ifndef NOMINMAX
|
| 84 |
+
# define NOMINMAX // disable macros min() and max()
|
| 85 |
+
#endif
|
| 86 |
+
|
| 87 |
+
#define WIN32_LEAN_AND_MEAN
|
| 88 |
+
#include <windows.h>
|
| 89 |
+
#undef WIN32_LEAN_AND_MEAN
|
| 90 |
+
#undef NOMINMAX
|
| 91 |
+
|
| 92 |
+
// We use critical sections on Windows to support Windows XP and older versions,
|
| 93 |
+
// unfortunatly cond_wait() is racy between lock_release() and WaitForSingleObject()
|
| 94 |
+
// but apart from this they have the same speed performance of SRW locks.
|
| 95 |
+
typedef CRITICAL_SECTION Lock;
|
| 96 |
+
typedef HANDLE WaitCondition;
|
| 97 |
+
typedef HANDLE NativeHandle;
|
| 98 |
+
|
| 99 |
+
// On Windows 95 and 98 parameter lpThreadId my not be null
|
| 100 |
+
inline DWORD* dwWin9xKludge() { static DWORD dw; return &dw; }
|
| 101 |
+
|
| 102 |
+
# define lock_init(x) InitializeCriticalSection(&(x))
|
| 103 |
+
# define lock_grab(x) EnterCriticalSection(&(x))
|
| 104 |
+
# define lock_release(x) LeaveCriticalSection(&(x))
|
| 105 |
+
# define lock_destroy(x) DeleteCriticalSection(&(x))
|
| 106 |
+
# define cond_init(x) { x = CreateEvent(0, FALSE, FALSE, 0); }
|
| 107 |
+
# define cond_destroy(x) CloseHandle(x)
|
| 108 |
+
# define cond_signal(x) SetEvent(x)
|
| 109 |
+
# define cond_wait(x,y) { lock_release(y); WaitForSingleObject(x, INFINITE); lock_grab(y); }
|
| 110 |
+
# define cond_timedwait(x,y,z) { lock_release(y); WaitForSingleObject(x,z); lock_grab(y); }
|
| 111 |
+
# define thread_create(x,f,t) (x = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)f,t,0,dwWin9xKludge()))
|
| 112 |
+
# define thread_join(x) { WaitForSingleObject(x, INFINITE); CloseHandle(x); }
|
| 113 |
+
|
| 114 |
+
#endif
|
| 115 |
+
|
| 116 |
+
#endif // #ifndef PLATFORM_H_INCLUDED
|
stockfish-4-win/src/position.cpp
ADDED
|
@@ -0,0 +1,1453 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
+
Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
+
|
| 6 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 7 |
+
it under the terms of the GNU General Public License as published by
|
| 8 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 9 |
+
(at your option) any later version.
|
| 10 |
+
|
| 11 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 12 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 13 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 14 |
+
GNU General Public License for more details.
|
| 15 |
+
|
| 16 |
+
You should have received a copy of the GNU General Public License
|
| 17 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 18 |
+
*/
|
| 19 |
+
|
| 20 |
+
#include <algorithm>
|
| 21 |
+
#include <cassert>
|
| 22 |
+
#include <cstring>
|
| 23 |
+
#include <iomanip>
|
| 24 |
+
#include <iostream>
|
| 25 |
+
#include <sstream>
|
| 26 |
+
|
| 27 |
+
#include "bitcount.h"
|
| 28 |
+
#include "movegen.h"
|
| 29 |
+
#include "notation.h"
|
| 30 |
+
#include "position.h"
|
| 31 |
+
#include "psqtab.h"
|
| 32 |
+
#include "rkiss.h"
|
| 33 |
+
#include "thread.h"
|
| 34 |
+
#include "tt.h"
|
| 35 |
+
|
| 36 |
+
using std::string;
|
| 37 |
+
using std::cout;
|
| 38 |
+
using std::endl;
|
| 39 |
+
|
| 40 |
+
static const string PieceToChar(" PNBRQK pnbrqk");
|
| 41 |
+
|
| 42 |
+
CACHE_LINE_ALIGNMENT
|
| 43 |
+
|
| 44 |
+
Score psq[COLOR_NB][PIECE_TYPE_NB][SQUARE_NB];
|
| 45 |
+
Value PieceValue[PHASE_NB][PIECE_NB] = {
|
| 46 |
+
{ VALUE_ZERO, PawnValueMg, KnightValueMg, BishopValueMg, RookValueMg, QueenValueMg },
|
| 47 |
+
{ VALUE_ZERO, PawnValueEg, KnightValueEg, BishopValueEg, RookValueEg, QueenValueEg } };
|
| 48 |
+
|
| 49 |
+
namespace Zobrist {
|
| 50 |
+
|
| 51 |
+
Key psq[COLOR_NB][PIECE_TYPE_NB][SQUARE_NB];
|
| 52 |
+
Key enpassant[FILE_NB];
|
| 53 |
+
Key castle[CASTLE_RIGHT_NB];
|
| 54 |
+
Key side;
|
| 55 |
+
Key exclusion;
|
| 56 |
+
}
|
| 57 |
+
|
| 58 |
+
Key Position::exclusion_key() const { return st->key ^ Zobrist::exclusion;}
|
| 59 |
+
|
| 60 |
+
namespace {
|
| 61 |
+
|
| 62 |
+
// min_attacker() is an helper function used by see() to locate the least
|
| 63 |
+
// valuable attacker for the side to move, remove the attacker we just found
|
| 64 |
+
// from the bitboards and scan for new X-ray attacks behind it.
|
| 65 |
+
|
| 66 |
+
template<int Pt> FORCE_INLINE
|
| 67 |
+
PieceType min_attacker(const Bitboard* bb, const Square& to, const Bitboard& stmAttackers,
|
| 68 |
+
Bitboard& occupied, Bitboard& attackers) {
|
| 69 |
+
|
| 70 |
+
Bitboard b = stmAttackers & bb[Pt];
|
| 71 |
+
if (!b)
|
| 72 |
+
return min_attacker<Pt+1>(bb, to, stmAttackers, occupied, attackers);
|
| 73 |
+
|
| 74 |
+
occupied ^= b & ~(b - 1);
|
| 75 |
+
|
| 76 |
+
if (Pt == PAWN || Pt == BISHOP || Pt == QUEEN)
|
| 77 |
+
attackers |= attacks_bb<BISHOP>(to, occupied) & (bb[BISHOP] | bb[QUEEN]);
|
| 78 |
+
|
| 79 |
+
if (Pt == ROOK || Pt == QUEEN)
|
| 80 |
+
attackers |= attacks_bb<ROOK>(to, occupied) & (bb[ROOK] | bb[QUEEN]);
|
| 81 |
+
|
| 82 |
+
attackers &= occupied; // After X-ray that may add already processed pieces
|
| 83 |
+
return (PieceType)Pt;
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
template<> FORCE_INLINE
|
| 87 |
+
PieceType min_attacker<KING>(const Bitboard*, const Square&, const Bitboard&, Bitboard&, Bitboard&) {
|
| 88 |
+
return KING; // No need to update bitboards, it is the last cycle
|
| 89 |
+
}
|
| 90 |
+
|
| 91 |
+
} // namespace
|
| 92 |
+
|
| 93 |
+
|
| 94 |
+
/// CheckInfo c'tor
|
| 95 |
+
|
| 96 |
+
CheckInfo::CheckInfo(const Position& pos) {
|
| 97 |
+
|
| 98 |
+
Color them = ~pos.side_to_move();
|
| 99 |
+
ksq = pos.king_square(them);
|
| 100 |
+
|
| 101 |
+
pinned = pos.pinned_pieces();
|
| 102 |
+
dcCandidates = pos.discovered_check_candidates();
|
| 103 |
+
|
| 104 |
+
checkSq[PAWN] = pos.attacks_from<PAWN>(ksq, them);
|
| 105 |
+
checkSq[KNIGHT] = pos.attacks_from<KNIGHT>(ksq);
|
| 106 |
+
checkSq[BISHOP] = pos.attacks_from<BISHOP>(ksq);
|
| 107 |
+
checkSq[ROOK] = pos.attacks_from<ROOK>(ksq);
|
| 108 |
+
checkSq[QUEEN] = checkSq[BISHOP] | checkSq[ROOK];
|
| 109 |
+
checkSq[KING] = 0;
|
| 110 |
+
}
|
| 111 |
+
|
| 112 |
+
|
| 113 |
+
/// Position::init() initializes at startup the various arrays used to compute
|
| 114 |
+
/// hash keys and the piece square tables. The latter is a two-step operation:
|
| 115 |
+
/// First, the white halves of the tables are copied from PSQT[] tables. Second,
|
| 116 |
+
/// the black halves of the tables are initialized by flipping and changing the
|
| 117 |
+
/// sign of the white scores.
|
| 118 |
+
|
| 119 |
+
void Position::init() {
|
| 120 |
+
|
| 121 |
+
RKISS rk;
|
| 122 |
+
|
| 123 |
+
for (Color c = WHITE; c <= BLACK; c++)
|
| 124 |
+
for (PieceType pt = PAWN; pt <= KING; pt++)
|
| 125 |
+
for (Square s = SQ_A1; s <= SQ_H8; s++)
|
| 126 |
+
Zobrist::psq[c][pt][s] = rk.rand<Key>();
|
| 127 |
+
|
| 128 |
+
for (File f = FILE_A; f <= FILE_H; f++)
|
| 129 |
+
Zobrist::enpassant[f] = rk.rand<Key>();
|
| 130 |
+
|
| 131 |
+
for (int cr = CASTLES_NONE; cr <= ALL_CASTLES; cr++)
|
| 132 |
+
{
|
| 133 |
+
Bitboard b = cr;
|
| 134 |
+
while (b)
|
| 135 |
+
{
|
| 136 |
+
Key k = Zobrist::castle[1ULL << pop_lsb(&b)];
|
| 137 |
+
Zobrist::castle[cr] ^= k ? k : rk.rand<Key>();
|
| 138 |
+
}
|
| 139 |
+
}
|
| 140 |
+
|
| 141 |
+
Zobrist::side = rk.rand<Key>();
|
| 142 |
+
Zobrist::exclusion = rk.rand<Key>();
|
| 143 |
+
|
| 144 |
+
for (PieceType pt = PAWN; pt <= KING; pt++)
|
| 145 |
+
{
|
| 146 |
+
PieceValue[MG][make_piece(BLACK, pt)] = PieceValue[MG][pt];
|
| 147 |
+
PieceValue[EG][make_piece(BLACK, pt)] = PieceValue[EG][pt];
|
| 148 |
+
|
| 149 |
+
Score v = make_score(PieceValue[MG][pt], PieceValue[EG][pt]);
|
| 150 |
+
|
| 151 |
+
for (Square s = SQ_A1; s <= SQ_H8; s++)
|
| 152 |
+
{
|
| 153 |
+
psq[WHITE][pt][ s] = (v + PSQT[pt][s]);
|
| 154 |
+
psq[BLACK][pt][~s] = -(v + PSQT[pt][s]);
|
| 155 |
+
}
|
| 156 |
+
}
|
| 157 |
+
}
|
| 158 |
+
|
| 159 |
+
|
| 160 |
+
/// Position::operator=() creates a copy of 'pos'. We want the new born Position
|
| 161 |
+
/// object do not depend on any external data so we detach state pointer from
|
| 162 |
+
/// the source one.
|
| 163 |
+
|
| 164 |
+
Position& Position::operator=(const Position& pos) {
|
| 165 |
+
|
| 166 |
+
std::memcpy(this, &pos, sizeof(Position));
|
| 167 |
+
startState = *st;
|
| 168 |
+
st = &startState;
|
| 169 |
+
nodes = 0;
|
| 170 |
+
|
| 171 |
+
assert(pos_is_ok());
|
| 172 |
+
|
| 173 |
+
return *this;
|
| 174 |
+
}
|
| 175 |
+
|
| 176 |
+
|
| 177 |
+
/// Position::set() initializes the position object with the given FEN string.
|
| 178 |
+
/// This function is not very robust - make sure that input FENs are correct,
|
| 179 |
+
/// this is assumed to be the responsibility of the GUI.
|
| 180 |
+
|
| 181 |
+
void Position::set(const string& fenStr, bool isChess960, Thread* th) {
|
| 182 |
+
/*
|
| 183 |
+
A FEN string defines a particular position using only the ASCII character set.
|
| 184 |
+
|
| 185 |
+
A FEN string contains six fields separated by a space. The fields are:
|
| 186 |
+
|
| 187 |
+
1) Piece placement (from white's perspective). Each rank is described, starting
|
| 188 |
+
with rank 8 and ending with rank 1; within each rank, the contents of each
|
| 189 |
+
square are described from file A through file H. Following the Standard
|
| 190 |
+
Algebraic Notation (SAN), each piece is identified by a single letter taken
|
| 191 |
+
from the standard English names. White pieces are designated using upper-case
|
| 192 |
+
letters ("PNBRQK") while Black take lowercase ("pnbrqk"). Blank squares are
|
| 193 |
+
noted using digits 1 through 8 (the number of blank squares), and "/"
|
| 194 |
+
separates ranks.
|
| 195 |
+
|
| 196 |
+
2) Active color. "w" means white moves next, "b" means black.
|
| 197 |
+
|
| 198 |
+
3) Castling availability. If neither side can castle, this is "-". Otherwise,
|
| 199 |
+
this has one or more letters: "K" (White can castle kingside), "Q" (White
|
| 200 |
+
can castle queenside), "k" (Black can castle kingside), and/or "q" (Black
|
| 201 |
+
can castle queenside).
|
| 202 |
+
|
| 203 |
+
4) En passant target square (in algebraic notation). If there's no en passant
|
| 204 |
+
target square, this is "-". If a pawn has just made a 2-square move, this
|
| 205 |
+
is the position "behind" the pawn. This is recorded regardless of whether
|
| 206 |
+
there is a pawn in position to make an en passant capture.
|
| 207 |
+
|
| 208 |
+
5) Halfmove clock. This is the number of halfmoves since the last pawn advance
|
| 209 |
+
or capture. This is used to determine if a draw can be claimed under the
|
| 210 |
+
fifty-move rule.
|
| 211 |
+
|
| 212 |
+
6) Fullmove number. The number of the full move. It starts at 1, and is
|
| 213 |
+
incremented after Black's move.
|
| 214 |
+
*/
|
| 215 |
+
|
| 216 |
+
char col, row, token;
|
| 217 |
+
size_t p;
|
| 218 |
+
Square sq = SQ_A8;
|
| 219 |
+
std::istringstream ss(fenStr);
|
| 220 |
+
|
| 221 |
+
clear();
|
| 222 |
+
ss >> std::noskipws;
|
| 223 |
+
|
| 224 |
+
// 1. Piece placement
|
| 225 |
+
while ((ss >> token) && !isspace(token))
|
| 226 |
+
{
|
| 227 |
+
if (isdigit(token))
|
| 228 |
+
sq += Square(token - '0'); // Advance the given number of files
|
| 229 |
+
|
| 230 |
+
else if (token == '/')
|
| 231 |
+
sq -= Square(16);
|
| 232 |
+
|
| 233 |
+
else if ((p = PieceToChar.find(token)) != string::npos)
|
| 234 |
+
{
|
| 235 |
+
put_piece(sq, color_of(Piece(p)), type_of(Piece(p)));
|
| 236 |
+
sq++;
|
| 237 |
+
}
|
| 238 |
+
}
|
| 239 |
+
|
| 240 |
+
// 2. Active color
|
| 241 |
+
ss >> token;
|
| 242 |
+
sideToMove = (token == 'w' ? WHITE : BLACK);
|
| 243 |
+
ss >> token;
|
| 244 |
+
|
| 245 |
+
// 3. Castling availability. Compatible with 3 standards: Normal FEN standard,
|
| 246 |
+
// Shredder-FEN that uses the letters of the columns on which the rooks began
|
| 247 |
+
// the game instead of KQkq and also X-FEN standard that, in case of Chess960,
|
| 248 |
+
// if an inner rook is associated with the castling right, the castling tag is
|
| 249 |
+
// replaced by the file letter of the involved rook, as for the Shredder-FEN.
|
| 250 |
+
while ((ss >> token) && !isspace(token))
|
| 251 |
+
{
|
| 252 |
+
Square rsq;
|
| 253 |
+
Color c = islower(token) ? BLACK : WHITE;
|
| 254 |
+
|
| 255 |
+
token = char(toupper(token));
|
| 256 |
+
|
| 257 |
+
if (token == 'K')
|
| 258 |
+
for (rsq = relative_square(c, SQ_H1); type_of(piece_on(rsq)) != ROOK; rsq--) {}
|
| 259 |
+
|
| 260 |
+
else if (token == 'Q')
|
| 261 |
+
for (rsq = relative_square(c, SQ_A1); type_of(piece_on(rsq)) != ROOK; rsq++) {}
|
| 262 |
+
|
| 263 |
+
else if (token >= 'A' && token <= 'H')
|
| 264 |
+
rsq = File(token - 'A') | relative_rank(c, RANK_1);
|
| 265 |
+
|
| 266 |
+
else
|
| 267 |
+
continue;
|
| 268 |
+
|
| 269 |
+
set_castle_right(c, rsq);
|
| 270 |
+
}
|
| 271 |
+
|
| 272 |
+
// 4. En passant square. Ignore if no pawn capture is possible
|
| 273 |
+
if ( ((ss >> col) && (col >= 'a' && col <= 'h'))
|
| 274 |
+
&& ((ss >> row) && (row == '3' || row == '6')))
|
| 275 |
+
{
|
| 276 |
+
st->epSquare = File(col - 'a') | Rank(row - '1');
|
| 277 |
+
|
| 278 |
+
if (!(attackers_to(st->epSquare) & pieces(sideToMove, PAWN)))
|
| 279 |
+
st->epSquare = SQ_NONE;
|
| 280 |
+
}
|
| 281 |
+
|
| 282 |
+
// 5-6. Halfmove clock and fullmove number
|
| 283 |
+
ss >> std::skipws >> st->rule50 >> gamePly;
|
| 284 |
+
|
| 285 |
+
// Convert from fullmove starting from 1 to ply starting from 0,
|
| 286 |
+
// handle also common incorrect FEN with fullmove = 0.
|
| 287 |
+
gamePly = std::max(2 * (gamePly - 1), 0) + int(sideToMove == BLACK);
|
| 288 |
+
|
| 289 |
+
st->key = compute_key();
|
| 290 |
+
st->pawnKey = compute_pawn_key();
|
| 291 |
+
st->materialKey = compute_material_key();
|
| 292 |
+
st->psq = compute_psq_score();
|
| 293 |
+
st->npMaterial[WHITE] = compute_non_pawn_material(WHITE);
|
| 294 |
+
st->npMaterial[BLACK] = compute_non_pawn_material(BLACK);
|
| 295 |
+
st->checkersBB = attackers_to(king_square(sideToMove)) & pieces(~sideToMove);
|
| 296 |
+
chess960 = isChess960;
|
| 297 |
+
thisThread = th;
|
| 298 |
+
|
| 299 |
+
assert(pos_is_ok());
|
| 300 |
+
}
|
| 301 |
+
|
| 302 |
+
|
| 303 |
+
/// Position::set_castle_right() is an helper function used to set castling
|
| 304 |
+
/// rights given the corresponding color and the rook starting square.
|
| 305 |
+
|
| 306 |
+
void Position::set_castle_right(Color c, Square rfrom) {
|
| 307 |
+
|
| 308 |
+
Square kfrom = king_square(c);
|
| 309 |
+
CastlingSide cs = kfrom < rfrom ? KING_SIDE : QUEEN_SIDE;
|
| 310 |
+
CastleRight cr = make_castle_right(c, cs);
|
| 311 |
+
|
| 312 |
+
st->castleRights |= cr;
|
| 313 |
+
castleRightsMask[kfrom] |= cr;
|
| 314 |
+
castleRightsMask[rfrom] |= cr;
|
| 315 |
+
castleRookSquare[c][cs] = rfrom;
|
| 316 |
+
|
| 317 |
+
Square kto = relative_square(c, cs == KING_SIDE ? SQ_G1 : SQ_C1);
|
| 318 |
+
Square rto = relative_square(c, cs == KING_SIDE ? SQ_F1 : SQ_D1);
|
| 319 |
+
|
| 320 |
+
for (Square s = std::min(rfrom, rto); s <= std::max(rfrom, rto); s++)
|
| 321 |
+
if (s != kfrom && s != rfrom)
|
| 322 |
+
castlePath[c][cs] |= s;
|
| 323 |
+
|
| 324 |
+
for (Square s = std::min(kfrom, kto); s <= std::max(kfrom, kto); s++)
|
| 325 |
+
if (s != kfrom && s != rfrom)
|
| 326 |
+
castlePath[c][cs] |= s;
|
| 327 |
+
}
|
| 328 |
+
|
| 329 |
+
|
| 330 |
+
/// Position::fen() returns a FEN representation of the position. In case
|
| 331 |
+
/// of Chess960 the Shredder-FEN notation is used. Mainly a debugging function.
|
| 332 |
+
|
| 333 |
+
const string Position::fen() const {
|
| 334 |
+
|
| 335 |
+
std::ostringstream ss;
|
| 336 |
+
|
| 337 |
+
for (Rank rank = RANK_8; rank >= RANK_1; rank--)
|
| 338 |
+
{
|
| 339 |
+
for (File file = FILE_A; file <= FILE_H; file++)
|
| 340 |
+
{
|
| 341 |
+
Square sq = file | rank;
|
| 342 |
+
|
| 343 |
+
if (is_empty(sq))
|
| 344 |
+
{
|
| 345 |
+
int emptyCnt = 1;
|
| 346 |
+
|
| 347 |
+
for ( ; file < FILE_H && is_empty(sq++); file++)
|
| 348 |
+
emptyCnt++;
|
| 349 |
+
|
| 350 |
+
ss << emptyCnt;
|
| 351 |
+
}
|
| 352 |
+
else
|
| 353 |
+
ss << PieceToChar[piece_on(sq)];
|
| 354 |
+
}
|
| 355 |
+
|
| 356 |
+
if (rank > RANK_1)
|
| 357 |
+
ss << '/';
|
| 358 |
+
}
|
| 359 |
+
|
| 360 |
+
ss << (sideToMove == WHITE ? " w " : " b ");
|
| 361 |
+
|
| 362 |
+
if (can_castle(WHITE_OO))
|
| 363 |
+
ss << (chess960 ? file_to_char(file_of(castle_rook_square(WHITE, KING_SIDE)), false) : 'K');
|
| 364 |
+
|
| 365 |
+
if (can_castle(WHITE_OOO))
|
| 366 |
+
ss << (chess960 ? file_to_char(file_of(castle_rook_square(WHITE, QUEEN_SIDE)), false) : 'Q');
|
| 367 |
+
|
| 368 |
+
if (can_castle(BLACK_OO))
|
| 369 |
+
ss << (chess960 ? file_to_char(file_of(castle_rook_square(BLACK, KING_SIDE)), true) : 'k');
|
| 370 |
+
|
| 371 |
+
if (can_castle(BLACK_OOO))
|
| 372 |
+
ss << (chess960 ? file_to_char(file_of(castle_rook_square(BLACK, QUEEN_SIDE)), true) : 'q');
|
| 373 |
+
|
| 374 |
+
if (st->castleRights == CASTLES_NONE)
|
| 375 |
+
ss << '-';
|
| 376 |
+
|
| 377 |
+
ss << (ep_square() == SQ_NONE ? " - " : " " + square_to_string(ep_square()) + " ")
|
| 378 |
+
<< st->rule50 << " " << 1 + (gamePly - int(sideToMove == BLACK)) / 2;
|
| 379 |
+
|
| 380 |
+
return ss.str();
|
| 381 |
+
}
|
| 382 |
+
|
| 383 |
+
|
| 384 |
+
/// Position::pretty() returns an ASCII representation of the position to be
|
| 385 |
+
/// printed to the standard output together with the move's san notation.
|
| 386 |
+
|
| 387 |
+
const string Position::pretty(Move move) const {
|
| 388 |
+
|
| 389 |
+
const string dottedLine = "\n+---+---+---+---+---+---+---+---+";
|
| 390 |
+
const string twoRows = dottedLine + "\n| | . | | . | | . | | . |"
|
| 391 |
+
+ dottedLine + "\n| . | | . | | . | | . | |";
|
| 392 |
+
|
| 393 |
+
string brd = twoRows + twoRows + twoRows + twoRows + dottedLine;
|
| 394 |
+
|
| 395 |
+
for (Bitboard b = pieces(); b; )
|
| 396 |
+
{
|
| 397 |
+
Square s = pop_lsb(&b);
|
| 398 |
+
brd[513 - 68 * rank_of(s) + 4 * file_of(s)] = PieceToChar[piece_on(s)];
|
| 399 |
+
}
|
| 400 |
+
|
| 401 |
+
std::ostringstream ss;
|
| 402 |
+
|
| 403 |
+
if (move)
|
| 404 |
+
ss << "\nMove: " << (sideToMove == BLACK ? ".." : "")
|
| 405 |
+
<< move_to_san(*const_cast<Position*>(this), move);
|
| 406 |
+
|
| 407 |
+
ss << brd << "\nFen: " << fen() << "\nKey: " << std::hex << std::uppercase
|
| 408 |
+
<< std::setfill('0') << std::setw(16) << st->key << "\nCheckers: ";
|
| 409 |
+
|
| 410 |
+
for (Bitboard b = checkers(); b; )
|
| 411 |
+
ss << square_to_string(pop_lsb(&b)) << " ";
|
| 412 |
+
|
| 413 |
+
ss << "\nLegal moves: ";
|
| 414 |
+
for (MoveList<LEGAL> it(*this); *it; ++it)
|
| 415 |
+
ss << move_to_san(*const_cast<Position*>(this), *it) << " ";
|
| 416 |
+
|
| 417 |
+
return ss.str();
|
| 418 |
+
}
|
| 419 |
+
|
| 420 |
+
|
| 421 |
+
/// Position:hidden_checkers() returns a bitboard of all pinned / discovery check
|
| 422 |
+
/// pieces, according to the call parameters. Pinned pieces protect our king,
|
| 423 |
+
/// discovery check pieces attack the enemy king.
|
| 424 |
+
|
| 425 |
+
Bitboard Position::hidden_checkers(Square ksq, Color c) const {
|
| 426 |
+
|
| 427 |
+
Bitboard b, pinners, result = 0;
|
| 428 |
+
|
| 429 |
+
// Pinners are sliders that give check when pinned piece is removed
|
| 430 |
+
pinners = ( (pieces( ROOK, QUEEN) & PseudoAttacks[ROOK ][ksq])
|
| 431 |
+
| (pieces(BISHOP, QUEEN) & PseudoAttacks[BISHOP][ksq])) & pieces(c);
|
| 432 |
+
|
| 433 |
+
while (pinners)
|
| 434 |
+
{
|
| 435 |
+
b = between_bb(ksq, pop_lsb(&pinners)) & pieces();
|
| 436 |
+
|
| 437 |
+
if (!more_than_one(b))
|
| 438 |
+
result |= b & pieces(sideToMove);
|
| 439 |
+
}
|
| 440 |
+
return result;
|
| 441 |
+
}
|
| 442 |
+
|
| 443 |
+
|
| 444 |
+
/// Position::attackers_to() computes a bitboard of all pieces which attack a
|
| 445 |
+
/// given square. Slider attacks use occ bitboard as occupancy.
|
| 446 |
+
|
| 447 |
+
Bitboard Position::attackers_to(Square s, Bitboard occ) const {
|
| 448 |
+
|
| 449 |
+
return (attacks_from<PAWN>(s, BLACK) & pieces(WHITE, PAWN))
|
| 450 |
+
| (attacks_from<PAWN>(s, WHITE) & pieces(BLACK, PAWN))
|
| 451 |
+
| (attacks_from<KNIGHT>(s) & pieces(KNIGHT))
|
| 452 |
+
| (attacks_bb<ROOK>(s, occ) & pieces(ROOK, QUEEN))
|
| 453 |
+
| (attacks_bb<BISHOP>(s, occ) & pieces(BISHOP, QUEEN))
|
| 454 |
+
| (attacks_from<KING>(s) & pieces(KING));
|
| 455 |
+
}
|
| 456 |
+
|
| 457 |
+
|
| 458 |
+
/// Position::attacks_from() computes a bitboard of all attacks of a given piece
|
| 459 |
+
/// put in a given square. Slider attacks use occ bitboard as occupancy.
|
| 460 |
+
|
| 461 |
+
Bitboard Position::attacks_from(Piece p, Square s, Bitboard occ) {
|
| 462 |
+
|
| 463 |
+
assert(is_ok(s));
|
| 464 |
+
|
| 465 |
+
switch (type_of(p))
|
| 466 |
+
{
|
| 467 |
+
case BISHOP: return attacks_bb<BISHOP>(s, occ);
|
| 468 |
+
case ROOK : return attacks_bb<ROOK>(s, occ);
|
| 469 |
+
case QUEEN : return attacks_bb<BISHOP>(s, occ) | attacks_bb<ROOK>(s, occ);
|
| 470 |
+
default : return StepAttacksBB[p][s];
|
| 471 |
+
}
|
| 472 |
+
}
|
| 473 |
+
|
| 474 |
+
|
| 475 |
+
/// Position::pl_move_is_legal() tests whether a pseudo-legal move is legal
|
| 476 |
+
|
| 477 |
+
bool Position::pl_move_is_legal(Move m, Bitboard pinned) const {
|
| 478 |
+
|
| 479 |
+
assert(is_ok(m));
|
| 480 |
+
assert(pinned == pinned_pieces());
|
| 481 |
+
|
| 482 |
+
Color us = sideToMove;
|
| 483 |
+
Square from = from_sq(m);
|
| 484 |
+
|
| 485 |
+
assert(color_of(piece_moved(m)) == us);
|
| 486 |
+
assert(piece_on(king_square(us)) == make_piece(us, KING));
|
| 487 |
+
|
| 488 |
+
// En passant captures are a tricky special case. Because they are rather
|
| 489 |
+
// uncommon, we do it simply by testing whether the king is attacked after
|
| 490 |
+
// the move is made.
|
| 491 |
+
if (type_of(m) == ENPASSANT)
|
| 492 |
+
{
|
| 493 |
+
Color them = ~us;
|
| 494 |
+
Square to = to_sq(m);
|
| 495 |
+
Square capsq = to + pawn_push(them);
|
| 496 |
+
Square ksq = king_square(us);
|
| 497 |
+
Bitboard b = (pieces() ^ from ^ capsq) | to;
|
| 498 |
+
|
| 499 |
+
assert(to == ep_square());
|
| 500 |
+
assert(piece_moved(m) == make_piece(us, PAWN));
|
| 501 |
+
assert(piece_on(capsq) == make_piece(them, PAWN));
|
| 502 |
+
assert(piece_on(to) == NO_PIECE);
|
| 503 |
+
|
| 504 |
+
return !(attacks_bb< ROOK>(ksq, b) & pieces(them, QUEEN, ROOK))
|
| 505 |
+
&& !(attacks_bb<BISHOP>(ksq, b) & pieces(them, QUEEN, BISHOP));
|
| 506 |
+
}
|
| 507 |
+
|
| 508 |
+
// If the moving piece is a king, check whether the destination
|
| 509 |
+
// square is attacked by the opponent. Castling moves are checked
|
| 510 |
+
// for legality during move generation.
|
| 511 |
+
if (type_of(piece_on(from)) == KING)
|
| 512 |
+
return type_of(m) == CASTLE || !(attackers_to(to_sq(m)) & pieces(~us));
|
| 513 |
+
|
| 514 |
+
// A non-king move is legal if and only if it is not pinned or it
|
| 515 |
+
// is moving along the ray towards or away from the king.
|
| 516 |
+
return !pinned
|
| 517 |
+
|| !(pinned & from)
|
| 518 |
+
|| squares_aligned(from, to_sq(m), king_square(us));
|
| 519 |
+
}
|
| 520 |
+
|
| 521 |
+
|
| 522 |
+
/// Position::is_pseudo_legal() takes a random move and tests whether the move
|
| 523 |
+
/// is pseudo legal. It is used to validate moves from TT that can be corrupted
|
| 524 |
+
/// due to SMP concurrent access or hash position key aliasing.
|
| 525 |
+
|
| 526 |
+
bool Position::is_pseudo_legal(const Move m) const {
|
| 527 |
+
|
| 528 |
+
Color us = sideToMove;
|
| 529 |
+
Square from = from_sq(m);
|
| 530 |
+
Square to = to_sq(m);
|
| 531 |
+
Piece pc = piece_moved(m);
|
| 532 |
+
|
| 533 |
+
// Use a slower but simpler function for uncommon cases
|
| 534 |
+
if (type_of(m) != NORMAL)
|
| 535 |
+
return MoveList<LEGAL>(*this).contains(m);
|
| 536 |
+
|
| 537 |
+
// Is not a promotion, so promotion piece must be empty
|
| 538 |
+
if (promotion_type(m) - 2 != NO_PIECE_TYPE)
|
| 539 |
+
return false;
|
| 540 |
+
|
| 541 |
+
// If the from square is not occupied by a piece belonging to the side to
|
| 542 |
+
// move, the move is obviously not legal.
|
| 543 |
+
if (pc == NO_PIECE || color_of(pc) != us)
|
| 544 |
+
return false;
|
| 545 |
+
|
| 546 |
+
// The destination square cannot be occupied by a friendly piece
|
| 547 |
+
if (pieces(us) & to)
|
| 548 |
+
return false;
|
| 549 |
+
|
| 550 |
+
// Handle the special case of a pawn move
|
| 551 |
+
if (type_of(pc) == PAWN)
|
| 552 |
+
{
|
| 553 |
+
// Move direction must be compatible with pawn color
|
| 554 |
+
int direction = to - from;
|
| 555 |
+
if ((us == WHITE) != (direction > 0))
|
| 556 |
+
return false;
|
| 557 |
+
|
| 558 |
+
// We have already handled promotion moves, so destination
|
| 559 |
+
// cannot be on the 8/1th rank.
|
| 560 |
+
if (rank_of(to) == RANK_8 || rank_of(to) == RANK_1)
|
| 561 |
+
return false;
|
| 562 |
+
|
| 563 |
+
// Proceed according to the square delta between the origin and
|
| 564 |
+
// destination squares.
|
| 565 |
+
switch (direction)
|
| 566 |
+
{
|
| 567 |
+
case DELTA_NW:
|
| 568 |
+
case DELTA_NE:
|
| 569 |
+
case DELTA_SW:
|
| 570 |
+
case DELTA_SE:
|
| 571 |
+
// Capture. The destination square must be occupied by an enemy
|
| 572 |
+
// piece (en passant captures was handled earlier).
|
| 573 |
+
if (piece_on(to) == NO_PIECE || color_of(piece_on(to)) != ~us)
|
| 574 |
+
return false;
|
| 575 |
+
|
| 576 |
+
// From and to files must be one file apart, avoids a7h5
|
| 577 |
+
if (abs(file_of(from) - file_of(to)) != 1)
|
| 578 |
+
return false;
|
| 579 |
+
break;
|
| 580 |
+
|
| 581 |
+
case DELTA_N:
|
| 582 |
+
case DELTA_S:
|
| 583 |
+
// Pawn push. The destination square must be empty.
|
| 584 |
+
if (!is_empty(to))
|
| 585 |
+
return false;
|
| 586 |
+
break;
|
| 587 |
+
|
| 588 |
+
case DELTA_NN:
|
| 589 |
+
// Double white pawn push. The destination square must be on the fourth
|
| 590 |
+
// rank, and both the destination square and the square between the
|
| 591 |
+
// source and destination squares must be empty.
|
| 592 |
+
if ( rank_of(to) != RANK_4
|
| 593 |
+
|| !is_empty(to)
|
| 594 |
+
|| !is_empty(from + DELTA_N))
|
| 595 |
+
return false;
|
| 596 |
+
break;
|
| 597 |
+
|
| 598 |
+
case DELTA_SS:
|
| 599 |
+
// Double black pawn push. The destination square must be on the fifth
|
| 600 |
+
// rank, and both the destination square and the square between the
|
| 601 |
+
// source and destination squares must be empty.
|
| 602 |
+
if ( rank_of(to) != RANK_5
|
| 603 |
+
|| !is_empty(to)
|
| 604 |
+
|| !is_empty(from + DELTA_S))
|
| 605 |
+
return false;
|
| 606 |
+
break;
|
| 607 |
+
|
| 608 |
+
default:
|
| 609 |
+
return false;
|
| 610 |
+
}
|
| 611 |
+
}
|
| 612 |
+
else if (!(attacks_from(pc, from) & to))
|
| 613 |
+
return false;
|
| 614 |
+
|
| 615 |
+
// Evasions generator already takes care to avoid some kind of illegal moves
|
| 616 |
+
// and pl_move_is_legal() relies on this. So we have to take care that the
|
| 617 |
+
// same kind of moves are filtered out here.
|
| 618 |
+
if (checkers())
|
| 619 |
+
{
|
| 620 |
+
if (type_of(pc) != KING)
|
| 621 |
+
{
|
| 622 |
+
// Double check? In this case a king move is required
|
| 623 |
+
if (more_than_one(checkers()))
|
| 624 |
+
return false;
|
| 625 |
+
|
| 626 |
+
// Our move must be a blocking evasion or a capture of the checking piece
|
| 627 |
+
if (!((between_bb(lsb(checkers()), king_square(us)) | checkers()) & to))
|
| 628 |
+
return false;
|
| 629 |
+
}
|
| 630 |
+
// In case of king moves under check we have to remove king so to catch
|
| 631 |
+
// as invalid moves like b1a1 when opposite queen is on c1.
|
| 632 |
+
else if (attackers_to(to, pieces() ^ from) & pieces(~us))
|
| 633 |
+
return false;
|
| 634 |
+
}
|
| 635 |
+
|
| 636 |
+
return true;
|
| 637 |
+
}
|
| 638 |
+
|
| 639 |
+
|
| 640 |
+
/// Position::move_gives_check() tests whether a pseudo-legal move gives a check
|
| 641 |
+
|
| 642 |
+
bool Position::move_gives_check(Move m, const CheckInfo& ci) const {
|
| 643 |
+
|
| 644 |
+
assert(is_ok(m));
|
| 645 |
+
assert(ci.dcCandidates == discovered_check_candidates());
|
| 646 |
+
assert(color_of(piece_moved(m)) == sideToMove);
|
| 647 |
+
|
| 648 |
+
Square from = from_sq(m);
|
| 649 |
+
Square to = to_sq(m);
|
| 650 |
+
PieceType pt = type_of(piece_on(from));
|
| 651 |
+
|
| 652 |
+
// Direct check ?
|
| 653 |
+
if (ci.checkSq[pt] & to)
|
| 654 |
+
return true;
|
| 655 |
+
|
| 656 |
+
// Discovery check ?
|
| 657 |
+
if (unlikely(ci.dcCandidates) && (ci.dcCandidates & from))
|
| 658 |
+
{
|
| 659 |
+
// For pawn and king moves we need to verify also direction
|
| 660 |
+
if ( (pt != PAWN && pt != KING)
|
| 661 |
+
|| !squares_aligned(from, to, king_square(~sideToMove)))
|
| 662 |
+
return true;
|
| 663 |
+
}
|
| 664 |
+
|
| 665 |
+
// Can we skip the ugly special cases ?
|
| 666 |
+
if (type_of(m) == NORMAL)
|
| 667 |
+
return false;
|
| 668 |
+
|
| 669 |
+
Color us = sideToMove;
|
| 670 |
+
Square ksq = king_square(~us);
|
| 671 |
+
|
| 672 |
+
switch (type_of(m))
|
| 673 |
+
{
|
| 674 |
+
case PROMOTION:
|
| 675 |
+
return attacks_from(Piece(promotion_type(m)), to, pieces() ^ from) & ksq;
|
| 676 |
+
|
| 677 |
+
// En passant capture with check ? We have already handled the case
|
| 678 |
+
// of direct checks and ordinary discovered check, the only case we
|
| 679 |
+
// need to handle is the unusual case of a discovered check through
|
| 680 |
+
// the captured pawn.
|
| 681 |
+
case ENPASSANT:
|
| 682 |
+
{
|
| 683 |
+
Square capsq = file_of(to) | rank_of(from);
|
| 684 |
+
Bitboard b = (pieces() ^ from ^ capsq) | to;
|
| 685 |
+
|
| 686 |
+
return (attacks_bb< ROOK>(ksq, b) & pieces(us, QUEEN, ROOK))
|
| 687 |
+
| (attacks_bb<BISHOP>(ksq, b) & pieces(us, QUEEN, BISHOP));
|
| 688 |
+
}
|
| 689 |
+
case CASTLE:
|
| 690 |
+
{
|
| 691 |
+
Square kfrom = from;
|
| 692 |
+
Square rfrom = to; // 'King captures the rook' notation
|
| 693 |
+
Square kto = relative_square(us, rfrom > kfrom ? SQ_G1 : SQ_C1);
|
| 694 |
+
Square rto = relative_square(us, rfrom > kfrom ? SQ_F1 : SQ_D1);
|
| 695 |
+
|
| 696 |
+
return (PseudoAttacks[ROOK][rto] & ksq)
|
| 697 |
+
&& (attacks_bb<ROOK>(rto, (pieces() ^ kfrom ^ rfrom) | rto | kto) & ksq);
|
| 698 |
+
}
|
| 699 |
+
default:
|
| 700 |
+
assert(false);
|
| 701 |
+
return false;
|
| 702 |
+
}
|
| 703 |
+
}
|
| 704 |
+
|
| 705 |
+
|
| 706 |
+
/// Position::do_move() makes a move, and saves all information necessary
|
| 707 |
+
/// to a StateInfo object. The move is assumed to be legal. Pseudo-legal
|
| 708 |
+
/// moves should be filtered out before this function is called.
|
| 709 |
+
|
| 710 |
+
void Position::do_move(Move m, StateInfo& newSt) {
|
| 711 |
+
|
| 712 |
+
CheckInfo ci(*this);
|
| 713 |
+
do_move(m, newSt, ci, move_gives_check(m, ci));
|
| 714 |
+
}
|
| 715 |
+
|
| 716 |
+
void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveIsCheck) {
|
| 717 |
+
|
| 718 |
+
assert(is_ok(m));
|
| 719 |
+
assert(&newSt != st);
|
| 720 |
+
|
| 721 |
+
nodes++;
|
| 722 |
+
Key k = st->key;
|
| 723 |
+
|
| 724 |
+
// Copy some fields of old state to our new StateInfo object except the ones
|
| 725 |
+
// which are going to be recalculated from scratch anyway, then switch our state
|
| 726 |
+
// pointer to point to the new, ready to be updated, state.
|
| 727 |
+
std::memcpy(&newSt, st, StateCopySize64 * sizeof(uint64_t));
|
| 728 |
+
|
| 729 |
+
newSt.previous = st;
|
| 730 |
+
st = &newSt;
|
| 731 |
+
|
| 732 |
+
// Update side to move
|
| 733 |
+
k ^= Zobrist::side;
|
| 734 |
+
|
| 735 |
+
// Increment ply counters.In particular rule50 will be later reset it to zero
|
| 736 |
+
// in case of a capture or a pawn move.
|
| 737 |
+
gamePly++;
|
| 738 |
+
st->rule50++;
|
| 739 |
+
st->pliesFromNull++;
|
| 740 |
+
|
| 741 |
+
Color us = sideToMove;
|
| 742 |
+
Color them = ~us;
|
| 743 |
+
Square from = from_sq(m);
|
| 744 |
+
Square to = to_sq(m);
|
| 745 |
+
Piece pc = piece_on(from);
|
| 746 |
+
PieceType pt = type_of(pc);
|
| 747 |
+
PieceType capture = type_of(m) == ENPASSANT ? PAWN : type_of(piece_on(to));
|
| 748 |
+
|
| 749 |
+
assert(color_of(pc) == us);
|
| 750 |
+
assert(piece_on(to) == NO_PIECE || color_of(piece_on(to)) == them || type_of(m) == CASTLE);
|
| 751 |
+
assert(capture != KING);
|
| 752 |
+
|
| 753 |
+
if (type_of(m) == CASTLE)
|
| 754 |
+
{
|
| 755 |
+
assert(pc == make_piece(us, KING));
|
| 756 |
+
|
| 757 |
+
bool kingSide = to > from;
|
| 758 |
+
Square rfrom = to; // Castle is encoded as "king captures friendly rook"
|
| 759 |
+
Square rto = relative_square(us, kingSide ? SQ_F1 : SQ_D1);
|
| 760 |
+
to = relative_square(us, kingSide ? SQ_G1 : SQ_C1);
|
| 761 |
+
capture = NO_PIECE_TYPE;
|
| 762 |
+
|
| 763 |
+
do_castle(from, to, rfrom, rto);
|
| 764 |
+
|
| 765 |
+
st->psq += psq[us][ROOK][rto] - psq[us][ROOK][rfrom];
|
| 766 |
+
k ^= Zobrist::psq[us][ROOK][rfrom] ^ Zobrist::psq[us][ROOK][rto];
|
| 767 |
+
}
|
| 768 |
+
|
| 769 |
+
if (capture)
|
| 770 |
+
{
|
| 771 |
+
Square capsq = to;
|
| 772 |
+
|
| 773 |
+
// If the captured piece is a pawn, update pawn hash key, otherwise
|
| 774 |
+
// update non-pawn material.
|
| 775 |
+
if (capture == PAWN)
|
| 776 |
+
{
|
| 777 |
+
if (type_of(m) == ENPASSANT)
|
| 778 |
+
{
|
| 779 |
+
capsq += pawn_push(them);
|
| 780 |
+
|
| 781 |
+
assert(pt == PAWN);
|
| 782 |
+
assert(to == st->epSquare);
|
| 783 |
+
assert(relative_rank(us, to) == RANK_6);
|
| 784 |
+
assert(piece_on(to) == NO_PIECE);
|
| 785 |
+
assert(piece_on(capsq) == make_piece(them, PAWN));
|
| 786 |
+
|
| 787 |
+
board[capsq] = NO_PIECE;
|
| 788 |
+
}
|
| 789 |
+
|
| 790 |
+
st->pawnKey ^= Zobrist::psq[them][PAWN][capsq];
|
| 791 |
+
}
|
| 792 |
+
else
|
| 793 |
+
st->npMaterial[them] -= PieceValue[MG][capture];
|
| 794 |
+
|
| 795 |
+
// Update board and piece lists
|
| 796 |
+
remove_piece(capsq, them, capture);
|
| 797 |
+
|
| 798 |
+
// Update material hash key and prefetch access to materialTable
|
| 799 |
+
k ^= Zobrist::psq[them][capture][capsq];
|
| 800 |
+
st->materialKey ^= Zobrist::psq[them][capture][pieceCount[them][capture]];
|
| 801 |
+
prefetch((char*)thisThread->materialTable[st->materialKey]);
|
| 802 |
+
|
| 803 |
+
// Update incremental scores
|
| 804 |
+
st->psq -= psq[them][capture][capsq];
|
| 805 |
+
|
| 806 |
+
// Reset rule 50 counter
|
| 807 |
+
st->rule50 = 0;
|
| 808 |
+
}
|
| 809 |
+
|
| 810 |
+
// Update hash key
|
| 811 |
+
k ^= Zobrist::psq[us][pt][from] ^ Zobrist::psq[us][pt][to];
|
| 812 |
+
|
| 813 |
+
// Reset en passant square
|
| 814 |
+
if (st->epSquare != SQ_NONE)
|
| 815 |
+
{
|
| 816 |
+
k ^= Zobrist::enpassant[file_of(st->epSquare)];
|
| 817 |
+
st->epSquare = SQ_NONE;
|
| 818 |
+
}
|
| 819 |
+
|
| 820 |
+
// Update castle rights if needed
|
| 821 |
+
if (st->castleRights && (castleRightsMask[from] | castleRightsMask[to]))
|
| 822 |
+
{
|
| 823 |
+
int cr = castleRightsMask[from] | castleRightsMask[to];
|
| 824 |
+
k ^= Zobrist::castle[st->castleRights & cr];
|
| 825 |
+
st->castleRights &= ~cr;
|
| 826 |
+
}
|
| 827 |
+
|
| 828 |
+
// Prefetch TT access as soon as we know the new hash key
|
| 829 |
+
prefetch((char*)TT.first_entry(k));
|
| 830 |
+
|
| 831 |
+
// Move the piece. The tricky Chess960 castle is handled earlier
|
| 832 |
+
if (type_of(m) != CASTLE)
|
| 833 |
+
move_piece(from, to, us, pt);
|
| 834 |
+
|
| 835 |
+
// If the moving piece is a pawn do some special extra work
|
| 836 |
+
if (pt == PAWN)
|
| 837 |
+
{
|
| 838 |
+
// Set en-passant square, only if moved pawn can be captured
|
| 839 |
+
if ( (int(to) ^ int(from)) == 16
|
| 840 |
+
&& (attacks_from<PAWN>(from + pawn_push(us), us) & pieces(them, PAWN)))
|
| 841 |
+
{
|
| 842 |
+
st->epSquare = Square((from + to) / 2);
|
| 843 |
+
k ^= Zobrist::enpassant[file_of(st->epSquare)];
|
| 844 |
+
}
|
| 845 |
+
|
| 846 |
+
if (type_of(m) == PROMOTION)
|
| 847 |
+
{
|
| 848 |
+
PieceType promotion = promotion_type(m);
|
| 849 |
+
|
| 850 |
+
assert(relative_rank(us, to) == RANK_8);
|
| 851 |
+
assert(promotion >= KNIGHT && promotion <= QUEEN);
|
| 852 |
+
|
| 853 |
+
remove_piece(to, us, PAWN);
|
| 854 |
+
put_piece(to, us, promotion);
|
| 855 |
+
|
| 856 |
+
// Update hash keys
|
| 857 |
+
k ^= Zobrist::psq[us][PAWN][to] ^ Zobrist::psq[us][promotion][to];
|
| 858 |
+
st->pawnKey ^= Zobrist::psq[us][PAWN][to];
|
| 859 |
+
st->materialKey ^= Zobrist::psq[us][promotion][pieceCount[us][promotion]-1]
|
| 860 |
+
^ Zobrist::psq[us][PAWN][pieceCount[us][PAWN]];
|
| 861 |
+
|
| 862 |
+
// Update incremental score
|
| 863 |
+
st->psq += psq[us][promotion][to] - psq[us][PAWN][to];
|
| 864 |
+
|
| 865 |
+
// Update material
|
| 866 |
+
st->npMaterial[us] += PieceValue[MG][promotion];
|
| 867 |
+
}
|
| 868 |
+
|
| 869 |
+
// Update pawn hash key and prefetch access to pawnsTable
|
| 870 |
+
st->pawnKey ^= Zobrist::psq[us][PAWN][from] ^ Zobrist::psq[us][PAWN][to];
|
| 871 |
+
prefetch((char*)thisThread->pawnsTable[st->pawnKey]);
|
| 872 |
+
|
| 873 |
+
// Reset rule 50 draw counter
|
| 874 |
+
st->rule50 = 0;
|
| 875 |
+
}
|
| 876 |
+
|
| 877 |
+
// Update incremental scores
|
| 878 |
+
st->psq += psq[us][pt][to] - psq[us][pt][from];
|
| 879 |
+
|
| 880 |
+
// Set capture piece
|
| 881 |
+
st->capturedType = capture;
|
| 882 |
+
|
| 883 |
+
// Update the key with the final value
|
| 884 |
+
st->key = k;
|
| 885 |
+
|
| 886 |
+
// Update checkers bitboard, piece must be already moved
|
| 887 |
+
st->checkersBB = 0;
|
| 888 |
+
|
| 889 |
+
if (moveIsCheck)
|
| 890 |
+
{
|
| 891 |
+
if (type_of(m) != NORMAL)
|
| 892 |
+
st->checkersBB = attackers_to(king_square(them)) & pieces(us);
|
| 893 |
+
else
|
| 894 |
+
{
|
| 895 |
+
// Direct checks
|
| 896 |
+
if (ci.checkSq[pt] & to)
|
| 897 |
+
st->checkersBB |= to;
|
| 898 |
+
|
| 899 |
+
// Discovery checks
|
| 900 |
+
if (ci.dcCandidates && (ci.dcCandidates & from))
|
| 901 |
+
{
|
| 902 |
+
if (pt != ROOK)
|
| 903 |
+
st->checkersBB |= attacks_from<ROOK>(king_square(them)) & pieces(us, QUEEN, ROOK);
|
| 904 |
+
|
| 905 |
+
if (pt != BISHOP)
|
| 906 |
+
st->checkersBB |= attacks_from<BISHOP>(king_square(them)) & pieces(us, QUEEN, BISHOP);
|
| 907 |
+
}
|
| 908 |
+
}
|
| 909 |
+
}
|
| 910 |
+
|
| 911 |
+
sideToMove = ~sideToMove;
|
| 912 |
+
|
| 913 |
+
assert(pos_is_ok());
|
| 914 |
+
}
|
| 915 |
+
|
| 916 |
+
|
| 917 |
+
/// Position::undo_move() unmakes a move. When it returns, the position should
|
| 918 |
+
/// be restored to exactly the same state as before the move was made.
|
| 919 |
+
|
| 920 |
+
void Position::undo_move(Move m) {
|
| 921 |
+
|
| 922 |
+
assert(is_ok(m));
|
| 923 |
+
|
| 924 |
+
sideToMove = ~sideToMove;
|
| 925 |
+
|
| 926 |
+
Color us = sideToMove;
|
| 927 |
+
Color them = ~us;
|
| 928 |
+
Square from = from_sq(m);
|
| 929 |
+
Square to = to_sq(m);
|
| 930 |
+
PieceType pt = type_of(piece_on(to));
|
| 931 |
+
PieceType capture = st->capturedType;
|
| 932 |
+
|
| 933 |
+
assert(is_empty(from) || type_of(m) == CASTLE);
|
| 934 |
+
assert(capture != KING);
|
| 935 |
+
|
| 936 |
+
if (type_of(m) == PROMOTION)
|
| 937 |
+
{
|
| 938 |
+
PieceType promotion = promotion_type(m);
|
| 939 |
+
|
| 940 |
+
assert(promotion == pt);
|
| 941 |
+
assert(relative_rank(us, to) == RANK_8);
|
| 942 |
+
assert(promotion >= KNIGHT && promotion <= QUEEN);
|
| 943 |
+
|
| 944 |
+
remove_piece(to, us, promotion);
|
| 945 |
+
put_piece(to, us, PAWN);
|
| 946 |
+
pt = PAWN;
|
| 947 |
+
}
|
| 948 |
+
|
| 949 |
+
if (type_of(m) == CASTLE)
|
| 950 |
+
{
|
| 951 |
+
bool kingSide = to > from;
|
| 952 |
+
Square rfrom = to; // Castle is encoded as "king captures friendly rook"
|
| 953 |
+
Square rto = relative_square(us, kingSide ? SQ_F1 : SQ_D1);
|
| 954 |
+
to = relative_square(us, kingSide ? SQ_G1 : SQ_C1);
|
| 955 |
+
capture = NO_PIECE_TYPE;
|
| 956 |
+
pt = KING;
|
| 957 |
+
do_castle(to, from, rto, rfrom);
|
| 958 |
+
}
|
| 959 |
+
else
|
| 960 |
+
move_piece(to, from, us, pt); // Put the piece back at the source square
|
| 961 |
+
|
| 962 |
+
if (capture)
|
| 963 |
+
{
|
| 964 |
+
Square capsq = to;
|
| 965 |
+
|
| 966 |
+
if (type_of(m) == ENPASSANT)
|
| 967 |
+
{
|
| 968 |
+
capsq -= pawn_push(us);
|
| 969 |
+
|
| 970 |
+
assert(pt == PAWN);
|
| 971 |
+
assert(to == st->previous->epSquare);
|
| 972 |
+
assert(relative_rank(us, to) == RANK_6);
|
| 973 |
+
assert(piece_on(capsq) == NO_PIECE);
|
| 974 |
+
}
|
| 975 |
+
|
| 976 |
+
put_piece(capsq, them, capture); // Restore the captured piece
|
| 977 |
+
}
|
| 978 |
+
|
| 979 |
+
// Finally point our state pointer back to the previous state
|
| 980 |
+
st = st->previous;
|
| 981 |
+
gamePly--;
|
| 982 |
+
|
| 983 |
+
assert(pos_is_ok());
|
| 984 |
+
}
|
| 985 |
+
|
| 986 |
+
|
| 987 |
+
/// Position::do_castle() is a helper used to do/undo a castling move. This
|
| 988 |
+
/// is a bit tricky, especially in Chess960.
|
| 989 |
+
|
| 990 |
+
void Position::do_castle(Square kfrom, Square kto, Square rfrom, Square rto) {
|
| 991 |
+
|
| 992 |
+
// Remove both pieces first since squares could overlap in Chess960
|
| 993 |
+
remove_piece(kfrom, sideToMove, KING);
|
| 994 |
+
remove_piece(rfrom, sideToMove, ROOK);
|
| 995 |
+
board[kfrom] = board[rfrom] = NO_PIECE; // Since remove_piece doesn't do it for us
|
| 996 |
+
put_piece(kto, sideToMove, KING);
|
| 997 |
+
put_piece(rto, sideToMove, ROOK);
|
| 998 |
+
}
|
| 999 |
+
|
| 1000 |
+
|
| 1001 |
+
/// Position::do(undo)_null_move() is used to do(undo) a "null move": It flips
|
| 1002 |
+
/// the side to move without executing any move on the board.
|
| 1003 |
+
|
| 1004 |
+
void Position::do_null_move(StateInfo& newSt) {
|
| 1005 |
+
|
| 1006 |
+
assert(!checkers());
|
| 1007 |
+
|
| 1008 |
+
std::memcpy(&newSt, st, sizeof(StateInfo)); // Fully copy here
|
| 1009 |
+
|
| 1010 |
+
newSt.previous = st;
|
| 1011 |
+
st = &newSt;
|
| 1012 |
+
|
| 1013 |
+
if (st->epSquare != SQ_NONE)
|
| 1014 |
+
{
|
| 1015 |
+
st->key ^= Zobrist::enpassant[file_of(st->epSquare)];
|
| 1016 |
+
st->epSquare = SQ_NONE;
|
| 1017 |
+
}
|
| 1018 |
+
|
| 1019 |
+
st->key ^= Zobrist::side;
|
| 1020 |
+
prefetch((char*)TT.first_entry(st->key));
|
| 1021 |
+
|
| 1022 |
+
st->rule50++;
|
| 1023 |
+
st->pliesFromNull = 0;
|
| 1024 |
+
|
| 1025 |
+
sideToMove = ~sideToMove;
|
| 1026 |
+
|
| 1027 |
+
assert(pos_is_ok());
|
| 1028 |
+
}
|
| 1029 |
+
|
| 1030 |
+
void Position::undo_null_move() {
|
| 1031 |
+
|
| 1032 |
+
assert(!checkers());
|
| 1033 |
+
|
| 1034 |
+
st = st->previous;
|
| 1035 |
+
sideToMove = ~sideToMove;
|
| 1036 |
+
}
|
| 1037 |
+
|
| 1038 |
+
|
| 1039 |
+
/// Position::see() is a static exchange evaluator: It tries to estimate the
|
| 1040 |
+
/// material gain or loss resulting from a move. Parameter 'asymmThreshold' takes
|
| 1041 |
+
/// tempi into account. If the side who initiated the capturing sequence does the
|
| 1042 |
+
/// last capture, he loses a tempo and if the result is below 'asymmThreshold'
|
| 1043 |
+
/// the capturing sequence is considered bad.
|
| 1044 |
+
|
| 1045 |
+
int Position::see_sign(Move m) const {
|
| 1046 |
+
|
| 1047 |
+
assert(is_ok(m));
|
| 1048 |
+
|
| 1049 |
+
// Early return if SEE cannot be negative because captured piece value
|
| 1050 |
+
// is not less then capturing one. Note that king moves always return
|
| 1051 |
+
// here because king midgame value is set to 0.
|
| 1052 |
+
if (PieceValue[MG][piece_moved(m)] <= PieceValue[MG][piece_on(to_sq(m))])
|
| 1053 |
+
return 1;
|
| 1054 |
+
|
| 1055 |
+
return see(m);
|
| 1056 |
+
}
|
| 1057 |
+
|
| 1058 |
+
int Position::see(Move m, int asymmThreshold) const {
|
| 1059 |
+
|
| 1060 |
+
Square from, to;
|
| 1061 |
+
Bitboard occupied, attackers, stmAttackers;
|
| 1062 |
+
int swapList[32], slIndex = 1;
|
| 1063 |
+
PieceType captured;
|
| 1064 |
+
Color stm;
|
| 1065 |
+
|
| 1066 |
+
assert(is_ok(m));
|
| 1067 |
+
|
| 1068 |
+
from = from_sq(m);
|
| 1069 |
+
to = to_sq(m);
|
| 1070 |
+
swapList[0] = PieceValue[MG][type_of(piece_on(to))];
|
| 1071 |
+
stm = color_of(piece_on(from));
|
| 1072 |
+
occupied = pieces() ^ from;
|
| 1073 |
+
|
| 1074 |
+
// Castle moves are implemented as king capturing the rook so cannot be
|
| 1075 |
+
// handled correctly. Simply return 0 that is always the correct value
|
| 1076 |
+
// unless in the rare case the rook ends up under attack.
|
| 1077 |
+
if (type_of(m) == CASTLE)
|
| 1078 |
+
return 0;
|
| 1079 |
+
|
| 1080 |
+
if (type_of(m) == ENPASSANT)
|
| 1081 |
+
{
|
| 1082 |
+
occupied ^= to - pawn_push(stm); // Remove the captured pawn
|
| 1083 |
+
swapList[0] = PieceValue[MG][PAWN];
|
| 1084 |
+
}
|
| 1085 |
+
|
| 1086 |
+
// Find all attackers to the destination square, with the moving piece
|
| 1087 |
+
// removed, but possibly an X-ray attacker added behind it.
|
| 1088 |
+
attackers = attackers_to(to, occupied) & occupied;
|
| 1089 |
+
|
| 1090 |
+
// If the opponent has no attackers we are finished
|
| 1091 |
+
stm = ~stm;
|
| 1092 |
+
stmAttackers = attackers & pieces(stm);
|
| 1093 |
+
if (!stmAttackers)
|
| 1094 |
+
return swapList[0];
|
| 1095 |
+
|
| 1096 |
+
// The destination square is defended, which makes things rather more
|
| 1097 |
+
// difficult to compute. We proceed by building up a "swap list" containing
|
| 1098 |
+
// the material gain or loss at each stop in a sequence of captures to the
|
| 1099 |
+
// destination square, where the sides alternately capture, and always
|
| 1100 |
+
// capture with the least valuable piece. After each capture, we look for
|
| 1101 |
+
// new X-ray attacks from behind the capturing piece.
|
| 1102 |
+
captured = type_of(piece_on(from));
|
| 1103 |
+
|
| 1104 |
+
do {
|
| 1105 |
+
assert(slIndex < 32);
|
| 1106 |
+
|
| 1107 |
+
// Add the new entry to the swap list
|
| 1108 |
+
swapList[slIndex] = -swapList[slIndex - 1] + PieceValue[MG][captured];
|
| 1109 |
+
slIndex++;
|
| 1110 |
+
|
| 1111 |
+
// Locate and remove the next least valuable attacker
|
| 1112 |
+
captured = min_attacker<PAWN>(byTypeBB, to, stmAttackers, occupied, attackers);
|
| 1113 |
+
stm = ~stm;
|
| 1114 |
+
stmAttackers = attackers & pieces(stm);
|
| 1115 |
+
|
| 1116 |
+
// Stop before processing a king capture
|
| 1117 |
+
if (captured == KING && stmAttackers)
|
| 1118 |
+
{
|
| 1119 |
+
swapList[slIndex++] = QueenValueMg * 16;
|
| 1120 |
+
break;
|
| 1121 |
+
}
|
| 1122 |
+
|
| 1123 |
+
} while (stmAttackers);
|
| 1124 |
+
|
| 1125 |
+
// If we are doing asymmetric SEE evaluation and the same side does the first
|
| 1126 |
+
// and the last capture, he loses a tempo and gain must be at least worth
|
| 1127 |
+
// 'asymmThreshold', otherwise we replace the score with a very low value,
|
| 1128 |
+
// before negamaxing.
|
| 1129 |
+
if (asymmThreshold)
|
| 1130 |
+
for (int i = 0; i < slIndex; i += 2)
|
| 1131 |
+
if (swapList[i] < asymmThreshold)
|
| 1132 |
+
swapList[i] = - QueenValueMg * 16;
|
| 1133 |
+
|
| 1134 |
+
// Having built the swap list, we negamax through it to find the best
|
| 1135 |
+
// achievable score from the point of view of the side to move.
|
| 1136 |
+
while (--slIndex)
|
| 1137 |
+
swapList[slIndex-1] = std::min(-swapList[slIndex], swapList[slIndex-1]);
|
| 1138 |
+
|
| 1139 |
+
return swapList[0];
|
| 1140 |
+
}
|
| 1141 |
+
|
| 1142 |
+
|
| 1143 |
+
/// Position::clear() erases the position object to a pristine state, with an
|
| 1144 |
+
/// empty board, white to move, and no castling rights.
|
| 1145 |
+
|
| 1146 |
+
void Position::clear() {
|
| 1147 |
+
|
| 1148 |
+
std::memset(this, 0, sizeof(Position));
|
| 1149 |
+
startState.epSquare = SQ_NONE;
|
| 1150 |
+
st = &startState;
|
| 1151 |
+
|
| 1152 |
+
for (int i = 0; i < 8; i++)
|
| 1153 |
+
for (int j = 0; j < 16; j++)
|
| 1154 |
+
pieceList[0][i][j] = pieceList[1][i][j] = SQ_NONE;
|
| 1155 |
+
}
|
| 1156 |
+
|
| 1157 |
+
|
| 1158 |
+
/// Position::compute_key() computes the hash key of the position. The hash
|
| 1159 |
+
/// key is usually updated incrementally as moves are made and unmade, the
|
| 1160 |
+
/// compute_key() function is only used when a new position is set up, and
|
| 1161 |
+
/// to verify the correctness of the hash key when running in debug mode.
|
| 1162 |
+
|
| 1163 |
+
Key Position::compute_key() const {
|
| 1164 |
+
|
| 1165 |
+
Key k = Zobrist::castle[st->castleRights];
|
| 1166 |
+
|
| 1167 |
+
for (Bitboard b = pieces(); b; )
|
| 1168 |
+
{
|
| 1169 |
+
Square s = pop_lsb(&b);
|
| 1170 |
+
k ^= Zobrist::psq[color_of(piece_on(s))][type_of(piece_on(s))][s];
|
| 1171 |
+
}
|
| 1172 |
+
|
| 1173 |
+
if (ep_square() != SQ_NONE)
|
| 1174 |
+
k ^= Zobrist::enpassant[file_of(ep_square())];
|
| 1175 |
+
|
| 1176 |
+
if (sideToMove == BLACK)
|
| 1177 |
+
k ^= Zobrist::side;
|
| 1178 |
+
|
| 1179 |
+
return k;
|
| 1180 |
+
}
|
| 1181 |
+
|
| 1182 |
+
|
| 1183 |
+
/// Position::compute_pawn_key() computes the hash key of the position. The
|
| 1184 |
+
/// hash key is usually updated incrementally as moves are made and unmade,
|
| 1185 |
+
/// the compute_pawn_key() function is only used when a new position is set
|
| 1186 |
+
/// up, and to verify the correctness of the pawn hash key when running in
|
| 1187 |
+
/// debug mode.
|
| 1188 |
+
|
| 1189 |
+
Key Position::compute_pawn_key() const {
|
| 1190 |
+
|
| 1191 |
+
Key k = 0;
|
| 1192 |
+
|
| 1193 |
+
for (Bitboard b = pieces(PAWN); b; )
|
| 1194 |
+
{
|
| 1195 |
+
Square s = pop_lsb(&b);
|
| 1196 |
+
k ^= Zobrist::psq[color_of(piece_on(s))][PAWN][s];
|
| 1197 |
+
}
|
| 1198 |
+
|
| 1199 |
+
return k;
|
| 1200 |
+
}
|
| 1201 |
+
|
| 1202 |
+
|
| 1203 |
+
/// Position::compute_material_key() computes the hash key of the position.
|
| 1204 |
+
/// The hash key is usually updated incrementally as moves are made and unmade,
|
| 1205 |
+
/// the compute_material_key() function is only used when a new position is set
|
| 1206 |
+
/// up, and to verify the correctness of the material hash key when running in
|
| 1207 |
+
/// debug mode.
|
| 1208 |
+
|
| 1209 |
+
Key Position::compute_material_key() const {
|
| 1210 |
+
|
| 1211 |
+
Key k = 0;
|
| 1212 |
+
|
| 1213 |
+
for (Color c = WHITE; c <= BLACK; c++)
|
| 1214 |
+
for (PieceType pt = PAWN; pt <= QUEEN; pt++)
|
| 1215 |
+
for (int cnt = 0; cnt < pieceCount[c][pt]; cnt++)
|
| 1216 |
+
k ^= Zobrist::psq[c][pt][cnt];
|
| 1217 |
+
|
| 1218 |
+
return k;
|
| 1219 |
+
}
|
| 1220 |
+
|
| 1221 |
+
|
| 1222 |
+
/// Position::compute_psq_score() computes the incremental scores for the middle
|
| 1223 |
+
/// game and the endgame. These functions are used to initialize the incremental
|
| 1224 |
+
/// scores when a new position is set up, and to verify that the scores are correctly
|
| 1225 |
+
/// updated by do_move and undo_move when the program is running in debug mode.
|
| 1226 |
+
Score Position::compute_psq_score() const {
|
| 1227 |
+
|
| 1228 |
+
Score score = SCORE_ZERO;
|
| 1229 |
+
|
| 1230 |
+
for (Bitboard b = pieces(); b; )
|
| 1231 |
+
{
|
| 1232 |
+
Square s = pop_lsb(&b);
|
| 1233 |
+
Piece pc = piece_on(s);
|
| 1234 |
+
score += psq[color_of(pc)][type_of(pc)][s];
|
| 1235 |
+
}
|
| 1236 |
+
|
| 1237 |
+
return score;
|
| 1238 |
+
}
|
| 1239 |
+
|
| 1240 |
+
|
| 1241 |
+
/// Position::compute_non_pawn_material() computes the total non-pawn middle
|
| 1242 |
+
/// game material value for the given side. Material values are updated
|
| 1243 |
+
/// incrementally during the search, this function is only used while
|
| 1244 |
+
/// initializing a new Position object.
|
| 1245 |
+
|
| 1246 |
+
Value Position::compute_non_pawn_material(Color c) const {
|
| 1247 |
+
|
| 1248 |
+
Value value = VALUE_ZERO;
|
| 1249 |
+
|
| 1250 |
+
for (PieceType pt = KNIGHT; pt <= QUEEN; pt++)
|
| 1251 |
+
value += pieceCount[c][pt] * PieceValue[MG][pt];
|
| 1252 |
+
|
| 1253 |
+
return value;
|
| 1254 |
+
}
|
| 1255 |
+
|
| 1256 |
+
|
| 1257 |
+
/// Position::is_draw() tests whether the position is drawn by material,
|
| 1258 |
+
/// repetition, or the 50 moves rule. It does not detect stalemates, this
|
| 1259 |
+
/// must be done by the search.
|
| 1260 |
+
bool Position::is_draw() const {
|
| 1261 |
+
|
| 1262 |
+
// Draw by material?
|
| 1263 |
+
if ( !pieces(PAWN)
|
| 1264 |
+
&& (non_pawn_material(WHITE) + non_pawn_material(BLACK) <= BishopValueMg))
|
| 1265 |
+
return true;
|
| 1266 |
+
|
| 1267 |
+
// Draw by the 50 moves rule?
|
| 1268 |
+
if (st->rule50 > 99 && (!checkers() || MoveList<LEGAL>(*this).size()))
|
| 1269 |
+
return true;
|
| 1270 |
+
|
| 1271 |
+
// Draw by repetition?
|
| 1272 |
+
int i = 4, e = std::min(st->rule50, st->pliesFromNull);
|
| 1273 |
+
|
| 1274 |
+
if (i <= e)
|
| 1275 |
+
{
|
| 1276 |
+
StateInfo* stp = st->previous->previous;
|
| 1277 |
+
|
| 1278 |
+
do {
|
| 1279 |
+
stp = stp->previous->previous;
|
| 1280 |
+
|
| 1281 |
+
if (stp->key == st->key)
|
| 1282 |
+
return true;
|
| 1283 |
+
|
| 1284 |
+
i += 2;
|
| 1285 |
+
|
| 1286 |
+
} while (i <= e);
|
| 1287 |
+
}
|
| 1288 |
+
|
| 1289 |
+
return false;
|
| 1290 |
+
}
|
| 1291 |
+
|
| 1292 |
+
|
| 1293 |
+
/// Position::flip() flips position with the white and black sides reversed. This
|
| 1294 |
+
/// is only useful for debugging especially for finding evaluation symmetry bugs.
|
| 1295 |
+
|
| 1296 |
+
static char toggle_case(char c) {
|
| 1297 |
+
return char(islower(c) ? toupper(c) : tolower(c));
|
| 1298 |
+
}
|
| 1299 |
+
|
| 1300 |
+
void Position::flip() {
|
| 1301 |
+
|
| 1302 |
+
string f, token;
|
| 1303 |
+
std::stringstream ss(fen());
|
| 1304 |
+
|
| 1305 |
+
for (Rank rank = RANK_8; rank >= RANK_1; rank--) // Piece placement
|
| 1306 |
+
{
|
| 1307 |
+
std::getline(ss, token, rank > RANK_1 ? '/' : ' ');
|
| 1308 |
+
f.insert(0, token + (f.empty() ? " " : "/"));
|
| 1309 |
+
}
|
| 1310 |
+
|
| 1311 |
+
ss >> token; // Active color
|
| 1312 |
+
f += (token == "w" ? "B " : "W "); // Will be lowercased later
|
| 1313 |
+
|
| 1314 |
+
ss >> token; // Castling availability
|
| 1315 |
+
f += token + " ";
|
| 1316 |
+
|
| 1317 |
+
std::transform(f.begin(), f.end(), f.begin(), toggle_case);
|
| 1318 |
+
|
| 1319 |
+
ss >> token; // En passant square
|
| 1320 |
+
f += (token == "-" ? token : token.replace(1, 1, token[1] == '3' ? "6" : "3"));
|
| 1321 |
+
|
| 1322 |
+
std::getline(ss, token); // Half and full moves
|
| 1323 |
+
f += token;
|
| 1324 |
+
|
| 1325 |
+
set(f, is_chess960(), this_thread());
|
| 1326 |
+
|
| 1327 |
+
assert(pos_is_ok());
|
| 1328 |
+
}
|
| 1329 |
+
|
| 1330 |
+
|
| 1331 |
+
/// Position::pos_is_ok() performs some consitency checks for the position object.
|
| 1332 |
+
/// This is meant to be helpful when debugging.
|
| 1333 |
+
|
| 1334 |
+
bool Position::pos_is_ok(int* failedStep) const {
|
| 1335 |
+
|
| 1336 |
+
int dummy, *step = failedStep ? failedStep : &dummy;
|
| 1337 |
+
|
| 1338 |
+
// What features of the position should be verified?
|
| 1339 |
+
const bool all = false;
|
| 1340 |
+
|
| 1341 |
+
const bool debugBitboards = all || false;
|
| 1342 |
+
const bool debugKingCount = all || false;
|
| 1343 |
+
const bool debugKingCapture = all || false;
|
| 1344 |
+
const bool debugCheckerCount = all || false;
|
| 1345 |
+
const bool debugKey = all || false;
|
| 1346 |
+
const bool debugMaterialKey = all || false;
|
| 1347 |
+
const bool debugPawnKey = all || false;
|
| 1348 |
+
const bool debugIncrementalEval = all || false;
|
| 1349 |
+
const bool debugNonPawnMaterial = all || false;
|
| 1350 |
+
const bool debugPieceCounts = all || false;
|
| 1351 |
+
const bool debugPieceList = all || false;
|
| 1352 |
+
const bool debugCastleSquares = all || false;
|
| 1353 |
+
|
| 1354 |
+
*step = 1;
|
| 1355 |
+
|
| 1356 |
+
if (sideToMove != WHITE && sideToMove != BLACK)
|
| 1357 |
+
return false;
|
| 1358 |
+
|
| 1359 |
+
if ((*step)++, piece_on(king_square(WHITE)) != W_KING)
|
| 1360 |
+
return false;
|
| 1361 |
+
|
| 1362 |
+
if ((*step)++, piece_on(king_square(BLACK)) != B_KING)
|
| 1363 |
+
return false;
|
| 1364 |
+
|
| 1365 |
+
if ((*step)++, debugKingCount)
|
| 1366 |
+
{
|
| 1367 |
+
int kingCount[COLOR_NB] = {};
|
| 1368 |
+
|
| 1369 |
+
for (Square s = SQ_A1; s <= SQ_H8; s++)
|
| 1370 |
+
if (type_of(piece_on(s)) == KING)
|
| 1371 |
+
kingCount[color_of(piece_on(s))]++;
|
| 1372 |
+
|
| 1373 |
+
if (kingCount[0] != 1 || kingCount[1] != 1)
|
| 1374 |
+
return false;
|
| 1375 |
+
}
|
| 1376 |
+
|
| 1377 |
+
if ((*step)++, debugKingCapture)
|
| 1378 |
+
if (attackers_to(king_square(~sideToMove)) & pieces(sideToMove))
|
| 1379 |
+
return false;
|
| 1380 |
+
|
| 1381 |
+
if ((*step)++, debugCheckerCount && popcount<Full>(st->checkersBB) > 2)
|
| 1382 |
+
return false;
|
| 1383 |
+
|
| 1384 |
+
if ((*step)++, debugBitboards)
|
| 1385 |
+
{
|
| 1386 |
+
// The intersection of the white and black pieces must be empty
|
| 1387 |
+
if (pieces(WHITE) & pieces(BLACK))
|
| 1388 |
+
return false;
|
| 1389 |
+
|
| 1390 |
+
// The union of the white and black pieces must be equal to all
|
| 1391 |
+
// occupied squares
|
| 1392 |
+
if ((pieces(WHITE) | pieces(BLACK)) != pieces())
|
| 1393 |
+
return false;
|
| 1394 |
+
|
| 1395 |
+
// Separate piece type bitboards must have empty intersections
|
| 1396 |
+
for (PieceType p1 = PAWN; p1 <= KING; p1++)
|
| 1397 |
+
for (PieceType p2 = PAWN; p2 <= KING; p2++)
|
| 1398 |
+
if (p1 != p2 && (pieces(p1) & pieces(p2)))
|
| 1399 |
+
return false;
|
| 1400 |
+
}
|
| 1401 |
+
|
| 1402 |
+
if ((*step)++, ep_square() != SQ_NONE && relative_rank(sideToMove, ep_square()) != RANK_6)
|
| 1403 |
+
return false;
|
| 1404 |
+
|
| 1405 |
+
if ((*step)++, debugKey && st->key != compute_key())
|
| 1406 |
+
return false;
|
| 1407 |
+
|
| 1408 |
+
if ((*step)++, debugPawnKey && st->pawnKey != compute_pawn_key())
|
| 1409 |
+
return false;
|
| 1410 |
+
|
| 1411 |
+
if ((*step)++, debugMaterialKey && st->materialKey != compute_material_key())
|
| 1412 |
+
return false;
|
| 1413 |
+
|
| 1414 |
+
if ((*step)++, debugIncrementalEval && st->psq != compute_psq_score())
|
| 1415 |
+
return false;
|
| 1416 |
+
|
| 1417 |
+
if ((*step)++, debugNonPawnMaterial)
|
| 1418 |
+
if ( st->npMaterial[WHITE] != compute_non_pawn_material(WHITE)
|
| 1419 |
+
|| st->npMaterial[BLACK] != compute_non_pawn_material(BLACK))
|
| 1420 |
+
return false;
|
| 1421 |
+
|
| 1422 |
+
if ((*step)++, debugPieceCounts)
|
| 1423 |
+
for (Color c = WHITE; c <= BLACK; c++)
|
| 1424 |
+
for (PieceType pt = PAWN; pt <= KING; pt++)
|
| 1425 |
+
if (pieceCount[c][pt] != popcount<Full>(pieces(c, pt)))
|
| 1426 |
+
return false;
|
| 1427 |
+
|
| 1428 |
+
if ((*step)++, debugPieceList)
|
| 1429 |
+
for (Color c = WHITE; c <= BLACK; c++)
|
| 1430 |
+
for (PieceType pt = PAWN; pt <= KING; pt++)
|
| 1431 |
+
for (int i = 0; i < pieceCount[c][pt]; i++)
|
| 1432 |
+
if ( board[pieceList[c][pt][i]] != make_piece(c, pt)
|
| 1433 |
+
|| index[pieceList[c][pt][i]] != i)
|
| 1434 |
+
return false;
|
| 1435 |
+
|
| 1436 |
+
if ((*step)++, debugCastleSquares)
|
| 1437 |
+
for (Color c = WHITE; c <= BLACK; c++)
|
| 1438 |
+
for (CastlingSide s = KING_SIDE; s <= QUEEN_SIDE; s = CastlingSide(s + 1))
|
| 1439 |
+
{
|
| 1440 |
+
CastleRight cr = make_castle_right(c, s);
|
| 1441 |
+
|
| 1442 |
+
if (!can_castle(cr))
|
| 1443 |
+
continue;
|
| 1444 |
+
|
| 1445 |
+
if ( (castleRightsMask[king_square(c)] & cr) != cr
|
| 1446 |
+
|| piece_on(castleRookSquare[c][s]) != make_piece(c, ROOK)
|
| 1447 |
+
|| castleRightsMask[castleRookSquare[c][s]] != cr)
|
| 1448 |
+
return false;
|
| 1449 |
+
}
|
| 1450 |
+
|
| 1451 |
+
*step = 0;
|
| 1452 |
+
return true;
|
| 1453 |
+
}
|
stockfish-4-win/src/position.h
ADDED
|
@@ -0,0 +1,459 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
+
Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
+
|
| 6 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 7 |
+
it under the terms of the GNU General Public License as published by
|
| 8 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 9 |
+
(at your option) any later version.
|
| 10 |
+
|
| 11 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 12 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 13 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 14 |
+
GNU General Public License for more details.
|
| 15 |
+
|
| 16 |
+
You should have received a copy of the GNU General Public License
|
| 17 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 18 |
+
*/
|
| 19 |
+
|
| 20 |
+
#ifndef POSITION_H_INCLUDED
|
| 21 |
+
#define POSITION_H_INCLUDED
|
| 22 |
+
|
| 23 |
+
#include <cassert>
|
| 24 |
+
#include <cstddef>
|
| 25 |
+
|
| 26 |
+
#include "bitboard.h"
|
| 27 |
+
#include "types.h"
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
/// The checkInfo struct is initialized at c'tor time and keeps info used
|
| 31 |
+
/// to detect if a move gives check.
|
| 32 |
+
class Position;
|
| 33 |
+
struct Thread;
|
| 34 |
+
|
| 35 |
+
struct CheckInfo {
|
| 36 |
+
|
| 37 |
+
explicit CheckInfo(const Position&);
|
| 38 |
+
|
| 39 |
+
Bitboard dcCandidates;
|
| 40 |
+
Bitboard pinned;
|
| 41 |
+
Bitboard checkSq[PIECE_TYPE_NB];
|
| 42 |
+
Square ksq;
|
| 43 |
+
};
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
/// The StateInfo struct stores information we need to restore a Position
|
| 47 |
+
/// object to its previous state when we retract a move. Whenever a move
|
| 48 |
+
/// is made on the board (by calling Position::do_move), a StateInfo object
|
| 49 |
+
/// must be passed as a parameter.
|
| 50 |
+
|
| 51 |
+
struct StateInfo {
|
| 52 |
+
Key pawnKey, materialKey;
|
| 53 |
+
Value npMaterial[COLOR_NB];
|
| 54 |
+
int castleRights, rule50, pliesFromNull;
|
| 55 |
+
Score psq;
|
| 56 |
+
Square epSquare;
|
| 57 |
+
|
| 58 |
+
Key key;
|
| 59 |
+
Bitboard checkersBB;
|
| 60 |
+
PieceType capturedType;
|
| 61 |
+
StateInfo* previous;
|
| 62 |
+
};
|
| 63 |
+
|
| 64 |
+
|
| 65 |
+
/// When making a move the current StateInfo up to 'key' excluded is copied to
|
| 66 |
+
/// the new one. Here we calculate the quad words (64bits) needed to be copied.
|
| 67 |
+
const size_t StateCopySize64 = offsetof(StateInfo, key) / sizeof(uint64_t) + 1;
|
| 68 |
+
|
| 69 |
+
|
| 70 |
+
/// The position data structure. A position consists of the following data:
|
| 71 |
+
///
|
| 72 |
+
/// * For each piece type, a bitboard representing the squares occupied
|
| 73 |
+
/// by pieces of that type.
|
| 74 |
+
/// * For each color, a bitboard representing the squares occupied by
|
| 75 |
+
/// pieces of that color.
|
| 76 |
+
/// * A bitboard of all occupied squares.
|
| 77 |
+
/// * A bitboard of all checking pieces.
|
| 78 |
+
/// * A 64-entry array of pieces, indexed by the squares of the board.
|
| 79 |
+
/// * The current side to move.
|
| 80 |
+
/// * Information about the castling rights for both sides.
|
| 81 |
+
/// * The initial files of the kings and both pairs of rooks. This is
|
| 82 |
+
/// used to implement the Chess960 castling rules.
|
| 83 |
+
/// * The en passant square (which is SQ_NONE if no en passant capture is
|
| 84 |
+
/// possible).
|
| 85 |
+
/// * The squares of the kings for both sides.
|
| 86 |
+
/// * Hash keys for the position itself, the current pawn structure, and
|
| 87 |
+
/// the current material situation.
|
| 88 |
+
/// * Hash keys for all previous positions in the game for detecting
|
| 89 |
+
/// repetition draws.
|
| 90 |
+
/// * A counter for detecting 50 move rule draws.
|
| 91 |
+
|
| 92 |
+
class Position {
|
| 93 |
+
public:
|
| 94 |
+
Position() {}
|
| 95 |
+
Position(const Position& p, Thread* t) { *this = p; thisThread = t; }
|
| 96 |
+
Position(const std::string& f, bool c960, Thread* t) { set(f, c960, t); }
|
| 97 |
+
Position& operator=(const Position&);
|
| 98 |
+
static void init();
|
| 99 |
+
|
| 100 |
+
// Text input/output
|
| 101 |
+
void set(const std::string& fen, bool isChess960, Thread* th);
|
| 102 |
+
const std::string fen() const;
|
| 103 |
+
const std::string pretty(Move m = MOVE_NONE) const;
|
| 104 |
+
|
| 105 |
+
// Position representation
|
| 106 |
+
Bitboard pieces() const;
|
| 107 |
+
Bitboard pieces(PieceType pt) const;
|
| 108 |
+
Bitboard pieces(PieceType pt1, PieceType pt2) const;
|
| 109 |
+
Bitboard pieces(Color c) const;
|
| 110 |
+
Bitboard pieces(Color c, PieceType pt) const;
|
| 111 |
+
Bitboard pieces(Color c, PieceType pt1, PieceType pt2) const;
|
| 112 |
+
Piece piece_on(Square s) const;
|
| 113 |
+
Square king_square(Color c) const;
|
| 114 |
+
Square ep_square() const;
|
| 115 |
+
bool is_empty(Square s) const;
|
| 116 |
+
template<PieceType Pt> int count(Color c) const;
|
| 117 |
+
template<PieceType Pt> const Square* list(Color c) const;
|
| 118 |
+
|
| 119 |
+
// Castling
|
| 120 |
+
int can_castle(CastleRight f) const;
|
| 121 |
+
int can_castle(Color c) const;
|
| 122 |
+
bool castle_impeded(Color c, CastlingSide s) const;
|
| 123 |
+
Square castle_rook_square(Color c, CastlingSide s) const;
|
| 124 |
+
|
| 125 |
+
// Checking
|
| 126 |
+
Bitboard checkers() const;
|
| 127 |
+
Bitboard discovered_check_candidates() const;
|
| 128 |
+
Bitboard pinned_pieces() const;
|
| 129 |
+
|
| 130 |
+
// Attacks to/from a given square
|
| 131 |
+
Bitboard attackers_to(Square s) const;
|
| 132 |
+
Bitboard attackers_to(Square s, Bitboard occ) const;
|
| 133 |
+
Bitboard attacks_from(Piece p, Square s) const;
|
| 134 |
+
static Bitboard attacks_from(Piece p, Square s, Bitboard occ);
|
| 135 |
+
template<PieceType> Bitboard attacks_from(Square s) const;
|
| 136 |
+
template<PieceType> Bitboard attacks_from(Square s, Color c) const;
|
| 137 |
+
|
| 138 |
+
// Properties of moves
|
| 139 |
+
bool move_gives_check(Move m, const CheckInfo& ci) const;
|
| 140 |
+
bool pl_move_is_legal(Move m, Bitboard pinned) const;
|
| 141 |
+
bool is_pseudo_legal(const Move m) const;
|
| 142 |
+
bool is_capture(Move m) const;
|
| 143 |
+
bool is_capture_or_promotion(Move m) const;
|
| 144 |
+
bool is_passed_pawn_push(Move m) const;
|
| 145 |
+
Piece piece_moved(Move m) const;
|
| 146 |
+
PieceType captured_piece_type() const;
|
| 147 |
+
|
| 148 |
+
// Piece specific
|
| 149 |
+
bool pawn_is_passed(Color c, Square s) const;
|
| 150 |
+
bool pawn_on_7th(Color c) const;
|
| 151 |
+
bool opposite_bishops() const;
|
| 152 |
+
bool bishop_pair(Color c) const;
|
| 153 |
+
|
| 154 |
+
// Doing and undoing moves
|
| 155 |
+
void do_move(Move m, StateInfo& st);
|
| 156 |
+
void do_move(Move m, StateInfo& st, const CheckInfo& ci, bool moveIsCheck);
|
| 157 |
+
void undo_move(Move m);
|
| 158 |
+
void do_null_move(StateInfo& st);
|
| 159 |
+
void undo_null_move();
|
| 160 |
+
|
| 161 |
+
// Static exchange evaluation
|
| 162 |
+
int see(Move m, int asymmThreshold = 0) const;
|
| 163 |
+
int see_sign(Move m) const;
|
| 164 |
+
|
| 165 |
+
// Accessing hash keys
|
| 166 |
+
Key key() const;
|
| 167 |
+
Key exclusion_key() const;
|
| 168 |
+
Key pawn_key() const;
|
| 169 |
+
Key material_key() const;
|
| 170 |
+
|
| 171 |
+
// Incremental piece-square evaluation
|
| 172 |
+
Score psq_score() const;
|
| 173 |
+
Value non_pawn_material(Color c) const;
|
| 174 |
+
|
| 175 |
+
// Other properties of the position
|
| 176 |
+
Color side_to_move() const;
|
| 177 |
+
int game_ply() const;
|
| 178 |
+
bool is_chess960() const;
|
| 179 |
+
Thread* this_thread() const;
|
| 180 |
+
int64_t nodes_searched() const;
|
| 181 |
+
void set_nodes_searched(int64_t n);
|
| 182 |
+
bool is_draw() const;
|
| 183 |
+
|
| 184 |
+
// Position consistency check, for debugging
|
| 185 |
+
bool pos_is_ok(int* failedStep = NULL) const;
|
| 186 |
+
void flip();
|
| 187 |
+
|
| 188 |
+
private:
|
| 189 |
+
// Initialization helpers (used while setting up a position)
|
| 190 |
+
void clear();
|
| 191 |
+
void set_castle_right(Color c, Square rfrom);
|
| 192 |
+
|
| 193 |
+
// Helper functions
|
| 194 |
+
void do_castle(Square kfrom, Square kto, Square rfrom, Square rto);
|
| 195 |
+
Bitboard hidden_checkers(Square ksq, Color c) const;
|
| 196 |
+
void put_piece(Square s, Color c, PieceType pt);
|
| 197 |
+
void remove_piece(Square s, Color c, PieceType pt);
|
| 198 |
+
void move_piece(Square from, Square to, Color c, PieceType pt);
|
| 199 |
+
|
| 200 |
+
// Computing hash keys from scratch (for initialization and debugging)
|
| 201 |
+
Key compute_key() const;
|
| 202 |
+
Key compute_pawn_key() const;
|
| 203 |
+
Key compute_material_key() const;
|
| 204 |
+
|
| 205 |
+
// Computing incremental evaluation scores and material counts
|
| 206 |
+
Score compute_psq_score() const;
|
| 207 |
+
Value compute_non_pawn_material(Color c) const;
|
| 208 |
+
|
| 209 |
+
// Board and pieces
|
| 210 |
+
Piece board[SQUARE_NB];
|
| 211 |
+
Bitboard byTypeBB[PIECE_TYPE_NB];
|
| 212 |
+
Bitboard byColorBB[COLOR_NB];
|
| 213 |
+
int pieceCount[COLOR_NB][PIECE_TYPE_NB];
|
| 214 |
+
Square pieceList[COLOR_NB][PIECE_TYPE_NB][16];
|
| 215 |
+
int index[SQUARE_NB];
|
| 216 |
+
|
| 217 |
+
// Other info
|
| 218 |
+
int castleRightsMask[SQUARE_NB];
|
| 219 |
+
Square castleRookSquare[COLOR_NB][CASTLING_SIDE_NB];
|
| 220 |
+
Bitboard castlePath[COLOR_NB][CASTLING_SIDE_NB];
|
| 221 |
+
StateInfo startState;
|
| 222 |
+
int64_t nodes;
|
| 223 |
+
int gamePly;
|
| 224 |
+
Color sideToMove;
|
| 225 |
+
Thread* thisThread;
|
| 226 |
+
StateInfo* st;
|
| 227 |
+
int chess960;
|
| 228 |
+
};
|
| 229 |
+
|
| 230 |
+
inline int64_t Position::nodes_searched() const {
|
| 231 |
+
return nodes;
|
| 232 |
+
}
|
| 233 |
+
|
| 234 |
+
inline void Position::set_nodes_searched(int64_t n) {
|
| 235 |
+
nodes = n;
|
| 236 |
+
}
|
| 237 |
+
|
| 238 |
+
inline Piece Position::piece_on(Square s) const {
|
| 239 |
+
return board[s];
|
| 240 |
+
}
|
| 241 |
+
|
| 242 |
+
inline Piece Position::piece_moved(Move m) const {
|
| 243 |
+
return board[from_sq(m)];
|
| 244 |
+
}
|
| 245 |
+
|
| 246 |
+
inline bool Position::is_empty(Square s) const {
|
| 247 |
+
return board[s] == NO_PIECE;
|
| 248 |
+
}
|
| 249 |
+
|
| 250 |
+
inline Color Position::side_to_move() const {
|
| 251 |
+
return sideToMove;
|
| 252 |
+
}
|
| 253 |
+
|
| 254 |
+
inline Bitboard Position::pieces() const {
|
| 255 |
+
return byTypeBB[ALL_PIECES];
|
| 256 |
+
}
|
| 257 |
+
|
| 258 |
+
inline Bitboard Position::pieces(PieceType pt) const {
|
| 259 |
+
return byTypeBB[pt];
|
| 260 |
+
}
|
| 261 |
+
|
| 262 |
+
inline Bitboard Position::pieces(PieceType pt1, PieceType pt2) const {
|
| 263 |
+
return byTypeBB[pt1] | byTypeBB[pt2];
|
| 264 |
+
}
|
| 265 |
+
|
| 266 |
+
inline Bitboard Position::pieces(Color c) const {
|
| 267 |
+
return byColorBB[c];
|
| 268 |
+
}
|
| 269 |
+
|
| 270 |
+
inline Bitboard Position::pieces(Color c, PieceType pt) const {
|
| 271 |
+
return byColorBB[c] & byTypeBB[pt];
|
| 272 |
+
}
|
| 273 |
+
|
| 274 |
+
inline Bitboard Position::pieces(Color c, PieceType pt1, PieceType pt2) const {
|
| 275 |
+
return byColorBB[c] & (byTypeBB[pt1] | byTypeBB[pt2]);
|
| 276 |
+
}
|
| 277 |
+
|
| 278 |
+
template<PieceType Pt> inline int Position::count(Color c) const {
|
| 279 |
+
return pieceCount[c][Pt];
|
| 280 |
+
}
|
| 281 |
+
|
| 282 |
+
template<PieceType Pt> inline const Square* Position::list(Color c) const {
|
| 283 |
+
return pieceList[c][Pt];
|
| 284 |
+
}
|
| 285 |
+
|
| 286 |
+
inline Square Position::ep_square() const {
|
| 287 |
+
return st->epSquare;
|
| 288 |
+
}
|
| 289 |
+
|
| 290 |
+
inline Square Position::king_square(Color c) const {
|
| 291 |
+
return pieceList[c][KING][0];
|
| 292 |
+
}
|
| 293 |
+
|
| 294 |
+
inline int Position::can_castle(CastleRight f) const {
|
| 295 |
+
return st->castleRights & f;
|
| 296 |
+
}
|
| 297 |
+
|
| 298 |
+
inline int Position::can_castle(Color c) const {
|
| 299 |
+
return st->castleRights & ((WHITE_OO | WHITE_OOO) << (2 * c));
|
| 300 |
+
}
|
| 301 |
+
|
| 302 |
+
inline bool Position::castle_impeded(Color c, CastlingSide s) const {
|
| 303 |
+
return byTypeBB[ALL_PIECES] & castlePath[c][s];
|
| 304 |
+
}
|
| 305 |
+
|
| 306 |
+
inline Square Position::castle_rook_square(Color c, CastlingSide s) const {
|
| 307 |
+
return castleRookSquare[c][s];
|
| 308 |
+
}
|
| 309 |
+
|
| 310 |
+
template<PieceType Pt>
|
| 311 |
+
inline Bitboard Position::attacks_from(Square s) const {
|
| 312 |
+
|
| 313 |
+
return Pt == BISHOP || Pt == ROOK ? attacks_bb<Pt>(s, pieces())
|
| 314 |
+
: Pt == QUEEN ? attacks_from<ROOK>(s) | attacks_from<BISHOP>(s)
|
| 315 |
+
: StepAttacksBB[Pt][s];
|
| 316 |
+
}
|
| 317 |
+
|
| 318 |
+
template<>
|
| 319 |
+
inline Bitboard Position::attacks_from<PAWN>(Square s, Color c) const {
|
| 320 |
+
return StepAttacksBB[make_piece(c, PAWN)][s];
|
| 321 |
+
}
|
| 322 |
+
|
| 323 |
+
inline Bitboard Position::attacks_from(Piece p, Square s) const {
|
| 324 |
+
return attacks_from(p, s, byTypeBB[ALL_PIECES]);
|
| 325 |
+
}
|
| 326 |
+
|
| 327 |
+
inline Bitboard Position::attackers_to(Square s) const {
|
| 328 |
+
return attackers_to(s, byTypeBB[ALL_PIECES]);
|
| 329 |
+
}
|
| 330 |
+
|
| 331 |
+
inline Bitboard Position::checkers() const {
|
| 332 |
+
return st->checkersBB;
|
| 333 |
+
}
|
| 334 |
+
|
| 335 |
+
inline Bitboard Position::discovered_check_candidates() const {
|
| 336 |
+
return hidden_checkers(king_square(~sideToMove), sideToMove);
|
| 337 |
+
}
|
| 338 |
+
|
| 339 |
+
inline Bitboard Position::pinned_pieces() const {
|
| 340 |
+
return hidden_checkers(king_square(sideToMove), ~sideToMove);
|
| 341 |
+
}
|
| 342 |
+
|
| 343 |
+
inline bool Position::pawn_is_passed(Color c, Square s) const {
|
| 344 |
+
return !(pieces(~c, PAWN) & passed_pawn_mask(c, s));
|
| 345 |
+
}
|
| 346 |
+
|
| 347 |
+
inline Key Position::key() const {
|
| 348 |
+
return st->key;
|
| 349 |
+
}
|
| 350 |
+
|
| 351 |
+
inline Key Position::pawn_key() const {
|
| 352 |
+
return st->pawnKey;
|
| 353 |
+
}
|
| 354 |
+
|
| 355 |
+
inline Key Position::material_key() const {
|
| 356 |
+
return st->materialKey;
|
| 357 |
+
}
|
| 358 |
+
|
| 359 |
+
inline Score Position::psq_score() const {
|
| 360 |
+
return st->psq;
|
| 361 |
+
}
|
| 362 |
+
|
| 363 |
+
inline Value Position::non_pawn_material(Color c) const {
|
| 364 |
+
return st->npMaterial[c];
|
| 365 |
+
}
|
| 366 |
+
|
| 367 |
+
inline bool Position::is_passed_pawn_push(Move m) const {
|
| 368 |
+
|
| 369 |
+
return type_of(piece_moved(m)) == PAWN
|
| 370 |
+
&& pawn_is_passed(sideToMove, to_sq(m));
|
| 371 |
+
}
|
| 372 |
+
|
| 373 |
+
inline int Position::game_ply() const {
|
| 374 |
+
return gamePly;
|
| 375 |
+
}
|
| 376 |
+
|
| 377 |
+
inline bool Position::opposite_bishops() const {
|
| 378 |
+
|
| 379 |
+
return pieceCount[WHITE][BISHOP] == 1
|
| 380 |
+
&& pieceCount[BLACK][BISHOP] == 1
|
| 381 |
+
&& opposite_colors(pieceList[WHITE][BISHOP][0], pieceList[BLACK][BISHOP][0]);
|
| 382 |
+
}
|
| 383 |
+
|
| 384 |
+
inline bool Position::bishop_pair(Color c) const {
|
| 385 |
+
|
| 386 |
+
return pieceCount[c][BISHOP] >= 2
|
| 387 |
+
&& opposite_colors(pieceList[c][BISHOP][0], pieceList[c][BISHOP][1]);
|
| 388 |
+
}
|
| 389 |
+
|
| 390 |
+
inline bool Position::pawn_on_7th(Color c) const {
|
| 391 |
+
return pieces(c, PAWN) & rank_bb(relative_rank(c, RANK_7));
|
| 392 |
+
}
|
| 393 |
+
|
| 394 |
+
inline bool Position::is_chess960() const {
|
| 395 |
+
return chess960;
|
| 396 |
+
}
|
| 397 |
+
|
| 398 |
+
inline bool Position::is_capture_or_promotion(Move m) const {
|
| 399 |
+
|
| 400 |
+
assert(is_ok(m));
|
| 401 |
+
return type_of(m) ? type_of(m) != CASTLE : !is_empty(to_sq(m));
|
| 402 |
+
}
|
| 403 |
+
|
| 404 |
+
inline bool Position::is_capture(Move m) const {
|
| 405 |
+
|
| 406 |
+
// Note that castle is coded as "king captures the rook"
|
| 407 |
+
assert(is_ok(m));
|
| 408 |
+
return (!is_empty(to_sq(m)) && type_of(m) != CASTLE) || type_of(m) == ENPASSANT;
|
| 409 |
+
}
|
| 410 |
+
|
| 411 |
+
inline PieceType Position::captured_piece_type() const {
|
| 412 |
+
return st->capturedType;
|
| 413 |
+
}
|
| 414 |
+
|
| 415 |
+
inline Thread* Position::this_thread() const {
|
| 416 |
+
return thisThread;
|
| 417 |
+
}
|
| 418 |
+
|
| 419 |
+
inline void Position::put_piece(Square s, Color c, PieceType pt) {
|
| 420 |
+
|
| 421 |
+
board[s] = make_piece(c, pt);
|
| 422 |
+
byTypeBB[ALL_PIECES] |= s;
|
| 423 |
+
byTypeBB[pt] |= s;
|
| 424 |
+
byColorBB[c] |= s;
|
| 425 |
+
index[s] = pieceCount[c][pt]++;
|
| 426 |
+
pieceList[c][pt][index[s]] = s;
|
| 427 |
+
}
|
| 428 |
+
|
| 429 |
+
inline void Position::move_piece(Square from, Square to, Color c, PieceType pt) {
|
| 430 |
+
|
| 431 |
+
// index[from] is not updated and becomes stale. This works as long
|
| 432 |
+
// as index[] is accessed just by known occupied squares.
|
| 433 |
+
Bitboard from_to_bb = SquareBB[from] ^ SquareBB[to];
|
| 434 |
+
byTypeBB[ALL_PIECES] ^= from_to_bb;
|
| 435 |
+
byTypeBB[pt] ^= from_to_bb;
|
| 436 |
+
byColorBB[c] ^= from_to_bb;
|
| 437 |
+
board[from] = NO_PIECE;
|
| 438 |
+
board[to] = make_piece(c, pt);
|
| 439 |
+
index[to] = index[from];
|
| 440 |
+
pieceList[c][pt][index[to]] = to;
|
| 441 |
+
}
|
| 442 |
+
|
| 443 |
+
inline void Position::remove_piece(Square s, Color c, PieceType pt) {
|
| 444 |
+
|
| 445 |
+
// WARNING: This is not a reversible operation. If we remove a piece in
|
| 446 |
+
// do_move() and then replace it in undo_move() we will put it at the end of
|
| 447 |
+
// the list and not in its original place, it means index[] and pieceList[]
|
| 448 |
+
// are not guaranteed to be invariant to a do_move() + undo_move() sequence.
|
| 449 |
+
byTypeBB[ALL_PIECES] ^= s;
|
| 450 |
+
byTypeBB[pt] ^= s;
|
| 451 |
+
byColorBB[c] ^= s;
|
| 452 |
+
/* board[s] = NO_PIECE; */ // Not needed, will be overwritten by capturing
|
| 453 |
+
Square lastSquare = pieceList[c][pt][--pieceCount[c][pt]];
|
| 454 |
+
index[lastSquare] = index[s];
|
| 455 |
+
pieceList[c][pt][index[lastSquare]] = lastSquare;
|
| 456 |
+
pieceList[c][pt][pieceCount[c][pt]] = SQ_NONE;
|
| 457 |
+
}
|
| 458 |
+
|
| 459 |
+
#endif // #ifndef POSITION_H_INCLUDED
|
stockfish-4-win/src/psqtab.h
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
+
Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
+
|
| 6 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 7 |
+
it under the terms of the GNU General Public License as published by
|
| 8 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 9 |
+
(at your option) any later version.
|
| 10 |
+
|
| 11 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 12 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 13 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 14 |
+
GNU General Public License for more details.
|
| 15 |
+
|
| 16 |
+
You should have received a copy of the GNU General Public License
|
| 17 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 18 |
+
*/
|
| 19 |
+
|
| 20 |
+
#ifndef PSQTAB_H_INCLUDED
|
| 21 |
+
#define PSQTAB_H_INCLUDED
|
| 22 |
+
|
| 23 |
+
#include "types.h"
|
| 24 |
+
|
| 25 |
+
#define S(mg, eg) make_score(mg, eg)
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
/// PSQT[PieceType][Square] contains Piece-Square scores. For each piece type on
|
| 29 |
+
/// a given square a (midgame, endgame) score pair is assigned. PSQT is defined
|
| 30 |
+
/// for white side, for black side the tables are symmetric.
|
| 31 |
+
|
| 32 |
+
static const Score PSQT[][SQUARE_NB] = {
|
| 33 |
+
{ },
|
| 34 |
+
{ // Pawn
|
| 35 |
+
S( 0, 0), S( 0, 0), S( 0, 0), S( 0, 0), S(0, 0), S( 0, 0), S( 0, 0), S( 0, 0),
|
| 36 |
+
S(-20,-8), S(-6,-8), S( 4,-8), S(14,-8), S(14,-8), S( 4,-8), S(-6,-8), S(-20,-8),
|
| 37 |
+
S(-20,-8), S(-6,-8), S( 9,-8), S(34,-8), S(34,-8), S( 9,-8), S(-6,-8), S(-20,-8),
|
| 38 |
+
S(-20,-8), S(-6,-8), S(17,-8), S(54,-8), S(54,-8), S(17,-8), S(-6,-8), S(-20,-8),
|
| 39 |
+
S(-20,-8), S(-6,-8), S(17,-8), S(34,-8), S(34,-8), S(17,-8), S(-6,-8), S(-20,-8),
|
| 40 |
+
S(-20,-8), S(-6,-8), S( 9,-8), S(14,-8), S(14,-8), S( 9,-8), S(-6,-8), S(-20,-8),
|
| 41 |
+
S(-20,-8), S(-6,-8), S( 4,-8), S(14,-8), S(14,-8), S( 4,-8), S(-6,-8), S(-20,-8),
|
| 42 |
+
S( 0, 0), S( 0, 0), S( 0, 0), S( 0, 0), S(0, 0), S( 0, 0), S( 0, 0), S( 0, 0)
|
| 43 |
+
},
|
| 44 |
+
{ // Knight
|
| 45 |
+
S(-135,-104), S(-107,-79), S(-80,-55), S(-67,-42), S(-67,-42), S(-80,-55), S(-107,-79), S(-135,-104),
|
| 46 |
+
S( -93, -79), S( -67,-55), S(-39,-30), S(-25,-17), S(-25,-17), S(-39,-30), S( -67,-55), S( -93, -79),
|
| 47 |
+
S( -53, -55), S( -25,-30), S( 1, -6), S( 13, 5), S( 13, 5), S( 1, -6), S( -25,-30), S( -53, -55),
|
| 48 |
+
S( -25, -42), S( 1,-17), S( 27, 5), S( 41, 18), S( 41, 18), S( 27, 5), S( 1,-17), S( -25, -42),
|
| 49 |
+
S( -11, -42), S( 13,-17), S( 41, 5), S( 55, 18), S( 55, 18), S( 41, 5), S( 13,-17), S( -11, -42),
|
| 50 |
+
S( -11, -55), S( 13,-30), S( 41, -6), S( 55, 5), S( 55, 5), S( 41, -6), S( 13,-30), S( -11, -55),
|
| 51 |
+
S( -53, -79), S( -25,-55), S( 1,-30), S( 13,-17), S( 13,-17), S( 1,-30), S( -25,-55), S( -53, -79),
|
| 52 |
+
S(-193,-104), S( -67,-79), S(-39,-55), S(-25,-42), S(-25,-42), S(-39,-55), S( -67,-79), S(-193,-104)
|
| 53 |
+
},
|
| 54 |
+
{ // Bishop
|
| 55 |
+
S(-40,-59), S(-40,-42), S(-35,-35), S(-30,-26), S(-30,-26), S(-35,-35), S(-40,-42), S(-40,-59),
|
| 56 |
+
S(-17,-42), S( 0,-26), S( -4,-18), S( 0,-11), S( 0,-11), S( -4,-18), S( 0,-26), S(-17,-42),
|
| 57 |
+
S(-13,-35), S( -4,-18), S( 8,-11), S( 4, -4), S( 4, -4), S( 8,-11), S( -4,-18), S(-13,-35),
|
| 58 |
+
S( -8,-26), S( 0,-11), S( 4, -4), S( 17, 4), S( 17, 4), S( 4, -4), S( 0,-11), S( -8,-26),
|
| 59 |
+
S( -8,-26), S( 0,-11), S( 4, -4), S( 17, 4), S( 17, 4), S( 4, -4), S( 0,-11), S( -8,-26),
|
| 60 |
+
S(-13,-35), S( -4,-18), S( 8,-11), S( 4, -4), S( 4, -4), S( 8,-11), S( -4,-18), S(-13,-35),
|
| 61 |
+
S(-17,-42), S( 0,-26), S( -4,-18), S( 0,-11), S( 0,-11), S( -4,-18), S( 0,-26), S(-17,-42),
|
| 62 |
+
S(-17,-59), S(-17,-42), S(-13,-35), S( -8,-26), S( -8,-26), S(-13,-35), S(-17,-42), S(-17,-59)
|
| 63 |
+
},
|
| 64 |
+
{ // Rook
|
| 65 |
+
S(-12, 3), S(-7, 3), S(-2, 3), S(2, 3), S(2, 3), S(-2, 3), S(-7, 3), S(-12, 3),
|
| 66 |
+
S(-12, 3), S(-7, 3), S(-2, 3), S(2, 3), S(2, 3), S(-2, 3), S(-7, 3), S(-12, 3),
|
| 67 |
+
S(-12, 3), S(-7, 3), S(-2, 3), S(2, 3), S(2, 3), S(-2, 3), S(-7, 3), S(-12, 3),
|
| 68 |
+
S(-12, 3), S(-7, 3), S(-2, 3), S(2, 3), S(2, 3), S(-2, 3), S(-7, 3), S(-12, 3),
|
| 69 |
+
S(-12, 3), S(-7, 3), S(-2, 3), S(2, 3), S(2, 3), S(-2, 3), S(-7, 3), S(-12, 3),
|
| 70 |
+
S(-12, 3), S(-7, 3), S(-2, 3), S(2, 3), S(2, 3), S(-2, 3), S(-7, 3), S(-12, 3),
|
| 71 |
+
S(-12, 3), S(-7, 3), S(-2, 3), S(2, 3), S(2, 3), S(-2, 3), S(-7, 3), S(-12, 3),
|
| 72 |
+
S(-12, 3), S(-7, 3), S(-2, 3), S(2, 3), S(2, 3), S(-2, 3), S(-7, 3), S(-12, 3)
|
| 73 |
+
},
|
| 74 |
+
{ // Queen
|
| 75 |
+
S(8,-80), S(8,-54), S(8,-42), S(8,-30), S(8,-30), S(8,-42), S(8,-54), S(8,-80),
|
| 76 |
+
S(8,-54), S(8,-30), S(8,-18), S(8, -6), S(8, -6), S(8,-18), S(8,-30), S(8,-54),
|
| 77 |
+
S(8,-42), S(8,-18), S(8, -6), S(8, 6), S(8, 6), S(8, -6), S(8,-18), S(8,-42),
|
| 78 |
+
S(8,-30), S(8, -6), S(8, 6), S(8, 18), S(8, 18), S(8, 6), S(8, -6), S(8,-30),
|
| 79 |
+
S(8,-30), S(8, -6), S(8, 6), S(8, 18), S(8, 18), S(8, 6), S(8, -6), S(8,-30),
|
| 80 |
+
S(8,-42), S(8,-18), S(8, -6), S(8, 6), S(8, 6), S(8, -6), S(8,-18), S(8,-42),
|
| 81 |
+
S(8,-54), S(8,-30), S(8,-18), S(8, -6), S(8, -6), S(8,-18), S(8,-30), S(8,-54),
|
| 82 |
+
S(8,-80), S(8,-54), S(8,-42), S(8,-30), S(8,-30), S(8,-42), S(8,-54), S(8,-80)
|
| 83 |
+
},
|
| 84 |
+
{ // King
|
| 85 |
+
S(287, 18), S(311, 77), S(262,105), S(214,135), S(214,135), S(262,105), S(311, 77), S(287, 18),
|
| 86 |
+
S(262, 77), S(287,135), S(238,165), S(190,193), S(190,193), S(238,165), S(287,135), S(262, 77),
|
| 87 |
+
S(214,105), S(238,165), S(190,193), S(142,222), S(142,222), S(190,193), S(238,165), S(214,105),
|
| 88 |
+
S(190,135), S(214,193), S(167,222), S(119,251), S(119,251), S(167,222), S(214,193), S(190,135),
|
| 89 |
+
S(167,135), S(190,193), S(142,222), S( 94,251), S( 94,251), S(142,222), S(190,193), S(167,135),
|
| 90 |
+
S(142,105), S(167,165), S(119,193), S( 69,222), S( 69,222), S(119,193), S(167,165), S(142,105),
|
| 91 |
+
S(119, 77), S(142,135), S( 94,165), S( 46,193), S( 46,193), S( 94,165), S(142,135), S(119, 77),
|
| 92 |
+
S(94, 18), S(119, 77), S( 69,105), S( 21,135), S( 21,135), S( 69,105), S(119, 77), S( 94, 18)
|
| 93 |
+
}
|
| 94 |
+
};
|
| 95 |
+
|
| 96 |
+
#undef S
|
| 97 |
+
|
| 98 |
+
#endif // #ifndef PSQTAB_H_INCLUDED
|
stockfish-4-win/src/rkiss.h
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
+
Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
+
|
| 6 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 7 |
+
it under the terms of the GNU General Public License as published by
|
| 8 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 9 |
+
(at your option) any later version.
|
| 10 |
+
|
| 11 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 12 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 13 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 14 |
+
GNU General Public License for more details.
|
| 15 |
+
|
| 16 |
+
You should have received a copy of the GNU General Public License
|
| 17 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 18 |
+
|
| 19 |
+
This file is based on original code by Heinz van Saanen and is
|
| 20 |
+
available under the GNU General Public License as published by
|
| 21 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 22 |
+
(at your option) any later version.
|
| 23 |
+
*/
|
| 24 |
+
|
| 25 |
+
#ifndef RKISS_H_INCLUDED
|
| 26 |
+
#define RKISS_H_INCLUDED
|
| 27 |
+
|
| 28 |
+
#include "types.h"
|
| 29 |
+
|
| 30 |
+
/// RKISS is our pseudo random number generator (PRNG) used to compute hash keys.
|
| 31 |
+
/// George Marsaglia invented the RNG-Kiss-family in the early 90's. This is a
|
| 32 |
+
/// specific version that Heinz van Saanen derived from some public domain code
|
| 33 |
+
/// by Bob Jenkins. Following the feature list, as tested by Heinz.
|
| 34 |
+
///
|
| 35 |
+
/// - Quite platform independent
|
| 36 |
+
/// - Passes ALL dieharder tests! Here *nix sys-rand() e.g. fails miserably:-)
|
| 37 |
+
/// - ~12 times faster than my *nix sys-rand()
|
| 38 |
+
/// - ~4 times faster than SSE2-version of Mersenne twister
|
| 39 |
+
/// - Average cycle length: ~2^126
|
| 40 |
+
/// - 64 bit seed
|
| 41 |
+
/// - Return doubles with a full 53 bit mantissa
|
| 42 |
+
/// - Thread safe
|
| 43 |
+
|
| 44 |
+
class RKISS {
|
| 45 |
+
|
| 46 |
+
struct S { uint64_t a, b, c, d; } s; // Keep variables always together
|
| 47 |
+
|
| 48 |
+
uint64_t rotate(uint64_t x, uint64_t k) const {
|
| 49 |
+
return (x << k) | (x >> (64 - k));
|
| 50 |
+
}
|
| 51 |
+
|
| 52 |
+
uint64_t rand64() {
|
| 53 |
+
|
| 54 |
+
const uint64_t
|
| 55 |
+
e = s.a - rotate(s.b, 7);
|
| 56 |
+
s.a = s.b ^ rotate(s.c, 13);
|
| 57 |
+
s.b = s.c + rotate(s.d, 37);
|
| 58 |
+
s.c = s.d + e;
|
| 59 |
+
return s.d = e + s.a;
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
public:
|
| 63 |
+
RKISS(int seed = 73) {
|
| 64 |
+
|
| 65 |
+
s.a = 0xf1ea5eed;
|
| 66 |
+
s.b = s.c = s.d = 0xd4e12c77;
|
| 67 |
+
for (int i = 0; i < seed; i++) // Scramble a few rounds
|
| 68 |
+
rand64();
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
template<typename T> T rand() { return T(rand64()); }
|
| 72 |
+
};
|
| 73 |
+
|
| 74 |
+
#endif // #ifndef RKISS_H_INCLUDED
|
stockfish-4-win/src/search.cpp
ADDED
|
@@ -0,0 +1,1810 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
+
Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
+
|
| 6 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 7 |
+
it under the terms of the GNU General Public License as published by
|
| 8 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 9 |
+
(at your option) any later version.
|
| 10 |
+
|
| 11 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 12 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 13 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 14 |
+
GNU General Public License for more details.
|
| 15 |
+
|
| 16 |
+
You should have received a copy of the GNU General Public License
|
| 17 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 18 |
+
*/
|
| 19 |
+
|
| 20 |
+
#include <algorithm>
|
| 21 |
+
#include <cassert>
|
| 22 |
+
#include <cmath>
|
| 23 |
+
#include <cstring>
|
| 24 |
+
#include <iostream>
|
| 25 |
+
#include <sstream>
|
| 26 |
+
|
| 27 |
+
#include "book.h"
|
| 28 |
+
#include "evaluate.h"
|
| 29 |
+
#include "movegen.h"
|
| 30 |
+
#include "movepick.h"
|
| 31 |
+
#include "notation.h"
|
| 32 |
+
#include "search.h"
|
| 33 |
+
#include "timeman.h"
|
| 34 |
+
#include "thread.h"
|
| 35 |
+
#include "tt.h"
|
| 36 |
+
#include "ucioption.h"
|
| 37 |
+
|
| 38 |
+
namespace Search {
|
| 39 |
+
|
| 40 |
+
volatile SignalsType Signals;
|
| 41 |
+
LimitsType Limits;
|
| 42 |
+
std::vector<RootMove> RootMoves;
|
| 43 |
+
Position RootPos;
|
| 44 |
+
Color RootColor;
|
| 45 |
+
Time::point SearchTime;
|
| 46 |
+
StateStackPtr SetupStates;
|
| 47 |
+
}
|
| 48 |
+
|
| 49 |
+
using std::string;
|
| 50 |
+
using Eval::evaluate;
|
| 51 |
+
using namespace Search;
|
| 52 |
+
|
| 53 |
+
namespace {
|
| 54 |
+
|
| 55 |
+
// Set to true to force running with one thread. Used for debugging
|
| 56 |
+
const bool FakeSplit = false;
|
| 57 |
+
|
| 58 |
+
// This is the minimum interval in msec between two check_time() calls
|
| 59 |
+
const int TimerResolution = 5;
|
| 60 |
+
|
| 61 |
+
// Different node types, used as template parameter
|
| 62 |
+
enum NodeType { Root, PV, NonPV, SplitPointRoot, SplitPointPV, SplitPointNonPV };
|
| 63 |
+
|
| 64 |
+
// Dynamic razoring margin based on depth
|
| 65 |
+
inline Value razor_margin(Depth d) { return Value(512 + 16 * int(d)); }
|
| 66 |
+
|
| 67 |
+
// Futility lookup tables (initialized at startup) and their access functions
|
| 68 |
+
Value FutilityMargins[16][64]; // [depth][moveNumber]
|
| 69 |
+
int FutilityMoveCounts[2][32]; // [improving][depth]
|
| 70 |
+
|
| 71 |
+
inline Value futility_margin(Depth d, int mn) {
|
| 72 |
+
|
| 73 |
+
return d < 7 * ONE_PLY ? FutilityMargins[std::max(int(d), 1)][std::min(mn, 63)]
|
| 74 |
+
: 2 * VALUE_INFINITE;
|
| 75 |
+
}
|
| 76 |
+
|
| 77 |
+
// Reduction lookup tables (initialized at startup) and their access function
|
| 78 |
+
int8_t Reductions[2][2][64][64]; // [pv][improving][depth][moveNumber]
|
| 79 |
+
|
| 80 |
+
template <bool PvNode> inline Depth reduction(bool i, Depth d, int mn) {
|
| 81 |
+
|
| 82 |
+
return (Depth) Reductions[PvNode][i][std::min(int(d) / ONE_PLY, 63)][std::min(mn, 63)];
|
| 83 |
+
}
|
| 84 |
+
|
| 85 |
+
size_t PVSize, PVIdx;
|
| 86 |
+
TimeManager TimeMgr;
|
| 87 |
+
int BestMoveChanges;
|
| 88 |
+
Value DrawValue[COLOR_NB];
|
| 89 |
+
HistoryStats History;
|
| 90 |
+
GainsStats Gains;
|
| 91 |
+
CountermovesStats Countermoves;
|
| 92 |
+
|
| 93 |
+
template <NodeType NT>
|
| 94 |
+
Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, bool cutNode);
|
| 95 |
+
|
| 96 |
+
template <NodeType NT, bool InCheck>
|
| 97 |
+
Value qsearch(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth);
|
| 98 |
+
|
| 99 |
+
void id_loop(Position& pos);
|
| 100 |
+
Value value_to_tt(Value v, int ply);
|
| 101 |
+
Value value_from_tt(Value v, int ply);
|
| 102 |
+
bool check_is_dangerous(const Position& pos, Move move, Value futilityBase, Value beta);
|
| 103 |
+
bool allows(const Position& pos, Move first, Move second);
|
| 104 |
+
bool refutes(const Position& pos, Move first, Move second);
|
| 105 |
+
string uci_pv(const Position& pos, int depth, Value alpha, Value beta);
|
| 106 |
+
|
| 107 |
+
struct Skill {
|
| 108 |
+
Skill(int l) : level(l), best(MOVE_NONE) {}
|
| 109 |
+
~Skill() {
|
| 110 |
+
if (enabled()) // Swap best PV line with the sub-optimal one
|
| 111 |
+
std::swap(RootMoves[0], *std::find(RootMoves.begin(),
|
| 112 |
+
RootMoves.end(), best ? best : pick_move()));
|
| 113 |
+
}
|
| 114 |
+
|
| 115 |
+
bool enabled() const { return level < 20; }
|
| 116 |
+
bool time_to_pick(int depth) const { return depth == 1 + level; }
|
| 117 |
+
Move pick_move();
|
| 118 |
+
|
| 119 |
+
int level;
|
| 120 |
+
Move best;
|
| 121 |
+
};
|
| 122 |
+
|
| 123 |
+
} // namespace
|
| 124 |
+
|
| 125 |
+
|
| 126 |
+
/// Search::init() is called during startup to initialize various lookup tables
|
| 127 |
+
|
| 128 |
+
void Search::init() {
|
| 129 |
+
|
| 130 |
+
int d; // depth (ONE_PLY == 2)
|
| 131 |
+
int hd; // half depth (ONE_PLY == 1)
|
| 132 |
+
int mc; // moveCount
|
| 133 |
+
|
| 134 |
+
// Init reductions array
|
| 135 |
+
for (hd = 1; hd < 64; hd++) for (mc = 1; mc < 64; mc++)
|
| 136 |
+
{
|
| 137 |
+
double pvRed = log(double(hd)) * log(double(mc)) / 3.0;
|
| 138 |
+
double nonPVRed = 0.33 + log(double(hd)) * log(double(mc)) / 2.25;
|
| 139 |
+
Reductions[1][1][hd][mc] = (int8_t) ( pvRed >= 1.0 ? floor( pvRed * int(ONE_PLY)) : 0);
|
| 140 |
+
Reductions[0][1][hd][mc] = (int8_t) (nonPVRed >= 1.0 ? floor(nonPVRed * int(ONE_PLY)) : 0);
|
| 141 |
+
|
| 142 |
+
Reductions[1][0][hd][mc] = Reductions[1][1][hd][mc];
|
| 143 |
+
Reductions[0][0][hd][mc] = Reductions[0][1][hd][mc];
|
| 144 |
+
|
| 145 |
+
if (Reductions[0][0][hd][mc] > 2 * ONE_PLY)
|
| 146 |
+
Reductions[0][0][hd][mc] += ONE_PLY;
|
| 147 |
+
}
|
| 148 |
+
|
| 149 |
+
// Init futility margins array
|
| 150 |
+
for (d = 1; d < 16; d++) for (mc = 0; mc < 64; mc++)
|
| 151 |
+
FutilityMargins[d][mc] = Value(112 * int(log(double(d * d) / 2) / log(2.0) + 1.001) - 8 * mc + 45);
|
| 152 |
+
|
| 153 |
+
// Init futility move count array
|
| 154 |
+
for (d = 0; d < 32; d++)
|
| 155 |
+
{
|
| 156 |
+
FutilityMoveCounts[0][d] = int(3.001 + 0.3 * pow(double(d ), 1.8)) * (d < 5 ? 4 : 3) / 4;
|
| 157 |
+
FutilityMoveCounts[1][d] = int(3.001 + 0.3 * pow(double(d + 0.98), 1.8));
|
| 158 |
+
}
|
| 159 |
+
}
|
| 160 |
+
|
| 161 |
+
|
| 162 |
+
/// Search::perft() is our utility to verify move generation. All the leaf nodes
|
| 163 |
+
/// up to the given depth are generated and counted and the sum returned.
|
| 164 |
+
|
| 165 |
+
static size_t perft(Position& pos, Depth depth) {
|
| 166 |
+
|
| 167 |
+
StateInfo st;
|
| 168 |
+
size_t cnt = 0;
|
| 169 |
+
CheckInfo ci(pos);
|
| 170 |
+
const bool leaf = depth == 2 * ONE_PLY;
|
| 171 |
+
|
| 172 |
+
for (MoveList<LEGAL> it(pos); *it; ++it)
|
| 173 |
+
{
|
| 174 |
+
pos.do_move(*it, st, ci, pos.move_gives_check(*it, ci));
|
| 175 |
+
cnt += leaf ? MoveList<LEGAL>(pos).size() : ::perft(pos, depth - ONE_PLY);
|
| 176 |
+
pos.undo_move(*it);
|
| 177 |
+
}
|
| 178 |
+
return cnt;
|
| 179 |
+
}
|
| 180 |
+
|
| 181 |
+
size_t Search::perft(Position& pos, Depth depth) {
|
| 182 |
+
return depth > ONE_PLY ? ::perft(pos, depth) : MoveList<LEGAL>(pos).size();
|
| 183 |
+
}
|
| 184 |
+
|
| 185 |
+
/// Search::think() is the external interface to Stockfish's search, and is
|
| 186 |
+
/// called by the main thread when the program receives the UCI 'go' command. It
|
| 187 |
+
/// searches from RootPos and at the end prints the "bestmove" to output.
|
| 188 |
+
|
| 189 |
+
void Search::think() {
|
| 190 |
+
|
| 191 |
+
static PolyglotBook book; // Defined static to initialize the PRNG only once
|
| 192 |
+
|
| 193 |
+
RootColor = RootPos.side_to_move();
|
| 194 |
+
TimeMgr.init(Limits, RootPos.game_ply(), RootColor);
|
| 195 |
+
|
| 196 |
+
if (RootMoves.empty())
|
| 197 |
+
{
|
| 198 |
+
RootMoves.push_back(MOVE_NONE);
|
| 199 |
+
sync_cout << "info depth 0 score "
|
| 200 |
+
<< score_to_uci(RootPos.checkers() ? -VALUE_MATE : VALUE_DRAW)
|
| 201 |
+
<< sync_endl;
|
| 202 |
+
|
| 203 |
+
goto finalize;
|
| 204 |
+
}
|
| 205 |
+
|
| 206 |
+
if (Options["OwnBook"] && !Limits.infinite && !Limits.mate)
|
| 207 |
+
{
|
| 208 |
+
Move bookMove = book.probe(RootPos, Options["Book File"], Options["Best Book Move"]);
|
| 209 |
+
|
| 210 |
+
if (bookMove && std::count(RootMoves.begin(), RootMoves.end(), bookMove))
|
| 211 |
+
{
|
| 212 |
+
std::swap(RootMoves[0], *std::find(RootMoves.begin(), RootMoves.end(), bookMove));
|
| 213 |
+
goto finalize;
|
| 214 |
+
}
|
| 215 |
+
}
|
| 216 |
+
|
| 217 |
+
if (Options["Contempt Factor"] && !Options["UCI_AnalyseMode"])
|
| 218 |
+
{
|
| 219 |
+
int cf = Options["Contempt Factor"] * PawnValueMg / 100; // From centipawns
|
| 220 |
+
cf = cf * Material::game_phase(RootPos) / PHASE_MIDGAME; // Scale down with phase
|
| 221 |
+
DrawValue[ RootColor] = VALUE_DRAW - Value(cf);
|
| 222 |
+
DrawValue[~RootColor] = VALUE_DRAW + Value(cf);
|
| 223 |
+
}
|
| 224 |
+
else
|
| 225 |
+
DrawValue[WHITE] = DrawValue[BLACK] = VALUE_DRAW;
|
| 226 |
+
|
| 227 |
+
if (Options["Write Search Log"])
|
| 228 |
+
{
|
| 229 |
+
Log log(Options["Search Log Filename"]);
|
| 230 |
+
log << "\nSearching: " << RootPos.fen()
|
| 231 |
+
<< "\ninfinite: " << Limits.infinite
|
| 232 |
+
<< " ponder: " << Limits.ponder
|
| 233 |
+
<< " time: " << Limits.time[RootColor]
|
| 234 |
+
<< " increment: " << Limits.inc[RootColor]
|
| 235 |
+
<< " moves to go: " << Limits.movestogo
|
| 236 |
+
<< std::endl;
|
| 237 |
+
}
|
| 238 |
+
|
| 239 |
+
// Reset the threads, still sleeping: will be wake up at split time
|
| 240 |
+
for (size_t i = 0; i < Threads.size(); i++)
|
| 241 |
+
Threads[i]->maxPly = 0;
|
| 242 |
+
|
| 243 |
+
Threads.sleepWhileIdle = Options["Idle Threads Sleep"];
|
| 244 |
+
|
| 245 |
+
// Set best timer interval to avoid lagging under time pressure. Timer is
|
| 246 |
+
// used to check for remaining available thinking time.
|
| 247 |
+
Threads.timer->msec =
|
| 248 |
+
Limits.use_time_management() ? std::min(100, std::max(TimeMgr.available_time() / 16, TimerResolution)) :
|
| 249 |
+
Limits.nodes ? 2 * TimerResolution
|
| 250 |
+
: 100;
|
| 251 |
+
|
| 252 |
+
Threads.timer->notify_one(); // Wake up the recurring timer
|
| 253 |
+
|
| 254 |
+
id_loop(RootPos); // Let's start searching !
|
| 255 |
+
|
| 256 |
+
Threads.timer->msec = 0; // Stop the timer
|
| 257 |
+
Threads.sleepWhileIdle = true; // Send idle threads to sleep
|
| 258 |
+
|
| 259 |
+
if (Options["Write Search Log"])
|
| 260 |
+
{
|
| 261 |
+
Time::point elapsed = Time::now() - SearchTime + 1;
|
| 262 |
+
|
| 263 |
+
Log log(Options["Search Log Filename"]);
|
| 264 |
+
log << "Nodes: " << RootPos.nodes_searched()
|
| 265 |
+
<< "\nNodes/second: " << RootPos.nodes_searched() * 1000 / elapsed
|
| 266 |
+
<< "\nBest move: " << move_to_san(RootPos, RootMoves[0].pv[0]);
|
| 267 |
+
|
| 268 |
+
StateInfo st;
|
| 269 |
+
RootPos.do_move(RootMoves[0].pv[0], st);
|
| 270 |
+
log << "\nPonder move: " << move_to_san(RootPos, RootMoves[0].pv[1]) << std::endl;
|
| 271 |
+
RootPos.undo_move(RootMoves[0].pv[0]);
|
| 272 |
+
}
|
| 273 |
+
|
| 274 |
+
finalize:
|
| 275 |
+
|
| 276 |
+
// When search is stopped this info is not printed
|
| 277 |
+
sync_cout << "info nodes " << RootPos.nodes_searched()
|
| 278 |
+
<< " time " << Time::now() - SearchTime + 1 << sync_endl;
|
| 279 |
+
|
| 280 |
+
// When we reach max depth we arrive here even without Signals.stop is raised,
|
| 281 |
+
// but if we are pondering or in infinite search, according to UCI protocol,
|
| 282 |
+
// we shouldn't print the best move before the GUI sends a "stop" or "ponderhit"
|
| 283 |
+
// command. We simply wait here until GUI sends one of those commands (that
|
| 284 |
+
// raise Signals.stop).
|
| 285 |
+
if (!Signals.stop && (Limits.ponder || Limits.infinite))
|
| 286 |
+
{
|
| 287 |
+
Signals.stopOnPonderhit = true;
|
| 288 |
+
RootPos.this_thread()->wait_for(Signals.stop);
|
| 289 |
+
}
|
| 290 |
+
|
| 291 |
+
// Best move could be MOVE_NONE when searching on a stalemate position
|
| 292 |
+
sync_cout << "bestmove " << move_to_uci(RootMoves[0].pv[0], RootPos.is_chess960())
|
| 293 |
+
<< " ponder " << move_to_uci(RootMoves[0].pv[1], RootPos.is_chess960())
|
| 294 |
+
<< sync_endl;
|
| 295 |
+
}
|
| 296 |
+
|
| 297 |
+
|
| 298 |
+
namespace {
|
| 299 |
+
|
| 300 |
+
// id_loop() is the main iterative deepening loop. It calls search() repeatedly
|
| 301 |
+
// with increasing depth until the allocated thinking time has been consumed,
|
| 302 |
+
// user stops the search, or the maximum search depth is reached.
|
| 303 |
+
|
| 304 |
+
void id_loop(Position& pos) {
|
| 305 |
+
|
| 306 |
+
Stack stack[MAX_PLY_PLUS_6], *ss = stack+2; // To allow referencing (ss-2)
|
| 307 |
+
int depth, prevBestMoveChanges;
|
| 308 |
+
Value bestValue, alpha, beta, delta;
|
| 309 |
+
|
| 310 |
+
std::memset(ss-2, 0, 5 * sizeof(Stack));
|
| 311 |
+
(ss-1)->currentMove = MOVE_NULL; // Hack to skip update gains
|
| 312 |
+
|
| 313 |
+
depth = BestMoveChanges = 0;
|
| 314 |
+
bestValue = delta = alpha = -VALUE_INFINITE;
|
| 315 |
+
beta = VALUE_INFINITE;
|
| 316 |
+
|
| 317 |
+
TT.new_search();
|
| 318 |
+
History.clear();
|
| 319 |
+
Gains.clear();
|
| 320 |
+
Countermoves.clear();
|
| 321 |
+
|
| 322 |
+
PVSize = Options["MultiPV"];
|
| 323 |
+
Skill skill(Options["Skill Level"]);
|
| 324 |
+
|
| 325 |
+
// Do we have to play with skill handicap? In this case enable MultiPV search
|
| 326 |
+
// that we will use behind the scenes to retrieve a set of possible moves.
|
| 327 |
+
if (skill.enabled() && PVSize < 4)
|
| 328 |
+
PVSize = 4;
|
| 329 |
+
|
| 330 |
+
PVSize = std::min(PVSize, RootMoves.size());
|
| 331 |
+
|
| 332 |
+
// Iterative deepening loop until requested to stop or target depth reached
|
| 333 |
+
while (++depth <= MAX_PLY && !Signals.stop && (!Limits.depth || depth <= Limits.depth))
|
| 334 |
+
{
|
| 335 |
+
// Save last iteration's scores before first PV line is searched and all
|
| 336 |
+
// the move scores but the (new) PV are set to -VALUE_INFINITE.
|
| 337 |
+
for (size_t i = 0; i < RootMoves.size(); i++)
|
| 338 |
+
RootMoves[i].prevScore = RootMoves[i].score;
|
| 339 |
+
|
| 340 |
+
prevBestMoveChanges = BestMoveChanges; // Only sensible when PVSize == 1
|
| 341 |
+
BestMoveChanges = 0;
|
| 342 |
+
|
| 343 |
+
// MultiPV loop. We perform a full root search for each PV line
|
| 344 |
+
for (PVIdx = 0; PVIdx < PVSize; PVIdx++)
|
| 345 |
+
{
|
| 346 |
+
// Reset aspiration window starting size
|
| 347 |
+
if (depth >= 5)
|
| 348 |
+
{
|
| 349 |
+
delta = Value(16);
|
| 350 |
+
alpha = std::max(RootMoves[PVIdx].prevScore - delta,-VALUE_INFINITE);
|
| 351 |
+
beta = std::min(RootMoves[PVIdx].prevScore + delta, VALUE_INFINITE);
|
| 352 |
+
}
|
| 353 |
+
|
| 354 |
+
// Start with a small aspiration window and, in case of fail high/low,
|
| 355 |
+
// research with bigger window until not failing high/low anymore.
|
| 356 |
+
while (true)
|
| 357 |
+
{
|
| 358 |
+
bestValue = search<Root>(pos, ss, alpha, beta, depth * ONE_PLY, false);
|
| 359 |
+
|
| 360 |
+
// Bring to front the best move. It is critical that sorting is
|
| 361 |
+
// done with a stable algorithm because all the values but the first
|
| 362 |
+
// and eventually the new best one are set to -VALUE_INFINITE and
|
| 363 |
+
// we want to keep the same order for all the moves but the new
|
| 364 |
+
// PV that goes to the front. Note that in case of MultiPV search
|
| 365 |
+
// the already searched PV lines are preserved.
|
| 366 |
+
std::stable_sort(RootMoves.begin() + PVIdx, RootMoves.end());
|
| 367 |
+
|
| 368 |
+
// Write PV back to transposition table in case the relevant
|
| 369 |
+
// entries have been overwritten during the search.
|
| 370 |
+
for (size_t i = 0; i <= PVIdx; i++)
|
| 371 |
+
RootMoves[i].insert_pv_in_tt(pos);
|
| 372 |
+
|
| 373 |
+
// If search has been stopped return immediately. Sorting and
|
| 374 |
+
// writing PV back to TT is safe becuase RootMoves is still
|
| 375 |
+
// valid, although refers to previous iteration.
|
| 376 |
+
if (Signals.stop)
|
| 377 |
+
return;
|
| 378 |
+
|
| 379 |
+
// When failing high/low give some update (without cluttering
|
| 380 |
+
// the UI) before to research.
|
| 381 |
+
if ( (bestValue <= alpha || bestValue >= beta)
|
| 382 |
+
&& Time::now() - SearchTime > 3000)
|
| 383 |
+
sync_cout << uci_pv(pos, depth, alpha, beta) << sync_endl;
|
| 384 |
+
|
| 385 |
+
// In case of failing low/high increase aspiration window and
|
| 386 |
+
// research, otherwise exit the loop.
|
| 387 |
+
if (bestValue <= alpha)
|
| 388 |
+
{
|
| 389 |
+
alpha = std::max(bestValue - delta, -VALUE_INFINITE);
|
| 390 |
+
|
| 391 |
+
Signals.failedLowAtRoot = true;
|
| 392 |
+
Signals.stopOnPonderhit = false;
|
| 393 |
+
}
|
| 394 |
+
else if (bestValue >= beta)
|
| 395 |
+
beta = std::min(bestValue + delta, VALUE_INFINITE);
|
| 396 |
+
|
| 397 |
+
else
|
| 398 |
+
break;
|
| 399 |
+
|
| 400 |
+
delta += delta / 2;
|
| 401 |
+
|
| 402 |
+
assert(alpha >= -VALUE_INFINITE && beta <= VALUE_INFINITE);
|
| 403 |
+
}
|
| 404 |
+
|
| 405 |
+
// Sort the PV lines searched so far and update the GUI
|
| 406 |
+
std::stable_sort(RootMoves.begin(), RootMoves.begin() + PVIdx + 1);
|
| 407 |
+
|
| 408 |
+
if (PVIdx + 1 == PVSize || Time::now() - SearchTime > 3000)
|
| 409 |
+
sync_cout << uci_pv(pos, depth, alpha, beta) << sync_endl;
|
| 410 |
+
}
|
| 411 |
+
|
| 412 |
+
// Do we need to pick now the sub-optimal best move ?
|
| 413 |
+
if (skill.enabled() && skill.time_to_pick(depth))
|
| 414 |
+
skill.pick_move();
|
| 415 |
+
|
| 416 |
+
if (Options["Write Search Log"])
|
| 417 |
+
{
|
| 418 |
+
RootMove& rm = RootMoves[0];
|
| 419 |
+
if (skill.best != MOVE_NONE)
|
| 420 |
+
rm = *std::find(RootMoves.begin(), RootMoves.end(), skill.best);
|
| 421 |
+
|
| 422 |
+
Log log(Options["Search Log Filename"]);
|
| 423 |
+
log << pretty_pv(pos, depth, rm.score, Time::now() - SearchTime, &rm.pv[0])
|
| 424 |
+
<< std::endl;
|
| 425 |
+
}
|
| 426 |
+
|
| 427 |
+
// Do we have found a "mate in x"?
|
| 428 |
+
if ( Limits.mate
|
| 429 |
+
&& bestValue >= VALUE_MATE_IN_MAX_PLY
|
| 430 |
+
&& VALUE_MATE - bestValue <= 2 * Limits.mate)
|
| 431 |
+
Signals.stop = true;
|
| 432 |
+
|
| 433 |
+
// Do we have time for the next iteration? Can we stop searching now?
|
| 434 |
+
if (Limits.use_time_management() && !Signals.stopOnPonderhit)
|
| 435 |
+
{
|
| 436 |
+
bool stop = false; // Local variable, not the volatile Signals.stop
|
| 437 |
+
|
| 438 |
+
// Take in account some extra time if the best move has changed
|
| 439 |
+
if (depth > 4 && depth < 50 && PVSize == 1)
|
| 440 |
+
TimeMgr.pv_instability(BestMoveChanges, prevBestMoveChanges);
|
| 441 |
+
|
| 442 |
+
// Stop search if most of available time is already consumed. We
|
| 443 |
+
// probably don't have enough time to search the first move at the
|
| 444 |
+
// next iteration anyway.
|
| 445 |
+
if (Time::now() - SearchTime > (TimeMgr.available_time() * 62) / 100)
|
| 446 |
+
stop = true;
|
| 447 |
+
|
| 448 |
+
// Stop search early if one move seems to be much better than others
|
| 449 |
+
if ( depth >= 12
|
| 450 |
+
&& !stop
|
| 451 |
+
&& PVSize == 1
|
| 452 |
+
&& bestValue > VALUE_MATED_IN_MAX_PLY
|
| 453 |
+
&& ( RootMoves.size() == 1
|
| 454 |
+
|| Time::now() - SearchTime > (TimeMgr.available_time() * 20) / 100))
|
| 455 |
+
{
|
| 456 |
+
Value rBeta = bestValue - 2 * PawnValueMg;
|
| 457 |
+
ss->excludedMove = RootMoves[0].pv[0];
|
| 458 |
+
ss->skipNullMove = true;
|
| 459 |
+
Value v = search<NonPV>(pos, ss, rBeta - 1, rBeta, (depth - 3) * ONE_PLY, true);
|
| 460 |
+
ss->skipNullMove = false;
|
| 461 |
+
ss->excludedMove = MOVE_NONE;
|
| 462 |
+
|
| 463 |
+
if (v < rBeta)
|
| 464 |
+
stop = true;
|
| 465 |
+
}
|
| 466 |
+
|
| 467 |
+
if (stop)
|
| 468 |
+
{
|
| 469 |
+
// If we are allowed to ponder do not stop the search now but
|
| 470 |
+
// keep pondering until GUI sends "ponderhit" or "stop".
|
| 471 |
+
if (Limits.ponder)
|
| 472 |
+
Signals.stopOnPonderhit = true;
|
| 473 |
+
else
|
| 474 |
+
Signals.stop = true;
|
| 475 |
+
}
|
| 476 |
+
}
|
| 477 |
+
}
|
| 478 |
+
}
|
| 479 |
+
|
| 480 |
+
|
| 481 |
+
// search<>() is the main search function for both PV and non-PV nodes and for
|
| 482 |
+
// normal and SplitPoint nodes. When called just after a split point the search
|
| 483 |
+
// is simpler because we have already probed the hash table, done a null move
|
| 484 |
+
// search, and searched the first move before splitting, we don't have to repeat
|
| 485 |
+
// all this work again. We also don't need to store anything to the hash table
|
| 486 |
+
// here: This is taken care of after we return from the split point.
|
| 487 |
+
|
| 488 |
+
template <NodeType NT>
|
| 489 |
+
Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, bool cutNode) {
|
| 490 |
+
|
| 491 |
+
const bool PvNode = (NT == PV || NT == Root || NT == SplitPointPV || NT == SplitPointRoot);
|
| 492 |
+
const bool SpNode = (NT == SplitPointPV || NT == SplitPointNonPV || NT == SplitPointRoot);
|
| 493 |
+
const bool RootNode = (NT == Root || NT == SplitPointRoot);
|
| 494 |
+
|
| 495 |
+
assert(alpha >= -VALUE_INFINITE && alpha < beta && beta <= VALUE_INFINITE);
|
| 496 |
+
assert(PvNode || (alpha == beta - 1));
|
| 497 |
+
assert(depth > DEPTH_ZERO);
|
| 498 |
+
|
| 499 |
+
Move quietsSearched[64];
|
| 500 |
+
StateInfo st;
|
| 501 |
+
const TTEntry *tte;
|
| 502 |
+
SplitPoint* splitPoint;
|
| 503 |
+
Key posKey;
|
| 504 |
+
Move ttMove, move, excludedMove, bestMove, threatMove;
|
| 505 |
+
Depth ext, newDepth;
|
| 506 |
+
Value bestValue, value, ttValue;
|
| 507 |
+
Value eval, nullValue, futilityValue;
|
| 508 |
+
bool inCheck, givesCheck, pvMove, singularExtensionNode, improving;
|
| 509 |
+
bool captureOrPromotion, dangerous, doFullDepthSearch;
|
| 510 |
+
int moveCount, quietCount;
|
| 511 |
+
|
| 512 |
+
// Step 1. Initialize node
|
| 513 |
+
Thread* thisThread = pos.this_thread();
|
| 514 |
+
inCheck = pos.checkers();
|
| 515 |
+
|
| 516 |
+
if (SpNode)
|
| 517 |
+
{
|
| 518 |
+
splitPoint = ss->splitPoint;
|
| 519 |
+
bestMove = splitPoint->bestMove;
|
| 520 |
+
threatMove = splitPoint->threatMove;
|
| 521 |
+
bestValue = splitPoint->bestValue;
|
| 522 |
+
tte = NULL;
|
| 523 |
+
ttMove = excludedMove = MOVE_NONE;
|
| 524 |
+
ttValue = VALUE_NONE;
|
| 525 |
+
|
| 526 |
+
assert(splitPoint->bestValue > -VALUE_INFINITE && splitPoint->moveCount > 0);
|
| 527 |
+
|
| 528 |
+
goto moves_loop;
|
| 529 |
+
}
|
| 530 |
+
|
| 531 |
+
moveCount = quietCount = 0;
|
| 532 |
+
bestValue = -VALUE_INFINITE;
|
| 533 |
+
ss->currentMove = threatMove = (ss+1)->excludedMove = bestMove = MOVE_NONE;
|
| 534 |
+
ss->ply = (ss-1)->ply + 1;
|
| 535 |
+
ss->futilityMoveCount = 0;
|
| 536 |
+
(ss+1)->skipNullMove = false; (ss+1)->reduction = DEPTH_ZERO;
|
| 537 |
+
(ss+2)->killers[0] = (ss+2)->killers[1] = MOVE_NONE;
|
| 538 |
+
|
| 539 |
+
// Used to send selDepth info to GUI
|
| 540 |
+
if (PvNode && thisThread->maxPly < ss->ply)
|
| 541 |
+
thisThread->maxPly = ss->ply;
|
| 542 |
+
|
| 543 |
+
if (!RootNode)
|
| 544 |
+
{
|
| 545 |
+
// Step 2. Check for aborted search and immediate draw
|
| 546 |
+
if (Signals.stop || pos.is_draw() || ss->ply > MAX_PLY)
|
| 547 |
+
return DrawValue[pos.side_to_move()];
|
| 548 |
+
|
| 549 |
+
// Step 3. Mate distance pruning. Even if we mate at the next move our score
|
| 550 |
+
// would be at best mate_in(ss->ply+1), but if alpha is already bigger because
|
| 551 |
+
// a shorter mate was found upward in the tree then there is no need to search
|
| 552 |
+
// further, we will never beat current alpha. Same logic but with reversed signs
|
| 553 |
+
// applies also in the opposite condition of being mated instead of giving mate,
|
| 554 |
+
// in this case return a fail-high score.
|
| 555 |
+
alpha = std::max(mated_in(ss->ply), alpha);
|
| 556 |
+
beta = std::min(mate_in(ss->ply+1), beta);
|
| 557 |
+
if (alpha >= beta)
|
| 558 |
+
return alpha;
|
| 559 |
+
}
|
| 560 |
+
|
| 561 |
+
// Step 4. Transposition table lookup
|
| 562 |
+
// We don't want the score of a partial search to overwrite a previous full search
|
| 563 |
+
// TT value, so we use a different position key in case of an excluded move.
|
| 564 |
+
excludedMove = ss->excludedMove;
|
| 565 |
+
posKey = excludedMove ? pos.exclusion_key() : pos.key();
|
| 566 |
+
tte = TT.probe(posKey);
|
| 567 |
+
ttMove = RootNode ? RootMoves[PVIdx].pv[0] : tte ? tte->move() : MOVE_NONE;
|
| 568 |
+
ttValue = tte ? value_from_tt(tte->value(), ss->ply) : VALUE_NONE;
|
| 569 |
+
|
| 570 |
+
// At PV nodes we check for exact scores, while at non-PV nodes we check for
|
| 571 |
+
// a fail high/low. Biggest advantage at probing at PV nodes is to have a
|
| 572 |
+
// smooth experience in analysis mode. We don't probe at Root nodes otherwise
|
| 573 |
+
// we should also update RootMoveList to avoid bogus output.
|
| 574 |
+
if ( !RootNode
|
| 575 |
+
&& tte
|
| 576 |
+
&& tte->depth() >= depth
|
| 577 |
+
&& ttValue != VALUE_NONE // Only in case of TT access race
|
| 578 |
+
&& ( PvNode ? tte->bound() == BOUND_EXACT
|
| 579 |
+
: ttValue >= beta ? (tte->bound() & BOUND_LOWER)
|
| 580 |
+
: (tte->bound() & BOUND_UPPER)))
|
| 581 |
+
{
|
| 582 |
+
TT.refresh(tte);
|
| 583 |
+
ss->currentMove = ttMove; // Can be MOVE_NONE
|
| 584 |
+
|
| 585 |
+
if ( ttValue >= beta
|
| 586 |
+
&& ttMove
|
| 587 |
+
&& !pos.is_capture_or_promotion(ttMove)
|
| 588 |
+
&& ttMove != ss->killers[0])
|
| 589 |
+
{
|
| 590 |
+
ss->killers[1] = ss->killers[0];
|
| 591 |
+
ss->killers[0] = ttMove;
|
| 592 |
+
}
|
| 593 |
+
return ttValue;
|
| 594 |
+
}
|
| 595 |
+
|
| 596 |
+
// Step 5. Evaluate the position statically and update parent's gain statistics
|
| 597 |
+
if (inCheck)
|
| 598 |
+
{
|
| 599 |
+
ss->staticEval = ss->evalMargin = eval = VALUE_NONE;
|
| 600 |
+
goto moves_loop;
|
| 601 |
+
}
|
| 602 |
+
|
| 603 |
+
else if (tte)
|
| 604 |
+
{
|
| 605 |
+
// Never assume anything on values stored in TT
|
| 606 |
+
if ( (ss->staticEval = eval = tte->eval_value()) == VALUE_NONE
|
| 607 |
+
||(ss->evalMargin = tte->eval_margin()) == VALUE_NONE)
|
| 608 |
+
eval = ss->staticEval = evaluate(pos, ss->evalMargin);
|
| 609 |
+
|
| 610 |
+
// Can ttValue be used as a better position evaluation?
|
| 611 |
+
if (ttValue != VALUE_NONE)
|
| 612 |
+
if ( ((tte->bound() & BOUND_LOWER) && ttValue > eval)
|
| 613 |
+
|| ((tte->bound() & BOUND_UPPER) && ttValue < eval))
|
| 614 |
+
eval = ttValue;
|
| 615 |
+
}
|
| 616 |
+
else
|
| 617 |
+
{
|
| 618 |
+
eval = ss->staticEval = evaluate(pos, ss->evalMargin);
|
| 619 |
+
TT.store(posKey, VALUE_NONE, BOUND_NONE, DEPTH_NONE, MOVE_NONE,
|
| 620 |
+
ss->staticEval, ss->evalMargin);
|
| 621 |
+
}
|
| 622 |
+
|
| 623 |
+
// Update gain for the parent non-capture move given the static position
|
| 624 |
+
// evaluation before and after the move.
|
| 625 |
+
if ( !pos.captured_piece_type()
|
| 626 |
+
&& ss->staticEval != VALUE_NONE
|
| 627 |
+
&& (ss-1)->staticEval != VALUE_NONE
|
| 628 |
+
&& (move = (ss-1)->currentMove) != MOVE_NULL
|
| 629 |
+
&& type_of(move) == NORMAL)
|
| 630 |
+
{
|
| 631 |
+
Square to = to_sq(move);
|
| 632 |
+
Gains.update(pos.piece_on(to), to, -(ss-1)->staticEval - ss->staticEval);
|
| 633 |
+
}
|
| 634 |
+
|
| 635 |
+
// Step 6. Razoring (skipped when in check)
|
| 636 |
+
if ( !PvNode
|
| 637 |
+
&& depth < 4 * ONE_PLY
|
| 638 |
+
&& eval + razor_margin(depth) < beta
|
| 639 |
+
&& ttMove == MOVE_NONE
|
| 640 |
+
&& abs(beta) < VALUE_MATE_IN_MAX_PLY
|
| 641 |
+
&& !pos.pawn_on_7th(pos.side_to_move()))
|
| 642 |
+
{
|
| 643 |
+
Value rbeta = beta - razor_margin(depth);
|
| 644 |
+
Value v = qsearch<NonPV, false>(pos, ss, rbeta-1, rbeta, DEPTH_ZERO);
|
| 645 |
+
if (v < rbeta)
|
| 646 |
+
// Logically we should return (v + razor_margin(depth)), but
|
| 647 |
+
// surprisingly this did slightly weaker in tests.
|
| 648 |
+
return v;
|
| 649 |
+
}
|
| 650 |
+
|
| 651 |
+
// Step 7. Static null move pruning (skipped when in check)
|
| 652 |
+
// We're betting that the opponent doesn't have a move that will reduce
|
| 653 |
+
// the score by more than futility_margin(depth) if we do a null move.
|
| 654 |
+
if ( !PvNode
|
| 655 |
+
&& !ss->skipNullMove
|
| 656 |
+
&& depth < 4 * ONE_PLY
|
| 657 |
+
&& eval - futility_margin(depth, (ss-1)->futilityMoveCount) >= beta
|
| 658 |
+
&& abs(beta) < VALUE_MATE_IN_MAX_PLY
|
| 659 |
+
&& abs(eval) < VALUE_KNOWN_WIN
|
| 660 |
+
&& pos.non_pawn_material(pos.side_to_move()))
|
| 661 |
+
return eval - futility_margin(depth, (ss-1)->futilityMoveCount);
|
| 662 |
+
|
| 663 |
+
// Step 8. Null move search with verification search (is omitted in PV nodes)
|
| 664 |
+
if ( !PvNode
|
| 665 |
+
&& !ss->skipNullMove
|
| 666 |
+
&& depth > ONE_PLY
|
| 667 |
+
&& eval >= beta
|
| 668 |
+
&& abs(beta) < VALUE_MATE_IN_MAX_PLY
|
| 669 |
+
&& pos.non_pawn_material(pos.side_to_move()))
|
| 670 |
+
{
|
| 671 |
+
ss->currentMove = MOVE_NULL;
|
| 672 |
+
|
| 673 |
+
// Null move dynamic reduction based on depth
|
| 674 |
+
Depth R = 3 * ONE_PLY + depth / 4;
|
| 675 |
+
|
| 676 |
+
// Null move dynamic reduction based on value
|
| 677 |
+
if (eval - PawnValueMg > beta)
|
| 678 |
+
R += ONE_PLY;
|
| 679 |
+
|
| 680 |
+
pos.do_null_move(st);
|
| 681 |
+
(ss+1)->skipNullMove = true;
|
| 682 |
+
nullValue = depth-R < ONE_PLY ? -qsearch<NonPV, false>(pos, ss+1, -beta, -alpha, DEPTH_ZERO)
|
| 683 |
+
: - search<NonPV>(pos, ss+1, -beta, -alpha, depth-R, !cutNode);
|
| 684 |
+
(ss+1)->skipNullMove = false;
|
| 685 |
+
pos.undo_null_move();
|
| 686 |
+
|
| 687 |
+
if (nullValue >= beta)
|
| 688 |
+
{
|
| 689 |
+
// Do not return unproven mate scores
|
| 690 |
+
if (nullValue >= VALUE_MATE_IN_MAX_PLY)
|
| 691 |
+
nullValue = beta;
|
| 692 |
+
|
| 693 |
+
if (depth < 12 * ONE_PLY)
|
| 694 |
+
return nullValue;
|
| 695 |
+
|
| 696 |
+
// Do verification search at high depths
|
| 697 |
+
ss->skipNullMove = true;
|
| 698 |
+
Value v = search<NonPV>(pos, ss, alpha, beta, depth-R, false);
|
| 699 |
+
ss->skipNullMove = false;
|
| 700 |
+
|
| 701 |
+
if (v >= beta)
|
| 702 |
+
return nullValue;
|
| 703 |
+
}
|
| 704 |
+
else
|
| 705 |
+
{
|
| 706 |
+
// The null move failed low, which means that we may be faced with
|
| 707 |
+
// some kind of threat. If the previous move was reduced, check if
|
| 708 |
+
// the move that refuted the null move was somehow connected to the
|
| 709 |
+
// move which was reduced. If a connection is found, return a fail
|
| 710 |
+
// low score (which will cause the reduced move to fail high in the
|
| 711 |
+
// parent node, which will trigger a re-search with full depth).
|
| 712 |
+
threatMove = (ss+1)->currentMove;
|
| 713 |
+
|
| 714 |
+
if ( depth < 5 * ONE_PLY
|
| 715 |
+
&& (ss-1)->reduction
|
| 716 |
+
&& threatMove != MOVE_NONE
|
| 717 |
+
&& allows(pos, (ss-1)->currentMove, threatMove))
|
| 718 |
+
return alpha;
|
| 719 |
+
}
|
| 720 |
+
}
|
| 721 |
+
|
| 722 |
+
// Step 9. ProbCut (skipped when in check)
|
| 723 |
+
// If we have a very good capture (i.e. SEE > seeValues[captured_piece_type])
|
| 724 |
+
// and a reduced search returns a value much above beta, we can (almost) safely
|
| 725 |
+
// prune the previous move.
|
| 726 |
+
if ( !PvNode
|
| 727 |
+
&& depth >= 5 * ONE_PLY
|
| 728 |
+
&& !ss->skipNullMove
|
| 729 |
+
&& abs(beta) < VALUE_MATE_IN_MAX_PLY)
|
| 730 |
+
{
|
| 731 |
+
Value rbeta = beta + 200;
|
| 732 |
+
Depth rdepth = depth - ONE_PLY - 3 * ONE_PLY;
|
| 733 |
+
|
| 734 |
+
assert(rdepth >= ONE_PLY);
|
| 735 |
+
assert((ss-1)->currentMove != MOVE_NONE);
|
| 736 |
+
assert((ss-1)->currentMove != MOVE_NULL);
|
| 737 |
+
|
| 738 |
+
MovePicker mp(pos, ttMove, History, pos.captured_piece_type());
|
| 739 |
+
CheckInfo ci(pos);
|
| 740 |
+
|
| 741 |
+
while ((move = mp.next_move<false>()) != MOVE_NONE)
|
| 742 |
+
if (pos.pl_move_is_legal(move, ci.pinned))
|
| 743 |
+
{
|
| 744 |
+
ss->currentMove = move;
|
| 745 |
+
pos.do_move(move, st, ci, pos.move_gives_check(move, ci));
|
| 746 |
+
value = -search<NonPV>(pos, ss+1, -rbeta, -rbeta+1, rdepth, !cutNode);
|
| 747 |
+
pos.undo_move(move);
|
| 748 |
+
if (value >= rbeta)
|
| 749 |
+
return value;
|
| 750 |
+
}
|
| 751 |
+
}
|
| 752 |
+
|
| 753 |
+
// Step 10. Internal iterative deepening (skipped when in check)
|
| 754 |
+
if ( depth >= (PvNode ? 5 * ONE_PLY : 8 * ONE_PLY)
|
| 755 |
+
&& ttMove == MOVE_NONE
|
| 756 |
+
&& (PvNode || ss->staticEval + Value(256) >= beta))
|
| 757 |
+
{
|
| 758 |
+
Depth d = depth - 2 * ONE_PLY - (PvNode ? DEPTH_ZERO : depth / 4);
|
| 759 |
+
|
| 760 |
+
ss->skipNullMove = true;
|
| 761 |
+
search<PvNode ? PV : NonPV>(pos, ss, alpha, beta, d, true);
|
| 762 |
+
ss->skipNullMove = false;
|
| 763 |
+
|
| 764 |
+
tte = TT.probe(posKey);
|
| 765 |
+
ttMove = tte ? tte->move() : MOVE_NONE;
|
| 766 |
+
}
|
| 767 |
+
|
| 768 |
+
moves_loop: // When in check and at SpNode search starts from here
|
| 769 |
+
|
| 770 |
+
Square prevMoveSq = to_sq((ss-1)->currentMove);
|
| 771 |
+
Move countermoves[] = { Countermoves[pos.piece_on(prevMoveSq)][prevMoveSq].first,
|
| 772 |
+
Countermoves[pos.piece_on(prevMoveSq)][prevMoveSq].second };
|
| 773 |
+
|
| 774 |
+
MovePicker mp(pos, ttMove, depth, History, countermoves, ss);
|
| 775 |
+
CheckInfo ci(pos);
|
| 776 |
+
value = bestValue; // Workaround a bogus 'uninitialized' warning under gcc
|
| 777 |
+
improving = ss->staticEval >= (ss-2)->staticEval
|
| 778 |
+
|| ss->staticEval == VALUE_NONE
|
| 779 |
+
||(ss-2)->staticEval == VALUE_NONE;
|
| 780 |
+
|
| 781 |
+
singularExtensionNode = !RootNode
|
| 782 |
+
&& !SpNode
|
| 783 |
+
&& depth >= (PvNode ? 6 * ONE_PLY : 8 * ONE_PLY)
|
| 784 |
+
&& ttMove != MOVE_NONE
|
| 785 |
+
&& !excludedMove // Recursive singular search is not allowed
|
| 786 |
+
&& (tte->bound() & BOUND_LOWER)
|
| 787 |
+
&& tte->depth() >= depth - 3 * ONE_PLY;
|
| 788 |
+
|
| 789 |
+
// Step 11. Loop through moves
|
| 790 |
+
// Loop through all pseudo-legal moves until no moves remain or a beta cutoff occurs
|
| 791 |
+
while ((move = mp.next_move<SpNode>()) != MOVE_NONE)
|
| 792 |
+
{
|
| 793 |
+
assert(is_ok(move));
|
| 794 |
+
|
| 795 |
+
if (move == excludedMove)
|
| 796 |
+
continue;
|
| 797 |
+
|
| 798 |
+
// At root obey the "searchmoves" option and skip moves not listed in Root
|
| 799 |
+
// Move List, as a consequence any illegal move is also skipped. In MultiPV
|
| 800 |
+
// mode we also skip PV moves which have been already searched.
|
| 801 |
+
if (RootNode && !std::count(RootMoves.begin() + PVIdx, RootMoves.end(), move))
|
| 802 |
+
continue;
|
| 803 |
+
|
| 804 |
+
if (SpNode)
|
| 805 |
+
{
|
| 806 |
+
// Shared counter cannot be decremented later if move turns out to be illegal
|
| 807 |
+
if (!pos.pl_move_is_legal(move, ci.pinned))
|
| 808 |
+
continue;
|
| 809 |
+
|
| 810 |
+
moveCount = ++splitPoint->moveCount;
|
| 811 |
+
splitPoint->mutex.unlock();
|
| 812 |
+
}
|
| 813 |
+
else
|
| 814 |
+
moveCount++;
|
| 815 |
+
|
| 816 |
+
if (RootNode)
|
| 817 |
+
{
|
| 818 |
+
Signals.firstRootMove = (moveCount == 1);
|
| 819 |
+
|
| 820 |
+
if (thisThread == Threads.main() && Time::now() - SearchTime > 3000)
|
| 821 |
+
sync_cout << "info depth " << depth / ONE_PLY
|
| 822 |
+
<< " currmove " << move_to_uci(move, pos.is_chess960())
|
| 823 |
+
<< " currmovenumber " << moveCount + PVIdx << sync_endl;
|
| 824 |
+
}
|
| 825 |
+
|
| 826 |
+
ext = DEPTH_ZERO;
|
| 827 |
+
captureOrPromotion = pos.is_capture_or_promotion(move);
|
| 828 |
+
givesCheck = pos.move_gives_check(move, ci);
|
| 829 |
+
dangerous = givesCheck
|
| 830 |
+
|| pos.is_passed_pawn_push(move)
|
| 831 |
+
|| type_of(move) == CASTLE;
|
| 832 |
+
|
| 833 |
+
// Step 12. Extend checks and, in PV nodes, also dangerous moves
|
| 834 |
+
if (PvNode && dangerous)
|
| 835 |
+
ext = ONE_PLY;
|
| 836 |
+
|
| 837 |
+
else if (givesCheck && pos.see_sign(move) >= 0)
|
| 838 |
+
ext = ONE_PLY / 2;
|
| 839 |
+
|
| 840 |
+
// Singular extension search. If all moves but one fail low on a search of
|
| 841 |
+
// (alpha-s, beta-s), and just one fails high on (alpha, beta), then that move
|
| 842 |
+
// is singular and should be extended. To verify this we do a reduced search
|
| 843 |
+
// on all the other moves but the ttMove, if result is lower than ttValue minus
|
| 844 |
+
// a margin then we extend ttMove.
|
| 845 |
+
if ( singularExtensionNode
|
| 846 |
+
&& move == ttMove
|
| 847 |
+
&& !ext
|
| 848 |
+
&& pos.pl_move_is_legal(move, ci.pinned)
|
| 849 |
+
&& abs(ttValue) < VALUE_KNOWN_WIN)
|
| 850 |
+
{
|
| 851 |
+
assert(ttValue != VALUE_NONE);
|
| 852 |
+
|
| 853 |
+
Value rBeta = ttValue - int(depth);
|
| 854 |
+
ss->excludedMove = move;
|
| 855 |
+
ss->skipNullMove = true;
|
| 856 |
+
value = search<NonPV>(pos, ss, rBeta - 1, rBeta, depth / 2, cutNode);
|
| 857 |
+
ss->skipNullMove = false;
|
| 858 |
+
ss->excludedMove = MOVE_NONE;
|
| 859 |
+
|
| 860 |
+
if (value < rBeta)
|
| 861 |
+
ext = ONE_PLY;
|
| 862 |
+
}
|
| 863 |
+
|
| 864 |
+
// Update current move (this must be done after singular extension search)
|
| 865 |
+
newDepth = depth - ONE_PLY + ext;
|
| 866 |
+
|
| 867 |
+
// Step 13. Futility pruning (is omitted in PV nodes)
|
| 868 |
+
if ( !PvNode
|
| 869 |
+
&& !captureOrPromotion
|
| 870 |
+
&& !inCheck
|
| 871 |
+
&& !dangerous
|
| 872 |
+
/* && move != ttMove Already implicit in the next condition */
|
| 873 |
+
&& bestValue > VALUE_MATED_IN_MAX_PLY)
|
| 874 |
+
{
|
| 875 |
+
// Move count based pruning
|
| 876 |
+
if ( depth < 16 * ONE_PLY
|
| 877 |
+
&& moveCount >= FutilityMoveCounts[improving][depth]
|
| 878 |
+
&& (!threatMove || !refutes(pos, move, threatMove)))
|
| 879 |
+
{
|
| 880 |
+
if (SpNode)
|
| 881 |
+
splitPoint->mutex.lock();
|
| 882 |
+
|
| 883 |
+
continue;
|
| 884 |
+
}
|
| 885 |
+
|
| 886 |
+
// Value based pruning
|
| 887 |
+
// We illogically ignore reduction condition depth >= 3*ONE_PLY for predicted depth,
|
| 888 |
+
// but fixing this made program slightly weaker.
|
| 889 |
+
Depth predictedDepth = newDepth - reduction<PvNode>(improving, depth, moveCount);
|
| 890 |
+
futilityValue = ss->staticEval + ss->evalMargin + futility_margin(predictedDepth, moveCount)
|
| 891 |
+
+ Gains[pos.piece_moved(move)][to_sq(move)];
|
| 892 |
+
|
| 893 |
+
if (futilityValue < beta)
|
| 894 |
+
{
|
| 895 |
+
bestValue = std::max(bestValue, futilityValue);
|
| 896 |
+
|
| 897 |
+
if (SpNode)
|
| 898 |
+
{
|
| 899 |
+
splitPoint->mutex.lock();
|
| 900 |
+
if (bestValue > splitPoint->bestValue)
|
| 901 |
+
splitPoint->bestValue = bestValue;
|
| 902 |
+
}
|
| 903 |
+
continue;
|
| 904 |
+
}
|
| 905 |
+
|
| 906 |
+
// Prune moves with negative SEE at low depths
|
| 907 |
+
if ( predictedDepth < 4 * ONE_PLY
|
| 908 |
+
&& pos.see_sign(move) < 0)
|
| 909 |
+
{
|
| 910 |
+
if (SpNode)
|
| 911 |
+
splitPoint->mutex.lock();
|
| 912 |
+
|
| 913 |
+
continue;
|
| 914 |
+
}
|
| 915 |
+
|
| 916 |
+
// We have not pruned the move that will be searched, but remember how
|
| 917 |
+
// far in the move list we are to be more aggressive in the child node.
|
| 918 |
+
ss->futilityMoveCount = moveCount;
|
| 919 |
+
}
|
| 920 |
+
else
|
| 921 |
+
ss->futilityMoveCount = 0;
|
| 922 |
+
|
| 923 |
+
// Check for legality only before to do the move
|
| 924 |
+
if (!RootNode && !SpNode && !pos.pl_move_is_legal(move, ci.pinned))
|
| 925 |
+
{
|
| 926 |
+
moveCount--;
|
| 927 |
+
continue;
|
| 928 |
+
}
|
| 929 |
+
|
| 930 |
+
pvMove = PvNode && moveCount == 1;
|
| 931 |
+
ss->currentMove = move;
|
| 932 |
+
if (!SpNode && !captureOrPromotion && quietCount < 64)
|
| 933 |
+
quietsSearched[quietCount++] = move;
|
| 934 |
+
|
| 935 |
+
// Step 14. Make the move
|
| 936 |
+
pos.do_move(move, st, ci, givesCheck);
|
| 937 |
+
|
| 938 |
+
// Step 15. Reduced depth search (LMR). If the move fails high will be
|
| 939 |
+
// re-searched at full depth.
|
| 940 |
+
if ( depth > 3 * ONE_PLY
|
| 941 |
+
&& !pvMove
|
| 942 |
+
&& !captureOrPromotion
|
| 943 |
+
&& !dangerous
|
| 944 |
+
&& move != ttMove
|
| 945 |
+
&& move != ss->killers[0]
|
| 946 |
+
&& move != ss->killers[1])
|
| 947 |
+
{
|
| 948 |
+
ss->reduction = reduction<PvNode>(improving, depth, moveCount);
|
| 949 |
+
|
| 950 |
+
if (!PvNode && cutNode)
|
| 951 |
+
ss->reduction += ONE_PLY;
|
| 952 |
+
|
| 953 |
+
if (move == countermoves[0] || move == countermoves[1])
|
| 954 |
+
ss->reduction = std::max(DEPTH_ZERO, ss->reduction-ONE_PLY);
|
| 955 |
+
|
| 956 |
+
Depth d = std::max(newDepth - ss->reduction, ONE_PLY);
|
| 957 |
+
if (SpNode)
|
| 958 |
+
alpha = splitPoint->alpha;
|
| 959 |
+
|
| 960 |
+
value = -search<NonPV>(pos, ss+1, -(alpha+1), -alpha, d, true);
|
| 961 |
+
|
| 962 |
+
doFullDepthSearch = (value > alpha && ss->reduction != DEPTH_ZERO);
|
| 963 |
+
ss->reduction = DEPTH_ZERO;
|
| 964 |
+
}
|
| 965 |
+
else
|
| 966 |
+
doFullDepthSearch = !pvMove;
|
| 967 |
+
|
| 968 |
+
// Step 16. Full depth search, when LMR is skipped or fails high
|
| 969 |
+
if (doFullDepthSearch)
|
| 970 |
+
{
|
| 971 |
+
if (SpNode)
|
| 972 |
+
alpha = splitPoint->alpha;
|
| 973 |
+
|
| 974 |
+
value = newDepth < ONE_PLY ?
|
| 975 |
+
givesCheck ? -qsearch<NonPV, true>(pos, ss+1, -(alpha+1), -alpha, DEPTH_ZERO)
|
| 976 |
+
: -qsearch<NonPV, false>(pos, ss+1, -(alpha+1), -alpha, DEPTH_ZERO)
|
| 977 |
+
: - search<NonPV>(pos, ss+1, -(alpha+1), -alpha, newDepth, !cutNode);
|
| 978 |
+
}
|
| 979 |
+
|
| 980 |
+
// Only for PV nodes do a full PV search on the first move or after a fail
|
| 981 |
+
// high, in the latter case search only if value < beta, otherwise let the
|
| 982 |
+
// parent node to fail low with value <= alpha and to try another move.
|
| 983 |
+
if (PvNode && (pvMove || (value > alpha && (RootNode || value < beta))))
|
| 984 |
+
value = newDepth < ONE_PLY ?
|
| 985 |
+
givesCheck ? -qsearch<PV, true>(pos, ss+1, -beta, -alpha, DEPTH_ZERO)
|
| 986 |
+
: -qsearch<PV, false>(pos, ss+1, -beta, -alpha, DEPTH_ZERO)
|
| 987 |
+
: - search<PV>(pos, ss+1, -beta, -alpha, newDepth, false);
|
| 988 |
+
// Step 17. Undo move
|
| 989 |
+
pos.undo_move(move);
|
| 990 |
+
|
| 991 |
+
assert(value > -VALUE_INFINITE && value < VALUE_INFINITE);
|
| 992 |
+
|
| 993 |
+
// Step 18. Check for new best move
|
| 994 |
+
if (SpNode)
|
| 995 |
+
{
|
| 996 |
+
splitPoint->mutex.lock();
|
| 997 |
+
bestValue = splitPoint->bestValue;
|
| 998 |
+
alpha = splitPoint->alpha;
|
| 999 |
+
}
|
| 1000 |
+
|
| 1001 |
+
// Finished searching the move. If Signals.stop is true, the search
|
| 1002 |
+
// was aborted because the user interrupted the search or because we
|
| 1003 |
+
// ran out of time. In this case, the return value of the search cannot
|
| 1004 |
+
// be trusted, and we don't update the best move and/or PV.
|
| 1005 |
+
if (Signals.stop || thisThread->cutoff_occurred())
|
| 1006 |
+
return value; // To avoid returning VALUE_INFINITE
|
| 1007 |
+
|
| 1008 |
+
if (RootNode)
|
| 1009 |
+
{
|
| 1010 |
+
RootMove& rm = *std::find(RootMoves.begin(), RootMoves.end(), move);
|
| 1011 |
+
|
| 1012 |
+
// PV move or new best move ?
|
| 1013 |
+
if (pvMove || value > alpha)
|
| 1014 |
+
{
|
| 1015 |
+
rm.score = value;
|
| 1016 |
+
rm.extract_pv_from_tt(pos);
|
| 1017 |
+
|
| 1018 |
+
// We record how often the best move has been changed in each
|
| 1019 |
+
// iteration. This information is used for time management: When
|
| 1020 |
+
// the best move changes frequently, we allocate some more time.
|
| 1021 |
+
if (!pvMove)
|
| 1022 |
+
BestMoveChanges++;
|
| 1023 |
+
}
|
| 1024 |
+
else
|
| 1025 |
+
// All other moves but the PV are set to the lowest value, this
|
| 1026 |
+
// is not a problem when sorting becuase sort is stable and move
|
| 1027 |
+
// position in the list is preserved, just the PV is pushed up.
|
| 1028 |
+
rm.score = -VALUE_INFINITE;
|
| 1029 |
+
}
|
| 1030 |
+
|
| 1031 |
+
if (value > bestValue)
|
| 1032 |
+
{
|
| 1033 |
+
bestValue = SpNode ? splitPoint->bestValue = value : value;
|
| 1034 |
+
|
| 1035 |
+
if (value > alpha)
|
| 1036 |
+
{
|
| 1037 |
+
bestMove = SpNode ? splitPoint->bestMove = move : move;
|
| 1038 |
+
|
| 1039 |
+
if (PvNode && value < beta) // Update alpha! Always alpha < beta
|
| 1040 |
+
alpha = SpNode ? splitPoint->alpha = value : value;
|
| 1041 |
+
else
|
| 1042 |
+
{
|
| 1043 |
+
assert(value >= beta); // Fail high
|
| 1044 |
+
|
| 1045 |
+
if (SpNode)
|
| 1046 |
+
splitPoint->cutoff = true;
|
| 1047 |
+
|
| 1048 |
+
break;
|
| 1049 |
+
}
|
| 1050 |
+
}
|
| 1051 |
+
}
|
| 1052 |
+
|
| 1053 |
+
// Step 19. Check for splitting the search
|
| 1054 |
+
if ( !SpNode
|
| 1055 |
+
&& depth >= Threads.minimumSplitDepth
|
| 1056 |
+
&& Threads.available_slave(thisThread)
|
| 1057 |
+
&& thisThread->splitPointsSize < MAX_SPLITPOINTS_PER_THREAD)
|
| 1058 |
+
{
|
| 1059 |
+
assert(bestValue < beta);
|
| 1060 |
+
|
| 1061 |
+
thisThread->split<FakeSplit>(pos, ss, alpha, beta, &bestValue, &bestMove,
|
| 1062 |
+
depth, threatMove, moveCount, &mp, NT, cutNode);
|
| 1063 |
+
if (bestValue >= beta)
|
| 1064 |
+
break;
|
| 1065 |
+
}
|
| 1066 |
+
}
|
| 1067 |
+
|
| 1068 |
+
if (SpNode)
|
| 1069 |
+
return bestValue;
|
| 1070 |
+
|
| 1071 |
+
// Step 20. Check for mate and stalemate
|
| 1072 |
+
// All legal moves have been searched and if there are no legal moves, it
|
| 1073 |
+
// must be mate or stalemate. Note that we can have a false positive in
|
| 1074 |
+
// case of Signals.stop or thread.cutoff_occurred() are set, but this is
|
| 1075 |
+
// harmless because return value is discarded anyhow in the parent nodes.
|
| 1076 |
+
// If we are in a singular extension search then return a fail low score.
|
| 1077 |
+
// A split node has at least one move, the one tried before to be splitted.
|
| 1078 |
+
if (!moveCount)
|
| 1079 |
+
return excludedMove ? alpha
|
| 1080 |
+
: inCheck ? mated_in(ss->ply) : DrawValue[pos.side_to_move()];
|
| 1081 |
+
|
| 1082 |
+
// If we have pruned all the moves without searching return a fail-low score
|
| 1083 |
+
if (bestValue == -VALUE_INFINITE)
|
| 1084 |
+
bestValue = alpha;
|
| 1085 |
+
|
| 1086 |
+
TT.store(posKey, value_to_tt(bestValue, ss->ply),
|
| 1087 |
+
bestValue >= beta ? BOUND_LOWER :
|
| 1088 |
+
PvNode && bestMove ? BOUND_EXACT : BOUND_UPPER,
|
| 1089 |
+
depth, bestMove, ss->staticEval, ss->evalMargin);
|
| 1090 |
+
|
| 1091 |
+
// Quiet best move: update killers, history and countermoves
|
| 1092 |
+
if ( bestValue >= beta
|
| 1093 |
+
&& !pos.is_capture_or_promotion(bestMove)
|
| 1094 |
+
&& !inCheck)
|
| 1095 |
+
{
|
| 1096 |
+
if (ss->killers[0] != bestMove)
|
| 1097 |
+
{
|
| 1098 |
+
ss->killers[1] = ss->killers[0];
|
| 1099 |
+
ss->killers[0] = bestMove;
|
| 1100 |
+
}
|
| 1101 |
+
|
| 1102 |
+
// Increase history value of the cut-off move and decrease all the other
|
| 1103 |
+
// played non-capture moves.
|
| 1104 |
+
Value bonus = Value(int(depth) * int(depth));
|
| 1105 |
+
History.update(pos.piece_moved(bestMove), to_sq(bestMove), bonus);
|
| 1106 |
+
for (int i = 0; i < quietCount - 1; i++)
|
| 1107 |
+
{
|
| 1108 |
+
Move m = quietsSearched[i];
|
| 1109 |
+
History.update(pos.piece_moved(m), to_sq(m), -bonus);
|
| 1110 |
+
}
|
| 1111 |
+
|
| 1112 |
+
if (is_ok((ss-1)->currentMove))
|
| 1113 |
+
Countermoves.update(pos.piece_on(prevMoveSq), prevMoveSq, bestMove);
|
| 1114 |
+
}
|
| 1115 |
+
|
| 1116 |
+
assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE);
|
| 1117 |
+
|
| 1118 |
+
return bestValue;
|
| 1119 |
+
}
|
| 1120 |
+
|
| 1121 |
+
|
| 1122 |
+
// qsearch() is the quiescence search function, which is called by the main
|
| 1123 |
+
// search function when the remaining depth is zero (or, to be more precise,
|
| 1124 |
+
// less than ONE_PLY).
|
| 1125 |
+
|
| 1126 |
+
template <NodeType NT, bool InCheck>
|
| 1127 |
+
Value qsearch(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth) {
|
| 1128 |
+
|
| 1129 |
+
const bool PvNode = (NT == PV);
|
| 1130 |
+
|
| 1131 |
+
assert(NT == PV || NT == NonPV);
|
| 1132 |
+
assert(InCheck == !!pos.checkers());
|
| 1133 |
+
assert(alpha >= -VALUE_INFINITE && alpha < beta && beta <= VALUE_INFINITE);
|
| 1134 |
+
assert(PvNode || (alpha == beta - 1));
|
| 1135 |
+
assert(depth <= DEPTH_ZERO);
|
| 1136 |
+
|
| 1137 |
+
StateInfo st;
|
| 1138 |
+
const TTEntry* tte;
|
| 1139 |
+
Key posKey;
|
| 1140 |
+
Move ttMove, move, bestMove;
|
| 1141 |
+
Value bestValue, value, ttValue, futilityValue, futilityBase, oldAlpha;
|
| 1142 |
+
bool givesCheck, evasionPrunable;
|
| 1143 |
+
Depth ttDepth;
|
| 1144 |
+
|
| 1145 |
+
// To flag BOUND_EXACT a node with eval above alpha and no available moves
|
| 1146 |
+
if (PvNode)
|
| 1147 |
+
oldAlpha = alpha;
|
| 1148 |
+
|
| 1149 |
+
ss->currentMove = bestMove = MOVE_NONE;
|
| 1150 |
+
ss->ply = (ss-1)->ply + 1;
|
| 1151 |
+
|
| 1152 |
+
// Check for an instant draw or maximum ply reached
|
| 1153 |
+
if (pos.is_draw() || ss->ply > MAX_PLY)
|
| 1154 |
+
return DrawValue[pos.side_to_move()];
|
| 1155 |
+
|
| 1156 |
+
// Decide whether or not to include checks, this fixes also the type of
|
| 1157 |
+
// TT entry depth that we are going to use. Note that in qsearch we use
|
| 1158 |
+
// only two types of depth in TT: DEPTH_QS_CHECKS or DEPTH_QS_NO_CHECKS.
|
| 1159 |
+
ttDepth = InCheck || depth >= DEPTH_QS_CHECKS ? DEPTH_QS_CHECKS
|
| 1160 |
+
: DEPTH_QS_NO_CHECKS;
|
| 1161 |
+
|
| 1162 |
+
// Transposition table lookup
|
| 1163 |
+
posKey = pos.key();
|
| 1164 |
+
tte = TT.probe(posKey);
|
| 1165 |
+
ttMove = tte ? tte->move() : MOVE_NONE;
|
| 1166 |
+
ttValue = tte ? value_from_tt(tte->value(),ss->ply) : VALUE_NONE;
|
| 1167 |
+
|
| 1168 |
+
if ( tte
|
| 1169 |
+
&& tte->depth() >= ttDepth
|
| 1170 |
+
&& ttValue != VALUE_NONE // Only in case of TT access race
|
| 1171 |
+
&& ( PvNode ? tte->bound() == BOUND_EXACT
|
| 1172 |
+
: ttValue >= beta ? (tte->bound() & BOUND_LOWER)
|
| 1173 |
+
: (tte->bound() & BOUND_UPPER)))
|
| 1174 |
+
{
|
| 1175 |
+
ss->currentMove = ttMove; // Can be MOVE_NONE
|
| 1176 |
+
return ttValue;
|
| 1177 |
+
}
|
| 1178 |
+
|
| 1179 |
+
// Evaluate the position statically
|
| 1180 |
+
if (InCheck)
|
| 1181 |
+
{
|
| 1182 |
+
ss->staticEval = ss->evalMargin = VALUE_NONE;
|
| 1183 |
+
bestValue = futilityBase = -VALUE_INFINITE;
|
| 1184 |
+
}
|
| 1185 |
+
else
|
| 1186 |
+
{
|
| 1187 |
+
if (tte)
|
| 1188 |
+
{
|
| 1189 |
+
// Never assume anything on values stored in TT
|
| 1190 |
+
if ( (ss->staticEval = bestValue = tte->eval_value()) == VALUE_NONE
|
| 1191 |
+
||(ss->evalMargin = tte->eval_margin()) == VALUE_NONE)
|
| 1192 |
+
ss->staticEval = bestValue = evaluate(pos, ss->evalMargin);
|
| 1193 |
+
}
|
| 1194 |
+
else
|
| 1195 |
+
ss->staticEval = bestValue = evaluate(pos, ss->evalMargin);
|
| 1196 |
+
|
| 1197 |
+
// Stand pat. Return immediately if static value is at least beta
|
| 1198 |
+
if (bestValue >= beta)
|
| 1199 |
+
{
|
| 1200 |
+
if (!tte)
|
| 1201 |
+
TT.store(pos.key(), value_to_tt(bestValue, ss->ply), BOUND_LOWER,
|
| 1202 |
+
DEPTH_NONE, MOVE_NONE, ss->staticEval, ss->evalMargin);
|
| 1203 |
+
|
| 1204 |
+
return bestValue;
|
| 1205 |
+
}
|
| 1206 |
+
|
| 1207 |
+
if (PvNode && bestValue > alpha)
|
| 1208 |
+
alpha = bestValue;
|
| 1209 |
+
|
| 1210 |
+
futilityBase = ss->staticEval + ss->evalMargin + Value(128);
|
| 1211 |
+
}
|
| 1212 |
+
|
| 1213 |
+
// Initialize a MovePicker object for the current position, and prepare
|
| 1214 |
+
// to search the moves. Because the depth is <= 0 here, only captures,
|
| 1215 |
+
// queen promotions and checks (only if depth >= DEPTH_QS_CHECKS) will
|
| 1216 |
+
// be generated.
|
| 1217 |
+
MovePicker mp(pos, ttMove, depth, History, to_sq((ss-1)->currentMove));
|
| 1218 |
+
CheckInfo ci(pos);
|
| 1219 |
+
|
| 1220 |
+
// Loop through the moves until no moves remain or a beta cutoff occurs
|
| 1221 |
+
while ((move = mp.next_move<false>()) != MOVE_NONE)
|
| 1222 |
+
{
|
| 1223 |
+
assert(is_ok(move));
|
| 1224 |
+
|
| 1225 |
+
givesCheck = pos.move_gives_check(move, ci);
|
| 1226 |
+
|
| 1227 |
+
// Futility pruning
|
| 1228 |
+
if ( !PvNode
|
| 1229 |
+
&& !InCheck
|
| 1230 |
+
&& !givesCheck
|
| 1231 |
+
&& move != ttMove
|
| 1232 |
+
&& type_of(move) != PROMOTION
|
| 1233 |
+
&& !pos.is_passed_pawn_push(move))
|
| 1234 |
+
{
|
| 1235 |
+
futilityValue = futilityBase
|
| 1236 |
+
+ PieceValue[EG][pos.piece_on(to_sq(move))]
|
| 1237 |
+
+ (type_of(move) == ENPASSANT ? PawnValueEg : VALUE_ZERO);
|
| 1238 |
+
|
| 1239 |
+
if (futilityValue < beta)
|
| 1240 |
+
{
|
| 1241 |
+
bestValue = std::max(bestValue, futilityValue);
|
| 1242 |
+
continue;
|
| 1243 |
+
}
|
| 1244 |
+
|
| 1245 |
+
// Prune moves with negative or equal SEE and also moves with positive
|
| 1246 |
+
// SEE where capturing piece loses a tempo and SEE < beta - futilityBase.
|
| 1247 |
+
if ( futilityBase < beta
|
| 1248 |
+
&& pos.see(move, beta - futilityBase) <= 0)
|
| 1249 |
+
{
|
| 1250 |
+
bestValue = std::max(bestValue, futilityBase);
|
| 1251 |
+
continue;
|
| 1252 |
+
}
|
| 1253 |
+
}
|
| 1254 |
+
|
| 1255 |
+
// Detect non-capture evasions that are candidate to be pruned
|
| 1256 |
+
evasionPrunable = InCheck
|
| 1257 |
+
&& bestValue > VALUE_MATED_IN_MAX_PLY
|
| 1258 |
+
&& !pos.is_capture(move)
|
| 1259 |
+
&& !pos.can_castle(pos.side_to_move());
|
| 1260 |
+
|
| 1261 |
+
// Don't search moves with negative SEE values
|
| 1262 |
+
if ( !PvNode
|
| 1263 |
+
&& (!InCheck || evasionPrunable)
|
| 1264 |
+
&& move != ttMove
|
| 1265 |
+
&& type_of(move) != PROMOTION
|
| 1266 |
+
&& pos.see_sign(move) < 0)
|
| 1267 |
+
continue;
|
| 1268 |
+
|
| 1269 |
+
// Don't search useless checks
|
| 1270 |
+
if ( !PvNode
|
| 1271 |
+
&& !InCheck
|
| 1272 |
+
&& givesCheck
|
| 1273 |
+
&& move != ttMove
|
| 1274 |
+
&& !pos.is_capture_or_promotion(move)
|
| 1275 |
+
&& ss->staticEval + PawnValueMg / 4 < beta
|
| 1276 |
+
&& !check_is_dangerous(pos, move, futilityBase, beta))
|
| 1277 |
+
continue;
|
| 1278 |
+
|
| 1279 |
+
// Check for legality only before to do the move
|
| 1280 |
+
if (!pos.pl_move_is_legal(move, ci.pinned))
|
| 1281 |
+
continue;
|
| 1282 |
+
|
| 1283 |
+
ss->currentMove = move;
|
| 1284 |
+
|
| 1285 |
+
// Make and search the move
|
| 1286 |
+
pos.do_move(move, st, ci, givesCheck);
|
| 1287 |
+
value = givesCheck ? -qsearch<NT, true>(pos, ss+1, -beta, -alpha, depth - ONE_PLY)
|
| 1288 |
+
: -qsearch<NT, false>(pos, ss+1, -beta, -alpha, depth - ONE_PLY);
|
| 1289 |
+
pos.undo_move(move);
|
| 1290 |
+
|
| 1291 |
+
assert(value > -VALUE_INFINITE && value < VALUE_INFINITE);
|
| 1292 |
+
|
| 1293 |
+
// Check for new best move
|
| 1294 |
+
if (value > bestValue)
|
| 1295 |
+
{
|
| 1296 |
+
bestValue = value;
|
| 1297 |
+
|
| 1298 |
+
if (value > alpha)
|
| 1299 |
+
{
|
| 1300 |
+
if (PvNode && value < beta) // Update alpha here! Always alpha < beta
|
| 1301 |
+
{
|
| 1302 |
+
alpha = value;
|
| 1303 |
+
bestMove = move;
|
| 1304 |
+
}
|
| 1305 |
+
else // Fail high
|
| 1306 |
+
{
|
| 1307 |
+
TT.store(posKey, value_to_tt(value, ss->ply), BOUND_LOWER,
|
| 1308 |
+
ttDepth, move, ss->staticEval, ss->evalMargin);
|
| 1309 |
+
|
| 1310 |
+
return value;
|
| 1311 |
+
}
|
| 1312 |
+
}
|
| 1313 |
+
}
|
| 1314 |
+
}
|
| 1315 |
+
|
| 1316 |
+
// All legal moves have been searched. A special case: If we're in check
|
| 1317 |
+
// and no legal moves were found, it is checkmate.
|
| 1318 |
+
if (InCheck && bestValue == -VALUE_INFINITE)
|
| 1319 |
+
return mated_in(ss->ply); // Plies to mate from the root
|
| 1320 |
+
|
| 1321 |
+
TT.store(posKey, value_to_tt(bestValue, ss->ply),
|
| 1322 |
+
PvNode && bestValue > oldAlpha ? BOUND_EXACT : BOUND_UPPER,
|
| 1323 |
+
ttDepth, bestMove, ss->staticEval, ss->evalMargin);
|
| 1324 |
+
|
| 1325 |
+
assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE);
|
| 1326 |
+
|
| 1327 |
+
return bestValue;
|
| 1328 |
+
}
|
| 1329 |
+
|
| 1330 |
+
|
| 1331 |
+
// value_to_tt() adjusts a mate score from "plies to mate from the root" to
|
| 1332 |
+
// "plies to mate from the current position". Non-mate scores are unchanged.
|
| 1333 |
+
// The function is called before storing a value to the transposition table.
|
| 1334 |
+
|
| 1335 |
+
Value value_to_tt(Value v, int ply) {
|
| 1336 |
+
|
| 1337 |
+
assert(v != VALUE_NONE);
|
| 1338 |
+
|
| 1339 |
+
return v >= VALUE_MATE_IN_MAX_PLY ? v + ply
|
| 1340 |
+
: v <= VALUE_MATED_IN_MAX_PLY ? v - ply : v;
|
| 1341 |
+
}
|
| 1342 |
+
|
| 1343 |
+
|
| 1344 |
+
// value_from_tt() is the inverse of value_to_tt(): It adjusts a mate score
|
| 1345 |
+
// from the transposition table (where refers to the plies to mate/be mated
|
| 1346 |
+
// from current position) to "plies to mate/be mated from the root".
|
| 1347 |
+
|
| 1348 |
+
Value value_from_tt(Value v, int ply) {
|
| 1349 |
+
|
| 1350 |
+
return v == VALUE_NONE ? VALUE_NONE
|
| 1351 |
+
: v >= VALUE_MATE_IN_MAX_PLY ? v - ply
|
| 1352 |
+
: v <= VALUE_MATED_IN_MAX_PLY ? v + ply : v;
|
| 1353 |
+
}
|
| 1354 |
+
|
| 1355 |
+
|
| 1356 |
+
// check_is_dangerous() tests if a checking move can be pruned in qsearch()
|
| 1357 |
+
|
| 1358 |
+
bool check_is_dangerous(const Position& pos, Move move, Value futilityBase, Value beta)
|
| 1359 |
+
{
|
| 1360 |
+
Piece pc = pos.piece_moved(move);
|
| 1361 |
+
Square from = from_sq(move);
|
| 1362 |
+
Square to = to_sq(move);
|
| 1363 |
+
Color them = ~pos.side_to_move();
|
| 1364 |
+
Square ksq = pos.king_square(them);
|
| 1365 |
+
Bitboard enemies = pos.pieces(them);
|
| 1366 |
+
Bitboard kingAtt = pos.attacks_from<KING>(ksq);
|
| 1367 |
+
Bitboard occ = pos.pieces() ^ from ^ ksq;
|
| 1368 |
+
Bitboard oldAtt = pos.attacks_from(pc, from, occ);
|
| 1369 |
+
Bitboard newAtt = pos.attacks_from(pc, to, occ);
|
| 1370 |
+
|
| 1371 |
+
// Checks which give opponent's king at most one escape square are dangerous
|
| 1372 |
+
if (!more_than_one(kingAtt & ~(enemies | newAtt | to)))
|
| 1373 |
+
return true;
|
| 1374 |
+
|
| 1375 |
+
// Queen contact check is very dangerous
|
| 1376 |
+
if (type_of(pc) == QUEEN && (kingAtt & to))
|
| 1377 |
+
return true;
|
| 1378 |
+
|
| 1379 |
+
// Creating new double threats with checks is dangerous
|
| 1380 |
+
Bitboard b = (enemies ^ ksq) & newAtt & ~oldAtt;
|
| 1381 |
+
while (b)
|
| 1382 |
+
{
|
| 1383 |
+
// Note that here we generate illegal "double move"!
|
| 1384 |
+
if (futilityBase + PieceValue[EG][pos.piece_on(pop_lsb(&b))] >= beta)
|
| 1385 |
+
return true;
|
| 1386 |
+
}
|
| 1387 |
+
|
| 1388 |
+
return false;
|
| 1389 |
+
}
|
| 1390 |
+
|
| 1391 |
+
|
| 1392 |
+
// allows() tests whether the 'first' move at previous ply somehow makes the
|
| 1393 |
+
// 'second' move possible, for instance if the moving piece is the same in
|
| 1394 |
+
// both moves. Normally the second move is the threat (the best move returned
|
| 1395 |
+
// from a null search that fails low).
|
| 1396 |
+
|
| 1397 |
+
bool allows(const Position& pos, Move first, Move second) {
|
| 1398 |
+
|
| 1399 |
+
assert(is_ok(first));
|
| 1400 |
+
assert(is_ok(second));
|
| 1401 |
+
assert(color_of(pos.piece_on(from_sq(second))) == ~pos.side_to_move());
|
| 1402 |
+
assert(color_of(pos.piece_on(to_sq(first))) == ~pos.side_to_move());
|
| 1403 |
+
|
| 1404 |
+
Square m1from = from_sq(first);
|
| 1405 |
+
Square m2from = from_sq(second);
|
| 1406 |
+
Square m1to = to_sq(first);
|
| 1407 |
+
Square m2to = to_sq(second);
|
| 1408 |
+
|
| 1409 |
+
// The piece is the same or second's destination was vacated by the first move
|
| 1410 |
+
if (m1to == m2from || m2to == m1from)
|
| 1411 |
+
return true;
|
| 1412 |
+
|
| 1413 |
+
// Second one moves through the square vacated by first one
|
| 1414 |
+
if (between_bb(m2from, m2to) & m1from)
|
| 1415 |
+
return true;
|
| 1416 |
+
|
| 1417 |
+
// Second's destination is defended by the first move's piece
|
| 1418 |
+
Bitboard m1att = pos.attacks_from(pos.piece_on(m1to), m1to, pos.pieces() ^ m2from);
|
| 1419 |
+
if (m1att & m2to)
|
| 1420 |
+
return true;
|
| 1421 |
+
|
| 1422 |
+
// Second move gives a discovered check through the first's checking piece
|
| 1423 |
+
if (m1att & pos.king_square(pos.side_to_move()))
|
| 1424 |
+
{
|
| 1425 |
+
assert(between_bb(m1to, pos.king_square(pos.side_to_move())) & m2from);
|
| 1426 |
+
return true;
|
| 1427 |
+
}
|
| 1428 |
+
|
| 1429 |
+
return false;
|
| 1430 |
+
}
|
| 1431 |
+
|
| 1432 |
+
|
| 1433 |
+
// refutes() tests whether a 'first' move is able to defend against a 'second'
|
| 1434 |
+
// opponent's move. In this case will not be pruned. Normally the second move
|
| 1435 |
+
// is the threat (the best move returned from a null search that fails low).
|
| 1436 |
+
|
| 1437 |
+
bool refutes(const Position& pos, Move first, Move second) {
|
| 1438 |
+
|
| 1439 |
+
assert(is_ok(first));
|
| 1440 |
+
assert(is_ok(second));
|
| 1441 |
+
|
| 1442 |
+
Square m1from = from_sq(first);
|
| 1443 |
+
Square m2from = from_sq(second);
|
| 1444 |
+
Square m1to = to_sq(first);
|
| 1445 |
+
Square m2to = to_sq(second);
|
| 1446 |
+
|
| 1447 |
+
// Don't prune moves of the threatened piece
|
| 1448 |
+
if (m1from == m2to)
|
| 1449 |
+
return true;
|
| 1450 |
+
|
| 1451 |
+
// If the threatened piece has value less than or equal to the value of the
|
| 1452 |
+
// threat piece, don't prune moves which defend it.
|
| 1453 |
+
if ( pos.is_capture(second)
|
| 1454 |
+
&& ( PieceValue[MG][pos.piece_on(m2from)] >= PieceValue[MG][pos.piece_on(m2to)]
|
| 1455 |
+
|| type_of(pos.piece_on(m2from)) == KING))
|
| 1456 |
+
{
|
| 1457 |
+
// Update occupancy as if the piece and the threat are moving
|
| 1458 |
+
Bitboard occ = pos.pieces() ^ m1from ^ m1to ^ m2from;
|
| 1459 |
+
Piece pc = pos.piece_on(m1from);
|
| 1460 |
+
|
| 1461 |
+
// The moved piece attacks the square 'tto' ?
|
| 1462 |
+
if (pos.attacks_from(pc, m1to, occ) & m2to)
|
| 1463 |
+
return true;
|
| 1464 |
+
|
| 1465 |
+
// Scan for possible X-ray attackers behind the moved piece
|
| 1466 |
+
Bitboard xray = (attacks_bb< ROOK>(m2to, occ) & pos.pieces(color_of(pc), QUEEN, ROOK))
|
| 1467 |
+
| (attacks_bb<BISHOP>(m2to, occ) & pos.pieces(color_of(pc), QUEEN, BISHOP));
|
| 1468 |
+
|
| 1469 |
+
// Verify attackers are triggered by our move and not already existing
|
| 1470 |
+
if (unlikely(xray) && (xray & ~pos.attacks_from<QUEEN>(m2to)))
|
| 1471 |
+
return true;
|
| 1472 |
+
}
|
| 1473 |
+
|
| 1474 |
+
// Don't prune safe moves which block the threat path
|
| 1475 |
+
if ((between_bb(m2from, m2to) & m1to) && pos.see_sign(first) >= 0)
|
| 1476 |
+
return true;
|
| 1477 |
+
|
| 1478 |
+
return false;
|
| 1479 |
+
}
|
| 1480 |
+
|
| 1481 |
+
|
| 1482 |
+
// When playing with strength handicap choose best move among the MultiPV set
|
| 1483 |
+
// using a statistical rule dependent on 'level'. Idea by Heinz van Saanen.
|
| 1484 |
+
|
| 1485 |
+
Move Skill::pick_move() {
|
| 1486 |
+
|
| 1487 |
+
static RKISS rk;
|
| 1488 |
+
|
| 1489 |
+
// PRNG sequence should be not deterministic
|
| 1490 |
+
for (int i = Time::now() % 50; i > 0; i--)
|
| 1491 |
+
rk.rand<unsigned>();
|
| 1492 |
+
|
| 1493 |
+
// RootMoves are already sorted by score in descending order
|
| 1494 |
+
int variance = std::min(RootMoves[0].score - RootMoves[PVSize - 1].score, PawnValueMg);
|
| 1495 |
+
int weakness = 120 - 2 * level;
|
| 1496 |
+
int max_s = -VALUE_INFINITE;
|
| 1497 |
+
best = MOVE_NONE;
|
| 1498 |
+
|
| 1499 |
+
// Choose best move. For each move score we add two terms both dependent on
|
| 1500 |
+
// weakness, one deterministic and bigger for weaker moves, and one random,
|
| 1501 |
+
// then we choose the move with the resulting highest score.
|
| 1502 |
+
for (size_t i = 0; i < PVSize; i++)
|
| 1503 |
+
{
|
| 1504 |
+
int s = RootMoves[i].score;
|
| 1505 |
+
|
| 1506 |
+
// Don't allow crazy blunders even at very low skills
|
| 1507 |
+
if (i > 0 && RootMoves[i-1].score > s + 2 * PawnValueMg)
|
| 1508 |
+
break;
|
| 1509 |
+
|
| 1510 |
+
// This is our magic formula
|
| 1511 |
+
s += ( weakness * int(RootMoves[0].score - s)
|
| 1512 |
+
+ variance * (rk.rand<unsigned>() % weakness)) / 128;
|
| 1513 |
+
|
| 1514 |
+
if (s > max_s)
|
| 1515 |
+
{
|
| 1516 |
+
max_s = s;
|
| 1517 |
+
best = RootMoves[i].pv[0];
|
| 1518 |
+
}
|
| 1519 |
+
}
|
| 1520 |
+
return best;
|
| 1521 |
+
}
|
| 1522 |
+
|
| 1523 |
+
|
| 1524 |
+
// uci_pv() formats PV information according to UCI protocol. UCI requires
|
| 1525 |
+
// to send all the PV lines also if are still to be searched and so refer to
|
| 1526 |
+
// the previous search score.
|
| 1527 |
+
|
| 1528 |
+
string uci_pv(const Position& pos, int depth, Value alpha, Value beta) {
|
| 1529 |
+
|
| 1530 |
+
std::stringstream s;
|
| 1531 |
+
Time::point elapsed = Time::now() - SearchTime + 1;
|
| 1532 |
+
size_t uciPVSize = std::min((size_t)Options["MultiPV"], RootMoves.size());
|
| 1533 |
+
int selDepth = 0;
|
| 1534 |
+
|
| 1535 |
+
for (size_t i = 0; i < Threads.size(); i++)
|
| 1536 |
+
if (Threads[i]->maxPly > selDepth)
|
| 1537 |
+
selDepth = Threads[i]->maxPly;
|
| 1538 |
+
|
| 1539 |
+
for (size_t i = 0; i < uciPVSize; i++)
|
| 1540 |
+
{
|
| 1541 |
+
bool updated = (i <= PVIdx);
|
| 1542 |
+
|
| 1543 |
+
if (depth == 1 && !updated)
|
| 1544 |
+
continue;
|
| 1545 |
+
|
| 1546 |
+
int d = updated ? depth : depth - 1;
|
| 1547 |
+
Value v = updated ? RootMoves[i].score : RootMoves[i].prevScore;
|
| 1548 |
+
|
| 1549 |
+
if (s.rdbuf()->in_avail()) // Not at first line
|
| 1550 |
+
s << "\n";
|
| 1551 |
+
|
| 1552 |
+
s << "info depth " << d
|
| 1553 |
+
<< " seldepth " << selDepth
|
| 1554 |
+
<< " score " << (i == PVIdx ? score_to_uci(v, alpha, beta) : score_to_uci(v))
|
| 1555 |
+
<< " nodes " << pos.nodes_searched()
|
| 1556 |
+
<< " nps " << pos.nodes_searched() * 1000 / elapsed
|
| 1557 |
+
<< " time " << elapsed
|
| 1558 |
+
<< " multipv " << i + 1
|
| 1559 |
+
<< " pv";
|
| 1560 |
+
|
| 1561 |
+
for (size_t j = 0; RootMoves[i].pv[j] != MOVE_NONE; j++)
|
| 1562 |
+
s << " " << move_to_uci(RootMoves[i].pv[j], pos.is_chess960());
|
| 1563 |
+
}
|
| 1564 |
+
|
| 1565 |
+
return s.str();
|
| 1566 |
+
}
|
| 1567 |
+
|
| 1568 |
+
} // namespace
|
| 1569 |
+
|
| 1570 |
+
|
| 1571 |
+
/// RootMove::extract_pv_from_tt() builds a PV by adding moves from the TT table.
|
| 1572 |
+
/// We consider also failing high nodes and not only BOUND_EXACT nodes so to
|
| 1573 |
+
/// allow to always have a ponder move even when we fail high at root, and a
|
| 1574 |
+
/// long PV to print that is important for position analysis.
|
| 1575 |
+
|
| 1576 |
+
void RootMove::extract_pv_from_tt(Position& pos) {
|
| 1577 |
+
|
| 1578 |
+
StateInfo state[MAX_PLY_PLUS_6], *st = state;
|
| 1579 |
+
const TTEntry* tte;
|
| 1580 |
+
int ply = 0;
|
| 1581 |
+
Move m = pv[0];
|
| 1582 |
+
|
| 1583 |
+
pv.clear();
|
| 1584 |
+
|
| 1585 |
+
do {
|
| 1586 |
+
pv.push_back(m);
|
| 1587 |
+
|
| 1588 |
+
assert(MoveList<LEGAL>(pos).contains(pv[ply]));
|
| 1589 |
+
|
| 1590 |
+
pos.do_move(pv[ply++], *st++);
|
| 1591 |
+
tte = TT.probe(pos.key());
|
| 1592 |
+
|
| 1593 |
+
} while ( tte
|
| 1594 |
+
&& pos.is_pseudo_legal(m = tte->move()) // Local copy, TT could change
|
| 1595 |
+
&& pos.pl_move_is_legal(m, pos.pinned_pieces())
|
| 1596 |
+
&& ply < MAX_PLY
|
| 1597 |
+
&& (!pos.is_draw() || ply < 2));
|
| 1598 |
+
|
| 1599 |
+
pv.push_back(MOVE_NONE); // Must be zero-terminating
|
| 1600 |
+
|
| 1601 |
+
while (ply) pos.undo_move(pv[--ply]);
|
| 1602 |
+
}
|
| 1603 |
+
|
| 1604 |
+
|
| 1605 |
+
/// RootMove::insert_pv_in_tt() is called at the end of a search iteration, and
|
| 1606 |
+
/// inserts the PV back into the TT. This makes sure the old PV moves are searched
|
| 1607 |
+
/// first, even if the old TT entries have been overwritten.
|
| 1608 |
+
|
| 1609 |
+
void RootMove::insert_pv_in_tt(Position& pos) {
|
| 1610 |
+
|
| 1611 |
+
StateInfo state[MAX_PLY_PLUS_6], *st = state;
|
| 1612 |
+
const TTEntry* tte;
|
| 1613 |
+
int ply = 0;
|
| 1614 |
+
|
| 1615 |
+
do {
|
| 1616 |
+
tte = TT.probe(pos.key());
|
| 1617 |
+
|
| 1618 |
+
if (!tte || tte->move() != pv[ply]) // Don't overwrite correct entries
|
| 1619 |
+
TT.store(pos.key(), VALUE_NONE, BOUND_NONE, DEPTH_NONE, pv[ply], VALUE_NONE, VALUE_NONE);
|
| 1620 |
+
|
| 1621 |
+
assert(MoveList<LEGAL>(pos).contains(pv[ply]));
|
| 1622 |
+
|
| 1623 |
+
pos.do_move(pv[ply++], *st++);
|
| 1624 |
+
|
| 1625 |
+
} while (pv[ply] != MOVE_NONE);
|
| 1626 |
+
|
| 1627 |
+
while (ply) pos.undo_move(pv[--ply]);
|
| 1628 |
+
}
|
| 1629 |
+
|
| 1630 |
+
|
| 1631 |
+
/// Thread::idle_loop() is where the thread is parked when it has no work to do
|
| 1632 |
+
|
| 1633 |
+
void Thread::idle_loop() {
|
| 1634 |
+
|
| 1635 |
+
// Pointer 'this_sp' is not null only if we are called from split(), and not
|
| 1636 |
+
// at the thread creation. So it means we are the split point's master.
|
| 1637 |
+
SplitPoint* this_sp = splitPointsSize ? activeSplitPoint : NULL;
|
| 1638 |
+
|
| 1639 |
+
assert(!this_sp || (this_sp->masterThread == this && searching));
|
| 1640 |
+
|
| 1641 |
+
while (true)
|
| 1642 |
+
{
|
| 1643 |
+
// If we are not searching, wait for a condition to be signaled instead of
|
| 1644 |
+
// wasting CPU time polling for work.
|
| 1645 |
+
while ((!searching && Threads.sleepWhileIdle) || exit)
|
| 1646 |
+
{
|
| 1647 |
+
if (exit)
|
| 1648 |
+
{
|
| 1649 |
+
assert(!this_sp);
|
| 1650 |
+
return;
|
| 1651 |
+
}
|
| 1652 |
+
|
| 1653 |
+
// Grab the lock to avoid races with Thread::notify_one()
|
| 1654 |
+
mutex.lock();
|
| 1655 |
+
|
| 1656 |
+
// If we are master and all slaves have finished then exit idle_loop
|
| 1657 |
+
if (this_sp && !this_sp->slavesMask)
|
| 1658 |
+
{
|
| 1659 |
+
mutex.unlock();
|
| 1660 |
+
break;
|
| 1661 |
+
}
|
| 1662 |
+
|
| 1663 |
+
// Do sleep after retesting sleep conditions under lock protection, in
|
| 1664 |
+
// particular we need to avoid a deadlock in case a master thread has,
|
| 1665 |
+
// in the meanwhile, allocated us and sent the notify_one() call before
|
| 1666 |
+
// we had the chance to grab the lock.
|
| 1667 |
+
if (!searching && !exit)
|
| 1668 |
+
sleepCondition.wait(mutex);
|
| 1669 |
+
|
| 1670 |
+
mutex.unlock();
|
| 1671 |
+
}
|
| 1672 |
+
|
| 1673 |
+
// If this thread has been assigned work, launch a search
|
| 1674 |
+
if (searching)
|
| 1675 |
+
{
|
| 1676 |
+
assert(!exit);
|
| 1677 |
+
|
| 1678 |
+
Threads.mutex.lock();
|
| 1679 |
+
|
| 1680 |
+
assert(searching);
|
| 1681 |
+
assert(activeSplitPoint);
|
| 1682 |
+
SplitPoint* sp = activeSplitPoint;
|
| 1683 |
+
|
| 1684 |
+
Threads.mutex.unlock();
|
| 1685 |
+
|
| 1686 |
+
Stack stack[MAX_PLY_PLUS_6], *ss = stack+2; // To allow referencing (ss-2)
|
| 1687 |
+
Position pos(*sp->pos, this);
|
| 1688 |
+
|
| 1689 |
+
std::memcpy(ss-2, sp->ss-2, 5 * sizeof(Stack));
|
| 1690 |
+
ss->splitPoint = sp;
|
| 1691 |
+
|
| 1692 |
+
sp->mutex.lock();
|
| 1693 |
+
|
| 1694 |
+
assert(activePosition == NULL);
|
| 1695 |
+
|
| 1696 |
+
activePosition = &pos;
|
| 1697 |
+
|
| 1698 |
+
switch (sp->nodeType) {
|
| 1699 |
+
case Root:
|
| 1700 |
+
search<SplitPointRoot>(pos, ss, sp->alpha, sp->beta, sp->depth, sp->cutNode);
|
| 1701 |
+
break;
|
| 1702 |
+
case PV:
|
| 1703 |
+
search<SplitPointPV>(pos, ss, sp->alpha, sp->beta, sp->depth, sp->cutNode);
|
| 1704 |
+
break;
|
| 1705 |
+
case NonPV:
|
| 1706 |
+
search<SplitPointNonPV>(pos, ss, sp->alpha, sp->beta, sp->depth, sp->cutNode);
|
| 1707 |
+
break;
|
| 1708 |
+
default:
|
| 1709 |
+
assert(false);
|
| 1710 |
+
}
|
| 1711 |
+
|
| 1712 |
+
assert(searching);
|
| 1713 |
+
|
| 1714 |
+
searching = false;
|
| 1715 |
+
activePosition = NULL;
|
| 1716 |
+
sp->slavesMask &= ~(1ULL << idx);
|
| 1717 |
+
sp->nodes += pos.nodes_searched();
|
| 1718 |
+
|
| 1719 |
+
// Wake up master thread so to allow it to return from the idle loop
|
| 1720 |
+
// in case we are the last slave of the split point.
|
| 1721 |
+
if ( Threads.sleepWhileIdle
|
| 1722 |
+
&& this != sp->masterThread
|
| 1723 |
+
&& !sp->slavesMask)
|
| 1724 |
+
{
|
| 1725 |
+
assert(!sp->masterThread->searching);
|
| 1726 |
+
sp->masterThread->notify_one();
|
| 1727 |
+
}
|
| 1728 |
+
|
| 1729 |
+
// After releasing the lock we cannot access anymore any SplitPoint
|
| 1730 |
+
// related data in a safe way becuase it could have been released under
|
| 1731 |
+
// our feet by the sp master. Also accessing other Thread objects is
|
| 1732 |
+
// unsafe because if we are exiting there is a chance are already freed.
|
| 1733 |
+
sp->mutex.unlock();
|
| 1734 |
+
}
|
| 1735 |
+
|
| 1736 |
+
// If this thread is the master of a split point and all slaves have finished
|
| 1737 |
+
// their work at this split point, return from the idle loop.
|
| 1738 |
+
if (this_sp && !this_sp->slavesMask)
|
| 1739 |
+
{
|
| 1740 |
+
this_sp->mutex.lock();
|
| 1741 |
+
bool finished = !this_sp->slavesMask; // Retest under lock protection
|
| 1742 |
+
this_sp->mutex.unlock();
|
| 1743 |
+
if (finished)
|
| 1744 |
+
return;
|
| 1745 |
+
}
|
| 1746 |
+
}
|
| 1747 |
+
}
|
| 1748 |
+
|
| 1749 |
+
|
| 1750 |
+
/// check_time() is called by the timer thread when the timer triggers. It is
|
| 1751 |
+
/// used to print debug info and, more important, to detect when we are out of
|
| 1752 |
+
/// available time and so stop the search.
|
| 1753 |
+
|
| 1754 |
+
void check_time() {
|
| 1755 |
+
|
| 1756 |
+
static Time::point lastInfoTime = Time::now();
|
| 1757 |
+
int64_t nodes = 0; // Workaround silly 'uninitialized' gcc warning
|
| 1758 |
+
|
| 1759 |
+
if (Time::now() - lastInfoTime >= 1000)
|
| 1760 |
+
{
|
| 1761 |
+
lastInfoTime = Time::now();
|
| 1762 |
+
dbg_print();
|
| 1763 |
+
}
|
| 1764 |
+
|
| 1765 |
+
if (Limits.ponder)
|
| 1766 |
+
return;
|
| 1767 |
+
|
| 1768 |
+
if (Limits.nodes)
|
| 1769 |
+
{
|
| 1770 |
+
Threads.mutex.lock();
|
| 1771 |
+
|
| 1772 |
+
nodes = RootPos.nodes_searched();
|
| 1773 |
+
|
| 1774 |
+
// Loop across all split points and sum accumulated SplitPoint nodes plus
|
| 1775 |
+
// all the currently active positions nodes.
|
| 1776 |
+
for (size_t i = 0; i < Threads.size(); i++)
|
| 1777 |
+
for (int j = 0; j < Threads[i]->splitPointsSize; j++)
|
| 1778 |
+
{
|
| 1779 |
+
SplitPoint& sp = Threads[i]->splitPoints[j];
|
| 1780 |
+
|
| 1781 |
+
sp.mutex.lock();
|
| 1782 |
+
|
| 1783 |
+
nodes += sp.nodes;
|
| 1784 |
+
Bitboard sm = sp.slavesMask;
|
| 1785 |
+
while (sm)
|
| 1786 |
+
{
|
| 1787 |
+
Position* pos = Threads[pop_lsb(&sm)]->activePosition;
|
| 1788 |
+
if (pos)
|
| 1789 |
+
nodes += pos->nodes_searched();
|
| 1790 |
+
}
|
| 1791 |
+
|
| 1792 |
+
sp.mutex.unlock();
|
| 1793 |
+
}
|
| 1794 |
+
|
| 1795 |
+
Threads.mutex.unlock();
|
| 1796 |
+
}
|
| 1797 |
+
|
| 1798 |
+
Time::point elapsed = Time::now() - SearchTime;
|
| 1799 |
+
bool stillAtFirstMove = Signals.firstRootMove
|
| 1800 |
+
&& !Signals.failedLowAtRoot
|
| 1801 |
+
&& elapsed > TimeMgr.available_time();
|
| 1802 |
+
|
| 1803 |
+
bool noMoreTime = elapsed > TimeMgr.maximum_time() - 2 * TimerResolution
|
| 1804 |
+
|| stillAtFirstMove;
|
| 1805 |
+
|
| 1806 |
+
if ( (Limits.use_time_management() && noMoreTime)
|
| 1807 |
+
|| (Limits.movetime && elapsed >= Limits.movetime)
|
| 1808 |
+
|| (Limits.nodes && nodes >= Limits.nodes))
|
| 1809 |
+
Signals.stop = true;
|
| 1810 |
+
}
|
stockfish-4-win/src/search.h
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
+
Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
+
|
| 6 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 7 |
+
it under the terms of the GNU General Public License as published by
|
| 8 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 9 |
+
(at your option) any later version.
|
| 10 |
+
|
| 11 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 12 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 13 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 14 |
+
GNU General Public License for more details.
|
| 15 |
+
|
| 16 |
+
You should have received a copy of the GNU General Public License
|
| 17 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 18 |
+
*/
|
| 19 |
+
|
| 20 |
+
#ifndef SEARCH_H_INCLUDED
|
| 21 |
+
#define SEARCH_H_INCLUDED
|
| 22 |
+
|
| 23 |
+
#include <cstring>
|
| 24 |
+
#include <memory>
|
| 25 |
+
#include <stack>
|
| 26 |
+
#include <vector>
|
| 27 |
+
|
| 28 |
+
#include "misc.h"
|
| 29 |
+
#include "position.h"
|
| 30 |
+
#include "types.h"
|
| 31 |
+
|
| 32 |
+
struct SplitPoint;
|
| 33 |
+
|
| 34 |
+
namespace Search {
|
| 35 |
+
|
| 36 |
+
/// The Stack struct keeps track of the information we need to remember from
|
| 37 |
+
/// nodes shallower and deeper in the tree during the search. Each search thread
|
| 38 |
+
/// has its own array of Stack objects, indexed by the current ply.
|
| 39 |
+
|
| 40 |
+
struct Stack {
|
| 41 |
+
SplitPoint* splitPoint;
|
| 42 |
+
int ply;
|
| 43 |
+
Move currentMove;
|
| 44 |
+
Move excludedMove;
|
| 45 |
+
Move killers[2];
|
| 46 |
+
Depth reduction;
|
| 47 |
+
Value staticEval;
|
| 48 |
+
Value evalMargin;
|
| 49 |
+
int skipNullMove;
|
| 50 |
+
int futilityMoveCount;
|
| 51 |
+
};
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
/// RootMove struct is used for moves at the root of the tree. For each root
|
| 55 |
+
/// move we store a score, a node count, and a PV (really a refutation in the
|
| 56 |
+
/// case of moves which fail low). Score is normally set at -VALUE_INFINITE for
|
| 57 |
+
/// all non-pv moves.
|
| 58 |
+
struct RootMove {
|
| 59 |
+
|
| 60 |
+
RootMove(Move m) : score(-VALUE_INFINITE), prevScore(-VALUE_INFINITE) {
|
| 61 |
+
pv.push_back(m); pv.push_back(MOVE_NONE);
|
| 62 |
+
}
|
| 63 |
+
|
| 64 |
+
bool operator<(const RootMove& m) const { return score > m.score; } // Ascending sort
|
| 65 |
+
bool operator==(const Move& m) const { return pv[0] == m; }
|
| 66 |
+
|
| 67 |
+
void extract_pv_from_tt(Position& pos);
|
| 68 |
+
void insert_pv_in_tt(Position& pos);
|
| 69 |
+
|
| 70 |
+
Value score;
|
| 71 |
+
Value prevScore;
|
| 72 |
+
std::vector<Move> pv;
|
| 73 |
+
};
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
/// The LimitsType struct stores information sent by GUI about available time
|
| 77 |
+
/// to search the current move, maximum depth/time, if we are in analysis mode
|
| 78 |
+
/// or if we have to ponder while is our opponent's side to move.
|
| 79 |
+
|
| 80 |
+
struct LimitsType {
|
| 81 |
+
|
| 82 |
+
LimitsType() { std::memset(this, 0, sizeof(LimitsType)); }
|
| 83 |
+
bool use_time_management() const { return !(mate | movetime | depth | nodes | infinite); }
|
| 84 |
+
|
| 85 |
+
int time[COLOR_NB], inc[COLOR_NB], movestogo, depth, nodes, movetime, mate, infinite, ponder;
|
| 86 |
+
};
|
| 87 |
+
|
| 88 |
+
|
| 89 |
+
/// The SignalsType struct stores volatile flags updated during the search
|
| 90 |
+
/// typically in an async fashion, for instance to stop the search by the GUI.
|
| 91 |
+
|
| 92 |
+
struct SignalsType {
|
| 93 |
+
bool stopOnPonderhit, firstRootMove, stop, failedLowAtRoot;
|
| 94 |
+
};
|
| 95 |
+
|
| 96 |
+
typedef std::auto_ptr<std::stack<StateInfo> > StateStackPtr;
|
| 97 |
+
|
| 98 |
+
extern volatile SignalsType Signals;
|
| 99 |
+
extern LimitsType Limits;
|
| 100 |
+
extern std::vector<RootMove> RootMoves;
|
| 101 |
+
extern Position RootPos;
|
| 102 |
+
extern Color RootColor;
|
| 103 |
+
extern Time::point SearchTime;
|
| 104 |
+
extern StateStackPtr SetupStates;
|
| 105 |
+
|
| 106 |
+
extern void init();
|
| 107 |
+
extern size_t perft(Position& pos, Depth depth);
|
| 108 |
+
extern void think();
|
| 109 |
+
|
| 110 |
+
} // namespace Search
|
| 111 |
+
|
| 112 |
+
#endif // #ifndef SEARCH_H_INCLUDED
|
stockfish-4-win/src/thread.cpp
ADDED
|
@@ -0,0 +1,394 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
+
Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
+
|
| 6 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 7 |
+
it under the terms of the GNU General Public License as published by
|
| 8 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 9 |
+
(at your option) any later version.
|
| 10 |
+
|
| 11 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 12 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 13 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 14 |
+
GNU General Public License for more details.
|
| 15 |
+
|
| 16 |
+
You should have received a copy of the GNU General Public License
|
| 17 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 18 |
+
*/
|
| 19 |
+
|
| 20 |
+
#include <algorithm> // For std::count
|
| 21 |
+
#include <cassert>
|
| 22 |
+
|
| 23 |
+
#include "movegen.h"
|
| 24 |
+
#include "search.h"
|
| 25 |
+
#include "thread.h"
|
| 26 |
+
#include "ucioption.h"
|
| 27 |
+
|
| 28 |
+
using namespace Search;
|
| 29 |
+
|
| 30 |
+
ThreadPool Threads; // Global object
|
| 31 |
+
|
| 32 |
+
namespace {
|
| 33 |
+
|
| 34 |
+
// start_routine() is the C function which is called when a new thread
|
| 35 |
+
// is launched. It is a wrapper to the virtual function idle_loop().
|
| 36 |
+
|
| 37 |
+
extern "C" { long start_routine(ThreadBase* th) { th->idle_loop(); return 0; } }
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
// Helpers to launch a thread after creation and joining before delete. Must be
|
| 41 |
+
// outside Thread c'tor and d'tor because object shall be fully initialized
|
| 42 |
+
// when start_routine (and hence virtual idle_loop) is called and when joining.
|
| 43 |
+
|
| 44 |
+
template<typename T> T* new_thread() {
|
| 45 |
+
T* th = new T();
|
| 46 |
+
thread_create(th->handle, start_routine, th); // Will go to sleep
|
| 47 |
+
return th;
|
| 48 |
+
}
|
| 49 |
+
|
| 50 |
+
void delete_thread(ThreadBase* th) {
|
| 51 |
+
th->exit = true; // Search must be already finished
|
| 52 |
+
th->notify_one();
|
| 53 |
+
thread_join(th->handle); // Wait for thread termination
|
| 54 |
+
delete th;
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
+
}
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
// ThreadBase::notify_one() wakes up the thread when there is some work to do
|
| 61 |
+
|
| 62 |
+
void ThreadBase::notify_one() {
|
| 63 |
+
|
| 64 |
+
mutex.lock();
|
| 65 |
+
sleepCondition.notify_one();
|
| 66 |
+
mutex.unlock();
|
| 67 |
+
}
|
| 68 |
+
|
| 69 |
+
|
| 70 |
+
// ThreadBase::wait_for() set the thread to sleep until condition 'b' turns true
|
| 71 |
+
|
| 72 |
+
void ThreadBase::wait_for(volatile const bool& b) {
|
| 73 |
+
|
| 74 |
+
mutex.lock();
|
| 75 |
+
while (!b) sleepCondition.wait(mutex);
|
| 76 |
+
mutex.unlock();
|
| 77 |
+
}
|
| 78 |
+
|
| 79 |
+
|
| 80 |
+
// Thread c'tor just inits data but does not launch any thread of execution that
|
| 81 |
+
// instead will be started only upon c'tor returns.
|
| 82 |
+
|
| 83 |
+
Thread::Thread() /* : splitPoints() */ { // Value-initialization bug in MSVC
|
| 84 |
+
|
| 85 |
+
searching = false;
|
| 86 |
+
maxPly = splitPointsSize = 0;
|
| 87 |
+
activeSplitPoint = NULL;
|
| 88 |
+
activePosition = NULL;
|
| 89 |
+
idx = Threads.size();
|
| 90 |
+
}
|
| 91 |
+
|
| 92 |
+
|
| 93 |
+
// TimerThread::idle_loop() is where the timer thread waits msec milliseconds
|
| 94 |
+
// and then calls check_time(). If msec is 0 thread sleeps until is woken up.
|
| 95 |
+
extern void check_time();
|
| 96 |
+
|
| 97 |
+
void TimerThread::idle_loop() {
|
| 98 |
+
|
| 99 |
+
while (!exit)
|
| 100 |
+
{
|
| 101 |
+
mutex.lock();
|
| 102 |
+
|
| 103 |
+
if (!exit)
|
| 104 |
+
sleepCondition.wait_for(mutex, msec ? msec : INT_MAX);
|
| 105 |
+
|
| 106 |
+
mutex.unlock();
|
| 107 |
+
|
| 108 |
+
if (msec)
|
| 109 |
+
check_time();
|
| 110 |
+
}
|
| 111 |
+
}
|
| 112 |
+
|
| 113 |
+
|
| 114 |
+
// MainThread::idle_loop() is where the main thread is parked waiting to be started
|
| 115 |
+
// when there is a new search. Main thread will launch all the slave threads.
|
| 116 |
+
|
| 117 |
+
void MainThread::idle_loop() {
|
| 118 |
+
|
| 119 |
+
while (true)
|
| 120 |
+
{
|
| 121 |
+
mutex.lock();
|
| 122 |
+
|
| 123 |
+
thinking = false;
|
| 124 |
+
|
| 125 |
+
while (!thinking && !exit)
|
| 126 |
+
{
|
| 127 |
+
Threads.sleepCondition.notify_one(); // Wake up UI thread if needed
|
| 128 |
+
sleepCondition.wait(mutex);
|
| 129 |
+
}
|
| 130 |
+
|
| 131 |
+
mutex.unlock();
|
| 132 |
+
|
| 133 |
+
if (exit)
|
| 134 |
+
return;
|
| 135 |
+
|
| 136 |
+
searching = true;
|
| 137 |
+
|
| 138 |
+
Search::think();
|
| 139 |
+
|
| 140 |
+
assert(searching);
|
| 141 |
+
|
| 142 |
+
searching = false;
|
| 143 |
+
}
|
| 144 |
+
}
|
| 145 |
+
|
| 146 |
+
|
| 147 |
+
// Thread::cutoff_occurred() checks whether a beta cutoff has occurred in the
|
| 148 |
+
// current active split point, or in some ancestor of the split point.
|
| 149 |
+
|
| 150 |
+
bool Thread::cutoff_occurred() const {
|
| 151 |
+
|
| 152 |
+
for (SplitPoint* sp = activeSplitPoint; sp; sp = sp->parentSplitPoint)
|
| 153 |
+
if (sp->cutoff)
|
| 154 |
+
return true;
|
| 155 |
+
|
| 156 |
+
return false;
|
| 157 |
+
}
|
| 158 |
+
|
| 159 |
+
|
| 160 |
+
// Thread::is_available_to() checks whether the thread is available to help the
|
| 161 |
+
// thread 'master' at a split point. An obvious requirement is that thread must
|
| 162 |
+
// be idle. With more than two threads, this is not sufficient: If the thread is
|
| 163 |
+
// the master of some split point, it is only available as a slave to the slaves
|
| 164 |
+
// which are busy searching the split point at the top of slaves split point
|
| 165 |
+
// stack (the "helpful master concept" in YBWC terminology).
|
| 166 |
+
|
| 167 |
+
bool Thread::is_available_to(const Thread* master) const {
|
| 168 |
+
|
| 169 |
+
if (searching)
|
| 170 |
+
return false;
|
| 171 |
+
|
| 172 |
+
// Make a local copy to be sure doesn't become zero under our feet while
|
| 173 |
+
// testing next condition and so leading to an out of bound access.
|
| 174 |
+
int size = splitPointsSize;
|
| 175 |
+
|
| 176 |
+
// No split points means that the thread is available as a slave for any
|
| 177 |
+
// other thread otherwise apply the "helpful master" concept if possible.
|
| 178 |
+
return !size || (splitPoints[size - 1].slavesMask & (1ULL << master->idx));
|
| 179 |
+
}
|
| 180 |
+
|
| 181 |
+
|
| 182 |
+
// init() is called at startup to create and launch requested threads, that will
|
| 183 |
+
// go immediately to sleep due to 'sleepWhileIdle' set to true. We cannot use
|
| 184 |
+
// a c'tor becuase Threads is a static object and we need a fully initialized
|
| 185 |
+
// engine at this point due to allocation of Endgames in Thread c'tor.
|
| 186 |
+
|
| 187 |
+
void ThreadPool::init() {
|
| 188 |
+
|
| 189 |
+
sleepWhileIdle = true;
|
| 190 |
+
timer = new_thread<TimerThread>();
|
| 191 |
+
push_back(new_thread<MainThread>());
|
| 192 |
+
read_uci_options();
|
| 193 |
+
}
|
| 194 |
+
|
| 195 |
+
|
| 196 |
+
// exit() cleanly terminates the threads before the program exits
|
| 197 |
+
|
| 198 |
+
void ThreadPool::exit() {
|
| 199 |
+
|
| 200 |
+
delete_thread(timer); // As first because check_time() accesses threads data
|
| 201 |
+
|
| 202 |
+
for (iterator it = begin(); it != end(); ++it)
|
| 203 |
+
delete_thread(*it);
|
| 204 |
+
}
|
| 205 |
+
|
| 206 |
+
|
| 207 |
+
// read_uci_options() updates internal threads parameters from the corresponding
|
| 208 |
+
// UCI options and creates/destroys threads to match the requested number. Thread
|
| 209 |
+
// objects are dynamically allocated to avoid creating in advance all possible
|
| 210 |
+
// threads, with included pawns and material tables, if only few are used.
|
| 211 |
+
|
| 212 |
+
void ThreadPool::read_uci_options() {
|
| 213 |
+
|
| 214 |
+
maxThreadsPerSplitPoint = Options["Max Threads per Split Point"];
|
| 215 |
+
minimumSplitDepth = Options["Min Split Depth"] * ONE_PLY;
|
| 216 |
+
size_t requested = Options["Threads"];
|
| 217 |
+
|
| 218 |
+
assert(requested > 0);
|
| 219 |
+
|
| 220 |
+
// Value 0 has a special meaning: We determine the optimal minimum split depth
|
| 221 |
+
// automatically. Anyhow the minimumSplitDepth should never be under 4 plies.
|
| 222 |
+
if (!minimumSplitDepth)
|
| 223 |
+
minimumSplitDepth = (requested < 8 ? 4 : 7) * ONE_PLY;
|
| 224 |
+
else
|
| 225 |
+
minimumSplitDepth = std::max(4 * ONE_PLY, minimumSplitDepth);
|
| 226 |
+
|
| 227 |
+
while (size() < requested)
|
| 228 |
+
push_back(new_thread<Thread>());
|
| 229 |
+
|
| 230 |
+
while (size() > requested)
|
| 231 |
+
{
|
| 232 |
+
delete_thread(back());
|
| 233 |
+
pop_back();
|
| 234 |
+
}
|
| 235 |
+
}
|
| 236 |
+
|
| 237 |
+
|
| 238 |
+
// slave_available() tries to find an idle thread which is available as a slave
|
| 239 |
+
// for the thread 'master'.
|
| 240 |
+
|
| 241 |
+
Thread* ThreadPool::available_slave(const Thread* master) const {
|
| 242 |
+
|
| 243 |
+
for (const_iterator it = begin(); it != end(); ++it)
|
| 244 |
+
if ((*it)->is_available_to(master))
|
| 245 |
+
return *it;
|
| 246 |
+
|
| 247 |
+
return NULL;
|
| 248 |
+
}
|
| 249 |
+
|
| 250 |
+
|
| 251 |
+
// split() does the actual work of distributing the work at a node between
|
| 252 |
+
// several available threads. If it does not succeed in splitting the node
|
| 253 |
+
// (because no idle threads are available), the function immediately returns.
|
| 254 |
+
// If splitting is possible, a SplitPoint object is initialized with all the
|
| 255 |
+
// data that must be copied to the helper threads and then helper threads are
|
| 256 |
+
// told that they have been assigned work. This will cause them to instantly
|
| 257 |
+
// leave their idle loops and call search(). When all threads have returned from
|
| 258 |
+
// search() then split() returns.
|
| 259 |
+
|
| 260 |
+
template <bool Fake>
|
| 261 |
+
void Thread::split(Position& pos, const Stack* ss, Value alpha, Value beta, Value* bestValue,
|
| 262 |
+
Move* bestMove, Depth depth, Move threatMove, int moveCount,
|
| 263 |
+
MovePicker* movePicker, int nodeType, bool cutNode) {
|
| 264 |
+
|
| 265 |
+
assert(pos.pos_is_ok());
|
| 266 |
+
assert(*bestValue <= alpha && alpha < beta && beta <= VALUE_INFINITE);
|
| 267 |
+
assert(*bestValue > -VALUE_INFINITE);
|
| 268 |
+
assert(depth >= Threads.minimumSplitDepth);
|
| 269 |
+
assert(searching);
|
| 270 |
+
assert(splitPointsSize < MAX_SPLITPOINTS_PER_THREAD);
|
| 271 |
+
|
| 272 |
+
// Pick the next available split point from the split point stack
|
| 273 |
+
SplitPoint& sp = splitPoints[splitPointsSize];
|
| 274 |
+
|
| 275 |
+
sp.masterThread = this;
|
| 276 |
+
sp.parentSplitPoint = activeSplitPoint;
|
| 277 |
+
sp.slavesMask = 1ULL << idx;
|
| 278 |
+
sp.depth = depth;
|
| 279 |
+
sp.bestValue = *bestValue;
|
| 280 |
+
sp.bestMove = *bestMove;
|
| 281 |
+
sp.threatMove = threatMove;
|
| 282 |
+
sp.alpha = alpha;
|
| 283 |
+
sp.beta = beta;
|
| 284 |
+
sp.nodeType = nodeType;
|
| 285 |
+
sp.cutNode = cutNode;
|
| 286 |
+
sp.movePicker = movePicker;
|
| 287 |
+
sp.moveCount = moveCount;
|
| 288 |
+
sp.pos = &pos;
|
| 289 |
+
sp.nodes = 0;
|
| 290 |
+
sp.cutoff = false;
|
| 291 |
+
sp.ss = ss;
|
| 292 |
+
|
| 293 |
+
// Try to allocate available threads and ask them to start searching setting
|
| 294 |
+
// 'searching' flag. This must be done under lock protection to avoid concurrent
|
| 295 |
+
// allocation of the same slave by another master.
|
| 296 |
+
Threads.mutex.lock();
|
| 297 |
+
sp.mutex.lock();
|
| 298 |
+
|
| 299 |
+
splitPointsSize++;
|
| 300 |
+
activeSplitPoint = &sp;
|
| 301 |
+
activePosition = NULL;
|
| 302 |
+
|
| 303 |
+
size_t slavesCnt = 1; // This thread is always included
|
| 304 |
+
Thread* slave;
|
| 305 |
+
|
| 306 |
+
while ( (slave = Threads.available_slave(this)) != NULL
|
| 307 |
+
&& ++slavesCnt <= Threads.maxThreadsPerSplitPoint && !Fake)
|
| 308 |
+
{
|
| 309 |
+
sp.slavesMask |= 1ULL << slave->idx;
|
| 310 |
+
slave->activeSplitPoint = &sp;
|
| 311 |
+
slave->searching = true; // Slave leaves idle_loop()
|
| 312 |
+
slave->notify_one(); // Could be sleeping
|
| 313 |
+
}
|
| 314 |
+
|
| 315 |
+
// Everything is set up. The master thread enters the idle loop, from which
|
| 316 |
+
// it will instantly launch a search, because its 'searching' flag is set.
|
| 317 |
+
// The thread will return from the idle loop when all slaves have finished
|
| 318 |
+
// their work at this split point.
|
| 319 |
+
if (slavesCnt > 1 || Fake)
|
| 320 |
+
{
|
| 321 |
+
sp.mutex.unlock();
|
| 322 |
+
Threads.mutex.unlock();
|
| 323 |
+
|
| 324 |
+
Thread::idle_loop(); // Force a call to base class idle_loop()
|
| 325 |
+
|
| 326 |
+
// In helpful master concept a master can help only a sub-tree of its split
|
| 327 |
+
// point, and because here is all finished is not possible master is booked.
|
| 328 |
+
assert(!searching);
|
| 329 |
+
assert(!activePosition);
|
| 330 |
+
|
| 331 |
+
// We have returned from the idle loop, which means that all threads are
|
| 332 |
+
// finished. Note that setting 'searching' and decreasing splitPointsSize is
|
| 333 |
+
// done under lock protection to avoid a race with Thread::is_available_to().
|
| 334 |
+
Threads.mutex.lock();
|
| 335 |
+
sp.mutex.lock();
|
| 336 |
+
}
|
| 337 |
+
|
| 338 |
+
searching = true;
|
| 339 |
+
splitPointsSize--;
|
| 340 |
+
activeSplitPoint = sp.parentSplitPoint;
|
| 341 |
+
activePosition = &pos;
|
| 342 |
+
pos.set_nodes_searched(pos.nodes_searched() + sp.nodes);
|
| 343 |
+
*bestMove = sp.bestMove;
|
| 344 |
+
*bestValue = sp.bestValue;
|
| 345 |
+
|
| 346 |
+
sp.mutex.unlock();
|
| 347 |
+
Threads.mutex.unlock();
|
| 348 |
+
}
|
| 349 |
+
|
| 350 |
+
// Explicit template instantiations
|
| 351 |
+
template void Thread::split<false>(Position&, const Stack*, Value, Value, Value*, Move*, Depth, Move, int, MovePicker*, int, bool);
|
| 352 |
+
template void Thread::split< true>(Position&, const Stack*, Value, Value, Value*, Move*, Depth, Move, int, MovePicker*, int, bool);
|
| 353 |
+
|
| 354 |
+
|
| 355 |
+
// wait_for_think_finished() waits for main thread to go to sleep then returns
|
| 356 |
+
|
| 357 |
+
void ThreadPool::wait_for_think_finished() {
|
| 358 |
+
|
| 359 |
+
MainThread* t = main();
|
| 360 |
+
t->mutex.lock();
|
| 361 |
+
while (t->thinking) sleepCondition.wait(t->mutex);
|
| 362 |
+
t->mutex.unlock();
|
| 363 |
+
}
|
| 364 |
+
|
| 365 |
+
|
| 366 |
+
// start_thinking() wakes up the main thread sleeping in MainThread::idle_loop()
|
| 367 |
+
// so to start a new search, then returns immediately.
|
| 368 |
+
|
| 369 |
+
void ThreadPool::start_thinking(const Position& pos, const LimitsType& limits,
|
| 370 |
+
const std::vector<Move>& searchMoves, StateStackPtr& states) {
|
| 371 |
+
wait_for_think_finished();
|
| 372 |
+
|
| 373 |
+
SearchTime = Time::now(); // As early as possible
|
| 374 |
+
|
| 375 |
+
Signals.stopOnPonderhit = Signals.firstRootMove = false;
|
| 376 |
+
Signals.stop = Signals.failedLowAtRoot = false;
|
| 377 |
+
|
| 378 |
+
RootMoves.clear();
|
| 379 |
+
RootPos = pos;
|
| 380 |
+
Limits = limits;
|
| 381 |
+
if (states.get()) // If we don't set a new position, preserve current state
|
| 382 |
+
{
|
| 383 |
+
SetupStates = states; // Ownership transfer here
|
| 384 |
+
assert(!states.get());
|
| 385 |
+
}
|
| 386 |
+
|
| 387 |
+
for (MoveList<LEGAL> it(pos); *it; ++it)
|
| 388 |
+
if ( searchMoves.empty()
|
| 389 |
+
|| std::count(searchMoves.begin(), searchMoves.end(), *it))
|
| 390 |
+
RootMoves.push_back(RootMove(*it));
|
| 391 |
+
|
| 392 |
+
main()->thinking = true;
|
| 393 |
+
main()->notify_one(); // Starts main thread
|
| 394 |
+
}
|
stockfish-4-win/src/thread.h
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
+
Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
+
|
| 6 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 7 |
+
it under the terms of the GNU General Public License as published by
|
| 8 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 9 |
+
(at your option) any later version.
|
| 10 |
+
|
| 11 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 12 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 13 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 14 |
+
GNU General Public License for more details.
|
| 15 |
+
|
| 16 |
+
You should have received a copy of the GNU General Public License
|
| 17 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 18 |
+
*/
|
| 19 |
+
|
| 20 |
+
#ifndef THREAD_H_INCLUDED
|
| 21 |
+
#define THREAD_H_INCLUDED
|
| 22 |
+
|
| 23 |
+
#include <vector>
|
| 24 |
+
|
| 25 |
+
#include "material.h"
|
| 26 |
+
#include "movepick.h"
|
| 27 |
+
#include "pawns.h"
|
| 28 |
+
#include "position.h"
|
| 29 |
+
#include "search.h"
|
| 30 |
+
|
| 31 |
+
const int MAX_THREADS = 64; // Because SplitPoint::slavesMask is a uint64_t
|
| 32 |
+
const int MAX_SPLITPOINTS_PER_THREAD = 8;
|
| 33 |
+
|
| 34 |
+
struct Mutex {
|
| 35 |
+
Mutex() { lock_init(l); }
|
| 36 |
+
~Mutex() { lock_destroy(l); }
|
| 37 |
+
|
| 38 |
+
void lock() { lock_grab(l); }
|
| 39 |
+
void unlock() { lock_release(l); }
|
| 40 |
+
|
| 41 |
+
private:
|
| 42 |
+
friend struct ConditionVariable;
|
| 43 |
+
|
| 44 |
+
Lock l;
|
| 45 |
+
};
|
| 46 |
+
|
| 47 |
+
struct ConditionVariable {
|
| 48 |
+
ConditionVariable() { cond_init(c); }
|
| 49 |
+
~ConditionVariable() { cond_destroy(c); }
|
| 50 |
+
|
| 51 |
+
void wait(Mutex& m) { cond_wait(c, m.l); }
|
| 52 |
+
void wait_for(Mutex& m, int ms) { timed_wait(c, m.l, ms); }
|
| 53 |
+
void notify_one() { cond_signal(c); }
|
| 54 |
+
|
| 55 |
+
private:
|
| 56 |
+
WaitCondition c;
|
| 57 |
+
};
|
| 58 |
+
|
| 59 |
+
struct Thread;
|
| 60 |
+
|
| 61 |
+
struct SplitPoint {
|
| 62 |
+
|
| 63 |
+
// Const data after split point has been setup
|
| 64 |
+
const Position* pos;
|
| 65 |
+
const Search::Stack* ss;
|
| 66 |
+
Thread* masterThread;
|
| 67 |
+
Depth depth;
|
| 68 |
+
Value beta;
|
| 69 |
+
int nodeType;
|
| 70 |
+
Move threatMove;
|
| 71 |
+
bool cutNode;
|
| 72 |
+
|
| 73 |
+
// Const pointers to shared data
|
| 74 |
+
MovePicker* movePicker;
|
| 75 |
+
SplitPoint* parentSplitPoint;
|
| 76 |
+
|
| 77 |
+
// Shared data
|
| 78 |
+
Mutex mutex;
|
| 79 |
+
volatile uint64_t slavesMask;
|
| 80 |
+
volatile int64_t nodes;
|
| 81 |
+
volatile Value alpha;
|
| 82 |
+
volatile Value bestValue;
|
| 83 |
+
volatile Move bestMove;
|
| 84 |
+
volatile int moveCount;
|
| 85 |
+
volatile bool cutoff;
|
| 86 |
+
};
|
| 87 |
+
|
| 88 |
+
|
| 89 |
+
/// ThreadBase struct is the base of the hierarchy from where we derive all the
|
| 90 |
+
/// specialized thread classes.
|
| 91 |
+
|
| 92 |
+
struct ThreadBase {
|
| 93 |
+
|
| 94 |
+
ThreadBase() : exit(false) {}
|
| 95 |
+
virtual ~ThreadBase() {}
|
| 96 |
+
virtual void idle_loop() = 0;
|
| 97 |
+
void notify_one();
|
| 98 |
+
void wait_for(volatile const bool& b);
|
| 99 |
+
|
| 100 |
+
Mutex mutex;
|
| 101 |
+
ConditionVariable sleepCondition;
|
| 102 |
+
NativeHandle handle;
|
| 103 |
+
volatile bool exit;
|
| 104 |
+
};
|
| 105 |
+
|
| 106 |
+
|
| 107 |
+
/// Thread struct keeps together all the thread related stuff like locks, state
|
| 108 |
+
/// and especially split points. We also use per-thread pawn and material hash
|
| 109 |
+
/// tables so that once we get a pointer to an entry its life time is unlimited
|
| 110 |
+
/// and we don't have to care about someone changing the entry under our feet.
|
| 111 |
+
|
| 112 |
+
struct Thread : public ThreadBase {
|
| 113 |
+
|
| 114 |
+
Thread();
|
| 115 |
+
virtual void idle_loop();
|
| 116 |
+
bool cutoff_occurred() const;
|
| 117 |
+
bool is_available_to(const Thread* master) const;
|
| 118 |
+
|
| 119 |
+
template <bool Fake>
|
| 120 |
+
void split(Position& pos, const Search::Stack* ss, Value alpha, Value beta, Value* bestValue, Move* bestMove,
|
| 121 |
+
Depth depth, Move threatMove, int moveCount, MovePicker* movePicker, int nodeType, bool cutNode);
|
| 122 |
+
|
| 123 |
+
SplitPoint splitPoints[MAX_SPLITPOINTS_PER_THREAD];
|
| 124 |
+
Material::Table materialTable;
|
| 125 |
+
Endgames endgames;
|
| 126 |
+
Pawns::Table pawnsTable;
|
| 127 |
+
Position* activePosition;
|
| 128 |
+
size_t idx;
|
| 129 |
+
int maxPly;
|
| 130 |
+
SplitPoint* volatile activeSplitPoint;
|
| 131 |
+
volatile int splitPointsSize;
|
| 132 |
+
volatile bool searching;
|
| 133 |
+
};
|
| 134 |
+
|
| 135 |
+
|
| 136 |
+
/// MainThread and TimerThread are derived classes used to characterize the two
|
| 137 |
+
/// special threads: the main one and the recurring timer.
|
| 138 |
+
|
| 139 |
+
struct MainThread : public Thread {
|
| 140 |
+
MainThread() : thinking(true) {} // Avoid a race with start_thinking()
|
| 141 |
+
virtual void idle_loop();
|
| 142 |
+
volatile bool thinking;
|
| 143 |
+
};
|
| 144 |
+
|
| 145 |
+
struct TimerThread : public ThreadBase {
|
| 146 |
+
TimerThread() : msec(0) {}
|
| 147 |
+
virtual void idle_loop();
|
| 148 |
+
int msec;
|
| 149 |
+
};
|
| 150 |
+
|
| 151 |
+
|
| 152 |
+
/// ThreadPool struct handles all the threads related stuff like init, starting,
|
| 153 |
+
/// parking and, the most important, launching a slave thread at a split point.
|
| 154 |
+
/// All the access to shared thread data is done through this class.
|
| 155 |
+
|
| 156 |
+
struct ThreadPool : public std::vector<Thread*> {
|
| 157 |
+
|
| 158 |
+
void init(); // No c'tor and d'tor, threads rely on globals that should
|
| 159 |
+
void exit(); // be initialized and valid during the whole thread lifetime.
|
| 160 |
+
|
| 161 |
+
MainThread* main() { return static_cast<MainThread*>((*this)[0]); }
|
| 162 |
+
void read_uci_options();
|
| 163 |
+
Thread* available_slave(const Thread* master) const;
|
| 164 |
+
void wait_for_think_finished();
|
| 165 |
+
void start_thinking(const Position&, const Search::LimitsType&,
|
| 166 |
+
const std::vector<Move>&, Search::StateStackPtr&);
|
| 167 |
+
|
| 168 |
+
bool sleepWhileIdle;
|
| 169 |
+
Depth minimumSplitDepth;
|
| 170 |
+
size_t maxThreadsPerSplitPoint;
|
| 171 |
+
Mutex mutex;
|
| 172 |
+
ConditionVariable sleepCondition;
|
| 173 |
+
TimerThread* timer;
|
| 174 |
+
};
|
| 175 |
+
|
| 176 |
+
extern ThreadPool Threads;
|
| 177 |
+
|
| 178 |
+
#endif // #ifndef THREAD_H_INCLUDED
|
stockfish-4-win/src/timeman.cpp
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
+
Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
+
|
| 6 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 7 |
+
it under the terms of the GNU General Public License as published by
|
| 8 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 9 |
+
(at your option) any later version.
|
| 10 |
+
|
| 11 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 12 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 13 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 14 |
+
GNU General Public License for more details.
|
| 15 |
+
|
| 16 |
+
You should have received a copy of the GNU General Public License
|
| 17 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 18 |
+
*/
|
| 19 |
+
|
| 20 |
+
#include <cmath>
|
| 21 |
+
#include <algorithm>
|
| 22 |
+
|
| 23 |
+
#include "search.h"
|
| 24 |
+
#include "timeman.h"
|
| 25 |
+
#include "ucioption.h"
|
| 26 |
+
|
| 27 |
+
namespace {
|
| 28 |
+
|
| 29 |
+
/// Constants
|
| 30 |
+
|
| 31 |
+
const int MoveHorizon = 50; // Plan time management at most this many moves ahead
|
| 32 |
+
const float MaxRatio = 7.0f; // When in trouble, we can step over reserved time with this ratio
|
| 33 |
+
const float StealRatio = 0.33f; // However we must not steal time from remaining moves over this ratio
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
// MoveImportance[] is based on naive statistical analysis of "how many games are still undecided
|
| 37 |
+
// after n half-moves". Game is considered "undecided" as long as neither side has >275cp advantage.
|
| 38 |
+
// Data was extracted from CCRL game database with some simple filtering criteria.
|
| 39 |
+
const int MoveImportance[512] = {
|
| 40 |
+
7780, 7780, 7780, 7780, 7780, 7780, 7780, 7780, 7780, 7780, 7780, 7780, 7780, 7780, 7780, 7780,
|
| 41 |
+
7780, 7780, 7780, 7780, 7778, 7778, 7776, 7776, 7776, 7773, 7770, 7768, 7766, 7763, 7757, 7751,
|
| 42 |
+
7743, 7735, 7724, 7713, 7696, 7689, 7670, 7656, 7627, 7605, 7571, 7549, 7522, 7493, 7462, 7425,
|
| 43 |
+
7385, 7350, 7308, 7272, 7230, 7180, 7139, 7094, 7055, 7010, 6959, 6902, 6841, 6778, 6705, 6651,
|
| 44 |
+
6569, 6508, 6435, 6378, 6323, 6253, 6152, 6085, 5995, 5931, 5859, 5794, 5717, 5646, 5544, 5462,
|
| 45 |
+
5364, 5282, 5172, 5078, 4988, 4901, 4831, 4764, 4688, 4609, 4536, 4443, 4365, 4293, 4225, 4155,
|
| 46 |
+
4085, 4005, 3927, 3844, 3765, 3693, 3634, 3560, 3479, 3404, 3331, 3268, 3207, 3146, 3077, 3011,
|
| 47 |
+
2947, 2894, 2828, 2776, 2727, 2676, 2626, 2589, 2538, 2490, 2442, 2394, 2345, 2302, 2243, 2192,
|
| 48 |
+
2156, 2115, 2078, 2043, 2004, 1967, 1922, 1893, 1845, 1809, 1772, 1736, 1702, 1674, 1640, 1605,
|
| 49 |
+
1566, 1536, 1509, 1479, 1452, 1423, 1388, 1362, 1332, 1304, 1289, 1266, 1250, 1228, 1206, 1180,
|
| 50 |
+
1160, 1134, 1118, 1100, 1080, 1068, 1051, 1034, 1012, 1001, 980, 960, 945, 934, 916, 900, 888,
|
| 51 |
+
878, 865, 852, 828, 807, 787, 770, 753, 744, 731, 722, 706, 700, 683, 676, 671, 664, 652, 641,
|
| 52 |
+
634, 627, 613, 604, 591, 582, 568, 560, 552, 540, 534, 529, 519, 509, 495, 484, 474, 467, 460,
|
| 53 |
+
450, 438, 427, 419, 410, 406, 399, 394, 387, 382, 377, 372, 366, 359, 353, 348, 343, 337, 333,
|
| 54 |
+
328, 321, 315, 309, 303, 298, 293, 287, 284, 281, 277, 273, 265, 261, 255, 251, 247, 241, 240,
|
| 55 |
+
235, 229, 218, 217, 213, 212, 208, 206, 197, 193, 191, 189, 185, 184, 180, 177, 172, 170, 170,
|
| 56 |
+
170, 166, 163, 159, 158, 156, 155, 151, 146, 141, 138, 136, 132, 130, 128, 125, 123, 122, 118,
|
| 57 |
+
118, 118, 117, 115, 114, 108, 107, 105, 105, 105, 102, 97, 97, 95, 94, 93, 91, 88, 86, 83, 80,
|
| 58 |
+
80, 79, 79, 79, 78, 76, 75, 72, 72, 71, 70, 68, 65, 63, 61, 61, 59, 59, 59, 58, 56, 55, 54, 54,
|
| 59 |
+
52, 49, 48, 48, 48, 48, 45, 45, 45, 44, 43, 41, 41, 41, 41, 40, 40, 38, 37, 36, 34, 34, 34, 33,
|
| 60 |
+
31, 29, 29, 29, 28, 28, 28, 28, 28, 28, 28, 27, 27, 27, 27, 27, 24, 24, 23, 23, 22, 21, 20, 20,
|
| 61 |
+
19, 19, 19, 19, 19, 18, 18, 18, 18, 17, 17, 17, 17, 17, 16, 16, 15, 15, 14, 14, 14, 12, 12, 11,
|
| 62 |
+
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,
|
| 63 |
+
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,
|
| 64 |
+
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,
|
| 65 |
+
2, 1, 1, 1, 1, 1, 1, 1 };
|
| 66 |
+
|
| 67 |
+
int move_importance(int ply) { return MoveImportance[std::min(ply, 511)]; }
|
| 68 |
+
|
| 69 |
+
|
| 70 |
+
/// Function Prototypes
|
| 71 |
+
|
| 72 |
+
enum TimeType { OptimumTime, MaxTime };
|
| 73 |
+
|
| 74 |
+
template<TimeType>
|
| 75 |
+
int remaining(int myTime, int movesToGo, int fullMoveNumber, int slowMover);
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
+
|
| 79 |
+
void TimeManager::pv_instability(int curChanges, int prevChanges) {
|
| 80 |
+
|
| 81 |
+
unstablePVExtraTime = curChanges * (optimumSearchTime / 2)
|
| 82 |
+
+ prevChanges * (optimumSearchTime / 3);
|
| 83 |
+
}
|
| 84 |
+
|
| 85 |
+
|
| 86 |
+
void TimeManager::init(const Search::LimitsType& limits, int currentPly, Color us)
|
| 87 |
+
{
|
| 88 |
+
/* We support four different kind of time controls:
|
| 89 |
+
|
| 90 |
+
increment == 0 && movesToGo == 0 means: x basetime [sudden death!]
|
| 91 |
+
increment == 0 && movesToGo != 0 means: x moves in y minutes
|
| 92 |
+
increment > 0 && movesToGo == 0 means: x basetime + z increment
|
| 93 |
+
increment > 0 && movesToGo != 0 means: x moves in y minutes + z increment
|
| 94 |
+
|
| 95 |
+
Time management is adjusted by following UCI parameters:
|
| 96 |
+
|
| 97 |
+
emergencyMoveHorizon: Be prepared to always play at least this many moves
|
| 98 |
+
emergencyBaseTime : Always attempt to keep at least this much time (in ms) at clock
|
| 99 |
+
emergencyMoveTime : Plus attempt to keep at least this much time for each remaining emergency move
|
| 100 |
+
minThinkingTime : No matter what, use at least this much thinking before doing the move
|
| 101 |
+
*/
|
| 102 |
+
|
| 103 |
+
int hypMTG, hypMyTime, t1, t2;
|
| 104 |
+
|
| 105 |
+
// Read uci parameters
|
| 106 |
+
int emergencyMoveHorizon = Options["Emergency Move Horizon"];
|
| 107 |
+
int emergencyBaseTime = Options["Emergency Base Time"];
|
| 108 |
+
int emergencyMoveTime = Options["Emergency Move Time"];
|
| 109 |
+
int minThinkingTime = Options["Minimum Thinking Time"];
|
| 110 |
+
int slowMover = Options["Slow Mover"];
|
| 111 |
+
|
| 112 |
+
// Initialize to maximum values but unstablePVExtraTime that is reset
|
| 113 |
+
unstablePVExtraTime = 0;
|
| 114 |
+
optimumSearchTime = maximumSearchTime = limits.time[us];
|
| 115 |
+
|
| 116 |
+
// We calculate optimum time usage for different hypothetic "moves to go"-values and choose the
|
| 117 |
+
// minimum of calculated search time values. Usually the greatest hypMTG gives the minimum values.
|
| 118 |
+
for (hypMTG = 1; hypMTG <= (limits.movestogo ? std::min(limits.movestogo, MoveHorizon) : MoveHorizon); hypMTG++)
|
| 119 |
+
{
|
| 120 |
+
// Calculate thinking time for hypothetic "moves to go"-value
|
| 121 |
+
hypMyTime = limits.time[us]
|
| 122 |
+
+ limits.inc[us] * (hypMTG - 1)
|
| 123 |
+
- emergencyBaseTime
|
| 124 |
+
- emergencyMoveTime * std::min(hypMTG, emergencyMoveHorizon);
|
| 125 |
+
|
| 126 |
+
hypMyTime = std::max(hypMyTime, 0);
|
| 127 |
+
|
| 128 |
+
t1 = minThinkingTime + remaining<OptimumTime>(hypMyTime, hypMTG, currentPly, slowMover);
|
| 129 |
+
t2 = minThinkingTime + remaining<MaxTime>(hypMyTime, hypMTG, currentPly, slowMover);
|
| 130 |
+
|
| 131 |
+
optimumSearchTime = std::min(optimumSearchTime, t1);
|
| 132 |
+
maximumSearchTime = std::min(maximumSearchTime, t2);
|
| 133 |
+
}
|
| 134 |
+
|
| 135 |
+
if (Options["Ponder"])
|
| 136 |
+
optimumSearchTime += optimumSearchTime / 4;
|
| 137 |
+
|
| 138 |
+
// Make sure that maxSearchTime is not over absoluteMaxSearchTime
|
| 139 |
+
optimumSearchTime = std::min(optimumSearchTime, maximumSearchTime);
|
| 140 |
+
}
|
| 141 |
+
|
| 142 |
+
|
| 143 |
+
namespace {
|
| 144 |
+
|
| 145 |
+
template<TimeType T>
|
| 146 |
+
int remaining(int myTime, int movesToGo, int currentPly, int slowMover)
|
| 147 |
+
{
|
| 148 |
+
const float TMaxRatio = (T == OptimumTime ? 1 : MaxRatio);
|
| 149 |
+
const float TStealRatio = (T == OptimumTime ? 0 : StealRatio);
|
| 150 |
+
|
| 151 |
+
int thisMoveImportance = move_importance(currentPly) * slowMover / 100;
|
| 152 |
+
int otherMovesImportance = 0;
|
| 153 |
+
|
| 154 |
+
for (int i = 1; i < movesToGo; i++)
|
| 155 |
+
otherMovesImportance += move_importance(currentPly + 2 * i);
|
| 156 |
+
|
| 157 |
+
float ratio1 = (TMaxRatio * thisMoveImportance) / float(TMaxRatio * thisMoveImportance + otherMovesImportance);
|
| 158 |
+
float ratio2 = (thisMoveImportance + TStealRatio * otherMovesImportance) / float(thisMoveImportance + otherMovesImportance);
|
| 159 |
+
|
| 160 |
+
return int(floor(myTime * std::min(ratio1, ratio2)));
|
| 161 |
+
}
|
| 162 |
+
}
|
stockfish-4-win/src/timeman.h
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
+
Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
+
|
| 6 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 7 |
+
it under the terms of the GNU General Public License as published by
|
| 8 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 9 |
+
(at your option) any later version.
|
| 10 |
+
|
| 11 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 12 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 13 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 14 |
+
GNU General Public License for more details.
|
| 15 |
+
|
| 16 |
+
You should have received a copy of the GNU General Public License
|
| 17 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 18 |
+
*/
|
| 19 |
+
|
| 20 |
+
#ifndef TIMEMAN_H_INCLUDED
|
| 21 |
+
#define TIMEMAN_H_INCLUDED
|
| 22 |
+
|
| 23 |
+
/// The TimeManager class computes the optimal time to think depending on the
|
| 24 |
+
/// maximum available time, the move game number and other parameters.
|
| 25 |
+
|
| 26 |
+
class TimeManager {
|
| 27 |
+
public:
|
| 28 |
+
void init(const Search::LimitsType& limits, int currentPly, Color us);
|
| 29 |
+
void pv_instability(int curChanges, int prevChanges);
|
| 30 |
+
int available_time() const { return optimumSearchTime + unstablePVExtraTime; }
|
| 31 |
+
int maximum_time() const { return maximumSearchTime; }
|
| 32 |
+
|
| 33 |
+
private:
|
| 34 |
+
int optimumSearchTime;
|
| 35 |
+
int maximumSearchTime;
|
| 36 |
+
int unstablePVExtraTime;
|
| 37 |
+
};
|
| 38 |
+
|
| 39 |
+
#endif // #ifndef TIMEMAN_H_INCLUDED
|
stockfish-4-win/src/tt.cpp
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
+
Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
+
|
| 6 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 7 |
+
it under the terms of the GNU General Public License as published by
|
| 8 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 9 |
+
(at your option) any later version.
|
| 10 |
+
|
| 11 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 12 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 13 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 14 |
+
GNU General Public License for more details.
|
| 15 |
+
|
| 16 |
+
You should have received a copy of the GNU General Public License
|
| 17 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 18 |
+
*/
|
| 19 |
+
|
| 20 |
+
#include <cstring>
|
| 21 |
+
#include <iostream>
|
| 22 |
+
|
| 23 |
+
#include "bitboard.h"
|
| 24 |
+
#include "tt.h"
|
| 25 |
+
|
| 26 |
+
TranspositionTable TT; // Our global transposition table
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
/// TranspositionTable::set_size() sets the size of the transposition table,
|
| 30 |
+
/// measured in megabytes. Transposition table consists of a power of 2 number
|
| 31 |
+
/// of clusters and each cluster consists of ClusterSize number of TTEntry.
|
| 32 |
+
|
| 33 |
+
void TranspositionTable::set_size(size_t mbSize) {
|
| 34 |
+
|
| 35 |
+
assert(msb((mbSize << 20) / sizeof(TTEntry)) < 32);
|
| 36 |
+
|
| 37 |
+
uint32_t size = ClusterSize << msb((mbSize << 20) / sizeof(TTEntry[ClusterSize]));
|
| 38 |
+
|
| 39 |
+
if (hashMask == size - ClusterSize)
|
| 40 |
+
return;
|
| 41 |
+
|
| 42 |
+
hashMask = size - ClusterSize;
|
| 43 |
+
free(mem);
|
| 44 |
+
mem = calloc(size * sizeof(TTEntry) + CACHE_LINE_SIZE - 1, 1);
|
| 45 |
+
|
| 46 |
+
if (!mem)
|
| 47 |
+
{
|
| 48 |
+
std::cerr << "Failed to allocate " << mbSize
|
| 49 |
+
<< "MB for transposition table." << std::endl;
|
| 50 |
+
exit(EXIT_FAILURE);
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
table = (TTEntry*)((uintptr_t(mem) + CACHE_LINE_SIZE - 1) & ~(CACHE_LINE_SIZE - 1));
|
| 54 |
+
}
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
/// TranspositionTable::clear() overwrites the entire transposition table
|
| 58 |
+
/// with zeroes. It is called whenever the table is resized, or when the
|
| 59 |
+
/// user asks the program to clear the table (from the UCI interface).
|
| 60 |
+
|
| 61 |
+
void TranspositionTable::clear() {
|
| 62 |
+
|
| 63 |
+
std::memset(table, 0, (hashMask + ClusterSize) * sizeof(TTEntry));
|
| 64 |
+
}
|
| 65 |
+
|
| 66 |
+
|
| 67 |
+
/// TranspositionTable::probe() looks up the current position in the
|
| 68 |
+
/// transposition table. Returns a pointer to the TTEntry or NULL if
|
| 69 |
+
/// position is not found.
|
| 70 |
+
|
| 71 |
+
const TTEntry* TranspositionTable::probe(const Key key) const {
|
| 72 |
+
|
| 73 |
+
const TTEntry* tte = first_entry(key);
|
| 74 |
+
uint32_t key32 = key >> 32;
|
| 75 |
+
|
| 76 |
+
for (unsigned i = 0; i < ClusterSize; i++, tte++)
|
| 77 |
+
if (tte->key() == key32)
|
| 78 |
+
return tte;
|
| 79 |
+
|
| 80 |
+
return NULL;
|
| 81 |
+
}
|
| 82 |
+
|
| 83 |
+
|
| 84 |
+
/// TranspositionTable::store() writes a new entry containing position key and
|
| 85 |
+
/// valuable information of current position. The lowest order bits of position
|
| 86 |
+
/// key are used to decide on which cluster the position will be placed.
|
| 87 |
+
/// When a new entry is written and there are no empty entries available in cluster,
|
| 88 |
+
/// it replaces the least valuable of entries. A TTEntry t1 is considered to be
|
| 89 |
+
/// more valuable than a TTEntry t2 if t1 is from the current search and t2 is from
|
| 90 |
+
/// a previous search, or if the depth of t1 is bigger than the depth of t2.
|
| 91 |
+
|
| 92 |
+
void TranspositionTable::store(const Key key, Value v, Bound b, Depth d, Move m, Value statV, Value evalM) {
|
| 93 |
+
|
| 94 |
+
int c1, c2, c3;
|
| 95 |
+
TTEntry *tte, *replace;
|
| 96 |
+
uint32_t key32 = key >> 32; // Use the high 32 bits as key inside the cluster
|
| 97 |
+
|
| 98 |
+
tte = replace = first_entry(key);
|
| 99 |
+
|
| 100 |
+
for (unsigned i = 0; i < ClusterSize; i++, tte++)
|
| 101 |
+
{
|
| 102 |
+
if (!tte->key() || tte->key() == key32) // Empty or overwrite old
|
| 103 |
+
{
|
| 104 |
+
if (!m)
|
| 105 |
+
m = tte->move(); // Preserve any existing ttMove
|
| 106 |
+
|
| 107 |
+
replace = tte;
|
| 108 |
+
break;
|
| 109 |
+
}
|
| 110 |
+
|
| 111 |
+
// Implement replace strategy
|
| 112 |
+
c1 = (replace->generation() == generation ? 2 : 0);
|
| 113 |
+
c2 = (tte->generation() == generation || tte->bound() == BOUND_EXACT ? -2 : 0);
|
| 114 |
+
c3 = (tte->depth() < replace->depth() ? 1 : 0);
|
| 115 |
+
|
| 116 |
+
if (c1 + c2 + c3 > 0)
|
| 117 |
+
replace = tte;
|
| 118 |
+
}
|
| 119 |
+
|
| 120 |
+
replace->save(key32, v, b, d, m, generation, statV, evalM);
|
| 121 |
+
}
|
stockfish-4-win/src/tt.h
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
+
Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
+
|
| 6 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 7 |
+
it under the terms of the GNU General Public License as published by
|
| 8 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 9 |
+
(at your option) any later version.
|
| 10 |
+
|
| 11 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 12 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 13 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 14 |
+
GNU General Public License for more details.
|
| 15 |
+
|
| 16 |
+
You should have received a copy of the GNU General Public License
|
| 17 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 18 |
+
*/
|
| 19 |
+
|
| 20 |
+
#ifndef TT_H_INCLUDED
|
| 21 |
+
#define TT_H_INCLUDED
|
| 22 |
+
|
| 23 |
+
#include "misc.h"
|
| 24 |
+
#include "types.h"
|
| 25 |
+
|
| 26 |
+
/// The TTEntry is the 128 bit transposition table entry, defined as below:
|
| 27 |
+
///
|
| 28 |
+
/// key: 32 bit
|
| 29 |
+
/// move: 16 bit
|
| 30 |
+
/// bound type: 8 bit
|
| 31 |
+
/// generation: 8 bit
|
| 32 |
+
/// value: 16 bit
|
| 33 |
+
/// depth: 16 bit
|
| 34 |
+
/// static value: 16 bit
|
| 35 |
+
/// static margin: 16 bit
|
| 36 |
+
|
| 37 |
+
struct TTEntry {
|
| 38 |
+
|
| 39 |
+
void save(uint32_t k, Value v, Bound b, Depth d, Move m, int g, Value ev, Value em) {
|
| 40 |
+
|
| 41 |
+
key32 = (uint32_t)k;
|
| 42 |
+
move16 = (uint16_t)m;
|
| 43 |
+
bound8 = (uint8_t)b;
|
| 44 |
+
generation8 = (uint8_t)g;
|
| 45 |
+
value16 = (int16_t)v;
|
| 46 |
+
depth16 = (int16_t)d;
|
| 47 |
+
evalValue = (int16_t)ev;
|
| 48 |
+
evalMargin = (int16_t)em;
|
| 49 |
+
}
|
| 50 |
+
void set_generation(uint8_t g) { generation8 = g; }
|
| 51 |
+
|
| 52 |
+
uint32_t key() const { return key32; }
|
| 53 |
+
Depth depth() const { return (Depth)depth16; }
|
| 54 |
+
Move move() const { return (Move)move16; }
|
| 55 |
+
Value value() const { return (Value)value16; }
|
| 56 |
+
Bound bound() const { return (Bound)bound8; }
|
| 57 |
+
int generation() const { return (int)generation8; }
|
| 58 |
+
Value eval_value() const { return (Value)evalValue; }
|
| 59 |
+
Value eval_margin() const { return (Value)evalMargin; }
|
| 60 |
+
|
| 61 |
+
private:
|
| 62 |
+
uint32_t key32;
|
| 63 |
+
uint16_t move16;
|
| 64 |
+
uint8_t bound8, generation8;
|
| 65 |
+
int16_t value16, depth16, evalValue, evalMargin;
|
| 66 |
+
};
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
/// A TranspositionTable consists of a power of 2 number of clusters and each
|
| 70 |
+
/// cluster consists of ClusterSize number of TTEntry. Each non-empty entry
|
| 71 |
+
/// contains information of exactly one position. Size of a cluster shall not be
|
| 72 |
+
/// bigger than a cache line size. In case it is less, it should be padded to
|
| 73 |
+
/// guarantee always aligned accesses.
|
| 74 |
+
|
| 75 |
+
class TranspositionTable {
|
| 76 |
+
|
| 77 |
+
static const unsigned ClusterSize = 4; // A cluster is 64 Bytes
|
| 78 |
+
|
| 79 |
+
public:
|
| 80 |
+
~TranspositionTable() { free(mem); }
|
| 81 |
+
void new_search() { generation++; }
|
| 82 |
+
|
| 83 |
+
const TTEntry* probe(const Key key) const;
|
| 84 |
+
TTEntry* first_entry(const Key key) const;
|
| 85 |
+
void refresh(const TTEntry* tte) const;
|
| 86 |
+
void set_size(size_t mbSize);
|
| 87 |
+
void clear();
|
| 88 |
+
void store(const Key key, Value v, Bound type, Depth d, Move m, Value statV, Value kingD);
|
| 89 |
+
|
| 90 |
+
private:
|
| 91 |
+
uint32_t hashMask;
|
| 92 |
+
TTEntry* table;
|
| 93 |
+
void* mem;
|
| 94 |
+
uint8_t generation; // Size must be not bigger than TTEntry::generation8
|
| 95 |
+
};
|
| 96 |
+
|
| 97 |
+
extern TranspositionTable TT;
|
| 98 |
+
|
| 99 |
+
|
| 100 |
+
/// TranspositionTable::first_entry() returns a pointer to the first entry of
|
| 101 |
+
/// a cluster given a position. The lowest order bits of the key are used to
|
| 102 |
+
/// get the index of the cluster.
|
| 103 |
+
|
| 104 |
+
inline TTEntry* TranspositionTable::first_entry(const Key key) const {
|
| 105 |
+
|
| 106 |
+
return table + ((uint32_t)key & hashMask);
|
| 107 |
+
}
|
| 108 |
+
|
| 109 |
+
|
| 110 |
+
/// TranspositionTable::refresh() updates the 'generation' value of the TTEntry
|
| 111 |
+
/// to avoid aging. Normally called after a TT hit.
|
| 112 |
+
|
| 113 |
+
inline void TranspositionTable::refresh(const TTEntry* tte) const {
|
| 114 |
+
|
| 115 |
+
const_cast<TTEntry*>(tte)->set_generation(generation);
|
| 116 |
+
}
|
| 117 |
+
|
| 118 |
+
#endif // #ifndef TT_H_INCLUDED
|
stockfish-4-win/src/types.h
ADDED
|
@@ -0,0 +1,443 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
+
Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
+
|
| 6 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 7 |
+
it under the terms of the GNU General Public License as published by
|
| 8 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 9 |
+
(at your option) any later version.
|
| 10 |
+
|
| 11 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 12 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 13 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 14 |
+
GNU General Public License for more details.
|
| 15 |
+
|
| 16 |
+
You should have received a copy of the GNU General Public License
|
| 17 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 18 |
+
*/
|
| 19 |
+
|
| 20 |
+
#ifndef TYPES_H_INCLUDED
|
| 21 |
+
#define TYPES_H_INCLUDED
|
| 22 |
+
|
| 23 |
+
/// For Linux and OSX configuration is done automatically using Makefile. To get
|
| 24 |
+
/// started type 'make help'.
|
| 25 |
+
///
|
| 26 |
+
/// For Windows, part of the configuration is detected automatically, but some
|
| 27 |
+
/// switches need to be set manually:
|
| 28 |
+
///
|
| 29 |
+
/// -DNDEBUG | Disable debugging mode. Use always.
|
| 30 |
+
///
|
| 31 |
+
/// -DNO_PREFETCH | Disable use of prefetch asm-instruction. A must if you want
|
| 32 |
+
/// | the executable to run on some very old machines.
|
| 33 |
+
///
|
| 34 |
+
/// -DUSE_POPCNT | Add runtime support for use of popcnt asm-instruction. Works
|
| 35 |
+
/// | only in 64-bit mode. For compiling requires hardware with
|
| 36 |
+
/// | popcnt support.
|
| 37 |
+
|
| 38 |
+
#include <cassert>
|
| 39 |
+
#include <cctype>
|
| 40 |
+
#include <climits>
|
| 41 |
+
#include <cstdlib>
|
| 42 |
+
|
| 43 |
+
#include "platform.h"
|
| 44 |
+
|
| 45 |
+
#define unlikely(x) (x) // For code annotation purposes
|
| 46 |
+
|
| 47 |
+
#if defined(_WIN64) && !defined(IS_64BIT)
|
| 48 |
+
# include <intrin.h> // MSVC popcnt and bsfq instrinsics
|
| 49 |
+
# define IS_64BIT
|
| 50 |
+
# define USE_BSFQ
|
| 51 |
+
#endif
|
| 52 |
+
|
| 53 |
+
#if defined(USE_POPCNT) && defined(_MSC_VER) && defined(__INTEL_COMPILER)
|
| 54 |
+
# include <nmmintrin.h> // Intel header for _mm_popcnt_u64() intrinsic
|
| 55 |
+
#endif
|
| 56 |
+
|
| 57 |
+
# if !defined(NO_PREFETCH) && (defined(__INTEL_COMPILER) || defined(_MSC_VER))
|
| 58 |
+
# include <xmmintrin.h> // Intel and Microsoft header for _mm_prefetch()
|
| 59 |
+
# endif
|
| 60 |
+
|
| 61 |
+
#define CACHE_LINE_SIZE 64
|
| 62 |
+
#if defined(_MSC_VER) || defined(__INTEL_COMPILER)
|
| 63 |
+
# define CACHE_LINE_ALIGNMENT __declspec(align(CACHE_LINE_SIZE))
|
| 64 |
+
#else
|
| 65 |
+
# define CACHE_LINE_ALIGNMENT __attribute__ ((aligned(CACHE_LINE_SIZE)))
|
| 66 |
+
#endif
|
| 67 |
+
|
| 68 |
+
#ifdef _MSC_VER
|
| 69 |
+
# define FORCE_INLINE __forceinline
|
| 70 |
+
#elif defined(__GNUC__)
|
| 71 |
+
# define FORCE_INLINE inline __attribute__((always_inline))
|
| 72 |
+
#else
|
| 73 |
+
# define FORCE_INLINE inline
|
| 74 |
+
#endif
|
| 75 |
+
|
| 76 |
+
#ifdef USE_POPCNT
|
| 77 |
+
const bool HasPopCnt = true;
|
| 78 |
+
#else
|
| 79 |
+
const bool HasPopCnt = false;
|
| 80 |
+
#endif
|
| 81 |
+
|
| 82 |
+
#ifdef IS_64BIT
|
| 83 |
+
const bool Is64Bit = true;
|
| 84 |
+
#else
|
| 85 |
+
const bool Is64Bit = false;
|
| 86 |
+
#endif
|
| 87 |
+
|
| 88 |
+
typedef uint64_t Key;
|
| 89 |
+
typedef uint64_t Bitboard;
|
| 90 |
+
|
| 91 |
+
const int MAX_MOVES = 192;
|
| 92 |
+
const int MAX_PLY = 100;
|
| 93 |
+
const int MAX_PLY_PLUS_6 = MAX_PLY + 6;
|
| 94 |
+
|
| 95 |
+
/// A move needs 16 bits to be stored
|
| 96 |
+
///
|
| 97 |
+
/// bit 0- 5: destination square (from 0 to 63)
|
| 98 |
+
/// bit 6-11: origin square (from 0 to 63)
|
| 99 |
+
/// bit 12-13: promotion piece type - 2 (from KNIGHT-2 to QUEEN-2)
|
| 100 |
+
/// bit 14-15: special move flag: promotion (1), en passant (2), castle (3)
|
| 101 |
+
///
|
| 102 |
+
/// Special cases are MOVE_NONE and MOVE_NULL. We can sneak these in because in
|
| 103 |
+
/// any normal move destination square is always different from origin square
|
| 104 |
+
/// while MOVE_NONE and MOVE_NULL have the same origin and destination square.
|
| 105 |
+
|
| 106 |
+
enum Move {
|
| 107 |
+
MOVE_NONE,
|
| 108 |
+
MOVE_NULL = 65
|
| 109 |
+
};
|
| 110 |
+
|
| 111 |
+
enum MoveType {
|
| 112 |
+
NORMAL,
|
| 113 |
+
PROMOTION = 1 << 14,
|
| 114 |
+
ENPASSANT = 2 << 14,
|
| 115 |
+
CASTLE = 3 << 14
|
| 116 |
+
};
|
| 117 |
+
|
| 118 |
+
enum CastleRight { // Defined as in PolyGlot book hash key
|
| 119 |
+
CASTLES_NONE,
|
| 120 |
+
WHITE_OO,
|
| 121 |
+
WHITE_OOO = WHITE_OO << 1,
|
| 122 |
+
BLACK_OO = WHITE_OO << 2,
|
| 123 |
+
BLACK_OOO = WHITE_OO << 3,
|
| 124 |
+
ALL_CASTLES = WHITE_OO | WHITE_OOO | BLACK_OO | BLACK_OOO,
|
| 125 |
+
CASTLE_RIGHT_NB = 16
|
| 126 |
+
};
|
| 127 |
+
|
| 128 |
+
enum CastlingSide {
|
| 129 |
+
KING_SIDE,
|
| 130 |
+
QUEEN_SIDE,
|
| 131 |
+
CASTLING_SIDE_NB = 2
|
| 132 |
+
};
|
| 133 |
+
|
| 134 |
+
enum Phase {
|
| 135 |
+
PHASE_ENDGAME,
|
| 136 |
+
PHASE_MIDGAME = 128,
|
| 137 |
+
MG = 0, EG = 1, PHASE_NB = 2
|
| 138 |
+
};
|
| 139 |
+
|
| 140 |
+
enum ScaleFactor {
|
| 141 |
+
SCALE_FACTOR_DRAW = 0,
|
| 142 |
+
SCALE_FACTOR_NORMAL = 64,
|
| 143 |
+
SCALE_FACTOR_MAX = 128,
|
| 144 |
+
SCALE_FACTOR_NONE = 255
|
| 145 |
+
};
|
| 146 |
+
|
| 147 |
+
enum Bound {
|
| 148 |
+
BOUND_NONE,
|
| 149 |
+
BOUND_UPPER,
|
| 150 |
+
BOUND_LOWER,
|
| 151 |
+
BOUND_EXACT = BOUND_UPPER | BOUND_LOWER
|
| 152 |
+
};
|
| 153 |
+
|
| 154 |
+
enum Value {
|
| 155 |
+
VALUE_ZERO = 0,
|
| 156 |
+
VALUE_DRAW = 0,
|
| 157 |
+
VALUE_KNOWN_WIN = 15000,
|
| 158 |
+
VALUE_MATE = 30000,
|
| 159 |
+
VALUE_INFINITE = 30001,
|
| 160 |
+
VALUE_NONE = 30002,
|
| 161 |
+
|
| 162 |
+
VALUE_MATE_IN_MAX_PLY = VALUE_MATE - MAX_PLY,
|
| 163 |
+
VALUE_MATED_IN_MAX_PLY = -VALUE_MATE + MAX_PLY,
|
| 164 |
+
|
| 165 |
+
VALUE_ENSURE_INTEGER_SIZE_P = INT_MAX,
|
| 166 |
+
VALUE_ENSURE_INTEGER_SIZE_N = INT_MIN,
|
| 167 |
+
|
| 168 |
+
PawnValueMg = 198, PawnValueEg = 258,
|
| 169 |
+
KnightValueMg = 817, KnightValueEg = 846,
|
| 170 |
+
BishopValueMg = 836, BishopValueEg = 857,
|
| 171 |
+
RookValueMg = 1270, RookValueEg = 1278,
|
| 172 |
+
QueenValueMg = 2521, QueenValueEg = 2558
|
| 173 |
+
};
|
| 174 |
+
|
| 175 |
+
enum PieceType {
|
| 176 |
+
NO_PIECE_TYPE, PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING,
|
| 177 |
+
ALL_PIECES = 0,
|
| 178 |
+
PIECE_TYPE_NB = 8
|
| 179 |
+
};
|
| 180 |
+
|
| 181 |
+
enum Piece {
|
| 182 |
+
NO_PIECE,
|
| 183 |
+
W_PAWN = 1, W_KNIGHT, W_BISHOP, W_ROOK, W_QUEEN, W_KING,
|
| 184 |
+
B_PAWN = 9, B_KNIGHT, B_BISHOP, B_ROOK, B_QUEEN, B_KING,
|
| 185 |
+
PIECE_NB = 16
|
| 186 |
+
};
|
| 187 |
+
|
| 188 |
+
enum Color {
|
| 189 |
+
WHITE, BLACK, NO_COLOR, COLOR_NB = 2
|
| 190 |
+
};
|
| 191 |
+
|
| 192 |
+
enum Depth {
|
| 193 |
+
|
| 194 |
+
ONE_PLY = 2,
|
| 195 |
+
|
| 196 |
+
DEPTH_ZERO = 0 * ONE_PLY,
|
| 197 |
+
DEPTH_QS_CHECKS = -1 * ONE_PLY,
|
| 198 |
+
DEPTH_QS_NO_CHECKS = -2 * ONE_PLY,
|
| 199 |
+
DEPTH_QS_RECAPTURES = -7 * ONE_PLY,
|
| 200 |
+
|
| 201 |
+
DEPTH_NONE = -127 * ONE_PLY
|
| 202 |
+
};
|
| 203 |
+
|
| 204 |
+
enum Square {
|
| 205 |
+
SQ_A1, SQ_B1, SQ_C1, SQ_D1, SQ_E1, SQ_F1, SQ_G1, SQ_H1,
|
| 206 |
+
SQ_A2, SQ_B2, SQ_C2, SQ_D2, SQ_E2, SQ_F2, SQ_G2, SQ_H2,
|
| 207 |
+
SQ_A3, SQ_B3, SQ_C3, SQ_D3, SQ_E3, SQ_F3, SQ_G3, SQ_H3,
|
| 208 |
+
SQ_A4, SQ_B4, SQ_C4, SQ_D4, SQ_E4, SQ_F4, SQ_G4, SQ_H4,
|
| 209 |
+
SQ_A5, SQ_B5, SQ_C5, SQ_D5, SQ_E5, SQ_F5, SQ_G5, SQ_H5,
|
| 210 |
+
SQ_A6, SQ_B6, SQ_C6, SQ_D6, SQ_E6, SQ_F6, SQ_G6, SQ_H6,
|
| 211 |
+
SQ_A7, SQ_B7, SQ_C7, SQ_D7, SQ_E7, SQ_F7, SQ_G7, SQ_H7,
|
| 212 |
+
SQ_A8, SQ_B8, SQ_C8, SQ_D8, SQ_E8, SQ_F8, SQ_G8, SQ_H8,
|
| 213 |
+
SQ_NONE,
|
| 214 |
+
|
| 215 |
+
SQUARE_NB = 64,
|
| 216 |
+
|
| 217 |
+
DELTA_N = 8,
|
| 218 |
+
DELTA_E = 1,
|
| 219 |
+
DELTA_S = -8,
|
| 220 |
+
DELTA_W = -1,
|
| 221 |
+
|
| 222 |
+
DELTA_NN = DELTA_N + DELTA_N,
|
| 223 |
+
DELTA_NE = DELTA_N + DELTA_E,
|
| 224 |
+
DELTA_SE = DELTA_S + DELTA_E,
|
| 225 |
+
DELTA_SS = DELTA_S + DELTA_S,
|
| 226 |
+
DELTA_SW = DELTA_S + DELTA_W,
|
| 227 |
+
DELTA_NW = DELTA_N + DELTA_W
|
| 228 |
+
};
|
| 229 |
+
|
| 230 |
+
enum File {
|
| 231 |
+
FILE_A, FILE_B, FILE_C, FILE_D, FILE_E, FILE_F, FILE_G, FILE_H, FILE_NB
|
| 232 |
+
};
|
| 233 |
+
|
| 234 |
+
enum Rank {
|
| 235 |
+
RANK_1, RANK_2, RANK_3, RANK_4, RANK_5, RANK_6, RANK_7, RANK_8, RANK_NB
|
| 236 |
+
};
|
| 237 |
+
|
| 238 |
+
|
| 239 |
+
/// Score enum keeps a midgame and an endgame value in a single integer (enum),
|
| 240 |
+
/// first LSB 16 bits are used to store endgame value, while upper bits are used
|
| 241 |
+
/// for midgame value. Compiler is free to choose the enum type as long as can
|
| 242 |
+
/// keep its data, so ensure Score to be an integer type.
|
| 243 |
+
enum Score {
|
| 244 |
+
SCORE_ZERO,
|
| 245 |
+
SCORE_ENSURE_INTEGER_SIZE_P = INT_MAX,
|
| 246 |
+
SCORE_ENSURE_INTEGER_SIZE_N = INT_MIN
|
| 247 |
+
};
|
| 248 |
+
|
| 249 |
+
inline Score make_score(int mg, int eg) { return Score((mg << 16) + eg); }
|
| 250 |
+
|
| 251 |
+
/// Extracting the signed lower and upper 16 bits it not so trivial because
|
| 252 |
+
/// according to the standard a simple cast to short is implementation defined
|
| 253 |
+
/// and so is a right shift of a signed integer.
|
| 254 |
+
inline Value mg_value(Score s) { return Value(((s + 0x8000) & ~0xffff) / 0x10000); }
|
| 255 |
+
|
| 256 |
+
/// On Intel 64 bit we have a small speed regression with the standard conforming
|
| 257 |
+
/// version, so use a faster code in this case that, although not 100% standard
|
| 258 |
+
/// compliant it seems to work for Intel and MSVC.
|
| 259 |
+
#if defined(IS_64BIT) && (!defined(__GNUC__) || defined(__INTEL_COMPILER))
|
| 260 |
+
|
| 261 |
+
inline Value eg_value(Score s) { return Value(int16_t(s & 0xffff)); }
|
| 262 |
+
|
| 263 |
+
#else
|
| 264 |
+
|
| 265 |
+
inline Value eg_value(Score s) {
|
| 266 |
+
return Value((int)(unsigned(s) & 0x7fffu) - (int)(unsigned(s) & 0x8000u));
|
| 267 |
+
}
|
| 268 |
+
|
| 269 |
+
#endif
|
| 270 |
+
|
| 271 |
+
#define ENABLE_SAFE_OPERATORS_ON(T) \
|
| 272 |
+
inline T operator+(const T d1, const T d2) { return T(int(d1) + int(d2)); } \
|
| 273 |
+
inline T operator-(const T d1, const T d2) { return T(int(d1) - int(d2)); } \
|
| 274 |
+
inline T operator*(int i, const T d) { return T(i * int(d)); } \
|
| 275 |
+
inline T operator*(const T d, int i) { return T(int(d) * i); } \
|
| 276 |
+
inline T operator-(const T d) { return T(-int(d)); } \
|
| 277 |
+
inline T& operator+=(T& d1, const T d2) { d1 = d1 + d2; return d1; } \
|
| 278 |
+
inline T& operator-=(T& d1, const T d2) { d1 = d1 - d2; return d1; } \
|
| 279 |
+
inline T& operator*=(T& d, int i) { d = T(int(d) * i); return d; }
|
| 280 |
+
|
| 281 |
+
#define ENABLE_OPERATORS_ON(T) ENABLE_SAFE_OPERATORS_ON(T) \
|
| 282 |
+
inline T operator++(T& d, int) { d = T(int(d) + 1); return d; } \
|
| 283 |
+
inline T operator--(T& d, int) { d = T(int(d) - 1); return d; } \
|
| 284 |
+
inline T operator/(const T d, int i) { return T(int(d) / i); } \
|
| 285 |
+
inline T& operator/=(T& d, int i) { d = T(int(d) / i); return d; }
|
| 286 |
+
|
| 287 |
+
ENABLE_OPERATORS_ON(Value)
|
| 288 |
+
ENABLE_OPERATORS_ON(PieceType)
|
| 289 |
+
ENABLE_OPERATORS_ON(Piece)
|
| 290 |
+
ENABLE_OPERATORS_ON(Color)
|
| 291 |
+
ENABLE_OPERATORS_ON(Depth)
|
| 292 |
+
ENABLE_OPERATORS_ON(Square)
|
| 293 |
+
ENABLE_OPERATORS_ON(File)
|
| 294 |
+
ENABLE_OPERATORS_ON(Rank)
|
| 295 |
+
|
| 296 |
+
/// Added operators for adding integers to a Value
|
| 297 |
+
inline Value operator+(Value v, int i) { return Value(int(v) + i); }
|
| 298 |
+
inline Value operator-(Value v, int i) { return Value(int(v) - i); }
|
| 299 |
+
|
| 300 |
+
ENABLE_SAFE_OPERATORS_ON(Score)
|
| 301 |
+
|
| 302 |
+
/// Only declared but not defined. We don't want to multiply two scores due to
|
| 303 |
+
/// a very high risk of overflow. So user should explicitly convert to integer.
|
| 304 |
+
inline Score operator*(Score s1, Score s2);
|
| 305 |
+
|
| 306 |
+
/// Division of a Score must be handled separately for each term
|
| 307 |
+
inline Score operator/(Score s, int i) {
|
| 308 |
+
return make_score(mg_value(s) / i, eg_value(s) / i);
|
| 309 |
+
}
|
| 310 |
+
|
| 311 |
+
#undef ENABLE_OPERATORS_ON
|
| 312 |
+
#undef ENABLE_SAFE_OPERATORS_ON
|
| 313 |
+
|
| 314 |
+
extern Value PieceValue[PHASE_NB][PIECE_NB];
|
| 315 |
+
|
| 316 |
+
struct ExtMove {
|
| 317 |
+
Move move;
|
| 318 |
+
int score;
|
| 319 |
+
};
|
| 320 |
+
|
| 321 |
+
inline bool operator<(const ExtMove& f, const ExtMove& s) {
|
| 322 |
+
return f.score < s.score;
|
| 323 |
+
}
|
| 324 |
+
|
| 325 |
+
inline Color operator~(Color c) {
|
| 326 |
+
return Color(c ^ 1);
|
| 327 |
+
}
|
| 328 |
+
|
| 329 |
+
inline Square operator~(Square s) {
|
| 330 |
+
return Square(s ^ 56); // Vertical flip SQ_A1 -> SQ_A8
|
| 331 |
+
}
|
| 332 |
+
|
| 333 |
+
inline Square operator|(File f, Rank r) {
|
| 334 |
+
return Square((r << 3) | f);
|
| 335 |
+
}
|
| 336 |
+
|
| 337 |
+
inline Value mate_in(int ply) {
|
| 338 |
+
return VALUE_MATE - ply;
|
| 339 |
+
}
|
| 340 |
+
|
| 341 |
+
inline Value mated_in(int ply) {
|
| 342 |
+
return -VALUE_MATE + ply;
|
| 343 |
+
}
|
| 344 |
+
|
| 345 |
+
inline Piece make_piece(Color c, PieceType pt) {
|
| 346 |
+
return Piece((c << 3) | pt);
|
| 347 |
+
}
|
| 348 |
+
|
| 349 |
+
inline CastleRight make_castle_right(Color c, CastlingSide s) {
|
| 350 |
+
return CastleRight(WHITE_OO << ((s == QUEEN_SIDE) + 2 * c));
|
| 351 |
+
}
|
| 352 |
+
|
| 353 |
+
inline PieceType type_of(Piece p) {
|
| 354 |
+
return PieceType(p & 7);
|
| 355 |
+
}
|
| 356 |
+
|
| 357 |
+
inline Color color_of(Piece p) {
|
| 358 |
+
assert(p != NO_PIECE);
|
| 359 |
+
return Color(p >> 3);
|
| 360 |
+
}
|
| 361 |
+
|
| 362 |
+
inline bool is_ok(Square s) {
|
| 363 |
+
return s >= SQ_A1 && s <= SQ_H8;
|
| 364 |
+
}
|
| 365 |
+
|
| 366 |
+
inline File file_of(Square s) {
|
| 367 |
+
return File(s & 7);
|
| 368 |
+
}
|
| 369 |
+
|
| 370 |
+
inline Rank rank_of(Square s) {
|
| 371 |
+
return Rank(s >> 3);
|
| 372 |
+
}
|
| 373 |
+
|
| 374 |
+
inline Square mirror(Square s) {
|
| 375 |
+
return Square(s ^ 7); // Horizontal flip SQ_A1 -> SQ_H1
|
| 376 |
+
}
|
| 377 |
+
|
| 378 |
+
inline Square relative_square(Color c, Square s) {
|
| 379 |
+
return Square(s ^ (c * 56));
|
| 380 |
+
}
|
| 381 |
+
|
| 382 |
+
inline Rank relative_rank(Color c, Rank r) {
|
| 383 |
+
return Rank(r ^ (c * 7));
|
| 384 |
+
}
|
| 385 |
+
|
| 386 |
+
inline Rank relative_rank(Color c, Square s) {
|
| 387 |
+
return relative_rank(c, rank_of(s));
|
| 388 |
+
}
|
| 389 |
+
|
| 390 |
+
inline bool opposite_colors(Square s1, Square s2) {
|
| 391 |
+
int s = int(s1) ^ int(s2);
|
| 392 |
+
return ((s >> 3) ^ s) & 1;
|
| 393 |
+
}
|
| 394 |
+
|
| 395 |
+
inline char file_to_char(File f, bool tolower = true) {
|
| 396 |
+
return char(f - FILE_A + (tolower ? 'a' : 'A'));
|
| 397 |
+
}
|
| 398 |
+
|
| 399 |
+
inline char rank_to_char(Rank r) {
|
| 400 |
+
return char(r - RANK_1 + '1');
|
| 401 |
+
}
|
| 402 |
+
|
| 403 |
+
inline Square pawn_push(Color c) {
|
| 404 |
+
return c == WHITE ? DELTA_N : DELTA_S;
|
| 405 |
+
}
|
| 406 |
+
|
| 407 |
+
inline Square from_sq(Move m) {
|
| 408 |
+
return Square((m >> 6) & 0x3F);
|
| 409 |
+
}
|
| 410 |
+
|
| 411 |
+
inline Square to_sq(Move m) {
|
| 412 |
+
return Square(m & 0x3F);
|
| 413 |
+
}
|
| 414 |
+
|
| 415 |
+
inline MoveType type_of(Move m) {
|
| 416 |
+
return MoveType(m & (3 << 14));
|
| 417 |
+
}
|
| 418 |
+
|
| 419 |
+
inline PieceType promotion_type(Move m) {
|
| 420 |
+
return PieceType(((m >> 12) & 3) + 2);
|
| 421 |
+
}
|
| 422 |
+
|
| 423 |
+
inline Move make_move(Square from, Square to) {
|
| 424 |
+
return Move(to | (from << 6));
|
| 425 |
+
}
|
| 426 |
+
|
| 427 |
+
template<MoveType T>
|
| 428 |
+
inline Move make(Square from, Square to, PieceType pt = KNIGHT) {
|
| 429 |
+
return Move(to | (from << 6) | T | ((pt - KNIGHT) << 12));
|
| 430 |
+
}
|
| 431 |
+
|
| 432 |
+
inline bool is_ok(Move m) {
|
| 433 |
+
return from_sq(m) != to_sq(m); // Catches also MOVE_NULL and MOVE_NONE
|
| 434 |
+
}
|
| 435 |
+
|
| 436 |
+
#include <string>
|
| 437 |
+
|
| 438 |
+
inline const std::string square_to_string(Square s) {
|
| 439 |
+
char ch[] = { file_to_char(file_of(s)), rank_to_char(rank_of(s)), 0 };
|
| 440 |
+
return ch;
|
| 441 |
+
}
|
| 442 |
+
|
| 443 |
+
#endif // #ifndef TYPES_H_INCLUDED
|
stockfish-4-win/src/uci.cpp
ADDED
|
@@ -0,0 +1,219 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
| 3 |
+
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
|
| 4 |
+
Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad
|
| 5 |
+
|
| 6 |
+
Stockfish is free software: you can redistribute it and/or modify
|
| 7 |
+
it under the terms of the GNU General Public License as published by
|
| 8 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 9 |
+
(at your option) any later version.
|
| 10 |
+
|
| 11 |
+
Stockfish is distributed in the hope that it will be useful,
|
| 12 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 13 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 14 |
+
GNU General Public License for more details.
|
| 15 |
+
|
| 16 |
+
You should have received a copy of the GNU General Public License
|
| 17 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 18 |
+
*/
|
| 19 |
+
|
| 20 |
+
#include <iomanip>
|
| 21 |
+
#include <iostream>
|
| 22 |
+
#include <sstream>
|
| 23 |
+
#include <string>
|
| 24 |
+
|
| 25 |
+
#include "evaluate.h"
|
| 26 |
+
#include "notation.h"
|
| 27 |
+
#include "position.h"
|
| 28 |
+
#include "search.h"
|
| 29 |
+
#include "thread.h"
|
| 30 |
+
#include "ucioption.h"
|
| 31 |
+
|
| 32 |
+
using namespace std;
|
| 33 |
+
|
| 34 |
+
extern void benchmark(const Position& pos, istream& is);
|
| 35 |
+
|
| 36 |
+
namespace {
|
| 37 |
+
|
| 38 |
+
// FEN string of the initial position, normal chess
|
| 39 |
+
const char* StartFEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
|
| 40 |
+
|
| 41 |
+
// Keep track of position keys along the setup moves (from start position to the
|
| 42 |
+
// position just before to start searching). Needed by repetition draw detection.
|
| 43 |
+
Search::StateStackPtr SetupStates;
|
| 44 |
+
|
| 45 |
+
void setoption(istringstream& up);
|
| 46 |
+
void position(Position& pos, istringstream& up);
|
| 47 |
+
void go(const Position& pos, istringstream& up);
|
| 48 |
+
}
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
/// Wait for a command from the user, parse this text string as an UCI command,
|
| 52 |
+
/// and call the appropriate functions. Also intercepts EOF from stdin to ensure
|
| 53 |
+
/// that we exit gracefully if the GUI dies unexpectedly. In addition to the UCI
|
| 54 |
+
/// commands, the function also supports a few debug commands.
|
| 55 |
+
|
| 56 |
+
void UCI::loop(const string& args) {
|
| 57 |
+
|
| 58 |
+
Position pos(StartFEN, false, Threads.main()); // The root position
|
| 59 |
+
string token, cmd = args;
|
| 60 |
+
|
| 61 |
+
do {
|
| 62 |
+
if (args.empty() && !getline(cin, cmd)) // Block here waiting for input
|
| 63 |
+
cmd = "quit";
|
| 64 |
+
|
| 65 |
+
istringstream is(cmd);
|
| 66 |
+
|
| 67 |
+
is >> skipws >> token;
|
| 68 |
+
|
| 69 |
+
if (token == "quit" || token == "stop" || token == "ponderhit")
|
| 70 |
+
{
|
| 71 |
+
// GUI sends 'ponderhit' to tell us to ponder on the same move the
|
| 72 |
+
// opponent has played. In case Signals.stopOnPonderhit is set we are
|
| 73 |
+
// waiting for 'ponderhit' to stop the search (for instance because we
|
| 74 |
+
// already ran out of time), otherwise we should continue searching but
|
| 75 |
+
// switching from pondering to normal search.
|
| 76 |
+
if (token != "ponderhit" || Search::Signals.stopOnPonderhit)
|
| 77 |
+
{
|
| 78 |
+
Search::Signals.stop = true;
|
| 79 |
+
Threads.main()->notify_one(); // Could be sleeping
|
| 80 |
+
}
|
| 81 |
+
else
|
| 82 |
+
Search::Limits.ponder = false;
|
| 83 |
+
}
|
| 84 |
+
else if (token == "perft" && (is >> token)) // Read perft depth
|
| 85 |
+
{
|
| 86 |
+
stringstream ss;
|
| 87 |
+
|
| 88 |
+
ss << Options["Hash"] << " "
|
| 89 |
+
<< Options["Threads"] << " " << token << " current perft";
|
| 90 |
+
|
| 91 |
+
benchmark(pos, ss);
|
| 92 |
+
}
|
| 93 |
+
else if (token == "key")
|
| 94 |
+
sync_cout << hex << uppercase << setfill('0')
|
| 95 |
+
<< "position key: " << setw(16) << pos.key()
|
| 96 |
+
<< "\nmaterial key: " << setw(16) << pos.material_key()
|
| 97 |
+
<< "\npawn key: " << setw(16) << pos.pawn_key()
|
| 98 |
+
<< dec << sync_endl;
|
| 99 |
+
|
| 100 |
+
else if (token == "uci")
|
| 101 |
+
sync_cout << "id name " << engine_info(true)
|
| 102 |
+
<< "\n" << Options
|
| 103 |
+
<< "\nuciok" << sync_endl;
|
| 104 |
+
|
| 105 |
+
else if (token == "eval")
|
| 106 |
+
{
|
| 107 |
+
Search::RootColor = pos.side_to_move(); // Ensure it is set
|
| 108 |
+
sync_cout << Eval::trace(pos) << sync_endl;
|
| 109 |
+
}
|
| 110 |
+
else if (token == "ucinewgame") { /* Avoid returning "Unknown command" */ }
|
| 111 |
+
else if (token == "go") go(pos, is);
|
| 112 |
+
else if (token == "position") position(pos, is);
|
| 113 |
+
else if (token == "setoption") setoption(is);
|
| 114 |
+
else if (token == "flip") pos.flip();
|
| 115 |
+
else if (token == "bench") benchmark(pos, is);
|
| 116 |
+
else if (token == "d") sync_cout << pos.pretty() << sync_endl;
|
| 117 |
+
else if (token == "isready") sync_cout << "readyok" << sync_endl;
|
| 118 |
+
else
|
| 119 |
+
sync_cout << "Unknown command: " << cmd << sync_endl;
|
| 120 |
+
|
| 121 |
+
} while (token != "quit" && args.empty()); // Args have one-shot behaviour
|
| 122 |
+
|
| 123 |
+
Threads.wait_for_think_finished(); // Cannot quit while search is running
|
| 124 |
+
}
|
| 125 |
+
|
| 126 |
+
|
| 127 |
+
namespace {
|
| 128 |
+
|
| 129 |
+
// position() is called when engine receives the "position" UCI command.
|
| 130 |
+
// The function sets up the position described in the given fen string ("fen")
|
| 131 |
+
// or the starting position ("startpos") and then makes the moves given in the
|
| 132 |
+
// following move list ("moves").
|
| 133 |
+
|
| 134 |
+
void position(Position& pos, istringstream& is) {
|
| 135 |
+
|
| 136 |
+
Move m;
|
| 137 |
+
string token, fen;
|
| 138 |
+
|
| 139 |
+
is >> token;
|
| 140 |
+
|
| 141 |
+
if (token == "startpos")
|
| 142 |
+
{
|
| 143 |
+
fen = StartFEN;
|
| 144 |
+
is >> token; // Consume "moves" token if any
|
| 145 |
+
}
|
| 146 |
+
else if (token == "fen")
|
| 147 |
+
while (is >> token && token != "moves")
|
| 148 |
+
fen += token + " ";
|
| 149 |
+
else
|
| 150 |
+
return;
|
| 151 |
+
|
| 152 |
+
pos.set(fen, Options["UCI_Chess960"], Threads.main());
|
| 153 |
+
SetupStates = Search::StateStackPtr(new std::stack<StateInfo>());
|
| 154 |
+
|
| 155 |
+
// Parse move list (if any)
|
| 156 |
+
while (is >> token && (m = move_from_uci(pos, token)) != MOVE_NONE)
|
| 157 |
+
{
|
| 158 |
+
SetupStates->push(StateInfo());
|
| 159 |
+
pos.do_move(m, SetupStates->top());
|
| 160 |
+
}
|
| 161 |
+
}
|
| 162 |
+
|
| 163 |
+
|
| 164 |
+
// setoption() is called when engine receives the "setoption" UCI command. The
|
| 165 |
+
// function updates the UCI option ("name") to the given value ("value").
|
| 166 |
+
|
| 167 |
+
void setoption(istringstream& is) {
|
| 168 |
+
|
| 169 |
+
string token, name, value;
|
| 170 |
+
|
| 171 |
+
is >> token; // Consume "name" token
|
| 172 |
+
|
| 173 |
+
// Read option name (can contain spaces)
|
| 174 |
+
while (is >> token && token != "value")
|
| 175 |
+
name += string(" ", !name.empty()) + token;
|
| 176 |
+
|
| 177 |
+
// Read option value (can contain spaces)
|
| 178 |
+
while (is >> token)
|
| 179 |
+
value += string(" ", !value.empty()) + token;
|
| 180 |
+
|
| 181 |
+
if (Options.count(name))
|
| 182 |
+
Options[name] = value;
|
| 183 |
+
else
|
| 184 |
+
sync_cout << "No such option: " << name << sync_endl;
|
| 185 |
+
}
|
| 186 |
+
|
| 187 |
+
|
| 188 |
+
// go() is called when engine receives the "go" UCI command. The function sets
|
| 189 |
+
// the thinking time and other parameters from the input string, and starts
|
| 190 |
+
// the search.
|
| 191 |
+
|
| 192 |
+
void go(const Position& pos, istringstream& is) {
|
| 193 |
+
|
| 194 |
+
Search::LimitsType limits;
|
| 195 |
+
vector<Move> searchMoves;
|
| 196 |
+
string token;
|
| 197 |
+
|
| 198 |
+
while (is >> token)
|
| 199 |
+
{
|
| 200 |
+
if (token == "searchmoves")
|
| 201 |
+
while (is >> token)
|
| 202 |
+
searchMoves.push_back(move_from_uci(pos, token));
|
| 203 |
+
|
| 204 |
+
else if (token == "wtime") is >> limits.time[WHITE];
|
| 205 |
+
else if (token == "btime") is >> limits.time[BLACK];
|
| 206 |
+
else if (token == "winc") is >> limits.inc[WHITE];
|
| 207 |
+
else if (token == "binc") is >> limits.inc[BLACK];
|
| 208 |
+
else if (token == "movestogo") is >> limits.movestogo;
|
| 209 |
+
else if (token == "depth") is >> limits.depth;
|
| 210 |
+
else if (token == "nodes") is >> limits.nodes;
|
| 211 |
+
else if (token == "movetime") is >> limits.movetime;
|
| 212 |
+
else if (token == "mate") is >> limits.mate;
|
| 213 |
+
else if (token == "infinite") limits.infinite = true;
|
| 214 |
+
else if (token == "ponder") limits.ponder = true;
|
| 215 |
+
}
|
| 216 |
+
|
| 217 |
+
Threads.start_thinking(pos, limits, searchMoves, SetupStates);
|
| 218 |
+
}
|
| 219 |
+
}
|